aboutsummaryrefslogtreecommitdiff
path: root/include/xscom.h
blob: a6bb7e400435fea3c4af071e9ee06b6a7e23fc92 (plain)
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
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2013-2019 IBM Corp. */

#ifndef __XSCOM_H
#define __XSCOM_H

#include <stdint.h>
#include <processor.h>
#include <cpu.h>

/*
 * SCOM "partID" definitions:
 *
 * All Ids are 32-bits long, top nibble is reserved for the
 * 'type' field:
 *     0x0 = Processor Chip
 *     0x8 = Memory Buffer (Centaur) Chip
 *     0x4 = EX/Core Chiplet
 *
 * Processor Chip = Logical Fabric Id = PIR>>7
 *     0b0000.0000.0000.0000.0000.0000.00NN.NCCC
 *     N=Node, C=Chip
 * Centaur Chip = Associated Processor Chip with memory channel
 * appended and flag set
 *     0b1000.0000.0000.0000.0000.00NN.NCCC.MMMM
 *     N=Node, C=Chip, M=Memory Channel
 * Processor EX/Core chiplet = PIR >> 3 with flag set.
 * On P8:
 *     0b0100.0000.0000.0000.0000.00NN.NCCC.PPPP
 * On P9:
 *     0b0100.0000.0000.0000.0000.0NNN.CCCP.PPPP
 *     N=Node, C=Chip, P=Processor core
 */

/*
 * SCOM Address definition extracted from HWPs for documentation
 * purposes
 *
 * "Normal" (legacy) format
 *
 *            111111 11112222 22222233 33333333 44444444 44555555 55556666
 * 01234567 89012345 67890123 45678901 23456789 01234567 89012345 67890123
 * -------- -------- -------- -------- -------- -------- -------- --------
 * 00000000 00000000 00000000 00000000 0MCCCCCC ????PPPP 00LLLLLL LLLLLLLL
 *                                      ||          |    |
 *                                      ||          |    `-> Local Address*
 *                                      ||          |
 *                                      ||          `-> Port
 *                                      ||
 *                                      |`-> Chiplet ID**
 *                                      |
 *                                      `-> Multicast bit
 *
 *  * Local address is composed of "00" + 4-bit ring + 10-bit ID
 *    The 10-bit ID is usually 4-bit sat_id and 6-bit reg_id
 *
 * ** Chiplet ID turns into multicast operation type and group number
 *    if the multicast bit is set
 *
 * "Indirect" format
 *
 *
 *            111111 11112222 22222233 33333333 44444444 44555555 55556666
 * 01234567 89012345 67890123 45678901 23456789 01234567 89012345 67890123
 * -------- -------- -------- -------- -------- -------- -------- --------
 * 10000000 0000IIII IIIIIGGG GGGLLLLL 0MCCCCCC ????PPPP 00LLLLLL LLLLLLLL
 *              |         |      |      ||          |    |
 *              |         |      |      ||          |    `-> Local Address*
 *              |         |      |      ||          |
 *              |         |      |      ||          `-> Port
 *              |         |      |      ||
 *              |         |      |      |`-> Chiplet ID**
 *              |         |      |      |
 *              |         |      |      `-> Multicast bit
 *              |         |      |
 *              |         |      `-> Lane ID
 *              |         |
 *              |         `-> RX or TX Group ID
 *              |
 *              `-> Indirect Register Address
 *
 *  * Local address is composed of "00" + 4-bit ring + 4-bit sat_id + "111111"
 *
 * ** Chiplet ID turns into multicast operation type and group number
 *    if the multicast bit is set
 */

/*
 * Generate a local address from a given ring/satellite/offset
 * combination:
 *
 *     Ring    Satellite     offset
 *  +---------+---------+-------------+
 *  |    4    |    4    |     6       |
 *  +---------+---------+-------------+
 */
#define XSCOM_SAT(_r, _s, _o)	\
	(((_r) << 10) | ((_s) << 6) | (_o))

/*
 * Additional useful definitions for P8
 */
#define P8_EX_PCB_SLAVE_BASE	0x100F0000

#define XSCOM_ADDR_P8_EX_SLAVE(core, offset) \
     (P8_EX_PCB_SLAVE_BASE | (((core) & 0xF) << 24) | ((offset) & 0xFFFF))

