iPXE
pcivpd.c File Reference

PCI Vital Product Data. More...

#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/isapnp.h>
#include <ipxe/pcivpd.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int pci_vpd_init (struct pci_vpd *vpd, struct pci_device *pci)
 Initialise PCI Vital Product Data.
static int pci_vpd_read_dword (struct pci_vpd *vpd, int address, uint32_t *data)
 Read one dword of PCI Vital Product Data.
static int pci_vpd_write_dword (struct pci_vpd *vpd, int address, uint32_t data)
 Write one dword of PCI Vital Product Data.
int pci_vpd_read (struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
 Read PCI VPD.
int pci_vpd_write (struct pci_vpd *vpd, unsigned int address, const void *buf, size_t len)
 Write PCI VPD.
static void pci_vpd_dump (struct pci_vpd *vpd, unsigned int address, size_t len)
 Dump PCI VPD region (for debugging)
static int pci_vpd_find_tag (struct pci_vpd *vpd, unsigned int tag, unsigned int *address, size_t *len)
 Locate PCI VPD tag.
int pci_vpd_find (struct pci_vpd *vpd, unsigned int field, unsigned int *address, size_t *len)
 Locate PCI VPD field.
int pci_vpd_resize (struct pci_vpd *vpd, unsigned int field, size_t len, unsigned int *address)
 Resize VPD field.

Detailed Description

PCI Vital Product Data.

Definition in file pcivpd.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ pci_vpd_init()

int pci_vpd_init ( struct pci_vpd * vpd,
struct pci_device * pci )

Initialise PCI Vital Product Data.

Parameters
vpdPCI VPD
pciPCI device
Return values
rcReturn status code

Definition at line 48 of file pcivpd.c.

48 {
49
50 /* Initialise structure */
51 vpd->pci = pci;
53
54 /* Locate VPD capability */
56 if ( ! vpd->cap ) {
57 DBGC ( vpd, PCI_FMT " does not support VPD\n",
58 PCI_ARGS ( pci ) );
59 return -ENOTTY;
60 }
61
62 DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n",
63 PCI_ARGS ( pci ), vpd->cap );
64 return 0;
65}
#define DBGC(...)
Definition compiler.h:505
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
#define PCI_FMT
PCI device debug message format.
Definition pci.h:312
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition pci.h:315
#define PCI_CAP_ID_VPD
Vital product data.
Definition pci.h:96
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition pciextra.c:39
static void pci_vpd_invalidate_cache(struct pci_vpd *vpd)
Invalidate PCI VPD read cache.
Definition pcivpd.h:167
int cap
VPD capability offset.
Definition pcivpd.h:134
struct pci_device * pci
PCI device.
Definition pcivpd.h:132

References pci_vpd::cap, DBGC, ENOTTY, pci_vpd::pci, PCI_ARGS, PCI_CAP_ID_VPD, pci_find_capability(), PCI_FMT, and pci_vpd_invalidate_cache().

Referenced by nvs_vpd_init().

◆ pci_vpd_read_dword()

int pci_vpd_read_dword ( struct pci_vpd * vpd,
int address,
uint32_t * data )
static

Read one dword of PCI Vital Product Data.

Parameters
vpdPCI VPD
addressAddress to read
Return values
dataRead data
rcReturn status code

Definition at line 75 of file pcivpd.c.

