bnx2: Cleanup error handling in bnx2_open().
[safe/jmp/linux-2.6] / drivers / net / bnx2.c
index 3872e51..d4be238 100644 (file)
@@ -2996,9 +2996,9 @@ next_rx:
 static irqreturn_t
 bnx2_msi(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
 
        prefetch(bnapi->status_blk.msi);
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
@@ -3017,9 +3017,9 @@ bnx2_msi(int irq, void *dev_instance)
 static irqreturn_t
 bnx2_msi_1shot(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
 
        prefetch(bnapi->status_blk.msi);
 
@@ -3035,9 +3035,9 @@ bnx2_msi_1shot(int irq, void *dev_instance)
 static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
        struct status_block *sblk = bnapi->status_blk.msi;
 
        /* When using INTx, it is possible for the interrupt to arrive
@@ -3072,23 +3072,6 @@ bnx2_interrupt(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t
-bnx2_tx_msix(int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC];
-
-       prefetch(bnapi->status_blk.msix);
-
-       /* Return here if interrupt is disabled. */
-       if (unlikely(atomic_read(&bp->intr_sem) != 0))
-               return IRQ_HANDLED;
-
-       netif_rx_schedule(dev, &bnapi->napi);
-       return IRQ_HANDLED;
-}
-
 static inline int
 bnx2_has_fast_work(struct bnx2_napi *bnapi)
 {
@@ -3119,30 +3102,6 @@ bnx2_has_work(struct bnx2_napi *bnapi)
        return 0;
 }
 
-static int bnx2_tx_poll(struct napi_struct *napi, int budget)
-{
-       struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
-       struct bnx2 *bp = bnapi->bp;
-       struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
-       int work_done = 0;
-       struct status_block_msix *sblk = bnapi->status_blk.msix;
-
-       do {
-               work_done += bnx2_tx_int(bp, bnapi, budget - work_done);
-               if (unlikely(work_done >= budget))
-                       return work_done;
-
-               bnapi->last_status_idx = sblk->status_idx;
-               rmb();
-       } while (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons);
-
-       netif_rx_complete(bp->dev, napi);
-       REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
-              BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-              bnapi->last_status_idx);
-       return work_done;
-}
-
 static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
        struct status_block *sblk = bnapi->status_blk.msi;
@@ -3178,6 +3137,33 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
        return work_done;
 }
 
+static int bnx2_poll_msix(struct napi_struct *napi, int budget)
+{
+       struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
+       struct bnx2 *bp = bnapi->bp;
+       int work_done = 0;
+       struct status_block_msix *sblk = bnapi->status_blk.msix;
+
+       while (1) {
+               work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
+               if (unlikely(work_done >= budget))
+                       break;
+
+               bnapi->last_status_idx = sblk->status_idx;
+               /* status idx must be read before checking for more work. */
+               rmb();
+               if (likely(!bnx2_has_fast_work(bnapi))) {
+
+                       netif_rx_complete(bp->dev, napi);
+                       REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+                              BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+                              bnapi->last_status_idx);
+                       break;
+               }
+       }
+       return work_done;
+}
+
 static int bnx2_poll(struct napi_struct *napi, int budget)
 {
        struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
@@ -4556,15 +4542,25 @@ bnx2_init_chip(struct bnx2 *bp)
                      BNX2_HC_CONFIG_COLLECT_STATS;
        }
 
-       if (bp->flags & BNX2_FLAG_USING_MSIX) {
-               u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
-                          BNX2_HC_SB_CONFIG_1;
-
+       if (bp->irq_nvecs > 1) {
                REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
                       BNX2_HC_MSIX_BIT_VECTOR_VAL);
 
+               val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
+       }
+
+       if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
+               val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+       REG_WR(bp, BNX2_HC_CONFIG, val);
+
+       for (i = 1; i < bp->irq_nvecs; i++) {
+               u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+                          BNX2_HC_SB_CONFIG_1;
+
                REG_WR(bp, base,
                        BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
+                       BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
                        BNX2_HC_SB_CONFIG_1_ONE_SHOT);
 
                REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
@@ -4574,13 +4570,13 @@ bnx2_init_chip(struct bnx2 *bp)
                REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
                        (bp->tx_ticks_int << 16) | bp->tx_ticks);
 
-               val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
-       }
+               REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
+                      (bp->rx_quick_cons_trip_int << 16) |
+                       bp->rx_quick_cons_trip);
 
-       if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
-               val |= BNX2_HC_CONFIG_ONE_SHOT;
-
-       REG_WR(bp, BNX2_HC_CONFIG, val);
+               REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
+                       (bp->rx_ticks_int << 16) | bp->rx_ticks);
+       }
 
        /* Clear internal stats counters. */
        REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
@@ -4751,7 +4747,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
                val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
-                      BNX2_L2CTX_RBDC_JUMBO_KEY);
+                      BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
 
                val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
@@ -4801,6 +4797,7 @@ static void
 bnx2_init_all_rings(struct bnx2 *bp)
 {
        int i;
+       u32 val;
 
        bnx2_clear_ring_states(bp);
 
@@ -4812,8 +4809,33 @@ bnx2_init_all_rings(struct bnx2 *bp)
                REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
                       (TX_TSS_CID << 7));
 
+       REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
+       bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
+
        for (i = 0; i < bp->num_rx_rings; i++)
                bnx2_init_rx_ring(bp, i);
