Exemple #1
0
static bool radeon_read_bios(struct radeon_device *rdev)
{
	uint8_t __iomem *bios;
	bus_size_t size;
	pcireg_t address, mask;
	bus_space_handle_t romh;
	int rc;

	rdev->bios = NULL;
	/* XXX: some cards may return 0 for rom size? ddx has a workaround */

	address = pci_conf_read(rdev->pc, rdev->pa_tag, PCI_ROM_REG);
	pci_conf_write(rdev->pc, rdev->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
	mask = pci_conf_read(rdev->pc, rdev->pa_tag, PCI_ROM_REG);
	address |= PCI_ROM_ENABLE;
	pci_conf_write(rdev->pc, rdev->pa_tag, PCI_ROM_REG, address);

	size = PCI_ROM_SIZE(mask);
	if (size == 0)
		return false;
	rc = bus_space_map(rdev->memt, PCI_ROM_ADDR(address), size,
	    BUS_SPACE_MAP_LINEAR, &romh);
	if (rc != 0) {
		printf(": can't map PCI ROM (%d)\n", rc);
		return false;
	}
	bios = (uint8_t *)bus_space_vaddr(rdev->memt, romh);
	if (!bios) {
		printf(": bus_space_vaddr failed\n");
		return false;
	}

	if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa)
		goto fail;
	rdev->bios = kmalloc(size, GFP_KERNEL);
	memcpy(rdev->bios, bios, size);
	bus_space_unmap(rdev->memt, romh, size);
	return true;
fail:
	bus_space_unmap(rdev->memt, romh, size);
	return false;
}
Exemple #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;
}
int
cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa)
{
	struct pci_vpd_largeres *res;
	struct pci_vpd *vpd;
	bus_space_handle_t romh;
	bus_space_tag_t romt;
	bus_size_t romsize;
	u_int8_t buf[32], *desc;
	pcireg_t address, mask;
	int dataoff, vpdoff, len;
	int rv = -1;

	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe);
	mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	address |= PCI_ROM_ENABLE;
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);

	romt = pa->pa_memt;
	romsize = PCI_ROM_SIZE(mask);
	if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) {
		romsize = 0;
		goto fail;
	}

	bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
	if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr)))
		goto fail;

	dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
	if (dataoff < 0x1c)
		goto fail;

	bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
	if (bcmp(buf, cas_promdat, sizeof(cas_promdat)) ||
	    bcmp(buf + PROMDATA_DATA2, cas_promdat2, sizeof(cas_promdat2)))
		goto fail;

	vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
	if (vpdoff < 0x1c)
		goto fail;

next:
	bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
	if (!PCI_VPDRES_ISLARGE(buf[0]))
		goto fail;

	res = (struct pci_vpd_largeres *)buf;
	vpdoff += sizeof(*res);

	len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb);
	switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)) {
	case PCI_VPDRES_TYPE_IDENTIFIER_STRING:
		/* Skip identifier string. */
		vpdoff += len;
		goto next;

	case PCI_VPDRES_TYPE_VPD:
		while (len > 0) {
			bus_space_read_region_1(romt, romh, vpdoff,
			     buf, sizeof(buf));

			vpd = (struct pci_vpd *)buf;
			vpdoff += sizeof(*vpd) + vpd->vpd_len;
			len -= sizeof(*vpd) + vpd->vpd_len;

			/*
			 * We're looking for an "Enhanced" VPD...
			 */
			if (vpd->vpd_key0 != 'Z')
				continue;

			desc = buf + sizeof(*vpd);

			/* 
			 * ...which is an instance property...
			 */
			if (desc[0] != 'I')
				continue;
			desc += 3;

			/* 
			 * ...that's a byte array with the proper
			 * length for a MAC address...
			 */
			if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN)
				continue;
			desc += 2;

			/*
			 * ...named "local-mac-address".
			 */
			if (strcmp(desc, "local-mac-address") != 0)
				continue;
			desc += strlen("local-mac-address") + 1;
					
			bcopy(desc, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
			rv = 0;
		}
		break;

	default:
		goto fail;
	}

 fail:
	if (romsize != 0)
		bus_space_unmap(romt, romh, romsize);

	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	address &= ~PCI_ROM_ENABLE;
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);

	return (rv);
}
Exemple #4
0
int
gem_pci_enaddr(struct gem_softc *sc, struct pci_attach_args *pa)
{
	struct pci_vpd *vpd;
	bus_space_handle_t romh;
	bus_space_tag_t romt;
	bus_size_t romsize;
	u_int8_t buf[32];
	pcireg_t address, mask;
	int dataoff, vpdoff;
	int rv = -1;

	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe);
	mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	address |= PCI_ROM_ENABLE;
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);

	romt = pa->pa_memt;
	romsize = PCI_ROM_SIZE(mask);
	if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) {
		romsize = 0;
		goto fail;
	}

	bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
	if (bcmp(buf, gem_promhdr, sizeof(gem_promhdr)))
		goto fail;

	dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
	if (dataoff < 0x1c)
		goto fail;

	bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
	if (bcmp(buf, gem_promdat, sizeof(gem_promdat)) ||
	    bcmp(buf + PROMDATA_DATA2, gem_promdat2, sizeof(gem_promdat2)))
		goto fail;

	vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
	if (vpdoff < 0x1c)
		goto fail;

	bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));

	/*
	 * The VPD of gem is not in PCI 2.2 standard format.  The length
	 * in the resource header is in big endian.
	 */
	vpd = (struct pci_vpd *)(buf + 3);
	if (!PCI_VPDRES_ISLARGE(buf[0]) ||
	    PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD)
		goto fail;
	if (vpd->vpd_key0 != 'N' || vpd->vpd_key1 != 'A')
		goto fail;

	bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
	rv = 0;

 fail:
	if (romsize != 0)
		bus_space_unmap(romt, romh, romsize);

	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	address &= ~PCI_ROM_ENABLE;
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);

	return (rv);
}
Exemple #5
0
/*
 * Grovel the STI ROM image.
 */