76 {
77 struct pci_device *pci = vpd->pci;
78 unsigned int cap = vpd->cap;
79 unsigned int retries;
81
82 /* Fail if no VPD present */
83 if ( ! cap )
84 return -ENOTTY;
85
86 /* Return cached value, if present */
87 if ( pci_vpd_cache_is_valid ( vpd ) &&
88 ( vpd->cache.address == address ) ) {
89 *data = vpd->cache.data;
90 return 0;
91 }
92
93 /* Initiate read */
95
96 /* Wait for read to complete */
97 for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
98
99 /* Check if data is ready */
100 pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
101 if ( flag & PCI_VPD_FLAG ) {
102
103 /* Read data */
104 pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ),
105 data );
106 DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n",
107 PCI_ARGS ( pci ), address, htonl ( *data ) );
108
109 /* Populate cache */
110 vpd->cache.address = address;
111 vpd->cache.data = *data;
112
113 return 0;
114 }
115
116 /* Wait 1ms before retrying */
117 mdelay ( 1 );
118 }
119
120 DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n",
121 PCI_ARGS ( pci ), address, cap );
122 return -ETIMEDOUT;
123}
uint32_t flag
Flag number.
Definition aqc1xx.h:2
unsigned short uint16_t
Definition stdint.h:11
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint64_t address
Base address.
Definition ena.h:13
#define DBGC2(...)
Definition compiler.h:522
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define htonl(value)
Definition byteswap.h:134
int pci_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
Read 32-bit dword from PCI configuration space.
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
#define PCI_VPD_MAX_WAIT_MS
Maximum wait for PCI VPD (in ms)
Definition pcivpd.h:119
#define PCI_VPD_DATA
PCI VPD data register.
Definition pcivpd.h:25
#define PCI_VPD_ADDRESS
PCI VPD address register.
Definition pcivpd.h:19
static int pci_vpd_cache_is_valid(struct pci_vpd *vpd)
Check if PCI VPD read cache is valid.
Definition pcivpd.h:157
#define PCI_VPD_FLAG
PCI VPD write flag.
Definition pcivpd.h:22
A PCI device.
Definition pci.h:211
int address
Address.
Definition pcivpd.h:124
uint32_t data
Data.
Definition pcivpd.h:126
struct pci_vpd_cache cache
Read cache.
Definition pcivpd.h:136
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79

References address, pci_vpd_cache::address, pci_vpd::cache, pci_vpd::cap, data, pci_vpd_cache::data, DBGC, DBGC2, ENOTTY, ETIMEDOUT, flag, htonl, mdelay(), pci_vpd::pci, PCI_ARGS, PCI_FMT, pci_read_config_dword(), pci_read_config_word(), PCI_VPD_ADDRESS, pci_vpd_cache_is_valid(), PCI_VPD_DATA, PCI_VPD_FLAG, PCI_VPD_MAX_WAIT_MS, and pci_write_config_word().

Referenced by pci_vpd_read(), and pci_vpd_write().

◆ pci_vpd_write_dword()

int pci_vpd_write_dword ( struct pci_vpd * vpd,
int address,
uint32_t data )
static

Write one dword of PCI Vital Product Data.

Parameters
vpdPCI VPD
addressAddress to write
dataData to write
Return values
rcReturn status code

Definition at line 133 of file pcivpd.c.

134 {
135 struct pci_device *pci = vpd->pci;
136 unsigned int cap = vpd->cap;
137 unsigned int retries;
139
140 /* Fail if no VPD present */
141 if ( ! cap )
142 return -ENOTTY;
143
144 /* Invalidate cache */
146
147 DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n",
148 PCI_ARGS ( pci ), address, htonl ( data ) );
149
150 /* Write data */
151 pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data );
152
153 /* Initiate write */
154 pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ),
155 ( address | PCI_VPD_FLAG ) );
156
157 /* Wait for write to complete */
158 for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
159
160 /* Check if write has completed */
161 pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
162 if ( ! ( flag & PCI_VPD_FLAG ) )
163 return 0;
164
165 /* Wait 1ms before retrying */
166 mdelay ( 1 );
167 }
168
169 DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n",
170 PCI_ARGS ( pci ), address, cap );
171 return -ETIMEDOUT;
172}
int pci_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
Write 32-bit dword to PCI configuration space.

References address, pci_vpd::cap, data, DBGC, DBGC2, ENOTTY, ETIMEDOUT, flag, htonl, mdelay(), pci_vpd::pci, PCI_ARGS, PCI_FMT, pci_read_config_word(), PCI_VPD_ADDRESS, PCI_VPD_DATA, PCI_VPD_FLAG, pci_vpd_invalidate_cache(), PCI_VPD_MAX_WAIT_MS, pci_write_config_dword(), and pci_write_config_word().

Referenced by pci_vpd_write().

◆ pci_vpd_read()

int pci_vpd_read ( struct pci_vpd * vpd,
unsigned int address,
void * buf,
size_t len )

Read PCI VPD.

Parameters
vpdPCI VPD
addressStarting address
bufData buffer
lenLength of data buffer
Return values
rcReturn status code

