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
select SYS_HAS_EARLY_PRINTK
select HAVE_PCI
select IRQ_MIPS_CPU
select IRQ_DOMAIN_HIERARCHY
select NR_CPUS_DEFAULT_64
select PCI_DRIVERS_GENERIC
select PCI_XTALK_BRIDGE
select SYS_HAS_CPU_R10000
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
......@@ -1241,6 +1244,9 @@ config IRQ_GT641XX
config PCI_GT64XXX_PCI0
bool
config PCI_XTALK_BRIDGE
bool
config NO_EXCEPT_FILL
bool
......
......@@ -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_ohci_dmamask = DMA_BIT_MASK(32);
static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32);
static u64 alchemy_all_dmamask = DMA_BIT_MASK(32);
/* Power on callback for the ehci platform driver */
static int alchemy_ehci_power_on(struct platform_device *pdev)
......@@ -231,7 +229,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ;
pdev->name = "ohci-platform";
pdev->id = 0;
pdev->dev.dma_mask = &alchemy_ohci_dmamask;
pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ohci_pdata;
if (platform_device_register(pdev))
......@@ -251,7 +249,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ;
pdev->name = "ehci-platform";
pdev->id = 0;
pdev->dev.dma_mask = &alchemy_ehci_dmamask;
pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ehci_pdata;
if (platform_device_register(pdev))
......@@ -271,7 +269,7 @@ static void __init alchemy_setup_usb(int ctype)
res[1].flags = IORESOURCE_IRQ;
pdev->name = "ohci-platform";
pdev->id = 1;
pdev->dev.dma_mask = &alchemy_ohci_dmamask;
pdev->dev.dma_mask = &alchemy_all_dmamask;
pdev->dev.platform_data = &alchemy_ohci_pdata;
if (platform_device_register(pdev))
......@@ -338,7 +336,11 @@ static struct platform_device au1xxx_eth0_device = {
.name = "au1000-eth",
.id = 0,
.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 = {
......@@ -370,7 +372,11 @@ static struct platform_device au1xxx_eth1_device = {
.name = "au1000-eth",
.id = 1,
.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,
......
......@@ -43,14 +43,14 @@ void __init *plat_get_fdt(void)
/* Already set up */
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
* provided with the appropriate device tree for the board.
* Make use of it & search for any machine struct based upon
* the root compatible string.
*/
fdt = (void *)fw_arg1;
fdt = (void *)fw_passed_dtb;
for_each_mips_machine(check_mach) {
match = mips_machine_is_compatible(check_mach, fdt);
......
......@@ -7,18 +7,9 @@
#include <asm/mmzone.h>
struct cpuinfo_ip27 {
// cpuid_t p_cpuid; /* PROM assigned cpuid */
cnodeid_t p_nodeid; /* my node ID in compact-id-space */
nasid_t p_nasid; /* my node ID in numa-as-id-space */
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];
......@@ -30,7 +21,7 @@ extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
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];
......
......@@ -801,15 +801,13 @@ struct bridge_err_cmdword {
#define PCI64_ATTR_RMF_SHFT 48
struct bridge_controller {
struct pci_controller pc;
struct resource mem;
struct resource io;
struct resource busn;
struct bridge_regs *base;
nasid_t nasid;
unsigned int widget_id;
u64 baddr;
unsigned long baddr;
unsigned long intr_addr;
struct irq_domain *domain;
unsigned int pci_int[8];
nasid_t nasid;
};
#define BRIDGE_CONTROLLER(bus) \
......@@ -822,8 +820,4 @@ struct bridge_controller {
#define bridge_clr(bc, reg, val) \
__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 */
/* 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;
#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))
#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 /* _ASM_XTALK_XTALK_H */
......@@ -1973,6 +1973,14 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
panic("Unknown Ingenic Processor ID!");
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)
......
......@@ -64,17 +64,11 @@ struct mips_perf_event {
#define CNTR_EVEN 0x55555555
#define CNTR_ODD 0xaaaaaaaa
#define CNTR_ALL 0xffffffff
#ifdef CONFIG_MIPS_MT_SMP
enum {
T = 0,
V = 1,
P = 2,
} range;
#else
#define T
#define V
#define P
#endif
};
static struct mips_perf_event raw_event;
......@@ -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 cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
#ifdef CONFIG_MIPS_MT_SMP
unsigned int range = evt->event_base >> 24;
#endif /* CONFIG_MIPS_MT_SMP */
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)
/* Make sure interrupt enabled. */
MIPS_PERFCTRL_IE;
#ifdef CONFIG_CPU_BMIPS5000
{
if (IS_ENABLED(CONFIG_CPU_BMIPS5000)) {
/* enable the counter for the calling thread */
cpuc->saved_ctrl[idx] |=
(1 << (12 + vpe_id())) | BRCM_PERFCTRL_TC;
}
#else
#ifdef CONFIG_MIPS_MT_SMP
if (range > V) {
} else if (IS_ENABLED(CONFIG_MIPS_MT_SMP) && range > V) {
/* The counter is processor wide. Set it up to count all TCs. */
pr_debug("Enabling perf counter for all TCs\n");
cpuc->saved_ctrl[idx] |= M_TC_EN_ALL;
} else
#endif /* CONFIG_MIPS_MT_SMP */
{
} else {
unsigned int cpu, ctrl;
/*
......@@ -365,7 +351,6 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
cpuc->saved_ctrl[idx] |= ctrl;
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().
*/
......
......@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI_AR2315) += pci-ar2315.o
obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o
obj-$(CONFIG_PCI_AR724X) += pci-ar724x.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.
#
......@@ -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_EVAL) += 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_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
......
......@@ -7,162 +7,7 @@
* Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
* 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/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)
{
......@@ -177,29 +22,6 @@ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
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
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);
#endif /* CONFIG_NUMA */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
pci_fixup_ioc3);
......@@ -3,6 +3,7 @@
#include <linux/if_ether.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/paccess.h>
#include <asm/sgi/ip22.h>
......@@ -25,6 +26,8 @@ static struct sgiwd93_platform_data sgiwd93_0_pd = {
.irq = SGI_WD93_0_IRQ,
};
static u64 sgiwd93_0_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sgiwd93_0_device = {
.name = "sgiwd93",
.id = 0,
......@@ -32,6 +35,8 @@ static struct platform_device sgiwd93_0_device = {
.resource = sgiwd93_0_resources,
.dev = {
.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 = {
.irq = SGI_WD93_1_IRQ,
};
static u64 sgiwd93_1_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sgiwd93_1_device = {
.name = "sgiwd93",
.id = 1,
......@@ -56,6 +63,8 @@ static struct platform_device sgiwd93_1_device = {
.resource = sgiwd93_1_resources,
.dev = {
.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[] = {
static struct sgiseeq_platform_data eth0_pd;
static u64 sgiseeq_dma_mask = DMA_BIT_MASK(32);
static struct platform_device eth0_device = {
.name = "sgiseeq",
.id = 0,
......@@ -103,6 +114,8 @@ static struct platform_device eth0_device = {
.resource = sgiseeq_0_resources,
.dev = {
.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)
ioc3_eth_init();
ioport_resource.start = 0;
ioport_resource.end = ~0UL;
set_io_port_base(IO_BASE);
}
......@@ -12,22 +12,20 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq_cpu.h>
#include <asm/pci/bridge.h>
#include <asm/sn/addrs.h>
#include <asm/sn/agent.h>
#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/sn/intr.h>
#include <asm/sn/irq_alloc.h>
struct hub_irq_data {
struct bridge_controller *bc;
u64 *irq_mask[2];
cpuid_t cpu;
int bit;
int pin;
};
static DECLARE_BITMAP(hub_irq_map, IP27_HUB_IRQ_COUNT);
......@@ -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);
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[1], hd->irq_mask[1]);
}
......@@ -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);
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[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)
{
nasid_t nasid;
......@@ -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[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,
......@@ -163,7 +98,7 @@ static int set_affinity_hub_irq(struct irq_data *d, const struct cpumask *mask,
setup_hub_mask(hd, mask);
if (irqd_is_started(d))
startup_bridge_irq(d);
enable_hub_irq(d);
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,
static struct irq_chip hub_irq_type = {
.name = "HUB",
.irq_startup = startup_bridge_irq,
.irq_shutdown = shutdown_bridge_irq,
.irq_mask = disable_hub_irq,
.irq_unmask = enable_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_data *hub;
struct irq_desc *desc;
int swlevel;
int irq;
if (nr_irqs > 1 || !info)
return -EINVAL;
hd = kzalloc(sizeof(*hd), GFP_KERNEL);
if (!hd)
......@@ -196,46 +133,41 @@ int request_bridge_irq(struct bridge_controller *bc, int pin)
kfree(hd);
return -EAGAIN;
}
irq = swlevel + IP27_HUB_IRQ_BASE;
hd->bc = bc;
hd->bit = swlevel;
hd->pin = pin;
irq_set_chip_data(irq, hd);
irq_domain_set_info(domain, virq, swlevel, &hub_irq_type, hd,
handle_level_irq, NULL, NULL);
/* 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);
desc = irq_to_desc(irq);
desc->irq_common_data.node = bc->nasid;
/* Make sure it's not already pending when we connect it. */
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);
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++)
set_bit(i, hub_irq_map);
irqd = irq_domain_get_irq_data(domain, virq);
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
* 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)
{
cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu);
struct irq_domain *domain;
u64 pend0;
int irq;
/* copied from Irix intpend0() */
pend0 = LOCAL_HUB_L(PI_INT_PEND0);
......@@ -276,7 +210,14 @@ static void ip27_do_irq_mask0(struct irq_desc *desc)
generic_smp_call_function_interrupt();
} else
#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);
}
......@@ -285,7 +226,9 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
{
cpuid_t cpu = smp_processor_id();
unsigned long *mask = per_cpu(irq_enable_mask, cpu);
struct irq_domain *domain;
u64 pend1;
int irq;
/* copied from Irix intpend0() */
pend1 = LOCAL_HUB_L(PI_INT_PEND1);
......@@ -294,7 +237,12 @@ static void ip27_do_irq_mask1(struct irq_desc *desc)
if (!pend1)
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);
}
......@@ -325,11 +273,41 @@ void install_ipi(void)
void __init arch_init_irq(void)
{
struct irq_domain *domain;
struct fwnode_handle *fn;
int i;
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_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_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 @@
#include <linux/kernel.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/klconfig.h>
#include <asm/sn/hub.h>
......@@ -20,7 +23,48 @@
#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
#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)
{
......@@ -31,13 +75,10 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid)
(RAW_NODE_SWIN_BASE(nasid, widget) + 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) {
case BRIDGE_WIDGET_PART_NUM:
case XBRIDGE_WIDGET_PART_NUM:
bridge_probe(nasid, widget, masterwid);
bridge_platform_create(nasid, widget, masterwid);
break;
default:
break;
......@@ -52,8 +93,6 @@ static int xbow_probe(nasid_t nasid)
klxbow_t *xbow_p;
unsigned masterwid, i;
printk("is xbow\n");
/*
* found xbow, so may have multiple bridges
* need to probe xbow
......@@ -117,19 +156,17 @@ static void xtalk_probe_node(cnodeid_t nid)
(RAW_NODE_SWIN_BASE(nasid, 0x0) + 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) {
case BRIDGE_WIDGET_PART_NUM:
bridge_probe(nasid, 0x8, 0xa);
bridge_platform_create(nasid, 0x8, 0xa);
break;
case XBOW_WIDGET_PART_NUM:
case XXBOW_WIDGET_PART_NUM:
pr_info("xtalk:n%d/0 xbow widget\n", nasid);
xbow_probe(nasid);
break;
default:
printk(" unknown widget??\n");
pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
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