]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherbcm.c
merge
[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
19 #include "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         Pcidev *pdev;
28         ulong *nic, *status;
29         /* One Ring to find them, One Ring to bring them all and in the darkness bind them */
30         ulong *recvret, *recvprod, *sendr;
31         ulong port;
32         ulong recvreti, recvprodi, sendri, sendcleani;
33         Block **sends;
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 #define csr32(c, r)     ((c)->nic[(r)/4])
199 #define mem32(c, r) csr32(c, (r)+0x8000)
200
201 static Ctlr *bcmhead, *bcmtail;
202
203 static ulong
204 dummyread(ulong x)
205 {
206         return x;
207 }
208
209 static int
210 miir(Ctlr *ctlr, int ra)
211 {
212         while(csr32(ctlr, MIComm) & (1<<29));
213         csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
214         while(csr32(ctlr, MIComm) & (1<<29));
215         if(csr32(ctlr, MIComm) & (1<<28)) return -1;
216         return csr32(ctlr, MIComm) & 0xFFFF;
217 }
218
219 static int
220 miiw(Ctlr *ctlr, int ra, int value)
221 {
222         while(csr32(ctlr, MIComm) & (1<<29));
223         csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
224         while(csr32(ctlr, MIComm) & (1<<29));
225         return 0;
226 }
227
228 static void
229 checklink(Ether *edev)
230 {
231         Ctlr *ctlr;
232         ulong i;
233
234         ctlr = edev->ctlr;
235         miir(ctlr, PhyStatus); /* dummy read necessary */
236         if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
237                 edev->link = 0;
238                 edev->mbps = 1000;
239                 ctlr->duplex = 1;
240                 print("bcm: no link\n");
241                 goto out;
242         }
243         edev->link = 1;
244         while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
245         i = miir(ctlr, PhyGbitStatus);
246         if(i & (Phy1000FD | Phy1000HD)) {
247                 edev->mbps = 1000;
248                 ctlr->duplex = (i & Phy1000FD) != 0;
249         } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
250                 edev->mbps = 100;
251                 ctlr->duplex = (i & Phy100FD) != 0;
252         } else if(i & (Phy10FD | Phy10HD)) {
253                 edev->mbps = 10;
254                 ctlr->duplex = (i & Phy10FD) != 0;
255         } else {
256                 edev->link = 0;
257                 edev->mbps = 1000;
258                 ctlr->duplex = 1;
259                 print("bcm: link partner supports neither 10/100/1000 Mbps\n"); 
260                 goto out;
261         }
262         print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
263 out:
264         if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
265         else csr32(ctlr, MACMode) |= MACHalfDuplex;
266         if(edev->mbps >= 1000)
267                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
268         else
269                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
270         csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */
271 }
272
273 static ulong*
274 currentrecvret(Ctlr *ctlr)
275 {
276         if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0;
277         return ctlr->recvret + ctlr->recvreti * 8;
278 }
279
280 static void
281 consumerecvret(Ctlr *ctlr)
282 {
283         csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
284 }
285
286 static int
287 replenish(Ctlr *ctlr)
288 {
289         ulong *next;
290         ulong incr;
291         Block *bp;
292         
293         incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1);
294         if(incr == (ctlr->status[2] >> 16)) return -1;
295         bp = iallocb(Rbsz);
296         if(bp == nil) {
297                 print("bcm: out of memory for receive buffers\n");
298                 return -1;
299         }
300         next = ctlr->recvprod + ctlr->recvprodi * 8;
301         memset(next, 0, 32);
302         next[1] = PADDR(bp->rp);
303         next[2] = Rbsz;
304         next[7] = (ulong) bp;
305         coherence();
306         csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
307         return 0;
308 }
309
310 static void
311 bcmreceive(Ether *edev)
312 {
313         Ctlr *ctlr;
314         Block *bp;
315         ulong *pkt, len;
316         
317         ctlr = edev->ctlr;
318         for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
319                 bp = (Block*) pkt[7];
320                 len = pkt[2] & 0xFFFF;
321                 bp->wp = bp->rp + len;
322                 if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
323                 if(pkt[3] & FrameError) {
324                         freeb(bp); /* dump erroneous packets */ 
325                 } else {
326                         etheriq(edev, bp, 1);
327                 }
328         }
329 }
330
331 static void
332 bcmtransclean(Ether *edev, int dolock)
333 {
334         Ctlr *ctlr;
335         
336         ctlr = edev->ctlr;
337         if(dolock)
338                 ilock(&ctlr->txlock);
339         while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
340                 freeb(ctlr->sends[ctlr->sendcleani]);
341                 ctlr->sends[ctlr->sendcleani] = 0;
342                 ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
343         }
344         if(dolock)
345                 iunlock(&ctlr->txlock);
346 }
347
348 static void
349 bcmtransmit(Ether *edev)
350 {
351         Ctlr *ctlr;
352         Block *bp;
353         ulong *next;
354         ulong incr;
355         
356         ctlr = edev->ctlr;
357         ilock(&ctlr->txlock);
358         while(1) {
359                 incr = (ctlr->sendri + 1) & (SendRingLen - 1);
360                 if(incr == (ctlr->status[4] >> 16)) {
361                         print("bcm: send queue full\n");
362                         break;
363                 }
364                 bp = qget(edev->oq);
365                 if(bp == nil) break;
366                 setmalloctag(bp, (ulong)(void*)bcmtransmit);
367                 next = ctlr->sendr + ctlr->sendri * 4;
368                 next[0] = 0;
369                 next[1] = PADDR(bp->rp);
370                 next[2] = (BLEN(bp) << 16) | PacketEnd;
371                 next[3] = 0;
372                 if(ctlr->sends[ctlr->sendri] != 0)
373                         freeb(ctlr->sends[ctlr->sendri]);
374                 ctlr->sends[ctlr->sendri] = bp;
375                 coherence();
376                 csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
377         }
378         iunlock(&ctlr->txlock);
379 }
380
381 static void
382 bcmerror(Ether *edev)
383 {
384         Ctlr *ctlr;
385         
386         ctlr = edev->ctlr;
387         if(csr32(ctlr, FlowAttention)) {
388                 if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
389                         panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
390                 }
391                 csr32(ctlr, FlowAttention) = 0;
392         }
393         csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
394         if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
395                 print("bcm: DMA error\n");
396                 csr32(ctlr, ReadDMAStatus) = 0;
397                 csr32(ctlr, WriteDMAStatus) = 0;
398         }
399         if(csr32(ctlr, RISCState)) {
400                 if(csr32(ctlr, RISCState) & 0x78000403) {
401                         panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
402                 }
403                 csr32(ctlr, RISCState) = 0;
404         }
405 }
406
407 static void
408 bcminterrupt(Ureg*, void *arg)
409 {
410         Ether *edev;
411         Ctlr *ctlr;
412         ulong status, tag;
413         
414         edev = arg;
415         ctlr = edev->ctlr;
416         ilock(&ctlr->imlock);
417         dummyread(csr32(ctlr, InterruptMailbox));
418         csr32(ctlr, InterruptMailbox) = 1;
419         status = ctlr->status[0];
420         tag = ctlr->status[1];
421         ctlr->status[0] = 0;
422         if(status & Error) bcmerror(edev);
423         if(status & LinkStateChange) checklink(edev);
424 //      print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
425         bcmreceive(edev);
426         bcmtransclean(edev, 1);
427         bcmtransmit(edev);
428         csr32(ctlr, InterruptMailbox) = tag << 24;
429         iunlock(&ctlr->imlock);
430 }
431
432 static int
433 bcminit(Ether *edev)
434 {
435         ulong i, j;
436         Ctlr *ctlr;
437         
438         ctlr = edev->ctlr;
439         print("bcm: reset\n");
440         /* initialization procedure according to the datasheet */
441         csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
442         csr32(ctlr, SwArbitration) |= SwArbitSet1;
443         for(i = 0; i < 10000 && (csr32(ctlr, SwArbitration) & SwArbitWon1) == 0; i++)
444                 microdelay(100);
445         if(i == 10000){
446                 iprint("bcm: arbiter failed to respond\n");
447                 return -1;
448         }
449         csr32(ctlr, MemArbiterMode) |= Enable;
450         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
451         csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
452         csr32(ctlr, ModeControl) |= ByteWordSwap;
453         csr32(ctlr, MemoryWindow) = 0;
454         mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
455         csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
456         csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
457         microdelay(100000);
458         ctlr->pdev->pcr |= 1<<1; /* pci memory access enable */
459         pcisetbme(ctlr->pdev);
460         csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
461         csr32(ctlr, MemArbiterMode) |= Enable;
462         csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
463         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
464         csr32(ctlr, ModeControl) |= ByteWordSwap;
465         csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
466         microdelay(40000);
467         for(i = 0; i < 100000 && mem32(ctlr, 0xB50) != 0xB49A89AB; i++)
468                 microdelay(100);
469         if(i == 100000){
470                 iprint("bcm: chip failed to reset\n");
471                 return -1;
472         }
473         csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
474         memset(ctlr->status, 0, 20);
475         csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
476         csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
477         csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
478         csr32(ctlr, MBUFLowWatermark) = 0x20;
479         csr32(ctlr, MBUFHighWatermark) = 0x60;
480         csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
481         csr32(ctlr, BufferManMode) |= Enable | Attn;
482         for(i = 0; i < 100 && (csr32(ctlr, BufferManMode) & Enable) == 0; i++)
483                 microdelay(100);
484         if(i == 100){
485                 iprint("bcm: buffer manager failed to start\n");
486                 return -1;
487         }
488         csr32(ctlr, FTQReset) = -1;
489         csr32(ctlr, FTQReset) = 0;
490         for(i = 0; i < 1000 && csr32(ctlr, FTQReset) != 0; i++)
491                 microdelay(100);
492         if(i == 1000){
493                 iprint("bcm: ftq failed to reset\n");
494                 return -1;
495         }
496         csr32(ctlr, ReceiveBDHostAddr) = 0;
497         csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
498         csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
499         csr32(ctlr, ReceiveBDNIC) = 0x6000;
500         csr32(ctlr, ReceiveBDRepl) = 25;
501         csr32(ctlr, SendBDRingHostIndex) = 0;
502         csr32(ctlr, SendBDRingHostIndex+4) = 0;
503         mem32(ctlr, SendRCB) = 0;
504         mem32(ctlr, SendRCB + 4) = PADDR(ctlr->sendr);
505         mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
506         mem32(ctlr, SendRCB + 12) = 0x4000;
507         for(i=1;i<4;i++)
508                 mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
509         mem32(ctlr, RecvRetRCB) = 0;
510         mem32(ctlr, RecvRetRCB + 4) = PADDR(ctlr->recvret);
511         mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
512         csr32(ctlr, RecvProdBDRingIndex) = 0;
513         csr32(ctlr, RecvProdBDRingIndex+4) = 0;
514         /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
515         microdelay(1000); 
516         i = csr32(ctlr, 0x410);
517         j = edev->ea[0] = i >> 8;
518         j += edev->ea[1] = i;
519         i = csr32(ctlr, MACAddress + 4);
520         j += edev->ea[2] = i >> 24;
521         j += edev->ea[3] = i >> 16;
522         j += edev->ea[4] = i >> 8;
523         j += edev->ea[5] = i;
524         csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
525         csr32(ctlr, ReceiveMTU) = Rbsz;
526         csr32(ctlr, TransmitMACLengths) = 0x2620;
527         csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
528         csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
529         csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
530         csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
531         csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
532         csr32(ctlr, HostCoalescingMode) = 0;
533         for(i = 0; i < 200 && csr32(ctlr, HostCoalescingMode) != 0; i++)
534                 microdelay(100);
535         if(i == 200){
536                 iprint("bcm: host coalescing engine failed to stop\n");
537                 return -1;
538         }
539         csr32(ctlr, HostCoalescingRecvTicks) = 150;
540         csr32(ctlr, HostCoalescingSendTicks) = 150;
541         csr32(ctlr, RecvMaxCoalescedFrames) = 10;
542         csr32(ctlr, SendMaxCoalescedFrames) = 10;
543         csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
544         csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
545         csr32(ctlr, StatusBlockHostAddr) = 0;
546         csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(ctlr->status);
547         csr32(ctlr, HostCoalescingMode) |= Enable;
548         csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
549         csr32(ctlr, ReceiveListPlacementMode) |= Enable;
550         csr32(ctlr, MACMode) |= MACEnable;
551         csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
552         csr32(ctlr, InterruptMailbox) = 0;
553         csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
554         csr32(ctlr, ReadDMAMode) |= 0x3fe;
555         csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
556         csr32(ctlr, SendDataCompletionMode) |= Enable;
557         csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
558         csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
559         csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
560         csr32(ctlr, SendDataInitiatorMode) |= Enable;
561         csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
562         csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
563         ctlr->recvprodi = 0;
564         while(replenish(ctlr) >= 0);
565         csr32(ctlr, TransmitMACMode) |= Enable;
566         csr32(ctlr, ReceiveMACMode) |= Enable;
567         csr32(ctlr, PowerControlStatus) &= ~3;
568         csr32(ctlr, MIStatus) |= 1<<0;
569         csr32(ctlr, MACEventEnable) = 0;
570         csr32(ctlr, MACEventStatus) |= (1<<12);
571         csr32(ctlr, MIMode) = 0xC0000;
572         microdelay(40);
573         miiw(ctlr, PhyControl, 1<<15);
574         for(i = 0; i < 1000 && miir(ctlr, PhyControl) & (1<<15); i++)
575                 microdelay(100);
576         if(i == 1000){
577                 iprint("bcm: PHY failed to reset\n");
578                 return -1;
579         }
580         miiw(ctlr, PhyAuxControl, 2);
581         miir(ctlr, PhyIntStatus);
582         miir(ctlr, PhyIntStatus);
583         miiw(ctlr, PhyIntMask, ~(1<<1));
584         checklink(edev);
585         csr32(ctlr, MACEventEnable) |= 1<<12;
586         csr32(ctlr, MACHash) = -1;
587         csr32(ctlr, MACHash+4) = -1;
588         csr32(ctlr, MACHash+8) = -1;
589         csr32(ctlr, MACHash+12) = -1;
590         for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
591         csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
592         csr32(ctlr, MSIMode) |= Enable;
593         csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
594         return 0;
595 }
596
597 static void
598 bcmpci(void)
599 {
600         Pcidev *pdev;
601         
602         pdev = nil;
603         while(pdev = pcimatch(pdev, 0, 0)) {
604                 Ctlr *ctlr;
605                 void *mem;
606                 
607                 if(pdev->ccrb != 2 || pdev->ccru != 0)
608                         continue;
609                 
610                 switch((pdev->vid<<16) | pdev->did){
611                 default: continue;
612                 case 0x14e4165a:
613                 case 0x14e4167d:
614                 case 0x14e41670:
615                 case 0x14e41672:
616                 case 0x14e41673:
617                 case 0x14e41674:
618                 case 0x14e41677:
619                 case 0x14e4167A:
620                 case 0x14e4167b:
621                 case 0x14e41693:
622                 case 0x14e4169B:
623                 case 0x14e41712:
624                 case 0x14e41713:
625                         break;
626                 }
627                 pcisetbme(pdev);
628                 pcisetpms(pdev, 0);
629                 ctlr = malloc(sizeof(Ctlr));
630                 if(ctlr == nil) {
631                         print("bcm: unable to alloc Ctlr\n");
632                         continue;
633                 }
634                 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
635                 if(mem == nil) {
636                         print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
637                         free(ctlr);
638                         continue;
639                 }
640                 ctlr->pdev = pdev;
641                 ctlr->nic = mem;
642                 ctlr->port = pdev->mem[0].bar & ~0x0F;
643                 ctlr->status = xspanalloc(20, 16, 0);
644                 ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
645                 ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
646                 ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
647                 ctlr->sends = malloc(sizeof(Block) * SendRingLen);
648                 if(bcmhead != nil)
649                         bcmtail->link = ctlr;
650                 else
651                         bcmhead = ctlr;
652                 bcmtail = ctlr;
653         }
654 }
655
656 static void
657 bcmpromiscuous(void* arg, int on)
658 {
659         Ctlr *ctlr;
660         
661         ctlr = ((Ether*)arg)->ctlr;
662         if(on)
663                 csr32(ctlr, ReceiveMACMode) |= 1<<8;
664         else
665                 csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
666 }
667
668 static void
669 bcmmulticast(void*, uchar*, int)
670 {
671 }
672
673 static int
674 bcmpnp(Ether* edev)
675 {
676         Ctlr *ctlr;
677         
678 again:
679         if(bcmhead == nil)
680                 bcmpci();
681         
682         for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
683                 if(ctlr->active)
684                         continue;
685                 
686                 if(edev->port == 0 || edev->port == ctlr->port) {
687                         ctlr->active = 1;
688                         break;
689                 }
690         }
691         
692         if(ctlr == nil)
693                 return -1;
694         
695         edev->ctlr = ctlr;
696         edev->port = ctlr->port;
697         edev->irq = ctlr->pdev->intl;
698         edev->tbdf = ctlr->pdev->tbdf;
699         edev->interrupt = bcminterrupt;
700         edev->transmit = bcmtransmit;
701         edev->multicast = bcmmulticast;
702         edev->promiscuous = bcmpromiscuous;
703         edev->arg = edev;
704         edev->mbps = 1000;
705         
706         if(bcminit(edev) < 0){
707                 edev->ctlr = nil;
708                 goto again;
709         }
710         return 0;
711 }
712
713 void
714 etherbcmlink(void)
715 {
716         addethercard("BCM5755", bcmpnp);
717 }