1f2dbfd3Robert Mustacchi/*
2f2dbfd3Robert Mustacchi * This file and its contents are supplied under the terms of the
3f2dbfd3Robert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4f2dbfd3Robert Mustacchi * You may only use this file in accordance with the terms of version
5f2dbfd3Robert Mustacchi * 1.0 of the CDDL.
6f2dbfd3Robert Mustacchi *
7f2dbfd3Robert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8f2dbfd3Robert Mustacchi * source.  A copy of the CDDL is also available via the Internet at
9f2dbfd3Robert Mustacchi * http://www.illumos.org/license/CDDL.
10f2dbfd3Robert Mustacchi */
11f2dbfd3Robert Mustacchi
12f2dbfd3Robert Mustacchi/*
13f2dbfd3Robert Mustacchi * Copyright 2019, Joyent, Inc.
14f2dbfd3Robert Mustacchi */
15f2dbfd3Robert Mustacchi
16f2dbfd3Robert Mustacchi/*
17f2dbfd3Robert Mustacchi * AMD Family 17 Northbridge and Data Fabric Driver
18f2dbfd3Robert Mustacchi *
19f2dbfd3Robert Mustacchi * This driver attaches to the AMD Family 17h northbridge and data fabric bus.
20f2dbfd3Robert Mustacchi * Each Zeppelin die ('processor node' in cpuid.c parlance) has its own
21f2dbfd3Robert Mustacchi * northbridge and access to the data fabric bus. The northbridge and data
22f2dbfd3Robert Mustacchi * fabric both provide access to various features such as:
23f2dbfd3Robert Mustacchi *
24f2dbfd3Robert Mustacchi *  - The System Management Network (SMN)
25f2dbfd3Robert Mustacchi *  - Data Fabric via Fabric Indirect Config Access (FICAA)
26f2dbfd3Robert Mustacchi *
27f2dbfd3Robert Mustacchi * These are required to access things such as temperature sensors or memory
28f2dbfd3Robert Mustacchi * controller configuration registers.
29f2dbfd3Robert Mustacchi *
30f2dbfd3Robert Mustacchi * In AMD Family 17h systems, the 'northbridge' is an ASIC that is part of the
31f2dbfd3Robert Mustacchi * package that contains many I/O capabilities related to things like PCI
32f2dbfd3Robert Mustacchi * express, etc. The 'data fabric' is the means by which different components
33f2dbfd3Robert Mustacchi * both inside the socket and multiple sockets are connected together. Both the
34f2dbfd3Robert Mustacchi * northbridge and the data fabric have dedicated PCI devices which the
35f2dbfd3Robert Mustacchi * operating system can use to interact with them.
36f2dbfd3Robert Mustacchi *
37f2dbfd3Robert Mustacchi * ------------------------
38f2dbfd3Robert Mustacchi * Mapping Devices Together
39f2dbfd3Robert Mustacchi * ------------------------
40f2dbfd3Robert Mustacchi *
41f2dbfd3Robert Mustacchi * The operating system needs to expose things like temperature sensors and DRAM
42f2dbfd3Robert Mustacchi * configuration registers in terms that are meaningful to the system such as
43f2dbfd3Robert Mustacchi * logical CPUs, cores, etc. This driver attaches to the PCI IDs that represent
44f2dbfd3Robert Mustacchi * the northbridge and data fabric; however, there are multiple PCI devices (one
45f2dbfd3Robert Mustacchi * per die) that exist. This driver does manage to map all of these three things
46f2dbfd3Robert Mustacchi * together; however, it requires some acrobatics. Unfortunately, there's no
47f2dbfd3Robert Mustacchi * direct way to map a northbridge to its corresponding die. However, we can map
48f2dbfd3Robert Mustacchi * a CPU die to a data fabric PCI device and a data fabric PCI device to a
49f2dbfd3Robert Mustacchi * corresponding northbridge PCI device.
50f2dbfd3Robert Mustacchi *
51f2dbfd3Robert Mustacchi * In current Zen based products, there is a direct mapping between processor
52f2dbfd3Robert Mustacchi * nodes and a data fabric PCI device. All of the devices are on PCI Bus 0 and
53f2dbfd3Robert Mustacchi * start from Device 0x18. Device 0x18 maps to processor node 0, 0x19 to
54f2dbfd3Robert Mustacchi * processor node 1, etc. This means that to map a logical CPU to a data fabric
55f2dbfd3Robert Mustacchi * device, we take its processor node id, add it to 0x18 and find the PCI device
56f2dbfd3Robert Mustacchi * that is on bus 0, device 0x18. As each data fabric device is attached based
57f2dbfd3Robert Mustacchi * on its PCI ID, we add it to the global list, amd_nbdf_dfs that is in the
58f2dbfd3Robert Mustacchi * amd_f17nbdf_t structure.
59f2dbfd3Robert Mustacchi *
60f2dbfd3Robert Mustacchi * The northbridge PCI device has a defined device and function, but the PCI bus
61f2dbfd3Robert Mustacchi * that it's on can vary. Each die has its own series of PCI buses that are
62f2dbfd3Robert Mustacchi * assigned to it and the northbridge PCI device is on the first of die-specific
63f2dbfd3Robert Mustacchi * PCI bus for each die. This also means that the northbridge will not show up
64f2dbfd3Robert Mustacchi * on PCI bus 0, which is the PCI bus that all of the data fabric devices are
65f2dbfd3Robert Mustacchi * on. While conventionally the northbridge with the lowest PCI bus value
66f2dbfd3Robert Mustacchi * would correspond to processor node zero, hardware does not guarantee that at
67f2dbfd3Robert Mustacchi * all. Because we don't want to be at the mercy of firmware, we don't rely on
68f2dbfd3Robert Mustacchi * this ordering, even though we have yet to find a system that deviates from
69f2dbfd3Robert Mustacchi * this scheme.
70f2dbfd3Robert Mustacchi *
71f2dbfd3Robert Mustacchi * One of the registers in the data fabric device's function 0
72f2dbfd3Robert Mustacchi * (AMDF17_DF_CFG_ADDR_CTL), happens to have the first PCI bus that is
73f2dbfd3Robert Mustacchi * associated with the processor node. This means, that we can map a data fabric
74f2dbfd3Robert Mustacchi * device to a northbridge by finding the northbridge whose PCI bus matches the
75f2dbfd3Robert Mustacchi * value in the corresponding data fabric's AMDF17_DF_CFG_ADDR_CTL.
76f2dbfd3Robert Mustacchi *
77f2dbfd3Robert Mustacchi * This means that we can map a northbridge to a data fabric device and a data
780e6adfeRobert Mustacchi * fabric device to a die. Because these are generally 1:1 mappings, there is a
790e6adfeRobert Mustacchi * transitive relationship and therefore we know which northbridge is associated
800e6adfeRobert Mustacchi * with which processor die. This is summarized in the following image:
81f2dbfd3Robert Mustacchi *
82f2dbfd3Robert Mustacchi *  +-------+      +----------------------------+         +--------------+
83f2dbfd3Robert Mustacchi *  | Die 0 | ---> | Data Fabric PCI BDF 0/18/0 |-------> | Northbridge  |
84f2dbfd3Robert Mustacchi *  +-------+      | AMDF17_DF_CFG_ADDR: bus 10 |         | PCI  10/0/0  |
85f2dbfd3Robert Mustacchi *     ...         +----------------------------+         +--------------+
86f2dbfd3Robert Mustacchi *  +-------+      +------------------------------+         +--------------+
87f2dbfd3Robert Mustacchi *  | Die n | ---> | Data Fabric PCI BDF 0/18+n/0 |-------> | Northbridge  |
88f2dbfd3Robert Mustacchi *  +-------+      | AMDF17_DF_CFG_ADDR: bus 133  |         | PCI 133/0/0  |
89f2dbfd3Robert Mustacchi *                 +------------------------------+         +--------------+
90f2dbfd3Robert Mustacchi *
91f2dbfd3Robert Mustacchi * Note, the PCI buses used by the northbridges here are arbitrary. They do not
92f2dbfd3Robert Mustacchi * reflect the actual values by hardware; however, the bus/device/function (BDF)
93f2dbfd3Robert Mustacchi * of the data fabric accurately models hardware. All of the BDF values are in
94f2dbfd3Robert Mustacchi * hex.
95f2dbfd3Robert Mustacchi *
960e6adfeRobert Mustacchi * Starting with the Rome generation of processors (Family 17h Model 30-3Fh),
970e6adfeRobert Mustacchi * AMD has multiple northbridges that exist on a given die. All of these
980e6adfeRobert Mustacchi * northbridges share the same data fabric and system management network port.
990e6adfeRobert Mustacchi * From our perspective this means that some of the northbridge devices will be
1000e6adfeRobert Mustacchi * redundant and that we will no longer have a 1:1 mapping between the
1010e6adfeRobert Mustacchi * northbridge and the data fabric devices. Every data fabric will have a
1020e6adfeRobert Mustacchi * northbridge, but not every northbridge will have a data fabric device mapped.
1030e6adfeRobert Mustacchi * Because we're always trying to map from a die to a northbridge and not the
1040e6adfeRobert Mustacchi * reverse, the fact that there are extra northbridge devices hanging around
1050e6adfeRobert Mustacchi * that we don't know about shouldn't be a problem.
1060e6adfeRobert Mustacchi *
107f2dbfd3Robert Mustacchi * -------------------------------
108f2dbfd3Robert Mustacchi * Attach and Detach Complications
109f2dbfd3Robert Mustacchi * -------------------------------
110f2dbfd3Robert Mustacchi *
111f2dbfd3Robert Mustacchi * Because we need to map different PCI devices together, this means that we
112f2dbfd3Robert Mustacchi * have multiple dev_info_t structures that we need to manage. Each of these is
113f2dbfd3Robert Mustacchi * independently attached and detached. While this is easily managed for attach,
114f2dbfd3Robert Mustacchi * it is not for detach.
115f2dbfd3Robert Mustacchi *
116f2dbfd3Robert Mustacchi * Once a device has been detached it will only come back if we have an active
117f2dbfd3Robert Mustacchi * minor node that will be accessed. While we have minor nodes associated with
118f2dbfd3Robert Mustacchi * the northbridges, we don't with the data fabric devices. This means that if
119f2dbfd3Robert Mustacchi * they are detached, nothing would ever cause them to be reattached. The system
120f2dbfd3Robert Mustacchi * also doesn't provide us a way or any guarantees around making sure that we're
121f2dbfd3Robert Mustacchi * attached to all such devices before we detach. As a result, unfortunately,
122f2dbfd3Robert Mustacchi * it's easier to basically have detach always fail.
123f2dbfd3Robert Mustacchi *
124f2dbfd3Robert Mustacchi * To deal with both development and if issues arise in the field, there is a
125f2dbfd3Robert Mustacchi * knob, amdf17df_allow_detach, which if set to a non-zero value, will allow
126f2dbfd3Robert Mustacchi * instances to detach.
127f2dbfd3Robert Mustacchi *
128f2dbfd3Robert Mustacchi * ---------------
129f2dbfd3Robert Mustacchi * Exposed Devices
130f2dbfd3Robert Mustacchi * ---------------
131f2dbfd3Robert Mustacchi *
132f2dbfd3Robert Mustacchi * Currently we expose a single set of character devices which represent
133f2dbfd3Robert Mustacchi * temperature sensors for this family of processors. Because temperature
134f2dbfd3Robert Mustacchi * sensors exist on a per-processor node basis, we create a single minor node
135f2dbfd3Robert Mustacchi * for each one. Because our naming matches the cpuid naming, FMA can match that
136f2dbfd3Robert Mustacchi * up to logical CPUs and take care of matching the sensors appropriately. We
137f2dbfd3Robert Mustacchi * internally rate limit the sensor updates to 100ms, which is controlled by the
138f2dbfd3Robert Mustacchi * global amdf17nbdf_cache_ms.
139f2dbfd3Robert Mustacchi */
140f2dbfd3Robert Mustacchi
141f2dbfd3Robert Mustacchi#include <sys/modctl.h>
142f2dbfd3Robert Mustacchi#include <sys/conf.h>
143f2dbfd3Robert Mustacchi#include <sys/devops.h>
144f2dbfd3Robert Mustacchi#include <sys/types.h>
145f2dbfd3Robert Mustacchi#include <sys/file.h>
146f2dbfd3Robert Mustacchi#include <sys/open.h>
147f2dbfd3Robert Mustacchi#include <sys/cred.h>
148f2dbfd3Robert Mustacchi#include <sys/ddi.h>
149f2dbfd3Robert Mustacchi#include <sys/sunddi.h>
150f2dbfd3Robert Mustacchi#include <sys/cmn_err.h>
151f2dbfd3Robert Mustacchi#include <sys/list.h>
152f2dbfd3Robert Mustacchi#include <sys/pci.h>
153f2dbfd3Robert Mustacchi#include <sys/stddef.h>
154f2dbfd3Robert Mustacchi#include <sys/stat.h>
155f2dbfd3Robert Mustacchi#include <sys/x86_archext.h>
156f2dbfd3Robert Mustacchi#include <sys/cpuvar.h>
157f2dbfd3Robert Mustacchi#include <sys/sensors.h>
158f2dbfd3Robert Mustacchi
159f2dbfd3Robert Mustacchi/*
160f2dbfd3Robert Mustacchi * The range of minors that we'll allow.
161f2dbfd3Robert Mustacchi */
162f2dbfd3Robert Mustacchi#define	AMDF17_MINOR_LOW	1
163f2dbfd3Robert Mustacchi#define	AMDF17_MINOR_HIGH	INT32_MAX
164f2dbfd3Robert Mustacchi
165f2dbfd3Robert Mustacchi/*
166f2dbfd3Robert Mustacchi * This is the value of the first PCI data fabric device that globally exists.
167f2dbfd3Robert Mustacchi * It always maps to AMD's first nodeid (what we call cpi_procnodeid).
168f2dbfd3Robert Mustacchi */
169f2dbfd3Robert Mustacchi#define	AMDF17_DF_FIRST_DEVICE	0x18
170f2dbfd3Robert Mustacchi
171f2dbfd3Robert Mustacchi/*
172f2dbfd3Robert Mustacchi * The data fabric devices are defined to always be on PCI bus zero.
173f2dbfd3Robert Mustacchi */
174f2dbfd3Robert Mustacchi#define	AMDF17_DF_BUSNO		0x00
175f2dbfd3Robert Mustacchi
176f2dbfd3Robert Mustacchi/*
177f2dbfd3Robert Mustacchi * This register contains the BUS A of the the processor node that corresponds
178f2dbfd3Robert Mustacchi * to the data fabric device.
179f2dbfd3Robert Mustacchi */
180f2dbfd3Robert Mustacchi#define	AMDF17_DF_CFG_ADDR_CTL		0x84
181f2dbfd3Robert Mustacchi#define	AMDF17_DF_CFG_ADDR_CTL_MASK	0xff
182f2dbfd3Robert Mustacchi
183f2dbfd3Robert Mustacchi/*
184f2dbfd3Robert Mustacchi * Northbridge registers that are related to accessing the SMN. One writes to
185f2dbfd3Robert Mustacchi * the SMN address register and then can read from the SMN data register.
186f2dbfd3Robert Mustacchi */
187f2dbfd3Robert Mustacchi#define	AMDF17_NB_SMN_ADDR	0x60
188f2dbfd3Robert Mustacchi#define	AMDF17_NB_SMN_DATA	0x64
189f2dbfd3Robert Mustacchi
190f2dbfd3Robert Mustacchi/*
191f2dbfd3Robert Mustacchi * The following are register offsets and the meaning of their bits related to
192f2dbfd3Robert Mustacchi * temperature. These addresses are addresses in the System Management Network
193f2dbfd3Robert Mustacchi * which is accessed through the northbridge.  They are not addresses in PCI
194f2dbfd3Robert Mustacchi * configuration space.
195f2dbfd3Robert Mustacchi */
196f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP			0x00059800
197f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP_TEMPERATURE(x)	((x) >> 21)
198f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP_RANGE_SEL		(1 << 19)
199f2dbfd3Robert Mustacchi
200f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP_RANGE_ADJ		(-49)
201f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP_DECIMAL_BITS		3
202f2dbfd3Robert Mustacchi#define	AMDF17_SMU_THERMAL_CURTEMP_BITS_MASK		0x7
203f2dbfd3Robert Mustacchi
204f2dbfd3Robert Mustacchi/*
205f2dbfd3Robert Mustacchi * The temperature sensor in family 17 is measured in terms of 0.125 C steps.
206f2dbfd3Robert Mustacchi */
207f2dbfd3Robert Mustacchi#define	AMDF17_THERMAL_GRANULARITY	8
208f2dbfd3Robert Mustacchi
209f2dbfd3Robert Mustacchistruct amdf17nb;
210f2dbfd3Robert Mustacchistruct amdf17df;
211f2dbfd3Robert Mustacchi
212f2dbfd3Robert Mustacchitypedef struct amdf17nb {
213f2dbfd3Robert Mustacchi	list_node_t		amd_nb_link;
214f2dbfd3Robert Mustacchi	dev_info_t		*amd_nb_dip;
215f2dbfd3Robert Mustacchi	ddi_acc_handle_t	amd_nb_cfgspace;
216f2dbfd3Robert Mustacchi	uint_t			amd_nb_bus;
217f2dbfd3Robert Mustacchi	uint_t			amd_nb_dev;
218f2dbfd3Robert Mustacchi	uint_t			amd_nb_func;
219f2dbfd3Robert Mustacchi	struct amdf17df		*amd_nb_df;
220f2dbfd3Robert Mustacchi	uint_t			amd_nb_procnodeid;
221f2dbfd3Robert Mustacchi	id_t			amd_nb_temp_minor;
222f2dbfd3Robert Mustacchi	hrtime_t		amd_nb_temp_last_read;
223f2dbfd3Robert Mustacchi	int			amd_nb_temp_off;
224f2dbfd3Robert Mustacchi	uint32_t		amd_nb_temp_reg;
225f2dbfd3Robert Mustacchi	/* Values derived from the above */
226f2dbfd3Robert Mustacchi	int64_t			amd_nb_temp;
227f2dbfd3Robert Mustacchi} amdf17nb_t;
228f2dbfd3Robert Mustacchi
229f2dbfd3Robert Mustacchitypedef struct amdf17df {
230f2dbfd3Robert Mustacchi	list_node_t		amd_df_link;
231f2dbfd3Robert Mustacchi	dev_info_t		*amd_df_f0_dip;
232f2dbfd3Robert Mustacchi	ddi_acc_handle_t	amd_df_f0_cfgspace;
233f2dbfd3Robert Mustacchi	uint_t			amd_df_procnodeid;
234f2dbfd3Robert Mustacchi	uint_t			amd_df_iobus;
235f2dbfd3Robert Mustacchi	amdf17nb_t		*amd_df_nb;
236f2dbfd3Robert Mustacchi} amdf17df_t;
237f2dbfd3Robert Mustacchi
238f2dbfd3Robert Mustacchitypedef struct amdf17nbdf {
239f2dbfd3Robert Mustacchi	kmutex_t	amd_nbdf_lock;
240f2dbfd3Robert Mustacchi	id_space_t	*amd_nbdf_minors;
241f2dbfd3Robert Mustacchi	list_t		amd_nbdf_nbs;
242f2dbfd3Robert Mustacchi	list_t		amd_nbdf_dfs;
243f2dbfd3Robert Mustacchi} amdf17nbdf_t;
244f2dbfd3Robert Mustacchi
245f2dbfd3Robert Mustacchitypedef enum {
246f2dbfd3Robert Mustacchi	AMD_NBDF_TYPE_UNKNOWN,
247f2dbfd3Robert Mustacchi	AMD_NBDF_TYPE_NORTHBRIDGE,
248f2dbfd3Robert Mustacchi	AMD_NBDF_TYPE_DATA_FABRIC
249f2dbfd3Robert Mustacchi} amdf17nbdf_type_t;
250f2dbfd3Robert Mustacchi
251f2dbfd3Robert Mustacchitypedef struct {
252f2dbfd3Robert Mustacchi	uint16_t		amd_nbdft_pci_did;
253f2dbfd3Robert Mustacchi	amdf17nbdf_type_t	amd_nbdft_type;
254f2dbfd3Robert Mustacchi} amdf17nbdf_table_t;
255f2dbfd3Robert Mustacchi
256f2dbfd3Robert Mustacchistatic const amdf17nbdf_table_t amdf17nbdf_dev_map[] = {
257f2dbfd3Robert Mustacchi	/* Family 17h Ryzen, Epyc Models 00h-0fh (Zen uarch) */
258f2dbfd3Robert Mustacchi	{ 0x1450, AMD_NBDF_TYPE_NORTHBRIDGE },
259f2dbfd3Robert Mustacchi	{ 0x1460, AMD_NBDF_TYPE_DATA_FABRIC },
2600e6adfeRobert Mustacchi	/* Family 17h Raven Ridge Models 10h-1fh (Zen uarch) */
2610e6adfeRobert Mustacchi	{ 0x15d0, AMD_NBDF_TYPE_NORTHBRIDGE },
2620e6adfeRobert Mustacchi	{ 0x15e8, AMD_NBDF_TYPE_DATA_FABRIC },
2630e6adfeRobert Mustacchi	/* Family 17h Epyc Models 30h-3fh (Zen 2 uarch) */
2640e6adfeRobert Mustacchi	{ 0x1480, AMD_NBDF_TYPE_NORTHBRIDGE },
2650e6adfeRobert Mustacchi	{ 0x1490, AMD_NBDF_TYPE_DATA_FABRIC },
2660e6adfeRobert Mustacchi	/*
2670e6adfeRobert Mustacchi	 * Family 17h Ryzen Models 70-7fh (Zen 2 uarch)
2680e6adfeRobert Mustacchi	 *
2690e6adfeRobert Mustacchi	 * While this family has its own PCI ID for the data fabric device, it
2700e6adfeRobert Mustacchi	 * shares the same northbridge ID as the Zen 2 EPYC models 30-3f --
2710e6adfeRobert Mustacchi	 * 0x1480.
2720e6adfeRobert Mustacchi	 */
2730e6adfeRobert Mustacchi	{ 0x1440, AMD_NBDF_TYPE_DATA_FABRIC },
274f2dbfd3Robert Mustacchi	{ PCI_EINVAL16 }
275f2dbfd3Robert Mustacchi};
276f2dbfd3Robert Mustacchi
277f2dbfd3Robert Mustacchitypedef struct {
278f2dbfd3Robert Mustacchi	const char	*amd_nbdfo_brand;
279f2dbfd3Robert Mustacchi	uint_t		amd_nbdfo_family;
280f2dbfd3Robert Mustacchi	int		amd_nbdfo_off;
281f2dbfd3Robert Mustacchi} amdf17nbdf_offset_t;
282f2dbfd3Robert Mustacchi
283f2dbfd3Robert Mustacchi/*
284f2dbfd3Robert Mustacchi * AMD processors report a control temperature (called Tctl) which may be
285f2dbfd3Robert Mustacchi * different from the junction temperature, which is the value that is actually
286f2dbfd3Robert Mustacchi * measured from the die (sometimes called Tdie or Tjct). This is done so that
287f2dbfd3Robert Mustacchi * socket-based environmental monitoring can be consistent from a platform
288f2dbfd3Robert Mustacchi * perspective, but doesn't help us. Unfortunately, these values aren't in
289f2dbfd3Robert Mustacchi * datasheets that we can find, but have been documented partially in a series
290f2dbfd3Robert Mustacchi * of blog posts by AMD when discussing their 'Ryzen Master' monitoring software
291f2dbfd3Robert Mustacchi * for Windows.
292f2dbfd3Robert Mustacchi *
293f2dbfd3Robert Mustacchi * The brand strings below may contain partial matches such in the Threadripper
294f2dbfd3Robert Mustacchi * cases so we can match the entire family of processors. The offset value is
295f2dbfd3Robert Mustacchi * the quantity in degrees that we should adjust Tctl to reach Tdie.
296f2dbfd3Robert Mustacchi */
297f2dbfd3Robert Mustacchistatic const amdf17nbdf_offset_t amdf17nbdf_offsets[] = {
298f2dbfd3Robert Mustacchi	{ "AMD Ryzen 5 1600X", 0x17, -20 },
299f2dbfd3Robert Mustacchi	{ "AMD Ryzen 7 1700X", 0x17, -20 },
300f2dbfd3Robert Mustacchi	{ "AMD Ryzen 7 1800X", 0x17, -20 },
301f2dbfd3Robert Mustacchi	{ "AMD Ryzen 7 2700X", 0x17, -10 },
302f2dbfd3Robert Mustacchi	{ "AMD Ryzen Threadripper 19", 0x17, -27 },
303f2dbfd3Robert Mustacchi	{ "AMD Ryzen Threadripper 29", 0x17, -27 },
304f2dbfd3Robert Mustacchi	{ NULL }
305f2dbfd3Robert Mustacchi};
306f2dbfd3Robert Mustacchi
307f2dbfd3Robert Mustacchi/*
308f2dbfd3Robert Mustacchi * This indicates a number of milliseconds that we should wait between reads.
309f2dbfd3Robert Mustacchi * This is somewhat arbitrary, but the goal is to reduce cross call activity
310f2dbfd3Robert Mustacchi * and reflect that the sensor may not update all the time.
311f2dbfd3Robert Mustacchi */
312f2dbfd3Robert Mustacchiuint_t amdf17nbdf_cache_ms = 100;
313f2dbfd3Robert Mustacchi
314f2dbfd3Robert Mustacchi/*
315f2dbfd3Robert Mustacchi * This indicates whether detach is allowed. It is not by default. See the
316f2dbfd3Robert Mustacchi * theory statement section 'Attach and Detach Complications' for more
317f2dbfd3Robert Mustacchi * information.
318f2dbfd3Robert Mustacchi */
319f2dbfd3Robert Mustacchiuint_t amdf17nbdf_allow_detach = 0;
320f2dbfd3Robert Mustacchi
321f2dbfd3Robert Mustacchi/*
322f2dbfd3Robert Mustacchi * Global data that we keep regarding the device.
323f2dbfd3Robert Mustacchi */
324f2dbfd3Robert Mustacchiamdf17nbdf_t *amdf17nbdf;
325f2dbfd3Robert Mustacchi
326f2dbfd3Robert Mustacchistatic amdf17nb_t *
327f2dbfd3Robert Mustacchiamdf17nbdf_lookup_nb(amdf17nbdf_t *nbdf, minor_t minor)
328f2dbfd3Robert Mustacchi{
329f2dbfd3Robert Mustacchi	ASSERT(MUTEX_HELD(&nbdf->amd_nbdf_lock));
330f2dbfd3Robert Mustacchi
331f2dbfd3Robert Mustacchi	if (minor < AMDF17_MINOR_LOW || minor > AMDF17_MINOR_HIGH) {
332f2dbfd3Robert Mustacchi		return (NULL);
333f2dbfd3Robert Mustacchi	}
334f2dbfd3Robert Mustacchi
335f2dbfd3Robert Mustacchi	for (amdf17nb_t *nb = list_head(&nbdf->amd_nbdf_nbs); nb != NULL;
336f2dbfd3Robert Mustacchi	    nb = list_next(&nbdf->amd_nbdf_nbs, nb)) {
337f2dbfd3Robert Mustacchi		if ((id_t)minor == nb->amd_nb_temp_minor) {
338f2dbfd3Robert Mustacchi			return (nb);
339f2dbfd3Robert Mustacchi		}
340f2dbfd3Robert Mustacchi	}
341f2dbfd3Robert Mustacchi
342f2dbfd3Robert Mustacchi	return (NULL);
343f2dbfd3Robert Mustacchi}
344f2dbfd3Robert Mustacchi
345f2dbfd3Robert Mustacchistatic void
346f2dbfd3Robert Mustacchiamdf17nbdf_cleanup_nb(amdf17nbdf_t *nbdf, amdf17nb_t *nb)
347f2dbfd3Robert Mustacchi{
348f2dbfd3Robert Mustacchi	if (nb == NULL)
349f2dbfd3Robert Mustacchi		return;
350f2dbfd3Robert Mustacchi
351f2dbfd3Robert Mustacchi	ddi_remove_minor_node(nb->amd_nb_dip, NULL);
352f2dbfd3Robert Mustacchi	if (nb->amd_nb_temp_minor > 0) {
353f2dbfd3Robert Mustacchi		id_free(nbdf->amd_nbdf_minors, nb->amd_nb_temp_minor);
354f2dbfd3Robert Mustacchi	}
355f2dbfd3Robert Mustacchi	if (nb->amd_nb_cfgspace != NULL) {
356f2dbfd3Robert Mustacchi		pci_config_teardown(&nb->amd_nb_cfgspace);
357f2dbfd3Robert Mustacchi	}
358f2dbfd3Robert Mustacchi	kmem_free(nb, sizeof (amdf17nb_t));
359f2dbfd3Robert Mustacchi}
360f2dbfd3Robert Mustacchi
361f2dbfd3Robert Mustacchistatic void
362f2dbfd3Robert Mustacchiamdf17nbdf_cleanup_df(amdf17df_t *df)
363f2dbfd3Robert Mustacchi{
364f2dbfd3Robert Mustacchi	if (df == NULL)
365f2dbfd3Robert Mustacchi		return;
366f2dbfd3Robert Mustacchi
367f2dbfd3Robert Mustacchi	if (df->amd_df_f0_cfgspace != NULL) {
368f2dbfd3Robert Mustacchi		pci_config_teardown(&df->amd_df_f0_cfgspace);
369f2dbfd3Robert Mustacchi	}
370f2dbfd3Robert Mustacchi	kmem_free(df, sizeof (amdf17df_t));
371f2dbfd3Robert Mustacchi}
372f2dbfd3Robert Mustacchi
373f2dbfd3Robert Mustacchistatic int
374f2dbfd3Robert Mustacchiamdf17nbdf_smn_read(amdf17nbdf_t *nbdf, amdf17nb_t *nb, uint32_t addr,
375f2dbfd3Robert Mustacchi    uint32_t *valp)
376f2dbfd3Robert Mustacchi{
377f2dbfd3Robert Mustacchi	VERIFY(MUTEX_HELD(&nbdf->amd_nbdf_lock));
378f2dbfd3Robert Mustacchi
379f2dbfd3Robert Mustacchi	pci_config_put32(nb->amd_nb_cfgspace, AMDF17_NB_SMN_ADDR, addr);
380f2dbfd3Robert Mustacchi	*valp = pci_config_get32(nb->amd_nb_cfgspace, AMDF17_NB_SMN_DATA);
381f2dbfd3Robert Mustacchi
382f2dbfd3Robert Mustacchi	return (0);
383f2dbfd3Robert Mustacchi}
384f2dbfd3Robert Mustacchi
385f2dbfd3Robert Mustacchistatic int
386f2dbfd3Robert Mustacchiamdf17nbdf_temp_read(amdf17nbdf_t *nbdf, amdf17nb_t *nb)
387f2dbfd3Robert Mustacchi{
388f2dbfd3Robert Mustacchi	int ret;
389f2dbfd3Robert Mustacchi	uint32_t reg, rawtemp, decimal;
390f2dbfd3Robert Mustacchi
391f2dbfd3Robert Mustacchi	ASSERT(MUTEX_HELD(&nbdf->amd_nbdf_lock));
392f2dbfd3Robert Mustacchi
393f2dbfd3Robert Mustacchi	/*
394f2dbfd3Robert Mustacchi	 * Update the last read time first. Even if this fails, we want to make
395f2dbfd3Robert Mustacchi	 * sure that we latch the fact that we tried.
396f2dbfd3Robert Mustacchi	 */
397f2dbfd3Robert Mustacchi	nb->amd_nb_temp_last_read = gethrtime();
398f2dbfd3Robert Mustacchi	if ((ret = amdf17nbdf_smn_read(nbdf, nb, AMDF17_SMU_THERMAL_CURTEMP,
399f2dbfd3Robert Mustacchi	    &reg)) != 0) {
400f2dbfd3Robert Mustacchi		return (ret);
401f2dbfd3Robert Mustacchi	}
402f2dbfd3Robert Mustacchi
403f2dbfd3Robert Mustacchi	nb->amd_nb_temp_reg = reg;
404f2dbfd3Robert Mustacchi
405f2dbfd3Robert Mustacchi	/*
406f2dbfd3Robert Mustacchi	 * Take the primary temperature value and break apart its decimal value
407f2dbfd3Robert Mustacchi	 * from its main value.
408f2dbfd3Robert Mustacchi	 */
409f2dbfd3Robert Mustacchi	rawtemp = AMDF17_SMU_THERMAL_CURTEMP_TEMPERATURE(reg);
410f2dbfd3Robert Mustacchi	decimal = rawtemp & AMDF17_SMU_THERMAL_CURTEMP_BITS_MASK;
411f2dbfd3Robert Mustacchi	rawtemp = rawtemp >> AMDF17_SMU_THERMAL_CURTEMP_DECIMAL_BITS;
412f2dbfd3Robert Mustacchi
413f2dbfd3Robert Mustacchi	if ((reg & AMDF17_SMU_THERMAL_CURTEMP_RANGE_SEL) != 0) {
414f2dbfd3Robert Mustacchi		rawtemp += AMDF17_SMU_THERMAL_CURTEMP_RANGE_ADJ;
415f2dbfd3Robert Mustacchi	}
416f2dbfd3Robert Mustacchi	rawtemp += nb->amd_nb_temp_off;
417f2dbfd3Robert Mustacchi	nb->amd_nb_temp = rawtemp << AMDF17_SMU_THERMAL_CURTEMP_DECIMAL_BITS;
418f2dbfd3Robert Mustacchi	nb->amd_nb_temp += decimal;
419f2dbfd3Robert Mustacchi
420f2dbfd3Robert Mustacchi	return (0);
421f2dbfd3Robert Mustacchi}
422f2dbfd3Robert Mustacchi
423f2dbfd3Robert Mustacchistatic int
424f2dbfd3Robert Mustacchiamdf17nbdf_temp_init(amdf17nbdf_t *nbdf, amdf17nb_t *nb)
425f2dbfd3Robert Mustacchi{
426f2dbfd3Robert Mustacchi	uint_t i, family;
427f2dbfd3Robert Mustacchi	char buf[256];
428f2dbfd3Robert Mustacchi
429f2dbfd3Robert Mustacchi	if (cpuid_getbrandstr(CPU, buf, sizeof (buf)) >= sizeof (buf)) {
430f2dbfd3Robert Mustacchi		dev_err(nb->amd_nb_dip, CE_WARN, "!failed to read processor "
431f2dbfd3Robert Mustacchi		    "brand string, brand larger than internal buffer");
432f2dbfd3Robert Mustacchi		return (EOVERFLOW);
433f2dbfd3Robert Mustacchi	}
434f2dbfd3Robert Mustacchi
435f2dbfd3Robert Mustacchi	family = cpuid_getfamily(CPU);
436f2dbfd3Robert Mustacchi
437f2dbfd3Robert Mustacchi	for (i = 0; amdf17nbdf_offsets[i].amd_nbdfo_brand != NULL; i++) {
438f2dbfd3Robert Mustacchi		if (family != amdf17nbdf_offsets[i].amd_nbdfo_family)
439f2dbfd3Robert Mustacchi			continue;
440f2dbfd3Robert Mustacchi		if (strncmp(buf, amdf17nbdf_offsets[i].amd_nbdfo_brand,
441f2dbfd3Robert Mustacchi		    strlen(amdf17nbdf_offsets[i].amd_nbdfo_brand)) == 0) {
442f2dbfd3Robert Mustacchi			nb->amd_nb_temp_off =
443f2dbfd3Robert Mustacchi			    amdf17nbdf_offsets[i].amd_nbdfo_off;
444f2dbfd3Robert Mustacchi			break;
445f2dbfd3Robert Mustacchi		}
446f2dbfd3Robert Mustacchi	}
447f2dbfd3Robert Mustacchi
448f2dbfd3Robert Mustacchi	return (amdf17nbdf_temp_read(nbdf, nb));
449f2dbfd3Robert Mustacchi}
450f2dbfd3Robert Mustacchi
451f2dbfd3Robert Mustacchistatic amdf17nbdf_type_t
452f2dbfd3Robert Mustacchiamdf17nbdf_dip_type(uint16_t dev)
453f2dbfd3Robert Mustacchi{
454f2dbfd3Robert Mustacchi	uint_t i;
455f2dbfd3Robert Mustacchi	const amdf17nbdf_table_t *tp = amdf17nbdf_dev_map;
456f2dbfd3Robert Mustacchi
457f2dbfd3Robert Mustacchi	for (i = 0; tp[i].amd_nbdft_pci_did != PCI_EINVAL16; i++) {
458f2dbfd3Robert Mustacchi		if (tp[i].amd_nbdft_pci_did == dev) {
459f2dbfd3Robert Mustacchi			return (tp[i].amd_nbdft_type);
460f2dbfd3Robert Mustacchi		}
461f2dbfd3Robert Mustacchi	}
462f2dbfd3Robert Mustacchi
463f2dbfd3Robert Mustacchi	return (AMD_NBDF_TYPE_UNKNOWN);
464f2dbfd3Robert Mustacchi}
465f2dbfd3Robert Mustacchi
466f2dbfd3Robert Mustacchistatic boolean_t
467f2dbfd3Robert Mustacchiamdf17nbdf_map(amdf17nbdf_t *nbdf, amdf17nb_t *nb, amdf17df_t *df)
468f2dbfd3Robert Mustacchi{
469f2dbfd3Robert Mustacchi	int ret;
470f2dbfd3Robert Mustacchi	char buf[128];
471f2dbfd3Robert Mustacchi
472f2dbfd3Robert Mustacchi	ASSERT(MUTEX_HELD(&nbdf->amd_nbdf_lock));
473f2dbfd3Robert Mustacchi
474f2dbfd3Robert Mustacchi	/*
475f2dbfd3Robert Mustacchi	 * This means that we encountered a duplicate. We're going to stop
476f2dbfd3Robert Mustacchi	 * processing, but we're not going to fail its attach at this point.
477f2dbfd3Robert Mustacchi	 */
478f2dbfd3Robert Mustacchi	if (nb->amd_nb_df != NULL) {
479f2dbfd3Robert Mustacchi		dev_err(nb->amd_nb_dip, CE_WARN, "!trying to map NB %u/%u/%u "
480f2dbfd3Robert Mustacchi		    "to DF procnode %u, but NB is already mapped to DF "
481f2dbfd3Robert Mustacchi		    "procnode %u!",
482f2dbfd3Robert Mustacchi		    nb->amd_nb_bus, nb->amd_nb_dev, nb->amd_nb_func,
483f2dbfd3Robert Mustacchi		    df->amd_df_procnodeid, nb->amd_nb_df->amd_df_procnodeid);
484f2dbfd3Robert Mustacchi		return (B_TRUE);
485f2dbfd3Robert Mustacchi	}
486f2dbfd3Robert Mustacchi
487f2dbfd3Robert Mustacchi	/*
488f2dbfd3Robert Mustacchi	 * Now that we have found a mapping, initialize our temperature
489f2dbfd3Robert Mustacchi	 * information and create the minor node.
490f2dbfd3Robert Mustacchi	 */
491f2dbfd3Robert Mustacchi	nb->amd_nb_procnodeid = df->amd_df_procnodeid;
492f2dbfd3Robert Mustacchi	nb->amd_nb_temp_minor = id_alloc(nbdf->amd_nbdf_minors);
493f2dbfd3Robert Mustacchi
494f2dbfd3Robert Mustacchi	if ((ret = amdf17nbdf_temp_init(nbdf, nb)) != 0) {
495f2dbfd3Robert Mustacchi		dev_err(nb->amd_nb_dip, CE_WARN, "!failed to init SMN "
496f2dbfd3Robert Mustacchi		    "temperature data on node %u: %d", nb->amd_nb_procnodeid,
497f2dbfd3Robert Mustacchi		    ret);
498f2dbfd3Robert Mustacchi		return (B_FALSE);
499f2dbfd3Robert Mustacchi	}
500f2dbfd3Robert Mustacchi
501f2dbfd3Robert Mustacchi	if (snprintf(buf, sizeof (buf), "procnode.%u", nb->amd_nb_procnodeid) >=
502f2dbfd3Robert Mustacchi	    sizeof (buf)) {
503f2dbfd3Robert Mustacchi		dev_err(nb->amd_nb_dip, CE_WARN, "!unexpected buffer name "
504f2dbfd3Robert Mustacchi		    "overrun assembling temperature minor %u",
505f2dbfd3Robert Mustacchi		    nb->amd_nb_procnodeid);
506f2dbfd3Robert Mustacchi		return (B_FALSE);
507f2dbfd3Robert Mustacchi	}
508f2dbfd3Robert Mustacchi
509f2dbfd3Robert Mustacchi	if (ddi_create_minor_node(nb->amd_nb_dip, buf, S_IFCHR,
510f2dbfd3Robert Mustacchi	    nb->amd_nb_temp_minor, DDI_NT_SENSOR_TEMP_CPU, 0) != DDI_SUCCESS) {
511f2dbfd3Robert Mustacchi		dev_err(nb->amd_nb_dip, CE_WARN, "!failed to create minor node "
512f2dbfd3Robert Mustacchi		    "%s", buf);
513f2dbfd3Robert Mustacchi		return (B_FALSE);
514f2dbfd3Robert Mustacchi	}
515f2dbfd3Robert Mustacchi
516f2dbfd3Robert Mustacchi	/*
517f2dbfd3Robert Mustacchi	 * Now that's it's all done, note that they're mapped to each other.
518f2dbfd3Robert Mustacchi	 */
519f2dbfd3Robert Mustacchi	nb->amd_nb_df = df;
520f2dbfd3Robert Mustacchi	df->amd_df_nb = nb;
521f2dbfd3Robert Mustacchi
522f2dbfd3Robert Mustacchi	return (B_TRUE);
523f2dbfd3Robert Mustacchi}
524f2dbfd3Robert Mustacchi
525f2dbfd3Robert Mustacchistatic boolean_t
526f2dbfd3Robert Mustacchiamdf17nbdf_add_nb(amdf17nbdf_t *nbdf, amdf17nb_t *nb)
527f2dbfd3Robert Mustacchi{
528f2dbfd3Robert Mustacchi	amdf17df_t *df;
529f2dbfd3Robert Mustacchi	boolean_t ret = B_TRUE;
530f2dbfd3Robert Mustacchi
531f2dbfd3Robert Mustacchi	mutex_enter(&nbdf->amd_nbdf_lock);
532f2dbfd3Robert Mustacchi	list_insert_tail(&nbdf->amd_nbdf_nbs, nb);
533f2dbfd3Robert Mustacchi	for (df = list_head(&nbdf->amd_nbdf_dfs); df != NULL;
534f2dbfd3Robert Mustacchi	    df = list_next(&nbdf->amd_nbdf_dfs, df)) {
535f2dbfd3Robert Mustacchi		if (nb->amd_nb_bus == df->amd_df_iobus) {
536f2dbfd3Robert Mustacchi			ret = amdf17nbdf_map(nbdf, nb, df);
537f2dbfd3Robert Mustacchi			break;
538f2dbfd3Robert Mustacchi		}
539f2dbfd3Robert Mustacchi	}
540f2dbfd3Robert Mustacchi	mutex_exit(&nbdf->amd_nbdf_lock);
541f2dbfd3Robert Mustacchi
542f2dbfd3Robert Mustacchi	return (ret);
543f2dbfd3Robert Mustacchi}
544f2dbfd3Robert Mustacchi
545f2dbfd3Robert Mustacchistatic boolean_t
546f2dbfd3Robert Mustacchiamdf17nbdf_add_df(amdf17nbdf_t *nbdf, amdf17df_t *df)
547f2dbfd3Robert Mustacchi{
548f2dbfd3Robert Mustacchi	amdf17nb_t *nb;
549f2dbfd3Robert Mustacchi	boolean_t ret = B_TRUE;
550f2dbfd3Robert Mustacchi
551f2dbfd3Robert Mustacchi	mutex_enter(&nbdf->amd_nbdf_lock);
552f2dbfd3Robert Mustacchi	list_insert_tail(&nbdf->amd_nbdf_dfs, df);
553f2dbfd3Robert Mustacchi	for (nb = list_head(&nbdf->amd_nbdf_nbs); nb != NULL;
554f2dbfd3Robert Mustacchi	    nb = list_next(&nbdf->amd_nbdf_nbs, nb)) {
555f2dbfd3Robert Mustacchi		if (nb->amd_nb_bus == df->amd_df_iobus) {
556f2dbfd3Robert Mustacchi			ret = amdf17nbdf_map(nbdf, nb, df);
557f2dbfd3Robert Mustacchi		}
558f2dbfd3Robert Mustacchi	}
559f2dbfd3Robert Mustacchi	mutex_exit(&nbdf->amd_nbdf_lock);
560f2dbfd3Robert Mustacchi
561f2dbfd3Robert Mustacchi	return (ret);
562f2dbfd3Robert Mustacchi}
563f2dbfd3Robert Mustacchi
564f2dbfd3Robert Mustacchistatic boolean_t
565f2dbfd3Robert Mustacchiamdf17nbdf_attach_nb(amdf17nbdf_t *nbdf, dev_info_t *dip, ddi_acc_handle_t hdl,
566f2dbfd3Robert Mustacchi    uint_t bus, uint_t dev, uint_t func)
567f2dbfd3Robert Mustacchi{
568f2dbfd3Robert Mustacchi	amdf17nb_t *nb;
569f2dbfd3Robert Mustacchi
570f2dbfd3Robert Mustacchi	nb = kmem_zalloc(sizeof (amdf17nb_t), KM_SLEEP);
571f2dbfd3Robert Mustacchi	nb->amd_nb_dip = dip;
572f2dbfd3Robert Mustacchi	nb->amd_nb_cfgspace = hdl;
573f2dbfd3Robert Mustacchi	nb->amd_nb_bus = bus;
574f2dbfd3Robert Mustacchi	nb->amd_nb_dev = dev;
575f2dbfd3Robert Mustacchi	nb->amd_nb_func = func;
576f2dbfd3Robert Mustacchi	/*
577f2dbfd3Robert Mustacchi	 * Set this to a value we won't get from the processor.
578f2dbfd3Robert Mustacchi	 */
579f2dbfd3Robert Mustacchi	nb->amd_nb_procnodeid = UINT_MAX;
580f2dbfd3Robert Mustacchi
581f2dbfd3Robert Mustacchi	if (!amdf17nbdf_add_nb(nbdf, nb)) {
582f2dbfd3Robert Mustacchi		amdf17nbdf_cleanup_nb(nbdf, nb);
583f2dbfd3Robert Mustacchi		return (B_FALSE);
584f2dbfd3Robert Mustacchi	}
585f2dbfd3Robert Mustacchi
586f2dbfd3Robert Mustacchi	return (B_TRUE);
587f2dbfd3Robert Mustacchi}
588f2dbfd3Robert Mustacchi
589f2dbfd3Robert Mustacchistatic boolean_t
590f2dbfd3Robert Mustacchiamdf17nbdf_attach_df(amdf17nbdf_t *nbdf, dev_info_t *dip, ddi_acc_handle_t hdl,
591f2dbfd3Robert Mustacchi    uint_t bus, uint_t dev, uint_t func)
592f2dbfd3Robert Mustacchi{
593f2dbfd3Robert Mustacchi	amdf17df_t *df;
594f2dbfd3Robert Mustacchi
595f2dbfd3Robert Mustacchi	if (bus != AMDF17_DF_BUSNO) {
596f2dbfd3Robert Mustacchi		dev_err(dip, CE_WARN, "!encountered data fabric device with "
597f2dbfd3Robert Mustacchi		    "unexpected PCI bus assignment, found 0x%x, expected 0x%x",
598f2dbfd3Robert Mustacchi		    bus, AMDF17_DF_BUSNO);
599f2dbfd3Robert Mustacchi		return (B_FALSE);
600f2dbfd3Robert Mustacchi	}
601f2dbfd3Robert Mustacchi
602f2dbfd3Robert Mustacchi	if (dev < AMDF17_DF_FIRST_DEVICE) {
603f2dbfd3Robert Mustacchi		dev_err(dip, CE_WARN, "!encountered data fabric device with "
604f2dbfd3Robert Mustacchi		    "PCI device assignment below the first minimum device "
605f2dbfd3Robert Mustacchi		    "(0x%x): 0x%x", AMDF17_DF_FIRST_DEVICE, dev);
606f2dbfd3Robert Mustacchi		return (B_FALSE);
607f2dbfd3Robert Mustacchi	}
608f2dbfd3Robert Mustacchi
609f2dbfd3Robert Mustacchi	/*
610f2dbfd3Robert Mustacchi	 * At the moment we only care about function 0. However, we may care
611f2dbfd3Robert Mustacchi	 * about Function 4 in the future which has access to the FICAA.
612f2dbfd3Robert Mustacchi	 * However, only function zero should ever be attached, so this is just
613f2dbfd3Robert Mustacchi	 * an extra precaution.
614f2dbfd3Robert Mustacchi	 */
615f2dbfd3Robert Mustacchi	if (func != 0) {
616f2dbfd3Robert Mustacchi		dev_err(dip, CE_WARN, "!encountered data fabric device with "
617f2dbfd3Robert Mustacchi		    "unxpected PCI function assignment, found 0x%x, expected "
618f2dbfd3Robert Mustacchi		    "0x0", func);
619f2dbfd3Robert Mustacchi		return (B_FALSE);
620f2dbfd3Robert Mustacchi	}
621f2dbfd3Robert Mustacchi
622f2dbfd3Robert Mustacchi	df = kmem_zalloc(sizeof (amdf17df_t), KM_SLEEP);
623f2dbfd3Robert Mustacchi	df->amd_df_f0_dip = dip;
624f2dbfd3Robert Mustacchi	df->amd_df_f0_cfgspace = hdl;
625f2dbfd3Robert Mustacchi	df->amd_df_procnodeid = dev - AMDF17_DF_FIRST_DEVICE;
626f2dbfd3Robert Mustacchi	df->amd_df_iobus = pci_config_get32(hdl, AMDF17_DF_CFG_ADDR_CTL) &
627f2dbfd3Robert Mustacchi	    AMDF17_DF_CFG_ADDR_CTL_MASK;
628f2dbfd3Robert Mustacchi
629f2dbfd3Robert Mustacchi	if (!amdf17nbdf_add_df(nbdf, df)) {
630f2dbfd3Robert Mustacchi		amdf17nbdf_cleanup_df(df);
631f2dbfd3Robert Mustacchi		return (B_FALSE);
632f2dbfd3Robert Mustacchi	}
633f2dbfd3Robert Mustacchi
634f2dbfd3Robert Mustacchi	return (B_TRUE);
635f2dbfd3Robert Mustacchi}
636f2dbfd3Robert Mustacchi
637f2dbfd3Robert Mustacchistatic int
638f2dbfd3Robert Mustacchiamdf17nbdf_open(dev_t *devp, int flags, int otype, cred_t *credp)
639f2dbfd3Robert Mustacchi{
640f2dbfd3Robert Mustacchi	amdf17nbdf_t *nbdf = amdf17nbdf;
641f2dbfd3Robert Mustacchi	minor_t m;
642f2dbfd3Robert Mustacchi
643f2dbfd3Robert Mustacchi	if (crgetzoneid(credp) != GLOBAL_ZONEID || drv_priv(credp)) {
644f2dbfd3Robert Mustacchi		return (EPERM);
645f2dbfd3Robert Mustacchi	}
646f2dbfd3Robert Mustacchi
647f2dbfd3Robert Mustacchi	if ((flags & (FEXCL | FNDELAY | FWRITE)) != 0) {
648f2dbfd3Robert Mustacchi		return (EINVAL);
649f2dbfd3Robert Mustacchi	}
650f2dbfd3Robert Mustacchi
651f2dbfd3Robert Mustacchi	if (otype != OTYP_CHR) {
652f2dbfd3Robert Mustacchi		return (EINVAL);
653f2dbfd3Robert Mustacchi	}
654f2dbfd3Robert Mustacchi
655f2dbfd3Robert Mustacchi	m = getminor(*devp);
656f2dbfd3Robert Mustacchi
657f2dbfd3Robert Mustacchi	/*
658f2dbfd3Robert Mustacchi	 * Sanity check the minor
659f2dbfd3Robert Mustacchi	 */
660f2dbfd3Robert Mustacchi	mutex_enter(&nbdf->amd_nbdf_lock);
661f2dbfd3Robert Mustacchi	if (amdf17nbdf_lookup_nb(nbdf, m) == NULL) {
662f2dbfd3Robert Mustacchi		mutex_exit(&nbdf->amd_nbdf_lock);
663f2dbfd3Robert Mustacchi		return (ENXIO);
664f2dbfd3Robert Mustacchi	}
665f2dbfd3Robert Mustacchi	mutex_exit(&nbdf->amd_nbdf_lock);
666f2dbfd3Robert Mustacchi
667f2dbfd3Robert Mustacchi	return (0);
668f2dbfd3Robert Mustacchi}
669f2dbfd3Robert Mustacchi
670f2dbfd3Robert Mustacchistatic int
671f2dbfd3Robert Mustacchiamdf17nbdf_ioctl_kind(intptr_t arg, int mode)
672f2dbfd3Robert Mustacchi{
673f2dbfd3Robert Mustacchi	sensor_ioctl_kind_t kind;
674f2dbfd3Robert Mustacchi
675f2dbfd3Robert Mustacchi	bzero(&kind, sizeof (sensor_ioctl_kind_t));
676f2dbfd3Robert Mustacchi	kind.sik_kind = SENSOR_KIND_TEMPERATURE;
677f2dbfd3Robert Mustacchi
678f2dbfd3Robert Mustacchi	if (ddi_copyout((void *)&kind, (void *)arg,
679f2dbfd3Robert Mustacchi	    sizeof (sensor_ioctl_kind_t), mode & FKIOCTL) != 0) {
680f2dbfd3Robert Mustacchi		return (EFAULT);
681f2dbfd3Robert Mustacchi	}
682f2dbfd3Robert Mustacchi
683f2dbfd3Robert Mustacchi	return (0);
684f2dbfd3Robert Mustacchi}
685f2dbfd3Robert Mustacchi
686f2dbfd3Robert Mustacchistatic int
6871045e13Robert Mustacchiamdf17nbdf_ioctl_scalar(amdf17nbdf_t *nbdf, minor_t minor, intptr_t arg,
6881045e13Robert Mustacchi    int mode)
689f2dbfd3Robert Mustacchi{
690f2dbfd3Robert Mustacchi	amdf17nb_t *nb;
691f2dbfd3Robert Mustacchi	hrtime_t diff;
6921045e13Robert Mustacchi	sensor_ioctl_scalar_t scalar;
693f2dbfd3Robert Mustacchi
6941045e13Robert Mustacchi	bzero(&scalar, sizeof (scalar));
695f2dbfd3Robert Mustacchi
696f2dbfd3Robert Mustacchi	mutex_enter(&nbdf->amd_nbdf_lock);
697f2dbfd3Robert Mustacchi	nb = amdf17nbdf_lookup_nb(nbdf, minor);
698f2dbfd3Robert Mustacchi	if (nb == NULL) {
699f2dbfd3Robert Mustacchi		mutex_exit(&nbdf->amd_nbdf_lock);
700f2dbfd3Robert Mustacchi		return (ENXIO);
701f2dbfd3Robert Mustacchi	}
702f2dbfd3Robert Mustacchi
703f2dbfd3Robert Mustacchi	diff = NSEC2MSEC(gethrtime() - nb->amd_nb_temp_last_read);
704f2dbfd3Robert Mustacchi	if (diff > 0 && diff > (hrtime_t)amdf17nbdf_cache_ms) {
705f2dbfd3Robert Mustacchi		int ret;
706f2dbfd3Robert Mustacchi
707f2dbfd3Robert Mustacchi		ret = amdf17nbdf_temp_read(nbdf, nb);
708f2dbfd3Robert Mustacchi		if (ret != 0) {
709f2dbfd3Robert Mustacchi			mutex_exit(&nbdf->amd_nbdf_lock);
710f2dbfd3Robert Mustacchi			return (ret);
711f2dbfd3Robert Mustacchi		}
712f2dbfd3Robert Mustacchi	}
713f2dbfd3Robert Mustacchi
7141045e13Robert Mustacchi	scalar.sis_unit = SENSOR_UNIT_CELSIUS;
7151045e13Robert Mustacchi	scalar.sis_value = nb->amd_nb_temp;
7161045e13Robert Mustacchi	scalar.sis_gran = AMDF17_THERMAL_GRANULARITY;
717f2dbfd3Robert Mustacchi	mutex_exit(&nbdf->amd_nbdf_lock);
718f2dbfd3Robert Mustacchi
7191045e13Robert Mustacchi	if (ddi_copyout(&scalar, (void *)arg, sizeof (scalar),
720f2dbfd3Robert Mustacchi	    mode & FKIOCTL) != 0) {
721f2dbfd3Robert Mustacchi		return (EFAULT);
722f2dbfd3Robert Mustacchi	}
723f2dbfd3Robert Mustacchi
724f2dbfd3Robert Mustacchi	return (0);
725f2dbfd3Robert Mustacchi}
726f2dbfd3Robert Mustacchi
727f2dbfd3Robert Mustacchistatic int
728f2dbfd3Robert Mustacchiamdf17nbdf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
729f2dbfd3Robert Mustacchi    int *rvalp)
730f2dbfd3Robert Mustacchi{
731f2dbfd3Robert Mustacchi	minor_t m;
732f2dbfd3Robert Mustacchi	amdf17nbdf_t *nbdf = amdf17nbdf;
733f2dbfd3Robert Mustacchi
734f2dbfd3Robert Mustacchi	if ((mode & FREAD) == 0) {
735f2dbfd3Robert Mustacchi		return (EINVAL);
736f2dbfd3Robert Mustacchi	}
737f2dbfd3Robert Mustacchi
738f2dbfd3Robert Mustacchi	m = getminor(dev);
739f2dbfd3Robert Mustacchi
740f2dbfd3Robert Mustacchi	switch (cmd) {
7411045e13Robert Mustacchi	case SENSOR_IOCTL_KIND:
742f2dbfd3Robert Mustacchi		return (amdf17nbdf_ioctl_kind(arg, mode));
7431045e13Robert Mustacchi	case SENSOR_IOCTL_SCALAR:
7441045e13Robert Mustacchi		return (amdf17nbdf_ioctl_scalar(nbdf, m, arg, mode));
745f2dbfd3Robert Mustacchi	default:
746f2dbfd3Robert Mustacchi		return (ENOTTY);
747f2dbfd3Robert Mustacchi	}
748f2dbfd3Robert Mustacchi}
749f2dbfd3Robert Mustacchi
750f2dbfd3Robert Mustacchi/*
751f2dbfd3Robert Mustacchi * We don't really do any state tracking on close, so for now, just allow it to
752f2dbfd3Robert Mustacchi * always succeed.
753f2dbfd3Robert Mustacchi */
754f2dbfd3Robert Mustacchistatic int
755f2dbfd3Robert Mustacchiamdf17nbdf_close(dev_t dev, int flags, int otype, cred_t *credp)
756f2dbfd3Robert Mustacchi{
757f2dbfd3Robert Mustacchi	return (0);
758f2dbfd3Robert Mustacchi}
759f2dbfd3Robert Mustacchi
760f2dbfd3Robert Mustacchistatic int
761f2dbfd3Robert Mustacchiamdf17nbdf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
762f2dbfd3Robert Mustacchi{
763f2dbfd3Robert Mustacchi	uint_t nregs;
764f2dbfd3Robert Mustacchi	int *regs;
765f2dbfd3Robert Mustacchi	uint_t bus, dev, func;
766f2dbfd3Robert Mustacchi	uint16_t pci_did;
767f2dbfd3Robert Mustacchi	ddi_acc_handle_t pci_hdl;
768f2dbfd3Robert Mustacchi	amdf17nbdf_type_t type;
769f2dbfd3Robert Mustacchi	amdf17nbdf_t *nbdf = amdf17nbdf;
770f2dbfd3Robert Mustacchi
771f2dbfd3Robert Mustacchi	if (cmd == DDI_RESUME)
772f2dbfd3Robert Mustacchi		return (DDI_SUCCESS);
773f2dbfd3Robert Mustacchi	if (cmd != DDI_ATTACH)
774f2dbfd3Robert Mustacchi		return (DDI_FAILURE);
775f2dbfd3Robert Mustacchi
776f2dbfd3Robert Mustacchi	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg",
777f2dbfd3Robert Mustacchi	    &regs, &nregs) != DDI_PROP_SUCCESS) {
778f2dbfd3Robert Mustacchi		dev_err(dip, CE_WARN, "!failed to find pci 'reg' property");
779f2dbfd3Robert Mustacchi		return (DDI_FAILURE);
780f2dbfd3Robert Mustacchi	}
781f2dbfd3Robert Mustacchi
782f2dbfd3Robert Mustacchi	if (nregs < 1) {
783f2dbfd3Robert Mustacchi		ddi_prop_free(regs);