Example #1
0
static int
acebus_update_props(ebus_devstate_t *ebus_p)
{
	dev_info_t *dip = ebus_p->dip;
	struct ebus_pci_rangespec er[2], *erp;
	pci_regspec_t *pci_rp, *prp;
	int length, rnums, imask[3], i, found = 0;

	/*
	 * If "ranges" property is found, then the device is initialized
	 * by OBP, hence simply return.
	 * Otherwise we create all the properties here.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "ranges", (int **)&erp, (uint_t *)&length) == DDI_PROP_SUCCESS) {
		ddi_prop_free(erp);
		return (DDI_SUCCESS);
	}

	/*
	 * interrupt-map is the only property that comes from a .conf file.
	 * Since it doesn't have the nodeid field set, it must be done here.
	 * Other properties can come from OBP or created here.
	 */
	if (acebus_set_imap(dip) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	/*
	 * Create the "ranges" property.
	 * Ebus has BAR0 and BAR1 allocated (both in memory space).
	 * Other BARs are 0.
	 * Hence there are 2 memory ranges it operates in. (one for each BAR).
	 * ie. there are 2 entries in its ranges property.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "assigned-addresses",
	    (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not get assigned-addresses",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	/*
	 * Create the 1st mem range in which it operates corresponding
	 * to BAR0
	 */
	er[0].ebus_phys_hi = EBUS_CHILD_PHYS_LOW_RANGE;
	rnums = (length * sizeof (int))/sizeof (pci_regspec_t);
	for (i = 0; i < rnums; i++) {
		prp = pci_rp + i;
		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[0].ebus_phys_hi) {
			found = 1;
			break;
		}
	}
	if (!found) {
		cmn_err(CE_WARN, "No assigned space for memory range 0.");
		ddi_prop_free(pci_rp);
		return (DDI_FAILURE);
	}
	found = 0;
	er[0].ebus_phys_low = 0;
	er[0].pci_phys_hi = prp->pci_phys_hi;
	er[0].pci_phys_mid = prp->pci_phys_mid;
	er[0].pci_phys_low = prp->pci_phys_low;
	er[0].rng_size = prp->pci_size_low;

	/*
	 * Create the 2nd mem range in which it operates corresponding
	 * to BAR1
	 */
	er[1].ebus_phys_hi = EBUS_CHILD_PHYS_HI_RANGE;
	for (i = 0; i < rnums; i++) {
		prp = pci_rp + i;
		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[1].ebus_phys_hi) {
			found = 1;
			break;
		}
	}
	if (!found) {
		cmn_err(CE_WARN, "No assigned space for memory range 1.");
		ddi_prop_free(pci_rp);
		return (DDI_FAILURE);
	}
	er[1].ebus_phys_low = 0;
	er[1].pci_phys_hi = prp->pci_phys_hi;
	er[1].pci_phys_mid = prp->pci_phys_mid;
	er[1].pci_phys_low = prp->pci_phys_low;
	er[1].rng_size = prp->pci_size_low;

	ddi_prop_free(pci_rp);
	length = sizeof (er) / sizeof (int);
	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "ranges", (int *)er, length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not create ranges property",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	/* The following properties are as defined by PCI 1275 bindings. */
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#address-cells", 2) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#size-cells", 1) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#interrupt-cells", 1) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);

	imask[0] = 0x1f;
	imask[1] = 0x00ffffff;
	imask[2] = 0x00000003;
	length = sizeof (imask) / sizeof (int);
	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "interrupt-map-mask", (int *)imask, length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not update imap mask property",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}

	return (DDI_SUCCESS);
}
/*
 * Solaris version
 */
static int
pci_device_solx_devfs_probe( struct pci_device * dev )
{
    int err = 0;
    di_node_t rnode = DI_NODE_NIL;
    i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
    int *regbuf;
    pci_regspec_t *reg;
    int i;
    int len = 0;
    uint ent = 0;
    nexus_t *nexus;

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

    /*
     * starting to find if it is MEM/MEM64/IO
     * using libdevinfo
     */
    if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
	err = errno;
	(void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
    } else {
	args.bus = dev->bus;
	args.dev = dev->dev;
	args.func = dev->func;
	(void) di_walk_node(rnode, DI_WALK_CLDFIRST,
		(void *)&args, find_target_node);
    }

    if (args.node != DI_NODE_NIL) {
#ifdef __sparc
	di_minor_t minor;
#endif

#ifdef __sparc
	if (minor = di_minor_next(args.node, DI_MINOR_NIL))
	    MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor);
	else
	    MAPPING_DEV_PATH(dev) = NULL;
#endif

	/*
	 * It will succeed for sure, because it was
	 * successfully called in find_target_node
	 */
	len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
				  "assigned-addresses",
				  &regbuf);

#ifdef __sparc
	if ((len <= 0) && di_phdl) {
	    len = di_prom_prop_lookup_ints(di_phdl, args.node,
				"assigned-addresses", &regbuf);
	}
#endif
    }

    if (len <= 0)
	goto cleanup;


    /*
     * how to find the size of rom???
     * if the device has expansion rom,
     * it must be listed in the last
     * cells because solaris find probe
     * the base address from offset 0x10
     * to 0x30h. So only check the last
     * item.
     */
    reg = (pci_regspec_t *)&regbuf[len - CELL_NUMS_1275];
    if (PCI_REG_REG_G(reg->pci_phys_hi) == PCI_CONF_ROM) {
	/*
	 * rom can only be 32 bits
	 */
	dev->rom_size = reg->pci_size_low;
	len = len - CELL_NUMS_1275;
    }
    else {
	/*
	 * size default to 64K and base address
	 * default to 0xC0000
	 */
	dev->rom_size = 0x10000;
    }

    /*
     * Solaris has its own BAR index.
     * Linux give two region slot for 64 bit address.
     */
    for (i = 0; i < len; i = i + CELL_NUMS_1275) {

	reg = (pci_regspec_t *)&regbuf[i];
	ent = reg->pci_phys_hi & 0xff;
	/*
	 * G35 broken in BAR0
	 */
	ent = (ent - PCI_CONF_BASE0) >> 2;
	if (ent >= 6) {
	    fprintf(stderr, "error ent = %d\n", ent);
	    break;
	}

	/*
	 * non relocatable resource is excluded
	 * such like 0xa0000, 0x3b0. If it is met,
	 * the loop is broken;
	 */
	if (!PCI_REG_REG_G(reg->pci_phys_hi))
	    break;

	if (reg->pci_phys_hi & PCI_PREFETCH_B) {
	    dev->regions[ent].is_prefetchable = 1;
	}


	/*
	 * We split the shift count 32 into two 16 to
	 * avoid the complaining of the compiler
	 */
	dev->regions[ent].base_addr = reg->pci_phys_low +
	    ((reg->pci_phys_mid << 16) << 16);
	dev->regions[ent].size = reg->pci_size_low +
	    ((reg->pci_size_hi << 16) << 16);

	switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
	    case PCI_ADDR_IO:
		dev->regions[ent].is_IO = 1;
		break;
	    case PCI_ADDR_MEM32:
		break;
	    case PCI_ADDR_MEM64:
		dev->regions[ent].is_64 = 1;
		/*
		 * Skip one slot for 64 bit address
		 */
		break;
	}
    }

  cleanup:
    if (rnode != DI_NODE_NIL) {
	di_fini(rnode);
    }
    return (err);
}