iPXE
pcivpd.h File Reference

PCI Vital Product Data. More...

#include <stdint.h>
#include <byteswap.h>
#include <ipxe/isapnp.h>
#include <ipxe/pci.h>

Go to the source code of this file.

Data Structures

struct  pci_vpd_field
 A PCI VPD field. More...
struct  pci_vpd_cache
 PCI VPD cache. More...
struct  pci_vpd
 PCI VPD. More...

Macros

#define PCI_VPD_ADDRESS   0x02
 PCI VPD address register.
#define PCI_VPD_FLAG   0x8000
 PCI VPD write flag.
#define PCI_VPD_DATA   0x04
 PCI VPD data register.
#define PCI_VPD_MAX_LEN   0xff
 Maximum PCI VPD field length.
#define PCI_VPD_FIELD(tag, keyword1, keyword2)
 Construct PCI VPD field descriptor.
#define PCI_VPD_WHOLE_TAG_FIELD(tag)
 Construct PCI VPD whole-tag field descriptor.
#define PCI_VPD_TAG(field)
 Extract PCI VPD ISAPnP tag.
#define PCI_VPD_KEYWORD(field)
 Extract PCI VPD keyword.
#define PCI_VPD_FIELD_FMT   "%c%c"
 PCI VPD field debug message format.
#define PCI_VPD_FIELD_ARGS(field)
 PCI VPD field debug message arguments.
#define PCI_VPD_TAG_RO   0x90
 PCI VPD Read-Only field tag.
#define PCI_VPD_TAG_RW   0x91
 PCI VPD Read-Write field tag.
#define PCI_VPD_FIELD_NAME   PCI_VPD_WHOLE_TAG_FIELD ( ISAPNP_TAG_ANSISTR )
 PCI VPD Card Name field descriptor.
#define PCI_VPD_FIELD_PN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'N' )
 PCI VPD Part Number field descriptor.
#define PCI_VPD_FIELD_EC   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'E', 'C' )
 PCI VPD Engineering Change Level field descriptor.
#define PCI_VPD_FIELD_FG   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'F', 'G' )
 PCI VPD Fabric Geography field descriptor.
#define PCI_VPD_FIELD_LC   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'L', 'C' )
 PCI VPD Location field descriptor.
#define PCI_VPD_FIELD_MN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'M', 'N' )
 PCI VPD Manufacturer ID field descriptor.
#define PCI_VPD_FIELD_PG   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'G' )
 PCI VPD PCI Geography field descriptor.
#define PCI_VPD_FIELD_SN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'S', 'N' )
 PCI VPD Serial Number field descriptor.
#define PCI_VPD_FIELD_CP   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'C', 'P' )
 PCI VPD Extended Capability field descriptor.
#define PCI_VPD_FIELD_RV   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'R', 'V' )
 PCI VPD Checksum and Reserved field descriptor.
#define PCI_VPD_FIELD_YA   PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'Y', 'A' )
 PCI VPD Asset Tag field descriptor.
#define PCI_VPD_FIELD_RW   PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'R', 'W' )
 PCI VPD Remaining Read/Write Area field descriptor.
#define PCI_VPD_MAX_WAIT_MS   100
 Maximum wait for PCI VPD (in ms)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int pci_vpd_is_present (struct pci_vpd *vpd)
 Check for presence of PCI VPD.
static int pci_vpd_cache_is_valid (struct pci_vpd *vpd)
 Check if PCI VPD read cache is valid.
static void pci_vpd_invalidate_cache (struct pci_vpd *vpd)
 Invalidate PCI VPD read cache.
int pci_vpd_init (struct pci_vpd *vpd, struct pci_device *pci)
 Initialise 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.
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.h.

Macro Definition Documentation

◆ PCI_VPD_ADDRESS

#define PCI_VPD_ADDRESS   0x02

PCI VPD address register.

Definition at line 19 of file pcivpd.h.

Referenced by pci_vpd_read_dword(), and pci_vpd_write_dword().

◆ PCI_VPD_FLAG

#define PCI_VPD_FLAG   0x8000

PCI VPD write flag.

Definition at line 22 of file pcivpd.h.

Referenced by pci_vpd_read_dword(), and pci_vpd_write_dword().

◆ PCI_VPD_DATA

