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;
}
/* * 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.
*/ staticint pci_vpd_wait(struct pci_dev *dev, bool set)
{ struct pci_vpd *vpd = &dev->vpd; unsignedlong timeout = jiffies + msecs_to_jiffies(125); unsignedlong 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;
}
staticint pci_vpd_find_tag(const u8 *buf, unsignedint len, u8 rdt, unsignedint *size)
{ int i = 0;
/* look for LRDT tags only, end tag is the only SRDT tag */ while (i + PCI_VPD_LRDT_TAG_SIZE <= len && buf[i] & PCI_VPD_LRDT) { unsignedint lrdt_len = pci_vpd_lrdt_size(buf + i);
u8 tag = buf[i];
i += PCI_VPD_LRDT_TAG_SIZE; if (tag == rdt) { if (i + lrdt_len > len)
lrdt_len = len - i; if (size)
*size = lrdt_len; return i;
}
/** * pci_read_vpd - Read one entry from Vital Product Data * @dev: PCI device struct * @pos: offset in VPD space * @count: number of bytes to read * @buf: pointer to where to store result
*/
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
{ return __pci_read_vpd(dev, pos, count, buf, true);
}
EXPORT_SYMBOL(pci_read_vpd);
/* Same, but allow to access any address */
ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
{ return __pci_read_vpd(dev, pos, count, buf, false);
}
EXPORT_SYMBOL(pci_read_vpd_any);
#ifdef CONFIG_PCI_QUIRKS /* * Quirk non-zero PCI functions to route VPD access through function 0 for * devices that share VPD resources between functions. The functions are * expected to be identical devices.
*/ staticvoid quirk_f0_vpd_link(struct pci_dev *dev)
{ struct pci_dev *f0;
/* * If a device follows the VPD format spec, the PCI core will not read or * write past the VPD End Tag. But some vendors do not follow the VPD * format spec, so we can't tell how much data is safe to access. Devices * may behave unpredictably if we access too much. Blacklist these devices * so we don't touch VPD at all.
*/ staticvoid quirk_blacklist_vpd(struct pci_dev *dev)
{
dev->vpd.len = PCI_VPD_SZ_INVALID;
pci_warn(dev, FW_BUG "disabling VPD access (can't determine size of non-standard VPD format)\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID, quirk_blacklist_vpd); /* * The Amazon Annapurna Labs 0x0031 device id is reused for other non Root Port * device types, so the quirk is registered for the PCI_CLASS_BRIDGE_PCI class.
*/
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031,
PCI_CLASS_BRIDGE_PCI, 8, quirk_blacklist_vpd);
staticvoid quirk_chelsio_extend_vpd(struct pci_dev *dev)
{ int chip = (dev->device & 0xf000) >> 12; int func = (dev->device & 0x0f00) >> 8; int prod = (dev->device & 0x00ff) >> 0;
/* * If this is a T3-based adapter, there's a 1KB VPD area at offset * 0xc00 which contains the preferred VPD values. If this is a T4 or * later based adapter, the special VPD is at offset 0x400 for the * Physical Functions (the SR-IOV Virtual Functions have no VPD * Capabilities). The PCI VPD Access core routines will normally * compute the size of the VPD by parsing the VPD Data Structure at * offset 0x000. This will result in silent failures when attempting * to accesses these other VPD areas which are beyond those computed * limits.
*/ if (chip == 0x0 && prod >= 0x20)
dev->vpd.len = 8192; elseif (chip >= 0x4 && func < 0x8)
dev->vpd.len = 2048;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.