803-v5.13-0004-nvmem-core-Add-functions-to-make-number-reading-easy.patch 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. From a28e824fb8270eda43fd0f65c2a5fdf33f55c5eb Mon Sep 17 00:00:00 2001
  2. From: Douglas Anderson <[email protected]>
  3. Date: Tue, 30 Mar 2021 12:12:37 +0100
  4. Subject: [PATCH] nvmem: core: Add functions to make number reading easy
  5. Sometimes the clients of nvmem just want to get a number out of
  6. nvmem. They don't want to think about exactly how many bytes the nvmem
  7. cell took up. They just want the number. Let's make it easy.
  8. In general this concept is useful because nvmem space is precious and
  9. usually the fewest bits are allocated that will hold a given value on
  10. a given system. However, even though small numbers might be fine on
  11. one system that doesn't mean that logically the number couldn't be
  12. bigger. Imagine nvmem containing a max frequency for a component. On
  13. one system perhaps that fits in 16 bits. On another system it might
  14. fit in 32 bits. The code reading this number doesn't care--it just
  15. wants the number.
  16. We'll provide two functions: nvmem_cell_read_variable_le_u32() and
  17. nvmem_cell_read_variable_le_u64().
  18. Comparing these to the existing functions like nvmem_cell_read_u32():
  19. * These new functions have no problems if the value was stored in
  20. nvmem in fewer bytes. It's OK to use these function as long as the
  21. value stored will fit in 32-bits (or 64-bits).
  22. * These functions avoid problems that the earlier APIs had with bit
  23. offsets. For instance, you can't use nvmem_cell_read_u32() to read a
  24. value has nbits=32 and bit_offset=4 because the nvmem cell must be
  25. at least 5 bytes big to hold this value. The new API accounts for
  26. this and works fine.
  27. * These functions make it very explicit that they assume that the
  28. number was stored in little endian format. The old functions made
  29. this assumption whenever bit_offset was non-zero (see
  30. nvmem_shift_read_buffer_in_place()) but didn't whenever the
  31. bit_offset was zero.
  32. NOTE: it's assumed that we don't need an 8-bit or 16-bit version of
  33. this function. The 32-bit version of the function can be used to read
  34. 8-bit or 16-bit data.
  35. At the moment, I'm only adding the "unsigned" versions of these
  36. functions, but if it ends up being useful someone could add a "signed"
  37. version that did 2's complement sign extension.
  38. At the moment, I'm only adding the "little endian" versions of these
  39. functions. Adding the "big endian" version would require adding "big
  40. endian" support to nvmem_shift_read_buffer_in_place().
  41. Signed-off-by: Douglas Anderson <[email protected]>
  42. Signed-off-by: Srinivas Kandagatla <[email protected]>
  43. Link: https://lore.kernel.org/r/[email protected]
  44. Signed-off-by: Greg Kroah-Hartman <[email protected]>
  45. ---
  46. drivers/nvmem/core.c | 95 ++++++++++++++++++++++++++++++++++
  47. include/linux/nvmem-consumer.h | 4 ++
  48. 2 files changed, 99 insertions(+)
  49. --- a/drivers/nvmem/core.c
  50. +++ b/drivers/nvmem/core.c
  51. @@ -1613,6 +1613,101 @@ int nvmem_cell_read_u64(struct device *d
  52. }
  53. EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
  54. +static void *nvmem_cell_read_variable_common(struct device *dev,
  55. + const char *cell_id,
  56. + size_t max_len, size_t *len)
  57. +{
  58. + struct nvmem_cell *cell;
  59. + int nbits;
  60. + void *buf;
  61. +
  62. + cell = nvmem_cell_get(dev, cell_id);
  63. + if (IS_ERR(cell))
  64. + return cell;
  65. +
  66. + nbits = cell->nbits;
  67. + buf = nvmem_cell_read(cell, len);
  68. + nvmem_cell_put(cell);
  69. + if (IS_ERR(buf))
  70. + return buf;
  71. +
  72. + /*
  73. + * If nbits is set then nvmem_cell_read() can significantly exaggerate
  74. + * the length of the real data. Throw away the extra junk.
  75. + */
  76. + if (nbits)
  77. + *len = DIV_ROUND_UP(nbits, 8);
  78. +
  79. + if (*len > max_len) {
  80. + kfree(buf);
  81. + return ERR_PTR(-ERANGE);
  82. + }
  83. +
  84. + return buf;
  85. +}
  86. +
  87. +/**
  88. + * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
  89. + *
  90. + * @dev: Device that requests the nvmem cell.
  91. + * @cell_id: Name of nvmem cell to read.
  92. + * @val: pointer to output value.
  93. + *
  94. + * Return: 0 on success or negative errno.
  95. + */
  96. +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
  97. + u32 *val)
  98. +{
  99. + size_t len;
  100. + u8 *buf;
  101. + int i;
  102. +
  103. + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
  104. + if (IS_ERR(buf))
  105. + return PTR_ERR(buf);
  106. +
  107. + /* Copy w/ implicit endian conversion */
  108. + *val = 0;
  109. + for (i = 0; i < len; i++)
  110. + *val |= buf[i] << (8 * i);
  111. +
  112. + kfree(buf);
  113. +
  114. + return 0;
  115. +}
  116. +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
  117. +
  118. +/**
  119. + * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number.
  120. + *
  121. + * @dev: Device that requests the nvmem cell.
  122. + * @cell_id: Name of nvmem cell to read.
  123. + * @val: pointer to output value.
  124. + *
  125. + * Return: 0 on success or negative errno.
  126. + */
  127. +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
  128. + u64 *val)
  129. +{
  130. + size_t len;
  131. + u8 *buf;
  132. + int i;
  133. +
  134. + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
  135. + if (IS_ERR(buf))
  136. + return PTR_ERR(buf);
  137. +
  138. + /* Copy w/ implicit endian conversion */
  139. + *val = 0;
  140. + for (i = 0; i < len; i++)
  141. + *val |= buf[i] << (8 * i);
  142. +
  143. + kfree(buf);
  144. +
  145. + return 0;
  146. +}
  147. +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64);
  148. +
  149. /**
  150. * nvmem_device_cell_read() - Read a given nvmem device and cell
  151. *
  152. --- a/include/linux/nvmem-consumer.h
  153. +++ b/include/linux/nvmem-consumer.h
  154. @@ -65,6 +65,10 @@ int nvmem_cell_read_u8(struct device *de
  155. int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
  156. int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
  157. int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val);
  158. +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
  159. + u32 *val);
  160. +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
  161. + u64 *val);
  162. /* direct nvmem device read/write interface */
  163. struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);