GIT 35583f73c45763931d01543c089a27dd51bcc3ae master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git#smc91x-eeprom --- Index: drivers/net/smc91x.c =================================================================== --- 3e84d1d21b77d739af7bca35a0da7ef481f7e6d6/drivers/net/smc91x.c (mode:100644) +++ 425d7be63270056d62d3d561048c48e992f91d87/drivers/net/smc91x.c (mode:100644) @@ -1722,6 +1722,160 @@ lp->msg_enable = level; } +/* + * Must be called with lp->lock locked. Caller must select bank 2 again. + */ +static int smc_read_eeprom_reg(void __iomem *ioaddr, unsigned int reg) +{ + unsigned int timeout; + + SMC_SELECT_BANK(2); + SMC_SET_PTR(reg); + + SMC_SELECT_BANK(1); + SMC_SET_CTL(SMC_GET_CTL() | CTL_EEPROM_SELECT | CTL_RELOAD); + timeout = 100; + while ((SMC_GET_CTL() & CTL_RELOAD) && --timeout) + udelay(100); + if (timeout == 0) { + printk(KERN_INFO "%s: timeout reading EEPROM register %02x\n", + CARDNAME, reg); + return -EIO; + } + + return SMC_GET_GP(); +} + +/* + * Must be called with lp->lock locked. Caller must select bank 2 again. + */ +static int smc_write_eeprom_reg(void __iomem *ioaddr, unsigned int reg, + unsigned int val) +{ + unsigned int timeout; + + SMC_SELECT_BANK(2); + SMC_SET_PTR(reg); + + SMC_SELECT_BANK(1); + SMC_SET_GP(val); + SMC_SET_CTL(SMC_GET_CTL() | CTL_EEPROM_SELECT | CTL_STORE); + timeout = 100; + while ((SMC_GET_CTL() & CTL_STORE) && --timeout) + udelay(100); + if (timeout == 0) { + printk(KERN_INFO "%s: timeout writing EEPROM register %02x\n", + CARDNAME, reg); + return -EIO; + } + + return 0; +} + +static int smc_ethtool_geteepromlen(struct net_device *dev) +{ + return SMC_EEPROM_SIZE; +} + +static int smc_ethtool_geteeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + + struct smc_local *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + unsigned reg; + int ret, len; + + len = eeprom->len; + reg = eeprom->offset >> 1; + eeprom->len = 0; + eeprom->magic = SMC_EEPROM_MAGIC; + + spin_lock_irq(&lp->lock); + + if (eeprom->offset & 1) { + ret = smc_read_eeprom_reg(ioaddr, reg++); + if (ret < 0) + goto out; + *data++ = ret >> 8; + eeprom->len++; + len--; + } + while (len) { + len -= 2; + ret = smc_read_eeprom_reg(ioaddr, reg++); + if (ret < 0) + goto out; + *data++ = ret & 0xff; + if (len < 0) { + eeprom->len++; + break; + } + *data++ = ret >> 8; + eeprom->len += 2; + } + + ret = 0; +out: + SMC_SELECT_BANK(2); + spin_unlock_irq(&lp->lock); + + return ret; +} + +static int smc_ethtool_seteeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smc_local *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + unsigned reg; + int ret, len; + + if (eeprom->magic != SMC_EEPROM_MAGIC) + return -EINVAL; + + reg = eeprom->offset >> 1; + len = eeprom->len; + + spin_lock_irq(&lp->lock); + + if (eeprom->offset & 1) { + ret = smc_read_eeprom_reg(ioaddr, reg); + if (ret < 0) + goto out; + ret = (ret & 0xff) | ((int)*data++ << 8); + ret = smc_write_eeprom_reg(ioaddr, reg++, ret); + if (ret < 0) + goto out; + len--; + } + while (len) { + len -= 2; + if (len < 0) { + ret = smc_read_eeprom_reg(ioaddr, reg); + if (ret < 0) + goto out; + ret = (ret & 0xff) | *data; + ret = smc_write_eeprom_reg(ioaddr, reg, ret); + if (ret < 0) + goto out; + break; + } + ret = *data++; + ret |= (int)*data++ << 8; + ret = smc_write_eeprom_reg(ioaddr, reg++, ret); + if (ret < 0) + goto out; + } + + ret = 0; +out: + SMC_SELECT_BANK(2); + spin_unlock_irq(&lp->lock); + + return ret; +} + static struct ethtool_ops smc_ethtool_ops = { .get_settings = smc_ethtool_getsettings, .set_settings = smc_ethtool_setsettings, @@ -1731,8 +1885,9 @@ .set_msglevel = smc_ethtool_setmsglevel, .nway_reset = smc_ethtool_nwayreset, .get_link = ethtool_op_get_link, -// .get_eeprom = smc_ethtool_geteeprom, -// .set_eeprom = smc_ethtool_seteeprom, + .get_eeprom_len = smc_ethtool_geteepromlen, + .get_eeprom = smc_ethtool_geteeprom, + .set_eeprom = smc_ethtool_seteeprom, }; /* Index: drivers/net/smc91x.h =================================================================== --- 3e84d1d21b77d739af7bca35a0da7ef481f7e6d6/drivers/net/smc91x.h (mode:100644) +++ 425d7be63270056d62d3d561048c48e992f91d87/drivers/net/smc91x.h (mode:100644) @@ -404,6 +404,13 @@ #define SMC_DATA_EXTENT (4) /* + * 128 bytes serial EEPROM + */ +#define SMC_EEPROM_SIZE 128 + +#define SMC_EEPROM_MAGIC 0x3A8EBEEF + +/* . Bank Select Register: . . yyyy yyyy 0000 00xx @@ -834,6 +841,8 @@ #define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG ) #define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG ) #define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG ) +#define SMC_GET_GP() SMC_inw( ioaddr, GP_REG ) +#define SMC_SET_GP(x) SMC_outw( x, ioaddr, GP_REG ) #define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG ) #define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG ) #define SMC_GET_MII() SMC_inw( ioaddr, MII_REG )