示例#1
0
/*
 * Save the configuration registers for cdip as a property
 * so that it persists after detach/uninitchild.
 */
int
pci_save_config_regs(dev_info_t *dip)
{
	ddi_acc_handle_t confhdl;
	pci_config_header_state_t *chsp;
	pci_cap_save_desc_t *pci_cap_descp;
	int ret;
	uint32_t i, ncaps, nwords;
	uint32_t *regbuf, *p;
	uint8_t *maskbuf;
	size_t maskbufsz, regbufsz, capbufsz;
	ddi_acc_hdl_t *hp;
	off_t offset = 0;
	uint8_t cap_ptr, cap_id;
	int pcie = 0;
	PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip),
	    ddi_get_instance(dip)))

	if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) {
		cmn_err(CE_WARN, "%s%d can't get config handle",
		    ddi_driver_name(dip), ddi_get_instance(dip));

		return (DDI_FAILURE);
	}
	/*
	 * Determine if it is a pci express device. If it is, save entire
	 * 4k config space treating it as a array of 32 bit integers.
	 * If it is not, do it in a usual PCI way.
	 */
	cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR);
	/*
	 * Walk the capabilities searching for pci express capability
	 */
	while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
		cap_id = pci_config_get8(confhdl,
		    cap_ptr + PCI_CAP_ID);
		if (cap_id == PCI_CAP_ID_PCI_E) {
			pcie = 1;
			break;
		}
		cap_ptr = pci_config_get8(confhdl,
		    cap_ptr + PCI_CAP_NEXT_PTR);
	}

	if (pcie) {
		/* PCI express device. Can have data in all 4k space */
		regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE,
		    KM_SLEEP);
		p = regbuf;
		/*
		 * Allocate space for mask.
		 * mask size is 128 bytes (4096 / 4 / 8 )
		 */
		maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >>
		    INDEX_SHIFT);
		maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP);
		hp = impl_acc_hdl_get(confhdl);
		for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) {
			if (ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset),
			    (int32_t *)p) == DDI_SUCCESS) {
				/* it is readable register. set the bit */
				maskbuf[i >> INDEX_SHIFT] |=
				    (uint8_t)(1 << (i & BITMASK));
			}
			p++;
			offset += sizeof (uint32_t);
		}

		if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
		    SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf,
		    maskbufsz)) != DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN, "couldn't create %s property while"
			    "saving config space for %s@%d\n",
			    SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip),
			    ddi_get_instance(dip));
		} else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE,
		    dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf,
		    (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) {
			(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
			    SAVED_CONFIG_REGS_MASK);
			cmn_err(CE_WARN, "%s%d can't update prop %s",
			    ddi_driver_name(dip), ddi_get_instance(dip),
			    SAVED_CONFIG_REGS);
		}

		kmem_free(maskbuf, (size_t)maskbufsz);
		kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE);
	} else {
示例#2
0
static int
gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
{
	size_t len;
	caddr_t virt;
	int error = 0;
	uint64_t x;
	uint32_t l;
	uint16_t w;
	uint8_t b;
	char *name = fc_cell2ptr(cp->svc_name);
	struct fc_resource *ip;

	if (fc_cell2int(cp->nargs) != 1)
		return (fc_syntax_error(cp, "nargs must be 1"));

	if (fc_cell2int(cp->nresults) < 1)
		return (fc_syntax_error(cp, "nresults must be >= 1"));

	virt = fc_cell2ptr(fc_arg(cp, 0));

	/*
	 * Determine the access width .. we can switch on the 2nd
	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
	 */
	switch (*(name + 1)) {
	case 'x':	len = sizeof (x); break;
	case 'l':	len = sizeof (l); break;
	case 'w':	len = sizeof (w); break;
	case 'b':	len = sizeof (b); break;
	}

	/*
	 * Check the alignment ...
	 */
	if (((intptr_t)virt & (len - 1)) != 0)
		return (fc_priv_error(cp, "unaligned access"));

	/*
	 * Find if this virt is 'within' a request we know about
	 */
	fc_lock_resource_list(rp);
	for (ip = rp->head; ip != NULL; ip = ip->next) {
		if (ip->type == RT_MAP) {
		    if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
			((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
				break;
		} else if (ip->type == RT_CONTIGIOUS) {
		    if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
			<= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
				break;
		}
	}
	fc_unlock_resource_list(rp);

	if (ip == NULL) {
		return (fc_priv_error(cp, "request not within a "
		    "known mapping or contigious adddress"));
	}

	switch (len) {
	case sizeof (x):
		if (ip->type == RT_MAP)
		    error = ddi_peek64(rp->child,
			(int64_t *)virt, (int64_t *)&x);
		else /* RT_CONTIGIOUS */
		    x = *(int64_t *)virt;
		break;
	case sizeof (l):
		if (ip->type == RT_MAP)
		    error = ddi_peek32(rp->child,
			(int32_t *)virt, (int32_t *)&l);
		else /* RT_CONTIGIOUS */
		    l = *(int32_t *)virt;
		break;
	case sizeof (w):
		if (ip->type == RT_MAP)
		    error = ddi_peek16(rp->child,
			(int16_t *)virt, (int16_t *)&w);
		else /* RT_CONTIGIOUS */
		    w = *(int16_t *)virt;
		break;
	case sizeof (b):
		if (ip->type == RT_MAP)
		    error = ddi_peek8(rp->child,
			(int8_t *)virt, (int8_t *)&b);
		else /* RT_CONTIGIOUS */
		    b = *(int8_t *)virt;
		break;
	}

	if (error) {
		FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error "
		    "accessing virt %p len %d\n", virt, len);
		return (fc_priv_error(cp, "access error"));
	}

	cp->nresults = fc_int2cell(1);
	switch (len) {
	case sizeof (x): fc_result(cp, 0) = x; break;
	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
	}
	return (fc_success_op(ap, rp, cp));
}