diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-04-21 22:51:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-22 18:28:27 -0400 |
commit | f73dfc50f14d5c4c7f6243a87a65b78aef6f3a48 (patch) | |
tree | 7b007ea5cc52cf7730b2fb548cba4961b0fd0b76 /drivers/net | |
parent | bbd8c6a45b0f8557a8fc38fc763d7a51fac4459d (diff) |
qlcnic: fix fw initialization responsibility
Now any pci-func can start fw, whoever sees the reset ack first.
Before this, pci-func which sets the RESET state has the responsibility
to start fw.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index ff7705b26450..06349908092f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c | |||
@@ -2015,6 +2015,7 @@ err: | |||
2015 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 2015 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
2016 | } | 2016 | } |
2017 | 2017 | ||
2018 | /* Grab api lock, before checking state */ | ||
2018 | static int | 2019 | static int |
2019 | qlcnic_check_drv_state(struct qlcnic_adapter *adapter) | 2020 | qlcnic_check_drv_state(struct qlcnic_adapter *adapter) |
2020 | { | 2021 | { |
@@ -2037,6 +2038,9 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) | |||
2037 | u8 dev_init_timeo = adapter->dev_init_timeo; | 2038 | u8 dev_init_timeo = adapter->dev_init_timeo; |
2038 | int portnum = adapter->portnum; | 2039 | int portnum = adapter->portnum; |
2039 | 2040 | ||
2041 | if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) | ||
2042 | return 1; | ||
2043 | |||
2040 | if (qlcnic_api_lock(adapter)) | 2044 | if (qlcnic_api_lock(adapter)) |
2041 | return -1; | 2045 | return -1; |
2042 | 2046 | ||
@@ -2044,8 +2048,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) | |||
2044 | if (!(val & ((int)0x1 << (portnum * 4)))) { | 2048 | if (!(val & ((int)0x1 << (portnum * 4)))) { |
2045 | val |= ((u32)0x1 << (portnum * 4)); | 2049 | val |= ((u32)0x1 << (portnum * 4)); |
2046 | QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); | 2050 | QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val); |
2047 | } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) { | ||
2048 | goto start_fw; | ||
2049 | } | 2051 | } |
2050 | 2052 | ||
2051 | prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); | 2053 | prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); |
@@ -2053,7 +2055,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter) | |||
2053 | 2055 | ||
2054 | switch (prev_state) { | 2056 | switch (prev_state) { |
2055 | case QLCNIC_DEV_COLD: | 2057 | case QLCNIC_DEV_COLD: |
2056 | start_fw: | ||
2057 | QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING); | 2058 | QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING); |
2058 | qlcnic_api_unlock(adapter); | 2059 | qlcnic_api_unlock(adapter); |
2059 | return 1; | 2060 | return 1; |
@@ -2113,51 +2114,59 @@ qlcnic_fwinit_work(struct work_struct *work) | |||
2113 | { | 2114 | { |
2114 | struct qlcnic_adapter *adapter = container_of(work, | 2115 | struct qlcnic_adapter *adapter = container_of(work, |
2115 | struct qlcnic_adapter, fw_work.work); | 2116 | struct qlcnic_adapter, fw_work.work); |
2116 | int dev_state; | 2117 | u32 dev_state = 0xf; |
2117 | 2118 | ||
2118 | if (test_bit(__QLCNIC_START_FW, &adapter->state)) { | 2119 | if (qlcnic_api_lock(adapter)) |
2120 | goto err_ret; | ||
2119 | 2121 | ||
2120 | if (qlcnic_check_drv_state(adapter) && | 2122 | if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) { |
2121 | (adapter->fw_wait_cnt++ < adapter->reset_ack_timeo)) { | 2123 | dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n", |
2122 | qlcnic_schedule_work(adapter, | 2124 | adapter->reset_ack_timeo); |
2123 | qlcnic_fwinit_work, FW_POLL_DELAY); | 2125 | goto skip_ack_check; |
2124 | return; | 2126 | } |
2127 | |||
2128 | if (!qlcnic_check_drv_state(adapter)) { | ||
2129 | skip_ack_check: | ||
2130 | dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); | ||
2131 | if (dev_state == QLCNIC_DEV_NEED_RESET) { | ||
2132 | QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, | ||
2133 | QLCNIC_DEV_INITIALIZING); | ||
2134 | set_bit(__QLCNIC_START_FW, &adapter->state); | ||
2135 | QLCDB(adapter, DRV, "Restarting fw\n"); | ||
2125 | } | 2136 | } |
2126 | 2137 | ||
2127 | QLCDB(adapter, DRV, "Resetting FW\n"); | 2138 | qlcnic_api_unlock(adapter); |
2139 | |||
2128 | if (!qlcnic_start_firmware(adapter)) { | 2140 | if (!qlcnic_start_firmware(adapter)) { |
2129 | qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); | 2141 | qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); |
2130 | return; | 2142 | return; |
2131 | } | 2143 | } |
2132 | |||
2133 | goto err_ret; | 2144 | goto err_ret; |
2134 | } | 2145 | } |
2135 | 2146 | ||
2136 | if (adapter->fw_wait_cnt++ > (adapter->dev_init_timeo / 2)) { | 2147 | qlcnic_api_unlock(adapter); |
2137 | dev_err(&adapter->pdev->dev, | ||
2138 | "Waiting for device to reset timeout\n"); | ||
2139 | goto err_ret; | ||
2140 | } | ||
2141 | 2148 | ||
2142 | dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); | 2149 | dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); |
2143 | QLCDB(adapter, HW, "Func waiting: Device state=%d\n", dev_state); | 2150 | QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state); |
2144 | 2151 | ||
2145 | switch (dev_state) { | 2152 | switch (dev_state) { |
2146 | case QLCNIC_DEV_READY: | 2153 | case QLCNIC_DEV_NEED_RESET: |
2147 | if (!qlcnic_start_firmware(adapter)) { | 2154 | qlcnic_schedule_work(adapter, |
2148 | qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); | 2155 | qlcnic_fwinit_work, FW_POLL_DELAY); |
2149 | return; | 2156 | return; |
2150 | } | ||
2151 | case QLCNIC_DEV_FAILED: | 2157 | case QLCNIC_DEV_FAILED: |
2152 | break; | 2158 | break; |
2153 | 2159 | ||
2154 | default: | 2160 | default: |
2155 | qlcnic_schedule_work(adapter, | 2161 | if (!qlcnic_start_firmware(adapter)) { |
2156 | qlcnic_fwinit_work, 2 * FW_POLL_DELAY); | 2162 | qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); |
2157 | return; | 2163 | return; |
2164 | } | ||
2158 | } | 2165 | } |
2159 | 2166 | ||
2160 | err_ret: | 2167 | err_ret: |
2168 | dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u " | ||
2169 | "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt); | ||
2161 | netif_device_attach(adapter->netdev); | 2170 | netif_device_attach(adapter->netdev); |
2162 | qlcnic_clr_all_drv_state(adapter); | 2171 | qlcnic_clr_all_drv_state(adapter); |
2163 | } | 2172 | } |
@@ -2202,6 +2211,7 @@ err_ret: | |||
2202 | 2211 | ||
2203 | } | 2212 | } |
2204 | 2213 | ||
2214 | /*Transit to RESET state from READY state only */ | ||
2205 | static void | 2215 | static void |
2206 | qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) | 2216 | qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) |
2207 | { | 2217 | { |
@@ -2212,10 +2222,8 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) | |||
2212 | 2222 | ||
2213 | state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); | 2223 | state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); |
2214 | 2224 | ||
2215 | if (state != QLCNIC_DEV_INITIALIZING && | 2225 | if (state == QLCNIC_DEV_READY) { |
2216 | state != QLCNIC_DEV_NEED_RESET) { | ||
2217 | QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); | 2226 | QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); |
2218 | set_bit(__QLCNIC_START_FW, &adapter->state); | ||
2219 | QLCDB(adapter, DRV, "NEED_RESET state set\n"); | 2227 | QLCDB(adapter, DRV, "NEED_RESET state set\n"); |
2220 | } | 2228 | } |
2221 | 2229 | ||