iPXE
Functions
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. More...
 
static int pci_vpd_read_dword (struct pci_vpd *vpd, int address, uint32_t *data)
 Read one dword of PCI Vital Product Data. More...
 
static int pci_vpd_write_dword (struct pci_vpd *vpd, int address, uint32_t data)
 Write one dword of PCI Vital Product Data. More...
 
int pci_vpd_read (struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
 Read PCI VPD. More...
 
int pci_vpd_write (struct pci_vpd *vpd, unsigned int address, const void *buf, size_t len)
 Write PCI VPD. More...
 
static void pci_vpd_dump (struct pci_vpd *vpd, unsigned int address, size_t len)
 Dump PCI VPD region (for debugging) More...
 
static int pci_vpd_find_tag (struct pci_vpd *vpd, unsigned int tag, unsigned int *address, size_t *len)
 Locate PCI VPD tag. More...
 
int pci_vpd_find (struct pci_vpd *vpd, unsigned int field, unsigned int *address, size_t *len)
 Locate PCI VPD field. More...
 
int pci_vpd_resize (struct pci_vpd *vpd, unsigned int field, size_t len, unsigned int *address)
 Resize VPD field. More...
 

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 */
55  vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD );
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 }
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition: pciextra.c:38
#define DBGC(...)
Definition: compiler.h:505
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
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:594
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
#define PCI_CAP_ID_VPD
Vital product data.
Definition: pci.h:95

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

static 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;
80  uint16_t flag;
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 */
94  pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address );
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 }
#define PCI_VPD_MAX_WAIT_MS
Maximum wait for PCI VPD (in ms)
Definition: pcivpd.h:119
unsigned short uint16_t
Definition: stdint.h:11
#define PCI_VPD_FLAG
PCI VPD write flag.
Definition: pcivpd.h:22
uint64_t address
Base address.
Definition: ena.h:24
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
#define DBGC(...)
Definition: compiler.h:505
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
int cap
VPD capability offset.
Definition: pcivpd.h:134
#define htonl(value)
Definition: byteswap.h:133
int address
Address.
Definition: pcivpd.h:124
static int pci_vpd_cache_is_valid(struct pci_vpd *vpd)
Check if PCI VPD read cache is valid.
Definition: pcivpd.h:157
uint32_t data
Data.
Definition: pcivpd.h:126
int pci_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
Read 32-bit dword from PCI configuration space.
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
struct pci_vpd_cache cache
Read cache.
Definition: pcivpd.h:136
A PCI device.
Definition: pci.h:206
#define PCI_VPD_ADDRESS
PCI VPD address register.
Definition: pcivpd.h:19
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define DBGC2(...)
Definition: compiler.h:522
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:594
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define PCI_VPD_DATA
PCI VPD data register.
Definition: pcivpd.h:25
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:669
uint16_t flag
Flag number.
Definition: hyperv.h:14

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

static 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;
138  uint16_t flag;
139 
140  /* Fail if no VPD present */
141  if ( ! cap )
142  return -ENOTTY;
143 
144  /* Invalidate cache */
145  pci_vpd_invalidate_cache ( vpd );
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 }
#define PCI_VPD_MAX_WAIT_MS
Maximum wait for PCI VPD (in ms)
Definition: pcivpd.h:119
unsigned short uint16_t
Definition: stdint.h:11
#define PCI_VPD_FLAG
PCI VPD write flag.
Definition: pcivpd.h:22
uint64_t address
Base address.
Definition: ena.h:24
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
#define DBGC(...)
Definition: compiler.h:505
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
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
#define htonl(value)
Definition: byteswap.h:133
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
A PCI device.
Definition: pci.h:206
#define PCI_VPD_ADDRESS
PCI VPD address register.
Definition: pcivpd.h:19
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define DBGC2(...)
Definition: compiler.h:522
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:594
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
int pci_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
Write 32-bit dword to PCI configuration space.
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define PCI_VPD_DATA
PCI VPD data register.
Definition: pcivpd.h:25
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:669
uint16_t flag
Flag number.
Definition: hyperv.h:14

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;
186  uint32_t data;
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:14
uint64_t address
Base address.
Definition: ena.h:24
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
unsigned char uint8_t
Definition: stdint.h:10
unsigned int uint32_t
Definition: stdint.h:12
uint32_t len
Length.
Definition: ena.h:14
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint8_t bytes[64]
Definition: ib_mad.h:16

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;
228  uint32_t data;
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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint64_t address
Base address.
Definition: ena.h:24
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
unsigned char uint8_t
Definition: stdint.h:10
unsigned int uint32_t
Definition: stdint.h:12
uint32_t len
Length.
Definition: ena.h:14
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
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint8_t bytes[64]
Definition: ib_mad.h:16

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

static 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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition: pcivpd.c:183
uint64_t address
Base address.
Definition: ena.h:24
#define DBGC_HDA(...)
Definition: compiler.h:506
uint32_t len
Length.
Definition: ena.h:14
#define DBG_LOG
Definition: compiler.h:317

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

static 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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition: pcivpd.c:183
#define ISAPNP_TAG_END
Definition: isapnp.h:122
uint64_t address
Base address.
Definition: ena.h:24
#define ISAPNP_SMALL_TAG_NAME(tag)
Definition: isapnp.h:106
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
#define ISAPNP_SMALL_TAG_LEN(tag)
Definition: isapnp.h:107
#define ISAPNP_LARGE_TAG_NAME(tag)
Definition: isapnp.h:125
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
#define ISAPNP_IS_LARGE_TAG(tag)
Definition: isapnp.h:124
unsigned char uint8_t
Definition: stdint.h:10
#define le16_to_cpu(value)
Definition: byteswap.h:112
uint32_t len
Length.
Definition: ena.h:14
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
uint64_t tag
Identity tag.
Definition: edd.h:30

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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PCI_VPD_TAG(field)
Extract PCI VPD ISAPnP tag.
Definition: pcivpd.h:60
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition: pcivpd.c:183
uint64_t address
Base address.
Definition: ena.h:24
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
A PCI VPD field.
Definition: pcivpd.h:28
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_FIELD_FMT
PCI VPD field debug message format.
Definition: pcivpd.h:70
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
#define PCI_VPD_FIELD_ARGS(field)
PCI VPD field debug message arguments.
Definition: pcivpd.h:73
uint32_t len
Length.
Definition: ena.h:14
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
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
#define PCI_VPD_KEYWORD(field)
Extract PCI VPD keyword.
Definition: pcivpd.h:67

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 }
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
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PCI_VPD_TAG(field)
Extract PCI VPD ISAPnP tag.
Definition: pcivpd.h:60
int pci_vpd_read(struct pci_vpd *vpd, unsigned int address, void *buf, size_t len)
Read PCI VPD.
Definition: pcivpd.c:183
uint64_t address
Base address.
Definition: ena.h:24
#define DBGC(...)
Definition: compiler.h:505
A PCI VPD field.
Definition: pcivpd.h:28
#define PCI_VPD_TAG_RW
PCI VPD Read-Write field tag.
Definition: pcivpd.h:80
#define PCI_VPD_MAX_LEN
Maximum PCI VPD field length.
Definition: pcivpd.h:36
#define ENOMEM
Not enough space.
Definition: errno.h:534
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define PCI_VPD_FIELD_FMT
PCI VPD field debug message format.
Definition: pcivpd.h:70
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:307
int pci_vpd_write(struct pci_vpd *vpd, unsigned int address, const void *buf, size_t len)
Write PCI VPD.
Definition: pcivpd.c:225
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
#define PCI_VPD_FIELD_ARGS(field)
PCI VPD field debug message arguments.
Definition: pcivpd.h:73
#define ENXIO
No such device or address.
Definition: errno.h:599
#define ENOSPC
No space left on device.
Definition: errno.h:549
uint32_t len
Length.
Definition: ena.h:14
struct pci_device * pci
PCI device.
Definition: pcivpd.h:132
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:310
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
#define PCI_VPD_KEYWORD(field)
Extract PCI VPD keyword.
Definition: pcivpd.h:67
#define PCI_VPD_FIELD_RW
PCI VPD Remaining Read/Write Area field descriptor.
Definition: pcivpd.h:116

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