Skip to content

Commit 5768c99

Browse files
committed
wifi: brcmfmac: Support exchanging power mailbox messages via commonring
Newer firmwares have switched from using the hardware mailbox to commonring messages for power mailbox data. Implement this, which makes D3 work on WiFi chipsets in Apple devices. This is only enabled on v6 or newer, iff BRCMF_PCIE_SHARED_USE_MAILBOX is not set in the flags. Signed-off-by: Hector Martin <[email protected]>
1 parent ab927fb commit 5768c99

1 file changed

Lines changed: 55 additions & 20 deletions

File tree

  • drivers/net/wireless/broadcom/brcm80211/brcmfmac

drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ struct brcmf_pcie_shared_info {
369369
void *ringupd;
370370
dma_addr_t ringupd_dmahandle;
371371
u8 version;
372+
bool mb_via_ctl;
372373
};
373374

374375
struct brcmf_pcie_core_info {
@@ -820,6 +821,19 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
820821
u32 i;
821822

822823
shared = &devinfo->shared;
824+
825+
if (shared->mb_via_ctl) {
826+
struct pci_dev *pdev = devinfo->pdev;
827+
struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev);
828+
int ret;
829+
830+
ret = brcmf_msgbuf_h2d_mb_write(bus->drvr, htod_mb_data);
831+
if (ret < 0)
832+
brcmf_err(bus, "Failed to send H2D mailbox data (%d)\n",
833+
ret);
834+
return ret;
835+
}
836+
823837
addr = shared->htod_mb_data_addr;
824838
cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
825839

@@ -847,8 +861,29 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
847861
return 0;
848862
}
849863

864+
static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo, u32 data)
865+
{
866+
brcmf_dbg(PCIE, "D2H_MB_DATA: 0x%04x\n", data);
867+
if (data & BRCMF_D2H_DEV_DS_ENTER_REQ) {
868+
brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP REQ\n");
869+
brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_DS_ACK);
870+
brcmf_dbg(PCIE, "D2H_MB_DATA: sent DEEP SLEEP ACK\n");
871+
}
872+
if (data & BRCMF_D2H_DEV_DS_EXIT_NOTE)
873+
brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n");
874+
if (data & BRCMF_D2H_DEV_D3_ACK) {
875+
brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n");
876+
devinfo->mbdata_completed = true;
877+
wake_up(&devinfo->mbdata_resp_wait);
878+
}
879+
if (data & BRCMF_D2H_DEV_FWHALT) {
880+
brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n");
881+
brcmf_fw_crashed(&devinfo->pdev->dev);
882+
}
883+
}
884+
850885

851-
static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
886+
static void brcmf_pcie_poll_mb_data(struct brcmf_pciedev_info *devinfo)
852887
{
853888
struct brcmf_pcie_shared_info *shared;
854889
u32 addr;
@@ -863,23 +898,16 @@ static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
863898

864899
brcmf_pcie_write_tcm32(devinfo, addr, 0);
865900

866-
brcmf_dbg(PCIE, "D2H_MB_DATA: 0x%04x\n", dtoh_mb_data);
867-
if (dtoh_mb_data & BRCMF_D2H_DEV_DS_ENTER_REQ) {
868-
brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP REQ\n");
869-
brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_DS_ACK);
870-
brcmf_dbg(PCIE, "D2H_MB_DATA: sent DEEP SLEEP ACK\n");
871-
}
872-
if (dtoh_mb_data & BRCMF_D2H_DEV_DS_EXIT_NOTE)
873-
brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n");
874-
if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) {
875-
brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n");
876-
devinfo->mbdata_completed = true;
877-
wake_up(&devinfo->mbdata_resp_wait);
878-
}
879-
if (dtoh_mb_data & BRCMF_D2H_DEV_FWHALT) {
880-
brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n");
881-
brcmf_fw_crashed(&devinfo->pdev->dev);
882-
}
901+
brcmf_pcie_handle_mb_data(devinfo, dtoh_mb_data);
902+
}
903+
904+
905+
static void brcmf_pcie_d2h_mb_rx(struct device *dev, u32 data)
906+
{
907+
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
908+
struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
909+
910+
brcmf_pcie_handle_mb_data(buspub->devinfo, data);
883911
}
884912

885913

@@ -1009,7 +1037,7 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
10091037
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint,
10101038
status);
10111039
if (status & devinfo->reginfo->int_fn0)
1012-
brcmf_pcie_handle_mb_data(devinfo);
1040+
brcmf_pcie_poll_mb_data(devinfo);
10131041
}
10141042
if (devinfo->have_msi || status & devinfo->reginfo->int_d2h_db) {
10151043
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
@@ -1654,6 +1682,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
16541682
.get_blob = brcmf_pcie_get_blob,
16551683
.reset = brcmf_pcie_reset,
16561684
.debugfs_create = brcmf_pcie_debugfs_create,
1685+
.d2h_mb_rx = brcmf_pcie_d2h_mb_rx,
16571686
};
16581687

16591688

@@ -1744,6 +1773,10 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
17441773
shared->flags3 = brcmf_pcie_read_tcm32(devinfo, sharedram_addr +
17451774
BRCMF_SHARED_FLAGS3_OFFSET);
17461775

1776+
/* Check which mailbox mechanism to use */
1777+
if (!(shared->flags & BRCMF_PCIE_SHARED_USE_MAILBOX))
1778+
shared->mb_via_ctl = true;
1779+
17471780
/* Update host support flags */
17481781
host_cap = shared->version;
17491782
host_cap2 = 0;
@@ -2702,10 +2735,11 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
27022735
/* Check if device is still up and running, if so we are ready */
27032736
if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->intmask) != 0) {
27042737
brcmf_dbg(PCIE, "Try to wakeup device....\n");
2738+
/* Set the device up, so we can write the MB data message in ring mode */
2739+
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
27052740
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
27062741
goto cleanup;
27072742
brcmf_dbg(PCIE, "Hot resume, continue....\n");
2708-
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
27092743
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
27102744
brcmf_bus_change_state(bus, BRCMF_BUS_UP);
27112745
brcmf_pcie_intr_enable(devinfo);
@@ -2715,6 +2749,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
27152749
}
27162750

27172751
cleanup:
2752+
devinfo->state = BRCMFMAC_PCIE_STATE_DOWN;
27182753
brcmf_chip_detach(devinfo->ci);
27192754
devinfo->ci = NULL;
27202755
pdev = devinfo->pdev;

0 commit comments

Comments
 (0)