diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2006-03-07 14:22:28 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-03-17 15:08:04 -0500 |
commit | 9006ea75cfaded82acbc34d03e9d4e86447f40a9 (patch) | |
tree | a65ca3227d09488495444b9f4d43179c595191c4 /drivers | |
parent | 651be26f2daf31e61faf4b55ada709cf39ec76a2 (diff) |
[PATCH] ipw2200: switch to the new ipw2200-fw-3.0 image format
This patch modifies the driver to support the ipw2200-fw-3.0 image format.
The 3.0 fw image does not add any new capabilities, but as a result of
image format changes, it should fix two problems experienced by users:
1) Race conditions with the request_firmware interface and udev/hotplug
are improved as only a single request_firmware call is now required to
load the firmware and microcode (vs. 3 separate calls previously)
2) The monitor mode firmware (sniffer) is now packaged with the correct
boot image so it can now function without frequent restarts.
Note: Once you apply this patch, you will also need to upgrade your
firmware image to the 3.0 version available from:
http://ipw2200.sf.net/firmware.php
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 165 |
1 files changed, 64 insertions, 101 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 078f33b01c2f..0b74b5a16647 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -2829,33 +2829,11 @@ static void ipw_arc_release(struct ipw_priv *priv) | |||
2829 | mdelay(5); | 2829 | mdelay(5); |
2830 | } | 2830 | } |
2831 | 2831 | ||
2832 | struct fw_header { | ||
2833 | u32 version; | ||
2834 | u32 mode; | ||
2835 | }; | ||
2836 | |||
2837 | struct fw_chunk { | 2832 | struct fw_chunk { |
2838 | u32 address; | 2833 | u32 address; |
2839 | u32 length; | 2834 | u32 length; |
2840 | }; | 2835 | }; |
2841 | 2836 | ||
2842 | #define IPW_FW_MAJOR_VERSION 2 | ||
2843 | #define IPW_FW_MINOR_VERSION 4 | ||
2844 | |||
2845 | #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) | ||
2846 | #define IPW_FW_MAJOR(x) (x & 0xff) | ||
2847 | |||
2848 | #define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION) | ||
2849 | |||
2850 | #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ | ||
2851 | "." __stringify(IPW_FW_MINOR_VERSION) "-" | ||
2852 | |||
2853 | #if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0 | ||
2854 | #define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw" | ||
2855 | #else | ||
2856 | #define IPW_FW_NAME(x) "ipw2200_" x ".fw" | ||
2857 | #endif | ||
2858 | |||
2859 | static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | 2837 | static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) |
2860 | { | 2838 | { |
2861 | int rc = 0, i, addr; | 2839 | int rc = 0, i, addr; |
@@ -3124,33 +3102,47 @@ static int ipw_reset_nic(struct ipw_priv *priv) | |||
3124 | return rc; | 3102 | return rc; |
3125 | } | 3103 | } |
3126 | 3104 | ||
3105 | |||
3106 | struct ipw_fw { | ||
3107 | u32 ver; | ||
3108 | u32 boot_size; | ||
3109 | u32 ucode_size; | ||
3110 | u32 fw_size; | ||
3111 | u8 data[0]; | ||
3112 | }; | ||
3113 | |||
3127 | static int ipw_get_fw(struct ipw_priv *priv, | 3114 | static int ipw_get_fw(struct ipw_priv *priv, |
3128 | const struct firmware **fw, const char *name) | 3115 | const struct firmware **raw, const char *name) |
3129 | { | 3116 | { |
3130 | struct fw_header *header; | 3117 | struct ipw_fw *fw; |
3131 | int rc; | 3118 | int rc; |
3132 | 3119 | ||
3133 | /* ask firmware_class module to get the boot firmware off disk */ | 3120 | /* ask firmware_class module to get the boot firmware off disk */ |
3134 | rc = request_firmware(fw, name, &priv->pci_dev->dev); | 3121 | rc = request_firmware(raw, name, &priv->pci_dev->dev); |
3135 | if (rc < 0) { | 3122 | if (rc < 0) { |
3136 | IPW_ERROR("%s load failed: Reason %d\n", name, rc); | 3123 | IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc); |
3137 | return rc; | 3124 | return rc; |
3138 | } | 3125 | } |
3139 | 3126 | ||
3140 | header = (struct fw_header *)(*fw)->data; | 3127 | if ((*raw)->size < sizeof(*fw)) { |
3141 | if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) { | 3128 | IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size); |
3142 | IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", | 3129 | return -EINVAL; |
3143 | name, | 3130 | } |
3144 | IPW_FW_MAJOR(le32_to_cpu(header->version)), | 3131 | |
3145 | IPW_FW_MAJOR_VERSION); | 3132 | fw = (void *)(*raw)->data; |
3133 | |||
3134 | if ((*raw)->size < sizeof(*fw) + | ||
3135 | fw->boot_size + fw->ucode_size + fw->fw_size) { | ||
3136 | IPW_ERROR("%s is too small or corrupt (%zd)\n", | ||
3137 | name, (*raw)->size); | ||
3146 | return -EINVAL; | 3138 | return -EINVAL; |
3147 | } | 3139 | } |
3148 | 3140 | ||
3149 | IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", | 3141 | IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n", |
3150 | name, | 3142 | name, |
3151 | IPW_FW_MAJOR(le32_to_cpu(header->version)), | 3143 | le32_to_cpu(fw->ver) >> 16, |
3152 | IPW_FW_MINOR(le32_to_cpu(header->version)), | 3144 | le32_to_cpu(fw->ver) & 0xff, |
3153 | (*fw)->size - sizeof(struct fw_header)); | 3145 | (*raw)->size - sizeof(*fw)); |
3154 | return 0; | 3146 | return 0; |
3155 | } | 3147 | } |
3156 | 3148 | ||
@@ -3190,17 +3182,13 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, | |||
3190 | 3182 | ||
3191 | #ifdef CONFIG_PM | 3183 | #ifdef CONFIG_PM |
3192 | static int fw_loaded = 0; | 3184 | static int fw_loaded = 0; |
3193 | static const struct firmware *bootfw = NULL; | 3185 | static const struct firmware *raw = NULL; |
3194 | static const struct firmware *firmware = NULL; | ||
3195 | static const struct firmware *ucode = NULL; | ||
3196 | 3186 | ||
3197 | static void free_firmware(void) | 3187 | static void free_firmware(void) |
3198 | { | 3188 | { |
3199 | if (fw_loaded) { | 3189 | if (fw_loaded) { |
3200 | release_firmware(bootfw); | 3190 | release_firmware(raw); |
3201 | release_firmware(ucode); | 3191 | raw = NULL; |
3202 | release_firmware(firmware); | ||
3203 | bootfw = ucode = firmware = NULL; | ||
3204 | fw_loaded = 0; | 3192 | fw_loaded = 0; |
3205 | } | 3193 | } |
3206 | } | 3194 | } |
@@ -3211,32 +3199,46 @@ static void free_firmware(void) | |||
3211 | static int ipw_load(struct ipw_priv *priv) | 3199 | static int ipw_load(struct ipw_priv *priv) |
3212 | { | 3200 | { |
3213 | #ifndef CONFIG_PM | 3201 | #ifndef CONFIG_PM |
3214 | const struct firmware *bootfw = NULL; | 3202 | const struct firmware *raw = NULL; |
3215 | const struct firmware *firmware = NULL; | ||
3216 | const struct firmware *ucode = NULL; | ||
3217 | #endif | 3203 | #endif |
3218 | char *ucode_name; | 3204 | struct ipw_fw *fw; |
3219 | char *fw_name; | 3205 | u8 *boot_img, *ucode_img, *fw_img; |
3206 | u8 *name = NULL; | ||
3220 | int rc = 0, retries = 3; | 3207 | int rc = 0, retries = 3; |
3221 | 3208 | ||
3222 | switch (priv->ieee->iw_mode) { | 3209 | switch (priv->ieee->iw_mode) { |
3223 | case IW_MODE_ADHOC: | 3210 | case IW_MODE_ADHOC: |
3224 | ucode_name = IPW_FW_NAME("ibss_ucode"); | 3211 | name = "ipw2200-ibss.fw"; |
3225 | fw_name = IPW_FW_NAME("ibss"); | ||
3226 | break; | 3212 | break; |
3227 | #ifdef CONFIG_IPW2200_MONITOR | 3213 | #ifdef CONFIG_IPW2200_MONITOR |
3228 | case IW_MODE_MONITOR: | 3214 | case IW_MODE_MONITOR: |
3229 | ucode_name = IPW_FW_NAME("sniffer_ucode"); | 3215 | name = "ipw2200-sniffer.fw"; |
3230 | fw_name = IPW_FW_NAME("sniffer"); | ||
3231 | break; | 3216 | break; |
3232 | #endif | 3217 | #endif |
3233 | case IW_MODE_INFRA: | 3218 | case IW_MODE_INFRA: |
3234 | ucode_name = IPW_FW_NAME("bss_ucode"); | 3219 | name = "ipw2200-bss.fw"; |
3235 | fw_name = IPW_FW_NAME("bss"); | ||
3236 | break; | 3220 | break; |
3237 | default: | 3221 | } |
3222 | |||
3223 | if (!name) { | ||
3238 | rc = -EINVAL; | 3224 | rc = -EINVAL; |
3225 | goto error; | ||
3226 | } | ||
3227 | |||
3228 | #ifdef CONFIG_PM | ||
3229 | if (!fw_loaded) { | ||
3230 | #endif | ||
3231 | rc = ipw_get_fw(priv, &raw, name); | ||
3232 | if (rc < 0) | ||
3233 | goto error; | ||
3234 | #ifdef CONFIG_PM | ||
3239 | } | 3235 | } |
3236 | #endif | ||
3237 | |||
3238 | fw = (void *)raw->data; | ||
3239 | boot_img = &fw->data[0]; | ||
3240 | ucode_img = &fw->data[fw->boot_size]; | ||
3241 | fw_img = &fw->data[fw->boot_size + fw->ucode_size]; | ||
3240 | 3242 | ||
3241 | if (rc < 0) | 3243 | if (rc < 0) |
3242 | goto error; | 3244 | goto error; |
@@ -3269,18 +3271,8 @@ static int ipw_load(struct ipw_priv *priv) | |||
3269 | ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, | 3271 | ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, |
3270 | IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); | 3272 | IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); |
3271 | 3273 | ||
3272 | #ifdef CONFIG_PM | ||
3273 | if (!fw_loaded) { | ||
3274 | #endif | ||
3275 | rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); | ||
3276 | if (rc < 0) | ||
3277 | goto error; | ||
3278 | #ifdef CONFIG_PM | ||
3279 | } | ||
3280 | #endif | ||
3281 | /* DMA the initial boot firmware into the device */ | 3274 | /* DMA the initial boot firmware into the device */ |
3282 | rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), | 3275 | rc = ipw_load_firmware(priv, boot_img, fw->boot_size); |
3283 | bootfw->size - sizeof(struct fw_header)); | ||
3284 | if (rc < 0) { | 3276 | if (rc < 0) { |
3285 | IPW_ERROR("Unable to load boot firmware: %d\n", rc); | 3277 | IPW_ERROR("Unable to load boot firmware: %d\n", rc); |
3286 | goto error; | 3278 | goto error; |
@@ -3301,19 +3293,8 @@ static int ipw_load(struct ipw_priv *priv) | |||
3301 | /* ack fw init done interrupt */ | 3293 | /* ack fw init done interrupt */ |
3302 | ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); | 3294 | ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); |
3303 | 3295 | ||
3304 | #ifdef CONFIG_PM | ||
3305 | if (!fw_loaded) { | ||
3306 | #endif | ||
3307 | rc = ipw_get_fw(priv, &ucode, ucode_name); | ||
3308 | if (rc < 0) | ||
3309 | goto error; | ||
3310 | #ifdef CONFIG_PM | ||
3311 | } | ||
3312 | #endif | ||
3313 | |||
3314 | /* DMA the ucode into the device */ | 3296 | /* DMA the ucode into the device */ |
3315 | rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), | 3297 | rc = ipw_load_ucode(priv, ucode_img, fw->ucode_size); |
3316 | ucode->size - sizeof(struct fw_header)); | ||
3317 | if (rc < 0) { | 3298 | if (rc < 0) { |
3318 | IPW_ERROR("Unable to load ucode: %d\n", rc); | 3299 | IPW_ERROR("Unable to load ucode: %d\n", rc); |
3319 | goto error; | 3300 | goto error; |
@@ -3322,20 +3303,8 @@ static int ipw_load(struct ipw_priv *priv) | |||
3322 | /* stop nic */ | 3303 | /* stop nic */ |
3323 | ipw_stop_nic(priv); | 3304 | ipw_stop_nic(priv); |
3324 | 3305 | ||
3325 | #ifdef CONFIG_PM | ||
3326 | if (!fw_loaded) { | ||
3327 | #endif | ||
3328 | rc = ipw_get_fw(priv, &firmware, fw_name); | ||
3329 | if (rc < 0) | ||
3330 | goto error; | ||
3331 | #ifdef CONFIG_PM | ||
3332 | } | ||
3333 | #endif | ||
3334 | |||
3335 | /* DMA bss firmware into the device */ | 3306 | /* DMA bss firmware into the device */ |
3336 | rc = ipw_load_firmware(priv, firmware->data + | 3307 | rc = ipw_load_firmware(priv, fw_img, fw->fw_size); |
3337 | sizeof(struct fw_header), | ||
3338 | firmware->size - sizeof(struct fw_header)); | ||
3339 | if (rc < 0) { | 3308 | if (rc < 0) { |
3340 | IPW_ERROR("Unable to load firmware: %d\n", rc); | 3309 | IPW_ERROR("Unable to load firmware: %d\n", rc); |
3341 | goto error; | 3310 | goto error; |
@@ -3400,9 +3369,7 @@ static int ipw_load(struct ipw_priv *priv) | |||
3400 | ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); | 3369 | ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); |
3401 | 3370 | ||
3402 | #ifndef CONFIG_PM | 3371 | #ifndef CONFIG_PM |
3403 | release_firmware(bootfw); | 3372 | release_firmware(raw); |
3404 | release_firmware(ucode); | ||
3405 | release_firmware(firmware); | ||
3406 | #endif | 3373 | #endif |
3407 | return 0; | 3374 | return 0; |
3408 | 3375 | ||
@@ -3412,15 +3379,11 @@ static int ipw_load(struct ipw_priv *priv) | |||
3412 | priv->rxq = NULL; | 3379 | priv->rxq = NULL; |
3413 | } | 3380 | } |
3414 | ipw_tx_queue_free(priv); | 3381 | ipw_tx_queue_free(priv); |
3415 | if (bootfw) | 3382 | if (raw) |
3416 | release_firmware(bootfw); | 3383 | release_firmware(raw); |
3417 | if (ucode) | ||
3418 | release_firmware(ucode); | ||
3419 | if (firmware) | ||
3420 | release_firmware(firmware); | ||
3421 | #ifdef CONFIG_PM | 3384 | #ifdef CONFIG_PM |
3422 | fw_loaded = 0; | 3385 | fw_loaded = 0; |
3423 | bootfw = ucode = firmware = NULL; | 3386 | raw = NULL; |
3424 | #endif | 3387 | #endif |
3425 | 3388 | ||
3426 | return rc; | 3389 | return rc; |