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