4 * proper fatal error handling
11 #include "../port/lib.h"
16 #include "../port/error.h"
17 #include "../port/netif.h"
21 #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
23 typedef struct Ctlr Ctlr;
29 /* One Ring to find them, One Ring to bring them all and in the darkness bind them */
30 ulong *recvret, *recvprod, *sendr;
32 ulong recvreti, recvprodi, sendri, sendcleani;
38 RecvRetRingLen = 0x200,
39 RecvProdRingLen = 0x200,
48 PowerControlStatus = 0x4C,
53 IndirectAccessEnable = 1<<7,
54 EnablePCIStateRegister = 1<<4,
55 EnableClockControlRegister = 1<<5,
59 DMAWatermarkMask = ~(7<<19),
60 DMAWatermarkValue = 3<<19,
63 MemoryWindowData = 0x84,
68 InterruptMailbox = 0x204,
70 RecvProdBDRingIndex = 0x26c,
71 RecvBDRetRingIndex = 0x284,
72 SendBDRingHostIndex = 0x304,
75 MACPortMask = ~((1<<3)|(1<<2)),
78 MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11),
81 MACEventStatus = 0x404,
82 MACEventEnable = 0x408,
84 EthernetRandomBackoff = 0x438,
89 ReceiveMACMode = 0x468,
90 TransmitMACMode = 0x45C,
91 TransmitMACLengths = 0x464,
95 ReceiveRulesConfiguration = 0x500,
96 LowWatermarkMaximum = 0x504,
97 LowWatermarkMaxMask = ~0xFFFF,
98 LowWatermarkMaxValue = 2,
100 SendDataInitiatorMode = 0xC00,
101 SendInitiatorConfiguration = 0x0C08,
103 SendInitiatorMask = 0x0C0C,
105 SendDataCompletionMode = 0x1000,
106 SendBDSelectorMode = 0x1400,
107 SendBDInitiatorMode = 0x1800,
108 SendBDCompletionMode = 0x1C00,
110 ReceiveListPlacementMode = 0x2000,
111 ReceiveListPlacement = 0x2010,
112 ReceiveListPlacementConfiguration = 0x2014,
114 ReceiveListPlacementMask = 0x2018,
116 ReceiveDataBDInitiatorMode = 0x2400,
117 ReceiveBDHostAddr = 0x2450,
118 ReceiveBDFlags = 0x2458,
119 ReceiveBDNIC = 0x245C,
120 ReceiveDataCompletionMode = 0x2800,
121 ReceiveBDInitiatorMode = 0x2C00,
122 ReceiveBDRepl = 0x2C18,
124 ReceiveBDCompletionMode = 0x3000,
125 HostCoalescingMode = 0x3C00,
126 HostCoalescingRecvTicks = 0x3C08,
127 HostCoalescingSendTicks = 0x3C0C,
128 RecvMaxCoalescedFrames = 0x3C10,
129 SendMaxCoalescedFrames = 0x3C14,
130 RecvMaxCoalescedFramesInt = 0x3C20,
131 SendMaxCoalescedFramesInt = 0x3C24,
132 StatusBlockHostAddr = 0x3C38,
133 FlowAttention = 0x3C48,
135 MemArbiterMode = 0x4000,
137 BufferManMode = 0x4400,
139 MBUFLowWatermark = 0x4414,
140 MBUFHighWatermark = 0x4418,
142 ReadDMAMode = 0x4800,
143 ReadDMAStatus = 0x4804,
144 WriteDMAMode = 0x4C00,
145 WriteDMAStatus = 0x4C04,
151 ModeControl = 0x6800,
152 ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1),
155 InterruptOnMAC = 1<<26,
157 MiscConfiguration = 0x6804,
158 CoreClockBlocksReset = 1<<0,
159 GPHYPowerDownOverride = 1<<26,
160 DisableGRCResetOnPCIE = 1<<29,
163 MiscLocalControl = 0x6808,
164 InterruptOnAttn = 1<<3,
167 SwArbitration = 0x7020,
174 PhyLinkStatus = 1<<2,
175 PhyAutoNegComplete = 1<<5,
176 PhyPartnerStatus = 0x05,
181 PhyGbitStatus = 0x0A,
184 PhyAuxControl = 0x18,
189 LinkStateChange = 1<<1,
196 #define csr32(c, r) ((c)->nic[(r)/4])
197 #define mem32(c, r) csr32(c, (r)+0x8000)
199 static Ctlr *bcmhead, *bcmtail;
208 miir(Ctlr *ctlr, int ra)
210 while(csr32(ctlr, MIComm) & (1<<29));
211 csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
212 while(csr32(ctlr, MIComm) & (1<<29));
213 if(csr32(ctlr, MIComm) & (1<<28)) return -1;
214 return csr32(ctlr, MIComm) & 0xFFFF;
218 miiw(Ctlr *ctlr, int ra, int value)
220 while(csr32(ctlr, MIComm) & (1<<29));
221 csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
222 while(csr32(ctlr, MIComm) & (1<<29));
227 checklink(Ether *edev)
233 miir(ctlr, PhyStatus); /* dummy read necessary */
234 if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
238 print("bcm: no link\n");
242 while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
243 i = miir(ctlr, PhyGbitStatus);
244 if(i & (Phy1000FD | Phy1000HD)) {
246 ctlr->duplex = (i & Phy1000FD) != 0;
247 } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
249 ctlr->duplex = (i & Phy100FD) != 0;
250 } else if(i & (Phy10FD | Phy10HD)) {
252 ctlr->duplex = (i & Phy10FD) != 0;
257 print("bcm: link partner supports neither 10/100/1000 Mbps\n");
260 print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
262 if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
263 else csr32(ctlr, MACMode) |= MACHalfDuplex;
264 if(edev->mbps >= 1000)
265 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
267 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
268 csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */
272 currentrecvret(Ctlr *ctlr)
274 if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0;
275 return ctlr->recvret + ctlr->recvreti * 8;
279 consumerecvret(Ctlr *ctlr)
281 csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
285 replenish(Ctlr *ctlr)
291 incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1);
292 if(incr == (ctlr->status[2] >> 16)) return -1;
295 print("bcm: out of memory for receive buffers\n");
298 next = ctlr->recvprod + ctlr->recvprodi * 8;
300 next[1] = PADDR(bp->rp);
302 next[7] = (ulong) bp;
303 csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
308 bcmreceive(Ether *edev)
315 for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
316 bp = (Block*) pkt[7];
317 len = pkt[2] & 0xFFFF;
318 bp->wp = bp->rp + len;
319 if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
320 if(pkt[3] & FrameError) {
321 freeb(bp); /* dump erroneous packets */
323 etheriq(edev, bp, 1);
329 bcmtransclean(Ether *edev)
334 ilock(&ctlr->txlock);
335 while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
336 freeb(ctlr->sends[ctlr->sendri]);
337 ctlr->sends[ctlr->sendri] = 0;
338 ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
340 iunlock(&ctlr->txlock);
344 bcmtransmit(Ether *edev)
352 ilock(&ctlr->txlock);
354 incr = (ctlr->sendri + 1) & (SendRingLen - 1);
355 if(incr == (ctlr->status[4] >> 16)) {
356 print("bcm: send queue full\n");
361 next = ctlr->sendr + ctlr->sendri * 4;
363 next[1] = PADDR(bp->rp);
364 next[2] = (BLEN(bp) << 16) | PacketEnd;
366 ctlr->sends[ctlr->sendri] = bp;
367 csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
369 iunlock(&ctlr->txlock);
373 bcmerror(Ether *edev)
378 if(csr32(ctlr, FlowAttention)) {
379 if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
380 panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
382 csr32(ctlr, FlowAttention) = 0;
384 csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
385 if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
386 print("bcm: DMA error\n");
387 csr32(ctlr, ReadDMAStatus) = 0;
388 csr32(ctlr, WriteDMAStatus) = 0;
390 if(csr32(ctlr, RISCState)) {
391 if(csr32(ctlr, RISCState) & 0x78000403) {
392 panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
394 csr32(ctlr, RISCState) = 0;
399 bcminterrupt(Ureg*, void *arg)
407 dummyread(csr32(ctlr, InterruptMailbox));
408 csr32(ctlr, InterruptMailbox) = 1;
409 status = ctlr->status[0];
410 tag = ctlr->status[1];
412 if(status & Error) bcmerror(edev);
413 if(status & LinkStateChange) checklink(edev);
414 // print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
418 csr32(ctlr, InterruptMailbox) = tag << 24;
428 print("bcm: reset\n");
429 /* initialization procedure according to the datasheet */
430 csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
431 csr32(ctlr, SwArbitration) |= SwArbitSet1;
432 while((csr32(ctlr, SwArbitration) & SwArbitWon1) == 0);
433 csr32(ctlr, MemArbiterMode) |= Enable;
434 csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
435 csr32(ctlr, MemoryWindow) = 0;
436 mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
437 csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
438 csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
440 ctlr->pdev->pcr |= 1<<1;
441 pcisetbme(ctlr->pdev);
442 csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
443 csr32(ctlr, MemArbiterMode) |= Enable;
444 csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
445 csr32(ctlr, ModeControl) |= ByteWordSwap;
446 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
448 while(mem32(ctlr, 0xB50) != 0xB49A89AB);
449 csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
450 memset(ctlr->status, 0, 20);
451 csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
452 csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
453 csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
454 csr32(ctlr, MBUFLowWatermark) = 0x20;
455 csr32(ctlr, MBUFHighWatermark) = 0x60;
456 csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
457 csr32(ctlr, BufferManMode) |= Enable | Attn;
458 while((csr32(ctlr, BufferManMode) & Enable) == 0);
459 csr32(ctlr, FTQReset) = -1;
460 csr32(ctlr, FTQReset) = 0;
461 while(csr32(ctlr, FTQReset));
462 csr32(ctlr, ReceiveBDHostAddr) = 0;
463 csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
464 csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
465 csr32(ctlr, ReceiveBDNIC) = 0x6000;
466 csr32(ctlr, ReceiveBDRepl) = 25;
467 csr32(ctlr, SendBDRingHostIndex) = 0;
468 csr32(ctlr, SendBDRingHostIndex+4) = 0;
469 mem32(ctlr, SendRCB) = 0;
470 mem32(ctlr, SendRCB + 4) = PADDR(ctlr->sendr);
471 mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
472 mem32(ctlr, SendRCB + 12) = 0x4000;
474 mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
475 mem32(ctlr, RecvRetRCB) = 0;
476 mem32(ctlr, RecvRetRCB + 4) = PADDR(ctlr->recvret);
477 mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
478 csr32(ctlr, RecvProdBDRingIndex) = 0;
479 csr32(ctlr, RecvProdBDRingIndex+4) = 0;
480 /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
482 i = csr32(ctlr, 0x410);
483 j = edev->ea[0] = i >> 8;
484 j += edev->ea[1] = i;
485 i = csr32(ctlr, MACAddress + 4);
486 j += edev->ea[2] = i >> 24;
487 j += edev->ea[3] = i >> 16;
488 j += edev->ea[4] = i >> 8;
489 j += edev->ea[5] = i;
490 csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
491 csr32(ctlr, ReceiveMTU) = Rbsz;
492 csr32(ctlr, TransmitMACLengths) = 0x2620;
493 csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
494 csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
495 csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
496 csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
497 csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
498 csr32(ctlr, HostCoalescingMode) = 0;
499 while(csr32(ctlr, HostCoalescingMode) != 0);
500 csr32(ctlr, HostCoalescingRecvTicks) = 150;
501 csr32(ctlr, HostCoalescingSendTicks) = 150;
502 csr32(ctlr, RecvMaxCoalescedFrames) = 10;
503 csr32(ctlr, SendMaxCoalescedFrames) = 10;
504 csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
505 csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
506 csr32(ctlr, StatusBlockHostAddr) = 0;
507 csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(ctlr->status);
508 csr32(ctlr, HostCoalescingMode) |= Enable;
509 csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
510 csr32(ctlr, ReceiveListPlacementMode) |= Enable;
511 csr32(ctlr, MACMode) |= MACEnable;
512 csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
513 csr32(ctlr, InterruptMailbox) = 0;
514 csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
515 csr32(ctlr, ReadDMAMode) |= 0x3fe;
516 csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
517 csr32(ctlr, SendDataCompletionMode) |= Enable;
518 csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
519 csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
520 csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
521 csr32(ctlr, SendDataInitiatorMode) |= Enable;
522 csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
523 csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
525 while(replenish(ctlr) >= 0);
526 csr32(ctlr, TransmitMACMode) |= Enable;
527 csr32(ctlr, ReceiveMACMode) |= Enable;
528 csr32(ctlr, PowerControlStatus) &= ~3;
529 csr32(ctlr, MIStatus) |= 1<<0;
530 csr32(ctlr, MACEventEnable) = 0;
531 csr32(ctlr, MACEventStatus) |= (1<<12);
532 csr32(ctlr, MIMode) = 0xC0000;
534 miiw(ctlr, PhyControl, 1<<15);
535 while(miir(ctlr, PhyControl) & (1<<15));
536 miiw(ctlr, PhyAuxControl, 2);
537 miir(ctlr, PhyIntStatus);
538 miir(ctlr, PhyIntStatus);
539 miiw(ctlr, PhyIntMask, ~(1<<1));
541 csr32(ctlr, MACEventEnable) |= 1<<12;
542 csr32(ctlr, MACHash) = -1;
543 csr32(ctlr, MACHash+4) = -1;
544 csr32(ctlr, MACHash+8) = -1;
545 csr32(ctlr, MACHash+12) = -1;
546 for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
547 csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
548 csr32(ctlr, MSIMode) &= ~Enable;
549 while(csr32(ctlr, MSIMode) & Enable);
550 csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
559 while(pdev = pcimatch(pdev, 0, 0)) {
563 if(pdev->ccrb != 2 || pdev->ccru != 0)
566 switch((pdev->vid<<16) | pdev->did){
584 ctlr = malloc(sizeof(Ctlr));
586 print("bcm: unable to alloc Ctlr\n");
589 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
591 print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
597 ctlr->port = pdev->mem[0].bar & ~0x0F;
598 ctlr->status = xspanalloc(20, 16, 0);
599 ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
600 ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
601 ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
602 ctlr->sends = malloc(sizeof(Block) * SendRingLen);
604 bcmtail->link = ctlr;
612 bcmpromiscuous(void* arg, int on)
616 ctlr = ((Ether*)arg)->ctlr;
618 csr32(ctlr, ReceiveMACMode) |= 1<<8;
620 csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
624 bcmmulticast(void*, uchar*, int)
636 for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
640 if(edev->port == 0 || edev->port == ctlr->port) {
650 edev->port = ctlr->port;
651 edev->irq = ctlr->pdev->intl;
652 edev->tbdf = ctlr->pdev->tbdf;
653 edev->interrupt = bcminterrupt;
654 edev->transmit = bcmtransmit;
655 edev->multicast = bcmmulticast;
656 edev->promiscuous = bcmpromiscuous;
667 addethercard("BCM57xx", bcmpnp);