brcmfmac: use irq safe spinlock in brcmf_sdbrcm_txdata()
authorArend van Spriel <arend@broadcom.com>
Sat, 10 Aug 2013 10:27:19 +0000 (12:27 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 15 Aug 2013 20:07:51 +0000 (16:07 -0400)
Firmware-signalling needs transmit to firmware to be atomic and
uses a spinlock with irq disabled. Therefor, brcmf_sdbrcm_txdata()
should not use spin_unlock_bh() as it would enable the interrupts.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c

index 080395f49fa5922400419d821e1fda4fcc1b460e..9249b6d4206613e35be75e4b68fafce628e61aa5 100644 (file)
@@ -36,7 +36,11 @@ struct brcmf_bus_dcmd {
  *
  * @init: prepare for communication with dongle.
  * @stop: clear pending frames, disable data flow.
- * @txdata: send a data frame to the dongle (callee disposes skb).
+ * @txdata: send a data frame to the dongle. When the data
+ *     has been transferred, the common driver must be
+ *     notified using brcmf_txcomplete(). The common
+ *     driver calls this function with interrupts
+ *     disabled.
  * @txctl: transmit a control request message to dongle.
  * @rxctl: receive a control response message from dongle.
  * @gettxq: obtain a reference of bus transmit queue (optional).
index 264111968320e19950880bc910bc90818169577d..5cbce1dff0931fe81e1ef54832c4de9d8d66be6a 100644 (file)
@@ -2276,6 +2276,7 @@ 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;
+       ulong flags;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -2293,7 +2294,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        bus->sdcnt.fcqueued++;
 
        /* Priority based enq */
-       spin_lock_bh(&bus->txqlock);
+       spin_lock_irqsave(&bus->txqlock, flags);
        if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
                skb_pull(pkt, SDPCM_HDRLEN);
                brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
@@ -2307,7 +2308,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
                bus->txoff = true;
                brcmf_txflowblock(bus->sdiodev->dev, true);
        }
-       spin_unlock_bh(&bus->txqlock);
+       spin_unlock_irqrestore(&bus->txqlock, flags);
 
 #ifdef DEBUG
        if (pktq_plen(&bus->txq, prec) > qcount[prec])