Commit 10d0f97f authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/vpd'

- 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()
parents 7aae9412 78b5d5c9
...@@ -676,8 +676,6 @@ void t3_link_changed(struct adapter *adapter, int port_id); ...@@ -676,8 +676,6 @@ void t3_link_changed(struct adapter *adapter, int port_id);
void t3_link_fault(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); 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); 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_seeprom_wp(struct adapter *adapter, int enable);
int t3_get_tp_version(struct adapter *adapter, u32 *vers); int t3_get_tp_version(struct adapter *adapter, u32 *vers);
int t3_check_tpsram_version(struct adapter *adapter); int t3_check_tpsram_version(struct adapter *adapter);
......
...@@ -2036,20 +2036,16 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, ...@@ -2036,20 +2036,16 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
{ {
struct port_info *pi = netdev_priv(dev); struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter; struct adapter *adapter = pi->adapter;
int i, err = 0; int cnt;
u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
e->magic = EEPROM_MAGIC; e->magic = EEPROM_MAGIC;
for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) cnt = pci_read_vpd(adapter->pdev, e->offset, e->len, data);
err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]); if (cnt < 0)
return cnt;
if (!err) e->len = cnt;
memcpy(data, buf + e->offset, e->len);
kfree(buf); return 0;
return err;
} }
static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 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, ...@@ -2058,7 +2054,6 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
struct port_info *pi = netdev_priv(dev); struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter; struct adapter *adapter = pi->adapter;
u32 aligned_offset, aligned_len; u32 aligned_offset, aligned_len;
__le32 *p;
u8 *buf; u8 *buf;
int err; int err;
...@@ -2072,12 +2067,9 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, ...@@ -2072,12 +2067,9 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
buf = kmalloc(aligned_len, GFP_KERNEL); buf = kmalloc(aligned_len, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf); err = pci_read_vpd(adapter->pdev, aligned_offset, aligned_len,
if (!err && aligned_len > 4) buf);
err = t3_seeprom_read(adapter, if (err < 0)
aligned_offset + aligned_len - 4,
(__le32 *) & buf[aligned_len - 4]);
if (err)
goto out; goto out;
memcpy(buf + (eeprom->offset & 3), data, eeprom->len); memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
} else } else
...@@ -2087,17 +2079,13 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, ...@@ -2087,17 +2079,13 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
if (err) if (err)
goto out; goto out;
for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) { err = pci_write_vpd(adapter->pdev, aligned_offset, aligned_len, buf);
err = t3_seeprom_write(adapter, aligned_offset, *p); if (err >= 0)
aligned_offset += 4;
}
if (!err)
err = t3_seeprom_wp(adapter, 1); err = t3_seeprom_wp(adapter, 1);
out: out:
if (buf != data) if (buf != data)
kfree(buf); kfree(buf);
return err; return err < 0 ? err : 0;
} }
static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
......
...@@ -595,80 +595,9 @@ struct t3_vpd { ...@@ -595,80 +595,9 @@ struct t3_vpd {
u32 pad; /* for multiple-of-4 sizing and alignment */ u32 pad; /* for multiple-of-4 sizing and alignment */
}; };
#define EEPROM_MAX_POLL 40
#define EEPROM_STAT_ADDR 0x4000 #define EEPROM_STAT_ADDR 0x4000
#define VPD_BASE 0xc00 #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 * t3_seeprom_wp - enable/disable EEPROM write protection
* @adapter: the adapter * @adapter: the adapter
...@@ -678,7 +607,14 @@ int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data) ...@@ -678,7 +607,14 @@ int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
*/ */
int t3_seeprom_wp(struct adapter *adapter, int enable) 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) 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) ...@@ -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) static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{ {
int i, addr, ret;
struct t3_vpd vpd; struct t3_vpd vpd;
u8 base_val = 0;
int addr, ret;
/* /*
* Card information is normally at VPD_BASE but some early cards had * Card information is normally at VPD_BASE but some early cards had
* it at 0. * it at 0.
*/ */
ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd); ret = pci_read_vpd(adapter->pdev, VPD_BASE, 1, &base_val);
if (ret) if (ret < 0)
return ret; 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 = pci_read_vpd(adapter->pdev, addr, sizeof(vpd), &vpd);
ret = t3_seeprom_read(adapter, addr + i, if (ret < 0)
(__le32 *)((u8 *)&vpd + i)); return ret;
if (ret)
return ret;
}
ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk); ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
if (ret) if (ret)
......
...@@ -57,10 +57,7 @@ static size_t pci_vpd_size(struct pci_dev *dev) ...@@ -57,10 +57,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
size_t off = 0, size; size_t off = 0, size;
unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */ unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */
/* Otherwise the following reads would fail. */ while (pci_read_vpd_any(dev, off, 1, header) == 1) {
dev->vpd.len = PCI_VPD_MAX_SIZE;
while (pci_read_vpd(dev, off, 1, header) == 1) {
size = 0; size = 0;
if (off == 0 && (header[0] == 0x00 || header[0] == 0xff)) if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
...@@ -68,7 +65,7 @@ static size_t pci_vpd_size(struct pci_dev *dev) ...@@ -68,7 +65,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
if (header[0] & PCI_VPD_LRDT) { if (header[0] & PCI_VPD_LRDT) {
/* Large Resource Data Type Tag */ /* 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", pci_warn(dev, "failed VPD read at offset %zu\n",
off + 1); off + 1);
return off ?: PCI_VPD_SZ_INVALID; return off ?: PCI_VPD_SZ_INVALID;
...@@ -99,14 +96,14 @@ static size_t pci_vpd_size(struct pci_dev *dev) ...@@ -99,14 +96,14 @@ static size_t pci_vpd_size(struct pci_dev *dev)
return off ?: PCI_VPD_SZ_INVALID; 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; struct pci_vpd *vpd = &dev->vpd;
if (!vpd->cap) if (!vpd->cap)
return false; return false;
if (vpd->len == 0) { if (vpd->len == 0 && check_size) {
vpd->len = pci_vpd_size(dev); vpd->len = pci_vpd_size(dev);
if (vpd->len == PCI_VPD_SZ_INVALID) { if (vpd->len == PCI_VPD_SZ_INVALID) {
vpd->cap = 0; vpd->cap = 0;
...@@ -156,24 +153,27 @@ static int pci_vpd_wait(struct pci_dev *dev, bool set) ...@@ -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, 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; struct pci_vpd *vpd = &dev->vpd;
unsigned int max_len;
int ret = 0; int ret = 0;
loff_t end = pos + count; loff_t end = pos + count;
u8 *buf = arg; u8 *buf = arg;
if (!pci_vpd_available(dev)) if (!pci_vpd_available(dev, check_size))
return -ENODEV; return -ENODEV;
if (pos < 0) if (pos < 0)
return -EINVAL; return -EINVAL;
if (pos > vpd->len) max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
if (pos >= max_len)
return 0; return 0;
if (end > vpd->len) { if (end > max_len) {
end = vpd->len; end = max_len;
count = end - pos; count = end - pos;
} }
...@@ -217,20 +217,23 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count, ...@@ -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, 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; struct pci_vpd *vpd = &dev->vpd;
unsigned int max_len;
const u8 *buf = arg; const u8 *buf = arg;
loff_t end = pos + count; loff_t end = pos + count;
int ret = 0; int ret = 0;
if (!pci_vpd_available(dev)) if (!pci_vpd_available(dev, check_size))
return -ENODEV; return -ENODEV;
if (pos < 0 || (pos & 3) || (count & 3)) if (pos < 0 || (pos & 3) || (count & 3))
return -EINVAL; return -EINVAL;
if (end > vpd->len) max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
if (end > max_len)
return -EINVAL; return -EINVAL;
if (mutex_lock_killable(&vpd->lock)) if (mutex_lock_killable(&vpd->lock))
...@@ -313,7 +316,7 @@ void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size) ...@@ -313,7 +316,7 @@ void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size)
void *buf; void *buf;
int cnt; int cnt;
if (!pci_vpd_available(dev)) if (!pci_vpd_available(dev, true))
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
len = dev->vpd.len; len = dev->vpd.len;
...@@ -381,6 +384,24 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, ...@@ -381,6 +384,24 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
return -ENOENT; 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 * pci_read_vpd - Read one entry from Vital Product Data
* @dev: PCI device struct * @dev: PCI device struct
...@@ -389,6 +410,20 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, ...@@ -389,6 +410,20 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
* @buf: pointer to where to store result * @buf: pointer to where to store result
*/ */
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) 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; ssize_t ret;
...@@ -397,14 +432,13 @@ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) ...@@ -397,14 +432,13 @@ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
ret = pci_vpd_read(dev, pos, count, buf); ret = pci_vpd_write(dev, pos, count, buf, check_size);
pci_dev_put(dev); pci_dev_put(dev);
return ret; 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 * pci_write_vpd - Write entry to Vital Product Data
...@@ -415,22 +449,17 @@ EXPORT_SYMBOL(pci_read_vpd); ...@@ -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 pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
{ {
ssize_t ret; return __pci_write_vpd(dev, pos, count, buf, true);
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);
} }
EXPORT_SYMBOL(pci_write_vpd); 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, int pci_vpd_find_ro_info_keyword(const void *buf, unsigned int len,
const char *kw, unsigned int *size) const char *kw, unsigned int *size)
{ {
......
...@@ -1352,6 +1352,8 @@ void pci_unlock_rescan_remove(void); ...@@ -1352,6 +1352,8 @@ void pci_unlock_rescan_remove(void);
/* Vital Product Data routines */ /* Vital Product Data routines */
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); 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_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) */ /* 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); resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment