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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __P7IOC_H
#define __P7IOC_H
#include <cec.h>
#include <pci.h>
#include <ccan/container_of/container_of.h>
/*
* Memory windows and BUID assignment
*
* - GX BAR assignment
*
* I don't know of any spec here, so we're going to mimmic what
* OPAL seems to be doing:
*
* - BAR 0 : 32M, disabled. We just leave it alone.
* - BAR 1 : 8G, enabled. Appears to correspond to the MMIO
* space of the IOC itself and the PCI IO space
* - BAR 2: 128G,
* - BAR 3: 128G,
* - BAR 4: 128G, all 3 contiguous, forming a single 368G region
* and is used for M32 and M64 PHB windows.
*
* - Memory map
*
* MWIN1 = BAR1 (8G)
* MWIN2 = BAR2,3,4 (384G)
*
* MWIN2 is divided into 6 * 4G regions for use by M32's (*) and
* 6 * 32G regions for use by M64's.
*
* (*) The M32 will typically be configured to only 2G or so, however
* the OS is in control of that setting, and since we have to reserve
* a power of two, we reserve the whole 4G.
*
* - RGC registers: MWIN1 + 0x00000000
* - PHBn IO space: MWIN1 + 0x01000000 + n * 0x00800000 (8M each)
* - PHBn M32 : MWIN2 + n * 0x1_00000000 (4G each)
* - PHBn M64 : MWIN2 + (n + 1) * 0x8_00000000 (32G each)
*
* - BUID map. The RGC has interrupts, each PHB has then its own
* interrupts (errors etc...), 4 LSIs and 256 LSIs so
* respectively 1 BUID for self, 1 for LSIs and 16 for LSIs
*
* We keep all BUIDs below 0x10 reserved. They will be used for things
* like the PSI controller, the NX unit, etc.. in the P7 chip.
*
* RGC : 0x010
* PHBn LSI : 0x040 + n * 0x40 ( 1 BUID)
* PHBn MSI : 0x060 + n * 0x40 (0x10 BUIDs)
*
* -> For routing, each PHB gets a block of 0x40 BUIDs:
*
* from 0x40 * (n + 1) to 0x7f * (n + 1)
*/
/* Some definitions resulting from the above description
*
* Note: A better approach might be to read the GX BAR content
* and isolate the biggest contiguous windows. From there
* we could divide things algorithmically and thus be
* less sensitive to a change in the memory map by the FSP
*/
#define MWIN1_SIZE 0x200000000ul /* MWIN1 is 8G */
#define MWIN2_SIZE 0x6000000000ul /* MWIN2 is 384G */
#define PHB_IO_OFFSET 0x01000000ul /* Offset of PHB IO space in MWIN1 */
#define PHB_IO_SIZE 0x00800000ul
#define PHB_M32_OFFSET 0x0ul /* Offset of PHB M32 space in MWIN2 */
#define PHB_M32_SIZE 0x100000000ul
#define PHB_M64_OFFSET 0x800000000ul /* Offset of PHB M64 space in MWIN2 */
#define PHB_M64_SIZE 0x800000000ul
#define RGC_BUID_OFFSET 0x10 /* Offset of RGC BUID */
#define PHB_BUID_OFFSET 0x40 /* Offset of PHB BUID blocks */
#define PHB_BUID_SIZE 0x40 /* Size of PHB BUID blocks */
#define PHB_BUID_LSI_OFFSET 0x00 /* Offset of LSI in PHB BUID block */
#define PHB_BUID_MSI_OFFSET 0x20 /* Offset of MSI in PHB BUID block */
#define PHB_BUID_MSI_SIZE 0x10 /* Size of PHB MSI BUID block */
#define PHBn_IO_BASE(n) (PHB_IO_OFFSET + (n) * PHB_IO_SIZE)
#define PHBn_M32_BASE(n) (PHB_M32_OFFSET + (n) * PHB_M32_SIZE)
#define PHBn_M64_BASE(n) (PHB_M64_OFFSET + (n) * PHB_M64_SIZE)
#define PHBn_BUID_BASE(n) (PHB_BUID_OFFSET + (n) * PHB_BUID_SIZE)
#define BUID_TO_PHB(buid) (((buid) - PHB_BUID_OFFSET) / PHB_BUID_SIZE)
/* p7ioc has 6 PHBs */
#define P7IOC_NUM_PHBS 6
/* M32 window setting at boot:
*
* To allow for DMA, we need to split the 32-bit PCI address space between
* MMIO and DMA. For now, we use a 2G/2G split with MMIO at the top.
*
* Note: The top 64K of the M32 space are used by MSIs. This is not
* visible here but need to be conveyed to the OS one way or another
*
* Note2: The space reserved in the system address space for M32 is always
* 4G. That we chose to use a smaller portion of it is not relevant to
* the upper levels. To keep things consistent, the offset we apply to
* the window start is also applied on the host side.
*/
#define M32_PCI_START 0x80000000
#define M32_PCI_SIZE 0x80000000
/* PHB registers exist in both a hard coded space and a programmable
* AIB space. We program the latter to the values recommended in the
* documentation:
*
* 0x80000 + n * 0x10000
*/
#define PHBn_ASB_BASE(n) (((n) << 16))
#define PHBn_ASB_SIZE 0x10000ul
#define PHBn_AIB_BASE(n) (0x80000ul + ((n) << 16))
#define PHBn_AIB_SIZE 0x10000ul
/*
* LSI interrupts
*
* The LSI interrupt block supports 8 interrupts. 4 of them are the
* standard PCIe INTA..INTB. The rest is for additional functions
* of the PHB
*/
#define PHB_LSI_PCIE_INTA 0
#define PHB_LSI_PCIE_INTB 1
#define PHB_LSI_PCIE_INTC 2
#define PHB_LSI_PCIE_INTD 3
#define PHB_LSI_PCIE_HOTPLUG 4
#define PHB_LSI_PCIE_PERFCTR 5
#define PHB_LSI_PCIE_UNUSED 6
#define PHB_LSI_PCIE_ERROR 7
/* P7IOC PHB slot states */
#define P7IOC_SLOT_NORMAL PCI_SLOT_STATE_NORMAL
#define P7IOC_SLOT_LINK PCI_SLOT_STATE_LINK
#define P7IOC_SLOT_LINK_START (P7IOC_SLOT_LINK + 1)
#define P7IOC_SLOT_LINK_WAIT (P7IOC_SLOT_LINK + 2)
#define P7IOC_SLOT_HRESET PCI_SLOT_STATE_HRESET
#define P7IOC_SLOT_HRESET_START (P7IOC_SLOT_HRESET + 1)
#define P7IOC_SLOT_HRESET_TRAINING (P7IOC_SLOT_HRESET + 2)
#define P7IOC_SLOT_HRESET_DELAY (P7IOC_SLOT_HRESET + 3)
#define P7IOC_SLOT_HRESET_DELAY2 (P7IOC_SLOT_HRESET + 4)
#define P7IOC_SLOT_FRESET PCI_SLOT_STATE_FRESET
#define P7IOC_SLOT_FRESET_START (P7IOC_SLOT_FRESET + 1)
#define P7IOC_SLOT_FRESET_TRAINING (P7IOC_SLOT_FRESET + 2)
#define P7IOC_SLOT_FRESET_POWER_OFF (P7IOC_SLOT_FRESET + 3)
#define P7IOC_SLOT_FRESET_POWER_ON (P7IOC_SLOT_FRESET + 4)
#define P7IOC_SLOT_FRESET_ASSERT (P7IOC_SLOT_FRESET + 5)
#define P7IOC_SLOT_FRESET_DEASSERT (P7IOC_SLOT_FRESET + 6)
#define P7IOC_SLOT_CRESET PCI_SLOT_STATE_CRESET
#define P7IOC_SLOT_CRESET_START (P7IOC_SLOT_CRESET + 1)
/*
* In order to support error detection and recovery on different
* types of IOCs (e.g. P5IOC, P7IOC, P8IOC), the best bet would
* be make the implementation to be 2 layers: OPAL layer and IOC
* layer. The OPAL layer just handles the general information and
* IOC layer should process much more detailed information, which
* is sensitive to itself.
*/
#define P7IOC_ERR_SRC_NONE 0
#define P7IOC_ERR_SRC_EI 1
#define P7IOC_ERR_SRC_RGC 2
#define P7IOC_ERR_SRC_BI_UP 3
#define P7IOC_ERR_SRC_BI_DOWN 4
#define P7IOC_ERR_SRC_CI_P0 5
#define P7IOC_ERR_SRC_CI_P1 6
#define P7IOC_ERR_SRC_CI_P2 7
#define P7IOC_ERR_SRC_CI_P3 8
#define P7IOC_ERR_SRC_CI_P4 9
#define P7IOC_ERR_SRC_CI_P5 10
#define P7IOC_ERR_SRC_CI_P6 11
#define P7IOC_ERR_SRC_CI_P7 12
#define P7IOC_ERR_SRC_PHB0 13
#define P7IOC_ERR_SRC_PHB1 14
#define P7IOC_ERR_SRC_PHB2 15
#define P7IOC_ERR_SRC_PHB3 16
#define P7IOC_ERR_SRC_PHB4 17
#define P7IOC_ERR_SRC_PHB5 18
#define P7IOC_ERR_SRC_MISC 19
#define P7IOC_ERR_SRC_I2C 20
#define P7IOC_ERR_SRC_LAST 21
#define P7IOC_ERR_CLASS_NONE 0
#define P7IOC_ERR_CLASS_GXE 1
#define P7IOC_ERR_CLASS_PLL 2
#define P7IOC_ERR_CLASS_RGA 3
#define P7IOC_ERR_CLASS_PHB 4
#define P7IOC_ERR_CLASS_ER 5
#define P7IOC_ERR_CLASS_INF 6
#define P7IOC_ERR_CLASS_MAL 7
#define P7IOC_ERR_CLASS_LAST 8
/*
* P7IOC error descriptor. For errors from PHB and PE, they
* will be cached to the corresponding PHBs. However, the
* left errors (e.g. EI, CI Port0/1) will be cached to the
* IOC directly.
*/
struct p7ioc_err {
uint32_t err_src;
uint32_t err_class;
uint32_t err_bit;
};
struct p7ioc;
#define P7IOC_PHB_CFG_USE_ASB 0x00000001 /* ASB to access PCI-CFG */
#define P7IOC_PHB_CFG_BLOCKED 0x00000002 /* PCI-CFG blocked except 0 */
struct p7ioc_phb {
uint8_t index; /* 0..5 index inside p7ioc */
uint8_t gen;
uint32_t flags;
bool broken;
#define P7IOC_REV_DD10 0x00a20001
#define P7IOC_REV_DD11 0x00a20002
uint32_t rev; /* Both major and minor have 2 bytes */
void *regs_asb;
void *regs; /* AIB regs */
uint32_t buid_lsi;
uint32_t buid_msi;
uint64_t io_base;
uint64_t m32_base;
uint64_t m64_base;
int64_t ecap; /* cached PCI-E cap offset */
int64_t aercap; /* cached AER ecap offset */
uint64_t lxive_cache[8];
uint64_t mxive_cache[256];
uint64_t mve_cache[256];
uint64_t peltm_cache[128];
uint64_t peltv_lo_cache[128];
uint64_t peltv_hi_cache[128];
uint64_t tve_lo_cache[128];
uint64_t tve_hi_cache[128];
uint64_t iod_cache[128];
uint64_t m32d_cache[128];
uint64_t m64b_cache[16];
uint64_t m64d_cache[128];
bool err_pending;
struct p7ioc_err err;
struct p7ioc *ioc;
struct phb phb;
};
static inline struct p7ioc_phb *phb_to_p7ioc_phb(struct phb *phb)
{
return container_of(phb, struct p7ioc_phb, phb);
}
static inline bool p7ioc_phb_err_pending(struct p7ioc_phb *p)
{
return p->err_pending;
}
static inline void p7ioc_phb_set_err_pending(struct p7ioc_phb *p, bool pending)
{
if (!pending) {
p->err.err_src = P7IOC_ERR_SRC_NONE;
p->err.err_class = P7IOC_ERR_CLASS_NONE;
p->err.err_bit = -1;
}
p->err_pending = pending;
}
/*
* State structure for P7IOC IO HUB
*/
struct p7ioc {
/* Device node */
struct dt_node *dt_node;
/* MMIO regs */
void *regs;
/* Main MMIO window from GX for registers & PCI IO space */
uint64_t mmio1_win_start;
uint64_t mmio1_win_size;
/* Secondary MMIO window for PCI MMIO space */
uint64_t mmio2_win_start;
uint64_t mmio2_win_size;
/* BUID base for the PHB. This does include the top bits
* (chip, GX bus ID, etc...). This is initialized from the
* SPIRA. It does not contain the offset 0x10 for RGC
* interrupts.
*
* The OPAL-defined "interrupt-base" property will contain
* the RGC BUID, not this base value, since this is the real
* starting point of interrupts for the IOC and we don't want
* to cover the BUID 0..f gap which is reserved for P7 on-chip
* interrupt sources.
*/
uint32_t buid_base;
uint32_t rgc_buid;
/* XIVT cache for RGC interrupts */
uint64_t xive_cache[16];
bool err_pending;
struct p7ioc_err err;
/* PHB array & presence detect */
struct p7ioc_phb phbs[P7IOC_NUM_PHBS];
uint8_t phb_pdt;
struct io_hub hub;
};
static inline struct p7ioc *iohub_to_p7ioc(struct io_hub *hub)
{
return container_of(hub, struct p7ioc, hub);
}
static inline bool p7ioc_err_pending(struct p7ioc *ioc)
{
return ioc->err_pending;
}
static inline void p7ioc_set_err_pending(struct p7ioc *ioc, bool pending)
{
if (!pending) {
ioc->err.err_src = P7IOC_ERR_SRC_NONE;
ioc->err.err_class = P7IOC_ERR_CLASS_NONE;
ioc->err.err_bit = -1;
}
ioc->err_pending = pending;
}
static inline bool p7ioc_phb_enabled(struct p7ioc *ioc, unsigned int phb)
{
return !!(ioc->phb_pdt & (0x80 >> phb));
}
extern int64_t p7ioc_inits(struct p7ioc *ioc);
extern void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index);
extern int64_t p7ioc_phb_init(struct p7ioc_phb *p);
extern bool p7ioc_check_LEM(struct p7ioc *ioc, uint16_t *pci_error_type,
uint16_t *severity);
extern int64_t p7ioc_phb_get_xive(struct p7ioc_phb *p, uint32_t isn,
uint16_t *server, uint8_t *prio);
extern int64_t p7ioc_phb_set_xive(struct p7ioc_phb *p, uint32_t isn,
uint16_t server, uint8_t prio);
extern void p7ioc_reset(struct io_hub *hub);
extern void p7ioc_phb_reset(struct phb *phb);
#endif /* __P7IOC_H */
|