Пример #1
0
int
pci_func_configure(struct pci_func *f)
{
	uint32_t bar_width;
	uint32_t bar;
	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
	     bar += bar_width)
	{
		uint32_t oldv = pci_conf_read(f, bar);

		bar_width = 4;
		pci_conf_write(f, bar, 0xffffffff);
		uint32_t rv = pci_conf_read(f, bar);

		if (rv == 0)
			continue;

		int regnum = PCI_MAPREG_NUM(bar);
		uint32_t base, size;
		if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
			if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
				bar_width = 8;

			size = PCI_MAPREG_MEM_SIZE(rv);
			base = PCI_MAPREG_MEM_ADDR(oldv);
			if (!base) {
				/* device is not properly configured,
				   allocate mmio address for it */
				base = pci_allocate_memory(size);
				if (!base)
					return ENOMEM;
				oldv = base;
			}
#ifdef SHOW_PCI_VERBOSE_INFO
			printf("pci: allocated mem region %d: %d bytes at 0x%x\n",
				regnum, size, base);
#endif
		} else {
#ifdef CONFIG_ARCH_HAS_IO_SPACE
			/* TODO handle IO region */
#endif
		}

		pci_conf_write(f, bar, oldv);
		f->reg_base[regnum] = base;
		f->reg_size[regnum] = size;
	}
	f->irq_line = pci_allocate_irqline();
	/* FIXME */
	f->irq_pin = PCI_INTERRUPT_PIN_C;
	pci_conf_write(f, PCI_INTERRUPT_REG,
		       PCI_INTERRUPT_LINE(f->irq_line) |
		       PCI_INTERRUPT_PIN(f->irq_pin));

	printf("pci: function %02x:%02x.%d (%04x:%04x) configured\n",
		f->bus->busno, f->dev, f->func,
		PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id));
	return 0;
}
Пример #2
0
static int
pci_device_openbsd_probe(struct pci_device *device)
{
	struct pci_device_private *priv = (struct pci_device_private *)device;
	struct pci_mem_region *region;
	uint64_t reg64, size64;
	uint32_t bar, reg, size;
	int domain, bus, dev, func, err;

	domain = device->domain;
	bus = device->bus;
	dev = device->dev;
	func = device->func;

	err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
	if (err)
		return err;

	priv->header_type = PCI_HDRTYPE_TYPE(reg);
	if (priv->header_type != 0)
		return 0;

	region = device->regions;
	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
	     bar += sizeof(uint32_t), region++) {
		err = pci_read(domain, bus, dev, func, bar, &reg);
		if (err)
			return err;

		/* Probe the size of the region. */
		err = pci_readmask(domain, bus, dev, func, bar, &size);
		if (err)
			return err;

		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
			region->is_IO = 1;
			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
			region->size = PCI_MAPREG_IO_SIZE(size);
		} else {
			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
				region->is_prefetchable = 1;
			switch(PCI_MAPREG_MEM_TYPE(reg)) {
			case PCI_MAPREG_MEM_TYPE_32BIT:
			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
				region->size = PCI_MAPREG_MEM_SIZE(size);
				break;
			case PCI_MAPREG_MEM_TYPE_64BIT:
				region->is_64 = 1;

				reg64 = reg;
				size64 = size;

				bar += sizeof(uint32_t);

				err = pci_read(domain, bus, dev, func, bar, &reg);
				if (err)
					return err;
				reg64 |= (uint64_t)reg << 32;

				err = pci_readmask(domain, bus, dev, func, bar, &size);
				if (err)
					return err;
				size64 |= (uint64_t)size << 32;

				region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
				region->size = PCI_MAPREG_MEM64_SIZE(size64);
				region++;
				break;
			}
		}
	}

	/* Probe expansion ROM if present */
	err = pci_read(domain, bus, dev, func, PCI_ROM_REG, &reg);
	if (err)
		return err;
	if (reg != 0) {
		err = pci_write(domain, bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE);
		if (err)
			return err;
		pci_read(domain, bus, dev, func, PCI_ROM_REG, &size);
		pci_write(domain, bus, dev, func, PCI_ROM_REG, reg);

		if (PCI_ROM_ADDR(reg) != 0) {
			priv->rom_base = PCI_ROM_ADDR(reg);
			device->rom_size = PCI_ROM_SIZE(size);
		}
	}
	return 0;
}
Пример #3
0
/*
 * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
 *			       cardbus_function_tag_t cf, pcitag_t tag,
 *			       int reg, pcireg_t type, bus_addr_t *basep,
 *			       bus_size_t *sizep, int *flagsp)
 * This code is stolen from sys/dev/pci_map.c.
 */
