Example #1
0
/*ARGSUSED*/
static int
pxtool_access(px_t *px_p, pcitool_reg_t *prg_p, uint64_t *data_p,
    boolean_t is_write)
{
	dev_info_t *dip = px_p->px_dip;
	uint64_t phys_addr = prg_p->phys_addr;
	boolean_t endian = PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr);
	size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr);
	int rval = SUCCESS;

	/* Alignment checking.  Assumes base address is 8-byte aligned. */
	if (!IS_P2ALIGNED(phys_addr, size)) {
		DBG(DBG_TOOLS, dip, "not aligned.\n");
		prg_p->status = PCITOOL_NOT_ALIGNED;

		rval = EINVAL;

	} else if (is_write) {	/* Made it through checks.  Do the access. */

		DBG(DBG_PHYS_ACC, dip,
		    "%d byte %s pxtool_safe_phys_poke at addr 0x%" PRIx64 "\n",
		    size, (endian ? "BE" : "LE"), phys_addr);

		if (pxtool_safe_phys_poke(px_p, endian, size, phys_addr,
		    *data_p) != DDI_SUCCESS) {
			DBG(DBG_PHYS_ACC, dip,
			    "%d byte %s pxtool_safe_phys_poke at addr "
			    "0x%" PRIx64 " failed\n",
			    size, (endian ? "BE" : "LE"), phys_addr);
			prg_p->status = PCITOOL_INVALID_ADDRESS;

			rval = EFAULT;
		}

	} else {	/* Read */

		DBG(DBG_PHYS_ACC, dip,
		    "%d byte %s pxtool_safe_phys_peek at addr 0x%" PRIx64 "\n",
		    size, (endian ? "BE" : "LE"), phys_addr);

		if (pxtool_safe_phys_peek(px_p, endian, size, phys_addr,
		    data_p) != DDI_SUCCESS) {
			DBG(DBG_PHYS_ACC, dip,
			    "%d byte %s pxtool_safe_phys_peek at addr "
			    "0x%" PRIx64 " failed\n",
			    size, (endian ? "BE" : "LE"), phys_addr);
			prg_p->status = PCITOOL_INVALID_ADDRESS;

			rval = EFAULT;
		}
	}
	return (rval);
}
Example #2
0
/*
 * Perform register accesses on the nexus device itself.
 */
int
pxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
{

	pcitool_reg_t		prg;
	size_t			size;
	px_t			*px_p = DIP_TO_STATE(dip);
	boolean_t		is_write = B_FALSE;
	uint32_t		rval = 0;

	if (cmd == PCITOOL_NEXUS_SET_REG)
		is_write = B_TRUE;

	DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops set/get reg\n");

	/* Read data from userland. */
	if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t),
	    mode) != DDI_SUCCESS) {
		DBG(DBG_TOOLS, dip, "Error reading arguments\n");
		return (EFAULT);
	}

	size = PCITOOL_ACC_ATTR_SIZE(prg.acc_attr);

	DBG(DBG_TOOLS, dip, "raw bus:0x%x, dev:0x%x, func:0x%x\n",
	    prg.bus_no, prg.dev_no, prg.func_no);
	DBG(DBG_TOOLS, dip, "barnum:0x%x, offset:0x%" PRIx64 ", acc:0x%x\n",
	    prg.barnum, prg.offset, prg.acc_attr);
	DBG(DBG_TOOLS, dip, "data:0x%" PRIx64 ", phys_addr:0x%" PRIx64 "\n",
	    prg.data, prg.phys_addr);

	/*
	 * If bank num == ff, base phys addr passed in from userland.
	 *
	 * Normal bank specification is invalid, as there is no OBP property to
	 * back it up.
	 */
	if (prg.barnum != PCITOOL_BASE) {
		prg.status = PCITOOL_OUT_OF_RANGE;
		rval = EINVAL;
		goto done;
	}

	/* Allow only size of 8-bytes. */
	if (size != sizeof (uint64_t)) {
		prg.status = PCITOOL_INVALID_SIZE;
		rval = EINVAL;
		goto done;
	}

	/* Alignment checking. */
	if (!IS_P2ALIGNED(prg.offset, size)) {
		DBG(DBG_TOOLS, dip, "not aligned.\n");
		prg.status = PCITOOL_NOT_ALIGNED;
		rval = EINVAL;
		goto done;
	}

	prg.phys_addr += prg.offset;

	/*
	 * Only the hypervisor can access nexus registers.  As a result, there
	 * can be no error recovery in the OS.  If there is an error, the
	 * system will go down, but with a trap type 7f.  The OS cannot
	 * intervene with this kind of trap.
	 */

	/* Access device.  prg.status is modified. */
	rval = pxtool_phys_access(px_p, prg.phys_addr, &prg.data,
	    PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr), is_write);