#define PCI_VPD_DATA   0x04

PCI VPD data register.

Definition at line 25 of file pcivpd.h.

Referenced by pci_vpd_read_dword(), and pci_vpd_write_dword().

◆ PCI_VPD_MAX_LEN

#define PCI_VPD_MAX_LEN   0xff

Maximum PCI VPD field length.

Definition at line 36 of file pcivpd.h.

Referenced by pci_vpd_resize().

◆ PCI_VPD_FIELD

#define PCI_VPD_FIELD ( tag,
keyword1,
keyword2 )
Value:
( ( (tag) << 16 ) | ( (keyword2) << 8 ) | ( (keyword1) << 0 ) )
uint64_t tag
Identity tag.
Definition edd.h:1

Construct PCI VPD field descriptor.

Parameters
tagISAPnP tag
keyword1First character of keyword
keyword2Second character of keyword
Return values
fieldVPD field descriptor

Definition at line 45 of file pcivpd.h.

45#define PCI_VPD_FIELD( tag, keyword1, keyword2 ) \
46 ( ( (tag) << 16 ) | ( (keyword2) << 8 ) | ( (keyword1) << 0 ) )

◆ PCI_VPD_WHOLE_TAG_FIELD

#define PCI_VPD_WHOLE_TAG_FIELD ( tag)
Value:
PCI_VPD_FIELD ( (tag), '\0', '\0' )
#define PCI_VPD_FIELD(tag, keyword1, keyword2)
Construct PCI VPD field descriptor.
Definition pcivpd.h:45

Construct PCI VPD whole-tag field descriptor.

Parameters
tagISAPnP tag
Return values
fieldVPD field descriptor

Definition at line 53 of file pcivpd.h.

◆ PCI_VPD_TAG

#define PCI_VPD_TAG ( field)
Value:
( (field) >> 16 )

Extract PCI VPD ISAPnP tag.

Parameters
fieldVPD field descriptor
Return values
tagISAPnP tag

Definition at line 60 of file pcivpd.h.

Referenced by pci_vpd_find(), and pci_vpd_resize().

◆ PCI_VPD_KEYWORD

#define PCI_VPD_KEYWORD ( field)
Value:
( cpu_to_le16 ( (field) & 0xffff ) )
#define cpu_to_le16(value)
Definition byteswap.h:107

Extract PCI VPD keyword.

Parameters
fieldVPD field descriptor
Return values
keywordKeyword

Definition at line 67 of file pcivpd.h.

Referenced by pci_vpd_find(), and pci_vpd_resize().

◆ PCI_VPD_FIELD_FMT

#define PCI_VPD_FIELD_FMT   "%c%c"

PCI VPD field debug message format.

Definition at line 70 of file pcivpd.h.

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

◆ PCI_VPD_FIELD_ARGS

#define PCI_VPD_FIELD_ARGS ( field)
Value:
( (field) >> 0 ), ( (field) >> 8 )

PCI VPD field debug message arguments.

Definition at line 73 of file pcivpd.h.

73#define PCI_VPD_FIELD_ARGS( field ) \
74 ( (field) >> 0 ), ( (field) >> 8 )

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

◆ PCI_VPD_TAG_RO

#define PCI_VPD_TAG_RO   0x90

PCI VPD Read-Only field tag.

Definition at line 77 of file pcivpd.h.

◆ PCI_VPD_TAG_RW

#define PCI_VPD_TAG_RW   0x91

PCI VPD Read-Write field tag.

Definition at line 80 of file pcivpd.h.

Referenced by pci_vpd_resize().

◆ PCI_VPD_FIELD_NAME

#define PCI_VPD_FIELD_NAME   PCI_VPD_WHOLE_TAG_FIELD ( ISAPNP_TAG_ANSISTR )

PCI VPD Card Name field descriptor.

Definition at line 83 of file pcivpd.h.

◆ PCI_VPD_FIELD_PN

#define PCI_VPD_FIELD_PN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'N' )

PCI VPD Part Number field descriptor.

Definition at line 86 of file pcivpd.h.

◆ PCI_VPD_FIELD_EC

#define PCI_VPD_FIELD_EC   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'E', 'C' )

PCI VPD Engineering Change Level field descriptor.

