diff options
Diffstat (limited to 'drivers/net/wireless/ipw2x00/ipw2200.c')
-rw-r--r-- | drivers/net/wireless/ipw2x00/ipw2200.c | 120 |
1 files changed, 67 insertions, 53 deletions
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 6dcac73b4d29..f593fbbb4e52 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -2874,45 +2874,27 @@ static int ipw_fw_dma_add_command_block(struct ipw_priv *priv, | |||
2874 | return 0; | 2874 | return 0; |
2875 | } | 2875 | } |
2876 | 2876 | ||
2877 | static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, | 2877 | static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address, |
2878 | u32 src_phys, u32 dest_address, u32 length) | 2878 | int nr, u32 dest_address, u32 len) |
2879 | { | 2879 | { |
2880 | u32 bytes_left = length; | 2880 | int ret, i; |
2881 | u32 src_offset = 0; | 2881 | u32 size; |
2882 | u32 dest_offset = 0; | 2882 | |
2883 | int status = 0; | ||
2884 | IPW_DEBUG_FW(">> \n"); | 2883 | IPW_DEBUG_FW(">> \n"); |
2885 | IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n", | 2884 | IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n", |
2886 | src_phys, dest_address, length); | 2885 | nr, dest_address, len); |
2887 | while (bytes_left > CB_MAX_LENGTH) { | 2886 | |
2888 | status = ipw_fw_dma_add_command_block(priv, | 2887 | for (i = 0; i < nr; i++) { |
2889 | src_phys + src_offset, | 2888 | size = min_t(u32, len - i * CB_MAX_LENGTH, CB_MAX_LENGTH); |
2890 | dest_address + | 2889 | ret = ipw_fw_dma_add_command_block(priv, src_address[i], |
2891 | dest_offset, | 2890 | dest_address + |
2892 | CB_MAX_LENGTH, 0, 0); | 2891 | i * CB_MAX_LENGTH, size, |
2893 | if (status) { | 2892 | 0, 0); |
2893 | if (ret) { | ||
2894 | IPW_DEBUG_FW_INFO(": Failed\n"); | 2894 | IPW_DEBUG_FW_INFO(": Failed\n"); |
2895 | return -1; | 2895 | return -1; |
2896 | } else | 2896 | } else |
2897 | IPW_DEBUG_FW_INFO(": Added new cb\n"); | 2897 | IPW_DEBUG_FW_INFO(": Added new cb\n"); |
2898 | |||
2899 | src_offset += CB_MAX_LENGTH; | ||
2900 | dest_offset += CB_MAX_LENGTH; | ||
2901 | bytes_left -= CB_MAX_LENGTH; | ||
2902 | } | ||
2903 | |||
2904 | /* add the buffer tail */ | ||
2905 | if (bytes_left > 0) { | ||
2906 | status = | ||
2907 | ipw_fw_dma_add_command_block(priv, src_phys + src_offset, | ||
2908 | dest_address + dest_offset, | ||
2909 | bytes_left, 0, 0); | ||
2910 | if (status) { | ||
2911 | IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n"); | ||
2912 | return -1; | ||
2913 | } else | ||
2914 | IPW_DEBUG_FW_INFO | ||
2915 | (": Adding new cb - the buffer tail\n"); | ||
2916 | } | 2898 | } |
2917 | 2899 | ||
2918 | IPW_DEBUG_FW("<< \n"); | 2900 | IPW_DEBUG_FW("<< \n"); |
@@ -3160,59 +3142,91 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
3160 | 3142 | ||
3161 | static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) | 3143 | static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) |
3162 | { | 3144 | { |
3163 | int rc = -1; | 3145 | int ret = -1; |
3164 | int offset = 0; | 3146 | int offset = 0; |
3165 | struct fw_chunk *chunk; | 3147 | struct fw_chunk *chunk; |
3166 | dma_addr_t shared_phys; | 3148 | int total_nr = 0; |
3167 | u8 *shared_virt; | 3149 | int i; |
3150 | struct pci_pool *pool; | ||
3151 | u32 *virts[CB_NUMBER_OF_ELEMENTS_SMALL]; | ||
3152 | dma_addr_t phys[CB_NUMBER_OF_ELEMENTS_SMALL]; | ||
3168 | 3153 | ||
3169 | IPW_DEBUG_TRACE("<< : \n"); | 3154 | IPW_DEBUG_TRACE("<< : \n"); |
3170 | shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys); | ||
3171 | 3155 | ||
3172 | if (!shared_virt) | 3156 | pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0); |
3157 | if (!pool) { | ||
3158 | IPW_ERROR("pci_pool_create failed\n"); | ||
3173 | return -ENOMEM; | 3159 | return -ENOMEM; |
3174 | 3160 | } | |
3175 | memmove(shared_virt, data, len); | ||
3176 | 3161 | ||
3177 | /* Start the Dma */ | 3162 | /* Start the Dma */ |
3178 | rc = ipw_fw_dma_enable(priv); | 3163 | ret = ipw_fw_dma_enable(priv); |
3179 | 3164 | ||
3180 | /* the DMA is already ready this would be a bug. */ | 3165 | /* the DMA is already ready this would be a bug. */ |
3181 | BUG_ON(priv->sram_desc.last_cb_index > 0); | 3166 | BUG_ON(priv->sram_desc.last_cb_index > 0); |
3182 | 3167 | ||
3183 | do { | 3168 | do { |
3169 | u32 chunk_len; | ||
3170 | u8 *start; | ||
3171 | int size; | ||
3172 | int nr = 0; | ||
3173 | |||
3184 | chunk = (struct fw_chunk *)(data + offset); | 3174 | chunk = (struct fw_chunk *)(data + offset); |
3185 | offset += sizeof(struct fw_chunk); | 3175 | offset += sizeof(struct fw_chunk); |
3176 | chunk_len = le32_to_cpu(chunk->length); | ||
3177 | start = data + offset; | ||
3178 | |||
3179 | nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH; | ||
3180 | for (i = 0; i < nr; i++) { | ||
3181 | virts[total_nr] = pci_pool_alloc(pool, GFP_KERNEL, | ||
3182 | &phys[total_nr]); | ||
3183 | if (!virts[total_nr]) { | ||
3184 | ret = -ENOMEM; | ||
3185 | goto out; | ||
3186 | } | ||
3187 | size = min_t(u32, chunk_len - i * CB_MAX_LENGTH, | ||
3188 | CB_MAX_LENGTH); | ||
3189 | memcpy(virts[total_nr], start, size); | ||
3190 | start += size; | ||
3191 | total_nr++; | ||
3192 | /* We don't support fw chunk larger than 64*8K */ | ||
3193 | BUG_ON(total_nr > CB_NUMBER_OF_ELEMENTS_SMALL); | ||
3194 | } | ||
3195 | |||
3186 | /* build DMA packet and queue up for sending */ | 3196 | /* build DMA packet and queue up for sending */ |
3187 | /* dma to chunk->address, the chunk->length bytes from data + | 3197 | /* dma to chunk->address, the chunk->length bytes from data + |
3188 | * offeset*/ | 3198 | * offeset*/ |
3189 | /* Dma loading */ | 3199 | /* Dma loading */ |
3190 | rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, | 3200 | ret = ipw_fw_dma_add_buffer(priv, &phys[total_nr - nr], |
3191 | le32_to_cpu(chunk->address), | 3201 | nr, le32_to_cpu(chunk->address), |
3192 | le32_to_cpu(chunk->length)); | 3202 | chunk_len); |
3193 | if (rc) { | 3203 | if (ret) { |
3194 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); | 3204 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); |
3195 | goto out; | 3205 | goto out; |
3196 | } | 3206 | } |
3197 | 3207 | ||
3198 | offset += le32_to_cpu(chunk->length); | 3208 | offset += chunk_len; |
3199 | } while (offset < len); | 3209 | } while (offset < len); |
3200 | 3210 | ||
3201 | /* Run the DMA and wait for the answer */ | 3211 | /* Run the DMA and wait for the answer */ |
3202 | rc = ipw_fw_dma_kick(priv); | 3212 | ret = ipw_fw_dma_kick(priv); |
3203 | if (rc) { | 3213 | if (ret) { |
3204 | IPW_ERROR("dmaKick Failed\n"); | 3214 | IPW_ERROR("dmaKick Failed\n"); |
3205 | goto out; | 3215 | goto out; |
3206 | } | 3216 | } |
3207 | 3217 | ||
3208 | rc = ipw_fw_dma_wait(priv); | 3218 | ret = ipw_fw_dma_wait(priv); |
3209 | if (rc) { | 3219 | if (ret) { |
3210 | IPW_ERROR("dmaWaitSync Failed\n"); | 3220 | IPW_ERROR("dmaWaitSync Failed\n"); |
3211 | goto out; | 3221 | goto out; |
3212 | } | 3222 | } |
3213 | out: | 3223 | out: |
3214 | pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys); | 3224 | for (i = 0; i < total_nr; i++) |
3215 | return rc; | 3225 | pci_pool_free(pool, virts[i], phys[i]); |
3226 | |||
3227 | pci_pool_destroy(pool); | ||
3228 | |||
3229 | return ret; | ||
3216 | } | 3230 | } |
3217 | 3231 | ||
3218 | /* stop nic */ | 3232 | /* stop nic */ |