Added explicit errno reporting from error() API.
[akaros.git] / kern / drivers / net / bnx2x / bnx2x_dev.c
index 83d72ff..f149546 100644 (file)
@@ -33,6 +33,9 @@ extern int bnx2x_init_one(struct ether *dev, struct bnx2x *bp,
                           struct pci_device *pdev,
                           const struct pci_device_id *ent);
 extern int bnx2x_open(struct ether *dev);
+extern void bnx2x_set_rx_mode(struct ether *dev);
+extern netdev_tx_t bnx2x_start_xmit(struct block *block,
+                                    struct bnx2x_fp_txdata *txdata);
 
 spinlock_t bnx2x_tq_lock = SPINLOCK_INITIALIZER;
 TAILQ_HEAD(bnx2x_tq, bnx2x);
@@ -57,7 +60,7 @@ static long bnx2x_ifstat(struct ether *edev, void *a, long n, uint32_t offset)
        p = kzmalloc(READSTR, 0);
        if (p == NULL) {
                qunlock(&ctlr->slock);
-               error(Enomem);
+               error(ENOMEM, NULL);
        }
        l = 0;
        for (i = 0; i < Nstatistics; i++) {
@@ -98,12 +101,14 @@ static long bnx2x_ctl(struct ether *edev, void *buf, long n)
        struct cmdtab *ct;
 
        if ((ctlr = edev->ctlr) == NULL)
-               error(Enonexist);
+               error(ENODEV, NULL);
        cb = parsecmd(buf, n);
        if (waserror()) {
                kfree(cb);
                nexterror();
        }
+       if (cb->nf < 1)
+               error(EFAIL, "short control request");
 
        /* TODO: handle ctl command somehow.  igbe did the following: */
        //ct = lookupcmd(cb, igbectlmsg, ARRAY_SIZE(igbectlmsg));
@@ -135,39 +140,83 @@ static void bnx2x_multicast(void *arg, uint8_t * addr, int add)
        /* TODO: add or remove a multicast addr */
 }
 
-/* Transmit initialization.  Not mandatory for 9ns, but a good idea */
-static void bnx2x_txinit(struct bnx2x *ctlr)
+/* The poke function: we are guaranteed that only one copy of this func runs
+ * per poke tracker (per queue).  Both transmit and tx_int will poke, and after
+ * any pokes, the func will run at least once.
+ *
+ * Some notes for optimizing and synchronization:
+ *
+ * If we want a flag or something to keep us from checking the oq and attempting
+ * the xmit, all that will do is speed up xmit when the tx rings are full.
+ * You'd need to be careful.  The post/poke makes sure that this'll run after
+ * work was posted, but if this function sets an abort flag and later checks it,
+ * you need to check tx_avail *after* setting the flag (check, signal, check
+ * again).  Consider this:
+ *
+ * this func:
+ *             calls start_xmit, fails with BUSY.  wants to set ABORT flag
+ *
+ *      PAUSE - meanwhile:
+ *
+ * tx_int clears the ABORT flag, then pokes:
+ *             drain so there is room;
+ *             clear flag (combo of these is "post work");
+ *             poke;.  guaranteed that poke will happen after we cleared flag.
+ *                     but it is concurrent with this function
+ *
+ *             RESUME this func:
+ *
+ *             sets ABORT flag
+ *             returns.
+ *             tx_int's poke ensures we run again
+ *             we run again and see ABORT, then return
+ *             never try again til the next tx_int, if ever
+ *
+ * Instead, in this func, we must set ABORT flag, then check tx_avail.  Or
+ * have two flags, one set by us, another set by tx_int, where this func only
+ * clears the tx_int flag when it will attempt a start_xmit.
+ *
+ * It's probably easier to just check tx_avail before entering the while loop,
+ * if you're really concerned.  If you want to do the flag thing, probably use
+ * two flags (atomically), and be careful. */
+void __bnx2x_tx_queue(void *txdata_arg)
 {
+       struct bnx2x_fp_txdata *txdata = txdata_arg;
+       struct block *block;
+       struct queue *oq = txdata->oq;
+
+       /* TODO: avoid bugs til multi-queue is working */
+       assert(oq);
+       assert(txdata->txq_index == 0);
+
+       while ((block = qget(oq))) {
+               if ((bnx2x_start_xmit(block, txdata) != NETDEV_TX_OK)) {
+                       /* all queue readers are sync'd by the poke, so we can putback
+                        * without fear of going out of order. */
+
+                       /* TODO: q code has methods that should be called with the spinlock
+                        * held, but no methods to do the locking... */
+                       //spin_unlock_irqsave(&oq->lock);
+                       qputback(oq, block);
+                       //spin_lock_irqsave(&oq->lock);
+
+                       /* device can't handle any more, we're done for now.  tx_int will
+                        * poke when space frees up.  it may be poking concurrently, and in
+                        * which case, we'll run again immediately. */
+                       break;
+               }
+       }
 }
 
 static void bnx2x_transmit(struct ether *edev)
 {
-       struct block *bp;
-       struct bnx2x *ctlr;
-
-       ctlr = edev->ctlr;
-
-       /* Don't forget to spin_lock_irqsave */
+       struct bnx2x *ctlr = edev->ctlr;
+       struct bnx2x_fp_txdata *txdata;
+       /* TODO: determine the tx queue we're supposed to work on */
+       int txq_index = 0;
 
-       /* TODO: Free any completed packets */
-
-       /* Try to fill the ring back up.  While there is space, yank from the output
-        * queue (oq) and put them in the Tx desc. */
-       while (1) {
-       //while (NEXT_RING(tdt, ctlr->ntd) != tdh) {
-               if ((bp = qget(edev->oq)) == NULL)
-                       break;
-               //td = &ctlr->tdba[tdt];
-               //td->addr[0] = paddr_low32(bp->rp);
-               //td->addr[1] = paddr_high32(bp->rp);
-               /* if we're breaking out, make sure to set the IRQ mask */
-               //if (NEXT_RING(tdt, ctlr->ntd) == tdh) {
-               //      // other stuff removed
-               //      csr32w(ctlr, Tdt, tdt);
-               //      igbeim(ctlr, Txdw);
-               //      break;
-               //}
-       }
+       txdata = &ctlr->bnx2x_txq[txq_index];
+       poke(&txdata->poker, txdata);
 }
 
 /* Not mandatory.  Called to make sure there are free blocks available for
@@ -261,11 +310,19 @@ static void bnx2x_attach(struct ether *edev)
        ctlr = edev->ctlr;
        ctlr->edev = edev;      /* point back to Ether* */
 
