aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-08-13 16:30:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:33:11 -0400
commit415e49936b4b29b34c2fb561eeab867d41fc43a6 (patch)
tree2cf697d948c5eb0256b29d3c60a45f7c00ab1337 /drivers/net/wireless
parent3b24716fc978db9c27c4a069e5201460479340a4 (diff)
iwlwifi: traverse linklist to find the valid OTP block
For devices using OTP memory, EEPROM image can start from any one of the OTP blocks. If shadow RAM is disabled, we need to traverse link list to find the last valid block, then start the EEPROM image reading. If OTP is not full, the valid block is the block _before_ the last block on the link list; the last block on the link list is the empty block ready for next OTP refresh/update. If OTP is full, then the last block is the valid block to be used for configure the device. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c185
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h10
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
194struct iwl_cfg iwl6050_2agn_cfg = { 198struct 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
211struct iwl_cfg iwl6000_3agn_cfg = { 217struct 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
228struct iwl_cfg iwl6050_3agn_cfg = { 236struct 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
245MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); 255MODULE_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 */
897enum 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}
153EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); 153EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
154 154
155static 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
155static int iwlcore_get_nvm_type(struct iwl_priv *priv) 168static 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
268static 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 */
308static 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 */
337static 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");
379done:
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 */
187extern const u8 iwl_eeprom_band_1[14]; 193extern const u8 iwl_eeprom_band_1[14];