|
@@ -1681,27 +1681,41 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Translate a physical EEPROM address to virtual. The first 1K is accessed
|
|
|
- * through virtual addresses starting at 31K, the rest is accessed through
|
|
|
- * virtual addresses starting at 0. This mapping is correct only for PF0.
|
|
|
+/**
|
|
|
+ * eeprom_ptov - translate a physical EEPROM address to virtual
|
|
|
+ * @phys_addr: the physical EEPROM address
|
|
|
+ * @fn: the PCI function number
|
|
|
+ * @sz: size of function-specific area
|
|
|
+ *
|
|
|
+ * Translate a physical EEPROM address to virtual. The first 1K is
|
|
|
+ * accessed through virtual addresses starting at 31K, the rest is
|
|
|
+ * accessed through virtual addresses starting at 0.
|
|
|
+ *
|
|
|
+ * The mapping is as follows:
|
|
|
+ * [0..1K) -> [31K..32K)
|
|
|
+ * [1K..1K+A) -> [31K-A..31K)
|
|
|
+ * [1K+A..ES) -> [0..ES-A-1K)
|
|
|
+ *
|
|
|
+ * where A = @fn * @sz, and ES = EEPROM size.
|
|
|
*/
|
|
|
-static int eeprom_ptov(unsigned int phys_addr)
|
|
|
+static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
|
|
|
{
|
|
|
+ fn *= sz;
|
|
|
if (phys_addr < 1024)
|
|
|
return phys_addr + (31 << 10);
|
|
|
+ if (phys_addr < 1024 + fn)
|
|
|
+ return 31744 - fn + phys_addr - 1024;
|
|
|
if (phys_addr < EEPROMSIZE)
|
|
|
- return phys_addr - 1024;
|
|
|
+ return phys_addr - 1024 - fn;
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* The next two routines implement eeprom read/write from physical addresses.
|
|
|
- * The physical->virtual translation is correct only for PF0.
|
|
|
*/
|
|
|
static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
|
|
|
{
|
|
|
- int vaddr = eeprom_ptov(phys_addr);
|
|
|
+ int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
|
|
|
|
|
|
if (vaddr >= 0)
|
|
|
vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
|
|
@@ -1710,7 +1724,7 @@ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
|
|
|
|
|
|
static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
|
|
|
{
|
|
|
- int vaddr = eeprom_ptov(phys_addr);
|
|
|
+ int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
|
|
|
|
|
|
if (vaddr >= 0)
|
|
|
vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
|
|
@@ -1753,6 +1767,14 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
|
|
|
aligned_offset = eeprom->offset & ~3;
|
|
|
aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
|
|
|
|
|
|
+ if (adapter->fn > 0) {
|
|
|
+ u32 start = 1024 + adapter->fn * EEPROMPFSIZE;
|
|
|
+
|
|
|
+ if (aligned_offset < start ||
|
|
|
+ aligned_offset + aligned_len > start + EEPROMPFSIZE)
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+
|
|
|
if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
|
|
|
/*
|
|
|
* RMW possibly needed for first or last words.
|