Merge tag 'riscv-for-linus-4.19-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux

Pull RISC-V updates from Palmer Dabbelt:
 "This contains some major improvements to the RISC-V port, including
  the necessary interrupt controller and timer support to actually make
  it to userspace. Support for three devices has been added:

   - the ISA-mandated timers on RISC-V systems.

   - the ISA-mandated first-level interrupt controller on RISC-V
     systems, which is handled as part of our core arch code because
     it's very small and tightly tied to the ISA.

   - SiFive's platform-level interrupt controller, which talks to the
     actual devices.

  In addition to these new devices, there are a handful of cleanups all
  over the RISC-V tree:

   - build fixes for various configurations:
      * A fix to the vDSO build's makefile so it respects CFLAGS.
      * The addition of __lshrti3, a libgcc derived function necessary
        for some 32-bit configurations.
      * !SMP && PERF_EVENTS

   - Cleanups to the arch code to remove the remnants of old versions of
     the drivers that were just properly submitted.
      * Some dead code from the timer driver, most of which wasn't ever
        even compiled.
      * Cleanups of some interrupt #defines, which are now local to the
        interrupt handling code.

   - Fixes to ptrace(), which while not being sufficient to fully make
     GDB work are at least sufficient to get simple GDB tasks to work.

   - Early printk support via RISC-V's architecturally mandated SBI
     console device.

   - A fix to our early debug trap handler to ensure it's always
     aligned.

  These patches have all been through a fairly extensive review process,
  but as this enables a whole pile of functionality (ie, userspace) I'm
  confident we'll need to submit a few more patches. The only concrete
  issues I know about are the sys_riscv_flush_icache patches, but as I
  managed to screw those up on Friday I figured it'd be best to let them
  bake another week.

  This tag boots a Fedora root filesystem on QEMU's master branch for
  me, and before this morning's rebase (from 4.18-rc8 to 4.18) it booted
  on the HiFive Unleashed.

  Thanks to Christoph Hellwig and the other guys at WD for getting the
  new drivers in shape!"

* tag 'riscv-for-linus-4.19-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux:
  dt-bindings: interrupt-controller: SiFive Plaform Level Interrupt Controller
  dt-bindings: interrupt-controller: RISC-V local interrupt controller
  RISC-V: Fix !CONFIG_SMP compilation error
  irqchip: add a SiFive PLIC driver
  RISC-V: Add the directive for alignment of stvec's value
  clocksource: new RISC-V SBI timer driver
  RISC-V: implement low-level interrupt handling
  RISC-V: add a definition for the SIE SEIE bit
  RISC-V: remove INTERRUPT_CAUSE_* defines from asm/irq.h
  RISC-V: simplify software interrupt / IPI code
  RISC-V: remove timer leftovers
  RISC-V: Add early printk support via the SBI console
  RISC-V: Don't increment sepc after breakpoint.
  RISC-V: implement __lshrti3.
  RISC-V: Use KBUILD_CFLAGS instead of KCFLAGS when building the vDSO
This commit is contained in:
Linus Torvalds
2018-08-19 09:56:38 -07:00
27 changed files with 625 additions and 59 deletions

View File

@@ -609,4 +609,15 @@ config ATCPIT100_TIMER
help
This option enables support for the Andestech ATCPIT100 timers.
config RISCV_TIMER
bool "Timer for the RISC-V platform"
depends on RISCV
default y
select TIMER_PROBE
select TIMER_OF
help
This enables the per-hart timer built into all RISC-V systems, which
is accessed via both the SBI and the rdcycle instruction. This is
required for all RISC-V systems.
endmenu

View File

@@ -78,3 +78,4 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o

View File

@@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012 Regents of the University of California
* Copyright (C) 2017 SiFive
*/
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/sbi.h>
/*
* All RISC-V systems have a timer attached to every hart. These timers can be
* read by the 'rdcycle' pseudo instruction, and can use the SBI to setup
* events. In order to abstract the architecture-specific timer reading and
* setting functions away from the clock event insertion code, we provide
* function pointers to the clockevent subsystem that perform two basic
* operations: rdtime() reads the timer on the current CPU, and
* next_event(delta) sets the next timer event to 'delta' cycles in the future.
* As the timers are inherently a per-cpu resource, these callbacks perform
* operations on the current hart. There is guaranteed to be exactly one timer
* per hart on all RISC-V systems.
*/
static int riscv_clock_next_event(unsigned long delta,
struct clock_event_device *ce)
{
csr_set(sie, SIE_STIE);
sbi_set_timer(get_cycles64() + delta);
return 0;
}
static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
.name = "riscv_timer_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 100,
.set_next_event = riscv_clock_next_event,
};
/*
* It is guaranteed that all the timers across all the harts are synchronized
* within one tick of each other, so while this could technically go
* backwards when hopping between CPUs, practically it won't happen.
*/
static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs)
{
return get_cycles64();
}
static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
.name = "riscv_clocksource",
.rating = 300,
.mask = CLOCKSOURCE_MASK(BITS_PER_LONG),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.read = riscv_clocksource_rdtime,
};
static int riscv_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu);
ce->cpumask = cpumask_of(cpu);
clockevents_config_and_register(ce, riscv_timebase, 100, 0x7fffffff);
csr_set(sie, SIE_STIE);
return 0;
}
static int riscv_timer_dying_cpu(unsigned int cpu)
{
csr_clear(sie, SIE_STIE);
return 0;
}
/* called directly from the low-level interrupt handler */
void riscv_timer_interrupt(void)
{
struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event);
csr_clear(sie, SIE_STIE);
evdev->event_handler(evdev);
}
static int __init riscv_timer_init_dt(struct device_node *n)
{
int cpu_id = riscv_of_processor_hart(n), error;
struct clocksource *cs;
if (cpu_id != smp_processor_id())
return 0;
cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
clocksource_register_hz(cs, riscv_timebase);
error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,
"clockevents/riscv/timer:starting",
riscv_timer_starting_cpu, riscv_timer_dying_cpu);
if (error)
pr_err("RISCV timer register failed [%d] for cpu = [%d]\n",
error, cpu_id);
return error;
}
TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt);