diff options
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_main.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 197 |
1 files changed, 134 insertions, 63 deletions
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 234dab1f9982..ee573fe52a8e 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -208,6 +208,9 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter) struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; napi_enable(&sds_ring->napi); @@ -222,6 +225,9 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter) struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + return; + for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; qlcnic_disable_int(sds_ring); @@ -650,7 +656,10 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter) if (err) return err; - if (!qlcnic_can_start_firmware(adapter)) + err = qlcnic_can_start_firmware(adapter); + if (err < 0) + return err; + else if (!err) goto wait_init; first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc)); @@ -950,11 +959,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) adapter->max_sds_rings = max_sds_rings; if (qlcnic_attach(adapter)) - return; + goto out; if (netif_running(netdev)) __qlcnic_up(adapter, netdev); - +out: netif_device_attach(netdev); } @@ -976,8 +985,10 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) adapter->diag_test = test; ret = qlcnic_attach(adapter); - if (ret) + if (ret) { + netif_device_attach(netdev); return ret; + } if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -1010,16 +1021,12 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter) if (netif_running(netdev)) { err = qlcnic_attach(adapter); if (!err) - err = __qlcnic_up(adapter, netdev); - - if (err) - goto done; + __qlcnic_up(adapter, netdev); } netif_device_attach(netdev); } -done: clear_bit(__QLCNIC_RESETTING, &adapter->state); return err; } @@ -1139,6 +1146,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iounmap; } + qlcnic_setup_idc_param(adapter); err = qlcnic_start_firmware(adapter); if (err) @@ -1334,6 +1342,7 @@ err_out_detach: qlcnic_detach(adapter); err_out: qlcnic_clr_all_drv_state(adapter); + netif_device_attach(netdev); return err; } #endif @@ -1570,6 +1579,11 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int frag_count, no_of_desc; u32 num_txd = tx_ring->num_desc; + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + frag_count = skb_shinfo(skb)->nr_frags + 1; /* 4 fragments per cmd des */ @@ -1586,8 +1600,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pdev = adapter->pdev; - if (qlcnic_map_tx_skb(pdev, skb, pbuf)) + if (qlcnic_map_tx_skb(pdev, skb, pbuf)) { + adapter->stats.tx_dma_map_error++; goto drop_packet; + } pbuf->skb = skb; pbuf->frag_count = frag_count; @@ -1739,6 +1755,7 @@ static void qlcnic_tx_timeout_task(struct work_struct *work) request_reset: adapter->need_fw_reset = 1; clear_bit(__QLCNIC_RESETTING, &adapter->state); + QLCDB(adapter, DRV, "Resetting adapter\n"); } static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) @@ -1943,8 +1960,8 @@ static void qlcnic_poll_controller(struct net_device *netdev) } #endif -static void -qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) +static int +qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state) { u32 val; @@ -1952,18 +1969,20 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state) state != QLCNIC_DEV_NEED_QUISCENT); if (qlcnic_api_lock(adapter)) - return ; + return -EIO; val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); if (state == QLCNIC_DEV_NEED_RESET) - val |= ((u32)0x1 << (adapter->portnum * 4)); + QLC_DEV_SET_RST_RDY(val, adapter->portnum); else if (state == QLCNIC_DEV_NEED_QUISCENT) - val |= ((u32)0x1 << ((adapter->portnum * 4) + 1)); + QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); qlcnic_api_unlock(adapter); + + return 0; } static int @@ -1975,7 +1994,7 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter) return -EBUSY; val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); - val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); qlcnic_api_unlock(adapter); @@ -1992,14 +2011,14 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter) goto err; val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); - val &= ~((u32)0x1 << (adapter->portnum * 4)); + QLC_DEV_CLR_REF_CNT(val, adapter->portnum); QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); if (!(val & 0x11111111)) QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD); val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); - val &= ~((u32)0x3 << (adapter->portnum * 4)); + QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); qlcnic_api_unlock(adapter); @@ -2009,6 +2028,7 @@ err: clear_bit(__QLCNIC_RESETTING, &adapter->state); } +/* Grab api lock, before checking state */ static int qlcnic_check_drv_state(struct qlcnic_adapter *adapter) { @@ -2028,26 +2048,27 @@ static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) { u32 val, prev_state; - int cnt = 0; - int portnum = adapter->portnum; + u8 dev_init_timeo = adapter->dev_init_timeo; + u8 portnum = adapter->portnum; + + if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) + return 1; if (qlcnic_api_lock(adapter)) return -1; val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); - if (!(val & ((int)0x1 << (portnum * 4)))) { - val |= ((u32)0x1 << (portnum * 4)); + if (!(val & (1 << (portnum * 4)))) { + QLC_DEV_SET_REF_CNT(val, portnum); QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); - } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) { - goto start_fw; } prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + QLCDB(adapter, HW, "Device state = %u\n", prev_state); switch (prev_state) { case QLCNIC_DEV_COLD: -start_fw: - QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING); + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING); qlcnic_api_unlock(adapter); return 1; @@ -2057,35 +2078,43 @@ start_fw: case QLCNIC_DEV_NEED_RESET: val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); - val |= ((u32)0x1 << (portnum * 4)); + QLC_DEV_SET_RST_RDY(val, portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); break; case QLCNIC_DEV_NEED_QUISCENT: val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); - val |= ((u32)0x1 << ((portnum * 4) + 1)); + QLC_DEV_SET_QSCNT_RDY(val, portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); break; case QLCNIC_DEV_FAILED: qlcnic_api_unlock(adapter); return -1; + + case QLCNIC_DEV_INITIALIZING: + case QLCNIC_DEV_QUISCENT: + break; } qlcnic_api_unlock(adapter); - msleep(1000); - while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) && - ++cnt < 20) + + do { msleep(1000); + } while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) + && --dev_init_timeo); - if (cnt >= 20) + if (!dev_init_timeo) { + dev_err(&adapter->pdev->dev, + "Waiting for device to initialize timeout\n"); return -1; + } if (qlcnic_api_lock(adapter)) return -1; val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE); - val &= ~((u32)0x3 << (portnum * 4)); + QLC_DEV_CLR_RST_QSCNT(val, portnum); QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val); qlcnic_api_unlock(adapter); @@ -2098,44 +2127,60 @@ qlcnic_fwinit_work(struct work_struct *work) { struct qlcnic_adapter *adapter = container_of(work, struct qlcnic_adapter, fw_work.work); - int dev_state; + u32 dev_state = 0xf; - if (++adapter->fw_wait_cnt > FW_POLL_THRESH) + if (qlcnic_api_lock(adapter)) goto err_ret; - if (test_bit(__QLCNIC_START_FW, &adapter->state)) { + if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) { + dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n", + adapter->reset_ack_timeo); + goto skip_ack_check; + } - if (qlcnic_check_drv_state(adapter)) { - qlcnic_schedule_work(adapter, - qlcnic_fwinit_work, FW_POLL_DELAY); - return; + if (!qlcnic_check_drv_state(adapter)) { +skip_ack_check: + dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (dev_state == QLCNIC_DEV_NEED_RESET) { + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, + QLCNIC_DEV_INITIALIZING); + set_bit(__QLCNIC_START_FW, &adapter->state); + QLCDB(adapter, DRV, "Restarting fw\n"); } + qlcnic_api_unlock(adapter); + if (!qlcnic_start_firmware(adapter)) { qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); return; } - goto err_ret; } + qlcnic_api_unlock(adapter); + dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state); + switch (dev_state) { - case QLCNIC_DEV_READY: - if (!qlcnic_start_firmware(adapter)) { - qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); - return; - } + case QLCNIC_DEV_NEED_RESET: + qlcnic_schedule_work(adapter, + qlcnic_fwinit_work, FW_POLL_DELAY); + return; case QLCNIC_DEV_FAILED: break; default: - qlcnic_schedule_work(adapter, - qlcnic_fwinit_work, 2 * FW_POLL_DELAY); - return; + if (!qlcnic_start_firmware(adapter)) { + qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); + return; + } } err_ret: + dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u " + "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt); + netif_device_attach(adapter->netdev); qlcnic_clr_all_drv_state(adapter); } @@ -2163,7 +2208,8 @@ qlcnic_detach_work(struct work_struct *work) if (adapter->temp == QLCNIC_TEMP_PANIC) goto err_ret; - qlcnic_set_drv_state(adapter, adapter->dev_state); + if (qlcnic_set_drv_state(adapter, adapter->dev_state)) + goto err_ret; adapter->fw_wait_cnt = 0; @@ -2172,10 +2218,14 @@ qlcnic_detach_work(struct work_struct *work) return; err_ret: + dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n", + status, adapter->temp); + netif_device_attach(netdev); qlcnic_clr_all_drv_state(adapter); } +/*Transit to RESET state from READY state only */ static void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) { @@ -2186,9 +2236,9 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); - if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) { + if (state == QLCNIC_DEV_READY) { QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); - set_bit(__QLCNIC_START_FW, &adapter->state); + QLCDB(adapter, DRV, "NEED_RESET state set\n"); } qlcnic_api_unlock(adapter); @@ -2233,9 +2283,8 @@ qlcnic_attach_work(struct work_struct *work) qlcnic_config_indev_addr(netdev, NETDEV_UP); } - netif_device_attach(netdev); - done: + netif_device_attach(netdev); adapter->fw_fail_cnt = 0; clear_bit(__QLCNIC_RESETTING, &adapter->state); @@ -2285,8 +2334,11 @@ detach: QLCNIC_DEV_NEED_RESET; if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) && - !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) { + qlcnic_schedule_work(adapter, qlcnic_detach_work, 0); + QLCDB(adapter, DRV, "fw recovery scheduled.\n"); + } return 1; } @@ -2387,14 +2439,21 @@ static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, loff_t offset, size_t size) { + size_t crb_size = 4; + if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) return -EIO; - if ((size != 4) || (offset & 0x3)) - return -EINVAL; + if (offset < QLCNIC_PCI_CRBSPACE) { + if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, + QLCNIC_PCI_CAMQM_END)) + crb_size = 8; + else + return -EINVAL; + } - if (offset < QLCNIC_PCI_CRBSPACE) - return -EINVAL; + if ((size != crb_size) || (offset & (crb_size-1))) + return -EINVAL; return 0; } @@ -2406,14 +2465,20 @@ qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr, struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); u32 data; + u64 qmdata; int ret; ret = qlcnic_sysfs_validate_crb(adapter, offset, size); if (ret != 0) return ret; - data = QLCRD32(adapter, offset); - memcpy(buf, &data, size); + if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) { + qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata); + memcpy(buf, &qmdata, size); + } else { + data = QLCRD32(adapter, offset); + memcpy(buf, &data, size); + } return size; } @@ -2424,14 +2489,20 @@ qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr, struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); u32 data; + u64 qmdata; int ret; ret = qlcnic_sysfs_validate_crb(adapter, offset, size); if (ret != 0) return ret; - memcpy(&data, buf, size); - QLCWR32(adapter, offset, data); + if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) { + memcpy(&qmdata, buf, size); + qlcnic_pci_camqm_write_2M(adapter, offset, qmdata); + } else { + memcpy(&data, buf, size); + QLCWR32(adapter, offset, data); + } return size; } |