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