69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * CDDL HEADER START
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * The contents of this file are subject to the terms of the
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz * Common Development and Distribution License (the "License").
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz * You may not use this file except in compliance with the License.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
69cd775ffd53de411433f1f43de2b4f644793528schwartz * or http://www.opensolaris.org/os/licensing.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * See the License for the specific language governing permissions
69cd775ffd53de411433f1f43de2b4f644793528schwartz * and limitations under the License.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When distributing Covered Code, include this CDDL HEADER in each
69cd775ffd53de411433f1f43de2b4f644793528schwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * If applicable, add the following below this CDDL HEADER, with the
69cd775ffd53de411433f1f43de2b4f644793528schwartz * fields enclosed by brackets "[]" replaced with your own identifying
69cd775ffd53de411433f1f43de2b4f644793528schwartz * information: Portions Copyright [yyyy] [name of copyright owner]
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * CDDL HEADER END
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
1578c5210cc5a6709ee11c9693bb0a24ed8d38f8schwartz * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Use is subject to license terms.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz#pragma ident "%Z%%M% %I% %E% SMI"
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <sys/sysmacros.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <sys/machsystm.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <sys/cpuvar.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <sys/ddi_implfuncs.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_csr.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_regs.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_obj.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <sys/pci_tools.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_tools_var.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_asm_4u.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz#include <px_lib4u.h>
d4476ccb08e9498c2013971c4212dc6362fcec46schwartz#include <px_tools_ext.h>
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Delay needed to have a safe environment envelop any error which could
69cd775ffd53de411433f1f43de2b4f644793528schwartz * surface. The larger the number of bridges and switches, the larger the
69cd775ffd53de411433f1f43de2b4f644793528schwartz * number needed here.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * The way it works is as follows:
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * An access is done which causes an error. Fire errors are handled with
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * ontrap protection and usually come in first. Fabric errors can come in
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * later.
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * px_phys_peek_4u() disables interrupts. Interrupts are reenabled at the end
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * of that function if no errors have been caught by the trap handler, or by
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * peek_fault() which executes when a fire error occurs.
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * Fabric error messages get put on an event queue but are not processed until
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * interrupts are reenabled.
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * The delay gives time for the fabric errors to be processed by FMA before
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * changing the fm error flag back to DDI_FM_ERR_UNEXPECTED. If this isn't
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * done, then the fabric error which should be safe can panic the system.
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Note: this is a workaround until a better solution is found. While this
69cd775ffd53de411433f1f43de2b4f644793528schwartz * number is high, given enough bridges and switches in the device path, this
69cd775ffd53de411433f1f43de2b4f644793528schwartz * workaround can break. Also, other PIL 15 interrupts besides the ones we are
69cd775ffd53de411433f1f43de2b4f644793528schwartz * enveloping could delay processing of the interrupt we are trying to protect.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc/*
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc * Set delay to 10 ms
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc */
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshcint pxtool_delay_usec = 10000;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/* Number of inos per root complex. */
69cd775ffd53de411433f1f43de2b4f644793528schwartzint pxtool_num_inos = INTERRUPT_MAPPING_ENTRIES;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/* Mechanism for getting offsets of smaller datatypes aligned in 64 bit long */
69cd775ffd53de411433f1f43de2b4f644793528schwartztypedef union {
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t u64;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint32_t u32;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint16_t u16;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint8_t u8;
69cd775ffd53de411433f1f43de2b4f644793528schwartz} peek_poke_value_t;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Safe C wrapper around assy language routine px_phys_peek_4u
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Type is TRUE for big endian, FALSE for little endian.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Size is 1, 2, 4 or 8 bytes.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * paddr is the physical address in IO space to access read.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * value_p is where the value is returned.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartzstatic int
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_safe_phys_peek(px_t *px_p, boolean_t type, size_t size, uint64_t paddr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t *value_p)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_pec_t *pec_p = px_p->px_pec_p;
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
69cd775ffd53de411433f1f43de2b4f644793528schwartz on_trap_data_t otd;
69cd775ffd53de411433f1f43de2b4f644793528schwartz peek_poke_value_t peek_value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz int err = DDI_SUCCESS;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz mutex_enter(&pec_p->pec_pokefault_mutex);
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_p->pcitool_addr = (caddr_t)(paddr & px_paddr_mask);
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Set up trap handling to make the access safe.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * on_trap works like setjmp.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Set it up to not panic on data access error,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * but to call peek_fault instead.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Call px_phys_peek_4u after trap handling is setup.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When on_trap returns FALSE, it has been setup.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When it returns TRUE, an it has caught an error.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (!on_trap(&otd, OT_DATA_ACCESS)) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz otd.ot_trampoline = (uintptr_t)&peek_fault;
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = px_phys_peek_4u(size, paddr, &peek_value.u64, type);
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = DDI_FAILURE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz no_trap();
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Workaround: delay taking down safe access env.
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc * For more info, see comments where pxtool_delay_usec is declared.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc if ((err == DDI_FAILURE) && (pxtool_delay_usec > 0))
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc delay(drv_usectohz(pxtool_delay_usec));
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_p->pcitool_addr = NULL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz mutex_exit(&pec_p->pec_pokefault_mutex);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (err != DDI_FAILURE) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz switch (size) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 8:
69cd775ffd53de411433f1f43de2b4f644793528schwartz *value_p = peek_value.u64;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 4:
69cd775ffd53de411433f1f43de2b4f644793528schwartz *value_p = (uint64_t)peek_value.u32;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 2:
69cd775ffd53de411433f1f43de2b4f644793528schwartz *value_p = (uint64_t)peek_value.u16;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 1:
69cd775ffd53de411433f1f43de2b4f644793528schwartz *value_p = (uint64_t)peek_value.u8;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz default:
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = DDI_FAILURE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (err);
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Safe C wrapper around assy language routine px_phys_poke_4u
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Type is TRUE for big endian, FALSE for little endian.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Size is 1,2,4 or 8 bytes.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * paddr is the physical address in IO space to access read.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * value contains the value to be written.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartzstatic int
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_safe_phys_poke(px_t *px_p, boolean_t type, size_t size, uint64_t paddr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t value)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
69cd775ffd53de411433f1f43de2b4f644793528schwartz on_trap_data_t otd;
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_pec_t *pec_p = px_p->px_pec_p;
69cd775ffd53de411433f1f43de2b4f644793528schwartz peek_poke_value_t poke_value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz int err = DDI_SUCCESS;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz switch (size) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 8:
69cd775ffd53de411433f1f43de2b4f644793528schwartz poke_value.u64 = value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 4:
69cd775ffd53de411433f1f43de2b4f644793528schwartz poke_value.u32 = (uint32_t)value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 2:
69cd775ffd53de411433f1f43de2b4f644793528schwartz poke_value.u16 = (uint16_t)value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz case 1:
69cd775ffd53de411433f1f43de2b4f644793528schwartz poke_value.u8 = (uint8_t)value;
69cd775ffd53de411433f1f43de2b4f644793528schwartz break;
69cd775ffd53de411433f1f43de2b4f644793528schwartz default:
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (DDI_FAILURE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz mutex_enter(&pec_p->pec_pokefault_mutex);
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_ontrap_data = &otd;
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_p->pcitool_addr = (caddr_t)(paddr & px_paddr_mask);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * on_trap works like setjmp.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Set it up to not panic on data access error,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * but to call poke_fault instead.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Call px_phys_poke_4u after trap handling is setup.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When on_trap returns FALSE, it has been setup.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When it returns TRUE, an it has caught an error.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (!on_trap(&otd, OT_DATA_ACCESS)) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz otd.ot_trampoline = (uintptr_t)&poke_fault;
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = px_phys_poke_4u(size, paddr, &poke_value.u64, type);
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = DDI_FAILURE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
bf8fc2340620695a402331e5da7c7db43264174det px_lib_clr_errs(px_p, 0, paddr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (otd.ot_trap & OT_DATA_ACCESS)
69cd775ffd53de411433f1f43de2b4f644793528schwartz err = DDI_FAILURE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Take down protected environment. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz no_trap();
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_ontrap_data = NULL;
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz /*
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * Workaround: delay taking down safe access env.
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc * For more info, see comments where pxtool_delay_usec is declared.
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz */
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc if (pxtool_delay_usec > 0)
d36395bddcd1364dbc22fee5c57e14997fe2bee8rameshc delay(drv_usectohz(pxtool_delay_usec));
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
f0a73f0415a4150b270534bc7ed2cbb77d87c5a2schwartz pxu_p->pcitool_addr = NULL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz mutex_exit(&pec_p->pec_pokefault_mutex);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (err);
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Wrapper around pxtool_safe_phys_peek/poke.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Validates arguments and calls pxtool_safe_phys_peek/poke appropriately.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Dip is of the nexus,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * phys_addr is the address to write in physical space.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * pcitool_status returns more detailed status in addition to a more generic
69cd775ffd53de411433f1f43de2b4f644793528schwartz * errno-style function return value.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * other args are self-explanatory.
69cd775ffd53de411433f1f43de2b4f644793528schwartz *
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz * This function assumes that offset, bdf, and acc_attr are current in
69cd775ffd53de411433f1f43de2b4f644793528schwartz * prg_p. It also assumes that prg_p->phys_addr is the final phys addr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * including offset.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * This function modifies prg_p status and data.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*ARGSUSED*/
69cd775ffd53de411433f1f43de2b4f644793528schwartzstatic int
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartzpxtool_access(px_t *px_p, pcitool_reg_t *prg_p, uint64_t *data_p,
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz boolean_t is_write)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
69cd775ffd53de411433f1f43de2b4f644793528schwartz dev_info_t *dip = px_p->px_dip;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t phys_addr = prg_p->phys_addr;
69cd775ffd53de411433f1f43de2b4f644793528schwartz boolean_t endian = PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz int rval = SUCCESS;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Alignment checking. Assumes base address is 8-byte aligned. */
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz if (!IS_P2ALIGNED(phys_addr, size)) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "not aligned.\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg_p->status = PCITOOL_NOT_ALIGNED;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = EINVAL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else if (is_write) { /* Made it through checks. Do the access. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_PHYS_ACC, dip,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "%d byte %s pxtool_safe_phys_poke at addr 0x%" PRIx64 "\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz size, (endian ? "BE" : "LE"), phys_addr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (pxtool_safe_phys_poke(px_p, endian, size, phys_addr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz *data_p) != DDI_SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_PHYS_ACC, dip,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "%d byte %s pxtool_safe_phys_poke at addr "
69cd775ffd53de411433f1f43de2b4f644793528schwartz "0x%" PRIx64 " failed\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz size, (endian ? "BE" : "LE"), phys_addr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg_p->status = PCITOOL_INVALID_ADDRESS;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = EFAULT;
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else { /* Read */
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_PHYS_ACC, dip,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "%d byte %s pxtool_safe_phys_peek at addr 0x%" PRIx64 "\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz size, (endian ? "BE" : "LE"), phys_addr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (pxtool_safe_phys_peek(px_p, endian, size, phys_addr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz data_p) != DDI_SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_PHYS_ACC, dip,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "%d byte %s pxtool_safe_phys_peek at addr "
69cd775ffd53de411433f1f43de2b4f644793528schwartz "0x%" PRIx64 " failed\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz size, (endian ? "BE" : "LE"), phys_addr);
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg_p->status = PCITOOL_INVALID_ADDRESS;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = EFAULT;
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (rval);
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartzint
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz uint64_t *data_p, boolean_t is_write)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz return (pxtool_access(px_p, prg_p, data_p, is_write));
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartzint
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartzpxtool_pciiomem_access(px_t *px_p, pcitool_reg_t *prg_p,
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t *data_p, boolean_t is_write)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz return (pxtool_access(px_p, prg_p, data_p, is_write));
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartzint
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_dev_reg_ops_platchk(dev_info_t *dip, pcitool_reg_t *prg_p)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
69cd775ffd53de411433f1f43de2b4f644793528schwartz /*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Guard against checking a root nexus which is empty.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * On some systems this will result in a Fatal Reset.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
1578c5210cc5a6709ee11c9693bb0a24ed8d38f8schwartz if (ddi_get_child(dip) == NULL) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "pxtool_dev_reg_ops set/get reg: nexus has no devs!\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg_p->status = PCITOOL_IO_ERROR;
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (ENXIO);
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (SUCCESS);
69cd775ffd53de411433f1f43de2b4f644793528schwartz}
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Perform register accesses on the nexus device itself.
69cd775ffd53de411433f1f43de2b4f644793528schwartz */
69cd775ffd53de411433f1f43de2b4f644793528schwartzint
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
69cd775ffd53de411433f1f43de2b4f644793528schwartz{
69cd775ffd53de411433f1f43de2b4f644793528schwartz pcitool_reg_t prg;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint64_t base_addr;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint32_t reglen;
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_t *px_p = DIP_TO_STATE(dip);
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_nexus_regspec_t *px_rp = NULL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint32_t numbanks = 0;
69cd775ffd53de411433f1f43de2b4f644793528schwartz boolean_t write_flag = B_FALSE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint32_t rval = 0;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (cmd == PCITOOL_NEXUS_SET_REG)
69cd775ffd53de411433f1f43de2b4f644793528schwartz write_flag = B_TRUE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops set/get reg\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Read data from userland. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t), mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz DDI_SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "Error reading arguments\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (EFAULT);
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Read reg property which contains starting addr and size of banks. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
69cd775ffd53de411433f1f43de2b4f644793528schwartz "reg", (int **)&px_rp, &reglen) == DDI_SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (((reglen * sizeof (int)) %
69cd775ffd53de411433f1f43de2b4f644793528schwartz sizeof (px_nexus_regspec_t)) != 0) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "reg prop not well-formed");
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg.status = PCITOOL_REGPROP_NOTWELLFORMED;
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = EIO;
69cd775ffd53de411433f1f43de2b4f644793528schwartz goto done;
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz numbanks = (reglen * sizeof (int)) / sizeof (px_nexus_regspec_t);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Bounds check the bank number. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (prg.barnum >= numbanks) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg.status = PCITOOL_OUT_OF_RANGE;
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = EINVAL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz goto done;
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz base_addr = px_rp[prg.barnum].phys_addr;
69cd775ffd53de411433f1f43de2b4f644793528schwartz prg.phys_addr = base_addr + prg.offset;
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops: nexus: base:0x%" PRIx64 ", "
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz "offset:0x%" PRIx64 ", addr:0x%" PRIx64 ", max_offset:"
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz "0x%" PRIx64 "\n",
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz base_addr, prg.offset, prg.phys_addr, px_rp[prg.barnum].size);
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz if (prg.offset >= px_rp[prg.barnum].size) {
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz prg.status = PCITOOL_OUT_OF_RANGE;
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz rval = EINVAL;
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz goto done;
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Access device. prg.status is modified. */
dabea0db6f27d1bf410afbc09b7dcec947a03164schwartz rval = pxtool_access(px_p, &prg, &prg.data, write_flag);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartzdone:
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_rp != NULL)
69cd775ffd53de411433f1f43de2b4f644793528schwartz ddi_prop_free(px_rp);
69cd775ffd53de411433f1f43de2b4f644793528schwartz
2917a9c9c3eee6fcaedb239f5f68da01f4ed0da9schwartz prg.drvr_version = PCITOOL_VERSION;
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t),
69cd775ffd53de411433f1f43de2b4f644793528schwartz mode) != DDI_SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "Copyout failed.\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (EFAULT);
69cd775ffd53de411433f1f43de2b4f644793528schwartz }
69cd775ffd53de411433f1f43de2b4f644793528schwartz
69cd775ffd53de411433f1f43de2b4f644793528schwartz return (rval);
69cd775ffd53de411433f1f43de2b4f644793528schwartz}