Browse Source

[pci] Auto-resize VPD fields used for non-volatile storage

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
7bf37147b3
3 changed files with 151 additions and 40 deletions
  1. 142
    32
      src/drivers/nvs/nvsvpd.c
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 8
    8
      src/include/ipxe/nvsvpd.h

+ 142
- 32
src/drivers/nvs/nvsvpd.c View File

19
 FILE_LICENCE ( GPL2_OR_LATER );
19
 FILE_LICENCE ( GPL2_OR_LATER );
20
 
20
 
21
 #include <stdio.h>
21
 #include <stdio.h>
22
+#include <errno.h>
22
 #include <ipxe/nvs.h>
23
 #include <ipxe/nvs.h>
23
 #include <ipxe/pci.h>
24
 #include <ipxe/pci.h>
24
 #include <ipxe/pcivpd.h>
25
 #include <ipxe/pcivpd.h>
26
+#include <ipxe/nvo.h>
25
 #include <ipxe/nvsvpd.h>
27
 #include <ipxe/nvsvpd.h>
26
 
28
 
27
 /** @file
29
 /** @file
31
  */
33
  */
32
 
34
 
33
 /**
35
 /**
34
- * Read from VPD
36
+ * Read from VPD field
35
  *
37
  *
36
  * @v nvs		NVS device
38
  * @v nvs		NVS device
37
- * @v address		Starting address
38
- * @v buf		Data buffer
39
+ * @v field		VPD field descriptor
40
+ * @v data		Data buffer
39
  * @v len		Length of data buffer
41
  * @v len		Length of data buffer
40
  * @ret rc		Return status code
42
  * @ret rc		Return status code
41
  */
43
  */
42
-static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int address,
44
+static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
43
 			  void *data, size_t len ) {
45
 			  void *data, size_t len ) {
44
 	struct nvs_vpd_device *nvsvpd =
46
 	struct nvs_vpd_device *nvsvpd =
45
 		container_of ( nvs, struct nvs_vpd_device, nvs );
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;
46
 	int rc;
51
 	int rc;
47
 
52
 
48
-	if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, ( nvsvpd->address + address ),
49
-				   data, len ) ) != 0 ) {
50
-		DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not read "
51
-		       "[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
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 ),
52
 		       address, ( address + len ), strerror ( rc ) );
80
 		       address, ( address + len ), strerror ( rc ) );
53
 		return rc;
81
 		return rc;
54
 	}
82
 	}
57
 }
85
 }
58
 
86
 
59
 /**
87
 /**
60
- * Write to VPD
88
+ * Write to VPD field
61
  *
89
  *
62
  * @v nvs		NVS device
90
  * @v nvs		NVS device
63
- * @v address		Starting address
64
- * @v buf		Data buffer
91
+ * @v field		VPD field descriptor
92
+ * @v data		Data buffer
65
  * @v len		Length of data buffer
93
  * @v len		Length of data buffer
66
  * @ret rc		Return status code
94
  * @ret rc		Return status code
67
  */
95
  */
68
-static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
96
+static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
69
 			   const void *data, size_t len ) {
97
 			   const void *data, size_t len ) {
70
 	struct nvs_vpd_device *nvsvpd =
98
 	struct nvs_vpd_device *nvsvpd =
71
 		container_of ( nvs, struct nvs_vpd_device, nvs );
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;
72
 	int rc;
103
 	int rc;
73
 
104
 
74
-	if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, ( nvsvpd->address + address ),
75
-				    data, len ) ) != 0 ) {
76
-		DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not write "
77
-		       "[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
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 ),
78
 		       address, ( address + len ), strerror ( rc ) );
129
 		       address, ( address + len ), strerror ( rc ) );
79
 		return rc;
130
 		return rc;
80
 	}
131
 	}
82
 	return 0;
133
 	return 0;
83
 }
134
 }
84
 
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
+
85
 /**
166
 /**
86
  * Initialise NVS VPD device
167
  * Initialise NVS VPD device
87
  *
168
  *
89
  * @v pci		PCI device
170
  * @v pci		PCI device
90
  * @ret rc		Return status code
171
  * @ret rc		Return status code
91
  */