Definition at line 183 of file pcivpd.c.

184 {
185 uint8_t *bytes = buf;
187 size_t skip_len;
188 unsigned int i;
189 int rc;
190
191 /* Calculate length to skip at start of data */
192 skip_len = ( address & 0x03 );
193
194 /* Read data, a dword at a time */
195 for ( address &= ~0x03 ; len ; address += 4 ) {
196
197 /* Read whole dword */
198 if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 )
199 return rc;
200
201 /* Copy data to buffer */
202 for ( i = 4 ; i ; i-- ) {
203 if ( skip_len ) {
204 skip_len--;
205 } else if ( len ) {
206 *(bytes++) = data;
207 len--;
208 }
209 data = ( ( data << 24 ) | ( data >> 8 ) );
210 }
211 }
212
213 return 0;
214}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
ring len
Length.
Definition dwmac.h:226
uint8_t bytes[64]
Definition ib_mad.h:5
static int pci_vpd_read_dword(struct pci_vpd *vpd, int address, uint32_t *data)
Read one dword of PCI Vital Product Data.
Definition pcivpd.c:75

References address, bytes, data, len, pci_vpd_read_dword(), and rc.

Referenced by nvs_vpd_read(), pci_vpd_dump(), pci_vpd_find(), pci_vpd_find_tag(), and pci_vpd_resize().

◆ pci_vpd_write()

int pci_vpd_write ( struct pci_vpd * vpd,
unsigned int address,
const void * buf,
size_t len )

Write PCI VPD.

Parameters
vpdPCI VPD
addressStarting address
bufData buffer
lenLength of data buffer
Return values
rcReturn status code

Definition at line 225 of file pcivpd.c.

226 {
227 const uint8_t *bytes = buf;
229 size_t skip_len;
230 unsigned int i;
231 int rc;
232
233 /* Calculate length to skip at start of data */
234 skip_len = ( address & 0x03 );
235
236 /* Write data, a dword at a time */
237 for ( address &= ~0x03 ; len ; address += 4 ) {
238
239 /* Read existing dword, if necessary */
240 if ( skip_len || ( len <= 0x03 ) ) {
241 if ( ( rc = pci_vpd_read_dword ( vpd, address,
242 &data ) ) != 0 )
243 return rc;
244 }
245
246 /* Copy data from buffer */
247 for ( i = 4 ; i ; i-- ) {
248 if ( skip_len ) {
249 skip_len--;
250 } else if ( len ) {
251 data = ( ( data & ~0xff ) | *(bytes++) );
252 len--;
253 }
254 data = ( ( data << 24 ) | ( data >> 8 ) );
255 }
256
257 /* Write whole dword */
258 if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 )
259 return rc;
260 }
261 return 0;
262}
static int pci_vpd_write_dword(struct pci_vpd *vpd, int address, uint32_t data)
Write one dword of PCI Vital Product Data.
Definition pcivpd.c:133

References address, bytes, data, len, pci_vpd_read_dword(), pci_vpd_write_dword(), and rc.

Referenced by nvs_vpd_write(), and pci_vpd_resize().

◆ pci_vpd_dump()

void pci_vpd_dump ( struct pci_vpd * vpd,
unsigned int address,
size_t len )
static

Dump PCI VPD region (for debugging)

Parameters
vpdPCI VPD
addressStarting address
lenLength of data

Definition at line 271 of file pcivpd.c.

272 {
273 int rc;
274
275 /* Do nothing in non-debug builds */
276 if ( ! DBG_LOG )
277 return;
278
279 /* Read data */
280 {
281 char buf[len];
282 if ( ( rc = pci_vpd_read ( vpd, address, buf,
283 sizeof ( buf ) ) ) != 0 )
284 return;
285 DBGC_HDA ( vpd, address, buf, sizeof ( buf ) );
286 }
287}
#define DBG_LOG
Definition compiler.h:317
#define DBGC_HDA(...)
Definition compiler.h:506
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition pcivpd.c:183

References address, DBG_LOG, DBGC_HDA, len, pci_vpd_read(), and rc.

Referenced by pci_vpd_find(), and pci_vpd_resize().

◆ pci_vpd_find_tag()

int pci_vpd_find_tag ( struct pci_vpd * vpd,
unsigned int tag,
unsigned int * address,
size_t * len )
static

Locate PCI VPD tag.

Parameters
vpdPCI VPD
tagISAPnP tag
Return values
addressAddress of tag body
lenLength of tag body
rcReturn status code

Definition at line 298 of file pcivpd.c.

299 {
300 uint8_t read_tag;
301 uint16_t read_len;
302 int rc;
303
304 /* Scan through tags looking for a match */
305 *address = 0;
306 do {
307 /* Read tag byte */
308 if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag,
309 sizeof ( read_tag ) ) ) != 0 )
310 return rc;
311
312 /* Extract tag and length */
313 if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) {
314 if ( ( rc = pci_vpd_read ( vpd, *address, &read_len,
315 sizeof ( read_len ) ) ) != 0)
316 return rc;
317 *address += sizeof ( read_len );
318 read_len = le16_to_cpu ( read_len );
319 read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag );
320 } else {
321 read_len = ISAPNP_SMALL_TAG_LEN ( read_tag );
322 read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag );
323 }
324
325 /* Check for tag match */
326 if ( tag == read_tag ) {
327 *len = read_len;
328 DBGC ( vpd, PCI_FMT " VPD tag %02x is at "
329 "[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag,
330 *address, ( *address + *len ) );
331 return 0;
332 }
333
334 /* Move to next tag */
335 *address += read_len;
336
337 } while ( read_tag != ISAPNP_TAG_END );
338
339 DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n",
340 PCI_ARGS ( vpd->pci ), tag );
341 return -ENOENT;
342}
uint64_t tag
Identity tag.
Definition edd.h:1
#define ENOENT
No such file or directory.
Definition errno.h:515
#define le16_to_cpu(value)
Definition byteswap.h:113
#define ISAPNP_IS_LARGE_TAG(tag)
Definition isapnp.h:114
#define ISAPNP_SMALL_TAG_LEN(tag)
Definition isapnp.h:97
#define ISAPNP_SMALL_TAG_NAME(tag)
Definition isapnp.h:96
#define ISAPNP_TAG_END
Definition isapnp.h:112
#define ISAPNP_LARGE_TAG_NAME(tag)
Definition isapnp.h:115

References address, DBGC, ENOENT, ISAPNP_IS_LARGE_TAG, ISAPNP_LARGE_TAG_NAME, ISAPNP_SMALL_TAG_LEN, ISAPNP_SMALL_TAG_NAME, ISAPNP_TAG_END, le16_to_cpu, len, pci_vpd::pci, PCI_ARGS, PCI_FMT, pci_vpd_read(), rc, and tag.

Referenced by pci_vpd_find().

◆ pci_vpd_find()

int pci_vpd_find ( struct pci_vpd * vpd,
unsigned int field,
unsigned int * address,
size_t * len )

Locate PCI VPD field.

Parameters
vpdPCI VPD
fieldVPD field descriptor
Return values
addressAddress of field body
lenLength of field body
rcReturn status code

Definition at line 353 of file pcivpd.c.

