BNX2X: Init of one NIC complete
[akaros.git] / kern / drivers / net / bnx2x / bnx2x_dev.c
1 /* This file is part of the UCB release of Plan 9. It is subject to the license
2  * terms in the LICENSE file found in the top-level directory of this
3  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
4  * part of the UCB release of Plan 9, including this file, may be copied,
5  * modified, propagated, or distributed except according to the terms contained
6  * in the LICENSE file. */
7
8 /* Network driver stub for bnx2x_ */
9
10 #include <vfs.h>
11 #include <kfs.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kref.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <error.h>
19 #include <cpio.h>
20 #include <pmap.h>
21 #include <smp.h>
22 #include <arch/pci.h>
23 #include <ip.h>
24 #include <ns.h>
25 #include "bnx2x.h"
26
27 /* TODO: Cheap externs */
28 extern int __init bnx2x_init(void);
29 extern bool is_bnx2x_dev(struct pci_device *dev);
30 extern const struct pci_device_id *
31                     srch_bnx2x_pci_tbl(struct pci_device *needle);
32 extern int bnx2x_init_one(struct ether *dev, struct bnx2x *bp,
33                           struct pci_device *pdev,
34                           const struct pci_device_id *ent);
35 extern int bnx2x_open(struct ether *dev);
36
37 spinlock_t bnx2x_tq_lock = SPINLOCK_INITIALIZER;
38 TAILQ_HEAD(bnx2x_tq, bnx2x);
39 struct bnx2x_tq bnx2x_tq = TAILQ_HEAD_INITIALIZER(bnx2x_tq);
40
41 /* We're required to print out stats at some point.  Here are a couple from
42  * igbe, as an example. */
43 static char *statistics[Nstatistics] = {
44         "CRC Error",
45         "Alignment Error",
46 };
47
48 static long bnx2x_ifstat(struct ether *edev, void *a, long n, uint32_t offset)
49 {
50         struct bnx2x *ctlr;
51         char *p, *s;
52         int i, l, r;
53         uint64_t tuvl, ruvl;
54
55         ctlr = edev->ctlr;
56         qlock(&ctlr->slock);
57         p = kzmalloc(READSTR, 0);
58         if (p == NULL) {
59                 qunlock(&ctlr->slock);
60                 error(Enomem);
61         }
62         l = 0;
63         for (i = 0; i < Nstatistics; i++) {
64                 /* somehow read the device's HW stats */
65                 //r = csr32r(ctlr, Statistics + i * 4);
66                 r = 3;  /* TODO: this is the value for the statistic */
67                 if ((s = statistics[i]) == NULL)
68                         continue;
69                 /* based on the stat, spit out a string */
70                 switch (i) {
71                         default:
72                                 ctlr->statistics[i] += r;
73                                 if (ctlr->statistics[i] == 0)
74                                         continue;
75                                 l += snprintf(p + l, READSTR - l, "%s: %ud %ud\n",
76                                                           s, ctlr->statistics[i], r);
77                                 break;
78                 }
79         }
80
81         /* TODO: then print out the software-only (ctlr) stats */
82 //      l += snprintf(p + l, READSTR - l, "lintr: %ud %ud\n",
83 //                                ctlr->lintr, ctlr->lsleep);
84         n = readstr(offset, a, n, p);
85         kfree(p);
86         qunlock(&ctlr->slock);
87
88         return n;
89 }
90
91 static long bnx2x_ctl(struct ether *edev, void *buf, long n)
92 {
93         ERRSTACK(1);
94         int v;
95         char *p;
96         struct bnx2x *ctlr;
97         struct cmdbuf *cb;
98         struct cmdtab *ct;
99
100         if ((ctlr = edev->ctlr) == NULL)
101                 error(Enonexist);
102         cb = parsecmd(buf, n);
103         if (waserror()) {
104                 kfree(cb);
105                 nexterror();
106         }
107
108         /* TODO: handle ctl command somehow.  igbe did the following: */
109         //ct = lookupcmd(cb, igbectlmsg, ARRAY_SIZE(igbectlmsg));
110         
111         kfree(cb);
112         poperror();
113         return n;
114 }
115
116 static void bnx2x_promiscuous(void *arg, int on)
117 {
118         int rctl;
119         struct bnx2x *ctlr;
120         struct ether *edev;
121
122         edev = arg;
123         ctlr = edev->ctlr;
124         /* TODO: set promisc on/off */
125 }
126
127 static void bnx2x_multicast(void *arg, uint8_t * addr, int add)
128 {
129         int bit, x;
130         struct bnx2x *ctlr;
131         struct ether *edev;
132
133         edev = arg;
134         ctlr = edev->ctlr;
135         /* TODO: add or remove a multicast addr */
136 }
137
138 /* Transmit initialization.  Not mandatory for 9ns, but a good idea */
139 static void bnx2x_txinit(struct bnx2x *ctlr)
140 {
141 }
142
143 static void bnx2x_transmit(struct ether *edev)
144 {
145         struct block *bp;
146         struct bnx2x *ctlr;
147
148         ctlr = edev->ctlr;
149
150         /* Don't forget to spin_lock_irqsave */
151
152         /* TODO: Free any completed packets */
153
154         /* Try to fill the ring back up.  While there is space, yank from the output
155          * queue (oq) and put them in the Tx desc. */
156         while (1) {
157         //while (NEXT_RING(tdt, ctlr->ntd) != tdh) {
158                 if ((bp = qget(edev->oq)) == NULL)
159                         break;
160                 //td = &ctlr->tdba[tdt];
161                 //td->addr[0] = paddr_low32(bp->rp);
162                 //td->addr[1] = paddr_high32(bp->rp);
163                 /* if we're breaking out, make sure to set the IRQ mask */
164                 //if (NEXT_RING(tdt, ctlr->ntd) == tdh) {
165                 //      // other stuff removed
166                 //      csr32w(ctlr, Tdt, tdt);
167                 //      igbeim(ctlr, Txdw);
168                 //      break;
169                 //}
170         }
171 }
172
173 /* Not mandatory.  Called to make sure there are free blocks available for
174  * incoming packets */
175 static void bnx2x_replenish(struct bnx2x *ctlr)
176 {
177         struct block *bp;
178
179         while (1) {
180         //while (NEXT_RING(rdt, ctlr->nrd) != ctlr->rdh) {
181                 //if we want a new block
182                 {
183                         bp = iallocb(64); // TODO: use your block size, e.g. Rbsz
184                         if (bp == NULL) {
185                                 /* needs to be a safe print for interrupt level */
186                                 printk("#l%d bnx2x_replenish: no available buffers\n",
187                                            ctlr->edev->ctlrno);
188                                 break;
189                         }
190                         //ctlr->rb[rdt] = bp;
191                         //rd->addr[0] = paddr_low32(bp->rp);
192                         //rd->addr[1] = paddr_high32(bp->rp);
193                 }
194                 wmb();  /* ensure prev rd writes come before status = 0. */
195                 //rd->status = 0;
196         }
197 }
198
199 /* Not mandatory.  Device init. */
200 static void bnx2x_rxinit(struct bnx2x *ctlr)
201 {
202         bnx2x_replenish(ctlr);
203 }
204
205 static int bnx2x_rim(void* ctlr)
206 {
207         //return ((struct bnx2x*)ctlr)->rim != 0;
208         return 1;
209 }
210
211 /* Do we want a receive proc?  It is similar to softirq.  Or we can do the work
212  * in hard IRQ ctx. */
213 static void bnx2x_rproc(void *arg)
214 {
215         struct block *bp;
216         struct bnx2x *ctlr;
217         struct ether *edev;
218
219         edev = arg;
220         ctlr = edev->ctlr;
221
222         bnx2x_rxinit(ctlr);
223         /* TODO: one time RX init */
224
225
226         for (;;) {
227                 /* TODO: set up, once per sleep.  make sure we'll wake up */
228                 rendez_sleep(&ctlr->rrendez, bnx2x_rim, ctlr);
229
230                 for (;;) {
231                         /* if we can get a block, here's how to ram it up the stack */
232
233                         if (1) {
234                                 bp = (void*)0xdeadbeef;
235                                 //bp = ctlr->rb[rdh];
236                                 //bp->wp += rd->length;
237                                 //bp->next = NULL;
238                                 /* conditionally, set block flags */
239                                         //bp->flag |= Bipck; /* IP checksum done in HW */
240                                         //bp->flag |= Btcpck | Budpck;
241                                         //bp->checksum = rd->checksum;
242                                         //bp->flag |= Bpktck;   /* Packet checksum? */
243                                 etheriq(edev, bp, 1);
244                         } else {
245                                 //freeb(ctlr->rb[rdh]);
246                         }
247
248                 }
249                 // optionally
250                         bnx2x_replenish(ctlr);
251         }
252 }
253
254 static void bnx2x_attach(struct ether *edev)
255 {
256         ERRSTACK(1);
257         struct block *bp;
258         struct bnx2x *ctlr;
259         char *name;
260
261         ctlr = edev->ctlr;
262         ctlr->edev = edev;      /* point back to Ether* */
263
264         /* not sure if we'll need/want any of the 9ns stuff */
265         return;
266
267         qlock(&ctlr->alock);
268         /* TODO: make sure we haven't attached already.  If so, just return */
269
270         /* Alloc all your ctrl crap. */
271
272         /* the ktasks should free these names, if they ever exit */
273         name = kmalloc(KNAMELEN, KMALLOC_WAIT);
274         snprintf(name, KNAMELEN, "#l%d-bnx2x_rproc", edev->ctlrno);
275         ktask(name, bnx2x_rproc, edev);
276
277         bnx2x_txinit(ctlr);
278
279         qunlock(&ctlr->alock);
280 }
281
282 /* Hard IRQ */
283 static void bnx2x_interrupt(struct hw_trapframe *hw_tf, void *arg)
284 {
285         struct bnx2x *ctlr;
286         struct ether *edev;
287         int icr, im, txdw;
288
289         edev = arg;
290         ctlr = edev->ctlr;
291
292                         /* At some point, wake up the rproc */
293                         rendez_wakeup(&ctlr->rrendez);
294
295         /* optionally, might need to transmit (not sure if this is a good idea in
296          * hard irq or not) */
297         bnx2x_transmit(edev);
298 }
299
300 static void bnx2x_shutdown(struct ether *ether)
301 {
302         /*
303          * Perform a device reset to get the chip back to the
304          * power-on state, followed by an EEPROM reset to read
305          * the defaults for some internal registers.
306          */
307         /* igbe did: */
308         //igbedetach(ether->ctlr);
309 }
310
311 /* "reset", getting it back to the basic power-on state.  9ns drivers call this
312  * during the initial setup (from the PCI func) */
313 static int bnx2x_reset(struct bnx2x *ctlr)
314 {
315         int ctrl, i, pause, r, swdpio, txcw;
316
317         bnx2x_init_one(ctlr->edev, ctlr, ctlr->pcidev, ctlr->pci_id);
318         bnx2x_open(ctlr->edev);
319         //next ndo_set_rx_mode
320         /* despite the name, we attach at reset time.  BXE attach has a lot of
321          * mmio mappings that have to happen at boot (in akaros), instead of during
322          * devether's attach (at runtime) */
323
324         /* shut it up for now.  too much stats output */
325         ctlr->msg_enable = 0;
326
327 //extern int bnx2x_attach(struct bnx2x *sc);
328 //      bnx2x_attach(ctlr);
329 //
330 //      /* normally done during BSD's ifconfig */
331 //extern void bnx2x_init(void *xsc);
332 //      bnx2x_init(ctlr);
333
334 //      if (igbedetach(ctlr))
335 //              return -1;
336
337         return 0;
338 }
339
340 static void bnx2x_pci(void)
341 {
342         int cls, id;
343         struct pci_device *pcidev;
344         struct bnx2x *ctlr;
345         const struct pci_device_id *pci_id;
346
347         bnx2x_init();
348
349         STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
350                 /* This checks that pcidev is a Network Controller for Ethernet */
351                 if (pcidev->class != 0x02 || pcidev->subclass != 0x00)
352                         continue;
353                 id = pcidev->dev_id << 16 | pcidev->ven_id;
354
355                 pci_id = srch_bnx2x_pci_tbl(pcidev);
356                 if (!pci_id)
357                         continue;
358
359                 printk("bnx2x driver found 0x%04x:%04x at %02x:%02x.%x\n",
360                            pcidev->ven_id, pcidev->dev_id,
361                            pcidev->bus, pcidev->dev, pcidev->func);
362
363                 /* MMIO, pci_bus_master, etc, are all done in bnx2x_attach */
364
365                 cls = pcidev_read8(pcidev, PCI_CLSZ_REG);
366                 switch (cls) {
367                         default:
368                                 printd("bnx2x: unexpected CLS - %d\n", cls * 4);
369                                 break;
370                         case 0x00:
371                         case 0xFF:
372                                 /* bogus value; use a sane default.  cls is set in DWORD (u32)
373                                  * units. */
374                                 cls = ARCH_CL_SIZE / sizeof(long);
375                                 pcidev_write8(pcidev, PCI_CLSZ_REG, cls);
376                                 break;
377                         case 0x08:
378                         case 0x10:
379                                 break;
380                 }
381
382                 ctlr = kzmalloc(sizeof(struct bnx2x), 0);
383                 if (ctlr == NULL)
384                         error(Enomem);
385
386                 spinlock_init_irqsave(&ctlr->imlock);
387                 spinlock_init_irqsave(&ctlr->tlock);
388                 qlock_init(&ctlr->alock);
389                 qlock_init(&ctlr->slock);
390                 rendez_init(&ctlr->rrendez);
391
392                 ctlr->pcidev = pcidev;
393                 ctlr->pci_id = pci_id;
394                 
395                 spin_lock(&bnx2x_tq_lock);
396                 TAILQ_INSERT_TAIL(&bnx2x_tq, ctlr, link9ns);
397                 spin_unlock(&bnx2x_tq_lock);
398         }
399 }
400
401 /* Called by devether's probe routines.  Return -1 if the edev does not match
402  * any of your ctlrs. */
403 static int bnx2x_pnp(struct ether *edev)
404 {
405         struct bnx2x *ctlr;
406
407         /* Allocs ctlrs for all PCI devices matching our IDs, does various PCI and
408          * MMIO/port setup */
409         run_once(bnx2x_pci());
410
411         spin_lock(&bnx2x_tq_lock);
412         TAILQ_FOREACH(ctlr, &bnx2x_tq, link9ns) {
413                 /* just take the first inactive ctlr on the list */
414                 if (ctlr->active)
415                         continue;
416                 ctlr->active = 1;
417                 break;
418         }
419         spin_unlock(&bnx2x_tq_lock);
420         if (ctlr == NULL)
421                 return -1;
422
423         /* TODO: super-dirty hack.  This lock is normally not init'd until after
424          * reset reset/pnp.  But we want to use it earlier, since we call open
425          * during reset, instead of attach.  And that happens because we register
426          * IRQs in open, and MSIX IRQs need to be done at init time (Akaros could
427          * fix this).
428          *
429          * Anyway, we init the qlock here *and* in netifinit.  Good luck. */
430         qlock_init(&edev->qlock);
431
432         edev->ctlr = ctlr;
433         ctlr->edev = edev;
434
435         //edev->port = ctlr->port;      /* might just remove this from devether */
436         edev->irq = ctlr->pcidev->irqline;
437         edev->tbdf = MKBUS(BusPCI, ctlr->pcidev->bus, ctlr->pcidev->dev,
438                            ctlr->pcidev->func);
439         edev->mbps = 1000;
440         memmove(edev->ea, ctlr->link_params.mac_addr, Eaddrlen);
441         
442         /*
443          * Linkage to the generic ethernet driver.
444          */
445         edev->attach = bnx2x_attach;
446         edev->transmit = bnx2x_transmit;
447         edev->ifstat = bnx2x_ifstat;
448         edev->ctl = bnx2x_ctl;
449         edev->shutdown = bnx2x_shutdown;
450
451         edev->arg = edev;
452         edev->promiscuous = bnx2x_promiscuous;
453         edev->multicast = bnx2x_multicast;
454
455         /* Plan 9's MTU includes the header (e.g. 1514, instead of 1500).  Linux
456          * drivers expect just the payload and not the header, and will add in the
457          * 14 whenever it is needed.
458          *
459          * There might be issues when plan 9 code accesses maxmtu, now that it's
460          * 1500 instead of 1514.  Keep a lookout for Etoobig in etherwrite.  What a
461          * mess. */
462         edev->maxmtu -= ETHERHDRSIZE;
463
464         bnx2x_reset(ctlr);
465
466         return 0;
467 }
468
469 linker_func_3(etherbnx2x_link)
470 {
471         addethercard("bnx2x", bnx2x_pnp);
472 }