diff options
Diffstat (limited to 'drivers/net/cnic.c')
-rw-r--r-- | drivers/net/cnic.c | 1312 |
1 files changed, 788 insertions, 524 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 80471269977a..92bac19ad60a 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -40,9 +40,9 @@ #include "cnic_if.h" #include "bnx2.h" -#include "bnx2x_reg.h" -#include "bnx2x_fw_defs.h" -#include "bnx2x_hsi.h" +#include "bnx2x/bnx2x_reg.h" +#include "bnx2x/bnx2x_fw_defs.h" +#include "bnx2x/bnx2x_hsi.h" #include "../scsi/bnx2i/57xx_iscsi_constants.h" #include "../scsi/bnx2i/57xx_iscsi_hsi.h" #include "cnic.h" @@ -60,6 +60,7 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(CNIC_MODULE_VERSION); static LIST_HEAD(cnic_dev_list); +static LIST_HEAD(cnic_udev_list); static DEFINE_RWLOCK(cnic_dev_lock); static DEFINE_MUTEX(cnic_lock); @@ -81,29 +82,34 @@ static struct cnic_ops cnic_bnx2x_ops = { .cnic_ctl = cnic_ctl, }; +static struct workqueue_struct *cnic_wq; + static void cnic_shutdown_rings(struct cnic_dev *); static void cnic_init_rings(struct cnic_dev *); static int cnic_cm_set_pg(struct cnic_sock *); static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode) { - struct cnic_dev *dev = uinfo->priv; - struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev = uinfo->priv; + struct cnic_dev *dev; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (cp->uio_dev != -1) + if (udev->uio_dev != -1) return -EBUSY; rtnl_lock(); - if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) { + dev = udev->dev; + + if (!dev || !test_bit(CNIC_F_CNIC_UP, &dev->flags)) { rtnl_unlock(); return -ENODEV; } - cp->uio_dev = iminor(inode); + udev->uio_dev = iminor(inode); + cnic_shutdown_rings(dev); cnic_init_rings(dev); rtnl_unlock(); @@ -112,12 +118,9 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode) static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode) { - struct cnic_dev *dev = uinfo->priv; - struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev = uinfo->priv; - cnic_shutdown_rings(dev); - - cp->uio_dev = -1; + udev->uio_dev = -1; return 0; } @@ -242,14 +245,14 @@ static int cnic_in_use(struct cnic_sock *csk) return test_bit(SK_F_INUSE, &csk->flags); } -static void cnic_kwq_completion(struct cnic_dev *dev, u32 count) +static void cnic_spq_completion(struct cnic_dev *dev, int cmd, u32 count) { struct cnic_local *cp = dev->cnic_priv; struct cnic_eth_dev *ethdev = cp->ethdev; struct drv_ctl_info info; - info.cmd = DRV_CTL_COMPLETION_CMD; - info.data.comp.comp_count = count; + info.cmd = cmd; + info.data.credit.credit_count = count; ethdev->drv_ctl(dev->netdev, &info); } @@ -257,7 +260,7 @@ static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid) { u32 i; - for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) { + for (i = 0; i < cp->max_cid_space; i++) { if (cp->ctx_tbl[i].cid == cid) { *l5_cid = i; return 0; @@ -274,8 +277,9 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type, u16 len = 0; u32 msg_type = ISCSI_KEVENT_IF_DOWN; struct cnic_ulp_ops *ulp_ops; + struct cnic_uio_dev *udev = cp->udev; - if (cp->uio_dev == -1) + if (!udev || udev->uio_dev == -1) return -ENODEV; if (csk) { @@ -406,8 +410,7 @@ static void cnic_uio_stop(void) list_for_each_entry(dev, &cnic_dev_list, list) { struct cnic_local *cp = dev->cnic_priv; - if (cp->cnic_uinfo) - cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); } read_unlock(&cnic_dev_lock); } @@ -768,31 +771,45 @@ static void cnic_free_context(struct cnic_dev *dev) } } -static void cnic_free_resc(struct cnic_dev *dev) +static void __cnic_free_uio(struct cnic_uio_dev *udev) { - struct cnic_local *cp = dev->cnic_priv; - int i = 0; + uio_unregister_device(&udev->cnic_uinfo); - if (cp->cnic_uinfo) { - while (cp->uio_dev != -1 && i < 15) { - msleep(100); - i++; - } - uio_unregister_device(cp->cnic_uinfo); - kfree(cp->cnic_uinfo); - cp->cnic_uinfo = NULL; + if (udev->l2_buf) { + dma_free_coherent(&udev->pdev->dev, udev->l2_buf_size, + udev->l2_buf, udev->l2_buf_map); + udev->l2_buf = NULL; } - if (cp->l2_buf) { - dma_free_coherent(&dev->pcidev->dev, cp->l2_buf_size, - cp->l2_buf, cp->l2_buf_map); - cp->l2_buf = NULL; + if (udev->l2_ring) { + dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size, + udev->l2_ring, udev->l2_ring_map); + udev->l2_ring = NULL; } - if (cp->l2_ring) { - dma_free_coherent(&dev->pcidev->dev, cp->l2_ring_size, - cp->l2_ring, cp->l2_ring_map); - cp->l2_ring = NULL; + pci_dev_put(udev->pdev); + kfree(udev); +} + +static void cnic_free_uio(struct cnic_uio_dev *udev) +{ + if (!udev) + return; + + write_lock(&cnic_dev_lock); + list_del_init(&udev->list); + write_unlock(&cnic_dev_lock); + __cnic_free_uio(udev); +} + +static void cnic_free_resc(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev = cp->udev; + + if (udev) { + udev->dev = NULL; + cp->udev = NULL; } cnic_free_context(dev); @@ -804,7 +821,7 @@ static void cnic_free_resc(struct cnic_dev *dev) cnic_free_dma(dev, &cp->conn_buf_info); cnic_free_dma(dev, &cp->kwq_info); cnic_free_dma(dev, &cp->kwq_16_data_info); - cnic_free_dma(dev, &cp->kcq_info); + cnic_free_dma(dev, &cp->kcq1.dma); kfree(cp->iscsi_tbl); cp->iscsi_tbl = NULL; kfree(cp->ctx_tbl); @@ -863,37 +880,99 @@ static int cnic_alloc_context(struct cnic_dev *dev) return 0; } -static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) +static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info) +{ + int err, i, is_bnx2 = 0; + struct kcqe **kcq; + + if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) + is_bnx2 = 1; + + err = cnic_alloc_dma(dev, &info->dma, KCQ_PAGE_CNT, is_bnx2); + if (err) + return err; + + kcq = (struct kcqe **) info->dma.pg_arr; + info->kcq = kcq; + + if (is_bnx2) + return 0; + + for (i = 0; i < KCQ_PAGE_CNT; i++) { + struct bnx2x_bd_chain_next *next = + (struct bnx2x_bd_chain_next *) &kcq[i][MAX_KCQE_CNT]; + int j = i + 1; + + if (j >= KCQ_PAGE_CNT) + j = 0; + next->addr_hi = (u64) info->dma.pg_map_arr[j] >> 32; + next->addr_lo = info->dma.pg_map_arr[j] & 0xffffffff; + } + return 0; +} + +static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) { struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev; + + read_lock(&cnic_dev_lock); + list_for_each_entry(udev, &cnic_udev_list, list) { + if (udev->pdev == dev->pcidev) { + udev->dev = dev; + cp->udev = udev; + read_unlock(&cnic_dev_lock); + return 0; + } + } + read_unlock(&cnic_dev_lock); + + udev = kzalloc(sizeof(struct cnic_uio_dev), GFP_ATOMIC); + if (!udev) + return -ENOMEM; + + udev->uio_dev = -1; - cp->l2_ring_size = pages * BCM_PAGE_SIZE; - cp->l2_ring = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_ring_size, - &cp->l2_ring_map, - GFP_KERNEL | __GFP_COMP); - if (!cp->l2_ring) + 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) return -ENOMEM; - cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; - cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); - cp->l2_buf = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_buf_size, - &cp->l2_buf_map, - GFP_KERNEL | __GFP_COMP); - if (!cp->l2_buf) + 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) return -ENOMEM; + write_lock(&cnic_dev_lock); + list_add(&udev->list, &cnic_udev_list); + write_unlock(&cnic_dev_lock); + + pci_dev_get(udev->pdev); + + cp->udev = udev; + return 0; } -static int cnic_alloc_uio(struct cnic_dev *dev) { +static int cnic_init_uio(struct cnic_dev *dev) +{ struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev = cp->udev; struct uio_info *uinfo; - int ret; + int ret = 0; - uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); - if (!uinfo) + if (!udev) return -ENOMEM; + uinfo = &udev->cnic_uinfo; + uinfo->mem[0].addr = dev->netdev->base_addr; uinfo->mem[0].internal_addr = dev->regview; uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start; @@ -901,7 +980,7 @@ static int cnic_alloc_uio(struct cnic_dev *dev) { if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen & - PAGE_MASK; + PAGE_MASK; if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; else @@ -911,19 +990,19 @@ static int cnic_alloc_uio(struct cnic_dev *dev) { } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk & PAGE_MASK; - uinfo->mem[1].size = sizeof(struct host_def_status_block); + uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk); uinfo->name = "bnx2x_cnic"; } uinfo->mem[1].memtype = UIO_MEM_LOGICAL; - uinfo->mem[2].addr = (unsigned long) cp->l2_ring; - uinfo->mem[2].size = cp->l2_ring_size; + uinfo->mem[2].addr = (unsigned long) udev->l2_ring; + uinfo->mem[2].size = udev->l2_ring_size; uinfo->mem[2].memtype = UIO_MEM_LOGICAL; - uinfo->mem[3].addr = (unsigned long) cp->l2_buf; - uinfo->mem[3].size = cp->l2_buf_size; + uinfo->mem[3].addr = (unsigned long) udev->l2_buf; + uinfo->mem[3].size = udev->l2_buf_size; uinfo->mem[3].memtype = UIO_MEM_LOGICAL; uinfo->version = CNIC_MODULE_VERSION; @@ -932,16 +1011,17 @@ static int cnic_alloc_uio(struct cnic_dev *dev) { uinfo->open = cnic_uio_open; uinfo->release = cnic_uio_close; - uinfo->priv = dev; + if (udev->uio_dev == -1) { + if (!uinfo->priv) { + uinfo->priv = udev; - ret = uio_register_device(&dev->pcidev->dev, uinfo); - if (ret) { - kfree(uinfo); - return ret; + ret = uio_register_device(&udev->pdev->dev, uinfo); + } + } else { + cnic_init_rings(dev); } - cp->cnic_uinfo = uinfo; - return 0; + return ret; } static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) @@ -954,20 +1034,19 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) goto error; cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; - ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); + ret = cnic_alloc_kcq(dev, &cp->kcq1); if (ret) goto error; - cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; ret = cnic_alloc_context(dev); if (ret) goto error; - ret = cnic_alloc_l2_rings(dev, 2); + ret = cnic_alloc_uio_rings(dev, 2); if (ret) goto error; - ret = cnic_alloc_uio(dev); + ret = cnic_init_uio(dev); if (ret) goto error; @@ -981,17 +1060,10 @@ error: static int cnic_alloc_bnx2x_context(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - struct cnic_eth_dev *ethdev = cp->ethdev; int ctx_blk_size = cp->ethdev->ctx_blk_size; - int total_mem, blks, i, cid_space; - - if (BNX2X_ISCSI_START_CID < ethdev->starting_cid) - return -EINVAL; - - cid_space = MAX_ISCSI_TBL_SZ + - (BNX2X_ISCSI_START_CID - ethdev->starting_cid); + int total_mem, blks, i; - total_mem = BNX2X_CONTEXT_MEM_SIZE * cid_space; + total_mem = BNX2X_CONTEXT_MEM_SIZE * cp->max_cid_space; blks = total_mem / ctx_blk_size; if (total_mem % ctx_blk_size) blks++; @@ -999,13 +1071,13 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev) if (blks > cp->ethdev->ctx_tbl_len) return -ENOMEM; - cp->ctx_arr = kzalloc(blks * sizeof(struct cnic_ctx), GFP_KERNEL); + cp->ctx_arr = kcalloc(blks, sizeof(struct cnic_ctx), GFP_KERNEL); if (cp->ctx_arr == NULL) return -ENOMEM; cp->ctx_blks = blks; cp->ctx_blk_size = ctx_blk_size; - if (BNX2X_CHIP_IS_E1H(cp->chip_id)) + if (!BNX2X_CHIP_IS_57710(cp->chip_id)) cp->ctx_align = 0; else cp->ctx_align = ctx_blk_size; @@ -1035,16 +1107,29 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev) static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + u32 start_cid = ethdev->starting_cid; int i, j, n, ret, pages; struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info; + cp->iro_arr = ethdev->iro_arr; + + cp->max_cid_space = MAX_ISCSI_TBL_SZ; + cp->iscsi_start_cid = start_cid; + if (start_cid < BNX2X_ISCSI_START_CID) { + u32 delta = BNX2X_ISCSI_START_CID - start_cid; + + cp->iscsi_start_cid = BNX2X_ISCSI_START_CID; + cp->max_cid_space += delta; + } + cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ, GFP_KERNEL); if (!cp->iscsi_tbl) goto error; cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) * - MAX_CNIC_L5_CONTEXT, GFP_KERNEL); + cp->max_cid_space, GFP_KERNEL); if (!cp->ctx_tbl) goto error; @@ -1053,7 +1138,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI; } - pages = PAGE_ALIGN(MAX_CNIC_L5_CONTEXT * CNIC_KWQ16_DATA_SIZE) / + pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) / PAGE_SIZE; ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0); @@ -1061,7 +1146,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) return -ENOMEM; n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE; - for (i = 0, j = 0; i < MAX_ISCSI_TBL_SZ; i++) { + for (i = 0, j = 0; i < cp->max_cid_space; i++) { long off = CNIC_KWQ16_DATA_SIZE * (i % n); cp->ctx_tbl[i].kwqe_data = kwq_16_dma->pg_arr[j] + off; @@ -1072,22 +1157,9 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) j++; } - ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 0); + ret = cnic_alloc_kcq(dev, &cp->kcq1); if (ret) goto error; - cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; - - for (i = 0; i < KCQ_PAGE_CNT; i++) { - struct bnx2x_bd_chain_next *next = - (struct bnx2x_bd_chain_next *) - &cp->kcq[i][MAX_KCQE_CNT]; - int j = i + 1; - - if (j >= KCQ_PAGE_CNT) - j = 0; - next->addr_hi = (u64) cp->kcq_info.pg_map_arr[j] >> 32; - next->addr_lo = cp->kcq_info.pg_map_arr[j] & 0xffffffff; - } pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS * BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE; @@ -1106,15 +1178,13 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk; - memset(cp->status_blk.bnx2x, 0, sizeof(*cp->status_blk.bnx2x)); - cp->l2_rx_ring_size = 15; - ret = cnic_alloc_l2_rings(dev, 4); + ret = cnic_alloc_uio_rings(dev, 4); if (ret) goto error; - ret = cnic_alloc_uio(dev); + ret = cnic_init_uio(dev); if (ret) goto error; @@ -1188,9 +1258,9 @@ static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid, kwqe.hdr.conn_and_cmd_data = cpu_to_le32(((cmd << SPE_HDR_CMD_ID_SHIFT) | - BNX2X_HW_CID(cid, cp->func))); + BNX2X_HW_CID(cp, cid))); kwqe.hdr.type = cpu_to_le16(type); - kwqe.hdr.reserved = 0; + kwqe.hdr.reserved1 = 0; kwqe.data.phy_address.lo = cpu_to_le32(l5_data->phy_address.lo); kwqe.data.phy_address.hi = cpu_to_le32(l5_data->phy_address.hi); @@ -1225,8 +1295,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe) { struct cnic_local *cp = dev->cnic_priv; struct iscsi_kwqe_init1 *req1 = (struct iscsi_kwqe_init1 *) kwqe; - int func = cp->func, pages; - int hq_bds; + int hq_bds, pages; + u32 pfid = cp->pfid; cp->num_iscsi_tasks = req1->num_tasks_per_conn; cp->num_ccells = req1->num_ccells_per_conn; @@ -1243,60 +1313,60 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe) return 0; /* init Tstorm RAM */ - CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid), req1->rq_num_wqes); - CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid), PAGE_SIZE); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT); + TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT); CNIC_WR16(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func), + TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid), req1->num_tasks_per_conn); /* init Ustorm RAM */ CNIC_WR16(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(func), + USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid), req1->rq_buffer_size); - CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid), PAGE_SIZE); CNIC_WR8(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT); + USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT); CNIC_WR16(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_NUM_OF_TASKS_OFFSET(func), + USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid), req1->num_tasks_per_conn); - CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(pfid), req1->rq_num_wqes); - CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(pfid), req1->cq_num_wqes); - CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfid), cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS); /* init Xstorm RAM */ - CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid), PAGE_SIZE); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT); + XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT); CNIC_WR16(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func), + XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid), req1->num_tasks_per_conn); - CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(pfid), hq_bds); - CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(pfid), req1->num_tasks_per_conn); - CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfid), cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS); /* init Cstorm RAM */ - CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid), PAGE_SIZE); CNIC_WR8(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT); + CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT); CNIC_WR16(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func), + CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid), req1->num_tasks_per_conn); - CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(pfid), req1->cq_num_wqes); - CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(func), + CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(pfid), hq_bds); return 0; @@ -1306,7 +1376,7 @@ static int cnic_bnx2x_iscsi_init2(struct cnic_dev *dev, struct kwqe *kwqe) { struct iscsi_kwqe_init2 *req2 = (struct iscsi_kwqe_init2 *) kwqe; struct cnic_local *cp = dev->cnic_priv; - int func = cp->func; + u32 pfid = cp->pfid; struct iscsi_kcqe kcqe; struct kcqe *cqes[1]; @@ -1318,21 +1388,21 @@ static int cnic_bnx2x_iscsi_init2(struct cnic_dev *dev, struct kwqe *kwqe) } CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]); + TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid), req2->error_bit_map[0]); CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4, + TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid) + 4, req2->error_bit_map[1]); CNIC_WR16(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn); + USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfid), req2->max_cq_sqn); CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]); + USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid), req2->error_bit_map[0]); CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4, + USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfid) + 4, req2->error_bit_map[1]); CNIC_WR16(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn); + CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfid), req2->max_cq_sqn); kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS; @@ -1440,7 +1510,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[], struct cnic_context *ctx = &cp->ctx_tbl[req1->iscsi_conn_id]; struct cnic_iscsi *iscsi = ctx->proto.iscsi; u32 cid = ctx->cid; - u32 hw_cid = BNX2X_HW_CID(cid, cp->func); + u32 hw_cid = BNX2X_HW_CID(cp, cid); struct iscsi_context *ictx; struct regpair context_addr; int i, j, n = 2, n_max; @@ -1506,8 +1576,10 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[], ictx->tstorm_st_context.tcp.cwnd = 0x5A8; ictx->tstorm_st_context.tcp.flags2 |= TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN; + ictx->tstorm_st_context.tcp.ooo_support_mode = + TCP_TSTORM_OOO_DROP_AND_PROC_ACK; - ictx->timers_context.flags |= ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG; + ictx->timers_context.flags |= TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG; ictx->ustorm_st_context.ring.rq.pbl_base.lo = req2->rq_page_table_addr_lo; @@ -1606,10 +1678,11 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], struct iscsi_kwqe_conn_offload1 *req1; struct iscsi_kwqe_conn_offload2 *req2; struct cnic_local *cp = dev->cnic_priv; + struct cnic_context *ctx; struct iscsi_kcqe kcqe; struct kcqe *cqes[1]; u32 l5_cid; - int ret; + int ret = 0; if (num < 2) { *work = num; @@ -1633,9 +1706,15 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], kcqe.iscsi_conn_id = l5_cid; kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE; + ctx = &cp->ctx_tbl[l5_cid]; + if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) { + kcqe.completion_status = + ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY; + goto done; + } + if (atomic_inc_return(&cp->iscsi_conn) > dev->max_iscsi_conn) { atomic_dec(&cp->iscsi_conn); - ret = 0; goto done; } ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid); @@ -1652,8 +1731,7 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], } kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS; - kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp->ctx_tbl[l5_cid].cid, - cp->func); + kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp, cp->ctx_tbl[l5_cid].cid); done: cqes[0] = (struct kcqe *) &kcqe; @@ -1686,40 +1764,66 @@ static int cnic_bnx2x_iscsi_update(struct cnic_dev *dev, struct kwqe *kwqe) return ret; } +static int cnic_bnx2x_destroy_ramrod(struct cnic_dev *dev, u32 l5_cid) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_context *ctx = &cp->ctx_tbl[l5_cid]; + union l5cm_specific_data l5_data; + int ret; + u32 hw_cid, type; + + init_waitqueue_head(&ctx->waitq); + ctx->wait_cond = 0; + memset(&l5_data, 0, sizeof(l5_data)); + hw_cid = BNX2X_HW_CID(cp, ctx->cid); + type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT) + & SPE_HDR_CONN_TYPE; + type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) & + SPE_HDR_FUNCTION_ID); + + ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL, + hw_cid, type, &l5_data); + + if (ret == 0) + wait_event(ctx->waitq, ctx->wait_cond); + + return ret; +} + static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe) { struct cnic_local *cp = dev->cnic_priv; struct iscsi_kwqe_conn_destroy *req = (struct iscsi_kwqe_conn_destroy *) kwqe; - union l5cm_specific_data l5_data; u32 l5_cid = req->reserved0; struct cnic_context *ctx = &cp->ctx_tbl[l5_cid]; int ret = 0; struct iscsi_kcqe kcqe; struct kcqe *cqes[1]; - if (!(ctx->ctx_flags & CTX_FL_OFFLD_START)) + if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) goto skip_cfc_delete; - while (!time_after(jiffies, ctx->timestamp + (2 * HZ))) - msleep(250); + if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) { + unsigned long delta = ctx->timestamp + (2 * HZ) - jiffies; - init_waitqueue_head(&ctx->waitq); - ctx->wait_cond = 0; - memset(&l5_data, 0, sizeof(l5_data)); - ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL, - req->context_id, - ETH_CONNECTION_TYPE | - (1 << SPE_HDR_COMMON_RAMROD_SHIFT), - &l5_data); - if (ret == 0) - wait_event(ctx->waitq, ctx->wait_cond); + if (delta > (2 * HZ)) + delta = 0; + + set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags); + queue_delayed_work(cnic_wq, &cp->delete_task, delta); + goto destroy_reply; + } + + ret = cnic_bnx2x_destroy_ramrod(dev, l5_cid); skip_cfc_delete: cnic_free_bnx2x_conn_resc(dev, l5_cid); atomic_dec(&cp->iscsi_conn); + clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags); +destroy_reply: memset(&kcqe, 0, sizeof(kcqe)); kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN; kcqe.iscsi_conn_id = l5_cid; @@ -1784,37 +1888,37 @@ static void cnic_init_storm_conn_bufs(struct cnic_dev *dev, static void cnic_init_bnx2x_mac(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - int func = CNIC_FUNC(cp); + u32 pfid = cp->pfid; u8 *mac = dev->mac_addr; CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(func), mac[0]); + XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfid), mac[0]); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(func), mac[1]); + XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfid), mac[1]); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(func), mac[2]); + XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfid), mac[2]); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(func), mac[3]); + XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfid), mac[3]); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(func), mac[4]); + XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfid), mac[4]); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(func), mac[5]); + XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfid), mac[5]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func), mac[5]); + TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[5]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func) + 1, + TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1, mac[4]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func), mac[3]); + TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[3]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 1, + TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1, mac[2]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 2, + TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 2, mac[1]); CNIC_WR8(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 3, + TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 3, mac[0]); } @@ -1830,10 +1934,10 @@ static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts) } CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), xstorm_flags); + XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags); CNIC_WR16(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), tstorm_flags); + TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags); } static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[], @@ -1908,7 +2012,7 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[], cnic_init_storm_conn_bufs(dev, kwqe1, kwqe3, conn_buf); CNIC_WR16(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->func), csk->vlan_id); + XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->pfid), csk->vlan_id); cnic_bnx2x_set_tcp_timestamp(dev, kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP); @@ -1916,7 +2020,7 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[], ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_TCP_CONNECT, kwqe1->cid, ISCSI_CONNECTION_TYPE, &l5_data); if (!ret) - ctx->ctx_flags |= CTX_FL_OFFLD_START; + set_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags); return ret; } @@ -2042,7 +2146,7 @@ static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[], static void service_kcqes(struct cnic_dev *dev, int num_cqes) { struct cnic_local *cp = dev->cnic_priv; - int i, j; + int i, j, comp = 0; i = 0; j = 1; @@ -2053,7 +2157,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes) u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK; if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION)) - cnic_kwq_completion(dev, 1); + comp++; while (j < num_cqes) { u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag; @@ -2062,7 +2166,7 @@ static void service_kcqes(struct cnic_dev *dev, int num_cqes) break; if (unlikely(next_op & KCQE_RAMROD_COMPLETION)) - cnic_kwq_completion(dev, 1); + comp++; j++; } @@ -2092,6 +2196,8 @@ end: i += j; j = 1; } + if (unlikely(comp)) + cnic_spq_completion(dev, DRV_CTL_RET_L5_SPQ_CREDIT_CMD, comp); } static u16 cnic_bnx2_next_idx(u16 idx) @@ -2120,18 +2226,20 @@ static u16 cnic_bnx2x_hw_idx(u16 idx) return idx; } -static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod) +static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info) { struct cnic_local *cp = dev->cnic_priv; - u16 i, ri, last; + u16 i, ri, hw_prod, last; struct kcqe *kcqe; int kcqe_cnt = 0, last_cnt = 0; - i = ri = last = *sw_prod; + i = ri = last = info->sw_prod_idx; ri &= MAX_KCQ_IDX; + hw_prod = *info->hw_prod_idx_ptr; + hw_prod = cp->hw_idx(hw_prod); while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) { - kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)]; + kcqe = &info->kcq[KCQ_PG(ri)][KCQ_IDX(ri)]; cp->completed_kcq[kcqe_cnt++] = kcqe; i = cp->next_idx(i); ri = i & MAX_KCQ_IDX; @@ -2141,15 +2249,16 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod) } } - *sw_prod = last; + info->sw_prod_idx = last; return last_cnt; } static int cnic_l2_completion(struct cnic_local *cp) { u16 hw_cons, sw_cons; + struct cnic_uio_dev *udev = cp->udev; union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *) - (cp->l2_ring + (2 * BCM_PAGE_SIZE)); + (udev->l2_ring + (2 * BCM_PAGE_SIZE)); u32 cmd; int comp = 0; @@ -2180,10 +2289,14 @@ static int cnic_l2_completion(struct cnic_local *cp) static void cnic_chk_pkt_rings(struct cnic_local *cp) { - u16 rx_cons = *cp->rx_cons_ptr; - u16 tx_cons = *cp->tx_cons_ptr; + u16 rx_cons, tx_cons; int comp = 0; + if (!test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags)) + return; + + rx_cons = *cp->rx_cons_ptr; + tx_cons = *cp->tx_cons_ptr; if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) { if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags)) comp = cnic_l2_completion(cp); @@ -2191,109 +2304,86 @@ static void cnic_chk_pkt_rings(struct cnic_local *cp) cp->tx_cons = tx_cons; cp->rx_cons = rx_cons; - uio_event_notify(cp->cnic_uinfo); + if (cp->udev) + uio_event_notify(&cp->udev->cnic_uinfo); } if (comp) clear_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags); } -static int cnic_service_bnx2(void *data, void *status_blk) +static u32 cnic_service_bnx2_queues(struct cnic_dev *dev) { - struct cnic_dev *dev = data; - struct status_block *sblk = status_blk; struct cnic_local *cp = dev->cnic_priv; - u32 status_idx = sblk->status_idx; - u16 hw_prod, sw_prod; + u32 status_idx = (u16) *cp->kcq1.status_idx_ptr; int kcqe_cnt; - if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) - return status_idx; - cp->kwq_con_idx = *cp->kwq_con_idx_ptr; - hw_prod = sblk->status_completion_producer_index; - sw_prod = cp->kcq_prod_idx; - while (sw_prod != hw_prod) { - kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod); - if (kcqe_cnt == 0) - goto done; + while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) { service_kcqes(dev, kcqe_cnt); /* Tell compiler that status_blk fields can change. */ barrier(); - if (status_idx != sblk->status_idx) { - status_idx = sblk->status_idx; + if (status_idx != *cp->kcq1.status_idx_ptr) { + status_idx = (u16) *cp->kcq1.status_idx_ptr; cp->kwq_con_idx = *cp->kwq_con_idx_ptr; - hw_prod = sblk->status_completion_producer_index; } else break; } -done: - CNIC_WR16(dev, cp->kcq_io_addr, sw_prod); - - cp->kcq_prod_idx = sw_prod; + CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx); cnic_chk_pkt_rings(cp); + return status_idx; } -static void cnic_service_bnx2_msix(unsigned long data) +static int cnic_service_bnx2(void *data, void *status_blk) { - struct cnic_dev *dev = (struct cnic_dev *) data; + struct cnic_dev *dev = data; struct cnic_local *cp = dev->cnic_priv; - struct status_block_msix *status_blk = cp->status_blk.bnx2; - u32 status_idx = status_blk->status_idx; - u16 hw_prod, sw_prod; - int kcqe_cnt; - - cp->kwq_con_idx = status_blk->status_cmd_consumer_index; - - hw_prod = status_blk->status_completion_producer_index; - sw_prod = cp->kcq_prod_idx; - while (sw_prod != hw_prod) { - kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod); - if (kcqe_cnt == 0) - goto done; + u32 status_idx = *cp->kcq1.status_idx_ptr; - service_kcqes(dev, kcqe_cnt); + if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) + return status_idx; - /* Tell compiler that status_blk fields can change. */ - barrier(); - if (status_idx != status_blk->status_idx) { - status_idx = status_blk->status_idx; - cp->kwq_con_idx = status_blk->status_cmd_consumer_index; - hw_prod = status_blk->status_completion_producer_index; - } else - break; - } + return cnic_service_bnx2_queues(dev); +} -done: - CNIC_WR16(dev, cp->kcq_io_addr, sw_prod); - cp->kcq_prod_idx = sw_prod; +static void cnic_service_bnx2_msix(unsigned long data) +{ + struct cnic_dev *dev = (struct cnic_dev *) data; + struct cnic_local *cp = dev->cnic_priv; - cnic_chk_pkt_rings(cp); + cp->last_status_idx = cnic_service_bnx2_queues(dev); - cp->last_status_idx = status_idx; CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx); } +static void cnic_doirq(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + u16 prod = cp->kcq1.sw_prod_idx & MAX_KCQ_IDX; + + if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) { + prefetch(cp->status_blk.gen); + prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); + + tasklet_schedule(&cp->cnic_irq_task); + } +} + static irqreturn_t cnic_irq(int irq, void *dev_instance) { struct cnic_dev *dev = dev_instance; struct cnic_local *cp = dev->cnic_priv; - u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX; if (cp->ack_int) cp->ack_int(dev); - prefetch(cp->status_blk.gen); - prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); - - if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) - tasklet_schedule(&cp->cnic_irq_task); + cnic_doirq(dev); return IRQ_HANDLED; } @@ -2316,68 +2406,86 @@ static inline void cnic_ack_bnx2x_int(struct cnic_dev *dev, u8 id, u8 storm, CNIC_WR(dev, hc_addr, (*(u32 *)&igu_ack)); } +static void cnic_ack_igu_sb(struct cnic_dev *dev, u8 igu_sb_id, u8 segment, + u16 index, u8 op, u8 update) +{ + struct igu_regular cmd_data; + u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id) * 8; + + cmd_data.sb_id_and_flags = + (index << IGU_REGULAR_SB_INDEX_SHIFT) | + (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) | + (update << IGU_REGULAR_BUPDATE_SHIFT) | + (op << IGU_REGULAR_ENABLE_INT_SHIFT); + + + CNIC_WR(dev, igu_addr, cmd_data.sb_id_and_flags); +} + static void cnic_ack_bnx2x_msix(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID, 0, + cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, CSTORM_ID, 0, IGU_INT_DISABLE, 0); } -static void cnic_service_bnx2x_bh(unsigned long data) +static void cnic_ack_bnx2x_e2_msix(struct cnic_dev *dev) { - struct cnic_dev *dev = (struct cnic_dev *) data; struct cnic_local *cp = dev->cnic_priv; - u16 hw_prod, sw_prod; - struct cstorm_status_block_c *sblk = - &cp->status_blk.bnx2x->c_status_block; - u32 status_idx = sblk->status_block_index; - int kcqe_cnt; - if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) - return; + cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF, 0, + IGU_INT_DISABLE, 0); +} - hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS]; - hw_prod = cp->hw_idx(hw_prod); - sw_prod = cp->kcq_prod_idx; - while (sw_prod != hw_prod) { - kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod); - if (kcqe_cnt == 0) - goto done; +static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info) +{ + u32 last_status = *info->status_idx_ptr; + int kcqe_cnt; + + while ((kcqe_cnt = cnic_get_kcqes(dev, info))) { service_kcqes(dev, kcqe_cnt); /* Tell compiler that sblk fields can change. */ barrier(); - if (status_idx == sblk->status_block_index) + if (last_status == *info->status_idx_ptr) break; - status_idx = sblk->status_block_index; - hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS]; - hw_prod = cp->hw_idx(hw_prod); + last_status = *info->status_idx_ptr; } + return last_status; +} -done: - CNIC_WR16(dev, cp->kcq_io_addr, sw_prod + MAX_KCQ_IDX); - cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID, - status_idx, IGU_INT_ENABLE, 1); +static void cnic_service_bnx2x_bh(unsigned long data) +{ + struct cnic_dev *dev = (struct cnic_dev *) data; + struct cnic_local *cp = dev->cnic_priv; + u32 status_idx; - cp->kcq_prod_idx = sw_prod; + if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) + return; + + status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1); + + CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX); + if (BNX2X_CHIP_IS_E2(cp->chip_id)) + cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF, + status_idx, IGU_INT_ENABLE, 1); + else + cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID, + status_idx, IGU_INT_ENABLE, 1); } static int cnic_service_bnx2x(void *data, void *status_blk) { struct cnic_dev *dev = data; struct cnic_local *cp = dev->cnic_priv; - u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX; - if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) { - prefetch(cp->status_blk.bnx2x); - prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); + if (!(cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)) + cnic_doirq(dev); - tasklet_schedule(&cp->cnic_irq_task); - cnic_chk_pkt_rings(cp); - } + cnic_chk_pkt_rings(cp); return 0; } @@ -2387,8 +2495,7 @@ static void cnic_ulp_stop(struct cnic_dev *dev) struct cnic_local *cp = dev->cnic_priv; int if_type; - if (cp->cnic_uinfo) - cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { struct cnic_ulp_ops *ulp_ops; @@ -2736,6 +2843,13 @@ static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid, if (l5_cid >= MAX_CM_SK_TBL_SZ) return -EINVAL; + if (cp->ctx_tbl) { + struct cnic_context *ctx = &cp->ctx_tbl[l5_cid]; + + if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) + return -EAGAIN; + } + csk1 = &cp->csk_tbl[l5_cid]; if (atomic_read(&csk1->ref_count)) return -EAGAIN; @@ -2824,7 +2938,7 @@ static int cnic_get_v4_route(struct sockaddr_in *dst_addr, err = ip_route_output_key(&init_net, &rt, &fl); if (!err) - *dst = &rt->u.dst; + *dst = &rt->dst; return err; #else return -ENETUNREACH; @@ -2996,7 +3110,7 @@ err_out: static int cnic_cm_abort(struct cnic_sock *csk) { struct cnic_local *cp = csk->dev->cnic_priv; - u32 opcode; + u32 opcode = L4_KCQE_OPCODE_VALUE_RESET_COMP; if (!cnic_in_use(csk)) return -EINVAL; @@ -3008,12 +3122,9 @@ static int cnic_cm_abort(struct cnic_sock *csk) * connect was not successful. */ - csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP; - if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) - opcode = csk->state; - else - opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD; cp->close_conn(csk, opcode); + if (csk->state != opcode) + return -EALREADY; return 0; } @@ -3026,6 +3137,8 @@ static int cnic_cm_close(struct cnic_sock *csk) if (cnic_close_prep(csk)) { csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP; return cnic_cm_close_req(csk); + } else { + return -EALREADY; } return 0; } @@ -3141,12 +3254,6 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) break; case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED: - if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { - cnic_cm_upcall(cp, csk, opcode); - break; - } else if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) - csk->state = opcode; - /* fall through */ case L4_KCQE_OPCODE_VALUE_CLOSE_COMP: case L4_KCQE_OPCODE_VALUE_RESET_COMP: case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE: @@ -3202,19 +3309,22 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev) static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode) { - if ((opcode == csk->state) || - (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED && - csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) { - if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) - return 1; + if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) { + /* Unsolicited RESET_COMP or RESET_RECEIVED */ + opcode = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED; + csk->state = opcode; } - /* 57710+ only workaround to handle unsolicited RESET_COMP - * which will be treated like a RESET RCVD notification - * which triggers the clean up procedure + + /* 1. If event opcode matches the expected event in csk->state + * 2. If the expected event is CLOSE_COMP, we accept any event + * 3. If the expected event is 0, meaning the connection was never + * never established, we accept the opcode from cm_abort. */ - else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) { + if (opcode == csk->state || csk->state == 0 || + csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) { if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) { - csk->state = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED; + if (csk->state == 0) + csk->state = opcode; return 1; } } @@ -3226,8 +3336,14 @@ static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode) struct cnic_dev *dev = csk->dev; struct cnic_local *cp = dev->cnic_priv; + if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) { + cnic_cm_upcall(cp, csk, opcode); + return; + } + clear_bit(SK_F_CONNECT_START, &csk->flags); cnic_close_conn(csk); + csk->state = opcode; cnic_cm_upcall(cp, csk, opcode); } @@ -3257,8 +3373,12 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode) case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED: case L4_KCQE_OPCODE_VALUE_CLOSE_COMP: case L4_KCQE_OPCODE_VALUE_RESET_COMP: - if (cnic_ready_to_close(csk, opcode)) - cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE; + if (cnic_ready_to_close(csk, opcode)) { + if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) + cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE; + else + close_complete = 1; + } break; case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE: cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD; @@ -3281,39 +3401,106 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode) static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) { + struct cnic_local *cp = dev->cnic_priv; + int i; + + if (!cp->ctx_tbl) + return; + + if (!netif_running(dev->netdev)) + return; + + for (i = 0; i < cp->max_cid_space; i++) { + struct cnic_context *ctx = &cp->ctx_tbl[i]; + + while (test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) + msleep(10); + + if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags)) + netdev_warn(dev->netdev, "CID %x not deleted\n", + ctx->cid); + } + + cancel_delayed_work(&cp->delete_task); + flush_workqueue(cnic_wq); + + if (atomic_read(&cp->iscsi_conn) != 0) + netdev_warn(dev->netdev, "%d iSCSI connections not destroyed\n", + atomic_read(&cp->iscsi_conn)); } static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - int func = CNIC_FUNC(cp); + u32 pfid = cp->pfid; + u32 port = CNIC_PORT(cp); cnic_init_bnx2x_mac(dev); cnic_bnx2x_set_tcp_timestamp(dev, 1); CNIC_WR16(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_LOCAL_VLAN_OFFSET(func), 0); + XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfid), 0); CNIC_WR(dev, BAR_XSTRORM_INTMEM + - XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(func), 1); + XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(port), 1); CNIC_WR(dev, BAR_XSTRORM_INTMEM + - XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(func), + XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(port), DEF_MAX_DA_COUNT); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(func), DEF_TTL); + XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfid), DEF_TTL); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(func), DEF_TOS); + XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfid), DEF_TOS); CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(func), 2); + XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfid), 2); CNIC_WR(dev, BAR_XSTRORM_INTMEM + - XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(func), DEF_SWS_TIMER); + XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfid), DEF_SWS_TIMER); - CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(func), + CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(pfid), DEF_MAX_CWND); return 0; } +static void cnic_delete_task(struct work_struct *work) +{ + struct cnic_local *cp; + struct cnic_dev *dev; + u32 i; + int need_resched = 0; + + cp = container_of(work, struct cnic_local, delete_task.work); + dev = cp->dev; + + for (i = 0; i < cp->max_cid_space; i++) { + struct cnic_context *ctx = &cp->ctx_tbl[i]; + + if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags) || + !test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) + continue; + + if (!time_after(jiffies, ctx->timestamp + (2 * HZ))) { + need_resched = 1; + continue; + } + + if (!test_and_clear_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags)) + continue; + + cnic_bnx2x_destroy_ramrod(dev, i); + + cnic_free_bnx2x_conn_resc(dev, i); + if (ctx->ulp_proto_id == CNIC_ULP_ISCSI) + atomic_dec(&cp->iscsi_conn); + + clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags); + } + + if (need_resched) + queue_delayed_work(cnic_wq, &cp->delete_task, + msecs_to_jiffies(10)); + +} + static int cnic_cm_open(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -3328,6 +3515,8 @@ static int cnic_cm_open(struct cnic_dev *dev) if (err) goto err_out; + INIT_DELAYED_WORK(&cp->delete_task, cnic_delete_task); + dev->cm_create = cnic_cm_create; dev->cm_destroy = cnic_cm_destroy; dev->cm_connect = cnic_cm_connect; @@ -3420,11 +3609,24 @@ static void cnic_free_irq(struct cnic_dev *dev) if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { cp->disable_int_sync(dev); - tasklet_disable(&cp->cnic_irq_task); + tasklet_kill(&cp->cnic_irq_task); free_irq(ethdev->irq_arr[0].vector, dev); } } +static int cnic_request_irq(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + int err; + + err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, "cnic", dev); + if (err) + tasklet_disable(&cp->cnic_irq_task); + + return err; +} + static int cnic_init_bnx2_irq(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -3445,12 +3647,10 @@ static int cnic_init_bnx2_irq(struct cnic_dev *dev) cp->last_status_idx = cp->status_blk.bnx2->status_idx; tasklet_init(&cp->cnic_irq_task, cnic_service_bnx2_msix, (unsigned long) dev); - err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, - "cnic", dev); - if (err) { - tasklet_disable(&cp->cnic_irq_task); + err = cnic_request_irq(dev); + if (err) return err; - } + while (cp->status_blk.bnx2->status_completion_producer_index && i < 10) { CNIC_WR(dev, BNX2_HC_COALESCE_NOW, @@ -3517,11 +3717,12 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; struct cnic_eth_dev *ethdev = cp->ethdev; + struct cnic_uio_dev *udev = cp->udev; u32 cid_addr, tx_cid, sb_id; u32 val, offset0, offset1, offset2, offset3; int i; struct tx_bd *txbd; - dma_addr_t buf_map; + dma_addr_t buf_map, ring_map = udev->l2_ring_map; struct status_block *s_blk = cp->status_blk.gen; sb_id = cp->status_blk_num; @@ -3563,18 +3764,18 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev) val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16); cnic_ctx_wr(dev, cid_addr, offset1, val); - txbd = (struct tx_bd *) cp->l2_ring; + txbd = (struct tx_bd *) udev->l2_ring; - buf_map = cp->l2_buf_map; + buf_map = udev->l2_buf_map; for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) { txbd->tx_bd_haddr_hi = (u64) buf_map >> 32; txbd->tx_bd_haddr_lo = (u64) buf_map & 0xffffffff; } - val = (u64) cp->l2_ring_map >> 32; + val = (u64) ring_map >> 32; cnic_ctx_wr(dev, cid_addr, offset2, val); txbd->tx_bd_haddr_hi = val; - val = (u64) cp->l2_ring_map & 0xffffffff; + val = (u64) ring_map & 0xffffffff; cnic_ctx_wr(dev, cid_addr, offset3, val); txbd->tx_bd_haddr_lo = val; } @@ -3583,10 +3784,12 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; struct cnic_eth_dev *ethdev = cp->ethdev; + struct cnic_uio_dev *udev = cp->udev; u32 cid_addr, sb_id, val, coal_reg, coal_val; int i; struct rx_bd *rxbd; struct status_block *s_blk = cp->status_blk.gen; + dma_addr_t ring_map = udev->l2_ring_map; sb_id = cp->status_blk_num; cnic_init_context(dev, 2); @@ -3620,22 +3823,22 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev) val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id); cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val); - rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE); + rxbd = (struct rx_bd *) (udev->l2_ring + BCM_PAGE_SIZE); for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) { dma_addr_t buf_map; int n = (i % cp->l2_rx_ring_size) + 1; - buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size); + buf_map = udev->l2_buf_map + (n * cp->l2_single_buf_size); rxbd->rx_bd_len = cp->l2_single_buf_size; rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32; rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff; } - val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32; + val = (u64) (ring_map + BCM_PAGE_SIZE) >> 32; cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val); rxbd->rx_bd_haddr_hi = val; - val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff; + val = (u64) (ring_map + BCM_PAGE_SIZE) & 0xffffffff; cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val); rxbd->rx_bd_haddr_lo = val; @@ -3694,7 +3897,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) struct cnic_local *cp = dev->cnic_priv; struct cnic_eth_dev *ethdev = cp->ethdev; struct status_block *sblk = cp->status_blk.gen; - u32 val; + u32 val, kcq_cid_addr, kwq_cid_addr; int err; cnic_set_bnx2_mac(dev); @@ -3719,7 +3922,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) cnic_init_context(dev, KWQ_CID); cnic_init_context(dev, KCQ_CID); - cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID); + kwq_cid_addr = GET_CID_ADDR(KWQ_CID); cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX; cp->max_kwq_idx = MAX_KWQ_IDX; @@ -3735,50 +3938,59 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) /* Initialize the kernel work queue context. */ val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE | (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ; - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val); val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16; - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT; - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32); - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); val = (u32) cp->kwq_info.pgtbl_map; - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); - cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID); - cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX; + kcq_cid_addr = GET_CID_ADDR(KCQ_CID); + cp->kcq1.io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX; - cp->kcq_prod_idx = 0; + cp->kcq1.sw_prod_idx = 0; + cp->kcq1.hw_prod_idx_ptr = + (u16 *) &sblk->status_completion_producer_index; + + cp->kcq1.status_idx_ptr = (u16 *) &sblk->status_idx; /* Initialize the kernel complete queue context. */ val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE | (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ; - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val); + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val); val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16; - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT; - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); - val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32); - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); + val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32); + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); - val = (u32) cp->kcq_info.pgtbl_map; - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); + val = (u32) cp->kcq1.dma.pgtbl_map; + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); cp->int_num = 0; if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + struct status_block_msix *msblk = cp->status_blk.bnx2; u32 sb_id = cp->status_blk_num; 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; cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT; - cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); - cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); + cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); + cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); } /* Enable Commnad Scheduler notification when we write to the @@ -3843,42 +4055,55 @@ static int cnic_init_bnx2x_irq(struct cnic_dev *dev) tasklet_init(&cp->cnic_irq_task, cnic_service_bnx2x_bh, (unsigned long) dev); - if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { - err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, - "cnic", dev); - if (err) - tasklet_disable(&cp->cnic_irq_task); - } + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) + err = cnic_request_irq(dev); + return err; } +static inline void cnic_storm_memset_hc_disable(struct cnic_dev *dev, + u16 sb_id, u8 sb_index, + u8 disable) +{ + + u32 addr = BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_OFFSET(sb_id) + + offsetof(struct hc_status_block_data_e1x, index_data) + + sizeof(struct hc_index_data)*sb_index + + offsetof(struct hc_index_data, flags); + u16 flags = CNIC_RD16(dev, addr); + /* clear and set */ + flags &= ~HC_INDEX_DATA_HC_ENABLED; + flags |= (((~disable) << HC_INDEX_DATA_HC_ENABLED_SHIFT) & + HC_INDEX_DATA_HC_ENABLED); + CNIC_WR16(dev, addr, flags); +} + static void cnic_enable_bnx2x_int(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; u8 sb_id = cp->status_blk_num; - int port = CNIC_PORT(cp); CNIC_WR8(dev, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id, - HC_INDEX_C_ISCSI_EQ_CONS), - 64 / 12); - CNIC_WR16(dev, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, - HC_INDEX_C_ISCSI_EQ_CONS), 0); + CSTORM_STATUS_BLOCK_DATA_OFFSET(sb_id) + + offsetof(struct hc_status_block_data_e1x, index_data) + + sizeof(struct hc_index_data)*HC_INDEX_ISCSI_EQ_CONS + + offsetof(struct hc_index_data, timeout), 64 / 12); + cnic_storm_memset_hc_disable(dev, sb_id, HC_INDEX_ISCSI_EQ_CONS, 0); } static void cnic_disable_bnx2x_int_sync(struct cnic_dev *dev) { } -static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) +static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev, + struct client_init_ramrod_data *data) { struct cnic_local *cp = dev->cnic_priv; - union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) cp->l2_ring; - struct eth_context *context; - struct regpair context_addr; - dma_addr_t buf_map; - int func = CNIC_FUNC(cp); + struct cnic_uio_dev *udev = cp->udev; + union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) udev->l2_ring; + dma_addr_t buf_map, ring_map = udev->l2_ring_map; + struct host_sp_status_block *sb = cp->bnx2x_def_status_blk; int port = CNIC_PORT(cp); int i; int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); @@ -3886,7 +4111,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) memset(txbd, 0, BCM_PAGE_SIZE); - buf_map = cp->l2_buf_map; + buf_map = udev->l2_buf_map; for (i = 0; i < MAX_TX_DESC_CNT; i += 3, txbd += 3) { struct eth_tx_start_bd *start_bd = &txbd->start_bd; struct eth_tx_bd *reg_bd = &((txbd + 2)->reg_bd); @@ -3903,33 +4128,23 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT); } - context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 1, &context_addr); - val = (u64) cp->l2_ring_map >> 32; + val = (u64) ring_map >> 32; txbd->next_bd.addr_hi = cpu_to_le32(val); - context->xstorm_st_context.tx_bd_page_base_hi = val; + data->tx.tx_bd_page_base.hi = cpu_to_le32(val); - val = (u64) cp->l2_ring_map & 0xffffffff; + val = (u64) ring_map & 0xffffffff; txbd->next_bd.addr_lo = cpu_to_le32(val); - context->xstorm_st_context.tx_bd_page_base_lo = val; + data->tx.tx_bd_page_base.lo = cpu_to_le32(val); - context->cstorm_st_context.sb_index_number = - HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS; - context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID; - - if (cli < MAX_X_STAT_COUNTER_ID) - context->xstorm_st_context.statistics_data = cli | - XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE; - - context->xstorm_ag_context.cdu_reserved = - CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func), - CDU_REGION_NUMBER_XCM_AG, - ETH_CONNECTION_TYPE); + /* Other ramrod params */ + data->tx.tx_sb_index_number = HC_SP_INDEX_ETH_ISCSI_CQ_CONS; + data->tx.tx_status_block_id = BNX2X_DEF_SB_ID; /* reset xstorm per client statistics */ - if (cli < MAX_X_STAT_COUNTER_ID) { + if (cli < MAX_STAT_COUNTER_ID) { val = BAR_XSTRORM_INTMEM + XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++) @@ -3937,111 +4152,77 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) } cp->tx_cons_ptr = - &cp->bnx2x_def_status_blk->c_def_status_block.index_values[ - HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS]; + &sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_CQ_CONS]; } -static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev) +static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev, + struct client_init_ramrod_data *data) { struct cnic_local *cp = dev->cnic_priv; - struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (cp->l2_ring + + struct cnic_uio_dev *udev = cp->udev; + struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring + BCM_PAGE_SIZE); struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *) - (cp->l2_ring + (2 * BCM_PAGE_SIZE)); - struct eth_context *context; - struct regpair context_addr; + (udev->l2_ring + (2 * BCM_PAGE_SIZE)); + struct host_sp_status_block *sb = cp->bnx2x_def_status_blk; int i; int port = CNIC_PORT(cp); - int func = CNIC_FUNC(cp); int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); + int cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli); u32 val; - struct tstorm_eth_client_config tstorm_client = {0}; + dma_addr_t ring_map = udev->l2_ring_map; + + /* General data */ + data->general.client_id = cli; + data->general.statistics_en_flg = 1; + data->general.statistics_counter_id = cli; + data->general.activate_flg = 1; + data->general.sp_client_id = cli; for (i = 0; i < BNX2X_MAX_RX_DESC_CNT; i++, rxbd++) { dma_addr_t buf_map; int n = (i % cp->l2_rx_ring_size) + 1; - buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size); + buf_map = udev->l2_buf_map + (n * cp->l2_single_buf_size); rxbd->addr_hi = cpu_to_le32((u64) buf_map >> 32); rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff); } - context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 0, &context_addr); - val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32; + val = (u64) (ring_map + BCM_PAGE_SIZE) >> 32; rxbd->addr_hi = cpu_to_le32(val); + data->rx.bd_page_base.hi = cpu_to_le32(val); - context->ustorm_st_context.common.bd_page_base_hi = val; - - val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff; + val = (u64) (ring_map + BCM_PAGE_SIZE) & 0xffffffff; rxbd->addr_lo = cpu_to_le32(val); - - context->ustorm_st_context.common.bd_page_base_lo = val; - - context->ustorm_st_context.common.sb_index_numbers = - BNX2X_ISCSI_RX_SB_INDEX_NUM; - context->ustorm_st_context.common.clientId = cli; - context->ustorm_st_context.common.status_block_id = BNX2X_DEF_SB_ID; - if (cli < MAX_U_STAT_COUNTER_ID) { - context->ustorm_st_context.common.flags = - USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS; - context->ustorm_st_context.common.statistics_counter_id = cli; - } - context->ustorm_st_context.common.mc_alignment_log_size = 0; - context->ustorm_st_context.common.bd_buff_size = - cp->l2_single_buf_size; - - context->ustorm_ag_context.cdu_usage = - CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func), - CDU_REGION_NUMBER_UCM_AG, - ETH_CONNECTION_TYPE); + data->rx.bd_page_base.lo = cpu_to_le32(val); rxcqe += BNX2X_MAX_RCQ_DESC_CNT; - val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) >> 32; + val = (u64) (ring_map + (2 * BCM_PAGE_SIZE)) >> 32; rxcqe->addr_hi = cpu_to_le32(val); + data->rx.cqe_page_base.hi = cpu_to_le32(val); - CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_CQE_PAGE_BASE_OFFSET(port, cli) + 4, val); - - CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_CQE_PAGE_NEXT_OFFSET(port, cli) + 4, val); - - val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) & 0xffffffff; + val = (u64) (ring_map + (2 * BCM_PAGE_SIZE)) & 0xffffffff; rxcqe->addr_lo = cpu_to_le32(val); + data->rx.cqe_page_base.lo = cpu_to_le32(val); - CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_CQE_PAGE_BASE_OFFSET(port, cli), val); - - CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_CQE_PAGE_NEXT_OFFSET(port, cli), val); + /* Other ramrod params */ + data->rx.client_qzone_id = cl_qzone_id; + data->rx.rx_sb_index_number = HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS; + data->rx.status_block_id = BNX2X_DEF_SB_ID; - /* client tstorm info */ - tstorm_client.mtu = cp->l2_single_buf_size - 14; - tstorm_client.config_flags = TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE; + data->rx.cache_line_alignment_log_size = L1_CACHE_SHIFT; + data->rx.bd_buff_size = cpu_to_le16(cp->l2_single_buf_size); - if (cli < MAX_T_STAT_COUNTER_ID) { - tstorm_client.config_flags |= - TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; - tstorm_client.statistics_counter_id = cli; - } - - CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, cli), - ((u32 *)&tstorm_client)[0]); - CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, cli) + 4, - ((u32 *)&tstorm_client)[1]); - - /* reset tstorm per client statistics */ - if (cli < MAX_T_STAT_COUNTER_ID) { + data->rx.mtu = cpu_to_le16(cp->l2_single_buf_size - 14); + data->rx.outer_vlan_removal_enable_flg = 1; + /* reset tstorm and ustorm per client statistics */ + if (cli < MAX_STAT_COUNTER_ID) { val = BAR_TSTRORM_INTMEM + TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++) CNIC_WR(dev, val + i * 4, 0); - } - /* reset ustorm per client statistics */ - if (cli < MAX_U_STAT_COUNTER_ID) { val = BAR_USTRORM_INTMEM + USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++) @@ -4049,21 +4230,22 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev) } cp->rx_cons_ptr = - &cp->bnx2x_def_status_blk->u_def_status_block.index_values[ - HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS]; + &sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS]; } static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - u32 base, addr, val; + u32 base, base2, addr, val; int port = CNIC_PORT(cp); dev->max_iscsi_conn = 0; base = CNIC_RD(dev, MISC_REG_SHARED_MEM_ADDR); - if (base < 0xa0000 || base >= 0xc0000) + if (base == 0) return; + base2 = CNIC_RD(dev, (CNIC_PATH(cp) ? MISC_REG_GENERIC_CR_1 : + MISC_REG_GENERIC_CR_0)); addr = BNX2X_SHMEM_ADDR(base, dev_info.port_hw_config[port].iscsi_mac_upper); @@ -4096,16 +4278,25 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev) val16 ^= 0x1e1e; dev->max_iscsi_conn = val16; } - if (BNX2X_CHIP_IS_E1H(cp->chip_id)) { + if (BNX2X_CHIP_IS_E1H(cp->chip_id) || BNX2X_CHIP_IS_E2(cp->chip_id)) { int func = CNIC_FUNC(cp); + u32 mf_cfg_addr; + + if (BNX2X_SHMEM2_HAS(base2, mf_cfg_addr)) + mf_cfg_addr = CNIC_RD(dev, BNX2X_SHMEM2_ADDR(base2, + mf_cfg_addr)); + else + mf_cfg_addr = base + BNX2X_SHMEM_MF_BLK_OFFSET; + + addr = mf_cfg_addr + + offsetof(struct mf_cfg, func_mf_config[func].e1hov_tag); - addr = BNX2X_SHMEM_ADDR(base, - mf_cfg.func_mf_config[func].e1hov_tag); val = CNIC_RD(dev, addr); val &= FUNC_MF_CFG_E1HOV_TAG_MASK; if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { - addr = BNX2X_SHMEM_ADDR(base, - mf_cfg.func_mf_config[func].config); + addr = mf_cfg_addr + + offsetof(struct mf_cfg, + func_mf_config[func].config); val = CNIC_RD(dev, addr); val &= FUNC_MF_CFG_PROTOCOL_MASK; if (val != FUNC_MF_CFG_PROTOCOL_ISCSI) @@ -4117,91 +4308,125 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev) static int cnic_start_bnx2x_hw(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; int func = CNIC_FUNC(cp), ret, i; - int port = CNIC_PORT(cp); - u16 eq_idx; - u8 sb_id = cp->status_blk_num; + u32 pfid; + + if (BNX2X_CHIP_IS_E2(cp->chip_id)) { + u32 val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN_OVWR); + + if (!(val & 1)) + val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN); + else + val = (val >> 1) & 1; + + if (val) + cp->pfid = func >> 1; + else + cp->pfid = func & 0x6; + } else { + cp->pfid = func; + } + pfid = cp->pfid; ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ, - BNX2X_ISCSI_START_CID); + cp->iscsi_start_cid); if (ret) return -ENOMEM; - cp->kcq_io_addr = BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0); - cp->kcq_prod_idx = 0; + cp->bnx2x_igu_sb_id = ethdev->irq_arr[0].status_blk_num2; + + cp->kcq1.io_addr = BAR_CSTRORM_INTMEM + + CSTORM_ISCSI_EQ_PROD_OFFSET(pfid, 0); + cp->kcq1.sw_prod_idx = 0; + + if (BNX2X_CHIP_IS_E2(cp->chip_id)) { + struct host_hc_status_block_e2 *sb = cp->status_blk.gen; + + cp->kcq1.hw_prod_idx_ptr = + &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS]; + cp->kcq1.status_idx_ptr = + &sb->sb.running_index[SM_RX_ID]; + } else { + struct host_hc_status_block_e1x *sb = cp->status_blk.gen; + + cp->kcq1.hw_prod_idx_ptr = + &sb->sb.index_values[HC_INDEX_ISCSI_EQ_CONS]; + cp->kcq1.status_idx_ptr = + &sb->sb.running_index[SM_RX_ID]; + } cnic_get_bnx2x_iscsi_info(dev); /* Only 1 EQ */ - CNIC_WR16(dev, cp->kcq_io_addr, MAX_KCQ_IDX); + CNIC_WR16(dev, cp->kcq1.io_addr, MAX_KCQ_IDX); CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0); + CSTORM_ISCSI_EQ_CONS_OFFSET(pfid, 0), 0); CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0), - cp->kcq_info.pg_map_arr[1] & 0xffffffff); + CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfid, 0), + cp->kcq1.dma.pg_map_arr[1] & 0xffffffff); CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4, - (u64) cp->kcq_info.pg_map_arr[1] >> 32); + CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfid, 0) + 4, + (u64) cp->kcq1.dma.pg_map_arr[1] >> 32); CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0), - cp->kcq_info.pg_map_arr[0] & 0xffffffff); + CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfid, 0), + cp->kcq1.dma.pg_map_arr[0] & 0xffffffff); CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4, - (u64) cp->kcq_info.pg_map_arr[0] >> 32); + CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfid, 0) + 4, + (u64) cp->kcq1.dma.pg_map_arr[0] >> 32); CNIC_WR8(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1); + CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfid, 0), 1); CNIC_WR16(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_SB_NUM_OFFSET(func, 0), cp->status_blk_num); + CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfid, 0), cp->status_blk_num); CNIC_WR8(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(func, 0), - HC_INDEX_C_ISCSI_EQ_CONS); + CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfid, 0), + HC_INDEX_ISCSI_EQ_CONS); for (i = 0; i < cp->conn_buf_info.num_pages; i++) { CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i), + TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i), cp->conn_buf_info.pgtbl[2 * i]); CNIC_WR(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i) + 4, + TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i) + 4, cp->conn_buf_info.pgtbl[(2 * i) + 1]); } CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func), + USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfid), cp->gbl_buf_info.pg_map_arr[0] & 0xffffffff); CNIC_WR(dev, BAR_USTRORM_INTMEM + - USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func) + 4, + USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfid) + 4, (u64) cp->gbl_buf_info.pg_map_arr[0] >> 32); + CNIC_WR(dev, BAR_TSTRORM_INTMEM + + TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfid), DEF_RCV_BUF); + cnic_setup_bnx2x_context(dev); - eq_idx = CNIC_RD16(dev, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) + - offsetof(struct cstorm_status_block_c, - index_values[HC_INDEX_C_ISCSI_EQ_CONS])); - if (eq_idx != 0) { - netdev_err(dev->netdev, "EQ cons index %x != 0\n", eq_idx); - return -EBUSY; - } ret = cnic_init_bnx2x_irq(dev); if (ret) return ret; - cnic_init_bnx2x_tx_ring(dev); - cnic_init_bnx2x_rx_ring(dev); - return 0; } static void cnic_init_rings(struct cnic_dev *dev) { + struct cnic_local *cp = dev->cnic_priv; + struct cnic_uio_dev *udev = cp->udev; + + if (test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags)) + return; + if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { cnic_init_bnx2_tx_ring(dev); cnic_init_bnx2_rx_ring(dev); + set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags); } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { - struct cnic_local *cp = dev->cnic_priv; u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); + u32 cl_qzone_id, type; + struct client_init_ramrod_data *data; union l5cm_specific_data l5_data; struct ustorm_eth_rx_producers rx_prods = {0}; u32 off, i; @@ -4210,21 +4435,38 @@ static void cnic_init_rings(struct cnic_dev *dev) rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT; barrier(); + cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli); + off = BAR_USTRORM_INTMEM + - USTORM_RX_PRODS_OFFSET(CNIC_PORT(cp), cli); + (BNX2X_CHIP_IS_E2(cp->chip_id) ? + USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) : + USTORM_RX_PRODS_E1X_OFFSET(CNIC_PORT(cp), cli)); for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++) CNIC_WR(dev, off + i * 4, ((u32 *) &rx_prods)[i]); set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags); - cnic_init_bnx2x_tx_ring(dev); - cnic_init_bnx2x_rx_ring(dev); + data = udev->l2_buf; + + memset(data, 0, sizeof(*data)); + + cnic_init_bnx2x_tx_ring(dev, data); + cnic_init_bnx2x_rx_ring(dev, data); + + l5_data.phy_address.lo = udev->l2_buf_map & 0xffffffff; + l5_data.phy_address.hi = (u64) udev->l2_buf_map >> 32; + + type = (ETH_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT) + & SPE_HDR_CONN_TYPE; + type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) & + SPE_HDR_FUNCTION_ID); + + set_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags); - l5_data.phy_address.lo = cli; - l5_data.phy_address.hi = 0; cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CLIENT_SETUP, - BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data); + BNX2X_ISCSI_L2_CID, type, &l5_data); + i = 0; while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) && ++i < 10) @@ -4233,13 +4475,18 @@ static void cnic_init_rings(struct cnic_dev *dev) if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags)) netdev_err(dev->netdev, "iSCSI CLIENT_SETUP did not complete\n"); - cnic_kwq_completion(dev, 1); + cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1); cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1); } } static void cnic_shutdown_rings(struct cnic_dev *dev) { + struct cnic_local *cp = dev->cnic_priv; + + if (!test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags)) + return; + if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { cnic_shutdown_bnx2_rx_ring(dev); } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { @@ -4247,6 +4494,7 @@ static void cnic_shutdown_rings(struct cnic_dev *dev) u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); union l5cm_specific_data l5_data; int i; + u32 type; cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0); @@ -4264,14 +4512,18 @@ static void cnic_shutdown_rings(struct cnic_dev *dev) if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags)) netdev_err(dev->netdev, "iSCSI CLIENT_HALT did not complete\n"); - cnic_kwq_completion(dev, 1); + cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1); memset(&l5_data, 0, sizeof(l5_data)); - cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL, - BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE | - (1 << SPE_HDR_COMMON_RAMROD_SHIFT), &l5_data); + type = (NONE_CONNECTION_TYPE << SPE_HDR_CONN_TYPE_SHIFT) + & SPE_HDR_CONN_TYPE; + type |= ((cp->pfid << SPE_HDR_FUNCTION_ID_SHIFT) & + SPE_HDR_FUNCTION_ID); + cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL, + BNX2X_ISCSI_L2_CID, type, &l5_data); msleep(10); } + clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags); } static int cnic_register_netdev(struct cnic_dev *dev) @@ -4314,7 +4566,6 @@ static int cnic_start_hw(struct cnic_dev *dev) return -EALREADY; dev->regview = ethdev->io_base; - cp->chip_id = ethdev->chip_id; pci_dev_get(dev->pcidev); cp->func = PCI_FUNC(dev->pcidev->devfn); cp->status_blk.gen = ethdev->irq_arr[0].status_blk; @@ -4366,18 +4617,12 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev) static void cnic_stop_bnx2x_hw(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; - u8 sb_id = cp->status_blk_num; - int port = CNIC_PORT(cp); cnic_free_irq(dev); - CNIC_WR16(dev, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) + - offsetof(struct cstorm_status_block_c, - index_values[HC_INDEX_C_ISCSI_EQ_CONS]), - 0); + *cp->kcq1.hw_prod_idx_ptr = 0; CNIC_WR(dev, BAR_CSTRORM_INTMEM + - CSTORM_ISCSI_EQ_CONS_OFFSET(cp->func, 0), 0); - CNIC_WR16(dev, cp->kcq_io_addr, 0); + CSTORM_ISCSI_EQ_CONS_OFFSET(cp->pfid, 0), 0); + CNIC_WR16(dev, cp->kcq1.io_addr, 0); cnic_free_resc(dev); } @@ -4390,10 +4635,11 @@ 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->uio_dev != -1 && i < 15) { + while (cp->udev->uio_dev != -1 && i < 15) { msleep(100); i++; } + cnic_shutdown_rings(dev); clear_bit(CNIC_F_CNIC_UP, &dev->flags); rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL); synchronize_rcu(); @@ -4442,7 +4688,6 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev, cp = cdev->cnic_priv; cp->dev = cdev; - cp->uio_dev = -1; cp->l2_single_buf_size = 0x400; cp->l2_rx_ring_size = 3; @@ -4497,6 +4742,7 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev) cp = cdev->cnic_priv; cp->ethdev = ethdev; cdev->pcidev = pdev; + cp->chip_id = ethdev->chip_id; cp->cnic_ops = &cnic_bnx2_ops; cp->start_hw = cnic_start_bnx2_hw; @@ -4551,6 +4797,7 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev) cp = cdev->cnic_priv; cp->ethdev = ethdev; cdev->pcidev = pdev; + cp->chip_id = ethdev->chip_id; cp->cnic_ops = &cnic_bnx2x_ops; cp->start_hw = cnic_start_bnx2x_hw; @@ -4562,7 +4809,10 @@ 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; - cp->ack_int = cnic_ack_bnx2x_msix; + if (BNX2X_CHIP_IS_E2(cp->chip_id)) + cp->ack_int = cnic_ack_bnx2x_e2_msix; + else + cp->ack_int = cnic_ack_bnx2x_msix; cp->close_conn = cnic_close_bnx2x_conn; cp->next_idx = cnic_bnx2x_next_idx; cp->hw_idx = cnic_bnx2x_hw_idx; @@ -4670,6 +4920,7 @@ static struct notifier_block cnic_netdev_notifier = { static void cnic_release(void) { struct cnic_dev *dev; + struct cnic_uio_dev *udev; while (!list_empty(&cnic_dev_list)) { dev = list_entry(cnic_dev_list.next, struct cnic_dev, list); @@ -4683,6 +4934,11 @@ static void cnic_release(void) list_del_init(&dev->list); cnic_free_dev(dev); } + while (!list_empty(&cnic_udev_list)) { + udev = list_entry(cnic_udev_list.next, struct cnic_uio_dev, + list); + cnic_free_uio(udev); + } } static int __init cnic_init(void) @@ -4697,6 +4953,13 @@ static int __init cnic_init(void) return rc; } + cnic_wq = create_singlethread_workqueue("cnic_wq"); + if (!cnic_wq) { + cnic_release(); + unregister_netdevice_notifier(&cnic_netdev_notifier); + return -ENOMEM; + } + return 0; } @@ -4704,6 +4967,7 @@ static void __exit cnic_exit(void) { unregister_netdevice_notifier(&cnic_netdev_notifier); cnic_release(); + destroy_workqueue(cnic_wq); } module_init(cnic_init); |