Exemple #1
0
static int
gusc_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
#if __FreeBSD_version >= 700031
		driver_filter_t *filter,
#endif
		driver_intr_t *intr, void *arg, void **cookiep)
{
	sc_p scp = (sc_p)device_get_softc(dev);
	devclass_t devclass;

#if __FreeBSD_version >= 700031
	if (filter != NULL) {
		printf("gusc.c: we cannot use a filter here\n");
		return (EINVAL);
	}
#endif
	devclass = device_get_devclass(child);
	if (strcmp(devclass_get_name(devclass), "midi") == 0) {
		scp->midi_intr.intr = intr;
		scp->midi_intr.arg = arg;
		return 0;
	} else if (strcmp(devclass_get_name(devclass), "pcm") == 0) {
		scp->pcm_intr.intr = intr;
		scp->pcm_intr.arg = arg;
		return 0;
	}
	return bus_generic_setup_intr(dev, child, irq, flags,
#if __FreeBSD_version >= 700031
				filter,
#endif
				intr, arg, cookiep);
}
Exemple #2
0
/**
 * Find an NVRAM child device on @p dev, if any.
 * 
 * @retval device_t An NVRAM device.
 * @retval NULL If no NVRAM device is found.
 */
static device_t
find_nvram_child(device_t dev)
{
	device_t chipc, nvram;

	/* Look for a directly-attached NVRAM child */
	nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass),
	    -1);
	if (nvram == NULL)
		return (NULL);

	/* Further checks require a bhnd(4) bus */
	if (device_get_devclass(dev) != bhnd_devclass)
		return (NULL);

	/* Look for a ChipCommon-attached OTP device */
	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
		/* Recursively search the ChipCommon device */
		if ((nvram = find_nvram_child(chipc)) != NULL)
			return (nvram);
	}

	/* Not found */
	return (NULL);
}
Exemple #3
0
static int
gusc_setup_intr(device_t dev, device_t child, struct resource *irq,
		int flags, driver_intr_t *intr, void *arg, void **cookiep)
{
	sc_p scp = (sc_p)device_get_softc(dev);
	devclass_t devclass;

	devclass = device_get_devclass(child);
	if (strcmp(devclass_get_name(devclass), "midi") == 0) {
		scp->midi_intr.intr = intr;
		scp->midi_intr.arg = arg;
		return 0;
	} else if (strcmp(devclass_get_name(devclass), "pcm") == 0) {
		scp->pcm_intr.intr = intr;
		scp->pcm_intr.arg = arg;
		return 0;
	}
	return bus_generic_setup_intr(dev, child, irq, flags, intr,
				      arg, cookiep, NULL, NULL);
}
/**
 * Initialize the full bridge configuration.
 * 
 * This is called during the DEVICE_ATTACH() process by the bridged bhndb(4)
 * bus, prior to probe/attachment of child cores.
 * 
 * At this point, we can introspect the enumerated cores, find our host
 * bridge device, and apply any bridge-level hardware workarounds required
 * for proper operation of the bridged device cores.
 */
static int
bhndb_pci_init_full_config(device_t dev, device_t child,
    const struct bhndb_hw_priority *prio_table)
{
	struct bhnd_core_info		 core;
	const struct bhndb_pci_id	*id;
	struct bhndb_pci_softc		*sc;
	struct bhndb_region		*pcir;
	bhnd_addr_t			 pcir_addr;
	bhnd_size_t			 pcir_size;
	int				 error;

	sc = device_get_softc(dev);

	/* Let bhndb perform full discovery and initialization of the
	 * available register windows and bridge resources. */
	if ((error = bhndb_generic_init_full_config(dev, child, prio_table)))
		return (error);

	/* 
	 * Identify our PCI bridge core, its register family, and any
	 * applicable hardware quirks.
	 */
	KASSERT(sc->bhndb.hostb_dev,
	    ("missing hostb device\n"));

	core = bhnd_get_core_info(sc->bhndb.hostb_dev);
	id = bhndb_pci_find_core_id(&core);
	if (id == NULL) {
		device_printf(dev, "%s %s hostb core is not recognized\n",
		    bhnd_vendor_name(core.vendor), bhnd_core_name(&core));
	}

	sc->regfmt = id->regfmt;

	/* Now that we've identified the PCI bridge core, we can determine the
	 * full set of device quirks */
	sc->quirks = bhndb_pci_discover_quirks(sc, id);

	/*
	 * Determine and save a reference to the bhndb resource and offset
	 * at which the bridge core's device registers are mapped.
	 * 
	 * All known bhnd(4) hardware provides a fixed static mapping of
	 * the PCI core's registers. If this changes in the future -- which
	 * is unlikely -- this driver will need to be adjusted to use
	 * dynamic register windows.
	 */

	/* Find base address and size of the PCI core's register block. */
	error = bhnd_get_region_addr(sc->bhndb.hostb_dev, BHND_PORT_DEVICE, 0,
	    0, &pcir_addr, &pcir_size);
	if (error) {
		device_printf(dev,
		    "failed to locate PCI core registers\n");
		return (error);
	}

	/* Find the bhndb_region that statically maps this block */
	pcir = bhndb_find_resource_region(sc->bhndb.bus_res, pcir_addr,
	    pcir_size);
	if (pcir == NULL || pcir->static_regwin == NULL) {
		device_printf(dev,
		    "missing static PCI core register window\n");
		return (ENXIO);
	}

	/* Save borrowed reference to the mapped PCI core registers */
	sc->mem_off = pcir->static_regwin->win_offset;
	sc->mem_res = bhndb_find_regwin_resource(sc->bhndb.bus_res,
	    pcir->static_regwin);
	if (sc->mem_res == NULL || !(rman_get_flags(sc->mem_res) & RF_ACTIVE)) {
		device_printf(dev,
		    "no active resource maps the PCI core register window\n");
		return (ENXIO);
	}

	/* Configure a direct bhnd_resource wrapper that we can pass to
	 * bhnd_resource APIs */
	sc->bhnd_mem_res = (struct bhnd_resource) {
		.res = sc->mem_res,
		.direct = true
	};

	/*
	 * Attach MMIO device (if this is a PCIe device), which is used for
	 * access to the PCIe SerDes required by the quirk workarounds.
	 */
	if (sc->pci_devclass == BHND_DEVCLASS_PCIE) {
		sc->mdio = device_add_child(dev, 
		    devclass_get_name(bhnd_mdio_pci_devclass), 0);
		if (sc->mdio == NULL)
			return (ENXIO);

		if ((error = device_probe_and_attach(sc->mdio))) {
			device_printf(dev, "failed to attach MDIO device\n");
			return (error);
		}
	}

	/* Apply any early one-time quirk workarounds */
	if ((error = bhndb_pci_wars_early_once(sc)))
		return (error);

	/* Apply attach-time quirk workarounds, required before the bridged
	 * bhnd(4) bus itself performs a full attach(). */
	if ((error = bhndb_pci_wars_hwup(sc)))
		return (error);

	return (0);
}

/**
 * Apply any hardware workarounds that must be executed prior to attempting
 * register access on the bridged chipset.
 * 
 * This must be called very early in attach() or resume(), after the basic
 * set of applicable device quirks has been determined.
 */
static int
bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc)
{
	int error;

	if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) {
		if ((error = bhndb_enable_pci_clocks(sc))) {
			device_printf(sc->dev, "failed to enable clocks\n");
			return (error);
		}
	}

	return (0);
}