* [RFC PATCH 05/12] arm/sdei: add support to trigger event by GIC interrupt ID
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Add an external interface to trigger an SDEI event bound to an
interrupt by providing GIC interrupt ID.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 38 ++++++++++++++++++++++++++++++++++++++
target/arm/sdei.h | 7 +++++++
2 files changed, 45 insertions(+)
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index f9a1208..088ed76 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -453,6 +453,29 @@ static int64_t sdei_version(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
(0ULL << SDEI_VERSION_MINOR_SHIFT);
}
+static bool inject_event(QemuSDEState *s, CPUState *cs,
+ int32_t event, int irq)
+{
+ QemuSDE *sde;
+
+ if (event < 0) {
+ return false;
+ }
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return false;
+ }
+ if (irq > 0 && sde->prop->interrupt != irq) {
+ /* Someone unbinds the interrupt! */
+ put_sde(sde, cs);
+ return false;
+ }
+ sde->pending = true;
+ dispatch_single(s, sde, cs);
+ return true;
+}
+
static int64_t unregister_single_sde(QemuSDEState *s, int32_t event,
CPUState *cs, bool force)
{
@@ -1033,6 +1056,21 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
}
}
+bool trigger_sdei_by_irq(int cpu, int irq)
+{
+ QemuSDEState *s = sde_state;
+
+ if (!s || irq >= ARRAY_SIZE(s->irq_map)) {
+ return false;
+ }
+
+ if (s->irq_map[irq] == SDEI_INVALID_EVENT_ID) {
+ return false;
+ }
+
+ return inject_event(s, arm_get_cpu_by_id(cpu), s->irq_map[irq], irq);
+}
+
static void qemu_shared_sde_init(QemuSDEState *s)
{
int i;
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index a69a0e4..a61e788 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -31,4 +31,11 @@
void sdei_handle_request(CPUState *cs, struct kvm_run *run);
+/*
+ * Trigger an SDEI event bound to an interrupt.
+ * Return true if event has been triggered successfully.
+ * Return false if event has not been triggered for some reason.
+ */
+bool trigger_sdei_by_irq(int cpu, int irq);
+
#endif
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 03/12] arm/sdei: add support to handle SDEI requests from guest
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, James Morse, Marc Zyngier,
Jingyi Wang, Heyi Guo, wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Add support for all interfaces defined in ARM SDEI 1.0 spec.
http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
The exit reason KVM_EXIT_HYPERCALL is used to indicate it is an
HVC/SMC forward, and the structure kvm_run->hypercall is used to pass
arguments and return values between KVM and qemu:
Input:
nr: the immediate value of SMC/HVC calls; not really used today.
args[6]: x0..x5 (This is not fully conform with SMCCC which requires
x6 as argument as well, but we can use GET_ONE_REG ioctl
for such rare case).
Return:
args[0..3]: x0..x3 as defined in SMCCC. We rely on KVM to extract
args[0..3] and write them to x0..x3 when hypercall exit
returns.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 911 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
target/arm/sdei.h | 34 ++
2 files changed, 945 insertions(+)
create mode 100644 target/arm/sdei.h
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 7f12d69..b40fa36 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -29,6 +29,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
#include "qemu/error-report.h"
+#include "sdei.h"
#include "sdei_int.h"
#include "internals.h"
#include "hw/boards.h"
@@ -84,6 +85,12 @@ static void qemu_sde_cpu_init(QemuSDEState *s)
}
}
+static inline QemuSDECpu *get_sde_cpu(QemuSDEState *s, CPUState *cs)
+{
+ assert(cs->cpu_index < s->sdei_max_cpus);
+ return &s->sde_cpus[cs->cpu_index];
+}
+
static bool is_valid_event_number(int32_t event)
{
int32_t slot_id;
@@ -122,6 +129,910 @@ static QemuSDEProp *get_sde_prop_no_lock(QemuSDEState *s, int32_t event)
return &s->sde_props_state[SDEI_EVENT_TO_SLOT(event)];
}
+static QemuSDEProp *get_sde_prop(QemuSDEState *s, int32_t event)
+{
+ QemuSDEProp *sde_props = s->sde_props_state;
+
+ if (!is_valid_event_number(event)) {
+ return NULL;
+ }
+
+ event = SDEI_EVENT_TO_SLOT(event);
+
+ qemu_mutex_lock(&sde_props[event].lock);
+ if (sde_props[event].event_id < 0) {
+ qemu_mutex_unlock(&sde_props[event].lock);
+ return NULL;
+ }
+ return &sde_props[event];
+}
+
+static void put_sde_prop(QemuSDEProp *prop)
+{
+ qemu_mutex_unlock(&prop->lock);
+}
+
+static void sde_slot_lock(QemuSDE *sde, CPUState *cs)
+{
+ qemu_mutex_lock(&sde->lock);
+}
+
+static void sde_slot_unlock(QemuSDE *sde, CPUState *cs)
+{
+ qemu_mutex_unlock(&sde->lock);
+}
+
+/*
+ * It will always return a pointer to a preallocated sde; event number must be
+ * validated before calling this function.
+ */
+static QemuSDE *get_sde_no_check(QemuSDEState *s, int32_t event, CPUState *cs)
+{
+ QemuSDE **array = s->sde_cpus[cs->cpu_index].private_sde_array;
+ int32_t sde_index = SDEI_EVENT_TO_SLOT(event);
+ QemuSDE *sde;
+
+ if (SDEI_IS_SHARED_EVENT(event)) {
+ array = s->shared_sde_array;
+ sde_index -= PRIVATE_SLOT_COUNT;
+ }
+
+ sde = array[sde_index];
+ sde_slot_lock(sde, cs);
+ return sde;
+}
+
+static void put_sde(QemuSDE *sde, CPUState *cs)
+{
+ sde_slot_unlock(sde, cs);
+}
+
+static inline bool is_sde_nested(QemuSDECpu *sde_cpu)
+{
+ return sde_cpu->critical_running_event >= 0 &&
+ sde_cpu->normal_running_event >= 0;
+}
+
+static int32_t get_running_sde(QemuSDEState *s, CPUState *cs)
+{
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+
+ if (sde_cpu->critical_running_event >= 0) {
+ return sde_cpu->critical_running_event;
+ }
+ return sde_cpu->normal_running_event;
+}
+
+static void override_return_value(CPUState *cs, uint64_t *args)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ args[i] = env->xregs[i];
+ }
+}
+
+static void sde_save_cpu_ctx(CPUState *cs, QemuSDECpu *sde_cpu, bool critical)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+ memcpy(ctx->xregs, env->xregs, sizeof(ctx->xregs));
+ ctx->pc = env->pc;
+ ctx->pstate = pstate_read(env);
+}
+
+static void sde_restore_cpu_ctx(QemuSDEState *s, CPUState *cs, bool critical)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+ QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+ /*
+ * TODO: we need to optimize to only restore affected registers by calling
+ * ioctl individialy
+ */
+ kvm_arch_get_registers(cs);
+
+ env->aarch64 = ((ctx->pstate & PSTATE_nRW) == 0);
+ memcpy(env->xregs, ctx->xregs, sizeof(ctx->xregs));
+ env->pc = ctx->pc;
+ pstate_write(env, ctx->pstate);
+ aarch64_restore_sp(env, (env->pstate >> 2) & 3);
+}
+
+static void sde_restore_cpu_ctx_for_resume(QemuSDEState *s,
+ CPUState *cs,
+ bool critical,
+ uint64_t resume_addr)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+ QemuSDECpuCtx *ctx = &sde_cpu->ctx[critical ? 1 : 0];
+
+ /*
+ * TODO: we need to optimize to only restore affected registers by calling
+ * ioctl individialy
+ */
+ kvm_arch_get_registers(cs);
+
+ memcpy(env->xregs, ctx->xregs, sizeof(ctx->xregs));
+ env->pc = resume_addr;
+ env->aarch64 = 1;
+ /* Constructe pstate in pstate_read() */
+ env->daif = 0xF << 6;
+ /* Clear nRW/M[4] and M[3:0] */
+ env->pstate &= ~0x1F;
+ /* Set exception mode to EL1h */
+ env->pstate |= PSTATE_MODE_EL1h;
+ env->elr_el[1] = ctx->pc;
+ env->banked_spsr[KVM_SPSR_EL1 + 1] = ctx->pstate;
+ aarch64_restore_sp(env, 1);
+}
+
+static void sde_build_cpu_ctx(CPUState *cs, QemuSDECpu *sde_cpu, QemuSDE *sde)
+{
+ CPUARMState *env = &ARM_CPU(cs)->env;
+
+ env->xregs[0] = sde->prop->event_id;
+ env->xregs[1] = sde->ep_argument;
+ env->xregs[2] = env->pc;
+ env->xregs[3] = pstate_read(env);
+ env->pc = sde->ep_address;
+ env->aarch64 = 1;
+ /* Constructe pstate in pstate_read() */
+ env->daif = 0xF << 6;
+ /* Clear nRW/M[4] and M[3:0] */
+ env->pstate &= ~0x1F;
+ /* Set exception mode to EL1h */
+ env->pstate |= PSTATE_MODE_EL1h;
+ aarch64_restore_sp(env, 1);
+}
+
+static void trigger_sde(CPUState *cs, run_on_cpu_data data)
+{
+ QemuSDEState *s = sde_state;
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+ int32_t event = data.host_int;
+ QemuSDE *sde;
+
+ assert(cs == current_cpu);
+
+ if (sde_cpu->masked || sde_cpu->critical_running_event >= 0) {
+ return;
+ }
+
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ /* Some race condition happens! */
+ put_sde(sde, cs);
+ return;
+ }
+
+ if (sde_cpu->normal_running_event >= 0 && !sde->prop->is_critical) {
+ put_sde(sde, cs);
+ return;
+ }
+
+ if (!sde->enabled || !sde->pending || sde->running) {
+ /* Some race condition happens! */
+ put_sde(sde, cs);
+ return;
+ }
+
+ sde->pending = false;
+ sde->running = true;
+
+ if (sde->prop->is_critical) {
+ sde_cpu->critical_running_event = sde->prop->event_id;
+ } else {
+ sde_cpu->normal_running_event = sde->prop->event_id;
+ }
+
+ kvm_arch_get_registers(cs);
+ sde_save_cpu_ctx(cs, sde_cpu, sde->prop->is_critical);
+ sde_build_cpu_ctx(cs, sde_cpu, sde);
+ kvm_arch_put_registers(cs, 1);
+ put_sde(sde, cs);
+}
+
+static int64_t dispatch_single(QemuSDEState *s, QemuSDE *sde, CPUState *cs)
+{
+ int32_t event = sde->prop->event_id;
+ bool pending = sde->pending;
+ bool enabled = sde->enabled;
+ CPUState *target = sde->target_cpu;
+ put_sde(sde, cs);
+
+ if (pending && enabled) {
+ /*
+ * TODO: we need to find a free-unmasked PE to trigger for shared
+ * unpinned event
+ */
+ async_run_on_cpu(target, trigger_sde,
+ RUN_ON_CPU_HOST_INT(event));
+ }
+ return SDEI_SUCCESS;
+}
+
+static void dispatch_cpu(QemuSDEState *s, CPUState *cs, bool is_critical)
+{
+ QemuSDE *sde;
+ int i;
+
+ for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+ sde = get_sde_no_check(s, i, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ continue;
+ }
+ if (sde->prop->is_critical != is_critical) {
+ put_sde(sde, cs);
+ continue;
+ }
+ if (!sde->enabled || !sde->pending || sde->running ||
+ sde->target_cpu != cs) {
+ put_sde(sde, cs);
+ continue;
+ }
+
+ dispatch_single(s, sde, cs);
+ }
+}
+
+static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
+ bool is_shared, int intid)
+{
+ int index;
+ int start = 0;
+ int count = PRIVATE_SLOT_COUNT;
+ int32_t event;
+ QemuSDEProp *sde_props = s->sde_props_state;
+
+ if (is_shared) {
+ start = PRIVATE_SLOT_COUNT;
+ count = PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT;
+ }
+
+ qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+ for (index = start; index < count; index++) {
+ qemu_mutex_lock(&sde_props[index].lock);
+ if (sde_props[index].interrupt == intid) {
+ event = sde_props[index].event_id;
+ qemu_mutex_unlock(&sde_props[index].lock);
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ return event;
+ }
+ qemu_mutex_unlock(&sde_props[index].lock);
+ }
+
+ for (index = start; index < count; index++) {
+ qemu_mutex_lock(&sde_props[index].lock);
+ if (sde_props[index].event_id < 0) {
+ event = sde_props[index].event_id = 0x40000000 | index;
+ sde_props[index].interrupt = intid;
+ sde_props[index].is_shared = is_shared;
+ sde_props[index].is_critical = is_critical;
+ s->irq_map[intid] = event;
+ qemu_mutex_unlock(&sde_props[index].lock);
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ return event;
+ }
+ qemu_mutex_unlock(&sde_props[index].lock);
+ }
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ return SDEI_OUT_OF_RESOURCE;
+}
+
+static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
+{
+ int32_t ret = SDEI_SUCCESS;
+ if (atomic_read(&prop->refcount) > 0) {
+ ret = SDEI_DENIED;
+ goto unlock_return;
+ }
+
+ s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
+ prop->event_id = SDEI_INVALID_EVENT_ID;
+ prop->interrupt = SDEI_INVALID_INTERRUPT;
+
+unlock_return:
+ qemu_mutex_unlock(&prop->lock);
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ return ret;
+}
+
+typedef int64_t (*sdei_single_function)(QemuSDEState *s,
+ CPUState *cs,
+ struct kvm_run *run);
+
+static int64_t sdei_version(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
+{
+ return (1ULL << SDEI_VERSION_MAJOR_SHIFT) |
+ (0ULL << SDEI_VERSION_MINOR_SHIFT);
+}
+
+static int64_t unregister_single_sde(QemuSDEState *s, int32_t event,
+ CPUState *cs, bool force)
+{
+ QemuSDE *sde;
+ QemuSDEProp *prop;
+ int ret = 0;
+
+ prop = get_sde_prop(s, event);
+ if (!prop) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ put_sde_prop(prop);
+ return SDEI_DENIED;
+ }
+
+ if (sde->running && !force) {
+ sde->unregister_pending = true;
+ ret = SDEI_PENDING;
+ } else {
+ atomic_dec(&prop->refcount);
+ sde->event_id = SDEI_INVALID_EVENT_ID;
+ sde->enabled = false;
+ sde->running = false;
+ sde->pending = false;
+ sde->unregister_pending = false;
+ }
+ put_sde(sde, cs);
+ put_sde_prop(prop);
+ return ret;
+}
+
+static int64_t sdei_private_reset_common(QemuSDEState *s, CPUState *cs,
+ bool force)
+{
+ int64_t ret = SDEI_SUCCESS;
+ int i;
+
+ for (i = 0; i < PRIVATE_SLOT_COUNT; i++) {
+ int64_t ret1;
+ ret1 = unregister_single_sde(s, i, cs, force);
+ /* Ignore other return values in reset interface */
+ if (ret1 == SDEI_PENDING) {
+ ret = SDEI_DENIED;
+ }
+ }
+
+ return ret;
+}
+
+static int64_t sdei_shared_reset_common(QemuSDEState *s, CPUState *cs,
+ bool force)
+{
+ int i;
+ QemuSDEProp *prop;
+ int32_t start_event = PRIVATE_SLOT_COUNT;
+ int64_t ret = SDEI_SUCCESS;
+
+ for (i = start_event; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+ int64_t ret1 = unregister_single_sde(s, i, cs, force);
+ /* Ignore other return values in reset interface */
+ if (ret1 == SDEI_PENDING) {
+ ret = SDEI_DENIED;
+ }
+ }
+ if (ret) {
+ return ret;
+ }
+
+ for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
+ qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+ prop = get_sde_prop(s, i);
+ if (!prop || prop->interrupt == SDEI_INVALID_INTERRUPT) {
+ if (prop) {
+ put_sde_prop(prop);
+ }
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ continue;
+ }
+ ret |= sdei_free_event_num_locked(s, prop);
+ }
+
+ return ret ? SDEI_DENIED : SDEI_SUCCESS;
+}
+
+
+static int64_t sdei_event_register(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ QemuSDEProp *prop;
+ CPUState *target = cs;
+ uint64_t *args = (uint64_t *)run->hypercall.args;
+ int32_t event = args[1];
+ uint64_t rm_mode = SDEI_EVENT_REGISTER_RM_PE;
+
+ prop = get_sde_prop(s, event);
+ if (!prop) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id != SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ put_sde_prop(prop);
+ return SDEI_DENIED;
+ }
+
+ if (prop->is_shared) {
+ rm_mode = args[4] & 1ULL;
+ if (rm_mode == SDEI_EVENT_REGISTER_RM_PE) {
+ target = arm_get_cpu_by_id(args[5]);
+ if (!target) {
+ put_sde_prop(prop);
+ return SDEI_INVALID_PARAMETERS;
+ }
+ }
+ }
+
+ sde->target_cpu = target;
+ sde->ep_address = args[2];
+ sde->ep_argument = args[3];
+ sde->prop = prop;
+ sde->routing_mode = rm_mode;
+ sde->event_id = prop->event_id;
+
+ put_sde(sde, cs);
+ atomic_inc(&prop->refcount);
+ put_sde_prop(prop);
+
+ return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_enable(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+
+ if (!is_valid_event_number(event)) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde->enabled = true;
+ return dispatch_single(s, sde, cs);
+}
+
+static int64_t sdei_event_disable(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ uint64_t *args = (uint64_t *)run->hypercall.args;
+ int32_t event = args[1];
+
+ if (!is_valid_event_number(event)) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde->enabled = false;
+ put_sde(sde, cs);
+ return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_context(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ uint32_t param_id = args[1];
+ int critical;
+ QemuSDECpuCtx *ctx;
+
+ if (param_id >= SDEI_PARAM_MAX) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ if (sde_cpu->critical_running_event >= 0) {
+ critical = 1;
+ } else if (sde_cpu->normal_running_event >= 0) {
+ critical = 0;
+ } else {
+ return SDEI_DENIED;
+ }
+
+ ctx = &sde_cpu->ctx[critical];
+ return ctx->xregs[param_id];
+}
+
+static int64_t sdei_event_complete(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ QemuSDECpu *cpu = get_sde_cpu(s, cs);
+ int32_t event;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ bool is_critical;
+
+ event = get_running_sde(s, cs);
+ if (event < 0) {
+ return SDEI_DENIED;
+ }
+
+ assert(is_valid_event_number(event));
+ sde = get_sde_no_check(s, event, cs);
+ assert(sde->event_id != SDEI_INVALID_EVENT_ID);
+
+ sde->running = false;
+ is_critical = sde->prop->is_critical;
+ if (sde->unregister_pending) {
+ atomic_dec(&sde->prop->refcount);
+ sde->event_id = SDEI_INVALID_EVENT_ID;
+ sde->unregister_pending = false;
+ }
+ put_sde(sde, cs);
+
+ sde_restore_cpu_ctx(s, cs, is_critical);
+
+ kvm_arch_put_registers(cs, 1);
+ override_return_value(cs, args);
+ if (cpu->critical_running_event >= 0) {
+ cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+ } else {
+ cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+ }
+
+ /* TODO: we should not queue more than one sde in work queue */
+ dispatch_cpu(s, cs, true);
+ if (cpu->critical_running_event < 0 && cpu->normal_running_event < 0) {
+ dispatch_cpu(s, cs, false);
+ }
+ return args[0];
+}
+
+static int64_t sdei_event_complete_and_resume(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ QemuSDECpu *cpu = get_sde_cpu(s, cs);
+ int32_t event;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ bool is_critical;
+ uint64_t resume_addr = args[1];
+
+ event = get_running_sde(s, cs);
+ if (event < 0) {
+ return SDEI_DENIED;
+ }
+
+ assert(is_valid_event_number(event));
+ sde = get_sde_no_check(s, event, cs);
+ assert(sde->event_id != SDEI_INVALID_EVENT_ID);
+
+ sde->running = false;
+ is_critical = sde->prop->is_critical;
+
+ if (sde->unregister_pending) {
+ atomic_dec(&sde->prop->refcount);
+ sde->event_id = SDEI_INVALID_EVENT_ID;
+ sde->unregister_pending = false;
+ }
+ put_sde(sde, cs);
+
+ sde_restore_cpu_ctx_for_resume(s, cs, is_critical, resume_addr);
+ kvm_arch_put_registers(cs, 1);
+
+ override_return_value(cs, args);
+ if (cpu->critical_running_event >= 0) {
+ cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+ } else {
+ cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+ }
+
+ dispatch_cpu(s, cs, true);
+ if (cpu->critical_running_event < 0 && cpu->normal_running_event < 0) {
+ dispatch_cpu(s, cs, false);
+ }
+ return args[0];
+}
+
+static int64_t sdei_event_unregister(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+
+ return unregister_single_sde(s, event, cs, false);
+}
+
+static int64_t sdei_event_status(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+ int64_t status = 0;
+
+ if (!is_valid_event(s, event)) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return status;
+ }
+
+ status |= SDEI_EVENT_STATUS_REGISTERED;
+ if (sde->enabled) {
+ status |= SDEI_EVENT_STATUS_ENABLED;
+ }
+ if (sde->running) {
+ status |= SDEI_EVENT_STATUS_RUNNING;
+ }
+ put_sde(sde, cs);
+ return status;
+}
+
+static int64_t sdei_event_get_info(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDEProp *prop;
+ QemuSDE *sde;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+ uint32_t info = args[2];
+ int64_t ret;
+
+ if (info > SDEI_EVENT_INFO_EV_ROUTING_AFF) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ prop = get_sde_prop(s, event);
+ if (!prop) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ switch (info) {
+ case SDEI_EVENT_INFO_EV_TYPE:
+ ret = prop->is_shared;
+ break;
+ case SDEI_EVENT_INFO_EV_SIGNALED:
+ ret = (event == SDEI_STD_EVT_SOFTWARE_SIGNAL) ? 1 : 0;
+ break;
+ case SDEI_EVENT_INFO_EV_PRIORITY:
+ ret = prop->is_critical;
+ break;
+ case SDEI_EVENT_INFO_EV_ROUTING_MODE:
+ case SDEI_EVENT_INFO_EV_ROUTING_AFF:
+ ret = SDEI_INVALID_PARAMETERS;
+ if (!prop->is_shared) {
+ break;
+ }
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ ret = SDEI_DENIED;
+ break;
+ }
+ if (info == SDEI_EVENT_INFO_EV_ROUTING_MODE) {
+ ret = sde->routing_mode;
+ } else if (sde->routing_mode == SDEI_EVENT_REGISTER_RM_PE) {
+ ret = ARM_CPU(sde->target_cpu)->mp_affinity;
+ }
+ put_sde(sde, cs);
+ break;
+ default:
+ ret = SDEI_NOT_SUPPORTED;
+ }
+ put_sde_prop(prop);
+ return ret;
+}
+
+static int64_t sdei_event_routing_set(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ CPUState *target = cs;
+ uint64_t *args = (uint64_t *)run->hypercall.args;
+ int32_t event = args[1];
+ uint64_t mode = args[2];
+ uint64_t affinity = args[3];
+
+ if (mode & ~1ULL) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+ if (mode == SDEI_EVENT_REGISTER_RM_PE) {
+ target = arm_get_cpu_by_id(affinity);
+ if (!target) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+ }
+
+ if (!is_valid_event(s, event) || !SDEI_IS_SHARED_EVENT(event)) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return SDEI_DENIED;
+ }
+ if (sde->enabled || sde->running ||
+ sde->pending || sde->unregister_pending) {
+ put_sde(sde, cs);
+ return SDEI_DENIED;
+ }
+
+ sde->target_cpu = target;
+ sde->routing_mode = mode;
+ put_sde(sde, cs);
+
+ return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_pe_mask(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDECpu *sde_cpu;
+
+ sde_cpu = get_sde_cpu(s, cs);
+ if (sde_cpu->masked) {
+ return 0;
+ }
+ sde_cpu->masked = true;
+ return 1;
+}
+
+static int64_t sdei_event_pe_unmask(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDECpu *sde_cpu;
+
+ sde_cpu = get_sde_cpu(s, cs);
+ sde_cpu->masked = false;
+ dispatch_cpu(s, cs, true);
+ dispatch_cpu(s, cs, false);
+ return SDEI_SUCCESS;
+}
+
+static int64_t sdei_event_interrupt_bind(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ uint32_t intid = args[1];
+
+ if (intid < GIC_NR_SGIS || intid >= GIC_MAXIRQ) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+ return sdei_alloc_event_num(s, false, intid >= 32, intid);
+}
+
+static int64_t sdei_event_interrupt_release(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDEProp *prop;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+
+ qemu_mutex_lock(&s->sdei_interrupt_bind_lock);
+ prop = get_sde_prop(s, event);
+ if (!prop) {
+ qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ return sdei_free_event_num_locked(s, prop);
+}
+
+static int64_t sdei_event_signal(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ QemuSDE *sde;
+ CPUState *target_cpu;
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ int32_t event = args[1];
+
+ if (event != SDEI_STD_EVT_SOFTWARE_SIGNAL) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ target_cpu = arm_get_cpu_by_id(args[2]);
+ if (!target_cpu) {
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde = get_sde_no_check(s, event, target_cpu);
+ if (sde->event_id == SDEI_INVALID_EVENT_ID) {
+ put_sde(sde, cs);
+ return SDEI_INVALID_PARAMETERS;
+ }
+
+ sde->pending = true;
+ return dispatch_single(s, sde, target_cpu);
+}
+
+static int64_t sdei_features(QemuSDEState *s, CPUState *cs, struct kvm_run *run)
+{
+ uint64_t *args = (uint64_t *)(run->hypercall.args);
+ uint32_t feature = args[1];
+
+ switch (feature) {
+ case SDEI_FEATURE_BIND_SLOTS:
+ return ((SHARED_SLOT_COUNT - PLAT_SHARED_SLOT_COUNT) << 16) |
+ (PRIVATE_SLOT_COUNT - PLAT_PRIVATE_SLOT_COUNT);
+ default:
+ return SDEI_INVALID_PARAMETERS;
+ }
+}
+
+static int64_t sdei_private_reset(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ return sdei_private_reset_common(s, cs, false);
+}
+
+static int64_t sdei_shared_reset(QemuSDEState *s, CPUState *cs,
+ struct kvm_run *run)
+{
+ return sdei_shared_reset_common(s, cs, false);
+}
+
+static sdei_single_function sdei_functions[] = {
+ sdei_version,
+ sdei_event_register,
+ sdei_event_enable,
+ sdei_event_disable,
+ sdei_event_context,
+ sdei_event_complete,
+ sdei_event_complete_and_resume,
+ sdei_event_unregister,
+ sdei_event_status,
+ sdei_event_get_info,
+ sdei_event_routing_set,
+ sdei_event_pe_mask,
+ sdei_event_pe_unmask,
+ sdei_event_interrupt_bind,
+ sdei_event_interrupt_release,
+ sdei_event_signal,
+ sdei_features,
+ sdei_private_reset,
+ sdei_shared_reset,
+};
+
+void sdei_handle_request(CPUState *cs, struct kvm_run *run)
+{
+ uint32_t func_id = run->hypercall.args[0];
+
+ if (!sde_state) {
+ run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+ return;
+ }
+
+ if (func_id < SDEI_1_0_FN_BASE || func_id > SDEI_MAX_REQ) {
+ error_report("Invalid SDEI function ID: 0x%x", func_id);
+ run->hypercall.args[0] = SDEI_INVALID_PARAMETERS;
+ return;
+ }
+
+ func_id -= SDEI_1_0_FN_BASE;
+ if (func_id < ARRAY_SIZE(sdei_functions) && sdei_functions[func_id]) {
+ run->hypercall.args[0] = sdei_functions[func_id](sde_state, cs, run);
+ } else {
+ run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+ }
+}
+
static void qemu_shared_sde_init(QemuSDEState *s)
{
int i;
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
new file mode 100644
index 0000000..a69a0e4
--- /dev/null
+++ b/target/arm/sdei.h
@@ -0,0 +1,34 @@
+/*
+ * ARM SDEI emulation external interfaces
+ *
+ * Copyright (c) 2019 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Heyi Guo <guoheyi@huawei.com>
+ * Jingyi Wang <wangjingyi11@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SDEI_H
+#define QEMU_SDEI_H
+
+#include <linux/kvm.h>
+#include <linux/arm_sdei.h>
+#include "hw/core/cpu.h"
+
+#define SDEI_MAX_REQ SDEI_1_0_FN(0x12)
+
+void sdei_handle_request(CPUState *cs, struct kvm_run *run);
+
+#endif
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 06/12] core/irq: add qemu_irq_remove_intercept interface
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
We use qemu_irq as the bridge for other qemu modules to switch from
irq injection to SDEI event trigger after VM binds the interrupt to
SDEI event. We use qemu_irq_intercept_in() to override qemu_irq
handler with SDEI event trigger, so we also need a corresponding
interface to restore the handler to default one (i.e. ARM GIC).
qemu_irq_remove_intercept() is the new interface to do the above
job.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
hw/core/irq.c | 11 +++++++++++
include/hw/irq.h | 8 ++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 7cc0295..114bce6 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -145,6 +145,17 @@ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
}
}
+void qemu_irq_remove_intercept(qemu_irq *gpio_in, int n)
+{
+ int i;
+ qemu_irq *old_irqs = gpio_in[0]->opaque;
+ for (i = 0; i < n; i++) {
+ gpio_in[i]->handler = old_irqs[i]->handler;
+ gpio_in[i]->opaque = old_irqs[i]->opaque;
+ }
+ qemu_free_irqs(old_irqs, n);
+}
+
static const TypeInfo irq_type_info = {
.name = TYPE_IRQ,
.parent = TYPE_OBJECT,
diff --git a/include/hw/irq.h b/include/hw/irq.h
index fe527f6..1af1db9 100644
--- a/include/hw/irq.h
+++ b/include/hw/irq.h
@@ -56,8 +56,12 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
*/
qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
-/* For internal use in qtest. Similar to qemu_irq_split, but operating
- on an existing vector of qemu_irq. */
+/*
+ * Similar to qemu_irq_split, but operating on an existing vector of qemu_irq.
+ */
void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
+/* Restore the irq handler intercepted by qemu_irq_intercept_in() */
+void qemu_irq_remove_intercept(qemu_irq *gpio_in, int n);
+
#endif
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 04/12] arm/sdei: add system reset callback
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, James Morse, Marc Zyngier,
Jingyi Wang, Heyi Guo, wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
For this is a logical device which is not attached to system bus, we
cannot use DeviceClass->reset interface directly. Instead we register
our own reset callback to reset SDEI services when system resets.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index b40fa36..f9a1208 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -1083,6 +1083,26 @@ static void qemu_sde_init(QemuSDEState *s)
qemu_private_sde_init(s);
}
+static void qemu_sde_reset(void *opaque)
+{
+ int64_t ret;
+ CPUState *cs;
+ QemuSDEState *s = opaque;
+
+ CPU_FOREACH(cs) {
+ QemuSDECpu *sde_cpu = get_sde_cpu(s, cs);
+ sdei_private_reset_common(s, cs, true);
+ sde_cpu->masked = true;
+ sde_cpu->critical_running_event = SDEI_INVALID_EVENT_ID;
+ sde_cpu->normal_running_event = SDEI_INVALID_EVENT_ID;
+ }
+
+ ret = sdei_shared_reset_common(s, first_cpu, true);
+ if (ret) {
+ error_report("SDEI system reset failed: 0x%lx", ret);
+ }
+}
+
static int qemu_sdei_pre_save(void *opaque)
{
QemuSDEState *s = opaque;
@@ -1235,6 +1255,7 @@ static void sdei_initfn(Object *obj)
sde_state = s;
qemu_sde_init(s);
+ qemu_register_reset(qemu_sde_reset, s);
}
static void qemu_sde_class_init(ObjectClass *klass, void *data)
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 10/12] arm/sdei: check KVM cap and enable SDEI
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Check KVM hypercall forward capability and enable it, and set global
flag "sdei_enabled" to true if everything works well.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 17 +++++++++++++++++
target/arm/sdei.h | 2 ++
2 files changed, 19 insertions(+)
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index efdb681..000545e 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -43,6 +43,7 @@
#define TYPE_QEMU_SDEI "qemu_sdei"
#define QEMU_SDEI(obj) OBJECT_CHECK(QemuSDEState, (obj), TYPE_QEMU_SDEI)
+bool sdei_enabled;
static QemuSDEState *sde_state;
typedef struct QemuSDEIBindNotifyEntry {
@@ -1465,6 +1466,7 @@ static const VMStateDescription vmstate_sde_state = {
static void sdei_initfn(Object *obj)
{
QemuSDEState *s = QEMU_SDEI(obj);
+ KVMState *kvm = KVM_STATE(current_machine->accelerator);
if (sde_state) {
error_report("Only one SDEI dispatcher is allowed!");
@@ -1474,6 +1476,21 @@ static void sdei_initfn(Object *obj)
qemu_sde_init(s);
qemu_register_reset(qemu_sde_reset, s);
+
+ if (kvm_check_extension(kvm, KVM_CAP_FORWARD_HYPERCALL)) {
+ int ret;
+ ret = kvm_vm_enable_cap(kvm, KVM_CAP_FORWARD_HYPERCALL, 0,
+ KVM_CAP_FORWARD_HYPERCALL_EXCL_PSCI);
+ if (ret < 0) {
+ error_report("Enable hypercall forwarding failed: %s",
+ strerror(-ret));
+ abort();
+ }
+ sdei_enabled = true;
+ info_report("qemu sdei enabled");
+ } else {
+ info_report("KVM does not support forwarding hypercall.");
+ }
}
static void qemu_sde_class_init(ObjectClass *klass, void *data)
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index feaaf1a..95e7d8d 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -29,6 +29,8 @@
#define SDEI_MAX_REQ SDEI_1_0_FN(0x12)
+extern bool sdei_enabled;
+
void sdei_handle_request(CPUState *cs, struct kvm_run *run);
/*
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 07/12] arm/sdei: override qemu_irq handler when binding interrupt
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Override qemu_irq handler to support trigger SDEI event transparently
after guest binds interrupt to SDEI event. We don't have good way to
get GIC device and to guarantee SDEI device is initialized after GIC,
so we search GIC in system bus when the first SDEI request happens or
in VMSTATE post_load().
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++--
target/arm/sdei_int.h | 3 ++
2 files changed, 137 insertions(+), 3 deletions(-)
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 088ed76..9ceb131 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -85,6 +85,24 @@ static void qemu_sde_cpu_init(QemuSDEState *s)
}
}
+static int gic_int_to_irq(int num_irq, int intid, int cpu)
+{
+ if (intid >= GIC_INTERNAL) {
+ return intid - GIC_INTERNAL;
+ }
+ return num_irq - GIC_INTERNAL + cpu * GIC_INTERNAL + intid;
+}
+
+static int irq_to_gic_int(int num_irq, int irq, int *cpu)
+{
+ if (irq < num_irq - GIC_INTERNAL) {
+ return irq + GIC_INTERNAL;
+ }
+ irq -= num_irq - GIC_INTERNAL;
+ *cpu = irq / GIC_INTERNAL;
+ return irq % GIC_INTERNAL;
+}
+
static inline QemuSDECpu *get_sde_cpu(QemuSDEState *s, CPUState *cs)
{
assert(cs->cpu_index < s->sdei_max_cpus);
@@ -381,6 +399,76 @@ static void dispatch_cpu(QemuSDEState *s, CPUState *cs, bool is_critical)
}
}
+static void qemu_sdei_irq_handler(void *opaque, int irq, int level)
+{
+ int cpu = 0;
+ irq = irq_to_gic_int(sde_state->num_irq, irq, &cpu);
+ trigger_sdei_by_irq(cpu, irq);
+}
+
+static void override_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+ qemu_irq irq;
+ QemuSDE *sde;
+ CPUState *cs;
+ int cpu;
+
+ /* SPI */
+ if (intid >= GIC_INTERNAL) {
+ cs = arm_get_cpu_by_id(0);
+ irq = qdev_get_gpio_in(s->gic_dev,
+ gic_int_to_irq(s->num_irq, intid, 0));
+ if (irq) {
+ qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+ }
+ sde = get_sde_no_check(s, event, cs);
+ sde->irq = irq;
+ put_sde(sde, cs);
+ return;
+ }
+ /* PPI */
+ for (cpu = 0; cpu < s->sdei_max_cpus; cpu++) {
+ cs = arm_get_cpu_by_id(cpu);
+ irq = qdev_get_gpio_in(s->gic_dev,
+ gic_int_to_irq(s->num_irq, intid, cpu));
+ if (irq) {
+ qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+ }
+ sde = get_sde_no_check(s, event, cs);
+ sde->irq = irq;
+ put_sde(sde, cs);
+ }
+}
+
+static void restore_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+ QemuSDE *sde;
+ CPUState *cs;
+ int cpu;
+
+ /* SPI */
+ if (intid >= GIC_INTERNAL) {
+ cs = arm_get_cpu_by_id(0);
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->irq) {
+ qemu_irq_remove_intercept(&sde->irq, 1);
+ sde->irq = NULL;
+ }
+ put_sde(sde, cs);
+ return;
+ }
+ /* PPI */
+ for (cpu = 0; cpu < s->sdei_max_cpus; cpu++) {
+ cs = arm_get_cpu_by_id(cpu);
+ sde = get_sde_no_check(s, event, cs);
+ if (sde->irq) {
+ qemu_irq_remove_intercept(&sde->irq, 1);
+ sde->irq = NULL;
+ }
+ put_sde(sde, cs);
+ }
+}
+
static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
bool is_shared, int intid)
{
@@ -414,6 +502,7 @@ static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
sde_props[index].interrupt = intid;
sde_props[index].is_shared = is_shared;
sde_props[index].is_critical = is_critical;
+ override_qemu_irq(s, event, intid);
s->irq_map[intid] = event;
qemu_mutex_unlock(&sde_props[index].lock);
qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
@@ -433,6 +522,7 @@ static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
goto unlock_return;
}
+ restore_qemu_irq(s, prop->event_id, prop->interrupt);
s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
prop->event_id = SDEI_INVALID_EVENT_ID;
prop->interrupt = SDEI_INVALID_INTERRUPT;
@@ -929,13 +1019,33 @@ static int64_t sdei_event_pe_unmask(QemuSDEState *s, CPUState *cs,
return SDEI_SUCCESS;
}
+static int dev_walkerfn(DeviceState *dev, void *opaque)
+{
+ QemuSDEState *s = opaque;
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GICV3_COMMON)) {
+ GICv3State *gic = ARM_GICV3_COMMON(dev);
+ s->num_irq = gic->num_irq;
+ s->gic_dev = dev;
+ return -1;
+ }
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GIC_COMMON)) {
+ GICState *gic = ARM_GIC_COMMON(dev);
+ s->num_irq = gic->num_irq;
+ s->gic_dev = dev;
+ return -1;
+ }
+ return 0;
+}
+
static int64_t sdei_event_interrupt_bind(QemuSDEState *s, CPUState *cs,
struct kvm_run *run)
{
uint64_t *args = (uint64_t *)(run->hypercall.args);
uint32_t intid = args[1];
- if (intid < GIC_NR_SGIS || intid >= GIC_MAXIRQ) {
+ if (intid < GIC_NR_SGIS || intid >= s->num_irq) {
return SDEI_INVALID_PARAMETERS;
}
return sdei_alloc_event_num(s, false, intid >= 32, intid);
@@ -1042,6 +1152,17 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
return;
}
+ if (!sde_state->gic_dev) {
+ /* Search for ARM GIC device */
+ qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+ NULL, NULL, NULL, sde_state);
+ if (!sde_state->gic_dev) {
+ error_report("Cannot find ARM GIC device!");
+ run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+ return;
+ }
+ }
+
if (func_id < SDEI_1_0_FN_BASE || func_id > SDEI_MAX_REQ) {
error_report("Invalid SDEI function ID: 0x%x", func_id);
run->hypercall.args[0] = SDEI_INVALID_PARAMETERS;
@@ -1198,9 +1319,19 @@ static int qemu_sdei_post_load(void *opaque, int version_id)
}
}
+ /* Search for ARM GIC device */
+ qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+ NULL, NULL, NULL, s);
+ if (!s->gic_dev) {
+ error_report("Cannot find ARM GIC device!");
+ return 0;
+ }
+
for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
- if (sde_props[i].interrupt != SDEI_INVALID_INTERRUPT) {
- s->irq_map[sde_props[i].interrupt] = sde_props[i].event_id;
+ int intid = sde_props[i].interrupt;
+ if (intid != SDEI_INVALID_INTERRUPT) {
+ s->irq_map[intid] = sde_props[i].event_id;
+ override_qemu_irq(s, sde_props[i].event_id, intid);
}
}
diff --git a/target/arm/sdei_int.h b/target/arm/sdei_int.h
index 7f69507..3930591 100644
--- a/target/arm/sdei_int.h
+++ b/target/arm/sdei_int.h
@@ -63,6 +63,7 @@ typedef struct QemuSDEProp {
typedef struct QemuSDE {
QemuSDEProp *prop;
CPUState *target_cpu;
+ qemu_irq irq;
QemuMutex lock;
bool enabled;
bool running;
@@ -95,9 +96,11 @@ typedef struct QemuSDECpu {
typedef struct QemuSDEState {
DeviceState parent_obj;
+ DeviceState *gic_dev;
QemuSDEProp sde_props_state[PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT];
QemuSDECpu *sde_cpus;
int sdei_max_cpus;
+ int num_irq;
QemuSDE *shared_sde_array[SHARED_SLOT_COUNT];
int32_t irq_map[GIC_MAXIRQ];
QemuMutex sdei_interrupt_bind_lock;
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 08/12] arm/sdei: add support to register interrupt bind notifier
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Other qemu modules related with the interrupt bind operation may want
to be notified when guest requests to bind interrupt to sdei event, so
we add register and unregister interfaces.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/sdei.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
target/arm/sdei.h | 17 +++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 9ceb131..efdb681 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -45,6 +45,52 @@
static QemuSDEState *sde_state;
+typedef struct QemuSDEIBindNotifyEntry {
+ QTAILQ_ENTRY(QemuSDEIBindNotifyEntry) entry;
+ QemuSDEIBindNotify *func;
+ void *opaque;
+ int irq;
+} QemuSDEIBindNotifyEntry;
+
+static QTAILQ_HEAD(, QemuSDEIBindNotifyEntry) bind_notifiers =
+ QTAILQ_HEAD_INITIALIZER(bind_notifiers);
+
+void qemu_register_sdei_bind_notifier(QemuSDEIBindNotify *func,
+ void *opaque, int irq)
+{
+ QemuSDEIBindNotifyEntry *be = g_new0(QemuSDEIBindNotifyEntry, 1);
+
+ be->func = func;
+ be->opaque = opaque;
+ be->irq = irq;
+ QTAILQ_INSERT_TAIL(&bind_notifiers, be, entry);
+}
+
+void qemu_unregister_sdei_bind_notifier(QemuSDEIBindNotify *func,
+ void *opaque, int irq)
+{
+ QemuSDEIBindNotifyEntry *be;
+
+ QTAILQ_FOREACH(be, &bind_notifiers, entry) {
+ if (be->func == func && be->opaque == opaque && be->irq == irq) {
+ QTAILQ_REMOVE(&bind_notifiers, be, entry);
+ g_free(be);
+ return;
+ }
+ }
+}
+
+static void sdei_notify_bind(int irq, int32_t event, bool bind)
+{
+ QemuSDEIBindNotifyEntry *be, *nbe;
+
+ QTAILQ_FOREACH_SAFE(be, &bind_notifiers, entry, nbe) {
+ if (be->irq == irq) {
+ be->func(be->opaque, irq, event, bind);
+ }
+ }
+}
+
static void qemu_sde_prop_init(QemuSDEState *s)
{
QemuSDEProp *sde_props = s->sde_props_state;
@@ -502,6 +548,7 @@ static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
sde_props[index].interrupt = intid;
sde_props[index].is_shared = is_shared;
sde_props[index].is_critical = is_critical;
+ sdei_notify_bind(intid, event, true);
override_qemu_irq(s, event, intid);
s->irq_map[intid] = event;
qemu_mutex_unlock(&sde_props[index].lock);
@@ -522,6 +569,7 @@ static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
goto unlock_return;
}
+ sdei_notify_bind(prop->interrupt, prop->event_id, false);
restore_qemu_irq(s, prop->event_id, prop->interrupt);
s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
prop->event_id = SDEI_INVALID_EVENT_ID;
@@ -1331,6 +1379,7 @@ static int qemu_sdei_post_load(void *opaque, int version_id)
int intid = sde_props[i].interrupt;
if (intid != SDEI_INVALID_INTERRUPT) {
s->irq_map[intid] = sde_props[i].event_id;
+ sdei_notify_bind(intid, sde_props[i].event_id, true);
override_qemu_irq(s, sde_props[i].event_id, intid);
}
}
diff --git a/target/arm/sdei.h b/target/arm/sdei.h
index a61e788..feaaf1a 100644
--- a/target/arm/sdei.h
+++ b/target/arm/sdei.h
@@ -38,4 +38,21 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run);
*/
bool trigger_sdei_by_irq(int cpu, int irq);
+/*
+ * Notify callback prototype; the argument "bind" tells whether it is a bind
+ * operation or unbind one.
+ */
+typedef void QemuSDEIBindNotify(void *opaque, int irq,
+ int32_t event, bool bind);
+/*
+ * Register a notify callback for a specific interrupt bind operation; the
+ * client be both notified by bind and unbind operation.
+ */
+void qemu_register_sdei_bind_notifier(QemuSDEIBindNotify *func,
+ void *opaque, int irq);
+/*
+ * Unregister a notify callback for a specific interrupt bind operation.
+ */
+void qemu_unregister_sdei_bind_notifier(QemuSDEIBindNotify *func,
+ void *opaque, int irq);
#endif
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 11/12] arm/kvm: handle guest exit of hypercall
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, James Morse, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Add support to handle guest exit of hypercall, and forward to SDEI
dispatcher if SDEI is enabled and it is an SDEI request.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
target/arm/kvm.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b2eaa50..97a67b1 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -30,6 +30,7 @@
#include "hw/boards.h"
#include "hw/irq.h"
#include "qemu/log.h"
+#include "sdei.h"
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
@@ -668,6 +669,19 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
}
+static void kvm_arm_handle_hypercall(CPUState *cs, struct kvm_run *run)
+{
+ uint32_t func_id = run->hypercall.args[0];
+
+ if (sdei_enabled &&
+ func_id >= SDEI_1_0_FN_BASE && func_id <= SDEI_MAX_REQ) {
+ sdei_handle_request(cs, run);
+ } else {
+ run->hypercall.args[0] = -1;
+ }
+}
+
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
@@ -678,6 +692,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
ret = EXCP_DEBUG;
} /* otherwise return to guest */
break;
+ case KVM_EXIT_HYPERCALL:
+ kvm_arm_handle_hypercall(cs, run);
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
__func__, run->exit_reason);
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 09/12] linux-headers/kvm.h: add capability to forward hypercall
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
Cornelia Huck, James Morse, Paolo Bonzini, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
To keep backward compatibility, we add new KVM capability
"KVM_CAP_FORWARD_HYPERCALL" to probe whether KVM supports forwarding
hypercall to userspace.
The capability should be enabled explicitly, for we don't want user
space application to deal with unexpected hypercall exits. We also use
an additional argument to pass exception bit mask, to request KVM to
forward all hypercalls except the classes specified in the bit mask.
Currently only PSCI can be set as exception, so that we can still keep
consistent with the original PSCI processing flow.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
---
| 3 +++
1 file changed, 3 insertions(+)
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 18892d6..20e8a68 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -711,6 +711,8 @@ struct kvm_enable_cap {
__u8 pad[64];
};
+#define KVM_CAP_FORWARD_HYPERCALL_EXCL_PSCI (1 << 0)
+
/* for KVM_PPC_GET_PVINFO */
#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
@@ -995,6 +997,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_SVE 170
#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
+#define KVM_CAP_FORWARD_HYPERCALL 174
#ifdef KVM_CAP_IRQ_ROUTING
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RFC PATCH 12/12] virt/acpi: add SDEI table if SDEI is enabled
From: Heyi Guo @ 2019-09-24 15:21 UTC (permalink / raw)
To: qemu-arm, qemu-devel, linux-arm-kernel, kvmarm
Cc: Mark Rutland, Peter Maydell, Michael S. Tsirkin, Marc Zyngier,
Shannon Zhao, James Morse, Igor Mammedov, Heyi Guo,
wanghaibin.wang, Dave Martin
In-Reply-To: <1569338511-3572-1-git-send-email-guoheyi@huawei.com>
Add SDEI table if SDEI is enabled, so that guest OS can get aware and
utilize the interfaces.
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Shannon Zhao <shannon.zhaosl@gmail.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
---
hw/arm/virt-acpi-build.c | 16 ++++++++++++++++
include/hw/acpi/acpi-defs.h | 5 +++++
2 files changed, 21 insertions(+)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 6cdf156..1088214 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -32,6 +32,7 @@
#include "trace.h"
#include "hw/core/cpu.h"
#include "target/arm/cpu.h"
+#include "target/arm/sdei.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
#include "hw/nvram/fw_cfg.h"
@@ -475,6 +476,16 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
static void
+build_sdei(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
+{
+ int sdei_start = table_data->len;
+
+ (void)acpi_data_push(table_data, sizeof(AcpiSdei));
+ build_header(linker, table_data, (void *)(table_data->data + sdei_start),
+ "SDEI", table_data->len - sdei_start, 1, NULL, NULL);
+}
+
+static void
build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
AcpiSerialPortConsoleRedirection *spcr;
@@ -796,6 +807,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_spcr(tables_blob, tables->linker, vms);
+ if (sdei_enabled) {
+ acpi_add_table(table_offsets, tables_blob);
+ build_sdei(tables_blob, tables->linker, vms);
+ }
+
if (ms->numa_state->num_nodes > 0) {
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, vms);
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 57a3f58..0a2265d 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -634,4 +634,9 @@ struct AcpiIortRC {
} QEMU_PACKED;
typedef struct AcpiIortRC AcpiIortRC;
+struct AcpiSdei {
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+} QEMU_PACKED;
+typedef struct AcpiSdei AcpiSdei;
+
#endif
--
1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3] mfd: mt6360: add pmic mt6360 driver
From: Gene Chen @ 2019-09-24 15:25 UTC (permalink / raw)
To: lee.jones, matthias.bgg
Cc: gene_chen, linux-kernel, cy_huang, linux-mediatek, Wilma.Wu,
linux-arm-kernel, shufan_lee
From: Gene Chen <gene_chen@richtek.com>
Add mfd driver for mt6360 pmic chip include
Battery Charger/USB_PD/Flash LED/RGB LED/LDO/Buck
Signed-off-by: Gene Chen <gene_chen@richtek.com
---
drivers/mfd/Kconfig | 12 +
drivers/mfd/Makefile | 1 +
drivers/mfd/mt6360-core.c | 463 +++++++++++++++++++++++++++++++++++++
include/linux/mfd/mt6360-private.h | 279 ++++++++++++++++++++++
include/linux/mfd/mt6360.h | 33 +++
5 files changed, 788 insertions(+)
create mode 100644 drivers/mfd/mt6360-core.c
create mode 100644 include/linux/mfd/mt6360-private.h
create mode 100644 include/linux/mfd/mt6360.h
changelogs between v1 & v2
- include missing header file
changelogs between v2 & v3
- add changelogs
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f129f96..a422c76 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -862,6 +862,18 @@ config MFD_MAX8998
additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_MT6360
+ tristate "Mediatek MT6360 SubPMIC"
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ depends on I2C
+ help
+ Say Y here to enable MT6360 PMU/PMIC/LDO functional support.
+ PMU part include charger, flashlight, rgb led
+ PMIC part include 2-channel BUCKs and 2-channel LDOs
+ LDO part include 4-channel LDOs
+
config MFD_MT6397
tristate "MediaTek MT6397 PMIC Support"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f026ada..77a8f0b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -241,6 +241,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
+obj-$(CONFIG_MFD_MT6360) += mt6360-core.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c
new file mode 100644
index 0000000..d3580618
--- /dev/null
+++ b/drivers/mfd/mt6360-core.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+
+#include <linux/mfd/mt6360.h>
+#include <linux/mfd/mt6360-private.h>
+
+/* reg 0 -> 0 ~ 7 */
+#define MT6360_CHG_TREG_EVT (4)
+#define MT6360_CHG_AICR_EVT (5)
+#define MT6360_CHG_MIVR_EVT (6)
+#define MT6360_PWR_RDY_EVT (7)
+/* REG 1 -> 8 ~ 15 */
+#define MT6360_CHG_BATSYSUV_EVT (9)
+#define MT6360_FLED_CHG_VINOVP_EVT (11)
+#define MT6360_CHG_VSYSUV_EVT (12)
+#define MT6360_CHG_VSYSOV_EVT (13)
+#define MT6360_CHG_VBATOV_EVT (14)
+#define MT6360_CHG_VBUSOV_EVT (15)
+/* REG 2 -> 16 ~ 23 */
+/* REG 3 -> 24 ~ 31 */
+#define MT6360_WD_PMU_DET (25)
+#define MT6360_WD_PMU_DONE (26)
+#define MT6360_CHG_TMRI (27)
+#define MT6360_CHG_ADPBADI (29)
+#define MT6360_CHG_RVPI (30)
+#define MT6360_OTPI (31)
+/* REG 4 -> 32 ~ 39 */
+#define MT6360_CHG_AICCMEASL (32)
+#define MT6360_CHGDET_DONEI (34)
+#define MT6360_WDTMRI (35)
+#define MT6360_SSFINISHI (36)
+#define MT6360_CHG_RECHGI (37)
+#define MT6360_CHG_TERMI (38)
+#define MT6360_CHG_IEOCI (39)
+/* REG 5 -> 40 ~ 47 */
+#define MT6360_PUMPX_DONEI (40)
+#define MT6360_BAT_OVP_ADC_EVT (41)
+#define MT6360_TYPEC_OTP_EVT (42)
+#define MT6360_ADC_WAKEUP_EVT (43)
+#define MT6360_ADC_DONEI (44)
+#define MT6360_BST_BATUVI (45)
+#define MT6360_BST_VBUSOVI (46)
+#define MT6360_BST_OLPI (47)
+/* REG 6 -> 48 ~ 55 */
+#define MT6360_ATTACH_I (48)
+#define MT6360_DETACH_I (49)
+#define MT6360_QC30_STPDONE (51)
+#define MT6360_QC_VBUSDET_DONE (52)
+#define MT6360_HVDCP_DET (53)
+#define MT6360_CHGDETI (54)
+#define MT6360_DCDTI (55)
+/* REG 7 -> 56 ~ 63 */
+#define MT6360_FOD_DONE_EVT (56)
+#define MT6360_FOD_OV_EVT (57)
+#define MT6360_CHRDET_UVP_EVT (58)
+#define MT6360_CHRDET_OVP_EVT (59)
+#define MT6360_CHRDET_EXT_EVT (60)
+#define MT6360_FOD_LR_EVT (61)
+#define MT6360_FOD_HR_EVT (62)
+#define MT6360_FOD_DISCHG_FAIL_EVT (63)
+/* REG 8 -> 64 ~ 71 */
+#define MT6360_USBID_EVT (64)
+#define MT6360_APWDTRST_EVT (65)
+#define MT6360_EN_EVT (66)
+#define MT6360_QONB_RST_EVT (67)
+#define MT6360_MRSTB_EVT (68)
+#define MT6360_OTP_EVT (69)
+#define MT6360_VDDAOV_EVT (70)
+#define MT6360_SYSUV_EVT (71)
+/* REG 9 -> 72 ~ 79 */
+#define MT6360_FLED_STRBPIN_EVT (72)
+#define MT6360_FLED_TORPIN_EVT (73)
+#define MT6360_FLED_TX_EVT (74)
+#define MT6360_FLED_LVF_EVT (75)
+#define MT6360_FLED2_SHORT_EVT (78)
+#define MT6360_FLED1_SHORT_EVT (79)
+/* REG 10 -> 80 ~ 87 */
+#define MT6360_FLED2_STRB_EVT (80)
+#define MT6360_FLED1_STRB_EVT (81)
+#define MT6360_FLED2_STRB_TO_EVT (82)
+#define MT6360_FLED1_STRB_TO_EVT (83)
+#define MT6360_FLED2_TOR_EVT (84)
+#define MT6360_FLED1_TOR_EVT (85)
+/* REG 11 -> 88 ~ 95 */
+/* REG 12 -> 96 ~ 103 */
+#define MT6360_BUCK1_PGB_EVT (96)
+#define MT6360_BUCK1_OC_EVT (100)
+#define MT6360_BUCK1_OV_EVT (101)
+#define MT6360_BUCK1_UV_EVT (102)
+/* REG 13 -> 104 ~ 111 */
+#define MT6360_BUCK2_PGB_EVT (104)
+#define MT6360_BUCK2_OC_EVT (108)
+#define MT6360_BUCK2_OV_EVT (109)
+#define MT6360_BUCK2_UV_EVT (110)
+/* REG 14 -> 112 ~ 119 */
+#define MT6360_LDO1_OC_EVT (113)
+#define MT6360_LDO2_OC_EVT (114)
+#define MT6360_LDO3_OC_EVT (115)
+#define MT6360_LDO5_OC_EVT (117)
+#define MT6360_LDO6_OC_EVT (118)
+#define MT6360_LDO7_OC_EVT (119)
+/* REG 15 -> 120 ~ 127 */
+#define MT6360_LDO1_PGB_EVT (121)
+#define MT6360_LDO2_PGB_EVT (122)
+#define MT6360_LDO3_PGB_EVT (123)
+#define MT6360_LDO5_PGB_EVT (125)
+#define MT6360_LDO6_PGB_EVT (126)
+#define MT6360_LDO7_PGB_EVT (127)
+
+#define MT6360_REGMAP_IRQ_REG(_irq_evt) \
+ REGMAP_IRQ_REG(_irq_evt, (_irq_evt) / 8, BIT((_irq_evt) % 8))
+
+#define MT6360_MFD_CELL(_name) \
+ { \
+ .name = #_name, \
+ .of_compatible = "mediatek," #_name, \
+ .num_resources = ARRAY_SIZE(_name##_resources), \
+ .resources = _name##_resources, \
+ }
+
+static const struct regmap_irq mt6360_pmu_irqs[] = {
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_TREG_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_AICR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_MIVR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_PWR_RDY_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_BATSYSUV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED_CHG_VINOVP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_VSYSUV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_VSYSOV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_VBATOV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_VBUSOV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_WD_PMU_DET),
+ MT6360_REGMAP_IRQ_REG(MT6360_WD_PMU_DONE),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_TMRI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_ADPBADI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_RVPI),
+ MT6360_REGMAP_IRQ_REG(MT6360_OTPI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_AICCMEASL),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHGDET_DONEI),
+ MT6360_REGMAP_IRQ_REG(MT6360_WDTMRI),
+ MT6360_REGMAP_IRQ_REG(MT6360_SSFINISHI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_RECHGI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_TERMI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_IEOCI),
+ MT6360_REGMAP_IRQ_REG(MT6360_PUMPX_DONEI),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHG_TREG_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BAT_OVP_ADC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_TYPEC_OTP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_ADC_WAKEUP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_ADC_DONEI),
+ MT6360_REGMAP_IRQ_REG(MT6360_BST_BATUVI),
+ MT6360_REGMAP_IRQ_REG(MT6360_BST_VBUSOVI),
+ MT6360_REGMAP_IRQ_REG(MT6360_BST_OLPI),
+ MT6360_REGMAP_IRQ_REG(MT6360_ATTACH_I),
+ MT6360_REGMAP_IRQ_REG(MT6360_DETACH_I),
+ MT6360_REGMAP_IRQ_REG(MT6360_QC30_STPDONE),
+ MT6360_REGMAP_IRQ_REG(MT6360_QC_VBUSDET_DONE),
+ MT6360_REGMAP_IRQ_REG(MT6360_HVDCP_DET),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHGDETI),
+ MT6360_REGMAP_IRQ_REG(MT6360_DCDTI),
+ MT6360_REGMAP_IRQ_REG(MT6360_FOD_DONE_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FOD_OV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_UVP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_OVP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_EXT_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FOD_LR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FOD_HR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FOD_DISCHG_FAIL_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_USBID_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_APWDTRST_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_EN_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_QONB_RST_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_MRSTB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_OTP_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_VDDAOV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_SYSUV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED_STRBPIN_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED_TORPIN_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED_TX_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED_LVF_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED2_SHORT_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED1_SHORT_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED2_STRB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED1_STRB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED2_STRB_TO_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED1_STRB_TO_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED2_TOR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_FLED1_TOR_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_OV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_UV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_OV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_UV_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO1_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO2_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO3_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO5_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO6_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO7_OC_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO1_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO2_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO3_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO5_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO6_PGB_EVT),
+ MT6360_REGMAP_IRQ_REG(MT6360_LDO7_PGB_EVT),
+};
+
+static int mt6360_pmu_handle_post_irq(void *irq_drv_data)
+{
+ struct mt6360_pmu_info *mpi = irq_drv_data;
+
+ return regmap_update_bits(mpi->regmap,
+ MT6360_PMU_IRQ_SET, MT6360_IRQ_RETRIG, MT6360_IRQ_RETRIG);
+}
+
+static const struct regmap_irq_chip mt6360_pmu_irq_chip = {
+ .irqs = mt6360_pmu_irqs,
+ .num_irqs = ARRAY_SIZE(mt6360_pmu_irqs),
+ .num_regs = MT6360_PMU_IRQ_REGNUM,
+ .mask_base = MT6360_PMU_CHG_MASK1,
+ .status_base = MT6360_PMU_CHG_IRQ1,
+ .ack_base = MT6360_PMU_CHG_IRQ1,
+ .init_ack_masked = true,
+ .use_ack = true,
+ .handle_post_irq = mt6360_pmu_handle_post_irq,
+};
+
+static const struct regmap_config mt6360_pmu_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MT6360_PMU_MAXREG,
+};
+
+static const struct resource mt6360_adc_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6360_ADC_DONEI, "adc_donei"),
+};
+
+static const struct resource mt6360_chg_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_TREG_EVT, "chg_treg_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_PWR_RDY_EVT, "pwr_rdy_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_BATSYSUV_EVT, "chg_batsysuv_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_VSYSUV_EVT, "chg_vsysuv_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_VSYSOV_EVT, "chg_vsysov_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_VBATOV_EVT, "chg_vbatov_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_VBUSOV_EVT, "chg_vbusov_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_AICCMEASL, "chg_aiccmeasl"),
+ DEFINE_RES_IRQ_NAMED(MT6360_WDTMRI, "wdtmri"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_RECHGI, "chg_rechgi"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_TERMI, "chg_termi"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHG_IEOCI, "chg_ieoci"),
+ DEFINE_RES_IRQ_NAMED(MT6360_PUMPX_DONEI, "pumpx_donei"),
+ DEFINE_RES_IRQ_NAMED(MT6360_ATTACH_I, "attach_i"),
+ DEFINE_RES_IRQ_NAMED(MT6360_CHRDET_EXT_EVT, "chrdet_ext_evt"),
+};
+
+static const struct resource mt6360_led_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED_CHG_VINOVP_EVT, "fled_chg_vinovp_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED_LVF_EVT, "fled_lvf_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED2_SHORT_EVT, "fled2_short_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED1_SHORT_EVT, "fled1_short_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED2_STRB_TO_EVT, "fled2_strb_to_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_FLED1_STRB_TO_EVT, "fled1_strb_to_evt"),
+};
+
+static const struct resource mt6360_pmic_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_PGB_EVT, "buck1_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OC_EVT, "buck1_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OV_EVT, "buck1_ov_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_UV_EVT, "buck1_uv_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_PGB_EVT, "buck2_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OC_EVT, "buck2_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OV_EVT, "buck2_ov_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_UV_EVT, "buck2_uv_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO6_OC_EVT, "ldo6_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"),
+};
+
+static const struct resource mt6360_ldo_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO1_OC_EVT, "ldo1_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO2_OC_EVT, "ldo2_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO3_OC_EVT, "ldo3_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO5_OC_EVT, "ldo5_oc_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO1_PGB_EVT, "ldo1_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO2_PGB_EVT, "ldo2_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO3_PGB_EVT, "ldo3_pgb_evt"),
+ DEFINE_RES_IRQ_NAMED(MT6360_LDO5_PGB_EVT, "ldo5_pgb_evt"),
+};
+
+static const struct mfd_cell mt6360_devs[] = {
+ MT6360_MFD_CELL(mt6360_adc),
+ MT6360_MFD_CELL(mt6360_chg),
+ MT6360_MFD_CELL(mt6360_led),
+ MT6360_MFD_CELL(mt6360_pmic),
+ MT6360_MFD_CELL(mt6360_ldo),
+ /* tcpc dev */
+ {
+ .name = "mt6360_tcpc",
+ .of_compatible = "mediatek,mt6360_tcpc",
+ },
+};
+
+static const unsigned short mt6360_slave_addr[MT6360_SLAVE_MAX] = {
+ MT6360_PMU_SLAVEID,
+ MT6360_PMIC_SLAVEID,
+ MT6360_LDO_SLAVEID,
+ MT6360_TCPC_SLAVEID,
+};
+
+static int mt6360_pmu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mt6360_pmu_info *mpi;
+ unsigned int reg_data = 0;
+ int i, ret;
+
+ mpi = devm_kzalloc(&client->dev, sizeof(*mpi), GFP_KERNEL);
+ if (!mpi)
+ return -ENOMEM;
+ mpi->dev = &client->dev;
+ i2c_set_clientdata(client, mpi);
+
+ /* regmap regiser */
+ mpi->regmap = devm_regmap_init_i2c(client, &mt6360_pmu_regmap_config);
+ if (IS_ERR(mpi->regmap)) {
+ dev_err(&client->dev, "regmap register fail\n");
+ return PTR_ERR(mpi->regmap);
+ }
+ /* chip id check */
+ ret = regmap_read(mpi->regmap, MT6360_PMU_DEV_INFO, ®_data);
+ if (ret < 0) {
+ dev_err(&client->dev, "device not found\n");
+ return ret;
+ }
+ if ((reg_data & CHIP_VEN_MASK) != CHIP_VEN_MT6360) {
+ dev_err(&client->dev, "not mt6360 chip\n");
+ return -ENODEV;
+ }
+ mpi->chip_rev = reg_data & CHIP_REV_MASK;
+ /* irq register */
+ memcpy(&mpi->irq_chip, &mt6360_pmu_irq_chip, sizeof(mpi->irq_chip));
+ mpi->irq_chip.name = dev_name(&client->dev);
+ mpi->irq_chip.irq_drv_data = mpi;
+ ret = devm_regmap_add_irq_chip(&client->dev, mpi->regmap, client->irq,
+ IRQF_TRIGGER_FALLING, 0, &mpi->irq_chip,
+ &mpi->irq_data);
+ if (ret < 0) {
+ dev_err(&client->dev, "regmap irq chip add fail\n");
+ return ret;
+ }
+ /* new i2c slave device */
+ for (i = 0; i < MT6360_SLAVE_MAX; i++) {
+ if (mt6360_slave_addr[i] == client->addr) {
+ mpi->i2c[i] = client;
+ continue;
+ }
+ mpi->i2c[i] = i2c_new_dummy(client->adapter,
+ mt6360_slave_addr[i]);
+ if (!mpi->i2c[i]) {
+ dev_err(&client->dev, "new i2c dev [%d] fail\n", i);
+ ret = -ENODEV;
+ goto out;
+ }
+ i2c_set_clientdata(mpi->i2c[i], mpi);
+ }
+ /* mfd cell register */
+ ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
+ mt6360_devs, ARRAY_SIZE(mt6360_devs), NULL,
+ 0, regmap_irq_get_domain(mpi->irq_data));
+ if (ret < 0) {
+ dev_err(&client->dev, "mfd add cells fail\n");
+ goto out;
+ }
+ dev_info(&client->dev, "Successfully probed\n");
+ return 0;
+out:
+ while (--i >= 0) {
+ if (mpi->i2c[i]->addr == client->addr)
+ continue;
+ i2c_unregister_device(mpi->i2c[i]);
+ }
+ return ret;
+}
+
+static int mt6360_pmu_remove(struct i2c_client *client)
+{
+ struct mt6360_pmu_info *mpi = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < MT6360_SLAVE_MAX; i++) {
+ if (mpi->i2c[i]->addr == client->addr)
+ continue;
+ i2c_unregister_device(mpi->i2c[i]);
+ }
+ return 0;
+}
+
+static int __maybe_unused mt6360_pmu_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(i2c->irq);
+ return 0;
+}
+
+static int __maybe_unused mt6360_pmu_resume(struct device *dev)
+{
+
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(i2c->irq);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mt6360_pmu_pm_ops,
+ mt6360_pmu_suspend, mt6360_pmu_resume);
+
+static const struct of_device_id __maybe_unused mt6360_pmu_of_id[] = {
+ { .compatible = "mediatek,mt6360_pmu", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt6360_pmu_of_id);
+
+static const struct i2c_device_id mt6360_pmu_id[] = {
+ { "mt6360_pmu", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mt6360_pmu_id);
+
+static struct i2c_driver mt6360_pmu_driver = {
+ .driver = {
+ .name = "mt6360_pmu",
+ .owner = THIS_MODULE,
+ .pm = &mt6360_pmu_pm_ops,
+ .of_match_table = of_match_ptr(mt6360_pmu_of_id),
+ },
+ .probe = mt6360_pmu_probe,
+ .remove = mt6360_pmu_remove,
+ .id_table = mt6360_pmu_id,
+};
+module_i2c_driver(mt6360_pmu_driver);
+
+MODULE_AUTHOR("CY_Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6360 PMU I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
diff --git a/include/linux/mfd/mt6360-private.h b/include/linux/mfd/mt6360-private.h
new file mode 100644
index 0000000..b07b3d9
--- /dev/null
+++ b/include/linux/mfd/mt6360-private.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __MT6360_PRIVATE_H__
+#define __MT6360_PRIVATE_H__
+
+#include <linux/interrupt.h>
+
+/* PMU register defininition */
+#define MT6360_PMU_DEV_INFO (0x00)
+#define MT6360_PMU_CORE_CTRL1 (0x01)
+#define MT6360_PMU_RST1 (0x02)
+#define MT6360_PMU_CRCEN (0x03)
+#define MT6360_PMU_RST_PAS_CODE1 (0x04)
+#define MT6360_PMU_RST_PAS_CODE2 (0x05)
+#define MT6360_PMU_CORE_CTRL2 (0x06)
+#define MT6360_PMU_TM_PAS_CODE1 (0x07)
+#define MT6360_PMU_TM_PAS_CODE2 (0x08)
+#define MT6360_PMU_TM_PAS_CODE3 (0x09)
+#define MT6360_PMU_TM_PAS_CODE4 (0x0A)
+#define MT6360_PMU_IRQ_IND (0x0B)
+#define MT6360_PMU_IRQ_MASK (0x0C)
+#define MT6360_PMU_IRQ_SET (0x0D)
+#define MT6360_PMU_SHDN_CTRL (0x0E)
+#define MT6360_PMU_TM_INF (0x0F)
+#define MT6360_PMU_I2C_CTRL (0x10)
+#define MT6360_PMU_CHG_CTRL1 (0x11)
+#define MT6360_PMU_CHG_CTRL2 (0x12)
+#define MT6360_PMU_CHG_CTRL3 (0x13)
+#define MT6360_PMU_CHG_CTRL4 (0x14)
+#define MT6360_PMU_CHG_CTRL5 (0x15)
+#define MT6360_PMU_CHG_CTRL6 (0x16)
+#define MT6360_PMU_CHG_CTRL7 (0x17)
+#define MT6360_PMU_CHG_CTRL8 (0x18)
+#define MT6360_PMU_CHG_CTRL9 (0x19)
+#define MT6360_PMU_CHG_CTRL10 (0x1A)
+#define MT6360_PMU_CHG_CTRL11 (0x1B)
+#define MT6360_PMU_CHG_CTRL12 (0x1C)
+#define MT6360_PMU_CHG_CTRL13 (0x1D)
+#define MT6360_PMU_CHG_CTRL14 (0x1E)
+#define MT6360_PMU_CHG_CTRL15 (0x1F)
+#define MT6360_PMU_CHG_CTRL16 (0x20)
+#define MT6360_PMU_CHG_AICC_RESULT (0x21)
+#define MT6360_PMU_DEVICE_TYPE (0x22)
+#define MT6360_PMU_QC_CONTROL1 (0x23)
+#define MT6360_PMU_QC_CONTROL2 (0x24)
+#define MT6360_PMU_QC30_CONTROL1 (0x25)
+#define MT6360_PMU_QC30_CONTROL2 (0x26)
+#define MT6360_PMU_USB_STATUS1 (0x27)
+#define MT6360_PMU_QC_STATUS1 (0x28)
+#define MT6360_PMU_QC_STATUS2 (0x29)
+#define MT6360_PMU_CHG_PUMP (0x2A)
+#define MT6360_PMU_CHG_CTRL17 (0x2B)
+#define MT6360_PMU_CHG_CTRL18 (0x2C)
+#define MT6360_PMU_CHRDET_CTRL1 (0x2D)
+#define MT6360_PMU_CHRDET_CTRL2 (0x2E)
+#define MT6360_PMU_DPDN_CTRL (0x2F)
+#define MT6360_PMU_CHG_HIDDEN_CTRL1 (0x30)
+#define MT6360_PMU_CHG_HIDDEN_CTRL2 (0x31)
+#define MT6360_PMU_CHG_HIDDEN_CTRL3 (0x32)
+#define MT6360_PMU_CHG_HIDDEN_CTRL4 (0x33)
+#define MT6360_PMU_CHG_HIDDEN_CTRL5 (0x34)
+#define MT6360_PMU_CHG_HIDDEN_CTRL6 (0x35)
+#define MT6360_PMU_CHG_HIDDEN_CTRL7 (0x36)
+#define MT6360_PMU_CHG_HIDDEN_CTRL8 (0x37)
+#define MT6360_PMU_CHG_HIDDEN_CTRL9 (0x38)
+#define MT6360_PMU_CHG_HIDDEN_CTRL10 (0x39)
+#define MT6360_PMU_CHG_HIDDEN_CTRL11 (0x3A)
+#define MT6360_PMU_CHG_HIDDEN_CTRL12 (0x3B)
+#define MT6360_PMU_CHG_HIDDEN_CTRL13 (0x3C)
+#define MT6360_PMU_CHG_HIDDEN_CTRL14 (0x3D)
+#define MT6360_PMU_CHG_HIDDEN_CTRL15 (0x3E)
+#define MT6360_PMU_CHG_HIDDEN_CTRL16 (0x3F)
+#define MT6360_PMU_CHG_HIDDEN_CTRL17 (0x40)
+#define MT6360_PMU_CHG_HIDDEN_CTRL18 (0x41)
+#define MT6360_PMU_CHG_HIDDEN_CTRL19 (0x42)
+#define MT6360_PMU_CHG_HIDDEN_CTRL20 (0x43)
+#define MT6360_PMU_CHG_HIDDEN_CTRL21 (0x44)
+#define MT6360_PMU_CHG_HIDDEN_CTRL22 (0x45)
+#define MT6360_PMU_CHG_HIDDEN_CTRL23 (0x46)
+#define MT6360_PMU_CHG_HIDDEN_CTRL24 (0x47)
+#define MT6360_PMU_CHG_HIDDEN_CTRL25 (0x48)
+#define MT6360_PMU_BC12_CTRL (0x49)
+#define MT6360_PMU_CHG_STAT (0x4A)
+#define MT6360_PMU_RESV1 (0x4B)
+#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEH (0x4E)
+#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEL (0x4F)
+#define MT6360_PMU_TYPEC_OTP_HYST_TH (0x50)
+#define MT6360_PMU_TYPEC_OTP_CTRL (0x51)
+#define MT6360_PMU_ADC_BAT_DATA_H (0x52)
+#define MT6360_PMU_ADC_BAT_DATA_L (0x53)
+#define MT6360_PMU_IMID_BACKBST_ON (0x54)
+#define MT6360_PMU_IMID_BACKBST_OFF (0x55)
+#define MT6360_PMU_ADC_CONFIG (0x56)
+#define MT6360_PMU_ADC_EN2 (0x57)
+#define MT6360_PMU_ADC_IDLE_T (0x58)
+#define MT6360_PMU_ADC_RPT_1 (0x5A)
+#define MT6360_PMU_ADC_RPT_2 (0x5B)
+#define MT6360_PMU_ADC_RPT_3 (0x5C)
+#define MT6360_PMU_ADC_RPT_ORG1 (0x5D)
+#define MT6360_PMU_ADC_RPT_ORG2 (0x5E)
+#define MT6360_PMU_BAT_OVP_TH_SEL_CODEH (0x5F)
+#define MT6360_PMU_BAT_OVP_TH_SEL_CODEL (0x60)
+#define MT6360_PMU_CHG_CTRL19 (0x61)
+#define MT6360_PMU_VDDASUPPLY (0x62)
+#define MT6360_PMU_BC12_MANUAL (0x63)
+#define MT6360_PMU_CHGDET_FUNC (0x64)
+#define MT6360_PMU_FOD_CTRL (0x65)
+#define MT6360_PMU_CHG_CTRL20 (0x66)
+#define MT6360_PMU_CHG_HIDDEN_CTRL26 (0x67)
+#define MT6360_PMU_CHG_HIDDEN_CTRL27 (0x68)
+#define MT6360_PMU_RESV2 (0x69)
+#define MT6360_PMU_USBID_CTRL1 (0x6D)
+#define MT6360_PMU_USBID_CTRL2 (0x6E)
+#define MT6360_PMU_USBID_CTRL3 (0x6F)
+#define MT6360_PMU_FLED_CFG (0x70)
+#define MT6360_PMU_RESV3 (0x71)
+#define MT6360_PMU_FLED1_CTRL (0x72)
+#define MT6360_PMU_FLED_STRB_CTRL (0x73)
+#define MT6360_PMU_FLED1_STRB_CTRL2 (0x74)
+#define MT6360_PMU_FLED1_TOR_CTRL (0x75)
+#define MT6360_PMU_FLED2_CTRL (0x76)
+#define MT6360_PMU_RESV4 (0x77)
+#define MT6360_PMU_FLED2_STRB_CTRL2 (0x78)
+#define MT6360_PMU_FLED2_TOR_CTRL (0x79)
+#define MT6360_PMU_FLED_VMIDTRK_CTRL1 (0x7A)
+#define MT6360_PMU_FLED_VMID_RTM (0x7B)
+#define MT6360_PMU_FLED_VMIDTRK_CTRL2 (0x7C)
+#define MT6360_PMU_FLED_PWSEL (0x7D)
+#define MT6360_PMU_FLED_EN (0x7E)
+#define MT6360_PMU_FLED_Hidden1 (0x7F)
+#define MT6360_PMU_RGB_EN (0x80)
+#define MT6360_PMU_RGB1_ISNK (0x81)
+#define MT6360_PMU_RGB2_ISNK (0x82)
+#define MT6360_PMU_RGB3_ISNK (0x83)
+#define MT6360_PMU_RGB_ML_ISNK (0x84)
+#define MT6360_PMU_RGB1_DIM (0x85)
+#define MT6360_PMU_RGB2_DIM (0x86)
+#define MT6360_PMU_RGB3_DIM (0x87)
+#define MT6360_PMU_RESV5 (0x88)
+#define MT6360_PMU_RGB12_Freq (0x89)
+#define MT6360_PMU_RGB34_Freq (0x8A)
+#define MT6360_PMU_RGB1_Tr (0x8B)
+#define MT6360_PMU_RGB1_Tf (0x8C)
+#define MT6360_PMU_RGB1_TON_TOFF (0x8D)
+#define MT6360_PMU_RGB2_Tr (0x8E)
+#define MT6360_PMU_RGB2_Tf (0x8F)
+#define MT6360_PMU_RGB2_TON_TOFF (0x90)
+#define MT6360_PMU_RGB3_Tr (0x91)
+#define MT6360_PMU_RGB3_Tf (0x92)
+#define MT6360_PMU_RGB3_TON_TOFF (0x93)
+#define MT6360_PMU_RGB_Hidden_CTRL1 (0x94)
+#define MT6360_PMU_RGB_Hidden_CTRL2 (0x95)
+#define MT6360_PMU_RESV6 (0x97)
+#define MT6360_PMU_SPARE1 (0x9A)
+#define MT6360_PMU_SPARE2 (0xA0)
+#define MT6360_PMU_SPARE3 (0xB0)
+#define MT6360_PMU_SPARE4 (0xC0)
+#define MT6360_PMU_CHG_IRQ1 (0xD0)
+#define MT6360_PMU_CHG_IRQ2 (0xD1)
+#define MT6360_PMU_CHG_IRQ3 (0xD2)
+#define MT6360_PMU_CHG_IRQ4 (0xD3)
+#define MT6360_PMU_CHG_IRQ5 (0xD4)
+#define MT6360_PMU_CHG_IRQ6 (0xD5)
+#define MT6360_PMU_QC_IRQ (0xD6)
+#define MT6360_PMU_FOD_IRQ (0xD7)
+#define MT6360_PMU_BASE_IRQ (0xD8)
+#define MT6360_PMU_FLED_IRQ1 (0xD9)
+#define MT6360_PMU_FLED_IRQ2 (0xDA)
+#define MT6360_PMU_RGB_IRQ (0xDB)
+#define MT6360_PMU_BUCK1_IRQ (0xDC)
+#define MT6360_PMU_BUCK2_IRQ (0xDD)
+#define MT6360_PMU_LDO_IRQ1 (0xDE)
+#define MT6360_PMU_LDO_IRQ2 (0xDF)
+#define MT6360_PMU_CHG_STAT1 (0xE0)
+#define MT6360_PMU_CHG_STAT2 (0xE1)
+#define MT6360_PMU_CHG_STAT3 (0xE2)
+#define MT6360_PMU_CHG_STAT4 (0xE3)
+#define MT6360_PMU_CHG_STAT5 (0xE4)
+#define MT6360_PMU_CHG_STAT6 (0xE5)
+#define MT6360_PMU_QC_STAT (0xE6)
+#define MT6360_PMU_FOD_STAT (0xE7)
+#define MT6360_PMU_BASE_STAT (0xE8)
+#define MT6360_PMU_FLED_STAT1 (0xE9)
+#define MT6360_PMU_FLED_STAT2 (0xEA)
+#define MT6360_PMU_RGB_STAT (0xEB)
+#define MT6360_PMU_BUCK1_STAT (0xEC)
+#define MT6360_PMU_BUCK2_STAT (0xED)
+#define MT6360_PMU_LDO_STAT1 (0xEE)
+#define MT6360_PMU_LDO_STAT2 (0xEF)
+#define MT6360_PMU_CHG_MASK1 (0xF0)
+#define MT6360_PMU_CHG_MASK2 (0xF1)
+#define MT6360_PMU_CHG_MASK3 (0xF2)
+#define MT6360_PMU_CHG_MASK4 (0xF3)
+#define MT6360_PMU_CHG_MASK5 (0xF4)
+#define MT6360_PMU_CHG_MASK6 (0xF5)
+#define MT6360_PMU_QC_MASK (0xF6)
+#define MT6360_PMU_FOD_MASK (0xF7)
+#define MT6360_PMU_BASE_MASK (0xF8)
+#define MT6360_PMU_FLED_MASK1 (0xF9)
+#define MT6360_PMU_FLED_MASK2 (0xFA)
+#define MT6360_PMU_FAULTB_MASK (0xFB)
+#define MT6360_PMU_BUCK1_MASK (0xFC)
+#define MT6360_PMU_BUCK2_MASK (0xFD)
+#define MT6360_PMU_LDO_MASK1 (0xFE)
+#define MT6360_PMU_LDO_MASK2 (0xFF)
+#define MT6360_PMU_MAXREG (MT6360_PMU_LDO_MASK2)
+
+
+/* MT6360_PMU_IRQ_SET */
+#define MT6360_PMU_IRQ_REGNUM (MT6360_PMU_LDO_IRQ2 - MT6360_PMU_CHG_IRQ1 + 1)
+#define MT6360_IRQ_RETRIG BIT(2)
+
+#define CHIP_VEN_MASK (0xF0)
+#define CHIP_VEN_MT6360 (0x50)
+#define CHIP_REV_MASK (0x0F)
+
+/* IRQ definitions */
+struct mt6360_pmu_irq_desc {
+ const char *name;
+ irq_handler_t irq_handler;
+};
+
+#define MT6360_DT_VALPROP(name, type) \
+ {#name, offsetof(type, name)}
+
+struct mt6360_val_prop {
+ const char *name;
+ size_t offset;
+};
+
+static inline void mt6360_dt_parser_helper(struct device_node *np, void *data,
+ const struct mt6360_val_prop *props,
+ int prop_cnt)
+{
+ int i;
+
+ for (i = 0; i < prop_cnt; i++) {
+ if (unlikely(!props[i].name))
+ continue;
+ of_property_read_u32(np, props[i].name, data + props[i].offset);
+ }
+}
+
+#define MT6360_PDATA_VALPROP(name, type, reg, shift, mask, func, base) \
+ {offsetof(type, name), reg, shift, mask, func, base}
+
+struct mt6360_pdata_prop {
+ size_t offset;
+ u8 reg;
+ u8 shift;
+ u8 mask;
+ u32 (*transform)(u32 val);
+ u8 base;
+};
+
+static inline int mt6360_pdata_apply_helper(void *context, void *pdata,
+ const struct mt6360_pdata_prop *prop,
+ int prop_cnt)
+{
+ int i, ret;
+ u32 val;
+
+ for (i = 0; i < prop_cnt; i++) {
+ val = *(u32 *)(pdata + prop[i].offset);
+ if (prop[i].transform)
+ val = prop[i].transform(val);
+ val += prop[i].base;
+ ret = regmap_update_bits(context,
+ prop[i].reg, prop[i].mask, val << prop[i].shift);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+#endif /* __MT6360_PRIVATE_H__ */
diff --git a/include/linux/mfd/mt6360.h b/include/linux/mfd/mt6360.h
new file mode 100644
index 0000000..ba2e80a
--- /dev/null
+++ b/include/linux/mfd/mt6360.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __MT6360_H__
+#define __MT6360_H__
+
+#include <linux/regmap.h>
+
+enum {
+ MT6360_SLAVE_PMU = 0,
+ MT6360_SLAVE_PMIC,
+ MT6360_SLAVE_LDO,
+ MT6360_SLAVE_TCPC,
+ MT6360_SLAVE_MAX,
+};
+
+#define MT6360_PMU_SLAVEID (0x34)
+#define MT6360_PMIC_SLAVEID (0x1A)
+#define MT6360_LDO_SLAVEID (0x64)
+#define MT6360_TCPC_SLAVEID (0x4E)
+
+struct mt6360_pmu_info {
+ struct i2c_client *i2c[MT6360_SLAVE_MAX];
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
+ struct regmap_irq_chip irq_chip;
+ unsigned int chip_rev;
+};
+
+#endif /* __MT6360_H__ */
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v8 3/3] mm: fix double page fault on arm64 if PTE_AF is cleared
From: Jia He @ 2019-09-24 15:29 UTC (permalink / raw)
To: Catalin Marinas, Justin He (Arm Technology China)
Cc: Mark Rutland, Kaly Xin (Arm Technology China), Ralph Campbell,
Andrew Morton, Suzuki Poulose, Marc Zyngier, Anshuman Khandual,
linux-kernel@vger.kernel.org, Matthew Wilcox, linux-mm@kvack.org,
Jérôme Glisse, James Morse,
linux-arm-kernel@lists.infradead.org, Punit Agrawal,
Thomas Gleixner, nd, Will Deacon, Alex Van Brunt,
Kirill A. Shutemov, Robin Murphy
In-Reply-To: <20190924103324.GB41214@arrakis.emea.arm.com>
Hi Catalin
On 2019/9/24 18:33, Catalin Marinas wrote:
> On Tue, Sep 24, 2019 at 06:43:06AM +0000, Justin He (Arm Technology China) wrote:
>> Catalin Marinas wrote:
>>> On Sat, Sep 21, 2019 at 09:50:54PM +0800, Jia He wrote:
>>>> @@ -2151,21 +2163,53 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
>>>> * fails, we just zero-fill it. Live with it.
>>>> */
>>>> if (unlikely(!src)) {
>>>> - void *kaddr = kmap_atomic(dst);
>>>> - void __user *uaddr = (void __user *)(va & PAGE_MASK);
>>>> + void *kaddr;
>>>> + pte_t entry;
>>>> + void __user *uaddr = (void __user *)(addr & PAGE_MASK);
>>>>
>>>> + /* On architectures with software "accessed" bits, we would
>>>> + * take a double page fault, so mark it accessed here.
>>>> + */
> [...]
>>>> + if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
>>>> + vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr,
>>>> + &vmf->ptl);
>>>> + if (likely(pte_same(*vmf->pte, vmf->orig_pte))) {
>>>> + entry = pte_mkyoung(vmf->orig_pte);
>>>> + if (ptep_set_access_flags(vma, addr,
>>>> + vmf->pte, entry, 0))
>>>> + update_mmu_cache(vma, addr, vmf->pte);
>>>> + } else {
>>>> + /* Other thread has already handled the fault
>>>> + * and we don't need to do anything. If it's
>>>> + * not the case, the fault will be triggered
>>>> + * again on the same address.
>>>> + */
>>>> + pte_unmap_unlock(vmf->pte, vmf->ptl);
>>>> + return false;
>>>> + }
>>>> + pte_unmap_unlock(vmf->pte, vmf->ptl);
>>>> + }
> [...]
>>>> +
>>>> + kaddr = kmap_atomic(dst);
>>> Since you moved the kmap_atomic() here, could the above
>>> arch_faults_on_old_pte() run in a preemptible context? I suggested to
>>> add a WARN_ON in patch 2 to be sure.
>> Should I move kmap_atomic back to the original line? Thus, we can make sure
>> that arch_faults_on_old_pte() is in the context of preempt_disabled?
>> Otherwise, arch_faults_on_old_pte() may cause plenty of warning if I add
>> a WARN_ON in arch_faults_on_old_pte. I tested it when I enable the PREEMPT=y
>> on a ThunderX2 qemu guest.
> So we have two options here:
>
> 1. Change arch_faults_on_old_pte() scope to the whole system rather than
> just the current CPU. You'd have to wire up a new arm64 capability
> for the access flag but this way we don't care whether it's
> preemptible or not.
>
> 2. Keep the arch_faults_on_old_pte() per-CPU but make sure we are not
> preempted here. The kmap_atomic() move would do but you'd have to
> kunmap_atomic() before the return.
>
> I think the answer to my question below also has some implication on
> which option to pick:
>
>>>> /*
>>>> * This really shouldn't fail, because the page is there
>>>> * in the page tables. But it might just be unreadable,
>>>> * in which case we just give up and fill the result with
>>>> * zeroes.
>>>> */
>>>> - if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
>>>> + if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
>>>> + /* Give a warn in case there can be some obscure
>>>> + * use-case
>>>> + */
>>>> + WARN_ON_ONCE(1);
>>> That's more of a question for the mm guys: at this point we do the
>>> copying with the ptl released; is there anything else that could have
>>> made the pte old in the meantime? I think unuse_pte() is only called on
>>> anonymous vmas, so it shouldn't be the case here.
> If we need to hold the ptl here, you could as well have an enclosing
> kmap/kunmap_atomic (option 2) with some goto instead of "return false".
I am not 100% sure that I understand your suggestion well, so I drafted the patch
here:
Changes: optimize the indentions
hold the ptl longer
-static inline void cow_user_page(struct page *dst, struct page *src, unsigned
long va, struct vm_area_struct *vma)
+static inline bool cow_user_page(struct page *dst, struct page *src,
+ struct vm_fault *vmf)
{
+ struct vm_area_struct *vma = vmf->vma;
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long addr = vmf->address;
+ bool ret;
+ pte_t entry;
+ void *kaddr;
+ void __user *uaddr;
+
debug_dma_assert_idle(src);
+ if (likely(src)) {
+ copy_user_highpage(dst, src, addr, vma);
+ return true;
+ }
+
/*
* If the source page was a PFN mapping, we don't have
* a "struct page" for it. We do a best-effort copy by
* just copying from the original user address. If that
* fails, we just zero-fill it. Live with it.
*/
- if (unlikely(!src)) {
- void *kaddr = kmap_atomic(dst);
- void __user *uaddr = (void __user *)(va & PAGE_MASK);
+ kaddr = kmap_atomic(dst);
+ uaddr = (void __user *)(addr & PAGE_MASK);
+
+ /*
+ * On architectures with software "accessed" bits, we would
+ * take a double page fault, so mark it accessed here.
+ */
+ vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
+ if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
+ if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
+ /*
+ * Other thread has already handled the fault
+ * and we don't need to do anything. If it's
+ * not the case, the fault will be triggered
+ * again on the same address.
+ */
+ ret = false;
+ goto pte_unlock;
+ }
+
+ entry = pte_mkyoung(vmf->orig_pte);
+ if (ptep_set_access_flags(vma, addr, vmf->pte, entry, 0))
+ update_mmu_cache(vma, addr, vmf->pte);
+ }
+ /*
+ * This really shouldn't fail, because the page is there
+ * in the page tables. But it might just be unreadable,
+ * in which case we just give up and fill the result with
+ * zeroes.
+ */
+ if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
/*
- * This really shouldn't fail, because the page is there
- * in the page tables. But it might just be unreadable,
- * in which case we just give up and fill the result with
- * zeroes.
+ * Give a warn in case there can be some obscure
+ * use-case
*/
- if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
- clear_page(kaddr);
- kunmap_atomic(kaddr);
- flush_dcache_page(dst);
- } else
- copy_user_highpage(dst, src, va, vma);
+ WARN_ON_ONCE(1);
+ clear_page(kaddr);
+ }
+
+ ret = true;
+
+pte_unlock:
+ pte_unmap_unlock(vmf->pte, vmf->ptl);
+ kunmap_atomic(kaddr);
+ flush_dcache_page(dst);
+
+ return ret;
}
---
Cheers,
Justin (Jia He)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v10 0/6] mm / virtio: Provide support for unused page reporting
From: David Hildenbrand @ 2019-09-24 15:32 UTC (permalink / raw)
To: Michal Hocko, Alexander Duyck
Cc: yang.zhang.wz, pagupta, kvm, mst, lcapitulino, linux-mm,
alexander.h.duyck, aarcange, virtio-dev, riel, willy, wei.w.wang,
vbabka, konrad.wilk, dan.j.williams, linux-arm-kernel, osalvador,
nitesh, dave.hansen, linux-kernel, pbonzini, akpm, mgorman
In-Reply-To: <20190924142342.GX23050@dhcp22.suse.cz>
On 24.09.19 16:23, Michal Hocko wrote:
> On Wed 18-09-19 10:52:25, Alexander Duyck wrote:
> [...]
>> In order to try and keep the time needed to find a non-reported page to
>> a minimum we maintain a "reported_boundary" pointer. This pointer is used
>> by the get_unreported_pages iterator to determine at what point it should
>> resume searching for non-reported pages. In order to guarantee pages do
>> not get past the scan I have modified add_to_free_list_tail so that it
>> will not insert pages behind the reported_boundary.
>>
>> If another process needs to perform a massive manipulation of the free
>> list, such as compaction, it can either reset a given individual boundary
>> which will push the boundary back to the list_head, or it can clear the
>> bit indicating the zone is actively processing which will result in the
>> reporting process resetting all of the boundaries for a given zone.
>
> Is this any different from the previous version? The last review
> feedback (both from me and Mel) was that we are not happy to have an
> externally imposed constrains on how the page allocator is supposed to
> maintain its free lists.
>
> If this is really the only way to go forward then I would like to hear
> very convincing arguments about other approaches not being feasible.
Adding to what Alexander said, I don't consider the other approaches
(especially the bitmap-based approach Nitesh is currently working on)
infeasible. There might be more rough edges (e.g., sparse zones) and
eventually sometimes a little more work to be done, but definitely
feasible. Incorporating stuff into the buddy might make some tasks
(e.g., identify free pages) more efficient.
I still somewhat like the idea of capturing hints of free pages (in
whatever data structure) and then going over the hints, seeing if the
pages are still free. Then only temporarily isolating the still-free
pages, reporting them, and un-isolating them after they were reported. I
like the idea that the pages are not fake-allocated but only temporarily
blocked. That works nicely e.g., with the movable zone (contain only
movable data).
But anyhow, after decades of people working on free page
hinting/reporting, I am happy with anything that gets accepted upstream :D
--
Thanks,
David / dhildenb
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] mfd: mt6360: add pmic mt6360 driver
From: Gene Chen @ 2019-09-24 15:34 UTC (permalink / raw)
To: Lee Jones
Cc: gene_chen, linux-kernel, linux-mediatek, matthias.bgg, Wilma.Wu,
linux-arm-kernel, shufan_lee
In-Reply-To: <20190919071828.GC5016@dell>
2019-09-19 15:18 GMT+08:00, Lee Jones <lee.jones@linaro.org>:
> On Thu, 19 Sep 2019, Gene Chen wrote:
>
>> Lee Jones <lee.jones@linaro.org> 於 2019年9月18日 週三 下午6:51寫道:
>> >
>> > On Wed, 18 Sep 2019, Gene Chen wrote:
>> >
>> > > From: Gene Chen <gene_chen@richtek.com>
>> > >
>> > > Add mfd driver for mt6360 pmic chip include
>> > > Battery Charger/USB_PD/Flash LED/RGB LED/LDO/Buck
>> > >
>> > > Signed-off-by: Gene Chen <gene_chen@richtek.com
>> > > ---
>> >
>> > This looks different from the one you sent before, but I don't see a
>> > version bump or any changelog in this space. Please re-submit with
>> > the differences noted.
>> >
>>
>> the change is
>> 1. add missing include file
>> 2. modify commit message
>>
>> this patch is regarded as version 1
>
> It's different to the first one you sent to the list, so it needs a
> version bump and a change log. There also appears to still be issues
> with it, if the auto-builders are to be believed.
>
> Do ensure you thoroughly test your patches before sending upstream.
>
> Please fix the issues and resubmit your v3 with a nice changelog.
>
thank you for suggestion
may i ask how to disable kbuild test reboot for s390/x86_64/ia64?
we want support only cross compiler = aarch64-linux-gnu-
and we have test build pass with our patch
>> > > drivers/mfd/Kconfig | 12 +
>> > > drivers/mfd/Makefile | 1 +
>> > > drivers/mfd/mt6360-core.c | 463
>> > > +++++++++++++++++++++++++++++++++++++
>> > > include/linux/mfd/mt6360-private.h | 279 ++++++++++++++++++++++
>> > > include/linux/mfd/mt6360.h | 33 +++
>> > > 5 files changed, 788 insertions(+)
>> > > create mode 100644 drivers/mfd/mt6360-core.c
>> > > create mode 100644 include/linux/mfd/mt6360-private.h
>> > > create mode 100644 include/linux/mfd/mt6360.h
>> >
>
> --
> Lee Jones [李琼斯]
> Linaro Services Technical Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH 01/12] linux-headers: import arm_sdei.h
From: Michael S. Tsirkin @ 2019-09-24 15:39 UTC (permalink / raw)
To: Heyi Guo
Cc: Mark Rutland, Peter Maydell, Marc Zyngier, Cornelia Huck,
qemu-devel, Dave Martin, qemu-arm, James Morse, Paolo Bonzini,
wanghaibin.wang, kvmarm, linux-arm-kernel
In-Reply-To: <1569338511-3572-2-git-send-email-guoheyi@huawei.com>
On Tue, Sep 24, 2019 at 11:21:40PM +0800, Heyi Guo wrote:
> Import Linux header file include/uapi/linux/arm_sdei.h from kernel
> v5.3 release.
>
> This is to prepare for qemu SDEI emulation.
>
> Signed-off-by: Heyi Guo <guoheyi@huawei.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Dave Martin <Dave.Martin@arm.com>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Cornelia Huck <cohuck@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
Some issues with this. First linux-headers is for linux as a host.
This is for linux as a guest, so belongs in include/standard-headers.
Second, please add to scripts/update-linux-headers.sh in a 1st patch,
then add the file in the second patch.
> ---
> linux-headers/linux/arm_sdei.h | 73 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 73 insertions(+)
> create mode 100644 linux-headers/linux/arm_sdei.h
>
> diff --git a/linux-headers/linux/arm_sdei.h b/linux-headers/linux/arm_sdei.h
> new file mode 100644
> index 0000000..af0630b
> --- /dev/null
> +++ b/linux-headers/linux/arm_sdei.h
> @@ -0,0 +1,73 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/* Copyright (C) 2017 Arm Ltd. */
> +#ifndef _UAPI_LINUX_ARM_SDEI_H
> +#define _UAPI_LINUX_ARM_SDEI_H
> +
> +#define SDEI_1_0_FN_BASE 0xC4000020
> +#define SDEI_1_0_MASK 0xFFFFFFE0
> +#define SDEI_1_0_FN(n) (SDEI_1_0_FN_BASE + (n))
> +
> +#define SDEI_1_0_FN_SDEI_VERSION SDEI_1_0_FN(0x00)
> +#define SDEI_1_0_FN_SDEI_EVENT_REGISTER SDEI_1_0_FN(0x01)
> +#define SDEI_1_0_FN_SDEI_EVENT_ENABLE SDEI_1_0_FN(0x02)
> +#define SDEI_1_0_FN_SDEI_EVENT_DISABLE SDEI_1_0_FN(0x03)
> +#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT SDEI_1_0_FN(0x04)
> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE SDEI_1_0_FN(0x05)
> +#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME SDEI_1_0_FN(0x06)
> +#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER SDEI_1_0_FN(0x07)
> +#define SDEI_1_0_FN_SDEI_EVENT_STATUS SDEI_1_0_FN(0x08)
> +#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO SDEI_1_0_FN(0x09)
> +#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET SDEI_1_0_FN(0x0A)
> +#define SDEI_1_0_FN_SDEI_PE_MASK SDEI_1_0_FN(0x0B)
> +#define SDEI_1_0_FN_SDEI_PE_UNMASK SDEI_1_0_FN(0x0C)
> +#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND SDEI_1_0_FN(0x0D)
> +#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E)
> +#define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11)
> +#define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12)
> +
> +#define SDEI_VERSION_MAJOR_SHIFT 48
> +#define SDEI_VERSION_MAJOR_MASK 0x7fff
> +#define SDEI_VERSION_MINOR_SHIFT 32
> +#define SDEI_VERSION_MINOR_MASK 0xffff
> +#define SDEI_VERSION_VENDOR_SHIFT 0
> +#define SDEI_VERSION_VENDOR_MASK 0xffffffff
> +
> +#define SDEI_VERSION_MAJOR(x) (x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK)
> +#define SDEI_VERSION_MINOR(x) (x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK)
> +#define SDEI_VERSION_VENDOR(x) (x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK)
> +
> +/* SDEI return values */
> +#define SDEI_SUCCESS 0
> +#define SDEI_NOT_SUPPORTED -1
> +#define SDEI_INVALID_PARAMETERS -2
> +#define SDEI_DENIED -3
> +#define SDEI_PENDING -5
> +#define SDEI_OUT_OF_RESOURCE -10
> +
> +/* EVENT_REGISTER flags */
> +#define SDEI_EVENT_REGISTER_RM_ANY 0
> +#define SDEI_EVENT_REGISTER_RM_PE 1
> +
> +/* EVENT_STATUS return value bits */
> +#define SDEI_EVENT_STATUS_RUNNING 2
> +#define SDEI_EVENT_STATUS_ENABLED 1
> +#define SDEI_EVENT_STATUS_REGISTERED 0
> +
> +/* EVENT_COMPLETE status values */
> +#define SDEI_EV_HANDLED 0
> +#define SDEI_EV_FAILED 1
> +
> +/* GET_INFO values */
> +#define SDEI_EVENT_INFO_EV_TYPE 0
> +#define SDEI_EVENT_INFO_EV_SIGNALED 1
> +#define SDEI_EVENT_INFO_EV_PRIORITY 2
> +#define SDEI_EVENT_INFO_EV_ROUTING_MODE 3
> +#define SDEI_EVENT_INFO_EV_ROUTING_AFF 4
> +
> +/* and their results */
> +#define SDEI_EVENT_TYPE_PRIVATE 0
> +#define SDEI_EVENT_TYPE_SHARED 1
> +#define SDEI_EVENT_PRIORITY_NORMAL 0
> +#define SDEI_EVENT_PRIORITY_CRITICAL 1
> +
> +#endif /* _UAPI_LINUX_ARM_SDEI_H */
> --
> 1.8.3.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] PM / devfreq: Lock devfreq in trans_stat_show
From: Matthias Kaehlcke @ 2019-09-24 15:44 UTC (permalink / raw)
To: Leonard Crestez
Cc: Artur Świgoń, linux-pm@vger.kernel.org,
Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi, Kyungmin Park,
MyungJoo Ham, dl-linux-imx, Georgi Djakov,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <VI1PR04MB7023BF1AD2C61C8A5ABAD5FEEE840@VI1PR04MB7023.eurprd04.prod.outlook.com>
On Tue, Sep 24, 2019 at 07:44:16AM +0000, Leonard Crestez wrote:
> On 2019-09-24 5:07 AM, Chanwoo Choi wrote:
> >> @@ -1507,16 +1508,22 @@ static ssize_t trans_stat_show(struct device *dev,
> >> struct devfreq *devfreq = to_devfreq(dev);
> >> ssize_t len;
> >> int i, j;
> >> unsigned int max_state = devfreq->profile->max_state;
> >>
> >> - if (!devfreq->stop_polling &&
> >> - devfreq_update_status(devfreq, devfreq->previous_freq))
> >> - return 0;
> >> if (max_state == 0)
> >> return sprintf(buf, "Not Supported.\n");
> >>
> >> + /* lock and update */
> >
> > It is not necessary. Anyone can know that this code is related to mutex lock/unlock.
>
> OK. You're the second person to mention this but it's quite strange to
> see objections raised against comments.
Comments are great if they add value, in this case the comment is
stating the obvious, which IMO just adds noise to the code.
The coding style guidelines also briefly touch this topic:
8) Commenting
-------------
Comments are good, but there is also a danger of over-commenting.
Documentation/process/coding-style.rst
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v10 0/6] mm / virtio: Provide support for unused page reporting
From: Nitesh Narayan Lal @ 2019-09-24 15:51 UTC (permalink / raw)
To: David Hildenbrand, Michal Hocko, Alexander Duyck
Cc: yang.zhang.wz, pagupta, kvm, mst, lcapitulino, linux-mm,
alexander.h.duyck, aarcange, virtio-dev, riel, willy, wei.w.wang,
vbabka, konrad.wilk, dan.j.williams, linux-arm-kernel, osalvador,
dave.hansen, linux-kernel, pbonzini, akpm, mgorman
In-Reply-To: <d2a7acdd-3bb9-05c9-42d0-70a500801cd6@redhat.com>
On 9/24/19 11:32 AM, David Hildenbrand wrote:
> On 24.09.19 16:23, Michal Hocko wrote:
>> On Wed 18-09-19 10:52:25, Alexander Duyck wrote:
>> [...]
>>> In order to try and keep the time needed to find a non-reported page to
>>> a minimum we maintain a "reported_boundary" pointer. This pointer is used
>>> by the get_unreported_pages iterator to determine at what point it should
>>> resume searching for non-reported pages. In order to guarantee pages do
>>> not get past the scan I have modified add_to_free_list_tail so that it
>>> will not insert pages behind the reported_boundary.
>>>
>>> If another process needs to perform a massive manipulation of the free
>>> list, such as compaction, it can either reset a given individual boundary
>>> which will push the boundary back to the list_head, or it can clear the
>>> bit indicating the zone is actively processing which will result in the
>>> reporting process resetting all of the boundaries for a given zone.
>> Is this any different from the previous version? The last review
>> feedback (both from me and Mel) was that we are not happy to have an
>> externally imposed constrains on how the page allocator is supposed to
>> maintain its free lists.
>>
>> If this is really the only way to go forward then I would like to hear
>> very convincing arguments about other approaches not being feasible.
> Adding to what Alexander said, I don't consider the other approaches
> (especially the bitmap-based approach Nitesh is currently working on)
> infeasible. There might be more rough edges (e.g., sparse zones) and
> eventually sometimes a little more work to be done, but definitely
> feasible. Incorporating stuff into the buddy might make some tasks
> (e.g., identify free pages) more efficient.
My plan was to get a framework ready which can perform decently and
is acceptable upstream (keeping core-mm changes to a minimum) and then keep
optimizing it for different use-cases.
Indeed, the bitmap-based approach may not be efficient for every available use
case. But then I am not sure if we want to target that, considering it may require
mm-changes.
> I still somewhat like the idea of capturing hints of free pages (in
> whatever data structure) and then going over the hints, seeing if the
> pages are still free. Then only temporarily isolating the still-free
> pages, reporting them, and un-isolating them after they were reported. I
> like the idea that the pages are not fake-allocated but only temporarily
> blocked. That works nicely e.g., with the movable zone (contain only
> movable data).
>
> But anyhow, after decades of people working on free page
> hinting/reporting, I am happy with anything that gets accepted upstream :D
+1
>
--
Nitesh
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 0/6] Add the Mobiveil EP and Layerscape Gen4 EP driver support
From: Russell King - ARM Linux admin @ 2019-09-24 15:52 UTC (permalink / raw)
To: Xiaowei Bao
Cc: mark.rutland, devicetree, lorenzo.pieralisi, linux-pci,
Zhiqiang.Hou, linux-kernel, leoyang.li, Minghuan.Lian, robh+dt,
mingkai.hu, bhelgaas, andrew.murray, kishon, shawnguo,
linux-arm-kernel
In-Reply-To: <20190924141847.GW25745@shell.armlinux.org.uk>
On Tue, Sep 24, 2019 at 03:18:47PM +0100, Russell King - ARM Linux admin wrote:
> On Mon, Sep 16, 2019 at 10:17:36AM +0800, Xiaowei Bao wrote:
> > This patch set are for adding Mobiveil EP driver and adding PCIe Gen4
> > EP driver of NXP Layerscape platform.
> >
> > This patch set depends on:
> > https://patchwork.kernel.org/project/linux-pci/list/?series=159139
> >
> > Xiaowei Bao (6):
> > PCI: mobiveil: Add the EP driver support
> > dt-bindings: Add DT binding for PCIE GEN4 EP of the layerscape
> > PCI: mobiveil: Add PCIe Gen4 EP driver for NXP Layerscape SoCs
> > PCI: mobiveil: Add workaround for unsupported request error
> > arm64: dts: lx2160a: Add PCIe EP node
> > misc: pci_endpoint_test: Add the layerscape PCIe GEN4 EP device
> > support
> >
> > .../bindings/pci/layerscape-pcie-gen4.txt | 28 +-
> > MAINTAINERS | 3 +
> > arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 56 ++
> > drivers/misc/pci_endpoint_test.c | 2 +
> > drivers/pci/controller/mobiveil/Kconfig | 22 +-
> > drivers/pci/controller/mobiveil/Makefile | 2 +
> > .../controller/mobiveil/pcie-layerscape-gen4-ep.c | 169 ++++++
> > drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c | 568 +++++++++++++++++++++
> > drivers/pci/controller/mobiveil/pcie-mobiveil.c | 99 +++-
> > drivers/pci/controller/mobiveil/pcie-mobiveil.h | 72 +++
> > 10 files changed, 1009 insertions(+), 12 deletions(-)
> > create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
> > create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-ep.c
>
> Hi,
>
> I've applied "PCI: mobiveil: Fix the CPU base address setup in inbound
> window" and your patch set to 5.3, which seems to be able to detect the
> PCIe card I have plugged in:
>
> layerscape-pcie-gen4 3800000.pcie: host bridge /soc/pcie@3800000 ranges:
> layerscape-pcie-gen4 3800000.pcie: MEM 0xa040000000..0xa07fffffff -> 0x40000000
> layerscape-pcie-gen4 3800000.pcie: PCI host bridge to bus 0000:00
> pci_bus 0000:00: root bus resource [bus 00-ff]
> pci_bus 0000:00: root bus resource [mem 0xa040000000-0xa07fffffff] (bus address
> [0x40000000-0x7fffffff])
> pci 0000:00:00.0: [1957:8d90] type 01 class 0x060400
> pci 0000:00:00.0: enabling Extended Tags
> pci 0000:00:00.0: supports D1 D2
> pci 0000:00:00.0: PME# supported from D0 D1 D2 D3hot D3cold
> pci 0000:01:00.0: [15b3:6750] type 00 class 0x020000
> pci 0000:01:00.0: reg 0x10: [mem 0xa040000000-0xa0400fffff 64bit]
> pci 0000:01:00.0: reg 0x18: [mem 0xa040800000-0xa040ffffff 64bit pref]
> pci 0000:01:00.0: reg 0x30: [mem 0xa041000000-0xa0410fffff pref]
> pci 0000:00:00.0: up support 3 enabled 0
> pci 0000:00:00.0: dn support 1 enabled 0
> pci 0000:00:00.0: BAR 9: assigned [mem 0xa040000000-0xa0407fffff 64bit pref]
> pci 0000:00:00.0: BAR 8: assigned [mem 0xa040800000-0xa0409fffff]
> pci 0000:01:00.0: BAR 2: assigned [mem 0xa040000000-0xa0407fffff 64bit pref]
> pci 0000:01:00.0: BAR 0: assigned [mem 0xa040800000-0xa0408fffff 64bit]
> pci 0000:01:00.0: BAR 6: assigned [mem 0xa040900000-0xa0409fffff pref]
> pci 0000:00:00.0: PCI bridge to [bus 01-ff]
> pci 0000:00:00.0: bridge window [mem 0xa040800000-0xa0409fffff]
> pci 0000:00:00.0: bridge window [mem 0xa040000000-0xa0407fffff 64bit pref]
> pci 0000:00:00.0: Max Payload Size set to 256/ 256 (was 128), Max Read Rq 256pci 0000:01:00.0: Max Payload Size set to 256/ 256 (was 128), Max Read Rq 256pcieport 0000:00:00.0: PCIe capabilities: 0x13
> pcieport 0000:00:00.0: init_service_irqs: -19
>
> However, a bit later in the kernel boot, I get:
>
> SError Interrupt on CPU1, code 0xbf000002 -- SError
> CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.3.0+ #392
> Hardware name: SolidRun LX2160A COM express type 7 module (DT)
> pstate: 60400085 (nZCv daIf +PAN -UAO)
> pc : pci_generic_config_read+0xb0/0xc0
> lr : pci_generic_config_read+0x1c/0xc0
> sp : ffffff8010f9baf0
> x29: ffffff8010f9baf0 x28: ffffff8010d620a0
> x27: ffffff8010d79000 x26: ffffff8010d62000
> x25: ffffff8010cb06d4 x24: 0000000000000000
> x23: ffffff8010e499b8 x22: ffffff8010f9bbaf
> x21: 0000000000000000 x20: ffffffe2eda11800
> x19: ffffff8010f62158 x18: ffffff8010bdede0
> x17: ffffff8010bdede8 x16: ffffff8010b96970
> x15: ffffffffffffffff x14: ffffffffff000000
> x13: ffffffffffffffff x12: 0000000000000030
> x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f
> x9 : 2dff716475687163 x8 : ffffffffffffffff
> x7 : fefefefefefefefe x6 : 0000000000000000
> x5 : 0000000000000000 x4 : ffffff8010f9bb6c
> x3 : 0000000000000001 x2 : 0000000000000003
> x1 : 0000000000000000 x0 : 0000000000000000
> Kernel panic - not syncing: Asynchronous SError Interrupt
> CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.3.0+ #392
> Hardware name: SolidRun LX2160A COM express type 7 module (DT)
> Call trace:
> dump_backtrace+0x0/0x120
> show_stack+0x14/0x1c
> dump_stack+0x9c/0xc0
> panic+0x148/0x34c
> print_tainted+0x0/0xa8
> arm64_serror_panic+0x74/0x80
> do_serror+0x8c/0x13c
> el1_error+0xbc/0x160
> pci_generic_config_read+0xb0/0xc0
> pci_bus_read_config_byte+0x64/0x90
> pci_read_config_byte+0x40/0x48
> pci_assign_irq+0x34/0xc8
> pci_device_probe+0x28/0x148
> really_probe+0x1c4/0x2d0
> driver_probe_device+0x58/0xfc
> device_driver_attach+0x68/0x70
> __driver_attach+0x94/0xdc
> bus_for_each_dev+0x50/0xa0
> driver_attach+0x20/0x28
> bus_add_driver+0x14c/0x200
> driver_register+0x6c/0x124
> __pci_register_driver+0x48/0x50
> mlx4_init+0x154/0x180
> do_one_initcall+0x30/0x250
> kernel_init_freeable+0x23c/0x32c
> kernel_init+0x10/0xfc
> ret_from_fork+0x10/0x18
> SMP: stopping secondary CPUs
> Kernel Offset: disabled
> CPU features: 0x0002,21006008
> Memory Limit: none
>
> and there it dies. Any ideas?
The failing access seems to be:
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
for the Mellanox Ethernet card. Presumably, being a PCIe ethernet
card, it doesn't implement this register (just a guess), and aborts
the PCI transaction, which is presumably triggering the above SError.
Note that I've used this card with the Macchiatobin (Armada 8040)
without issue.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [v3,3/3] Documentation: dt: binding: fsl: Add 'fsl,ippdexpcr-alt-addr' property
From: Leo Li @ 2019-09-24 15:58 UTC (permalink / raw)
To: Biwen Li, shawnguo@kernel.org, robh+dt@kernel.org,
mark.rutland@arm.com, Ran Wang
Cc: devicetree@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Biwen Li
In-Reply-To: <20190924024548.4356-3-biwen.li@nxp.com>
> -----Original Message-----
> From: Biwen Li <biwen.li@nxp.com>
> Sent: Monday, September 23, 2019 9:46 PM
> To: Leo Li <leoyang.li@nxp.com>; shawnguo@kernel.org;
> robh+dt@kernel.org; mark.rutland@arm.com; Ran Wang
> <ran.wang_1@nxp.com>
> Cc: linuxppc-dev@lists.ozlabs.org; linux-arm-kernel@lists.infradead.org;
> linux-kernel@vger.kernel.org; devicetree@vger.kernel.org; Biwen Li
> <biwen.li@nxp.com>
> Subject: [v3,3/3] Documentation: dt: binding: fsl: Add 'fsl,ippdexpcr-alt-addr'
> property
>
> The 'fsl,ippdexpcr-alt-addr' property is used to handle an errata A-008646 on
> LS1021A
>
> Signed-off-by: Biwen Li <biwen.li@nxp.com>
> ---
> Change in v3:
> - rename property name
> fsl,rcpm-scfg -> fsl,ippdexpcr-alt-addr
>
> Change in v2:
> - update desc of the property 'fsl,rcpm-scfg'
>
> Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 14
> ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
> b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
> index 5a33619d881d..157dcf6da17c 100644
> --- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
> +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
> @@ -34,6 +34,11 @@ Chassis Version Example Chips
> Optional properties:
> - little-endian : RCPM register block is Little Endian. Without it RCPM
> will be Big Endian (default case).
> + - fsl,ippdexpcr-alt-addr : Must add the property for SoC LS1021A,
You probably should mention this is related to a hardware issue on LS1021a and only needed on LS1021a.
> + Must include n + 1 entries (n = #fsl,rcpm-wakeup-cells, such as:
> + #fsl,rcpm-wakeup-cells equal to 2, then must include 2 + 1 entries).
#fsl,rcpm-wakeup-cells is the number of IPPDEXPCR registers on an SoC. However you are defining an offset to scfg registers here. Why these two are related? The length here should actually be related to the #address-cells of the soc/. But since this is only needed for LS1021, you can just make it 3.
> + The first entry must be a link to the SCFG device node.
> + The non-first entry must be offset of registers of SCFG.
>
> Example:
> The RCPM node for T4240:
> @@ -43,6 +48,15 @@ The RCPM node for T4240:
> #fsl,rcpm-wakeup-cells = <2>;
> };
>
> +The RCPM node for LS1021A:
> + rcpm: rcpm@1ee2140 {
> + compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
> + reg = <0x0 0x1ee2140 0x0 0x8>;
> + #fsl,rcpm-wakeup-cells = <2>;
> + fsl,ippdexpcr-alt-addr = <&scfg 0x0 0x51c>; /*
> SCFG_SPARECR8 */
> + };
> +
> +
> * Freescale RCPM Wakeup Source Device Tree Bindings
> -------------------------------------------
> Required fsl,rcpm-wakeup property should be added to a device node if the
> device
> --
> 2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCHv6 0/2] Variscite DART-6UL SoM support
From: Oliver Graute @ 2019-09-24 16:20 UTC (permalink / raw)
To: shawnguo
Cc: Mark Rutland, devicetree, narmstrong, Sascha Hauer, m.felsch,
linux-kernel, oliver.graute, Rob Herring, NXP Linux Team,
Pengutronix Kernel Team, Fabio Estevam, linux-arm-kernel
Need feedback to the following patches which adds support for a DART-6UL Board
Need feedback if the division between customboard and SoM is done right
Need some feedback why ethernet RX is not working the right way. RX is deaf.
Need feedback howto document propertys and compatible the right way
Product Page: https://www.variscite.com/product/evaluation-kits/dart-6ul-kits
Oliver Graute (2):
ARM: dts: imx6ul: Add Variscite DART-6UL SoM support
ARM: dts: Add support for i.MX6 UltraLite DART Variscite Customboard
arch/arm/boot/dts/Makefile | 1 +
.../boot/dts/imx6ul-imx6ull-var-dart-common.dtsi | 445 +++++++++++++++++++++
arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts | 196 +++++++++
3 files changed, 642 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6ul-imx6ull-var-dart-common.dtsi
create mode 100644 arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCHv6 1/2] ARM: dts: imx6ul: Add Variscite DART-6UL SoM support
From: Oliver Graute @ 2019-09-24 16:20 UTC (permalink / raw)
To: shawnguo
Cc: Mark Rutland, devicetree, narmstrong, Sascha Hauer, m.felsch,
linux-kernel, oliver.graute, Rob Herring, NXP Linux Team,
Pengutronix Kernel Team, Fabio Estevam, linux-arm-kernel
In-Reply-To: <1569342022-15901-1-git-send-email-oliver.graute@gmail.com>
This patch adds support for the i.MX6UL variant of the Variscite DART-6UL
SoM Carrier-Board
Signed-off-by: Oliver Graute <oliver.graute@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v6:
- renamed touch regulator
- renamed rmii clock
- moved some muxing to baseboard
- added pinctrl for gpio key
- added bus-width to usdhc1
- fixed missing subnode on partitions
.../boot/dts/imx6ul-imx6ull-var-dart-common.dtsi | 381 +++++++++++++++++++++
1 file changed, 381 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6ul-imx6ull-var-dart-common.dtsi
diff --git a/arch/arm/boot/dts/imx6ul-imx6ull-var-dart-common.dtsi b/arch/arm/boot/dts/imx6ul-imx6ull-var-dart-common.dtsi
new file mode 100644
index 00000000..c91b2c6
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-imx6ull-var-dart-common.dtsi
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/dts-v1/;
+
+#include "imx6ul.dtsi"
+/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>;
+ };
+
+ clk_rmii_ref: clock-rmii-ref {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ clock-output-names = "rmii-ref";
+ };
+
+ reg_touch_3v3: regulator-touch-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "touch_3v3_supply";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_sd1_vmmc: regulator-sd1-vmmc {
+ compatible = "regulator-fixed";
+ regulator-name = "VSD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_gpio_dvfs: regulator-gpio {
+ compatible = "regulator-gpio";
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "gpio_dvfs";
+ regulator-type = "voltage";
+ gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ states = <1300000 0x1 1400000 0x0>;
+ };
+};
+
+&cpu0 {
+ arm-supply = <®_arm>;
+ soc-supply = <®_soc>;
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ phy-mode = "rmii";
+ phy-reset-gpios=<&gpio5 0 1>;
+ phy-reset-duration=<100>;
+ phy-reset-on-resume;
+ phy-handle = <ðphy0>;
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
+ phy-mode = "rmii";
+ phy-handle = <ðphy1>;
+ phy-reset-gpios=<&gpio1 10 1>;
+ phy-reset-duration=<100>;
+ phy-reset-on-resume;
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ micrel,rmii-reference-clock-select-25-mhz;
+ clocks = <&clk_rmii_ref>;
+ clock-names = "rmii-ref";
+ reg = <1>;
+ };
+
+ ethphy1: ethernet-phy@3 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ micrel,rmii-reference-clock-select-25-mhz;
+ clocks = <&clk_rmii_ref>;
+ clock-names = "rmii-ref";
+ reg = <3>;
+ };
+ };
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ status = "okay";
+
+ nand@0 {
+
+ partition@0 {
+ label = "spl";
+ reg = <0x00000000 0x00200000>;
+ };
+
+ partition@200000 {
+ label = "uboot";
+ reg = <0x00200000 0x00200000>;
+ };
+
+ partition@400000 {
+ label = "uboot-env";
+ reg = <0x00400000 0x00200000>;
+ };
+
+ partition@600000 {
+ label = "kernel";
+ reg = <0x00600000 0x00800000>;
+ };
+
+ partition@e00000 {
+ label = "rootfs";
+ reg = <0x00e00000 0x3f200000>;
+ };
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+};
+
+&sai2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai2>;
+ assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
+ <&clks IMX6UL_CLK_SAI2>;
+ assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
+ assigned-clock-rates = <0>, <12288000>;
+ fsl,sai-mclk-direction-output;
+ status = "okay";
+};
+
+&snvs_poweroff {
+ status = "okay";
+};
+
+&snvs_rtc {
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ uart-has-rtscts;
+};
+
+&usdhc1 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+ bus-width = <4>;
+ no-1-8-v;
+ keep-power-in-suspend;
+ vmmc-supply = <®_sd1_vmmc>;
+ non-removable;
+ status = "okay";
+};
+
+&wdog1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdog>;
+ fsl,ext-reset-output;
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog>;
+
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
+ MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
+ MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
+ MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
+ MX6UL_PAD_JTAG_MOD__GPIO1_IO10 0x1b0b0
+ >;
+ };
+
+ pinctrl_flexcan1: flexcan1grp{
+ fsl,pins = <
+ MX6UL_PAD_LCD_DATA09__FLEXCAN1_RX 0x1b020
+ MX6UL_PAD_LCD_DATA08__FLEXCAN1_TX 0x1b020
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp{
+ fsl,pins = <
+ MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020
+ MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020
+ >;
+ };
+
+ pinctrl_gpio_keys: gpio_keysgrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x17059
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6UL_PAD_CSI_HSYNC__GPIO4_IO20 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpminandgrp {
+ fsl,pins = <
+ MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1
+ MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1
+ MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1
+ MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000
+ MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1
+ MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1
+ MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1
+ MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1
+ MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1
+ MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1
+ MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1
+ MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1
+ MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1
+ MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1
+ MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1
+ MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_hog: hoggrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO03__OSC32K_32K_OUT 0x03029
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
+ MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
+ MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
+ >;
+ };
+
+ pinctrl_lcdif: lcdif {
+ fsl,pins = <
+ MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79
+ MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79
+ MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79
+ MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79
+ MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79
+ MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79
+ MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79
+ MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79
+ MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79
+ MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79
+ MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79
+ MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79
+ MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79
+ MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79
+ MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79
+ MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79
+ MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79
+ MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79
+ MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79
+ MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6UL_PAD_LCD_DATA00__PWM1_OUT 0x110b0
+ >;
+ };
+
+ pinctrl_sai2: sai2grp {
+ fsl,pins = <
+ MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK 0x17088
+ MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC 0x17088
+ MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088
+ MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA 0x11088
+ MX6UL_PAD_JTAG_TMS__SAI2_MCLK 0x17088
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
+ MX6UL_PAD_UART2_CTS_B__UART2_DCE_CTS 0x1b0b1
+ MX6UL_PAD_UART2_RTS_B__UART2_DCE_RTS 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1
+ MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1
+ MX6UL_PAD_UART3_CTS_B__UART3_DCE_CTS 0x1b0b1
+ MX6UL_PAD_UART3_RTS_B__UART3_DCE_RTS 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x17059
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059
+ MX6UL_PAD_CSI_VSYNC__GPIO4_IO19 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
+ MX6UL_PAD_CSI_VSYNC__GPIO4_IO19 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+ fsl,pins = <
+ MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9
+ MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9
+ MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
+ MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
+ MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
+ MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
+ MX6UL_PAD_CSI_VSYNC__GPIO4_IO19 0x1b0b1
+ >;
+ };
+
+ pinctrl_wdog: wdoggrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO08__WDOG1_WDOG_B 0x78b0
+ >;
+ };
+};
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv6 2/2] ARM: dts: Add support for i.MX6 UltraLite DART Variscite Customboard
From: Oliver Graute @ 2019-09-24 16:20 UTC (permalink / raw)
To: shawnguo
Cc: Mark Rutland, devicetree, narmstrong, Sascha Hauer, m.felsch,
linux-kernel, oliver.graute, Rob Herring, NXP Linux Team,
Pengutronix Kernel Team, Fabio Estevam, linux-arm-kernel
In-Reply-To: <1569342022-15901-1-git-send-email-oliver.graute@gmail.com>
This patch adds DeviceTree Source for the i.MX6 UltraLite DART NAND/WIFI
Signed-off-by: Oliver Graute <oliver.graute@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v6:
- added some muxing
- added codec in sound node
- added adc1 node
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts | 221 ++++++++++++++++++++++++
2 files changed, 222 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index a24a6a1..a2a69e4 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -579,6 +579,7 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-tx6ul-0010.dtb \
imx6ul-tx6ul-0011.dtb \
imx6ul-tx6ul-mainboard.dtb \
+ imx6ul-var-6ulcustomboard.dtb \
imx6ull-14x14-evk.dtb \
imx6ull-colibri-eval-v3.dtb \
imx6ull-colibri-wifi-eval-v3.dtb \
diff --git a/arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts b/arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts
new file mode 100644
index 00000000..031d8d4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-var-6ulcustomboard.dts
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Support for Variscite DART-6UL Module
+ *
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2015-2016 Variscite Ltd. - http://www.variscite.com
+ * Copyright (C) 2018-2019 Oliver Graute <oliver.graute@gmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include "imx6ul-imx6ull-var-dart-common.dtsi"
+
+/ {
+ model = "Variscite i.MX6 UltraLite Carrier-board";
+ compatible = "variscite,6ulcustomboard", "fsl,imx6ul";
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 20000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <6>;
+ status = "okay";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ user {
+ gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_BACK>;
+ gpio-key,wakeup;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ d16-led {
+ gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "wm8731audio";
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Line", "Line Jack",
+ "Microphone", "Mic Jack";
+ simple-audio-card,routing =
+ "Headphone Jack", "RHPOUT",
+ "Headphone Jack", "LHPOUT",
+ "LLINEIN", "Line Jack",
+ "RLINEIN", "Line Jack",
+ "MICIN", "Mic Bias",
+ "Mic Bias", "Mic Jack";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&codec_dai>;
+ simple-audio-card,frame-master = <&codec_dai>;
+
+ cpu_dai: simple-audio-card,cpu {
+ sound-dai = <&sai2>;
+ };
+
+ codec_dai: simple-audio-card,codec {
+ sound-dai = <&wm8731>;
+ system-clock-frequency = <12288000>;
+ };
+ };
+};
+
+&adc1 {
+ vref-supply = <®_touch_3v3>;
+ status = "okay";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ status = "okay";
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock_frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ wm8731: audio-codec@1a {
+ compatible = "wlf,wm8731";
+ reg = <0x1a>;
+ #sound-dai-cells = <0>;
+ clocks = <&clks IMX6UL_CLK_SAI2>;
+ clock-names = "mclk";
+ };
+
+ touchscreen@38 {
+ compatible = "edt,edt-ft5x06";
+ reg = <0x38>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <4 IRQ_TYPE_NONE>;
+ touchscreen-size-x = <800>;
+ touchscreen-size-y = <480>;
+ touchscreen-inverted-x;
+ touchscreen-inverted-y;
+ wakeup-source;
+ };
+
+ rtc@68 {
+ compatible = "dallas,ds1337";
+ reg = <0x68>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rtc>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+&lcdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcdif>;
+ display = <&display0>;
+ status = "okay";
+
+ display0: display0 {
+ bits-per-pixel = <16>;
+ bus-width = <24>;
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing0 {
+ clock-frequency =<35000000>;
+ hactive = <800>;
+ vactive = <480>;
+ hfront-porch = <40>;
+ hback-porch = <40>;
+ hsync-len = <48>;
+ vback-porch = <29>;
+ vfront-porch = <13>;
+ vsync-len = <3>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <0>;
+ };
+ };
+ };
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
+&usbotg1 {
+ disable-over-current;
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbotg2 {
+ disable-over-current;
+ dr_mode = "host";
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_rtc: rtcgrp {
+ fsl,pins = <
+ MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x1b0b0
+ >;
+ };
+};
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v8 3/3] mm: fix double page fault on arm64 if PTE_AF is cleared
From: Catalin Marinas @ 2019-09-24 16:35 UTC (permalink / raw)
To: Jia He
Cc: Mark Rutland, Kaly Xin (Arm Technology China), Ralph Campbell,
Justin He (Arm Technology China), Andrew Morton, Suzuki Poulose,
Marc Zyngier, Anshuman Khandual, linux-kernel@vger.kernel.org,
Matthew Wilcox, linux-mm@kvack.org, Jérôme Glisse,
James Morse, linux-arm-kernel@lists.infradead.org, Punit Agrawal,
Thomas Gleixner, nd, Will Deacon, Alex Van Brunt,
Kirill A. Shutemov, Robin Murphy
In-Reply-To: <6267b685-5162-85ac-087f-112303bb7035@gmail.com>
On Tue, Sep 24, 2019 at 11:29:07PM +0800, Jia He wrote:
> On 2019/9/24 18:33, Catalin Marinas wrote:
> > On Tue, Sep 24, 2019 at 06:43:06AM +0000, Justin He (Arm Technology China) wrote:
> > > Catalin Marinas wrote:
> > > > On Sat, Sep 21, 2019 at 09:50:54PM +0800, Jia He wrote:
> > > > > /*
> > > > > * This really shouldn't fail, because the page is there
> > > > > * in the page tables. But it might just be unreadable,
> > > > > * in which case we just give up and fill the result with
> > > > > * zeroes.
> > > > > */
> > > > > - if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
> > > > > + if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
> > > > > + /* Give a warn in case there can be some obscure
> > > > > + * use-case
> > > > > + */
> > > > > + WARN_ON_ONCE(1);
> > > > That's more of a question for the mm guys: at this point we do the
> > > > copying with the ptl released; is there anything else that could have
> > > > made the pte old in the meantime? I think unuse_pte() is only called on
> > > > anonymous vmas, so it shouldn't be the case here.
> >
> > If we need to hold the ptl here, you could as well have an enclosing
> > kmap/kunmap_atomic (option 2) with some goto instead of "return false".
>
> I am not 100% sure that I understand your suggestion well, so I
> drafted the patch
Well, however you think the code is cleaner really.
The copy/paste didn't work well, tabs disappeared (or rather the
Exchange server corrupting outgoing emails) but I'll try to comment
below:
> -static inline void cow_user_page(struct page *dst, struct page *src,
> unsigned long va, struct vm_area_struct *vma)
> +static inline bool cow_user_page(struct page *dst, struct page *src,
> + struct vm_fault *vmf)
> {
> + struct vm_area_struct *vma = vmf->vma;
> + struct mm_struct *mm = vma->vm_mm;
> + unsigned long addr = vmf->address;
> + bool ret;
> + pte_t entry;
> + void *kaddr;
> + void __user *uaddr;
> +
> debug_dma_assert_idle(src);
>
> + if (likely(src)) {
> + copy_user_highpage(dst, src, addr, vma);
> + return true;
> + }
> +
> /*
> * If the source page was a PFN mapping, we don't have
> * a "struct page" for it. We do a best-effort copy by
> * just copying from the original user address. If that
> * fails, we just zero-fill it. Live with it.
> */
> - if (unlikely(!src)) {
> - void *kaddr = kmap_atomic(dst);
> - void __user *uaddr = (void __user *)(va & PAGE_MASK);
> + kaddr = kmap_atomic(dst);
> + uaddr = (void __user *)(addr & PAGE_MASK);
> +
> + /*
> + * On architectures with software "accessed" bits, we would
> + * take a double page fault, so mark it accessed here.
> + */
> + vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
> + if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
I'd move the pte_offset_map_lock() inside the 'if' block as we don't
want to affect architectures that handle old ptes automatically.
> + if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
> + /*
> + * Other thread has already handled the fault
> + * and we don't need to do anything. If it's
> + * not the case, the fault will be triggered
> + * again on the same address.
> + */
> + ret = false;
> + goto pte_unlock;
> + }
> +
> + entry = pte_mkyoung(vmf->orig_pte);
> + if (ptep_set_access_flags(vma, addr, vmf->pte, entry, 0))
> + update_mmu_cache(vma, addr, vmf->pte);
> + }
>
> + /*
> + * This really shouldn't fail, because the page is there
> + * in the page tables. But it might just be unreadable,
> + * in which case we just give up and fill the result with
> + * zeroes.
> + */
> + if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
> /*
> - * This really shouldn't fail, because the page is there
> - * in the page tables. But it might just be unreadable,
> - * in which case we just give up and fill the result with
> - * zeroes.
> + * Give a warn in case there can be some obscure
> + * use-case
> */
> - if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
> - clear_page(kaddr);
> - kunmap_atomic(kaddr);
> - flush_dcache_page(dst);
> - } else
> - copy_user_highpage(dst, src, va, vma);
> + WARN_ON_ONCE(1);
> + clear_page(kaddr);
> + }
> +
> + ret = true;
> +
> +pte_unlock:
> + pte_unmap_unlock(vmf->pte, vmf->ptl);
Since the locking would be moved in the 'if' block above, we need
another check here before unlocking:
if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte))
pte_unmap_unlock(vmf->pte, vmf->ptl);
You could probably replace the two calls to arch_faults_on_old_pte()
with a single bool variable initialisation, something like:
force_mkyoung = arch_faults_on_old_pte() &&
!pte_young(vmf->orig_pte)
and only check for "if (force_mkyoung)" in both cases.
> + kunmap_atomic(kaddr);
> + flush_dcache_page(dst);
> +
> + return ret;
> }
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] ARM: OMAP2+: Fix missing reset done flag for am3 and am43
From: Tony Lindgren @ 2019-09-24 16:36 UTC (permalink / raw)
To: linux-omap; +Cc: linux-arm-kernel
For ti,sysc-omap4 compatible devices with no sysstatus register, we do have
reset done status available in the SOFTRESET bit that clears when the reset
is done. This is documented for example in am437x TRM for DMTIMER_TIOCP_CFG
register. The am335x TRM just says that SOFTRESET bit value 1 means reset is
ongoing, but it behaves the same way clearing after reset is done.
With the ti-sysc driver handling this automatically based on no sysstatus
register defined, we see warnings if SYSC_HAS_RESET_STATUS is missing in the
legacy platform data:
ti-sysc 48042000.target-module: sysc_flags 00000222 != 00000022
ti-sysc 48044000.target-module: sysc_flags 00000222 != 00000022
ti-sysc 48046000.target-module: sysc_flags 00000222 != 00000022
...
Let's fix these warnings by adding SYSC_HAS_RESET_STATUS. Let's also
remove the useless parentheses while at it.
If it turns out we do have ti,sysc-omap4 compatible devices without a
working SOFTRESET bit we can set up additional quirk handling for it.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -811,7 +811,8 @@ static struct omap_hwmod_class_sysconfig am33xx_timer_sysc = {
.rev_offs = 0x0000,
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .sysc_flags = SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_RESET_STATUS,
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
SIDLE_SMART_WKUP),
.sysc_fields = &omap_hwmod_sysc_type2,
--
2.23.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/6] PCI: mobiveil: Add PCIe Gen4 EP driver for NXP Layerscape SoCs
From: Russell King - ARM Linux admin @ 2019-09-24 16:38 UTC (permalink / raw)
To: Xiaowei Bao
Cc: mark.rutland, devicetree, lorenzo.pieralisi, linux-pci,
Zhiqiang.Hou, linux-kernel, leoyang.li, Minghuan.Lian, robh+dt,
linux-arm-kernel, bhelgaas, andrew.murray, kishon, shawnguo,
mingkai.hu
In-Reply-To: <20190916021742.22844-4-xiaowei.bao@nxp.com>
On Mon, Sep 16, 2019 at 10:17:39AM +0800, Xiaowei Bao wrote:
> This PCIe controller is based on the Mobiveil GPEX IP, it work in EP
> mode if select this config opteration.
>
> Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
> ---
> MAINTAINERS | 2 +
> drivers/pci/controller/mobiveil/Kconfig | 17 ++-
> drivers/pci/controller/mobiveil/Makefile | 1 +
> .../controller/mobiveil/pcie-layerscape-gen4-ep.c | 156 +++++++++++++++++++++
> 4 files changed, 173 insertions(+), 3 deletions(-)
> create mode 100644 drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b997056..0858b54 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -12363,11 +12363,13 @@ F: drivers/pci/controller/dwc/*layerscape*
>
> PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER
> M: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> +M: Xiaowei Bao <xiaowei.bao@nxp.com>
> L: linux-pci@vger.kernel.org
> L: linux-arm-kernel@lists.infradead.org
> S: Maintained
> F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
> F: drivers/pci/controller/mobibeil/pcie-layerscape-gen4.c
> +F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
>
> PCI DRIVER FOR GENERIC OF HOSTS
> M: Will Deacon <will@kernel.org>
> diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
> index 2054950..0696b6e 100644
> --- a/drivers/pci/controller/mobiveil/Kconfig
> +++ b/drivers/pci/controller/mobiveil/Kconfig
> @@ -27,13 +27,24 @@ config PCIE_MOBIVEIL_PLAT
> for address translation and it is a PCIe Gen4 IP.
>
> config PCIE_LAYERSCAPE_GEN4
> - bool "Freescale Layerscape PCIe Gen4 controller"
> + bool "Freescale Layerscpe PCIe Gen4 controller in RC mode"
> depends on PCI
> depends on OF && (ARM64 || ARCH_LAYERSCAPE)
> depends on PCI_MSI_IRQ_DOMAIN
> select PCIE_MOBIVEIL_HOST
> help
> Say Y here if you want PCIe Gen4 controller support on
> - Layerscape SoCs. The PCIe controller can work in RC or
> - EP mode according to RCW[HOST_AGT_PEX] setting.
> + Layerscape SoCs. And the PCIe controller work in RC mode
> + by setting the RCW[HOST_AGT_PEX] to 0.
> +
> +config PCIE_LAYERSCAPE_GEN4_EP
> + bool "Freescale Layerscpe PCIe Gen4 controller in EP mode"
> + depends on PCI
> + depends on OF && (ARM64 || ARCH_LAYERSCAPE)
> + depends on PCI_ENDPOINT
> + select PCIE_MOBIVEIL_EP
> + help
> + Say Y here if you want PCIe Gen4 controller support on
> + Layerscape SoCs. And the PCIe controller work in EP mode
> + by setting the RCW[HOST_AGT_PEX] to 1.
> endmenu
> diff --git a/drivers/pci/controller/mobiveil/Makefile b/drivers/pci/controller/mobiveil/Makefile
> index 686d41f..6f54856 100644
> --- a/drivers/pci/controller/mobiveil/Makefile
> +++ b/drivers/pci/controller/mobiveil/Makefile
> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
> obj-$(CONFIG_PCIE_MOBIVEIL_EP) += pcie-mobiveil-ep.o
> obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
> obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie-layerscape-gen4.o
> +obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4_EP) += pcie-layerscape-gen4-ep.o
> diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
> new file mode 100644
> index 0000000..7bfec51
> --- /dev/null
> +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4-ep.c
> @@ -0,0 +1,156 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCIe controller EP driver for Freescale Layerscape SoCs
> + *
> + * Copyright (C) 2019 NXP Semiconductor.
> + *
> + * Author: Xiaowei Bao <xiaowei.bao@nxp.com>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/resource.h>
> +
> +#include "pcie-mobiveil.h"
> +
> +#define PCIE_LX2_BAR_NUM 4
> +
> +#define to_ls_pcie_g4_ep(x) dev_get_drvdata((x)->dev)
> +
> +struct ls_pcie_g4_ep {
> + struct mobiveil_pcie *mv_pci;
> +};
> +
> +static const struct of_device_id ls_pcie_g4_ep_of_match[] = {
> + { .compatible = "fsl,lx2160a-pcie-ep",},
> + { },
> +};
> +
> +static const struct pci_epc_features ls_pcie_g4_epc_features = {
> + .linkup_notifier = false,
> + .msi_capable = true,
> + .msix_capable = true,
> + .reserved_bar = (1 << BAR_4) | (1 << BAR_5),
BIT(BAR_4) | BIT(BAR_5) ?
> +};
> +
> +static const struct pci_epc_features*
> +ls_pcie_g4_ep_get_features(struct mobiveil_pcie_ep *ep)
> +{
> + return &ls_pcie_g4_epc_features;
> +}
> +
> +static void ls_pcie_g4_ep_init(struct mobiveil_pcie_ep *ep)
> +{
> + struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
> + int win_idx;
> + u8 bar;
> +
> + ep->bar_num = PCIE_LX2_BAR_NUM;
> +
> + for (bar = BAR_0; bar < ep->epc->max_functions * ep->bar_num; bar++)
> + mobiveil_pcie_ep_reset_bar(mv_pci, bar);
> +
> + for (win_idx = 0; win_idx < ep->apio_wins; win_idx++)
> + mobiveil_pcie_disable_ob_win(mv_pci, win_idx);
> +}
> +
> +static int ls_pcie_g4_ep_raise_irq(struct mobiveil_pcie_ep *ep, u8 func_no,
> + enum pci_epc_irq_type type,
> + u16 interrupt_num)
> +{
> + struct mobiveil_pcie *mv_pci = to_mobiveil_pcie_from_ep(ep);
> +
> + switch (type) {
> + case PCI_EPC_IRQ_LEGACY:
> + return mobiveil_pcie_ep_raise_legacy_irq(ep, func_no);
> + case PCI_EPC_IRQ_MSI:
> + return mobiveil_pcie_ep_raise_msi_irq(ep, func_no,
> + interrupt_num);
> + case PCI_EPC_IRQ_MSIX:
> + return mobiveil_pcie_ep_raise_msix_irq(ep, func_no,
> + interrupt_num);
> + default:
> + dev_err(&mv_pci->pdev->dev, "UNKNOWN IRQ type\n");
> + }
> +
> + return 0;
> +}
> +
> +static const struct mobiveil_pcie_ep_ops pcie_ep_ops = {
> + .ep_init = ls_pcie_g4_ep_init,
> + .raise_irq = ls_pcie_g4_ep_raise_irq,
> + .get_features = ls_pcie_g4_ep_get_features,
> +};
> +
> +static int __init ls_pcie_gen4_add_pcie_ep(struct ls_pcie_g4_ep *ls_ep,
> + struct platform_device *pdev)
> +{
> + struct mobiveil_pcie *mv_pci = ls_ep->mv_pci;
> + struct device *dev = &pdev->dev;
> + struct mobiveil_pcie_ep *ep;
> + struct resource *res;
> + int ret;
> +
> + ep = &mv_pci->ep;
> + ep->ops = &pcie_ep_ops;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
> + if (!res)
> + return -EINVAL;
> +
> + ep->phys_base = res->start;
> + ep->addr_size = resource_size(res);
> +
> + ret = mobiveil_pcie_ep_init(ep);
> + if (ret) {
> + dev_err(dev, "failed to initialize layerscape endpoint\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int __init ls_pcie_g4_ep_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mobiveil_pcie *mv_pci;
> + struct ls_pcie_g4_ep *ls_ep;
> + struct resource *res;
> + int ret;
> +
> + ls_ep = devm_kzalloc(dev, sizeof(*ls_ep), GFP_KERNEL);
> + if (!ls_ep)
> + return -ENOMEM;
> +
> + mv_pci = devm_kzalloc(dev, sizeof(*mv_pci), GFP_KERNEL);
> + if (!mv_pci)
> + return -ENOMEM;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
> + mv_pci->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
> + if (IS_ERR(mv_pci->csr_axi_slave_base))
> + return PTR_ERR(mv_pci->csr_axi_slave_base);
> +
> + mv_pci->pdev = pdev;
> + ls_ep->mv_pci = mv_pci;
> +
> + platform_set_drvdata(pdev, ls_ep);
> +
> + ret = ls_pcie_gen4_add_pcie_ep(ls_ep, pdev);
> +
> + return ret;
> +}
> +
> +static struct platform_driver ls_pcie_g4_ep_driver = {
> + .driver = {
> + .name = "layerscape-pcie-gen4-ep",
> + .of_match_table = ls_pcie_g4_ep_of_match,
> + .suppress_bind_attrs = true,
> + },
> +};
> +builtin_platform_driver_probe(ls_pcie_g4_ep_driver, ls_pcie_g4_ep_probe);
> --
> 2.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox