diff options
author | Kou Ishizaki <kou.ishizaki@toshiba.co.jp> | 2007-02-20 17:33:41 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-27 04:16:02 -0500 |
commit | abdb66b566fce5641c90100e0a113a94bab43fda (patch) | |
tree | a93d9d4063159353f0a1e765723ba462b2682446 | |
parent | d406eafee814c0e20af00a9a74f68f6993d8cb9c (diff) |
spidernet: autoneg support for Celleb
Add auto negotiation support for Celleb.
Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/spider_net.c | 176 | ||||
-rw-r--r-- | drivers/net/spider_net.h | 10 |
2 files changed, 170 insertions, 16 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index de2625411bff..8aa3ebe2a0ec 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c | |||
@@ -166,6 +166,41 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | /** | 168 | /** |
169 | * spider_net_setup_aneg - initial auto-negotiation setup | ||
170 | * @card: device structure | ||
171 | **/ | ||
172 | static void | ||
173 | spider_net_setup_aneg(struct spider_net_card *card) | ||
174 | { | ||
175 | struct mii_phy *phy = &card->phy; | ||
176 | u32 advertise = 0; | ||
177 | u16 bmcr, bmsr, stat1000, estat; | ||
178 | |||
179 | bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR); | ||
180 | bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); | ||
181 | stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000); | ||
182 | estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS); | ||
183 | |||
184 | if (bmsr & BMSR_10HALF) | ||
185 | advertise |= ADVERTISED_10baseT_Half; | ||
186 | if (bmsr & BMSR_10FULL) | ||
187 | advertise |= ADVERTISED_10baseT_Full; | ||
188 | if (bmsr & BMSR_100HALF) | ||
189 | advertise |= ADVERTISED_100baseT_Half; | ||
190 | if (bmsr & BMSR_100FULL) | ||
191 | advertise |= ADVERTISED_100baseT_Full; | ||
192 | |||
193 | if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL)) | ||
194 | advertise |= SUPPORTED_1000baseT_Full; | ||
195 | if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF)) | ||
196 | advertise |= SUPPORTED_1000baseT_Half; | ||
197 | |||
198 | mii_phy_probe(phy, phy->mii_id); | ||
199 | phy->def->ops->setup_aneg(phy, advertise); | ||
200 | |||
201 | } | ||
202 | |||
203 | /** | ||
169 | * spider_net_rx_irq_off - switch off rx irq on this spider card | 204 | * spider_net_rx_irq_off - switch off rx irq on this spider card |
170 | * @card: device structure | 205 | * @card: device structure |
171 | * | 206 | * |
@@ -1248,6 +1283,33 @@ spider_net_set_mac(struct net_device *netdev, void *p) | |||
1248 | } | 1283 | } |
1249 | 1284 | ||
1250 | /** | 1285 | /** |
1286 | * spider_net_link_reset | ||
1287 | * @netdev: net device structure | ||
1288 | * | ||
1289 | * This is called when the PHY_LINK signal is asserted. For the blade this is | ||
1290 | * not connected so we should never get here. | ||
1291 | * | ||
1292 | */ | ||
1293 | static void | ||
1294 | spider_net_link_reset(struct net_device *netdev) | ||
1295 | { | ||
1296 | |||
1297 | struct spider_net_card *card = netdev_priv(netdev); | ||
1298 | |||
1299 | del_timer_sync(&card->aneg_timer); | ||
1300 | |||
1301 | /* clear interrupt, block further interrupts */ | ||
1302 | spider_net_write_reg(card, SPIDER_NET_GMACST, | ||
1303 | spider_net_read_reg(card, SPIDER_NET_GMACST)); | ||
1304 | spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); | ||
1305 | |||
1306 | /* reset phy and setup aneg */ | ||
1307 | spider_net_setup_aneg(card); | ||
1308 | mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); | ||
1309 | |||
1310 | } | ||
1311 | |||
1312 | /** | ||
1251 | * spider_net_handle_error_irq - handles errors raised by an interrupt | 1313 | * spider_net_handle_error_irq - handles errors raised by an interrupt |
1252 | * @card: card structure | 1314 | * @card: card structure |
1253 | * @status_reg: interrupt status register 0 (GHIINT0STS) | 1315 | * @status_reg: interrupt status register 0 (GHIINT0STS) |
@@ -1500,6 +1562,9 @@ spider_net_interrupt(int irq, void *ptr) | |||
1500 | if (status_reg & SPIDER_NET_TXINT) | 1562 | if (status_reg & SPIDER_NET_TXINT) |
1501 | netif_rx_schedule(netdev); | 1563 | netif_rx_schedule(netdev); |
1502 | 1564 | ||
1565 | if (status_reg & SPIDER_NET_LINKINT) | ||
1566 | spider_net_link_reset(netdev); | ||
1567 | |||
1503 | if (status_reg & SPIDER_NET_ERRINT ) | 1568 | if (status_reg & SPIDER_NET_ERRINT ) |
1504 | spider_net_handle_error_irq(card, status_reg); | 1569 | spider_net_handle_error_irq(card, status_reg); |
1505 | 1570 | ||
@@ -1624,8 +1689,6 @@ spider_net_enable_card(struct spider_net_card *card) | |||
1624 | 1689 | ||
1625 | spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, | 1690 | spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, |
1626 | SPIDER_NET_LENLMT_VALUE); | 1691 | SPIDER_NET_LENLMT_VALUE); |
1627 | spider_net_write_reg(card, SPIDER_NET_GMACMODE, | ||
1628 | SPIDER_NET_MACMODE_VALUE); | ||
1629 | spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, | 1692 | spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, |
1630 | SPIDER_NET_OPMODE_VALUE); | 1693 | SPIDER_NET_OPMODE_VALUE); |
1631 | 1694 | ||
@@ -1656,6 +1719,11 @@ spider_net_open(struct net_device *netdev) | |||
1656 | struct spider_net_card *card = netdev_priv(netdev); | 1719 | struct spider_net_card *card = netdev_priv(netdev); |
1657 | int result; | 1720 | int result; |
1658 | 1721 | ||
1722 | /* start probing with copper */ | ||
1723 | spider_net_setup_aneg(card); | ||
1724 | if (card->phy.def->phy_id) | ||
1725 | mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); | ||
1726 | |||
1659 | result = spider_net_init_chain(card, &card->tx_chain); | 1727 | result = spider_net_init_chain(card, &card->tx_chain); |
1660 | if (result) | 1728 | if (result) |
1661 | goto alloc_tx_failed; | 1729 | goto alloc_tx_failed; |
@@ -1693,17 +1761,88 @@ alloc_skbs_failed: | |||
1693 | alloc_rx_failed: | 1761 | alloc_rx_failed: |
1694 | spider_net_free_chain(card, &card->tx_chain); | 1762 | spider_net_free_chain(card, &card->tx_chain); |
1695 | alloc_tx_failed: | 1763 | alloc_tx_failed: |
1764 | del_timer_sync(&card->aneg_timer); | ||
1696 | return result; | 1765 | return result; |
1697 | } | 1766 | } |
1698 | 1767 | ||
1699 | /** | 1768 | /** |
1769 | * spider_net_link_phy | ||
1770 | * @data: used for pointer to card structure | ||
1771 | * | ||
1772 | */ | ||
1773 | static void spider_net_link_phy(unsigned long data) | ||
1774 | { | ||
1775 | struct spider_net_card *card = (struct spider_net_card *)data; | ||
1776 | struct mii_phy *phy = &card->phy; | ||
1777 | |||
1778 | /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */ | ||
1779 | if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) { | ||
1780 | |||
1781 | pr_info("%s: link is down trying to bring it up\n", card->netdev->name); | ||
1782 | |||
1783 | switch (phy->medium) { | ||
1784 | case GMII_COPPER: | ||
1785 | /* enable fiber with autonegotiation first */ | ||
1786 | if (phy->def->ops->enable_fiber) | ||
1787 | phy->def->ops->enable_fiber(phy, 1); | ||
1788 | phy->medium = GMII_FIBER; | ||
1789 | break; | ||
1790 | |||
1791 | case GMII_FIBER: | ||
1792 | /* fiber didn't come up, try to disable fiber autoneg */ | ||
1793 | if (phy->def->ops->enable_fiber) | ||
1794 | phy->def->ops->enable_fiber(phy, 0); | ||
1795 | phy->medium = GMII_UNKNOWN; | ||
1796 | break; | ||
1797 | |||
1798 | case GMII_UNKNOWN: | ||
1799 | /* copper, fiber with and without failed, | ||
1800 | * retry from beginning */ | ||
1801 | spider_net_setup_aneg(card); | ||
1802 | phy->medium = GMII_COPPER; | ||
1803 | break; | ||
1804 | } | ||
1805 | |||
1806 | card->aneg_count = 0; | ||
1807 | mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); | ||
1808 | return; | ||
1809 | } | ||
1810 | |||
1811 | /* link still not up, try again later */ | ||
1812 | if (!(phy->def->ops->poll_link(phy))) { | ||
1813 | card->aneg_count++; | ||
1814 | mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); | ||
1815 | return; | ||
1816 | } | ||
1817 | |||
1818 | /* link came up, get abilities */ | ||
1819 | phy->def->ops->read_link(phy); | ||
1820 | |||
1821 | spider_net_write_reg(card, SPIDER_NET_GMACST, | ||
1822 | spider_net_read_reg(card, SPIDER_NET_GMACST)); | ||
1823 | spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4); | ||
1824 | |||
1825 | if (phy->speed == 1000) | ||
1826 | spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001); | ||
1827 | else | ||
1828 | spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0); | ||
1829 | |||
1830 | card->aneg_count = 0; | ||
1831 | |||
1832 | pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n", | ||
1833 | phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half", | ||
1834 | phy->autoneg==1 ? "" : "no "); | ||
1835 | |||
1836 | return; | ||
1837 | } | ||
1838 | |||
1839 | /** | ||
1700 | * spider_net_setup_phy - setup PHY | 1840 | * spider_net_setup_phy - setup PHY |
1701 | * @card: card structure | 1841 | * @card: card structure |
1702 | * | 1842 | * |
1703 | * returns 0 on success, <0 on failure | 1843 | * returns 0 on success, <0 on failure |
1704 | * | 1844 | * |
1705 | * spider_net_setup_phy is used as part of spider_net_probe. Sets | 1845 | * spider_net_setup_phy is used as part of spider_net_probe. |
1706 | * the PHY to 1000 Mbps | ||
1707 | **/ | 1846 | **/ |
1708 | static int | 1847 | static int |
1709 | spider_net_setup_phy(struct spider_net_card *card) | 1848 | spider_net_setup_phy(struct spider_net_card *card) |
@@ -1714,21 +1853,21 @@ spider_net_setup_phy(struct spider_net_card *card) | |||
1714 | SPIDER_NET_DMASEL_VALUE); | 1853 | SPIDER_NET_DMASEL_VALUE); |
1715 | spider_net_write_reg(card, SPIDER_NET_GPCCTRL, | 1854 | spider_net_write_reg(card, SPIDER_NET_GPCCTRL, |
1716 | SPIDER_NET_PHY_CTRL_VALUE); | 1855 | SPIDER_NET_PHY_CTRL_VALUE); |
1717 | phy->mii_id = 1; | 1856 | |
1718 | phy->dev = card->netdev; | 1857 | phy->dev = card->netdev; |
1719 | phy->mdio_read = spider_net_read_phy; | 1858 | phy->mdio_read = spider_net_read_phy; |
1720 | phy->mdio_write = spider_net_write_phy; | 1859 | phy->mdio_write = spider_net_write_phy; |
1721 | 1860 | ||
1722 | mii_phy_probe(phy, phy->mii_id); | 1861 | for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) { |
1723 | 1862 | unsigned short id; | |
1724 | if (phy->def->ops->setup_forced) | 1863 | id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); |
1725 | phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); | 1864 | if (id != 0x0000 && id != 0xffff) { |
1726 | 1865 | if (!mii_phy_probe(phy, phy->mii_id)) { | |
1727 | phy->def->ops->enable_fiber(phy); | 1866 | pr_info("Found %s.\n", phy->def->name); |
1728 | 1867 | break; | |
1729 | phy->def->ops->read_link(phy); | 1868 | } |
1730 | pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, | 1869 | } |
1731 | phy->speed, phy->duplex==1 ? "Full" : "Half"); | 1870 | } |
1732 | 1871 | ||
1733 | return 0; | 1872 | return 0; |
1734 | } | 1873 | } |
@@ -1900,11 +2039,13 @@ spider_net_stop(struct net_device *netdev) | |||
1900 | netif_carrier_off(netdev); | 2039 | netif_carrier_off(netdev); |
1901 | netif_stop_queue(netdev); | 2040 | netif_stop_queue(netdev); |
1902 | del_timer_sync(&card->tx_timer); | 2041 | del_timer_sync(&card->tx_timer); |
2042 | del_timer_sync(&card->aneg_timer); | ||
1903 | 2043 | ||
1904 | /* disable/mask all interrupts */ | 2044 | /* disable/mask all interrupts */ |
1905 | spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); | 2045 | spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); |
1906 | spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); | 2046 | spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); |
1907 | spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); | 2047 | spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); |
2048 | spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); | ||
1908 | 2049 | ||
1909 | free_irq(netdev->irq, netdev); | 2050 | free_irq(netdev->irq, netdev); |
1910 | 2051 | ||
@@ -2043,6 +2184,11 @@ spider_net_setup_netdev(struct spider_net_card *card) | |||
2043 | card->tx_timer.data = (unsigned long) card; | 2184 | card->tx_timer.data = (unsigned long) card; |
2044 | netdev->irq = card->pdev->irq; | 2185 | netdev->irq = card->pdev->irq; |
2045 | 2186 | ||
2187 | card->aneg_count = 0; | ||
2188 | init_timer(&card->aneg_timer); | ||
2189 | card->aneg_timer.function = spider_net_link_phy; | ||
2190 | card->aneg_timer.data = (unsigned long) card; | ||
2191 | |||
2046 | card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; | 2192 | card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; |
2047 | 2193 | ||
2048 | card->tx_chain.num_desc = tx_descriptors; | 2194 | card->tx_chain.num_desc = tx_descriptors; |
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 2fec5cf76926..6f5ee27f80fc 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h | |||
@@ -50,6 +50,8 @@ extern char spider_net_driver_name[]; | |||
50 | #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 | 50 | #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 |
51 | 51 | ||
52 | #define SPIDER_NET_TX_TIMER (HZ/5) | 52 | #define SPIDER_NET_TX_TIMER (HZ/5) |
53 | #define SPIDER_NET_ANEG_TIMER (HZ) | ||
54 | #define SPIDER_NET_ANEG_TIMEOUT 2 | ||
53 | 55 | ||
54 | #define SPIDER_NET_RX_CSUM_DEFAULT 1 | 56 | #define SPIDER_NET_RX_CSUM_DEFAULT 1 |
55 | 57 | ||
@@ -104,6 +106,7 @@ extern char spider_net_driver_name[]; | |||
104 | 106 | ||
105 | #define SPIDER_NET_GMACOPEMD 0x00000100 | 107 | #define SPIDER_NET_GMACOPEMD 0x00000100 |
106 | #define SPIDER_NET_GMACLENLMT 0x00000108 | 108 | #define SPIDER_NET_GMACLENLMT 0x00000108 |
109 | #define SPIDER_NET_GMACST 0x00000110 | ||
107 | #define SPIDER_NET_GMACINTEN 0x00000118 | 110 | #define SPIDER_NET_GMACINTEN 0x00000118 |
108 | #define SPIDER_NET_GMACPHYCTRL 0x00000120 | 111 | #define SPIDER_NET_GMACPHYCTRL 0x00000120 |
109 | 112 | ||
@@ -333,9 +336,12 @@ enum spider_net_int2_status { | |||
333 | /* We rely on flagged descriptor interrupts */ | 336 | /* We rely on flagged descriptor interrupts */ |
334 | #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) | 337 | #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) |
335 | 338 | ||
339 | #define SPIDER_NET_LINKINT ( 1 << SPIDER_NET_GMAC2INT ) | ||
340 | |||
336 | #define SPIDER_NET_ERRINT ( 0xffffffff & \ | 341 | #define SPIDER_NET_ERRINT ( 0xffffffff & \ |
337 | (~SPIDER_NET_TXINT) & \ | 342 | (~SPIDER_NET_TXINT) & \ |
338 | (~SPIDER_NET_RXINT) ) | 343 | (~SPIDER_NET_RXINT) & \ |
344 | (~SPIDER_NET_LINKINT) ) | ||
339 | 345 | ||
340 | #define SPIDER_NET_GPREXEC 0x80000000 | 346 | #define SPIDER_NET_GPREXEC 0x80000000 |
341 | #define SPIDER_NET_GPRDAT_MASK 0x0000ffff | 347 | #define SPIDER_NET_GPRDAT_MASK 0x0000ffff |
@@ -442,6 +448,8 @@ struct spider_net_card { | |||
442 | struct spider_net_descr_chain rx_chain; | 448 | struct spider_net_descr_chain rx_chain; |
443 | struct spider_net_descr *low_watermark; | 449 | struct spider_net_descr *low_watermark; |
444 | 450 | ||
451 | int aneg_count; | ||
452 | struct timer_list aneg_timer; | ||
445 | struct timer_list tx_timer; | 453 | struct timer_list tx_timer; |
446 | struct work_struct tx_timeout_task; | 454 | struct work_struct tx_timeout_task; |
447 | atomic_t tx_timeout_task_counter; | 455 | atomic_t tx_timeout_task_counter; |