Merge branch 'pci/vpd'
authorBjorn Helgaas <bhelgaas@google.com>
Fri, 5 Nov 2021 16:28:47 +0000 (11:28 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 5 Nov 2021 16:28:47 +0000 (11:28 -0500)
- Add pci_read_vpd_any(), pci_write_vpd_any() to access VPD at arbitrary
  offsets (Heiner Kallweit)

- Use VPD API to replace custom code in cxgb3 driver (Heiner Kallweit)

* pci/vpd:
  cxgb3: Remove seeprom_write and use VPD API
  cxgb3: Use VPD API in t3_seeprom_wp()
  cxgb3: Remove t3_seeprom_read and use VPD API
  PCI/VPD: Use pci_read_vpd_any() in pci_vpd_size()
  PCI/VPD: Add pci_read/write_vpd_any()

drivers/net/ethernet/chelsio/cxgb3/common.h
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
drivers/pci/vpd.c
include/linux/pci.h

index b706f2f..d115ec9 100644 (file)
@@ -676,8 +676,6 @@ void t3_link_changed(struct adapter *adapter, int port_id);
 void t3_link_fault(struct adapter *adapter, int port_id);
 int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
 const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
-int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data);
-int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data);
 int t3_seeprom_wp(struct adapter *adapter, int enable);
 int t3_get_tp_version(struct adapter *adapter, u32 *vers);
 int t3_check_tpsram_version(struct adapter *adapter);
index 38e4770..e185f5f 100644 (file)
@@ -2036,20 +2036,16 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 {
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
-       int i, err = 0;
-
-       u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
+       int cnt;
 
        e->magic = EEPROM_MAGIC;
-       for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
-               err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
+       cnt = pci_read_vpd(adapter->pdev, e->offset, e->len, data);
+       if (cnt < 0)
+               return cnt;
 
-       if (!err)
-               memcpy(data, buf + e->offset, e->len);
-       kfree(buf);
-       return err;
+       e->len = cnt;
+
+       return 0;
 }
 
 static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -2058,7 +2054,6 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
        u32 aligned_offset, aligned_len;
-       __le32 *p;
        u8 *buf;
        int err;
 
@@ -2072,12 +2067,9 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                buf = kmalloc(aligned_len, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
-               err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
-               if (!err && aligned_len > 4)
-                       err = t3_seeprom_read(adapter,
-                                             aligned_offset + aligned_len - 4,
-                                             (__le32 *) & buf[aligned_len - 4]);
-               if (err)
+               err = pci_read_vpd(adapter->pdev, aligned_offset, aligned_len,
+                                  buf);
+               if (err < 0)
                        goto out;
                memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
        } else
@@ -2087,17 +2079,13 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        if (err)
                goto out;
 
-       for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
-               err = t3_seeprom_write(adapter, aligned_offset, *p);
-               aligned_offset += 4;
-       }
-
-       if (!err)
+       err = pci_write_vpd(adapter->pdev, aligned_offset, aligned_len, buf);
+       if (err >= 0)
                err = t3_seeprom_wp(adapter, 1);
 out:
        if (buf != data)
                kfree(buf);
-       return err;
+       return err < 0 ? err : 0;
 }
 
 static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
index 7ff31d1..cb85c2f 100644 (file)
@@ -595,80 +595,9 @@ struct t3_vpd {
        u32 pad;                /* for multiple-of-4 sizing and alignment */
 };
 
-#define EEPROM_MAX_POLL   40
 #define EEPROM_STAT_ADDR  0x4000
 #define VPD_BASE          0xc00
 
