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