drivers/pci/vpd.c
Source file repositories/reference/linux-study-clean/drivers/pci/vpd.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pci/vpd.c- Extension
.c- Size
- 15651 bytes
- Lines
- 627
- Domain
- Representative Device Path
- Bucket
- PCIe NVMe Storage Path
- Inferred role
- Representative Device Path: exported/initcall integration point
- Status
- integration implementation candidate
Why This File Exists
Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.
- Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/pci.hlinux/delay.hlinux/export.hlinux/sched/signal.hlinux/unaligned.hpci.h
Detected Declarations
function Copyrightfunction pci_vpd_srdt_tagfunction pci_vpd_srdt_sizefunction pci_vpd_info_field_sizefunction pci_vpd_sizefunction pci_vpd_availablefunction pci_vpd_waitfunction pci_vpd_readfunction pci_vpd_writefunction pci_vpd_initfunction vpd_readfunction vpd_writefunction vpd_attr_is_visiblefunction pci_vpd_find_tagfunction pci_vpd_find_id_stringfunction pci_vpd_find_info_keywordfunction __pci_read_vpdfunction pci_read_vpdfunction pci_read_vpd_anyfunction __pci_write_vpdfunction pci_write_vpdfunction pci_write_vpd_anyfunction pci_vpd_find_ro_info_keywordfunction pci_vpd_check_csumfunction quirk_f0_vpd_linkfunction quirk_blacklist_vpdfunction quirk_chelsio_extend_vpdexport pci_vpd_allocexport pci_vpd_find_id_stringexport pci_read_vpdexport pci_read_vpd_anyexport pci_write_vpdexport pci_write_vpd_anyexport pci_vpd_find_ro_info_keywordexport pci_vpd_check_csum
Annotated Snippet
if (header[0] & PCI_VPD_LRDT) {
/* Large Resource Data Type Tag */
if (pci_read_vpd_any(dev, off + 1, 2, &header[1]) != 2) {
pci_warn(dev, "failed VPD read at offset %zu\n",
off + 1);
return off ?: PCI_VPD_SZ_INVALID;
}
size = pci_vpd_lrdt_size(header);
if (off + size > PCI_VPD_MAX_SIZE)
goto error;
off += PCI_VPD_LRDT_TAG_SIZE + size;
} else {
/* Short Resource Data Type Tag */
tag = pci_vpd_srdt_tag(header);
size = pci_vpd_srdt_size(header);
if (off + size > PCI_VPD_MAX_SIZE)
goto error;
off += PCI_VPD_SRDT_TAG_SIZE + size;
if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
return off;
}
}
return off;
error:
pci_info(dev, "invalid VPD tag %#04x (size %zu) at offset %zu%s\n",
header[0], size, off, off == 0 ?
"; assume missing optional EEPROM" : "");
return off ?: PCI_VPD_SZ_INVALID;
}
static bool pci_vpd_available(struct pci_dev *dev, bool check_size)
{
struct pci_vpd *vpd = &dev->vpd;
if (!vpd->cap)
return false;
if (vpd->len == 0 && check_size) {
vpd->len = pci_vpd_size(dev);
if (vpd->len == PCI_VPD_SZ_INVALID) {
vpd->cap = 0;
return false;
}
}
return true;
}
/*
* Wait for last operation to complete.
* This code has to spin since there is no other notification from the PCI
* hardware. Since the VPD is often implemented by serial attachment to an
* EEPROM, it may take many milliseconds to complete.
* @set: if true wait for flag to be set, else wait for it to be cleared
*
* Returns 0 on success, negative values indicate error.
*/
static int pci_vpd_wait(struct pci_dev *dev, bool set)
{
struct pci_vpd *vpd = &dev->vpd;
unsigned long timeout = jiffies + msecs_to_jiffies(125);
unsigned long max_sleep = 16;
u16 status;
int ret;
do {
ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
&status);
if (ret < 0)
return ret;
if (!!(status & PCI_VPD_ADDR_F) == set)
return 0;
if (time_after(jiffies, timeout))
break;
usleep_range(10, max_sleep);
if (max_sleep < 1024)
max_sleep *= 2;
} while (true);
pci_warn(dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
return -ETIMEDOUT;
}
static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
Annotation
- Immediate include surface: `linux/pci.h`, `linux/delay.h`, `linux/export.h`, `linux/sched/signal.h`, `linux/unaligned.h`, `pci.h`.
- Detected declarations: `function Copyright`, `function pci_vpd_srdt_tag`, `function pci_vpd_srdt_size`, `function pci_vpd_info_field_size`, `function pci_vpd_size`, `function pci_vpd_available`, `function pci_vpd_wait`, `function pci_vpd_read`, `function pci_vpd_write`, `function pci_vpd_init`.
- Atlas domain: Representative Device Path / PCIe NVMe Storage Path.
- Implementation status: integration implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.