You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nvsvpd.c 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdio.h>
  25. #include <errno.h>
  26. #include <ipxe/nvs.h>
  27. #include <ipxe/pci.h>
  28. #include <ipxe/pcivpd.h>
  29. #include <ipxe/nvo.h>
  30. #include <ipxe/nvsvpd.h>
  31. /** @file
  32. *
  33. * Non-Volatile Storage using Vital Product Data
  34. *
  35. */
  36. /**
  37. * Read from VPD field
  38. *
  39. * @v nvs NVS device
  40. * @v field VPD field descriptor
  41. * @v data Data buffer
  42. * @v len Length of data buffer
  43. * @ret rc Return status code
  44. */
  45. static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
  46. void *data, size_t len ) {
  47. struct nvs_vpd_device *nvsvpd =
  48. container_of ( nvs, struct nvs_vpd_device, nvs );
  49. struct pci_device *pci = nvsvpd->vpd.pci;
  50. unsigned int address;
  51. size_t max_len;
  52. int rc;
  53. /* Allow reading non-existent field */
  54. if ( len == 0 )
  55. return 0;
  56. /* Locate VPD field */
  57. if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
  58. &max_len ) ) != 0 ) {
  59. DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
  60. PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
  61. PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
  62. return rc;
  63. }
  64. /* Sanity check */
  65. if ( len > max_len ) {
  66. DBGC ( pci, PCI_FMT " NVS VPD cannot read %#02zx bytes "
  67. "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
  68. PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
  69. address, ( address + max_len ) );
  70. return -ENXIO;
  71. }
  72. /* Read from VPD field */
  73. if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, address, data, len ) ) != 0 ) {
  74. DBGC ( pci, PCI_FMT " NVS VPD could not read field "
  75. PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
  76. PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
  77. address, ( address + len ), strerror ( rc ) );
  78. return rc;
  79. }
  80. return 0;
  81. }
  82. /**
  83. * Write to VPD field
  84. *
  85. * @v nvs NVS device
  86. * @v field VPD field descriptor
  87. * @v data Data buffer
  88. * @v len Length of data buffer
  89. * @ret rc Return status code
  90. */
  91. static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
  92. const void *data, size_t len ) {
  93. struct nvs_vpd_device *nvsvpd =
  94. container_of ( nvs, struct nvs_vpd_device, nvs );
  95. struct pci_device *pci = nvsvpd->vpd.pci;
  96. unsigned int address;
  97. size_t max_len;
  98. int rc;
  99. /* Locate VPD field */
  100. if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
  101. &max_len ) ) != 0 ) {
  102. DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
  103. PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
  104. PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
  105. return rc;
  106. }
  107. /* Sanity check */
  108. if ( len > max_len ) {
  109. DBGC ( pci, PCI_FMT " NVS VPD cannot write %#02zx bytes "
  110. "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
  111. PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
  112. address, ( address + max_len ) );
  113. return -ENXIO;
  114. }
  115. /* Write field */
  116. if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, address, data,
  117. len ) ) != 0 ) {
  118. DBGC ( pci, PCI_FMT " NVS VPD could not write field "
  119. PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
  120. PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
  121. address, ( address + len ), strerror ( rc ) );
  122. return rc;
  123. }
  124. return 0;
  125. }
  126. /**
  127. * Resize VPD field
  128. *
  129. * @v nvs NVS device
  130. * @v field VPD field descriptor
  131. * @v data Data buffer
  132. * @v len Length of data buffer
  133. * @ret rc Return status code
  134. */
  135. static int nvs_vpd_resize ( struct nvs_device *nvs, unsigned int field,
  136. size_t len ) {
  137. struct nvs_vpd_device *nvsvpd =
  138. container_of ( nvs, struct nvs_vpd_device, nvs );
  139. struct pci_device *pci = nvsvpd->vpd.pci;
  140. unsigned int address;
  141. int rc;
  142. /* Resize field */
  143. if ( ( rc = pci_vpd_resize ( &nvsvpd->vpd, field, len,
  144. &address ) ) != 0 ) {
  145. DBGC ( pci, PCI_FMT " NVS VPD could not resize field "
  146. PCI_VPD_FIELD_FMT " to %#02zx bytes: %s\n",
  147. PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
  148. len, strerror ( rc ) );
  149. return rc;
  150. }
  151. return 0;
  152. }
  153. /**
  154. * Initialise NVS VPD device
  155. *
  156. * @v nvsvpd NVS VPD device
  157. * @v pci PCI device
  158. * @ret rc Return status code
  159. */
  160. int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
  161. int rc;
  162. /* Initialise VPD device */
  163. if ( ( rc = pci_vpd_init ( &nvsvpd->vpd, pci ) ) != 0 ) {
  164. DBGC ( pci, PCI_FMT " NVS could not initialise "
  165. "VPD: %s\n", PCI_ARGS ( pci ), strerror ( rc ) );
  166. return rc;
  167. }
  168. /* Initialise NVS device */
  169. nvsvpd->nvs.read = nvs_vpd_read;
  170. nvsvpd->nvs.write = nvs_vpd_write;
  171. return 0;
  172. }
  173. /**
  174. * Resize non-volatile option storage within NVS VPD device
  175. *
  176. * @v nvo Non-volatile options block
  177. * @v len New length
  178. * @ret rc Return status code
  179. */
  180. static int nvs_vpd_nvo_resize ( struct nvo_block *nvo, size_t len ) {
  181. int rc;
  182. /* Resize VPD field */
  183. if ( ( rc = nvs_vpd_resize ( nvo->nvs, nvo->address, len ) ) != 0 )
  184. return rc;
  185. return 0;
  186. }
  187. /**
  188. * Initialise non-volatile option storage within NVS VPD device
  189. *
  190. * @v nvsvpd NVS VPD device
  191. * @v field VPD field descriptor
  192. * @v nvo Non-volatile options block
  193. * @v refcnt Containing object reference counter, or NULL
  194. */
  195. void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd, unsigned int field,
  196. struct nvo_block *nvo, struct refcnt *refcnt ) {
  197. struct pci_device *pci = nvsvpd->vpd.pci;
  198. unsigned int address;
  199. size_t len;
  200. int rc;
  201. /* Locate VPD field, if present */
  202. if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
  203. &len ) ) != 0 ) {
  204. DBGC ( pci, PCI_FMT " NVS VPD field " PCI_VPD_FIELD_FMT
  205. " not present; assuming empty\n",
  206. PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ) );
  207. len = 0;
  208. }
  209. /* Initialise non-volatile options block */
  210. nvo_init ( nvo, &nvsvpd->nvs, field, len, nvs_vpd_nvo_resize, refcnt );
  211. }