aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKou Ishizaki <kou.ishizaki@toshiba.co.jp>2007-02-20 17:33:41 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-27 04:16:02 -0500
commitabdb66b566fce5641c90100e0a113a94bab43fda (patch)
treea93d9d4063159353f0a1e765723ba462b2682446 /drivers
parentd406eafee814c0e20af00a9a74f68f6993d8cb9c (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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/spider_net.c176
-rw-r--r--drivers/net/spider_net.h10
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 **/
172static void
173spider_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 */
1293static void
1294spider_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:
1693alloc_rx_failed: 1761alloc_rx_failed:
1694 spider_net_free_chain(card, &card->tx_chain); 1762 spider_net_free_chain(card, &card->tx_chain);
1695alloc_tx_failed: 1763alloc_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 */
1773static 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 **/
1708static int 1847static int
1709spider_net_setup_phy(struct spider_net_card *card) 1848spider_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;