-       /* not sure if we'll need/want any of the 9ns stuff */
-       return;
-
        qlock(&ctlr->alock);
-       /* TODO: make sure we haven't attached already.  If so, just return */
+       if (ctlr->attached) {
+               qunlock(&ctlr->alock);
+               return;
+       }
+
+       bnx2x_open(ctlr->edev);
+       bnx2x_set_rx_mode(edev);
+
+       ctlr->attached = TRUE;
+       qunlock(&ctlr->alock);
+       /* not sure if we'll need/want any of the other 9ns stuff */
+       return;
 
        /* Alloc all your ctrl crap. */
 
@@ -274,8 +331,6 @@ static void bnx2x_attach(struct ether *edev)
        snprintf(name, KNAMELEN, "#l%d-bnx2x_rproc", edev->ctlrno);
        ktask(name, bnx2x_rproc, edev);
 
-       bnx2x_txinit(ctlr);
-
        qunlock(&ctlr->alock);
 }
 
@@ -315,25 +370,6 @@ static int bnx2x_reset(struct bnx2x *ctlr)
        int ctrl, i, pause, r, swdpio, txcw;
 
        bnx2x_init_one(ctlr->edev, ctlr, ctlr->pcidev, ctlr->pci_id);
-       bnx2x_open(ctlr->edev);
-       //next ndo_set_rx_mode
-       /* despite the name, we attach at reset time.  BXE attach has a lot of
-        * mmio mappings that have to happen at boot (in akaros), instead of during
-        * devether's attach (at runtime) */
-
-       /* shut it up for now.  too much stats output */
-       ctlr->msg_enable = 0;
-
-//extern int bnx2x_attach(struct bnx2x *sc);
-//     bnx2x_attach(ctlr);
-//
-//     /* normally done during BSD's ifconfig */
-//extern void bnx2x_init(void *xsc);
-//     bnx2x_init(ctlr);
-
-//     if (igbedetach(ctlr))
-//             return -1;
-
        return 0;
 }
 
@@ -344,8 +380,6 @@ static void bnx2x_pci(void)
        struct bnx2x *ctlr;
        const struct pci_device_id *pci_id;
 
-       bnx2x_init();
-
        STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
                /* This checks that pcidev is a Network Controller for Ethernet */
                if (pcidev->class != 0x02 || pcidev->subclass != 0x00)
@@ -356,6 +390,9 @@ static void bnx2x_pci(void)
                if (!pci_id)
                        continue;
 
+               /* only run bnx2x's __init method once we know we have one */
+               run_once(bnx2x_init());
+
                printk("bnx2x driver found 0x%04x:%04x at %02x:%02x.%x\n",
                           pcidev->ven_id, pcidev->dev_id,
                           pcidev->bus, pcidev->dev, pcidev->func);
@@ -381,7 +418,7 @@ static void bnx2x_pci(void)
 
                ctlr = kzmalloc(sizeof(struct bnx2x), 0);
                if (ctlr == NULL)
-                       error(Enomem);
+                       error(ENOMEM, NULL);
 
                spinlock_init_irqsave(&ctlr->imlock);
                spinlock_init_irqsave(&ctlr->tlock);
@@ -420,15 +457,6 @@ static int bnx2x_pnp(struct ether *edev)
        if (ctlr == NULL)
                return -1;
 
-       /* TODO: super-dirty hack.  This lock is normally not init'd until after
-        * reset reset/pnp.  But we want to use it earlier, since we call open
-        * during reset, instead of attach.  And that happens because we register
-        * IRQs in open, and MSIX IRQs need to be done at init time (Akaros could
-        * fix this).
-        *
-        * Anyway, we init the qlock here *and* in netifinit.  Good luck. */
-       qlock_init(&edev->qlock);
-
        edev->ctlr = ctlr;
        ctlr->edev = edev;
 
@@ -452,15 +480,6 @@ static int bnx2x_pnp(struct ether *edev)
        edev->promiscuous = bnx2x_promiscuous;
        edev->multicast = bnx2x_multicast;
 
-       /* Plan 9's MTU includes the header (e.g. 1514, instead of 1500).  Linux
-        * drivers expect just the payload and not the header, and will add in the
-        * 14 whenever it is needed.
-        *
-        * There might be issues when plan 9 code accesses maxmtu, now that it's
-        * 1500 instead of 1514.  Keep a lookout for Etoobig in etherwrite.  What a
-        * mess. */
-       edev->maxmtu -= ETHERHDRSIZE;
-
        bnx2x_reset(ctlr);
 
        return 0;