Commit bcd17397 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mips_5.2_2' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux

Pull a few more MIPS updates from Paul Burton:
 "Some SGI IP27 specific PCI rework and a batch of fixes:

   - A build fix for BMIPS5000 configurations with
     CONFIG_HW_PERF_EVENTS=y, which also neatly removes some #ifdefery.

   - A fix to report supported ISAs correctly on older Ingenic SoCs
     which incorrectly indicate MIPSr2 support in their cop0 Config
     register.

   - Some PCI modernization for SGI IP27 systems as part of ongoing work
     to support some other SGI systems.

   - A fix allowing use of appended DTB files with generic kernels.

   - DMA mask fixes for SGI IP22 & Alchemy systems"

* tag 'mips_5.2_2' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux:
  MIPS: Alchemy: add DMA masks for on-chip ethernet
  MIPS: SGI-IP22: provide missing dma_mask/coherent_dma_mask
  generic: fix appended dtb support
  MIPS: SGI-IP27: abstract chipset irq from bridge
  MIPS: SGI-IP27: use generic PCI driver
  MIPS: Fix Ingenic SoCs sometimes reporting wrong ISA
  MIPS: perf: Fix build with CONFIG_CPU_BMIPS5000 enabled
parents b0bb1269 b1e479e3
...@@ -674,7 +674,10 @@ config SGI_IP27 ...@@ -674,7 +674,10 @@ config SGI_IP27
select SYS_HAS_EARLY_PRINTK select SYS_HAS_EARLY_PRINTK
select HAVE_PCI select HAVE_PCI
select IRQ_MIPS_CPU select IRQ_MIPS_CPU
select IRQ_DOMAIN_HIERARCHY
select NR_CPUS_DEFAULT_64 select NR_CPUS_DEFAULT_64
select PCI_DRIVERS_GENERIC
select PCI_XTALK_BRIDGE
select SYS_HAS_CPU_R10000 select SYS_HAS_CPU_R10000
select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN
...@@ -1241,6 +1244,9 @@ config IRQ_GT641XX ...@@ -1241,6 +1244,9 @@ config IRQ_GT641XX
config PCI_GT64XXX_PCI0 config PCI_GT64XXX_PCI0
bool bool
config PCI_XTALK_BRIDGE
bool
config NO_EXCEPT_FILL config NO_EXCEPT_FILL
bool bool
......
...@@ -131,9 +131,7 @@ static void __init alchemy_setup_uarts(int ctype) ...@@ -131,9 +131,7 @@ static void __init alchemy_setup_uarts(int ctype)
} }
/* The dmamask must be set for OHCI/EHCI to work */ static u64 alchemy_all_dmamask = DMA_BIT_MASK(32);
static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32);
static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32);
/* Power on callback for the ehci platform driver */ /* Power on callback for the ehci platform driver */
static int alchemy_ehci_power_on(struct platform_device *pdev) static int alchemy_ehci_power_on(struct platform_device *pdev)
...@@ -231,7 +229,7 @@ static void __init alchemy_setup_usb(int ctype) ...@@ -231,7 +229,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ; res[1].flags = IORESOURCE_IRQ;
pdev->name = "ohci-platform"; pdev->name = "ohci-platform";
pdev->id = 0; pdev->id = 0;
pdev->dev.dma_mask = &alchemy_ohci_dmamask; pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ohci_pdata; pdev->dev.platform_data = &alchemy_ohci_pdata;
if (platform_device_register(pdev)) if (platform_device_register(pdev))
...@@ -251,7 +249,7 @@ static void __init alchemy_setup_usb(int ctype) ...@@ -251,7 +249,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ; res[1].flags = IORESOURCE_IRQ;
pdev->name = "ehci-platform"; pdev->name = "ehci-platform";
pdev->id = 0; pdev->id = 0;
pdev->dev.dma_mask = &alchemy_ehci_dmamask; pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ehci_pdata; pdev->dev.platform_data = &alchemy_ehci_pdata;
if (platform_device_register(pdev)) if (platform_device_register(pdev))
...@@ -271,7 +269,7 @@ static void __init alchemy_setup_usb(int ctype) ...@@ -271,7 +269,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ; res[1].flags = IORESOURCE_IRQ;
pdev->name = "ohci-platform"; pdev->name = "ohci-platform";
pdev->id = 1; pdev->id = 1;
pdev->dev.dma_mask = &alchemy_ohci_dmamask; pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ohci_pdata; pdev->dev.platform_data = &alchemy_ohci_pdata;
if (platform_device_register(pdev)) if (platform_device_register(pdev))
...@@ -338,7 +336,11 @@ static struct platform_device au1xxx_eth0_device = { ...@@ -338,7 +336,11 @@ static struct platform_device au1xxx_eth0_device = {
.name = "au1000-eth", .name = "au1000-eth",
.id = 0, .id = 0,
.num_resources = MAC_RES_COUNT, .num_resources = MAC_RES_COUNT,
.dev.platform_data = &au1xxx_eth0_platform_data, .dev = {
.dma_mask = &alchemy_all_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &au1xxx_eth0_platform_data,
},
}; };
static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = { static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
...@@ -370,7 +372,11 @@ static struct platform_device au1xxx_eth1_device = { ...@@ -370,7 +372,11 @@ static struct platform_device au1xxx_eth1_device = {
.name = "au1000-eth", .name = "au1000-eth",
.id = 1, .id = 1,
.num_resources = MAC_RES_COUNT, .num_resources = MAC_RES_COUNT,
.dev.platform_data = &au1xxx_eth1_platform_data, .dev = {
.dma_mask = &alchemy_all_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &au1xxx_eth1_platform_data,
},
}; };
void __init au1xxx_override_eth_cfg(unsigned int port, void __init au1xxx_override_eth_cfg(unsigned int port,
......
...@@ -43,14 +43,14 @@ void __init *plat_get_fdt(void) ...@@ -43,14 +43,14 @@ void __init *plat_get_fdt(void)
/* Already set up */ /* Already set up */
return (void *)fdt; return (void *)fdt;
if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) { if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_passed_dtb)) {
/* /*
* We booted using the UHI boot protocol, so we have been * We booted using the UHI boot protocol, so we have been
* provided with the appropriate device tree for the board. * provided with the appropriate device tree for the board.
* Make use of it & search for any machine struct based upon * Make use of it & search for any machine struct based upon
* the root compatible string. * the root compatible string.
*/ */
fdt = (void *)fw_arg1; fdt = (void *)fw_passed_dtb;
for_each_mips_machine(check_mach) { for_each_mips_machine(check_mach) {
match = mips_machine_is_compatible(check_mach, fdt); match = mips_machine_is_compatible(check_mach, fdt);
......
...@@ -7,18 +7,9 @@ ...@@ -7,18 +7,9 @@
#include <asm/mmzone.h> #include <asm/mmzone.h>
struct cpuinfo_ip27 { struct cpuinfo_ip27 {
// cpuid_t p_cpuid; /* PROM assigned cpuid */
cnodeid_t p_nodeid; /* my node ID in compact-id-space */ cnodeid_t p_nodeid; /* my node ID in compact-id-space */
nasid_t p_nasid; /* my node ID in numa-as-id-space */ nasid_t p_nasid; /* my node ID in numa-as-id-space */
unsigned char p_slice; /* Physical position on node board */ unsigned char p_slice; /* Physical position on node board */
#if 0
unsigned long loops_per_sec;
unsigned long ipi_count;
unsigned long irq_attempt[NR_IRQS];
unsigned long smp_local_irq_count;
unsigned long prof_multiplier;
unsigned long prof_counter;
#endif
}; };
extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
...@@ -30,7 +21,7 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; ...@@ -30,7 +21,7 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
struct pci_bus; struct pci_bus;
extern int pcibus_to_node(struct pci_bus *); extern int pcibus_to_node(struct pci_bus *);
#define cpumask_of_pcibus(bus) (cpu_online_mask) #define cpumask_of_pcibus(bus) (cpumask_of_node(pcibus_to_node(bus)))
extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
......
...@@ -801,15 +801,13 @@ struct bridge_err_cmdword { ...@@ -801,15 +801,13 @@ struct bridge_err_cmdword {
#define PCI64_ATTR_RMF_SHFT 48 #define PCI64_ATTR_RMF_SHFT 48
struct bridge_controller { struct bridge_controller {
struct pci_controller pc;
struct resource mem;
struct resource io;
struct resource busn; struct resource busn;
struct bridge_regs *base; struct bridge_regs *base;
nasid_t nasid; unsigned long baddr;
unsigned int widget_id; unsigned long intr_addr;
u64 baddr; struct irq_domain *domain;
unsigned int pci_int[8]; unsigned int pci_int[8];
nasid_t nasid;
}; };
#define BRIDGE_CONTROLLER(bus) \ #define BRIDGE_CONTROLLER(bus) \
...@@ -822,8 +820,4 @@ struct bridge_controller { ...@@ -822,8 +820,4 @@ struct bridge_controller {
#define bridge_clr(bc, reg, val) \ #define bridge_clr(bc, reg, val) \
__raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg) __raw_writel(__raw_readl(&bc->base->reg) & ~(val), &bc->base->reg)
extern int request_bridge_irq(struct bridge_controller *bc, int pin);
extern struct pci_ops bridge_pci_ops;
#endif /* _ASM_PCI_BRIDGE_H */ #endif /* _ASM_PCI_BRIDGE_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_SN_IRQ_ALLOC_H
#define __ASM_SN_IRQ_ALLOC_H
struct irq_alloc_info {
void *ctrl;
nasid_t nasid;
int pin;
};
#endif /* __ASM_SN_IRQ_ALLOC_H */
...@@ -47,15 +47,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t; ...@@ -47,15 +47,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t;
#define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT)) #define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT))
#define XIO_PACK(p, o) ((((uint64_t)(p))<<XIO_PORT_SHIFT) | ((o)&XIO_ADDR_BITS)) #define XIO_PACK(p, o) ((((uint64_t)(p))<<XIO_PORT_SHIFT) | ((o)&XIO_ADDR_BITS))
#ifdef CONFIG_PCI
extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
#else
static inline int bridge_probe(nasid_t nasid, int widget, int masterwid)
{
return 0;
}
#endif
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif /* _ASM_XTALK_XTALK_H */ #endif /* _ASM_XTALK_XTALK_H */
...@@ -1973,6 +1973,14 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) ...@@ -1973,6 +1973,14 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
panic("Unknown Ingenic Processor ID!"); panic("Unknown Ingenic Processor ID!");
break; break;
} }
/*
* The config0 register in the Xburst CPUs with a processor ID of
* PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
* but they don't actually support this ISA.
*/
if ((c->processor_id & PRID_COMP_MASK) == PRID_COMP_INGENIC_D0)
c->isa_level &= ~MIPS_CPU_ISA_M32R2;
} }
static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
......
...@@ -64,17 +64,11 @@ struct mips_perf_event { ...@@ -64,17 +64,11 @@ struct mips_perf_event {
#define CNTR_EVEN 0x55555555 #define CNTR_EVEN 0x55555555
#define CNTR_ODD 0xaaaaaaaa #define CNTR_ODD 0xaaaaaaaa
#define CNTR_ALL 0xffffffff #define CNTR_ALL 0xffffffff
#ifdef CONFIG_MIPS_MT_SMP
enum { enum {
T = 0, T = 0,
V = 1, V = 1,
P = 2, P = 2,
} range; } range;
#else
#define T
#define V
#define P
#endif
}; };
static struct mips_perf_event raw_event; static struct mips_perf_event raw_event;
...@@ -325,9 +319,7 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) ...@@ -325,9 +319,7 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
{ {
struct perf_event *event = container_of(evt, struct perf_event, hw); struct perf_event *event = container_of(evt, struct perf_event, hw);
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
#ifdef CONFIG_MIPS_MT_SMP
unsigned int range = evt->event_base >> 24; unsigned int range = evt->event_base >> 24;
#endif /* CONFIG_MIPS_MT_SMP */
WARN_ON(idx < 0 || idx >= mipspmu.num_counters); WARN_ON(idx < 0 || idx >= mipspmu.num_counters);
...@@ -336,21 +328,15 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) ...@@ -336,21 +328,15 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
/* Make sure interrupt enabled. */ /* Make sure interrupt enabled. */
MIPS_PERFCTRL_IE; MIPS_PERFCTRL_IE;
#ifdef CONFIG_CPU_BMIPS5000 if (IS_ENABLED(CONFIG_CPU_BMIPS5000)) {
{
/* enable the counter for the calling thread */ /* enable the counter for the calling thread */
cpuc->saved_ctrl[idx] |= cpuc->saved_ctrl[idx] |=
(1 << (12 + vpe_id())) | BRCM_PERFCTRL_TC; (1 << (12 + vpe_id())) | BRCM_PERFCTRL_TC;
} } else if (IS_ENABLED(CONFIG_MIPS_MT_SMP) && range > V) {
#else
#ifdef CONFIG_MIPS_MT_SMP
if (range > V) {
/* The counter is processor wide. Set it up to count all TCs. */ /* The counter is processor wide. Set it up to count all TCs. */
pr_debug("Enabling perf counter for all TCs\n"); pr_debug("Enabling perf counter for all TCs\n");
cpuc->saved_ctrl[idx] |= M_TC_EN_ALL; cpuc->saved_ctrl[idx] |= M_TC_EN_ALL;
} else } else {
#endif /* CONFIG_MIPS_MT_SMP */
{
unsigned int cpu, ctrl; unsigned int cpu, ctrl;
/* /*
...@@ -365,7 +351,6 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) ...@@ -365,7 +351,6 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
cpuc->saved_ctrl[idx] |= ctrl; cpuc->saved_ctrl[idx] |= ctrl;
pr_debug("Enabling perf counter for CPU%d\n", cpu); pr_debug("Enabling perf counter for CPU%d\n", cpu);
} }
#endif /* CONFIG_CPU_BMIPS5000 */
/* /*
* We do not actually let the counter run. Leave it until start(). * We do not actually let the counter run. Leave it until start().
*/ */
......
...@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI_AR2315) += pci-ar2315.o ...@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI_AR2315) += pci-ar2315.o
obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o
obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o
obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o
obj-$(CONFIG_PCI_XTALK_BRIDGE) += pci-xtalk-bridge.o
# #
# These are still pretty much in the old state, watch, go blind. # These are still pretty much in the old state, watch, go blind.
# #
...@@ -39,7 +40,7 @@ obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o ...@@ -39,7 +40,7 @@ obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o obj-$(CONFIG_SGI_IP27) += pci-ip27.o
obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o
obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
......
...@@ -7,162 +7,7 @@ ...@@ -7,162 +7,7 @@
* Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/ */
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/dma-direct.h>
#include <asm/sn/arch.h>
#include <asm/pci/bridge.h> #include <asm/pci/bridge.h>
#include <asm/paccess.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn0/hub.h>
/*
* Max #PCI busses we can handle; ie, max #PCI bridges.
*/
#define MAX_PCI_BUSSES 40
/*
* XXX: No kmalloc available when we do our crosstalk scan,
* we should try to move it later in the boot process.
*/
static struct bridge_controller bridges[MAX_PCI_BUSSES];
extern struct pci_ops bridge_pci_ops;
int bridge_probe(nasid_t nasid, int widget_id, int masterwid)
{
unsigned long offset = NODE_OFFSET(nasid);
struct bridge_controller *bc;
static int num_bridges = 0;
int slot;
pci_set_flags(PCI_PROBE_ONLY);
printk("a bridge\n");
/* XXX: kludge alert.. */
if (!num_bridges)
ioport_resource.end = ~0UL;
bc = &bridges[num_bridges];
bc->pc.pci_ops = &bridge_pci_ops;
bc->pc.mem_resource = &bc->mem;
bc->pc.io_resource = &bc->io;
bc->pc.index = num_bridges;
bc->mem.name = "Bridge PCI MEM";
bc->pc.mem_offset = offset;
bc->mem.start = 0;
bc->mem.end = ~0UL;
bc->mem.flags = IORESOURCE_MEM;
bc->io.name = "Bridge IO MEM";
bc->pc.io_offset = offset;
bc->io.start = 0UL;
bc->io.end = ~0UL;
bc->io.flags = IORESOURCE_IO;
bc->widget_id = widget_id;
bc->nasid = nasid;
bc->baddr = (u64)masterwid << 60 | PCI64_ATTR_BAR;
/*
* point to this bridge
*/
bc->base = (struct bridge_regs *)RAW_NODE_SWIN_BASE(nasid, widget_id);
/*
* Clear all pending interrupts.
*/
bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
/*
* Until otherwise set up, assume all interrupts are from slot 0
*/
bridge_write(bc, b_int_device, 0x0);
/*
* swap pio's to pci mem and io space (big windows)
*/
bridge_set(bc, b_wid_control, BRIDGE_CTRL_IO_SWAP |
BRIDGE_CTRL_MEM_SWAP);
#ifdef CONFIG_PAGE_SIZE_4KB
bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#else /* 16kB or larger */
bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#endif
/*
* Hmm... IRIX sets additional bits in the address which
* are documented as reserved in the bridge docs.
*/
bridge_write(bc, b_wid_int_upper, 0x8000 | (masterwid << 16));
bridge_write(bc, b_wid_int_lower, 0x01800090); /* PI_INT_PEND_MOD off*/
bridge_write(bc, b_dir_map, (masterwid << 20)); /* DMA */
bridge_write(bc, b_int_enable, 0);
for (slot = 0; slot < 8; slot ++) {
bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
bc->pci_int[slot] = -1;
}
bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
register_pci_controller(&bc->pc);
num_bridges++;
return 0;
}
/*
* All observed requests have pin == 1. We could have a global here, that
* gets incremented and returned every time - unfortunately, pci_map_irq
* may be called on the same device over and over, and need to return the
* same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
*
* A given PCI device, in general, should be able to intr any of the cpus
* on any one of the hubs connected to its xbow.
*/
int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
return 0;
}
static inline struct pci_dev *bridge_root_dev(struct pci_dev *dev)
{
while (dev->bus->parent) {
/* Move up the chain of bridges. */
dev = dev->bus->self;
}
return dev;
}
/* Do platform specific device initialization at pci_enable_device() time */
int pcibios_plat_dev_init(struct pci_dev *dev)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
struct pci_dev *rdev = bridge_root_dev(dev);
int slot = PCI_SLOT(rdev->devfn);
int irq;
irq = bc->pci_int[slot];
if (irq == -1) {
irq = request_bridge_irq(bc, slot);
if (irq < 0)
return irq;
bc->pci_int[slot] = irq;
}
dev->irq = irq;
return 0;
}
dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
{ {
...@@ -177,29 +22,6 @@ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr) ...@@ -177,29 +22,6 @@ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
return dma_addr & ~(0xffUL << 56); return dma_addr & ~(0xffUL << 56);
} }
/*
* Device might live on a subordinate PCI bus. XXX Walk up the chain of buses
* to find the slot number in sense of the bridge device register.
* XXX This also means multiple devices might rely on conflicting bridge
* settings.
*/
static inline void pci_disable_swapping(struct pci_dev *dev)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(dev->devfn);
/* Turn off byte swapping */
bridge->b_device[slot].reg &= ~BRIDGE_DEV_SWAP_DIR;
bridge->b_widget.w_tflush; /* Flush */
}
static void pci_fixup_ioc3(struct pci_dev *d)
{
pci_disable_swapping(d);
}
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
int pcibus_to_node(struct pci_bus *bus) int pcibus_to_node(struct pci_bus *bus)
{ {
...@@ -209,6 +31,3 @@ int pcibus_to_node(struct pci_bus *bus) ...@@ -209,6 +31,3 @@ int pcibus_to_node(struct pci_bus *bus)
} }
EXPORT_SYMBOL(pcibus_to_node); EXPORT_SYMBOL(pcibus_to_node);
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
pci_fixup_ioc3);
// SPDX-License-Identifier: GPL-2.0
/* /*
* This file is subject to the terms and conditions of the GNU General Public * Copyright (C) 2003 Christoph Hellwig (hch@lst.de)
* License. See the file "COPYING" in the main directory of this archive * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
* for more details.
*
* Copyright (C) 1999, 2000, 04, 06 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/ */
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/paccess.h> #include <linux/smp.h>
#include <linux/dma-direct.h>
#include <linux/platform_device.h>
#include <linux/platform_data/xtalk-bridge.h>
#include <asm/pci/bridge.h> #include <asm/pci/bridge.h>
#include <asm/sn/arch.h> #include <asm/paccess.h>
#include <asm/sn/intr.h> #include <asm/sn/irq_alloc.h>
#include <asm/sn/sn0/hub.h>
/* /*
* Most of the IOC3 PCI config register aren't present * Most of the IOC3 PCI config register aren't present
...@@ -29,6 +32,20 @@ static u32 emulate_ioc3_cfg(int where, int size) ...@@ -29,6 +32,20 @@ static u32 emulate_ioc3_cfg(int where, int size)
return 0; return 0;
} }
static void bridge_disable_swapping(struct pci_dev *dev)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
int slot = PCI_SLOT(dev->devfn);
/* Turn off byte swapping */
bridge_clr(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
bridge_read(bc, b_widget.w_tflush); /* Flush */
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
bridge_disable_swapping);
/* /*
* The Bridge ASIC supports both type 0 and type 1 access. Type 1 is * The Bridge ASIC supports both type 0 and type 1 access. Type 1 is
* not really documented, so right now I can't write code which uses it. * not really documented, so right now I can't write code which uses it.
...@@ -39,20 +56,19 @@ static u32 emulate_ioc3_cfg(int where, int size) ...@@ -39,20 +56,19 @@ static u32 emulate_ioc3_cfg(int where, int size)
* which is used in SGI systems. The IOC3 can only handle 32-bit PCI * which is used in SGI systems. The IOC3 can only handle 32-bit PCI
* accesses and does only decode parts of it's address space. * accesses and does only decode parts of it's address space.
*/ */
static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value) int where, int size, u32 *value)
{ {
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
struct bridge_regs *bridge = bc->base; struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn); int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn); int fn = PCI_FUNC(devfn);
volatile void *addr; void *addr;
u32 cf, shift, mask; u32 cf, shift, mask;
int res; int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr)) if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
/* /*
...@@ -65,11 +81,11 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -65,11 +81,11 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
if (size == 1) if (size == 1)
res = get_dbe(*value, (u8 *) addr); res = get_dbe(*value, (u8 *)addr);
else if (size == 2) else if (size == 2)
res = get_dbe(*value, (u16 *) addr); res = get_dbe(*value, (u16 *)addr);
else else
res = get_dbe(*value, (u32 *) addr); res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
...@@ -84,8 +100,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -84,8 +100,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
} }
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *)addr))
if (get_dbe(cf, (u32 *) addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3); shift = ((where & 3) << 3);
...@@ -96,20 +111,20 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -96,20 +111,20 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
} }
static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value) int where, int size, u32 *value)
{ {
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
struct bridge_regs *bridge = bc->base; struct bridge_regs *bridge = bc->base;
int busno = bus->number; int busno = bus->number;
int slot = PCI_SLOT(devfn); int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn); int fn = PCI_FUNC(devfn);
volatile void *addr; void *addr;
u32 cf, shift, mask; u32 cf, shift, mask;
int res; int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11)); bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID]; addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr)) if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
/* /*
...@@ -119,15 +134,14 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -119,15 +134,14 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
goto is_ioc3; goto is_ioc3;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))]; addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
if (size == 1) if (size == 1)
res = get_dbe(*value, (u8 *) addr); res = get_dbe(*value, (u8 *)addr);
else if (size == 2) else if (size == 2)
res = get_dbe(*value, (u16 *) addr); res = get_dbe(*value, (u16 *)addr);
else else
res = get_dbe(*value, (u32 *) addr); res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
...@@ -141,10 +155,8 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -141,10 +155,8 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
} }
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | where]; addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
if (get_dbe(cf, (u32 *)addr))
if (get_dbe(cf, (u32 *) addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3); shift = ((where & 3) << 3);
...@@ -155,7 +167,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn, ...@@ -155,7 +167,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
} }
static int pci_read_config(struct pci_bus *bus, unsigned int devfn, static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * value) int where, int size, u32 *value)
{ {
if (!pci_is_root_bus(bus)) if (!pci_is_root_bus(bus))
return pci_conf1_read_config(bus, devfn, where, size, value); return pci_conf1_read_config(bus, devfn, where, size, value);
...@@ -170,12 +182,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -170,12 +182,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
struct bridge_regs *bridge = bc->base; struct bridge_regs *bridge = bc->base;
int slot = PCI_SLOT(devfn); int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn); int fn = PCI_FUNC(devfn);
volatile void *addr; void *addr;
u32 cf, shift, mask, smask; u32 cf, shift, mask, smask;
int res; int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr)) if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
/* /*
...@@ -187,13 +199,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -187,13 +199,12 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
if (size == 1) { if (size == 1)
res = put_dbe(value, (u8 *) addr); res = put_dbe(value, (u8 *)addr);
} else if (size == 2) { else if (size == 2)
res = put_dbe(value, (u16 *) addr); res = put_dbe(value, (u16 *)addr);
} else { else
res = put_dbe(value, (u32 *) addr); res = put_dbe(value, (u32 *)addr);
}
if (res) if (res)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
...@@ -210,7 +221,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -210,7 +221,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *) addr)) if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3); shift = ((where & 3) << 3);
...@@ -218,7 +229,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -218,7 +229,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
smask = mask << shift; smask = mask << shift;
cf = (cf & ~smask) | ((value & mask) << shift); cf = (cf & ~smask) | ((value & mask) << shift);
if (put_dbe(cf, (u32 *) addr)) if (put_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
...@@ -232,13 +243,13 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -232,13 +243,13 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
int slot = PCI_SLOT(devfn); int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn); int fn = PCI_FUNC(devfn);
int busno = bus->number; int busno = bus->number;
volatile void *addr; void *addr;
u32 cf, shift, mask, smask; u32 cf, shift, mask, smask;
int res; int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11)); bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID]; addr = &bridge->b_type1_cfg.c[(fn << 8) | PCI_VENDOR_ID];
if (get_dbe(cf, (u32 *) addr)) if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
/* /*
...@@ -250,13 +261,12 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -250,13 +261,12 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))]; addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
if (size == 1) { if (size == 1)
res = put_dbe(value, (u8 *) addr); res = put_dbe(value, (u8 *)addr);
} else if (size == 2) { else if (size == 2)
res = put_dbe(value, (u16 *) addr); res = put_dbe(value, (u16 *)addr);
} else { else
res = put_dbe(value, (u32 *) addr); res = put_dbe(value, (u32 *)addr);
}
if (res) if (res)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
...@@ -272,8 +282,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -272,8 +282,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
if (get_dbe(cf, (u32 *)addr))
if (get_dbe(cf, (u32 *) addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
shift = ((where & 3) << 3); shift = ((where & 3) << 3);
...@@ -281,7 +290,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -281,7 +290,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
smask = mask << shift; smask = mask << shift;
cf = (cf & ~smask) | ((value & mask) << shift); cf = (cf & ~smask) | ((value & mask) << shift);
if (put_dbe(cf, (u32 *) addr)) if (put_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
...@@ -296,7 +305,306 @@ static int pci_write_config(struct pci_bus *bus, unsigned int devfn, ...@@ -296,7 +305,306 @@ static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
return pci_conf0_write_config(bus, devfn, where, size, value); return pci_conf0_write_config(bus, devfn, where, size, value);
} }
struct pci_ops bridge_pci_ops = { static struct pci_ops bridge_pci_ops = {
.read = pci_read_config, .read = pci_read_config,
.write = pci_write_config, .write = pci_write_config,
}; };
struct bridge_irq_chip_data {
struct bridge_controller *bc;
nasid_t nasid;
};
static int bridge_set_affinity(struct irq_data *d, const struct cpumask *mask,
bool force)
{
#ifdef CONFIG_NUMA
struct bridge_irq_chip_data *data = d->chip_data;
int bit = d->parent_data->hwirq;
int pin = d->hwirq;
nasid_t nasid;
int ret, cpu;
ret = irq_chip_set_affinity_parent(d, mask, force);
if (ret >= 0) {
cpu = cpumask_first_and(mask, cpu_online_mask);
nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
bridge_write(data->bc, b_int_addr[pin].addr,
(((data->bc->intr_addr >> 30) & 0x30000) |
bit | (nasid << 8)));
bridge_read(data->bc, b_wid_tflush);
}
return ret;
#else
return irq_chip_set_affinity_parent(d, mask, force);
#endif
}
struct irq_chip bridge_irq_chip = {
.name = "BRIDGE",
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_set_affinity = bridge_set_affinity
};
static int bridge_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
struct bridge_irq_chip_data *data;
struct irq_alloc_info *info = arg;
int ret;
if (nr_irqs > 1 || !info)
return -EINVAL;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
if (ret >= 0) {
data->bc = info->ctrl;
data->nasid = info->nasid;
irq_domain_set_info(domain, virq, info->pin, &bridge_irq_chip,
data, handle_level_irq, NULL, NULL);
} else {
kfree(data);
}
return ret;
}
static void bridge_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{
struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
if (nr_irqs)
return;
kfree(irqd->chip_data);
irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
static int bridge_domain_activate(struct irq_domain *domain,
struct irq_data *irqd, bool reserve)
{
struct bridge_irq_chip_data *data = irqd->chip_data;
struct bridge_controller *bc = data->bc;
int bit = irqd->parent_data->hwirq;
int pin = irqd->hwirq;
u32 device;
bridge_write(bc, b_int_addr[pin].addr,
(((bc->intr_addr >> 30) & 0x30000) |
bit | (data->nasid << 8)));
bridge_set(bc, b_int_enable, (1 << pin));
bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
/*
* Enable sending of an interrupt clear packt to the hub on a high to
* low transition of the interrupt pin.
*
* IRIX sets additional bits in the address which are documented as
* reserved in the bridge docs.
*/
bridge_set(bc, b_int_mode, (1UL << pin));
/*
* We assume the bridge to have a 1:1 mapping between devices
* (slots) and intr pins.
*/
device = bridge_read(bc, b_int_device);
device &= ~(7 << (pin*3));
device |= (pin << (pin*3));
bridge_write(bc, b_int_device, device);
bridge_read(bc, b_wid_tflush);
return 0;
}
static void bridge_domain_deactivate(struct irq_domain *domain,
struct irq_data *irqd)
{
struct bridge_irq_chip_data *data = irqd->chip_data;
bridge_clr(data->bc, b_int_enable, (1 << irqd->hwirq));
bridge_read(data->bc, b_wid_tflush);
}
static const struct irq_domain_ops bridge_domain_ops = {
.alloc = bridge_domain_alloc,
.free = bridge_domain_free,
.activate = bridge_domain_activate,
.deactivate = bridge_domain_deactivate
};
/*
* All observed requests have pin == 1. We could have a global here, that
* gets incremented and returned every time - unfortunately, pci_map_irq
* may be called on the same device over and over, and need to return the
* same value. On O2000, pin can be 0 or 1, and PCI slots can be [0..7].
*
* A given PCI device, in general, should be able to intr any of the cpus
* on any one of the hubs connected to its xbow.
*/
static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus);
struct irq_alloc_info info;
int irq;
irq = bc->pci_int[slot];
if (irq == -1) {
info.ctrl = bc;
info.nasid = bc->nasid;
info.pin = slot;
irq = irq_domain_alloc_irqs(bc->domain, 1, bc->nasid, &info);
if (irq < 0)
return irq;
bc->pci_int[slot] = irq;
}
return irq;
}
static int bridge_probe(struct platform_device *pdev)
{
struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct bridge_controller *bc;
struct pci_host_bridge *host;
struct irq_domain *domain, *parent;
struct fwnode_handle *fn;
int slot;
int err;
parent = irq_get_default_host();
if (!parent)
return -ENODEV;
fn = irq_domain_alloc_named_fwnode("BRIDGE");
if (!fn)
return -ENOMEM;
domain = irq_domain_create_hierarchy(parent, 0, 8, fn,
&bridge_domain_ops, NULL);
irq_domain_free_fwnode(fn);
if (!domain)
return -ENOMEM;
pci_set_flags(PCI_PROBE_ONLY);
host = devm_pci_alloc_host_bridge(dev, sizeof(*bc));
if (!host) {
err = -ENOMEM;
goto err_remove_domain;
}
bc = pci_host_bridge_priv(host);
bc->busn.name = "Bridge PCI busn";
bc->busn.start = 0;
bc->busn.end = 0xff;
bc->busn.flags = IORESOURCE_BUS;
bc->domain = domain;
pci_add_resource_offset(&host->windows, &bd->mem, bd->mem_offset);
pci_add_resource_offset(&host->windows, &bd->io, bd->io_offset);
pci_add_resource(&host->windows, &bc->busn);
err = devm_request_pci_bus_resources(dev, &host->windows);
if (err < 0)
goto err_free_resource;
bc->nasid = bd->nasid;
bc->baddr = (u64)bd->masterwid << 60 | PCI64_ATTR_BAR;
bc->base = (struct bridge_regs *)bd->bridge_addr;
bc->intr_addr = bd->intr_addr;
/*
* Clear all pending interrupts.
*/
bridge_write(bc, b_int_rst_stat, BRIDGE_IRR_ALL_CLR);
/*
* Until otherwise set up, assume all interrupts are from slot 0
*/
bridge_write(bc, b_int_device, 0x0);
/*
* disable swapping for big windows
*/
bridge_clr(bc, b_wid_control,
BRIDGE_CTRL_IO_SWAP | BRIDGE_CTRL_MEM_SWAP);
#ifdef CONFIG_PAGE_SIZE_4KB
bridge_clr(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#else /* 16kB or larger */
bridge_set(bc, b_wid_control, BRIDGE_CTRL_PAGE_SIZE);
#endif
/*
* Hmm... IRIX sets additional bits in the address which
* are documented as reserved in the bridge docs.
*/
bridge_write(bc, b_wid_int_upper,
((bc->intr_addr >> 32) & 0xffff) | (bd->masterwid << 16));
bridge_write(bc, b_wid_int_lower, bc->intr_addr & 0xffffffff);
bridge_write(bc, b_dir_map, (bd->masterwid << 20)); /* DMA */
bridge_write(bc, b_int_enable, 0);
for (slot = 0; slot < 8; slot++) {
bridge_set(bc, b_device[slot].reg, BRIDGE_DEV_SWAP_DIR);
bc->pci_int[slot] = -1;
}
bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
host->dev.parent = dev;
host->sysdata = bc;
host->busnr = 0;
host->ops = &bridge_pci_ops;
host->map_irq = bridge_map_irq;
host->swizzle_irq = pci_common_swizzle;
err = pci_scan_root_bus_bridge(host);
if (err < 0)
goto err_free_resource;
pci_bus_claim_resources(host->bus);
pci_bus_add_devices(host->bus);
platform_set_drvdata(pdev, host->bus);
return 0;
err_free_resource:
pci_free_resource_list(&host->windows);
err_remove_domain:
irq_domain_remove(domain);
return err;
}
static int bridge_remove(struct platform_device *pdev)
{
struct pci_bus *bus = platform_get_drvdata(pdev);
struct bridge_controller *bc = BRIDGE_CONTROLLER(bus);
irq_domain_remove(bc->domain);
pci_lock_rescan_remove();
pci_stop_root_bus(bus);
pci_remove_root_bus(bus);
pci_unlock_rescan_remove();
return 0;
}
static struct platform_driver bridge_driver = {
.probe = bridge_probe,
.remove = bridge_remove,
.driver = {
.name = "xtalk-bridge",
}
};
builtin_platform_driver(bridge_driver);
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/paccess.h> #include <asm/paccess.h>
#include <asm/sgi/ip22.h> #include <asm/sgi/ip22.h>
...@@ -25,6 +26,8 @@ static struct sgiwd93_platform_data sgiwd93_0_pd = { ...@@ -25,6 +26,8 @@ static struct sgiwd93_platform_data sgiwd93_0_pd = {
.irq = SGI_WD93_0_IRQ, .irq = SGI_WD93_0_IRQ,
}; };
static u64 sgiwd93_0_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sgiwd93_0_device = { static struct platform_device sgiwd93_0_device = {
.name = "sgiwd93", .name = "sgiwd93",
.id = 0, .id = 0,
...@@ -32,6 +35,8 @@ static struct platform_device sgiwd93_0_device = { ...@@ -32,6 +35,8 @@ static struct platform_device sgiwd93_0_device = {
.resource = sgiwd93_0_resources, .resource = sgiwd93_0_resources,
.dev = { .dev = {
.platform_data = &sgiwd93_0_pd, .platform_data = &sgiwd93_0_pd,
.dma_mask = &sgiwd93_0_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}, },
}; };
...@@ -49,6 +54,8 @@ static struct sgiwd93_platform_data sgiwd93_1_pd = { ...@@ -49,6 +54,8 @@ static struct sgiwd93_platform_data sgiwd93_1_pd = {
.irq = SGI_WD93_1_IRQ, .irq = SGI_WD93_1_IRQ,
}; };
static u64 sgiwd93_1_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sgiwd93_1_device = { static struct platform_device sgiwd93_1_device = {
.name = "sgiwd93", .name = "sgiwd93",
.id = 1, .id = 1,
...@@ -56,6 +63,8 @@ static struct platform_device sgiwd93_1_device = { ...@@ -56,6 +63,8 @@ static struct platform_device sgiwd93_1_device = {
.resource = sgiwd93_1_resources, .resource = sgiwd93_1_resources,
.dev = { .dev = {
.platform_data = &sgiwd93_1_pd, .platform_data = &sgiwd93_1_pd,
.dma_mask = &sgiwd93_1_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}, },
}; };
...@@ -96,6 +105,8 @@ static struct resource sgiseeq_0_resources[] = { ...@@ -96,6 +105,8 @@ static struct resource sgiseeq_0_resources[] = {
static struct sgiseeq_platform_data eth0_pd; static struct sgiseeq_platform_data eth0_pd;
static u64 sgiseeq_dma_mask = DMA_BIT_MASK(32);
static struct platform_device eth0_device = { static struct platform_device eth0_device = {
.name = "sgiseeq", .name = "sgiseeq",
.id = 0, .id = 0,
...@@ -103,6 +114,8 @@ static struct platform_device eth0_device = { ...@@ -103,6 +114,8 @@ static struct platform_device eth0_device = {
.resource = sgiseeq_0_resources, .resource = sgiseeq_0_resources,
.dev = { .dev = {
.platform_data = &eth0_pd, .platform_data = &eth0_pd,
.dma_mask = &sgiseeq_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}, },
}; };
......
...@@ -184,5 +184,7 @@ void __init plat_mem_setup(void) ...@@ -184,5 +184,7 @@ void __init plat_mem_setup(void)
ioc3_eth_init(); ioc3_eth_init();
ioport_resource.start = 0;
ioport_resource.end = ~0UL;
set_io_port_base(IO_BASE); set_io_port_base(IO_BASE);
} }
...@@ -12,22 +12,20 @@ ...@@ -12,22 +12,20 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/sched.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq_cpu.h> #include <asm/irq_cpu.h>
#include <asm/pci/bridge.h>
#include <asm/sn/addrs.h> #include <asm/sn/addrs.h>
#include <asm/sn/agent.h> #include <asm/sn/agent.h>
#include <asm/sn/arch.h> #include <asm/sn/arch.h>
#include <asm/sn/hub.h> #include <asm/sn/hub.h>
#include <asm/sn/intr.h> #include <asm/sn/intr.h>
#include <asm/sn/irq_alloc.h>
struct hub_irq_data { struct hub_irq_data {
struct bridge_controller *bc;
u64 *irq_mask[2]; u64 *irq_mask[2];
cpuid_t cpu; cpuid_t cpu;
int bit;
int pin;
}; };
static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT); static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
...@@ -54,7 +52,7 @@ static void enable_hub_irq(struct irq_data *d) ...@@ -54,7 +52,7 @@ static void enable_hub_irq(struct irq_data *d)
struct hub_irq_data *hd = irq_data_get_irq_chip_data(d); struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu); unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
set_bit(hd->bit, mask); set_bit(d->hwirq, mask);
__raw_writeq(mask[0], hd->irq_mask[0]); __raw_writeq(mask[0], hd->irq_mask[0]);
__raw_writeq(mask[1], hd->irq_mask[1]); __raw_writeq(mask[1], hd->irq_mask[1]);
} }
...@@ -64,71 +62,11 @@ static void disable_hub_irq(struct irq_data *d) ...@@ -64,71 +62,11 @@ static void disable_hub_irq(struct irq_data *d)
struct hub_irq_data *hd = irq_data_get_irq_chip_data(d); struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu); unsigned long *mask = per_cpu(irq_enable_mask, hd->cpu);
clear_bit(hd->bit, mask); clear_bit(d->hwirq, mask);
__raw_writeq(mask[0], hd->irq_mask[0]); __raw_writeq(mask[0], hd->irq_mask[0]);
__raw_writeq(mask[1], hd->irq_mask[1]); __raw_writeq(mask[1], hd->irq_mask[1]);
} }
static unsigned int startup_bridge_irq(struct irq_data *d)
{
struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
struct bridge_controller *bc;
nasid_t nasid;
u32 device;
int pin;
if (!hd)
return -EINVAL;
pin = hd->pin;
bc = hd->bc;
nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(hd->cpu));
bridge_write(bc, b_int_addr[pin].addr,
(0x20000 | hd->bit | (nasid << 8)));
bridge_set(bc, b_int_enable, (1 << pin));
bridge_set(bc, b_int_enable, 0x7ffffe00); /* more stuff in int_enable */
/*
* Enable sending of an interrupt clear packt to the hub on a high to
* low transition of the interrupt pin.
*
* IRIX sets additional bits in the address which are documented as
* reserved in the bridge docs.
*/
bridge_set(bc, b_int_mode, (1UL << pin));
/*
* We assume the bridge to have a 1:1 mapping between devices
* (slots) and intr pins.
*/
device = bridge_read(bc, b_int_device);
device &= ~(7 << (pin*3));
device |= (pin << (pin*3));
bridge_write(bc, b_int_device, device);
bridge_read(bc, b_wid_tflush);
enable_hub_irq(d);
return 0; /* Never anything pending. */
}
static void shutdown_bridge_irq(struct irq_data *d)
{
struct hub_irq_data *hd = irq_data_get_irq_chip_data(d);
struct bridge_controller *bc;
if (!hd)
return;
disable_hub_irq(d);
bc = hd->bc;
bridge_clr(bc, b_int_enable, (1 << hd->pin));
bridge_read(bc, b_wid_tflush);
}
static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask) static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
{ {
nasid_t nasid; nasid_t nasid;
...@@ -144,9 +82,6 @@ static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask) ...@@ -144,9 +82,6 @@ static void setup_hub_mask(struct hub_irq_data *hd, const struct cpumask *mask)
hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_B); hd->irq_mask[0] = REMOTE_HUB_PTR(nasid, PI_INT_MASK0_B);
hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_B); hd->irq_mask[1] = REMOTE_HUB_PTR(nasid, PI_INT_MASK1_B);
} }
/* Make sure it's not already pending when we connect it. */
REMOTE_HUB_CLR_INTR(nasid, hd->bit);
} }
static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask, static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
...@@ -163,7 +98,7 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask, ...@@ -163,7 +98,7 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
setup_hub_mask(hd, mask); setup_hub_mask(hd, mask);
if (irqd_is_started(d)) if (irqd_is_started(d))
startup_bridge_irq(d); enable_hub_irq(d);
irq_data_update_effective_affinity(d, cpumask_of(hd->cpu)); irq_data_update_effective_affinity(d, cpumask_of(hd->cpu));
...@@ -172,20 +107,22 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask, ...@@ -172,20 +107,22 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
static struct irq_chip hub_irq_type = { static struct irq_chip hub_irq_type = {
.name = "HUB", .name = "HUB",
.irq_startup = startup_bridge_irq,
.irq_shutdown = shutdown_bridge_irq,
.irq_mask = disable_hub_irq, .irq_mask = disable_hub_irq,
.irq_unmask = enable_hub_irq, .irq_unmask = enable_hub_irq,
.irq_set_affinity = set_affinity_hub_irq, .irq_set_affinity = set_affinity_hub_irq,
}; };
int request_bridge_irq(struct bridge_controller *bc, int pin) static int hub_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{ {
struct irq_alloc_info *info = arg;
struct hub_irq_data *hd; struct hub_irq_data *hd;
struct hub_data *hub; struct hub_data *hub;
struct irq_desc *desc; struct irq_desc *desc;
int swlevel; int swlevel;
int irq;
if (nr_irqs > 1 || !info)
return -EINVAL;
hd = kzalloc(sizeof(*hd), GFP_KERNEL); hd = kzalloc(sizeof(*hd), GFP_KERNEL);
if (!hd) if (!hd)
...@@ -196,46 +133,41 @@ int request_bridge_irq(struct bridge_controller *bc, int pin) ...@@ -196,46 +133,41 @@ int request_bridge_irq(struct bridge_controller *bc, int pin)
kfree(hd); kfree(hd);
return -EAGAIN; return -EAGAIN;
} }
irq = swlevel + IP27_HUB_IRQ_BASE; irq_domain_set_info(domain, virq, swlevel, &hub_irq_type, hd,
handle_level_irq, NULL, NULL);
hd->bc = bc;
hd->bit = swlevel;
hd->pin = pin;
irq_set_chip_data(irq, hd);
/* use CPU connected to nearest hub */ /* use CPU connected to nearest hub */
hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid)); hub = hub_data(NASID_TO_COMPACT_NODEID(info->nasid));
setup_hub_mask(hd, &hub->h_cpus); setup_hub_mask(hd, &hub->h_cpus);
desc = irq_to_desc(irq); /* Make sure it's not already pending when we connect it. */
desc->irq_common_data.node = bc->nasid; REMOTE_HUB_CLR_INTR(info->nasid, swlevel);
desc = irq_to_desc(virq);
desc->irq_common_data.node = info->nasid;
cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus); cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus);
return irq; return 0;
} }
void ip27_hub_irq_init(void) static void hub_domain_free(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs)
{ {
int i; struct irq_data *irqd;
for (i = IP27_HUB_IRQ_BASE;
i < (IP27_HUB_IRQ_BASE + IP27_HUB_IRQ_COUNT); i++)
irq_set_chip_and_handler(i, &hub_irq_type, handle_level_irq);
/*
* Some interrupts are reserved by hardware or by software convention.
* Mark these as reserved right away so they won't be used accidentally
* later.
*/
for (i = 0; i <= BASE_PCI_IRQ; i++)
set_bit(i, hub_irq_map);
set_bit(IP_PEND0_6_63, hub_irq_map); if (nr_irqs > 1)
return;
for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) irqd = irq_domain_get_irq_data(domain, virq);
set_bit(i, hub_irq_map); if (irqd && irqd->chip_data)
kfree(irqd->chip_data);
} }
static const struct irq_domain_ops hub_domain_ops = {
.alloc = hub_domain_alloc,
.free = hub_domain_free,
};
/* /*
* This code is unnecessarily complex, because we do * This code is unnecessarily complex, because we do
* intr enabling. Basically, once we grab the set of intrs we need * intr enabling. Basically, once we grab the set of intrs we need
...@@ -252,7 +184,9 @@ static void ip27_do_irq_mask0(struct irq_desc *desc) ...@@ -252,7 +184,9 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
{ {
cpuid_t cpu = smp_processor_id(); cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu); unsigned long *mask = per_cpu(irq_enable_mask, cpu);
struct irq_domain *domain;
u64 pend0; u64 pend0;
int irq;
/* copied from Irix intpend0() */ /* copied from Irix intpend0() */
pend0 = LOCAL_HUB_L(PI_INT_PEND0); pend0 = LOCAL_HUB_L(PI_INT_PEND0);
...@@ -276,7 +210,14 @@ static void ip27_do_irq_mask0(struct irq_desc *desc) ...@@ -276,7 +210,14 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
generic_smp_call_function_interrupt(); generic_smp_call_function_interrupt();
} else } else
#endif #endif
generic_handle_irq(__ffs(pend0) + IP27_HUB_IRQ_BASE); {
domain = irq_desc_get_handler_data(desc);
irq = irq_linear_revmap(domain, __ffs(pend0));
if (irq)
generic_handle_irq(irq);
else
spurious_interrupt();
}
LOCAL_HUB_L(PI_INT_PEND0); LOCAL_HUB_L(PI_INT_PEND0);
} }
...@@ -285,7 +226,9 @@ static void ip27_do_irq_mask1(struct irq_desc *desc) ...@@ -285,7 +226,9 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
{ {
cpuid_t cpu = smp_processor_id(); cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu); unsigned long *mask = per_cpu(irq_enable_mask, cpu);
struct irq_domain *domain;
u64 pend1; u64 pend1;
int irq;
/* copied from Irix intpend0() */ /* copied from Irix intpend0() */
pend1 = LOCAL_HUB_L(PI_INT_PEND1); pend1 = LOCAL_HUB_L(PI_INT_PEND1);
...@@ -294,7 +237,12 @@ static void ip27_do_irq_mask1(struct irq_desc *desc) ...@@ -294,7 +237,12 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
if (!pend1) if (!pend1)
return; return;
generic_handle_irq(__ffs(pend1) + IP27_HUB_IRQ_BASE + 64); domain = irq_desc_get_handler_data(desc);
irq = irq_linear_revmap(domain, __ffs(pend1) + 64);
if (irq)
generic_handle_irq(irq);
else
spurious_interrupt();
LOCAL_HUB_L(PI_INT_PEND1); LOCAL_HUB_L(PI_INT_PEND1);
} }
...@@ -325,11 +273,41 @@ void install_ipi(void) ...@@ -325,11 +273,41 @@ void install_ipi(void)
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
struct irq_domain *domain;
struct fwnode_handle *fn;
int i;
mips_cpu_irq_init(); mips_cpu_irq_init();
ip27_hub_irq_init();
/*
* Some interrupts are reserved by hardware or by software convention.
* Mark these as reserved right away so they won't be used accidentally
* later.
*/
for (i = 0; i <= BASE_PCI_IRQ; i++)
set_bit(i, hub_irq_map);
set_bit(IP_PEND0_6_63, hub_irq_map);
for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++)
set_bit(i, hub_irq_map);
fn = irq_domain_alloc_named_fwnode("HUB");
WARN_ON(fn == NULL);
if (!fn)
return;
domain = irq_domain_create_linear(fn, IP27_HUB_IRQ_COUNT,
&hub_domain_ops, NULL);
WARN_ON(domain == NULL);
if (!domain)
return;
irq_set_default_host(domain);
irq_set_percpu_devid(IP27_HUB_PEND0_IRQ); irq_set_percpu_devid(IP27_HUB_PEND0_IRQ);
irq_set_chained_handler(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0); irq_set_chained_handler_and_data(IP27_HUB_PEND0_IRQ, ip27_do_irq_mask0,
domain);
irq_set_percpu_devid(IP27_HUB_PEND1_IRQ); irq_set_percpu_devid(IP27_HUB_PEND1_IRQ);
irq_set_chained_handler(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1); irq_set_chained_handler_and_data(IP27_HUB_PEND1_IRQ, ip27_do_irq_mask1,
domain);
} }
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/platform_device.h>
#include <linux/platform_data/xtalk-bridge.h>
#include <asm/sn/addrs.h>
#include <asm/sn/types.h> #include <asm/sn/types.h>
#include <asm/sn/klconfig.h> #include <asm/sn/klconfig.h>
#include <asm/sn/hub.h> #include <asm/sn/hub.h>
...@@ -20,7 +23,48 @@ ...@@ -20,7 +23,48 @@
#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */ #define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
#define BASE_XBOW_PORT 8 /* Lowest external port */ #define BASE_XBOW_PORT 8 /* Lowest external port */
extern int bridge_probe(nasid_t nasid, int widget, int masterwid); static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
{
struct xtalk_bridge_platform_data *bd;
struct platform_device *pdev;
unsigned long offset;
bd = kzalloc(sizeof(*bd), GFP_KERNEL);
if (!bd)
goto no_mem;
pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
if (!pdev) {
kfree(bd);
goto no_mem;
}
offset = NODE_OFFSET(nasid);
bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
bd->intr_addr = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
bd->nasid = nasid;
bd->masterwid = masterwid;
bd->mem.name = "Bridge PCI MEM";
bd->mem.start = offset + (widget << SWIN_SIZE_BITS);
bd->mem.end = bd->mem.start + SWIN_SIZE - 1;
bd->mem.flags = IORESOURCE_MEM;
bd->mem_offset = offset;
bd->io.name = "Bridge PCI IO";
bd->io.start = offset + (widget << SWIN_SIZE_BITS);
bd->io.end = bd->io.start + SWIN_SIZE - 1;
bd->io.flags = IORESOURCE_IO;
bd->io_offset = offset;
platform_device_add_data(pdev, bd, sizeof(*bd));
platform_device_add(pdev);
pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
return;
no_mem:
pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
}
static int probe_one_port(nasid_t nasid, int widget, int masterwid) static int probe_one_port(nasid_t nasid, int widget, int masterwid)
{ {
...@@ -31,13 +75,10 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid) ...@@ -31,13 +75,10 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid)
(RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID); (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
partnum = XWIDGET_PART_NUM(widget_id); partnum = XWIDGET_PART_NUM(widget_id);
printk(KERN_INFO "Cpu %d, Nasid 0x%x, widget 0x%x (partnum 0x%x) is ",
smp_processor_id(), nasid, widget, partnum);
switch (partnum) { switch (partnum) {
case BRIDGE_WIDGET_PART_NUM: case BRIDGE_WIDGET_PART_NUM:
case XBRIDGE_WIDGET_PART_NUM: case XBRIDGE_WIDGET_PART_NUM:
bridge_probe(nasid, widget, masterwid); bridge_platform_create(nasid, widget, masterwid);
break; break;
default: default:
break; break;
...@@ -52,8 +93,6 @@ static int xbow_probe(nasid_t nasid) ...@@ -52,8 +93,6 @@ static int xbow_probe(nasid_t nasid)
klxbow_t *xbow_p; klxbow_t *xbow_p;
unsigned masterwid, i; unsigned masterwid, i;
printk("is xbow\n");
/* /*
* found xbow, so may have multiple bridges * found xbow, so may have multiple bridges
* need to probe xbow * need to probe xbow
...@@ -117,19 +156,17 @@ static void xtalk_probe_node(cnodeid_t nid) ...@@ -117,19 +156,17 @@ static void xtalk_probe_node(cnodeid_t nid)
(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
partnum = XWIDGET_PART_NUM(widget_id); partnum = XWIDGET_PART_NUM(widget_id);
printk(KERN_INFO "Cpu %d, Nasid 0x%x: partnum 0x%x is ",
smp_processor_id(), nasid, partnum);
switch (partnum) { switch (partnum) {
case BRIDGE_WIDGET_PART_NUM: case BRIDGE_WIDGET_PART_NUM:
bridge_probe(nasid, 0x8, 0xa); bridge_platform_create(nasid, 0x8, 0xa);
break; break;
case XBOW_WIDGET_PART_NUM: case XBOW_WIDGET_PART_NUM:
case XXBOW_WIDGET_PART_NUM: case XXBOW_WIDGET_PART_NUM:
pr_info("xtalk:n%d/0 xbow widget\n", nasid);
xbow_probe(nasid); xbow_probe(nasid);
break; break;
default: default:
printk(" unknown widget??\n"); pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
break; break;
} }
} }
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* SGI PCI Xtalk Bridge
*/
#ifndef PLATFORM_DATA_XTALK_BRIDGE_H
#define PLATFORM_DATA_XTALK_BRIDGE_H
#include <asm/sn/types.h>
struct xtalk_bridge_platform_data {
struct resource mem;
struct resource io;
unsigned long bridge_addr;
unsigned long intr_addr;
unsigned long mem_offset;
unsigned long io_offset;
nasid_t nasid;
int masterwid;
};
#endif /* PLATFORM_DATA_XTALK_BRIDGE_H */
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