1
0
Fork 0

ARM: PL08x: don't manipulate txd->srcbus or txd->dstbus during LLI fill

Don't alter any txd->srcbus or txd->dstbus values while building the
LLI list.  This allows us to see the original dma_addr_t values passed
in via the prep_memcpy() method.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
wifi-calibration
Russell King - ARM Linux 2011-01-03 22:43:15 +00:00 committed by Dan Williams
parent 5f638b4f31
commit 542361f8e3
1 changed files with 83 additions and 76 deletions

View File

@ -481,38 +481,45 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
return retbits; return retbits;
} }
struct pl08x_lli_build_data {
struct pl08x_txd *txd;
struct pl08x_driver_data *pl08x;
struct pl08x_bus_data srcbus;
struct pl08x_bus_data dstbus;
size_t remainder;
};
/* /*
* Autoselect a master bus to use for the transfer * Autoselect a master bus to use for the transfer
* this prefers the destination bus if both available * this prefers the destination bus if both available
* if fixed address on one bus the other will be chosen * if fixed address on one bus the other will be chosen
*/ */
static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl)
struct pl08x_bus_data **sbus, u32 cctl)
{ {
if (!(cctl & PL080_CONTROL_DST_INCR)) { if (!(cctl & PL080_CONTROL_DST_INCR)) {
*mbus = src_bus; *mbus = &bd->srcbus;
*sbus = dst_bus; *sbus = &bd->dstbus;
} else if (!(cctl & PL080_CONTROL_SRC_INCR)) { } else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
*mbus = dst_bus; *mbus = &bd->dstbus;
*sbus = src_bus; *sbus = &bd->srcbus;
} else { } else {
if (dst_bus->buswidth == 4) { if (bd->dstbus.buswidth == 4) {
*mbus = dst_bus; *mbus = &bd->dstbus;
*sbus = src_bus; *sbus = &bd->srcbus;
} else if (src_bus->buswidth == 4) { } else if (bd->srcbus.buswidth == 4) {
*mbus = src_bus; *mbus = &bd->srcbus;
*sbus = dst_bus; *sbus = &bd->dstbus;
} else if (dst_bus->buswidth == 2) { } else if (bd->dstbus.buswidth == 2) {
*mbus = dst_bus; *mbus = &bd->dstbus;
*sbus = src_bus; *sbus = &bd->srcbus;
} else if (src_bus->buswidth == 2) { } else if (bd->srcbus.buswidth == 2) {
*mbus = src_bus; *mbus = &bd->srcbus;
*sbus = dst_bus; *sbus = &bd->dstbus;
} else { } else {
/* src_bus->buswidth == 1 */ /* bd->srcbus.buswidth == 1 */
*mbus = dst_bus; *mbus = &bd->dstbus;
*sbus = src_bus; *sbus = &bd->srcbus;
} }
} }
} }
@ -521,29 +528,29 @@ static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
* Fills in one LLI for a certain transfer descriptor * Fills in one LLI for a certain transfer descriptor
* and advance the counter * and advance the counter
*/ */
static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) int num_llis, int len, u32 cctl)
{ {
struct pl08x_lli *llis_va = txd->llis_va; struct pl08x_lli *llis_va = bd->txd->llis_va;
dma_addr_t llis_bus = txd->llis_bus; dma_addr_t llis_bus = bd->txd->llis_bus;
BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
llis_va[num_llis].cctl = cctl; llis_va[num_llis].cctl = cctl;
llis_va[num_llis].src = txd->srcbus.addr; llis_va[num_llis].src = bd->srcbus.addr;
llis_va[num_llis].dst = txd->dstbus.addr; llis_va[num_llis].dst = bd->dstbus.addr;
llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli);
if (pl08x->lli_buses & PL08X_AHB2) if (bd->pl08x->lli_buses & PL08X_AHB2)
llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; llis_va[num_llis].lli |= PL080_LLI_LM_AHB2;
if (cctl & PL080_CONTROL_SRC_INCR) if (cctl & PL080_CONTROL_SRC_INCR)
txd->srcbus.addr += len; bd->srcbus.addr += len;
if (cctl & PL080_CONTROL_DST_INCR) if (cctl & PL080_CONTROL_DST_INCR)
txd->dstbus.addr += len; bd->dstbus.addr += len;
BUG_ON(*remainder < len); BUG_ON(bd->remainder < len);
*remainder -= len; bd->remainder -= len;
} }
/* /*
@ -567,7 +574,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txd) struct pl08x_txd *txd)
{ {
struct pl08x_bus_data *mbus, *sbus; struct pl08x_bus_data *mbus, *sbus;
size_t remainder; struct pl08x_lli_build_data bd;
int num_llis = 0; int num_llis = 0;
u32 cctl; u32 cctl;
size_t max_bytes_per_lli; size_t max_bytes_per_lli;
@ -586,38 +593,43 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
/* Get the default CCTL */ /* Get the default CCTL */
cctl = txd->cctl; cctl = txd->cctl;
bd.txd = txd;
bd.pl08x = pl08x;
bd.srcbus.addr = txd->srcbus.addr;
bd.dstbus.addr = txd->dstbus.addr;
/* Find maximum width of the source bus */ /* Find maximum width of the source bus */
txd->srcbus.maxwidth = bd.srcbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
PL080_CONTROL_SWIDTH_SHIFT); PL080_CONTROL_SWIDTH_SHIFT);
/* Find maximum width of the destination bus */ /* Find maximum width of the destination bus */
txd->dstbus.maxwidth = bd.dstbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
PL080_CONTROL_DWIDTH_SHIFT); PL080_CONTROL_DWIDTH_SHIFT);
/* Set up the bus widths to the maximum */ /* Set up the bus widths to the maximum */
txd->srcbus.buswidth = txd->srcbus.maxwidth; bd.srcbus.buswidth = bd.srcbus.maxwidth;
txd->dstbus.buswidth = txd->dstbus.maxwidth; bd.dstbus.buswidth = bd.dstbus.maxwidth;
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s source bus is %d bytes wide, dest bus is %d bytes wide\n", "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
__func__, txd->srcbus.buswidth, txd->dstbus.buswidth); __func__, bd.srcbus.buswidth, bd.dstbus.buswidth);
/* /*
* Bytes transferred == tsize * MIN(buswidths), not max(buswidths) * Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
*/ */
max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) *
PL080_CONTROL_TRANSFER_SIZE_MASK; PL080_CONTROL_TRANSFER_SIZE_MASK;
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s max bytes per lli = %zu\n", "%s max bytes per lli = %zu\n",
__func__, max_bytes_per_lli); __func__, max_bytes_per_lli);
/* We need to count this down to zero */ /* We need to count this down to zero */
remainder = txd->len; bd.remainder = txd->len;
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s remainder = %zu\n", "%s remainder = %zu\n",
__func__, remainder); __func__, bd.remainder);
/* /*
* Choose bus to align to * Choose bus to align to
@ -625,22 +637,20 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
* - if fixed address on one bus chooses other * - if fixed address on one bus chooses other
* - modifies cctl to choose an appropriate master * - modifies cctl to choose an appropriate master
*/ */
pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
&mbus, &sbus, cctl);
if (txd->len < mbus->buswidth) { if (txd->len < mbus->buswidth) {
/* /*
* Less than a bus width available * Less than a bus width available
* - send as single bytes * - send as single bytes
*/ */
while (remainder) { while (bd.remainder) {
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s single byte LLIs for a transfer of " "%s single byte LLIs for a transfer of "
"less than a bus width (remain 0x%08x)\n", "less than a bus width (remain 0x%08x)\n",
__func__, remainder); __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1); cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
cctl, &remainder);
total_bytes++; total_bytes++;
} }
} else { } else {
@ -652,10 +662,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s adjustment lli for less than bus width " "%s adjustment lli for less than bus width "
"(remain 0x%08x)\n", "(remain 0x%08x)\n",
__func__, remainder); __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1); cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
cctl, &remainder);
total_bytes++; total_bytes++;
} }
@ -675,14 +684,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
* Make largest possible LLIs until less than one bus * Make largest possible LLIs until less than one bus
* width left * width left
*/ */
while (remainder > (mbus->buswidth - 1)) { while (bd.remainder > (mbus->buswidth - 1)) {
size_t lli_len, target_len, tsize, odd_bytes; size_t lli_len, target_len, tsize, odd_bytes;
/* /*
* If enough left try to send max possible, * If enough left try to send max possible,
* otherwise try to send the remainder * otherwise try to send the remainder
*/ */
target_len = min(remainder, max_bytes_per_lli); target_len = min(bd.remainder, max_bytes_per_lli);
/* /*
* Set bus lengths for incrementing buses to the * Set bus lengths for incrementing buses to the
@ -690,24 +699,24 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
* limiting on the target length calculated above. * limiting on the target length calculated above.
*/ */
if (cctl & PL080_CONTROL_SRC_INCR) if (cctl & PL080_CONTROL_SRC_INCR)
txd->srcbus.fill_bytes = bd.srcbus.fill_bytes =
pl08x_pre_boundary(txd->srcbus.addr, pl08x_pre_boundary(bd.srcbus.addr,
target_len); target_len);
else else
txd->srcbus.fill_bytes = target_len; bd.srcbus.fill_bytes = target_len;
if (cctl & PL080_CONTROL_DST_INCR) if (cctl & PL080_CONTROL_DST_INCR)
txd->dstbus.fill_bytes = bd.dstbus.fill_bytes =
pl08x_pre_boundary(txd->dstbus.addr, pl08x_pre_boundary(bd.dstbus.addr,
target_len); target_len);
else else
txd->dstbus.fill_bytes = target_len; bd.dstbus.fill_bytes = target_len;
/* Find the nearest */ /* Find the nearest */
lli_len = min(txd->srcbus.fill_bytes, lli_len = min(bd.srcbus.fill_bytes,
txd->dstbus.fill_bytes); bd.dstbus.fill_bytes);
BUG_ON(lli_len > remainder); BUG_ON(lli_len > bd.remainder);
if (lli_len <= 0) { if (lli_len <= 0) {
dev_err(&pl08x->adev->dev, dev_err(&pl08x->adev->dev,
@ -764,15 +773,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
} }
cctl = pl08x_cctl_bits(cctl, cctl = pl08x_cctl_bits(cctl,
txd->srcbus.buswidth, bd.srcbus.buswidth,
txd->dstbus.buswidth, bd.dstbus.buswidth,
tsize); tsize);
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n",
__func__, lli_len, remainder); __func__, lli_len, bd.remainder);
pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, pl08x_fill_lli_for_desc(&bd, num_llis++,
lli_len, cctl, &remainder); lli_len, cctl);
total_bytes += lli_len; total_bytes += lli_len;
} }
@ -784,14 +793,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
*/ */
int j; int j;
for (j = 0; (j < mbus->buswidth) for (j = 0; (j < mbus->buswidth)
&& (remainder); j++) { && (bd.remainder); j++) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1); cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s align with boundary, single byte (remain 0x%08zx)\n", "%s align with boundary, single byte (remain 0x%08zx)\n",
__func__, remainder); __func__, bd.remainder);
pl08x_fill_lli_for_desc(pl08x, txd, pl08x_fill_lli_for_desc(&bd,
num_llis++, 1, cctl, num_llis++, 1, cctl);
&remainder);
total_bytes++; total_bytes++;
} }
} }
@ -800,13 +808,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
/* /*
* Send any odd bytes * Send any odd bytes
*/ */
while (remainder) { while (bd.remainder) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1); cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev, dev_vdbg(&pl08x->adev->dev,
"%s align with boundary, single odd byte (remain %zu)\n", "%s align with boundary, single odd byte (remain %zu)\n",
__func__, remainder); __func__, bd.remainder);
pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
cctl, &remainder);
total_bytes++; total_bytes++;
} }
} }