static int
cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
{
	pcireg_t address, mask;
	int s;

	if (reg != CARDBUS_ROM_REG &&
	    (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
		panic("cardbus_mem_find: bad request");
	}

	/*
	 * Section 6.2.5.1, `Address Maps', tells us that:
	 *
	 * 1) The builtin software should have already mapped the device in a
	 * reasonable way.
	 *
	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
	 * n bits of the address to 0.  As recommended, we write all 1s and see
	 * what we get back.
	 */
	s = splhigh();
	address = cardbus_conf_read(cc, cf, tag, reg);
	cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
	mask = cardbus_conf_read(cc, cf, tag, reg);
	cardbus_conf_write(cc, cf, tag, reg, address);
	splx(s);

	if (reg != CARDBUS_ROM_REG) {
		/* memory space BAR */

		if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
			printf("cardbus_mem_find: expected type mem, found i/o\n");
			return 1;
		}
		if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
			printf("cardbus_mem_find: expected mem type %08x, found %08x\n",
			    PCI_MAPREG_MEM_TYPE(type),
			    PCI_MAPREG_MEM_TYPE(address));
			return 1;
		}
	}

	if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
		printf("cardbus_mem_find: void region\n");
		return 1;
	}

	switch (PCI_MAPREG_MEM_TYPE(address)) {
	case PCI_MAPREG_MEM_TYPE_32BIT:
	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
		break;
	case PCI_MAPREG_MEM_TYPE_64BIT:
		printf("cardbus_mem_find: 64-bit memory mapping register\n");
		return 1;
	default:
		printf("cardbus_mem_find: reserved mapping register type\n");
		return 1;
	}

	if (basep != 0) {
		*basep = PCI_MAPREG_MEM_ADDR(address);
	}
	if (sizep != 0) {
		*sizep = PCI_MAPREG_MEM_SIZE(mask);
	}
	if (flagsp != 0) {
		*flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ?
		    BUS_SPACE_MAP_PREFETCHABLE : 0;
	}

	return 0;
}
Пример #4
0
void
pciaddr_resource_manage(struct pcibios_softc *sc, pci_chipset_tag_t pc,
    pcitag_t tag, pciaddr_resource_manage_func_t func)
{
	struct extent *ex;
	pcireg_t val, mask;
	bus_addr_t addr;
	bus_size_t size;
	int error, mapreg, type, reg_start, reg_end, width;

	val = pci_conf_read(pc, tag, PCI_BHLC_REG);
	switch (PCI_HDRTYPE_TYPE(val)) {
	default:
		printf("WARNING: unknown PCI device header 0x%x.\n",
		    PCI_HDRTYPE_TYPE(val));
		sc->nbogus++;
		return;
	case 0: 
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_END;
		break;
	case 1: /* PCI-PCI bridge */
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_PPB_END;
		break;
	case 2: /* PCI-CardBus bridge */
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_PCB_END;
		break;
	}
	error = 0;
    
	for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
		/* inquire PCI device bus space requirement */
		val = pci_conf_read(pc, tag, mapreg);
		pci_conf_write(pc, tag, mapreg, ~0);

		mask = pci_conf_read(pc, tag, mapreg);
		pci_conf_write(pc, tag, mapreg, val);
	
		type = PCI_MAPREG_TYPE(val);
		width = 4;
		if (type == PCI_MAPREG_TYPE_MEM) {
			if (PCI_MAPREG_MEM_TYPE(val) == 
			    PCI_MAPREG_MEM_TYPE_64BIT) {
				/* XXX We could examine the upper 32 bits
				 * XXX of the BAR here, but we are totally 
				 * XXX unprepared to handle a non-zero value, 
				 * XXX either here or anywhere else in 
				 * XXX i386-land. 
				 * XXX So just arrange to not look at the
				 * XXX upper 32 bits, lest we misinterpret
				 * XXX it as a 32-bit BAR set to zero. 
				 */
			    width = 8;
			}
			addr = PCI_MAPREG_MEM_ADDR(val);
			size = PCI_MAPREG_MEM_SIZE(mask);
			ex = sc->extent_mem;
		} else {
			/* XXX some devices give 32bit value */
			addr = PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END;
			size = PCI_MAPREG_IO_SIZE(mask);
			ex = sc->extent_port;
		}
	
		if (!size) /* unused register */
			continue;

		/* reservation/allocation phase */
		error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size);

		PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n", 
				mapreg, type ? "port" : "mem ", 
				(unsigned int)addr, (unsigned int)size));
	}

	if (error)
		sc->nbogus++;

	PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK"));
}
Пример #5
0
static void
cac_pci_attach(device_t parent, device_t self, void *aux)
{
    struct pci_attach_args *pa;
    const struct cac_pci_type *ct;
    struct cac_softc *sc;
    pci_chipset_tag_t pc;
    pci_intr_handle_t ih;
    const char *intrstr;
    pcireg_t reg;
    int memr, ior, i;
    char intrbuf[PCI_INTRSTR_LEN];

    aprint_naive(": RAID controller\n");

    sc = device_private(self);
    sc->sc_dev = self;
    pa = (struct pci_attach_args *)aux;
    pc = pa->pa_pc;
    ct = cac_pci_findtype(pa);

    /*
     * Map the PCI register window.
     */
    memr = -1;
    ior = -1;

    for (i = 0x10; i <= 0x14; i += 4) {
        reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i);

        if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
            if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0)
                ior = i;
        } else {
            if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0)
                memr = i;
        }
    }

    if (memr != -1) {
        if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0,
                           &sc->sc_iot, &sc->sc_ioh, NULL, NULL))
            memr = -1;
        else
            ior = -1;
    }
    if (ior != -1)
        if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0,
                           &sc->sc_iot, &sc->sc_ioh, NULL, NULL))
            ior = -1;
    if (memr == -1 && ior == -1) {
        aprint_error_dev(self, "can't map i/o or memory space\n");
        return;
    }

    sc->sc_dmat = pa->pa_dmat;

    /* Enable the device. */
    reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
    pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
                   reg | PCI_COMMAND_MASTER_ENABLE);

    /* Map and establish the interrupt. */
    if (pci_intr_map(pa, &ih)) {
        aprint_error("can't map interrupt\n");
        return;
    }
    intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
    sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, cac_intr, sc);
    if (sc->sc_ih == NULL) {
        aprint_error("can't establish interrupt");
        if (intrstr != NULL)
            aprint_error(" at %s", intrstr);
        aprint_error("\n");
        return;
    }

    aprint_normal(": Compaq %s\n", ct->ct_typestr);

    /* Now attach to the bus-independent code. */
    memcpy(&sc->sc_cl, ct->ct_linkage, sizeof(sc->sc_cl));
    cac_init(sc, intrstr, (ct->ct_flags & CT_STARTFW) != 0);
}
Пример #6
0
static int
pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
    bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
{
	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff;
	u_int64_t waddress, wmask;
	int s, is64bit, isrom;

	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
	isrom = (reg == PCI_MAPREG_ROM);

	if ((!isrom) && (reg < PCI_MAPREG_START ||
#if 0
	    /*
	     * Can't do this check; some devices have mapping registers
	     * way out in left field.
	     */
	    reg >= PCI_MAPREG_END ||
#endif
	    (reg & 3)))
		panic("pci_mem_find: bad request");

	if (is64bit && (reg + 4) >= PCI_MAPREG_END)
		panic("pci_mem_find: bad 64-bit request");

	/*
	 * Section 6.2.5.1, `Address Maps', tells us that:
	 *
	 * 1) The builtin software should have already mapped the device in a
	 * reasonable way.
	 *
	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
	 * n bits of the address to 0.  As recommended, we write all 1s and see
	 * what we get back.
	 */
	s = splhigh();
	address = pci_conf_read(pc, tag, reg);
	pci_conf_write(pc, tag, reg, 0xffffffff);
	mask = pci_conf_read(pc, tag, reg);
	pci_conf_write(pc, tag, reg, address);
	if (is64bit) {
		address1 = pci_conf_read(pc, tag, reg + 4);
		pci_conf_write(pc, tag, reg + 4, 0xffffffff);
		mask1 = pci_conf_read(pc, tag, reg + 4);
		pci_conf_write(pc, tag, reg + 4, address1);
	}
	splx(s);

	if (!isrom) {
		/*
		 * roms should have an enable bit instead of a memory
		 * type decoder bit.  For normal BARs, make sure that
		 * the address decoder type matches what we asked for.
		 */
		if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
			printf("pci_mem_find: expected type mem, found i/o\n");
			return (1);
		}
		/* XXX Allow 64bit bars for 32bit requests.*/
		if (PCI_MAPREG_MEM_TYPE(address) !=
		    PCI_MAPREG_MEM_TYPE(type) &&
		    PCI_MAPREG_MEM_TYPE(address) !=
		    PCI_MAPREG_MEM_TYPE_64BIT) {
			printf("pci_mem_find: "
			    "expected mem type %08x, found %08x\n",
			    PCI_MAPREG_MEM_TYPE(type),
			    PCI_MAPREG_MEM_TYPE(address));
			return (1);
		}
	}

	waddress = (u_int64_t)address1 << 32UL | address;
	wmask = (u_int64_t)mask1 << 32UL | mask;

	if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
	    (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
		aprint_debug("pci_mem_find: void region\n");
		return (1);
	}

	switch (PCI_MAPREG_MEM_TYPE(address)) {
	case PCI_MAPREG_MEM_TYPE_32BIT:
	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
		break;
	case PCI_MAPREG_MEM_TYPE_64BIT:
		/*
		 * Handle the case of a 64-bit memory register on a
		 * platform with 32-bit addressing.  Make sure that
		 * the address assigned and the device's memory size
		 * fit in 32 bits.  We implicitly assume that if
		 * bus_addr_t is 64-bit, then so is bus_size_t.
		 */
		if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
		    (address1 != 0 || mask1 != 0xffffffff)) {
			printf("pci_mem_find: 64-bit memory map which is "
			    "inaccessible on a 32-bit platform\n");
			return (1);
		}
		break;
	default:
		printf("pci_mem_find: reserved mapping register type\n");
		return (1);
	}

	if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
		if (basep != 0)
			*basep = PCI_MAPREG_MEM_ADDR(address);
		if (sizep != 0)
			*sizep = PCI_MAPREG_MEM_SIZE(mask);
	} else {
		if (basep != 0)
			*basep = PCI_MAPREG_MEM64_ADDR(waddress);
		if (sizep != 0)
			*sizep = PCI_MAPREG_MEM64_SIZE(wmask);
	}
	if (flagsp != 0)
		*flagsp = (isrom || PCI_MAPREG_MEM_PREFETCHABLE(address)) ?
		    BUS_SPACE_MAP_PREFETCHABLE : 0;

	return (0);
}
Пример #7
0
void
pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag,
    pciaddr_resource_manage_func_t func, void *ctx)
{
	pcireg_t val, mask;
	bus_addr_t addr;
	bus_size_t size;
	int error, useport, usemem, mapreg, type, reg_start, reg_end, width;

	val = pci_conf_read(pc, tag, PCI_BHLC_REG);
	switch (PCI_HDRTYPE_TYPE(val)) {
	default:
		aprint_error("WARNING: unknown PCI device header.");
		pciaddr.nbogus++;
		return;
	case PCI_HDRTYPE_DEVICE:
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_END;
		break;
	case PCI_HDRTYPE_PPB: /* PCI-PCI bridge */
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_PPB_END;
		break;
	case PCI_HDRTYPE_PCB: /* PCI-CardBus bridge */
		reg_start = PCI_MAPREG_START;
		reg_end   = PCI_MAPREG_PCB_END;
		break;
	}
	error = useport = usemem = 0;

	for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
		/* inquire PCI device bus space requirement */
		val = pci_conf_read(pc, tag, mapreg);
		pci_conf_write(pc, tag, mapreg, ~0);

		mask = pci_conf_read(pc, tag, mapreg);
		pci_conf_write(pc, tag, mapreg, val);

		type = PCI_MAPREG_TYPE(val);
		width = 4;
		if (type == PCI_MAPREG_TYPE_MEM) {
			if (PCI_MAPREG_MEM_TYPE(val) ==
			    PCI_MAPREG_MEM_TYPE_64BIT) {
				/* XXX We could examine the upper 32 bits
				 * XXX of the BAR here, but we are totally
				 * XXX unprepared to handle a non-zero value,
				 * XXX either here or anywhere else in
				 * XXX i386-land.
				 * XXX So just arrange to not look at the
				 * XXX upper 32 bits, lest we misinterpret
				 * XXX it as a 32-bit BAR set to zero.
				 */
			    width = 8;
			}
			size = PCI_MAPREG_MEM_SIZE(mask);
		} else {
			size = PCI_MAPREG_IO_SIZE(mask);
		}
		addr = pciaddr_ioaddr(val);

		if (size == 0) /* unused register */
			continue;

		if (type == PCI_MAPREG_TYPE_MEM)
			++usemem;
		else
			++useport;

		/* reservation/allocation phase */
		error += (*func) (pc, tag, mapreg, ctx, type, &addr, size);

		aprint_debug("\n\t%02xh %s 0x%08x 0x%08x",
				mapreg, type ? "port" : "mem ",
				(unsigned int)addr, (unsigned int)size);
	}

	/* enable/disable PCI device */
	val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
	if (error == 0)
		val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
			PCI_COMMAND_MASTER_ENABLE);
	else
		val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
			 PCI_COMMAND_MASTER_ENABLE);
	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val);

	if (error != 0)
		pciaddr.nbogus++;

	aprint_debug("\n\t\t[%s]\n", error ? "NG" : "OK");
}
Пример #8
0
int
obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
    bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
{
	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr;
	u_int64_t waddress, wmask;
	int s, is64bit;

	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);

	if (reg < PCI_MAPREG_START ||
#if 0
	    /*
	     * Can't do this check; some devices have mapping registers
	     * way out in left field.
	     */
	    reg >= PCI_MAPREG_END ||
#endif
	    (reg & 3))
		panic("pci_mem_find: bad request");

	if (is64bit && (reg + 4) >= PCI_MAPREG_END)
		panic("pci_mem_find: bad 64-bit request");

	/*
	 * Section 6.2.5.1, `Address Maps', tells us that:
	 *
	 * 1) The builtin software should have already mapped the device in a
	 * reasonable way.
	 *
	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
	 * n bits of the address to 0.  As recommended, we write all 1s while
	 * the device is disabled and see what we get back.
	 */
	s = splhigh();
	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
	if (csr & PCI_COMMAND_MEM_ENABLE)
		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
		    csr & ~PCI_COMMAND_MEM_ENABLE);
	address = pci_conf_read(pc, tag, reg);
	pci_conf_write(pc, tag, reg, 0xffffffff);
	mask = pci_conf_read(pc, tag, reg);
	pci_conf_write(pc, tag, reg, address);
	if (is64bit) {
		address1 = pci_conf_read(pc, tag, reg + 4);
		pci_conf_write(pc, tag, reg + 4, 0xffffffff);
		mask1 = pci_conf_read(pc, tag, reg + 4);
		pci_conf_write(pc, tag, reg + 4, address1);
	}
	if (csr & PCI_COMMAND_MEM_ENABLE)
		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
	splx(s);

	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
