Example #1
0
void
puc_cardbus_attach(struct device *parent, struct device *self, void *aux)
{
    struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self;
    struct puc_softc *sc = &csc->sc_psc;
    struct cardbus_attach_args *ca = aux;
    struct cardbus_devfunc *ct = ca->ca_ct;
    cardbus_chipset_tag_t cc = ct->ct_cc;
    pci_chipset_tag_t pc = ca->ca_pc;
    cardbus_function_tag_t cf = ct->ct_cf;
    struct puc_attach_args paa;
    pcireg_t reg;
    int i;

    Cardbus_function_enable(ct);

    csc->ct = ct;

    reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG);
    sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id),
                                       PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg));

    puc_print_ports(sc->sc_desc);

    /* the fifth one is some memory we dunno */
    for (i = 0; i < PUC_NBARS; i++) {
        pcireg_t type;
        int bar;

        sc->sc_bar_mappings[i].mapped = 0;
        bar = PCI_MAPREG_START + 4 * i;
        if (!pci_mapreg_probe(pc, ca->ca_tag, bar, &type))
            continue;

        if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct,
                                              bar, type, 0,
                                              &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
                                              &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s)))
            printf("%s: couldn't map BAR at offset 0x%lx\n",
                   sc->sc_dev.dv_xname, (long)bar);
        sc->sc_bar_mappings[i].type = type;
    }

    csc->intrline = ca->ca_intrline;

    if (pci_get_capability(pc, ca->ca_tag, PCI_CAP_PWRMGMT, &reg,
                           0)) {
        reg = pci_conf_read(pc, ca->ca_tag, reg + 4) & 3;
        if (reg) {
            printf("%s: awakening from state D%d\n",
                   sc->sc_dev.dv_xname, reg);
            pci_conf_write(pc, ca->ca_tag, reg + 4, 0);
        }
    }

    (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
    (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
    (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);

    paa.puc = sc;
    paa.hwtype = COM_UART_OX16C950;		/* XXX */
    paa.intr_string = &puc_cardbus_intr_string;
    paa.intr_establish = &puc_cardbus_intr_establish;
    puc_common_attach(sc, &paa);
}
Example #2
0
int
pci_probe_device(struct pci_softc *sc, pcitag_t tag,
    int (*match)(const struct pci_attach_args *),
    struct pci_attach_args *pap)
{
	pci_chipset_tag_t pc = sc->sc_pc;
	struct pci_attach_args pa;
	pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar;
#ifdef __HAVE_PCI_MSI_MSIX
	pcireg_t cap;
	int off;
#endif
	int ret, pin, bus, device, function, i, width;
	int locs[PCICF_NLOCS];

	pci_decompose_tag(pc, tag, &bus, &device, &function);

	/* a driver already attached? */
	if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match)
		return 0;

	bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
	if (PCI_HDRTYPE_TYPE(bhlcr) > 2)
		return 0;

	id = pci_conf_read(pc, tag, PCI_ID_REG);
	/* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */
	pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG);

	/* Invalid vendor ID value? */
	if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
		return 0;
	/* XXX Not invalid, but we've done this ~forever. */
	if (PCI_VENDOR(id) == 0)
		return 0;

	/* Collect memory range info */
	memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0,
	    sizeof(sc->PCI_SC_DEVICESC(device, function).c_range));
	i = 0;
	switch (PCI_HDRTYPE_TYPE(bhlcr)) {
	case PCI_HDRTYPE_PPB:
		endbar = PCI_MAPREG_PPB_END;
		break;
	case PCI_HDRTYPE_PCB:
		endbar = PCI_MAPREG_PCB_END;
		break;
	default:
		endbar = PCI_MAPREG_END;
		break;
	}
	for (bar = PCI_MAPREG_START; bar < endbar; bar += width) {
		struct pci_range *r;
		pcireg_t type;

		width = 4;
		if (pci_mapreg_probe(pc, tag, bar, &type) == 0)
			continue;

		if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) {
			if (PCI_MAPREG_MEM_TYPE(type) ==
			    PCI_MAPREG_MEM_TYPE_64BIT)
				width = 8;

			r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++];
			if (pci_mapreg_info(pc, tag, bar, type,
			    &r->r_offset, &r->r_size, &r->r_flags) != 0)
				break;
			if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10)
			    && (r->r_size == 0x1000000)) {
				struct pci_range *nr;
				/*
				 * this has to be a mach64
				 * split things up so each half-aperture can
				 * be mapped PREFETCHABLE except the last page
				 * which may contain registers
				 */
				r->r_size = 0x7ff000;
				r->r_flags = BUS_SPACE_MAP_LINEAR |
					     BUS_SPACE_MAP_PREFETCHABLE;
				nr = &sc->PCI_SC_DEVICESC(device,
				    function).c_range[i++];
				nr->r_offset = r->r_offset + 0x800000;
				nr->r_size = 0x7ff000;
				nr->r_flags = BUS_SPACE_MAP_LINEAR |
					      BUS_SPACE_MAP_PREFETCHABLE;
			}
			
		}
	}

	pa.pa_iot = sc->sc_iot;
	pa.pa_memt = sc->sc_memt;
	pa.pa_dmat = sc->sc_dmat;
	pa.pa_dmat64 = sc->sc_dmat64;
	pa.pa_pc = pc;
	pa.pa_bus = bus;
	pa.pa_device = device;
	pa.pa_function = function;
	pa.pa_tag = tag;
	pa.pa_id = id;
	pa.pa_class = pciclass;

	/*
	 * Set up memory, I/O enable, and PCI command flags
	 * as appropriate.
	 */
	pa.pa_flags = sc->sc_flags;

	/*
	 * If the cache line size is not configured, then
	 * clear the MRL/MRM/MWI command-ok flags.
	 */
	if (PCI_CACHELINE(bhlcr) == 0) {
		pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY|
		    PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY);
	}

	if (sc->sc_bridgetag == NULL) {
		pa.pa_intrswiz = 0;
		pa.pa_intrtag = tag;
	} else {
		pa.pa_intrswiz = sc->sc_intrswiz + device;
		pa.pa_intrtag = sc->sc_intrtag;
	}

	intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);

	pin = PCI_INTERRUPT_PIN(intr);
	pa.pa_rawintrpin = pin;
	if (pin == PCI_INTERRUPT_PIN_NONE) {
		/* no interrupt */
		pa.pa_intrpin = 0;
	} else {
		/*
		 * swizzle it based on the number of busses we're
		 * behind and our device number.
		 */
		pa.pa_intrpin = 	/* XXX */
		    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
	}
	pa.pa_intrline = PCI_INTERRUPT_LINE(intr);

