Commit 99cb233d60cbe644203f19938c729ea2bb004d70
Committed by
Jesse Barnes
1 parent
a94c248113
Exists in
master
and in
7 other branches
PCI: Limit VPD read/write lengths for Broadcom 5706, 5708, 5709 rev.
For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the VPD end tag will hang the device. This problem was initially observed when a vpd entry was created in sysfs ('/sys/bus/pci/devices/<id>/vpd'). A read to this sysfs entry will dump 32k of data. Reading a full 32k will cause an access beyond the VPD end tag causing the device to hang. Once the device is hung, the bnx2 driver will not be able to reset the device. We believe that it is legal to read beyond the end tag and therefore the solution is to limit the read/write length. A majority of this patch is from Matthew Wilcox who gave code for reworking the PCI vpd size information. A PCI quirk added for the Broadcom NIC's to limit the read/write's. Signed-off-by: Benjamin Li <benli@broadcom.com> Signed-off-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Showing 4 changed files with 48 additions and 12 deletions Side-by-side Diff
drivers/pci/access.c
... | ... | @@ -178,8 +178,7 @@ |
178 | 178 | int ret; |
179 | 179 | int begin, end, i; |
180 | 180 | |
181 | - if (pos < 0 || pos > PCI_VPD_PCI22_SIZE || | |
182 | - size > PCI_VPD_PCI22_SIZE - pos) | |
181 | + if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) | |
183 | 182 | return -EINVAL; |
184 | 183 | if (size == 0) |
185 | 184 | return 0; |
... | ... | @@ -223,8 +222,8 @@ |
223 | 222 | u32 val; |
224 | 223 | int ret; |
225 | 224 | |
226 | - if (pos < 0 || pos > PCI_VPD_PCI22_SIZE || pos & 3 || | |
227 | - size > PCI_VPD_PCI22_SIZE - pos || size < 4) | |
225 | + if (pos < 0 || pos > vpd->base.len || pos & 3 || | |
226 | + size > vpd->base.len - pos || size < 4) | |
228 | 227 | return -EINVAL; |
229 | 228 | |
230 | 229 | val = (u8) *buf++; |
... | ... | @@ -255,11 +254,6 @@ |
255 | 254 | return 4; |
256 | 255 | } |
257 | 256 | |
258 | -static int pci_vpd_pci22_get_size(struct pci_dev *dev) | |
259 | -{ | |
260 | - return PCI_VPD_PCI22_SIZE; | |
261 | -} | |
262 | - | |
263 | 257 | static void pci_vpd_pci22_release(struct pci_dev *dev) |
264 | 258 | { |
265 | 259 | kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); |
... | ... | @@ -268,7 +262,6 @@ |
268 | 262 | static struct pci_vpd_ops pci_vpd_pci22_ops = { |
269 | 263 | .read = pci_vpd_pci22_read, |
270 | 264 | .write = pci_vpd_pci22_write, |
271 | - .get_size = pci_vpd_pci22_get_size, | |
272 | 265 | .release = pci_vpd_pci22_release, |
273 | 266 | }; |
274 | 267 | |
... | ... | @@ -284,6 +277,7 @@ |
284 | 277 | if (!vpd) |
285 | 278 | return -ENOMEM; |
286 | 279 | |
280 | + vpd->base.len = PCI_VPD_PCI22_SIZE; | |
287 | 281 | vpd->base.ops = &pci_vpd_pci22_ops; |
288 | 282 | spin_lock_init(&vpd->lock); |
289 | 283 | vpd->cap = cap; |
drivers/pci/pci-sysfs.c
... | ... | @@ -736,7 +736,7 @@ |
736 | 736 | attr = kzalloc(sizeof(*attr), GFP_ATOMIC); |
737 | 737 | if (attr) { |
738 | 738 | pdev->vpd->attr = attr; |
739 | - attr->size = pdev->vpd->ops->get_size(pdev); | |
739 | + attr->size = pdev->vpd->len; | |
740 | 740 | attr->attr.name = "vpd"; |
741 | 741 | attr->attr.mode = S_IRUSR | S_IWUSR; |
742 | 742 | attr->read = pci_read_vpd; |
drivers/pci/pci.h
... | ... | @@ -21,11 +21,11 @@ |
21 | 21 | struct pci_vpd_ops { |
22 | 22 | int (*read)(struct pci_dev *dev, int pos, int size, char *buf); |
23 | 23 | int (*write)(struct pci_dev *dev, int pos, int size, const char *buf); |
24 | - int (*get_size)(struct pci_dev *dev); | |
25 | 24 | void (*release)(struct pci_dev *dev); |
26 | 25 | }; |
27 | 26 | |
28 | 27 | struct pci_vpd { |
28 | + unsigned int len; | |
29 | 29 | struct pci_vpd_ops *ops; |
30 | 30 | struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ |
31 | 31 | }; |
drivers/pci/quirks.c
... | ... | @@ -1670,6 +1670,48 @@ |
1670 | 1670 | } |
1671 | 1671 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); |
1672 | 1672 | |
1673 | +/* | |
1674 | + * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the | |
1675 | + * VPD end tag will hang the device. This problem was initially | |
1676 | + * observed when a vpd entry was created in sysfs | |
1677 | + * ('/sys/bus/pci/devices/<id>/vpd'). A read to this sysfs entry | |
1678 | + * will dump 32k of data. Reading a full 32k will cause an access | |
1679 | + * beyond the VPD end tag causing the device to hang. Once the device | |
1680 | + * is hung, the bnx2 driver will not be able to reset the device. | |
1681 | + * We believe that it is legal to read beyond the end tag and | |
1682 | + * therefore the solution is to limit the read/write length. | |
1683 | + */ | |
1684 | +static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev) | |
1685 | +{ | |
1686 | + /* Only disable the VPD capability for 5706, 5708, and 5709 rev. A */ | |
1687 | + if ((dev->device == PCI_DEVICE_ID_NX2_5706) || | |
1688 | + (dev->device == PCI_DEVICE_ID_NX2_5708) || | |
1689 | + ((dev->device == PCI_DEVICE_ID_NX2_5709) && | |
1690 | + (dev->revision & 0xf0) == 0x0)) { | |
1691 | + if (dev->vpd) | |
1692 | + dev->vpd->len = 0x80; | |
1693 | + } | |
1694 | +} | |
1695 | + | |
1696 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1697 | + PCI_DEVICE_ID_NX2_5706, | |
1698 | + quirk_brcm_570x_limit_vpd); | |
1699 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1700 | + PCI_DEVICE_ID_NX2_5706S, | |
1701 | + quirk_brcm_570x_limit_vpd); | |
1702 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1703 | + PCI_DEVICE_ID_NX2_5708, | |
1704 | + quirk_brcm_570x_limit_vpd); | |
1705 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1706 | + PCI_DEVICE_ID_NX2_5708S, | |
1707 | + quirk_brcm_570x_limit_vpd); | |
1708 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1709 | + PCI_DEVICE_ID_NX2_5709, | |
1710 | + quirk_brcm_570x_limit_vpd); | |
1711 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, | |
1712 | + PCI_DEVICE_ID_NX2_5709S, | |
1713 | + quirk_brcm_570x_limit_vpd); | |
1714 | + | |
1673 | 1715 | #ifdef CONFIG_PCI_MSI |
1674 | 1716 | /* Some chipsets do not support MSI. We cannot easily rely on setting |
1675 | 1717 | * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually |