diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-14 13:05:21 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-14 13:05:21 -0800 | 
| commit | 4964e0664c80680fa6b28ef91381c076a5b25c2c (patch) | |
| tree | 62099c5aaeee7274bcc66bcfba35d479affa97cf /arch/mips/pci/pci-xlr.c | |
| parent | 0a80939b3e6af4b0dc93bf88ec02fd7e90a16f1b (diff) | |
| parent | 7bf6612e8a9d6a0b3b82e8e2611942be1258b307 (diff) | |
| download | olio-linux-3.10-4964e0664c80680fa6b28ef91381c076a5b25c2c.tar.xz olio-linux-3.10-4964e0664c80680fa6b28ef91381c076a5b25c2c.zip  | |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (119 commits)
  MIPS: Delete unused function add_temporary_entry.
  MIPS: Set default pci cache line size.
  MIPS: Flush huge TLB
  MIPS: Octeon: Remove SYS_SUPPORTS_HIGHMEM.
  MIPS: Octeon: Add support for OCTEON II PCIe
  MIPS: Octeon: Update PCI Latency timer and enable more error reporting.
  MIPS: Alchemy: Update cpu-feature-overrides
  MIPS: Alchemy: db1200: Improve PB1200 detection.
  MIPS: Alchemy: merge Au1000 and Au1300-style IRQ controller code.
  MIPS: Alchemy: chain IRQ controllers to MIPS IRQ controller
  MIPS: Alchemy: irq: register pm at irq init time
  MIPS: Alchemy: Touchscreen support on DB1100
  MIPS: Alchemy: Hook up IrDA on DB1000/DB1100
  net/irda: convert au1k_ir to platform driver.
  MIPS: Alchemy: remove unused board headers
  MTD: nand: make au1550nd.c a platform_driver
  MIPS: Netlogic: Mark Netlogic chips as SMT capable
  MIPS: Netlogic: Add support for XLP 3XX cores
  MIPS: Netlogic: Merge some of XLR/XLP wakup code
  MIPS: Netlogic: Add default XLP config.
  ...
Fix up trivial conflicts in arch/mips/kernel/{perf_event_mipsxx.c,
traps.c} and drivers/tty/serial/Makefile
Diffstat (limited to 'arch/mips/pci/pci-xlr.c')
| -rw-r--r-- | arch/mips/pci/pci-xlr.c | 128 | 
1 files changed, 127 insertions, 1 deletions
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 38fece16c43..3d701a962ef 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c @@ -36,12 +36,18 @@  #include <linux/pci.h>  #include <linux/kernel.h>  #include <linux/init.h> +#include <linux/msi.h>  #include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h>  #include <linux/console.h>  #include <asm/io.h>  #include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> + +#include <asm/netlogic/xlr/msidef.h>  #include <asm/netlogic/xlr/iomap.h>  #include <asm/netlogic/xlr/pic.h>  #include <asm/netlogic/xlr/xlr.h> @@ -150,7 +156,7 @@ struct pci_controller nlm_pci_controller = {  	.io_offset      = 0x00000000UL,  }; -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int get_irq_vector(const struct pci_dev *dev)  {  	if (!nlm_chip_is_xls())  		return	PIC_PCIX_IRQ;	/* for XLR just one IRQ*/ @@ -182,6 +188,101 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  	return 0;  } +#ifdef CONFIG_PCI_MSI +void destroy_irq(unsigned int irq) +{ +	    /* nothing to do yet */ +} + +void arch_teardown_msi_irq(unsigned int irq) +{ +	destroy_irq(irq); +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ +	struct msi_msg msg; +	int irq, ret; + +	irq = get_irq_vector(dev); +	if (irq <= 0) +		return 1; + +	msg.address_hi = MSI_ADDR_BASE_HI; +	msg.address_lo = MSI_ADDR_BASE_LO   | +		MSI_ADDR_DEST_MODE_PHYSICAL | +		MSI_ADDR_REDIRECTION_CPU; + +	msg.data = MSI_DATA_TRIGGER_EDGE | +		MSI_DATA_LEVEL_ASSERT    | +		MSI_DATA_DELIVERY_FIXED; + +	ret = irq_set_msi_desc(irq, desc); +	if (ret < 0) { +		destroy_irq(irq); +		return ret; +	} + +	write_msi_msg(irq, &msg); +	return 0; +} +#endif + +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ +	uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET); + +	nlm_read_reg(pcibase, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ +	uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + +	switch (d->irq) { +	case PIC_PCIE_LINK0_IRQ: +		nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK1_IRQ: +		nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK2_IRQ: +		nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK3_IRQ: +		nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); +		break; +	} +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ +	uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + +	switch (d->irq) { +	case PIC_PCIE_LINK0_IRQ: +		nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK1_IRQ: +		nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_XLSB0_LINK2_IRQ: +		nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_XLSB0_LINK3_IRQ: +		nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); +		break; +	} +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	return get_irq_vector(dev); +} +  /* Do platform specific device initialization at pci_enable_device() time */  int pcibios_plat_dev_init(struct pci_dev *dev)  { @@ -204,6 +305,31 @@ static int __init pcibios_init(void)  	pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n");  	register_pci_controller(&nlm_pci_controller); +	/* +	 * For PCI interrupts, we need to ack the PCI controller too, overload +	 * irq handler data to do this +	 */ +	if (nlm_chip_is_xls()) { +		if (nlm_chip_is_xls_b()) { +			irq_set_handler_data(PIC_PCIE_LINK0_IRQ, +							xls_pcie_ack_b); +			irq_set_handler_data(PIC_PCIE_LINK1_IRQ, +							xls_pcie_ack_b); +			irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, +							xls_pcie_ack_b); +			irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, +							xls_pcie_ack_b); +		} else { +			irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); +			irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); +			irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); +			irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); +		} +	} else { +		/* XLR PCI controller ACK */ +		irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); +	} +  	return 0;  }  |