int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt) { int i; for (i = off; i < len; ) { u8 val = buf[i]; if (val & PCI_VPD_LRDT) { /* Don't return success of the tag isn't complete */ if (i + PCI_VPD_LRDT_TAG_SIZE > len) break; if (val == rdt) return i; i += PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&buf[i]); } else { u8 tag = val & ~PCI_VPD_SRDT_LEN_MASK; if (tag == rdt) return i; if (tag == PCI_VPD_SRDT_END) break; i += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(&buf[i]); } } return -ENOENT; }
/** * 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; }