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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * CMU-CH nexus utility routines:
29 * property and config routines for attach()
30 * reg/intr/range/assigned-address property routines for bus_map()
31 * init_child()
32 * fault handling
33 * debug functions
34 */
35
36 #include <sys/types.h>
37 #include <sys/kmem.h>
38 #include <sys/async.h>
39 #include <sys/sysmacros.h>
40 #include <sys/sunddi.h>
41 #include <sys/sunndi.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/fm/io/pci.h>
44 #include <sys/fm/util.h>
45 #include <sys/ddi_impldefs.h>
46 #include <sys/pcicmu/pcicmu.h>
47 #include <sys/promif.h>
48
49 /*
50 * get_pcmu_properties
51 *
52 * This function is called from the attach routine to get the key
53 * properties of the pci nodes.
54 *
55 * used by: pcmu_attach()
56 *
57 * return value: DDI_FAILURE on failure
58 */
59 int
get_pcmu_properties(pcmu_t * pcmu_p,dev_info_t * dip)60 get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip)
61 {
62 int i;
63
64 /*
65 * Get the device's port id.
66 */
67 if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) {
68 cmn_err(CE_WARN, "%s%d: no portid property\n",
69 ddi_driver_name(dip), ddi_get_instance(dip));
70 return (DDI_FAILURE);
71 }
72
73 /*
74 * Get the bus-ranges property.
75 */
76 i = sizeof (pcmu_p->pcmu_bus_range);
77 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
78 "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) {
79 cmn_err(CE_WARN, "%s%d: no bus-range property\n",
80 ddi_driver_name(dip), ddi_get_instance(dip));
81 return (DDI_FAILURE);
82 }
83 PCMU_DBG2(PCMU_DBG_ATTACH, dip,
84 "get_pcmu_properties: bus-range (%x,%x)\n",
85 pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi);
86
87 /*
88 * Get the ranges property.
89 */
90 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
91 (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) !=
92 DDI_SUCCESS) {
93 cmn_err(CE_WARN, "%s%d: no ranges property\n",
94 ddi_driver_name(dip), ddi_get_instance(dip));
95 return (DDI_FAILURE);
96 }
97 pcmu_fix_ranges(pcmu_p->pcmu_ranges,
98 pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t));
99
100 /*
101 * Determine the number upa slot interrupts.
102 */
103 pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip);
104 PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n",
105 pcmu_p->pcmu_numproxy);
106 return (DDI_SUCCESS);
107 }
108
109 /*
110 * free_pcmu_properties:
111 *
112 * This routine frees the memory used to cache the
113 * "ranges" properties of the pci bus device node.
114 *
115 * used by: pcmu_detach()
116 *
117 * return value: none
118 */
119 void
free_pcmu_properties(pcmu_t * pcmu_p)120 free_pcmu_properties(pcmu_t *pcmu_p)
121 {
122 kmem_free(pcmu_p->pcmu_ranges, pcmu_p->pcmu_ranges_length);
123 }
124
125 /*
126 * pcmu_reloc_reg
127 *
128 * If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses"
129 * property to fetch corresponding relocated address.
130 *
131 * used by: pcmu_map()
132 *
133 * return value:
134 *
135 * DDI_SUCCESS - on success
136 * DDI_ME_INVAL - regspec is invalid
137 */
138 int
pcmu_reloc_reg(dev_info_t * dip,dev_info_t * rdip,pcmu_t * pcmu_p,pci_regspec_t * rp)139 pcmu_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pcmu_t *pcmu_p,
140 pci_regspec_t *rp)
141 {
142 int assign_len, assign_entries, i;
143 pci_regspec_t *assign_p;
144 register uint32_t phys_hi = rp->pci_phys_hi;
145 register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK;
146 register uint32_t phys_addr = phys_hi & mask;
147
148 PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
149 "\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n",
150 rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
151 rp->pci_size_hi, rp->pci_size_low);
152
153 if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) {
154 return (DDI_SUCCESS);
155 }
156
157 /* phys_mid must be 0 regardless space type. XXX-64 bit mem space */
158 if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) {
159 PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip,
160 "phys_mid or size_hi not 0\n");
161 return (DDI_ME_INVAL);
162 }
163
164 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
165 "assigned-addresses", (caddr_t)&assign_p, &assign_len)) {
166 return (DDI_ME_INVAL);
167 }
168
169 assign_entries = assign_len / sizeof (pci_regspec_t);
170 for (i = 0; i < assign_entries; i++, assign_p++) {
171 if ((assign_p->pci_phys_hi & mask) == phys_addr) {
172 rp->pci_phys_low += assign_p->pci_phys_low;
173 break;
174 }
175 }
176 kmem_free(assign_p - i, assign_len);
177 PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
178 "\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n",
179 rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
180 rp->pci_size_hi, rp->pci_size_low);
181 return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL);
182 }
183
184 /*
185 * use "ranges" to translate relocated pci regspec into parent space
186 */
187 int
pcmu_xlate_reg(pcmu_t * pcmu_p,pci_regspec_t * pcmu_rp,struct regspec * new_rp)188 pcmu_xlate_reg(pcmu_t *pcmu_p, pci_regspec_t *pcmu_rp, struct regspec *new_rp)
189 {
190 int n;
191 pcmu_ranges_t *rng_p = pcmu_p->pcmu_ranges;
192 int rng_n = pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t);
193
194 uint32_t space_type = PCI_REG_ADDR_G(pcmu_rp->pci_phys_hi);
195 uint32_t reg_end, reg_begin = pcmu_rp->pci_phys_low;
196 uint32_t sz = pcmu_rp->pci_size_low;
197
198 uint32_t rng_begin, rng_end;
199
200 if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
201 if (reg_begin > PCI_CONF_HDR_SIZE) {
202 return (DDI_ME_INVAL);
203 }
204 sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE;
205 reg_begin += pcmu_rp->pci_phys_hi;
206 }
207 reg_end = reg_begin + sz - 1;
208
209 for (n = 0; n < rng_n; n++, rng_p++) {
210 if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) {
211 continue; /* not the same space type */
212 }
213
214 rng_begin = rng_p->child_low;
215 if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
216 rng_begin += rng_p->child_high;
217 }
218 rng_end = rng_begin + rng_p->size_low - 1;
219 if (reg_begin >= rng_begin && reg_end <= rng_end) {
220 break;
221 }
222 }
223 if (n >= rng_n) {
224 return (DDI_ME_REGSPEC_RANGE);
225 }
226
227 new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low;
228 new_rp->regspec_bustype = rng_p->parent_high;
229 new_rp->regspec_size = sz;
230 PCMU_DBG4(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip,
231 "\tpcmu_xlate_reg: entry %d new_rp %x.%x %x\n",
232 n, new_rp->regspec_bustype, new_rp->regspec_addr, sz);
233 return (DDI_SUCCESS);
234 }
235
236
237 /*
238 * pcmu_report_dev
239 *
240 * This function is called from our control ops routine on a
241 * DDI_CTLOPS_REPORTDEV request.
242 *
243 * The display format is
244 *
245 * <name><inst> at <pname><pinst> device <dev> function <func>
246 *
247 * where
248 *
249 * <name> this device's name property
250 * <inst> this device's instance number
251 * <name> parent device's name property
252 * <inst> parent device's instance number
253 * <dev> this device's device number
254 * <func> this device's function number
255 */
256 int
pcmu_report_dev(dev_info_t * dip)257 pcmu_report_dev(dev_info_t *dip)
258 {
259 if (dip == (dev_info_t *)0) {
260 return (DDI_FAILURE);
261 }
262 cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(dip),
263 ddi_get_name_addr(dip), ddi_driver_name(dip),
264 ddi_get_instance(dip));
265 return (DDI_SUCCESS);
266 }
267
268 /*
269 * name_child
270 *
271 * This function is called from pcmu_init_child to name a node. It is
272 * also passed as a callback for node merging functions.
273 *
274 * return value: DDI_SUCCESS, DDI_FAILURE
275 */
276 static int
name_child(dev_info_t * child,char * name,int namelen)277 name_child(dev_info_t *child, char *name, int namelen)
278 {
279 pci_regspec_t *pcmu_rp;
280 int reglen;
281 uint_t func;
282 char **unit_addr;
283 uint_t n;
284
285 /*
286 * Set the address portion of the node name based on
287 * unit-address property, if it exists.
288 * The interpretation of the unit-address is DD[,F]
289 * where DD is the device id and F is the function.
290 */
291 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
292 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) ==
293 DDI_PROP_SUCCESS) {
294 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
295 cmn_err(CE_WARN, "unit-address property in %s.conf"
296 " not well-formed", ddi_driver_name(child));
297 ddi_prop_free(unit_addr);
298 return (DDI_FAILURE);
299 }
300 (void) snprintf(name, namelen, "%s", *unit_addr);
301 ddi_prop_free(unit_addr);
302 return (DDI_SUCCESS);
303 }
304
305 /*
306 * The unit-address property is does not exist. Set the address
307 * portion of the node name based on the function and device number.
308 */
309 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
310 "reg", (int **)&pcmu_rp, (uint_t *)®len) == DDI_SUCCESS) {
311 if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
312 cmn_err(CE_WARN, "reg property not well-formed");
313 return (DDI_FAILURE);
314 }
315
316 func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi);
317 if (func != 0) {
318 (void) snprintf(name, namelen, "%x,%x",
319 PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func);
320 } else {
321 (void) snprintf(name, namelen, "%x",
322 PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi));
323 }
324 ddi_prop_free(pcmu_rp);
325 return (DDI_SUCCESS);
326 }
327 cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child));
328 return (DDI_FAILURE);
329 }
330
331 int
pcmu_uninit_child(pcmu_t * pcmu_p,dev_info_t * child)332 pcmu_uninit_child(pcmu_t *pcmu_p, dev_info_t *child)
333 {
334 PCMU_DBG2(PCMU_DBG_CTLOPS, pcmu_p->pcmu_dip,
335 "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n",
336 ddi_driver_name(child), ddi_get_instance(child));
337
338 ddi_set_name_addr(child, NULL);
339 ddi_remove_minor_node(child, NULL);
340 impl_rem_dev_props(child);
341
342 PCMU_DBG0(PCMU_DBG_PWR, ddi_get_parent(child), "\n\n");
343 return (DDI_SUCCESS);
344 }
345
346 /*
347 * pcmu_init_child
348 *
349 * This function is called from our control ops routine on a
350 * DDI_CTLOPS_INITCHILD request. It builds and sets the device's
351 * parent private data area.
352 *
353 * used by: pcmu_ctlops()
354 *
355 * return value: none
356 */
357 int
pcmu_init_child(pcmu_t * pcmu_p,dev_info_t * child)358 pcmu_init_child(pcmu_t *pcmu_p, dev_info_t *child)
359 {
360 char name[10];
361 ddi_acc_handle_t config_handle;
362 uint8_t bcr;
363 uint8_t header_type;
364
365 if (name_child(child, name, 10) != DDI_SUCCESS)
366 return (DDI_FAILURE);
367 ddi_set_name_addr(child, name);
368
369 PCMU_DBG2(PCMU_DBG_PWR, ddi_get_parent(child),
370 "INITCHILD: config regs setup for %s@%s\n",
371 ddi_node_name(child), ddi_get_name_addr(child));
372
373 /*
374 * Map the child configuration space to for initialization.
375 * We assume the obp will do the following in the devices
376 * config space:
377 *
378 * Set the latency-timer register to values appropriate
379 * for the devices on the bus (based on other devices
380 * MIN_GNT and MAX_LAT registers.
381 *
382 * Set the fast back-to-back enable bit in the command
383 * register if it's supported and all devices on the bus
384 * have the capability.
385 *
386 */
387 if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
388 ddi_set_name_addr(child, NULL);
389 return (DDI_FAILURE);
390 }
391
392 /*
393 * Determine the configuration header type.
394 */
395 header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
396 PCMU_DBG2(PCMU_DBG_INIT_CLD, pcmu_p->pcmu_dip, "%s: header_type=%x\n",
397 ddi_driver_name(child), header_type);
398
399 /*
400 * If the device has a bus control register then program it
401 * based on the settings in the command register.
402 */
403 if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
404 bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
405 if (pcmu_command_default & PCI_COMM_PARITY_DETECT)
406 bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
407 if (pcmu_command_default & PCI_COMM_SERR_ENABLE)
408 bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
409 bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
410 pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
411 }
412
413 pci_config_teardown(&config_handle);
414 return (DDI_SUCCESS);
415 }
416
417 /*
418 * pcmu_get_reg_set_size
419 *
420 * Given a dev info pointer to a pci child and a register number, this
421 * routine returns the size element of that reg set property.
422 *
423 * used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE
424 *
425 * return value: size of reg set on success, zero on error
426 */
427 off_t
pcmu_get_reg_set_size(dev_info_t * child,int rnumber)428 pcmu_get_reg_set_size(dev_info_t *child, int rnumber)
429 {
430 pci_regspec_t *pcmu_rp;
431 off_t size;
432 int i;
433
434 if (rnumber < 0) {
435 return (0);
436 }
437
438 /*
439 * Get the reg property for the device.
440 */
441 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
442 (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
443 return (0);
444 }
445
446 if (rnumber >= (i / (int)sizeof (pci_regspec_t))) {
447 kmem_free(pcmu_rp, i);
448 return (0);
449 }
450
451 size = pcmu_rp[rnumber].pci_size_low |
452 ((uint64_t)pcmu_rp[rnumber].pci_size_hi << 32);
453 kmem_free(pcmu_rp, i);
454 return (size);
455 }
456
457
458 /*
459 * pcmu_get_nreg_set
460 *
461 * Given a dev info pointer to a pci child, this routine returns the
462 * number of sets in its "reg" property.
463 *
464 * used by: pcmu_ctlops() - DDI_CTLOPS_NREGS
465 *
466 * return value: # of reg sets on success, zero on error
467 */
468 uint_t
pcmu_get_nreg_set(dev_info_t * child)469 pcmu_get_nreg_set(dev_info_t *child)
470 {
471 pci_regspec_t *pcmu_rp;
472 int i, n;
473
474 /*
475 * Get the reg property for the device.
476 */
477 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
478 (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
479 return (0);
480 }
481 n = i / (int)sizeof (pci_regspec_t);
482 kmem_free(pcmu_rp, i);
483 return (n);
484 }
485
486 int
pcmu_cfg_report(dev_info_t * dip,ddi_fm_error_t * derr,pcmu_errstate_t * pcmu_err_p,int caller,uint32_t prierr)487 pcmu_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr,
488 pcmu_errstate_t *pcmu_err_p, int caller, uint32_t prierr)
489 {
490 int fatal = 0;
491 int nonfatal = 0;
492 int i;
493 pcmu_t *pcmu_p;
494 int instance = ddi_get_instance(dip);
495
496 ASSERT(dip);
497
498 pcmu_p = get_pcmu_soft_state(instance);
499
500 derr->fme_ena = derr->fme_ena ? derr->fme_ena :
501 fm_ena_generate(0, FM_ENA_FMT1);
502
503 for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
504 if (pcmu_err_p->pcmu_cfg_stat & pci_err_tbl[i].reg_bit) {
505 char buf[FM_MAX_CLASS];
506 char *aux_msg = NULL;
507
508 switch (pci_err_tbl[i].reg_bit) {
509 case PCI_STAT_R_MAST_AB:
510 aux_msg = "Recieved Master Abort";
511 /* LINTED fallthrough on case statement */
512 case PCI_STAT_R_TARG_AB:
513 if (aux_msg != NULL)
514 aux_msg = "Recieved Target Abort";
515 if (prierr) {
516 /*
517 * piow case are already handled in
518 * pcmu_pbm_afsr_report()
519 */
520 break;
521 }
522 if (caller != PCI_TRAP_CALL) {
523 /*
524 * if we haven't come from trap handler
525 * we won't have an address
526 */
527 fatal++;
528 }
529 break;
530 default:
531 /*
532 * dpe on dma write or ta on dma
533 */
534 nonfatal++;
535 break;
536 }
537 (void) snprintf(buf, FM_MAX_CLASS, "%s %s: %s %s",
538 (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str,
539 (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str,
540 "PCI config space:", aux_msg);
541 cmn_err(CE_WARN, "%s %s=0x%p", buf, "pbm-csr",
542 (void *)(pcmu_p->pcmu_pcbm_p)->pcbm_ctrl_reg);
543 }
544 }
545
546 if (fatal)
547 return (DDI_FM_FATAL);
548 else if (nonfatal)
549 return (DDI_FM_NONFATAL);
550
551 return (DDI_FM_OK);
552 }
553
554 void
pcmu_child_cfg_save(dev_info_t * dip)555 pcmu_child_cfg_save(dev_info_t *dip)
556 {
557 dev_info_t *cdip;
558 int ret = DDI_SUCCESS;
559
560 /*
561 * Save the state of the configuration headers of child
562 * nodes.
563 */
564
565 for (cdip = ddi_get_child(dip); cdip != NULL;
566 cdip = ddi_get_next_sibling(cdip)) {
567
568 /*
569 * Not interested in children who are not already
570 * init'ed. They will be set up in pcmu_init_child().
571 */
572 if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
573 PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping "
574 "%s%d not in CF1\n", ddi_driver_name(cdip),
575 ddi_get_instance(cdip));
576
577 continue;
578 }
579
580 /*
581 * Only save config registers if not already saved by child.
582 */
583 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
584 SAVED_CONFIG_REGS) == 1) {
585
586 continue;
587 }
588
589 /*
590 * The nexus needs to save config registers. Create a property
591 * so it knows to restore on resume.
592 */
593 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
594 "nexus-saved-config-regs");
595
596 if (ret != DDI_PROP_SUCCESS) {
597 cmn_err(CE_WARN, "%s%d can't update prop %s",
598 ddi_driver_name(cdip), ddi_get_instance(cdip),
599 "nexus-saved-config-regs");
600 }
601
602 (void) pci_save_config_regs(cdip);
603 }
604 }
605
606 void
pcmu_child_cfg_restore(dev_info_t * dip)607 pcmu_child_cfg_restore(dev_info_t *dip)
608 {
609 dev_info_t *cdip;
610
611 /*
612 * Restore config registers for children that did not save
613 * their own registers. Children pwr states are UNKNOWN after
614 * a resume since it is possible for the PM framework to call
615 * resume without an actual power cycle. (ie if suspend fails).
616 */
617 for (cdip = ddi_get_child(dip); cdip != NULL;
618 cdip = ddi_get_next_sibling(cdip)) {
619
620 /*
621 * Not interested in children who are not already
622 * init'ed. They will be set up by pcmu_init_child().
623 */
624 if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
625 PCMU_DBG2(PCMU_DBG_DETACH, dip,
626 "DDI_RESUME: skipping %s%d not in CF1\n",
627 ddi_driver_name(cdip), ddi_get_instance(cdip));
628 continue;
629 }
630
631 /*
632 * Only restore config registers if saved by nexus.
633 */
634 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
635 "nexus-saved-config-regs") == 1) {
636 (void) pci_restore_config_regs(cdip);
637
638 PCMU_DBG2(PCMU_DBG_PWR, dip,
639 "DDI_RESUME: nexus restoring %s%d config regs\n",
640 ddi_driver_name(cdip), ddi_get_instance(cdip));
641
642 if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
643 "nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
644 cmn_err(CE_WARN, "%s%d can't remove prop %s",
645 ddi_driver_name(cdip),
646 ddi_get_instance(cdip),
647 "nexus-saved-config-regs");
648 }
649 }
650 }
651 }
652
653 #ifdef DEBUG
654 extern uint64_t pcmu_debug_flags;
655
656 pcmu_dflag_to_str_t pcmu_dflag_strings [] = {
657 {PCMU_DBG_ATTACH, "pcmu_attach"},
658 {PCMU_DBG_DETACH, "pcmu_detach"},
659 {PCMU_DBG_MAP, "pcmu_map"},
660 {PCMU_DBG_A_INTX, "pcmu_add_intx"},
661 {PCMU_DBG_R_INTX, "pcmu_rem_intx"},
662 {PCMU_DBG_INIT_CLD, "pcmu_init_child"},
663 {PCMU_DBG_CTLOPS, "pcmu_ctlops"},
664 {PCMU_DBG_INTR, "pcmu_intr_wrapper"},
665 {PCMU_DBG_ERR_INTR, "pcmu_pbm_error_intr"},
666 {PCMU_DBG_BUS_FAULT, "pcmu_fault"},
667 {PCMU_DBG_IB, "pcmu_ib"},
668 {PCMU_DBG_CB, "pcmu_cb"},
669 {PCMU_DBG_PBM, "pcmu_pbm"},
670 {PCMU_DBG_OPEN, "pcmu_open"},
671 {PCMU_DBG_CLOSE, "pcmu_close"},
672 {PCMU_DBG_IOCTL, "pcmu_ioctl"},
673 {PCMU_DBG_PWR, "pcmu_pwr"}
674 };
675
676 void
pcmu_debug(uint64_t flag,dev_info_t * dip,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)677 pcmu_debug(uint64_t flag, dev_info_t *dip, char *fmt,
678 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
679 {
680 char *s = "pcmu unknown";
681 uint_t cont = 0;
682 int i;
683 int no_rec = (sizeof (pcmu_dflag_strings) /
684 sizeof (pcmu_dflag_to_str_t));
685
686 if (flag & PCMU_DBG_CONT) {
687 flag &= ~PCMU_DBG_CONT;
688 cont = 1;
689 }
690 if ((pcmu_debug_flags & flag) == flag) {
691 for (i = 0; i < no_rec; i++) {
692 if (pcmu_dflag_strings[i].flag == flag) {
693 s = pcmu_dflag_strings[i].string;
694 break;
695 }
696 }
697 if (s && cont == 0) {
698 prom_printf("%s(%d): %s: ", ddi_driver_name(dip),
699 ddi_get_instance(dip), s);
700 }
701 prom_printf(fmt, a1, a2, a3, a4, a5);
702 }
703 }
704 #endif
705