Commit c24a8a7a authored by Jayachandran C's avatar Jayachandran C Committed by Ralf Baechle

MIPS: Netlogic: Add MSI support for XLP

Add MSI chip and MSIX chip definitions.

For MSI, we map the link interrupt to a MSI link IRQ which will
do a second level of dispatch based on the MSI status register.

The MSI chip definitions use the MSI enable register to enable
and disable the MSI irqs.

For MSI-X, we split the 32 available MSI-X vectors across the
four PCIe links (8 each). These PIC interrupts generate an IRQ
per link which uses a second level dispatch as well.

The MSI-X chip definition uses the standard functions to enable
and disable interrupts.
Signed-off-by: default avatarJayachandran C <jchandra@broadcom.com>
Signed-off-by: default avatarJohn Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/6270/
parent 27547abf
...@@ -775,6 +775,7 @@ config NLM_XLP_BOARD ...@@ -775,6 +775,7 @@ config NLM_XLP_BOARD
select CEVT_R4K select CEVT_R4K
select CSRC_R4K select CSRC_R4K
select IRQ_CPU select IRQ_CPU
select ARCH_SUPPORTS_MSI
select ZONE_DMA32 if 64BIT select ZONE_DMA32 if 64BIT
select SYNC_R4K select SYNC_R4K
select SYS_HAS_EARLY_PRINTK select SYS_HAS_EARLY_PRINTK
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
#define __ASM_NETLOGIC_IRQ_H #define __ASM_NETLOGIC_IRQ_H
#include <asm/mach-netlogic/multi-node.h> #include <asm/mach-netlogic/multi-node.h>
#define NR_IRQS (64 * NLM_NR_NODES) #define NLM_IRQS_PER_NODE 1024
#define NR_IRQS (NLM_IRQS_PER_NODE * NLM_NR_NODES)
#define MIPS_CPU_IRQ_BASE 0 #define MIPS_CPU_IRQ_BASE 0
......
...@@ -112,8 +112,14 @@ struct nlm_soc_info { ...@@ -112,8 +112,14 @@ struct nlm_soc_info {
struct irq_data; struct irq_data;
uint64_t nlm_pci_irqmask(int node); uint64_t nlm_pci_irqmask(int node);
void nlm_setup_pic_irq(int node, int picirq, int irq, int irt);
void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)); void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *));
#ifdef CONFIG_PCI_MSI
void nlm_dispatch_msi(int node, int lirq);
void nlm_dispatch_msix(int node, int msixirq);
#endif
/* /*
* The NR_IRQs is divided between nodes, each of them has a separate irq space * The NR_IRQs is divided between nodes, each of them has a separate irq space
*/ */
......
...@@ -52,25 +52,42 @@ ...@@ -52,25 +52,42 @@
#define PCIE_BYTE_SWAP_MEM_LIM 0x248 #define PCIE_BYTE_SWAP_MEM_LIM 0x248
#define PCIE_BYTE_SWAP_IO_BASE 0x249 #define PCIE_BYTE_SWAP_IO_BASE 0x249
#define PCIE_BYTE_SWAP_IO_LIM 0x24A #define PCIE_BYTE_SWAP_IO_LIM 0x24A
#define PCIE_BRIDGE_MSIX_ADDR_BASE 0x24F
#define PCIE_BRIDGE_MSIX_ADDR_LIMIT 0x250
#define PCIE_MSI_STATUS 0x25A #define PCIE_MSI_STATUS 0x25A
#define PCIE_MSI_EN 0x25B #define PCIE_MSI_EN 0x25B
#define PCIE_MSIX_STATUS 0x25D
#define PCIE_INT_STATUS0 0x25F
#define PCIE_INT_STATUS1 0x260
#define PCIE_INT_EN0 0x261 #define PCIE_INT_EN0 0x261
#define PCIE_INT_EN1 0x262
/* PCIE_MSI_EN */ /* other */
#define PCIE_MSI_VECTOR_INT_EN 0xFFFFFFFF #define PCIE_NLINKS 4
/* PCIE_INT_EN0 */
#define PCIE_MSI_INT_EN (1 << 9)
/* MSI addresses */
#define MSI_ADDR_BASE 0xfffee00000ULL
#define MSI_ADDR_SZ 0x10000
#define MSI_LINK_ADDR(n, l) (MSI_ADDR_BASE + \
(PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ)
#define MSIX_ADDR_BASE 0xfffef00000ULL
#define MSIX_LINK_ADDR(n, l) (MSIX_ADDR_BASE + \
(PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) #define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r)
#define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v)
#define nlm_get_pcie_base(node, inst) \ #define nlm_get_pcie_base(node, inst) \
nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst)) nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
#define nlm_get_pcie_regbase(node, inst) \
(nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ)
int xlp_pcie_link_irt(int link); #ifdef CONFIG_PCI_MSI
void xlp_init_node_msi_irqs(int node, int link);
#else
static inline void xlp_init_node_msi_irqs(int node, int link) {}
#endif
struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev);
#endif #endif
#endif /* __NLM_HAL_PCIBUS_H__ */ #endif /* __NLM_HAL_PCIBUS_H__ */
...@@ -193,14 +193,9 @@ ...@@ -193,14 +193,9 @@
#define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) #define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX)
#define PIC_CLOCK_TIMER 7 #define PIC_CLOCK_TIMER 7
#define PIC_IRQ_BASE 8
#if !defined(LOCORE) && !defined(__ASSEMBLY__) #if !defined(LOCORE) && !defined(__ASSEMBLY__)
#define PIC_IRT_FIRST_IRQ (PIC_IRQ_BASE)
#define PIC_IRT_LAST_IRQ 63
#define PIC_IRQ_IS_IRT(irq) ((irq) >= PIC_IRT_FIRST_IRQ)
/* /*
* Misc * Misc
*/ */
......
...@@ -37,10 +37,9 @@ ...@@ -37,10 +37,9 @@
#define PIC_UART_0_IRQ 17 #define PIC_UART_0_IRQ 17
#define PIC_UART_1_IRQ 18 #define PIC_UART_1_IRQ 18
#define PIC_PCIE_LINK_0_IRQ 19
#define PIC_PCIE_LINK_1_IRQ 20 #define PIC_PCIE_LINK_LEGACY_IRQ_BASE 19
#define PIC_PCIE_LINK_2_IRQ 21 #define PIC_PCIE_LINK_LEGACY_IRQ(i) (19 + (i))
#define PIC_PCIE_LINK_3_IRQ 22
#define PIC_EHCI_0_IRQ 23 #define PIC_EHCI_0_IRQ 23
#define PIC_EHCI_1_IRQ 24 #define PIC_EHCI_1_IRQ 24
...@@ -58,6 +57,23 @@ ...@@ -58,6 +57,23 @@
#define PIC_I2C_2_IRQ 32 #define PIC_I2C_2_IRQ 32
#define PIC_I2C_3_IRQ 33 #define PIC_I2C_3_IRQ 33
#define PIC_PCIE_LINK_MSI_IRQ_BASE 44 /* 44 - 47 MSI IRQ */
#define PIC_PCIE_LINK_MSI_IRQ(i) (44 + (i))
/* MSI-X with second link-level dispatch */
#define PIC_PCIE_MSIX_IRQ_BASE 48 /* 48 - 51 MSI-X IRQ */
#define PIC_PCIE_MSIX_IRQ(i) (48 + (i))
#define NLM_MSIX_VEC_BASE 96 /* 96 - 127 - MSIX mapped */
#define NLM_MSI_VEC_BASE 128 /* 128 -255 - MSI mapped */
#define NLM_PIC_INDIRECT_VEC_BASE 512
#define NLM_GPIO_VEC_BASE 768
#define PIC_IRQ_BASE 8
#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE
#define PIC_IRT_LAST_IRQ 63
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
/* SMP support functions */ /* SMP support functions */
......
...@@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void) ...@@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void)
#endif #endif
} }
void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) void nlm_setup_pic_irq(int node, int picirq, int irq, int irt)
{ {
struct nlm_pic_irq *pic_data; struct nlm_pic_irq *pic_data;
...@@ -207,24 +208,24 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) ...@@ -207,24 +208,24 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *))
static void nlm_init_node_irqs(int node) static void nlm_init_node_irqs(int node)
{ {
int i, irt;
uint64_t irqmask;
struct nlm_soc_info *nodep; struct nlm_soc_info *nodep;
int i, irt;
pr_info("Init IRQ for node %d\n", node); pr_info("Init IRQ for node %d\n", node);
nodep = nlm_get_node(node); nodep = nlm_get_node(node);
irqmask = PERCPU_IRQ_MASK; nodep->irqmask = PERCPU_IRQ_MASK;
for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) { for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) {
irt = nlm_irq_to_irt(i); irt = nlm_irq_to_irt(i);
if (irt == -1) if (irt == -1) /* unused irq */
continue; continue;
nlm_setup_pic_irq(node, i, i, irt); nodep->irqmask |= 1ull << i;
/* set interrupts to first cpu in node */ if (irt == -2) /* not a direct PIC irq */
continue;
nlm_pic_init_irt(nodep->picbase, irt, i, nlm_pic_init_irt(nodep->picbase, irt, i,
node * NLM_CPUS_PER_NODE, 0); node * NLM_CPUS_PER_NODE, 0);
irqmask |= (1ull << i); nlm_setup_pic_irq(node, i, i, irt);
} }
nodep->irqmask = irqmask;
} }
void nlm_smp_irq_init(int hwcpuid) void nlm_smp_irq_init(int hwcpuid)
...@@ -256,6 +257,18 @@ asmlinkage void plat_irq_dispatch(void) ...@@ -256,6 +257,18 @@ asmlinkage void plat_irq_dispatch(void)
return; return;
} }
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP)
/* PCI interrupts need a second level dispatch for MSI bits */
if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) {
nlm_dispatch_msi(node, i);
return;
}
if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) {
nlm_dispatch_msix(node, i);
return;
}
#endif
/* top level irq handling */ /* top level irq handling */
do_IRQ(nlm_irq_to_xirq(node, i)); do_IRQ(nlm_irq_to_xirq(node, i));
} }
......
...@@ -135,9 +135,17 @@ int nlm_irq_to_irt(int irq) ...@@ -135,9 +135,17 @@ int nlm_irq_to_irt(int irq)
case PIC_I2C_3_IRQ: case PIC_I2C_3_IRQ:
irt = irt + 3; break; irt = irt + 3; break;
} }
} else if (irq >= PIC_PCIE_LINK_0_IRQ && irq <= PIC_PCIE_LINK_3_IRQ) { } else if (irq >= PIC_PCIE_LINK_LEGACY_IRQ(0) &&
irq <= PIC_PCIE_LINK_LEGACY_IRQ(3)) {
/* HW bug, PCI IRT entries are bad on early silicon, fix */ /* HW bug, PCI IRT entries are bad on early silicon, fix */
irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_0_IRQ); irt = PIC_IRT_PCIE_LINK_INDEX(irq -
PIC_PCIE_LINK_LEGACY_IRQ_BASE);
} else if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) &&
irq <= PIC_PCIE_LINK_MSI_IRQ(3)) {
irt = -2;
} else if (irq >= PIC_PCIE_MSIX_IRQ(0) &&
irq <= PIC_PCIE_MSIX_IRQ(3)) {
irt = -2;
} else { } else {
irt = -1; irt = -1;
} }
......
...@@ -60,4 +60,5 @@ obj-$(CONFIG_CPU_XLP) += pci-xlp.o ...@@ -60,4 +60,5 @@ obj-$(CONFIG_CPU_XLP) += pci-xlp.o
ifdef CONFIG_PCI_MSI ifdef CONFIG_PCI_MSI
obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o
obj-$(CONFIG_CPU_XLP) += msi-xlp.o
endif endif
This diff is collapsed.
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <asm/netlogic/interrupt.h> #include <asm/netlogic/interrupt.h>
#include <asm/netlogic/haldefs.h> #include <asm/netlogic/haldefs.h>
#include <asm/netlogic/common.h> #include <asm/netlogic/common.h>
#include <asm/netlogic/mips-extns.h>
#include <asm/netlogic/xlp-hal/iomap.h> #include <asm/netlogic/xlp-hal/iomap.h>
#include <asm/netlogic/xlp-hal/pic.h> #include <asm/netlogic/xlp-hal/pic.h>
...@@ -162,7 +163,7 @@ struct pci_controller nlm_pci_controller = { ...@@ -162,7 +163,7 @@ struct pci_controller nlm_pci_controller = {
.io_offset = 0x00000000UL, .io_offset = 0x00000000UL,
}; };
static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
{ {
struct pci_bus *bus, *p; struct pci_bus *bus, *p;
...@@ -174,11 +175,6 @@ static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) ...@@ -174,11 +175,6 @@ static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
return p ? bus->self : NULL; return p ? bus->self : NULL;
} }
static inline int nlm_pci_link_to_irq(int link)
{
return PIC_PCIE_LINK_0_IRQ + link;
}
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{ {
struct pci_dev *lnkdev; struct pci_dev *lnkdev;
...@@ -193,7 +189,7 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ...@@ -193,7 +189,7 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return 0; return 0;
lnkfunc = PCI_FUNC(lnkdev->devfn); lnkfunc = PCI_FUNC(lnkdev->devfn);
lnkslot = PCI_SLOT(lnkdev->devfn); lnkslot = PCI_SLOT(lnkdev->devfn);
return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc)); return nlm_irq_to_xirq(lnkslot / 8, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
} }
/* Do platform specific device initialization at pci_enable_device() time */ /* Do platform specific device initialization at pci_enable_device() time */
...@@ -257,16 +253,17 @@ static int __init pcibios_init(void) ...@@ -257,16 +253,17 @@ static int __init pcibios_init(void)
if (!nodep->coremask) if (!nodep->coremask)
continue; /* node does not exist */ continue; /* node does not exist */
for (link = 0; link < 4; link++) { for (link = 0; link < PCIE_NLINKS; link++) {
pciebase = nlm_get_pcie_base(n, link); pciebase = nlm_get_pcie_base(n, link);
if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
continue; continue;
xlp_config_pci_bswap(n, link); xlp_config_pci_bswap(n, link);
xlp_init_node_msi_irqs(n, link);
/* put in intpin and irq - u-boot does not */ /* put in intpin and irq - u-boot does not */
reg = nlm_read_pci_reg(pciebase, 0xf); reg = nlm_read_pci_reg(pciebase, 0xf);
reg &= ~0x1fu; reg &= ~0x1fu;
reg |= (1 << 8) | nlm_pci_link_to_irq(link); reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
nlm_write_pci_reg(pciebase, 0xf, reg); nlm_write_pci_reg(pciebase, 0xf, reg);
pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment