mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-20 00:57:21 +07:00
brcmfmac: make sdio suspend wait for threads to freeze
Borrowed the idea of the PM freezer to make sdio suspend wait for watchdog and DPC thread to freeze at a safe point in their thread routine. The suspend takes 20-25 msec. Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@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: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
c7cd5d27d8
commit
9982464379
@ -58,6 +58,14 @@
|
||||
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
|
||||
#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
|
||||
|
||||
struct brcmf_sdiod_freezer {
|
||||
atomic_t freezing;
|
||||
atomic_t thread_count;
|
||||
u32 frozen_count;
|
||||
wait_queue_head_t thread_freeze;
|
||||
struct completion resumed;
|
||||
};
|
||||
|
||||
static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
|
||||
module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
|
||||
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
|
||||
@ -895,6 +903,87 @@ static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
|
||||
sdiodev->txglomsz = brcmf_sdiod_txglomsz;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
sdiodev->freezer = kzalloc(sizeof(*sdiodev->freezer), GFP_KERNEL);
|
||||
if (!sdiodev->freezer)
|
||||
return -ENOMEM;
|
||||
atomic_set(&sdiodev->freezer->thread_count, 0);
|
||||
atomic_set(&sdiodev->freezer->freezing, 0);
|
||||
init_waitqueue_head(&sdiodev->freezer->thread_freeze);
|
||||
init_completion(&sdiodev->freezer->resumed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
if (sdiodev->freezer) {
|
||||
WARN_ON(atomic_read(&sdiodev->freezer->freezing));
|
||||
kfree(sdiodev->freezer);
|
||||
}
|
||||
}
|
||||
|
||||
static int brcmf_sdiod_freezer_on(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
atomic_t *expect = &sdiodev->freezer->thread_count;
|
||||
int res = 0;
|
||||
|
||||
sdiodev->freezer->frozen_count = 0;
|
||||
reinit_completion(&sdiodev->freezer->resumed);
|
||||
atomic_set(&sdiodev->freezer->freezing, 1);
|
||||
brcmf_sdio_trigger_dpc(sdiodev->bus);
|
||||
wait_event(sdiodev->freezer->thread_freeze,
|
||||
atomic_read(expect) == sdiodev->freezer->frozen_count);
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
res = brcmf_sdio_sleep(sdiodev->bus, true);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void brcmf_sdiod_freezer_off(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
brcmf_sdio_sleep(sdiodev->bus, false);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
atomic_set(&sdiodev->freezer->freezing, 0);
|
||||
complete_all(&sdiodev->freezer->resumed);
|
||||
}
|
||||
|
||||
bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
return atomic_read(&sdiodev->freezer->freezing);
|
||||
}
|
||||
|
||||
void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
if (!brcmf_sdiod_freezing(sdiodev))
|
||||
return;
|
||||
sdiodev->freezer->frozen_count++;
|
||||
wake_up(&sdiodev->freezer->thread_freeze);
|
||||
wait_for_completion(&sdiodev->freezer->resumed);
|
||||
}
|
||||
|
||||
void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
atomic_inc(&sdiodev->freezer->thread_count);
|
||||
}
|
||||
|
||||
void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
atomic_dec(&sdiodev->freezer->thread_count);
|
||||
}
|
||||
#else
|
||||
static int brcmf_sdiod_freezer_attach(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
if (sdiodev->bus) {
|
||||
@ -902,6 +991,8 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
|
||||
sdiodev->bus = NULL;
|
||||
}
|
||||
|
||||
brcmf_sdiod_freezer_detach(sdiodev);
|
||||
|
||||
/* Disable Function 2 */
|
||||
sdio_claim_host(sdiodev->func[2]);
|
||||
sdio_disable_func(sdiodev->func[2]);
|
||||
@ -973,6 +1064,10 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
*/
|
||||
brcmf_sdiod_sgtable_alloc(sdiodev);
|
||||
|
||||
ret = brcmf_sdiod_freezer_attach(sdiodev);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* try to attach to the target device */
|
||||
sdiodev->bus = brcmf_sdio_probe(sdiodev);
|
||||
if (!sdiodev->bus) {
|
||||
@ -1069,9 +1164,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
||||
#endif
|
||||
|
||||
brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
|
||||
sdiodev->sleeping = false;
|
||||
atomic_set(&sdiodev->suspend, false);
|
||||
init_waitqueue_head(&sdiodev->idle_wait);
|
||||
|
||||
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
|
||||
err = brcmf_sdiod_probe(sdiodev);
|
||||
@ -1133,24 +1225,22 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int brcmf_ops_sdio_suspend(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
struct brcmf_bus *bus_if;
|
||||
struct brcmf_sdio_dev *sdiodev;
|
||||
mmc_pm_flag_t sdio_flags;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
func = container_of(dev, struct sdio_func, dev);
|
||||
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
|
||||
if (func->num != SDIO_FUNC_1)
|
||||
return 0;
|
||||
|
||||
|
||||
bus_if = dev_get_drvdata(dev);
|
||||
sdiodev = bus_if->bus_priv.sdio;
|
||||
|
||||
/* wait for watchdog to go idle */
|
||||
if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping,
|
||||
msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) {
|
||||
brcmf_err("bus still active\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
/* disable watchdog */
|
||||
brcmf_sdiod_freezer_on(sdiodev);
|
||||
brcmf_sdio_wd_timer(sdiodev->bus, 0);
|
||||
atomic_set(&sdiodev->suspend, true);
|
||||
|
||||
if (sdiodev->wowl_enabled) {
|
||||
sdio_flags = MMC_PM_KEEP_POWER;
|
||||
@ -1168,12 +1258,13 @@ static int brcmf_ops_sdio_resume(struct device *dev)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)
|
||||
disable_irq_wake(sdiodev->pdata->oob_irq_nr);
|
||||
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
|
||||
atomic_set(&sdiodev->suspend, false);
|
||||
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
|
||||
if (func->num != SDIO_FUNC_2)
|
||||
return 0;
|
||||
|
||||
brcmf_sdiod_freezer_off(sdiodev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -515,6 +515,7 @@ struct brcmf_sdio {
|
||||
bool txoff; /* Transmit flow-controlled */
|
||||
struct brcmf_sdio_count sdcnt;
|
||||
bool sr_enabled; /* SaveRestore enabled */
|
||||
bool sleeping;
|
||||
|
||||
u8 tx_hdrlen; /* sdio bus header length for tx packet */
|
||||
bool txglom; /* host tx glomming enable flag */
|
||||
@ -1013,12 +1014,12 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
|
||||
|
||||
brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
|
||||
(sleep ? "SLEEP" : "WAKE"),
|
||||
(bus->sdiodev->sleeping ? "SLEEP" : "WAKE"));
|
||||
(bus->sleeping ? "SLEEP" : "WAKE"));
|
||||
|
||||
/* If SR is enabled control bus state with KSO */
|
||||
if (bus->sr_enabled) {
|
||||
/* Done if we're already in the requested state */
|
||||
if (sleep == bus->sdiodev->sleeping)
|
||||
if (sleep == bus->sleeping)
|
||||
goto end;
|
||||
|
||||
/* Going to sleep */
|
||||
@ -1065,9 +1066,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
|
||||
} else {
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
|
||||
}
|
||||
bus->sdiodev->sleeping = sleep;
|
||||
if (sleep)
|
||||
wake_up(&bus->sdiodev->idle_wait);
|
||||
bus->sleeping = sleep;
|
||||
brcmf_dbg(SDIO, "new state %s\n",
|
||||
(sleep ? "SLEEP" : "WAKE"));
|
||||
done:
|
||||
@ -2603,21 +2602,6 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int retry;
|
||||
|
||||
/* Wait for possible resume to complete */
|
||||
retry = 0;
|
||||
while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50))
|
||||
msleep(20);
|
||||
if (atomic_read(&sdiodev->suspend))
|
||||
return -EIO;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
||||
{
|
||||
u32 newstatus = 0;
|
||||
@ -2628,9 +2612,6 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
if (brcmf_sdio_pm_resume_wait(bus->sdiodev))
|
||||
return;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
|
||||
/* If waiting for HTAVAIL, check status */
|
||||
@ -2862,11 +2843,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
|
||||
qcount[prec] = pktq_plen(&bus->txq, prec);
|
||||
#endif
|
||||
|
||||
if (atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
atomic_inc(&bus->dpc_tskcnt);
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
|
||||
brcmf_sdio_trigger_dpc(bus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2964,11 +2941,8 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
|
||||
bus->ctrl_frame_buf = msg;
|
||||
bus->ctrl_frame_len = msglen;
|
||||
bus->ctrl_frame_stat = true;
|
||||
if (atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
atomic_inc(&bus->dpc_tskcnt);
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
|
||||
brcmf_sdio_trigger_dpc(bus);
|
||||
wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
|
||||
msecs_to_jiffies(CTL_DONE_TIMEOUT));
|
||||
|
||||
@ -3548,6 +3522,14 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
|
||||
{
|
||||
if (atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
atomic_inc(&bus->dpc_tskcnt);
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
}
|
||||
|
||||
void brcmf_sdio_isr(struct brcmf_sdio *bus)
|
||||
{
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
@ -3602,9 +3584,8 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
|
||||
SDIO_CCCR_INTx,
|
||||
NULL);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
intstatus =
|
||||
devpend & (INTR_STATUS_FUNC1 |
|
||||
INTR_STATUS_FUNC2);
|
||||
intstatus = devpend & (INTR_STATUS_FUNC1 |
|
||||
INTR_STATUS_FUNC2);
|
||||
}
|
||||
|
||||
/* If there is something, make like the ISR and
|
||||
@ -3667,6 +3648,11 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
|
||||
atomic_set(&bus->dpc_tskcnt, 0);
|
||||
brcmf_sdio_dpc(bus);
|
||||
}
|
||||
if (brcmf_sdiod_freezing(bus->sdiodev)) {
|
||||
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
|
||||
brcmf_sdiod_try_freeze(bus->sdiodev);
|
||||
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3944,13 +3930,19 @@ static int
|
||||
brcmf_sdio_watchdog_thread(void *data)
|
||||
{
|
||||
struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
|
||||
int wait;
|
||||
|
||||
allow_signal(SIGTERM);
|
||||
/* Run until signal received */
|
||||
brcmf_sdiod_freezer_count(bus->sdiodev);
|
||||
while (1) {
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
|
||||
brcmf_sdiod_freezer_uncount(bus->sdiodev);
|
||||
wait = wait_for_completion_interruptible(&bus->watchdog_wait);
|
||||
brcmf_sdiod_freezer_count(bus->sdiodev);
|
||||
brcmf_sdiod_try_freeze(bus->sdiodev);
|
||||
if (!wait) {
|
||||
brcmf_sdio_bus_watchdog(bus);
|
||||
/* Count the tick for reference */
|
||||
bus->sdcnt.tickcnt++;
|
||||
@ -4089,6 +4081,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
int ret;
|
||||
struct brcmf_sdio *bus;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
@ -4117,12 +4110,16 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
|
||||
}
|
||||
|
||||
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
|
||||
bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
|
||||
if (bus->brcmf_wq == NULL) {
|
||||
/* single-threaded workqueue */
|
||||
wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
|
||||
dev_name(&sdiodev->func[1]->dev));
|
||||
if (!wq) {
|
||||
brcmf_err("insufficient memory to create txworkqueue\n");
|
||||
goto fail;
|
||||
}
|
||||
brcmf_sdiod_freezer_count(sdiodev);
|
||||
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
|
||||
bus->brcmf_wq = wq;
|
||||
|
||||
/* attempt to attach to the dongle */
|
||||
if (!(brcmf_sdio_probe_attach(bus))) {
|
||||
@ -4143,7 +4140,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
/* Initialize watchdog thread */
|
||||
init_completion(&bus->watchdog_wait);
|
||||
bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,
|
||||
bus, "brcmf_watchdog");
|
||||
bus, "brcmf_wdog/%s",
|
||||
dev_name(&sdiodev->func[1]->dev));
|
||||
if (IS_ERR(bus->watchdog_tsk)) {
|
||||
pr_warn("brcmf_watchdog thread failed to start\n");
|
||||
bus->watchdog_tsk = NULL;
|
||||
@ -4303,3 +4301,15 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
|
||||
bus->save_ms = wdtick;
|
||||
}
|
||||
}
|
||||
|
||||
int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
ret = brcmf_sdio_bus_sleep(bus, sleep, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -175,15 +175,13 @@ struct brcmf_sdreg {
|
||||
};
|
||||
|
||||
struct brcmf_sdio;
|
||||
struct brcmf_sdiod_freezer;
|
||||
|
||||
struct brcmf_sdio_dev {
|
||||
struct sdio_func *func[SDIO_MAX_FUNCS];
|
||||
u8 num_funcs; /* Supported funcs on client */
|
||||
u32 sbwad; /* Save backplane window address */
|
||||
struct brcmf_sdio *bus;
|
||||
atomic_t suspend; /* suspend flag */
|
||||
bool sleeping;
|
||||
wait_queue_head_t idle_wait;
|
||||
struct device *dev;
|
||||
struct brcmf_bus *bus_if;
|
||||
struct brcmfmac_sdio_platform_data *pdata;
|
||||
@ -201,6 +199,7 @@ struct brcmf_sdio_dev {
|
||||
char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
|
||||
bool wowl_enabled;
|
||||
enum brcmf_sdiod_state state;
|
||||
struct brcmf_sdiod_freezer *freezer;
|
||||
};
|
||||
|
||||
/* sdio core registers */
|
||||
@ -343,6 +342,28 @@ int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
|
||||
|
||||
/* Issue an abort to the specified function */
|
||||
int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
|
||||
void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
|
||||
enum brcmf_sdiod_state state);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev);
|
||||
#else
|
||||
static inline bool brcmf_sdiod_freezing(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void brcmf_sdiod_try_freeze(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
}
|
||||
static inline void brcmf_sdiod_freezer_count(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
}
|
||||
static inline void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdio_remove(struct brcmf_sdio *bus);
|
||||
@ -350,8 +371,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus);
|
||||
|
||||
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
|
||||
void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
|
||||
|
||||
void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
|
||||
enum brcmf_sdiod_state state);
|
||||
int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
|
||||
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
|
||||
|
||||
#endif /* BRCMFMAC_SDIO_H */
|
||||
|
Loading…
Reference in New Issue
Block a user