Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1d3f812 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: fix spurious interrupts in 3-msi"

parents 6c1643de fd01373b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -207,6 +207,8 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
		seq_puts(s, "???\n");
	}
	seq_printf(s, "  desc_rdy_pol   = %d\n", sring->desc_rdy_pol);
	seq_printf(s, "  invalid_buff_id_cnt   = %d\n",
		   sring->invalid_buff_id_cnt);

	if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
		uint i;
+40 −25
Original line number Diff line number Diff line
@@ -285,21 +285,24 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
	u32 isr = wil_ioread32_and_clear(wil->csr +
	u32 isr;
	bool need_unmask = true;

	wil6210_mask_irq_rx(wil);

	isr = wil_ioread32_and_clear(wil->csr +
				     HOSTADDR(RGF_DMA_EP_RX_ICR) +
				     offsetof(struct RGF_ICR, ICR));
	bool need_unmask = true;

	trace_wil6210_irq_rx(isr);
	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);

	if (unlikely(!isr)) {
		wil_err_ratelimited(wil, "spurious IRQ: RX\n");
		wil6210_unmask_irq_rx(wil);
		return IRQ_NONE;
	}

	wil6210_mask_irq_rx(wil);

	/* RX_DONE and RX_HTRSH interrupts are the same if interrupt
	 * moderation is not used. Interrupt moderation may cause RX
	 * buffer overflow while RX_DONE is delayed. The required
@@ -344,21 +347,24 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
	u32 isr = wil_ioread32_and_clear(wil->csr +
	u32 isr;
	bool need_unmask = true;

	wil6210_mask_irq_rx_edma(wil);

	isr = wil_ioread32_and_clear(wil->csr +
				     HOSTADDR(RGF_INT_GEN_RX_ICR) +
				     offsetof(struct RGF_ICR, ICR));
	bool need_unmask = true;

	trace_wil6210_irq_rx(isr);
	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);

	if (unlikely(!isr)) {
		wil_err(wil, "spurious IRQ: RX\n");
		wil6210_unmask_irq_rx_edma(wil);
		return IRQ_NONE;
	}

	wil6210_mask_irq_rx_edma(wil);

	if (likely(isr & BIT_RX_STATUS_IRQ)) {
		wil_dbg_irq(wil, "RX status ring\n");
		isr &= ~BIT_RX_STATUS_IRQ;
@@ -392,21 +398,24 @@ static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
	u32 isr = wil_ioread32_and_clear(wil->csr +
	u32 isr;
	bool need_unmask = true;

	wil6210_mask_irq_tx_edma(wil);

	isr = wil_ioread32_and_clear(wil->csr +
				     HOSTADDR(RGF_INT_GEN_TX_ICR) +
				     offsetof(struct RGF_ICR, ICR));
	bool need_unmask = true;

	trace_wil6210_irq_tx(isr);
	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);

	if (unlikely(!isr)) {
		wil_err(wil, "spurious IRQ: TX\n");
		wil6210_unmask_irq_tx_edma(wil);
		return IRQ_NONE;
	}

	wil6210_mask_irq_tx_edma(wil);

	if (likely(isr & BIT_TX_STATUS_IRQ)) {
		wil_dbg_irq(wil, "TX status ring\n");
		isr &= ~BIT_TX_STATUS_IRQ;
@@ -435,21 +444,24 @@ static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
	u32 isr = wil_ioread32_and_clear(wil->csr +
	u32 isr;
	bool need_unmask = true;

	wil6210_mask_irq_tx(wil);

	isr = wil_ioread32_and_clear(wil->csr +
				     HOSTADDR(RGF_DMA_EP_TX_ICR) +
				     offsetof(struct RGF_ICR, ICR));
	bool need_unmask = true;

	trace_wil6210_irq_tx(isr);
	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);

	if (unlikely(!isr)) {
		wil_err_ratelimited(wil, "spurious IRQ: TX\n");
		wil6210_unmask_irq_tx(wil);
		return IRQ_NONE;
	}

	wil6210_mask_irq_tx(wil);

	if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) {
		wil_dbg_irq(wil, "TX done\n");
		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
@@ -521,7 +533,11 @@ static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
	u32 isr = wil_ioread32_and_clear(wil->csr +
	u32 isr;

	wil6210_mask_irq_misc(wil, false);

	isr = wil_ioread32_and_clear(wil->csr +
				     HOSTADDR(RGF_DMA_EP_MISC_ICR) +
				     offsetof(struct RGF_ICR, ICR));

@@ -530,11 +546,10 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)

	if (!isr) {
		wil_err(wil, "spurious IRQ: MISC\n");
		wil6210_unmask_irq_misc(wil, false);
		return IRQ_NONE;
	}

	wil6210_mask_irq_misc(wil, false);

	if (isr & ISR_MISC_FW_ERROR) {
		u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
		u32 ucode_assert_code =
+19 −3
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
	struct wil_memio io;
	void __iomem *a;
	bool need_copy = false;
	int rc;

	if (copy_from_user(&io, data, sizeof(io)))
		return -EFAULT;
@@ -72,6 +73,11 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
			io.op);
		return -EINVAL;
	}

	rc = wil_mem_access_lock(wil);
	if (rc)
		return rc;

	/* operation */
	switch (io.op & WIL_MMIO_OP_MASK) {
	case WIL_MMIO_READ:
@@ -86,9 +92,12 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
#endif
	default:
		wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
		wil_mem_access_unlock(wil);
		return -EINVAL;
	}

	wil_mem_access_unlock(wil);

	if (need_copy) {
		wil_dbg_ioctl(wil,
			      "IO done: addr(0x%08x) val(0x%08x) op(0x%08x)\n",
@@ -134,6 +143,12 @@ static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
	if (!block)
		return -ENOMEM;

	rc = wil_mem_access_lock(wil);
	if (rc) {
		kfree(block);
		return rc;
	}

	/* operation */
	switch (io.op & WIL_MMIO_OP_MASK) {
	case WIL_MMIO_READ:
@@ -142,7 +157,7 @@ static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
		if (copy_to_user((void __user *)(uintptr_t)io.block,
				 block, io.size)) {
			rc = -EFAULT;
			goto out_free;
			goto out_unlock;
		}
		break;
#if defined(CONFIG_WIL6210_WRITE_IOCTL)
@@ -150,7 +165,7 @@ static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
		if (copy_from_user(block, (void __user *)(uintptr_t)io.block,
				   io.size)) {
			rc = -EFAULT;
			goto out_free;
			goto out_unlock;
		}
		wil_memcpy_toio_32(a, block, io.size);
		wmb(); /* make sure write propagated to HW */
@@ -163,7 +178,8 @@ static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
		break;
	}

out_free:
out_unlock:
	wil_mem_access_unlock(wil);
	kfree(block);
	return rc;
}
+0 −5
Original line number Diff line number Diff line
@@ -1560,11 +1560,6 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
	if (wil->hw_version < HW_VER_TALYN_MB) {
		wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
		wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
	} else {
		wil_s(wil,
		      RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0);
		wil_w(wil, RGF_CAF_ICR_TALYN_MB +
		      offsetof(struct RGF_ICR, IMV), ~0);
	}
	/* clear PAL_UNIT_ICR (potential D0->D3 leftover)
	 * In Talyn-MB host cannot access this register due to
+39 −11
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048)
#define MAX_INVALID_BUFF_ID_RETRY (3)

static void wil_tx_desc_unmap_edma(struct device *dev,
				   union wil_tx_desc *desc,
@@ -302,7 +303,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
	struct list_head *free = &wil->rx_buff_mgmt.free;
	int i;

	wil->rx_buff_mgmt.buff_arr = kcalloc(size, sizeof(struct wil_rx_buff),
	wil->rx_buff_mgmt.buff_arr = kcalloc(size + 1,
					     sizeof(struct wil_rx_buff),
					     GFP_KERNEL);
	if (!wil->rx_buff_mgmt.buff_arr)
		return -ENOMEM;
@@ -311,14 +313,16 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
	INIT_LIST_HEAD(active);
	INIT_LIST_HEAD(free);

	/* Linkify the list */
	/* Linkify the list.
	 * buffer id 0 should not be used (marks invalid id).
	 */
	buff_arr = wil->rx_buff_mgmt.buff_arr;
	for (i = 0; i < size; i++) {
	for (i = 1; i <= size; i++) {
		list_add(&buff_arr[i].list, free);
		buff_arr[i].id = i;
	}

	wil->rx_buff_mgmt.size = size;
	wil->rx_buff_mgmt.size = size + 1;

	return 0;
}
@@ -882,26 +886,50 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,

	/* Extract the buffer ID from the status message */
	buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg));
	if (unlikely(!wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))) {

	while (!buff_id) {
		struct wil_rx_status_extended *s;
		int invalid_buff_id_retry = 0;

		wil_dbg_txrx(wil,
			     "buff_id is not updated yet by HW, (swhead 0x%x)\n",
			     sring->swhead);
		if (++invalid_buff_id_retry > MAX_INVALID_BUFF_ID_RETRY)
			break;

		/* Read the status message again */
		s = (struct wil_rx_status_extended *)
			(sring->va + (sring->elem_size * sring->swhead));
		*(struct wil_rx_status_extended *)msg = *s;
		buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg));
	}

	if (unlikely(!wil_val_in_range(buff_id, 1, wil->rx_buff_mgmt.size))) {
		wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n",
			buff_id, sring->swhead);
		wil_rx_status_reset_buff_id(sring);
		wil_sring_advance_swhead(sring);
		sring->invalid_buff_id_cnt++;
		goto again;
	}

	wil_sring_advance_swhead(sring);

	/* Extract the SKB from the rx_buff management array */
	skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
	wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
	if (!skb) {
		wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
		wil_rx_status_reset_buff_id(sring);
		/* Move the buffer from the active list to the free list */
		list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
		list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
			       &wil->rx_buff_mgmt.free);
		wil_sring_advance_swhead(sring);
		sring->invalid_buff_id_cnt++;
		goto again;
	}

	wil_rx_status_reset_buff_id(sring);
	wil_sring_advance_swhead(sring);

	memcpy(&pa, skb->cb, sizeof(pa));
	dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
	dmalen = le16_to_cpu(wil_rx_status_get_length(msg));
@@ -916,7 +944,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
			  sizeof(struct wil_rx_status_extended), false);

	/* Move the buffer from the active list to the free list */
	list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
	list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
		       &wil->rx_buff_mgmt.free);

	eop = wil_rx_status_get_eop(msg);
Loading