Skip to content

Commit d23623f

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 da750ac commit d23623f

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
@@ -371,6 +371,7 @@ struct brcmf_pcie_shared_info {
371371
void *ringupd;
372372
dma_addr_t ringupd_dmahandle;
373373
u8 version;
374+
bool mb_via_ctl;
374375
};
375376

376377
struct brcmf_pcie_core_info {
@@ -822,6 +823,19 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
822823
u32 i;
823824

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

@@ -849,8 +863,29 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
849863
return 0;
850864
}
851865

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

853-
static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
888+
static void brcmf_pcie_poll_mb_data(struct brcmf_pciedev_info *devinfo)
854889
{
855890
struct brcmf_pcie_shared_info *shared;
856891
u32 addr;
@@ -865,23 +900,16 @@ static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
865900

866901
brcmf_pcie_write_tcm32(devinfo, addr, 0);
867902

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

887915

@@ -1011,7 +1039,7 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
10111039
brcmf_pcie_write_reg32(devinfo, devinfo->reginfo->mailboxint,
10121040
status);
10131041
if (status & devinfo->reginfo->int_fn0)
1014-
brcmf_pcie_handle_mb_data(devinfo);
1042+
brcmf_pcie_poll_mb_data(devinfo);
10151043
}
10161044
if (devinfo->have_msi || status & devinfo->reginfo->int_d2h_db) {
10171045
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
@@ -1656,6 +1684,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
16561684
.get_blob = brcmf_pcie_get_blob,
16571685
.reset = brcmf_pcie_reset,
16581686
.debugfs_create = brcmf_pcie_debugfs_create,
1687+
.d2h_mb_rx = brcmf_pcie_d2h_mb_rx,
16591688
};
16601689

16611690

@@ -1746,6 +1775,10 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
17461775
shared->flags3 = brcmf_pcie_read_tcm32(devinfo, sharedram_addr +
17471776
BRCMF_SHARED_FLAGS3_OFFSET);
17481777

1778+
/* Check which mailbox mechanism to use */
1779+
if (!(shared->flags & BRCMF_PCIE_SHARED_USE_MAILBOX))
1780+
shared->mb_via_ctl = true;
1781+
17491782
/* Update host support flags */
17501783
host_cap = shared->version;
17511784
host_cap2 = 0;
@@ -2718,10 +2751,11 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
27182751
/* Check if device is still up and running, if so we are ready */
27192752
if (brcmf_pcie_read_reg32(devinfo, devinfo->reginfo->intmask) != 0) {
27202753
brcmf_dbg(PCIE, "Try to wakeup device....\n");
2754+
/* Set the device up, so we can write the MB data message in ring mode */
2755+
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
27212756
if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM))
27222757
goto cleanup;
27232758
brcmf_dbg(PCIE, "Hot resume, continue....\n");
2724-
devinfo->state = BRCMFMAC_PCIE_STATE_UP;
27252759
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
27262760
brcmf_bus_change_state(bus, BRCMF_BUS_UP);
27272761
brcmf_pcie_intr_enable(devinfo);
@@ -2731,6 +2765,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev)
27312765
}
27322766

27332767
cleanup:
2768+
devinfo->state = BRCMFMAC_PCIE_STATE_DOWN;
27342769
brcmf_chip_detach(devinfo->ci);
27352770
devinfo->ci = NULL;
27362771
pdev = devinfo->pdev;

0 commit comments

Comments
 (0)