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 <string.h>
41 #include "libbdk-arch/bdk-csrs-ecam.h"
42 #include "libbdk-arch/bdk-csrs-pccbr.h"
43 #include "libbdk-arch/bdk-csrs-pccpf.h"
44 #include "libbdk-arch/bdk-csrs-rvu.h"
45 #include "libbdk-hal/device/bdk-device.h"
46 #include "libbdk-hal/bdk-ecam.h"
47
48 /* This code is an optional part of the BDK. It is only linked in
49 if BDK_REQUIRE() needs it */
50 BDK_REQUIRE_DEFINE(ECAM);
51
52 /**
53 * Walk an ECAM finding all internal devices. Each internal
54 * device is then added to the list of device maintained by
55 * bdk-device.
56 *
57 * @param node Node to walk
58 * @param ecam Ecam to walk
59 * @param bus Zero on first call. Will be non-zero when sub busses are walked
60 */
ecam_walk_internal_bus(bdk_node_t node,int ecam,int bus)61 static void ecam_walk_internal_bus(bdk_node_t node, int ecam, int bus)
62 {
63 /* Create a fake bdk-device to pass around until we create the
64 real device */
65 bdk_device_t device;
66 memset(&device, 0, sizeof(device));
67 device.node = node;
68 device.ecam = ecam;
69 device.bus = bus;
70
71 /* Scan all possible device IDs on the bus */
72 for (int dev = 0; dev < 32; dev++)
73 {
74 /* Update the current scan location */
75 device.dev = dev;
76 device.func = 0;
77
78 uint32_t device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
79
80 /* Only add devices that exist. Our internal devices can have function
81 zero missing. The all ones we get back matches the multi-function
82 check, but not a bridge. This means the later code works fine */
83 if (device_id != (uint32_t)-1)
84 bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
85
86 /* Check for Multi function and Bridge devices */
87 BDK_CSR_DEFINE(clsize, BDK_PCCPF_XXX_CLSIZE);
88 clsize.u = bdk_ecam_read32(&device, BDK_PCCPF_XXX_CLSIZE);
89 int ismultifunction = (clsize.s.hdrtype & 0x80);
90 int isbridge = (clsize.s.hdrtype & 0x7f) == 1;
91
92 if (ismultifunction)
93 {
94 /* Scan for other functions on multifunction devices */
95 for (int func = 1; func < 8; func++)
96 {
97 /* Check if we're past all functions */
98 device.func = func;
99 device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
100 if (device_id != (uint32_t)-1)
101 bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
102 }
103 device.func = 0;
104 }
105 if (isbridge)
106 {
107 /* Internal bus numbers are hard coded. Read the bus ID */
108 bdk_pccbr_xxx_bus_t ibus;
109 ibus.u = bdk_ecam_read32(&device, BDK_PCCBR_XXX_BUS);
110 /* Asim used to have a bug where bus number were zero, report errors
111 for those */
112 if (ibus.s.sbnum == 0)
113 {
114 bdk_error("N%d:E%d:%d:%d.%d: Secondary bus number is zero\n",
115 device.node, device.ecam, device.bus, device.dev, device.func);
116 }
117 /* Real PCIe external device use high bus numbers, so skip them */
118 else if (ibus.s.sbnum < 16)
119 {
120 ecam_walk_internal_bus(node, ecam, ibus.s.sbnum);
121 }
122 }
123 }
124 }
125
126 /**
127 * Return the number of internal ECAMS on a node.
128 *
129 * @param node Node to query
130 *
131 * @return Number of ECAMs available
132 */
bdk_ecam_get_num(bdk_node_t node)133 int bdk_ecam_get_num(bdk_node_t node)
134 {
135 /* CN88XX lacks the ECAM_CONST for finding the number of ECAMs */
136 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
137 return 4;
138 else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
139 return 3; /* Map ECAMs to the first 3 domains */
140 else
141 {
142 BDK_CSR_INIT(ecam_const, node, BDK_ECAMX_CONST(0));
143 if (ecam_const.s.ecams == 0)
144 {
145 bdk_error("N%d.ECAM: Number of ecams incorrect in ECAMX_CONST\n", node);
146 return 1;
147 }
148 return ecam_const.s.ecams;
149 }
150 }
151
152 /**
153 * Initialize RVU functions for use by the BDK. This doesn't setup the hardware
154 * behind RVU, juse allows register access to it. The BDK uses a static RVU
155 * configuration where everything is accessable from RVU PF0.
156 *
157 * @param node Node to initialize
158 *
159 * @return Zero on success, negative on failure
160 */
__bdk_ecam_rvu_init(bdk_node_t node)161 static int __bdk_ecam_rvu_init(bdk_node_t node)
162 {
163 const int rvu_pf = 0;
164 /* Enable PF access to all blocks */
165 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CPTX_CFG(rvu_pf, 0),
166 c.s.num_lfs = 1); // FIXME: How many LFs?
167 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_INT_CFG(rvu_pf),
168 c.s.msix_offset = 0);
169 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_MSIX_CFG(rvu_pf),
170 c.s.pf_msixt_offset = 0;
171 c.s.pf_msixt_sizem1 = 0;
172 c.s.vf_msixt_offset = 0;
173 c.s.vf_msixt_sizem1 = 0);
174 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NIXX_CFG(rvu_pf, 0),
175 c.s.has_lf = 1);
176 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NPA_CFG(rvu_pf),
177 c.s.has_lf = 1);
178 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSO_CFG(rvu_pf),
179 c.s.num_lfs = 1); // FIXME: How many LFs?
180 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSOW_CFG(rvu_pf),
181 c.s.num_lfs = 1); // FIXME: How many LFs?
182 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_TIM_CFG(rvu_pf),
183 c.s.num_lfs = 1); // FIXME: How many LFs?
184 /* Enable RVU with full access */
185 BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CFG(rvu_pf),
186 c.s.me_flr_ena = 1;
187 c.s.af_ena = 1;
188 c.s.ena = 1;
189 c.s.nvf = 0;
190 c.s.first_hwvf = 0);
191 return 0;
192 }
193
194 /**
195 * Scan all ECAMs for devices and add them to bdk-device
196 *
197 * @param node Node to scan
198 *
199 * @return Zero on success, negative on failure
200 */
bdk_ecam_scan_all(bdk_node_t node)201 int bdk_ecam_scan_all(bdk_node_t node)
202 {
203 /* RVU must be setup before we scan the bus otherwise it doesn't
204 show up */
205 if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX))
206 __bdk_ecam_rvu_init(node);
207
208 int num_ecams = bdk_ecam_get_num(node);
209 for (int ecam = 0; ecam < num_ecams; ecam++)
210 ecam_walk_internal_bus(node, ecam, 0);
211
212 bdk_device_init();
213
214 return 0;
215 }
216
217