提交 08b8aa09 编写于 作者: M Michal Kazior 提交者: Kalle Valo

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: NAvery Pennarun <apenwarr@gmail.com>
Signed-off-by: NMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: NKalle Valo <kvalo@qca.qualcomm.com>
上级 7147a131
...@@ -329,6 +329,33 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, ...@@ -329,6 +329,33 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册