-/**
- *     t3_seeprom_read - read a VPD EEPROM location
- *     @adapter: adapter to read
- *     @addr: EEPROM address
- *     @data: where to store the read data
- *
- *     Read a 32-bit word from a location in VPD EEPROM using the card's PCI
- *     VPD ROM capability.  A zero is written to the flag bit when the
- *     address is written to the control register.  The hardware device will
- *     set the flag to 1 when 4 bytes have been read into the data register.
- */
-int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
-{
-       u16 val;
-       int attempts = EEPROM_MAX_POLL;
-       u32 v;
-       unsigned int base = adapter->params.pci.vpd_cap_addr;
-
-       if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
-               return -EINVAL;
-
-       pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
-       do {
-               udelay(10);
-               pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
-       } while (!(val & PCI_VPD_ADDR_F) && --attempts);
-
-       if (!(val & PCI_VPD_ADDR_F)) {
-               CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
-               return -EIO;
-       }
-       pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v);
-       *data = cpu_to_le32(v);
-       return 0;
-}
-
-/**
- *     t3_seeprom_write - write a VPD EEPROM location
- *     @adapter: adapter to write
- *     @addr: EEPROM address
- *     @data: value to write
- *
- *     Write a 32-bit word to a location in VPD EEPROM using the card's PCI
- *     VPD ROM capability.
- */
-int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
-{
-       u16 val;
-       int attempts = EEPROM_MAX_POLL;
-       unsigned int base = adapter->params.pci.vpd_cap_addr;
-
-       if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
-               return -EINVAL;
-
-       pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
-                              le32_to_cpu(data));
-       pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
-                             addr | PCI_VPD_ADDR_F);
-       do {
-               msleep(1);
-               pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
-       } while ((val & PCI_VPD_ADDR_F) && --attempts);
-
-       if (val & PCI_VPD_ADDR_F) {
-               CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
-               return -EIO;
-       }
-       return 0;
-}
-
 /**
  *     t3_seeprom_wp - enable/disable EEPROM write protection
  *     @adapter: the adapter
@@ -678,7 +607,14 @@ int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
  */
 int t3_seeprom_wp(struct adapter *adapter, int enable)
 {
-       return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+       u32 data = enable ? 0xc : 0;
+       int ret;
+
+       /* EEPROM_STAT_ADDR is outside VPD area, use pci_write_vpd_any() */
+       ret = pci_write_vpd_any(adapter->pdev, EEPROM_STAT_ADDR, sizeof(u32),
+                               &data);
+
+       return ret < 0 ? ret : 0;
 }
 
 static int vpdstrtouint(char *s, u8 len, unsigned int base, unsigned int *val)
@@ -708,24 +644,22 @@ static int vpdstrtou16(char *s, u8 len, unsigned int base, u16 *val)
  */
 static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 {
-       int i, addr, ret;
        struct t3_vpd vpd;
+       u8 base_val = 0;
+       int addr, ret;
 
        /*
         * Card information is normally at VPD_BASE but some early cards had
         * it at 0.
         */
-       ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd);
-       if (ret)
+       ret = pci_read_vpd(adapter->pdev, VPD_BASE, 1, &base_val);
+       if (ret < 0)
                return ret;
-       addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+       addr = base_val == PCI_VPD_LRDT_ID_STRING ? VPD_BASE : 0;
 
-       for (i = 0; i < sizeof(vpd); i += 4) {
-               ret = t3_seeprom_read(adapter, addr + i,
-                                     (__le32 *)((u8 *)&vpd + i));
-               if (ret)
-                       return ret;
-       }
+       ret = pci_read_vpd(adapter->pdev, addr, sizeof(vpd), &vpd);
+       if (ret < 0)
+               return ret;
 
        ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
        if (ret)
index 4be2489..a4fc4d0 100644 (file)
@@ -57,10 +57,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
        size_t off = 0, size;
        unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */
 
