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