Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linuxkpi/common/src/linuxkpi_80211_pm.c
283313 views
1
/*
2
* Copyright (c) 2025 The FreeBSD Foundation
3
*
4
* This software was developed by Björn Zeeb under sponsorship from
5
* the FreeBSD Foundation.
6
*
7
* SPDX-License-Identifier: BSD-2-Clause
8
*/
9
10
#include <sys/param.h>
11
#include <sys/kernel.h>
12
#include <sys/bus.h>
13
#include <sys/module.h>
14
15
#include <linux/pci.h>
16
#include <dev/pci/pcivar.h>
17
#include "linux_80211.h"
18
19
#include <net80211/ieee80211_var.h>
20
21
struct lkpi_80211_pm_softc {
22
/* PCI */
23
int (*suspend) (struct pci_dev *pdev, pm_message_t state);
24
int (*resume) (struct pci_dev *pdev);
25
};
26
27
static int
28
lkpi_80211_pm_suspend(struct pci_dev *pdev, pm_message_t state)
29
{
30
const struct dev_pm_ops *pmops;
31
struct lkpi_80211_pm_softc *sc;
32
struct ieee80211com *ic;
33
device_t dev;
34
int error;
35
36
dev = device_find_child(pdev->dev.bsddev, "lkpi80211_pm",
37
DEVICE_UNIT_ANY);
38
if (dev == NULL) {
39
/* Must not happen, so abort suspend if it does. */
40
device_printf(pdev->dev.bsddev,
41
"%s: cannot find lkpi80211_pm child for %s\n",
42
__func__, device_get_name(pdev->dev.bsddev));
43
return (ENXIO);
44
}
45
sc = device_get_softc(dev);
46
error = 0;
47
48
/* Call order: wireless then pdev. */
49
50
ic = ieee80211_find_com(device_get_nameunit(pdev->dev.bsddev));
51
if (ic != NULL) {
52
error = lkpi_80211_suspend(ic, state);
53
} else {
54
device_printf(pdev->dev.bsddev,
55
"%s: WARNING: wireless device not found\n", __func__);
56
}
57
if (error != 0)
58
goto err;
59
60
/* Logic duplicated from linux_pci_suspend(). */
61
pmops = pdev->pdrv->driver.pm;
62
if (sc->suspend != NULL)
63
error = sc->suspend(pdev, state);
64
else if (pmops != NULL && pmops->suspend != NULL) {
65
error = -pmops->suspend(&pdev->dev);
66
if (error == 0 && pmops->suspend_late != NULL)
67
error = -pmops->suspend_late(&pdev->dev);
68
if (error == 0 && pmops->suspend_noirq != NULL)
69
error = -pmops->suspend_noirq(&pdev->dev);
70
}
71
72
err:
73
if (error < 0)
74
error = -error;
75
76
if (error != 0)
77
device_printf(pdev->dev.bsddev,
78
"%s: WARNING: SUSPEND FAILED: %d\n", __func__, error);
79
80
return (error);
81
}
82
83
static int
84
lkpi_80211_pm_resume(struct pci_dev *pdev)
85
{
86
const struct dev_pm_ops *pmops;
87
struct lkpi_80211_pm_softc *sc;
88
struct ieee80211com *ic;
89
device_t dev;
90
int error;
91
92
dev = device_find_child(pdev->dev.bsddev, "lkpi80211_pm",
93
DEVICE_UNIT_ANY);
94
if (dev == NULL) {
95
/* Must not happen, so abort suspend if it does. */
96
device_printf(pdev->dev.bsddev,
97
"%s: cannot find lkpi80211_pm child\n", __func__);
98
return (ENXIO);
99
}
100
sc = device_get_softc(dev);
101
error = 0;
102
103
/* Call order: pdev then wireless. */
104
105
/* Logic duplicated from linux_pci_resume(). */
106
pmops = pdev->pdrv->driver.pm;
107
if (sc->resume != NULL) {
108
error = sc->resume(pdev);
109
} else if (pmops != NULL && pmops->resume != NULL) {
110
if (pmops->resume_early != NULL)
111
error = -pmops->resume_early(&pdev->dev);
112
if (error == 0 && pmops->resume != NULL)
113
error = -pmops->resume(&pdev->dev);
114
}
115
if (error != 0)
116
device_printf(pdev->dev.bsddev, "%s: resume failed!\n", __func__);
117
/* Do not error out but give wireless also a chance. */
118
119
ic = ieee80211_find_com(device_get_nameunit(pdev->dev.bsddev));
120
if (ic != NULL) {
121
error = lkpi_80211_resume(ic);
122
} else {
123
device_printf(pdev->dev.bsddev,
124
"%s: WARNING: wireless device not found\n", __func__);
125
}
126
127
if (error < 0)
128
error = -error;
129
130
return (error);
131
}
132
133
/* -------------------------------------------------------------------------- */
134
static void
135
lkpi_80211_pm_identify(driver_t *driver, device_t parent)
136
{
137
138
/* Make sure we're not being doubly invoked per parent. */
139
if (device_find_child(parent, driver->name, DEVICE_UNIT_ANY) != NULL)
140
return;
141
142
/* Make sure this is PCI for now. */
143
if (!is_pci_device(parent))
144
return;
145
146
if (BUS_ADD_CHILD(parent, 0, driver->name, DEVICE_UNIT_ANY) == NULL)
147
device_printf(parent, "%s: failed to add child\n", __func__);
148
}
149
150
static int
151
lkpi_80211_pm_probe(device_t dev)
152
{
153
device_set_descf(dev, "LinuxKPI 802.11 %s mac80211 PM",
154
device_get_nameunit(device_get_parent(dev)));
155
return (BUS_PROBE_DEFAULT);
156
}
157
158
static int
159
lkpi_80211_pm_attach(device_t dev)
160
{
161
struct lkpi_80211_pm_softc *sc;
162
struct pci_dev *pdev;
163
164
sc = device_get_softc(dev);
165
pdev = device_get_softc(device_get_parent(dev));
166
167
/* Intercept the driver suspend/resume calls. */
168
sc->suspend = pdev->pdrv->suspend;
169
pdev->pdrv->suspend = lkpi_80211_pm_suspend;
170
sc->resume = pdev->pdrv->resume;
171
pdev->pdrv->resume = lkpi_80211_pm_resume;
172
173
return (0);
174
}
175
176
static int
177
lkpi_80211_pm_detach(device_t dev)
178
{
179
struct lkpi_80211_pm_softc *sc;
180
struct pci_dev *pdev;
181
182
sc = device_get_softc(dev);
183
pdev = device_get_softc(device_get_parent(dev));
184
185
/* Restore the original notifications. */
186
pdev->pdrv->suspend = sc->suspend;
187
pdev->pdrv->resume = sc->resume;
188
189
return (0);
190
}
191
192
static device_method_t lkpi_80211_pm_methods[] = {
193
/* Device interface */
194
DEVMETHOD(device_identify, lkpi_80211_pm_identify),
195
DEVMETHOD(device_probe, lkpi_80211_pm_probe),
196
DEVMETHOD(device_attach, lkpi_80211_pm_attach),
197
DEVMETHOD(device_detach, lkpi_80211_pm_detach),
198
/*
199
* Do not think about device_suspend/resume here.
200
* We are not a PCI device and LinuxKPI PCI linux_pci_suspend/resume
201
* are getting the notifications so we have to hijack the
202
* LinuxKPI upcalls.
203
*/
204
205
DEVMETHOD_END
206
};
207
208
driver_t lkpi_80211_pm_driver = {
209
"lkpi80211_pm",
210
lkpi_80211_pm_methods,
211
sizeof(struct lkpi_80211_pm_softc),
212
};
213
214
MODULE_DEPEND(lkpi80211_pm, linuxkpi_wlan, 1, 1, 1);
215
MODULE_VERSION(lkpi80211_pm, 1);
216
217