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