Commit 097f70b3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus

Pull MIPS fixes from Ralf Baechle:
 - Properly setup irq handling for ATH79 platforms
 - Fix bootmem mapstart calculation for contiguous maps
 - Handle little endian and older CPUs correct in BPF
 - Fix console for Fulong 2E systems
 - Handle FTLB correctly on R6 CPUs
 - Fixes for CM, GIC and MAAR support code

* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus:
  MIPS: Initialise MAARs on secondary CPUs
  MIPS: print MAAR configuration during boot
  MIPS: mm: compile maar_init unconditionally
  irqchip: mips-gic: Fix pending & mask reads for MIPS64 with 32b GIC.
  irqchip: mips-gic: Convert CPU numbers to VP IDs.
  MIPS: CM: Provide a function to map from CPU to VP ID.
  MIPS: Fix FTLB detection for R6
  MIPS: cpu-features: Add cpu_has_ftlb
  MIPS: ATH79: Add irq chip ar7240-misc-intc
  MIPS: ATH79: Set missing irq ack handler for ar7100-misc-intc irq chip
  MIPS: BPF: Fix build on pre-R2 little endian CPUs
  MIPS: BPF: Avoid unreachable code on little endian
  MIPS: bootmem: Fix mapstart calculation for contiguous maps
  MIPS: Fix console output for Fulong2e system
