Skip to content

Commit

Permalink
iwlagn: fix (remove) use of PAGE_SIZE
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Dec 21, 2011
1 parent 3ac4467 commit 1066713
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 44 deletions.
2 changes: 0 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,7 @@ struct iwl_trans_pcie {

/* INT ICT Table */
__le32 *ict_tbl;
void *ict_tbl_vir;
dma_addr_t ict_tbl_dma;
dma_addr_t aligned_ict_tbl_dma;
int ict_index;
u32 inta;
bool use_ict;
Expand Down
73 changes: 31 additions & 42 deletions drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1151,66 +1151,58 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
* ICT functions
*
******************************************************************************/
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))

/* a device (PCI-E) page is 4096 bytes long */
#define ICT_SHIFT 12
#define ICT_SIZE (1 << ICT_SHIFT)
#define ICT_COUNT (ICT_SIZE / sizeof(u32))

/* Free dram table */
void iwl_free_isr_ict(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);

if (trans_pcie->ict_tbl_vir) {
dma_free_coherent(bus(trans)->dev,
(sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
trans_pcie->ict_tbl_vir,
if (trans_pcie->ict_tbl) {
dma_free_coherent(bus(trans)->dev, ICT_SIZE,
trans_pcie->ict_tbl,
trans_pcie->ict_tbl_dma);
trans_pcie->ict_tbl_vir = NULL;
memset(&trans_pcie->ict_tbl_dma, 0,
sizeof(trans_pcie->ict_tbl_dma));
memset(&trans_pcie->aligned_ict_tbl_dma, 0,
sizeof(trans_pcie->aligned_ict_tbl_dma));
trans_pcie->ict_tbl = NULL;
trans_pcie->ict_tbl_dma = 0;
}
}


/* allocate dram shared table it is a PAGE_SIZE aligned
/*
* allocate dram shared table, it is an aligned memory
* block of ICT_SIZE.
* also reset all data related to ICT table interrupt.
*/
int iwl_alloc_isr_ict(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);

/* allocate shrared data table */
trans_pcie->ict_tbl_vir =
dma_alloc_coherent(bus(trans)->dev,
(sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
&trans_pcie->ict_tbl_dma, GFP_KERNEL);
if (!trans_pcie->ict_tbl_vir)
trans_pcie->ict_tbl =
dma_alloc_coherent(bus(trans)->dev, ICT_SIZE,
&trans_pcie->ict_tbl_dma,
GFP_KERNEL);
if (!trans_pcie->ict_tbl)
return -ENOMEM;

/* align table to PAGE_SIZE boundary */
trans_pcie->aligned_ict_tbl_dma =
ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE);

IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n",
(unsigned long long)trans_pcie->ict_tbl_dma,
(unsigned long long)trans_pcie->aligned_ict_tbl_dma,
(int)(trans_pcie->aligned_ict_tbl_dma -
trans_pcie->ict_tbl_dma));
/* just an API sanity check ... it is guaranteed to be aligned */
if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
iwl_free_isr_ict(trans);
return -EINVAL;
}

trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir +
(trans_pcie->aligned_ict_tbl_dma -
trans_pcie->ict_tbl_dma);
IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
(unsigned long long)trans_pcie->ict_tbl_dma);

IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n",
trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir,
(int)(trans_pcie->aligned_ict_tbl_dma -
trans_pcie->ict_tbl_dma));
IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);

/* reset table and index to all 0 */
memset(trans_pcie->ict_tbl_vir, 0,
(sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
trans_pcie->ict_index = 0;

/* add periodic RX interrupt */
Expand All @@ -1228,23 +1220,20 @@ int iwl_reset_ict(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie =
IWL_TRANS_GET_PCIE_TRANS(trans);

if (!trans_pcie->ict_tbl_vir)
if (!trans_pcie->ict_tbl)
return 0;

spin_lock_irqsave(&trans->shrd->lock, flags);
iwl_disable_interrupts(trans);

memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
memset(trans_pcie->ict_tbl, 0, ICT_SIZE);

val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT;
val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;

val |= CSR_DRAM_INT_TBL_ENABLE;
val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;

IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X "
"aligned dma address %Lx\n",
val,
(unsigned long long)trans_pcie->aligned_ict_tbl_dma);
IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);

iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val);
trans_pcie->use_ict = true;
Expand Down

0 comments on commit 1066713

Please sign in to comment.