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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
27 */
28
29
30#include <sys/types.h>
31#include <sys/conf.h>
32#include <sys/ddi.h>
33#include <sys/sunddi.h>
34#include <sys/ddi_impldefs.h>
35#include <sys/ddi_subrdefs.h>
36#include <sys/pci.h>
37#include <sys/autoconf.h>
38#include <sys/cmn_err.h>
39#include <sys/errno.h>
40#include <sys/kmem.h>
41#include <sys/debug.h>
42#include <sys/sysmacros.h>
43#include <sys/pmubus.h>
44
45#include <sys/nexusdebug.h>
46/* Bitfield debugging definitions for this file */
47#define	PMUBUS_MAP_DEBUG	0x1
48#define	PMUBUS_REGACCESS_DEBUG	0x2
49#define	PMUBUS_RW_DEBUG		0x4
50
51/*
52 * The pmubus nexus is used to manage a shared register space.  Rather
53 * than having several driver's physically alias register mappings and
54 * have potential problems with register collisions, this nexus will
55 * serialize the access to this space.
56 *
57 * There are two types of sharing going on here:
58 * 1) Registers within the address space may be shared, however the registers
59 * themselves are unique.  The upper bit of the child's high address being zero
60 * signifies this register type.
61 *
62 * 2) The second type of register is one where a device may only own a few
63 * bits in the register.  I'll term this as "bit lane" access.  This is a more
64 * complicated scenario.  The drivers themselves are responsible for knowing
65 * which bit lanes in the register they own.  The read of a register only
66 * guarantees that those bits the driver is interested in are valid.  If a
67 * driver needs to set bits in a register, a read must be done first to
68 * identify the state of the drivers bits.  Depending on which way a bit needs
69 * to be driven, the driver will write a 1 to the bit to toggle it.  If a bit
70 * is to remain unchanged, a 0 is written to the bit.  So the access to the
71 * bit lane is an xor operation.
72 */
73/*
74 * Function prototypes for busops routines:
75 */
76static int pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
77    off_t off, off_t len, caddr_t *addrp);
78static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip,
79    ddi_ctl_enum_t op, void *arg, void *result);
80
81/*
82 * function prototypes for dev ops routines:
83 */
84static int pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
85static int pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
86
87/*
88 * general function prototypes:
89 */
90
91/*
92 * bus ops and dev ops structures:
93 */
94static struct bus_ops pmubus_bus_ops = {
95	BUSO_REV,
96	pmubus_map,
97	NULL,
98	NULL,
99	NULL,
100	i_ddi_map_fault,
101	NULL,
102	ddi_dma_allochdl,
103	ddi_dma_freehdl,
104	ddi_dma_bindhdl,
105	ddi_dma_unbindhdl,
106	ddi_dma_flush,
107	ddi_dma_win,
108	ddi_dma_mctl,
109	pmubus_ctlops,
110	ddi_bus_prop_op,
111	0,			/* (*bus_get_eventcookie)();	*/
112	0,			/* (*bus_add_eventcall)();	*/
113	0,			/* (*bus_remove_eventcall)();	*/
114	0,			/* (*bus_post_event)();		*/
115	0,			/* interrupt control		*/
116	0,			/* bus_config			*/
117	0,			/* bus_unconfig			*/
118	0,			/* bus_fm_init			*/
119	0,			/* bus_fm_fini			*/
120	0,			/* bus_fm_access_enter		*/
121	0,			/* bus_fm_access_exit		*/
122	0,			/* bus_power			*/
123	i_ddi_intr_ops		/* bus_intr_op			*/
124};
125
126static struct dev_ops pmubus_ops = {
127	DEVO_REV,
128	0,
129	ddi_no_info,
130	nulldev,
131	0,
132	pmubus_attach,
133	pmubus_detach,
134	nodev,
135	(struct cb_ops *)0,
136	&pmubus_bus_ops,
137	NULL,
138	ddi_quiesce_not_needed,		/* quiesce */
139};
140
141/*
142 * module definitions:
143 */
144#include <sys/modctl.h>
145extern struct mod_ops mod_driverops;
146
147static struct modldrv modldrv = {
148	&mod_driverops, 	/* Type of module.  This one is a driver */
149	"pmubus nexus driver",	/* Name of module. */
150	&pmubus_ops,		/* driver ops */
151};
152
153static struct modlinkage modlinkage = {
154	MODREV_1, (void *)&modldrv, NULL
155};
156
157/*
158 * driver global data:
159 */
160static void *per_pmubus_state;		/* per-pmubus soft state pointer */
161
162int
163_init(void)
164{
165	int e;
166
167	/*
168	 * Initialize per-pmubus soft state pointer.
169	 */
170	e = ddi_soft_state_init(&per_pmubus_state,
171	    sizeof (pmubus_devstate_t), 1);
172	if (e != 0)
173		return (e);
174
175	/*
176	 * Install the module.
177	 */
178	e = mod_install(&modlinkage);
179	if (e != 0)
180		ddi_soft_state_fini(&per_pmubus_state);
181
182	return (e);
183}
184
185int
186_fini(void)
187{
188	int e;
189
190	/*
191	 * Remove the module.
192	 */
193	e = mod_remove(&modlinkage);
194	if (e != 0)
195		return (e);
196
197	/*
198	 * Free the soft state info.
199	 */
200	ddi_soft_state_fini(&per_pmubus_state);
201	return (e);
202}
203
204int
205_info(struct modinfo *modinfop)
206{
207	return (mod_info(&modlinkage, modinfop));
208}
209
210/* device driver entry points */
211
212/*
213 * attach entry point:
214 *
215 * normal attach:
216 *
217 *	create soft state structure (dip, reg, nreg and state fields)
218 *	map in configuration header
219 *	make sure device is properly configured
220 *	report device
221 */
222static int
223pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
224{
225	pmubus_devstate_t *pmubusp;	/* per pmubus state pointer */
226	int32_t instance;
227
228	switch (cmd) {
229	case DDI_ATTACH:
230		/*
231		 * Allocate soft state for this instance.
232		 */
233		instance = ddi_get_instance(dip);
234		if (ddi_soft_state_zalloc(per_pmubus_state, instance) !=
235		    DDI_SUCCESS) {
236			cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft "
237			    "state.\n");
238			goto fail_exit;
239		}
240
241		pmubusp = ddi_get_soft_state(per_pmubus_state, instance);
242		pmubusp->pmubus_dip = dip;
243
244		/* Cache our register property */
245		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
246		    "reg", (caddr_t)&pmubusp->pmubus_regp,
247		    &pmubusp->pmubus_reglen) != DDI_SUCCESS) {
248			cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg "
249			    "property.\n");
250			goto fail_get_regs;
251		}
252
253		/* Cache our ranges property */
254		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
255		    "ranges", (caddr_t)&pmubusp->pmubus_rangep,
256		    &pmubusp->pmubus_rnglen) != DDI_SUCCESS) {
257			cmn_err(CE_WARN, "pmubus_attach: Can't acquire the "
258			    "ranges property.\n");
259			goto fail_get_ranges;
260
261		}
262
263		/* Calculate the number of ranges */
264		pmubusp->pmubus_nranges =
265		    pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t);
266
267		/* Set up the mapping to our registers */
268		if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) !=
269		    DDI_SUCCESS) {
270			cmn_err(CE_WARN, "pmubus_attach: Can't map in "
271			    "register space.\n");
272			goto fail_map_regs;
273		}
274
275		/* Initialize our register access mutex */
276		mutex_init(&pmubusp->pmubus_reg_access_lock, NULL,
277		    MUTEX_DRIVER, NULL);
278
279		ddi_report_dev(dip);
280		return (DDI_SUCCESS);
281
282	case DDI_RESUME:
283		return (DDI_SUCCESS);
284	}
285
286fail_map_regs:
287	kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen);
288
289fail_get_ranges:
290	kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen);
291
292fail_get_regs:
293	ddi_soft_state_free(per_pmubus_state, instance);
294
295fail_exit:
296	return (DDI_FAILURE);
297}
298
299/*
300 * detach entry point:
301 */
302static int
303pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
304{
305	int instance = ddi_get_instance(dip);
306	pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state,
307	    instance);
308
309	switch (cmd) {
310	case DDI_DETACH:
311		mutex_destroy(&pmubusp->pmubus_reg_access_lock);
312
313		/* Tear down our register mappings */
314		pci_config_teardown(&pmubusp->pmubus_reghdl);
315
316		/* Free our ranges property */
317		kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen);
318
319		/* Free the register property */
320		kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen);
321
322		ddi_soft_state_free(per_pmubus_state, instance);
323		break;
324
325	case DDI_SUSPEND:
326	default:
327		break;
328	}
329
330	return (DDI_SUCCESS);
331}
332
333/*ARGSUSED*/
334void
335pmubus_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr,
336    uint8_t *dev_addr, size_t repcount, uint_t flags)
337{
338}
339
340/*ARGSUSED*/
341void
342pmubus_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr,
343    uint16_t *dev_addr, size_t repcount, uint_t flags)
344{
345}
346
347/*ARGSUSED*/
348void
349pmubus_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr,
350    uint32_t *dev_addr, size_t repcount, uint_t flags)
351{
352}
353
354/*ARGSUSED*/
355void
356pmubus_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr,
357    uint64_t *dev_addr, size_t repcount, uint_t flags)
358{
359}
360
361/*ARGSUSED*/
362void
363pmubus_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr,
364    uint8_t *dev_addr, size_t repcount, uint_t flags)
365{
366}
367
368/*ARGSUSED*/
369void
370pmubus_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr,
371    uint16_t *dev_addr, size_t repcount, uint_t flags)
372{
373}
374
375/*ARGSUSED*/
376void
377pmubus_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr,
378    uint32_t *dev_addr, size_t repcount, uint_t flags)
379{
380}
381
382/*ARGSUSED*/
383void
384pmubus_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr,
385    uint64_t *dev_addr, size_t repcount, uint_t flags)
386{
387}
388
389/*ARGSUSED*/
390uint8_t
391pmubus_get8(ddi_acc_impl_t *hdlp, uint8_t *addr)
392{
393	ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp;
394	pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private;
395	pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp;
396	off_t offset;
397	uint8_t value;
398	uint8_t mask;
399
400	offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr;
401	offset &= PMUBUS_REGOFFSET;
402
403	if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) {
404		if (addr != 0 ||
405		    pmubus_mapreqp->mapreq_size != sizeof (value)) {
406			cmn_err(CE_WARN, "pmubus_get8: load discarded, "
407			    "incorrect access addr/size");
408			return ((uint8_t)-1);
409		}
410		mask = pmubus_mapreqp->mapreq_mask;
411	} else {
412		mask = (uint8_t)-1;
413	}
414
415	/* gets are simple, we just issue them no locking necessary */
416	value = pci_config_get8(softsp->pmubus_reghdl, offset) & mask;
417
418	DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get8: addr=%p offset=%lx value=%x "
419	    "mask=%x\n", (void *)addr, offset, value, mask));
420
421	return (value);
422}
423
424
425/*ARGSUSED*/
426uint16_t
427pmubus_noget16(ddi_acc_impl_t *hdlp, uint16_t *addr)
428{
429	return ((uint16_t)-1);
430}
431
432/*ARGSUSED*/
433uint32_t
434pmubus_get32(ddi_acc_impl_t *hdlp, uint32_t *addr)
435{
436	ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp;
437	pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private;
438	pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp;
439	off_t offset = (uintptr_t)addr & PMUBUS_REGOFFSET;
440	uint32_t value;
441	uint32_t mask;
442
443	offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr;
444	offset &= PMUBUS_REGOFFSET;
445
446	if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) {
447		if (addr != 0 ||
448		    pmubus_mapreqp->mapreq_size != sizeof (value)) {
449			cmn_err(CE_WARN, "pmubus_get32: load discarded, "
450			    "incorrect access addr/size");
451			return ((uint32_t)-1);
452		}
453		mask = pmubus_mapreqp->mapreq_mask;
454	} else {
455		mask = (uint32_t)-1;
456	}
457
458	/* gets are simple, we just issue them no locking necessary */
459	value = pci_config_get32(softsp->pmubus_reghdl, offset) & mask;
460
461	DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get32: addr=%p offset=%lx value=%x "
462	    "mask=%x\n", (void *)addr, offset, value, mask));
463
464	return (value);
465}
466
467/*ARGSUSED*/
468uint64_t
469pmubus_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr)
470{
471	return ((uint64_t)-1);
472}
473
474/*ARGSUSED*/
475void
476pmubus_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
477{
478	ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp;
479	pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private;
480	pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp;
481	off_t offset;
482	uint8_t tmp;
483
484	offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr;
485	offset &= PMUBUS_REGOFFSET;
486
487	if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) {
488		/*
489		 * Process "bit lane" register
490		 */
491		DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx "
492		    "value=%x mask=%lx\n", (void *)addr, offset, value,
493		    pmubus_mapreqp->mapreq_mask));
494
495		if (addr != 0 ||
496		    pmubus_mapreqp->mapreq_size != sizeof (value)) {
497			cmn_err(CE_WARN, "pmubus_put8: store discarded, "
498			    "incorrect access addr/size");
499			return;
500		}
501
502		mutex_enter(&softsp->pmubus_reg_access_lock);
503		tmp = pci_config_get8(softsp->pmubus_reghdl, offset);
504		tmp &= ~pmubus_mapreqp->mapreq_mask;
505		value &= pmubus_mapreqp->mapreq_mask;
506		tmp |= value;
507		pci_config_put8(softsp->pmubus_reghdl, offset, tmp);
508		mutex_exit(&softsp->pmubus_reg_access_lock);
509	} else {
510		/*
511		 * Process shared register
512		 */
513		DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx "
514		    "value=%x\n", (void *)addr, offset, value));
515		pci_config_put8(softsp->pmubus_reghdl, offset, value);
516	}
517
518	/* Flush store buffers XXX Should let drivers do this. */
519	tmp = pci_config_get8(softsp->pmubus_reghdl, offset);
520}
521
522/*ARGSUSED*/
523void
524pmubus_noput16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
525{
526}
527
528/*ARGSUSED*/
529void
530pmubus_put32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
531{
532	ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp;
533	pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private;
534	pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp;
535	off_t offset;
536	uint32_t tmp;
537
538	offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr;
539	offset &= PMUBUS_REGOFFSET;
540
541	if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) {
542		/*
543		 * Process "bit lane" register
544		 */
545		DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx "
546		    "value=%x mask=%lx\n", (void *)addr, offset, value,
547		    pmubus_mapreqp->mapreq_mask));
548
549		if (addr != 0 ||
550		    pmubus_mapreqp->mapreq_size != sizeof (value)) {
551			cmn_err(CE_WARN, "pmubus_put32: store discarded, "
552			    "incorrect access addr/size");
553			return;
554		}
555
556		mutex_enter(&softsp->pmubus_reg_access_lock);
557		tmp = pci_config_get32(softsp->pmubus_reghdl, offset);
558		tmp &= ~pmubus_mapreqp->mapreq_mask;
559		value &= pmubus_mapreqp->mapreq_mask;
560		tmp |= value;
561		pci_config_put32(softsp->pmubus_reghdl, offset, tmp);
562		mutex_exit(&softsp->pmubus_reg_access_lock);
563	} else {
564		/*
565		 * Process shared register
566		 */
567		DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx "
568		    "value=%x\n", (void *)addr, offset, value));
569		pci_config_put32(softsp->pmubus_reghdl, offset, value);
570	}
571
572	/* Flush store buffers XXX Should let drivers do this. */
573	tmp = pci_config_get32(softsp->pmubus_reghdl, offset);
574}
575
576/*ARGSUSED*/
577void
578pmubus_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
579{
580}
581
582/*
583 * This routine is used to translate our children's register properties.
584 * The return value specifies which type of register has been translated.
585 */
586/*ARGSUSED*/
587int
588pmubus_apply_range(pmubus_devstate_t *pmubusp, dev_info_t *rdip,
589    pmubus_regspec_t *regp, pci_regspec_t *pci_regp)
590{
591	pmu_rangespec_t *rangep;
592	int nranges = pmubusp->pmubus_nranges;
593	int i;
594	off_t offset;
595	int ret = DDI_ME_REGSPEC_RANGE;
596	uint64_t addr;
597
598	addr = regp->reg_addr & ~MAPPING_SHARED_BITS_MASK;
599
600	/* Scan the ranges for a match */
601	for (i = 0, rangep = pmubusp->pmubus_rangep; i < nranges; i++, rangep++)
602		if ((rangep->rng_child <= addr) &&
603		    ((addr + regp->reg_size) <=
604		    (rangep->rng_child + rangep->rng_size))) {
605			ret = DDI_SUCCESS;
606			break;
607		}
608
609	if (ret != DDI_SUCCESS)
610		return (ret);
611
612	/* Get the translated register */
613	offset = addr - rangep->rng_child;
614	pci_regp->pci_phys_hi = rangep->rng_parent_hi;
615	pci_regp->pci_phys_mid = rangep->rng_parent_mid;
616	pci_regp->pci_phys_low = rangep->rng_parent_low + offset;
617	pci_regp->pci_size_hi = 0;
618	pci_regp->pci_size_low = MIN(regp->reg_size, rangep->rng_size);
619
620	/* Figure out the type of reg space we have */
621	if (pci_regp->pci_phys_hi == pmubusp->pmubus_regp->pci_phys_hi) {
622		ret = MAPREQ_SHARED_REG;
623		if (regp->reg_addr & MAPPING_SHARED_BITS_MASK)
624			ret |= MAPREQ_SHARED_BITS;
625	}
626
627	return (ret);
628}
629
630static uint64_t
631pmubus_mask(pmubus_obpregspec_t *regs, int32_t rnumber,
632    uint64_t *masks)
633{
634	int i;
635	long n = -1;
636
637	for (i = 0; i <= rnumber; i++)
638		if (regs[i].reg_addr_hi & 0x80000000)
639			n++;
640
641	if (n == -1) {
642		cmn_err(CE_WARN, "pmubus_mask: missing mask");
643		return (0);
644	}
645
646	return (masks[n]);
647}
648
649/*
650 * The pmubus_map routine determines if it's child is attempting to map a
651 * shared reg.  If it is, it installs it's own vectors and bus private pointer.
652 */
653static int
654pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
655	off_t off, off_t len, caddr_t *addrp)
656{
657	pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state,
658	    ddi_get_instance(dip));
659	dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
660	pmubus_regspec_t pmubus_rp;
661	pmubus_obpregspec_t *pmubus_regs = NULL;
662	int pmubus_regs_size;
663	uint64_t *pmubus_regmask = NULL;
664	int pmubus_regmask_size;
665	pci_regspec_t pci_reg;
666	int32_t rnumber = mp->map_obj.rnumber;
667	pmubus_mapreq_t *pmubus_mapreqp;
668	int ret = DDI_SUCCESS;
669	char *map_fail1 = "Map Type Unknown";
670	char *map_fail2 = "DDI_MT_REGSPEC";
671	char *s = map_fail1;
672
673	*addrp = NULL;
674
675	/*
676	 * Handle the mapping according to its type.
677	 */
678	DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%lx len=%lx\n",
679	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len));
680	switch (mp->map_type) {
681	case DDI_MT_RNUMBER: {
682		int n;
683
684		/*
685		 * Get the "reg" property from the device node and convert
686		 * it to our parent's format.
687		 */
688		rnumber = mp->map_obj.rnumber;
689		DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x "
690		    "handlep=%p\n", ddi_get_name(rdip), ddi_get_instance(rdip),
691		    rnumber, (void *)mp->map_handlep));
692
693		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
694		    "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) !=
695		    DDI_SUCCESS) {
696			DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg "
697			    "property\n"));
698			ret = DDI_ME_RNUMBER_RANGE;
699			goto done;
700		}
701		n = pmubus_regs_size / sizeof (pmubus_obpregspec_t);
702
703		if (rnumber < 0 || rnumber >= n) {
704			DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n"));
705			ret = DDI_ME_RNUMBER_RANGE;
706			goto done;
707		}
708
709		pmubus_rp.reg_addr = ((uint64_t)
710		    pmubus_regs[rnumber].reg_addr_hi << 32) |
711		    (uint64_t)pmubus_regs[rnumber].reg_addr_lo;
712		pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size;
713
714		(void) ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
715		    "register-mask", (caddr_t)&pmubus_regmask,
716		    &pmubus_regmask_size);
717
718		/* Create our own mapping private structure */
719		break;
720
721	}
722	case DDI_MT_REGSPEC:
723		/*
724		 * This bus has no bus children that have to map in an address
725		 * space, so we can assume that we'll never see an
726		 * DDI_MT_REGSPEC request
727		 */
728		s = map_fail2;
729		ret = DDI_ME_REGSPEC_RANGE;
730		/*FALLTHROUGH*/
731
732	default:
733		if (ret == DDI_SUCCESS)
734			ret = DDI_ME_INVAL;
735		DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: "
736		    "%s is an invalid map type.\nmap request handlep=0x%p\n",
737		    ddi_get_name(rdip), ddi_get_instance(rdip), s, (void *)mp));
738
739		ret = DDI_ME_RNUMBER_RANGE;
740		goto done;
741	}
742
743	/* Adjust our reg property with offset and length */
744	if ((pmubus_rp.reg_addr + off) >
745	    (pmubus_rp.reg_addr + pmubus_rp.reg_size)) {
746		ret = DDI_ME_INVAL;
747		goto done;
748	}
749
750	pmubus_rp.reg_addr += off;
751	if (len && (len < pmubus_rp.reg_size))
752		pmubus_rp.reg_size = len;
753
754	/* Translate our child regspec into our parents address domain */
755	ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg);
756
757	/* Check if the apply range failed */
758	if (ret < DDI_SUCCESS)
759		goto done;
760
761	/*
762	 * If our childs xlated address falls into our shared address range,
763	 * setup our mapping handle.
764	 */
765	if (ret > DDI_SUCCESS) {
766		/* Figure out if we're mapping or unmapping */
767		switch (mp->map_op) {
768		case DDI_MO_MAP_LOCKED: {
769			ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep;
770
771			pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp),
772			    KM_SLEEP);
773
774			pmubus_mapreqp->mapreq_flags = ret;
775			pmubus_mapreqp->mapreq_softsp = pmubusp;
776			pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr;
777			pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size;
778
779			if (ret & MAPREQ_SHARED_BITS) {
780				pmubus_mapreqp->mapreq_mask =
781				    pmubus_mask(pmubus_regs, rnumber,
782				    pmubus_regmask);
783				DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d "
784				    "mask=%lx\n", rnumber,
785				    pmubus_mapreqp->mapreq_mask));
786				if (pmubus_mapreqp->mapreq_mask == 0) {
787					kmem_free(pmubus_mapreqp,
788					    sizeof (pmubus_mapreq_t));
789					ret = DDI_ME_INVAL;
790					break;
791				}
792			}
793
794			hp->ahi_common.ah_bus_private = pmubus_mapreqp;
795
796			/* Initialize the access vectors */
797			hp->ahi_get8 = pmubus_get8;
798			hp->ahi_get16 = pmubus_noget16;
799			hp->ahi_get32 = pmubus_get32;
800			hp->ahi_get64 = pmubus_noget64;
801			hp->ahi_put8 = pmubus_put8;
802			hp->ahi_put16 = pmubus_noput16;
803			hp->ahi_put32 = pmubus_put32;
804			hp->ahi_put64 = pmubus_noput64;
805			hp->ahi_rep_get8 = pmubus_norep_get8;
806			hp->ahi_rep_get16 = pmubus_norep_get16;
807			hp->ahi_rep_get32 = pmubus_norep_get32;
808			hp->ahi_rep_get64 = pmubus_norep_get64;
809			hp->ahi_rep_put8 = pmubus_norep_put8;
810			hp->ahi_rep_put16 = pmubus_norep_put16;
811			hp->ahi_rep_put32 = pmubus_norep_put32;
812			hp->ahi_rep_put64 = pmubus_norep_put64;
813
814			ret = DDI_SUCCESS;
815			break;
816		}
817
818		case DDI_MO_UNMAP: {
819			ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep;
820
821			pmubus_mapreqp = hp->ahi_common.ah_bus_private;
822
823			/* Free the our map request struct */
824			kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t));
825
826			ret = DDI_SUCCESS;
827			break;
828		}
829
830		default:
831			ret = DDI_ME_UNSUPPORTED;
832		}
833	} else {
834		/* Prepare the map request struct for a call to our parent */
835		mp->map_type = DDI_MT_REGSPEC;
836		mp->map_obj.rp = (struct regspec *)&pci_reg;
837
838		/* Pass the mapping operation up the device tree */
839		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
840		    (pdip, rdip, mp, off, len, addrp);
841	}
842
843done:
844	if (pmubus_regs != NULL)
845		kmem_free(pmubus_regs, pmubus_regs_size);
846	if (pmubus_regmask != NULL)
847		kmem_free(pmubus_regmask, pmubus_regmask_size);
848	return (ret);
849}
850
851static int
852pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip,
853    ddi_ctl_enum_t op, void *arg, void *result)
854{
855	dev_info_t *child = (dev_info_t *)arg;
856	pmubus_obpregspec_t *pmubus_rp;
857	char name[9];
858	int reglen;
859
860	switch (op) {
861	case DDI_CTLOPS_INITCHILD:
862
863		if (ddi_getlongprop(DDI_DEV_T_ANY, child,
864		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp,
865		    &reglen) != DDI_SUCCESS) {
866
867			return (DDI_FAILURE);
868		}
869
870		if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) {
871			cmn_err(CE_WARN,
872			    "pmubus: reg property not well-formed for "
873			    "%s size=%d\n", ddi_node_name(child), reglen);
874			kmem_free(pmubus_rp, reglen);
875
876			return (DDI_FAILURE);
877		}
878		(void) snprintf(name, sizeof (name), "%x,%x",
879		    pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo);
880		ddi_set_name_addr(child, name);
881		kmem_free(pmubus_rp, reglen);
882
883		return (DDI_SUCCESS);
884
885	case DDI_CTLOPS_UNINITCHILD:
886
887		ddi_set_name_addr(child, NULL);
888		ddi_remove_minor_node(child, NULL);
889		impl_rem_dev_props(child);
890
891		return (DDI_SUCCESS);
892	default:
893		break;
894	}
895
896	return (ddi_ctlops(dip, rdip, op, arg, result));
897}
898