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>
*
* @init: prepare for communication with dongle.
* @stop: clear pending frames, disable data flow.
*
* @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).
* @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).
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;
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;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(TRACE, "Enter\n");
bus->sdcnt.fcqueued++;
/* Priority based enq */
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);
if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
skb_pull(pkt, SDPCM_HDRLEN);
brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
bus->txoff = true;
brcmf_txflowblock(bus->sdiodev->dev, true);
}
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])
#ifdef DEBUG
if (pktq_plen(&bus->txq, prec) > qcount[prec])