-       /* Otherwise the following reads would fail. */
-       dev->vpd.len = PCI_VPD_MAX_SIZE;
-
-       while (pci_read_vpd(dev, off, 1, header) == 1) {
+       while (pci_read_vpd_any(dev, off, 1, header) == 1) {
                size = 0;
 
                if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
@@ -68,7 +65,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
 
                if (header[0] & PCI_VPD_LRDT) {
                        /* Large Resource Data Type Tag */
-                       if (pci_read_vpd(dev, off + 1, 2, &header[1]) != 2) {
+                       if (pci_read_vpd_any(dev, off + 1, 2, &header[1]) != 2) {
                                pci_warn(dev, "failed VPD read at offset %zu\n",
                                         off + 1);
                                return off ?: PCI_VPD_SZ_INVALID;
@@ -99,14 +96,14 @@ error:
        return off ?: PCI_VPD_SZ_INVALID;
 }
 
-static bool pci_vpd_available(struct pci_dev *dev)
+static bool pci_vpd_available(struct pci_dev *dev, bool check_size)
 {
        struct pci_vpd *vpd = &dev->vpd;
 
        if (!vpd->cap)
                return false;
 
-       if (vpd->len == 0) {
+       if (vpd->len == 0 && check_size) {
                vpd->len = pci_vpd_size(dev);
                if (vpd->len == PCI_VPD_SZ_INVALID) {
                        vpd->cap = 0;
@@ -156,24 +153,27 @@ static int pci_vpd_wait(struct pci_dev *dev, bool set)
 }
 
 static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
-                           void *arg)
+                           void *arg, bool check_size)
 {
        struct pci_vpd *vpd = &dev->vpd;
+       unsigned int max_len;
        int ret = 0;
        loff_t end = pos + count;
        u8 *buf = arg;
 
-       if (!pci_vpd_available(dev))
+       if (!pci_vpd_available(dev, check_size))
                return -ENODEV;
 
        if (pos < 0)
                return -EINVAL;
 
-       if (pos > vpd->len)
+       max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
+
+       if (pos >= max_len)
                return 0;
 
-       if (end > vpd->len) {
-               end = vpd->len;
+       if (end > max_len) {
+               end = max_len;
                count = end - pos;
        }
 
@@ -217,20 +217,23 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
 }
 
 static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
-                            const void *arg)
+                            const void *arg, bool check_size)
 {
        struct pci_vpd *vpd = &dev->vpd;
+       unsigned int max_len;
        const u8 *buf = arg;
        loff_t end = pos + count;
        int ret = 0;
 
-       if (!pci_vpd_available(dev))
+       if (!pci_vpd_available(dev, check_size))
                return -ENODEV;
 
        if (pos < 0 || (pos & 3) || (count & 3))
                return -EINVAL;
 
-       if (end > vpd->len)
+       max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
+
+       if (end > max_len)
                return -EINVAL;
 
        if (mutex_lock_killable(&vpd->lock))
@@ -313,7 +316,7 @@ void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size)
        void *buf;
        int cnt;
 
-       if (!pci_vpd_available(dev))
+       if (!pci_vpd_available(dev, true))
                return ERR_PTR(-ENODEV);
 
        len = dev->vpd.len;
@@ -381,6 +384,24 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
        return -ENOENT;
 }
 
+static ssize_t __pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf,
+                             bool check_size)
+{
+       ssize_t ret;
+
+       if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
+               dev = pci_get_func0_dev(dev);
+               if (!dev)
+                       return -ENODEV;
+
+               ret = pci_vpd_read(dev, pos, count, buf, check_size);
+               pci_dev_put(dev);
+               return ret;
+       }
+
+       return pci_vpd_read(dev, pos, count, buf, check_size);
+}
+
 /**
  * pci_read_vpd - Read one entry from Vital Product Data
  * @dev:       PCI device struct
@@ -389,6 +410,20 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
  * @buf:       pointer to where to store result
  */
 ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
+{
+       return __pci_read_vpd(dev, pos, count, buf, true);
+}
+EXPORT_SYMBOL(pci_read_vpd);
+
+/* Same, but allow to access any address */
+ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
+{
+       return __pci_read_vpd(dev, pos, count, buf, false);
+}
+EXPORT_SYMBOL(pci_read_vpd_any);
+
+static ssize_t __pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count,
+                              const void *buf, bool check_size)
 {
        ssize_t ret;
 
@@ -397,14 +432,13 @@ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
                if (!dev)
                        return -ENODEV;
 
-               ret = pci_vpd_read(dev, pos, count, buf);
+               ret = pci_vpd_write(dev, pos, count, buf, check_size);
                pci_dev_put(dev);
                return ret;
        }
 
-       return pci_vpd_read(dev, pos, count, buf);
+       return pci_vpd_write(dev, pos, count, buf, check_size);
 }
-EXPORT_SYMBOL(pci_read_vpd);
 
 /**
  * pci_write_vpd - Write entry to Vital Product Data
@@ -415,22 +449,17 @@ EXPORT_SYMBOL(pci_read_vpd);
  */
 ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
 {
-       ssize_t ret;
-
-       if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
-               dev = pci_get_func0_dev(dev);
-               if (!dev)
-                       return -ENODEV;
-
-               ret = pci_vpd_write(dev, pos, count, buf);
-               pci_dev_put(dev);
-               return ret;
-       }
-
-       return pci_vpd_write(dev, pos, count, buf);
+       return __pci_write_vpd(dev, pos, count, buf, true);
 }
 EXPORT_SYMBOL(pci_write_vpd);
 
+/* Same, but allow to access any address */
+ssize_t pci_write_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
+{
+       return __pci_write_vpd(dev, pos, count, buf, false);
+}
+EXPORT_SYMBOL(pci_write_vpd_any);
+
 int pci_vpd_find_ro_info_keyword(const void *buf, unsigned int len,
                                 const char *kw, unsigned int *size)
 {
index 91b3281..89c6a7c 100644 (file)
@@ -1352,6 +1352,8 @@ void pci_unlock_rescan_remove(void);
 /* Vital Product Data routines */
 ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
 ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
+ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
+ssize_t pci_write_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);