]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ethernet/broadcom/cnic.c
cnic: Allocate UIO resources only on devices that support iSCSI.
[~andy/linux] / drivers / net / ethernet / broadcom / cnic.c
index 2c89d17cbb292cfc3e971dbf180b95728d8e06b7..2107d79d69b37ca3f6740735e0971f31c0e3bbe0 100644 (file)
@@ -256,11 +256,16 @@ static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg)
        struct cnic_local *cp = dev->cnic_priv;
        struct cnic_eth_dev *ethdev = cp->ethdev;
        struct drv_ctl_info info;
+       struct fcoe_capabilities *fcoe_cap =
+               &info.data.register_data.fcoe_features;
 
-       if (reg)
+       if (reg) {
                info.cmd = DRV_CTL_ULP_REGISTER_CMD;
-       else
+               if (ulp_type == CNIC_ULP_FCOE && dev->fcoe_cap)
+                       memcpy(fcoe_cap, dev->fcoe_cap, sizeof(*fcoe_cap));
+       } else {
                info.cmd = DRV_CTL_ULP_UNREGISTER_CMD;
+       }
 
        info.data.ulp_type = ulp_type;
        ethdev->drv_ctl(dev->netdev, &info);
@@ -286,6 +291,9 @@ static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid)
 {
        u32 i;
 
+       if (!cp->ctx_tbl)
+               return -EINVAL;
+
        for (i = 0; i < cp->max_cid_space; i++) {
                if (cp->ctx_tbl[i].cid == cid) {
                        *l5_cid = i;
@@ -612,6 +620,8 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
 
        if (ulp_type == CNIC_ULP_ISCSI)
                cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+       else if (ulp_type == CNIC_ULP_FCOE)
+               dev->fcoe_cap = NULL;
 
        synchronize_rcu();
 
@@ -813,10 +823,8 @@ static void cnic_free_context(struct cnic_dev *dev)
        }
 }
 
-static void __cnic_free_uio(struct cnic_uio_dev *udev)
+static void __cnic_free_uio_rings(struct cnic_uio_dev *udev)
 {
-       uio_unregister_device(&udev->cnic_uinfo);
-
        if (udev->l2_buf) {
                dma_free_coherent(&udev->pdev->dev, udev->l2_buf_size,
                                  udev->l2_buf, udev->l2_buf_map);
@@ -829,6 +837,14 @@ static void __cnic_free_uio(struct cnic_uio_dev *udev)
                udev->l2_ring = NULL;
        }
 
+}
+
+static void __cnic_free_uio(struct cnic_uio_dev *udev)
+{
+       uio_unregister_device(&udev->cnic_uinfo);
+
+       __cnic_free_uio_rings(udev);
+
        pci_dev_put(udev->pdev);
        kfree(udev);
 }
@@ -852,6 +868,8 @@ static void cnic_free_resc(struct cnic_dev *dev)
        if (udev) {
                udev->dev = NULL;
                cp->udev = NULL;
+               if (udev->uio_dev == -1)
+                       __cnic_free_uio_rings(udev);
        }
 
        cnic_free_context(dev);
@@ -986,6 +1004,34 @@ static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info,
        return 0;
 }
 
