Exemple #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;
}
Exemple #2
0
int
apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
    pci_chipset_tag_t pc = pa->pa_pc;
    struct elroy_softc *sc = pc->_cookie;
    pcitag_t tag = pa->pa_tag;
    hppa_hpa_t hpa = cpu_gethpa(0);
    pcireg_t reg;

    reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
    printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), PCI_INTERRUPT_LINE(reg));
    apic_write(sc->sc_regs, APIC_ENT0(PCI_INTERRUPT_PIN(reg)),
               PCI_INTERRUPT_LINE(reg));
    apic_write(sc->sc_regs, APIC_ENT1(PCI_INTERRUPT_PIN(reg)),
               ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
    *ihp = PCI_INTERRUPT_LINE(reg) + 1;
    return (*ihp == 0);
}
Exemple #3
0
int
apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
	struct elroy_softc *sc = pa->pa_pc->_cookie;
	pci_chipset_tag_t pc = pa->pa_pc;
	pcitag_t tag = pa->pa_tag;
	pcireg_t reg;
	int line;

	reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
#ifdef DEBUG
	printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg),
	    PCI_INTERRUPT_LINE(reg));
#endif
	line = PCI_INTERRUPT_LINE(reg);
	if (sc->sc_irq[line] == 0)
		sc->sc_irq[line] = cpu_intr_findirq();
	*ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
	return (APIC_INT_IRQ(*ihp) == 0);
}
Exemple #4
0
static int
pci_scan_bus(struct pci_bus *bus)
{
	int totaldev = 0;
	struct pci_func df;
	memset(&df, 0, sizeof(df));
	df.bus = bus;

	for (df.dev = 0; df.dev < 32; df.dev++) {
		uint32_t bhlc = pci_conf_read(&df, PCI_BHLC_REG);
		struct pci_func f;
		if (PCI_HDRTYPE_TYPE(bhlc) > 1)	/* Unsupported or no device */
			continue;

		/* found a device */
		totaldev++;
		f = df;

		for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1);
				f.func++) {
			struct pci_func *af;
			uint32_t dev_id;
			uint32_t intr;

			dev_id = pci_conf_read(&f, PCI_ID_REG);
			if (PCI_VENDOR(dev_id) == 0xffff)
				continue;	

			/* found a function */
			af = kmem_alloc(sizeof(*af));
			*af = f;
			list_init(&af->link);
			list_insert(&pci_func_list, &af->link);
			af->dev_id = dev_id;

			intr = pci_conf_read(af, PCI_INTERRUPT_REG);
			af->irq_line = PCI_INTERRUPT_LINE(intr);
			af->dev_class = pci_conf_read(af, PCI_CLASS_REG);
#ifdef SHOW_PCI_VERBOSE_INFO
			pci_print_func(af);
#endif
		}
	}

	return totaldev;
}
int
pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
	pcireg_t intr;
	int pin;
	int line;

	intr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG);
	pin = pa->pa_intrpin;
	pa->pa_intrline = line = PCI_INTERRUPT_LINE(intr);
#if 0 /* XXXX why is it always 0 ? */
	if (pin == 0) {
		/* No IRQ used */
		goto bad;
	}
#endif
	if (pin > PCI_INTERRUPT_PIN_MAX) {
		printf("pci_intr_map: bad interrupt pin %d\n", pin);
		goto bad;
	}

	if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
		printf("pci_intr_map: no mapping for pin %c (line=%02x)\n",
		    '@' + pin, line);
		goto bad;
	}

	ihp->pirq = line;
	ihp->evtch = bind_pirq_to_evtch(ihp->pirq);
	if (ihp->evtch == -1)
		goto bad;

	return 0;

bad:
	ihp->pirq = -1;
	ihp->evtch = -1;
	return 1;
}
Exemple #6
0
void
kauaiataattach(struct device *parent, struct device *self, void *aux)
{
	int node;
	struct confargs ca;
	int namelen;
	u_int32_t reg[20];
	char name[32];
	int32_t intr[8];

	struct kauaiata_softc *sc = (struct kauaiata_softc *)self;
	struct pci_attach_args *pa = aux;
	pci_chipset_tag_t pc = pa->pa_pc;

	/* XXX assumes that this is /pci@f400000/ata-6 */

	/*
vendor 0x106b product 0x003b (class undefined unknown subclass 0x00, rev 0x00) at pci2 dev 13 function 0 not configured
	*/

	node = OF_finddevice("/pci@f4000000/ata-6");

	/*
	 * XXX - need to compare node and PCI id to verify this is the 
	 * correct device.
	 */

	ca.ca_nreg  = OF_getprop(node, "reg", reg, sizeof(reg));

	intr[0] = PCI_INTERRUPT_LINE(pci_conf_read(pc, pa->pa_tag,
	    PCI_INTERRUPT_REG));
	ca.ca_nintr = 4; /* claim to have 4 bytes of interrupt info */
	/* This needs to come from INTERRUPT REG above, but is not filled out */
	intr[0] = 0x27;

	namelen = OF_getprop(node, "name", name, sizeof(name));
	if ((namelen < 0) || (namelen >= sizeof(name))) {
		printf(" bad name prop len %x\n", namelen);
		return;
	}

	name[namelen] = 0; /* name property may not be null terminated */

	/* config read */
	sc->sc_membus_space.bus_base =
	    pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START);
#if 0
	pci_conf_write(pc, pa->pa_tag, PCI_MAPREG_START, 0xffffffff);
	size =  ~(pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START));
	pci_conf_write(pc, pa->pa_tag, PCI_MAPREG_START,
		sc->sc_membus_space.bus_base);
#endif

	ca.ca_baseaddr = sc->sc_membus_space.bus_base;

	sc->sc_membus_space.bus_reverse = 1;

	ca.ca_name = name;
	ca.ca_iot = &sc->sc_membus_space;
	ca.ca_dmat = pa->pa_dmat;

	ca.ca_reg = reg;
	reg[0] = 0x2000; /* offset to wdc registers */
	reg[1] = reg[9] - 0x2000; /* map size of wdc registers */
	reg[2] = 0x1000; /* offset to dbdma registers */
	reg[3] = 0x1000; /* map size of dbdma registers */
	ca.ca_intr = intr;

	printf("\n");

	config_found(self, &ca, kauaiata_print);
}
Exemple #7
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;
}