4 * proper fatal error handling
11 #include "../port/lib.h"
16 #include "../port/pci.h"
17 #include "../port/error.h"
18 #include "../port/netif.h"
19 #include "../port/etherif.h"
21 #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
23 typedef struct Ctlr Ctlr;
30 /* One Ring to find them, One Ring to bring them all and in the darkness bind them */
31 ulong *recvret, *recvprod, *sendr;
32 ulong recvreti, recvprodi, sendri, sendcleani;
33 Block **sends, **recvs;
38 RecvRetRingLen = 0x200,
39 RecvProdRingLen = 0x200,
48 PowerControlStatus = 0x4C,
55 EnablePCIStateRegister = 1<<4,
56 EnableClockControlRegister = 1<<5,
57 IndirectAccessEnable = 1<<7,
61 DMAWatermarkMask = ~(7<<19),
62 DMAWatermarkValue = 3<<19,
65 MemoryWindowData = 0x84,
70 InterruptMailbox = 0x204,
72 RecvProdBDRingIndex = 0x26c,
73 RecvBDRetRingIndex = 0x284,
74 SendBDRingHostIndex = 0x304,
77 MACPortMask = ~((1<<3)|(1<<2)),
80 MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11),
83 MACEventStatus = 0x404,
84 MACEventEnable = 0x408,
86 EthernetRandomBackoff = 0x438,
91 ReceiveMACMode = 0x468,
92 TransmitMACMode = 0x45C,
93 TransmitMACLengths = 0x464,
97 ReceiveRulesConfiguration = 0x500,
98 LowWatermarkMaximum = 0x504,
99 LowWatermarkMaxMask = ~0xFFFF,
100 LowWatermarkMaxValue = 2,
102 SendDataInitiatorMode = 0xC00,
103 SendInitiatorConfiguration = 0x0C08,
105 SendInitiatorMask = 0x0C0C,
107 SendDataCompletionMode = 0x1000,
108 SendBDSelectorMode = 0x1400,
109 SendBDInitiatorMode = 0x1800,
110 SendBDCompletionMode = 0x1C00,
112 ReceiveListPlacementMode = 0x2000,
113 ReceiveListPlacement = 0x2010,
114 ReceiveListPlacementConfiguration = 0x2014,
116 ReceiveListPlacementMask = 0x2018,
118 ReceiveDataBDInitiatorMode = 0x2400,
119 ReceiveBDHostAddr = 0x2450,
120 ReceiveBDFlags = 0x2458,
121 ReceiveBDNIC = 0x245C,
122 ReceiveDataCompletionMode = 0x2800,
123 ReceiveBDInitiatorMode = 0x2C00,
124 ReceiveBDRepl = 0x2C18,
126 ReceiveBDCompletionMode = 0x3000,
127 HostCoalescingMode = 0x3C00,
128 HostCoalescingRecvTicks = 0x3C08,
129 HostCoalescingSendTicks = 0x3C0C,
130 RecvMaxCoalescedFrames = 0x3C10,
131 SendMaxCoalescedFrames = 0x3C14,
132 RecvMaxCoalescedFramesInt = 0x3C20,
133 SendMaxCoalescedFramesInt = 0x3C24,
134 StatusBlockHostAddr = 0x3C38,
135 FlowAttention = 0x3C48,
137 MemArbiterMode = 0x4000,
139 BufferManMode = 0x4400,
141 MBUFLowWatermark = 0x4414,
142 MBUFHighWatermark = 0x4418,
144 ReadDMAMode = 0x4800,
145 ReadDMAStatus = 0x4804,
146 WriteDMAMode = 0x4C00,
147 WriteDMAStatus = 0x4C04,
153 ModeControl = 0x6800,
154 ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1),
157 InterruptOnMAC = 1<<26,
159 MiscConfiguration = 0x6804,
160 CoreClockBlocksReset = 1<<0,
161 GPHYPowerDownOverride = 1<<26,
162 DisableGRCResetOnPCIE = 1<<29,
165 MiscLocalControl = 0x6808,
166 InterruptOnAttn = 1<<3,
169 SwArbitration = 0x7020,
176 PhyLinkStatus = 1<<2,
177 PhyAutoNegComplete = 1<<5,
178 PhyPartnerStatus = 0x05,
183 PhyGbitStatus = 0x0A,
186 PhyAuxControl = 0x18,
191 LinkStateChange = 1<<1,
281 #define csr32(c, r) ((c)->nic[(r)/4])
282 #define mem32(c, r) csr32(c, (r)+0x8000)
284 static Ctlr *bcmhead, *bcmtail;
293 miir(Ctlr *ctlr, int ra)
295 while(csr32(ctlr, MIComm) & (1<<29));
296 csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
297 while(csr32(ctlr, MIComm) & (1<<29));
298 if(csr32(ctlr, MIComm) & (1<<28)) return -1;
299 return csr32(ctlr, MIComm) & 0xFFFF;
303 miiw(Ctlr *ctlr, int ra, int value)
305 while(csr32(ctlr, MIComm) & (1<<29));
306 csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
307 while(csr32(ctlr, MIComm) & (1<<29));
312 checklink(Ether *edev)
318 miir(ctlr, PhyStatus); /* dummy read necessary */
319 if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
323 print("bcm: no link\n");
327 while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
328 i = miir(ctlr, PhyGbitStatus);
329 if(i & (Phy1000FD | Phy1000HD)) {
331 ctlr->duplex = (i & Phy1000FD) != 0;
332 } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
334 ctlr->duplex = (i & Phy100FD) != 0;
335 } else if(i & (Phy10FD | Phy10HD)) {
337 ctlr->duplex = (i & Phy10FD) != 0;
342 print("bcm: link partner supports neither 10/100/1000 Mbps\n");
345 print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
347 if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
348 else csr32(ctlr, MACMode) |= MACHalfDuplex;
349 if(edev->mbps >= 1000)
350 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
352 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
353 csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */
357 currentrecvret(Ctlr *ctlr)
359 if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0;
360 return ctlr->recvret + ctlr->recvreti * 8;
364 consumerecvret(Ctlr *ctlr)
366 csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
370 replenish(Ctlr *ctlr)
377 idx = ctlr->recvprodi;
378 incr = (idx + 1) & (RecvProdRingLen - 1);
379 if(incr == (ctlr->status[2] >> 16)) return -1;
380 if(ctlr->recvs[idx] != 0) return -1;
383 print("bcm: out of memory for receive buffers\n");
386 ctlr->recvs[idx] = bp;
387 next = ctlr->recvprod + idx * 8;
389 pa = PCIWADDR(bp->rp);
395 csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
400 bcmreceive(Ether *edev)
404 ulong *pkt, len, idx;
407 for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
408 idx = pkt[7] & (RecvProdRingLen - 1);
409 bp = ctlr->recvs[idx];
411 print("bcm: nil block at %lux -- shouldn't happen\n", idx);
414 ctlr->recvs[idx] = 0;
415 len = pkt[2] & 0xFFFF;
416 bp->wp = bp->rp + len;
417 if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
418 if(pkt[3] & FrameError) {
419 freeb(bp); /* dump erroneous packets */
427 bcmtransclean(Ether *edev, int dolock)
433 ilock(&ctlr->txlock);
434 while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
435 freeb(ctlr->sends[ctlr->sendcleani]);
436 ctlr->sends[ctlr->sendcleani] = 0;
437 ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
440 iunlock(&ctlr->txlock);
444 bcmtransmit(Ether *edev)
453 ilock(&ctlr->txlock);
455 incr = (ctlr->sendri + 1) & (SendRingLen - 1);
456 if(incr == (ctlr->status[4] >> 16)) {
457 print("bcm: send queue full\n");
462 next = ctlr->sendr + ctlr->sendri * 4;
463 pa = PCIWADDR(bp->rp);
466 next[2] = (BLEN(bp) << 16) | PacketEnd;
468 if(ctlr->sends[ctlr->sendri] != 0)
469 freeb(ctlr->sends[ctlr->sendri]);
470 ctlr->sends[ctlr->sendri] = bp;
472 csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
474 iunlock(&ctlr->txlock);
478 bcmerror(Ether *edev)
483 if(csr32(ctlr, FlowAttention)) {
484 if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
485 panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
487 csr32(ctlr, FlowAttention) = 0;
489 csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
490 if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
491 print("bcm: DMA error\n");
492 csr32(ctlr, ReadDMAStatus) = 0;
493 csr32(ctlr, WriteDMAStatus) = 0;
495 if(csr32(ctlr, RISCState)) {
496 if(csr32(ctlr, RISCState) & 0x78000403) {
497 panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
499 csr32(ctlr, RISCState) = 0;
504 bcminterrupt(Ureg*, void *arg)
512 ilock(&ctlr->imlock);
513 dummyread(csr32(ctlr, InterruptMailbox));
514 csr32(ctlr, InterruptMailbox) = 1;
515 status = ctlr->status[0];
516 tag = ctlr->status[1];
518 if(status & Error) bcmerror(edev);
519 if(status & LinkStateChange) checklink(edev);
520 // print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
522 bcmtransclean(edev, 1);
524 csr32(ctlr, InterruptMailbox) = tag << 24;
525 iunlock(&ctlr->imlock);
536 print("bcm: reset\n");
537 /* initialization procedure according to the datasheet */
538 csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
539 csr32(ctlr, SwArbitration) |= SwArbitSet1;
540 for(i = 0; i < 10000 && (csr32(ctlr, SwArbitration) & SwArbitWon1) == 0; i++)
543 iprint("bcm: arbiter failed to respond\n");
546 csr32(ctlr, MemArbiterMode) |= Enable;
547 csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
548 csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
549 csr32(ctlr, ModeControl) |= ByteWordSwap;
550 csr32(ctlr, MemoryWindow) = 0;
551 mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
552 csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
553 csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
555 ctlr->pdev->pcr |= 1<<1; /* pci memory access enable */
556 pcisetbme(ctlr->pdev);
557 csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
558 csr32(ctlr, MemArbiterMode) |= Enable;
559 csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
560 csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
561 csr32(ctlr, ModeControl) |= ByteWordSwap;
562 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
564 for(i = 0; i < 100000 && mem32(ctlr, 0xB50) != 0xB49A89AB; i++)
567 iprint("bcm: chip failed to reset\n");
570 switch(ctlr->pdev->did){
574 csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
577 memset(ctlr->status, 0, 20);
578 csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
579 csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
580 csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
581 csr32(ctlr, MBUFLowWatermark) = 0x20;
582 csr32(ctlr, MBUFHighWatermark) = 0x60;
583 csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
584 csr32(ctlr, BufferManMode) |= Enable | Attn;
585 for(i = 0; i < 100 && (csr32(ctlr, BufferManMode) & Enable) == 0; i++)
588 iprint("bcm: buffer manager failed to start\n");
591 csr32(ctlr, FTQReset) = -1;
592 csr32(ctlr, FTQReset) = 0;
593 for(i = 0; i < 1000 && csr32(ctlr, FTQReset) != 0; i++)
596 iprint("bcm: ftq failed to reset\n");
599 pa = PCIWADDR(ctlr->recvprod);
600 csr32(ctlr, ReceiveBDHostAddr + 0) = pa >> 32;
601 csr32(ctlr, ReceiveBDHostAddr + 4) = pa;
602 csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
603 csr32(ctlr, ReceiveBDNIC) = 0x6000;
604 csr32(ctlr, ReceiveBDRepl) = 25;
605 csr32(ctlr, SendBDRingHostIndex) = 0;
606 csr32(ctlr, SendBDRingHostIndex+4) = 0;
607 pa = PCIWADDR(ctlr->sendr);
608 mem32(ctlr, SendRCB + 0) = pa >> 32;
609 mem32(ctlr, SendRCB + 4) = pa;
610 mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
611 mem32(ctlr, SendRCB + 12) = 0x4000;
613 mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
614 pa = PCIWADDR(ctlr->recvret);
615 mem32(ctlr, RecvRetRCB + 0) = pa >> 32;
616 mem32(ctlr, RecvRetRCB + 4) = pa;
617 mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
618 csr32(ctlr, RecvProdBDRingIndex) = 0;
619 csr32(ctlr, RecvProdBDRingIndex+4) = 0;
620 /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
622 i = csr32(ctlr, 0x410);
623 j = edev->ea[0] = i >> 8;
624 j += edev->ea[1] = i;
625 i = csr32(ctlr, MACAddress + 4);
626 j += edev->ea[2] = i >> 24;
627 j += edev->ea[3] = i >> 16;
628 j += edev->ea[4] = i >> 8;
629 j += edev->ea[5] = i;
630 csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
631 csr32(ctlr, ReceiveMTU) = Rbsz;
632 csr32(ctlr, TransmitMACLengths) = 0x2620;
633 csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
634 csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
635 csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
636 csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
637 csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
638 csr32(ctlr, HostCoalescingMode) = 0;
639 for(i = 0; i < 200 && csr32(ctlr, HostCoalescingMode) != 0; i++)
642 iprint("bcm: host coalescing engine failed to stop\n");
645 csr32(ctlr, HostCoalescingRecvTicks) = 150;
646 csr32(ctlr, HostCoalescingSendTicks) = 150;
647 csr32(ctlr, RecvMaxCoalescedFrames) = 10;
648 csr32(ctlr, SendMaxCoalescedFrames) = 10;
649 csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
650 csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
651 pa = PCIWADDR(ctlr->status);
652 csr32(ctlr, StatusBlockHostAddr + 0) = pa >> 32;
653 csr32(ctlr, StatusBlockHostAddr + 4) = pa;
654 csr32(ctlr, HostCoalescingMode) |= Enable;
655 csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
656 csr32(ctlr, ReceiveListPlacementMode) |= Enable;
657 csr32(ctlr, MACMode) |= MACEnable;
658 csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
659 csr32(ctlr, InterruptMailbox) = 0;
660 csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
661 csr32(ctlr, ReadDMAMode) |= 0x3fe;
662 csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
663 csr32(ctlr, SendDataCompletionMode) |= Enable;
664 csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
665 csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
666 csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
667 csr32(ctlr, SendDataInitiatorMode) |= Enable;
668 csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
669 csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
671 while(replenish(ctlr) >= 0);
672 csr32(ctlr, TransmitMACMode) |= Enable;
673 csr32(ctlr, ReceiveMACMode) |= Enable;
674 csr32(ctlr, PowerControlStatus) &= ~3;
675 csr32(ctlr, MIStatus) |= 1<<0;
676 csr32(ctlr, MACEventEnable) = 0;
677 csr32(ctlr, MACEventStatus) |= (1<<12);
678 csr32(ctlr, MIMode) = 0xC0000;
680 miiw(ctlr, PhyControl, 1<<15);
681 for(i = 0; i < 1000 && miir(ctlr, PhyControl) & (1<<15); i++)
684 iprint("bcm: PHY failed to reset\n");
687 miiw(ctlr, PhyAuxControl, 2);
688 miir(ctlr, PhyIntStatus);
689 miir(ctlr, PhyIntStatus);
690 miiw(ctlr, PhyIntMask, ~(1<<1));
692 csr32(ctlr, MACEventEnable) |= 1<<12;
693 csr32(ctlr, MACHash) = -1;
694 csr32(ctlr, MACHash+4) = -1;
695 csr32(ctlr, MACHash+8) = -1;
696 csr32(ctlr, MACHash+12) = -1;
697 for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
698 csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
699 csr32(ctlr, MSIMode) |= Enable;
700 csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
710 while(pdev = pcimatch(pdev, 0, 0)) {
714 if(pdev->ccrb != 2 || pdev->ccru != 0)
716 if(pdev->vid != 0x14e4)
718 if(pdev->mem[0].bar & 1)
802 case BCM5906: /* ??? */
803 case BCM5906M: /* ??? */
804 case 0x1670: /* ??? */
807 ctlr = malloc(sizeof(Ctlr));
809 print("bcm: unable to alloc Ctlr\n");
812 ctlr->sends = malloc(sizeof(ctlr->sends[0]) * SendRingLen);
813 ctlr->recvs = malloc(sizeof(ctlr->recvs[0]) * RecvProdRingLen);
814 if(ctlr->sends == nil || ctlr->recvs == nil){
815 print("bcm: unable to alloc ctlr->sends and ctlr->recvs\n");
821 ctlr->port = pdev->mem[0].bar & ~0xF;
822 mem = vmap(ctlr->port, pdev->mem[0].size);
824 print("bcm: can't map %llux\n", ctlr->port);
832 ctlr->status = xspanalloc(20, 16, 0);
833 ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
834 ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
835 ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
837 bcmtail->link = ctlr;
845 bcmpromiscuous(void* arg, int on)
849 ctlr = ((Ether*)arg)->ctlr;
851 csr32(ctlr, ReceiveMACMode) |= 1<<8;
853 csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
857 bcmmulticast(void*, uchar*, int)
870 for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
874 if(edev->port == 0 || edev->port == ctlr->port) {
883 pcienable(ctlr->pdev);
884 pcisetbme(ctlr->pdev);
887 edev->port = ctlr->port;
888 edev->irq = ctlr->pdev->intl;
889 edev->tbdf = ctlr->pdev->tbdf;
890 edev->transmit = bcmtransmit;
891 edev->multicast = bcmmulticast;
892 edev->promiscuous = bcmpromiscuous;
896 if(bcminit(edev) < 0){
901 intrenable(edev->irq, bcminterrupt, edev, edev->tbdf, edev->name);
909 addethercard("bcm", bcmpnp);