akaros/kern/drivers/net/bnx2x/bnx2x_dev.c
<<
>>
Prefs
   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 */
  26extern int __init bnx2x_init(void);
  27extern bool is_bnx2x_dev(struct pci_device *dev);
  28extern const struct pci_device_id *
  29                    srch_bnx2x_pci_tbl(struct pci_device *needle);
  30extern int bnx2x_init_one(struct ether *dev, struct bnx2x *bp,
  31                          struct pci_device *pdev,
  32                          const struct pci_device_id *ent);
  33extern int bnx2x_open(struct ether *dev);
  34extern void bnx2x_set_rx_mode(struct ether *dev);
  35extern netdev_tx_t bnx2x_start_xmit(struct block *block,
  36                                    struct bnx2x_fp_txdata *txdata);
  37
  38spinlock_t bnx2x_tq_lock = SPINLOCK_INITIALIZER;
  39TAILQ_HEAD(bnx2x_tq, bnx2x);
  40struct 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. */
  44static char *statistics[Nstatistics] = {
  45        "CRC Error",
  46        "Alignment Error",
  47};
  48
  49static 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
  92static 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. */
 158void __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
 189static 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 */
 202static 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. */
 229static void bnx2x_rxinit(struct bnx2x *ctlr)
 230{
 231        bnx2x_replenish(ctlr);
 232}
 233
 234static 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. */
 242static 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
 284static 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 */
 319static 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
 336static 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) */
 349static 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
 357static 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. */
 405static 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
 454linker_func_3(etherbnx2x_link)
 455{
 456        addethercard("bnx2x", bnx2x_pnp);
 457}
 458