diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2012-01-08 09:33:58 -0500 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2012-02-02 17:36:58 -0500 |
commit | cf6142975bcbb731bc131ee9d2a68b7561076545 (patch) | |
tree | 7cec34553e1d121f0ae601cc603e33007ccd8269 | |
parent | d48e2074e240192e8a0396e1ae0082dd0e78aa8e (diff) |
iwlwifi: consolidate the start_device flow
Now there is only one transport function that launch a specific fw:
trans_ops->start_fw. This one replaces trans_ops->start_device and
trans_ops->kick_nic. The code that actually loads the fw to the
device has been moved to the transport specific code.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 44 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-ucode.c | 87 |
4 files changed, 103 insertions, 120 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index ebea2435dac..731f287c0f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | |||
@@ -1130,11 +1130,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) | |||
1130 | isr_stats->tx++; | 1130 | isr_stats->tx++; |
1131 | handled |= CSR_INT_BIT_FH_TX; | 1131 | handled |= CSR_INT_BIT_FH_TX; |
1132 | /* Wake up uCode load routine, now that load is complete */ | 1132 | /* Wake up uCode load routine, now that load is complete */ |
1133 | #ifdef CONFIG_IWLWIFI_IDI | ||
1134 | trans->shrd->trans->ucode_write_complete = 1; | ||
1135 | #else | ||
1136 | trans->ucode_write_complete = 1; | 1133 | trans->ucode_write_complete = 1; |
1137 | #endif | ||
1138 | wake_up(&trans->shrd->wait_command_queue); | 1134 | wake_up(&trans->shrd->wait_command_queue); |
1139 | } | 1135 | } |
1140 | 1136 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 362444a7ed5..1030a252405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/pci-aspm.h> | 64 | #include <linux/pci-aspm.h> |
65 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
66 | #include <linux/debugfs.h> | 66 | #include <linux/debugfs.h> |
67 | #include <linux/sched.h> | ||
67 | #include <linux/bitops.h> | 68 | #include <linux/bitops.h> |
68 | #include <linux/gfp.h> | 69 | #include <linux/gfp.h> |
69 | 70 | ||
@@ -895,7 +896,79 @@ static const u8 iwlagn_pan_ac_to_queue[] = { | |||
895 | 7, 6, 5, 4, | 896 | 7, 6, 5, 4, |
896 | }; | 897 | }; |
897 | 898 | ||
898 | static int iwl_trans_pcie_start_device(struct iwl_trans *trans) | 899 | /* |
900 | * ucode | ||
901 | */ | ||
902 | static int iwl_load_section(struct iwl_trans *trans, const char *name, | ||
903 | struct fw_desc *image, u32 dst_addr) | ||
904 | { | ||
905 | dma_addr_t phy_addr = image->p_addr; | ||
906 | u32 byte_cnt = image->len; | ||
907 | int ret; | ||
908 | |||
909 | trans->ucode_write_complete = 0; | ||
910 | |||
911 | iwl_write_direct32(trans, | ||
912 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), | ||
913 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); | ||
914 | |||
915 | iwl_write_direct32(trans, | ||
916 | FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); | ||
917 | |||
918 | iwl_write_direct32(trans, | ||
919 | FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), | ||
920 | phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); | ||
921 | |||
922 | iwl_write_direct32(trans, | ||
923 | FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), | ||
924 | (iwl_get_dma_hi_addr(phy_addr) | ||
925 | << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); | ||
926 | |||
927 | iwl_write_direct32(trans, | ||
928 | FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), | ||
929 | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | | ||
930 | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | | ||
931 | FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); | ||
932 | |||
933 | iwl_write_direct32(trans, | ||
934 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), | ||
935 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | | ||
936 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | | ||
937 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); | ||
938 | |||
939 | IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name); | ||
940 | ret = wait_event_timeout(trans->shrd->wait_command_queue, | ||
941 | trans->ucode_write_complete, 5 * HZ); | ||
942 | if (!ret) { | ||
943 | IWL_ERR(trans, "Could not load the %s uCode section\n", | ||
944 | name); | ||
945 | return -ETIMEDOUT; | ||
946 | } | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int iwl_load_given_ucode(struct iwl_trans *trans, struct fw_img *image) | ||
952 | { | ||
953 | int ret = 0; | ||
954 | |||
955 | ret = iwl_load_section(trans, "INST", &image->code, | ||
956 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
957 | if (ret) | ||
958 | return ret; | ||
959 | |||
960 | ret = iwl_load_section(trans, "DATA", &image->data, | ||
961 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
962 | if (ret) | ||
963 | return ret; | ||
964 | |||
965 | /* Remove all resets to allow NIC to operate */ | ||
966 | iwl_write32(trans, CSR_RESET, 0); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, struct fw_img *fw) | ||
899 | { | 972 | { |
900 | int ret; | 973 | int ret; |
901 | struct iwl_trans_pcie *trans_pcie = | 974 | struct iwl_trans_pcie *trans_pcie = |
@@ -951,6 +1024,9 @@ static int iwl_trans_pcie_start_device(struct iwl_trans *trans) | |||
951 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 1024 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
952 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 1025 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
953 | 1026 | ||
1027 | /* Load the given image to the HW */ | ||
1028 | iwl_load_given_ucode(trans, fw); | ||
1029 | |||
954 | return 0; | 1030 | return 0; |
955 | } | 1031 | } |
956 | 1032 | ||
@@ -1353,12 +1429,6 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1353 | return 0; | 1429 | return 0; |
1354 | } | 1430 | } |
1355 | 1431 | ||
1356 | static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans) | ||
1357 | { | ||
1358 | /* Remove all resets to allow NIC to operate */ | ||
1359 | iwl_write32(trans, CSR_RESET, 0); | ||
1360 | } | ||
1361 | |||
1362 | static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | 1432 | static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) |
1363 | { | 1433 | { |
1364 | struct iwl_trans_pcie *trans_pcie = | 1434 | struct iwl_trans_pcie *trans_pcie = |
@@ -2086,7 +2156,7 @@ const struct iwl_trans_ops trans_ops_pcie = { | |||
2086 | .start_hw = iwl_trans_pcie_start_hw, | 2156 | .start_hw = iwl_trans_pcie_start_hw, |
2087 | .stop_hw = iwl_trans_pcie_stop_hw, | 2157 | .stop_hw = iwl_trans_pcie_stop_hw, |
2088 | .fw_alive = iwl_trans_pcie_fw_alive, | 2158 | .fw_alive = iwl_trans_pcie_fw_alive, |
2089 | .start_device = iwl_trans_pcie_start_device, | 2159 | .start_fw = iwl_trans_pcie_start_fw, |
2090 | .stop_device = iwl_trans_pcie_stop_device, | 2160 | .stop_device = iwl_trans_pcie_stop_device, |
2091 | 2161 | ||
2092 | .wake_any_queue = iwl_trans_pcie_wake_any_queue, | 2162 | .wake_any_queue = iwl_trans_pcie_wake_any_queue, |
@@ -2100,8 +2170,6 @@ const struct iwl_trans_ops trans_ops_pcie = { | |||
2100 | .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc, | 2170 | .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc, |
2101 | .tx_agg_setup = iwl_trans_pcie_tx_agg_setup, | 2171 | .tx_agg_setup = iwl_trans_pcie_tx_agg_setup, |
2102 | 2172 | ||
2103 | .kick_nic = iwl_trans_pcie_kick_nic, | ||
2104 | |||
2105 | .free = iwl_trans_pcie_free, | 2173 | .free = iwl_trans_pcie_free, |
2106 | .stop_queue = iwl_trans_pcie_stop_queue, | 2174 | .stop_queue = iwl_trans_pcie_stop_queue, |
2107 | 2175 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index d0b6146b097..4d1ae65b68e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -131,13 +131,25 @@ struct iwl_host_cmd { | |||
131 | u8 id; | 131 | u8 id; |
132 | }; | 132 | }; |
133 | 133 | ||
134 | /* one for each uCode image (inst/data, boot/init/runtime) */ | ||
135 | struct fw_desc { | ||
136 | dma_addr_t p_addr; /* hardware address */ | ||
137 | void *v_addr; /* software address */ | ||
138 | u32 len; /* size in bytes */ | ||
139 | }; | ||
140 | |||
141 | struct fw_img { | ||
142 | struct fw_desc code; /* firmware code image */ | ||
143 | struct fw_desc data; /* firmware data image */ | ||
144 | }; | ||
145 | |||
134 | /** | 146 | /** |
135 | * struct iwl_trans_ops - transport specific operations | 147 | * struct iwl_trans_ops - transport specific operations |
136 | * @start_hw: starts the HW- from that point on, the HW can send interrupts | 148 | * @start_hw: starts the HW- from that point on, the HW can send interrupts |
137 | * @stop_hw: stops the HW- from that point on, the HW will be in low power but | 149 | * @stop_hw: stops the HW- from that point on, the HW will be in low power but |
138 | * will still issue interrupt if the HW RF kill is triggered. | 150 | * will still issue interrupt if the HW RF kill is triggered. |
139 | * @start_device: allocates and inits all the resources for the transport | 151 | * @start_fw: allocates and inits all the resources for the transport |
140 | * layer. | 152 | * layer. Also kick a fw image. This handler may sleep. |
141 | * @fw_alive: called when the fw sends alive notification | 153 | * @fw_alive: called when the fw sends alive notification |
142 | * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* | 154 | * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* |
143 | * @stop_device:stops the whole device (embedded CPU put to reset) | 155 | * @stop_device:stops the whole device (embedded CPU put to reset) |
@@ -148,7 +160,6 @@ struct iwl_host_cmd { | |||
148 | * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is | 160 | * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is |
149 | * ready and a successful ADDBA response has been received. | 161 | * ready and a successful ADDBA response has been received. |
150 | * @tx_agg_disable: de-configure a Tx queue to send AMPDUs | 162 | * @tx_agg_disable: de-configure a Tx queue to send AMPDUs |
151 | * @kick_nic: remove the RESET from the embedded CPU and let it run | ||
152 | * @free: release all the ressource for the transport layer itself such as | 163 | * @free: release all the ressource for the transport layer itself such as |
153 | * irq, tasklet etc... | 164 | * irq, tasklet etc... |
154 | * @stop_queue: stop a specific queue | 165 | * @stop_queue: stop a specific queue |
@@ -166,7 +177,7 @@ struct iwl_trans_ops { | |||
166 | 177 | ||
167 | int (*start_hw)(struct iwl_trans *iwl_trans); | 178 | int (*start_hw)(struct iwl_trans *iwl_trans); |
168 | void (*stop_hw)(struct iwl_trans *iwl_trans); | 179 | void (*stop_hw)(struct iwl_trans *iwl_trans); |
169 | int (*start_device)(struct iwl_trans *trans); | 180 | int (*start_fw)(struct iwl_trans *trans, struct fw_img *fw); |
170 | void (*fw_alive)(struct iwl_trans *trans); | 181 | void (*fw_alive)(struct iwl_trans *trans); |
171 | void (*stop_device)(struct iwl_trans *trans); | 182 | void (*stop_device)(struct iwl_trans *trans); |
172 | 183 | ||
@@ -191,8 +202,6 @@ struct iwl_trans_ops { | |||
191 | enum iwl_rxon_context_id ctx, int sta_id, int tid, | 202 | enum iwl_rxon_context_id ctx, int sta_id, int tid, |
192 | int frame_limit, u16 ssn); | 203 | int frame_limit, u16 ssn); |
193 | 204 | ||
194 | void (*kick_nic)(struct iwl_trans *trans); | ||
195 | |||
196 | void (*free)(struct iwl_trans *trans); | 205 | void (*free)(struct iwl_trans *trans); |
197 | 206 | ||
198 | void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg); | 207 | void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg); |
@@ -209,18 +218,6 @@ struct iwl_trans_ops { | |||
209 | u32 (*read32)(struct iwl_trans *trans, u32 ofs); | 218 | u32 (*read32)(struct iwl_trans *trans, u32 ofs); |
210 | }; | 219 | }; |
211 | 220 | ||
212 | /* one for each uCode image (inst/data, boot/init/runtime) */ | ||
213 | struct fw_desc { | ||
214 | dma_addr_t p_addr; /* hardware address */ | ||
215 | void *v_addr; /* software address */ | ||
216 | u32 len; /* size in bytes */ | ||
217 | }; | ||
218 | |||
219 | struct fw_img { | ||
220 | struct fw_desc code; /* firmware code image */ | ||
221 | struct fw_desc data; /* firmware data image */ | ||
222 | }; | ||
223 | |||
224 | /* Opaque calibration results */ | 221 | /* Opaque calibration results */ |
225 | struct iwl_calib_result { | 222 | struct iwl_calib_result { |
226 | struct list_head list; | 223 | struct list_head list; |
@@ -284,9 +281,11 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans) | |||
284 | trans->ops->fw_alive(trans); | 281 | trans->ops->fw_alive(trans); |
285 | } | 282 | } |
286 | 283 | ||
287 | static inline int iwl_trans_start_device(struct iwl_trans *trans) | 284 | static inline int iwl_trans_start_fw(struct iwl_trans *trans, struct fw_img *fw) |
288 | { | 285 | { |
289 | return trans->ops->start_device(trans); | 286 | might_sleep(); |
287 | |||
288 | return trans->ops->start_fw(trans, fw); | ||
290 | } | 289 | } |
291 | 290 | ||
292 | static inline void iwl_trans_stop_device(struct iwl_trans *trans) | 291 | static inline void iwl_trans_stop_device(struct iwl_trans *trans) |
@@ -347,11 +346,6 @@ static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, | |||
347 | trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); | 346 | trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); |
348 | } | 347 | } |
349 | 348 | ||
350 | static inline void iwl_trans_kick_nic(struct iwl_trans *trans) | ||
351 | { | ||
352 | trans->ops->kick_nic(trans); | ||
353 | } | ||
354 | |||
355 | static inline void iwl_trans_free(struct iwl_trans *trans) | 349 | static inline void iwl_trans_free(struct iwl_trans *trans) |
356 | { | 350 | { |
357 | trans->ops->free(trans); | 351 | trans->ops->free(trans); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 793524a3ed7..87ce587d7d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c | |||
@@ -120,58 +120,6 @@ int iwl_alloc_fw_desc(struct iwl_trans *trans, struct fw_desc *desc, | |||
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | 122 | ||
123 | /* | ||
124 | * ucode | ||
125 | */ | ||
126 | static int iwl_load_section(struct iwl_trans *trans, const char *name, | ||
127 | struct fw_desc *image, u32 dst_addr) | ||
128 | { | ||
129 | dma_addr_t phy_addr = image->p_addr; | ||
130 | u32 byte_cnt = image->len; | ||
131 | int ret; | ||
132 | |||
133 | trans->ucode_write_complete = 0; | ||
134 | |||
135 | iwl_write_direct32(trans, | ||
136 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), | ||
137 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); | ||
138 | |||
139 | iwl_write_direct32(trans, | ||
140 | FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); | ||
141 | |||
142 | iwl_write_direct32(trans, | ||
143 | FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), | ||
144 | phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); | ||
145 | |||
146 | iwl_write_direct32(trans, | ||
147 | FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), | ||
148 | (iwl_get_dma_hi_addr(phy_addr) | ||
149 | << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); | ||
150 | |||
151 | iwl_write_direct32(trans, | ||
152 | FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), | ||
153 | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | | ||
154 | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | | ||
155 | FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); | ||
156 | |||
157 | iwl_write_direct32(trans, | ||
158 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), | ||
159 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | | ||
160 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | | ||
161 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); | ||
162 | |||
163 | IWL_DEBUG_FW(trans, "%s uCode section being loaded...\n", name); | ||
164 | ret = wait_event_timeout(trans->shrd->wait_command_queue, | ||
165 | trans->ucode_write_complete, 5 * HZ); | ||
166 | if (!ret) { | ||
167 | IWL_ERR(trans, "Could not load the %s uCode section\n", | ||
168 | name); | ||
169 | return -ETIMEDOUT; | ||
170 | } | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, | 123 | static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, |
176 | enum iwl_ucode_type ucode_type) | 124 | enum iwl_ucode_type ucode_type) |
177 | { | 125 | { |
@@ -188,28 +136,6 @@ static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans, | |||
188 | return NULL; | 136 | return NULL; |
189 | } | 137 | } |
190 | 138 | ||
191 | static int iwl_load_given_ucode(struct iwl_trans *trans, | ||
192 | enum iwl_ucode_type ucode_type) | ||
193 | { | ||
194 | int ret = 0; | ||
195 | struct fw_img *image = iwl_get_ucode_image(trans, ucode_type); | ||
196 | |||
197 | |||
198 | if (!image) { | ||
199 | IWL_ERR(trans, "Invalid ucode requested (%d)\n", | ||
200 | ucode_type); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | ret = iwl_load_section(trans, "INST", &image->code, | ||
205 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
206 | if (ret) | ||
207 | return ret; | ||
208 | |||
209 | return iwl_load_section(trans, "DATA", &image->data, | ||
210 | IWLAGN_RTC_DATA_LOWER_BOUND); | ||
211 | } | ||
212 | |||
213 | /* | 139 | /* |
214 | * Calibration | 140 | * Calibration |
215 | */ | 141 | */ |
@@ -646,28 +572,27 @@ int iwl_load_ucode_wait_alive(struct iwl_trans *trans, | |||
646 | { | 572 | { |
647 | struct iwl_notification_wait alive_wait; | 573 | struct iwl_notification_wait alive_wait; |
648 | struct iwl_alive_data alive_data; | 574 | struct iwl_alive_data alive_data; |
575 | struct fw_img *fw; | ||
649 | int ret; | 576 | int ret; |
650 | enum iwl_ucode_type old_type; | 577 | enum iwl_ucode_type old_type; |
651 | 578 | ||
652 | ret = iwl_trans_start_device(trans); | ||
653 | if (ret) | ||
654 | return ret; | ||
655 | |||
656 | iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE, | 579 | iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE, |
657 | iwl_alive_fn, &alive_data); | 580 | iwl_alive_fn, &alive_data); |
658 | 581 | ||
659 | old_type = trans->shrd->ucode_type; | 582 | old_type = trans->shrd->ucode_type; |
660 | trans->shrd->ucode_type = ucode_type; | 583 | trans->shrd->ucode_type = ucode_type; |
584 | fw = iwl_get_ucode_image(trans, ucode_type); | ||
661 | 585 | ||
662 | ret = iwl_load_given_ucode(trans, ucode_type); | 586 | if (!fw) |
587 | return -EINVAL; | ||
588 | |||
589 | ret = iwl_trans_start_fw(trans, fw); | ||
663 | if (ret) { | 590 | if (ret) { |
664 | trans->shrd->ucode_type = old_type; | 591 | trans->shrd->ucode_type = old_type; |
665 | iwl_remove_notification(trans->shrd, &alive_wait); | 592 | iwl_remove_notification(trans->shrd, &alive_wait); |
666 | return ret; | 593 | return ret; |
667 | } | 594 | } |
668 | 595 | ||
669 | iwl_trans_kick_nic(trans); | ||
670 | |||
671 | /* | 596 | /* |
672 | * Some things may run in the background now, but we | 597 | * Some things may run in the background now, but we |
673 | * just wait for the ALIVE notification here. | 598 | * just wait for the ALIVE notification here. |