Skip to content

Commit fe9ee51

Browse files
Maya Erezkvalo
authored andcommitted
wil6210: add support for PCIe D3hot in system suspend
In order to preserve the connection in suspend/resume flow, wil6210 host allows going to PCIe D3hot state in suspend, instead of performing a full wil6210 device reset. This requires the platform ability to initiate wakeup in case of RX data. To check that, a new platform API is added. In addition, add cfg80211 suspend/resume callbacks implementation. Signed-off-by: Maya Erez <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 5b49ee9 commit fe9ee51

File tree

11 files changed

+603
-49
lines changed

11 files changed

+603
-49
lines changed

drivers/net/wireless/ath/wil6210/cfg80211.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,42 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
16941694
return wil_ps_update(wil, ps_profile);
16951695
}
16961696

1697+
static int wil_cfg80211_suspend(struct wiphy *wiphy,
1698+
struct cfg80211_wowlan *wow)
1699+
{
1700+
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1701+
int rc;
1702+
1703+
/* Setting the wakeup trigger based on wow is TBD */
1704+
1705+
if (test_bit(wil_status_suspended, wil->status)) {
1706+
wil_dbg_pm(wil, "trying to suspend while suspended\n");
1707+
return 0;
1708+
}
1709+
1710+
rc = wil_can_suspend(wil, false);
1711+
if (rc)
1712+
goto out;
1713+
1714+
wil_dbg_pm(wil, "suspending\n");
1715+
1716+
wil_p2p_stop_discovery(wil);
1717+
1718+
wil_abort_scan(wil, true);
1719+
1720+
out:
1721+
return rc;
1722+
}
1723+
1724+
static int wil_cfg80211_resume(struct wiphy *wiphy)
1725+
{
1726+
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1727+
1728+
wil_dbg_pm(wil, "resuming\n");
1729+
1730+
return 0;
1731+
}
1732+
16971733
static const struct cfg80211_ops wil_cfg80211_ops = {
16981734
.add_virtual_intf = wil_cfg80211_add_iface,
16991735
.del_virtual_intf = wil_cfg80211_del_iface,
@@ -1725,6 +1761,8 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
17251761
.start_p2p_device = wil_cfg80211_start_p2p_device,
17261762
.stop_p2p_device = wil_cfg80211_stop_p2p_device,
17271763
.set_power_mgmt = wil_cfg80211_set_power_mgmt,
1764+
.suspend = wil_cfg80211_suspend,
1765+
.resume = wil_cfg80211_resume,
17281766
};
17291767

17301768
static void wil_wiphy_init(struct wiphy *wiphy)

drivers/net/wireless/ath/wil6210/debugfs.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
509509
void *buf;
510510
size_t ret;
511511

512+
if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
513+
test_bit(wil_status_suspended, wil_blob->wil->status))
514+
return 0;
515+
512516
if (pos < 0)
513517
return -EINVAL;
514518

@@ -1600,6 +1604,49 @@ static const struct file_operations fops_fw_version = {
16001604
.llseek = seq_lseek,
16011605
};
16021606

1607+
/*---------suspend_stats---------*/
1608+
static ssize_t wil_write_suspend_stats(struct file *file,
1609+
const char __user *buf,
1610+
size_t len, loff_t *ppos)
1611+
{
1612+
struct wil6210_priv *wil = file->private_data;
1613+
1614+
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
1615+
1616+
return len;
1617+
}
1618+
1619+
static ssize_t wil_read_suspend_stats(struct file *file,
1620+
char __user *user_buf,
1621+
size_t count, loff_t *ppos)
1622+
{
1623+
struct wil6210_priv *wil = file->private_data;
1624+
static char text[400];
1625+
int n;
1626+
1627+
n = snprintf(text, sizeof(text),
1628+
"Suspend statistics:\n"
1629+
"successful suspends:%ld failed suspends:%ld\n"
1630+
"successful resumes:%ld failed resumes:%ld\n"
1631+
"rejected by host:%ld rejected by device:%ld\n",
1632+
wil->suspend_stats.successful_suspends,
1633+
wil->suspend_stats.failed_suspends,
1634+
wil->suspend_stats.successful_resumes,
1635+
wil->suspend_stats.failed_resumes,
1636+
wil->suspend_stats.rejected_by_host,
1637+
wil->suspend_stats.rejected_by_device);
1638+
1639+
n = min_t(int, n, sizeof(text));
1640+
1641+
return simple_read_from_buffer(user_buf, count, ppos, text, n);
1642+
}
1643+
1644+
static const struct file_operations fops_suspend_stats = {
1645+
.read = wil_read_suspend_stats,
1646+
.write = wil_write_suspend_stats,
1647+
.open = simple_open,
1648+
};
1649+
16031650
/*----------------*/
16041651
static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
16051652
struct dentry *dbg)
@@ -1652,6 +1699,7 @@ static const struct {
16521699
{"led_blink_time", 0644, &fops_led_blink_time},
16531700
{"fw_capabilities", 0444, &fops_fw_capabilities},
16541701
{"fw_version", 0444, &fops_fw_version},
1702+
{"suspend_stats", 0644, &fops_suspend_stats},
16551703
};
16561704

