bcf7415f26a1c70e0891c8bda0a9ea4b66d16d88
[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 extern void bnx2x_set_rx_mode(struct ether *dev);
37 extern netdev_tx_t bnx2x_start_xmit(struct block *block,
38                                     struct bnx2x_fp_txdata *txdata);
39
40 spinlock_t bnx2x_tq_lock = SPINLOCK_INITIALIZER;
41 TAILQ_HEAD(bnx2x_tq, bnx2x);
42 struct bnx2x_tq bnx2x_tq = TAILQ_HEAD_INITIALIZER(bnx2x_tq);
43
44 /* We're required to print out stats at some point.  Here are a couple from
45  * igbe, as an example. */
46 static char *statistics[Nstatistics] = {
47         "CRC Error",
48         "Alignment Error",
49 };
50
51 static long bnx2x_ifstat(struct ether *edev, void *a, long n, uint32_t offset)
52 {
53         struct bnx2x *ctlr;
54         char *p, *s;
55         int i, l, r;
56         uint64_t tuvl, ruvl;
57
58         ctlr = edev->ctlr;
59         qlock(&ctlr->slock);
60         p = kzmalloc(READSTR, 0);
61         if (p == NULL) {
62                 qunlock(&ctlr->slock);
63                 error(ENOMEM, ERROR_FIXME);
64         }
65         l = 0;
66         for (i = 0; i < Nstatistics; i++) {
67                 /* somehow read the device's HW stats */
68                 //r = csr32r(ctlr, Statistics + i * 4);
69                 r = 3;  /* TODO: this is the value for the statistic */
70                 if ((s = statistics[i]) == NULL)
71                         continue;
72                 /* based on the stat, spit out a string */
73                 switch (i) {
74                         default:
75                                 ctlr->statistics[i] += r;
76                                 if (ctlr->statistics[i] == 0)
77                                         continue;
78                                 l += snprintf(p + l, READSTR - l, "%s: %ud %ud\n",
79                                                           s, ctlr->statistics[i], r);
80                                 break;
81                 }
82         }
83
84         /* TODO: then print out the software-only (ctlr) stats */
85 //      l += snprintf(p + l, READSTR - l, "lintr: %ud %ud\n",
86 //                                ctlr->lintr, ctlr->lsleep);
87         n = readstr(offset, a, n, p);
88         kfree(p);
89         qunlock(&ctlr->slock);
90
91         return n;
92 }
93
94 static long bnx2x_ctl(struct ether *edev, void *buf, long n)
95 {
96         ERRSTACK(1);
97         int v;
98         char *p;
99         struct bnx2x *ctlr;
100         struct cmdbuf *cb;
101         struct cmdtab *ct;
102
103         if ((ctlr = edev->ctlr) == NULL)
104                 error(ENODEV, ERROR_FIXME);
105         cb = parsecmd(buf, n);
106         if (waserror()) {
107                 kfree(cb);
108                 nexterror();
109         }
110         if (cb->nf < 1)
111                 error(EFAIL, "short control request");
112
113         /* TODO: handle ctl command somehow.  igbe did the following: */
114         //ct = lookupcmd(cb, igbectlmsg, ARRAY_SIZE(igbectlmsg));
115
116         kfree(cb);
117         poperror();
118         return n;
119 }
120
121 static void bnx2x_promiscuous(void *arg, int on)
122 {
123         int rctl;
124         struct bnx2x *ctlr;
125         struct ether *edev;
126
127         edev = arg;
128         ctlr = edev->ctlr;
129         /* TODO: set promisc on/off */
130         error(EFAIL, "bnx2x promiscuous mode not supported");
131 }
132
133 static void bnx2x_multicast(void *arg, uint8_t * addr, int add)
134 {
135         int bit, x;
136         struct bnx2x *ctlr;
137         struct ether *edev;
138
139         edev = arg;
140         ctlr = edev->ctlr;
141         /* TODO: add or remove a multicast addr */
142 }
143
144 /* The poke function: we are guaranteed that only one copy of this func runs
145  * per poke tracker (per queue).  Both transmit and tx_int will poke, and after
146  * any pokes, the func will run at least once.
147  *
148  * Some notes for optimizing and synchronization:
149  *
150  * If we want a flag or something to keep us from checking the oq and attempting
151  * the xmit, all that will do is speed up xmit when the tx rings are full.
152  * You'd need to be careful.  The post/poke makes sure that this'll run after
153  * work was posted, but if this function sets an abort flag and later checks it,
154  * you need to check tx_avail *after* setting the flag (check, signal, check
155  * again).  Consider this:
156  *
157  * this func:
158  *              calls start_xmit, fails with BUSY.  wants to set ABORT flag
159  *
160  *      PAUSE - meanwhile:
161  *
162  * tx_int clears the ABORT flag, then pokes:
163  *              drain so there is room;
164  *              clear flag (combo of these is "post work");
165  *              poke;.  guaranteed that poke will happen after we cleared flag.
166  *                      but it is concurrent with this function
167  *
168  *              RESUME this func:
169  *
170  *              sets ABORT flag
171  *              returns.
172  *              tx_int's poke ensures we run again
173  *              we run again and see ABORT, then return
174  *              never try again til the next tx_int, if ever
175  *
176  * Instead, in this func, we must set ABORT flag, then check tx_avail.  Or
177  * have two flags, one set by us, another set by tx_int, where this func only
178  * clears the tx_int flag when it will attempt a start_xmit.
179  *
180  * It's probably easier to just check tx_avail before entering the while loop,
181  * if you're really concerned.  If you want to do the flag thing, probably use
182  * two flags (atomically), and be careful. */
183 void __bnx2x_tx_queue(void *txdata_arg)
184 {
185         struct bnx2x_fp_txdata *txdata = txdata_arg;
186         struct block *block;
187         struct queue *oq = txdata->oq;
188
189         /* TODO: avoid bugs til multi-queue is working */
190         assert(oq);
191         assert(txdata->txq_index == 0);
192
193         while ((block = qget(oq))) {
194                 if ((bnx2x_start_xmit(block, txdata) != NETDEV_TX_OK)) {
195                         /* all queue readers are sync'd by the poke, so we can putback
196                          * without fear of going out of order. */
197
198                         /* TODO: q code has methods that should be called with the spinlock
199                          * held, but no methods to do the locking... */
200                         //spin_unlock_irqsave(&oq->lock);
201                         qputback(oq, block);
202                         //spin_lock_irqsave(&oq->lock);
203
204                         /* device can't handle any more, we're done for now.  tx_int will
205                          * poke when space frees up.  it may be poking concurrently, and in
206                          * which case, we'll run again immediately. */
207                         break;
208                 }
209         }
210 }
211
212 static void bnx2x_transmit(struct ether *edev)
213 {
214         struct bnx2x *ctlr = edev->ctlr;
215         struct bnx2x_fp_txdata *txdata;
216         /* TODO: determine the tx queue we're supposed to work on */
217         int txq_index = 0;
218
219         txdata = &ctlr->bnx2x_txq[txq_index];
220         poke(&txdata->poker, txdata);
221 }
222
223 /* Not mandatory.  Called to make sure there are free blocks available for
224  * incoming packets */
225 static void bnx2x_replenish(struct bnx2x *ctlr)
226 {
227         struct block *bp;
228
229         while (1) {
230         //while (NEXT_RING(rdt, ctlr->nrd) != ctlr->rdh) {
231                 //if we want a new block
232                 {
233                         // TODO: use your block size, e.g. Rbsz
234                         bp = block_alloc(64, MEM_ATOMIC);
235                         if (bp == NULL) {
236                                 /* needs to be a safe print for interrupt level */
237                                 printk("#l%d bnx2x_replenish: no available buffers\n",
238                                            ctlr->edev->ctlrno);
239                                 break;
240                         }
241                         //ctlr->rb[rdt] = bp;
242                         //rd->addr[0] = paddr_low32(bp->rp);
243                         //rd->addr[1] = paddr_high32(bp->rp);
244                 }
245                 wmb();  /* ensure prev rd writes come before status = 0. */
246                 //rd->status = 0;
247         }
248 }
249
250 /* Not mandatory.  Device init. */
251 static void bnx2x_rxinit(struct bnx2x *ctlr)
252 {
253         bnx2x_replenish(ctlr);
254 }
255
256 static int bnx2x_rim(void* ctlr)
257 {
258         //return ((struct bnx2x*)ctlr)->rim != 0;
259         return 1;
260 }
261
262 /* Do we want a receive proc?  It is similar to softirq.  Or we can do the work
263  * in hard IRQ ctx. */
264 static void bnx2x_rproc(void *arg)
265 {
266         struct block *bp;
267         struct bnx2x *ctlr;
268         struct ether *edev;
269
270         edev = arg;
271         ctlr = edev->ctlr;
272
273         bnx2x_rxinit(ctlr);
274         /* TODO: one time RX init */
275
276
277         for (;;) {
278                 /* TODO: set up, once per sleep.  make sure we'll wake up */
279                 rendez_sleep(&ctlr->rrendez, bnx2x_rim, ctlr);
280
281                 for (;;) {
282                         /* if we can get a block, here's how to ram it up the stack */
283
284                         if (1) {
285                                 bp = (void*)0xdeadbeef;
286                                 //bp = ctlr->rb[rdh];
287                                 //bp->wp += rd->length;
288                                 //bp->next = NULL;
289                                 /* conditionally, set block flags */
290                                         //bp->flag |= Bipck; /* IP checksum done in HW */
291                                         //bp->flag |= Btcpck | Budpck;
292                                         //bp->checksum = rd->checksum;
293                                         //bp->flag |= Bpktck;   /* Packet checksum? */
294                                 etheriq(edev, bp, 1);
295                         } else {
296                                 //freeb(ctlr->rb[rdh]);
297                         }
298
299                 }
300                 // optionally
301                         bnx2x_replenish(ctlr);
302         }
303 }
304
305 static void bnx2x_attach(struct ether *edev)
306 {
307         ERRSTACK(1);
308         struct block *bp;
309         struct bnx2x *ctlr;
310         char *name;
311
312         ctlr = edev->ctlr;
313         ctlr->edev = edev;      /* point back to Ether* */
314
315         qlock(&ctlr->alock);
316         if (ctlr->attached) {
317                 qunlock(&ctlr->alock);
318                 return;
319         }
320
321         bnx2x_open(ctlr->edev);
322         bnx2x_set_rx_mode(edev);
323
324         ctlr->attached = TRUE;
325         qunlock(&ctlr->alock);
326         /* not sure if we'll need/want any of the other 9ns stuff */
327         return;
328
329         /* Alloc all your ctrl crap. */
330
331         /* the ktasks should free these names, if they ever exit */
332         name = kmalloc(KNAMELEN, MEM_WAIT);
333         snprintf(name, KNAMELEN, "#l%d-bnx2x_rproc", edev->ctlrno);
334         ktask(name, bnx2x_rproc, edev);
335
336         qunlock(&ctlr->alock);
337 }
338
339 /* Hard IRQ */
340 static void bnx2x_interrupt(struct hw_trapframe *hw_tf, void *arg)
341 {
342         struct bnx2x *ctlr;
343         struct ether *edev;
344         int icr, im, txdw;
345
346         edev = arg;
347         ctlr = edev->ctlr;
348
349                         /* At some point, wake up the rproc */
350                         rendez_wakeup(&ctlr->rrendez);
351
352         /* optionally, might need to transmit (not sure if this is a good idea in
353          * hard irq or not) */
354         bnx2x_transmit(edev);
355 }
356
357 static void bnx2x_shutdown(struct ether *ether)
358 {
359         /*
360          * Perform a device reset to get the chip back to the
361          * power-on state, followed by an EEPROM reset to read
362          * the defaults for some internal registers.
363          */
364         /* igbe did: */
365         //igbedetach(ether->ctlr);
366 }
367
368 /* "reset", getting it back to the basic power-on state.  9ns drivers call this
369  * during the initial setup (from the PCI func) */
370 static int bnx2x_reset(struct bnx2x *ctlr)
371 {
372         int ctrl, i, pause, r, swdpio, txcw;
373
374         bnx2x_init_one(ctlr->edev, ctlr, ctlr->pcidev, ctlr->pci_id);
375         return 0;
376 }
377
378 static void bnx2x_pci(void)
379 {
380         int cls, id;
381         struct pci_device *pcidev;
382         struct bnx2x *ctlr;
383         const struct pci_device_id *pci_id;
384
385         STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
386                 /* This checks that pcidev is a Network Controller for Ethernet */
387                 if (pcidev->class != 0x02 || pcidev->subclass != 0x00)
388                         continue;
389                 id = pcidev->dev_id << 16 | pcidev->ven_id;
390
391                 pci_id = srch_bnx2x_pci_tbl(pcidev);
392                 if (!pci_id)
393                         continue;
394
395                 /* only run bnx2x's __init method once we know we have one */
396                 run_once(bnx2x_init());
397
398                 printk("bnx2x driver found 0x%04x:%04x at %02x:%02x.%x\n",
399                            pcidev->ven_id, pcidev->dev_id,
400                            pcidev->bus, pcidev->dev, pcidev->func);
401
402                 /* MMIO, pci_bus_master, etc, are all done in bnx2x_attach */
403
404                 cls = pcidev_read8(pcidev, PCI_CLSZ_REG);
405                 switch (cls) {
406                         default:
407                                 printd("bnx2x: unexpected CLS - %d\n", cls * 4);
408                                 break;
409                         case 0x00:
410                         case 0xFF:
411                                 /* bogus value; use a sane default.  cls is set in DWORD (u32)
412                                  * units. */
413                                 cls = ARCH_CL_SIZE / sizeof(long);
414                                 pcidev_write8(pcidev, PCI_CLSZ_REG, cls);
415                                 break;
416                         case 0x08:
417                         case 0x10:
418                                 break;
419                 }
420
421                 ctlr = kzmalloc(sizeof(struct bnx2x), 0);
422                 if (ctlr == NULL)
423                         error(ENOMEM, ERROR_FIXME);
424
425                 spinlock_init_irqsave(&ctlr->imlock);
426                 spinlock_init_irqsave(&ctlr->tlock);
427                 qlock_init(&ctlr->alock);
428                 qlock_init(&ctlr->slock);
429                 rendez_init(&ctlr->rrendez);
430
431                 ctlr->pcidev = pcidev;
432                 ctlr->pci_id = pci_id;
433
434                 spin_lock(&bnx2x_tq_lock);
435                 TAILQ_INSERT_TAIL(&bnx2x_tq, ctlr, link9ns);
436                 spin_unlock(&bnx2x_tq_lock);
437         }
438 }
439
440 /* Called by devether's probe routines.  Return -1 if the edev does not match
441  * any of your ctlrs. */
442 static int bnx2x_pnp(struct ether *edev)
443 {
444         struct bnx2x *ctlr;
445
446         /* Allocs ctlrs for all PCI devices matching our IDs, does various PCI and
447          * MMIO/port setup */
448         run_once(bnx2x_pci());
449
450         spin_lock(&bnx2x_tq_lock);
451         TAILQ_FOREACH(ctlr, &bnx2x_tq, link9ns) {
452                 /* just take the first inactive ctlr on the list */
453                 if (ctlr->active)
454                         continue;
455                 ctlr->active = 1;
456                 break;
457         }
458         spin_unlock(&bnx2x_tq_lock);
459         if (ctlr == NULL)
460                 return -1;
461
462         edev->ctlr = ctlr;
463         ctlr->edev = edev;
464
465         //edev->port = ctlr->port;      /* might just remove this from devether */
466         edev->irq = ctlr->pcidev->irqline;
467         edev->tbdf = MKBUS(BusPCI, ctlr->pcidev->bus, ctlr->pcidev->dev,
468                            ctlr->pcidev->func);
469         edev->mbps = 1000;
470         memmove(edev->ea, ctlr->link_params.mac_addr, Eaddrlen);
471
472         /*
473          * Linkage to the generic ethernet driver.
474          */
475         edev->attach = bnx2x_attach;
476         edev->transmit = bnx2x_transmit;
477         edev->ifstat = bnx2x_ifstat;
478         edev->ctl = bnx2x_ctl;
479         edev->shutdown = bnx2x_shutdown;
480
481         edev->arg = edev;
482         edev->promiscuous = bnx2x_promiscuous;
483         edev->multicast = bnx2x_multicast;
484
485         bnx2x_reset(ctlr);
486
487         return 0;
488 }
489
490 linker_func_3(etherbnx2x_link)
491 {
492         addethercard("bnx2x", bnx2x_pnp);
493 }