#ifdef __HAVE_PCI_MSI_MSIX
	if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) {
		/*
		 * XXX Should we enable MSI mapping ourselves on
		 * systems that have it disabled?
		 */
		if (cap & PCI_HT_MSI_ENABLED) {
			uint64_t addr;
			if ((cap & PCI_HT_MSI_FIXED) == 0) {
				addr = pci_conf_read(pc, tag,
				    off + PCI_HT_MSI_ADDR_LO);
				addr |= (uint64_t)pci_conf_read(pc, tag,
				    off + PCI_HT_MSI_ADDR_HI) << 32;
			} else
				addr = PCI_HT_MSI_FIXED_ADDR;

			/*
			 * XXX This will fail to enable MSI on systems
			 * that don't use the canonical address.
			 */
			if (addr == PCI_HT_MSI_FIXED_ADDR) {
				pa.pa_flags |= PCI_FLAGS_MSI_OKAY;
				pa.pa_flags |= PCI_FLAGS_MSIX_OKAY;
			}
		}
	}
#endif

	if (match != NULL) {
		ret = (*match)(&pa);
		if (ret != 0 && pap != NULL)
			*pap = pa;
	} else {
		struct pci_child *c;
		locs[PCICF_DEV] = device;
		locs[PCICF_FUNCTION] = function;

		c = &sc->PCI_SC_DEVICESC(device, function);
		pci_conf_capture(pc, tag, &c->c_conf);
		if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0)
			c->c_psok = true;
		else
			c->c_psok = false;

		c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa,
					     pciprint, config_stdsubmatch);

		ret = (c->c_dev != NULL);
	}

	return ret;
}
Example #3
0
void
puc_pci_attach(struct device *parent, struct device *self, void *aux)
{
	struct puc_pci_softc *psc = (struct puc_pci_softc *)self;
	struct puc_softc *sc = &psc->sc_psc;
	struct pci_attach_args *pa = aux;
	struct puc_attach_args paa;
	pcireg_t subsys;
	int i;

	subsys = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
	sc->sc_desc = puc_find_description(PCI_VENDOR(pa->pa_id),
	    PCI_PRODUCT(pa->pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys));

	puc_print_ports(sc->sc_desc);

	for (i = 0; i < PUC_NBARS; i++) {
		pcireg_t type;
		int bar;

		sc->sc_bar_mappings[i].mapped = 0;
		bar = PCI_MAPREG_START + 4 * i;
		if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, bar, &type))
			continue;

		sc->sc_bar_mappings[i].mapped = (pci_mapreg_map(pa, bar, type,
		    0, &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
		    &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s, 0)
		      == 0);
		if (sc->sc_bar_mappings[i].mapped)
			continue;

		/*
		 * If a port on this card is used as serial console,
		 * mapping the associated BAR will fail because the
		 * bus space is already mapped.  In that case, we try
		 * to re-use the already existing mapping.
		 * Unfortunately this means that if a BAR is used to
		 * support multiple ports, only the first port will
		 * work.
		 */
		if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, type,
		    &sc->sc_bar_mappings[i].a, NULL, NULL) == 0 &&
		    pa->pa_iot == comconsiot &&
		    sc->sc_bar_mappings[i].a == comconsaddr) {
			sc->sc_bar_mappings[i].t = comconsiot;
			sc->sc_bar_mappings[i].h = comconsioh;
			sc->sc_bar_mappings[i].s = COM_NPORTS;
			sc->sc_bar_mappings[i].mapped = 1;
			continue;
		}

		printf("%s: couldn't map BAR at offset 0x%lx\n",
		    sc->sc_dev.dv_xname, (long)bar);
	}

	/* Map interrupt. */
	psc->pc = pa->pa_pc;
	if (pci_intr_map(pa, &psc->ih)) {
		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
		return;
	}

	paa.puc = sc;
	paa.intr_string = &puc_pci_intr_string;
	paa.intr_establish = &puc_pci_intr_establish;

	puc_common_attach(sc, &paa);
}
Example #4
0
void
ppb_alloc_resources(struct ppb_softc *sc, struct pci_attach_args *pa)
{
	pci_chipset_tag_t pc = sc->sc_pc;
	pcireg_t id, busdata, blr, bhlcr, type, csr;
	pcireg_t addr, mask;
	pcitag_t tag;
	int bus, dev;
	int reg, reg_start, reg_end, reg_rom;
	int io_count = 0;
	int mem_count = 0;
	bus_addr_t start, end;
	u_long base, size;

	if (pa->pa_memex == NULL)
		return;

	busdata = pci_conf_read(pc, sc->sc_tag, PPB_REG_BUSINFO);
	bus = PPB_BUSINFO_SECONDARY(busdata);
	if (bus == 0)
		return;

	/*
	 * Count number of devices.  If there are no devices behind
	 * this bridge, there's no point in allocating any address
	 * space.
	 */
	for (dev = 0; dev < pci_bus_maxdevs(pc, bus); dev++) {
		tag = pci_make_tag(pc, bus, dev, 0);
		id = pci_conf_read(pc, tag, PCI_ID_REG);

		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
		    PCI_VENDOR(id) == 0)
			continue;

		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
		switch (PCI_HDRTYPE_TYPE(bhlcr)) {
		case 0:
			reg_start = PCI_MAPREG_START;
			reg_end = PCI_MAPREG_END;
			reg_rom = PCI_ROM_REG;
			break;
		case 1:	/* PCI-PCI bridge */
			reg_start = PCI_MAPREG_START;
			reg_end = PCI_MAPREG_PPB_END;
			reg_rom = 0;	/* 0x38 */
			break;
		case 2:	/* PCI-Cardbus bridge */
			reg_start = PCI_MAPREG_START;
			reg_end = PCI_MAPREG_PCB_END;
			reg_rom = 0;
			break;
		default:
			return;
		}

		for (reg = reg_start; reg < reg_end; reg += 4) {
			if (pci_mapreg_probe(pc, tag, reg, &type) == 0)
				continue;

			if (type == PCI_MAPREG_TYPE_IO)
				io_count++;
			else
				mem_count++;
		}

		if (reg_rom != 0) {
			addr = pci_conf_read(pc, tag, reg_rom);
			pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE);
			mask = pci_conf_read(pc, tag, reg_rom);
			pci_conf_write(pc, tag, reg_rom, addr);
			if (PCI_ROM_SIZE(mask))
				mem_count++;
		}
	}

	csr = pci_conf_read(pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);

	/*
	 * Get the bridge in a consistent state.  If memory mapped I/O
	 * is disabled, disabled the associated windows as well.  
	 */
	if ((csr & PCI_COMMAND_MEM_ENABLE) == 0) {
		pci_conf_write(pc, sc->sc_tag, PPB_REG_MEM, 0x0000ffff);
		pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFMEM, 0x0000ffff);
		pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFBASE_HI32, 0);
		pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFLIM_HI32, 0);
	}

	/* Allocate I/O address space if necessary. */
	if (io_count > 0 && pa->pa_ioex) {
		blr = pci_conf_read(pc, sc->sc_tag, PPB_REG_IOSTATUS);
		sc->sc_iobase = (blr << PPB_IO_SHIFT) & PPB_IO_MASK;
		sc->sc_iolimit = (blr & PPB_IO_MASK) | 0x00000fff;
		blr = pci_conf_read(pc, sc->sc_tag, PPB_REG_IO_HI);
		sc->sc_iobase |= (blr & 0x0000ffff) << 16;
		sc->sc_iolimit |= (blr & 0xffff0000);
		if (sc->sc_iolimit < sc->sc_iobase || sc->sc_iobase == 0) {
			start = max(PCI_IO_START, pa->pa_ioex->ex_start);
			end = min(PCI_IO_END, pa->pa_ioex->ex_end);
			for (size = 0x2000; size >= PPB_IO_MIN; size >>= 1)
				if (extent_alloc_subregion(pa->pa_ioex, start,
				    end, size, size, 0, 0, 0, &base) == 0)
					break;
			if (size >= PPB_IO_MIN) {
				sc->sc_iobase = base;
				sc->sc_iolimit = base + size - 1;
				blr = pci_conf_read(pc, sc->sc_tag,
				    PPB_REG_IOSTATUS);
				blr &= 0xffff0000;
				blr |= sc->sc_iolimit & PPB_IO_MASK;
				blr |= (sc->sc_iobase >> PPB_IO_SHIFT);
				pci_conf_write(pc, sc->sc_tag,
				    PPB_REG_IOSTATUS, blr);
				blr = (sc->sc_iobase & 0xffff0000) >> 16;
				blr |= sc->sc_iolimit & 0xffff0000;
				pci_conf_write(pc, sc->sc_tag,
				    PPB_REG_IO_HI, blr);

				csr |= PCI_COMMAND_IO_ENABLE;
			}