done:
	prg.drvr_version = PCITOOL_VERSION;
	if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t),
	    mode) != DDI_SUCCESS) {
		DBG(DBG_TOOLS, dip, "Copyout failed.\n");
		return (EFAULT);
	}

	return (rval);
}
Example #3
0
/*
 * This function is for PCI IO space and memory space access.
 * It assumes that offset, bdf, acc_attr are current in prg_p.
 * It assumes that prg_p->phys_addr is the final phys addr (including offset).
 * This function modifies prg_p status and data.
 */
int
pxtool_pciiomem_access(px_t *px_p, pcitool_reg_t *prg_p,
    uint64_t *data_p, boolean_t is_write)
{
	on_trap_data_t otd;
	uint32_t io_stat = 0;
	dev_info_t *dip = px_p->px_dip;
	px_pec_t *pec_p = px_p->px_pec_p;
	size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr);
	int rval = 0;

	/* Alignment checking. */
	if (!IS_P2ALIGNED(prg_p->offset, size)) {
		DBG(DBG_TOOLS, dip, "not aligned.\n");
		prg_p->status = PCITOOL_NOT_ALIGNED;
		return (EINVAL);
	}

	mutex_enter(&pec_p->pec_pokefault_mutex);
	pec_p->pec_ontrap_data = &otd;

	if (is_write) {
		pci_device_t bdf = PX_GET_BDF(prg_p);

		if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
			*data_p = pxtool_swap_endian(*data_p, size);

		pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;

		if (!on_trap(&otd, OT_DATA_ACCESS)) {
			otd.ot_trampoline = (uintptr_t)&poke_fault;
			rval = hvio_poke(px_p->px_dev_hdl, prg_p->phys_addr,
			    size, *data_p, bdf, &io_stat);
		} else
			rval = H_EIO;

		if (otd.ot_trap & OT_DATA_ACCESS)
			rval = H_EIO;

		DBG(DBG_TOOLS, dip, "iomem:phys_addr:0x%" PRIx64 ", bdf:0x%x, "
		    "rval:%d, io_stat:%d\n", prg_p->phys_addr, bdf,
		    rval, io_stat);
	} else {

		*data_p = 0;

		pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;

		if (!on_trap(&otd, OT_DATA_ACCESS)) {
			otd.ot_trampoline = (uintptr_t)&peek_fault;
			rval = hvio_peek(px_p->px_dev_hdl, prg_p->phys_addr,
			    size, &io_stat, data_p);
		} else
			rval = H_EIO;

		DBG(DBG_TOOLS, dip, "iomem:phys_addr:0x%" PRIx64 ", "
		    "size:0x%" PRIx64 ", hdl:0x%" PRIx64 ", "
		    "rval:%d, io_stat:%d\n", prg_p->phys_addr,
		    size, px_p->px_dev_hdl, rval, io_stat);
		DBG(DBG_TOOLS, dip, "read data:0x%" PRIx64 "\n", *data_p);

		if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
			*data_p = pxtool_swap_endian(*data_p, size);
	}

	/*
	 * Workaround: delay taking down safe access env.
	 * For more info, see comment where pxtool_iomem_delay_usec is declared.
	 */
	if (pxtool_iomem_delay_usec > 0)
		delay(drv_usectohz(pxtool_iomem_delay_usec));

	no_trap();
	pec_p->pec_ontrap_data = NULL;
	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
	mutex_exit(&pec_p->pec_pokefault_mutex);

	if (rval != SUCCESS) {
		prg_p->status = PCITOOL_INVALID_ADDRESS;
		rval = EINVAL;
	} else if (io_stat != SUCCESS) {
		prg_p->status = PCITOOL_IO_ERROR;
		rval = EIO;
	} else
		prg_p->status = PCITOOL_SUCCESS;

	return (rval);
}
Example #4
0
int
pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p,
    uint64_t *data_p, boolean_t is_write)
{
	pci_cfg_data_t data;
	on_trap_data_t otd;
	dev_info_t *dip = px_p->px_dip;
	px_pec_t *pec_p = px_p->px_pec_p;
	size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr);
	int rval = 0;
	pci_cfgacc_req_t req;

	if ((size <= 0) || (size > 8)) {
		DBG(DBG_TOOLS, dip, "not supported size.\n");
		prg_p->status = PCITOOL_INVALID_SIZE;
		return (ENOTSUP);
	}

	/* Alignment checking. */
	if (!IS_P2ALIGNED(prg_p->offset, size)) {
		DBG(DBG_TOOLS, dip, "not aligned.\n");
		prg_p->status = PCITOOL_NOT_ALIGNED;
		return (EINVAL);
	}

	mutex_enter(&pec_p->pec_pokefault_mutex);
	pec_p->pec_ontrap_data = &otd;

	req.rcdip = dip;
	req.bdf = PCI_GETBDF(prg_p->bus_no, prg_p->dev_no, prg_p->func_no);
	req.offset = prg_p->offset;
	req.size = size;
	req.write = is_write;
	if (is_write) {

		if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
			data.qw = pxtool_swap_endian(*data_p, size);
		else
			data.qw = *data_p;

		switch (size) {
			case sizeof (uint8_t):
				data.b = (uint8_t)data.qw;
				break;
			case sizeof (uint16_t):
				data.w = (uint16_t)data.qw;
				break;
			case sizeof (uint32_t):
				data.dw = (uint32_t)data.qw;
				break;
			case sizeof (uint64_t):
				break;
		}

		DBG(DBG_TOOLS, dip, "put: bdf:%d,%d,%d, off:0x%"PRIx64", size:"
		    "0x%"PRIx64", data:0x%"PRIx64"\n",
		    prg_p->bus_no, prg_p->dev_no, prg_p->func_no,
		    prg_p->offset, size, data.qw);

		pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;

		if (!on_trap(&otd, OT_DATA_ACCESS)) {
			otd.ot_trampoline = (uintptr_t)&poke_fault;
			VAL64(&req) = data.qw;
			pci_cfgacc_acc(&req);
		} else
			rval = H_EIO;

		if (otd.ot_trap & OT_DATA_ACCESS)
			rval = H_EIO;

	} else {

		data.qw = 0;

		pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;

		if (!on_trap(&otd, OT_DATA_ACCESS)) {
			otd.ot_trampoline = (uintptr_t)&peek_fault;
			pci_cfgacc_acc(&req);
			data.qw = VAL64(&req);
		} else
			rval = H_EIO;

		switch (size) {
			case sizeof (uint8_t):
				data.qw = (uint64_t)data.b;
				break;
			case sizeof (uint16_t):
				data.qw = (uint64_t)data.w;
				break;
			case sizeof (uint32_t):
				data.qw = (uint64_t)data.dw;
				break;
			case sizeof (uint64_t):
				break;
		}

		DBG(DBG_TOOLS, dip, "get: bdf:%d,%d,%d, off:0x%"PRIx64", size:"
		    "0x%"PRIx64", data:0x%"PRIx64"\n",
		    prg_p->bus_no, prg_p->dev_no, prg_p->func_no,
		    prg_p->offset, size, data.qw);
		*data_p = data.qw;

		if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr))
			*data_p = pxtool_swap_endian(*data_p, size);
	}

	/*
	 * Workaround: delay taking down safe access env.
	 * For more info, see comments where pxtool_cfg_delay_usec is declared.
	 */
	if (pxtool_cfg_delay_usec > 0)
		drv_usecwait(pxtool_cfg_delay_usec);

	no_trap();
	pec_p->pec_ontrap_data = NULL;
	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
	mutex_exit(&pec_p->pec_pokefault_mutex);

	if (rval != SUCCESS) {
		prg_p->status = PCITOOL_INVALID_ADDRESS;
		rval = EINVAL;
	} else
		prg_p->status = PCITOOL_SUCCESS;

	return (rval);
}
/*
 * Solaris version: read the VGA ROM data
 */
