Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI/VPD: Use pci_read_vpd_any() in pci_vpd_size()

Use new function pci_read_vpd_any() to simplify the code.

[bhelgaas: squash in fix for stack overflow reported & tested by
Qian [1] and Kunihiko [2]:
[1] https://lore.kernel.org/netdev/e89087c5-c495-c5ca-feb1-54cf3a8775c5@quicinc.com/
[2] https://lore.kernel.org/r/2f7e3770-ab47-42b5-719c-f7c661c07d28@socionext.com
Link: https://lore.kernel.org/r/6211be8a-5d10-8f3a-6d33-af695dc35caf@gmail.com
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Tested-by: Qian Cai <quic_qiancai@quicinc.com>
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Tested-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
]

Link: https://lore.kernel.org/r/049fa71c-c7af-9c69-51c0-05c1bc2bf660@gmail.com
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>

authored by

Heiner Kallweit and committed by
Bjorn Helgaas
3331325c bf2928c7

+13 -12
+13 -12
drivers/pci/vpd.c
··· 57 57 size_t off = 0, size; 58 58 unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */ 59 59 60 - /* Otherwise the following reads would fail. */ 61 - dev->vpd.len = PCI_VPD_MAX_SIZE; 62 - 63 - while (pci_read_vpd(dev, off, 1, header) == 1) { 60 + while (pci_read_vpd_any(dev, off, 1, header) == 1) { 64 61 size = 0; 65 62 66 63 if (off == 0 && (header[0] == 0x00 || header[0] == 0xff)) ··· 65 68 66 69 if (header[0] & PCI_VPD_LRDT) { 67 70 /* Large Resource Data Type Tag */ 68 - if (pci_read_vpd(dev, off + 1, 2, &header[1]) != 2) { 71 + if (pci_read_vpd_any(dev, off + 1, 2, &header[1]) != 2) { 69 72 pci_warn(dev, "failed VPD read at offset %zu\n", 70 73 off + 1); 71 74 return off ?: PCI_VPD_SZ_INVALID; ··· 96 99 return off ?: PCI_VPD_SZ_INVALID; 97 100 } 98 101 99 - static bool pci_vpd_available(struct pci_dev *dev) 102 + static bool pci_vpd_available(struct pci_dev *dev, bool check_size) 100 103 { 101 104 struct pci_vpd *vpd = &dev->vpd; 102 105 103 106 if (!vpd->cap) 104 107 return false; 105 108 106 - if (vpd->len == 0) { 109 + if (vpd->len == 0 && check_size) { 107 110 vpd->len = pci_vpd_size(dev); 108 111 if (vpd->len == PCI_VPD_SZ_INVALID) { 109 112 vpd->cap = 0; ··· 156 159 void *arg, bool check_size) 157 160 { 158 161 struct pci_vpd *vpd = &dev->vpd; 159 - unsigned int max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE; 162 + unsigned int max_len; 160 163 int ret = 0; 161 164 loff_t end = pos + count; 162 165 u8 *buf = arg; 163 166 164 - if (!pci_vpd_available(dev)) 167 + if (!pci_vpd_available(dev, check_size)) 165 168 return -ENODEV; 166 169 167 170 if (pos < 0) 168 171 return -EINVAL; 172 + 173 + max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE; 169 174 170 175 if (pos >= max_len) 171 176 return 0; ··· 220 221 const void *arg, bool check_size) 221 222 { 222 223 struct pci_vpd *vpd = &dev->vpd; 223 - unsigned int max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE; 224 + unsigned int max_len; 224 225 const u8 *buf = arg; 225 226 loff_t end = pos + count; 226 227 int ret = 0; 227 228 228 - if (!pci_vpd_available(dev)) 229 + if (!pci_vpd_available(dev, check_size)) 229 230 return -ENODEV; 230 231 231 232 if (pos < 0 || (pos & 3) || (count & 3)) 232 233 return -EINVAL; 234 + 235 + max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE; 233 236 234 237 if (end > max_len) 235 238 return -EINVAL; ··· 316 315 void *buf; 317 316 int cnt; 318 317 319 - if (!pci_vpd_available(dev)) 318 + if (!pci_vpd_available(dev, true)) 320 319 return ERR_PTR(-ENODEV); 321 320 322 321 len = dev->vpd.len;