+static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
+{
+       struct cnic_local *cp = udev->dev->cnic_priv;
+
+       if (udev->l2_ring)
+               return 0;
+
+       udev->l2_ring_size = pages * BCM_PAGE_SIZE;
+       udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
+                                          &udev->l2_ring_map,
+                                          GFP_KERNEL | __GFP_COMP);
+       if (!udev->l2_ring)
+               return -ENOMEM;
+
+       udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
+       udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+       udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
+                                         &udev->l2_buf_map,
+                                         GFP_KERNEL | __GFP_COMP);
+       if (!udev->l2_buf) {
+               __cnic_free_uio_rings(udev);
+               return -ENOMEM;
+       }
+
+       return 0;
+
+}
+
 static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
 {
        struct cnic_local *cp = dev->cnic_priv;
@@ -995,6 +1041,11 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
        list_for_each_entry(udev, &cnic_udev_list, list) {
                if (udev->pdev == dev->pcidev) {
                        udev->dev = dev;
+                       if (__cnic_alloc_uio_rings(udev, pages)) {
+                               udev->dev = NULL;
+                               read_unlock(&cnic_dev_lock);
+                               return -ENOMEM;
+                       }
                        cp->udev = udev;
                        read_unlock(&cnic_dev_lock);
                        return 0;
@@ -1010,20 +1061,9 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
 
        udev->dev = dev;
        udev->pdev = dev->pcidev;
-       udev->l2_ring_size = pages * BCM_PAGE_SIZE;
-       udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
-                                          &udev->l2_ring_map,
-                                          GFP_KERNEL | __GFP_COMP);
-       if (!udev->l2_ring)
-               goto err_udev;
 
-       udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
-       udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
-       udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
-                                         &udev->l2_buf_map,
-                                         GFP_KERNEL | __GFP_COMP);
-       if (!udev->l2_buf)
-               goto err_dma;
+       if (__cnic_alloc_uio_rings(udev, pages))
+               goto err_udev;
 
        write_lock(&cnic_dev_lock);
        list_add(&udev->list, &cnic_udev_list);
@@ -1034,9 +1074,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
        cp->udev = udev;
 
        return 0;
- err_dma:
-       dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size,
-                         udev->l2_ring, udev->l2_ring_map);
+
  err_udev:
        kfree(udev);
        return -ENOMEM;
@@ -1250,7 +1288,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
        if (ret)
                goto error;
 
-       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
+       if (CNIC_SUPPORTS_FCOE(cp)) {
                ret = cnic_alloc_kcq(dev, &cp->kcq2, true);
                if (ret)
                        goto error;
@@ -1265,6 +1303,9 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
        if (ret)
                goto error;
 
+       if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI)
+               return 0;
+
        cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
 
        cp->l2_rx_ring_size = 15;
@@ -2589,7 +2630,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
                return;
        }
 
-       cqes[0] = (struct kcqe *) &kcqe;
+       cqes[0] = &kcqe;
        cnic_reply_bnx2x_kcqes(dev, ulp_type, cqes, 1);
 }
 
@@ -3040,6 +3081,22 @@ static void cnic_ack_bnx2x_e2_msix(struct cnic_dev *dev)
                        IGU_INT_DISABLE, 0);
 }
 
