ath10k: abort incomplete scatter-gather pci tx properly
This prevents leaving incomplete scatter-gather transfer on CE rings which can lead firmware to crash. Reported-By: Avery Pennarun <apenwarr@gmail.com> Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
7147a13135
commit
08b8aa0931
|
@ -329,6 +329,33 @@ exit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe)
|
||||||
|
{
|
||||||
|
struct ath10k *ar = pipe->ar;
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
struct ath10k_ce_ring *src_ring = pipe->src_ring;
|
||||||
|
u32 ctrl_addr = pipe->ctrl_addr;
|
||||||
|
|
||||||
|
lockdep_assert_held(&ar_pci->ce_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function must be called only if there is an incomplete
|
||||||
|
* scatter-gather transfer (before index register is updated)
|
||||||
|
* that needs to be cleaned up.
|
||||||
|
*/
|
||||||
|
if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(src_ring->write_index ==
|
||||||
|
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
src_ring->write_index--;
|
||||||
|
src_ring->write_index &= src_ring->nentries_mask;
|
||||||
|
|
||||||
|
src_ring->per_transfer_context[src_ring->write_index] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||||
void *per_transfer_context,
|
void *per_transfer_context,
|
||||||
u32 buffer,
|
u32 buffer,
|
||||||
|
|
|
@ -160,6 +160,8 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||||
unsigned int transfer_id,
|
unsigned int transfer_id,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
|
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
|
||||||
|
|
||||||
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||||
int disable_interrupts);
|
int disable_interrupts);
|
||||||
|
|
|
@ -765,7 +765,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||||
unsigned int nentries_mask;
|
unsigned int nentries_mask;
|
||||||
unsigned int sw_index;
|
unsigned int sw_index;
|
||||||
unsigned int write_index;
|
unsigned int write_index;
|
||||||
int err, i;
|
int err, i = 0;
|
||||||
|
|
||||||
spin_lock_bh(&ar_pci->ce_lock);
|
spin_lock_bh(&ar_pci->ce_lock);
|
||||||
|
|
||||||
|
@ -776,7 +776,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||||
if (unlikely(CE_RING_DELTA(nentries_mask,
|
if (unlikely(CE_RING_DELTA(nentries_mask,
|
||||||
write_index, sw_index - 1) < n_items)) {
|
write_index, sw_index - 1) < n_items)) {
|
||||||
err = -ENOBUFS;
|
err = -ENOBUFS;
|
||||||
goto unlock;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_items - 1; i++) {
|
for (i = 0; i < n_items - 1; i++) {
|
||||||
|
@ -793,7 +793,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||||
items[i].transfer_id,
|
items[i].transfer_id,
|
||||||
CE_SEND_FLAG_GATHER);
|
CE_SEND_FLAG_GATHER);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `i` is equal to `n_items -1` after for() */
|
/* `i` is equal to `n_items -1` after for() */
|
||||||
|
@ -811,10 +811,15 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||||
items[i].transfer_id,
|
items[i].transfer_id,
|
||||||
0);
|
0);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto err;
|
||||||
|
|
||||||
|
spin_unlock_bh(&ar_pci->ce_lock);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
for (; i > 0; i--)
|
||||||
|
__ath10k_ce_send_revert(ce_pipe);
|
||||||
|
|
||||||
err = 0;
|
|
||||||
unlock:
|
|
||||||
spin_unlock_bh(&ar_pci->ce_lock);
|
spin_unlock_bh(&ar_pci->ce_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue