/** * pci_vpd_size - determine actual size of Vital Product Data * @dev: pci device struct * @old_size: current assumed size, also maximum allowed size */ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size) { size_t off = 0; unsigned char header[1+2]; /* 1 byte tag, 2 bytes length */ while (off < old_size && pci_read_vpd(dev, off, 1, header) == 1) { unsigned char tag; if (header[0] & PCI_VPD_LRDT) { /* Large Resource Data Type Tag */ tag = pci_vpd_lrdt_tag(header); /* Only read length from known tag items */ if ((tag == PCI_VPD_LTIN_ID_STRING) || (tag == PCI_VPD_LTIN_RO_DATA) || (tag == PCI_VPD_LTIN_RW_DATA)) { if (pci_read_vpd(dev, off+1, 2, &header[1]) != 2) { dev_warn(&dev->dev, "invalid large VPD tag %02x size at offset %zu", tag, off + 1); return 0; } off += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(header); } } else { /* Short Resource Data Type Tag */ off += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(header); tag = pci_vpd_srdt_tag(header); } if (tag == PCI_VPD_STIN_END) /* End tag descriptor */ return off; if ((tag != PCI_VPD_LTIN_ID_STRING) && (tag != PCI_VPD_LTIN_RO_DATA) && (tag != PCI_VPD_LTIN_RW_DATA)) { dev_warn(&dev->dev, "invalid %s VPD tag %02x at offset %zu", (header[0] & PCI_VPD_LRDT) ? "large" : "short", tag, off); return 0; } } return 0; }
/* The next two routines implement eeprom read/write from physical addresses. */ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) { int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); if (vaddr >= 0) vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); return vaddr < 0 ? vaddr : 0; }
static int read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum) { if (!pci_read_vpd(d->dev, pos, buf, len)) return 0; while (len--) *csum += *buf++; return 1; }
static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count, void *arg) { struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); ssize_t ret; if (!tdev) return -ENODEV; ret = pci_read_vpd(tdev, pos, count, arg); pci_dev_put(tdev); return ret; }