skge: eeprom support
authorStephen Hemminger <shemminger@linux-foundation.org>
Tue, 16 Oct 2007 19:15:53 +0000 (12:15 -0700)
committerJeff Garzik <jeff@garzik.org>
Wed, 17 Oct 2007 01:10:28 +0000 (21:10 -0400)
Add ability to read/write EEPROM

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/skge.c
drivers/net/skge.h

index a439d4304458da12ba0779c9f8ab666fe5d1a517..953f8023f24cfc1d07ab19c7815631219a68e7a7 100644 (file)
@@ -59,6 +59,9 @@
 #define BLINK_MS               250
 #define LINK_HZ                        HZ
 
+#define SKGE_EEPROM_MAGIC      0x9933aabb
+
+
 MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
 MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
 MODULE_LICENSE("GPL");
@@ -798,6 +801,98 @@ static int skge_phys_id(struct net_device *dev, u32 data)
        return 0;
 }
 
+static int skge_get_eeprom_len(struct net_device *dev)
+{
+       struct skge_port *skge = netdev_priv(dev);
+       u32 reg2;
+
+       pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, &reg2);
+       return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
+}
+
+static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
+{
+       u32 val;
+
+       pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
+
+       do {
+               pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+       } while (!(offset & PCI_VPD_ADDR_F));
+
+       pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+       return val;
+}
+
+static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
+{
+       pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val);
+       pci_write_config_word(pdev, cap + PCI_VPD_ADDR,
+                             offset | PCI_VPD_ADDR_F);
+
+       do {
+               pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+       } while (offset & PCI_VPD_ADDR_F);
+}
+
+static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                          u8 *data)
+{
+       struct skge_port *skge = netdev_priv(dev);
+       struct pci_dev *pdev = skge->hw->pdev;
+       int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+       int length = eeprom->len;
+       u16 offset = eeprom->offset;
+
+       if (!cap)
+               return -EINVAL;
+
+       eeprom->magic = SKGE_EEPROM_MAGIC;
+
+       while (length > 0) {
+               u32 val = skge_vpd_read(pdev, cap, offset);
+               int n = min_t(int, length, sizeof(val));
+
+               memcpy(data, &val, n);
+               length -= n;
+               data += n;
+               offset += n;
+       }
+       return 0;
+}
+
+static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                          u8 *data)
+{
+       struct skge_port *skge = netdev_priv(dev);
+       struct pci_dev *pdev = skge->hw->pdev;
+       int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+       int length = eeprom->len;
+       u16 offset = eeprom->offset;
+
+       if (!cap)
+               return -EINVAL;
+
+       if (eeprom->magic != SKGE_EEPROM_MAGIC)
+               return -EINVAL;
+
+       while (length > 0) {
+               u32 val;
+               int n = min_t(int, length, sizeof(val));
+
+               if (n < sizeof(val))
+                       val = skge_vpd_read(pdev, cap, offset);
+               memcpy(&val, data, n);
+
+               skge_vpd_write(pdev, cap, offset, val);
+
+               length -= n;
+               data += n;
+               offset += n;
+       }
+       return 0;
+}
+
 static const struct ethtool_ops skge_ethtool_ops = {
        .get_settings   = skge_get_settings,
        .set_settings   = skge_set_settings,
@@ -810,6 +905,9 @@ static const struct ethtool_ops skge_ethtool_ops = {
        .set_msglevel   = skge_set_msglevel,
        .nway_reset     = skge_nway_reset,
        .get_link       = ethtool_op_get_link,
+       .get_eeprom_len = skge_get_eeprom_len,
+       .get_eeprom     = skge_get_eeprom,
+       .set_eeprom     = skge_set_eeprom,
        .get_ringparam  = skge_get_ring_param,
        .set_ringparam  = skge_set_ring_param,
        .get_pauseparam = skge_get_pauseparam,
index 800329d99b214e57ee0ec6ef2fb25084fd28995d..51754246d59d4e0698870b3deb4e85f81166c40b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Definitions for the new Marvell Yukon / SysKonenct driver.
+ * Definitions for the new Marvell Yukon / SysKonnect driver.
  */
 #ifndef _SKGE_H
 #define _SKGE_H
@@ -8,8 +8,10 @@
 #define PCI_DEV_REG1   0x40
 #define  PCI_PHY_COMA  0x8000000
 #define  PCI_VIO       0x2000000
+
 #define PCI_DEV_REG2   0x44
-#define  PCI_REV_DESC   0x4
+#define  PCI_VPD_ROM_SZ        7L<<14  /* VPD ROM size 0=256, 1=512, ... */
+#define  PCI_REV_DESC  1<<2    /* Reverse Descriptor bytes */
 
 #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
                               PCI_STATUS_SIG_SYSTEM_ERROR | \