16571705
static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -1698,6 +1746,7 @@ static const struct dbg_off dbg_wil_off[] = {
16981746
WIL_FIELD(discovery_mode, 0644, doff_u8),
16991747
WIL_FIELD(chip_revision, 0444, doff_u8),
17001748
WIL_FIELD(abft_len, 0644, doff_u8),
1749+
WIL_FIELD(wakeup_trigger, 0644, doff_u8),
17011750
{},
17021751
};
17031752

drivers/net/wireless/ath/wil6210/interrupt.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
467467

468468
wil6210_unmask_irq_pseudo(wil);
469469

470+
if (wil->suspend_resp_rcvd) {
471+
wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
472+
wil->suspend_resp_comp = true;
473+
wake_up_interruptible(&wil->wq);
474+
}
475+
470476
return IRQ_HANDLED;
471477
}
472478

drivers/net/wireless/ath/wil6210/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,9 @@ int wil_priv_init(struct wil6210_priv *wil)
576576

577577
wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;
578578

579+
wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
580+
WMI_WAKEUP_TRIGGER_BCAST;
581+
579582
return 0;
580583

581584
out_wmi_wq:
@@ -586,8 +589,10 @@ int wil_priv_init(struct wil6210_priv *wil)
586589

587590
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
588591
{
589-
if (wil->platform_ops.bus_request)
592+
if (wil->platform_ops.bus_request) {
593+
wil->bus_request_kbps = kbps;
590594
wil->platform_ops.bus_request(wil->platform_handle, kbps);
595+
}
591596
}
592597

593598
/**

drivers/net/wireless/ath/wil6210/pcie_bus.c

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
112112

113113
wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only);
114114

115-
pdev->msi_enabled = 0;
116-
117115
pci_set_master(pdev);
118116

119117
wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx");
@@ -259,7 +257,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
259257
}
260258

261259
rc = pci_enable_device(pdev);
262-
if (rc) {
260+
if (rc && pdev->msi_enabled == 0) {
263261
wil_err(wil,
264262
"pci_enable_device failed, retry with MSI only\n");
265263
/* Work around for platforms that can't allocate IRQ:
@@ -274,6 +272,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
274272
goto err_plat;
275273
}
276274
/* rollback to err_disable_pdev */
275+
pci_set_power_state(pdev, PCI_D0);
277276

278277
rc = pci_request_region(pdev, 0, WIL_NAME);
279278
if (rc) {
@@ -294,6 +293,15 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
294293
wil_set_capabilities(wil);
295294
wil6210_clear_irq(wil);
296295

296+
wil->keep_radio_on_during_sleep =
297+
wil->platform_ops.keep_radio_on_during_sleep &&
298+
wil->platform_ops.keep_radio_on_during_sleep(
299+
wil->platform_handle) &&
300+
test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
301+
302+
wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
303+
wil->keep_radio_on_during_sleep);
304+
297305
/* FW should raise IRQ when ready */
298306
rc = wil_if_pcie_enable(wil);
299307
if (rc) {
@@ -390,15 +398,16 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
390398
goto out;
391399

392400
rc = wil_suspend(wil, is_runtime);
393-
if (rc)
394-
goto out;
395-
396-
/* TODO: how do I bring card in low power state? */
397-
398-
/* disable bus mastering */
399-
pci_clear_master(pdev);
400-
/* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */
401+
if (!rc) {
402+
wil->suspend_stats.successful_suspends++;
401403

404+
/* If platform device supports keep_radio_on_during_sleep
405+
* it will control PCIe master
406+
*/
407+
if (!wil->keep_radio_on_during_sleep)
408+
/* disable bus mastering */
409+
pci_clear_master(pdev);
410+
}
402411
out:
403412
return rc;
404413
}
@@ -411,12 +420,21 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
411420

412421
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
413422

414-
/* allow master */
415-
pci_set_master(pdev);
416-
423+
/* If platform device supports keep_radio_on_during_sleep it will
424+
* control PCIe master
425+
*/
426+
if (!wil->keep_radio_on_during_sleep)
427+
/* allow master */
428+
pci_set_master(pdev);
417429
rc = wil_resume(wil, is_runtime);
418-
if (rc)
419-
pci_clear_master(pdev);
430+
if (rc) {
431+
wil_err(wil, "device failed to resume (%d)\n", rc);
432+
wil->suspend_stats.failed_resumes++;
433+
if (!wil->keep_radio_on_during_sleep)
434+
pci_clear_master(pdev);
435+
} else {
436+
wil->suspend_stats.successful_resumes++;
437+
}
420438

421439
return rc;
422440
}

0 commit comments

Comments
 (0)