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

Commit df50f756 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville
Browse files

brcmfmac: Take bus flowcontrol at credit mgmt into account.



On bus flow control (no more host bus resources to send packets
to device) the netif flow control was toggled, however credit
management should also take this status into account. Since there
are multiple sources handling this flow control necessary spinlocks
were added to protect flow control related data/states.

Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 51f6dd9d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -583,6 +583,7 @@ enum brcmf_netif_stop_reason {
 * @bssidx: index of bss associated with this interface.
 * @mac_addr: assigned mac address.
 * @netif_stop: bitmap indicates reason why netif queues are stopped.
 * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
 * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
 * @pend_8021x_wait: used for signalling change in count.
 */
@@ -598,6 +599,7 @@ struct brcmf_if {
	s32 bssidx;
	u8 mac_addr[ETH_ALEN];
	u8 netif_stop;
	spinlock_t netif_stop_lock;
	atomic_t pend_8021x_cnt;
	wait_queue_head_t pend_8021x_wait;
};
+8 −0
Original line number Diff line number Diff line
@@ -240,11 +240,15 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
void brcmf_txflowblock_if(struct brcmf_if *ifp,
			  enum brcmf_netif_stop_reason reason, bool state)
{
	unsigned long flags;

	if (!ifp)
		return;

	brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
		  ifp->bssidx, ifp->netif_stop, reason, state);

	spin_lock_irqsave(&ifp->netif_stop_lock, flags);
	if (state) {
		if (!ifp->netif_stop)
			netif_stop_queue(ifp->ndev);
@@ -254,6 +258,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
		if (!ifp->netif_stop)
			netif_wake_queue(ifp->ndev);
	}
	spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
}

void brcmf_txflowblock(struct device *dev, bool state)
@@ -264,6 +269,8 @@ void brcmf_txflowblock(struct device *dev, bool state)

	brcmf_dbg(TRACE, "Enter\n");

	brcmf_fws_bus_blocked(drvr, state);

	for (i = 0; i < BRCMF_MAX_IFS; i++)
		brcmf_txflowblock_if(drvr->iflist[i],
				     BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state);
@@ -779,6 +786,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
	ifp->bssidx = bssidx;

	init_waitqueue_head(&ifp->pend_8021x_wait);
	spin_lock_init(&ifp->netif_stop_lock);

	if (mac_addr != NULL)
		memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
+1 −1
Original line number Diff line number Diff line
@@ -2369,12 +2369,12 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
	} else {
		ret = 0;
	}
	spin_unlock_bh(&bus->txqlock);

	if (pktq_len(&bus->txq) >= TXHI) {
		bus->txoff = true;
		brcmf_txflowblock(bus->sdiodev->dev, true);
	}
	spin_unlock_bh(&bus->txqlock);

#ifdef DEBUG
	if (pktq_plen(&bus->txq, prec) > qcount[prec])
+19 −2
Original line number Diff line number Diff line
@@ -431,6 +431,7 @@ struct brcmf_fws_info {
	u32 fifo_credit_map;
	u32 fifo_delay_map;
	unsigned long borrow_defer_timestamp;
	bool bus_flow_blocked;
};

/*
@@ -1833,6 +1834,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)

	brcmf_fws_lock(drvr, flags);
	if (skcb->mac->suppressed ||
	    fws->bus_flow_blocked ||
	    brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
	    brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) ||
	    (!multicast &&
@@ -1905,7 +1907,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)

	brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
	brcmf_fws_lock(fws->drvr, flags);
	for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) {
	for (fifo = NL80211_NUM_ACS; fifo >= 0 && !fws->bus_flow_blocked;
	     fifo--) {
		brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
			  fws->fifo_credit[fifo]);
		for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
@@ -1915,9 +1918,12 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
			if (brcmf_skbcb(skb)->if_flags &
			    BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
				credit++;
			if (fws->bus_flow_blocked)
				break;
		}
		if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
		    (credit == fws->fifo_credit[fifo])) {
		    (credit == fws->fifo_credit[fifo]) &&
		    (!fws->bus_flow_blocked)) {
			fws->fifo_credit[fifo] -= credit;
			while (brcmf_fws_borrow_credit(fws) == 0) {
				skb = brcmf_fws_deq(fws, fifo);
@@ -1929,6 +1935,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
					brcmf_fws_return_credits(fws, fifo, 1);
					break;
				}
				if (fws->bus_flow_blocked)
					break;
			}
		} else {
			fws->fifo_credit[fifo] -= credit;
@@ -2060,3 +2068,12 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
	}
	brcmf_fws_unlock(fws->drvr, flags);
}

void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
{
	struct brcmf_fws_info *fws = drvr->fws;

	fws->bus_flow_blocked = flow_blocked;
	if (!flow_blocked)
		brcmf_fws_schedule_deq(fws);
}
+1 −0
Original line number Diff line number Diff line
@@ -29,5 +29,6 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp);
void brcmf_fws_add_interface(struct brcmf_if *ifp);
void brcmf_fws_del_interface(struct brcmf_if *ifp);
void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);

#endif /* FWSIGNAL_H_ */
Loading