#ifdef DEBUG
		printf("pci_mem_find: expected type mem, found i/o\n");
#endif
		return (EINVAL);
	}
	if (type != -1 && 
	    PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
#ifdef DEBUG
		printf("pci_mem_find: expected mem type %08x, found %08x\n",
		    PCI_MAPREG_MEM_TYPE(type),
		    PCI_MAPREG_MEM_TYPE(address));
#endif
		return (EINVAL);
	}

	waddress = (u_int64_t)address1 << 32UL | address;
	wmask = (u_int64_t)mask1 << 32UL | mask;

	if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
	    (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
#ifdef DEBUG
		printf("pci_mem_find: void region\n");
#endif
		return (ENOENT);
	}

	switch (PCI_MAPREG_MEM_TYPE(address)) {
	case PCI_MAPREG_MEM_TYPE_32BIT:
	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
		break;
	case PCI_MAPREG_MEM_TYPE_64BIT:
		/*
		 * Handle the case of a 64-bit memory register on a
		 * platform with 32-bit addressing.  Make sure that
		 * the address assigned and the device's memory size
		 * fit in 32 bits.  We implicitly assume that if
		 * bus_addr_t is 64-bit, then so is bus_size_t.
		 */
		if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
		    (address1 != 0 || mask1 != 0xffffffff)) {
#ifdef DEBUG
			printf("pci_mem_find: 64-bit memory map which is "
			    "inaccessible on a 32-bit platform\n");
#endif
			return (EINVAL);
		}
		break;
	default:
