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