#define XSCOM_ADDR_P8_EX(core, addr) \
		((((core) & 0xF) << 24) | (addr))

/*
 * Additional useful definitions for P9
 *
 * Note: In all of these, the core numbering is the
 * *normal* (small) core number.
 */

/*
 * An EQ is a quad. The Pervasive spec also uses the term "EP"
 * to refer to an EQ and it's two child EX chiplets, but
 * nothing else does
 */
#define XSCOM_ADDR_P9_EQ(core, addr) \
	(((((core) & 0x1c) + 0x40) << 22) | (addr))
#define XSCOM_ADDR_P9_EQ_SLAVE(core, addr) \
	XSCOM_ADDR_P9_EQ(core, (addr) | 0xf0000)

/* An EX is a pair of cores. They are accessed via their corresponding EQs
 * with bit 0x400 indicating which of the 2 EX to address
 */
#define XSCOM_ADDR_P9_EX(core, addr) \
	(XSCOM_ADDR_P9_EQ(core, addr | (((core) & 2) << 9)))

/* An EC is an individual core and has its own XSCOM addressing */
#define XSCOM_ADDR_P9_EC(core, addr) \
	(((((core) & 0x1F) + 0x20) << 24) | (addr))
#define XSCOM_ADDR_P9_EC_SLAVE(core, addr) \
	XSCOM_ADDR_P9_EC(core, (addr) | 0xf0000)

/*
 * Additional useful definitions for P10
 */

/*
 * POWER10 pervasive structure
 * Chip has 8 EQ chiplets (aka super-chiplets), and other nest chiplets.
 * Each EQ contains 4 EX regions.
 * Each EX contains an ECL2, L3, MMA.
 * Each ECL2 contains an EC (core), L2, and NCU.
 *
 * Each EQ has a Quad Management Engine (QME), responsible for power management
 * for the cores, among other things.
 *
 * POWER10 XSCOM address format:
 *
 *      | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16-31|
 * MC=0 |WR|MC|SLAVE ADDR       |PIB MASTER |PORT NUMBER|LOCAL|
 * MC=1 |WR|MC|MC TYPE |MC GROUP|PIB MASTER |PORT NUMBER|LOCAL|
 *
 * * Port is also known as PSCOM endpoint.
 *
 * WR is set by the xscom access functions (XSCOM_DATA_IND_READ bit)
 * MC is always 0 (skiboot does not use multicast scoms).
 *
 * For unicast:
 * EQ0-7 is addressed from 0x20 to 0x27 in the top 8 bits.
 * L3 is on port 1
 * NCU is on port 1
 * ECL2 (core+L2) is on port 2 (XXX P10 scoms html doc suggests port 1?)
 * QME is on port E.
 *
 * EQ chiplets (aka super chiplet) local address format:
 *
 *      | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|
 *      |C0|C1|C2|C3|RING ID |SAT ID  |REGISTER ID      |
 *
 * EX0-4 are selected with one-hot encoding (C0-3)
 *
 * QME per-core register access address format:
 *      | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|
 *      |C0|C1|C2|C3| 1| 0| 0| 0|PER-CORE REGISTER ID   |
 *
 * NCU - ring 6 (port 1)
 * L3  - ring 3 (port 1) (XXX P10 scoms html doc suggests ring 6)
 * L2  - ring 0 (port 2) (XXX P10 scoms html doc suggests ring 4)
 * EC (PC unit) - rings 2-5 (port 2)
 *
 * Other chiplets:
 *
 *      | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|
 *      | 1|RING ID       |SAT ID     |REGISTER ID      |
 */

#define P10_CORE_EQ_CHIPLET(core)	(0x20 + ((core) >> 2))
#define P10_CORE_PROC(core)		((core) & 0x3)

#define XSCOM_P10_EQ(chiplet)		((chiplet) << 24)

#define XSCOM_P10_QME(chiplet) \
	(XSCOM_P10_EQ(chiplet) | (0xE << 16))

#define XSCOM_P10_QME_CORE(chiplet, proc) \
	(XSCOM_P10_QME(chiplet) | ((1 << (3 - proc)) << 12))