#ifdef DEBUG
		printf("pci_mem_find: reserved mapping register type\n");
#endif
		return (EINVAL);
	}

	if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
		if (basep != 0)
			*basep = PCI_MAPREG_MEM_ADDR(address);
		if (sizep != 0)
			*sizep = PCI_MAPREG_MEM_SIZE(mask);
	} else {
		if (basep != 0)
			*basep = PCI_MAPREG_MEM64_ADDR(waddress);
		if (sizep != 0)
			*sizep = PCI_MAPREG_MEM64_SIZE(wmask);
	}
	if (flagsp != 0)
		*flagsp =
#ifdef BUS_SPACE_MAP_PREFETCHABLE
		    PCI_MAPREG_MEM_PREFETCHABLE(address) ?
		      BUS_SPACE_MAP_PREFETCHABLE :
#endif
		  0;

	return (0);
}
/*
 * Enable memory and I/O on pci devices. Care about already enabled devices
 * (probabaly by the console driver).
 *
 * The idea behind the following code is:
 * We build a by sizes sorted list of the requirements of the different
 * pci devices. After that we choose the start addresses of that areas
 * in such a way that they are placed as closed as possible together.
 */
static void
enable_pci_devices(void)
{
    PCI_MEMREG memlist;
    PCI_MEMREG iolist;
    struct pci_memreg *p, *q;
    int dev, reg, id, class;
    pcitag_t tag;
    pcireg_t csr, address, mask;
    pci_chipset_tag_t pc;
    int sizecnt, membase_1m;

    pc = 0;
    csr = 0;
    tag = 0;

    LIST_INIT(&memlist);
    LIST_INIT(&iolist);

    /*
     * first step: go through all devices and gather memory and I/O
     * sizes
     */
    for (dev = 0; dev < pci_bus_maxdevs(pc,0); dev++) {

	tag = pci_make_tag(pc, 0, dev, 0);
	id  = pci_conf_read(pc, tag, PCI_ID_REG);
	if (id == 0 || id == 0xffffffff)
	    continue;

	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);

	/*
	 * special case: if a display card is found and memory is enabled
	 * preserve 128k at 0xa0000 as vga memory.
	 * XXX: if a display card is found without being enabled, leave
	 *      it alone! You will usually only create conflicts by enabeling
	 *      it.
	 */
	class = pci_conf_read(pc, tag, PCI_CLASS_REG);
	switch (PCI_CLASS(class)) {
	    case PCI_CLASS_PREHISTORIC:
	    case PCI_CLASS_DISPLAY:
	      if (csr & (PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) {
		    p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg),
				M_TEMP, M_WAITOK);
		    memset(p, '\0', sizeof(struct pci_memreg));
		    p->dev = dev;
		    p->csr = csr;
		    p->tag = tag;
		    p->reg = 0;     /* there is no register about this */
		    p->size = 0x20000;  /* 128kByte */
		    p->mask = 0xfffe0000;
		    p->address = 0xa0000;

		    insert_into_list(&memlist, p);
	      }
	      else continue;
	}

	for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {

	    address = pci_conf_read(pc, tag, reg);
	    pci_conf_write(pc, tag, reg, 0xffffffff);
	    mask    = pci_conf_read(pc, tag, reg);
	    pci_conf_write(pc, tag, reg, address);
	    if (mask == 0)
		continue; /* Register unused */

	    p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg),
			M_TEMP, M_WAITOK);
	    memset(p, '\0', sizeof(struct pci_memreg));
	    p->dev = dev;
	    p->csr = csr;
	    p->tag = tag;
	    p->reg = reg;
	    p->mask = mask;
	    p->address = 0;

	    if (mask & PCI_MAPREG_TYPE_IO) {
		p->size = PCI_MAPREG_IO_SIZE(mask);

		/*
		 * Align IO if necessary
		 */
		if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_IO_ALIGN_MASK)) {
		    p->mask = PCI_MACHDEP_IO_ALIGN_MASK;
		    p->size = PCI_MAPREG_IO_SIZE(p->mask);
		}

		/*
		 * if I/O is already enabled (probably by the console driver)
		 * save the address in order to take care about it later.
		 */
		if (csr & PCI_COMMAND_IO_ENABLE)
		    p->address = address;

		insert_into_list(&iolist, p);
	    } else {
		p->size = PCI_MAPREG_MEM_SIZE(mask);

		/*
		 * Align memory if necessary
		 */
		if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_MEM_ALIGN_MASK)) {
		    p->mask = PCI_MACHDEP_MEM_ALIGN_MASK;
		    p->size = PCI_MAPREG_MEM_SIZE(p->mask);
		}

		/*
		 * if memory is already enabled (probably by the console driver)
		 * save the address in order to take care about it later.
		 */
		if (csr & PCI_COMMAND_MEM_ENABLE)
		    p->address = address;

		insert_into_list(&memlist, p);

		if (PCI_MAPREG_MEM_TYPE(mask) == PCI_MAPREG_MEM_TYPE_64BIT)
		    reg++;
	    }
	}


