Skip to content

Commit cb92148

Browse files
Hariprasad Shenaibjorn-helgaas
authored andcommitted
PCI: Add pci_set_vpd_size() to set VPD size
After 104daa7 ("PCI: Determine actual VPD size on first access"), the PCI core computes the valid VPD size by parsing the VPD starting at offset 0x0. We don't attempt to read past that valid size because that causes some devices to crash. However, some devices do have data past that valid size. For example, Chelsio adapters contain two VPD structures, and the driver needs both of them. Add pci_set_vpd_size(). If a driver knows it is safe to read past the end of the VPD data structure at offset 0, it can use pci_set_vpd_size() to allow access to as much data as it needs. [bhelgaas: changelog, split patches, rename to pci_set_vpd_size() and return int (not ssize_t)] Fixes: 104daa7 ("PCI: Determine actual VPD size on first access") Tested-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Casey Leedom <leedom@chelsio.com> Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent b2d7a9c commit cb92148

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

drivers/pci/access.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,19 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
275275
}
276276
EXPORT_SYMBOL(pci_write_vpd);
277277

278+
/**
279+
* pci_set_vpd_size - Set size of Vital Product Data space
280+
* @dev: pci device struct
281+
* @len: size of vpd space
282+
*/
283+
int pci_set_vpd_size(struct pci_dev *dev, size_t len)
284+
{
285+
if (!dev->vpd || !dev->vpd->ops)
286+
return -ENODEV;
287+
return dev->vpd->ops->set_size(dev, len);
288+
}
289+
EXPORT_SYMBOL(pci_set_vpd_size);
290+
278291
#define PCI_VPD_MAX_SIZE (PCI_VPD_ADDR_MASK + 1)
279292

280293
/**
@@ -498,9 +511,23 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
498511
return ret ? ret : count;
499512
}
500513

514+
static int pci_vpd_set_size(struct pci_dev *dev, size_t len)
515+
{
516+
struct pci_vpd *vpd = dev->vpd;
517+
518+
if (len == 0 || len > PCI_VPD_MAX_SIZE)
519+
return -EIO;
520+
521+
vpd->valid = 1;
522+
vpd->len = len;
523+
524+
return 0;
525+
}
526+
501527
static const struct pci_vpd_ops pci_vpd_ops = {
502528
.read = pci_vpd_read,
503529
.write = pci_vpd_write,
530+
.set_size = pci_vpd_set_size,
504531
};
505532

506533
static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count,
@@ -533,9 +560,24 @@ static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count,
533560
return ret;
534561
}
535562

563+
static int pci_vpd_f0_set_size(struct pci_dev *dev, size_t len)
564+
{
565+
struct pci_dev *tdev = pci_get_slot(dev->bus,
566+
PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
567+
int ret;
568+
569+
if (!tdev)
570+
return -ENODEV;
571+
572+
ret = pci_set_vpd_size(tdev, len);
573+
pci_dev_put(tdev);
574+
return ret;
575+
}
576+
536577
static const struct pci_vpd_ops pci_vpd_f0_ops = {
537578
.read = pci_vpd_f0_read,
538579
.write = pci_vpd_f0_write,
580+
.set_size = pci_vpd_f0_set_size,
539581
};
540582

541583
int pci_vpd_init(struct pci_dev *dev)

drivers/pci/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
9797
struct pci_vpd_ops {
9898
ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
9999
ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
100+
int (*set_size)(struct pci_dev *dev, size_t len);
100101
};
101102

102103
struct pci_vpd {

include/linux/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ void pci_unlock_rescan_remove(void);
11111111
/* Vital product data routines */
11121112
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
11131113
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
1114+
int pci_set_vpd_size(struct pci_dev *dev, size_t len);
11141115

11151116
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
11161117
resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);

0 commit comments

Comments
 (0)