static int
pci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer )
{
    int err;
    struct pci_device_mapping prom = {
	.base = 0xC0000,
	.size = dev->rom_size,
	.flags = 0
    };

    err = pci_device_solx_devfs_map_range(dev, &prom);
    if (err == 0) {
	(void) bcopy(prom.memory, buffer, dev->rom_size);

	if (munmap(prom.memory, dev->rom_size) == -1) {
	    err = errno;
	}
    }
    return err;
}

/*
 * solaris version: Read the configurations space of the devices
 */
static int
pci_device_solx_devfs_read( struct pci_device * dev, void * data,
			     pciaddr_t offset, pciaddr_t size,
			     pciaddr_t * bytes_read )
{
    pcitool_reg_t cfg_prg;
    int err = 0;
    int i = 0;
    nexus_t *nexus;

#ifdef __sparc
    nexus = find_nexus_for_dev(dev);
#else
    nexus = find_nexus_for_bus(dev->domain, dev->bus);
#endif

    *bytes_read = 0;

    if ( nexus == NULL ) {
	return ENODEV;
    }

    cfg_prg.offset = offset;
    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
    cfg_prg.bus_no = dev->bus;
    cfg_prg.dev_no = dev->dev;
    cfg_prg.func_no = dev->func;
    cfg_prg.barnum = 0;
    cfg_prg.user_version = PCITOOL_USER_VERSION;

    for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1))
    {
	cfg_prg.offset = offset + i;

	if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
	    fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n",
		    nexus->path,
		    cfg_prg.bus_no,
		    cfg_prg.dev_no,
		    cfg_prg.func_no,
		    cfg_prg.offset);
	    fprintf(stderr, "Failure cause = %x\n", err);
	    break;
	}

	((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
	/*
	 * DWORDS Offset or bytes Offset ??
	 */
    }
    *bytes_read = i;

    return (err);
}