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