xref: /illumos-gate/usr/src/uts/sun4v/io/px/px_lib4v.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 
26 #include <sys/types.h>
27 #include <sys/sysmacros.h>
28 #include <sys/ddi.h>
29 #include <sys/async.h>
30 #include <sys/sunddi.h>
31 #include <sys/ddifm.h>
32 #include <sys/fm/protocol.h>
33 #include <sys/vmem.h>
34 #include <sys/intr.h>
35 #include <sys/ivintr.h>
36 #include <sys/errno.h>
37 #include <sys/hypervisor_api.h>
38 #include <sys/hsvc.h>
39 #include <px_obj.h>
40 #include <sys/machsystm.h>
41 #include "px_lib4v.h"
42 #include "px_err.h"
43 
44 /* mask for the ranges property in calculating the real PFN range */
45 uint_t px_ranges_phi_mask = ((1 << 28) -1);
46 
47 /*
48  * Hypervisor VPCI services information for the px nexus driver.
49  */
50 static	uint64_t	px_vpci_min_ver; /* Negotiated VPCI API minor version */
51 static	uint_t		px_vpci_users = 0; /* VPCI API users */
52 
53 static hsvc_info_t px_hsvc = {
54 	HSVC_REV_1, NULL, HSVC_GROUP_VPCI, PX_VPCI_MAJOR_VER,
55 	PX_VPCI_MINOR_VER, "PX"
56 };
57 
58 int
59 px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
60 {
61 	px_nexus_regspec_t	*rp;
62 	uint_t			reglen;
63 	int			ret;
64 
65 	uint64_t mjrnum;
66 	uint64_t mnrnum;
67 
68 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p\n", dip);
69 
70 	/*
71 	 * Check HV intr group api versioning.
72 	 * This driver uses the old interrupt routines which are supported
73 	 * in old firmware in the CORE API group and in newer firmware in
74 	 * the INTR API group.  Support for these calls will be dropped
75 	 * once the INTR API group major goes to 2.
76 	 */
77 	if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
78 	    (mjrnum > 1)) {
79 		cmn_err(CE_WARN, "niumx: unsupported intr api group: "
80 		    "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
81 		return (ENOTSUP);
82 	}
83 
84 	ret = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
85 	    "reg", (uchar_t **)&rp, &reglen);
86 	if (ret != DDI_PROP_SUCCESS) {
87 		DBG(DBG_ATTACH, dip, "px_lib_dev_init failed ret=%d\n", ret);
88 		return (DDI_FAILURE);
89 	}
90 
91 	/*
92 	 * Initilize device handle. The device handle uniquely identifies
93 	 * a SUN4V device. It consists of the lower 28-bits of the hi-cell
94 	 * of the first entry of the SUN4V device's "reg" property as
95 	 * defined by the SUN4V Bus Binding to Open Firmware.
96 	 */
97 	*dev_hdl = (devhandle_t)((rp->phys_addr >> 32) & DEVHDLE_MASK);
98 	ddi_prop_free(rp);
99 
100 	/*
101 	 * hotplug implementation requires this property to be associated with
102 	 * any indirect PCI config access services
103 	 */
104 	(void) ddi_prop_update_int(makedevice(ddi_driver_major(dip),
105 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR)), dip,
106 	    PCI_BUS_CONF_MAP_PROP, 1);
107 
108 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl);
109 
110 	/*
111 	 * Negotiate the API version for VPCI hypervisor services.
112 	 */
113 	if (px_vpci_users++)
114 		return (DDI_SUCCESS);
115 
116 	if ((ret = hsvc_register(&px_hsvc, &px_vpci_min_ver)) != 0) {
117 		cmn_err(CE_WARN, "%s: cannot negotiate hypervisor services "
118 		    "group: 0x%lx major: 0x%lx minor: 0x%lx errno: %d\n",
119 		    px_hsvc.hsvc_modname, px_hsvc.hsvc_group,
120 		    px_hsvc.hsvc_major, px_hsvc.hsvc_minor, ret);
121 
122 		return (DDI_FAILURE);
123 	}
124 
125 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: negotiated VPCI API version, "
126 	    "major 0x%lx minor 0x%lx\n", px_hsvc.hsvc_major, px_vpci_min_ver);
127 
128 	return (DDI_SUCCESS);
129 }
130 
131 /*ARGSUSED*/
132 int
133 px_lib_dev_fini(dev_info_t *dip)
134 {
135 	DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip);
136 
137 	(void) ddi_prop_remove(makedevice(ddi_driver_major(dip),
138 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR)), dip,
139 	    PCI_BUS_CONF_MAP_PROP);
140 
141 	if (--px_vpci_users == 0)
142 		(void) hsvc_unregister(&px_hsvc);
143 
144 	return (DDI_SUCCESS);
145 }
146 
147 /*ARGSUSED*/
148 int
149 px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino,
150     sysino_t *sysino)
151 {
152 	uint64_t	ret;
153 
154 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p "
155 	    "devino 0x%x\n", dip, devino);
156 
157 	if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip),
158 	    devino, sysino)) != H_EOK) {
159 		DBG(DBG_LIB_INT, dip,
160 		    "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret);
161 		return (DDI_FAILURE);
162 	}
163 
164 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n",
165 	    *sysino);
166 
167 	return (DDI_SUCCESS);
168 }
169 
170 /*ARGSUSED*/
171 int
172 px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino,
173     intr_valid_state_t *intr_valid_state)
174 {
175 	uint64_t	ret;
176 
177 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n",
178 	    dip, sysino);
179 
180 	if ((ret = hvio_intr_getvalid(sysino,
181 	    (int *)intr_valid_state)) != H_EOK) {
182 		DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n",
183 		    ret);
184 		return (DDI_FAILURE);
185 	}
186 
187 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n",
188 	    *intr_valid_state);
189 
190 	return (DDI_SUCCESS);
191 }
192 
193 /*ARGSUSED*/
194 int
195 px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino,
196     intr_valid_state_t intr_valid_state)
197 {
198 	uint64_t	ret;
199 
200 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx "
201 	    "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state);
202 
203 	if ((ret = hvio_intr_setvalid(sysino, intr_valid_state)) != H_EOK) {
204 		DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n",
205 		    ret);
206 		return (DDI_FAILURE);
207 	}
208 
209 	return (DDI_SUCCESS);
210 }
211 
212 /*ARGSUSED*/
213 int
214 px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino,
215     intr_state_t *intr_state)
216 {
217 	uint64_t	ret;
218 
219 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n",
220 	    dip, sysino);
221 
222 	if ((ret = hvio_intr_getstate(sysino, (int *)intr_state)) != H_EOK) {
223 		DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n",
224 		    ret);
225 		return (DDI_FAILURE);
226 	}
227 
228 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n",
229 	    *intr_state);
230 
231 	return (DDI_SUCCESS);
232 }
233 
234 /*ARGSUSED*/
235 int
236 px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino,
237     intr_state_t intr_state)
238 {
239 	uint64_t	ret;
240 
241 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx "
242 	    "intr_state 0x%x\n", dip, sysino, intr_state);
243 
244 	if ((ret = hvio_intr_setstate(sysino, intr_state)) != H_EOK) {
245 		DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n",
246 		    ret);
247 		return (DDI_FAILURE);
248 	}
249 
250 	return (DDI_SUCCESS);
251 }
252 
253 /*ARGSUSED*/
254 int
255 px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid)
256 {
257 	uint64_t	ret;
258 
259 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n",
260 	    dip, sysino);
261 
262 	if ((ret = hvio_intr_gettarget(sysino, cpuid)) != H_EOK) {
263 		DBG(DBG_LIB_INT, dip,
264 		    "hvio_intr_gettarget failed, ret 0x%lx\n", ret);
265 		return (DDI_FAILURE);
266 	}
267 
268 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", *cpuid);
269 
270 	return (DDI_SUCCESS);
271 }
272 
273 /*ARGSUSED*/
274 int
275 px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid)
276 {
277 	uint64_t	ret;
278 
279 	DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx "
280 	    "cpuid 0x%x\n", dip, sysino, cpuid);
281 
282 	ret = hvio_intr_settarget(sysino, cpuid);
283 	if (ret == H_ECPUERROR) {
284 		cmn_err(CE_PANIC,
285 		    "px_lib_intr_settarget: hvio_intr_settarget failed, "
286 		    "ret = 0x%lx, cpuid = 0x%x, sysino = 0x%lx\n", ret,
287 		    cpuid, sysino);
288 	} else if (ret != H_EOK) {
289 		DBG(DBG_LIB_INT, dip,
290 		    "hvio_intr_settarget failed, ret 0x%lx\n", ret);
291 		return (DDI_FAILURE);
292 	}
293 
294 	return (DDI_SUCCESS);
295 }
296 
297 /*ARGSUSED*/
298 int
299 px_lib_intr_reset(dev_info_t *dip)
300 {
301 	px_t		*px_p = DIP_TO_STATE(dip);
302 	px_ib_t		*ib_p = px_p->px_ib_p;
303 	px_ino_t	*ino_p;
304 
305 	DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip);
306 
307 	mutex_enter(&ib_p->ib_ino_lst_mutex);
308 
309 	/* Reset all Interrupts */
310 	for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next_p) {
311 		if (px_lib_intr_setstate(dip, ino_p->ino_sysino,
312 		    INTR_IDLE_STATE) != DDI_SUCCESS)
313 			return (BF_FATAL);
314 	}
315 
316 	mutex_exit(&ib_p->ib_ino_lst_mutex);
317 
318 	return (BF_NONE);
319 }
320 
321 /*ARGSUSED*/
322 int
323 px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages,
324     io_attributes_t attr, void *addr, size_t pfn_index, int flags)
325 {
326 	tsbnum_t	tsb_num = PCI_TSBID_TO_TSBNUM(tsbid);
327 	tsbindex_t	tsb_index = PCI_TSBID_TO_TSBINDEX(tsbid);
328 	io_page_list_t	*pfns, *pfn_p;
329 	pages_t		ttes_mapped = 0;
330 	int		i, err = DDI_SUCCESS;
331 
332 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx "
333 	    "pages 0x%x attr 0x%llx addr 0x%p pfn_index 0x%llx flags 0x%x\n",
334 	    dip, tsbid, pages, attr, addr, pfn_index, flags);
335 
336 	if ((pfns = pfn_p = kmem_zalloc((pages * sizeof (io_page_list_t)),
337 	    KM_NOSLEEP)) == NULL) {
338 		DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: kmem_zalloc failed\n");
339 		return (DDI_FAILURE);
340 	}
341 
342 	for (i = 0; i < pages; i++)
343 		pfns[i] = MMU_PTOB(PX_ADDR2PFN(addr, pfn_index, flags, i));
344 
345 	/*
346 	 * If HV VPCI version is 1.1 and higher, pass BDF, phantom function,
347 	 * and relaxed ordering attributes. Otherwise, pass only read or write
348 	 * attribute.
349 	 */
350 	if (px_vpci_min_ver == PX_VPCI_MINOR_VER_0)
351 		attr = attr & (PCI_MAP_ATTR_READ | PCI_MAP_ATTR_WRITE);
352 
353 	while ((ttes_mapped = pfn_p - pfns) < pages) {
354 		uintptr_t	ra = va_to_pa(pfn_p);
355 		pages_t		ttes2map;
356 		uint64_t	ret;
357 
358 		ttes2map = (MMU_PAGE_SIZE - P2PHASE(ra, MMU_PAGE_SIZE)) >> 3;
359 		ra = MMU_PTOB(MMU_BTOP(ra));
360 
361 		for (ttes2map = MIN(ttes2map, pages - ttes_mapped); ttes2map;
362 		    ttes2map -= ttes_mapped, pfn_p += ttes_mapped) {
363 
364 			ttes_mapped = 0;
365 			if ((ret = hvio_iommu_map(DIP_TO_HANDLE(dip),
366 			    PCI_TSBID(tsb_num, tsb_index + (pfn_p - pfns)),
367 			    ttes2map, attr, (io_page_list_t *)(ra |
368 			    ((uintptr_t)pfn_p & MMU_PAGE_OFFSET)),
369 			    &ttes_mapped)) != H_EOK) {
370 				DBG(DBG_LIB_DMA, dip, "hvio_iommu_map failed "
371 				    "ret 0x%lx\n", ret);
372 
373 				ttes_mapped = pfn_p - pfns;
374 				err = DDI_FAILURE;
375 				goto cleanup;
376 			}
377 
378 			DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: tsb_num 0x%x "
379 			    "tsb_index 0x%lx ttes_to_map 0x%lx attr 0x%llx "
380 			    "ra 0x%p ttes_mapped 0x%x\n", tsb_num,
381 			    tsb_index + (pfn_p - pfns), ttes2map, attr,
382 			    ra | ((uintptr_t)pfn_p & MMU_PAGE_OFFSET),
383 			    ttes_mapped);
384 		}
385 	}
386 
387 cleanup:
388 	if ((err == DDI_FAILURE) && ttes_mapped)
389 		(void) px_lib_iommu_demap(dip, tsbid, ttes_mapped);
390 
391 	kmem_free(pfns, pages * sizeof (io_page_list_t));
392 	return (err);
393 }
394 
395 /*ARGSUSED*/
396 int
397 px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages)
398 {
399 	tsbnum_t	tsb_num = PCI_TSBID_TO_TSBNUM(tsbid);
400 	tsbindex_t	tsb_index = PCI_TSBID_TO_TSBINDEX(tsbid);
401 	pages_t		ttes2demap, ttes_demapped = 0;
402 	uint64_t	ret;
403 
404 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx "
405 	    "pages 0x%x\n", dip, tsbid, pages);
406 
407 	for (ttes2demap = pages; ttes2demap;
408 	    ttes2demap -= ttes_demapped, tsb_index += ttes_demapped) {
409 		if ((ret = hvio_iommu_demap(DIP_TO_HANDLE(dip),
410 		    PCI_TSBID(tsb_num, tsb_index), ttes2demap,
411 		    &ttes_demapped)) != H_EOK) {
412 			DBG(DBG_LIB_DMA, dip, "hvio_iommu_demap failed, "
413 			    "ret 0x%lx\n", ret);
414 
415 			return (DDI_FAILURE);
416 		}
417 
418 		DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: tsb_num 0x%x "
419 		    "tsb_index 0x%lx ttes_to_demap 0x%lx ttes_demapped 0x%x\n",
420 		    tsb_num, tsb_index, ttes2demap, ttes_demapped);
421 	}
422 
423 	return (DDI_SUCCESS);
424 }
425 
426 /*ARGSUSED*/
427 int
428 px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p,
429     r_addr_t *r_addr_p)
430 {
431 	uint64_t	ret;
432 
433 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n",
434 	    dip, tsbid);
435 
436 	if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), tsbid,
437 	    attr_p, r_addr_p)) != H_EOK) {
438 		DBG(DBG_LIB_DMA, dip,
439 		    "hvio_iommu_getmap failed, ret 0x%lx\n", ret);
440 
441 		return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE);
442 	}
443 
444 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%llx "
445 	    "r_addr 0x%llx\n", *attr_p, *r_addr_p);
446 
447 	return (DDI_SUCCESS);
448 }
449 
450 /*ARGSUSED*/
451 uint64_t
452 px_get_rng_parent_hi_mask(px_t *px_p)
453 {
454 	return (PX_RANGE_PROP_MASK);
455 }
456 
457 /*
458  * Checks dma attributes against system bypass ranges
459  * A sun4v device must be capable of generating the entire 64-bit
460  * address in order to perform bypass DMA.
461  */
462 /*ARGSUSED*/
463 int
464 px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p,
465     uint64_t *lo_p, uint64_t *hi_p)
466 {
467 	if ((attr_p->dma_attr_addr_lo != 0ull) ||
468 	    (attr_p->dma_attr_addr_hi != UINT64_MAX)) {
469 
470 		return (DDI_DMA_BADATTR);
471 	}
472 
473 	*lo_p = 0ull;
474 	*hi_p = UINT64_MAX;
475 
476 	return (DDI_SUCCESS);
477 }
478 
479 
480 /*ARGSUSED*/
481 int
482 px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr,
483     io_addr_t *io_addr_p)
484 {
485 	uint64_t	ret;
486 
487 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx "
488 	    "attr 0x%llx\n", dip, ra, attr);
489 
490 	if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), ra,
491 	    attr, io_addr_p)) != H_EOK) {
492 		DBG(DBG_LIB_DMA, dip,
493 		    "hvio_iommu_getbypass failed, ret 0x%lx\n", ret);
494 		return (ret == H_ENOTSUPPORTED ? DDI_ENOTSUP : DDI_FAILURE);
495 	}
496 
497 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n",
498 	    *io_addr_p);
499 
500 	return (DDI_SUCCESS);
501 }
502 
503 /*
504  * Returns any needed IO address bit(s) for relaxed ordering in IOMMU
505  * bypass mode.
506  */
507 /* ARGSUSED */
508 uint64_t
509 px_lib_ro_bypass(dev_info_t *dip, io_attributes_t attr, uint64_t ioaddr)
510 {
511 	return (ioaddr);
512 }
513 
514 /*ARGSUSED*/
515 int
516 px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
517 	off_t off, size_t len, uint_t cache_flags)
518 {
519 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
520 	uint64_t sync_dir;
521 	size_t bytes_synced;
522 	int end, idx;
523 	off_t pg_off;
524 	devhandle_t hdl = DIP_TO_HANDLE(dip); /* need to cache hdl */
525 
526 	DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p "
527 	    "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n",
528 	    dip, rdip, handle, off, len, cache_flags);
529 
530 	if (!(mp->dmai_flags & PX_DMAI_FLAGS_INUSE)) {
531 		cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.",
532 		    ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp);
533 		return (DDI_FAILURE);
534 	}
535 
536 	if (mp->dmai_flags & PX_DMAI_FLAGS_NOSYNC)
537 		return (DDI_SUCCESS);
538 
539 	if (!len)
540 		len = mp->dmai_size;
541 
542 	if (mp->dmai_rflags & DDI_DMA_READ)
543 		sync_dir = HVIO_DMA_SYNC_DIR_FROM_DEV;
544 	else
545 		sync_dir = HVIO_DMA_SYNC_DIR_TO_DEV;
546 
547 	off += mp->dmai_offset;
548 	pg_off = off & MMU_PAGEOFFSET;
549 
550 	DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: page offset %x size %x\n",
551 	    pg_off, len);
552 
553 	/* sync on page basis */
554 	end = MMU_BTOPR(off + len - 1);
555 	for (idx = MMU_BTOP(off); idx < end; idx++,
556 	    len -= bytes_synced, pg_off = 0) {
557 		size_t bytes_to_sync = bytes_to_sync =
558 		    MIN(len, MMU_PAGESIZE - pg_off);
559 
560 		if (hvio_dma_sync(hdl, MMU_PTOB(PX_GET_MP_PFN(mp, idx)) +
561 		    pg_off, bytes_to_sync, sync_dir, &bytes_synced) != H_EOK)
562 			break;
563 
564 		DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: Called hvio_dma_sync "
565 		    "ra = %p bytes to sync = %x bytes synced %x\n",
566 		    MMU_PTOB(PX_GET_MP_PFN(mp, idx)) + pg_off, bytes_to_sync,
567 		    bytes_synced);
568 
569 		if (bytes_to_sync != bytes_synced)
570 			break;
571 	}
572 
573 	return (len ? DDI_FAILURE : DDI_SUCCESS);
574 }
575 
576 
577 /*
578  * MSIQ Functions:
579  */
580 
581 /*ARGSUSED*/
582 int
583 px_lib_msiq_init(dev_info_t *dip)
584 {
585 	px_t		*px_p = DIP_TO_STATE(dip);
586 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
587 	r_addr_t	ra;
588 	size_t		msiq_size;
589 	uint_t		rec_cnt;
590 	int		i, err = DDI_SUCCESS;
591 	uint64_t	ret;
592 
593 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip);
594 
595 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
596 
597 	/* sun4v requires all EQ allocation to be on q size boundary */
598 	if ((msiq_state_p->msiq_buf_p = contig_mem_alloc_align(
599 	    msiq_state_p->msiq_cnt * msiq_size, msiq_size)) == NULL) {
600 		DBG(DBG_LIB_MSIQ, dip,
601 		    "px_lib_msiq_init: Contig alloc failed\n");
602 
603 		return (DDI_FAILURE);
604 	}
605 
606 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
607 		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
608 		    ((caddr_t)msiq_state_p->msiq_buf_p + (i * msiq_size));
609 
610 		ra = (r_addr_t)va_to_pa((caddr_t)msiq_state_p->msiq_buf_p +
611 		    (i * msiq_size));
612 
613 		if ((ret = hvio_msiq_conf(DIP_TO_HANDLE(dip),
614 		    (i + msiq_state_p->msiq_1st_msiq_id),
615 		    ra, msiq_state_p->msiq_rec_cnt)) != H_EOK) {
616 			DBG(DBG_LIB_MSIQ, dip,
617 			    "hvio_msiq_conf failed, ret 0x%lx\n", ret);
618 			err = DDI_FAILURE;
619 			break;
620 		}
621 
622 		if ((err = px_lib_msiq_info(dip,
623 		    (i + msiq_state_p->msiq_1st_msiq_id),
624 		    &ra, &rec_cnt)) != DDI_SUCCESS) {
625 			DBG(DBG_LIB_MSIQ, dip,
626 			    "px_lib_msiq_info failed, ret 0x%x\n", err);
627 			err = DDI_FAILURE;
628 			break;
629 		}
630 
631 		DBG(DBG_LIB_MSIQ, dip,
632 		    "px_lib_msiq_init: ra 0x%p rec_cnt 0x%x\n", ra, rec_cnt);
633 	}
634 
635 	return (err);
636 }
637 
638 /*ARGSUSED*/
639 int
640 px_lib_msiq_fini(dev_info_t *dip)
641 {
642 	px_t		*px_p = DIP_TO_STATE(dip);
643 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
644 	size_t		msiq_size;
645 
646 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip);
647 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
648 
649 	if (msiq_state_p->msiq_buf_p != NULL)
650 		contig_mem_free(msiq_state_p->msiq_buf_p,
651 		    msiq_state_p->msiq_cnt * msiq_size);
652 
653 	return (DDI_SUCCESS);
654 }
655 
656 /*ARGSUSED*/
657 int
658 px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p,
659     uint_t *msiq_rec_cnt_p)
660 {
661 	uint64_t	ret;
662 
663 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n",
664 	    dip, msiq_id);
665 
666 	if ((ret = hvio_msiq_info(DIP_TO_HANDLE(dip),
667 	    msiq_id, ra_p, msiq_rec_cnt_p)) != H_EOK) {
668 		DBG(DBG_LIB_MSIQ, dip,
669 		    "hvio_msiq_info failed, ret 0x%lx\n", ret);
670 		return (DDI_FAILURE);
671 	}
672 
673 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n",
674 	    ra_p, *msiq_rec_cnt_p);
675 
676 	return (DDI_SUCCESS);
677 }
678 
679 /*ARGSUSED*/
680 int
681 px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id,
682     pci_msiq_valid_state_t *msiq_valid_state)
683 {
684 	uint64_t	ret;
685 
686 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n",
687 	    dip, msiq_id);
688 
689 	if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip),
690 	    msiq_id, msiq_valid_state)) != H_EOK) {
691 		DBG(DBG_LIB_MSIQ, dip,
692 		    "hvio_msiq_getvalid failed, ret 0x%lx\n", ret);
693 		return (DDI_FAILURE);
694 	}
695 
696 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n",
697 	    *msiq_valid_state);
698 
699 	return (DDI_SUCCESS);
700 }
701 
702 /*ARGSUSED*/
703 int
704 px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id,
705     pci_msiq_valid_state_t msiq_valid_state)
706 {
707 	uint64_t	ret;
708 
709 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x "
710 	    "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state);
711 
712 	if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip),
713 	    msiq_id, msiq_valid_state)) != H_EOK) {
714 		DBG(DBG_LIB_MSIQ, dip,
715 		    "hvio_msiq_setvalid failed, ret 0x%lx\n", ret);
716 		return (DDI_FAILURE);
717 	}
718 
719 	return (DDI_SUCCESS);
720 }
721 
722 /*ARGSUSED*/
723 int
724 px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id,
725     pci_msiq_state_t *msiq_state)
726 {
727 	uint64_t	ret;
728 
729 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n",
730 	    dip, msiq_id);
731 
732 	if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip),
733 	    msiq_id, msiq_state)) != H_EOK) {
734 		DBG(DBG_LIB_MSIQ, dip,
735 		    "hvio_msiq_getstate failed, ret 0x%lx\n", ret);
736 		return (DDI_FAILURE);
737 	}
738 
739 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n",
740 	    *msiq_state);
741 
742 	return (DDI_SUCCESS);
743 }
744 
745 /*ARGSUSED*/
746 int
747 px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id,
748     pci_msiq_state_t msiq_state)
749 {
750 	uint64_t	ret;
751 
752 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x "
753 	    "msiq_state 0x%x\n", dip, msiq_id, msiq_state);
754 
755 	if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip),
756 	    msiq_id, msiq_state)) != H_EOK) {
757 		DBG(DBG_LIB_MSIQ, dip,
758 		    "hvio_msiq_setstate failed, ret 0x%lx\n", ret);
759 		return (DDI_FAILURE);
760 	}
761 
762 	return (DDI_SUCCESS);
763 }
764 
765 /*ARGSUSED*/
766 int
767 px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id,
768     msiqhead_t *msiq_head_p)
769 {
770 	uint64_t	ret;
771 
772 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n",
773 	    dip, msiq_id);
774 
775 	if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip),
776 	    msiq_id, msiq_head_p)) != H_EOK) {
777 		DBG(DBG_LIB_MSIQ, dip,
778 		    "hvio_msiq_gethead failed, ret 0x%lx\n", ret);
779 		return (DDI_FAILURE);
780 	}
781 
782 	*msiq_head_p =  (*msiq_head_p / sizeof (msiq_rec_t));
783 
784 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_gethead: msiq_head 0x%x\n",
785 	    *msiq_head_p);
786 
787 	return (DDI_SUCCESS);
788 }
789 
790 /*ARGSUSED*/
791 int
792 px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id,
793     msiqhead_t msiq_head)
794 {
795 	uint64_t	ret;
796 
797 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x "
798 	    "msiq_head 0x%x\n", dip, msiq_id, msiq_head);
799 
800 	if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip),
801 	    msiq_id, msiq_head * sizeof (msiq_rec_t))) != H_EOK) {
802 		DBG(DBG_LIB_MSIQ, dip,
803 		    "hvio_msiq_sethead failed, ret 0x%lx\n", ret);
804 		return (DDI_FAILURE);
805 	}
806 
807 	return (DDI_SUCCESS);
808 }
809 
810 /*ARGSUSED*/
811 int
812 px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id,
813     msiqtail_t *msiq_tail_p)
814 {
815 	uint64_t	ret;
816 
817 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n",
818 	    dip, msiq_id);
819 
820 	if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip),
821 	    msiq_id, msiq_tail_p)) != H_EOK) {
822 		DBG(DBG_LIB_MSIQ, dip,
823 		    "hvio_msiq_gettail failed, ret 0x%lx\n", ret);
824 		return (DDI_FAILURE);
825 	}
826 
827 	*msiq_tail_p =  (*msiq_tail_p / sizeof (msiq_rec_t));
828 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n",
829 	    *msiq_tail_p);
830 
831 	return (DDI_SUCCESS);
832 }
833 
834 /*ARGSUSED*/
835 void
836 px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
837     msiq_rec_t *msiq_rec_p)
838 {
839 	msiq_rec_t	*curr_msiq_rec_p = (msiq_rec_t *)msiq_head_p;
840 
841 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p\n", dip);
842 
843 	if (!curr_msiq_rec_p->msiq_rec_type) {
844 		/* Set msiq_rec_type to zero */
845 		msiq_rec_p->msiq_rec_type = 0;
846 
847 		return;
848 	}
849 
850 	*msiq_rec_p = *curr_msiq_rec_p;
851 }
852 
853 /*ARGSUSED*/
854 void
855 px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p)
856 {
857 	msiq_rec_t	*curr_msiq_rec_p = (msiq_rec_t *)msiq_head_p;
858 
859 	DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p\n", dip);
860 
861 	/* Zero out msiq_rec_type field */
862 	curr_msiq_rec_p->msiq_rec_type  = 0;
863 }
864 
865 /*
866  * MSI Functions:
867  */
868 
869 /*ARGSUSED*/
870 int
871 px_lib_msi_init(dev_info_t *dip)
872 {
873 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip);
874 
875 	/* Noop */
876 	return (DDI_SUCCESS);
877 }
878 
879 /*ARGSUSED*/
880 int
881 px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num,
882     msiqid_t *msiq_id)
883 {
884 	uint64_t	ret;
885 
886 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n",
887 	    dip, msi_num);
888 
889 	if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip),
890 	    msi_num, msiq_id)) != H_EOK) {
891 		DBG(DBG_LIB_MSI, dip,
892 		    "hvio_msi_getmsiq failed, ret 0x%lx\n", ret);
893 		return (DDI_FAILURE);
894 	}
895 
896 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n",
897 	    *msiq_id);
898 
899 	return (DDI_SUCCESS);
900 }
901 
902 /*ARGSUSED*/
903 int
904 px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num,
905     msiqid_t msiq_id, msi_type_t msitype)
906 {
907 	uint64_t	ret;
908 
909 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x "
910 	    "msq_id 0x%x\n", dip, msi_num, msiq_id);
911 
912 	if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip),
913 	    msi_num, msiq_id, msitype)) != H_EOK) {
914 		DBG(DBG_LIB_MSI, dip,
915 		    "hvio_msi_setmsiq failed, ret 0x%lx\n", ret);
916 		return (DDI_FAILURE);
917 	}
918 
919 	return (DDI_SUCCESS);
920 }
921 
922 /*ARGSUSED*/
923 int
924 px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num,
925     pci_msi_valid_state_t *msi_valid_state)
926 {
927 	uint64_t	ret;
928 
929 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n",
930 	    dip, msi_num);
931 
932 	if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip),
933 	    msi_num, msi_valid_state)) != H_EOK) {
934 		DBG(DBG_LIB_MSI, dip,
935 		    "hvio_msi_getvalid failed, ret 0x%lx\n", ret);
936 		return (DDI_FAILURE);
937 	}
938 
939 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n",
940 	    *msi_valid_state);
941 
942 	return (DDI_SUCCESS);
943 }
944 
945 /*ARGSUSED*/
946 int
947 px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num,
948     pci_msi_valid_state_t msi_valid_state)
949 {
950 	uint64_t	ret;
951 
952 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x "
953 	    "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state);
954 
955 	if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip),
956 	    msi_num, msi_valid_state)) != H_EOK) {
957 		DBG(DBG_LIB_MSI, dip,
958 		    "hvio_msi_setvalid failed, ret 0x%lx\n", ret);
959 		return (DDI_FAILURE);
960 	}
961 
962 	return (DDI_SUCCESS);
963 }
964 
965 /*ARGSUSED*/
966 int
967 px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num,
968     pci_msi_state_t *msi_state)
969 {
970 	uint64_t	ret;
971 
972 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n",
973 	    dip, msi_num);
974 
975 	if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip),
976 	    msi_num, msi_state)) != H_EOK) {
977 		DBG(DBG_LIB_MSI, dip,
978 		    "hvio_msi_getstate failed, ret 0x%lx\n", ret);
979 		return (DDI_FAILURE);
980 	}
981 
982 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n",
983 	    *msi_state);
984 
985 	return (DDI_SUCCESS);
986 }
987 
988 /*ARGSUSED*/
989 int
990 px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num,
991     pci_msi_state_t msi_state)
992 {
993 	uint64_t	ret;
994 
995 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x "
996 	    "msi_state 0x%x\n", dip, msi_num, msi_state);
997 
998 	if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip),
999 	    msi_num, msi_state)) != H_EOK) {
1000 		DBG(DBG_LIB_MSI, dip,
1001 		    "hvio_msi_setstate failed, ret 0x%lx\n", ret);
1002 		return (DDI_FAILURE);
1003 	}
1004 
1005 	return (DDI_SUCCESS);
1006 }
1007 
1008 /*
1009  * MSG Functions:
1010  */
1011 
1012 /*ARGSUSED*/
1013 int
1014 px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
1015     msiqid_t *msiq_id)
1016 {
1017 	uint64_t	ret;
1018 
1019 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n",
1020 	    dip, msg_type);
1021 
1022 	if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip),
1023 	    msg_type, msiq_id)) != H_EOK) {
1024 		DBG(DBG_LIB_MSG, dip,
1025 		    "hvio_msg_getmsiq failed, ret 0x%lx\n", ret);
1026 		return (DDI_FAILURE);
1027 	}
1028 
1029 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n",
1030 	    *msiq_id);
1031 
1032 	return (DDI_SUCCESS);
1033 }
1034 
1035 /*ARGSUSED*/
1036 int
1037 px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
1038     msiqid_t msiq_id)
1039 {
1040 	uint64_t	ret;
1041 
1042 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_setmsiq: dip 0x%p msg_type 0x%x "
1043 	    "msq_id 0x%x\n", dip, msg_type, msiq_id);
1044 
1045 	if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip),
1046 	    msg_type, msiq_id)) != H_EOK) {
1047 		DBG(DBG_LIB_MSG, dip,
1048 		    "hvio_msg_setmsiq failed, ret 0x%lx\n", ret);
1049 		return (DDI_FAILURE);
1050 	}
1051 
1052 	return (DDI_SUCCESS);
1053 }
1054 
1055 /*ARGSUSED*/
1056 int
1057 px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
1058     pcie_msg_valid_state_t *msg_valid_state)
1059 {
1060 	uint64_t	ret;
1061 
1062 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n",
1063 	    dip, msg_type);
1064 
1065 	if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type,
1066 	    msg_valid_state)) != H_EOK) {
1067 		DBG(DBG_LIB_MSG, dip,
1068 		    "hvio_msg_getvalid failed, ret 0x%lx\n", ret);
1069 		return (DDI_FAILURE);
1070 	}
1071 
1072 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n",
1073 	    *msg_valid_state);
1074 
1075 	return (DDI_SUCCESS);
1076 }
1077 
1078 /*ARGSUSED*/
1079 int
1080 px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
1081     pcie_msg_valid_state_t msg_valid_state)
1082 {
1083 	uint64_t	ret;
1084 
1085 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x "
1086 	    "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state);
1087 
1088 	if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type,
1089 	    msg_valid_state)) != H_EOK) {
1090 		DBG(DBG_LIB_MSG, dip,
1091 		    "hvio_msg_setvalid failed, ret 0x%lx\n", ret);
1092 		return (DDI_FAILURE);
1093 	}
1094 
1095 	return (DDI_SUCCESS);
1096 }
1097 
1098 /*
1099  * Suspend/Resume Functions:
1100  * Currently unsupported by hypervisor and all functions are noops.
1101  */
1102 /*ARGSUSED*/
1103 int
1104 px_lib_suspend(dev_info_t *dip)
1105 {
1106 	DBG(DBG_ATTACH, dip, "px_lib_suspend: Not supported\n");
1107 
1108 	/* Not supported */
1109 	return (DDI_FAILURE);
1110 }
1111 
1112 /*ARGSUSED*/
1113 void
1114 px_lib_resume(dev_info_t *dip)
1115 {
1116 	DBG(DBG_ATTACH, dip, "px_lib_resume: Not supported\n");
1117 
1118 	/* Noop */
1119 }
1120 
1121 /*
1122  * Misc Functions:
1123  * Currently unsupported by hypervisor and all functions are noops.
1124  */
1125 /*ARGSUSED*/
1126 static int
1127 px_lib_config_get(dev_info_t *dip, pci_device_t bdf, pci_config_offset_t off,
1128     uint8_t size, pci_cfg_data_t *data_p)
1129 {
1130 	uint64_t	ret;
1131 
1132 	DBG(DBG_LIB_CFG, dip, "px_lib_config_get: dip 0x%p, bdf 0x%llx "
1133 	    "off 0x%x size 0x%x\n", dip, bdf, off, size);
1134 
1135 	if ((ret = hvio_config_get(DIP_TO_HANDLE(dip), bdf, off,
1136 	    size, data_p)) != H_EOK) {
1137 		DBG(DBG_LIB_CFG, dip,
1138 		    "hvio_config_get failed, ret 0x%lx\n", ret);
1139 		return (DDI_FAILURE);
1140 	}
1141 	DBG(DBG_LIB_CFG, dip, "px_config_get: data 0x%x\n", data_p->dw);
1142 
1143 	return (DDI_SUCCESS);
1144 }
1145 
1146 /*ARGSUSED*/
1147 static int
1148 px_lib_config_put(dev_info_t *dip, pci_device_t bdf, pci_config_offset_t off,
1149     uint8_t size, pci_cfg_data_t data)
1150 {
1151 	uint64_t	ret;
1152 
1153 	DBG(DBG_LIB_CFG, dip, "px_lib_config_put: dip 0x%p, bdf 0x%llx "
1154 	    "off 0x%x size 0x%x data 0x%llx\n", dip, bdf, off, size, data.qw);
1155 
1156 	if ((ret = hvio_config_put(DIP_TO_HANDLE(dip), bdf, off,
1157 	    size, data)) != H_EOK) {
1158 		DBG(DBG_LIB_CFG, dip,
1159 		    "hvio_config_put failed, ret 0x%lx\n", ret);
1160 		return (DDI_FAILURE);
1161 	}
1162 
1163 	return (DDI_SUCCESS);
1164 }
1165 
1166 static uint32_t
1167 px_pci_config_get(ddi_acc_impl_t *handle, uint32_t *addr, int size)
1168 {
1169 	px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
1170 	    handle->ahi_common.ah_bus_private;
1171 	uint32_t pci_dev_addr = px_pvt->raddr;
1172 	uint32_t vaddr = px_pvt->vaddr;
1173 	uint16_t off = (uint16_t)(uintptr_t)(addr - vaddr) & 0xfff;
1174 	uint64_t rdata = 0;
1175 
1176 	if (px_lib_config_get(px_pvt->dip, pci_dev_addr, off,
1177 	    size, (pci_cfg_data_t *)&rdata) != DDI_SUCCESS)
1178 		/* XXX update error kstats */
1179 		return (0xffffffff);
1180 	return ((uint32_t)rdata);
1181 }
1182 
1183 static void
1184 px_pci_config_put(ddi_acc_impl_t *handle, uint32_t *addr,
1185 		int size, pci_cfg_data_t wdata)
1186 {
1187 	px_config_acc_pvt_t *px_pvt = (px_config_acc_pvt_t *)
1188 	    handle->ahi_common.ah_bus_private;
1189 	uint32_t pci_dev_addr = px_pvt->raddr;
1190 	uint32_t vaddr = px_pvt->vaddr;
1191 	uint16_t off = (uint16_t)(uintptr_t)(addr - vaddr) & 0xfff;
1192 
1193 	if (px_lib_config_put(px_pvt->dip, pci_dev_addr, off,
1194 	    size, wdata) != DDI_SUCCESS) {
1195 		/*EMPTY*/
1196 		/* XXX update error kstats */
1197 	}
1198 }
1199 
1200 static uint8_t
1201 px_pci_config_get8(ddi_acc_impl_t *handle, uint8_t *addr)
1202 {
1203 	return ((uint8_t)px_pci_config_get(handle, (uint32_t *)addr, 1));
1204 }
1205 
1206 static uint16_t
1207 px_pci_config_get16(ddi_acc_impl_t *handle, uint16_t *addr)
1208 {
1209 	return ((uint16_t)px_pci_config_get(handle, (uint32_t *)addr, 2));
1210 }
1211 
1212 static uint32_t
1213 px_pci_config_get32(ddi_acc_impl_t *handle, uint32_t *addr)
1214 {
1215 	return ((uint32_t)px_pci_config_get(handle, (uint32_t *)addr, 4));
1216 }
1217 
1218 static uint64_t
1219 px_pci_config_get64(ddi_acc_impl_t *handle, uint64_t *addr)
1220 {
1221 	uint32_t rdatah, rdatal;
1222 
1223 	rdatal = (uint32_t)px_pci_config_get(handle, (uint32_t *)addr, 4);
1224 	rdatah = (uint32_t)px_pci_config_get(handle,
1225 	    (uint32_t *)((char *)addr+4), 4);
1226 	return (((uint64_t)rdatah << 32) | rdatal);
1227 }
1228 
1229 static void
1230 px_pci_config_put8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t data)
1231 {
1232 	pci_cfg_data_t wdata = { 0 };
1233 
1234 	wdata.qw = (uint8_t)data;
1235 	px_pci_config_put(handle, (uint32_t *)addr, 1, wdata);
1236 }
1237 
1238 static void
1239 px_pci_config_put16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t data)
1240 {
1241 	pci_cfg_data_t wdata = { 0 };
1242 
1243 	wdata.qw = (uint16_t)data;
1244 	px_pci_config_put(handle, (uint32_t *)addr, 2, wdata);
1245 }
1246 
1247 static void
1248 px_pci_config_put32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t data)
1249 {
1250 	pci_cfg_data_t wdata = { 0 };
1251 
1252 	wdata.qw = (uint32_t)data;
1253 	px_pci_config_put(handle, (uint32_t *)addr, 4, wdata);
1254 }
1255 
1256 static void
1257 px_pci_config_put64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t data)
1258 {
1259 	pci_cfg_data_t wdata = { 0 };
1260 
1261 	wdata.qw = (uint32_t)(data & 0xffffffff);
1262 	px_pci_config_put(handle, (uint32_t *)addr, 4, wdata);
1263 	wdata.qw = (uint32_t)((data >> 32) & 0xffffffff);
1264 	px_pci_config_put(handle, (uint32_t *)((char *)addr+4), 4, wdata);
1265 }
1266 
1267 static void
1268 px_pci_config_rep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr,
1269 			uint8_t *dev_addr, size_t repcount, uint_t flags)
1270 {
1271 	if (flags == DDI_DEV_AUTOINCR)
1272 		for (; repcount; repcount--)
1273 			*host_addr++ = px_pci_config_get8(handle, dev_addr++);
1274 	else
1275 		for (; repcount; repcount--)
1276 			*host_addr++ = px_pci_config_get8(handle, dev_addr);
1277 }
1278 
1279 /*
1280  * Function to rep read 16 bit data off the PCI configuration space behind
1281  * the 21554's host interface.
1282  */
1283 static void
1284 px_pci_config_rep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr,
1285 			uint16_t *dev_addr, size_t repcount, uint_t flags)
1286 {
1287 	if (flags == DDI_DEV_AUTOINCR)
1288 		for (; repcount; repcount--)
1289 			*host_addr++ = px_pci_config_get16(handle, dev_addr++);
1290 	else
1291 		for (; repcount; repcount--)
1292 			*host_addr++ = px_pci_config_get16(handle, dev_addr);
1293 }
1294 
1295 /*
1296  * Function to rep read 32 bit data off the PCI configuration space behind
1297  * the 21554's host interface.
1298  */
1299 static void
1300 px_pci_config_rep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr,
1301 			uint32_t *dev_addr, size_t repcount, uint_t flags)
1302 {
1303 	if (flags == DDI_DEV_AUTOINCR)
1304 		for (; repcount; repcount--)
1305 			*host_addr++ = px_pci_config_get32(handle, dev_addr++);
1306 	else
1307 		for (; repcount; repcount--)
1308 			*host_addr++ = px_pci_config_get32(handle, dev_addr);
1309 }
1310 
1311 /*
1312  * Function to rep read 64 bit data off the PCI configuration space behind
1313  * the 21554's host interface.
1314  */
1315 static void
1316 px_pci_config_rep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr,
1317 			uint64_t *dev_addr, size_t repcount, uint_t flags)
1318 {
1319 	if (flags == DDI_DEV_AUTOINCR)
1320 		for (; repcount; repcount--)
1321 			*host_addr++ = px_pci_config_get64(handle, dev_addr++);
1322 	else
1323 		for (; repcount; repcount--)
1324 			*host_addr++ = px_pci_config_get64(handle, dev_addr);
1325 }
1326 
1327 /*
1328  * Function to rep write 8 bit data into the PCI configuration space behind
1329  * the 21554's host interface.
1330  */
1331 static void
1332 px_pci_config_rep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr,
1333 			uint8_t *dev_addr, size_t repcount, uint_t flags)
1334 {
1335 	if (flags == DDI_DEV_AUTOINCR)
1336 		for (; repcount; repcount--)
1337 			px_pci_config_put8(handle, dev_addr++, *host_addr++);
1338 	else
1339 		for (; repcount; repcount--)
1340 			px_pci_config_put8(handle, dev_addr, *host_addr++);
1341 }
1342 
1343 /*
1344  * Function to rep write 16 bit data into the PCI configuration space behind
1345  * the 21554's host interface.
1346  */
1347 static void
1348 px_pci_config_rep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr,
1349 			uint16_t *dev_addr, size_t repcount, uint_t flags)
1350 {
1351 	if (flags == DDI_DEV_AUTOINCR)
1352 		for (; repcount; repcount--)
1353 			px_pci_config_put16(handle, dev_addr++, *host_addr++);
1354 	else
1355 		for (; repcount; repcount--)
1356 			px_pci_config_put16(handle, dev_addr, *host_addr++);
1357 }
1358 
1359 /*
1360  * Function to rep write 32 bit data into the PCI configuration space behind
1361  * the 21554's host interface.
1362  */
1363 static void
1364 px_pci_config_rep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr,
1365 			uint32_t *dev_addr, size_t repcount, uint_t flags)
1366 {
1367 	if (flags == DDI_DEV_AUTOINCR)
1368 		for (; repcount; repcount--)
1369 			px_pci_config_put32(handle, dev_addr++, *host_addr++);
1370 	else
1371 		for (; repcount; repcount--)
1372 			px_pci_config_put32(handle, dev_addr, *host_addr++);
1373 }
1374 
1375 /*
1376  * Function to rep write 64 bit data into the PCI configuration space behind
1377  * the 21554's host interface.
1378  */
1379 static void
1380 px_pci_config_rep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr,
1381 			uint64_t *dev_addr, size_t repcount, uint_t flags)
1382 {
1383 	if (flags == DDI_DEV_AUTOINCR)
1384 		for (; repcount; repcount--)
1385 			px_pci_config_put64(handle, dev_addr++, *host_addr++);
1386 	else
1387 		for (; repcount; repcount--)
1388 			px_pci_config_put64(handle, dev_addr, *host_addr++);
1389 }
1390 
1391 /*
1392  * Provide a private access handle to route config access calls to Hypervisor.
1393  * Beware: Do all error checking for config space accesses before calling
1394  * this function. ie. do error checking from the calling function.
1395  * Due to a lack of meaningful error code in DDI, the gauranteed return of
1396  * DDI_SUCCESS from here makes the code organization readable/easier from
1397  * the generic code.
1398  */
1399 /*ARGSUSED*/
1400 int
1401 px_lib_map_vconfig(dev_info_t *dip,
1402 	ddi_map_req_t *mp, pci_config_offset_t off,
1403 	pci_regspec_t *rp, caddr_t *addrp)
1404 {
1405 	int fmcap;
1406 	ndi_err_t *errp;
1407 	on_trap_data_t *otp;
1408 	ddi_acc_hdl_t *hp;
1409 	ddi_acc_impl_t *ap;
1410 	uchar_t busnum;	/* bus number */
1411 	uchar_t devnum;	/* device number */
1412 	uchar_t funcnum; /* function number */
1413 	px_config_acc_pvt_t *px_pvt;
1414 
1415 	hp = (ddi_acc_hdl_t *)mp->map_handlep;
1416 	ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1417 
1418 	/* Check for mapping teardown operation */
1419 	if ((mp->map_op == DDI_MO_UNMAP) ||
1420 	    (mp->map_op == DDI_MO_UNLOCK)) {
1421 		/* free up memory allocated for the private access handle. */
1422 		px_pvt = (px_config_acc_pvt_t *)hp->ah_bus_private;
1423 		kmem_free((void *)px_pvt, sizeof (px_config_acc_pvt_t));
1424 
1425 		/* unmap operation of PCI IO/config space. */
1426 		return (DDI_SUCCESS);
1427 	}
1428 
1429 	fmcap = ddi_fm_capable(dip);
1430 	if (DDI_FM_ACC_ERR_CAP(fmcap)) {
1431 		errp = ((ddi_acc_impl_t *)hp)->ahi_err;
1432 		otp = (on_trap_data_t *)errp->err_ontrap;
1433 		otp->ot_handle = (void *)(hp);
1434 		otp->ot_prot = OT_DATA_ACCESS;
1435 		errp->err_status = DDI_FM_OK;
1436 		errp->err_expected = DDI_FM_ERR_UNEXPECTED;
1437 		errp->err_cf = px_err_cfg_hdl_check;
1438 	}
1439 
1440 	ap->ahi_get8 = px_pci_config_get8;
1441 	ap->ahi_get16 = px_pci_config_get16;
1442 	ap->ahi_get32 = px_pci_config_get32;
1443 	ap->ahi_get64 = px_pci_config_get64;
1444 	ap->ahi_put8 = px_pci_config_put8;
1445 	ap->ahi_put16 = px_pci_config_put16;
1446 	ap->ahi_put32 = px_pci_config_put32;
1447 	ap->ahi_put64 = px_pci_config_put64;
1448 	ap->ahi_rep_get8 = px_pci_config_rep_get8;
1449 	ap->ahi_rep_get16 = px_pci_config_rep_get16;
1450 	ap->ahi_rep_get32 = px_pci_config_rep_get32;
1451 	ap->ahi_rep_get64 = px_pci_config_rep_get64;
1452 	ap->ahi_rep_put8 = px_pci_config_rep_put8;
1453 	ap->ahi_rep_put16 = px_pci_config_rep_put16;
1454 	ap->ahi_rep_put32 = px_pci_config_rep_put32;
1455 	ap->ahi_rep_put64 = px_pci_config_rep_put64;
1456 
1457 	/* Initialize to default check/notify functions */
1458 	ap->ahi_fault = 0;
1459 	ap->ahi_fault_check = i_ddi_acc_fault_check;
1460 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1461 
1462 	/* allocate memory for our private handle */
1463 	px_pvt = (px_config_acc_pvt_t *)
1464 	    kmem_zalloc(sizeof (px_config_acc_pvt_t), KM_SLEEP);
1465 	hp->ah_bus_private = (void *)px_pvt;
1466 
1467 	busnum = PCI_REG_BUS_G(rp->pci_phys_hi);
1468 	devnum = PCI_REG_DEV_G(rp->pci_phys_hi);
1469 	funcnum = PCI_REG_FUNC_G(rp->pci_phys_hi);
1470 
1471 	/* set up private data for use during IO routines */
1472 
1473 	/* addr needed by the HV APIs */
1474 	px_pvt->raddr = busnum << 16 | devnum << 11 | funcnum << 8;
1475 	/*
1476 	 * Address that specifies the actual offset into the 256MB
1477 	 * memory mapped configuration space, 4K per device.
1478 	 * First 12bits form the offset into 4K config space.
1479 	 * This address is only used during the IO routines to calculate
1480 	 * the offset at which the transaction must be performed.
1481 	 * Drivers bypassing DDI functions to access PCI config space will
1482 	 * panic the system since the following is a bogus virtual address.
1483 	 */
1484 	px_pvt->vaddr = busnum << 20 | devnum << 15 | funcnum << 12 | off;
1485 	px_pvt->dip = dip;
1486 
1487 	DBG(DBG_LIB_CFG, dip, "px_config_setup: raddr 0x%x, vaddr 0x%x\n",
1488 	    px_pvt->raddr, px_pvt->vaddr);
1489 	*addrp = (caddr_t)(uintptr_t)px_pvt->vaddr;
1490 	return (DDI_SUCCESS);
1491 }
1492 
1493 /*ARGSUSED*/
1494 void
1495 px_lib_map_attr_check(ddi_map_req_t *mp)
1496 {
1497 }
1498 
1499 /*
1500  * px_lib_log_safeacc_err:
1501  * Imitate a cpu/mem trap call when a peek/poke fails.
1502  * This will initiate something similar to px_fm_callback.
1503  */
1504 static void
1505 px_lib_log_safeacc_err(px_t *px_p, ddi_acc_handle_t handle, int fme_flag,
1506     r_addr_t addr)
1507 {
1508 	uint32_t	addr_high, addr_low;
1509 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
1510 	pci_ranges_t	*ranges_p;
1511 	int		range_len, i;
1512 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
1513 	ddi_fm_error_t derr;
1514 
1515 	derr.fme_status = DDI_FM_NONFATAL;
1516 	derr.fme_version = DDI_FME_VERSION;
1517 	derr.fme_flag = fme_flag;
1518 	derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1519 	derr.fme_acc_handle = handle;
1520 	if (hp)
1521 		hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
1522 
1523 	addr_high = (uint32_t)(addr >> 32);
1524 	addr_low = (uint32_t)addr;
1525 
1526 	/*
1527 	 * Make sure this failed load came from this PCIe port.  Check by
1528 	 * matching the upper 32 bits of the address with the ranges property.
1529 	 */
1530 	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
1531 	i = 0;
1532 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
1533 		if (ranges_p->parent_high == addr_high) {
1534 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
1535 			case PCI_ADDR_CONFIG:
1536 				bdf = (pcie_req_id_t)(addr_low >> 12);
1537 				break;
1538 			default:
1539 				bdf = PCIE_INVALID_BDF;
1540 				break;
1541 			}
1542 			break;
1543 		}
1544 	}
1545 
1546 	px_rp_en_q(px_p, bdf, addr, NULL);
1547 
1548 	if (px_fm_enter(px_p) == DDI_SUCCESS) {
1549 		(void) px_scan_fabric(px_p, px_p->px_dip, &derr);
1550 		px_fm_exit(px_p);
1551 	}
1552 }
1553 
1554 
1555 #ifdef  DEBUG
1556 int	px_peekfault_cnt = 0;
1557 int	px_pokefault_cnt = 0;
1558 #endif  /* DEBUG */
1559 
1560 /*
1561  * Do a safe write to a device.
1562  *
1563  * When this function is given a handle (cautious access), all errors are
1564  * suppressed.
1565  *
1566  * When this function is not given a handle (poke), only Unsupported Request
1567  * and Completer Abort errors are suppressed.
1568  *
1569  * In all cases, all errors are returned in the function return status.
1570  */
1571 
1572 int
1573 px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip,
1574     peekpoke_ctlops_t *in_args)
1575 {
1576 	px_t *px_p = DIP_TO_STATE(dip);
1577 	px_pec_t *pec_p = px_p->px_pec_p;
1578 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1579 
1580 	size_t repcount = in_args->repcount;
1581 	size_t size = in_args->size;
1582 	uintptr_t dev_addr = in_args->dev_addr;
1583 	uintptr_t host_addr = in_args->host_addr;
1584 
1585 	int err	= DDI_SUCCESS;
1586 	uint64_t hvio_poke_status;
1587 	uint32_t wrt_stat;
1588 
1589 	r_addr_t ra;
1590 	uint64_t pokeval;
1591 	pcie_req_id_t bdf;
1592 
1593 	ra = (r_addr_t)va_to_pa((void *)dev_addr);
1594 	for (; repcount; repcount--) {
1595 
1596 		switch (size) {
1597 		case sizeof (uint8_t):
1598 			pokeval = *(uint8_t *)host_addr;
1599 			break;
1600 		case sizeof (uint16_t):
1601 			pokeval = *(uint16_t *)host_addr;
1602 			break;
1603 		case sizeof (uint32_t):
1604 			pokeval = *(uint32_t *)host_addr;
1605 			break;
1606 		case sizeof (uint64_t):
1607 			pokeval = *(uint64_t *)host_addr;
1608 			break;
1609 		default:
1610 			DBG(DBG_MAP, px_p->px_dip,
1611 			    "poke: invalid size %d passed\n", size);
1612 			err = DDI_FAILURE;
1613 			goto done;
1614 		}
1615 
1616 		/*
1617 		 * Grab pokefault mutex since hypervisor does not guarantee
1618 		 * poke serialization.
1619 		 */
1620 		if (hp) {
1621 			i_ndi_busop_access_enter(hp->ahi_common.ah_dip,
1622 			    (ddi_acc_handle_t)hp);
1623 			pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1624 		} else {
1625 			mutex_enter(&pec_p->pec_pokefault_mutex);
1626 			pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
1627 		}
1628 
1629 		if (pcie_get_bdf_from_dip(rdip, &bdf) != DDI_SUCCESS) {
1630 			err = DDI_FAILURE;
1631 			goto done;
1632 		}
1633 
1634 		hvio_poke_status = hvio_poke(px_p->px_dev_hdl, ra, size,
1635 		    pokeval, bdf << 8, &wrt_stat);
1636 
1637 		if ((hvio_poke_status != H_EOK) || (wrt_stat != H_EOK)) {
1638 			err = DDI_FAILURE;
1639 #ifdef  DEBUG
1640 			px_pokefault_cnt++;
1641 #endif
1642 			/*
1643 			 * For CAUTIOUS and POKE access, notify FMA to
1644 			 * cleanup.  Imitate a cpu/mem trap call like in sun4u.
1645 			 */
1646 			px_lib_log_safeacc_err(px_p, (ddi_acc_handle_t)hp,
1647 			    (hp ? DDI_FM_ERR_EXPECTED :
1648 			    DDI_FM_ERR_POKE), ra);
1649 
1650 			pec_p->pec_ontrap_data = NULL;
1651 			pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1652 			if (hp) {
1653 				i_ndi_busop_access_exit(hp->ahi_common.ah_dip,
1654 				    (ddi_acc_handle_t)hp);
1655 			} else {
1656 				mutex_exit(&pec_p->pec_pokefault_mutex);
1657 			}
1658 			goto done;
1659 		}
1660 
1661 		pec_p->pec_ontrap_data = NULL;
1662 		pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1663 		if (hp) {
1664 			i_ndi_busop_access_exit(hp->ahi_common.ah_dip,
1665 			    (ddi_acc_handle_t)hp);
1666 		} else {
1667 			mutex_exit(&pec_p->pec_pokefault_mutex);
1668 		}
1669 
1670 		host_addr += size;
1671 
1672 		if (in_args->flags == DDI_DEV_AUTOINCR) {
1673 			dev_addr += size;
1674 			ra = (r_addr_t)va_to_pa((void *)dev_addr);
1675 		}
1676 	}
1677 
1678 done:
1679 	return (err);
1680 }
1681 
1682 
1683 /*ARGSUSED*/
1684 int
1685 px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip,
1686     peekpoke_ctlops_t *in_args, void *result)
1687 {
1688 	px_t *px_p = DIP_TO_STATE(dip);
1689 	px_pec_t *pec_p = px_p->px_pec_p;
1690 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1691 
1692 	size_t repcount = in_args->repcount;
1693 	uintptr_t dev_addr = in_args->dev_addr;
1694 	uintptr_t host_addr = in_args->host_addr;
1695 
1696 	r_addr_t ra;
1697 	uint32_t read_status;
1698 	uint64_t hvio_peek_status;
1699 	uint64_t peekval;
1700 	int err = DDI_SUCCESS;
1701 
1702 	result = (void *)in_args->host_addr;
1703 
1704 	ra = (r_addr_t)va_to_pa((void *)dev_addr);
1705 	for (; repcount; repcount--) {
1706 
1707 		/* Lock pokefault mutex so read doesn't mask a poke fault. */
1708 		if (hp) {
1709 			i_ndi_busop_access_enter(hp->ahi_common.ah_dip,
1710 			    (ddi_acc_handle_t)hp);
1711 			pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1712 		} else {
1713 			mutex_enter(&pec_p->pec_pokefault_mutex);
1714 			pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
1715 		}
1716 
1717 		hvio_peek_status = hvio_peek(px_p->px_dev_hdl, ra,
1718 		    in_args->size, &read_status, &peekval);
1719 
1720 		if ((hvio_peek_status != H_EOK) || (read_status != H_EOK)) {
1721 			err = DDI_FAILURE;
1722 
1723 			/*
1724 			 * For CAUTIOUS and PEEK access, notify FMA to
1725 			 * cleanup.  Imitate a cpu/mem trap call like in sun4u.
1726 			 */
1727 			px_lib_log_safeacc_err(px_p, (ddi_acc_handle_t)hp,
1728 			    (hp ? DDI_FM_ERR_EXPECTED :
1729 			    DDI_FM_ERR_PEEK), ra);
1730 
1731 			/* Stuff FFs in host addr if peek. */
1732 			if (hp == NULL) {
1733 				int i;
1734 				uint8_t *ff_addr = (uint8_t *)host_addr;
1735 				for (i = 0; i < in_args->size; i++)
1736 					*ff_addr++ = 0xff;
1737 			}
1738 #ifdef  DEBUG
1739 			px_peekfault_cnt++;
1740 #endif
1741 			pec_p->pec_ontrap_data = NULL;
1742 			pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1743 			if (hp) {
1744 				i_ndi_busop_access_exit(hp->ahi_common.ah_dip,
1745 				    (ddi_acc_handle_t)hp);
1746 			} else {
1747 				mutex_exit(&pec_p->pec_pokefault_mutex);
1748 			}
1749 			goto done;
1750 
1751 		}
1752 		pec_p->pec_ontrap_data = NULL;
1753 		pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1754 		if (hp) {
1755 			i_ndi_busop_access_exit(hp->ahi_common.ah_dip,
1756 			    (ddi_acc_handle_t)hp);
1757 		} else {
1758 			mutex_exit(&pec_p->pec_pokefault_mutex);
1759 		}
1760 
1761 		switch (in_args->size) {
1762 		case sizeof (uint8_t):
1763 			*(uint8_t *)host_addr = (uint8_t)peekval;
1764 			break;
1765 		case sizeof (uint16_t):
1766 			*(uint16_t *)host_addr = (uint16_t)peekval;
1767 			break;
1768 		case sizeof (uint32_t):
1769 			*(uint32_t *)host_addr = (uint32_t)peekval;
1770 			break;
1771 		case sizeof (uint64_t):
1772 			*(uint64_t *)host_addr = (uint64_t)peekval;
1773 			break;
1774 		default:
1775 			DBG(DBG_MAP, px_p->px_dip,
1776 			    "peek: invalid size %d passed\n",
1777 			    in_args->size);
1778 			err = DDI_FAILURE;
1779 			goto done;
1780 		}
1781 
1782 		host_addr += in_args->size;
1783 
1784 		if (in_args->flags == DDI_DEV_AUTOINCR) {
1785 			dev_addr += in_args->size;
1786 			ra = (r_addr_t)va_to_pa((void *)dev_addr);
1787 		}
1788 	}
1789 done:
1790 	return (err);
1791 }
1792 
1793 
1794 /* add interrupt vector */
1795 int
1796 px_err_add_intr(px_fault_t *px_fault_p)
1797 {
1798 	px_t	*px_p = DIP_TO_STATE(px_fault_p->px_fh_dip);
1799 
1800 	DBG(DBG_LIB_INT, px_p->px_dip,
1801 	    "px_err_add_intr: calling add_ivintr");
1802 
1803 	VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL,
1804 	    (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p, NULL,
1805 	    (caddr_t)&px_fault_p->px_intr_payload[0]) == 0);
1806 
1807 	DBG(DBG_LIB_INT, px_p->px_dip,
1808 	    "px_err_add_intr: ib_intr_enable ");
1809 
1810 	px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino);
1811 
1812 	return (DDI_SUCCESS);
1813 }
1814 
1815 /* remove interrupt vector */
1816 void
1817 px_err_rem_intr(px_fault_t *px_fault_p)
1818 {
1819 	px_t	*px_p = DIP_TO_STATE(px_fault_p->px_fh_dip);
1820 
1821 	px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
1822 	    IB_INTR_WAIT);
1823 
1824 	VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
1825 }
1826 
1827 void
1828 px_cb_intr_redist(void *arg)
1829 {
1830 	px_t	*px_p = (px_t *)arg;
1831 	px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(),
1832 	    px_p->px_inos[PX_INTR_XBC], B_FALSE);
1833 }
1834 
1835 int
1836 px_cb_add_intr(px_fault_t *f_p)
1837 {
1838 	px_t	*px_p = DIP_TO_STATE(f_p->px_fh_dip);
1839 
1840 	DBG(DBG_LIB_INT, px_p->px_dip,
1841 	    "px_err_add_intr: calling add_ivintr");
1842 
1843 	VERIFY(add_ivintr(f_p->px_fh_sysino, PX_ERR_PIL,
1844 	    (intrfunc)f_p->px_err_func, (caddr_t)f_p, NULL,
1845 	    (caddr_t)&f_p->px_intr_payload[0]) == 0);
1846 
1847 	intr_dist_add(px_cb_intr_redist, px_p);
1848 
1849 	DBG(DBG_LIB_INT, px_p->px_dip,
1850 	    "px_err_add_intr: ib_intr_enable ");
1851 
1852 	px_ib_intr_enable(px_p, intr_dist_cpuid(), f_p->px_intr_ino);
1853 
1854 	return (DDI_SUCCESS);
1855 }
1856 
1857 void
1858 px_cb_rem_intr(px_fault_t *f_p)
1859 {
1860 	intr_dist_rem(px_cb_intr_redist, DIP_TO_STATE(f_p->px_fh_dip));
1861 	px_err_rem_intr(f_p);
1862 }
1863 
1864 #ifdef FMA
1865 void
1866 px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status)
1867 {
1868 	px_pec_err_t	*err_pkt;
1869 
1870 	err_pkt = (px_pec_err_t *)px_fault_p->px_intr_payload;
1871 
1872 	/* initialise all the structure members */
1873 	rc_status->status_valid = 0;
1874 
1875 	if (err_pkt->pec_descr.P) {
1876 		/* PCI Status Register */
1877 		rc_status->pci_err_status = err_pkt->pci_err_status;
1878 		rc_status->status_valid |= PCI_ERR_STATUS_VALID;
1879 	}
1880 
1881 	if (err_pkt->pec_descr.E) {
1882 		/* PCIe Status Register */
1883 		rc_status->pcie_err_status = err_pkt->pcie_err_status;
1884 		rc_status->status_valid |= PCIE_ERR_STATUS_VALID;
1885 	}
1886 
1887 	if (err_pkt->pec_descr.U) {
1888 		rc_status->ue_status = err_pkt->ue_reg_status;
1889 		rc_status->status_valid |= UE_STATUS_VALID;
1890 	}
1891 
1892 	if (err_pkt->pec_descr.H) {
1893 		rc_status->ue_hdr1 = err_pkt->hdr[0];
1894 		rc_status->status_valid |= UE_HDR1_VALID;
1895 	}
1896 
1897 	if (err_pkt->pec_descr.I) {
1898 		rc_status->ue_hdr2 = err_pkt->hdr[1];
1899 		rc_status->status_valid |= UE_HDR2_VALID;
1900 	}
1901 
1902 	/* ue_fst_err_ptr - not available for sun4v?? */
1903 
1904 
1905 	if (err_pkt->pec_descr.S) {
1906 		rc_status->source_id = err_pkt->err_src_reg;
1907 		rc_status->status_valid |= SOURCE_ID_VALID;
1908 	}
1909 
1910 	if (err_pkt->pec_descr.R) {
1911 		rc_status->root_err_status = err_pkt->root_err_status;
1912 		rc_status->status_valid |= CE_STATUS_VALID;
1913 	}
1914 }
1915 #endif
1916 
1917 /*ARGSUSED*/
1918 int
1919 px_lib_pmctl(int cmd, px_t *px_p)
1920 {
1921 	return (DDI_FAILURE);
1922 }
1923 
1924 /*ARGSUSED*/
1925 uint_t
1926 px_pmeq_intr(caddr_t arg)
1927 {
1928 	return (DDI_INTR_CLAIMED);
1929 }
1930 
1931 /*
1932  * Unprotected raw reads/writes of fabric device's config space.
1933  * Only used for temporary PCI-E Fabric Error Handling.
1934  */
1935 uint32_t
1936 px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset) {
1937 	uint64_t 	data = 0;
1938 
1939 	(void) hvio_config_get(px_p->px_dev_hdl,
1940 	    (bdf << PX_RA_BDF_SHIFT), offset, 4,
1941 	    (pci_cfg_data_t *)&data);
1942 
1943 	return ((uint32_t)data);
1944 }
1945 
1946 void
1947 px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
1948     uint32_t val) {
1949 	pci_cfg_data_t	wdata = { 0 };
1950 
1951 	wdata.qw = (uint32_t)val;
1952 	(void) hvio_config_put(px_p->px_dev_hdl,
1953 	    (bdf << PX_RA_BDF_SHIFT), offset, 4, wdata);
1954 }
1955 
1956 /*ARGSUSED*/
1957 int
1958 px_lib_hotplug_init(dev_info_t *dip, void *arg)
1959 {
1960 	return (DDI_ENOTSUP);
1961 }
1962 
1963 /*ARGSUSED*/
1964 void
1965 px_lib_hotplug_uninit(dev_info_t *dip)
1966 {
1967 }
1968 
1969 /*ARGSUSED*/
1970 void
1971 px_hp_intr_redist(px_t *px_p)
1972 {
1973 }
1974 
1975 /* Dummy cpr add callback */
1976 /*ARGSUSED*/
1977 void
1978 px_cpr_add_callb(px_t *px_p)
1979 {
1980 }
1981 
1982 /* Dummy cpr rem callback */
1983 /*ARGSUSED*/
1984 void
1985 px_cpr_rem_callb(px_t *px_p)
1986 {
1987 }
1988 
1989 /*ARGSUSED*/
1990 boolean_t
1991 px_lib_is_in_drain_state(px_t *px_p)
1992 {
1993 	return (B_FALSE);
1994 }
1995 
1996 /*
1997  * There is no IOAPI to get the BDF of the pcie root port nexus at this moment.
1998  * Assume it is 0x0000, until otherwise noted.  For now, all sun4v platforms
1999  * have programmed the BDF to be 0x0000.
2000  */
2001 /*ARGSUSED*/
2002 pcie_req_id_t
2003 px_lib_get_bdf(px_t *px_p)
2004 {
2005 	return (0x0000);
2006 }
2007 
2008 int
2009 px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps)
2010 {
2011 	pci_device_t	bdf = px_lib_get_bdf(px_p);
2012 
2013 	if (hvio_get_rp_mps_cap(DIP_TO_HANDLE(dip), bdf, mps) == H_EOK)
2014 		return (DDI_SUCCESS);
2015 	else
2016 		return (DDI_FAILURE);
2017 }
2018 
2019 int
2020 px_lib_set_root_complex_mps(px_t *px_p,  dev_info_t *dip, int mps)
2021 {
2022 	pci_device_t	bdf = px_lib_get_bdf(px_p);
2023 
2024 	if (hvio_set_rp_mps(DIP_TO_HANDLE(dip), bdf, mps) == H_EOK)
2025 		return (DDI_SUCCESS);
2026 	else
2027 		return (DDI_FAILURE);
2028 }
2029