Skip to content

Commit 00e1a5d

Browse files
committed
PCI/VPD: Defer VPD sizing until first access
7bac544 ("PCI/VPD: Determine VPD size in pci_vpd_init()") reads VPD at enumeration-time to find the size. But this is quite slow, and we don't need the size until we actually need data from VPD. Dave reported a boot slowdown of more than two minutes [1]. Defer the VPD sizing until a driver or the user (via sysfs) requests information from VPD. If devices are quirked because VPD is known not to work, don't bother even looking for the VPD capability. The VPD will not be accessible at all. [1] https://lore.kernel.org/r/20210913141818.GA27911@codemonkey.org.uk/ Link: https://lore.kernel.org/r/20210914215543.GA1437800@bjorn-Precision-5520 Fixes: 7bac544 ("PCI/VPD: Determine VPD size in pci_vpd_init()") Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent 6880fa6 commit 00e1a5d

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

drivers/pci/vpd.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ static size_t pci_vpd_size(struct pci_dev *dev)
9999
return off ?: PCI_VPD_SZ_INVALID;
100100
}
101101

102+
static bool pci_vpd_available(struct pci_dev *dev)
103+
{
104+
struct pci_vpd *vpd = &dev->vpd;
105+
106+
if (!vpd->cap)
107+
return false;
108+
109+
if (vpd->len == 0) {
110+
vpd->len = pci_vpd_size(dev);
111+
if (vpd->len == PCI_VPD_SZ_INVALID) {
112+
vpd->cap = 0;
113+
return false;
114+
}
115+
}
116+
117+
return true;
118+
}
119+
102120
/*
103121
* Wait for last operation to complete.
104122
* This code has to spin since there is no other notification from the PCI
@@ -145,7 +163,7 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
145163
loff_t end = pos + count;
146164
u8 *buf = arg;
147165

148-
if (!vpd->cap)
166+
if (!pci_vpd_available(dev))
149167
return -ENODEV;
150168

151169
if (pos < 0)
@@ -206,7 +224,7 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
206224
loff_t end = pos + count;
207225
int ret = 0;
208226

209-
if (!vpd->cap)
227+
if (!pci_vpd_available(dev))
210228
return -ENODEV;
211229

212230
if (pos < 0 || (pos & 3) || (count & 3))
@@ -242,14 +260,11 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
242260

243261
void pci_vpd_init(struct pci_dev *dev)
244262
{
263+
if (dev->vpd.len == PCI_VPD_SZ_INVALID)
264+
return;
265+
245266
dev->vpd.cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
246267
mutex_init(&dev->vpd.lock);
247-
248-
if (!dev->vpd.len)
249-
dev->vpd.len = pci_vpd_size(dev);
250-
251-
if (dev->vpd.len == PCI_VPD_SZ_INVALID)
252-
dev->vpd.cap = 0;
253268
}
254269

255270
static ssize_t vpd_read(struct file *filp, struct kobject *kobj,
@@ -294,13 +309,14 @@ const struct attribute_group pci_dev_vpd_attr_group = {
294309

295310
void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size)
296311
{
297-
unsigned int len = dev->vpd.len;
312+
unsigned int len;
298313
void *buf;
299314
int cnt;
300315

301-
if (!dev->vpd.cap)
316+
if (!pci_vpd_available(dev))
302317
return ERR_PTR(-ENODEV);
303318

319+
len = dev->vpd.len;
304320
buf = kmalloc(len, GFP_KERNEL);
305321
if (!buf)
306322
return ERR_PTR(-ENOMEM);

0 commit comments

Comments
 (0)