nvm.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * NVM helpers
  4. *
  5. * Copyright (C) 2020, Intel Corporation
  6. * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  7. */
  8. #include <linux/idr.h>
  9. #include <linux/slab.h>
  10. #include <linux/vmalloc.h>
  11. #include "tb.h"
  12. static DEFINE_IDA(nvm_ida);
  13. /**
  14. * tb_nvm_alloc() - Allocate new NVM structure
  15. * @dev: Device owning the NVM
  16. *
  17. * Allocates new NVM structure with unique @id and returns it. In case
  18. * of error returns ERR_PTR().
  19. */
  20. struct tb_nvm *tb_nvm_alloc(struct device *dev)
  21. {
  22. struct tb_nvm *nvm;
  23. int ret;
  24. nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
  25. if (!nvm)
  26. return ERR_PTR(-ENOMEM);
  27. ret = ida_simple_get(&nvm_ida, 0, 0, GFP_KERNEL);
  28. if (ret < 0) {
  29. kfree(nvm);
  30. return ERR_PTR(ret);
  31. }
  32. nvm->id = ret;
  33. nvm->dev = dev;
  34. return nvm;
  35. }
  36. /**
  37. * tb_nvm_add_active() - Adds active NVMem device to NVM
  38. * @nvm: NVM structure
  39. * @size: Size of the active NVM in bytes
  40. * @reg_read: Pointer to the function to read the NVM (passed directly to the
  41. * NVMem device)
  42. *
  43. * Registers new active NVmem device for @nvm. The @reg_read is called
  44. * directly from NVMem so it must handle possible concurrent access if
  45. * needed. The first parameter passed to @reg_read is @nvm structure.
  46. * Returns %0 in success and negative errno otherwise.
  47. */
  48. int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read)
  49. {
  50. struct nvmem_config config;
  51. struct nvmem_device *nvmem;
  52. memset(&config, 0, sizeof(config));
  53. config.name = "nvm_active";
  54. config.reg_read = reg_read;
  55. config.read_only = true;
  56. config.id = nvm->id;
  57. config.stride = 4;
  58. config.word_size = 4;
  59. config.size = size;
  60. config.dev = nvm->dev;
  61. config.owner = THIS_MODULE;
  62. config.priv = nvm;
  63. nvmem = nvmem_register(&config);
  64. if (IS_ERR(nvmem))
  65. return PTR_ERR(nvmem);
  66. nvm->active = nvmem;
  67. return 0;
  68. }
  69. /**
  70. * tb_nvm_write_buf() - Write data to @nvm buffer
  71. * @nvm: NVM structure
  72. * @offset: Offset where to write the data
  73. * @val: Data buffer to write
  74. * @bytes: Number of bytes to write
  75. *
  76. * Helper function to cache the new NVM image before it is actually
  77. * written to the flash. Copies @bytes from @val to @nvm->buf starting
  78. * from @offset.
  79. */
  80. int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val,
  81. size_t bytes)
  82. {
  83. if (!nvm->buf) {
  84. nvm->buf = vmalloc(NVM_MAX_SIZE);
  85. if (!nvm->buf)
  86. return -ENOMEM;
  87. }
  88. nvm->flushed = false;
  89. nvm->buf_data_size = offset + bytes;
  90. memcpy(nvm->buf + offset, val, bytes);
  91. return 0;
  92. }
  93. /**
  94. * tb_nvm_add_non_active() - Adds non-active NVMem device to NVM
  95. * @nvm: NVM structure
  96. * @size: Size of the non-active NVM in bytes
  97. * @reg_write: Pointer to the function to write the NVM (passed directly
  98. * to the NVMem device)
  99. *
  100. * Registers new non-active NVmem device for @nvm. The @reg_write is called
  101. * directly from NVMem so it must handle possible concurrent access if
  102. * needed. The first parameter passed to @reg_write is @nvm structure.
  103. * Returns %0 in success and negative errno otherwise.
  104. */
  105. int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
  106. nvmem_reg_write_t reg_write)
  107. {
  108. struct nvmem_config config;
  109. struct nvmem_device *nvmem;
  110. memset(&config, 0, sizeof(config));
  111. config.name = "nvm_non_active";
  112. config.reg_write = reg_write;
  113. config.root_only = true;
  114. config.id = nvm->id;
  115. config.stride = 4;
  116. config.word_size = 4;
  117. config.size = size;
  118. config.dev = nvm->dev;
  119. config.owner = THIS_MODULE;
  120. config.priv = nvm;
  121. nvmem = nvmem_register(&config);
  122. if (IS_ERR(nvmem))
  123. return PTR_ERR(nvmem);
  124. nvm->non_active = nvmem;
  125. return 0;
  126. }
  127. /**
  128. * tb_nvm_free() - Release NVM and its resources
  129. * @nvm: NVM structure to release
  130. *
  131. * Releases NVM and the NVMem devices if they were registered.
  132. */
  133. void tb_nvm_free(struct tb_nvm *nvm)
  134. {
  135. if (nvm) {
  136. if (nvm->non_active)
  137. nvmem_unregister(nvm->non_active);
  138. if (nvm->active)
  139. nvmem_unregister(nvm->active);
  140. vfree(nvm->buf);
  141. ida_simple_remove(&nvm_ida, nvm->id);
  142. }
  143. kfree(nvm);
  144. }
  145. void tb_nvm_exit(void)
  146. {
  147. ida_destroy(&nvm_ida);
  148. }