From fb8a0d9d1bfd1e4355f307e86a6da7209eefd5f3 Mon Sep 17 00:00:00 2001 From: "Williams, Mitch A" Date: Wed, 10 Feb 2010 01:43:04 +0000 Subject: pci: Add SR-IOV convenience functions and macros Add and export pci_num_vf to allow other subsystems to determine how many virtual function devices are associated with an SR-IOV physical function device. Add macros dev_is_pci, dev_is_ps, and dev_num_vf to make it easier for non-PCI specific code to determine SR-IOV capabilities. Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/pci/iov.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b2a448e19fe6..3e5ab2bf6a5c 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -706,6 +706,21 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_sriov_migration); +/** + * pci_num_vf - return number of VFs associated with a PF device_release_driver + * @dev: the PCI device + * + * Returns number of VFs, or 0 if SR-IOV is not enabled. + */ +int pci_num_vf(struct pci_dev *dev) +{ + if (!dev || !dev->is_physfn) + return 0; + else + return dev->sriov->nr_virtfn; +} +EXPORT_SYMBOL_GPL(pci_num_vf); + static int ats_alloc_one(struct pci_dev *dev, int ps) { int pos; -- cgit v1.2.3 From 7a0deb6bcda98c2a764cb87f1441eef920fd3663 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 19 Feb 2010 17:57:46 +0000 Subject: pci: add support for 82576NS serdes to existing SR-IOV quirk This patch adds support for the 82576NS Serdes adapter to the existing pci quirk for 82576 parts. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d58b94030ef3..456c265b1fe9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2534,6 +2534,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150d, quirk_i82576_sriov); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov); #endif /* CONFIG_PCI_IOV */ -- cgit v1.2.3 From b55ac1b22690d2e5b02a61cf6d69c2d66969c79d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 26 Feb 2010 14:04:41 +0000 Subject: pci: Add helper to find a VPD resource data type This patch adds the pci_vpd_find_tag() helper function to find VPD resource data types in a buffer. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Acked-by: Jesse Barnes Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 24 ++++-------------------- drivers/net/tg3.c | 26 +++++--------------------- drivers/pci/Makefile | 2 +- drivers/pci/vpd.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 12 ++++++++++++ 5 files changed, 65 insertions(+), 42 deletions(-) create mode 100644 drivers/pci/vpd.c (limited to 'drivers/pci') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 084ef102b8c4..fd43feb5a350 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7769,28 +7769,12 @@ bnx2_read_vpd_fw_ver(struct bnx2 *bp) } for (i = 0; i <= BNX2_VPD_LEN - 3; ) { - unsigned char val = data[i]; unsigned int block_end; - if (val & PCI_VPD_LRDT) { - if (i + PCI_VPD_LRDT_TAG_SIZE > BNX2_VPD_LEN) - break; - - if (val != PCI_VPD_LRDT_RO_DATA) { - i += PCI_VPD_LRDT_TAG_SIZE + - pci_vpd_lrdt_size(&data[i]); - - continue; - } - } else { - if ((val & PCI_VPD_SRDT_TIN_MASK) == PCI_VPD_STIN_END) - break; - - i += PCI_VPD_SRDT_TAG_SIZE + - pci_vpd_srdt_size(&data[i]); - - continue; - } + i = pci_vpd_find_tag(data, i, BNX2_VPD_LEN, + PCI_VPD_LRDT_RO_DATA); + if (i < 0) + break; block_end = (i + PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&data[i])); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ed57a62b3ac8..76ad141ab448 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12547,7 +12547,7 @@ skip_phy_reset: static void __devinit tg3_read_partno(struct tg3 *tp) { unsigned char vpd_data[TG3_NVM_VPD_LEN]; /* in little-endian format */ - unsigned int i; + int i; u32 magic; if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || @@ -12586,28 +12586,12 @@ static void __devinit tg3_read_partno(struct tg3 *tp) /* Now parse and find the part number. */ for (i = 0; i < TG3_NVM_VPD_LEN - 2; ) { - unsigned char val = vpd_data[i]; unsigned int block_end; - if (val & PCI_VPD_LRDT) { - if (i + PCI_VPD_LRDT_TAG_SIZE > TG3_NVM_VPD_LEN) - break; - - if (val != PCI_VPD_LRDT_RO_DATA) { - i += PCI_VPD_LRDT_TAG_SIZE + - pci_vpd_lrdt_size(&vpd_data[i]); - - continue; - } - } else { - if ((val & PCI_VPD_SRDT_TIN_MASK) == PCI_VPD_STIN_END) - break; - - i += PCI_VPD_SRDT_TAG_SIZE + - pci_vpd_srdt_size(&vpd_data[i]); - - continue; - } + i = pci_vpd_find_tag(vpd_data, i, TG3_NVM_VPD_LEN, + PCI_VPD_LRDT_RO_DATA); + if (i < 0) + break; block_end = i + PCI_VPD_LRDT_TAG_SIZE + pci_vpd_lrdt_size(&vpd_data[i]); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 4df48d58eaa6..b2f6d777a084 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -4,7 +4,7 @@ obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ - irq.o + irq.o vpd.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c new file mode 100644 index 000000000000..6bc554576f8d --- /dev/null +++ b/drivers/pci/vpd.c @@ -0,0 +1,43 @@ +/* + * File: vpd.c + * Purpose: Provide PCI VPD support + * + * Copyright (C) 2010 Broadcom Corporation. + */ + +#include + +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; +} +EXPORT_SYMBOL_GPL(pci_vpd_find_tag); diff --git a/include/linux/pci.h b/include/linux/pci.h index 198d062640b7..e30ceea7345b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1395,5 +1395,17 @@ static inline u8 pci_vpd_srdt_size(const u8 *srdt) return (*srdt) & PCI_VPD_SRDT_LEN_MASK; } +/** + * pci_vpd_find_tag - Locates the Resource Data Type tag provided + * @buf: Pointer to buffered vpd data + * @off: The offset into the buffer at which to begin the search + * @len: The length of the vpd buffer + * @rdt: The Resource Data Type to search for + * + * Returns the index where the Resource Data Type was found or + * -ENOENT otherwise. + */ +int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt); + #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ -- cgit v1.2.3 From 4067a8541d397e9d6b443dd2ce0ecb78bfd991db Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 26 Feb 2010 14:04:43 +0000 Subject: pci: Add helper to search for VPD keywords This patch adds the pci_vpd_find_info_keyword() helper function to find information field keywords within read-only and read-write large resource data type sections. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Acked-by: Jesse Barnes Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 54 +++++++++++++++++++++++++++++------------------------ drivers/net/tg3.c | 32 +++++++++++++------------------ drivers/pci/vpd.c | 18 ++++++++++++++++++ include/linux/pci.h | 17 +++++++++++++++++ 4 files changed, 78 insertions(+), 43 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b808707f83ff..bc23bfb687c3 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7769,48 +7769,54 @@ bnx2_read_vpd_fw_ver(struct bnx2 *bp) } for (i = 0; i <= BNX2_VPD_LEN - 3; ) { - unsigned int block_end; + int j; + unsigned int block_end, rosize; i = pci_vpd_find_tag(data, i, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) break; - block_end = (i + PCI_VPD_LRDT_TAG_SIZE + - pci_vpd_lrdt_size(&data[i])); + rosize = pci_vpd_lrdt_size(&data[i]); + block_end = i + PCI_VPD_LRDT_TAG_SIZE + rosize; i += PCI_VPD_LRDT_TAG_SIZE; if (block_end > BNX2_VPD_LEN) goto vpd_done; - while (i < (block_end - 2)) { - int len = pci_vpd_info_field_size(&data[i]); + j = pci_vpd_find_info_keyword(data, i, rosize, + PCI_VPD_RO_KEYWORD_MFR_ID); + if (j > 0) { + int len = pci_vpd_info_field_size(&data[j]); - if (i + PCI_VPD_INFO_FLD_HDR_SIZE + len > block_end) + if (j + PCI_VPD_INFO_FLD_HDR_SIZE + len > block_end || + len != 4 || + memcmp(&data[j + PCI_VPD_INFO_FLD_HDR_SIZE], + "1028", 4)) goto vpd_done; - if (data[i] == 'M' && data[i + 1] == 'N') { - if (len != 4 || - memcmp(&data[i + PCI_VPD_INFO_FLD_HDR_SIZE], - "1028", 4)) - goto vpd_done; - mn_match = true; + mn_match = true; + } - } else if (data[i] == 'V' && data[i + 1] == '0') { - if (len > BNX2_MAX_VER_SLEN) - goto vpd_done; + j = pci_vpd_find_info_keyword(data, i, rosize, + PCI_VPD_RO_KEYWORD_VENDOR0); + if (j > 0) { + int len = pci_vpd_info_field_size(&data[j]); - v0_len = len; - v0_str = &data[i + PCI_VPD_INFO_FLD_HDR_SIZE]; - } - i += PCI_VPD_INFO_FLD_HDR_SIZE + len; - - if (mn_match && v0_str) { - memcpy(bp->fw_version, v0_str, v0_len); - bp->fw_version[v0_len] = ' '; + j += PCI_VPD_INFO_FLD_HDR_SIZE; + if (j + len > block_end || len > BNX2_MAX_VER_SLEN) goto vpd_done; - } + + v0_len = len; + v0_str = &data[j]; } + + if (mn_match && v0_str) { + memcpy(bp->fw_version, v0_str, v0_len); + bp->fw_version[v0_len] = ' '; + goto vpd_done; + } + goto vpd_done; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f59f36910e98..204c565caa5a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12586,39 +12586,33 @@ static void __devinit tg3_read_partno(struct tg3 *tp) /* Now parse and find the part number. */ for (i = 0; i < TG3_NVM_VPD_LEN - 2; ) { - unsigned int block_end; + unsigned int block_end, rosize; i = pci_vpd_find_tag(vpd_data, i, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) break; - block_end = i + PCI_VPD_LRDT_TAG_SIZE + - pci_vpd_lrdt_size(&vpd_data[i]); - + rosize = pci_vpd_lrdt_size(&vpd_data[i]); + block_end = i + PCI_VPD_LRDT_TAG_SIZE + rosize; i += PCI_VPD_LRDT_TAG_SIZE; if (block_end > TG3_NVM_VPD_LEN) goto out_not_found; - while (i < (block_end - 2)) { - if (vpd_data[i + 0] == 'P' && - vpd_data[i + 1] == 'N') { - int partno_len = pci_vpd_info_field_size(&vpd_data[i]); + i = pci_vpd_find_info_keyword(vpd_data, i, rosize, + PCI_VPD_RO_KEYWORD_PARTNO); + if (i > 0) { + u8 len = pci_vpd_info_field_size(&vpd_data[i]); - i += PCI_VPD_INFO_FLD_HDR_SIZE; - if (partno_len > TG3_BPN_SIZE || - (partno_len + i) > TG3_NVM_VPD_LEN) - goto out_not_found; + i += PCI_VPD_INFO_FLD_HDR_SIZE; + if (len > TG3_BPN_SIZE || + (len + i) > TG3_NVM_VPD_LEN) + break; - memcpy(tp->board_part_number, - &vpd_data[i], partno_len); + memcpy(tp->board_part_number, &vpd_data[i], len); - /* Success. */ - return; - } - i += PCI_VPD_INFO_FLD_HDR_SIZE + - pci_vpd_info_field_size(&vpd_data[i]); + return; } /* Part number not found. */ diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c index 6bc554576f8d..a5a5ca17cfe6 100644 --- a/drivers/pci/vpd.c +++ b/drivers/pci/vpd.c @@ -41,3 +41,21 @@ int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt) return -ENOENT; } EXPORT_SYMBOL_GPL(pci_vpd_find_tag); + +int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, + unsigned int len, const char *kw) +{ + int i; + + for (i = off; i + PCI_VPD_INFO_FLD_HDR_SIZE <= off + len;) { + if (buf[i + 0] == kw[0] && + buf[i + 1] == kw[1]) + return i; + + i += PCI_VPD_INFO_FLD_HDR_SIZE + + pci_vpd_info_field_size(&buf[i]); + } + + return -ENOENT; +} +EXPORT_SYMBOL_GPL(pci_vpd_find_info_keyword); diff --git a/include/linux/pci.h b/include/linux/pci.h index cfff32fc6e35..1f4a52131c99 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1375,6 +1375,10 @@ void pci_request_acs(void); #define PCI_VPD_INFO_FLD_HDR_SIZE 3 +#define PCI_VPD_RO_KEYWORD_PARTNO "PN" +#define PCI_VPD_RO_KEYWORD_MFR_ID "MN" +#define PCI_VPD_RO_KEYWORD_VENDOR0 "V0" + /** * pci_vpd_lrdt_size - Extracts the Large Resource Data Type length * @lrdt: Pointer to the beginning of the Large Resource Data Type tag @@ -1420,5 +1424,18 @@ static inline u8 pci_vpd_info_field_size(const u8 *info_field) */ int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt); +/** + * pci_vpd_find_info_keyword - Locates an information field keyword in the VPD + * @buf: Pointer to buffered vpd data + * @off: The offset into the buffer at which to begin the search + * @len: The length of the buffer area, relative to off, in which to search + * @kw: The keyword to search for + * + * Returns the index where the information field keyword was found or + * -ENOENT otherwise. + */ +int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, + unsigned int len, const char *kw); + #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ -- cgit v1.2.3