summaryrefslogtreecommitdiff
path: root/drivers/net/cnic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cnic.c')
-rw-r--r--drivers/net/cnic.c145
1 files changed, 110 insertions, 35 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 4b451a7c03e9..80471269977a 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -1143,12 +1143,12 @@ static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
spin_lock_bh(&cp->cnic_ulp_lock);
if (num_wqes > cnic_kwq_avail(cp) &&
- !(cp->cnic_local_flags & CNIC_LCL_FL_KWQ_INIT)) {
+ !test_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags)) {
spin_unlock_bh(&cp->cnic_ulp_lock);
return -EAGAIN;
}
- cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT;
+ clear_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags);
prod = cp->kwq_prod_idx;
sw_prod = prod & MAX_KWQ_IDX;
@@ -2092,7 +2092,6 @@ end:
i += j;
j = 1;
}
- return;
}
static u16 cnic_bnx2_next_idx(u16 idx)
@@ -2146,17 +2145,56 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
return last_cnt;
}
+static int cnic_l2_completion(struct cnic_local *cp)
+{
+ u16 hw_cons, sw_cons;
+ union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
+ (cp->l2_ring + (2 * BCM_PAGE_SIZE));
+ u32 cmd;
+ int comp = 0;
+
+ if (!test_bit(CNIC_F_BNX2X_CLASS, &cp->dev->flags))
+ return 0;
+
+ hw_cons = *cp->rx_cons_ptr;
+ if ((hw_cons & BNX2X_MAX_RCQ_DESC_CNT) == BNX2X_MAX_RCQ_DESC_CNT)
+ hw_cons++;
+
+ sw_cons = cp->rx_cons;
+ while (sw_cons != hw_cons) {
+ u8 cqe_fp_flags;
+
+ cqe = &cqe_ring[sw_cons & BNX2X_MAX_RCQ_DESC_CNT];
+ cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+ if (cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE) {
+ cmd = le32_to_cpu(cqe->ramrod_cqe.conn_and_cmd_data);
+ cmd >>= COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT;
+ if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP ||
+ cmd == RAMROD_CMD_ID_ETH_HALT)
+ comp++;
+ }
+ sw_cons = BNX2X_NEXT_RCQE(sw_cons);
+ }
+ return comp;
+}
+
static void cnic_chk_pkt_rings(struct cnic_local *cp)
{
u16 rx_cons = *cp->rx_cons_ptr;
u16 tx_cons = *cp->tx_cons_ptr;
+ int comp = 0;
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);
+
cp->tx_cons = tx_cons;
cp->rx_cons = rx_cons;
uio_event_notify(cp->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)
@@ -2325,7 +2363,6 @@ done:
status_idx, IGU_INT_ENABLE, 1);
cp->kcq_prod_idx = sw_prod;
- return;
}
static int cnic_service_bnx2x(void *data, void *status_blk)
@@ -3330,13 +3367,9 @@ static int cnic_cm_shutdown(struct cnic_dev *dev)
static void cnic_init_context(struct cnic_dev *dev, u32 cid)
{
- struct cnic_local *cp = dev->cnic_priv;
u32 cid_addr;
int i;
- if (CHIP_NUM(cp) == CHIP_NUM_5709)
- return;
-
cid_addr = GET_CID_ADDR(cid);
for (i = 0; i < CTX_SIZE; i += 4)
@@ -3493,14 +3526,11 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
sb_id = cp->status_blk_num;
tx_cid = 20;
- cnic_init_context(dev, tx_cid);
- cnic_init_context(dev, tx_cid + 1);
cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
struct status_block_msix *sblk = cp->status_blk.bnx2;
tx_cid = TX_TSS_CID + sb_id - 1;
- cnic_init_context(dev, tx_cid);
CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) |
(TX_TSS_CID << 7));
cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index;
@@ -3519,6 +3549,9 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
} else {
+ cnic_init_context(dev, tx_cid);
+ cnic_init_context(dev, tx_cid + 1);
+
offset0 = BNX2_L2CTX_TYPE;
offset1 = BNX2_L2CTX_CMD_TYPE;
offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
@@ -3692,7 +3725,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
cp->max_kwq_idx = MAX_KWQ_IDX;
cp->kwq_prod_idx = 0;
cp->kwq_con_idx = 0;
- cp->cnic_local_flags |= CNIC_LCL_FL_KWQ_INIT;
+ set_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags);
if (CHIP_NUM(cp) == CHIP_NUM_5706 || CHIP_NUM(cp) == CHIP_NUM_5708)
cp->kwq_con_idx_ptr = &sblk->status_rx_quick_consumer_index15;
@@ -3886,8 +3919,9 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS;
context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID;
- context->xstorm_st_context.statistics_data = (cli |
- XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
+ 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),
@@ -3895,10 +3929,12 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
ETH_CONNECTION_TYPE);
/* reset xstorm per client statistics */
- val = BAR_XSTRORM_INTMEM +
- XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
- for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
- CNIC_WR(dev, val + i * 4, 0);
+ if (cli < MAX_X_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++)
+ CNIC_WR(dev, val + i * 4, 0);
+ }
cp->tx_cons_ptr =
&cp->bnx2x_def_status_blk->c_def_status_block.index_values[
@@ -3945,9 +3981,11 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
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;
- context->ustorm_st_context.common.flags =
- USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS;
- context->ustorm_st_context.common.statistics_counter_id = cli;
+ 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;
@@ -3978,10 +4016,13 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
/* client tstorm info */
tstorm_client.mtu = cp->l2_single_buf_size - 14;
- tstorm_client.config_flags =
- (TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE |
- TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE);
- tstorm_client.statistics_counter_id = cli;
+ tstorm_client.config_flags = TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE;
+
+ 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),
@@ -3991,16 +4032,21 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
((u32 *)&tstorm_client)[1]);
/* reset tstorm per client statistics */
- 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);
+ if (cli < MAX_T_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 */
- val = BAR_USTRORM_INTMEM +
- USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
- for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
- CNIC_WR(dev, val + i * 4, 0);
+ 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++)
+ CNIC_WR(dev, val + i * 4, 0);
+ }
cp->rx_cons_ptr =
&cp->bnx2x_def_status_blk->u_def_status_block.index_values[
@@ -4170,6 +4216,8 @@ static void cnic_init_rings(struct cnic_dev *dev)
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);
@@ -4177,6 +4225,15 @@ static void cnic_init_rings(struct cnic_dev *dev)
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);
+ i = 0;
+ while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
+ ++i < 10)
+ msleep(1);
+
+ 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_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
}
}
@@ -4189,14 +4246,25 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
struct cnic_local *cp = dev->cnic_priv;
u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
union l5cm_specific_data l5_data;
+ int i;
cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
+ set_bit(CNIC_LCL_FL_L2_WAIT, &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_HALT,
BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
- msleep(10);
+ i = 0;
+ while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
+ ++i < 10)
+ msleep(1);
+
+ 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);
memset(&l5_data, 0, sizeof(l5_data));
cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL,
@@ -4317,7 +4385,15 @@ static void cnic_stop_hw(struct cnic_dev *dev)
{
if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
struct cnic_local *cp = dev->cnic_priv;
+ int i = 0;
+ /* Need to wait for the ring shutdown event to complete
+ * before clearing the CNIC_UP flag.
+ */
+ while (cp->uio_dev != -1 && i < 15) {
+ msleep(100);
+ i++;
+ }
clear_bit(CNIC_F_CNIC_UP, &dev->flags);
rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
synchronize_rcu();
@@ -4628,7 +4704,6 @@ static void __exit cnic_exit(void)
{
unregister_netdevice_notifier(&cnic_netdev_notifier);
cnic_release();
- return;
}
module_init(cnic_init);