aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorPhilip Craig <philipc@snapgear.com>2006-06-20 21:33:27 -0400
committerJeff Garzik <jeff@garzik.org>2006-06-22 23:20:29 -0400
commit722fdb33591bc7308a661913fb2f829128236b6f (patch)
tree6b8612e0f72f1ae26adb7d7f07a60e5f1a8bdf60 /drivers/net
parentd73f1e3c3b0703e25728ce5bdda9806d6f2c576f (diff)
[PATCH] 8139cp: add ethtool eeprom support
Implement the ethtool eeprom operations for the 8139cp driver. Tested on x86 and big-endian ARM. Signed-off-by: Philip Craig <philipc@snapgear.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/8139cp.c179
1 files changed, 167 insertions, 12 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index b49be8f2c107..a26077a175ad 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -401,6 +401,11 @@ static void cp_clean_rings (struct cp_private *cp);
401#ifdef CONFIG_NET_POLL_CONTROLLER 401#ifdef CONFIG_NET_POLL_CONTROLLER
402static void cp_poll_controller(struct net_device *dev); 402static void cp_poll_controller(struct net_device *dev);
403#endif 403#endif
404static int cp_get_eeprom_len(struct net_device *dev);
405static int cp_get_eeprom(struct net_device *dev,
406 struct ethtool_eeprom *eeprom, u8 *data);
407static int cp_set_eeprom(struct net_device *dev,
408 struct ethtool_eeprom *eeprom, u8 *data);
404 409
405static struct pci_device_id cp_pci_tbl[] = { 410static struct pci_device_id cp_pci_tbl[] = {
406 { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, 411 { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
@@ -1577,6 +1582,9 @@ static struct ethtool_ops cp_ethtool_ops = {
1577 .get_strings = cp_get_strings, 1582 .get_strings = cp_get_strings,
1578 .get_ethtool_stats = cp_get_ethtool_stats, 1583 .get_ethtool_stats = cp_get_ethtool_stats,
1579 .get_perm_addr = ethtool_op_get_perm_addr, 1584 .get_perm_addr = ethtool_op_get_perm_addr,
1585 .get_eeprom_len = cp_get_eeprom_len,
1586 .get_eeprom = cp_get_eeprom,
1587 .set_eeprom = cp_set_eeprom,
1580}; 1588};
1581 1589
1582static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) 1590static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1612,24 +1620,32 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
1612#define eeprom_delay() readl(ee_addr) 1620#define eeprom_delay() readl(ee_addr)
1613 1621
1614/* The EEPROM commands include the alway-set leading bit. */ 1622/* The EEPROM commands include the alway-set leading bit. */
1623#define EE_EXTEND_CMD (4)
1615#define EE_WRITE_CMD (5) 1624#define EE_WRITE_CMD (5)
1616#define EE_READ_CMD (6) 1625#define EE_READ_CMD (6)
1617#define EE_ERASE_CMD (7) 1626#define EE_ERASE_CMD (7)
1618 1627
1619static int read_eeprom (void __iomem *ioaddr, int location, int addr_len) 1628#define EE_EWDS_ADDR (0)
1620{ 1629#define EE_WRAL_ADDR (1)
1621 int i; 1630#define EE_ERAL_ADDR (2)
1622 unsigned retval = 0; 1631#define EE_EWEN_ADDR (3)
1623 void __iomem *ee_addr = ioaddr + Cfg9346; 1632
1624 int read_cmd = location | (EE_READ_CMD << addr_len); 1633#define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139
1625 1634
1635static void eeprom_cmd_start(void __iomem *ee_addr)
1636{
1626 writeb (EE_ENB & ~EE_CS, ee_addr); 1637 writeb (EE_ENB & ~EE_CS, ee_addr);
1627 writeb (EE_ENB, ee_addr); 1638 writeb (EE_ENB, ee_addr);
1628 eeprom_delay (); 1639 eeprom_delay ();
1640}
1629 1641
1630 /* Shift the read command bits out. */ 1642static void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len)
1631 for (i = 3 + addr_len - 1; i >= 0; i--) { 1643{
1632 int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; 1644 int i;
1645
1646 /* Shift the command bits out. */
1647 for (i = cmd_len - 1; i >= 0; i--) {
1648 int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
1633 writeb (EE_ENB | dataval, ee_addr); 1649 writeb (EE_ENB | dataval, ee_addr);
1634 eeprom_delay (); 1650 eeprom_delay ();
1635 writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); 1651 writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
@@ -1637,6 +1653,33 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
1637 } 1653 }
1638 writeb (EE_ENB, ee_addr); 1654 writeb (EE_ENB, ee_addr);
1639 eeprom_delay (); 1655 eeprom_delay ();
1656}
1657
1658static void eeprom_cmd_end(void __iomem *ee_addr)
1659{
1660 writeb (~EE_CS, ee_addr);
1661 eeprom_delay ();
1662}
1663
1664static void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd,
1665 int addr_len)
1666{
1667 int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2));
1668
1669 eeprom_cmd_start(ee_addr);
1670 eeprom_cmd(ee_addr, cmd, 3 + addr_len);
1671 eeprom_cmd_end(ee_addr);
1672}
1673
1674static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len)
1675{
1676 int i;
1677 u16 retval = 0;
1678 void __iomem *ee_addr = ioaddr + Cfg9346;
1679 int read_cmd = location | (EE_READ_CMD << addr_len);
1680
1681 eeprom_cmd_start(ee_addr);
1682 eeprom_cmd(ee_addr, read_cmd, 3 + addr_len);
1640 1683
1641 for (i = 16; i > 0; i--) { 1684 for (i = 16; i > 0; i--) {
1642 writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); 1685 writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
@@ -1648,13 +1691,125 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
1648 eeprom_delay (); 1691 eeprom_delay ();
1649 } 1692 }
1650 1693
1651 /* Terminate the EEPROM access. */ 1694 eeprom_cmd_end(ee_addr);
1652 writeb (~EE_CS, ee_addr);
1653 eeprom_delay ();
1654 1695
1655 return retval; 1696 return retval;
1656} 1697}
1657 1698
1699static void write_eeprom(void __iomem *ioaddr, int location, u16 val,
1700 int addr_len)
1701{
1702 int i;
1703 void __iomem *ee_addr = ioaddr + Cfg9346;
1704 int write_cmd = location | (EE_WRITE_CMD << addr_len);
1705
1706 eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len);
1707
1708 eeprom_cmd_start(ee_addr);
1709 eeprom_cmd(ee_addr, write_cmd, 3 + addr_len);
1710 eeprom_cmd(ee_addr, val, 16);
1711 eeprom_cmd_end(ee_addr);
1712
1713 eeprom_cmd_start(ee_addr);
1714 for (i = 0; i < 20000; i++)
1715 if (readb(ee_addr) & EE_DATA_READ)
1716 break;
1717 eeprom_cmd_end(ee_addr);
1718
1719 eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len);
1720}
1721
1722static int cp_get_eeprom_len(struct net_device *dev)
1723{
1724 struct cp_private *cp = netdev_priv(dev);
1725 int size;
1726
1727 spin_lock_irq(&cp->lock);
1728 size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128;
1729 spin_unlock_irq(&cp->lock);
1730
1731 return size;
1732}
1733
1734static int cp_get_eeprom(struct net_device *dev,
1735 struct ethtool_eeprom *eeprom, u8 *data)
1736{
1737 struct cp_private *cp = netdev_priv(dev);
1738 unsigned int addr_len;
1739 u16 val;
1740 u32 offset = eeprom->offset >> 1;
1741 u32 len = eeprom->len;
1742 u32 i = 0;
1743
1744 eeprom->magic = CP_EEPROM_MAGIC;
1745
1746 spin_lock_irq(&cp->lock);
1747
1748 addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
1749
1750 if (eeprom->offset & 1) {
1751 val = read_eeprom(cp->regs, offset, addr_len);
1752 data[i++] = (u8)(val >> 8);
1753 offset++;
1754 }
1755
1756 while (i < len - 1) {
1757 val = read_eeprom(cp->regs, offset, addr_len);
1758 data[i++] = (u8)val;
1759 data[i++] = (u8)(val >> 8);
1760 offset++;
1761 }
1762
1763 if (i < len) {
1764 val = read_eeprom(cp->regs, offset, addr_len);
1765 data[i] = (u8)val;
1766 }
1767
1768 spin_unlock_irq(&cp->lock);
1769 return 0;
1770}
1771
1772static int cp_set_eeprom(struct net_device *dev,
1773 struct ethtool_eeprom *eeprom, u8 *data)
1774{
1775 struct cp_private *cp = netdev_priv(dev);
1776 unsigned int addr_len;
1777 u16 val;
1778 u32 offset = eeprom->offset >> 1;
1779 u32 len = eeprom->len;
1780 u32 i = 0;
1781
1782 if (eeprom->magic != CP_EEPROM_MAGIC)
1783 return -EINVAL;
1784
1785 spin_lock_irq(&cp->lock);
1786
1787 addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
1788
1789 if (eeprom->offset & 1) {
1790 val = read_eeprom(cp->regs, offset, addr_len) & 0xff;
1791 val |= (u16)data[i++] << 8;
1792 write_eeprom(cp->regs, offset, val, addr_len);
1793 offset++;
1794 }
1795
1796 while (i < len - 1) {
1797 val = (u16)data[i++];
1798 val |= (u16)data[i++] << 8;
1799 write_eeprom(cp->regs, offset, val, addr_len);
1800 offset++;
1801 }
1802
1803 if (i < len) {
1804 val = read_eeprom(cp->regs, offset, addr_len) & 0xff00;
1805 val |= (u16)data[i];
1806 write_eeprom(cp->regs, offset, val, addr_len);
1807 }
1808
1809 spin_unlock_irq(&cp->lock);
1810 return 0;
1811}
1812
1658/* Put the board into D3cold state and wait for WakeUp signal */ 1813/* Put the board into D3cold state and wait for WakeUp signal */
1659static void cp_set_d3_state (struct cp_private *cp) 1814static void cp_set_d3_state (struct cp_private *cp)
1660{ 1815{