]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherbcm.c
ether82563: fix multicast for i210
[plan9front.git] / sys / src / 9 / pc / etherbcm.c
1 /*
2  * Broadcom BCM57xx
3  * Not implemented:
4  *  proper fatal error handling
5  *  multiple rings
6  *  QoS
7  *  checksum offloading
8  */
9
10 #include "u.h"
11 #include "../port/lib.h"
12 #include "mem.h"
13 #include "dat.h"
14 #include "fns.h"
15 #include "io.h"
16 #include "../port/error.h"
17 #include "../port/netif.h"
18 #include "../port/etherif.h"
19
20 #define Rbsz            ROUNDUP(sizeof(Etherpkt)+4, 4)
21
22 typedef struct Ctlr Ctlr;
23 struct Ctlr {
24         Lock txlock, imlock;
25         Ctlr *link;
26         Pcidev *pdev;
27         ulong *nic, *status;
28         /* One Ring to find them, One Ring to bring them all and in the darkness bind them */
29         ulong *recvret, *recvprod, *sendr;
30         ulong port;
31         ulong recvreti, recvprodi, sendri, sendcleani;
32         Block **sends, **recvs;
33         int active, duplex;
34 };
35
36 enum {
37         RecvRetRingLen = 0x200,
38         RecvProdRingLen = 0x200,
39         SendRingLen = 0x200,
40 };
41
42 enum {
43         Reset = 1<<0,
44         Enable = 1<<1,
45         Attn = 1<<2,
46         
47         PowerControlStatus = 0x4C,
48
49         MiscHostCtl = 0x68,
50         ClearIntA = 1<<0,
51         MaskPCIInt = 1<<1,
52         ByteSwap = 1<<2,
53         WordSwap = 1<<3,
54         EnablePCIStateRegister = 1<<4,
55         EnableClockControlRegister = 1<<5,
56         IndirectAccessEnable = 1<<7,
57         TaggedStatus = 1<<9,
58         
59         DMARWControl = 0x6C,
60         DMAWatermarkMask = ~(7<<19),
61         DMAWatermarkValue = 3<<19,
62
63         MemoryWindow = 0x7C,
64         MemoryWindowData = 0x84,
65         
66         SendRCB = 0x100,
67         RecvRetRCB = 0x200,
68         
69         InterruptMailbox = 0x204,
70         
71         RecvProdBDRingIndex = 0x26c,
72         RecvBDRetRingIndex = 0x284,
73         SendBDRingHostIndex = 0x304,
74         
75         MACMode = 0x400,
76         MACPortMask = ~((1<<3)|(1<<2)),
77         MACPortGMII = 1<<3,
78         MACPortMII = 1<<2,
79         MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11),
80         MACHalfDuplex = 1<<1,
81         
82         MACEventStatus = 0x404,
83         MACEventEnable = 0x408,
84         MACAddress = 0x410,
85         EthernetRandomBackoff = 0x438,
86         ReceiveMTU = 0x43C,
87         MIComm = 0x44C,
88         MIStatus = 0x450,
89         MIMode = 0x454,
90         ReceiveMACMode = 0x468,
91         TransmitMACMode = 0x45C,
92         TransmitMACLengths = 0x464,
93         MACHash = 0x470,
94         ReceiveRules = 0x480,
95         
96         ReceiveRulesConfiguration = 0x500,
97         LowWatermarkMaximum = 0x504,
98         LowWatermarkMaxMask = ~0xFFFF,
99         LowWatermarkMaxValue = 2,
100
101         SendDataInitiatorMode = 0xC00,
102         SendInitiatorConfiguration = 0x0C08,
103         SendStats = 1<<0,
104         SendInitiatorMask = 0x0C0C,
105         
106         SendDataCompletionMode = 0x1000,
107         SendBDSelectorMode = 0x1400,
108         SendBDInitiatorMode = 0x1800,
109         SendBDCompletionMode = 0x1C00,
110         
111         ReceiveListPlacementMode = 0x2000,
112         ReceiveListPlacement = 0x2010,
113         ReceiveListPlacementConfiguration = 0x2014,
114         ReceiveStats = 1<<0,
115         ReceiveListPlacementMask = 0x2018,
116         
117         ReceiveDataBDInitiatorMode = 0x2400,
118         ReceiveBDHostAddr = 0x2450,
119         ReceiveBDFlags = 0x2458,
120         ReceiveBDNIC = 0x245C,
121         ReceiveDataCompletionMode = 0x2800,
122         ReceiveBDInitiatorMode = 0x2C00,
123         ReceiveBDRepl = 0x2C18,
124         
125         ReceiveBDCompletionMode = 0x3000,
126         HostCoalescingMode = 0x3C00,
127         HostCoalescingRecvTicks = 0x3C08,
128         HostCoalescingSendTicks = 0x3C0C,
129         RecvMaxCoalescedFrames = 0x3C10,
130         SendMaxCoalescedFrames = 0x3C14,
131         RecvMaxCoalescedFramesInt = 0x3C20,
132         SendMaxCoalescedFramesInt = 0x3C24,
133         StatusBlockHostAddr = 0x3C38,
134         FlowAttention = 0x3C48,
135
136         MemArbiterMode = 0x4000,
137         
138         BufferManMode = 0x4400,
139         
140         MBUFLowWatermark = 0x4414,
141         MBUFHighWatermark = 0x4418,
142         
143         ReadDMAMode = 0x4800,
144         ReadDMAStatus = 0x4804,
145         WriteDMAMode = 0x4C00,
146         WriteDMAStatus = 0x4C04,
147         
148         RISCState = 0x5004,
149         FTQReset = 0x5C00,
150         MSIMode = 0x6000,
151         
152         ModeControl = 0x6800,
153         ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1),
154         HostStackUp = 1<<16,
155         HostSendBDs = 1<<17,
156         InterruptOnMAC = 1<<26,
157         
158         MiscConfiguration = 0x6804,
159         CoreClockBlocksReset = 1<<0,
160         GPHYPowerDownOverride = 1<<26,
161         DisableGRCResetOnPCIE = 1<<29,
162         TimerMask = ~0xFF,
163         TimerValue = 65<<1,
164         MiscLocalControl = 0x6808,
165         InterruptOnAttn = 1<<3,
166         AutoSEEPROM = 1<<24,
167         
168         SwArbitration = 0x7020,
169         SwArbitSet1 = 1<<1,
170         SwArbitWon1 = 1<<9,
171         TLPControl = 0x7C00,
172         
173         PhyControl = 0x00,
174         PhyStatus = 0x01,
175         PhyLinkStatus = 1<<2,
176         PhyAutoNegComplete = 1<<5,
177         PhyPartnerStatus = 0x05,
178         Phy100FD = 1<<8,
179         Phy100HD = 1<<7,
180         Phy10FD = 1<<6,
181         Phy10HD = 1<<5,
182         PhyGbitStatus = 0x0A,
183         Phy1000FD = 1<<12,
184         Phy1000HD = 1<<11,
185         PhyAuxControl = 0x18,
186         PhyIntStatus = 0x1A,
187         PhyIntMask = 0x1B,
188         
189         Updated = 1<<0,
190         LinkStateChange = 1<<1,
191         Error = 1<<2,
192         
193         PacketEnd = 1<<2,
194         FrameError = 1<<10,
195 };
196
197 enum {
198         BCM5752 = 0x1600, 
199         BCM5752M = 0x1601, 
200         BCM5709 = 0x1639, 
201         BCM5709S = 0x163a, 
202         BCM5716 = 0x163b, 
203         BCM5716S = 0x163c, 
204         BCM5700 = 0x1644, 
205         BCM5701 = 0x1645, 
206         BCM5702 = 0x1646, 
207         BCM5703 = 0x1647, 
208         BCM5704 = 0x1648, 
209         BCM5704S_2 = 0x1649, 
210         BCM5706 = 0x164a, 
211         BCM5708 = 0x164c, 
212         BCM5702FE = 0x164d, 
213         BCM57710 = 0x164e, 
214         BCM57711 = 0x164f, 
215         BCM57711E = 0x1650, 
216         BCM5705 = 0x1653, 
217         BCM5705_2 = 0x1654, 
218         BCM5717 = 0x1655, 
219         BCM5718 = 0x1656, 
220         BCM5720 = 0x1658, 
221         BCM5721 = 0x1659, 
222         BCM5722 = 0x165a, 
223         BCM5723 = 0x165b, 
224         BCM5724 = 0x165c, 
225         BCM5705M = 0x165d, 
226         BCM5705M_2 = 0x165e, 
227         BCM5714 = 0x1668, 
228         BCM5780 = 0x166a, 
229         BCM5780S = 0x166b, 
230         BCM5754M = 0x1672, 
231         BCM5755M = 0x1673, 
232         BCM5756ME = 0x1674, 
233         BCM5750 = 0x1676, 
234         BCM5751 = 0x1677, 
235         BCM5715 = 0x1678, 
236         BCM5715S = 0x1679, 
237         BCM5754 = 0x167a, 
238         BCM5755 = 0x167b, 
239         BCM5750M = 0x167c, 
240         BCM5751M = 0x167d, 
241         BCM5751F = 0x167e, 
242         BCM5787F = 0x167f, 
243         BCM5761e = 0x1680, 
244         BCM5761 = 0x1681, 
245         BCM5764M = 0x1684, 
246         BCM57760 = 0x1690, 
247         BCM57788 = 0x1691, 
248         BCM57780 = 0x1692, 
249         BCM5787M = 0x1693, 
250         BCM57790 = 0x1694, 
251         BCM5782 = 0x1696, 
252         BCM5784M = 0x1698, 
253         BCM5785 = 0x1699, 
254         BCM5786 = 0x169a, 
255         BCM5787 = 0x169b, 
256         BCM5788 = 0x169c, 
257         BCM5789 = 0x169d, 
258         BCM5785_2 = 0x16a0, 
259         BCM5702X = 0x16a6, 
260         BCM5703X = 0x16a7, 
261         BCM5704S = 0x16a8, 
262         BCM5706S = 0x16aa, 
263         BCM5708S = 0x16ac, 
264         BCM57761 = 0x16b0, 
265         BCM57781 = 0x16b1, 
266         BCM57791 = 0x16b2, 
267         BCM57765 = 0x16b4, 
268         BCM57785 = 0x16b5, 
269         BCM57795 = 0x16b6, 
270         BCM5702A3 = 0x16c6, 
271         BCM5703_2 = 0x16c7, 
272         BCM5781 = 0x16dd, 
273         BCM5753 = 0x16f7, 
274         BCM5753M = 0x16fd, 
275         BCM5753F = 0x16fe, 
276         BCM5906 = 0x1712,
277         BCM5906M = 0x1713,
278 };
279
280 #define csr32(c, r)     ((c)->nic[(r)/4])
281 #define mem32(c, r) csr32(c, (r)+0x8000)
282
283 static Ctlr *bcmhead, *bcmtail;
284
285 static ulong
286 dummyread(ulong x)
287 {
288         return x;
289 }
290
291 static int
292 miir(Ctlr *ctlr, int ra)
293 {
294         while(csr32(ctlr, MIComm) & (1<<29));
295         csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
296         while(csr32(ctlr, MIComm) & (1<<29));
297         if(csr32(ctlr, MIComm) & (1<<28)) return -1;
298         return csr32(ctlr, MIComm) & 0xFFFF;
299 }
300
301 static int
302 miiw(Ctlr *ctlr, int ra, int value)
303 {
304         while(csr32(ctlr, MIComm) & (1<<29));
305         csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
306         while(csr32(ctlr, MIComm) & (1<<29));
307         return 0;
308 }
309
310 static void
311 checklink(Ether *edev)
312 {
313         Ctlr *ctlr;
314         ulong i;
315
316         ctlr = edev->ctlr;
317         miir(ctlr, PhyStatus); /* dummy read necessary */
318         if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
319                 edev->link = 0;
320                 edev->mbps = 1000;
321                 ctlr->duplex = 1;
322                 print("bcm: no link\n");
323                 goto out;
324         }
325         edev->link = 1;
326         while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
327         i = miir(ctlr, PhyGbitStatus);
328         if(i & (Phy1000FD | Phy1000HD)) {
329                 edev->mbps = 1000;
330                 ctlr->duplex = (i & Phy1000FD) != 0;
331         } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
332                 edev->mbps = 100;
333                 ctlr->duplex = (i & Phy100FD) != 0;
334         } else if(i & (Phy10FD | Phy10HD)) {
335                 edev->mbps = 10;
336                 ctlr->duplex = (i & Phy10FD) != 0;
337         } else {
338                 edev->link = 0;
339                 edev->mbps = 1000;
340                 ctlr->duplex = 1;
341                 print("bcm: link partner supports neither 10/100/1000 Mbps\n"); 
342                 goto out;
343         }
344         print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
345 out:
346         if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
347         else csr32(ctlr, MACMode) |= MACHalfDuplex;
348         if(edev->mbps >= 1000)
349                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
350         else
351                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
352         csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */
353 }
354
355 static ulong*
356 currentrecvret(Ctlr *ctlr)
357 {
358         if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0;
359         return ctlr->recvret + ctlr->recvreti * 8;
360 }
361
362 static void
363 consumerecvret(Ctlr *ctlr)
364 {
365         csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
366 }
367
368 static int
369 replenish(Ctlr *ctlr)
370 {
371         ulong *next;
372         ulong incr, idx;
373         Block *bp;
374
375         idx = ctlr->recvprodi;
376         incr = (idx + 1) & (RecvProdRingLen - 1);
377         if(incr == (ctlr->status[2] >> 16)) return -1;
378         if(ctlr->recvs[idx] != 0) return -1;
379         bp = iallocb(Rbsz);
380         if(bp == nil) {
381                 print("bcm: out of memory for receive buffers\n");
382                 return -1;
383         }
384         ctlr->recvs[idx] = bp;
385         next = ctlr->recvprod + idx * 8;
386         memset(next, 0, 32);
387         next[1] = PADDR(bp->rp);
388         next[2] = Rbsz;
389         next[7] = idx;
390         coherence();
391         csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
392         return 0;
393 }
394
395 static void
396 bcmreceive(Ether *edev)
397 {
398         Ctlr *ctlr;
399         Block *bp;
400         ulong *pkt, len, idx;
401         
402         ctlr = edev->ctlr;
403         for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
404                 idx = pkt[7] & (RecvProdRingLen - 1);
405                 bp = ctlr->recvs[idx];
406                 if(bp == 0) {
407                         print("bcm: nil block at %lux -- shouldn't happen\n", idx);
408                         break;
409                 }
410                 ctlr->recvs[idx] = 0;
411                 len = pkt[2] & 0xFFFF;
412                 bp->wp = bp->rp + len;
413                 if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
414                 if(pkt[3] & FrameError) {
415                         freeb(bp); /* dump erroneous packets */ 
416                 } else {
417                         etheriq(edev, bp);
418                 }
419         }
420 }
421
422 static void
423 bcmtransclean(Ether *edev, int dolock)
424 {
425         Ctlr *ctlr;
426         
427         ctlr = edev->ctlr;
428         if(dolock)
429                 ilock(&ctlr->txlock);
430         while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
431                 freeb(ctlr->sends[ctlr->sendcleani]);
432                 ctlr->sends[ctlr->sendcleani] = 0;
433                 ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
434         }
435         if(dolock)
436                 iunlock(&ctlr->txlock);
437 }
438
439 static void
440 bcmtransmit(Ether *edev)
441 {
442         Ctlr *ctlr;
443         Block *bp;
444         ulong *next;
445         ulong incr;
446         
447         ctlr = edev->ctlr;
448         ilock(&ctlr->txlock);
449         while(1) {
450                 incr = (ctlr->sendri + 1) & (SendRingLen - 1);
451                 if(incr == (ctlr->status[4] >> 16)) {
452                         print("bcm: send queue full\n");
453                         break;
454                 }
455                 bp = qget(edev->oq);
456                 if(bp == nil) break;
457                 next = ctlr->sendr + ctlr->sendri * 4;
458                 next[0] = 0;
459                 next[1] = PADDR(bp->rp);
460                 next[2] = (BLEN(bp) << 16) | PacketEnd;
461                 next[3] = 0;
462                 if(ctlr->sends[ctlr->sendri] != 0)
463                         freeb(ctlr->sends[ctlr->sendri]);
464                 ctlr->sends[ctlr->sendri] = bp;
465                 coherence();
466                 csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
467         }
468         iunlock(&ctlr->txlock);
469 }
470
471 static void
472 bcmerror(Ether *edev)
473 {
474         Ctlr *ctlr;
475         
476         ctlr = edev->ctlr;
477         if(csr32(ctlr, FlowAttention)) {
478                 if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
479                         panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
480                 }
481                 csr32(ctlr, FlowAttention) = 0;
482         }
483         csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
484         if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
485                 print("bcm: DMA error\n");
486                 csr32(ctlr, ReadDMAStatus) = 0;
487                 csr32(ctlr, WriteDMAStatus) = 0;
488         }
489         if(csr32(ctlr, RISCState)) {
490                 if(csr32(ctlr, RISCState) & 0x78000403) {
491                         panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
492                 }
493                 csr32(ctlr, RISCState) = 0;
494         }
495 }
496
497 static void
498 bcminterrupt(Ureg*, void *arg)
499 {
500         Ether *edev;
501         Ctlr *ctlr;
502         ulong status, tag;
503         
504         edev = arg;
505         ctlr = edev->ctlr;
506         ilock(&ctlr->imlock);
507         dummyread(csr32(ctlr, InterruptMailbox));
508         csr32(ctlr, InterruptMailbox) = 1;
509         status = ctlr->status[0];
510         tag = ctlr->status[1];
511         ctlr->status[0] = 0;
512         if(status & Error) bcmerror(edev);
513         if(status & LinkStateChange) checklink(edev);
514 //      print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
515         bcmreceive(edev);
516         bcmtransclean(edev, 1);
517         bcmtransmit(edev);
518         csr32(ctlr, InterruptMailbox) = tag << 24;
519         iunlock(&ctlr->imlock);
520 }
521
522 static int
523 bcminit(Ether *edev)
524 {
525         ulong i, j;
526         Ctlr *ctlr;
527         
528         ctlr = edev->ctlr;
529         print("bcm: reset\n");
530         /* initialization procedure according to the datasheet */
531         csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
532         csr32(ctlr, SwArbitration) |= SwArbitSet1;
533         for(i = 0; i < 10000 && (csr32(ctlr, SwArbitration) & SwArbitWon1) == 0; i++)
534                 microdelay(100);
535         if(i == 10000){
536                 iprint("bcm: arbiter failed to respond\n");
537                 return -1;
538         }
539         csr32(ctlr, MemArbiterMode) |= Enable;
540         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
541         csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
542         csr32(ctlr, ModeControl) |= ByteWordSwap;
543         csr32(ctlr, MemoryWindow) = 0;
544         mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
545         csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
546         csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
547         microdelay(100000);
548         ctlr->pdev->pcr |= 1<<1; /* pci memory access enable */
549         pcisetbme(ctlr->pdev);
550         csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
551         csr32(ctlr, MemArbiterMode) |= Enable;
552         csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
553         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
554         csr32(ctlr, ModeControl) |= ByteWordSwap;
555         csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
556         microdelay(40000);
557         for(i = 0; i < 100000 && mem32(ctlr, 0xB50) != 0xB49A89AB; i++)
558                 microdelay(100);
559         if(i == 100000){
560                 iprint("bcm: chip failed to reset\n");
561                 return -1;
562         }
563         switch(ctlr->pdev->did){
564         case BCM5721:
565         case BCM5751:
566         case BCM5752:
567                 csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
568                 break;
569         }
570         memset(ctlr->status, 0, 20);
571         csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
572         csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
573         csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
574         csr32(ctlr, MBUFLowWatermark) = 0x20;
575         csr32(ctlr, MBUFHighWatermark) = 0x60;
576         csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
577         csr32(ctlr, BufferManMode) |= Enable | Attn;
578         for(i = 0; i < 100 && (csr32(ctlr, BufferManMode) & Enable) == 0; i++)
579                 microdelay(100);
580         if(i == 100){
581                 iprint("bcm: buffer manager failed to start\n");
582                 return -1;
583         }
584         csr32(ctlr, FTQReset) = -1;
585         csr32(ctlr, FTQReset) = 0;
586         for(i = 0; i < 1000 && csr32(ctlr, FTQReset) != 0; i++)
587                 microdelay(100);
588         if(i == 1000){
589                 iprint("bcm: ftq failed to reset\n");
590                 return -1;
591         }
592         csr32(ctlr, ReceiveBDHostAddr) = 0;
593         csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
594         csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
595         csr32(ctlr, ReceiveBDNIC) = 0x6000;
596         csr32(ctlr, ReceiveBDRepl) = 25;
597         csr32(ctlr, SendBDRingHostIndex) = 0;
598         csr32(ctlr, SendBDRingHostIndex+4) = 0;
599         mem32(ctlr, SendRCB) = 0;
600         mem32(ctlr, SendRCB + 4) = PADDR(ctlr->sendr);
601         mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
602         mem32(ctlr, SendRCB + 12) = 0x4000;
603         for(i=1;i<4;i++)
604                 mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
605         mem32(ctlr, RecvRetRCB) = 0;
606         mem32(ctlr, RecvRetRCB + 4) = PADDR(ctlr->recvret);
607         mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
608         csr32(ctlr, RecvProdBDRingIndex) = 0;
609         csr32(ctlr, RecvProdBDRingIndex+4) = 0;
610         /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
611         microdelay(1000); 
612         i = csr32(ctlr, 0x410);
613         j = edev->ea[0] = i >> 8;
614         j += edev->ea[1] = i;
615         i = csr32(ctlr, MACAddress + 4);
616         j += edev->ea[2] = i >> 24;
617         j += edev->ea[3] = i >> 16;
618         j += edev->ea[4] = i >> 8;
619         j += edev->ea[5] = i;
620         csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
621         csr32(ctlr, ReceiveMTU) = Rbsz;
622         csr32(ctlr, TransmitMACLengths) = 0x2620;
623         csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
624         csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
625         csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
626         csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
627         csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
628         csr32(ctlr, HostCoalescingMode) = 0;
629         for(i = 0; i < 200 && csr32(ctlr, HostCoalescingMode) != 0; i++)
630                 microdelay(100);
631         if(i == 200){
632                 iprint("bcm: host coalescing engine failed to stop\n");
633                 return -1;
634         }
635         csr32(ctlr, HostCoalescingRecvTicks) = 150;
636         csr32(ctlr, HostCoalescingSendTicks) = 150;
637         csr32(ctlr, RecvMaxCoalescedFrames) = 10;
638         csr32(ctlr, SendMaxCoalescedFrames) = 10;
639         csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
640         csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
641         csr32(ctlr, StatusBlockHostAddr) = 0;
642         csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(ctlr->status);
643         csr32(ctlr, HostCoalescingMode) |= Enable;
644         csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
645         csr32(ctlr, ReceiveListPlacementMode) |= Enable;
646         csr32(ctlr, MACMode) |= MACEnable;
647         csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
648         csr32(ctlr, InterruptMailbox) = 0;
649         csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
650         csr32(ctlr, ReadDMAMode) |= 0x3fe;
651         csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
652         csr32(ctlr, SendDataCompletionMode) |= Enable;
653         csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
654         csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
655         csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
656         csr32(ctlr, SendDataInitiatorMode) |= Enable;
657         csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
658         csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
659         ctlr->recvprodi = 0;
660         while(replenish(ctlr) >= 0);
661         csr32(ctlr, TransmitMACMode) |= Enable;
662         csr32(ctlr, ReceiveMACMode) |= Enable;
663         csr32(ctlr, PowerControlStatus) &= ~3;
664         csr32(ctlr, MIStatus) |= 1<<0;
665         csr32(ctlr, MACEventEnable) = 0;
666         csr32(ctlr, MACEventStatus) |= (1<<12);
667         csr32(ctlr, MIMode) = 0xC0000;
668         microdelay(40);
669         miiw(ctlr, PhyControl, 1<<15);
670         for(i = 0; i < 1000 && miir(ctlr, PhyControl) & (1<<15); i++)
671                 microdelay(100);
672         if(i == 1000){
673                 iprint("bcm: PHY failed to reset\n");
674                 return -1;
675         }
676         miiw(ctlr, PhyAuxControl, 2);
677         miir(ctlr, PhyIntStatus);
678         miir(ctlr, PhyIntStatus);
679         miiw(ctlr, PhyIntMask, ~(1<<1));
680         checklink(edev);
681         csr32(ctlr, MACEventEnable) |= 1<<12;
682         csr32(ctlr, MACHash) = -1;
683         csr32(ctlr, MACHash+4) = -1;
684         csr32(ctlr, MACHash+8) = -1;
685         csr32(ctlr, MACHash+12) = -1;
686         for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
687         csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
688         csr32(ctlr, MSIMode) |= Enable;
689         csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
690         return 0;
691 }
692
693 static void
694 bcmpci(void)
695 {
696         Pcidev *pdev;
697         
698         pdev = nil;
699         while(pdev = pcimatch(pdev, 0, 0)) {
700                 Ctlr *ctlr;
701                 void *mem;
702                 
703                 if(pdev->ccrb != 2 || pdev->ccru != 0)
704                         continue;
705                 if(pdev->vid != 0x14e4)
706                         continue;
707                 switch(pdev->did){
708                 default:
709                         continue;
710                 case BCM5752:
711                 case BCM5752M:
712                 case BCM5709:
713                 case BCM5709S:
714                 case BCM5716:
715                 case BCM5716S:
716                 case BCM5700:
717                 case BCM5701:
718                 case BCM5702:
719                 case BCM5703:
720                 case BCM5704:
721                 case BCM5704S_2:
722                 case BCM5706:
723                 case BCM5708:
724                 case BCM5702FE:
725                 case BCM57710:
726                 case BCM57711:
727                 case BCM57711E:
728                 case BCM5705:
729                 case BCM5705_2:
730                 case BCM5717:
731                 case BCM5718:
732                 case BCM5720:
733                 case BCM5721:
734                 case BCM5722:
735                 case BCM5723:
736                 case BCM5724:
737                 case BCM5705M:
738                 case BCM5705M_2:
739                 case BCM5714:
740                 case BCM5780:
741                 case BCM5780S:
742                 case BCM5754M:
743                 case BCM5755M:
744                 case BCM5756ME:
745                 case BCM5750:
746                 case BCM5751:
747                 case BCM5715:
748                 case BCM5715S:
749                 case BCM5754:
750                 case BCM5755:
751                 case BCM5750M:
752                 case BCM5751M:
753                 case BCM5751F:
754                 case BCM5787F:
755                 case BCM5761e:
756                 case BCM5761:
757                 case BCM5764M:
758                 case BCM57760:
759                 case BCM57788:
760                 case BCM57780:
761                 case BCM5787M:
762                 case BCM57790:
763                 case BCM5782:
764                 case BCM5784M:
765                 case BCM5785:
766                 case BCM5786:
767                 case BCM5787:
768                 case BCM5788:
769                 case BCM5789:
770                 case BCM5785_2:
771                 case BCM5702X:
772                 case BCM5703X:
773                 case BCM5704S:
774                 case BCM5706S:
775                 case BCM5708S:
776                 case BCM57761:
777                 case BCM57781:
778                 case BCM57791:
779                 case BCM57765:
780                 case BCM57785:
781                 case BCM57795:
782                 case BCM5702A3:
783                 case BCM5703_2:
784                 case BCM5781:
785                 case BCM5753:
786                 case BCM5753M:
787                 case BCM5753F:
788                 case BCM5906:   /* ??? */
789                 case BCM5906M:  /* ??? */
790                 case 0x1670:    /* ??? */
791                         break;
792                 }
793
794                 ctlr = malloc(sizeof(Ctlr));
795                 if(ctlr == nil) {
796                         print("bcm: unable to alloc Ctlr\n");
797                         continue;
798                 }
799                 ctlr->sends = malloc(sizeof(ctlr->sends[0]) * SendRingLen);
800                 ctlr->recvs = malloc(sizeof(ctlr->recvs[0]) * RecvProdRingLen);
801                 if(ctlr->sends == nil || ctlr->recvs == nil){
802                         print("bcm: unable to alloc ctlr->sends and ctlr->recvs\n");
803                         free(ctlr->sends);
804                         free(ctlr->recvs);
805                         free(ctlr);
806                         continue;
807                 }
808                 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
809                 if(mem == nil) {
810                         print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
811                         free(ctlr->sends);
812                         free(ctlr);
813                         continue;
814                 }
815                 ctlr->pdev = pdev;
816                 ctlr->nic = mem;
817                 ctlr->port = pdev->mem[0].bar & ~0x0F;
818                 ctlr->status = xspanalloc(20, 16, 0);
819                 ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
820                 ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
821                 ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
822                 if(bcmhead != nil)
823                         bcmtail->link = ctlr;
824                 else
825                         bcmhead = ctlr;
826                 bcmtail = ctlr;
827         }
828 }
829
830 static void
831 bcmpromiscuous(void* arg, int on)
832 {
833         Ctlr *ctlr;
834         
835         ctlr = ((Ether*)arg)->ctlr;
836         if(on)
837                 csr32(ctlr, ReceiveMACMode) |= 1<<8;
838         else
839                 csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
840 }
841
842 static void
843 bcmmulticast(void*, uchar*, int)
844 {
845 }
846
847 static int
848 bcmpnp(Ether* edev)
849 {
850         Ctlr *ctlr;
851         
852 again:
853         if(bcmhead == nil)
854                 bcmpci();
855         
856         for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
857                 if(ctlr->active)
858                         continue;
859                 
860                 if(edev->port == 0 || edev->port == ctlr->port) {
861                         ctlr->active = 1;
862                         break;
863                 }
864         }
865         
866         if(ctlr == nil)
867                 return -1;
868
869         pcienable(ctlr->pdev);
870         pcisetbme(ctlr->pdev);
871
872         edev->ctlr = ctlr;
873         edev->port = ctlr->port;
874         edev->irq = ctlr->pdev->intl;
875         edev->tbdf = ctlr->pdev->tbdf;
876         edev->transmit = bcmtransmit;
877         edev->multicast = bcmmulticast;
878         edev->promiscuous = bcmpromiscuous;
879         edev->arg = edev;
880         edev->mbps = 1000;
881         
882         if(bcminit(edev) < 0){
883                 edev->ctlr = nil;
884                 goto again;
885         }
886
887         intrenable(edev->irq, bcminterrupt, edev, edev->tbdf, edev->name);
888
889         return 0;
890 }
891
892 void
893 etherbcmlink(void)
894 {
895         addethercard("bcm", bcmpnp);
896 }