Beispiel #1
0
static int
cardbus_attach_card(device_t cbdev)
{
	device_t brdev = device_get_parent(cbdev);
	device_t child;
	int bus, domain, slot, func;
	int cardattached = 0;
	int cardbusfunchigh = 0;
	struct cardbus_softc *sc;

	sc = device_get_softc(cbdev);
	cardbus_detach_card(cbdev); /* detach existing cards */
	POWER_ENABLE_SOCKET(brdev, cbdev);
	domain = pcib_get_domain(cbdev);
	bus = pcib_get_bus(cbdev);
	slot = 0;
	/* For each function, set it up and try to attach a driver to it */
	for (func = 0; func <= cardbusfunchigh; func++) {
		struct cardbus_devinfo *dinfo;

		dinfo = (struct cardbus_devinfo *)
		    pci_read_device(brdev, domain, bus, slot, func,
			sizeof(struct cardbus_devinfo));
		if (dinfo == NULL)
			continue;
		if (dinfo->pci.cfg.mfdev)
			cardbusfunchigh = PCI_FUNCMAX;

		child = device_add_child(cbdev, NULL, -1);
		if (child == NULL) {
			DEVPRINTF((cbdev, "Cannot add child!\n"));
			pci_freecfg((struct pci_devinfo *)dinfo);
			continue;
		}
		dinfo->pci.cfg.dev = child;
		resource_list_init(&dinfo->pci.resources);
		device_set_ivars(child, dinfo);
		cardbus_device_create(sc, dinfo, cbdev, child);
		if (cardbus_do_cis(cbdev, child) != 0)
			DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n"));
		pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
		pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci);
		cardbus_device_setup_regs(&dinfo->pci.cfg);
		pci_add_resources(cbdev, child, 1, dinfo->mprefetchable);
		pci_print_verbose(&dinfo->pci);
		if (device_probe_and_attach(child) == 0)
			cardattached++;
		else
			pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1);
	}
	if (cardattached > 0)
		return (0);
/*	POWER_DISABLE_SOCKET(brdev, cbdev); */
	return (ENOENT);
}
Beispiel #2
0
static struct resource *
cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
    int *rid)
{
	struct resource *res;
	uint32_t space;

	space = *start & PCIM_CIS_ASI_MASK;
	switch (space) {
	case PCIM_CIS_ASI_CONFIG:
		DEVPRINTF((cbdev, "CIS in PCI config space\n"));
		/* CIS in PCI config space need no initialization */
		return (CIS_CONFIG_SPACE);
	case PCIM_CIS_ASI_BAR0:
	case PCIM_CIS_ASI_BAR1:
	case PCIM_CIS_ASI_BAR2:
	case PCIM_CIS_ASI_BAR3:
	case PCIM_CIS_ASI_BAR4:
	case PCIM_CIS_ASI_BAR5:
		*rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
		DEVPRINTF((cbdev, "CIS in BAR %#x\n", *rid));
		break;
	case PCIM_CIS_ASI_ROM:
		*rid = PCIR_BIOS;
		DEVPRINTF((cbdev, "CIS in option rom\n"));
		break;
	default:
		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
		    space);
		return (NULL);
	}

	/* allocate the memory space to read CIS */
	res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid,
	    rman_make_alignment_flags(4096) | RF_ACTIVE);
	if (res == NULL) {
		device_printf(cbdev, "Unable to allocate resource "
		    "to read CIS.\n");
		return (NULL);
	}
	DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));

	/* Flip to the right ROM image if CIS is in ROM */
	if (space == PCIM_CIS_ASI_ROM) {
		uint32_t imagesize;
		uint32_t imagebase = 0;
		uint32_t pcidata;
		uint16_t romsig;
		int romnum = 0;
		int imagenum;

		imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28;
		for (romnum = 0;; romnum++) {
			romsig = bus_read_2(res,
			    imagebase + CARDBUS_EXROM_SIGNATURE);
			if (romsig != 0xaa55) {
				device_printf(cbdev, "Bad header in rom %d: "
				    "[%x] %04x\n", romnum, imagebase +
				    CARDBUS_EXROM_SIGNATURE, romsig);
				cardbus_read_tuple_finish(cbdev, child, *rid,
				    res);
				*rid = 0;
				return (NULL);
			}

			/*
			 * If this was the Option ROM image that we were
			 * looking for, then we are done.
			 */
			if (romnum == imagenum)
				break;

			/* Find out where the next Option ROM image is */
			pcidata = imagebase + bus_read_2(res,
			    imagebase + CARDBUS_EXROM_DATA_PTR);
			imagesize = bus_read_2(res,
			    pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);

			if (imagesize == 0) {
				/*
				 * XXX some ROMs seem to have this as zero,
				 * can we assume this means 1 block?
				 */
				device_printf(cbdev, "Warning, size of Option "
				    "ROM image %d is 0 bytes, assuming 512 "
				    "bytes.\n", romnum);
				imagesize = 1;
			}

			/* Image size is in 512 byte units */
			imagesize <<= 9;

			if ((bus_read_1(res, pcidata +
			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
				device_printf(cbdev, "Cannot find CIS in "
				    "Option ROM\n");
				cardbus_read_tuple_finish(cbdev, child, *rid,
				    res);
				*rid = 0;
				return (NULL);
			}
			imagebase += imagesize;
		}
		*start = imagebase + (*start & PCIM_CIS_ADDR_MASK);
	} else {
Beispiel #3
0
static int
cbb_pci_attach(device_t brdev)
{
	static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
	struct sysctl_ctx_list *sctx;
	struct sysctl_oid *soid;
	int rid;
	device_t parent;
	uint32_t pribus;

	parent = device_get_parent(brdev);
	mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
	sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL);
	sc->dev = brdev;
	sc->cbdev = NULL;
	sc->exca[0].pccarddev = NULL;
	sc->domain = pci_get_domain(brdev);
	sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1);
	sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
	sc->pribus = pcib_get_bus(parent);
	SLIST_INIT(&sc->rl);
	cbb_powerstate_d0(brdev);

	rid = CBBR_SOCKBASE;
	sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (!sc->base_res) {
		device_printf(brdev, "Could not map register memory\n");
		mtx_destroy(&sc->mtx);
		return (ENOMEM);
	} else {
		DEVPRINTF((brdev, "Found memory at %08lx\n",
		    rman_get_start(sc->base_res)));
	}

	sc->bst = rman_get_bustag(sc->base_res);
	sc->bsh = rman_get_bushandle(sc->base_res);
	exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET);
	sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN;
	sc->exca[0].chipset = EXCA_CARDBUS;
	sc->chipinit = cbb_chipinit;
	sc->chipinit(sc);

	/*Sysctls*/
	sctx = device_get_sysctl_ctx(brdev);
	soid = device_get_sysctl_tree(brdev);
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
	    CTLFLAG_RD, &sc->domain, 0, "Domain number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
	    CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
	    CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
	    CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
#if 0
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory",
	    CTLFLAG_RD, &sc->subbus, 0, "Memory window open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "premem",
	    CTLFLAG_RD, &sc->subbus, 0, "Prefetch memroy window open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io1",
	    CTLFLAG_RD, &sc->subbus, 0, "io range 1 open");
	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io2",
	    CTLFLAG_RD, &sc->subbus, 0, "io range 2 open");
