Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/amdsmn/amdsmn.c
39536 views
1
/*-
2
* Copyright (c) 2017-2020 Conrad Meyer <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
* POSSIBILITY OF SUCH DAMAGE.
25
*/
26
27
/*
28
* Driver for the AMD Family 15h, 17h, 19h, 1Ah CPU System Management Network.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/bus.h>
33
#include <sys/conf.h>
34
#include <sys/lock.h>
35
#include <sys/kernel.h>
36
#include <sys/module.h>
37
#include <sys/mutex.h>
38
#include <sys/sysctl.h>
39
#include <sys/systm.h>
40
41
#include <machine/cpufunc.h>
42
#include <machine/cputypes.h>
43
#include <machine/md_var.h>
44
#include <machine/specialreg.h>
45
46
#include <dev/pci/pcivar.h>
47
#include <x86/pci_cfgreg.h>
48
49
#include <dev/amdsmn/amdsmn.h>
50
51
#define F15H_SMN_ADDR_REG 0xb8
52
#define F15H_SMN_DATA_REG 0xbc
53
#define F17H_SMN_ADDR_REG 0x60
54
#define F17H_SMN_DATA_REG 0x64
55
56
#define PCI_DEVICE_ID_AMD_15H_M60H_ROOT 0x1576
57
#define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450
58
#define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0
59
#define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 /* Also M70H, F19H M00H/M20H */
60
#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 /* Also F19H M50H */
61
#define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4
62
#define PCI_DEVICE_ID_AMD_19H_M40H_ROOT 0x14b5
63
#define PCI_DEVICE_ID_AMD_19H_M60H_ROOT 0x14d8 /* Also F1AH M40H */
64
#define PCI_DEVICE_ID_AMD_19H_M70H_ROOT 0x14e8
65
#define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a
66
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
67
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
68
69
70
struct pciid;
71
struct amdsmn_softc {
72
struct mtx smn_lock;
73
const struct pciid *smn_pciid;
74
};
75
76
static const struct pciid {
77
uint16_t amdsmn_vendorid;
78
uint16_t amdsmn_deviceid;
79
uint8_t amdsmn_addr_reg;
80
uint8_t amdsmn_data_reg;
81
} amdsmn_ids[] = {
82
{
83
.amdsmn_vendorid = CPU_VENDOR_AMD,
84
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_15H_M60H_ROOT,
85
.amdsmn_addr_reg = F15H_SMN_ADDR_REG,
86
.amdsmn_data_reg = F15H_SMN_DATA_REG,
87
},
88
{
89
.amdsmn_vendorid = CPU_VENDOR_AMD,
90
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_ROOT,
91
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
92
.amdsmn_data_reg = F17H_SMN_DATA_REG,
93
},
94
{
95
.amdsmn_vendorid = CPU_VENDOR_AMD,
96
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M10H_ROOT,
97
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
98
.amdsmn_data_reg = F17H_SMN_DATA_REG,
99
},
100
{
101
.amdsmn_vendorid = CPU_VENDOR_AMD,
102
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M30H_ROOT,
103
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
104
.amdsmn_data_reg = F17H_SMN_DATA_REG,
105
},
106
{
107
.amdsmn_vendorid = CPU_VENDOR_AMD,
108
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M60H_ROOT,
109
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
110
.amdsmn_data_reg = F17H_SMN_DATA_REG,
111
},
112
{
113
.amdsmn_vendorid = CPU_VENDOR_AMD,
114
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M10H_ROOT,
115
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
116
.amdsmn_data_reg = F17H_SMN_DATA_REG,
117
},
118
{
119
.amdsmn_vendorid = CPU_VENDOR_AMD,
120
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M40H_ROOT,
121
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
122
.amdsmn_data_reg = F17H_SMN_DATA_REG,
123
},
124
{
125
.amdsmn_vendorid = CPU_VENDOR_AMD,
126
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M60H_ROOT,
127
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
128
.amdsmn_data_reg = F17H_SMN_DATA_REG,
129
},
130
{
131
.amdsmn_vendorid = CPU_VENDOR_AMD,
132
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M70H_ROOT,
133
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
134
.amdsmn_data_reg = F17H_SMN_DATA_REG,
135
},
136
{
137
.amdsmn_vendorid = CPU_VENDOR_AMD,
138
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_1AH_M00H_ROOT,
139
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
140
.amdsmn_data_reg = F17H_SMN_DATA_REG,
141
},
142
{
143
.amdsmn_vendorid = CPU_VENDOR_AMD,
144
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_1AH_M20H_ROOT,
145
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
146
.amdsmn_data_reg = F17H_SMN_DATA_REG,
147
},
148
{
149
.amdsmn_vendorid = CPU_VENDOR_AMD,
150
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_1AH_M60H_ROOT,
151
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
152
.amdsmn_data_reg = F17H_SMN_DATA_REG,
153
},
154
};
155
156
/*
157
* Device methods.
158
*/
159
static void amdsmn_identify(driver_t *driver, device_t parent);
160
static int amdsmn_probe(device_t dev);
161
static int amdsmn_attach(device_t dev);
162
static int amdsmn_detach(device_t dev);
163
164
static device_method_t amdsmn_methods[] = {
165
/* Device interface */
166
DEVMETHOD(device_identify, amdsmn_identify),
167
DEVMETHOD(device_probe, amdsmn_probe),
168
DEVMETHOD(device_attach, amdsmn_attach),
169
DEVMETHOD(device_detach, amdsmn_detach),
170
DEVMETHOD_END
171
};
172
173
static driver_t amdsmn_driver = {
174
"amdsmn",
175
amdsmn_methods,
176
sizeof(struct amdsmn_softc),
177
};
178
179
DRIVER_MODULE(amdsmn, hostb, amdsmn_driver, NULL, NULL);
180
MODULE_VERSION(amdsmn, 1);
181
MODULE_PNP_INFO("U16:vendor;U16:device", pci, amdsmn, amdsmn_ids,
182
nitems(amdsmn_ids));
183
184
static bool
185
amdsmn_match(device_t parent, const struct pciid **pciid_out)
186
{
187
uint16_t vendor, device;
188
size_t i;
189
190
vendor = pci_get_vendor(parent);
191
device = pci_get_device(parent);
192
193
for (i = 0; i < nitems(amdsmn_ids); i++) {
194
if (vendor == amdsmn_ids[i].amdsmn_vendorid &&
195
device == amdsmn_ids[i].amdsmn_deviceid) {
196
if (pciid_out != NULL)
197
*pciid_out = &amdsmn_ids[i];
198
return (true);
199
}
200
}
201
return (false);
202
}
203
204
static void
205
amdsmn_identify(driver_t *driver, device_t parent)
206
{
207
device_t child;
208
209
/* Make sure we're not being doubly invoked. */
210
if (device_find_child(parent, "amdsmn", DEVICE_UNIT_ANY) != NULL)
211
return;
212
if (!amdsmn_match(parent, NULL))
213
return;
214
215
child = device_add_child(parent, "amdsmn", DEVICE_UNIT_ANY);
216
if (child == NULL)
217
device_printf(parent, "add amdsmn child failed\n");
218
}
219
220
static int
221
amdsmn_probe(device_t dev)
222
{
223
uint32_t family;
224
225
if (resource_disabled("amdsmn", 0))
226
return (ENXIO);
227
if (!amdsmn_match(device_get_parent(dev), NULL))
228
return (ENXIO);
229
230
family = CPUID_TO_FAMILY(cpu_id);
231
232
switch (family) {
233
case 0x15:
234
case 0x17:
235
case 0x19:
236
case 0x1a:
237
break;
238
default:
239
return (ENXIO);
240
}
241
device_set_descf(dev, "AMD Family %02Xh System Management Network",
242
family);
243
244
return (BUS_PROBE_GENERIC);
245
}
246
247
static int
248
amdsmn_attach(device_t dev)
249
{
250
struct amdsmn_softc *sc = device_get_softc(dev);
251
252
if (!amdsmn_match(device_get_parent(dev), &sc->smn_pciid))
253
return (ENXIO);
254
255
mtx_init(&sc->smn_lock, "SMN mtx", "SMN", MTX_DEF);
256
return (0);
257
}
258
259
int
260
amdsmn_detach(device_t dev)
261
{
262
struct amdsmn_softc *sc = device_get_softc(dev);
263
264
mtx_destroy(&sc->smn_lock);
265
return (0);
266
}
267
268
int
269
amdsmn_read(device_t dev, uint32_t addr, uint32_t *value)
270
{
271
struct amdsmn_softc *sc = device_get_softc(dev);
272
device_t parent;
273
274
parent = device_get_parent(dev);
275
276
mtx_lock(&sc->smn_lock);
277
pci_write_config(parent, sc->smn_pciid->amdsmn_addr_reg, addr, 4);
278
*value = pci_read_config(parent, sc->smn_pciid->amdsmn_data_reg, 4);
279
mtx_unlock(&sc->smn_lock);
280
281
return (0);
282
}
283
284
int
285
amdsmn_write(device_t dev, uint32_t addr, uint32_t value)
286
{
287
struct amdsmn_softc *sc = device_get_softc(dev);
288
device_t parent;
289
290
parent = device_get_parent(dev);
291
292
mtx_lock(&sc->smn_lock);
293
pci_write_config(parent, sc->smn_pciid->amdsmn_addr_reg, addr, 4);
294
pci_write_config(parent, sc->smn_pciid->amdsmn_data_reg, value, 4);
295
mtx_unlock(&sc->smn_lock);
296
297
return (0);
298
}
299
300