xref: /openbmc/linux/drivers/net/ethernet/dec/tulip/pnic.c (revision 6b0671a2)
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