parents e3be4266 e060f6ed
......@@ -4,8 +4,8 @@ The MISC interrupt controller is a secondary controller for lower priority
interrupt.
Required Properties:
- compatible: has to be "qca,<soctype>-cpu-intc", "qca,ar7100-misc-intc"
as fallback
- compatible: has to be "qca,<soctype>-cpu-intc", "qca,ar7100-misc-intc" or
"qca,<soctype>-cpu-intc", "qca,ar7240-misc-intc"
- reg: Base address and size of the controllers memory area
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
......@@ -13,6 +13,9 @@ Required Properties:
- #interrupt-cells : Specifies the number of cells needed to encode interrupt
source, should be 1
Compatible fallback depends on the SoC. Use ar7100 for ar71xx and ar913x,
use ar7240 for all other SoCs.
Please refer to interrupts.txt in this directory for details of the common
Interrupt Controllers bindings used by client devices.
......@@ -28,3 +31,16 @@ Example:
interrupt-controller;
#interrupt-cells = <1>;
};
Another example:
interrupt-controller@18060010 {
compatible = "qca,ar9331-misc-intc", qca,ar7240-misc-intc";
reg = <0x18060010 0x4>;
interrupt-parent = <&cpuintc>;
interrupts = <6>;
interrupt-controller;
#interrupt-cells = <1>;
};
......@@ -293,8 +293,26 @@ static int __init ath79_misc_intc_of_init(
return 0;
}
IRQCHIP_DECLARE(ath79_misc_intc, "qca,ar7100-misc-intc",
ath79_misc_intc_of_init);
static int __init ar7100_misc_intc_of_init(
struct device_node *node, struct device_node *parent)
{
ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
return ath79_misc_intc_of_init(node, parent);
}
IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
ar7100_misc_intc_of_init);
static int __init ar7240_misc_intc_of_init(
struct device_node *node, struct device_node *parent)
{
ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
return ath79_misc_intc_of_init(node, parent);
}
IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
ar7240_misc_intc_of_init);
static int __init ar79_cpu_intc_of_init(
struct device_node *node, struct device_node *parent)
......
......@@ -20,6 +20,9 @@
#ifndef cpu_has_tlb
#define cpu_has_tlb (cpu_data[0].options & MIPS_CPU_TLB)
#endif
#ifndef cpu_has_ftlb
#define cpu_has_ftlb (cpu_data[0].options & MIPS_CPU_FTLB)
#endif
#ifndef cpu_has_tlbinv
#define cpu_has_tlbinv (cpu_data[0].options & MIPS_CPU_TLBINV)
#endif
......
......@@ -385,6 +385,7 @@ enum cpu_type_enum {
#define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */
#define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */
#define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */
#define MIPS_CPU_FTLB 0x20000000000ull /* CPU has Fixed-page-size TLB */
/*
* CPU ASE encodings
......
......@@ -65,6 +65,15 @@ static inline void write_maar_pair(unsigned idx, phys_addr_t lower,
back_to_back_c0_hazard();
}
/**
* maar_init() - initialise MAARs
*
* Performs initialisation of MAARs for the current CPU, making use of the
* platforms implementation of platform_maar_init where necessary and
* duplicating the setup it provides on secondary CPUs.
*/
extern void maar_init(void);
/**
* struct maar_config - MAAR configuration data
* @lower: The lowest address that the MAAR pair will affect. Must be
......
......@@ -194,6 +194,7 @@ BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8)
BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0)
BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0)
BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130)
BUILD_CM_RW(sys_config2, MIPS_CM_GCB_OFS + 0x150)
/* Core Local & Core Other register accessor functions */
BUILD_CM_Cx_RW(reset_release, 0x00)
......@@ -316,6 +317,10 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
#define CM_GCR_L2_CONFIG_ASSOC_SHF 0
#define CM_GCR_L2_CONFIG_ASSOC_MSK (_ULCAST_(0xff) << 0)
/* GCR_SYS_CONFIG2 register fields */
#define CM_GCR_SYS_CONFIG2_MAXVPW_SHF 0
#define CM_GCR_SYS_CONFIG2_MAXVPW_MSK (_ULCAST_(0xf) << 0)
/* GCR_Cx_COHERENCE register fields */
#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0
#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0)
......@@ -405,4 +410,38 @@ static inline int mips_cm_revision(void)
return read_gcr_rev();
}
/**
* mips_cm_max_vp_width() - return the width in bits of VP indices
*
* Return: the width, in bits, of VP indices in fields that combine core & VP
* indices.
*/
static inline unsigned int mips_cm_max_vp_width(void)
{
extern int smp_num_siblings;
if (mips_cm_revision() >= CM_REV_CM3)
return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK;
return smp_num_siblings;
}
/**
* mips_cm_vp_id() - calculate the hardware VP ID for a CPU
* @cpu: the CPU whose VP ID to calculate
*
* Hardware such as the GIC uses identifiers for VPs which may not match the
* CPU numbers used by Linux. This function calculates the hardware VP
* identifier corresponding to a given CPU.
*
* Return: the VP ID for the CPU.
*/
static inline unsigned int mips_cm_vp_id(unsigned int cpu)
{
unsigned int core = cpu_data[cpu].core;
unsigned int vp = cpu_vpe_id(&cpu_data[cpu]);
return (core * mips_cm_max_vp_width()) + vp;
}
#endif /* __MIPS_ASM_MIPS_CM_H__ */
......@@ -487,6 +487,8 @@
/* Bits specific to the MIPS32/64 PRA. */
#define MIPS_CONF_MT (_ULCAST_(7) << 7)
#define MIPS_CONF_MT_TLB (_ULCAST_(1) << 7)
#define MIPS_CONF_MT_FTLB (_ULCAST_(4) << 7)
#define MIPS_CONF_AR (_ULCAST_(7) << 10)
#define MIPS_CONF_AT (_ULCAST_(3) << 13)
#define MIPS_CONF_M (_ULCAST_(1) << 31)
......
......@@ -410,16 +410,18 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable)
static inline unsigned int decode_config0(struct cpuinfo_mips *c)
{
unsigned int config0;
int isa;
int isa, mt;
config0 = read_c0_config();
/*
* Look for Standard TLB or Dual VTLB and FTLB
*/
if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
(((config0 & MIPS_CONF_MT) >> 7) == 4))
mt = config0 & MIPS_CONF_MT;
if (mt == MIPS_CONF_MT_TLB)
c->options |= MIPS_CPU_TLB;
else if (mt == MIPS_CONF_MT_FTLB)
c->options |= MIPS_CPU_TLB | MIPS_CPU_FTLB;
isa = (config0 & MIPS_CONF_AT) >> 13;
switch (isa) {
......@@ -559,15 +561,18 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
if (cpu_has_tlb) {
if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
c->options |= MIPS_CPU_TLBINV;
/*
* This is a bit ugly. R6 has dropped that field from
* config4 and the only valid configuration is VTLB+FTLB so
* set a good value for mmuextdef for that case.
* R6 has dropped the MMUExtDef field from config4.
* On R6 the fields always describe the FTLB, and only if it is
* present according to Config.MT.
*/
if (cpu_has_mips_r6)
if (!cpu_has_mips_r6)
mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
else if (cpu_has_ftlb)
mmuextdef = MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT;
else
mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
mmuextdef = 0;
switch (mmuextdef) {
case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
......
......@@ -338,7 +338,7 @@ static void __init bootmem_init(void)
if (end <= reserved_end)
continue;
#ifdef CONFIG_BLK_DEV_INITRD
/* mapstart should be after initrd_end */
/* Skip zones before initrd and initrd itself */
if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
continue;
#endif
......@@ -371,6 +371,14 @@ static void __init bootmem_init(void)
max_low_pfn = PFN_DOWN(HIGHMEM_START);
}
#ifdef CONFIG_BLK_DEV_INITRD
/*
* mapstart should be after initrd_end
*/
if (initrd_end)
mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end)));
#endif
/*
* Initialize the boot-time allocator with low memory only.
*/
......
......@@ -42,6 +42,7 @@
#include <asm/mmu_context.h>
#include <asm/time.h>
#include <asm/setup.h>
#include <asm/maar.h>
cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
......@@ -157,6 +158,7 @@ asmlinkage void start_secondary(void)
mips_clockevent_init();
mp_ops->init_secondary();
cpu_report();
maar_init();
/*
* XXX parity protection should be folded in here when it's converted
......
......@@ -64,6 +64,9 @@ void __init prom_init_env(void)
}
if (memsize == 0)
memsize = 256;
loongson_sysconf.nr_uarts = 1;
pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
#else
struct boot_params *boot_p;
......
......@@ -44,6 +44,7 @@
#include <asm/pgalloc.h>
#include <asm/tlb.h>
#include <asm/fixmap.h>
#include <asm/maar.h>
/*
* We have up to 8 empty zeroed pages so we can map one of the right colour
......@@ -252,6 +253,119 @@ void __init fixrange_init(unsigned long start, unsigned long end,
#endif
}
unsigned __weak platform_maar_init(unsigned num_pairs)
{
struct maar_config cfg[BOOT_MEM_MAP_MAX];
unsigned i, num_configured, num_cfg = 0;
phys_addr_t skip;
for (i = 0; i < boot_mem_map.nr_map; i++) {
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
case BOOT_MEM_INIT_RAM:
break;
default:
continue;
}
skip = 0x10000 - (boot_mem_map.map[i].addr & 0xffff);
cfg[num_cfg].lower = boot_mem_map.map[i].addr;
cfg[num_cfg].lower += skip;
cfg[num_cfg].upper = cfg[num_cfg].lower;
cfg[num_cfg].upper += boot_mem_map.map[i].size - 1;
cfg[num_cfg].upper -= skip;
cfg[num_cfg].attrs = MIPS_MAAR_S;
num_cfg++;
}
num_configured = maar_config(cfg, num_cfg, num_pairs);
if (num_configured < num_cfg)
pr_warn("Not enough MAAR pairs (%u) for all bootmem regions (%u)\n",
num_pairs, num_cfg);
return num_configured;
}
void maar_init(void)
{
unsigned num_maars, used, i;
phys_addr_t lower, upper, attr;
static struct {
struct maar_config cfgs[3];
unsigned used;
} recorded = { { { 0 } }, 0 };
if (!cpu_has_maar)
return;
/* Detect the number of MAARs */
write_c0_maari(~0);
back_to_back_c0_hazard();
num_maars = read_c0_maari() + 1;
/* MAARs should be in pairs */
WARN_ON(num_maars % 2);
/* Set MAARs using values we recorded already */
if (recorded.used) {
used = maar_config(recorded.cfgs, recorded.used, num_maars / 2);
BUG_ON(used != recorded.used);
} else {
/* Configure the required MAARs */
used = platform_maar_init(num_maars / 2);
}
/* Disable any further MAARs */
for (i = (used * 2); i < num_maars; i++) {
write_c0_maari(i);
back_to_back_c0_hazard();
write_c0_maar(0);
back_to_back_c0_hazard();
}
if (recorded.used)
return;
pr_info("MAAR configuration:\n");
for (i = 0; i < num_maars; i += 2) {
write_c0_maari(i);
back_to_back_c0_hazard();
upper = read_c0_maar();
write_c0_maari(i + 1);
back_to_back_c0_hazard();
lower = read_c0_maar();
attr = lower & upper;
lower = (lower & MIPS_MAAR_ADDR) << 4;
upper = ((upper & MIPS_MAAR_ADDR) << 4) | 0xffff;
pr_info(" [%d]: ", i / 2);
if (!(attr & MIPS_MAAR_V)) {
pr_cont("disabled\n");
continue;
}
pr_cont("%pa-%pa", &lower, &upper);
if (attr & MIPS_MAAR_S)
pr_cont(" speculate");
pr_cont("\n");
/* Record the setup for use on secondary CPUs */
if (used <= ARRAY_SIZE(recorded.cfgs)) {
recorded.cfgs[recorded.used].lower = lower;
recorded.cfgs[recorded.used].upper = upper;
recorded.cfgs[recorded.used].attrs = attr;
recorded.used++;
}
}
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
int page_is_ram(unsigned long pagenr)
{
......@@ -334,69 +448,6 @@ static inline void mem_init_free_highmem(void)
#endif
}
unsigned __weak platform_maar_init(unsigned num_pairs)
{
struct maar_config cfg[BOOT_MEM_MAP_MAX];
unsigned i, num_configured, num_cfg = 0;
phys_addr_t skip;
for (i = 0; i < boot_mem_map.nr_map; i++) {
switch (boot_mem_map.map[i].type) {
case BOOT_MEM_RAM:
case BOOT_MEM_INIT_RAM:
break;
default:
continue;
}
skip = 0x10000 - (boot_mem_map.map[i].addr & 0xffff);
cfg[num_cfg].lower = boot_mem_map.map[i].addr;
cfg[num_cfg].lower += skip;
cfg[num_cfg].upper = cfg[num_cfg].lower;
cfg[num_cfg].upper += boot_mem_map.map[i].size - 1;
cfg[num_cfg].upper -= skip;
cfg[num_cfg].attrs = MIPS_MAAR_S;
num_cfg++;
}
num_configured = maar_config(cfg, num_cfg, num_pairs);
if (num_configured < num_cfg)
pr_warn("Not enough MAAR pairs (%u) for all bootmem regions (%u)\n",
num_pairs, num_cfg);
return num_configured;
}
static void maar_init(void)
{
unsigned num_maars, used, i;
if (!cpu_has_maar)
return;
/* Detect the number of MAARs */
write_c0_maari(~0);
back_to_back_c0_hazard();
num_maars = read_c0_maari() + 1;
/* MAARs should be in pairs */
WARN_ON(num_maars % 2);
/* Configure the required MAARs */
used = platform_maar_init(num_maars / 2);
/* Disable any further MAARs */
for (i = (used * 2); i < num_maars; i++) {
write_c0_maari(i);
back_to_back_c0_hazard();
write_c0_maar(0);
back_to_back_c0_hazard();
}
}
void __init mem_init(void)
{
#ifdef CONFIG_HIGHMEM
......
......@@ -64,8 +64,20 @@ sk_load_word_positive:
PTR_ADDU t1, $r_skb_data, offset
lw $r_A, 0(t1)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
wsbh t0, $r_A
rotr $r_A, t0, 16
# else
sll t0, $r_A, 24
srl t1, $r_A, 24
srl t2, $r_A, 8
or t0, t0, t1
andi t2, t2, 0xff00
andi t1, $r_A, 0xff00
or t0, t0, t2
sll t1, t1, 8
or $r_A, t0, t1
# endif
#endif
jr $r_ra
move $r_ret, zero
......@@ -80,8 +92,16 @@ sk_load_half_positive:
PTR_ADDU t1, $r_skb_data, offset
lh $r_A, 0(t1)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
wsbh t0, $r_A
seh $r_A, t0
# else
sll t0, $r_A, 24
andi t1, $r_A, 0xff00
sra t0, t0, 16
srl t1, t1, 8
or $r_A, t0, t1
# endif
#endif
jr $r_ra
move $r_ret, zero
......@@ -148,23 +168,47 @@ sk_load_byte_positive:
NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp)
bpf_slow_path_common(4)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
wsbh t0, $r_s0
jr $r_ra
rotr $r_A, t0, 16
#endif
# else
sll t0, $r_s0, 24
srl t1, $r_s0, 24
srl t2, $r_s0, 8
or t0, t0, t1
andi t2, t2, 0xff00
andi t1, $r_s0, 0xff00
or t0, t0, t2
sll t1, t1, 8
jr $r_ra
or $r_A, t0, t1
# endif
#else
jr $r_ra
move $r_A, $r_s0
#endif
END(bpf_slow_path_word)
NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp)
bpf_slow_path_common(2)
#ifdef CONFIG_CPU_LITTLE_ENDIAN
# if defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
jr $r_ra
wsbh $r_A, $r_s0
#endif
# else
sll t0, $r_s0, 8
andi t1, $r_s0, 0xff00
andi t0, t0, 0xff00
srl t1, t1, 8
jr $r_ra
or $r_A, t0, t1
# endif
#else
jr $r_ra
move $r_A, $r_s0
#endif
END(bpf_slow_path_half)
......
......@@ -320,6 +320,14 @@ static void gic_handle_shared_int(bool chained)
intrmask[i] = gic_read(intrmask_reg);
pending_reg += gic_reg_step;
intrmask_reg += gic_reg_step;
if (!config_enabled(CONFIG_64BIT) || mips_cm_is64)
continue;
pending[i] |= (u64)gic_read(pending_reg) << 32;
intrmask[i] |= (u64)gic_read(intrmask_reg) << 32;
pending_reg += gic_reg_step;
intrmask_reg += gic_reg_step;
}
bitmap_and(pending, pending, intrmask, gic_shared_intrs);
......@@ -426,7 +434,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
spin_lock_irqsave(&gic_lock, flags);
/* Re-route this IRQ */
gic_map_to_vpe(irq, cpumask_first(&tmp));
gic_map_to_vpe(irq, mips_cm_vp_id(cpumask_first(&tmp)));
/* Update the pcpu_masks */
for (i = 0; i < NR_CPUS; i++)
......@@ -599,7 +607,7 @@ static __init void gic_ipi_init_one(unsigned int intr, int cpu,
GIC_SHARED_TO_HWIRQ(intr));
int i;
gic_map_to_vpe(intr, cpu);
gic_map_to_vpe(intr, mips_cm_vp_id(cpu));
for (i = 0; i < NR_CPUS; i++)
clear_bit(intr, pcpu_masks[i].pcpu_mask);
set_bit(intr, pcpu_masks[cpu].pcpu_mask);
......
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