コード例 #1
0
ファイル: ofw_pci.c プロジェクト: ngkaho1234/freebsd
static int
ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
{
	struct ofw_pci_softc *sc;
	struct ofw_pci_register reg;
	uint32_t pintr, mintr[2];
	int intrcells;
	phandle_t iparent;

	sc = device_get_softc(bus);
	pintr = pin;

	/* Fabricate imap information in case this isn't an OFW device */
	bzero(&reg, sizeof(reg));
	reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
	    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
	    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);

	intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
	    &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
	    mintr, sizeof(mintr), &iparent);
	if (intrcells) {
		pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
		return (pintr);
	}

	/* Maybe it's a real interrupt, not an intpin */
	if (pin > 4)
		return (pin);

	device_printf(bus, "could not route pin %d for device %d.%d\n",
	    pin, pci_get_slot(dev), pci_get_function(dev));
	return (PCI_INVALID_IRQ);
}
コード例 #2
0
ファイル: opal_dev.c プロジェクト: derekmarcotte/freebsd
static int
opaldev_probe(device_t dev)
{
	phandle_t iparent;
	pcell_t *irqs;
	int i, n_irqs;

	if (!ofw_bus_is_compatible(dev, "ibm,opal-v3"))
		return (ENXIO);
	if (opal_check() != 0)
		return (ENXIO);

	device_set_desc(dev, "OPAL Abstraction Firmware");

	/* Manually add IRQs before attaching */
	if (OF_hasprop(ofw_bus_get_node(dev), "opal-interrupts")) {
		iparent = OF_finddevice("/interrupt-controller@0");
		iparent = OF_xref_from_node(iparent);

		n_irqs = OF_getproplen(ofw_bus_get_node(dev),
                    "opal-interrupts") / sizeof(*irqs);
		irqs = malloc(n_irqs * sizeof(*irqs), M_DEVBUF, M_WAITOK);
		OF_getencprop(ofw_bus_get_node(dev), "opal-interrupts", irqs,
		    n_irqs * sizeof(*irqs));
		for (i = 0; i < n_irqs; i++)
			bus_set_resource(dev, SYS_RES_IRQ, i,
			    ofw_bus_map_intr(dev, iparent, 1, &irqs[i]), 1);
		free(irqs, M_DEVBUF);
	}


	return (BUS_PROBE_SPECIFIC);
}
コード例 #3
0
static int 
vdevice_attach(device_t dev) 
{
	phandle_t root, child;
	device_t cdev;
	int icells, i, nintr, *intr;
	phandle_t iparent;
	struct vdevice_devinfo *dinfo;

	root = ofw_bus_get_node(dev);

	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);

                if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo,
		    child) != 0) {
                        free(dinfo, M_DEVBUF);
                        continue;
                }
		resource_list_init(&dinfo->mdi_resources);

		if (OF_searchprop(child, "#interrupt-cells", &icells,
		    sizeof(icells)) <= 0)
			icells = 2;
		if (OF_getprop(child, "interrupt-parent", &iparent,
		    sizeof(iparent)) <= 0)
			iparent = -1;
		nintr = OF_getprop_alloc(child, "interrupts", sizeof(*intr),
		    (void **)&intr);
		if (nintr > 0) {
			for (i = 0; i < nintr; i += icells) {
				u_int irq = intr[i];
				if (iparent != -1)
					irq = ofw_bus_map_intr(dev, iparent,
					    icells, &intr[i]);

				resource_list_add(&dinfo->mdi_resources,
				    SYS_RES_IRQ, i, irq, irq, i);
			}
		}

                cdev = device_add_child(dev, NULL, -1);
                if (cdev == NULL) {
                        device_printf(dev, "<%s>: device_add_child failed\n",
                            dinfo->mdi_obdinfo.obd_name);
                        ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
                        free(dinfo, M_DEVBUF);
                        continue;
                }
		device_set_ivars(cdev, dinfo);
	}

	return (bus_generic_attach(dev));
}
コード例 #4
0
ファイル: ofw_pcib_pci.c プロジェクト: genba/freebsd
static int
ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
{
	struct ofw_pcib_softc *sc;
	struct ofw_bus_iinfo *ii;
	struct ofw_pci_register reg;
	cell_t pintr, mintr;
	phandle_t iparent;
	uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];

	sc = device_get_softc(bridge);
	ii = &sc->ops_iinfo;
	if (ii->opi_imapsz > 0) {
		pintr = intpin;

		/* Fabricate imap information if this isn't an OFW device */
		bzero(&reg, sizeof(reg));
		reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
		    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
		    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);

		if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, &reg,
		    sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
		    &iparent, maskbuf)) {
			/*
			 * If we've found a mapping, return it and don't map
			 * it again on higher levels - that causes problems
			 * in some cases, and never seems to be required.
			 */
			return (ofw_bus_map_intr(dev, iparent, mintr));
		}
	} else if (intpin >= 1 && intpin <= 4) {
		/*
		 * When an interrupt map is missing, we need to do the
		 * standard PCI swizzle and continue mapping at the parent.
		 */
		return (pcib_route_interrupt(bridge, dev, intpin));
	}
	return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent(
	    bridge)), bridge, intpin));
}
コード例 #5
0
ファイル: ofw_bus_subr.c プロジェクト: cyrilmagsuci/freebsd
int
ofw_bus_intr_to_rl(device_t dev, phandle_t node,
    struct resource_list *rl, int *rlen)
{
	phandle_t iparent;
	uint32_t icells, *intr;
	int err, i, irqnum, nintr, rid;
	boolean_t extended;

	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
	    (void **)&intr);
	if (nintr > 0) {
		iparent = ofw_bus_find_iparent(node);
		if (iparent == 0) {
			device_printf(dev, "No interrupt-parent found, "
			    "assuming direct parent\n");
			iparent = OF_parent(node);
			iparent = OF_xref_from_node(iparent);
		}
		if (OF_searchencprop(OF_node_from_xref(iparent), 
		    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
			device_printf(dev, "Missing #interrupt-cells "
			    "property, assuming <1>\n");
			icells = 1;
		}
		if (icells < 1 || icells > nintr) {
			device_printf(dev, "Invalid #interrupt-cells property "
			    "value <%d>, assuming <1>\n", icells);
			icells = 1;
		}
		extended = false;
	} else {
		nintr = OF_getencprop_alloc(node, "interrupts-extended",
		    sizeof(*intr), (void **)&intr);
		if (nintr <= 0)
			return (0);
		extended = true;
	}
	err = 0;
	rid = 0;
	for (i = 0; i < nintr; i += icells) {
		if (extended) {
			iparent = intr[i++];
			if (OF_searchencprop(OF_node_from_xref(iparent), 
			    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
				device_printf(dev, "Missing #interrupt-cells "
				    "property\n");
				err = ENOENT;
				break;
			}
			if (icells < 1 || (i + icells) > nintr) {
				device_printf(dev, "Invalid #interrupt-cells "
				    "property value <%d>\n", icells);
				err = ERANGE;
				break;
			}
		}
		irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
		resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
	}
	if (rlen != NULL)
		*rlen = rid;
	free(intr, M_OFWPROP);
	return (err);
}
コード例 #6
0
ファイル: ofw_pcibus.c プロジェクト: fengsi/freebsd
static int
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
{
	ofw_pci_intr_t intr[2];
	phandle_t node, iparent;
	int isz, icells;

	node = ofw_bus_get_node(child);

	if (node == -1) {
		/* Non-firmware enumerated child, use standard routing */
	
		intr[0] = pci_get_intpin(child);
		return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, 
		    intr[0]));
	}
	
	/*
	 * Try to determine the node's interrupt parent so we know which
	 * PIC to use.
	 */

	iparent = -1;
	if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
		iparent = -1;
	icells = 1;
	if (iparent != -1)
		OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells",
		    &icells, sizeof(icells));
	
	/*
	 * Any AAPL,interrupts property gets priority and is
	 * fully specified (i.e. does not need routing)
	 */

	isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr));
	if (isz == sizeof(intr[0])*icells)
		return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev,
		    iparent, icells, intr));

	isz = OF_getprop(node, "interrupts", intr, sizeof(intr));
	if (isz == sizeof(intr[0])*icells) {
		if (iparent != -1)
			intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr);
	} else {
		/* No property: our best guess is the intpin. */
		intr[0] = pci_get_intpin(child);
	}
	
	/*
	 * If we got intr from a property, it may or may not be an intpin.
	 * For on-board devices, it frequently is not, and is completely out
	 * of the valid intpin range.  For PCI slots, it hopefully is,
	 * otherwise we will have trouble interfacing with non-OFW buses
	 * such as cardbus.
	 * Since we cannot tell which it is without violating layering, we
	 * will always use the route_interrupt method, and treat exceptions
	 * on the level they become apparent.
	 */
	return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0]));
}
コード例 #7
0
ファイル: ofwbus.c プロジェクト: ChristosKa/freebsd
static struct ofwbus_devinfo *
ofwbus_setup_dinfo(device_t dev, phandle_t node)
{
	struct ofwbus_softc *sc;
	struct ofwbus_devinfo *ndi;
	uint32_t *reg, *intr, icells;
	uint64_t phys, size;
	phandle_t iparent;
	int i, j;
	int nintr;
	int nreg;

	sc = device_get_softc(dev);

	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
	if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) {
		free(ndi, M_DEVBUF);
		return (NULL);
	}
	if (OFWBUS_EXCLUDED(ndi->ndi_obdinfo.obd_name,
	    ndi->ndi_obdinfo.obd_type)) {
		ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo);
		free(ndi, M_DEVBUF);
		return (NULL);
	}

	resource_list_init(&ndi->ndi_rl);
	nreg = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
	if (nreg == -1)
		nreg = 0;
	if (nreg % (sc->acells + sc->scells) != 0) {
		if (bootverbose)
			device_printf(dev, "Malformed reg property on <%s>\n",
			    ndi->ndi_obdinfo.obd_name);
		nreg = 0;
	}

	for (i = 0; i < nreg; i += sc->acells + sc->scells) {
		phys = size = 0;
		for (j = 0; j < sc->acells; j++) {
			phys <<= 32;
			phys |= reg[i + j];
		}
		for (j = 0; j < sc->scells; j++) {
			size <<= 32;
			size |= reg[i + sc->acells + j];
		}
		/* Skip the dummy reg property of glue devices like ssm(4). */
		if (size != 0)
			resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i,
			    phys, phys + size - 1, size);
	}
	free(reg, M_OFWPROP);

	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
	    (void **)&intr);
	if (nintr > 0) {
		iparent = 0;
		OF_searchencprop(node, "interrupt-parent", &iparent,
		    sizeof(iparent));
		OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells",
		    &icells, sizeof(icells));
		for (i = 0; i < nintr; i+= icells) {
			intr[i] = ofw_bus_map_intr(dev, iparent, icells,
			    &intr[i]);
			resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i],
			    intr[i], 1);
		}
		free(intr, M_OFWPROP);
	}

	return (ndi);
}
コード例 #8
0
ファイル: ofw_pcibus.c プロジェクト: ChristosKa/freebsd
static void
ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
{
	device_t pcib;
	struct ofw_pci_register pcir;
	struct ofw_pcibus_devinfo *dinfo;
	phandle_t node, child;
	u_int func, slot;
	int intline;

	pcib = device_get_parent(dev);
	node = ofw_bus_get_node(dev);

	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
			continue;
		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);

		/* Some OFW device trees contain dupes. */
		if (pci_find_dbsf(domain, busno, slot, func) != NULL)
			continue;

		/*
		 * The preset in the intline register is usually bogus.  Reset
		 * it such that the PCI code will reroute the interrupt if
		 * needed.
		 */

		intline = PCI_INVALID_IRQ;
		if (OF_getproplen(child, "interrupts") > 0)
			intline = 0;
		PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE,
		    intline, 1);

		/*
		 * Now set up the PCI and OFW bus layer devinfo and add it
		 * to the PCI bus.
		 */

		dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
		    domain, busno, slot, func, sizeof(*dinfo));
		if (dinfo == NULL)
			continue;
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			pci_freecfg((struct pci_devinfo *)dinfo);
			continue;
		}
		dinfo->opd_dma_tag = NULL;
		pci_add_child(dev, (struct pci_devinfo *)dinfo);

		/*
		 * Some devices don't have an intpin set, but do have
		 * interrupts. These are fully specified, and set in the
		 * interrupts property, so add that value to the device's
		 * resource list.
		 */
		if (dinfo->opd_dinfo.cfg.intpin == 0) {
			ofw_pci_intr_t intr[2];
			phandle_t iparent;
			int icells;

			if (OF_getprop(child, "interrupts", &intr, 
			    sizeof(intr)) > 0) {
				iparent = 0;
				icells = 1;
				OF_getprop(child, "interrupt-parent", &iparent,
				    sizeof(iparent));
				if (iparent != 0) {
					OF_getprop(OF_xref_phandle(iparent),
					    "#interrupt-cells", &icells,
					    sizeof(icells));
					intr[0] = ofw_bus_map_intr(dev, iparent,
					    icells, intr);
				}

				resource_list_add(&dinfo->opd_dinfo.resources,
				    SYS_RES_IRQ, 0, intr[0], intr[0], 1);
			}
		}
	}
}
コード例 #9
0
ファイル: at91_pinctrl.c プロジェクト: 2asoft/freebsd
static struct pinctrl_devinfo *
at91_pinctrl_setup_dinfo(device_t dev, phandle_t node)
{
	struct pinctrl_softc *sc;
	struct pinctrl_devinfo *ndi;
	uint32_t *reg, *intr, icells;
	uint64_t phys, size;
	phandle_t iparent;
	int i, j, k;
	int nintr;
	int nreg;

	sc = device_get_softc(dev);

	ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
	if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
		free(ndi, M_DEVBUF);
		return (NULL);
	}

	resource_list_init(&ndi->rl);
	nreg = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
	if (nreg == -1)
		nreg = 0;
	if (nreg % (sc->acells + sc->scells) != 0) {
//		if (bootverbose)
			device_printf(dev, "Malformed reg property on <%s>\n",
			    ndi->obdinfo.obd_name);
		nreg = 0;
	}

	for (i = 0, k = 0; i < nreg; i += sc->acells + sc->scells, k++) {
		phys = size = 0;
		for (j = 0; j < sc->acells; j++) {
			phys <<= 32;
			phys |= reg[i + j];
		}
		for (j = 0; j < sc->scells; j++) {
			size <<= 32;
			size |= reg[i + sc->acells + j];
		}
		
		resource_list_add(&ndi->rl, SYS_RES_MEMORY, k,
		    phys, phys + size - 1, size);
	}
	OF_prop_free(reg);

	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
	    (void **)&intr);
	if (nintr > 0) {
		if (OF_searchencprop(node, "interrupt-parent", &iparent,
		    sizeof(iparent)) == -1) {
			device_printf(dev, "No interrupt-parent found, "
			    "assuming direct parent\n");
			iparent = OF_parent(node);
		}
		if (OF_searchencprop(OF_node_from_xref(iparent), 
		    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
			device_printf(dev, "Missing #interrupt-cells property,"
			    " assuming <1>\n");
			icells = 1;
		}
		if (icells < 1 || icells > nintr) {
			device_printf(dev, "Invalid #interrupt-cells property "
			    "value <%d>, assuming <1>\n", icells);
			icells = 1;
		}
		for (i = 0, k = 0; i < nintr; i += icells, k++) {
			intr[i] = ofw_bus_map_intr(dev, iparent, icells,
			    &intr[i]);
			resource_list_add(&ndi->rl, SYS_RES_IRQ, k, intr[i],
			    intr[i], 1);
		}
		OF_prop_free(intr);
	}

	return (ndi);
}