aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorVernon Sauder <vernoninhand@gmail.com>2009-01-16 08:23:19 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-21 17:34:52 -0500
commit357fe2c6d2b12482abd1c3f24a086a2f507f03fc (patch)
tree441806c01d65670b98fa6a081dec248ec48f5cb3 /drivers/net
parent31e2b7bd21035cb3d7cd567dfdf4f82817c4f6fb (diff)
smc91x: enable ethtool EEPROM interface
Signed-off-by: Vernon Sauder <vsauder@inhand.com> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/smc91x.c116
-rw-r--r--drivers/net/smc91x.h10
2 files changed, 124 insertions, 2 deletions
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index b215a8d85e62..508e8da2f65f 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1643,6 +1643,117 @@ static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level)
1643 lp->msg_enable = level; 1643 lp->msg_enable = level;
1644} 1644}
1645 1645
1646static int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word)
1647{
1648 u16 ctl;
1649 struct smc_local *lp = netdev_priv(dev);
1650 void __iomem *ioaddr = lp->base;
1651
1652 spin_lock_irq(&lp->lock);
1653 /* load word into GP register */
1654 SMC_SELECT_BANK(lp, 1);
1655 SMC_SET_GP(lp, word);
1656 /* set the address to put the data in EEPROM */
1657 SMC_SELECT_BANK(lp, 2);
1658 SMC_SET_PTR(lp, addr);
1659 /* tell it to write */
1660 SMC_SELECT_BANK(lp, 1);
1661 ctl = SMC_GET_CTL(lp);
1662 SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_STORE));
1663 /* wait for it to finish */
1664 do {
1665 udelay(1);
1666 } while (SMC_GET_CTL(lp) & CTL_STORE);
1667 /* clean up */
1668 SMC_SET_CTL(lp, ctl);
1669 SMC_SELECT_BANK(lp, 2);
1670 spin_unlock_irq(&lp->lock);
1671 return 0;
1672}
1673
1674static int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word)
1675{
1676 u16 ctl;
1677 struct smc_local *lp = netdev_priv(dev);
1678 void __iomem *ioaddr = lp->base;
1679
1680 spin_lock_irq(&lp->lock);
1681 /* set the EEPROM address to get the data from */
1682 SMC_SELECT_BANK(lp, 2);
1683 SMC_SET_PTR(lp, addr | PTR_READ);
1684 /* tell it to load */
1685 SMC_SELECT_BANK(lp, 1);
1686 SMC_SET_GP(lp, 0xffff); /* init to known */
1687 ctl = SMC_GET_CTL(lp);
1688 SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_RELOAD));
1689 /* wait for it to finish */
1690 do {
1691 udelay(1);
1692 } while (SMC_GET_CTL(lp) & CTL_RELOAD);
1693 /* read word from GP register */
1694 *word = SMC_GET_GP(lp);
1695 /* clean up */
1696 SMC_SET_CTL(lp, ctl);
1697 SMC_SELECT_BANK(lp, 2);
1698 spin_unlock_irq(&lp->lock);
1699 return 0;
1700}
1701
1702static int smc_ethtool_geteeprom_len(struct net_device *dev)
1703{
1704 return 0x23 * 2;
1705}
1706
1707static int smc_ethtool_geteeprom(struct net_device *dev,
1708 struct ethtool_eeprom *eeprom, u8 *data)
1709{
1710 int i;
1711 int imax;
1712
1713 DBG(1, "Reading %d bytes at %d(0x%x)\n",
1714 eeprom->len, eeprom->offset, eeprom->offset);
1715 imax = smc_ethtool_geteeprom_len(dev);
1716 for (i = 0; i < eeprom->len; i += 2) {
1717 int ret;
1718 u16 wbuf;
1719 int offset = i + eeprom->offset;
1720 if (offset > imax)
1721 break;
1722 ret = smc_read_eeprom_word(dev, offset >> 1, &wbuf);
1723 if (ret != 0)
1724 return ret;
1725 DBG(2, "Read 0x%x from 0x%x\n", wbuf, offset >> 1);
1726 data[i] = (wbuf >> 8) & 0xff;
1727 data[i+1] = wbuf & 0xff;
1728 }
1729 return 0;
1730}
1731
1732static int smc_ethtool_seteeprom(struct net_device *dev,
1733 struct ethtool_eeprom *eeprom, u8 *data)
1734{
1735 int i;
1736 int imax;
1737
1738 DBG(1, "Writing %d bytes to %d(0x%x)\n",
1739 eeprom->len, eeprom->offset, eeprom->offset);
1740 imax = smc_ethtool_geteeprom_len(dev);
1741 for (i = 0; i < eeprom->len; i += 2) {
1742 int ret;
1743 u16 wbuf;
1744 int offset = i + eeprom->offset;
1745 if (offset > imax)
1746 break;
1747 wbuf = (data[i] << 8) | data[i + 1];
1748 DBG(2, "Writing 0x%x to 0x%x\n", wbuf, offset >> 1);
1749 ret = smc_write_eeprom_word(dev, offset >> 1, wbuf);
1750 if (ret != 0)
1751 return ret;
1752 }
1753 return 0;
1754}
1755
1756
1646static const struct ethtool_ops smc_ethtool_ops = { 1757static const struct ethtool_ops smc_ethtool_ops = {
1647 .get_settings = smc_ethtool_getsettings, 1758 .get_settings = smc_ethtool_getsettings,
1648 .set_settings = smc_ethtool_setsettings, 1759 .set_settings = smc_ethtool_setsettings,
@@ -1652,8 +1763,9 @@ static const struct ethtool_ops smc_ethtool_ops = {
1652 .set_msglevel = smc_ethtool_setmsglevel, 1763 .set_msglevel = smc_ethtool_setmsglevel,
1653 .nway_reset = smc_ethtool_nwayreset, 1764 .nway_reset = smc_ethtool_nwayreset,
1654 .get_link = ethtool_op_get_link, 1765 .get_link = ethtool_op_get_link,
1655// .get_eeprom = smc_ethtool_geteeprom, 1766 .get_eeprom_len = smc_ethtool_geteeprom_len,
1656// .set_eeprom = smc_ethtool_seteeprom, 1767 .get_eeprom = smc_ethtool_geteeprom,
1768 .set_eeprom = smc_ethtool_seteeprom,
1657}; 1769};
1658 1770
1659/* 1771/*
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index c4ccd121bc9c..ed9ae43523a1 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -1141,6 +1141,16 @@ static const char * chip_ids[ 16 ] = {
1141 1141
1142#define SMC_GET_MII(lp) SMC_inw(ioaddr, MII_REG(lp)) 1142#define SMC_GET_MII(lp) SMC_inw(ioaddr, MII_REG(lp))
1143 1143
1144#define SMC_GET_GP(lp) SMC_inw(ioaddr, GP_REG(lp))
1145
1146#define SMC_SET_GP(lp, x) \
1147 do { \
1148 if (SMC_MUST_ALIGN_WRITE(lp)) \
1149 SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 1)); \
1150 else \
1151 SMC_outw(x, ioaddr, GP_REG(lp)); \
1152 } while (0)
1153
1144#define SMC_SET_MII(lp, x) SMC_outw(x, ioaddr, MII_REG(lp)) 1154#define SMC_SET_MII(lp, x) SMC_outw(x, ioaddr, MII_REG(lp))
1145 1155
1146#define SMC_GET_MIR(lp) SMC_inw(ioaddr, MIR_REG(lp)) 1156#define SMC_GET_MIR(lp) SMC_inw(ioaddr, MIR_REG(lp))