354 {
355 struct pci_vpd_field read_field;
356 int rc;
357
358 /* Locate containing tag */
359 if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ),
360 address, len ) ) != 0 )
361 return rc;
362
363 /* Return immediately if we are searching for a whole-tag field */
364 if ( ! PCI_VPD_KEYWORD ( field ) ) {
365 pci_vpd_dump ( vpd, *address, *len );
366 return 0;
367 }
368
369 /* Scan through fields looking for a match */
370 while ( *len >= sizeof ( read_field ) ) {
371
372 /* Read field header */
373 if ( ( rc = pci_vpd_read ( vpd, *address, &read_field,
374 sizeof ( read_field ) ) ) != 0 )
375 return rc;
376 *address += sizeof ( read_field );
377 *len -= sizeof ( read_field );
378
379 /* Check for keyword match */
380 if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) {
381 *len = read_field.len;
382 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
383 " is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ),
384 PCI_VPD_FIELD_ARGS ( field ),
385 *address, ( *address + *len ) );
386 pci_vpd_dump ( vpd, *address, *len );
387 return 0;
388 }
389
390 /* Move to next field */
391 if ( read_field.len > *len )
392 break;
393 *address += read_field.len;
394 *len -= read_field.len;
395 }
396
397 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n",
398 PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
399 return -ENOENT;
400}
static void pci_vpd_dump(struct pci_vpd *vpd, unsigned int address, size_t len)
Dump PCI VPD region (for debugging)
Definition pcivpd.c:271
static int pci_vpd_find_tag(struct pci_vpd *vpd, unsigned int tag, unsigned int *address, size_t *len)
Locate PCI VPD tag.
Definition pcivpd.c:298
#define PCI_VPD_KEYWORD(field)
Extract PCI VPD keyword.
Definition pcivpd.h:67
#define PCI_VPD_FIELD_ARGS(field)
PCI VPD field debug message arguments.
Definition pcivpd.h:73
#define PCI_VPD_FIELD_FMT
PCI VPD field debug message format.
Definition pcivpd.h:70
#define PCI_VPD_TAG(field)
Extract PCI VPD ISAPnP tag.
Definition pcivpd.h:60
A PCI VPD field.
Definition pcivpd.h:28

References address, DBGC, ENOENT, pci_vpd_field::keyword, len, pci_vpd_field::len, pci_vpd::pci, PCI_ARGS, PCI_FMT, pci_vpd_dump(), PCI_VPD_FIELD_ARGS, PCI_VPD_FIELD_FMT, pci_vpd_find_tag(), PCI_VPD_KEYWORD, pci_vpd_read(), PCI_VPD_TAG, and rc.

Referenced by nvs_vpd_nvo_init(), nvs_vpd_read(), nvs_vpd_write(), and pci_vpd_resize().

◆ pci_vpd_resize()

int pci_vpd_resize ( struct pci_vpd * vpd,
unsigned int field,
size_t len,
unsigned int * address )

Resize VPD field.

Parameters
vpdPCI VPD
fieldVPD field descriptor
lenNew length of field body
Return values
addressAddress of field body
rcReturn status code

Definition at line 411 of file pcivpd.c.

