]> 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         IndirectAccessEnable = 1<<7,
54         EnablePCIStateRegister = 1<<4,
55         EnableClockControlRegister = 1<<5,
56         TaggedStatus = 1<<9,
57         
58         DMARWControl = 0x6C,
59         DMAWatermarkMask = ~(7<<19),
60         DMAWatermarkValue = 3<<19,
61
62         MemoryWindow = 0x7C,
63         MemoryWindowData = 0x84,
64         
65         SendRCB = 0x100,
66         RecvRetRCB = 0x200,
67         
68         InterruptMailbox = 0x204,
69         
70         RecvProdBDRingIndex = 0x26c,
71         RecvBDRetRingIndex = 0x284,
72         SendBDRingHostIndex = 0x304,
73         
74         MACMode = 0x400,
75         MACPortMask = ~((1<<3)|(1<<2)),
76         MACPortGMII = 1<<3,
77         MACPortMII = 1<<2,
78         MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11),
79         MACHalfDuplex = 1<<1,
80         
81         MACEventStatus = 0x404,
82         MACEventEnable = 0x408,
83         MACAddress = 0x410,
84         EthernetRandomBackoff = 0x438,
85         ReceiveMTU = 0x43C,
86         MIComm = 0x44C,
87         MIStatus = 0x450,
88         MIMode = 0x454,
89         ReceiveMACMode = 0x468,
90         TransmitMACMode = 0x45C,
91         TransmitMACLengths = 0x464,
92         MACHash = 0x470,
93         ReceiveRules = 0x480,
94         
95         ReceiveRulesConfiguration = 0x500,
96         LowWatermarkMaximum = 0x504,
97         LowWatermarkMaxMask = ~0xFFFF,
98         LowWatermarkMaxValue = 2,
99
100         SendDataInitiatorMode = 0xC00,
101         SendInitiatorConfiguration = 0x0C08,
102         SendStats = 1<<0,
103         SendInitiatorMask = 0x0C0C,
104         
105         SendDataCompletionMode = 0x1000,
106         SendBDSelectorMode = 0x1400,
107         SendBDInitiatorMode = 0x1800,
108         SendBDCompletionMode = 0x1C00,
109         
110         ReceiveListPlacementMode = 0x2000,
111         ReceiveListPlacement = 0x2010,
112         ReceiveListPlacementConfiguration = 0x2014,
113         ReceiveStats = 1<<0,
114         ReceiveListPlacementMask = 0x2018,
115         
116         ReceiveDataBDInitiatorMode = 0x2400,
117         ReceiveBDHostAddr = 0x2450,
118         ReceiveBDFlags = 0x2458,
119         ReceiveBDNIC = 0x245C,
120         ReceiveDataCompletionMode = 0x2800,
121         ReceiveBDInitiatorMode = 0x2C00,
122         ReceiveBDRepl = 0x2C18,
123         
124         ReceiveBDCompletionMode = 0x3000,
125         HostCoalescingMode = 0x3C00,
126         HostCoalescingRecvTicks = 0x3C08,
127         HostCoalescingSendTicks = 0x3C0C,
128         RecvMaxCoalescedFrames = 0x3C10,
129         SendMaxCoalescedFrames = 0x3C14,
130         RecvMaxCoalescedFramesInt = 0x3C20,
131         SendMaxCoalescedFramesInt = 0x3C24,
132         StatusBlockHostAddr = 0x3C38,
133         FlowAttention = 0x3C48,
134
135         MemArbiterMode = 0x4000,
136         
137         BufferManMode = 0x4400,
138         
139         MBUFLowWatermark = 0x4414,
140         MBUFHighWatermark = 0x4418,
141         
142         ReadDMAMode = 0x4800,
143         ReadDMAStatus = 0x4804,
144         WriteDMAMode = 0x4C00,
145         WriteDMAStatus = 0x4C04,
146         
147         RISCState = 0x5004,
148         FTQReset = 0x5C00,
149         MSIMode = 0x6000,
150         
151         ModeControl = 0x6800,
152         ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1),
153         HostStackUp = 1<<16,
154         HostSendBDs = 1<<17,
155         InterruptOnMAC = 1<<26,
156         
157         MiscConfiguration = 0x6804,
158         CoreClockBlocksReset = 1<<0,
159         GPHYPowerDownOverride = 1<<26,
160         DisableGRCResetOnPCIE = 1<<29,
161         TimerMask = ~0xFF,
162         TimerValue = 65<<1,
163         MiscLocalControl = 0x6808,
164         InterruptOnAttn = 1<<3,
165         AutoSEEPROM = 1<<24,
166         
167         SwArbitration = 0x7020,
168         SwArbitSet1 = 1<<1,
169         SwArbitWon1 = 1<<9,
170         TLPControl = 0x7C00,
171         
172         PhyControl = 0x00,
173         PhyStatus = 0x01,
174         PhyLinkStatus = 1<<2,
175         PhyAutoNegComplete = 1<<5,
176         PhyPartnerStatus = 0x05,
177         Phy100FD = 1<<8,
178         Phy100HD = 1<<7,
179         Phy10FD = 1<<6,
180         Phy10HD = 1<<5,
181         PhyGbitStatus = 0x0A,
182         Phy1000FD = 1<<12,
183         Phy1000HD = 1<<11,
184         PhyAuxControl = 0x18,
185         PhyIntStatus = 0x1A,
186         PhyIntMask = 0x1B,
187         
188         Updated = 1<<0,
189         LinkStateChange = 1<<1,
190         Error = 1<<2,
191         
192         PacketEnd = 1<<2,
193         FrameError = 1<<10,
194 };
195
196 #define csr32(c, r)     ((c)->nic[(r)/4])
197 #define mem32(c, r) csr32(c, (r)+0x8000)
198
199 static Ctlr *bcmhead, *bcmtail;
200
201 static ulong
202 dummyread(ulong x)
203 {
204         return x;
205 }
206
207 static int
208 miir(Ctlr *ctlr, int ra)
209 {
210         while(csr32(ctlr, MIComm) & (1<<29));
211         csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
212         while(csr32(ctlr, MIComm) & (1<<29));
213         if(csr32(ctlr, MIComm) & (1<<28)) return -1;
214         return csr32(ctlr, MIComm) & 0xFFFF;
215 }
216
217 static int
218 miiw(Ctlr *ctlr, int ra, int value)
219 {
220         while(csr32(ctlr, MIComm) & (1<<29));
221         csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29);
222         while(csr32(ctlr, MIComm) & (1<<29));
223         return 0;
224 }
225
226 static void
227 checklink(Ether *edev)
228 {
229         Ctlr *ctlr;
230         ulong i;
231
232         ctlr = edev->ctlr;
233         miir(ctlr, PhyStatus); /* dummy read necessary */
234         if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
235                 edev->link = 0;
236                 edev->mbps = 1000;
237                 ctlr->duplex = 1;
238                 print("bcm: no link\n");
239                 goto out;
240         }
241         edev->link = 1;
242         while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
243         i = miir(ctlr, PhyGbitStatus);
244         if(i & (Phy1000FD | Phy1000HD)) {
245                 edev->mbps = 1000;
246                 ctlr->duplex = (i & Phy1000FD) != 0;
247         } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
248                 edev->mbps = 100;
249                 ctlr->duplex = (i & Phy100FD) != 0;
250         } else if(i & (Phy10FD | Phy10HD)) {
251                 edev->mbps = 10;
252                 ctlr->duplex = (i & Phy10FD) != 0;
253         } else {
254                 edev->link = 0;
255                 edev->mbps = 1000;
256                 ctlr->duplex = 1;
257                 print("bcm: link partner supports neither 10/100/1000 Mbps\n"); 
258                 goto out;
259         }
260         print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
261 out:
262         if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
263         else csr32(ctlr, MACMode) |= MACHalfDuplex;
264         if(edev->mbps >= 1000)
265                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
266         else
267                 csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
268         csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */
269 }
270
271 static ulong*
272 currentrecvret(Ctlr *ctlr)
273 {
274         if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0;
275         return ctlr->recvret + ctlr->recvreti * 8;
276 }
277
278 static void
279 consumerecvret(Ctlr *ctlr)
280 {
281         csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
282 }
283
284 static int
285 replenish(Ctlr *ctlr)
286 {
287         ulong *next;
288         ulong incr;
289         Block *bp;
290         
291         incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1);
292         if(incr == (ctlr->status[2] >> 16)) return -1;
293         bp = iallocb(Rbsz);
294         if(bp == nil) {
295                 print("bcm: out of memory for receive buffers\n");
296                 return -1;
297         }
298         next = ctlr->recvprod + ctlr->recvprodi * 8;
299         memset(next, 0, 32);
300         next[1] = PADDR(bp->rp);
301         next[2] = Rbsz;
302         next[7] = (ulong) bp;
303         csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
304         return 0;
305 }
306
307 static void
308 bcmreceive(Ether *edev)
309 {
310         Ctlr *ctlr;
311         Block *bp;
312         ulong *pkt, len;
313         
314         ctlr = edev->ctlr;
315         for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
316                 bp = (Block*) pkt[7];
317                 len = pkt[2] & 0xFFFF;
318                 bp->wp = bp->rp + len;
319                 if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
320                 if(pkt[3] & FrameError) {
321                         freeb(bp); /* dump erroneous packets */ 
322                 } else {
323                         etheriq(edev, bp, 1);
324                 }
325         }
326 }
327
328 static void
329 bcmtransclean(Ether *edev, int dolock)
330 {
331         Ctlr *ctlr;
332         
333         ctlr = edev->ctlr;
334         if(dolock)
335                 ilock(&ctlr->txlock);
336         while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
337                 freeb(ctlr->sends[ctlr->sendcleani]);
338                 ctlr->sends[ctlr->sendcleani] = 0;
339                 ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
340         }
341         if(dolock)
342                 iunlock(&ctlr->txlock);
343 }
344
345 static void
346 bcmtransmit(Ether *edev)
347 {
348         Ctlr *ctlr;
349         Block *bp;
350         ulong *next;
351         ulong incr;
352         
353         ctlr = edev->ctlr;
354         ilock(&ctlr->txlock);
355         while(1) {
356                 incr = (ctlr->sendri + 1) & (SendRingLen - 1);
357                 if(incr == (ctlr->status[4] >> 16)) {
358                         print("bcm: send queue full\n");
359                         break;
360                 }
361                 bp = qget(edev->oq);
362                 if(bp == nil) break;
363                 setmalloctag(bp, (ulong)(void*)bcmtransmit);
364                 next = ctlr->sendr + ctlr->sendri * 4;
365                 next[0] = 0;
366                 next[1] = PADDR(bp->rp);
367                 next[2] = (BLEN(bp) << 16) | PacketEnd;
368                 next[3] = 0;
369                 if(ctlr->sends[ctlr->sendri] != 0)
370                         freeb(ctlr->sends[ctlr->sendri]);
371                 ctlr->sends[ctlr->sendri] = bp;
372                 csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
373         }
374         iunlock(&ctlr->txlock);
375 }
376
377 static void
378 bcmerror(Ether *edev)
379 {
380         Ctlr *ctlr;
381         
382         ctlr = edev->ctlr;
383         if(csr32(ctlr, FlowAttention)) {
384                 if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
385                         panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
386                 }
387                 csr32(ctlr, FlowAttention) = 0;
388         }
389         csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
390         if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
391                 print("bcm: DMA error\n");
392                 csr32(ctlr, ReadDMAStatus) = 0;
393                 csr32(ctlr, WriteDMAStatus) = 0;
394         }
395         if(csr32(ctlr, RISCState)) {
396                 if(csr32(ctlr, RISCState) & 0x78000403) {
397                         panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
398                 }
399                 csr32(ctlr, RISCState) = 0;
400         }
401 }
402
403 static void
404 bcminterrupt(Ureg*, void *arg)
405 {
406         Ether *edev;
407         Ctlr *ctlr;
408         ulong status, tag;
409         
410         edev = arg;
411         ctlr = edev->ctlr;
412         ilock(&ctlr->imlock);
413         dummyread(csr32(ctlr, InterruptMailbox));
414         csr32(ctlr, InterruptMailbox) = 1;
415         status = ctlr->status[0];
416         tag = ctlr->status[1];
417         ctlr->status[0] = 0;
418         if(status & Error) bcmerror(edev);
419         if(status & LinkStateChange) checklink(edev);
420 //      print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
421         bcmreceive(edev);
422         bcmtransclean(edev, 1);
423         bcmtransmit(edev);
424         csr32(ctlr, InterruptMailbox) = tag << 24;
425         iunlock(&ctlr->imlock);
426 }
427
428 static void
429 bcminit(Ether *edev)
430 {
431         ulong i, j;
432         Ctlr *ctlr;
433         
434         ctlr = edev->ctlr;
435         print("bcm: reset\n");
436         /* initialization procedure according to the datasheet */
437         csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
438         csr32(ctlr, SwArbitration) |= SwArbitSet1;
439         while((csr32(ctlr, SwArbitration) & SwArbitWon1) == 0);
440         csr32(ctlr, MemArbiterMode) |= Enable;
441         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
442         csr32(ctlr, MemoryWindow) = 0;
443         mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
444         csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
445         csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
446         microdelay(100000);
447         ctlr->pdev->pcr |= 1<<1;
448         pcisetbme(ctlr->pdev);
449         csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
450         csr32(ctlr, MemArbiterMode) |= Enable;
451         csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
452         csr32(ctlr, ModeControl) |= ByteWordSwap;
453         csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
454         microdelay(40000);
455         while(mem32(ctlr, 0xB50) != 0xB49A89AB);
456         csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
457         memset(ctlr->status, 0, 20);
458         csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
459         csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
460         csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
461         csr32(ctlr, MBUFLowWatermark) = 0x20;
462         csr32(ctlr, MBUFHighWatermark) = 0x60;
463         csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
464         csr32(ctlr, BufferManMode) |= Enable | Attn;
465         while((csr32(ctlr, BufferManMode) & Enable) == 0);
466         csr32(ctlr, FTQReset) = -1;
467         csr32(ctlr, FTQReset) = 0;
468         while(csr32(ctlr, FTQReset));
469         csr32(ctlr, ReceiveBDHostAddr) = 0;
470         csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
471         csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
472         csr32(ctlr, ReceiveBDNIC) = 0x6000;
473         csr32(ctlr, ReceiveBDRepl) = 25;
474         csr32(ctlr, SendBDRingHostIndex) = 0;
475         csr32(ctlr, SendBDRingHostIndex+4) = 0;
476         mem32(ctlr, SendRCB) = 0;
477         mem32(ctlr, SendRCB + 4) = PADDR(ctlr->sendr);
478         mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
479         mem32(ctlr, SendRCB + 12) = 0x4000;
480         for(i=1;i<4;i++)
481                 mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
482         mem32(ctlr, RecvRetRCB) = 0;
483         mem32(ctlr, RecvRetRCB + 4) = PADDR(ctlr->recvret);
484         mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
485         csr32(ctlr, RecvProdBDRingIndex) = 0;
486         csr32(ctlr, RecvProdBDRingIndex+4) = 0;
487         /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
488         microdelay(1000); 
489         i = csr32(ctlr, 0x410);
490         j = edev->ea[0] = i >> 8;
491         j += edev->ea[1] = i;
492         i = csr32(ctlr, MACAddress + 4);
493         j += edev->ea[2] = i >> 24;
494         j += edev->ea[3] = i >> 16;
495         j += edev->ea[4] = i >> 8;
496         j += edev->ea[5] = i;
497         csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
498         csr32(ctlr, ReceiveMTU) = Rbsz;
499         csr32(ctlr, TransmitMACLengths) = 0x2620;
500         csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
501         csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
502         csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
503         csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
504         csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
505         csr32(ctlr, HostCoalescingMode) = 0;
506         while(csr32(ctlr, HostCoalescingMode) != 0);
507         csr32(ctlr, HostCoalescingRecvTicks) = 150;
508         csr32(ctlr, HostCoalescingSendTicks) = 150;
509         csr32(ctlr, RecvMaxCoalescedFrames) = 10;
510         csr32(ctlr, SendMaxCoalescedFrames) = 10;
511         csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
512         csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
513         csr32(ctlr, StatusBlockHostAddr) = 0;
514         csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(ctlr->status);
515         csr32(ctlr, HostCoalescingMode) |= Enable;
516         csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
517         csr32(ctlr, ReceiveListPlacementMode) |= Enable;
518         csr32(ctlr, MACMode) |= MACEnable;
519         csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
520         csr32(ctlr, InterruptMailbox) = 0;
521         csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
522         csr32(ctlr, ReadDMAMode) |= 0x3fe;
523         csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
524         csr32(ctlr, SendDataCompletionMode) |= Enable;
525         csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
526         csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
527         csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
528         csr32(ctlr, SendDataInitiatorMode) |= Enable;
529         csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
530         csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
531         ctlr->recvprodi = 0;
532         while(replenish(ctlr) >= 0);
533         csr32(ctlr, TransmitMACMode) |= Enable;
534         csr32(ctlr, ReceiveMACMode) |= Enable;
535         csr32(ctlr, PowerControlStatus) &= ~3;
536         csr32(ctlr, MIStatus) |= 1<<0;
537         csr32(ctlr, MACEventEnable) = 0;
538         csr32(ctlr, MACEventStatus) |= (1<<12);
539         csr32(ctlr, MIMode) = 0xC0000;
540         microdelay(40);
541         miiw(ctlr, PhyControl, 1<<15);
542         while(miir(ctlr, PhyControl) & (1<<15));
543         miiw(ctlr, PhyAuxControl, 2);
544         miir(ctlr, PhyIntStatus);
545         miir(ctlr, PhyIntStatus);
546         miiw(ctlr, PhyIntMask, ~(1<<1));
547         checklink(edev);
548         csr32(ctlr, MACEventEnable) |= 1<<12;
549         csr32(ctlr, MACHash) = -1;
550         csr32(ctlr, MACHash+4) = -1;
551         csr32(ctlr, MACHash+8) = -1;
552         csr32(ctlr, MACHash+12) = -1;
553         for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
554         csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
555         csr32(ctlr, MSIMode) |= Enable;
556         csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
557 }
558
559 static void
560 bcmpci(void)
561 {
562         Pcidev *pdev;
563         
564         pdev = nil;
565         while(pdev = pcimatch(pdev, 0, 0)) {
566                 Ctlr *ctlr;
567                 void *mem;
568                 
569                 if(pdev->ccrb != 2 || pdev->ccru != 0)
570                         continue;
571                 
572                 switch((pdev->vid<<16) | pdev->did){
573                 default: continue;
574                 case 0x14e4165a:
575                 case 0x14e4167d:
576                 case 0x14e41670:
577                 case 0x14e41672:
578                 case 0x14e41673:
579                 case 0x14e41674:
580                 case 0x14e41677:
581                 case 0x14e4167A:
582                 case 0x14e4167b:
583                 case 0x14e41693:
584                 case 0x14e4169B:
585                 case 0x14e41712:
586                 case 0x14e41713:
587                         break;
588                 }
589                 pcisetbme(pdev);
590                 pcisetpms(pdev, 0);
591                 ctlr = malloc(sizeof(Ctlr));
592                 if(ctlr == nil) {
593                         print("bcm: unable to alloc Ctlr\n");
594                         continue;
595                 }
596                 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
597                 if(mem == nil) {
598                         print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
599                         free(ctlr);
600                         continue;
601                 }
602                 ctlr->pdev = pdev;
603                 ctlr->nic = mem;
604                 ctlr->port = pdev->mem[0].bar & ~0x0F;
605                 ctlr->status = xspanalloc(20, 16, 0);
606                 ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
607                 ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
608                 ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
609                 ctlr->sends = malloc(sizeof(Block) * SendRingLen);
610                 if(bcmhead != nil)
611                         bcmtail->link = ctlr;
612                 else
613                         bcmhead = ctlr;
614                 bcmtail = ctlr;
615         }
616 }
617
618 static void
619 bcmpromiscuous(void* arg, int on)
620 {
621         Ctlr *ctlr;
622         
623         ctlr = ((Ether*)arg)->ctlr;
624         if(on)
625                 csr32(ctlr, ReceiveMACMode) |= 1<<8;
626         else
627                 csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
628 }
629
630 static void
631 bcmmulticast(void*, uchar*, int)
632 {
633 }
634
635 static int
636 bcmpnp(Ether* edev)
637 {
638         Ctlr *ctlr;
639         
640         if(bcmhead == nil)
641                 bcmpci();
642         
643         for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
644                 if(ctlr->active)
645                         continue;
646                 
647                 if(edev->port == 0 || edev->port == ctlr->port) {
648                         ctlr->active = 1;
649                         break;
650                 }
651         }
652         
653         if(ctlr == nil)
654                 return -1;
655         
656         edev->ctlr = ctlr;
657         edev->port = ctlr->port;
658         edev->irq = ctlr->pdev->intl;
659         edev->tbdf = ctlr->pdev->tbdf;
660         edev->interrupt = bcminterrupt;
661         edev->transmit = bcmtransmit;
662         edev->multicast = bcmmulticast;
663         edev->promiscuous = bcmpromiscuous;
664         edev->arg = edev;
665         edev->mbps = 1000;
666         
667         bcminit(edev);
668         return 0;
669 }
670
671 void
672 etherbcmlink(void)
673 {
674         addethercard("BCM5755", bcmpnp);
675 }