#endif

	/*
	 * This is a gross hack.  We should be scanning the entire pci
	 * tree, assigning bus numbers in a way such that we (1) can
	 * reserve 1 extra bus just in case and (2) all sub busses
	 * are in an appropriate range.
	 */
	DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus));
	pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
	if (sc->secbus == 0 || sc->pribus != pribus) {
		if (curr_bus_number <= sc->pribus)
			curr_bus_number = sc->pribus + 1;
		if (pribus != sc->pribus) {
			DEVPRINTF((brdev, "Setting primary bus to %d\n",
			    sc->pribus));
			pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
		}
		sc->secbus = curr_bus_number++;
		sc->subbus = curr_bus_number++;
		DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n",
		    sc->secbus, sc->subbus));
		pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1);
		pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1);
	}

	/* attach children */
	sc->cbdev = device_add_child(brdev, "cardbus", -1);
	if (sc->cbdev == NULL)
		DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n"));
	else if (device_probe_and_attach(sc->cbdev) != 0)
		DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n"));

	sc->exca[0].pccarddev = device_add_child(brdev, "pccard", -1);
	if (sc->exca[0].pccarddev == NULL)
		DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n"));
	else if (device_probe_and_attach(sc->exca[0].pccarddev) != 0)
		DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n"));

	/* Map and establish the interrupt. */
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid,
	    RF_SHAREABLE | RF_ACTIVE);
	if (sc->irq_res == NULL) {
		device_printf(brdev, "Unable to map IRQ...\n");
		goto err;
	}

	if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE,
	    cbb_pci_filt, NULL, sc, &sc->intrhand)) {
		device_printf(brdev, "couldn't establish interrupt\n");
		goto err;
	}

	/* reset 16-bit pcmcia bus */
	exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET);

	/* turn off power */
	cbb_power(brdev, CARD_OFF);

	/* CSC Interrupt: Card detect interrupt on */
	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);

	/* reset interrupt */
	cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT));

	if (bootverbose)
		cbb_print_config(brdev);

	/* Start the thread */
	if (kproc_create(cbb_event_thread, sc, &sc->event_thread, 0, 0,
	    "%s event thread", device_get_nameunit(brdev))) {
		device_printf(brdev, "unable to create event thread.\n");
		panic("cbb_create_event_thread");
	}
	sc->sc_root_token = root_mount_hold(device_get_nameunit(sc->dev));
	return (0);
err:
	if (sc->irq_res)
		bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);
	if (sc->base_res) {
		bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE,
		    sc->base_res);
	}
	mtx_destroy(&sc->mtx);
	return (ENOMEM);
}