412 {
413 struct pci_vpd_field rw_field;
414 struct pci_vpd_field old_field;
415 struct pci_vpd_field new_field;
416 unsigned int rw_address;
417 unsigned int old_address;
418 unsigned int copy_address;
419 unsigned int dst_address;
420 unsigned int dump_address;
421 size_t rw_len;
422 size_t old_len;
423 size_t available_len;
424 size_t copy_len;
425 size_t dump_len;
426 void *copy;
427 int rc;
428
429 /* Sanity checks */
430 assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW );
431 assert ( PCI_VPD_KEYWORD ( field ) != 0 );
432 assert ( field != PCI_VPD_FIELD_RW );
433
434 /* Locate 'RW' field */
435 if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address,
436 &rw_len ) ) != 0 )
437 goto err_no_rw;
438
439 /* Locate old field, if any */
440 if ( ( rc = pci_vpd_find ( vpd, field, &old_address,
441 &old_len ) ) == 0 ) {
442
443 /* Field already exists */
444 if ( old_address > rw_address ) {
445 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
446 " at [%04x,%04zx) is after field "
447 PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
448 PCI_ARGS ( vpd->pci ),
449 PCI_VPD_FIELD_ARGS ( field ),
450 old_address, ( old_address + old_len ),
452 rw_address, ( rw_address + rw_len ) );
453 rc = -ENXIO;
454 goto err_after_rw;
455 }
456 dst_address = ( old_address - sizeof ( old_field ) );
457 copy_address = ( old_address + old_len );
458 copy_len = ( rw_address - sizeof ( rw_field ) - copy_address );
459
460 /* Calculate available length */
461 available_len = ( rw_len + old_len );
462
463 } else {
464
465 /* Field does not yet exist */
466 dst_address = ( rw_address - sizeof ( rw_field ) );
467 copy_address = dst_address;
468 copy_len = 0;
469
470 /* Calculate available length */
471 available_len = ( ( rw_len > sizeof ( new_field ) ) ?
472 ( rw_len - sizeof ( new_field ) ) : 0 );
473 }
474
475 /* Dump region before changes */
476 dump_address = dst_address;
477 dump_len = ( rw_address + rw_len - dump_address );
478 DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT
479 " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
480 PCI_VPD_FIELD_ARGS ( field ), len );
481 pci_vpd_dump ( vpd, dump_address, dump_len );
482
483 /* Check available length */
484 if ( available_len > PCI_VPD_MAX_LEN )
485 available_len = PCI_VPD_MAX_LEN;
486 if ( len > available_len ) {
487 DBGC ( vpd, PCI_FMT " VPD no space for field "
488 PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n",
489 PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ),
490 len, available_len );
491 rc = -ENOSPC;
492 goto err_no_space;
493 }
494
495 /* Preserve intermediate fields, if any */
496 copy = malloc ( copy_len );
497 if ( ! copy ) {
498 rc = -ENOMEM;
499 goto err_copy_alloc;
500 }
501 if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 )
502 goto err_copy_read;
503
504 /* Create new field, if applicable */
505 if ( len ) {
506 new_field.keyword = PCI_VPD_KEYWORD ( field );
507 new_field.len = len;
508 if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field,
509 sizeof ( new_field ) ) ) != 0 )
510 goto err_new_write;
511 dst_address += sizeof ( new_field );
512 *address = dst_address;
513 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
514 "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
515 PCI_VPD_FIELD_ARGS ( field ), dst_address,
516 ( dst_address + new_field.len ) );
517 dst_address += len;
518 } else {
519 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
520 " no longer exists\n", PCI_ARGS ( vpd->pci ),
521 PCI_VPD_FIELD_ARGS ( field ) );
522 }
523
524 /* Restore intermediate fields, if any */
525 if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 )
526 goto err_copy_write;
527 dst_address += copy_len;
528
529 /* Create 'RW' field */
530 rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW );
531 rw_field.len = ( rw_len +
532 ( rw_address - sizeof ( rw_field ) ) - dst_address );
533 if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field,
534 sizeof ( rw_field ) ) ) != 0 )
535 goto err_rw_write;
536 dst_address += sizeof ( rw_field );
537 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
538 "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
539 PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address,
540 ( dst_address + rw_field.len ) );
541
542 /* Dump region after changes */
543 DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT
544 " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
545 PCI_VPD_FIELD_ARGS ( field ), len );
546 pci_vpd_dump ( vpd, dump_address, dump_len );
547
548 rc = 0;
549
550 err_rw_write:
551 err_new_write:
552 err_copy_write:
553 err_copy_read:
554 free ( copy );
555 err_copy_alloc:
556 err_no_space:
557 err_after_rw:
558 err_no_rw:
559 return rc;
560}
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define ENOSPC
No space left on device.
Definition errno.h:550
#define ENXIO
No such device or address.
Definition errno.h:600
#define ENOMEM
Not enough space.
Definition errno.h:535
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
int pci_vpd_write(struct pci_vpd *vpd, unsigned int address, const void *buf, size_t len)
Write PCI VPD.
Definition pcivpd.c:225
int pci_vpd_find(struct pci_vpd *vpd, unsigned int field, unsigned int *address, size_t *len)
Locate PCI VPD field.
Definition pcivpd.c:353
#define PCI_VPD_MAX_LEN
Maximum PCI VPD field length.
Definition pcivpd.h:36
#define PCI_VPD_FIELD_RW
PCI VPD Remaining Read/Write Area field descriptor.
Definition pcivpd.h:116
#define PCI_VPD_TAG_RW
PCI VPD Read-Write field tag.
Definition pcivpd.h:80
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55

References address, assert, DBGC, ENOMEM, ENOSPC, ENXIO, free, pci_vpd_field::keyword, len, pci_vpd_field::len, malloc(), pci_vpd::pci, PCI_ARGS, PCI_FMT, pci_vpd_dump(), PCI_VPD_FIELD_ARGS, PCI_VPD_FIELD_FMT, PCI_VPD_FIELD_RW, pci_vpd_find(), PCI_VPD_KEYWORD, PCI_VPD_MAX_LEN, pci_vpd_read(), PCI_VPD_TAG, PCI_VPD_TAG_RW, pci_vpd_write(), and rc.

Referenced by nvs_vpd_resize().