int
sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa)
{
	struct sti_softc *sc = &spc->sc_base;
	pcireg_t address, mask;
	bus_space_handle_t romh;
	bus_size_t romsize, subsize, stiromsize;
	bus_addr_t selected, offs, suboffs;
	u_int32_t tmp;
	int i;
	int rc;

	/* sort of inline sti_pci_enable_rom(sc) */
	address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
	mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
	address |= PCI_ROM_ENABLE;
	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
	sc->sc_flags |= STI_ROM_ENABLED;

	/*
	 * Map the complete ROM for now.
	 */

	romsize = PCI_ROM_SIZE(mask);
	rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize,
	    0, &romh);
	sti_pci_disable_rom(sc);
	if (rc != 0) {
		printf("%s: can't map PCI ROM (%d)\n",
		    sc->sc_dev.dv_xname, rc);
		goto fail2;
	}

	/*
	 * Iterate over the ROM images, pick the best candidate.
	 */

	selected = (bus_addr_t)-1;
	for (offs = 0; offs < romsize; offs += subsize) {
		sti_pci_enable_rom(sc);
		/*
		 * Check for a valid ROM header.
		 */
		tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
		tmp = letoh32(tmp);
		if (tmp != 0x55aa0000) {
			sti_pci_disable_rom(sc);
			if (offs == 0) {
				printf("%s: invalid PCI ROM header signature"
				    " (%08x)\n",
				    sc->sc_dev.dv_xname, tmp);
				rc = EINVAL;
			}
			break;
		}

		/*
		 * Check ROM type.
		 */
		tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
		tmp = letoh32(tmp);
		if (tmp != 0x00000001) {	/* 1 == STI ROM */
			sti_pci_disable_rom(sc);
			if (offs == 0) {
				printf("%s: invalid PCI ROM type (%08x)\n",
				    sc->sc_dev.dv_xname, tmp);
				rc = EINVAL;
			}
			break;
		}

		subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
		    offs + 0x0c);
		subsize <<= 9;

#ifdef STIDEBUG
		sti_pci_disable_rom(sc);
		printf("ROM offset %08lx size %08lx type %08x",
		    offs, subsize, tmp);
		sti_pci_enable_rom(sc);
#endif

		/*
		 * Check for a valid ROM data structure.
		 * We do not need it except to know what architecture the ROM
		 * code is for.
		 */

		suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
		    offs + 0x18);
		tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
		tmp = letoh32(tmp);
		if (tmp != 0x50434952) {	/* PCIR */
			sti_pci_disable_rom(sc);
			if (offs == 0) {
				printf("%s: invalid PCI data signature"
				    " (%08x)\n",
				    sc->sc_dev.dv_xname, tmp);
				rc = EINVAL;
			} else {
#ifdef STIDEBUG
				printf(" invalid PCI data signature %08x\n",
				    tmp);
#endif
				continue;
			}
		}

		tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
		sti_pci_disable_rom(sc);
#ifdef STIDEBUG
		printf(" code %02x", tmp);
#endif

		switch (tmp) {
#ifdef __hppa__
		case 0x10:
			if (selected == (bus_addr_t)-1)
				selected = offs;
			break;
#endif
#ifdef __i386__
		case 0x00:
			if (selected == (bus_addr_t)-1)
				selected = offs;
			break;
#endif
		default:
#ifdef STIDEBUG
			printf(" (wrong architecture)");
#endif
			break;
		}

#ifdef STIDEBUG
		if (selected == offs)
			printf(" -> SELECTED");
		printf("\n");
#endif
	}

	if (selected == (bus_addr_t)-1) {
		if (rc == 0) {
			printf("%s: found no ROM with correct microcode"
			    " architecture\n", sc->sc_dev.dv_xname);
			rc = ENOEXEC;
		}
		goto fail;
	}

	/*
	 * Read the STI region BAR assignments.
	 */

	sti_pci_enable_rom(sc);
	offs = selected +
	    (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
	for (i = 0; i < STI_REGION_MAX; i++) {
		rc = sti_readbar(sc, pa, i,
		    bus_space_read_1(pa->pa_memt, romh, offs + i));
		if (rc != 0)
			goto fail;
	}

	/*
	 * Find out where the STI ROM itself lies, and its size.
	 */

	offs = selected +
	    (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
	stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
	    offs + 0x18);
	stiromsize = letoh32(stiromsize);
	sti_pci_disable_rom(sc);

	/*
	 * Replace our mapping with a smaller mapping of only the area
	 * we are interested in.
	 */

	bus_space_unmap(pa->pa_memt, romh, romsize);
	rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs,
	    stiromsize, 0, &spc->sc_romh);
	if (rc != 0) {
		printf("%s: can't map STI ROM (%d)\n",
		    sc->sc_dev.dv_xname, rc);
		goto fail2;
	}

	return (0);

fail:
	bus_space_unmap(pa->pa_memt, romh, romsize);
fail2:
	sti_pci_disable_rom(sc);

	return (rc);
}