#if defined(_ATARIHW_)
	/*
	 * Both interrupt pin & line are set to the device (== slot)
	 * number. This makes sense on the atari Hades because the
	 * individual slots are hard-wired to a specific MFP-pin.
	 */
	csr  = (DEV2SLOT(dev) << PCI_INTERRUPT_PIN_SHIFT);
	csr |= (DEV2SLOT(dev) << PCI_INTERRUPT_LINE_SHIFT);
	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, csr);
#else
	/*
	 * On the Milan, we accept the BIOS's choice.
	 */
#endif
    }

    /*
     * second step: calculate the memory and I/O addresses beginning from
     * PCI_MEM_START and PCI_IO_START. Care about already mapped areas.
     *
     * begin with memory list
     */

    address = PCI_MEM_START;
    sizecnt = 0;
    membase_1m = 0;
    p = LIST_FIRST(&memlist);
    while (p != NULL) {
	if (!(p->csr & PCI_COMMAND_MEM_ENABLE)) {
	    if (PCI_MAPREG_MEM_TYPE(p->mask) == PCI_MAPREG_MEM_TYPE_32BIT_1M) {
		if (p->size > membase_1m)
		    membase_1m = p->size;
		do {
		    p->address = membase_1m;
		    membase_1m += p->size;
		} while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address,
					   p->size, PCI_COMMAND_MEM_ENABLE));
		if (membase_1m > 0x00100000) {
		    /*
		     * Should we panic here?
		     */
		    printf("\npcibus0: dev %d reg %d: memory not configured",
			    p->dev, p->reg);
		    p->reg = 0;
		}
	    } else {

		if (sizecnt && (p->size > sizecnt))
		    sizecnt = ((p->size + sizecnt) & p->mask) &
			      PCI_MAPREG_MEM_ADDR_MASK;
		if (sizecnt > address) {
		    address = sizecnt;
		    sizecnt = 0;
		}

		do {
		    p->address = address + sizecnt;
		    sizecnt += p->size;
		} while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address,
					   p->size, PCI_COMMAND_MEM_ENABLE));

		if ((address + sizecnt) > PCI_MEM_END) {
		    /*
		     * Should we panic here?
		     */
		    printf("\npcibus0: dev %d reg %d: memory not configured",
			    p->dev, p->reg);
		    p->reg = 0;
		}
	    }
	    if (p->reg > 0) {
		pci_conf_write(pc, p->tag, p->reg, p->address);
		csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG);
		csr |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
		pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr);
		p->csr = csr;
	    }
	}
	p = LIST_NEXT(p, link);
    }

    /*
     * now the I/O list
     */

    address = PCI_IO_START;
    sizecnt = 0;
    p = LIST_FIRST(&iolist);
    while (p != NULL) {
	if (!(p->csr & PCI_COMMAND_IO_ENABLE)) {

	    if (sizecnt && (p->size > sizecnt))
		sizecnt = ((p->size + sizecnt) & p->mask) &
			  PCI_MAPREG_IO_ADDR_MASK;
	    if (sizecnt > address) {
		address = sizecnt;
		sizecnt = 0;
	    }

	    do {
		p->address = address + sizecnt;
		sizecnt += p->size;
	    } while (overlap_pci_areas(LIST_FIRST(&iolist), p, p->address,
				       p->size, PCI_COMMAND_IO_ENABLE));

	    if ((address + sizecnt) > PCI_IO_END) {
		/*
		 * Should we panic here?
		 */
		printf("\npcibus0: dev %d reg %d: io not configured",
			p->dev, p->reg);
	    } else {
		pci_conf_write(pc, p->tag, p->reg, p->address);
		csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG);
		csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
		pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr);
		p->csr = csr;
	    }
	}
	p = LIST_NEXT(p, link);
    }

#ifdef DEBUG_PCI_MACHDEP
    printf("\nI/O List:\n");
    p = LIST_FIRST(&iolist);

    while (p != NULL) {
	printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev,
			p->reg, p->size, p->address);
	p = LIST_NEXT(p, link);
    }
    printf("\nMemlist:");
    p = LIST_FIRST(&memlist);

    while (p != NULL) {
	printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev,
			p->reg, p->size, p->address);
	p = LIST_NEXT(p, link);
    }
#endif

    /*
     * Free the lists
     */
    p = LIST_FIRST(&iolist);
    while (p != NULL) {
	q = p;
	LIST_REMOVE(q, link);
	free(p, M_WAITOK);
	p = LIST_FIRST(&iolist);
    }
    p = LIST_FIRST(&memlist);
    while (p != NULL) {
	q = p;
	LIST_REMOVE(q, link);
	free(p, M_WAITOK);
	p = LIST_FIRST(&memlist);
    }
}