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

Commit fccfe930 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville
Browse files

brcmfmac: simplify dpc handling using atomic operations



Instead of allocating an empty list item and queue that for
the dpc data worker to dequeue an atomic counter is used.

Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 1ab083a3
Loading
Loading
Loading
Loading
+12 −58
Original line number Diff line number Diff line
@@ -495,8 +495,7 @@ struct brcmf_sdio {

	struct workqueue_struct *brcmf_wq;
	struct work_struct datawork;
	struct list_head dpc_tsklst;
	spinlock_t dpc_tl_lock;
	atomic_t dpc_tskcnt;

	const struct firmware *firmware;
	u32 fw_ptr;
@@ -2061,23 +2060,6 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
	}
}

static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus)
{
	struct list_head *new_hd;
	unsigned long flags;

	if (in_interrupt())
		new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC);
	else
		new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL);
	if (new_hd == NULL)
		return;

	spin_lock_irqsave(&bus->dpc_tl_lock, flags);
	list_add_tail(new_hd, &bus->dpc_tsklst);
	spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
}

static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
{
	u8 idx;
@@ -2312,7 +2294,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
		   (!atomic_read(&bus->fcstate) &&
		    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
		    data_ok(bus)) || PKT_AVAILABLE()) {
		brcmf_sdbrcm_adddpctsk(bus);
		atomic_inc(&bus->dpc_tskcnt);
	}

	/* If we're done for now, turn off clock request. */
@@ -2342,7 +2324,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
	struct brcmf_sdio *bus = sdiodev->bus;
	unsigned long flags;

	brcmf_dbg(TRACE, "Enter\n");

@@ -2381,14 +2362,9 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
		qcount[prec] = pktq_plen(&bus->txq, prec);
#endif

	spin_lock_irqsave(&bus->dpc_tl_lock, flags);
	if (list_empty(&bus->dpc_tsklst)) {
		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);

		brcmf_sdbrcm_adddpctsk(bus);
	if (atomic_read(&bus->dpc_tskcnt) == 0) {
		atomic_inc(&bus->dpc_tskcnt);
		queue_work(bus->brcmf_wq, &bus->datawork);
	} else {
		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
	}

	return ret;
@@ -2525,7 +2501,6 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
	struct brcmf_sdio *bus = sdiodev->bus;
	unsigned long flags;

	brcmf_dbg(TRACE, "Enter\n");

@@ -2612,18 +2587,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
		} while (ret < 0 && retries++ < TXRETRIES);
	}

	spin_lock_irqsave(&bus->dpc_tl_lock, flags);
	if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
	    list_empty(&bus->dpc_tsklst)) {
		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);

	    atomic_read(&bus->dpc_tskcnt) == 0) {
		bus->activity = false;
		sdio_claim_host(bus->sdiodev->func[1]);
		brcmf_dbg(INFO, "idle\n");
		brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
		sdio_release_host(bus->sdiodev->func[1]);
	} else {
		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
	}

	if (ret)
@@ -3451,7 +3421,7 @@ void brcmf_sdbrcm_isr(void *arg)
	if (!bus->intr)
		brcmf_err("isr w/o interrupt configured!\n");

	brcmf_sdbrcm_adddpctsk(bus);
	atomic_inc(&bus->dpc_tskcnt);
	queue_work(bus->brcmf_wq, &bus->datawork);
}

@@ -3460,7 +3430,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
#ifdef DEBUG
	struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
#endif	/* DEBUG */
	unsigned long flags;

	brcmf_dbg(TIMER, "Enter\n");

@@ -3476,11 +3445,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
		if (!bus->intr ||
		    (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {

			spin_lock_irqsave(&bus->dpc_tl_lock, flags);
			if (list_empty(&bus->dpc_tsklst)) {
			if (atomic_read(&bus->dpc_tskcnt) == 0) {
				u8 devpend;
				spin_unlock_irqrestore(&bus->dpc_tl_lock,
						       flags);

				sdio_claim_host(bus->sdiodev->func[1]);
				devpend = brcmf_sdio_regrb(bus->sdiodev,
							   SDIO_CCCR_INTx,
@@ -3489,9 +3456,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
				intstatus =
				    devpend & (INTR_STATUS_FUNC1 |
					       INTR_STATUS_FUNC2);
			} else {
				spin_unlock_irqrestore(&bus->dpc_tl_lock,
						       flags);
			}

			/* If there is something, make like the ISR and
@@ -3500,7 +3464,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
				bus->sdcnt.pollcnt++;
				atomic_set(&bus->ipend, 1);

				brcmf_sdbrcm_adddpctsk(bus);
				atomic_inc(&bus->dpc_tskcnt);
				queue_work(bus->brcmf_wq, &bus->datawork);
			}
		}
@@ -3566,20 +3530,11 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
{
	struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
					      datawork);
	struct list_head *cur_hd, *tmp_hd;
	unsigned long flags;

	spin_lock_irqsave(&bus->dpc_tl_lock, flags);
	list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) {
		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);

	while (atomic_read(&bus->dpc_tskcnt)) {
		brcmf_sdbrcm_dpc(bus);

		spin_lock_irqsave(&bus->dpc_tl_lock, flags);
		list_del(cur_hd);
		kfree(cur_hd);
		atomic_dec(&bus->dpc_tskcnt);
	}
	spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
}

static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
@@ -3927,8 +3882,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
		bus->watchdog_tsk = NULL;
	}
	/* Initialize DPC thread */
	INIT_LIST_HEAD(&bus->dpc_tsklst);
	spin_lock_init(&bus->dpc_tl_lock);
	atomic_set(&bus->dpc_tskcnt, 0);

	/* Assign bus interface call back */
	bus->sdiodev->bus_if->dev = bus->sdiodev->dev;