162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci drivers/net/ethernet/dec/tulip/21142.c 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright 2000,2001 The Linux Kernel Team 562306a36Sopenharmony_ci Written/copyright 1994-2001 by Donald Becker. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci This software may be used and distributed according to the terms 862306a36Sopenharmony_ci of the GNU General Public License, incorporated herein by reference. 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci DC21143 manual "21143 PCI/CardBus 10/100Mb/s Ethernet LAN Controller 1162306a36Sopenharmony_ci Hardware Reference Manual" is currently available at : 1262306a36Sopenharmony_ci http://developer.intel.com/design/network/manuals/278074.htm 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci Please submit bugs to http://bugzilla.kernel.org/ . 1562306a36Sopenharmony_ci*/ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include "tulip.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; 2262306a36Sopenharmony_ciu16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; 2362306a36Sopenharmony_cistatic u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list 2762306a36Sopenharmony_ci of available transceivers. */ 2862306a36Sopenharmony_civoid t21142_media_task(struct work_struct *work) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct tulip_private *tp = 3162306a36Sopenharmony_ci container_of(work, struct tulip_private, media_work); 3262306a36Sopenharmony_ci struct net_device *dev = tp->dev; 3362306a36Sopenharmony_ci void __iomem *ioaddr = tp->base_addr; 3462306a36Sopenharmony_ci int csr12 = ioread32(ioaddr + CSR12); 3562306a36Sopenharmony_ci int next_tick = 60*HZ; 3662306a36Sopenharmony_ci int new_csr6 = 0; 3762306a36Sopenharmony_ci int csr14 = ioread32(ioaddr + CSR14); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* CSR12[LS10,LS100] are not reliable during autonegotiation */ 4062306a36Sopenharmony_ci if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) 4162306a36Sopenharmony_ci csr12 |= 6; 4262306a36Sopenharmony_ci if (tulip_debug > 2) 4362306a36Sopenharmony_ci dev_info(&dev->dev, "21143 negotiation status %08x, %s\n", 4462306a36Sopenharmony_ci csr12, medianame[dev->if_port]); 4562306a36Sopenharmony_ci if (tulip_media_cap[dev->if_port] & MediaIsMII) { 4662306a36Sopenharmony_ci if (tulip_check_duplex(dev) < 0) { 4762306a36Sopenharmony_ci netif_carrier_off(dev); 4862306a36Sopenharmony_ci next_tick = 3*HZ; 4962306a36Sopenharmony_ci } else { 5062306a36Sopenharmony_ci netif_carrier_on(dev); 5162306a36Sopenharmony_ci next_tick = 60*HZ; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } else if (tp->nwayset) { 5462306a36Sopenharmony_ci /* Don't screw up a negotiated session! */ 5562306a36Sopenharmony_ci if (tulip_debug > 1) 5662306a36Sopenharmony_ci dev_info(&dev->dev, 5762306a36Sopenharmony_ci "Using NWay-set %s media, csr12 %08x\n", 5862306a36Sopenharmony_ci medianame[dev->if_port], csr12); 5962306a36Sopenharmony_ci } else if (tp->medialock) { 6062306a36Sopenharmony_ci ; 6162306a36Sopenharmony_ci } else if (dev->if_port == 3) { 6262306a36Sopenharmony_ci if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ 6362306a36Sopenharmony_ci if (tulip_debug > 1) 6462306a36Sopenharmony_ci dev_info(&dev->dev, 6562306a36Sopenharmony_ci "No 21143 100baseTx link beat, %08x, trying NWay\n", 6662306a36Sopenharmony_ci csr12); 6762306a36Sopenharmony_ci t21142_start_nway(dev); 6862306a36Sopenharmony_ci next_tick = 3*HZ; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } else if ((csr12 & 0x7000) != 0x5000) { 7162306a36Sopenharmony_ci /* Negotiation failed. Search media types. */ 7262306a36Sopenharmony_ci if (tulip_debug > 1) 7362306a36Sopenharmony_ci dev_info(&dev->dev, 7462306a36Sopenharmony_ci "21143 negotiation failed, status %08x\n", 7562306a36Sopenharmony_ci csr12); 7662306a36Sopenharmony_ci if (!(csr12 & 4)) { /* 10mbps link beat good. */ 7762306a36Sopenharmony_ci new_csr6 = 0x82420000; 7862306a36Sopenharmony_ci dev->if_port = 0; 7962306a36Sopenharmony_ci iowrite32(0, ioaddr + CSR13); 8062306a36Sopenharmony_ci iowrite32(0x0003FFFF, ioaddr + CSR14); 8162306a36Sopenharmony_ci iowrite16(t21142_csr15[dev->if_port], ioaddr + CSR15); 8262306a36Sopenharmony_ci iowrite32(t21142_csr13[dev->if_port], ioaddr + CSR13); 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci /* Select 100mbps port to check for link beat. */ 8562306a36Sopenharmony_ci new_csr6 = 0x83860000; 8662306a36Sopenharmony_ci dev->if_port = 3; 8762306a36Sopenharmony_ci iowrite32(0, ioaddr + CSR13); 8862306a36Sopenharmony_ci iowrite32(0x0003FFFF, ioaddr + CSR14); 8962306a36Sopenharmony_ci iowrite16(8, ioaddr + CSR15); 9062306a36Sopenharmony_ci iowrite32(1, ioaddr + CSR13); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci if (tulip_debug > 1) 9362306a36Sopenharmony_ci dev_info(&dev->dev, "Testing new 21143 media %s\n", 9462306a36Sopenharmony_ci medianame[dev->if_port]); 9562306a36Sopenharmony_ci if (new_csr6 != (tp->csr6 & ~0x00D5)) { 9662306a36Sopenharmony_ci tp->csr6 &= 0x00D5; 9762306a36Sopenharmony_ci tp->csr6 |= new_csr6; 9862306a36Sopenharmony_ci iowrite32(0x0301, ioaddr + CSR12); 9962306a36Sopenharmony_ci tulip_restart_rxtx(tp); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci next_tick = 3*HZ; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* mod_timer synchronizes us with potential add_timer calls 10562306a36Sopenharmony_ci * from interrupts. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci mod_timer(&tp->timer, RUN_AT(next_tick)); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_civoid t21142_start_nway(struct net_device *dev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 11462306a36Sopenharmony_ci void __iomem *ioaddr = tp->base_addr; 11562306a36Sopenharmony_ci int csr14 = ((tp->sym_advertise & 0x0780) << 9) | 11662306a36Sopenharmony_ci ((tp->sym_advertise & 0x0020) << 1) | 0xffbf; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci dev->if_port = 0; 11962306a36Sopenharmony_ci tp->nway = tp->mediasense = 1; 12062306a36Sopenharmony_ci tp->nwayset = tp->lpar = 0; 12162306a36Sopenharmony_ci if (tulip_debug > 1) 12262306a36Sopenharmony_ci netdev_dbg(dev, "Restarting 21143 autonegotiation, csr14=%08x\n", 12362306a36Sopenharmony_ci csr14); 12462306a36Sopenharmony_ci iowrite32(0x0001, ioaddr + CSR13); 12562306a36Sopenharmony_ci udelay(100); 12662306a36Sopenharmony_ci iowrite32(csr14, ioaddr + CSR14); 12762306a36Sopenharmony_ci tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0); 12862306a36Sopenharmony_ci iowrite32(tp->csr6, ioaddr + CSR6); 12962306a36Sopenharmony_ci if (tp->mtable && tp->mtable->csr15dir) { 13062306a36Sopenharmony_ci iowrite32(tp->mtable->csr15dir, ioaddr + CSR15); 13162306a36Sopenharmony_ci iowrite32(tp->mtable->csr15val, ioaddr + CSR15); 13262306a36Sopenharmony_ci } else 13362306a36Sopenharmony_ci iowrite16(0x0008, ioaddr + CSR15); 13462306a36Sopenharmony_ci iowrite32(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid t21142_lnk_change(struct net_device *dev, int csr5) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 14262306a36Sopenharmony_ci void __iomem *ioaddr = tp->base_addr; 14362306a36Sopenharmony_ci int csr12 = ioread32(ioaddr + CSR12); 14462306a36Sopenharmony_ci int csr14 = ioread32(ioaddr + CSR14); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* CSR12[LS10,LS100] are not reliable during autonegotiation */ 14762306a36Sopenharmony_ci if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) 14862306a36Sopenharmony_ci csr12 |= 6; 14962306a36Sopenharmony_ci if (tulip_debug > 1) 15062306a36Sopenharmony_ci dev_info(&dev->dev, 15162306a36Sopenharmony_ci "21143 link status interrupt %08x, CSR5 %x, %08x\n", 15262306a36Sopenharmony_ci csr12, csr5, csr14); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* If NWay finished and we have a negotiated partner capability. */ 15562306a36Sopenharmony_ci if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { 15662306a36Sopenharmony_ci int setup_done = 0; 15762306a36Sopenharmony_ci int negotiated = tp->sym_advertise & (csr12 >> 16); 15862306a36Sopenharmony_ci tp->lpar = csr12 >> 16; 15962306a36Sopenharmony_ci tp->nwayset = 1; 16062306a36Sopenharmony_ci /* If partner cannot negotiate, it is 10Mbps Half Duplex */ 16162306a36Sopenharmony_ci if (!(csr12 & 0x8000)) dev->if_port = 0; 16262306a36Sopenharmony_ci else if (negotiated & 0x0100) dev->if_port = 5; 16362306a36Sopenharmony_ci else if (negotiated & 0x0080) dev->if_port = 3; 16462306a36Sopenharmony_ci else if (negotiated & 0x0040) dev->if_port = 4; 16562306a36Sopenharmony_ci else if (negotiated & 0x0020) dev->if_port = 0; 16662306a36Sopenharmony_ci else { 16762306a36Sopenharmony_ci tp->nwayset = 0; 16862306a36Sopenharmony_ci if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180)) 16962306a36Sopenharmony_ci dev->if_port = 3; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (tulip_debug > 1) { 17462306a36Sopenharmony_ci if (tp->nwayset) 17562306a36Sopenharmony_ci dev_info(&dev->dev, 17662306a36Sopenharmony_ci "Switching to %s based on link negotiation %04x & %04x = %04x\n", 17762306a36Sopenharmony_ci medianame[dev->if_port], 17862306a36Sopenharmony_ci tp->sym_advertise, tp->lpar, 17962306a36Sopenharmony_ci negotiated); 18062306a36Sopenharmony_ci else 18162306a36Sopenharmony_ci dev_info(&dev->dev, 18262306a36Sopenharmony_ci "Autonegotiation failed, using %s, link beat status %04x\n", 18362306a36Sopenharmony_ci medianame[dev->if_port], csr12); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (tp->mtable) { 18762306a36Sopenharmony_ci int i; 18862306a36Sopenharmony_ci for (i = 0; i < tp->mtable->leafcount; i++) 18962306a36Sopenharmony_ci if (tp->mtable->mleaf[i].media == dev->if_port) { 19062306a36Sopenharmony_ci int startup = ! ((tp->chip_id == DC21143 && (tp->revision == 48 || tp->revision == 65))); 19162306a36Sopenharmony_ci tp->cur_index = i; 19262306a36Sopenharmony_ci tulip_select_media(dev, startup); 19362306a36Sopenharmony_ci setup_done = 1; 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci if ( ! setup_done) { 19862306a36Sopenharmony_ci tp->csr6 = (dev->if_port & 1 ? 0x838E0000 : 0x82420000) | (tp->csr6 & 0x20ff); 19962306a36Sopenharmony_ci if (tp->full_duplex) 20062306a36Sopenharmony_ci tp->csr6 |= 0x0200; 20162306a36Sopenharmony_ci iowrite32(1, ioaddr + CSR13); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci#if 0 /* Restart shouldn't be needed. */ 20462306a36Sopenharmony_ci iowrite32(tp->csr6 | RxOn, ioaddr + CSR6); 20562306a36Sopenharmony_ci if (tulip_debug > 2) 20662306a36Sopenharmony_ci netdev_dbg(dev, " Restarting Tx and Rx, CSR5 is %08x\n", 20762306a36Sopenharmony_ci ioread32(ioaddr + CSR5)); 20862306a36Sopenharmony_ci#endif 20962306a36Sopenharmony_ci tulip_start_rxtx(tp); 21062306a36Sopenharmony_ci if (tulip_debug > 2) 21162306a36Sopenharmony_ci netdev_dbg(dev, " Setting CSR6 %08x/%x CSR12 %08x\n", 21262306a36Sopenharmony_ci tp->csr6, ioread32(ioaddr + CSR6), 21362306a36Sopenharmony_ci ioread32(ioaddr + CSR12)); 21462306a36Sopenharmony_ci } else if ((tp->nwayset && (csr5 & 0x08000000) && 21562306a36Sopenharmony_ci (dev->if_port == 3 || dev->if_port == 5) && 21662306a36Sopenharmony_ci (csr12 & 2) == 2) || 21762306a36Sopenharmony_ci (tp->nway && (csr5 & (TPLnkFail)))) { 21862306a36Sopenharmony_ci /* Link blew? Maybe restart NWay. */ 21962306a36Sopenharmony_ci del_timer_sync(&tp->timer); 22062306a36Sopenharmony_ci t21142_start_nway(dev); 22162306a36Sopenharmony_ci tp->timer.expires = RUN_AT(3*HZ); 22262306a36Sopenharmony_ci add_timer(&tp->timer); 22362306a36Sopenharmony_ci } else if (dev->if_port == 3 || dev->if_port == 5) { 22462306a36Sopenharmony_ci if (tulip_debug > 1) 22562306a36Sopenharmony_ci dev_info(&dev->dev, "21143 %s link beat %s\n", 22662306a36Sopenharmony_ci medianame[dev->if_port], 22762306a36Sopenharmony_ci (csr12 & 2) ? "failed" : "good"); 22862306a36Sopenharmony_ci if ((csr12 & 2) && ! tp->medialock) { 22962306a36Sopenharmony_ci del_timer_sync(&tp->timer); 23062306a36Sopenharmony_ci t21142_start_nway(dev); 23162306a36Sopenharmony_ci tp->timer.expires = RUN_AT(3*HZ); 23262306a36Sopenharmony_ci add_timer(&tp->timer); 23362306a36Sopenharmony_ci } else if (dev->if_port == 5) 23462306a36Sopenharmony_ci iowrite32(csr14 & ~0x080, ioaddr + CSR14); 23562306a36Sopenharmony_ci } else if (dev->if_port == 0 || dev->if_port == 4) { 23662306a36Sopenharmony_ci if ((csr12 & 4) == 0) 23762306a36Sopenharmony_ci dev_info(&dev->dev, "21143 10baseT link beat good\n"); 23862306a36Sopenharmony_ci } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ 23962306a36Sopenharmony_ci if (tulip_debug) 24062306a36Sopenharmony_ci dev_info(&dev->dev, "21143 10mbps sensed media\n"); 24162306a36Sopenharmony_ci dev->if_port = 0; 24262306a36Sopenharmony_ci } else if (tp->nwayset) { 24362306a36Sopenharmony_ci if (tulip_debug) 24462306a36Sopenharmony_ci dev_info(&dev->dev, "21143 using NWay-set %s, csr6 %08x\n", 24562306a36Sopenharmony_ci medianame[dev->if_port], tp->csr6); 24662306a36Sopenharmony_ci } else { /* 100mbps link beat good. */ 24762306a36Sopenharmony_ci if (tulip_debug) 24862306a36Sopenharmony_ci dev_info(&dev->dev, "21143 100baseTx sensed media\n"); 24962306a36Sopenharmony_ci dev->if_port = 3; 25062306a36Sopenharmony_ci tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff); 25162306a36Sopenharmony_ci iowrite32(0x0003FF7F, ioaddr + CSR14); 25262306a36Sopenharmony_ci iowrite32(0x0301, ioaddr + CSR12); 25362306a36Sopenharmony_ci tulip_restart_rxtx(tp); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci 258