|
|
1.1 root 1: /*
2: * Copyright (C) 2010 Michael Brown <[email protected]>.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: FILE_LICENCE ( GPL2_OR_LATER );
20:
21: #include <stdio.h>
22: #include <errno.h>
23: #include <ipxe/nvs.h>
24: #include <ipxe/pci.h>
25: #include <ipxe/pcivpd.h>
26: #include <ipxe/nvo.h>
27: #include <ipxe/nvsvpd.h>
28:
29: /** @file
30: *
31: * Non-Volatile Storage using Vital Product Data
32: *
33: */
34:
35: /**
36: * Read from VPD field
37: *
38: * @v nvs NVS device
39: * @v field VPD field descriptor
40: * @v data Data buffer
41: * @v len Length of data buffer
42: * @ret rc Return status code
43: */
44: static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
45: void *data, size_t len ) {
46: struct nvs_vpd_device *nvsvpd =
47: container_of ( nvs, struct nvs_vpd_device, nvs );
48: struct pci_device *pci = nvsvpd->vpd.pci;
49: unsigned int address;
50: size_t max_len;
51: int rc;
52:
53: /* Allow reading non-existent field */
54: if ( len == 0 )
55: return 0;
56:
57: /* Locate VPD field */
58: if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
59: &max_len ) ) != 0 ) {
60: DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
61: PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
62: PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
63: return rc;
64: }
65:
66: /* Sanity check */
67: if ( len > max_len ) {
68: DBGC ( pci, PCI_FMT " NVS VPD cannot read %#02zx bytes "
69: "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
70: PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
71: address, ( address + max_len ) );
72: return -ENXIO;
73: }
74:
75: /* Read from VPD field */
76: if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, address, data, len ) ) != 0 ) {
77: DBGC ( pci, PCI_FMT " NVS VPD could not read field "
78: PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
79: PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
80: address, ( address + len ), strerror ( rc ) );
81: return rc;
82: }
83:
84: return 0;
85: }
86:
87: /**
88: * Write to VPD field
89: *
90: * @v nvs NVS device
91: * @v field VPD field descriptor
92: * @v data Data buffer
93: * @v len Length of data buffer
94: * @ret rc Return status code
95: */
96: static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
97: const void *data, size_t len ) {
98: struct nvs_vpd_device *nvsvpd =
99: container_of ( nvs, struct nvs_vpd_device, nvs );
100: struct pci_device *pci = nvsvpd->vpd.pci;
101: unsigned int address;
102: size_t max_len;
103: int rc;
104:
105: /* Locate VPD field */
106: if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
107: &max_len ) ) != 0 ) {
108: DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
109: PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
110: PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
111: return rc;
112: }
113:
114: /* Sanity check */
115: if ( len > max_len ) {
116: DBGC ( pci, PCI_FMT " NVS VPD cannot write %#02zx bytes "
117: "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
118: PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
119: address, ( address + max_len ) );
120: return -ENXIO;
121: }
122:
123: /* Write field */
124: if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, address, data,
125: len ) ) != 0 ) {
126: DBGC ( pci, PCI_FMT " NVS VPD could not write field "
127: PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
128: PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
129: address, ( address + len ), strerror ( rc ) );
130: return rc;
131: }
132:
133: return 0;
134: }
135:
136: /**
137: * Resize VPD field
138: *
139: * @v nvs NVS device
140: * @v field VPD field descriptor
141: * @v data Data buffer
142: * @v len Length of data buffer
143: * @ret rc Return status code
144: */
145: static int nvs_vpd_resize ( struct nvs_device *nvs, unsigned int field,
146: size_t len ) {
147: struct nvs_vpd_device *nvsvpd =
148: container_of ( nvs, struct nvs_vpd_device, nvs );
149: struct pci_device *pci = nvsvpd->vpd.pci;
150: unsigned int address;
151: int rc;
152:
153: /* Resize field */
154: if ( ( rc = pci_vpd_resize ( &nvsvpd->vpd, field, len,
155: &address ) ) != 0 ) {
156: DBGC ( pci, PCI_FMT " NVS VPD could not resize field "
157: PCI_VPD_FIELD_FMT " to %#02zx bytes: %s\n",
158: PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
159: len, strerror ( rc ) );
160: return rc;
161: }
162:
163: return 0;
164: }
165:
166: /**
167: * Initialise NVS VPD device
168: *
169: * @v nvsvpd NVS VPD device
170: * @v pci PCI device
171: * @ret rc Return status code
172: */
173: int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
174: int rc;
175:
176: /* Initialise VPD device */
177: if ( ( rc = pci_vpd_init ( &nvsvpd->vpd, pci ) ) != 0 ) {
178: DBGC ( pci, PCI_FMT " NVS could not initialise "
179: "VPD: %s\n", PCI_ARGS ( pci ), strerror ( rc ) );
180: return rc;
181: }
182:
183: /* Initialise NVS device */
184: nvsvpd->nvs.read = nvs_vpd_read;
185: nvsvpd->nvs.write = nvs_vpd_write;
186:
187: return 0;
188: }
189:
190: /**
191: * Resize non-volatile option storage within NVS VPD device
192: *
193: * @v nvo Non-volatile options block
194: * @v len New length
195: * @ret rc Return status code
196: */
197: static int nvs_vpd_nvo_resize ( struct nvo_block *nvo, size_t len ) {
198: int rc;
199:
200: /* Resize VPD field */
201: if ( ( rc = nvs_vpd_resize ( nvo->nvs, nvo->address, len ) ) != 0 )
202: return rc;
203:
204: return 0;
205: }
206:
207: /**
208: * Initialise non-volatile option storage within NVS VPD device
209: *
210: * @v nvsvpd NVS VPD device
211: * @v field VPD field descriptor
212: * @v nvo Non-volatile options block
213: * @v refcnt Containing object reference counter, or NULL
214: */
215: void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd, unsigned int field,
216: struct nvo_block *nvo, struct refcnt *refcnt ) {
217: struct pci_device *pci = nvsvpd->vpd.pci;
218: unsigned int address;
219: size_t len;
220: int rc;
221:
222: /* Locate VPD field, if present */
223: if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
224: &len ) ) != 0 ) {
225: DBGC ( pci, PCI_FMT " NVS VPD field " PCI_VPD_FIELD_FMT
226: " not present; assuming empty\n",
227: PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ) );
228: len = 0;
229: }
230:
231: /* Initialise non-volatile options block */
232: nvo_init ( nvo, &nvsvpd->nvs, field, len, nvs_vpd_nvo_resize, refcnt );
233: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.