diff options
| author | David S. Miller <davem@davemloft.net> | 2009-08-29 02:04:57 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-08-29 02:04:57 -0400 |
| commit | ab1f5e49f84e7072a0aade47cfeecef70be46c0f (patch) | |
| tree | 9e5762343bbccf6254462ff158dbf4eb8f840781 /drivers | |
| parent | 3161e453e496eb5643faad30fff5a5ab183da0fe (diff) | |
| parent | 11ebd1bf07fafde8d16562966c96b05b0d4ced9e (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'drivers')
| -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 */ |
