1a88394cfSJeff Kirsher /*
23396c782SPaul Gortmaker drivers/net/ethernet/dec/tulip/pnic.c
3a88394cfSJeff Kirsher
4a88394cfSJeff Kirsher Copyright 2000,2001 The Linux Kernel Team
5a88394cfSJeff Kirsher Written/copyright 1994-2001 by Donald Becker.
6a88394cfSJeff Kirsher
7a88394cfSJeff Kirsher This software may be used and distributed according to the terms
8a88394cfSJeff Kirsher of the GNU General Public License, incorporated herein by reference.
9a88394cfSJeff Kirsher
10a88394cfSJeff Kirsher Please submit bugs to http://bugzilla.kernel.org/ .
11a88394cfSJeff Kirsher */
12a88394cfSJeff Kirsher
13a88394cfSJeff Kirsher #include <linux/interrupt.h>
14a88394cfSJeff Kirsher #include <linux/kernel.h>
15a88394cfSJeff Kirsher #include <linux/jiffies.h>
16a88394cfSJeff Kirsher #include "tulip.h"
17a88394cfSJeff Kirsher
18a88394cfSJeff Kirsher
pnic_do_nway(struct net_device * dev)19a88394cfSJeff Kirsher void pnic_do_nway(struct net_device *dev)
20a88394cfSJeff Kirsher {
21a88394cfSJeff Kirsher struct tulip_private *tp = netdev_priv(dev);
22a88394cfSJeff Kirsher void __iomem *ioaddr = tp->base_addr;
23a88394cfSJeff Kirsher u32 phy_reg = ioread32(ioaddr + 0xB8);
24*6b0671a2SColin Ian King u32 new_csr6;
25a88394cfSJeff Kirsher
26a88394cfSJeff Kirsher if (phy_reg & 0x78000000) { /* Ignore baseT4 */
27a88394cfSJeff Kirsher if (phy_reg & 0x20000000) dev->if_port = 5;
28a88394cfSJeff Kirsher else if (phy_reg & 0x40000000) dev->if_port = 3;
29a88394cfSJeff Kirsher else if (phy_reg & 0x10000000) dev->if_port = 4;
30a88394cfSJeff Kirsher else if (phy_reg & 0x08000000) dev->if_port = 0;
31a88394cfSJeff Kirsher tp->nwayset = 1;
32a88394cfSJeff Kirsher new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
33a88394cfSJeff Kirsher iowrite32(0x32 | (dev->if_port & 1), ioaddr + CSR12);
34a88394cfSJeff Kirsher if (dev->if_port & 1)
35a88394cfSJeff Kirsher iowrite32(0x1F868, ioaddr + 0xB8);
36a88394cfSJeff Kirsher if (phy_reg & 0x30000000) {
37a88394cfSJeff Kirsher tp->full_duplex = 1;
38a88394cfSJeff Kirsher new_csr6 |= 0x00000200;
39a88394cfSJeff Kirsher }
40a88394cfSJeff Kirsher if (tulip_debug > 1)
41a88394cfSJeff Kirsher netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n",
42a88394cfSJeff Kirsher phy_reg, medianame[dev->if_port]);
43a88394cfSJeff Kirsher if (tp->csr6 != new_csr6) {
44a88394cfSJeff Kirsher tp->csr6 = new_csr6;
45a88394cfSJeff Kirsher /* Restart Tx */
46a88394cfSJeff Kirsher tulip_restart_rxtx(tp);
47860e9538SFlorian Westphal netif_trans_update(dev);
48a88394cfSJeff Kirsher }
49a88394cfSJeff Kirsher }
50a88394cfSJeff Kirsher }
51a88394cfSJeff Kirsher
pnic_lnk_change(struct net_device * dev,int csr5)52a88394cfSJeff Kirsher void pnic_lnk_change(struct net_device *dev, int csr5)
53a88394cfSJeff Kirsher {
54a88394cfSJeff Kirsher struct tulip_private *tp = netdev_priv(dev);
55a88394cfSJeff Kirsher void __iomem *ioaddr = tp->base_addr;
56a88394cfSJeff Kirsher int phy_reg = ioread32(ioaddr + 0xB8);
57a88394cfSJeff Kirsher
58a88394cfSJeff Kirsher if (tulip_debug > 1)
59a88394cfSJeff Kirsher netdev_dbg(dev, "PNIC link changed state %08x, CSR5 %08x\n",
60a88394cfSJeff Kirsher phy_reg, csr5);
61a88394cfSJeff Kirsher if (ioread32(ioaddr + CSR5) & TPLnkFail) {
62a88394cfSJeff Kirsher iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
63a88394cfSJeff Kirsher /* If we use an external MII, then we mustn't use the
64a88394cfSJeff Kirsher * internal negotiation.
65a88394cfSJeff Kirsher */
66a88394cfSJeff Kirsher if (tulip_media_cap[dev->if_port] & MediaIsMII)
67a88394cfSJeff Kirsher return;
68a88394cfSJeff Kirsher if (! tp->nwayset || time_after(jiffies, dev_trans_start(dev) + 1*HZ)) {
69a88394cfSJeff Kirsher tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
70a88394cfSJeff Kirsher iowrite32(tp->csr6, ioaddr + CSR6);
71a88394cfSJeff Kirsher iowrite32(0x30, ioaddr + CSR12);
72a88394cfSJeff Kirsher iowrite32(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
73860e9538SFlorian Westphal netif_trans_update(dev);
74a88394cfSJeff Kirsher }
75a88394cfSJeff Kirsher } else if (ioread32(ioaddr + CSR5) & TPLnkPass) {
76a88394cfSJeff Kirsher if (tulip_media_cap[dev->if_port] & MediaIsMII) {
77a88394cfSJeff Kirsher spin_lock(&tp->lock);
78a88394cfSJeff Kirsher tulip_check_duplex(dev);
79a88394cfSJeff Kirsher spin_unlock(&tp->lock);
80a88394cfSJeff Kirsher } else {
81a88394cfSJeff Kirsher pnic_do_nway(dev);
82a88394cfSJeff Kirsher }
83a88394cfSJeff Kirsher iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
84a88394cfSJeff Kirsher }
85a88394cfSJeff Kirsher }
86a88394cfSJeff Kirsher
pnic_timer(struct timer_list * t)87a8c22a2bSKees Cook void pnic_timer(struct timer_list *t)
88a88394cfSJeff Kirsher {
89a8c22a2bSKees Cook struct tulip_private *tp = from_timer(tp, t, timer);
90a8c22a2bSKees Cook struct net_device *dev = tp->dev;
91a88394cfSJeff Kirsher void __iomem *ioaddr = tp->base_addr;
92a88394cfSJeff Kirsher int next_tick = 60*HZ;
93a88394cfSJeff Kirsher
94a88394cfSJeff Kirsher if(!ioread32(ioaddr + CSR7)) {
95a88394cfSJeff Kirsher /* the timer was called due to a work overflow
96a88394cfSJeff Kirsher * in the interrupt handler. Skip the connection
97a88394cfSJeff Kirsher * checks, the nic is definitively speaking with
98a88394cfSJeff Kirsher * his link partner.
99a88394cfSJeff Kirsher */
100a88394cfSJeff Kirsher goto too_good_connection;
101a88394cfSJeff Kirsher }
102a88394cfSJeff Kirsher
103a88394cfSJeff Kirsher if (tulip_media_cap[dev->if_port] & MediaIsMII) {
104a88394cfSJeff Kirsher spin_lock_irq(&tp->lock);
105a88394cfSJeff Kirsher if (tulip_check_duplex(dev) > 0)
106a88394cfSJeff Kirsher next_tick = 3*HZ;
107a88394cfSJeff Kirsher spin_unlock_irq(&tp->lock);
108a88394cfSJeff Kirsher } else {
109a88394cfSJeff Kirsher int csr12 = ioread32(ioaddr + CSR12);
110a88394cfSJeff Kirsher int new_csr6 = tp->csr6 & ~0x40C40200;
111a88394cfSJeff Kirsher int phy_reg = ioread32(ioaddr + 0xB8);
112a88394cfSJeff Kirsher int csr5 = ioread32(ioaddr + CSR5);
113a88394cfSJeff Kirsher
114a88394cfSJeff Kirsher if (tulip_debug > 1)
115a88394cfSJeff Kirsher netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n",
116a88394cfSJeff Kirsher phy_reg, medianame[dev->if_port], csr5);
117a88394cfSJeff Kirsher if (phy_reg & 0x04000000) { /* Remote link fault */
118a88394cfSJeff Kirsher iowrite32(0x0201F078, ioaddr + 0xB8);
119a88394cfSJeff Kirsher next_tick = 1*HZ;
120a88394cfSJeff Kirsher tp->nwayset = 0;
121a88394cfSJeff Kirsher } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
122a88394cfSJeff Kirsher pnic_do_nway(dev);
123a88394cfSJeff Kirsher next_tick = 60*HZ;
124a88394cfSJeff Kirsher } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
125a88394cfSJeff Kirsher if (tulip_debug > 1)
126a88394cfSJeff Kirsher netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
127a88394cfSJeff Kirsher medianame[dev->if_port],
128a88394cfSJeff Kirsher csr12,
129a88394cfSJeff Kirsher ioread32(ioaddr + CSR5),
130a88394cfSJeff Kirsher ioread32(ioaddr + 0xB8));
131a88394cfSJeff Kirsher next_tick = 3*HZ;
132a88394cfSJeff Kirsher if (tp->medialock) {
133a88394cfSJeff Kirsher } else if (tp->nwayset && (dev->if_port & 1)) {
134a88394cfSJeff Kirsher next_tick = 1*HZ;
135a88394cfSJeff Kirsher } else if (dev->if_port == 0) {
136a88394cfSJeff Kirsher dev->if_port = 3;
137a88394cfSJeff Kirsher iowrite32(0x33, ioaddr + CSR12);
138a88394cfSJeff Kirsher new_csr6 = 0x01860000;
139a88394cfSJeff Kirsher iowrite32(0x1F868, ioaddr + 0xB8);
140a88394cfSJeff Kirsher } else {
141a88394cfSJeff Kirsher dev->if_port = 0;
142a88394cfSJeff Kirsher iowrite32(0x32, ioaddr + CSR12);
143a88394cfSJeff Kirsher new_csr6 = 0x00420000;
144a88394cfSJeff Kirsher iowrite32(0x1F078, ioaddr + 0xB8);
145a88394cfSJeff Kirsher }
146a88394cfSJeff Kirsher if (tp->csr6 != new_csr6) {
147a88394cfSJeff Kirsher tp->csr6 = new_csr6;
148a88394cfSJeff Kirsher /* Restart Tx */
149a88394cfSJeff Kirsher tulip_restart_rxtx(tp);
150860e9538SFlorian Westphal netif_trans_update(dev);
151a88394cfSJeff Kirsher if (tulip_debug > 1)
152a88394cfSJeff Kirsher dev_info(&dev->dev,
153a88394cfSJeff Kirsher "Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n",
154a88394cfSJeff Kirsher medianame[dev->if_port],
155a88394cfSJeff Kirsher tp->full_duplex ? "full" : "half",
156a88394cfSJeff Kirsher new_csr6);
157a88394cfSJeff Kirsher }
158a88394cfSJeff Kirsher }
159a88394cfSJeff Kirsher }
160a88394cfSJeff Kirsher too_good_connection:
161a88394cfSJeff Kirsher mod_timer(&tp->timer, RUN_AT(next_tick));
162a88394cfSJeff Kirsher if(!ioread32(ioaddr + CSR7)) {
163a88394cfSJeff Kirsher if (tulip_debug > 1)
164a88394cfSJeff Kirsher dev_info(&dev->dev, "sw timer wakeup\n");
165a88394cfSJeff Kirsher disable_irq(dev->irq);
166a88394cfSJeff Kirsher tulip_refill_rx(dev);
167a88394cfSJeff Kirsher enable_irq(dev->irq);
168a88394cfSJeff Kirsher iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
169a88394cfSJeff Kirsher }
170a88394cfSJeff Kirsher }
171