aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-12-19 17:00:59 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-21 15:06:10 -0500
commit106671369e6d046c0b3e1e72b18ad6dd9cb298b0 (patch)
tree0f1f4be9f1f7b39e014443f96cc1d08efff1ea35 /drivers
parent3ac44670ad0fca8b6c43b3e4d8494c67c419f494 (diff)
iwlagn: fix (remove) use of PAGE_SIZE
The ICT code erroneously uses PAGE_SIZE. The bug is that PAGE_SIZE isn't necessarily 4096, so on such platforms this code will not work correctly as we'll try to attempt to read an index in the table that the device never wrote, it always has 4096-byte pages. Additionally, the manual alignment code here is unnecessary -- Documentation/DMA-API-HOWTO.txt states: The cpu return address and the DMA bus master address are both guaranteed to be aligned to the smallest PAGE_SIZE order which is greater than or equal to the requested size. This invariant exists (for example) to guarantee that if you allocate a chunk which is smaller than or equal to 64 kilobytes, the extent of the buffer you receive will not cross a 64K boundary. Just use appropriate new constants and get rid of the alignment code. Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c73
2 files changed, 31 insertions, 44 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index 63a2eb1a71f3..f6debf91d7b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -219,9 +219,7 @@ struct iwl_trans_pcie {
219 219
220 /* INT ICT Table */ 220 /* INT ICT Table */
221 __le32 *ict_tbl; 221 __le32 *ict_tbl;
222 void *ict_tbl_vir;
223 dma_addr_t ict_tbl_dma; 222 dma_addr_t ict_tbl_dma;
224 dma_addr_t aligned_ict_tbl_dma;
225 int ict_index; 223 int ict_index;
226 u32 inta; 224 u32 inta;
227 bool use_ict; 225 bool use_ict;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 06d5698cd03e..752493f00406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -1151,7 +1151,11 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
1151 * ICT functions 1151 * ICT functions
1152 * 1152 *
1153 ******************************************************************************/ 1153 ******************************************************************************/
1154#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) 1154
1155/* a device (PCI-E) page is 4096 bytes long */
1156#define ICT_SHIFT 12
1157#define ICT_SIZE (1 << ICT_SHIFT)
1158#define ICT_COUNT (ICT_SIZE / sizeof(u32))
1155 1159
1156/* Free dram table */ 1160/* Free dram table */
1157void iwl_free_isr_ict(struct iwl_trans *trans) 1161void iwl_free_isr_ict(struct iwl_trans *trans)
@@ -1159,21 +1163,19 @@ void iwl_free_isr_ict(struct iwl_trans *trans)
1159 struct iwl_trans_pcie *trans_pcie = 1163 struct iwl_trans_pcie *trans_pcie =
1160 IWL_TRANS_GET_PCIE_TRANS(trans); 1164 IWL_TRANS_GET_PCIE_TRANS(trans);
1161 1165
1162 if (trans_pcie->ict_tbl_vir) { 1166 if (trans_pcie->ict_tbl) {
1163 dma_free_coherent(bus(trans)->dev, 1167 dma_free_coherent(bus(trans)->dev, ICT_SIZE,
1164 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 1168 trans_pcie->ict_tbl,
1165 trans_pcie->ict_tbl_vir,
1166 trans_pcie->ict_tbl_dma); 1169 trans_pcie->ict_tbl_dma);
1167 trans_pcie->ict_tbl_vir = NULL; 1170 trans_pcie->ict_tbl = NULL;
1168 memset(&trans_pcie->ict_tbl_dma, 0, 1171 trans_pcie->ict_tbl_dma = 0;
1169 sizeof(trans_pcie->ict_tbl_dma));
1170 memset(&trans_pcie->aligned_ict_tbl_dma, 0,
1171 sizeof(trans_pcie->aligned_ict_tbl_dma));
1172 } 1172 }
1173} 1173}
1174 1174
1175 1175
1176/* allocate dram shared table it is a PAGE_SIZE aligned 1176/*
1177 * allocate dram shared table, it is an aligned memory
1178 * block of ICT_SIZE.
1177 * also reset all data related to ICT table interrupt. 1179 * also reset all data related to ICT table interrupt.
1178 */ 1180 */
1179int iwl_alloc_isr_ict(struct iwl_trans *trans) 1181int iwl_alloc_isr_ict(struct iwl_trans *trans)
@@ -1181,36 +1183,26 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans)
1181 struct iwl_trans_pcie *trans_pcie = 1183 struct iwl_trans_pcie *trans_pcie =
1182 IWL_TRANS_GET_PCIE_TRANS(trans); 1184 IWL_TRANS_GET_PCIE_TRANS(trans);
1183 1185
1184 /* allocate shrared data table */ 1186 trans_pcie->ict_tbl =
1185 trans_pcie->ict_tbl_vir = 1187 dma_alloc_coherent(bus(trans)->dev, ICT_SIZE,
1186 dma_alloc_coherent(bus(trans)->dev, 1188 &trans_pcie->ict_tbl_dma,
1187 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, 1189 GFP_KERNEL);
1188 &trans_pcie->ict_tbl_dma, GFP_KERNEL); 1190 if (!trans_pcie->ict_tbl)
1189 if (!trans_pcie->ict_tbl_vir)
1190 return -ENOMEM; 1191 return -ENOMEM;
1191 1192
1192 /* align table to PAGE_SIZE boundary */ 1193 /* just an API sanity check ... it is guaranteed to be aligned */
1193 trans_pcie->aligned_ict_tbl_dma = 1194 if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
1194 ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); 1195 iwl_free_isr_ict(trans);
1195 1196 return -EINVAL;
1196 IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", 1197 }
1197 (unsigned long long)trans_pcie->ict_tbl_dma,
1198 (unsigned long long)trans_pcie->aligned_ict_tbl_dma,
1199 (int)(trans_pcie->aligned_ict_tbl_dma -
1200 trans_pcie->ict_tbl_dma));
1201 1198
1202 trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + 1199 IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
1203 (trans_pcie->aligned_ict_tbl_dma - 1200 (unsigned long long)trans_pcie->ict_tbl_dma);
1204 trans_pcie->ict_tbl_dma);
1205 1201
1206 IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", 1202 IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
1207 trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir,
1208 (int)(trans_pcie->aligned_ict_tbl_dma -
1209 trans_pcie->ict_tbl_dma));
1210 1203
1211 /* reset table and index to all 0 */ 1204 /* reset table and index to all 0 */
1212 memset(trans_pcie->ict_tbl_vir, 0, 1205 memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
1213 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
1214 trans_pcie->ict_index = 0; 1206 trans_pcie->ict_index = 0;
1215 1207
1216 /* add periodic RX interrupt */ 1208 /* add periodic RX interrupt */
@@ -1228,23 +1220,20 @@ int iwl_reset_ict(struct iwl_trans *trans)
1228 struct iwl_trans_pcie *trans_pcie = 1220 struct iwl_trans_pcie *trans_pcie =
1229 IWL_TRANS_GET_PCIE_TRANS(trans); 1221 IWL_TRANS_GET_PCIE_TRANS(trans);
1230 1222
1231 if (!trans_pcie->ict_tbl_vir) 1223 if (!trans_pcie->ict_tbl)
1232 return 0; 1224 return 0;
1233 1225
1234 spin_lock_irqsave(&trans->shrd->lock, flags); 1226 spin_lock_irqsave(&trans->shrd->lock, flags);
1235 iwl_disable_interrupts(trans); 1227 iwl_disable_interrupts(trans);
1236 1228
1237 memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); 1229 memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
1238 1230
1239 val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; 1231 val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;
1240 1232
1241 val |= CSR_DRAM_INT_TBL_ENABLE; 1233 val |= CSR_DRAM_INT_TBL_ENABLE;
1242 val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; 1234 val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
1243 1235
1244 IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " 1236 IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);
1245 "aligned dma address %Lx\n",
1246 val,
1247 (unsigned long long)trans_pcie->aligned_ict_tbl_dma);
1248 1237
1249 iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); 1238 iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val);
1250 trans_pcie->use_ict = true; 1239 trans_pcie->use_ict = true;