diff options
author | Vernon Sauder <vernoninhand@gmail.com> | 2009-01-16 08:23:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-21 17:34:52 -0500 |
commit | 357fe2c6d2b12482abd1c3f24a086a2f507f03fc (patch) | |
tree | 441806c01d65670b98fa6a081dec248ec48f5cb3 /drivers/net | |
parent | 31e2b7bd21035cb3d7cd567dfdf4f82817c4f6fb (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.c | 116 | ||||
-rw-r--r-- | drivers/net/smc91x.h | 10 |
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 | ||
1646 | static 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 | |||
1674 | static 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 | |||
1702 | static int smc_ethtool_geteeprom_len(struct net_device *dev) | ||
1703 | { | ||
1704 | return 0x23 * 2; | ||
1705 | } | ||
1706 | |||
1707 | static 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 | |||
1732 | static 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 | |||
1646 | static const struct ethtool_ops smc_ethtool_ops = { | 1757 | static 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)) |