changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/pc/etherbcm.c

changeset 4350: 1f9d7811d546
parent: 591a78fd2fb6
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
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, **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 
376  idx = ctlr->recvprodi;
377  incr = (idx + 1) & (RecvProdRingLen - 1);
378  if(incr == (ctlr->status[2] >> 16)) return -1;
379  if(ctlr->recvs[idx] != 0) return -1;
380  bp = iallocb(Rbsz);
381  if(bp == nil) {
382  print("bcm: out of memory for receive buffers\n");
383  return -1;
384  }
385  ctlr->recvs[idx] = bp;
386  next = ctlr->recvprod + idx * 8;
387  memset(next, 0, 32);
388  next[1] = PADDR(bp->rp);
389  next[2] = Rbsz;
390  next[7] = idx;
391  coherence();
392  csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
393  return 0;
394 }
395 
396 static void
397 bcmreceive(Ether *edev)
398 {
399  Ctlr *ctlr;
400  Block *bp;
401  ulong *pkt, len, idx;
402 
403  ctlr = edev->ctlr;
404  for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
405  idx = pkt[7] & (RecvProdRingLen - 1);
406  bp = ctlr->recvs[idx];
407  if(bp == 0) {
408  print("bcm: nil block at %lux -- shouldn't happen\n", idx);
409  break;
410  }
411  ctlr->recvs[idx] = 0;
412  len = pkt[2] & 0xFFFF;
413  bp->wp = bp->rp + len;
414  if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
415  if(pkt[3] & FrameError) {
416  freeb(bp); /* dump erroneous packets */
417  } else {
418  etheriq(edev, bp, 1);
419  }
420  }
421 }
422 
423 static void
424 bcmtransclean(Ether *edev, int dolock)
425 {
426  Ctlr *ctlr;
427 
428  ctlr = edev->ctlr;
429  if(dolock)
430  ilock(&ctlr->txlock);
431  while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
432  freeb(ctlr->sends[ctlr->sendcleani]);
433  ctlr->sends[ctlr->sendcleani] = 0;
434  ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
435  }
436  if(dolock)
437  iunlock(&ctlr->txlock);
438 }
439 
440 static void
441 bcmtransmit(Ether *edev)
442 {
443  Ctlr *ctlr;
444  Block *bp;
445  ulong *next;
446  ulong incr;
447 
448  ctlr = edev->ctlr;
449  ilock(&ctlr->txlock);
450  while(1) {
451  incr = (ctlr->sendri + 1) & (SendRingLen - 1);
452  if(incr == (ctlr->status[4] >> 16)) {
453  print("bcm: send queue full\n");
454  break;
455  }
456  bp = qget(edev->oq);
457  if(bp == nil) break;
458  next = ctlr->sendr + ctlr->sendri * 4;
459  next[0] = 0;
460  next[1] = PADDR(bp->rp);
461  next[2] = (BLEN(bp) << 16) | PacketEnd;
462  next[3] = 0;
463  if(ctlr->sends[ctlr->sendri] != 0)
464  freeb(ctlr->sends[ctlr->sendri]);
465  ctlr->sends[ctlr->sendri] = bp;
466  coherence();
467  csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
468  }
469  iunlock(&ctlr->txlock);
470 }
471 
472 static void
473 bcmerror(Ether *edev)
474 {
475  Ctlr *ctlr;
476 
477  ctlr = edev->ctlr;
478  if(csr32(ctlr, FlowAttention)) {
479  if(csr32(ctlr, FlowAttention) & 0xF8FF8080UL) {
480  panic("bcm: fatal error %#.8ulx", csr32(ctlr, FlowAttention));
481  }
482  csr32(ctlr, FlowAttention) = 0;
483  }
484  csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
485  if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
486  print("bcm: DMA error\n");
487  csr32(ctlr, ReadDMAStatus) = 0;
488  csr32(ctlr, WriteDMAStatus) = 0;
489  }
490  if(csr32(ctlr, RISCState)) {
491  if(csr32(ctlr, RISCState) & 0x78000403) {
492  panic("bcm: RISC halted %#.8ulx", csr32(ctlr, RISCState));
493  }
494  csr32(ctlr, RISCState) = 0;
495  }
496 }
497 
498 static void
499 bcminterrupt(Ureg*, void *arg)
500 {
501  Ether *edev;
502  Ctlr *ctlr;
503  ulong status, tag;
504 
505  edev = arg;
506  ctlr = edev->ctlr;
507  ilock(&ctlr->imlock);
508  dummyread(csr32(ctlr, InterruptMailbox));
509  csr32(ctlr, InterruptMailbox) = 1;
510  status = ctlr->status[0];
511  tag = ctlr->status[1];
512  ctlr->status[0] = 0;
513  if(status & Error) bcmerror(edev);
514  if(status & LinkStateChange) checklink(edev);
515 // print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
516  bcmreceive(edev);
517  bcmtransclean(edev, 1);
518  bcmtransmit(edev);
519  csr32(ctlr, InterruptMailbox) = tag << 24;
520  iunlock(&ctlr->imlock);
521 }
522 
523 static int
524 bcminit(Ether *edev)
525 {
526  ulong i, j;
527  Ctlr *ctlr;
528 
529  ctlr = edev->ctlr;
530  print("bcm: reset\n");
531  /* initialization procedure according to the datasheet */
532  csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
533  csr32(ctlr, SwArbitration) |= SwArbitSet1;
534  for(i = 0; i < 10000 && (csr32(ctlr, SwArbitration) & SwArbitWon1) == 0; i++)
535  microdelay(100);
536  if(i == 10000){
537  iprint("bcm: arbiter failed to respond\n");
538  return -1;
539  }
540  csr32(ctlr, MemArbiterMode) |= Enable;
541  csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
542  csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
543  csr32(ctlr, ModeControl) |= ByteWordSwap;
544  csr32(ctlr, MemoryWindow) = 0;
545  mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
546  csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
547  csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
548  microdelay(100000);
549  ctlr->pdev->pcr |= 1<<1; /* pci memory access enable */
550  pcisetbme(ctlr->pdev);
551  csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
552  csr32(ctlr, MemArbiterMode) |= Enable;
553  csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
554  csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
555  csr32(ctlr, ModeControl) |= ByteWordSwap;
556  csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
557  microdelay(40000);
558  for(i = 0; i < 100000 && mem32(ctlr, 0xB50) != 0xB49A89AB; i++)
559  microdelay(100);
560  if(i == 100000){
561  iprint("bcm: chip failed to reset\n");
562  return -1;
563  }
564  switch(ctlr->pdev->did){
565  case BCM5721:
566  case BCM5751:
567  case BCM5752:
568  csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
569  break;
570  }
571  memset(ctlr->status, 0, 20);
572  csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
573  csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
574  csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue;
575  csr32(ctlr, MBUFLowWatermark) = 0x20;
576  csr32(ctlr, MBUFHighWatermark) = 0x60;
577  csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
578  csr32(ctlr, BufferManMode) |= Enable | Attn;
579  for(i = 0; i < 100 && (csr32(ctlr, BufferManMode) & Enable) == 0; i++)
580  microdelay(100);
581  if(i == 100){
582  iprint("bcm: buffer manager failed to start\n");
583  return -1;
584  }
585  csr32(ctlr, FTQReset) = -1;
586  csr32(ctlr, FTQReset) = 0;
587  for(i = 0; i < 1000 && csr32(ctlr, FTQReset) != 0; i++)
588  microdelay(100);
589  if(i == 1000){
590  iprint("bcm: ftq failed to reset\n");
591  return -1;
592  }
593  csr32(ctlr, ReceiveBDHostAddr) = 0;
594  csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
595  csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
596  csr32(ctlr, ReceiveBDNIC) = 0x6000;
597  csr32(ctlr, ReceiveBDRepl) = 25;
598  csr32(ctlr, SendBDRingHostIndex) = 0;
599  csr32(ctlr, SendBDRingHostIndex+4) = 0;
600  mem32(ctlr, SendRCB) = 0;
601  mem32(ctlr, SendRCB + 4) = PADDR(ctlr->sendr);
602  mem32(ctlr, SendRCB + 8) = SendRingLen << 16;
603  mem32(ctlr, SendRCB + 12) = 0x4000;
604  for(i=1;i<4;i++)
605  mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2;
606  mem32(ctlr, RecvRetRCB) = 0;
607  mem32(ctlr, RecvRetRCB + 4) = PADDR(ctlr->recvret);
608  mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16;
609  csr32(ctlr, RecvProdBDRingIndex) = 0;
610  csr32(ctlr, RecvProdBDRingIndex+4) = 0;
611  /* this delay is not in the datasheet, but necessary; Broadcom is fucking with us */
612  microdelay(1000);
613  i = csr32(ctlr, 0x410);
614  j = edev->ea[0] = i >> 8;
615  j += edev->ea[1] = i;
616  i = csr32(ctlr, MACAddress + 4);
617  j += edev->ea[2] = i >> 24;
618  j += edev->ea[3] = i >> 16;
619  j += edev->ea[4] = i >> 8;
620  j += edev->ea[5] = i;
621  csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF;
622  csr32(ctlr, ReceiveMTU) = Rbsz;
623  csr32(ctlr, TransmitMACLengths) = 0x2620;
624  csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */
625  csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF;
626  csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats;
627  csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
628  csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
629  csr32(ctlr, HostCoalescingMode) = 0;
630  for(i = 0; i < 200 && csr32(ctlr, HostCoalescingMode) != 0; i++)
631  microdelay(100);
632  if(i == 200){
633  iprint("bcm: host coalescing engine failed to stop\n");
634  return -1;
635  }
636  csr32(ctlr, HostCoalescingRecvTicks) = 150;
637  csr32(ctlr, HostCoalescingSendTicks) = 150;
638  csr32(ctlr, RecvMaxCoalescedFrames) = 10;
639  csr32(ctlr, SendMaxCoalescedFrames) = 10;
640  csr32(ctlr, RecvMaxCoalescedFramesInt) = 0;
641  csr32(ctlr, SendMaxCoalescedFramesInt) = 0;
642  csr32(ctlr, StatusBlockHostAddr) = 0;
643  csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(ctlr->status);
644  csr32(ctlr, HostCoalescingMode) |= Enable;
645  csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn;
646  csr32(ctlr, ReceiveListPlacementMode) |= Enable;
647  csr32(ctlr, MACMode) |= MACEnable;
648  csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM;
649  csr32(ctlr, InterruptMailbox) = 0;
650  csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */
651  csr32(ctlr, ReadDMAMode) |= 0x3fe;
652  csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn;
653  csr32(ctlr, SendDataCompletionMode) |= Enable;
654  csr32(ctlr, SendBDCompletionMode) |= Enable | Attn;
655  csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn;
656  csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4);
657  csr32(ctlr, SendDataInitiatorMode) |= Enable;
658  csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn;
659  csr32(ctlr, SendBDSelectorMode) |= Enable | Attn;
660  ctlr->recvprodi = 0;
661  while(replenish(ctlr) >= 0);
662  csr32(ctlr, TransmitMACMode) |= Enable;
663  csr32(ctlr, ReceiveMACMode) |= Enable;
664  csr32(ctlr, PowerControlStatus) &= ~3;
665  csr32(ctlr, MIStatus) |= 1<<0;
666  csr32(ctlr, MACEventEnable) = 0;
667  csr32(ctlr, MACEventStatus) |= (1<<12);
668  csr32(ctlr, MIMode) = 0xC0000;
669  microdelay(40);
670  miiw(ctlr, PhyControl, 1<<15);
671  for(i = 0; i < 1000 && miir(ctlr, PhyControl) & (1<<15); i++)
672  microdelay(100);
673  if(i == 1000){
674  iprint("bcm: PHY failed to reset\n");
675  return -1;
676  }
677  miiw(ctlr, PhyAuxControl, 2);
678  miir(ctlr, PhyIntStatus);
679  miir(ctlr, PhyIntStatus);
680  miiw(ctlr, PhyIntMask, ~(1<<1));
681  checklink(edev);
682  csr32(ctlr, MACEventEnable) |= 1<<12;
683  csr32(ctlr, MACHash) = -1;
684  csr32(ctlr, MACHash+4) = -1;
685  csr32(ctlr, MACHash+8) = -1;
686  csr32(ctlr, MACHash+12) = -1;
687  for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
688  csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
689  csr32(ctlr, MSIMode) |= Enable;
690  csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
691  return 0;
692 }
693 
694 static void
695 bcmpci(void)
696 {
697  Pcidev *pdev;
698 
699  pdev = nil;
700  while(pdev = pcimatch(pdev, 0, 0)) {
701  Ctlr *ctlr;
702  void *mem;
703 
704  if(pdev->ccrb != 2 || pdev->ccru != 0)
705  continue;
706  if(pdev->vid != 0x14e4)
707  continue;
708  switch(pdev->did){
709  default:
710  continue;
711  case BCM5752:
712  case BCM5752M:
713  case BCM5709:
714  case BCM5709S:
715  case BCM5716:
716  case BCM5716S:
717  case BCM5700:
718  case BCM5701:
719  case BCM5702:
720  case BCM5703:
721  case BCM5704:
722  case BCM5704S_2:
723  case BCM5706:
724  case BCM5708:
725  case BCM5702FE:
726  case BCM57710:
727  case BCM57711:
728  case BCM57711E:
729  case BCM5705:
730  case BCM5705_2:
731  case BCM5717:
732  case BCM5718:
733  case BCM5720:
734  case BCM5721:
735  case BCM5722:
736  case BCM5723:
737  case BCM5724:
738  case BCM5705M:
739  case BCM5705M_2:
740  case BCM5714:
741  case BCM5780:
742  case BCM5780S:
743  case BCM5754M:
744  case BCM5755M:
745  case BCM5756ME:
746  case BCM5750:
747  case BCM5751:
748  case BCM5715:
749  case BCM5715S:
750  case BCM5754:
751  case BCM5755:
752  case BCM5750M:
753  case BCM5751M:
754  case BCM5751F:
755  case BCM5787F:
756  case BCM5761e:
757  case BCM5761:
758  case BCM5764M:
759  case BCM57760:
760  case BCM57788:
761  case BCM57780:
762  case BCM5787M:
763  case BCM57790:
764  case BCM5782:
765  case BCM5784M:
766  case BCM5785:
767  case BCM5786:
768  case BCM5787:
769  case BCM5788:
770  case BCM5789:
771  case BCM5785_2:
772  case BCM5702X:
773  case BCM5703X:
774  case BCM5704S:
775  case BCM5706S:
776  case BCM5708S:
777  case BCM57761:
778  case BCM57781:
779  case BCM57791:
780  case BCM57765:
781  case BCM57785:
782  case BCM57795:
783  case BCM5702A3:
784  case BCM5703_2:
785  case BCM5781:
786  case BCM5753:
787  case BCM5753M:
788  case BCM5753F:
789  case BCM5906: /* ??? */
790  case BCM5906M: /* ??? */
791  case 0x1670: /* ??? */
792  break;
793  }
794 
795  pcisetbme(pdev);
796  pcisetpms(pdev, 0);
797  ctlr = malloc(sizeof(Ctlr));
798  if(ctlr == nil) {
799  print("bcm: unable to alloc Ctlr\n");
800  continue;
801  }
802  ctlr->sends = malloc(sizeof(ctlr->sends[0]) * SendRingLen);
803  ctlr->recvs = malloc(sizeof(ctlr->recvs[0]) * RecvProdRingLen);
804  if(ctlr->sends == nil || ctlr->recvs == nil){
805  print("bcm: unable to alloc ctlr->sends and ctlr->recvs\n");
806  free(ctlr->sends);
807  free(ctlr->recvs);
808  free(ctlr);
809  continue;
810  }
811  mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
812  if(mem == nil) {
813  print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
814  free(ctlr->sends);
815  free(ctlr);
816  continue;
817  }
818  ctlr->pdev = pdev;
819  ctlr->nic = mem;
820  ctlr->port = pdev->mem[0].bar & ~0x0F;
821  ctlr->status = xspanalloc(20, 16, 0);
822  ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
823  ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
824  ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
825  if(bcmhead != nil)
826  bcmtail->link = ctlr;
827  else
828  bcmhead = ctlr;
829  bcmtail = ctlr;
830  }
831 }
832 
833 static void
834 bcmpromiscuous(void* arg, int on)
835 {
836  Ctlr *ctlr;
837 
838  ctlr = ((Ether*)arg)->ctlr;
839  if(on)
840  csr32(ctlr, ReceiveMACMode) |= 1<<8;
841  else
842  csr32(ctlr, ReceiveMACMode) &= ~(1<<8);
843 }
844 
845 static void
846 bcmmulticast(void*, uchar*, int)
847 {
848 }
849 
850 static int
851 bcmpnp(Ether* edev)
852 {
853  Ctlr *ctlr;
854 
855 again:
856  if(bcmhead == nil)
857  bcmpci();
858 
859  for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
860  if(ctlr->active)
861  continue;
862 
863  if(edev->port == 0 || edev->port == ctlr->port) {
864  ctlr->active = 1;
865  break;
866  }
867  }
868 
869  if(ctlr == nil)
870  return -1;
871 
872  edev->ctlr = ctlr;
873  edev->port = ctlr->port;
874  edev->irq = ctlr->pdev->intl;
875  edev->tbdf = ctlr->pdev->tbdf;
876  edev->interrupt = bcminterrupt;
877  edev->transmit = bcmtransmit;
878  edev->multicast = bcmmulticast;
879  edev->promiscuous = bcmpromiscuous;
880  edev->arg = edev;
881  edev->mbps = 1000;
882 
883  if(bcminit(edev) < 0){
884  edev->ctlr = nil;
885  goto again;
886  }
887  return 0;
888 }
889 
890 void
891 etherbcmlink(void)
892 {
893  addethercard("bcm", bcmpnp);
894 }