Definition at line 89 of file pcivpd.h.

◆ PCI_VPD_FIELD_FG

#define PCI_VPD_FIELD_FG   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'F', 'G' )

PCI VPD Fabric Geography field descriptor.

Definition at line 92 of file pcivpd.h.

◆ PCI_VPD_FIELD_LC

#define PCI_VPD_FIELD_LC   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'L', 'C' )

PCI VPD Location field descriptor.

Definition at line 95 of file pcivpd.h.

◆ PCI_VPD_FIELD_MN

#define PCI_VPD_FIELD_MN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'M', 'N' )

PCI VPD Manufacturer ID field descriptor.

Definition at line 98 of file pcivpd.h.

◆ PCI_VPD_FIELD_PG

#define PCI_VPD_FIELD_PG   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'P', 'G' )

PCI VPD PCI Geography field descriptor.

Definition at line 101 of file pcivpd.h.

◆ PCI_VPD_FIELD_SN

#define PCI_VPD_FIELD_SN   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'S', 'N' )

PCI VPD Serial Number field descriptor.

Definition at line 104 of file pcivpd.h.

◆ PCI_VPD_FIELD_CP

#define PCI_VPD_FIELD_CP   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'C', 'P' )

PCI VPD Extended Capability field descriptor.

Definition at line 107 of file pcivpd.h.

◆ PCI_VPD_FIELD_RV

#define PCI_VPD_FIELD_RV   PCI_VPD_FIELD ( PCI_VPD_TAG_RO, 'R', 'V' )

PCI VPD Checksum and Reserved field descriptor.

Definition at line 110 of file pcivpd.h.

◆ PCI_VPD_FIELD_YA

#define PCI_VPD_FIELD_YA   PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'Y', 'A' )

PCI VPD Asset Tag field descriptor.

Definition at line 113 of file pcivpd.h.

◆ PCI_VPD_FIELD_RW

#define PCI_VPD_FIELD_RW   PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'R', 'W' )

PCI VPD Remaining Read/Write Area field descriptor.

Definition at line 116 of file pcivpd.h.

Referenced by pci_vpd_resize().

◆ PCI_VPD_MAX_WAIT_MS

#define PCI_VPD_MAX_WAIT_MS   100

Maximum wait for PCI VPD (in ms)

Definition at line 119 of file pcivpd.h.

Referenced by pci_vpd_read_dword(), and pci_vpd_write_dword().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ pci_vpd_is_present()

int pci_vpd_is_present ( struct pci_vpd * vpd)
inlinestatic

Check for presence of PCI VPD.

Parameters
vpdPCI VPD
Return values
is_presentVPD is present

Definition at line 146 of file pcivpd.h.

146 {
147 return ( vpd->cap != 0 );
148}
int cap
VPD capability offset.
Definition pcivpd.h:134

References pci_vpd::cap.

◆ pci_vpd_cache_is_valid()

int pci_vpd_cache_is_valid ( struct pci_vpd * vpd)
inlinestatic

Check if PCI VPD read cache is valid.

Parameters
vpdPCI VPD
Return values
is_validRead cache is valid

Definition at line 157 of file pcivpd.h.

157 {
158 return ( vpd->cache.address >= 0 );
159}
int address
Address.
Definition pcivpd.h:124
struct pci_vpd_cache cache
Read cache.
Definition pcivpd.h:136

References pci_vpd_cache::address, and pci_vpd::cache.

Referenced by pci_vpd_read_dword().

◆ pci_vpd_invalidate_cache()

void pci_vpd_invalidate_cache ( struct pci_vpd * vpd)
inlinestatic

Invalidate PCI VPD read cache.

Parameters
vpdPCI VPD

Definition at line 167 of file pcivpd.h.

167 {
168 vpd->cache.address = -1;
169}

References pci_vpd_cache::address, and pci_vpd::cache.

Referenced by pci_vpd_init(), and pci_vpd_write_dword().

◆ pci_vpd_init()

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

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
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()

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

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 data[48]
Additional event data.
Definition ena.h:11
uint64_t address
Base address.
Definition ena.h:13
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 )
extern

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_find()

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

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}
#define ENOENT
No such file or directory.
Definition errno.h:515
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition pcivpd.c:183
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 )
extern

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().