172
  */
92
-int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
93
-		   unsigned int field ) {
94
-	size_t len;
173
+int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
95
 	int rc;
174
 	int rc;
96
 
175
 
97
 	/* Initialise VPD device */
176
 	/* Initialise VPD device */
101
 		return rc;
180
 		return rc;
102
 	}
181
 	}
103
 
182
 
104
-	/* Locate VPD field */
105
-	if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &nvsvpd->address,
106
-				   &len ) ) != 0 ) {
107
-		DBGC ( pci, PCI_FMT " NVS could not locate VPD field "
108
-		       PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
109
-		       PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
110
-		return rc;
111
-	}
112
-
113
 	/* Initialise NVS device */
183
 	/* Initialise NVS device */
114
-	nvsvpd->nvs.size = len;
115
 	nvsvpd->nvs.read = nvs_vpd_read;
184
 	nvsvpd->nvs.read = nvs_vpd_read;
116
 	nvsvpd->nvs.write = nvs_vpd_write;
185
 	nvsvpd->nvs.write = nvs_vpd_write;
117
 
186
 
118
-	DBGC ( pci, PCI_FMT " NVS using VPD field " PCI_VPD_FIELD_FMT " at "
119
-	       "[%04x,%04x)\n", PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
120
-	       nvsvpd->address, ( nvsvpd->address + nvsvpd->nvs.size ) );
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;
121
 
203
 
122
 	return 0;
204
 	return 0;
123
 }
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
+}

+ 1
- 0
src/include/ipxe/errfile.h View File

73
 #define ERRFILE_spi		     ( ERRFILE_DRIVER | 0x00110000 )
73
 #define ERRFILE_spi		     ( ERRFILE_DRIVER | 0x00110000 )
74
 #define ERRFILE_i2c_bit		     ( ERRFILE_DRIVER | 0x00120000 )
74
 #define ERRFILE_i2c_bit		     ( ERRFILE_DRIVER | 0x00120000 )
75
 #define ERRFILE_spi_bit		     ( ERRFILE_DRIVER | 0x00130000 )
75
 #define ERRFILE_spi_bit		     ( ERRFILE_DRIVER | 0x00130000 )
76
+#define ERRFILE_nvsvpd		     ( ERRFILE_DRIVER | 0x00140000 )
76
 
77
 
77
 #define ERRFILE_3c509		     ( ERRFILE_DRIVER | 0x00200000 )
78
 #define ERRFILE_3c509		     ( ERRFILE_DRIVER | 0x00200000 )
78
 #define ERRFILE_bnx2		     ( ERRFILE_DRIVER | 0x00210000 )
79
 #define ERRFILE_bnx2		     ( ERRFILE_DRIVER | 0x00210000 )

+ 8
- 8
src/include/ipxe/nvsvpd.h View File

13
 #include <ipxe/nvs.h>
13
 #include <ipxe/nvs.h>
14
 #include <ipxe/pcivpd.h>
14
 #include <ipxe/pcivpd.h>
15
 
15
 
16
+struct nvo_block;
17
+struct refcnt;
18
+
16
 /** An NVS VPD device */
19
 /** An NVS VPD device */
17
 struct nvs_vpd_device {
20
 struct nvs_vpd_device {
18
 	/** NVS device */
21
 	/** NVS device */
19
 	struct nvs_device nvs;
22
 	struct nvs_device nvs;
20
 	/** PCI VPD device */
23
 	/** PCI VPD device */
21
 	struct pci_vpd vpd;
24
 	struct pci_vpd vpd;
22
-	/** Starting address
23
-	 *
24
-	 * This address is added to the NVS address to form the VPD
25
-	 * address.
26
-	 */
27
-	unsigned int address;
28
 };
25
 };
29
 
26
 
30
-extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
31
-			  unsigned int field );
27
+extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd,
28
+			  struct pci_device *pci );
29
+extern void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd,
30
+			       unsigned int field, struct nvo_block *nvo,
31
+			       struct refcnt *refcnt );
32
 
32
 
33
 #endif /* IPXE_NVSVPD_H */
33
 #endif /* IPXE_NVSVPD_H */

Loading…
Cancel
Save