1 /***********************license start***********************************
2 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
21 * permission.
22 *
23 * This Software, including technical data, may be subject to U.S. export
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other countries.
27 *
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include "libbdk-arch/bdk-csrs-pccpf.h"
41 #include "libbdk-arch/bdk-csrs-pem.h"
42 #include "libbdk-arch/bdk-csrs-rst.h"
43 #include "libbdk-hal/bdk-pcie.h"
44
45 #ifndef BDK_BUILD_HOST
46
47 /**
48 * Read a slow CSR, not RSL or NCB.
49 *
50 * @param type Bus type the CSR is on
51 * @param busnum Bus number the CSR is on
52 * @param size Width of the CSR in bytes
53 * @param address The address of the CSR
54 *
55 * @return The value of the CSR
56 */
__bdk_csr_read_slow(bdk_node_t node,bdk_csr_type_t type,int busnum,int size,uint64_t address)57 uint64_t __bdk_csr_read_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address)
58 {
59 switch (type)
60 {
61 case BDK_CSR_TYPE_DAB:
62 case BDK_CSR_TYPE_DAB32b:
63 case BDK_CSR_TYPE_NCB:
64 case BDK_CSR_TYPE_NCB32b:
65 case BDK_CSR_TYPE_PEXP_NCB:
66 case BDK_CSR_TYPE_RSL:
67 case BDK_CSR_TYPE_RSL32b:
68 case BDK_CSR_TYPE_RVU_PF_BAR0:
69 case BDK_CSR_TYPE_RVU_PF_BAR2:
70 case BDK_CSR_TYPE_RVU_PFVF_BAR2:
71 case BDK_CSR_TYPE_RVU_VF_BAR2:
72 /* Handled by inline code, we should never get here */
73 bdk_error("%s: Passed type that should be handled inline\n", __func__);
74 break;
75
76 case BDK_CSR_TYPE_PCCBR:
77 case BDK_CSR_TYPE_PCCPF:
78 case BDK_CSR_TYPE_PCCVF:
79 case BDK_CSR_TYPE_PEXP:
80 case BDK_CSR_TYPE_MDSB:
81 case BDK_CSR_TYPE_PCICONFIGEP_SHADOW:
82 case BDK_CSR_TYPE_PCICONFIGEPVF:
83 bdk_error("%s: Register not supported\n", __func__);
84 break;
85
86 case BDK_CSR_TYPE_SYSREG:
87 return bdk_sysreg_read(node, bdk_get_core_num(), address);
88
89 case BDK_CSR_TYPE_PCICONFIGRC:
90 {
91 union bdk_pcc_dev_con_s dev_con;
92 switch (busnum)
93 {
94 case 0:
95 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
96 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN88XX;
97 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
98 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN83XX;
99 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
100 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN81XX;
101 else
102 bdk_fatal("Update PCICONFIG in %s\n", __func__);
103 break;
104 case 1:
105 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
106 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN88XX;
107 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
108 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN83XX;
109 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
110 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN81XX;
111 else
112 bdk_fatal("Update PCICONFIG in %s\n", __func__);
113 break;
114 case 2:
115 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
116 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN88XX;
117 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
118 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN83XX;
119 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
120 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN81XX;
121 else
122 bdk_fatal("Update PCICONFIG in %s\n", __func__);
123 break;
124 case 3:
125 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
126 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN88XX;
127 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
128 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN83XX;
129 else
130 bdk_fatal("Update PCICONFIG in %s\n", __func__);
131 break;
132 case 4:
133 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC4;
134 break;
135 case 5:
136 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC5;
137 break;
138 default:
139 bdk_error("%s: Illegal PCIe bus number\n", __func__);
140 return -1;
141 }
142 return bdk_pcie_config_read32(node, 100 + dev_con.cn8.ecam, dev_con.s.bus, dev_con.s.func >> 3, dev_con.s.func & 7, address);
143 }
144 case BDK_CSR_TYPE_PCICONFIGEP:
145 {
146 BDK_CSR_DEFINE(cfg_rd, BDK_PEMX_CFG_RD(busnum));
147 cfg_rd.u = 0;
148 cfg_rd.s.addr = address;
149 BDK_CSR_WRITE(node, BDK_PEMX_CFG_RD(busnum), cfg_rd.u);
150 cfg_rd.u = BDK_CSR_READ(node, BDK_PEMX_CFG_RD(busnum));
151 return cfg_rd.s.data;
152 }
153 }
154 return -1; /* Return -1 as this looks invalid in register dumps. Zero is too common as a good value */
155 }
156
157
158 /**
159 * Write a value to a slow CSR, not RSL or NCB.
160 *
161 * @param type Bus type the CSR is on
162 * @param busnum Bus number the CSR is on
163 * @param size Width of the CSR in bytes
164 * @param address The address of the CSR
165 * @param value Value to write to the CSR
166 */
__bdk_csr_write_slow(bdk_node_t node,bdk_csr_type_t type,int busnum,int size,uint64_t address,uint64_t value)167 void __bdk_csr_write_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value)
168 {
169 switch (type)
170 {
171 case BDK_CSR_TYPE_DAB:
172 case BDK_CSR_TYPE_DAB32b:
173 case BDK_CSR_TYPE_NCB:
174 case BDK_CSR_TYPE_NCB32b:
175 case BDK_CSR_TYPE_PEXP_NCB:
176 case BDK_CSR_TYPE_RSL:
177 case BDK_CSR_TYPE_RSL32b:
178 case BDK_CSR_TYPE_RVU_PF_BAR0:
179 case BDK_CSR_TYPE_RVU_PF_BAR2:
180 case BDK_CSR_TYPE_RVU_PFVF_BAR2:
181 case BDK_CSR_TYPE_RVU_VF_BAR2:
182 /* Handled by inline code, we should never get here */
183 bdk_error("%s: Passed type that should be handled inline\n", __func__);
184 break;
185
186 case BDK_CSR_TYPE_PCCBR:
187 case BDK_CSR_TYPE_PCCPF:
188 case BDK_CSR_TYPE_PCCVF:
189 case BDK_CSR_TYPE_PEXP:
190 case BDK_CSR_TYPE_MDSB:
191 case BDK_CSR_TYPE_PCICONFIGEP_SHADOW:
192 case BDK_CSR_TYPE_PCICONFIGEPVF:
193 bdk_error("%s: Register not supported\n", __func__);
194 break;
195
196 case BDK_CSR_TYPE_SYSREG:
197 bdk_sysreg_write(node, bdk_get_core_num(), address, value);
198 break;
199
200 case BDK_CSR_TYPE_PCICONFIGRC:
201 {
202 union bdk_pcc_dev_con_s dev_con;
203 switch (busnum)
204 {
205 case 0:
206 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
207 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN88XX;
208 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
209 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN83XX;
210 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
211 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN81XX;
212 else
213 bdk_fatal("Update PCICONFIG in %s\n", __func__);
214 break;
215 case 1:
216 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
217 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN88XX;
218 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
219 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN83XX;
220 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
221 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN81XX;
222 else
223 bdk_fatal("Update PCICONFIG in %s\n", __func__);
224 break;
225 case 2:
226 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
227 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN88XX;
228 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
229 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN83XX;
230 else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
231 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN81XX;
232 else
233 bdk_fatal("Update PCICONFIG in %s\n", __func__);
234 break;
235 case 3:
236 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
237 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN88XX;
238 else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
239 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN83XX;
240 else
241 bdk_fatal("Update PCICONFIG in %s\n", __func__);
242 break;
243 case 4:
244 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC4;
245 break;
246 case 5:
247 dev_con.u = BDK_PCC_DEV_CON_E_PCIERC5;
248 break;
249 default:
250 bdk_error("%s: Illegal PCIe bus number\n", __func__);
251 return;
252 }
253 bdk_pcie_config_write32(node, 100 + dev_con.cn8.ecam, dev_con.s.bus, dev_con.s.func >> 3, dev_con.s.func & 7, address, value);
254 break;
255 }
256 case BDK_CSR_TYPE_PCICONFIGEP:
257 {
258 BDK_CSR_DEFINE(cfg_wr, BDK_PEMX_CFG_WR(busnum));
259 cfg_wr.u = 0;
260 cfg_wr.s.addr = address;
261 cfg_wr.s.data = value;
262 BDK_CSR_WRITE(node, BDK_PEMX_CFG_WR(busnum), cfg_wr.u);
263 break;
264 }
265 }
266 }
267
268 #endif
269
__bdk_csr_fatal(const char * name,int num_args,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4)270 void __bdk_csr_fatal(const char *name, int num_args, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4)
271 {
272 switch (num_args)
273 {
274 case 0:
275 bdk_fatal("%s is invalid on this chip\n", name);
276 case 1:
277 bdk_fatal("%s(%lu) is invalid on this chip\n", name, arg1);
278 case 2:
279 bdk_fatal("%s(%lu,%lu) is invalid on this chip\n", name, arg1, arg2);
280 case 3:
281 bdk_fatal("%s(%lu,%lu,%lu) is invalid on this chip\n", name, arg1, arg2, arg3);
282 default:
283 bdk_fatal("%s(%lu,%lu,%lu,%lu) is invalid on this chip\n", name, arg1, arg2, arg3, arg4);
284 }
285 }
286
287 /**
288 * Read a core system register from a different node or core
289 *
290 * @param node Node to read from
291 * @param core Core to read
292 * @param regnum Register to read in MRS encoding
293 *
294 * @return Register value
295 */
bdk_sysreg_read(int node,int core,uint64_t regnum)296 uint64_t bdk_sysreg_read(int node, int core, uint64_t regnum)
297 {
298 BDK_CSR_INIT(pp_reset, node, BDK_RST_PP_RESET);
299 if (pp_reset.u & (1ull<<core))
300 {
301 bdk_error("Attempt to read system register for core in reset\n");
302 return -1;
303 }
304
305 /* Addresses indicate selects as follows:
306 select 3,4,14,2,3
307 == 0x03040e020300
308 | | | | |^--- 1 if is E2H duplicated register
309 | | | |^^-- fifth select
310 | | |^^-- fourth select
311 | |^^-- third select
312 |^^-- second select
313 ^^-- first select */
314 uint64_t first = (regnum >> 40) & 0xff;
315 uint64_t second = (regnum >> 32) & 0xff;
316 uint64_t third = (regnum >> 24) & 0xff;
317 uint64_t fourth = (regnum >> 16) & 0xff;
318 uint64_t fifth = (regnum >> 8) & 0xff;
319 uint64_t regid = ((first & 3) << 14) | (second << 11) | (third << 7) | (fourth << 3) | fifth;
320
321 /* Note this requires DAP_IMP_DAR[caben] = 1 */
322 uint64_t address = 1ull<<47;
323 address |= 0x7Bull << 36;
324 address |= core << 19;
325 address |= regid << 3;
326 address = bdk_numa_get_address(node, address);
327 return bdk_read64_uint64(address);
328 }
329
330 /**
331 * Write a system register for a different node or core
332 *
333 * @param node Node to write too
334 * @param core Core to write
335 * @param regnum Register to write in MSR encoding
336 * @param value Value to write
337 */
bdk_sysreg_write(int node,int core,uint64_t regnum,uint64_t value)338 void bdk_sysreg_write(int node, int core, uint64_t regnum, uint64_t value)
339 {
340 BDK_CSR_INIT(pp_reset, node, BDK_RST_PP_RESET);
341 if (pp_reset.u & (1ull<<core))
342 {
343 bdk_error("Attempt to write system register for core in reset\n");
344 return;
345 }
346
347 /* Addresses indicate selects as follows:
348 select 3,4,14,2,3
349 == 0x03040e020300
350 | | | | |^--- 1 if is E2H duplicated register
351 | | | |^^-- fifth select
352 | | |^^-- fourth select
353 | |^^-- third select
354 |^^-- second select
355 ^^-- first select */
356 uint64_t first = (regnum >> 40) & 0xff;
357 uint64_t second = (regnum >> 32) & 0xff;
358 uint64_t third = (regnum >> 24) & 0xff;
359 uint64_t fourth = (regnum >> 16) & 0xff;
360 uint64_t fifth = (regnum >> 8) & 0xff;
361 uint64_t regid = ((first & 3) << 14) | (second << 11) | (third << 7) | (fourth << 3) | fifth;
362
363 /* Note this requires DAP_IMP_DAR[caben] = 1 */
364 uint64_t address = 1ull<<47;
365 address |= 0x7Bull << 36;
366 address |= core << 19;
367 address |= regid << 3;
368 address = bdk_numa_get_address(node, address);
369 bdk_write64_uint64(address, value);
370 }
371
372