7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/file.h>
28 #include <sys/sunndi.h>
29 #include <sys/sunddi.h>
30 #include <sys/sunldi.h>
31 #include <io/px/px_regs.h>
32 #include <sys/pci_tools.h>
33 #include <fpc.h>
34 #include <fpc-impl.h>
35
36 #define CHIP_COMPATIBLE_NAME "pciex108e,80f0"
37 #define BANK_ADDR_MASK 0x7FFFFF
38
39 #define OPEN_FLAGS (FREAD | FWRITE)
40
41 #define PCIE_BANK 0
42 #define JBUS_BANK 1
43
44 typedef struct px_regs {
45 uint32_t addr_hi;
46 uint32_t addr_lo;
84 TLU_PERFORMANCE_COUNTER_ONE,
85 TLU_PERFORMANCE_COUNTER_TWO,
86 LPU_LINK_PERFORMANCE_COUNTER1,
87 LPU_LINK_PERFORMANCE_COUNTER2
88 };
89
90 /*
91 * Add the following to one of the LPU_LINK_PERFORMANCE_COUNTERx offsets to
92 * write a value to that counter.
93 */
94 #define LPU_LINK_PERFCTR_WRITE_OFFSET 0x8
95
96 /*
97 * Note that LPU_LINK_PERFORMANCE_COUNTER_CONTROL register is hard-reset to
98 * zeros and this is the value we want. This register isn't touched by this
99 * module, and as long as it remains untouched by other modules we're OK.
100 */
101
102 static ldi_ident_t ldi_identifier;
103 static boolean_t ldi_identifier_valid = B_FALSE;
104 static cred_t *credentials = NULL;
105
106 /* Called by _init to determine if it is OK to install driver. */
107 int
108 fpc_platform_check()
109 {
110 return (SUCCESS);
111 }
112
113 /* Called during attach to do module-wide initialization. */
114 int
115 fpc_platform_module_init(dev_info_t *dip)
116 {
117 int status;
118
119 credentials = crget();
120 status = ldi_ident_from_dip(dip, &ldi_identifier);
121 if (status == 0)
122 ldi_identifier_valid = B_TRUE;
123 return ((status == 0) ? DDI_SUCCESS : DDI_FAILURE);
124 }
125
126 int
127 fpc_platform_node_init(dev_info_t *dip, int *avail)
128 {
129 int index;
130 char *name;
131 int nodename_size;
132 char *nodename = NULL;
133 fire4u_specific_t *platform_specific_data = NULL;
134 char *compatible = NULL;
135 px_regs_t *regs_p = NULL;
136 int regs_length = 0;
137
138 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
139 "compatible", &compatible) != DDI_PROP_SUCCESS)
194 return (DDI_FAILURE);
195 }
196
197 void
198 fpc_platform_node_fini(void *arg)
199 {
200 fire4u_specific_t *plat_arg = (fire4u_specific_t *)arg;
201 if (plat_arg == NULL)
202 return;
203 if (plat_arg->nodename)
204 kmem_free(plat_arg->nodename, strlen(plat_arg->nodename)+1);
205 kmem_free(plat_arg, sizeof (fire4u_specific_t));
206 }
207
208 /*ARGSUSED*/
209 void
210 fpc_platform_module_fini(dev_info_t *dip)
211 {
212 if (ldi_identifier_valid)
213 ldi_ident_release(ldi_identifier);
214 if (credentials)
215 crfree(credentials);
216 }
217
218 fire_perfreg_handle_t
219 fpc_get_perfreg_handle(int devnum)
220 {
221 int rval = EINVAL;
222
223 fire_counter_handle_impl_t *handle_impl =
224 kmem_zalloc(sizeof (fire_counter_handle_impl_t), KM_SLEEP);
225
226 if ((handle_impl->devspec =
227 fpc_get_platform_data_by_number(devnum)) != NULL) {
228 rval = ldi_open_by_name(handle_impl->devspec->nodename,
229 OPEN_FLAGS, credentials, &handle_impl->devhandle,
230 ldi_identifier);
231 }
232
233 if (rval != SUCCESS) {
234 kmem_free(handle_impl, sizeof (fire_counter_handle_impl_t));
235 return ((fire_perfreg_handle_t)-1);
236 } else {
237 return ((fire_perfreg_handle_t)handle_impl);
238 }
239 }
240
241 int
242 fpc_free_counter_handle(fire_perfreg_handle_t handle)
243 {
244 fire_counter_handle_impl_t *handle_impl =
245 (fire_counter_handle_impl_t *)handle;
246 (void) ldi_close(handle_impl->devhandle, OPEN_FLAGS, credentials);
247 kmem_free(handle_impl, sizeof (fire_counter_handle_impl_t));
248 return (SUCCESS);
249 }
250
251 int
252 fpc_event_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
253 uint64_t *reg_data, boolean_t is_write)
254 {
255 int rval;
256 int ioctl_rval;
257 pcitool_reg_t prg;
258 fire_counter_handle_impl_t *handle_impl =
259 (fire_counter_handle_impl_t *)handle;
260 int cmd = is_write ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
261
262 prg.user_version = PCITOOL_VERSION;
263
264 if (group == jbc) {
265 prg.barnum = JBUS_BANK;
266 prg.offset = counter_select_offsets[group] -
267 handle_impl->devspec->jbus_bank_base;
268 } else {
269 prg.barnum = PCIE_BANK;
270
271 /*
272 * Note that a pcie_bank_base isn't needed. Pcie register
273 * offsets are already relative to the start of their bank. No
274 * base needs to be subtracted to get the relative offset that
275 * pcitool ioctls want.
276 */
277 prg.offset = counter_select_offsets[group];
278 }
279 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 | PCITOOL_ACC_ATTR_ENDN_BIG;
280 prg.data = *reg_data;
281
282 /* Read original value. */
283 if (((rval = ldi_ioctl(handle_impl->devhandle, cmd, (intptr_t)&prg,
284 FKIOCTL, credentials, &ioctl_rval)) == SUCCESS) && (!is_write)) {
285 *reg_data = prg.data;
286 }
287
288 return (rval);
289 }
290
291 int
292 fpc_counter_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
293 int counter_index, uint64_t *value, boolean_t is_write)
294 {
295 int rval;
296 int ioctl_rval;
297 pcitool_reg_t prg;
298 fire_counter_handle_impl_t *handle_impl =
299 (fire_counter_handle_impl_t *)handle;
300 int command =
301 (is_write) ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
302
303 prg.user_version = PCITOOL_VERSION;
304 /*
305 * Note that stated PCIE offsets are relative to the beginning of their
306 * register bank, while JBUS offsets are absolute.
307 */
308 if (group == jbc) {
309 prg.barnum = JBUS_BANK;
310 prg.offset = counter_reg_offsets[counter_index] -
311 handle_impl->devspec->jbus_bank_base;
312 } else {
313 prg.barnum = PCIE_BANK;
314 prg.offset = counter_reg_offsets[counter_index];
315 }
316
317 if ((group == lpu) && (is_write)) {
318 prg.offset += LPU_LINK_PERFCTR_WRITE_OFFSET;
319 }
320
321 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 | PCITOOL_ACC_ATTR_ENDN_BIG;
322 prg.data = *value;
323
324 if (((rval = ldi_ioctl(handle_impl->devhandle, command, (intptr_t)&prg,
325 FKIOCTL, credentials, &ioctl_rval)) == SUCCESS) && (!is_write)) {
326 *value = prg.data;
327 }
328
329 return (rval);
330 }
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
29 */
30
31 #include <sys/file.h>
32 #include <sys/sunndi.h>
33 #include <sys/sunddi.h>
34 #include <sys/sunldi.h>
35 #include <io/px/px_regs.h>
36 #include <sys/pci_tools.h>
37 #include <fpc.h>
38 #include <fpc-impl.h>
39
40 #define CHIP_COMPATIBLE_NAME "pciex108e,80f0"
41 #define BANK_ADDR_MASK 0x7FFFFF
42
43 #define OPEN_FLAGS (FREAD | FWRITE)
44
45 #define PCIE_BANK 0
46 #define JBUS_BANK 1
47
48 typedef struct px_regs {
49 uint32_t addr_hi;
50 uint32_t addr_lo;
88 TLU_PERFORMANCE_COUNTER_ONE,
89 TLU_PERFORMANCE_COUNTER_TWO,
90 LPU_LINK_PERFORMANCE_COUNTER1,
91 LPU_LINK_PERFORMANCE_COUNTER2
92 };
93
94 /*
95 * Add the following to one of the LPU_LINK_PERFORMANCE_COUNTERx offsets to
96 * write a value to that counter.
97 */
98 #define LPU_LINK_PERFCTR_WRITE_OFFSET 0x8
99
100 /*
101 * Note that LPU_LINK_PERFORMANCE_COUNTER_CONTROL register is hard-reset to
102 * zeros and this is the value we want. This register isn't touched by this
103 * module, and as long as it remains untouched by other modules we're OK.
104 */
105
106 static ldi_ident_t ldi_identifier;
107 static boolean_t ldi_identifier_valid = B_FALSE;
108
109 /* Called by _init to determine if it is OK to install driver. */
110 int
111 fpc_platform_check()
112 {
113 return (SUCCESS);
114 }
115
116 /* Called during attach to do module-wide initialization. */
117 int
118 fpc_platform_module_init(dev_info_t *dip)
119 {
120 int status;
121
122 status = ldi_ident_from_dip(dip, &ldi_identifier);
123 if (status == 0)
124 ldi_identifier_valid = B_TRUE;
125 return ((status == 0) ? DDI_SUCCESS : DDI_FAILURE);
126 }
127
128 int
129 fpc_platform_node_init(dev_info_t *dip, int *avail)
130 {
131 int index;
132 char *name;
133 int nodename_size;
134 char *nodename = NULL;
135 fire4u_specific_t *platform_specific_data = NULL;
136 char *compatible = NULL;
137 px_regs_t *regs_p = NULL;
138 int regs_length = 0;
139
140 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
141 "compatible", &compatible) != DDI_PROP_SUCCESS)
196 return (DDI_FAILURE);
197 }
198
199 void
200 fpc_platform_node_fini(void *arg)
201 {
202 fire4u_specific_t *plat_arg = (fire4u_specific_t *)arg;
203 if (plat_arg == NULL)
204 return;
205 if (plat_arg->nodename)
206 kmem_free(plat_arg->nodename, strlen(plat_arg->nodename)+1);
207 kmem_free(plat_arg, sizeof (fire4u_specific_t));
208 }
209
210 /*ARGSUSED*/
211 void
212 fpc_platform_module_fini(dev_info_t *dip)
213 {
214 if (ldi_identifier_valid)
215 ldi_ident_release(ldi_identifier);
216 }
217
218 fire_perfreg_handle_t
219 fpc_get_perfreg_handle(int devnum)
220 {
221 int rval = EINVAL;
222
223 fire_counter_handle_impl_t *handle_impl =
224 kmem_zalloc(sizeof (fire_counter_handle_impl_t), KM_SLEEP);
225
226 if ((handle_impl->devspec =
227 fpc_get_platform_data_by_number(devnum)) != NULL) {
228 rval = ldi_open_by_name(handle_impl->devspec->nodename,
229 OPEN_FLAGS, kcred, &handle_impl->devhandle,
230 ldi_identifier);
231 }
232
233 if (rval != SUCCESS) {
234 kmem_free(handle_impl, sizeof (fire_counter_handle_impl_t));
235 return ((fire_perfreg_handle_t)-1);
236 } else {
237 return ((fire_perfreg_handle_t)handle_impl);
238 }
239 }
240
241 int
242 fpc_free_counter_handle(fire_perfreg_handle_t handle)
243 {
244 fire_counter_handle_impl_t *handle_impl =
245 (fire_counter_handle_impl_t *)handle;
246 (void) ldi_close(handle_impl->devhandle, OPEN_FLAGS, kcred);
247 kmem_free(handle_impl, sizeof (fire_counter_handle_impl_t));
248 return (SUCCESS);
249 }
250
251 int
252 fpc_event_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
253 uint64_t *reg_data, boolean_t is_write)
254 {
255 int rval;
256 int ioctl_rval;
257 pcitool_reg_t prg;
258 fire_counter_handle_impl_t *handle_impl =
259 (fire_counter_handle_impl_t *)handle;
260 int cmd = is_write ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
261
262 prg.user_version = PCITOOL_VERSION;
263
264 if (group == jbc) {
265 prg.barnum = JBUS_BANK;
266 prg.offset = counter_select_offsets[group] -
267 handle_impl->devspec->jbus_bank_base;
268 } else {
269 prg.barnum = PCIE_BANK;
270
271 /*
272 * Note that a pcie_bank_base isn't needed. Pcie register
273 * offsets are already relative to the start of their bank. No
274 * base needs to be subtracted to get the relative offset that
275 * pcitool ioctls want.
276 */
277 prg.offset = counter_select_offsets[group];
278 }
279 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 | PCITOOL_ACC_ATTR_ENDN_BIG;
280 prg.data = *reg_data;
281
282 /* Read original value. */
283 if (((rval = ldi_ioctl(handle_impl->devhandle, cmd, (intptr_t)&prg,
284 FKIOCTL, kcred, &ioctl_rval)) == SUCCESS) && (!is_write)) {
285 *reg_data = prg.data;
286 }
287
288 return (rval);
289 }
290
291 int
292 fpc_counter_io(fire_perfreg_handle_t handle, fire_perfcnt_t group,
293 int counter_index, uint64_t *value, boolean_t is_write)
294 {
295 int rval;
296 int ioctl_rval;
297 pcitool_reg_t prg;
298 fire_counter_handle_impl_t *handle_impl =
299 (fire_counter_handle_impl_t *)handle;
300 int command =
301 (is_write) ? PCITOOL_NEXUS_SET_REG : PCITOOL_NEXUS_GET_REG;
302
303 prg.user_version = PCITOOL_VERSION;
304 /*
305 * Note that stated PCIE offsets are relative to the beginning of their
306 * register bank, while JBUS offsets are absolute.
307 */
308 if (group == jbc) {
309 prg.barnum = JBUS_BANK;
310 prg.offset = counter_reg_offsets[counter_index] -
311 handle_impl->devspec->jbus_bank_base;
312 } else {
313 prg.barnum = PCIE_BANK;
314 prg.offset = counter_reg_offsets[counter_index];
315 }
316
317 if ((group == lpu) && (is_write)) {
318 prg.offset += LPU_LINK_PERFCTR_WRITE_OFFSET;
319 }
320
321 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 | PCITOOL_ACC_ATTR_ENDN_BIG;
322 prg.data = *value;
323
324 if (((rval = ldi_ioctl(handle_impl->devhandle, command, (intptr_t)&prg,
325 FKIOCTL, kcred, &ioctl_rval)) == SUCCESS) && (!is_write)) {
326 *value = prg.data;
327 }
328
329 return (rval);
330 }
|