#define XSCOM_P10_EC(chiplet, proc) \
	(XSCOM_P10_EQ(chiplet) | (0x2 << 16) | ((1 << (3 - proc)) << 12))

#define XSCOM_P10_NCU(chiplet, proc) \
	(XSCOM_P10_EQ(chiplet) | (0x1 << 16) | ((1 << (3 - proc)) << 12))

#define XSCOM_ADDR_P10_EQ(core, addr) \
	(XSCOM_P10_EQ(P10_CORE_EQ_CHIPLET(core)) | (addr))

#define XSCOM_ADDR_P10_QME(core, addr) \
	(XSCOM_P10_QME(P10_CORE_EQ_CHIPLET(core)) | (addr))

#define XSCOM_ADDR_P10_QME_CORE(core, addr) \
	(XSCOM_P10_QME_CORE(P10_CORE_EQ_CHIPLET(core), P10_CORE_PROC(core)) | (addr))

#define XSCOM_ADDR_P10_EC(core, addr) \
	(XSCOM_P10_EC(P10_CORE_EQ_CHIPLET(core), P10_CORE_PROC(core)) | (addr))

#define XSCOM_ADDR_P10_NCU(core, addr)					\
	(XSCOM_P10_NCU(P10_CORE_EQ_CHIPLET(core), P10_CORE_PROC(core)) | (addr))

/* Definitions relating to indirect XSCOMs shared with centaur */
#define XSCOM_ADDR_IND_FLAG		PPC_BIT(0)
#define XSCOM_ADDR_IND_ADDR		PPC_BITMASK(12,31)
#define XSCOM_ADDR_IND_DATA		PPC_BITMASK(48,63)

#define XSCOM_DATA_IND_READ		PPC_BIT(0)
#define XSCOM_DATA_IND_COMPLETE		PPC_BIT(32)
#define XSCOM_DATA_IND_ERR		PPC_BITMASK(33,35)
#define XSCOM_DATA_IND_DATA		PPC_BITMASK(48,63)
#define XSCOM_DATA_IND_FORM1_DATA	PPC_BITMASK(12,63)

/* HB folks say: try 10 time for now */
#define XSCOM_IND_MAX_RETRIES		10

/* Max number of retries when XSCOM remains busy */
#define XSCOM_BUSY_MAX_RETRIES		3000

/* Max number of retries for xscom clearing recovery. */
#define XSCOM_CLEAR_MAX_RETRIES		10

/* Retry count after which to reset XSCOM, if still busy */
#define XSCOM_BUSY_RESET_THRESHOLD	1000

/*
 * Error handling:
 *
 * Error codes TBD, 0 = success
 */

/* Use only in select places where multiple SCOMs are time/latency sensitive */
extern void _xscom_lock(void);
extern int _xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val, bool take_lock);
extern int _xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val, bool take_lock);
extern void _xscom_unlock(void);


/* Targeted SCOM access */
static inline int xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val)
{
	return _xscom_read(partid, pcb_addr, val, true);
}
static inline int xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val) {
	return _xscom_write(partid, pcb_addr, val, true);
}
extern int xscom_write_mask(uint32_t partid, uint64_t pcb_addr, uint64_t val, uint64_t mask);

/* This chip SCOM access */
extern int xscom_readme(uint64_t pcb_addr, uint64_t *val);
extern int xscom_writeme(uint64_t pcb_addr, uint64_t val);
extern void xscom_init(void);

/* Mark XSCOM lock as being in console path */
extern void xscom_used_by_console(void);

/* Returns true if XSCOM can be used. Typically this returns false if
 * the current CPU holds the XSCOM lock (to avoid re-entrancy from error path).
 */
extern bool xscom_ok(void);

extern int64_t xscom_read_cfam_chipid(uint32_t partid, uint32_t *chip_id);
extern int64_t xscom_trigger_xstop(void);


struct scom_controller {
	uint32_t part_id;
	void *private;
	int64_t (*read)(struct scom_controller *, uint32_t chip, uint64_t reg, uint64_t *val);
	int64_t (*write)(struct scom_controller *, uint32_t chip, uint64_t reg, uint64_t val);

	struct list_node link;
};

int64_t scom_register(struct scom_controller *new);

#endif /* __XSCOM_H */