+static void cnic_arm_bnx2x_msix(struct cnic_dev *dev, u32 idx)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, CSTORM_ID, idx,
+                          IGU_INT_ENABLE, 1);
+}
+
+static void cnic_arm_bnx2x_e2_msix(struct cnic_dev *dev, u32 idx)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF, idx,
+                       IGU_INT_ENABLE, 1);
+}
+
 static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
 {
        u32 last_status = *info->status_idx_ptr;
@@ -3076,9 +3133,8 @@ static void cnic_service_bnx2x_bh(unsigned long data)
                CNIC_WR16(dev, cp->kcq1.io_addr,
                          cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-               if (!BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
-                       cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
-                                          status_idx, IGU_INT_ENABLE, 1);
+               if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE) {
+                       cp->arm_int(dev, status_idx);
                        break;
                }
 
@@ -3217,6 +3273,9 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
                u32 l5_cid;
                struct cnic_local *cp = dev->cnic_priv;
 
+               if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+                       break;
+
                if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) {
                        struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
 
@@ -3947,6 +4006,15 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
                cnic_cm_upcall(cp, csk, opcode);
                break;
 
+       case L5CM_RAMROD_CMD_ID_CLOSE:
+               if (l4kcqe->status != 0) {
+                       netdev_warn(dev->netdev, "RAMROD CLOSE compl with "
+                                   "status 0x%x\n", l4kcqe->status);
+                       opcode = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
+                       /* Fall through */
+               } else {
+                       break;
+               }
        case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
        case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
        case L4_KCQE_OPCODE_VALUE_RESET_COMP:
@@ -4250,8 +4318,6 @@ static int cnic_cm_shutdown(struct cnic_dev *dev)
        struct cnic_local *cp = dev->cnic_priv;
        int i;
 
-       cp->stop_cm(dev);
-
        if (!cp->csk_tbl)
                return 0;
 
@@ -4669,9 +4735,9 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        cp->kcq1.sw_prod_idx = 0;
        cp->kcq1.hw_prod_idx_ptr =
-               (u16 *) &sblk->status_completion_producer_index;
+               &sblk->status_completion_producer_index;
 
-       cp->kcq1.status_idx_ptr = (u16 *) &sblk->status_idx;
+       cp->kcq1.status_idx_ptr = &sblk->status_idx;
 
        /* Initialize the kernel complete queue context. */
        val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
@@ -4697,9 +4763,9 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
                u32 sb = BNX2_L2CTX_L5_STATUSB_NUM(sb_id);
 
                cp->kcq1.hw_prod_idx_ptr =
-                       (u16 *) &msblk->status_completion_producer_index;
-               cp->kcq1.status_idx_ptr = (u16 *) &msblk->status_idx;
-               cp->kwq_con_idx_ptr = (u16 *) &msblk->status_cmd_consumer_index;
+                       &msblk->status_completion_producer_index;
+               cp->kcq1.status_idx_ptr = &msblk->status_idx;
+               cp->kwq_con_idx_ptr = &msblk->status_cmd_consumer_index;
                cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
                cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
                cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
@@ -4981,8 +5047,14 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
        cp->port_mode = CHIP_PORT_MODE_NONE;
 
        if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
-               u32 val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN_OVWR);
+               u32 val;
 
+               pci_read_config_dword(dev->pcidev, PCICFG_ME_REGISTER, &val);
+               cp->func = (u8) ((val & ME_REG_ABS_PF_NUM) >>
+                                ME_REG_ABS_PF_NUM_SHIFT);
+               func = CNIC_FUNC(cp);
+
+               val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN_OVWR);
                if (!(val & 1))
                        val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN);
                else
@@ -5282,11 +5354,12 @@ static void cnic_stop_hw(struct cnic_dev *dev)
                /* Need to wait for the ring shutdown event to complete
                 * before clearing the CNIC_UP flag.
                 */
-               while (cp->udev->uio_dev != -1 && i < 15) {
+               while (cp->udev && cp->udev->uio_dev != -1 && i < 15) {
                        msleep(100);
                        i++;
                }
                cnic_shutdown_rings(dev);
+               cp->stop_cm(dev);
                clear_bit(CNIC_F_CNIC_UP, &dev->flags);
                RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
                synchronize_rcu();
@@ -5446,8 +5519,7 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
 
        if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI))
                cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
-       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id) &&
-           !(ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE))
+       if (CNIC_SUPPORTS_FCOE(cp))
                cdev->max_fcoe_conn = ethdev->max_fcoe_conn;
 
        if (cdev->max_fcoe_conn > BNX2X_FCOE_NUM_CONNECTIONS)
@@ -5465,10 +5537,13 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
        cp->stop_cm = cnic_cm_stop_bnx2x_hw;
        cp->enable_int = cnic_enable_bnx2x_int;
        cp->disable_int_sync = cnic_disable_bnx2x_int_sync;
-       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id))
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                cp->ack_int = cnic_ack_bnx2x_e2_msix;
-       else
+               cp->arm_int = cnic_arm_bnx2x_e2_msix;
+       } else {
                cp->ack_int = cnic_ack_bnx2x_msix;
+               cp->arm_int = cnic_arm_bnx2x_msix;
+       }
        cp->close_conn = cnic_close_bnx2x_conn;
        return cdev;
 }
@@ -5516,9 +5591,7 @@ static void cnic_rcv_netevent(struct cnic_local *cp, unsigned long event,
        rcu_read_unlock();
 }
 
-/**
- * netdev event handler
- */
+/* netdev event handler */
 static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                                                         void *ptr)
 {