示例#1
0
void
fix_node_irq(int node, struct pcibus_attach_args *pba)
{
	struct { 
		u_int32_t phys_hi, phys_mid, phys_lo;
		u_int32_t size_hi, size_lo;
	} addr [8];
	u_int32_t map[144];
	int len;
	pcitag_t tag;
	u_int32_t irq;
	u_int32_t intr;
	int parent;

	pci_chipset_tag_t pc = pba->pba_pc;

	len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr));
	if (len == -1 || len < sizeof(addr[0]))
		return;

	/* if this node has a AAPL,interrupts property, firmware
	 * has initialized the register correctly.
	 */
	len = OF_getprop(node, "AAPL,interrupts", &intr, 4);
	if (len != 4) {

		parent = OF_parent(node);

		irq = -1;

		/* we want the first interrupt, set size_hi to 1 */
		addr[0].size_hi = 1;
		if (find_node_intr(parent, &addr[0].phys_hi, &irq) == -1) {
			len = OF_getprop(node, "interrupts", map,
			    sizeof(map));
			if (len != -1 && len != 4) {
				irq = map[0];
			} else 
				return;
		}
	} else
		irq = intr;
	/* program the interrupt line register with the value
	 * found in openfirmware
	 */

	tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
	    pcidev(addr[0].phys_hi), pcifunc(addr[0].phys_hi));

	intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
	intr &= ~PCI_INTERRUPT_LINE_MASK;
	intr |= irq & PCI_INTERRUPT_LINE_MASK;
	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
}
示例#2
0
static void
fixpci(int parent, pci_chipset_tag_t pc)
{
	int node;
	pcitag_t tag;
	pcireg_t csr, intr, id, cr;
	int len, i, ilen;
	int32_t irqs[4];
	struct {
		u_int32_t phys_hi, phys_mid, phys_lo;
		u_int32_t size_hi, size_lo;
	} addr[8];
	struct {
		u_int32_t phys_hi, phys_mid, phys_lo;
		u_int32_t icells[5];
	} iaddr;

	/*
	 * first hack - here we make the Ethernet portion of a
	 * UMAX E100 card work
	 */
#ifdef UMAX_E100_HACK
	tag = pci_make_tag(pc, 0, 17, 0);
	id = pci_conf_read(pc, tag, PCI_ID_REG);
	if ((PCI_VENDOR(id) == PCI_VENDOR_DEC) &&
	    (PCI_PRODUCT(id) == PCI_PRODUCT_DEC_21140)) {
		/* this could be one */
		pcireg_t isp, reg;
		pcitag_t tag_isp = pci_make_tag(pc, 0, 13, 0);
		/*
		 * here we go. We shouldn't encounter this anywhere else
		 * than on a UMAX S900 with an E100 board 
		 * look at 00:0d:00 for a Qlogic ISP 1020 to
		 * make sure we really have an E100 here 
		 */
		aprint_debug("\nfound E100 candidate tlp");
		isp = pci_conf_read(pc, tag_isp, PCI_ID_REG);
		if ((PCI_VENDOR(isp) == PCI_VENDOR_QLOGIC) &&
		    (PCI_PRODUCT(isp) == PCI_PRODUCT_QLOGIC_ISP1020)) {

			aprint_verbose("\nenabling UMAX E100 ethernet");

			pci_conf_write(pc, tag, 0x14, 0x80000000);

			/* now enable MMIO and busmastering */
			reg = pci_conf_read(pc, tag,
			    PCI_COMMAND_STATUS_REG);
			reg |= PCI_COMMAND_MEM_ENABLE |
			       PCI_COMMAND_MASTER_ENABLE;
			pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
			    reg);

			/* and finally the interrupt */
			reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
			reg &= ~PCI_INTERRUPT_LINE_MASK;
			reg |= 23;
			pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
		}
	}
#endif

	len = OF_getprop(parent, "#interrupt-cells", &ilen, sizeof(ilen));
	if (len < 0)            
		ilen = 0;       
	for (node = OF_child(parent); node; node = OF_peer(node)) {
		len = OF_getprop(node, "assigned-addresses", addr,
				 sizeof(addr));
		if (len < (int)sizeof(addr[0]))
			continue;

		tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
				   pcidev(addr[0].phys_hi),
				   pcifunc(addr[0].phys_hi));

		/*
		 * Make sure the IO and MEM enable bits are set in the CSR.
		 */
		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
		csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);

		for (i = 0; i < len / sizeof(addr[0]); i++) {
			switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
			case OFW_PCI_PHYS_HI_SPACE_IO:
				csr |= PCI_COMMAND_IO_ENABLE;
				break;

			case OFW_PCI_PHYS_HI_SPACE_MEM32:
			case OFW_PCI_PHYS_HI_SPACE_MEM64:
				csr |= PCI_COMMAND_MEM_ENABLE;
				break;
			}
		}

		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);

		/*
		 * Make sure the line register is programmed with the
		 * interrupt mapping.
		 */
		if (ilen == 0) {
			/*
			 * Early Apple OFW implementation don't handle
			 * interrupts as defined by the OFW PCI bindings.
			 */
			len = OF_getprop(node, "AAPL,interrupts", irqs, 4);
		} else {
			iaddr.phys_hi = addr[0].phys_hi;
			iaddr.phys_mid = addr[0].phys_mid;
			iaddr.phys_lo = addr[0].phys_lo;
			/*
			 * Thankfully, PCI can only have one entry in its
			 * "interrupts" property.
			 */
			len = OF_getprop(node, "interrupts", &iaddr.icells[0],
			    4*ilen);
			if (len != 4*ilen)
				continue;
			len = find_node_intr(node, &iaddr.phys_hi, irqs);
		}
		if (len <= 0) {
			/*
			 * If we still don't have an interrupt, try one
			 * more time.  This case covers devices behind the
			 * PCI-PCI bridge in a UMAX S900 or similar (9500?)
			 * system.  These slots all share the bridge's
			 * interrupt.
			 */
			len = find_node_intr(node, &addr[0].phys_hi, irqs);
			if (len <= 0)
				continue;
		}

		/* 
		 * For PowerBook 2400, 3400 and original G3:
		 * check if we have a 2nd ohare PIC - if so frob the built-in 
		 * tlp's IRQ to 60
		 * first see if we have something on bus 0 device 13 and if 
		 * it's a DEC 21041
		 */
		id = pci_conf_read(pc, tag, PCI_ID_REG);
		if ((tag == pci_make_tag(pc, 0, 13, 0)) &&
		    (PCI_VENDOR(id) == PCI_VENDOR_DEC) && 
		    (PCI_PRODUCT(id) == PCI_PRODUCT_DEC_21041)) {

			/* now look for the 2nd ohare */
			if (OF_finddevice("/bandit/pci106b,7") != -1) {

				irqs[0] = 60;
				aprint_verbose("\nohare: frobbing tlp IRQ to 60");
			}
		}

		intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
		intr &= ~PCI_INTERRUPT_LINE_MASK;
		intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK;
		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);

		/* fix secondary bus numbers on CardBus bridges */
		cr = pci_conf_read(pc, tag, PCI_CLASS_REG);
		if ((PCI_CLASS(cr) == PCI_CLASS_BRIDGE) &&
		    (PCI_SUBCLASS(cr) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
			uint32_t bi, busid;

			/*
			 * we found a CardBus bridge. Check if the bus number
			 * is sane
			 */
			bi = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
			busid = bi & 0xff;
			if (busid == 0) {
				fix_cardbus_bridge(node, pc, tag);
			}
		}
	}
}