1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Opl platform specific PICL functions.
26 *
27 * called when :
28 * machine_type == MTYPE_OPL
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <kstat.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <libintl.h>
39 #include <note.h>
40 #include <dlfcn.h>
41 #include <errno.h>
42 #include <sys/systeminfo.h>
43 #include <sys/openpromio.h>
44 #include <sys/sysmacros.h>
45 #include <picl.h>
46 #include "picldefs.h"
47 #include <pdevinfo.h>
48 #include <display.h>
49 #include <libprtdiag.h>
50 #include <alloca.h>
51 #include "opl_picl.h"
52 #include <sys/pci.h>
53 #include <sys/pci_tools.h>
54 #include <sys/types.h>
55
56 #if !defined(TEXT_DOMAIN)
57 #define TEXT_DOMAIN "SYS_TEST"
58 #endif
59
60 static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname,
61 void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args));
62 static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
63 picl_nodehdl_t *nodeh);
64 static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
65 int dev_no, int *actual, int *maximum, uint32_t *speed_max,
66 uint32_t *speed_at, int *type);
67 static int opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
68 static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
69 static int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
70 char **outbuf);
71 static int picldiag_get_clock_freq(picl_nodehdl_t modh,
72 uint32_t *freq, uint32_t *freq_max);
73 static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
74 char *prop_name, int *ret);
75 static uint32_t read_long(int fd, int bus, int dev, int func,
76 int offset, int *ret);
77 static uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
78 int *ret);
79 static uint16_t read_word(int fd, int bus, int dev, int func, int offset,
80 int *ret);
81
82 /*
83 * Collect I/O nodes information.
84 */
85 /* ARGSUSED */
86 static picl_errno_t
opl_pci_callback(picl_nodehdl_t pcih,void * args)87 opl_pci_callback(picl_nodehdl_t pcih, void *args)
88 {
89 picl_errno_t err = PICL_SUCCESS;
90 picl_nodehdl_t nodeh;
91 picl_prophdl_t proph;
92 picl_propinfo_t pinfo;
93 char path[MAXSTRLEN];
94 char parent_path[MAXSTRLEN];
95 static char root_path[MAXSTRLEN];
96 char piclclass[PICL_CLASSNAMELEN_MAX];
97 char name[MAXSTRLEN];
98 char model[MAXSTRLEN];
99 char *compatible;
100 char binding_name[MAXSTRLEN];
101 struct io_card pci_card;
102 char status[6] = "N/A";
103 int portid = PROP_INVALID;
104 int *reg_val;
105 int board = PROP_INVALID;
106 static int saved_board = PROP_INVALID;
107 static int saved_portid = PROP_INVALID;
108 int actual = PROP_INVALID, maximum = PROP_INVALID;
109 int bus_type;
110 int rev_id = PROP_INVALID, dev_id = PROP_INVALID;
111 int ven_id = PROP_INVALID;
112 size_t prop_size;
113
114 (void) memset(&pci_card, 0, sizeof (pci_card));
115
116 err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
117 piclclass, sizeof (piclclass));
118
119 if (err != PICL_SUCCESS)
120 /* Do not proceed to parse this branch */
121 return (err);
122
123 if (!IS_PCI(piclclass))
124 /* Do not parse non-pci nodes */
125 return (PICL_INVALIDARG);
126
127 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
128 sizeof (parent_path));
129 if (err != PICL_SUCCESS)
130 /* Do not proceed to parse this branch */
131 return (err);
132 err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
133 sizeof (board));
134
135 if (err == PICL_NORESPONSE)
136 /* Do not proceed to parse this branch */
137 return (err);
138 else if (err != PICL_PROPNOTFOUND) {
139 saved_board = board;
140 /* Save board node's pathname */
141 prop_size = sizeof (parent_path) + 1;
142 if (prop_size > MAXSTRLEN)
143 prop_size = MAXSTRLEN;
144 (void) strlcpy(root_path, parent_path, prop_size);
145 }
146
147 err = picl_get_propval_by_name
148 (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
149
150 if (err != PICL_PROPNOTFOUND)
151 saved_portid = portid;
152
153 /* Walk through the children */
154
155 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
156 sizeof (picl_nodehdl_t));
157
158 while (err == PICL_SUCCESS) {
159 uint32_t freq_max = 0, freq_at = 0;
160
161 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
162 piclclass, sizeof (piclclass));
163 if (err != PICL_SUCCESS)
164 /* Do not proceed to parse this node */
165 return (err);
166
167 if (IS_EBUS(piclclass)) {
168 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
169 &nodeh, sizeof (picl_nodehdl_t));
170 continue;
171 }
172
173 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
174 path, sizeof (path));
175 if (err != PICL_SUCCESS) {
176 /* Do not proceed to parse this node */
177 return (err);
178 }
179
180 prop_size = sizeof (path) + 1;
181 if (prop_size > MAXSTRLEN)
182 prop_size = MAXSTRLEN;
183 (void) strlcpy(pci_card.notes, path, prop_size);
184
185 pci_card.board = saved_board;
186 pci_card.schizo_portid = saved_portid;
187
188 /*
189 * Get bus#, dev# and func# for this card from 'reg' property.
190 */
191
192 err = picl_get_propinfo_by_name
193 (nodeh, OBP_PROP_REG, &pinfo, &proph);
194 if (err == PICL_SUCCESS) {
195 /* All of the array of bytes of "reg" have to be read */
196 reg_val = malloc(pinfo.size);
197 if (reg_val == NULL)
198 return (PICL_FAILURE);
199
200
201 err = picl_get_propval_by_name
202 (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
203
204 if (err != PICL_SUCCESS) {
205 free(reg_val);
206 /* Do not proceed to parse this node */
207 return (err);
208 }
209
210 if (reg_val[0] != 0) {
211 pci_card.dev_no =
212 (((reg_val[0]) & PCI_DEV_MASK) >> 11);
213 pci_card.func_no =
214 (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
215 pci_card.slot =
216 (((reg_val[0]) & PCI_BUS_MASK) >> 16);
217 } else
218 free(reg_val);
219 }
220
221 err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
222 pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
223 &bus_type);
224
225 if (err != PICL_SUCCESS) {
226 /*
227 * get_lane_width will fail when run as non-root.
228 * Set bus_type to PCI_UNKN so that bus frequency,
229 * bus type and lane width will print as "--" or UNKN.
230 */
231 bus_type = PCI_UNKN;
232 }
233
234
235 err = picl_get_propval_by_name
236 (nodeh, PICL_PROP_NAME, name, sizeof (name));
237 if (err != PICL_SUCCESS)
238 (void) strcpy(name, "");
239
240 /*
241 * Get the name of this card. If binding_name is found,
242 * name will be <nodename>-<binding_name>
243 */
244
245 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
246 binding_name, sizeof (binding_name));
247 if (err == PICL_PROPNOTFOUND) {
248 /*
249 * if compatible prop is found, name will be
250 * <nodename>-<compatible>
251 */
252 err = opl_get_first_compatible_value(nodeh,
253 &compatible);
254 if (err == PICL_SUCCESS) {
255 (void) strlcat(name, "-", MAXSTRLEN);
256 (void) strlcat(name, compatible, MAXSTRLEN);
257 free(compatible);
258 }
259 } else if (err != PICL_SUCCESS) {
260 /* No binding-name or compatible */
261 (void) strcpy(binding_name, "N/A");
262 } else if (strcmp(name, binding_name) != 0) {
263 (void) strlcat(name, "-", MAXSTRLEN);
264 (void) strlcat(name, binding_name, MAXSTRLEN);
265 }
266
267
268 prop_size = sizeof (name) + 1;
269 if (prop_size > MAXSTRLEN)
270 prop_size = MAXSTRLEN;
271 (void) strlcpy(pci_card.name, name, prop_size);
272
273 /* Get the status of the card */
274 err = picl_get_propval_by_name
275 (nodeh, PICL_PROP_STATUS, status, sizeof (status));
276
277
278 /* Get the model of this card */
279
280 err = picl_get_propval_by_name
281 (nodeh, OBP_PROP_MODEL, model, sizeof (model));
282 prop_size = sizeof (model) + 1;
283 if (prop_size > MAXSTRLEN)
284 prop_size = MAXSTRLEN;
285 if (err != PICL_SUCCESS)
286 (void) strcpy(model, "N/A");
287 (void) strlcpy(pci_card.model, model, prop_size);
288
289 if (bus_type == PCI)
290 (void) strlcpy(pci_card.bus_type,
291 "PCI", sizeof (pci_card.bus_type));
292 else if (bus_type == PCIX)
293 (void) strlcpy(pci_card.bus_type,
294 "PCIx", sizeof (pci_card.bus_type));
295 else if (bus_type == PCIE)
296 (void) strlcpy(pci_card.bus_type,
297 "PCIe", sizeof (pci_card.bus_type));
298 else
299 (void) strlcpy(pci_card.bus_type,
300 "UNKN", sizeof (pci_card.bus_type));
301
302 /* Get revision id */
303 err = picl_get_propval_by_name
304 (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
305
306 /* Get device id */
307 err = picl_get_propval_by_name
308 (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
309
310 /* Get vendor id */
311 err = picl_get_propval_by_name
312 (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
313
314 /*
315 * prtdiag -v prints all devices
316 */
317
318 /* Print board number */
319 log_printf("%02d ", pci_card.board);
320 /* Print IO Type */
321 log_printf("%-5.5s ", pci_card.bus_type);
322
323 log_printf("%-3d ", pci_card.schizo_portid);
324 log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id);
325
326 log_printf("%3d, %2d, %2d",
327 pci_card.slot, pci_card.dev_no, pci_card.func_no);
328
329 /* Print status */
330 log_printf(" %-5.5s ", status);
331
332 /* Print Lane widths, Max/Sup Freq, Speed */
333 if (bus_type == PCIE) {
334 PRINT_FMT(actual, maximum);
335 } else if (bus_type == PCIX) {
336 PRINT_FREQ_FMT(freq_at, freq_max);
337 } else if (bus_type == PCI) {
338 err = picldiag_get_clock_freq(nodeh, &freq_at,
339 &freq_max);
340 PRINT_FREQ_FMT(freq_at, freq_max);
341 } else
342 log_printf(" -- , -- ");
343
344 /* Print Card Name */
345 log_printf("%-30.30s", pci_card.name);
346
347 /* Print Card Model */
348 log_printf(" %-20.20s", pci_card.model);
349
350 log_printf("\n");
351
352 log_printf("%4s%-100.100s", " ", pci_card.notes);
353 log_printf("\n");
354 log_printf("\n");
355
356
357 err = picl_get_propval_by_name
358 (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
359
360 }
361
362 return (PICL_WALK_CONTINUE);
363 }
364
365 /*
366 * opl_display_pci
367 * Display all the PCI IO cards on this board.
368 */
369 static int
opl_display_pci(int syserrlog,picl_nodehdl_t plafh)370 opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
371 {
372 picl_errno_t err;
373 char *fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
374 char *fmt2 = "%-16s";
375 static int banner = FALSE; /* Have we printed the column headings? */
376
377 if (banner == FALSE) {
378 log_printf("\n", 0);
379 log_printf("=========================", 0);
380 log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
381 log_printf("=========================", 0);
382 log_printf("\n", 0);
383 log_printf("\n", 0);
384 log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
385 "", "", 0);
386 log_printf("\n", 0);
387
388 log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID",
389 " BDF", "State", "Act, Max", "Name", "Model", 0);
390
391 log_printf("\n");
392
393 log_printf(fmt,
394 "---", "-----", "----", " ------------------",
395 " ---------", "-----", "-----------",
396 "------------------------------",
397 "--------------------", 0);
398 log_printf("\n");
399 log_printf(fmt2, " Logical Path");
400 log_printf("\n");
401 log_printf(fmt2, " ------------");
402 log_printf("\n");
403 banner = TRUE;
404 }
405
406 err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
407 return (err);
408 }
409
410
411 /*
412 * return the first compatible value
413 */
414 static int
opl_get_first_compatible_value(picl_nodehdl_t nodeh,char ** outbuf)415 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
416 {
417 picl_errno_t err;
418 picl_prophdl_t proph;
419 picl_propinfo_t pinfo;
420 picl_prophdl_t tblh;
421 picl_prophdl_t rowproph;
422 char *pval;
423
424 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
425 &pinfo, &proph);
426 if (err != PICL_SUCCESS)
427 return (err);
428
429 if (pinfo.type == PICL_PTYPE_CHARSTRING) {
430 pval = malloc(pinfo.size);
431 if (pval == NULL)
432 return (PICL_FAILURE);
433 err = picl_get_propval(proph, pval, pinfo.size);
434 if (err != PICL_SUCCESS) {
435 free(pval);
436 return (err);
437 }
438 *outbuf = pval;
439 return (PICL_SUCCESS);
440 }
441
442 if (pinfo.type != PICL_PTYPE_TABLE)
443 return (PICL_FAILURE);
444
445 /* get first string from table */
446 err = picl_get_propval(proph, &tblh, pinfo.size);
447 if (err != PICL_SUCCESS)
448 return (err);
449
450 err = picl_get_next_by_row(tblh, &rowproph);
451 if (err != PICL_SUCCESS)
452 return (err);
453
454 err = picl_get_propinfo(rowproph, &pinfo);
455 if (err != PICL_SUCCESS)
456 return (err);
457
458 pval = malloc(pinfo.size);
459 if (pval == NULL)
460 return (PICL_FAILURE);
461
462 err = picl_get_propval(rowproph, pval, pinfo.size);
463 if (err != PICL_SUCCESS) {
464 free(pval);
465 return (err);
466 }
467
468 *outbuf = pval;
469 return (PICL_SUCCESS);
470 }
471
472 int
do_piclinfo(int syserrlog)473 do_piclinfo(int syserrlog)
474 {
475 picl_nodehdl_t rooth; /* root PICL node for IO display */
476 picl_nodehdl_t plafh; /* Platform PICL node for IO display */
477
478 picl_errno_t err;
479
480 err = picl_initialize();
481 if (err != PICL_SUCCESS) {
482 (void) log_printf("picl_initialize failed: %s\n",
483 picl_strerror(err));
484 return (err);
485 }
486
487
488 err = picl_get_root(&rooth);
489 if (err != PICL_SUCCESS) {
490 (void) log_printf("Getting root node failed: %s\n",
491 picl_strerror(err));
492 return (err);
493 }
494
495 err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
496
497 if (err != PICL_SUCCESS) {
498 (void) log_printf("Getting nodes by name failed: %s\n",
499 picl_strerror(err));
500 return (err);
501 }
502
503 err = opl_display_pci(syserrlog, plafh);
504
505 (void) picl_shutdown();
506
507 return (err);
508 }
509
510 /*
511 * search children to get the node by the nodename
512 */
513 static int
opl_get_node_by_name(picl_nodehdl_t rooth,char * name,picl_nodehdl_t * nodeh)514 opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
515 picl_nodehdl_t *nodeh)
516 {
517 picl_nodehdl_t childh;
518 int err;
519 char *nodename;
520
521 nodename = alloca(strlen(name) + 1);
522 if (nodename == NULL)
523 return (PICL_FAILURE);
524
525 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
526 sizeof (picl_nodehdl_t));
527
528 while (err == PICL_SUCCESS) {
529 err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
530 nodename, (strlen(name) + 1));
531 if (err != PICL_SUCCESS) {
532 err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
533 &childh, sizeof (picl_nodehdl_t));
534 continue;
535 }
536
537 if (strcmp(nodename, name) == 0) {
538 *nodeh = childh;
539 return (PICL_SUCCESS);
540 }
541
542 err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
543 &childh, sizeof (picl_nodehdl_t));
544 }
545
546 return (err);
547 }
548
549 static int
open_root_complex(char * root_complex)550 open_root_complex(char *root_complex)
551 {
552 char *path;
553 static char device_str[] = {"/devices"};
554 static char devctl_str[] = {":reg"};
555 int fd;
556
557 path = malloc(
558 strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
559 if (path == NULL)
560 return (PICL_FAILURE);
561 (void) strcpy(path, device_str);
562 (void) strcat(path, root_complex);
563 (void) strcat(path, devctl_str);
564
565 if ((fd = open(path, O_RDWR)) == -1) {
566 return (-1);
567 }
568 return (fd);
569 }
570
571 static uint32_t
read_long(int fd,int bus,int dev,int func,int offset,int * ret)572 read_long(int fd, int bus, int dev, int func, int offset, int *ret)
573 {
574 int rval;
575 pcitool_reg_t prg;
576
577 prg.user_version = PCITOOL_VERSION;
578 prg.barnum = 0;
579 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
580 PCITOOL_ACC_ATTR_ENDN_LTL;
581 prg.bus_no = bus;
582 prg.dev_no = dev;
583 prg.func_no = func;
584 prg.offset = offset;
585 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
586 if (rval != 0) {
587 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
588 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
589 }
590 *ret = rval;
591 return ((uint32_t)prg.data);
592 }
593
594 static uint16_t
read_word(int fd,int bus,int dev,int func,int offset,int * ret)595 read_word(int fd, int bus, int dev, int func, int offset, int *ret)
596 {
597 int rval;
598 pcitool_reg_t prg;
599
600 prg.user_version = PCITOOL_VERSION;
601 prg.barnum = 0;
602 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
603 PCITOOL_ACC_ATTR_ENDN_LTL;
604 prg.bus_no = bus;
605 prg.dev_no = dev;
606 prg.func_no = func;
607 prg.offset = offset;
608 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
609 if (rval != 0) {
610 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
611 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
612 }
613 *ret = rval;
614 return ((uint16_t)prg.data);
615 }
616
617 static uint8_t
read_byte(int fd,int bus,int dev,int func,int offset,int * ret)618 read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
619 {
620 int rval;
621 pcitool_reg_t prg;
622
623 prg.user_version = PCITOOL_VERSION;
624 prg.barnum = 0;
625 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
626 PCITOOL_ACC_ATTR_ENDN_LTL;
627 prg.bus_no = bus;
628 prg.dev_no = dev;
629 prg.func_no = func;
630 prg.offset = offset;
631 rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
632 if (rval != 0) {
633 log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
634 log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
635 }
636 *ret = rval;
637 return ((uint8_t)prg.data);
638 }
639
640
641 static picl_errno_t
get_lane_width(char * device_path,int bus,int dev,int func,int * actual,int * maximum,uint32_t * speed_max,uint32_t * speed_at,int * type)642 get_lane_width
643 (char *device_path, int bus, int dev, int func, int *actual,
644 int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
645 {
646 uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
647 int fd, ret;
648
649 if (device_path == NULL)
650 return (PICL_FAILURE);
651
652 fd = open_root_complex(device_path);
653 if (fd == -1)
654 return (PICL_FAILURE);
655
656 /*
657 * Link Capabilities and Link Status registers are in the
658 * PCI-E capabilities register. They are at offset
659 * 0xc and 0x12 respectively. They are documented in section
660 * 7.8 of the PCI Express Base Specification. The address of
661 * that structure is not fixed, it's kind of a linked list.
662 * The Capabilities Pointer reg (8 bits) is always at 0x34.
663 * It contains a pointer to the first capabilities structure.
664 * For each capability structure, the first 8 bits is the capability
665 * ID. The next 8 bits is the pointer to the next structure.
666 * If the Next Cap register is zero, it's the end of the list.
667 * The capability ID for the PCI-E strucutre is 0x10. The idea
668 * is to follow the links until you find a Cap ID of 0x10, then
669 * read the registers at 0xc and 0x12 from there.
670 * If there's no Cap ID 0x10, then it's not a PCI-E device.
671 */
672
673 cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
674 if (ret != 0) {
675 /* ioctl failure */
676 close(fd);
677 return (PICL_FAILURE);
678 }
679 cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
680 if (ret != 0) {
681 /* ioctl failure */
682 close(fd);
683 return (PICL_FAILURE);
684 }
685 *type = PCI;
686 capid = cap_reg & PCI_CAP_MASK;
687 while (cap_ptr != 0) {
688
689 if (capid == PCI_CAP_ID_PCI_E) {
690 link_cap = read_long(fd, bus, dev, func, cap_ptr +
691 PCIE_LINKCAP, &ret);
692 if (ret != 0) {
693 close(fd);
694 return (PICL_FAILURE);
695 }
696 link_status = read_word(fd, bus, dev, func,
697 cap_ptr + PCIE_LINKSTS, &ret);
698 if (ret != 0) {
699 close(fd);
700 return (PICL_FAILURE);
701 }
702 *actual = ((link_status >> PCI_LINK_SHIFT) &
703 PCI_LINK_MASK);
704 *maximum = ((link_cap >> PCI_LINK_SHIFT) &
705 PCI_LINK_MASK);
706 *type = PCIE;
707 } else if (capid == PCI_CAP_ID_PCIX) {
708 uint32_t pcix_status;
709 uint8_t hdr_type;
710 int max_speed = PCI_FREQ_66;
711
712 hdr_type = read_byte
713 (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
714 if (ret != 0) {
715 /* ioctl failure */
716 close(fd);
717 return (PICL_FAILURE);
718 }
719 *type = PCIX;
720 if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
721 /* This is a PCI-X bridge */
722 uint16_t sec_status, mode;
723 sec_status = read_word(fd, bus, dev, func,
724 cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
725 if (ret != 0) {
726 /* ioctl failure */
727 close(fd);
728 return (PICL_FAILURE);
729 }
730 if (sec_status & PCI_SEC_133)
731 max_speed = PCI_FREQ_133;
732 if (sec_status & PCI_SEC_266)
733 max_speed = PCI_FREQ_266;
734 if (sec_status & PCI_SEC_533)
735 max_speed = PCI_FREQ_533;
736 *speed_max = max_speed;
737 mode = (sec_status >> PCI_CLASS_BRIDGE) &
738 PCI_BRIDGE_MC;
739 if (mode) {
740 int speed;
741 if (mode == PCI_MODE_66)
742 speed = PCI_FREQ_66;
743 else if (mode == PCI_MODE_100)
744 speed = PCI_FREQ_100;
745 else if (mode == PCI_MODE_133)
746 speed = PCI_FREQ_133;
747 *speed_at = speed;
748 }
749
750 } else { /* Leaf device */
751 pcix_status = read_long(fd, bus, dev, func,
752 cap_ptr + PCI_PCIX_STATUS, &ret);
753 if (ret != 0) {
754 /* ioctl failure */
755 close(fd);
756 return (PICL_FAILURE);
757 }
758 if (pcix_status &
759 (PCI_LEAF_ULONG << PCI_SHIFT_133))
760 max_speed = PCI_FREQ_133;
761 if (pcix_status &
762 (PCI_LEAF_ULONG << PCI_SHIFT_266))
763 max_speed = PCI_FREQ_266;
764 if (pcix_status &
765 (PCI_LEAF_ULONG << PCI_SHIFT_533))
766 max_speed = PCI_FREQ_533;
767 *speed_max = max_speed;
768 }
769 }
770 cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
771 cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
772 if (ret != 0) {
773 /* ioctl failure */
774 close(fd);
775 return (PICL_FAILURE);
776 }
777 capid = cap_reg & PCI_CAP_MASK;
778 }
779
780 if (close(fd) == -1) {
781 return (PICL_FAILURE);
782 }
783
784 return (PICL_SUCCESS);
785 }
786
787 static int
is_66mhz_capable(picl_nodehdl_t nodeh)788 is_66mhz_capable(picl_nodehdl_t nodeh)
789 {
790 picl_errno_t err;
791 picl_prophdl_t proph;
792 picl_propinfo_t pinfo;
793
794 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_66MHZ_CAPABLE,
795 &pinfo, &proph);
796 if (err == PICL_SUCCESS)
797 return (1);
798 return (0);
799 }
800
801 /*
802 * get the clock frequency
803 */
804 static int
picldiag_get_clock_freq(picl_nodehdl_t modh,uint32_t * freq,uint32_t * freq_max)805 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq, uint32_t *freq_max)
806 {
807 int err;
808 uint64_t clk_freq;
809
810 *freq_max = PCI_FREQ_33;
811 if (is_66mhz_capable(modh))
812 *freq_max = PCI_FREQ_66;
813 clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
814 if (err != PICL_SUCCESS)
815 return (err);
816
817 *freq = ROUND_TO_MHZ(clk_freq);
818
819 return (PICL_SUCCESS);
820 }
821
822 static uint64_t
picldiag_get_uint_propval(picl_nodehdl_t modh,char * prop_name,int * ret)823 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
824 {
825 int err;
826 picl_prophdl_t proph;
827 picl_propinfo_t pinfo;
828 uint8_t uint8v;
829 uint16_t uint16v;
830 uint32_t uint32v;
831 uint64_t uint64v;
832
833 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
834 if (err != PICL_SUCCESS) {
835 *ret = err;
836 return (0);
837 }
838
839 /*
840 * If it is not an int or uint prop, return failure
841 */
842 if ((pinfo.type != PICL_PTYPE_INT) &&
843 (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
844 *ret = PICL_FAILURE;
845 return (0);
846 }
847
848
849 /* uint prop */
850
851 switch (pinfo.size) {
852 case sizeof (uint8_t):
853 err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
854 *ret = err;
855 return (uint8v);
856 case sizeof (uint16_t):
857 err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
858 *ret = err;
859 return (uint16v);
860 case sizeof (uint32_t):
861 err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
862 *ret = err;
863 return (uint32v);
864 case sizeof (uint64_t):
865 err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
866 *ret = err;
867 return (uint64v);
868 default: /* not supported size */
869 *ret = PICL_FAILURE;
870 return (0);
871 }
872 }
873
874 /*
875 * recursively visit all nodes
876 */
877 static picl_errno_t
do_walk(picl_nodehdl_t rooth,const char * classname,void * c_args,picl_errno_t (* callback_fn)(picl_nodehdl_t hdl,void * args))878 do_walk(picl_nodehdl_t rooth, const char *classname,
879 void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
880 {
881 picl_errno_t err;
882 picl_nodehdl_t chdh;
883 char classval[PICL_CLASSNAMELEN_MAX];
884
885 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
886 sizeof (chdh));
887 while (err == PICL_SUCCESS) {
888 err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
889 classval, sizeof (classval));
890 if (err != PICL_SUCCESS)
891 return (err);
892
893 err = callback_fn(chdh, c_args);
894
895 if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
896 PICL_WALK_CONTINUE)
897 return (err);
898
899 err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
900 sizeof (chdh));
901 }
902 if (err == PICL_PROPNOTFOUND) /* end of a branch */
903 return (PICL_WALK_CONTINUE);
904 return (err);
905 }
906
907 int
get_proc_mode(void)908 get_proc_mode(void)
909 {
910 picl_nodehdl_t nodeh;
911 picl_prophdl_t proph;
912 picl_errno_t err;
913
914 err = picl_initialize();
915 if (err != PICL_SUCCESS) {
916 (void) log_printf("picl_initialize failed: %s\n",
917 picl_strerror(err));
918 return (err);
919 }
920
921 err = picl_get_node_by_path("/platform", &nodeh);
922 if (err != PICL_SUCCESS) {
923 (void) log_printf("Getting plat node failed: %s\n",
924 picl_strerror(err));
925 return (err);
926 }
927
928 err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode", &proph);
929 if (err != PICL_SUCCESS) {
930 /* Do not display error message */
931 return (err);
932 }
933
934 (void) picl_shutdown();
935
936 return (err);
937 }
938