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 14 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,9 +19,11 @@
19 19
 FILE_LICENCE ( GPL2_OR_LATER );
20 20
 
21 21
 #include <stdio.h>
22
+#include <errno.h>
22 23
 #include <ipxe/nvs.h>
23 24
 #include <ipxe/pci.h>
24 25
 #include <ipxe/pcivpd.h>
26
+#include <ipxe/nvo.h>
25 27
 #include <ipxe/nvsvpd.h>
26 28
 
27 29
 /** @file
@@ -31,24 +33,50 @@ FILE_LICENCE ( GPL2_OR_LATER );
31 33
  */
32 34
 
33 35
 /**
34
- * Read from VPD
36
+ * Read from VPD field
35 37
  *
36 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 41
  * @v len		Length of data buffer
40 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 45
 			  void *data, size_t len ) {
44 46
 	struct nvs_vpd_device *nvsvpd =
45 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 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 80
 		       address, ( address + len ), strerror ( rc ) );
53 81
 		return rc;
54 82
 	}
@@ -57,24 +85,47 @@ static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int address,
57 85
 }
58 86
 
59 87
 /**
60
- * Write to VPD
88
+ * Write to VPD field
61 89
  *
62 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 93
  * @v len		Length of data buffer
66 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 97
 			   const void *data, size_t len ) {
70 98
 	struct nvs_vpd_device *nvsvpd =
71 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 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 129
 		       address, ( address + len ), strerror ( rc ) );
79 130
 		return rc;
80 131
 	}
@@ -82,6 +133,36 @@ static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
82 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 167
  * Initialise NVS VPD device
87 168
  *
@@ -89,9 +170,7 @@ static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
89 170
  * @v pci		PCI device
90 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 174
 	int rc;
96 175
 
97 176
 	/* Initialise VPD device */
@@ -101,23 +180,54 @@ int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
101 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 183
 	/* Initialise NVS device */
114
-	nvsvpd->nvs.size = len;
115 184
 	nvsvpd->nvs.read = nvs_vpd_read;
116 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 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,6 +73,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
73 73
 #define ERRFILE_spi		     ( ERRFILE_DRIVER | 0x00110000 )
74 74
 #define ERRFILE_i2c_bit		     ( ERRFILE_DRIVER | 0x00120000 )
75 75
 #define ERRFILE_spi_bit		     ( ERRFILE_DRIVER | 0x00130000 )
76
+#define ERRFILE_nvsvpd		     ( ERRFILE_DRIVER | 0x00140000 )
76 77
 
77 78
 #define ERRFILE_3c509		     ( ERRFILE_DRIVER | 0x00200000 )
78 79
 #define ERRFILE_bnx2		     ( ERRFILE_DRIVER | 0x00210000 )

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

@@ -13,21 +13,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
13 13
 #include <ipxe/nvs.h>
14 14
 #include <ipxe/pcivpd.h>
15 15
 
16
+struct nvo_block;
17
+struct refcnt;
18
+
16 19
 /** An NVS VPD device */
17 20
 struct nvs_vpd_device {
18 21
 	/** NVS device */
19 22
 	struct nvs_device nvs;
20 23
 	/** PCI VPD device */
21 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 33
 #endif /* IPXE_NVSVPD_H */

Loading…
Cancel
Save