diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-1000.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.c | 185 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.h | 10 |
6 files changed, 191 insertions, 43 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 191718a0c545..9bb6a287eaee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -149,12 +149,14 @@ struct iwl_cfg iwl1000_bgn_cfg = { | |||
149 | .ucode_api_min = IWL1000_UCODE_API_MIN, | 149 | .ucode_api_min = IWL1000_UCODE_API_MIN, |
150 | .sku = IWL_SKU_G|IWL_SKU_N, | 150 | .sku = IWL_SKU_G|IWL_SKU_N, |
151 | .ops = &iwl1000_ops, | 151 | .ops = &iwl1000_ops, |
152 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 152 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
153 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 153 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
154 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 154 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
155 | .mod_params = &iwl50_mod_params, | 155 | .mod_params = &iwl50_mod_params, |
156 | .valid_tx_ant = ANT_A, | 156 | .valid_tx_ant = ANT_A, |
157 | .valid_rx_ant = ANT_AB, | 157 | .valid_rx_ant = ANT_AB, |
158 | .need_pll_cfg = true, | 158 | .need_pll_cfg = true, |
159 | .max_ll_items = OTP_MAX_LL_ITEMS_1000, | ||
160 | .shadow_ram_support = false, | ||
159 | }; | 161 | }; |
160 | 162 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c3ec6c20cc94..0b731fd5ad1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -161,7 +161,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { | |||
161 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 161 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
162 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 162 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
163 | .ops = &iwl6000_ops, | 163 | .ops = &iwl6000_ops, |
164 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 164 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
165 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 165 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
166 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 166 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
167 | .mod_params = &iwl50_mod_params, | 167 | .mod_params = &iwl50_mod_params, |
@@ -169,6 +169,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = { | |||
169 | .valid_rx_ant = ANT_AB, | 169 | .valid_rx_ant = ANT_AB, |
170 | .need_pll_cfg = false, | 170 | .need_pll_cfg = false, |
171 | .pa_type = IWL_PA_HYBRID, | 171 | .pa_type = IWL_PA_HYBRID, |
172 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
173 | .shadow_ram_support = true, | ||
172 | }; | 174 | }; |
173 | 175 | ||
174 | /* | 176 | /* |
@@ -181,7 +183,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { | |||
181 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 183 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
182 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 184 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
183 | .ops = &iwl6000_ops, | 185 | .ops = &iwl6000_ops, |
184 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 186 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
185 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 187 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
186 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 188 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
187 | .mod_params = &iwl50_mod_params, | 189 | .mod_params = &iwl50_mod_params, |
@@ -189,6 +191,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = { | |||
189 | .valid_rx_ant = ANT_BC, | 191 | .valid_rx_ant = ANT_BC, |
190 | .need_pll_cfg = false, | 192 | .need_pll_cfg = false, |
191 | .pa_type = IWL_PA_INTERNAL, | 193 | .pa_type = IWL_PA_INTERNAL, |
194 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
195 | .shadow_ram_support = true, | ||
192 | }; | 196 | }; |
193 | 197 | ||
194 | struct iwl_cfg iwl6050_2agn_cfg = { | 198 | struct iwl_cfg iwl6050_2agn_cfg = { |
@@ -198,7 +202,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
198 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 202 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
199 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 203 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
200 | .ops = &iwl6000_ops, | 204 | .ops = &iwl6000_ops, |
201 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 205 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
202 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 206 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
203 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 207 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
204 | .mod_params = &iwl50_mod_params, | 208 | .mod_params = &iwl50_mod_params, |
@@ -206,6 +210,8 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
206 | .valid_rx_ant = ANT_AB, | 210 | .valid_rx_ant = ANT_AB, |
207 | .need_pll_cfg = false, | 211 | .need_pll_cfg = false, |
208 | .pa_type = IWL_PA_SYSTEM, | 212 | .pa_type = IWL_PA_SYSTEM, |
213 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
214 | .shadow_ram_support = true, | ||
209 | }; | 215 | }; |
210 | 216 | ||
211 | struct iwl_cfg iwl6000_3agn_cfg = { | 217 | struct iwl_cfg iwl6000_3agn_cfg = { |
@@ -215,7 +221,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { | |||
215 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 221 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
216 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 222 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
217 | .ops = &iwl6000_ops, | 223 | .ops = &iwl6000_ops, |
218 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 224 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
219 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 225 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
220 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 226 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
221 | .mod_params = &iwl50_mod_params, | 227 | .mod_params = &iwl50_mod_params, |
@@ -223,6 +229,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { | |||
223 | .valid_rx_ant = ANT_ABC, | 229 | .valid_rx_ant = ANT_ABC, |
224 | .need_pll_cfg = false, | 230 | .need_pll_cfg = false, |
225 | .pa_type = IWL_PA_SYSTEM, | 231 | .pa_type = IWL_PA_SYSTEM, |
232 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
233 | .shadow_ram_support = true, | ||
226 | }; | 234 | }; |
227 | 235 | ||
228 | struct iwl_cfg iwl6050_3agn_cfg = { | 236 | struct iwl_cfg iwl6050_3agn_cfg = { |
@@ -232,7 +240,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { | |||
232 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 240 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
233 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 241 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
234 | .ops = &iwl6000_ops, | 242 | .ops = &iwl6000_ops, |
235 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 243 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
236 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, | 244 | .eeprom_ver = EEPROM_5000_EEPROM_VERSION, |
237 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 245 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
238 | .mod_params = &iwl50_mod_params, | 246 | .mod_params = &iwl50_mod_params, |
@@ -240,6 +248,8 @@ struct iwl_cfg iwl6050_3agn_cfg = { | |||
240 | .valid_rx_ant = ANT_ABC, | 248 | .valid_rx_ant = ANT_ABC, |
241 | .need_pll_cfg = false, | 249 | .need_pll_cfg = false, |
242 | .pa_type = IWL_PA_SYSTEM, | 250 | .pa_type = IWL_PA_SYSTEM, |
251 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
252 | .shadow_ram_support = true, | ||
243 | }; | 253 | }; |
244 | 254 | ||
245 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); | 255 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32750f4f1ce1..509683487e0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -209,6 +209,8 @@ struct iwl_mod_params { | |||
209 | * @ucode_api_max: Highest version of uCode API supported by driver. | 209 | * @ucode_api_max: Highest version of uCode API supported by driver. |
210 | * @ucode_api_min: Lowest version of uCode API supported by driver. | 210 | * @ucode_api_min: Lowest version of uCode API supported by driver. |
211 | * @pa_type: used by 6000 series only to identify the type of Power Amplifier | 211 | * @pa_type: used by 6000 series only to identify the type of Power Amplifier |
212 | * @max_ll_items: max number of OTP blocks | ||
213 | * @shadow_ram_support: shadow support for OTP memory | ||
212 | * | 214 | * |
213 | * We enable the driver to be backward compatible wrt API version. The | 215 | * We enable the driver to be backward compatible wrt API version. The |
214 | * driver specifies which APIs it supports (with @ucode_api_max being the | 216 | * driver specifies which APIs it supports (with @ucode_api_max being the |
@@ -247,6 +249,8 @@ struct iwl_cfg { | |||
247 | bool need_pll_cfg; | 249 | bool need_pll_cfg; |
248 | bool use_isr_legacy; | 250 | bool use_isr_legacy; |
249 | enum iwl_pa_type pa_type; | 251 | enum iwl_pa_type pa_type; |
252 | const u16 max_ll_items; | ||
253 | const bool shadow_ram_support; | ||
250 | }; | 254 | }; |
251 | 255 | ||
252 | /*************************** | 256 | /*************************** |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c34f9d73306d..0b19a6f93c84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -887,6 +887,17 @@ enum iwl_nvm_type { | |||
887 | NVM_DEVICE_TYPE_OTP, | 887 | NVM_DEVICE_TYPE_OTP, |
888 | }; | 888 | }; |
889 | 889 | ||
890 | /* | ||
891 | * Two types of OTP memory access modes | ||
892 | * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, | ||
893 | * based on physical memory addressing | ||
894 | * IWL_OTP_ACCESS_RELATIVE - relative address mode, | ||
895 | * based on logical memory addressing | ||
896 | */ | ||
897 | enum iwl_access_mode { | ||
898 | IWL_OTP_ACCESS_ABSOLUTE, | ||
899 | IWL_OTP_ACCESS_RELATIVE, | ||
900 | }; | ||
890 | 901 | ||
891 | /** | 902 | /** |
892 | * enum iwl_pa_type - Power Amplifier type | 903 | * enum iwl_pa_type - Power Amplifier type |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ded63320a463..01b95e89009a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) | |||
152 | } | 152 | } |
153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); | 153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); |
154 | 154 | ||
155 | static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) | ||
156 | { | ||
157 | u32 otpgp; | ||
158 | |||
159 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
160 | if (mode == IWL_OTP_ACCESS_ABSOLUTE) | ||
161 | iwl_clear_bit(priv, CSR_OTP_GP_REG, | ||
162 | CSR_OTP_GP_REG_OTP_ACCESS_MODE); | ||
163 | else | ||
164 | iwl_set_bit(priv, CSR_OTP_GP_REG, | ||
165 | CSR_OTP_GP_REG_OTP_ACCESS_MODE); | ||
166 | } | ||
167 | |||
155 | static int iwlcore_get_nvm_type(struct iwl_priv *priv) | 168 | static int iwlcore_get_nvm_type(struct iwl_priv *priv) |
156 | { | 169 | { |
157 | u32 otpgp; | 170 | u32 otpgp; |
@@ -252,6 +265,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv) | |||
252 | return ret; | 265 | return ret; |
253 | } | 266 | } |
254 | 267 | ||
268 | static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) | ||
269 | { | ||
270 | int ret = 0; | ||
271 | u32 r; | ||
272 | u32 otpgp; | ||
273 | |||
274 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
275 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
276 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
277 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
278 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
279 | if (ret < 0) { | ||
280 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); | ||
281 | return ret; | ||
282 | } | ||
283 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
284 | /* check for ECC errors: */ | ||
285 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
286 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { | ||
287 | /* stop in this case */ | ||
288 | /* set the uncorrectable OTP ECC bit for acknowledgement */ | ||
289 | iwl_set_bit(priv, CSR_OTP_GP_REG, | ||
290 | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); | ||
291 | IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { | ||
295 | /* continue in this case */ | ||
296 | /* set the correctable OTP ECC bit for acknowledgement */ | ||
297 | iwl_set_bit(priv, CSR_OTP_GP_REG, | ||
298 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); | ||
299 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); | ||
300 | } | ||
301 | *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * iwl_is_otp_empty: check for empty OTP | ||
307 | */ | ||
308 | static bool iwl_is_otp_empty(struct iwl_priv *priv) | ||
309 | { | ||
310 | u16 next_link_addr = 0, link_value; | ||
311 | bool is_empty = false; | ||
312 | |||
313 | /* locate the beginning of OTP link list */ | ||
314 | if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { | ||
315 | if (!link_value) { | ||
316 | IWL_ERR(priv, "OTP is empty\n"); | ||
317 | is_empty = true; | ||
318 | } | ||
319 | } else { | ||
320 | IWL_ERR(priv, "Unable to read first block of OTP list.\n"); | ||
321 | is_empty = true; | ||
322 | } | ||
323 | |||
324 | return is_empty; | ||
325 | } | ||
326 | |||
327 | |||
328 | /* | ||
329 | * iwl_find_otp_image: find EEPROM image in OTP | ||
330 | * finding the OTP block that contains the EEPROM image. | ||
331 | * the last valid block on the link list (the block _before_ the last block) | ||
332 | * is the block we should read and used to configure the device. | ||
333 | * If all the available OTP blocks are full, the last block will be the block | ||
334 | * we should read and used to configure the device. | ||
335 | * only perform this operation if shadow RAM is disabled | ||
336 | */ | ||
337 | static int iwl_find_otp_image(struct iwl_priv *priv, | ||
338 | u16 *validblockaddr) | ||
339 | { | ||
340 | u16 next_link_addr = 0, link_value = 0, valid_addr; | ||
341 | int ret = 0; | ||
342 | int usedblocks = 0; | ||
343 | |||
344 | /* set addressing mode to absolute to traverse the link list */ | ||
345 | iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); | ||
346 | |||
347 | /* checking for empty OTP or error */ | ||
348 | if (iwl_is_otp_empty(priv)) | ||
349 | return -EINVAL; | ||
350 | |||
351 | /* | ||
352 | * start traverse link list | ||
353 | * until reach the max number of OTP blocks | ||
354 | * different devices have different number of OTP blocks | ||
355 | */ | ||
356 | do { | ||
357 | /* save current valid block address | ||
358 | * check for more block on the link list | ||
359 | */ | ||
360 | valid_addr = next_link_addr; | ||
361 | next_link_addr = link_value; | ||
362 | IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", | ||
363 | usedblocks, next_link_addr); | ||
364 | if (iwl_read_otp_word(priv, next_link_addr, &link_value)) | ||
365 | return -EINVAL; | ||
366 | if (!link_value) { | ||
367 | /* | ||
368 | * reach the end of link list, | ||
369 | * set address point to the starting address | ||
370 | * of the image | ||
371 | */ | ||
372 | goto done; | ||
373 | } | ||
374 | /* more in the link list, continue */ | ||
375 | usedblocks++; | ||
376 | } while (usedblocks < priv->cfg->max_ll_items); | ||
377 | /* OTP full, use last block */ | ||
378 | IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); | ||
379 | done: | ||
380 | *validblockaddr = valid_addr; | ||
381 | /* skip first 2 bytes (link list pointer) */ | ||
382 | *validblockaddr += 2; | ||
383 | return ret; | ||
384 | } | ||
385 | |||
255 | /** | 386 | /** |
256 | * iwl_eeprom_init - read EEPROM contents | 387 | * iwl_eeprom_init - read EEPROM contents |
257 | * | 388 | * |
@@ -266,15 +397,14 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
266 | int sz; | 397 | int sz; |
267 | int ret; | 398 | int ret; |
268 | u16 addr; | 399 | u16 addr; |
269 | u32 otpgp; | 400 | u16 validblockaddr = 0; |
401 | u16 cache_addr = 0; | ||
270 | 402 | ||
271 | priv->nvm_device_type = iwlcore_get_nvm_type(priv); | 403 | priv->nvm_device_type = iwlcore_get_nvm_type(priv); |
272 | if (priv->nvm_device_type == -ENOENT) | 404 | if (priv->nvm_device_type == -ENOENT) |
273 | return -ENOENT; | 405 | return -ENOENT; |
274 | /* allocate eeprom */ | 406 | /* allocate eeprom */ |
275 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) | 407 | IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); |
276 | priv->cfg->eeprom_size = | ||
277 | OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; | ||
278 | sz = priv->cfg->eeprom_size; | 408 | sz = priv->cfg->eeprom_size; |
279 | priv->eeprom = kzalloc(sz, GFP_KERNEL); | 409 | priv->eeprom = kzalloc(sz, GFP_KERNEL); |
280 | if (!priv->eeprom) { | 410 | if (!priv->eeprom) { |
@@ -302,46 +432,31 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
302 | if (ret) { | 432 | if (ret) { |
303 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); | 433 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); |
304 | ret = -ENOENT; | 434 | ret = -ENOENT; |
305 | goto err; | 435 | goto done; |
306 | } | 436 | } |
307 | _iwl_write32(priv, CSR_EEPROM_GP, | 437 | _iwl_write32(priv, CSR_EEPROM_GP, |
308 | iwl_read32(priv, CSR_EEPROM_GP) & | 438 | iwl_read32(priv, CSR_EEPROM_GP) & |
309 | ~CSR_EEPROM_GP_IF_OWNER_MSK); | 439 | ~CSR_EEPROM_GP_IF_OWNER_MSK); |
310 | /* clear */ | 440 | |
311 | _iwl_write32(priv, CSR_OTP_GP_REG, | 441 | iwl_set_bit(priv, CSR_OTP_GP_REG, |
312 | iwl_read32(priv, CSR_OTP_GP_REG) | | ||
313 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | | 442 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | |
314 | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); | 443 | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); |
315 | 444 | /* traversing the linked list if no shadow ram supported */ | |
316 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | 445 | if (!priv->cfg->shadow_ram_support) { |
317 | u32 r; | 446 | if (iwl_find_otp_image(priv, &validblockaddr)) { |
318 | 447 | ret = -ENOENT; | |
319 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
320 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
321 | |||
322 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
323 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
324 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
325 | if (ret < 0) { | ||
326 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); | ||
327 | goto done; | 448 | goto done; |
328 | } | 449 | } |
329 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | 450 | } |
330 | /* check for ECC errors: */ | 451 | for (addr = validblockaddr; addr < validblockaddr + sz; |
331 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | 452 | addr += sizeof(u16)) { |
332 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { | 453 | u16 eeprom_data; |
333 | /* stop in this case */ | 454 | |
334 | IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); | 455 | ret = iwl_read_otp_word(priv, addr, &eeprom_data); |
456 | if (ret) | ||
335 | goto done; | 457 | goto done; |
336 | } | 458 | e[cache_addr / 2] = eeprom_data; |
337 | if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { | 459 | cache_addr += sizeof(u16); |
338 | /* continue in this case */ | ||
339 | _iwl_write32(priv, CSR_OTP_GP_REG, | ||
340 | iwl_read32(priv, CSR_OTP_GP_REG) | | ||
341 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); | ||
342 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); | ||
343 | } | ||
344 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
345 | } | 460 | } |
346 | } else { | 461 | } else { |
347 | /* eeprom is an array of 16bit values */ | 462 | /* eeprom is an array of 16bit values */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 05d4fc4451dc..ca7920a8f52f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h | |||
@@ -180,8 +180,14 @@ struct iwl_eeprom_channel { | |||
180 | #define EEPROM_5050_EEPROM_VERSION (0x21E) | 180 | #define EEPROM_5050_EEPROM_VERSION (0x21E) |
181 | 181 | ||
182 | /* OTP */ | 182 | /* OTP */ |
183 | #define OTP_LOWER_BLOCKS_TOTAL (3) | 183 | /* lower blocks contain EEPROM image and calibration data */ |
184 | #define OTP_BLOCK_SIZE (0x400) | 184 | #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ |
185 | /* high blocks contain PAPD data */ | ||
186 | #define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ | ||
187 | #define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ | ||
188 | #define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ | ||
189 | #define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ | ||
190 | #define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ | ||
185 | 191 | ||
186 | /* 2.4 GHz */ | 192 | /* 2.4 GHz */ |
187 | extern const u8 iwl_eeprom_band_1[14]; | 193 | extern const u8 iwl_eeprom_band_1[14]; |