+
+       if (bp->num_rx_rings > 1) {
+               u32 tbl_32;
+               u8 *tbl = (u8 *) &tbl_32;
+
+               bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
+                               BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
+
+               for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
+                       tbl[i % 4] = i % (bp->num_rx_rings - 1);
+                       if ((i % 4) == 3)
+                               bnx2_reg_wr_ind(bp,
+                                               BNX2_RXP_SCRATCH_RSS_TBL + i,
+                                               cpu_to_be32(tbl_32));
+               }
+
+               val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
+                     BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
+
+               REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
+
+       }
 }
 
 static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
@@ -5636,7 +5658,6 @@ bnx2_restart_timer:
 static int
 bnx2_request_irq(struct bnx2 *bp)
 {
-       struct net_device *dev = bp->dev;
        unsigned long flags;
        struct bnx2_irq *irq;
        int rc = 0, i;
@@ -5649,7 +5670,7 @@ bnx2_request_irq(struct bnx2 *bp)
        for (i = 0; i < bp->irq_nvecs; i++) {
                irq = &bp->irq_tbl[i];
                rc = request_irq(irq->vector, irq->handler, flags, irq->name,
-                                dev);
+                                &bp->bnx2_napi[i]);
                if (rc)
                        break;
                irq->requested = 1;
@@ -5660,14 +5681,13 @@ bnx2_request_irq(struct bnx2 *bp)
 static void
 bnx2_free_irq(struct bnx2 *bp)
 {
-       struct net_device *dev = bp->dev;
        struct bnx2_irq *irq;
        int i;
 
        for (i = 0; i < bp->irq_nvecs; i++) {
                irq = &bp->irq_tbl[i];
                if (irq->requested)
-                       free_irq(irq->vector, dev);
+                       free_irq(irq->vector, &bp->bnx2_napi[i]);
                irq->requested = 0;
        }
        if (bp->flags & BNX2_FLAG_USING_MSI)
@@ -5679,7 +5699,7 @@ bnx2_free_irq(struct bnx2 *bp)
 }
 
 static void
-bnx2_enable_msix(struct bnx2 *bp)
+bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 {
        int i, rc;
        struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
@@ -5694,17 +5714,14 @@ bnx2_enable_msix(struct bnx2 *bp)
                msix_ent[i].vector = 0;
 
                strcpy(bp->irq_tbl[i].name, bp->dev->name);
-               if (i == 0)
-                       bp->irq_tbl[i].handler = bnx2_msi_1shot;
-               else
-                       bp->irq_tbl[i].handler = bnx2_tx_msix;
+               bp->irq_tbl[i].handler = bnx2_msi_1shot;
        }
 
        rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
        if (rc != 0)
                return;
 
-       bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
+       bp->irq_nvecs = msix_vecs;
        bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
        for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
                bp->irq_tbl[i].vector = msix_ent[i].vector;
@@ -5713,13 +5730,16 @@ bnx2_enable_msix(struct bnx2 *bp)
 static void
 bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
 {
+       int cpus = num_online_cpus();
+       int msix_vecs = min(cpus + 1, RX_MAX_RSS_RINGS);
+
        bp->irq_tbl[0].handler = bnx2_interrupt;
        strcpy(bp->irq_tbl[0].name, bp->dev->name);
        bp->irq_nvecs = 1;
        bp->irq_tbl[0].vector = bp->pdev->irq;
 
-       if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
-               bnx2_enable_msix(bp);
+       if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
+               bnx2_enable_msix(bp, msix_vecs);
 
        if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
            !(bp->flags & BNX2_FLAG_USING_MSIX)) {
@@ -5735,7 +5755,7 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
                }
        }
        bp->num_tx_rings = 1;
-       bp->num_rx_rings = 1;
+       bp->num_rx_rings = bp->irq_nvecs;
 }
 
 /* Called with rtnl_lock */
@@ -5753,29 +5773,16 @@ bnx2_open(struct net_device *dev)
        bnx2_setup_int_mode(bp, disable_msi);
        bnx2_napi_enable(bp);
        rc = bnx2_alloc_mem(bp);
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        rc = bnx2_request_irq(bp);
-
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        rc = bnx2_init_nic(bp, 1);
-
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_irq(bp);
-               bnx2_free_skbs(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 
@@ -5805,11 +5812,8 @@ bnx2_open(struct net_device *dev)
                                rc = bnx2_request_irq(bp);
 
                        if (rc) {
-                               bnx2_napi_disable(bp);
-                               bnx2_free_skbs(bp);
-                               bnx2_free_mem(bp);
                                del_timer_sync(&bp->timer);
-                               return rc;
+                               goto open_err;
                        }
                        bnx2_enable_int(bp);
                }
@@ -5822,6 +5826,13 @@ bnx2_open(struct net_device *dev)
        netif_start_queue(dev);
 
        return 0;
+
+open_err:
+       bnx2_napi_disable(bp);
+       bnx2_free_skbs(bp);
+       bnx2_free_irq(bp);
+       bnx2_free_mem(bp);
+       return rc;
 }
 
 static void
@@ -7567,7 +7578,7 @@ bnx2_init_napi(struct bnx2 *bp)
                if (i == 0)
                        poll = bnx2_poll;
                else
-                       poll = bnx2_tx_poll;
+                       poll = bnx2_poll_msix;
 
                netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
                bnapi->bp = bp;