1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2020 Oxide Computer Company
*/
#ifndef _AMDZEN_H
#define _AMDZEN_H
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/list.h>
#include <sys/pci.h>
#include <sys/taskq.h>
#include <sys/bitmap.h>
/*
* This header describes properties of the data fabric and our internal state
* for the Zen Nexus driver.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* The data fabric devices are always defined to be on PCI bus zero starting at
* device 0x18.
*/
#define AMDZEN_DF_BUSNO 0x00
#define AMDZEN_DF_FIRST_DEVICE 0x18
/*
* The maximum amount of Data Fabric node's we can see. In Zen 1 there were up
* to four per package.
*/
#define AMDZEN_MAX_DFS 0x8
/*
* The maximum number of PCI functions we expect to encounter on the data
* fabric.
*/
#define AMDZEN_MAX_DF_FUNCS 0x8
/*
* Registers in the data fabric space that we care about for the purposes of the
* nexus driver understanding itself.
*/
/*
* This set of registers provides us access to the count of instances in the
* data fabric and then a number of different pieces of information about them
* like their type. Note, these registers require indirect access because the
* information cannot be broadcast.
*/
#define AMDZEN_DF_F0_FBICNT 0x40
#define AMDZEN_DF_F0_FBICNT_COUNT(x) BITX(x, 7, 0)
#define AMDZEN_DF_F0_FBIINFO0 0x44
#define AMDZEN_DF_F0_FBIINFO0_TYPE(x) BITX(x, 3, 0)
typedef enum {
AMDZEN_DF_TYPE_CCM = 0,
AMDZEN_DF_TYPE_GCM,
AMDZEN_DF_TYPE_NCM,
AMDZEN_DF_TYPE_IOMS,
AMDZEN_DF_TYPE_CS,
AMDZEN_DF_TYPE_TCDX,
AMDZEN_DF_TYPE_PIE,
AMDZEN_DF_TYPE_SPF,
AMDZEN_DF_TYPE_LLC,
AMDZEN_DF_TYPE_CAKE
} amdzen_df_type_t;
#define AMDZEN_DF_F0_FBIINFO0_SDP_WIDTH(x) BITX(x, 5, 4)
typedef enum {
AMDZEN_DF_SDP_W_64 = 0,
AMDZEN_DF_SDP_W_128,
AMDZEN_DF_SDP_W_256,
AMDZEN_DF_SDP_W_512
} amdzen_df_sdp_width_t;
#define AMDZEN_DF_F0_FBIINFO0_ENABLED(x) BITX(x, 6, 6)
#define AMDZEN_DF_F0_FBIINFO0_FTI_WIDTH(x) BITX(x, 9, 8)
typedef enum {
AMDZEN_DF_FTI_W_64 = 0,
AMDZEN_DF_FTI_W_128,
AMDZEN_DF_FTI_W_256,
AMDZEN_DF_FTI_W_512
} amdzen_df_fti_width_t;
#define AMDZEN_DF_F0_FBIINFO0_SDP_PCOUNT(x) BITX(x, 13, 12)
#define AMDZEN_DF_F0_FBIINFO0_FTI_PCOUNT(x) BITX(x, 18, 16)
#define AMDZEN_DF_F0_FBIINFO0_HAS_MCA(x) BITX(x, 23, 23)
#define AMDZEN_DF_F0_FBIINFO0_SUBTYPE(x) BITX(x, 26, 24)
#define AMDZEN_DF_SUBTYPE_NONE 0
typedef enum {
AMDZEN_DF_CAKE_SUBTYPE_GMI = 1,
AMDZEN_DF_CAKE_SUBTYPE_xGMI = 2
} amdzen_df_cake_subtype_t;
typedef enum {
AMDZEN_DF_IOM_SUBTYPE_IOHUB = 1,
} amdzen_df_iom_subtype_t;
typedef enum {
AMDZEN_DF_CS_SUBTYPE_UMC = 1,
AMDZEN_DF_CS_SUBTYPE_CCIX = 2
} amdzen_df_cs_subtype_t;
#define AMDZEN_DF_F0_FBIINFO1 0x48
#define AMDZEN_DF_F0_FBIINFO1_FTI0_NINSTID(x) BITX(x, 7, 0)
#define AMDZEN_DF_F0_FBIINFO1_FTI1_NINSTID(x) BITX(x, 15, 8)
#define AMDZEN_DF_F0_FBIINFO1_FTI2_NINSTID(x) BITX(x, 23, 16)
#define AMDZEN_DF_F0_FBIINFO1_FTI3_NINSTID(x) BITX(x, 31, 24)
#define AMDZEN_DF_F0_FBIINFO2 0x4c
#define AMDZEN_DF_F0_FBIINFO2_FTI4_NINSTID(x) BITX(x, 7, 0)
#define AMDZEN_DF_F0_FBIINFO2_FTI5_NINSTID(x) BITX(x, 15, 8)
#define AMDZEN_DF_F0_FBIINFO3 0x50
#define AMDZEN_DF_F0_FBIINFO3_INSTID(x) BITX(x, 7, 0)
#define AMDZEN_DF_F0_FBIINFO3_FABID(x) BITX(x, 13, 8)
/*
* This register contains the information about the configuration of PCIe buses.
* We care about finding which one has our BUS A, which is required to map it to
* the northbridge.
*/
#define AMDZEN_DF_F0_CFG_ADDR_CTL 0x84
#define AMDZEN_DF_F0_CFG_ADDR_CTL_BUS_NUM(x) BITX(x, 7, 0)
/*
* Registers that describe how the system is actually put together.
*/
#define AMDZEN_DF_F1_SYSCFG 0x200
#define AMDZEN_DF_F1_SYSCFG_DIE_PRESENT(X) BITX(x, 7, 0)
#define AMDZEN_DF_F1_SYSCFG_DIE_TYPE(x) BITX(x, 18, 11)
#define AMDZEN_DF_F1_SYSCFG_MYDIE_TYPE(x) BITX(x, 24, 23)
typedef enum {
AMDZEN_DF_DIE_TYPE_CPU = 0,
AMDZEN_DF_DIE_TYPE_APU,
AMDZEN_DF_DIE_TYPE_dGPU
} amdzen_df_die_type_t;
#define AMDZEN_DF_F1_SYSCFG_OTHERDIE_TYPE(x) BITX(x, 26, 25)
#define AMDZEN_DF_F1_SYSCFG_OTHERSOCK(x) BITX(x, 27, 27)
#define AMDZEN_DF_F1_SYSCFG_NODEID(x) BITX(x, 30, 28)
#define AMDZEN_DF_F1_FIDMASK0 0x208
#define AMDZEN_DF_F1_FIDMASK0_COMP_MASK(x) BITX(x, 9, 0)
#define AMDZEN_DF_F1_FIDMASK0_NODE_MASK(x) BITX(x, 25, 16)
#define AMDZEN_DF_F1_FIDMASK1 0x20C
#define AMDZEN_DF_F1_FIDMASK1_NODE_SHIFT(x) BITX(x, 3, 0)
#define AMDZEN_DF_F1_FIDMASK1_SKT_SHIFT(x) BITX(x, 9, 8)
#define AMDZEN_DF_F1_FIDMASK1_DIE_MASK(x) BITX(x, 18, 16)
#define AMDZEN_DF_F1_FIDMASK1_SKT_MASK(x) BITX(x, 26, 24)
/*
* These two registers define information about the PSP and SMU on local and
* remote dies (from the context of the DF instance). The bits are the same.
*/
#define AMDZEN_DF_F1_PSPSMU_LOCAL 0x268
#define AMDZEN_DF_F1_PSPSMU_REMOTE 0x268
#define AMDZEN_DF_F1_PSPSMU_SMU_VALID(x) BITX(x, 0, 0)
#define AMDZEN_DF_F1_PSPSMU_SMU_UNITID(x) BITX(x, 6, 1)
#define AMDZEN_DF_F1_PSPSMU_SMU_COMPID(x) BITX(x, 15, 8)
#define AMDZEN_DF_F1_PSPSMU_PSP_VALID(x) BITX(x, 16, 16)
#define AMDZEN_DF_F1_PSPSMU_PSP_UNITID(x) BITX(x, 22, 17)
#define AMDZEN_DF_F1_PSPSMU_PSP_COMPID(x) BITX(x, 31, 24)
#define AMDZEN_DF_F1_CAKE_ENCR 0x2cc
/*
* These registers are used to define Indirect Access, commonly known as FICAA
* and FICAD for the system. While there are multiple copies of the indirect
* access registers in device 4, we're only allowed access to one set of those
* (which are the ones present here). Specifically the OS is given access to set
* 3.
*/
#define AMDZEN_DF_F4_FICAA 0x5c
#define AMDZEN_DF_F4_FICAA_TARG_INST (1 << 0)
#define AMDZEN_DF_F4_FICAA_SET_REG(x) ((x) & 0x3fc)
#define AMDZEN_DF_F4_FICAA_SET_FUNC(x) (((x) & 0x7) << 11)
#define AMDZEN_DF_F4_FICAA_SET_64B (1 << 14)
#define AMDZEN_DF_F4_FICAA_SET_INST(x) (((x) & 0xff) << 16)
#define AMDZEN_DF_F4_FICAD_LO 0x98
#define AMDZEN_DF_F4_FICAD_HI 0x9c
/*
* Northbridge registers that are relevant for the nexus, mostly for SMN.
*/
#define AMDZEN_NB_SMN_ADDR 0x60
#define AMDZEN_NB_SMN_DATA 0x64
/*
* AMD PCI ID for reference
*/
#define AMDZEN_PCI_VID_AMD 0x1022
/*
* Hygon PCI ID for reference
*/
#define AMDZEN_PCI_VID_HYGON 0x1d94
typedef enum {
AMDZEN_STUB_TYPE_DF,
AMDZEN_STUB_TYPE_NB
} amdzen_stub_type_t;
typedef struct {
list_node_t azns_link;
dev_info_t *azns_dip;
uint16_t azns_vid;
uint16_t azns_did;
uint16_t azns_bus;
uint16_t azns_dev;
uint16_t azns_func;
ddi_acc_handle_t azns_cfgspace;
} amdzen_stub_t;
typedef enum {
AMDZEN_DFE_F_MCA = 1 << 0,
AMDZEN_DFE_F_ENABLED = 1 << 1
} amdzen_df_ent_flags_t;
typedef struct {
uint8_t adfe_drvid;
amdzen_df_ent_flags_t adfe_flags;
amdzen_df_type_t adfe_type;
uint8_t adfe_subtype;
uint8_t adfe_fabric_id;
uint8_t adfe_inst_id;
amdzen_df_sdp_width_t adfe_sdp_width;
amdzen_df_fti_width_t adfe_fti_width;
uint8_t adfe_sdp_count;
uint8_t adfe_fti_count;
uint32_t adfe_info0;
uint32_t adfe_info1;
uint32_t adfe_info2;
uint32_t adfe_info3;
uint32_t adfe_syscfg;
uint32_t adfe_mask0;
uint32_t adfe_mask1;
} amdzen_df_ent_t;
typedef enum {
AMDZEN_DF_F_VALID = 1 << 0,
AMDZEN_DF_F_FOUND_NB = 1 << 1
} amdzen_df_flags_t;
typedef struct {
amdzen_df_flags_t adf_flags;
uint_t adf_nb_busno;
amdzen_stub_t *adf_funcs[AMDZEN_MAX_DF_FUNCS];
amdzen_stub_t *adf_nb;
uint_t adf_nents;
amdzen_df_ent_t *adf_ents;
uint32_t adf_nodeid;
uint32_t adf_syscfg;
uint32_t adf_mask0;
uint32_t adf_mask1;
} amdzen_df_t;
typedef enum {
AMDZEN_F_UNSUPPORTED = 1 << 0,
AMDZEN_F_DEVICE_ERROR = 1 << 1,
AMDZEN_F_MAP_ERROR = 1 << 2,
AMDZEN_F_SCAN_DISPATCHED = 1 << 3,
AMDZEN_F_SCAN_COMPLETE = 1 << 4,
AMDZEN_F_ATTACH_DISPATCHED = 1 << 5,
AMDZEN_F_ATTACH_COMPLETE = 1 << 6
} amdzen_flags_t;
#define AMDZEN_F_TASKQ_MASK (AMDZEN_F_SCAN_DISPATCHED | \
AMDZEN_F_SCAN_COMPLETE | AMDZEN_F_ATTACH_DISPATCHED | \
AMDZEN_F_ATTACH_COMPLETE)
typedef struct amdzen {
kmutex_t azn_mutex;
kcondvar_t azn_cv;
amdzen_flags_t azn_flags;
dev_info_t *azn_dip;
taskqid_t azn_taskqid;
uint_t azn_nscanned;
uint_t azn_npresent;
list_t azn_df_stubs;
list_t azn_nb_stubs;
uint_t azn_ndfs;
amdzen_df_t azn_dfs[AMDZEN_MAX_DFS];
} amdzen_t;
typedef enum {
AMDZEN_C_SMNTEMP = 1,
AMDZEN_C_USMN,
AMDZEN_C_ZEN_UDF
} amdzen_child_t;
/*
* Functions for stubs.
*/
extern int amdzen_attach_stub(dev_info_t *, ddi_attach_cmd_t);
extern int amdzen_detach_stub(dev_info_t *, ddi_detach_cmd_t);
#ifdef __cplusplus
}
#endif
#endif /* _AMDZEN_H */
|