Merge c903327d32 ("Merge tag 'printk-for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux") into android-mainline
Steps on the way to 6.12-rc1 Bug: 367265496 Change-Id: I0d94aa9be16f183bf187f91dc4916add32722775 Signed-off-by: Matthias Maennich <maennich@google.com>
This commit is contained in:
@@ -328,7 +328,7 @@ and an HDMI input, one input for each input type. Those are described in more
|
||||
detail below.
|
||||
|
||||
Special attention has been given to the rate at which new frames become
|
||||
available. The jitter will be around 1 jiffie (that depends on the HZ
|
||||
available. The jitter will be around 1 jiffy (that depends on the HZ
|
||||
configuration of your kernel, so usually 1/100, 1/250 or 1/1000 of a second),
|
||||
but the long-term behavior is exactly following the framerate. So a
|
||||
framerate of 59.94 Hz is really different from 60 Hz. If the framerate
|
||||
|
||||
@@ -31,13 +31,25 @@ description: |
|
||||
This device also represents the FIQ interrupt sources on platforms using AIC,
|
||||
which do not go through a discrete interrupt controller.
|
||||
|
||||
IPIs may be performed via MMIO registers on all variants of AIC. Starting
|
||||
from A11, system registers may also be used for "fast" IPIs. Starting from
|
||||
M1, even faster IPIs within the same cluster may be achieved by writing to
|
||||
a "local" fast IPI register as opposed to using the "global" fast IPI
|
||||
register.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: apple,t8103-aic
|
||||
- enum:
|
||||
- apple,s5l8960x-aic
|
||||
- apple,t7000-aic
|
||||
- apple,s8000-aic
|
||||
- apple,t8010-aic
|
||||
- apple,t8015-aic
|
||||
- apple,t8103-aic
|
||||
- const: apple,aic
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
@@ -24,6 +24,7 @@ properties:
|
||||
- rockchip,rk3228-timer
|
||||
- rockchip,rk3229-timer
|
||||
- rockchip,rk3368-timer
|
||||
- rockchip,rk3576-timer
|
||||
- rockchip,rk3588-timer
|
||||
- rockchip,px30-timer
|
||||
- const: rockchip,rk3288-timer
|
||||
|
||||
@@ -19,7 +19,7 @@ it really need to delay in atomic context?" If so...
|
||||
|
||||
ATOMIC CONTEXT:
|
||||
You must use the `*delay` family of functions. These
|
||||
functions use the jiffie estimation of clock speed
|
||||
functions use the jiffy estimation of clock speed
|
||||
and will busy wait for enough loop cycles to achieve
|
||||
the desired delay:
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ para que se ejecute, y la tarea en ejecución es interrumpida.
|
||||
==================================
|
||||
|
||||
CFS usa una granularidad de nanosegundos y no depende de ningún
|
||||
jiffie o detalles como HZ. De este modo, el gestor de tareas CFS no tiene
|
||||
jiffy o detalles como HZ. De este modo, el gestor de tareas CFS no tiene
|
||||
noción de "ventanas de tiempo" de la forma en que tenía el gestor de
|
||||
tareas previo, y tampoco tiene heurísticos. Únicamente hay un parámetro
|
||||
central ajustable (se ha de cambiar en CONFIG_SCHED_DEBUG):
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
/*
|
||||
* Even though the SPC takes max 3-5 ms to complete any OPP/COMMS
|
||||
* operation, the operation could start just before jiffie is about
|
||||
* operation, the operation could start just before jiffy is about
|
||||
* to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz
|
||||
*/
|
||||
#define TIMEOUT_US 20000
|
||||
|
||||
@@ -85,6 +85,7 @@ config LOONGARCH
|
||||
select GENERIC_ENTRY
|
||||
select GENERIC_GETTIMEOFDAY
|
||||
select GENERIC_IOREMAP if !ARCH_IOREMAP
|
||||
select GENERIC_IRQ_MATRIX_ALLOCATOR
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
|
||||
@@ -65,5 +65,6 @@
|
||||
#define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID)
|
||||
#define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR)
|
||||
#define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW)
|
||||
#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT)
|
||||
|
||||
#endif /* __ASM_CPU_FEATURES_H */
|
||||
|
||||
@@ -99,6 +99,7 @@ enum cpu_type_enum {
|
||||
#define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */
|
||||
#define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */
|
||||
#define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */
|
||||
#define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */
|
||||
|
||||
#define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG)
|
||||
#define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM)
|
||||
@@ -127,5 +128,6 @@ enum cpu_type_enum {
|
||||
#define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID)
|
||||
#define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR)
|
||||
#define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW)
|
||||
#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT)
|
||||
|
||||
#endif /* _ASM_CPU_H */
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
extern void ack_bad_irq(unsigned int irq);
|
||||
#define ack_bad_irq ack_bad_irq
|
||||
|
||||
#define NR_IPI 3
|
||||
#define NR_IPI 4
|
||||
|
||||
enum ipi_msg_type {
|
||||
IPI_RESCHEDULE,
|
||||
IPI_CALL_FUNCTION,
|
||||
IPI_IRQ_WORK,
|
||||
IPI_CLEAR_VECTOR,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -39,11 +39,22 @@ void spurious_interrupt(void);
|
||||
|
||||
#define NR_IRQS_LEGACY 16
|
||||
|
||||
/*
|
||||
* 256 Vectors Mapping for AVECINTC:
|
||||
*
|
||||
* 0 - 15: Mapping classic IPs, e.g. IP0-12.
|
||||
* 16 - 255: Mapping vectors for external IRQ.
|
||||
*
|
||||
*/
|
||||
#define NR_VECTORS 256
|
||||
#define NR_LEGACY_VECTORS 16
|
||||
#define IRQ_MATRIX_BITS NR_VECTORS
|
||||
|
||||
#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
|
||||
void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu);
|
||||
|
||||
#define MAX_IO_PICS 2
|
||||
#define NR_IRQS (64 + (256 * MAX_IO_PICS))
|
||||
#define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS))
|
||||
|
||||
struct acpi_vector_group {
|
||||
int node;
|
||||
@@ -65,7 +76,7 @@ extern struct acpi_vector_group msi_group[MAX_IO_PICS];
|
||||
#define LOONGSON_LPC_LAST_IRQ (LOONGSON_LPC_IRQ_BASE + 15)
|
||||
|
||||
#define LOONGSON_CPU_IRQ_BASE 16
|
||||
#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 14)
|
||||
#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 15)
|
||||
|
||||
#define LOONGSON_PCH_IRQ_BASE 64
|
||||
#define LOONGSON_PCH_ACPI_IRQ (LOONGSON_PCH_IRQ_BASE + 47)
|
||||
@@ -88,20 +99,8 @@ struct acpi_madt_bio_pic;
|
||||
struct acpi_madt_msi_pic;
|
||||
struct acpi_madt_lpc_pic;
|
||||
|
||||
int liointc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_lio_pic *acpi_liointc);
|
||||
int eiointc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_eio_pic *acpi_eiointc);
|
||||
void complete_irq_moving(void);
|
||||
|
||||
int htvec_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_ht_pic *acpi_htvec);
|
||||
int pch_lpc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_lpc_pic *acpi_pchlpc);
|
||||
int pch_msi_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_msi_pic *acpi_pchmsi);
|
||||
int pch_pic_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_bio_pic *acpi_pchpic);
|
||||
int find_pch_pic(u32 gsi);
|
||||
struct fwnode_handle *get_pch_msi_handle(int pci_segment);
|
||||
|
||||
extern struct acpi_madt_lio_pic *acpi_liointc;
|
||||
|
||||
@@ -246,8 +246,8 @@
|
||||
#define CSR_ESTAT_EXC_WIDTH 6
|
||||
#define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT)
|
||||
#define CSR_ESTAT_IS_SHIFT 0
|
||||
#define CSR_ESTAT_IS_WIDTH 14
|
||||
#define CSR_ESTAT_IS (_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT)
|
||||
#define CSR_ESTAT_IS_WIDTH 15
|
||||
#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT)
|
||||
|
||||
#define LOONGARCH_CSR_ERA 0x6 /* ERA */
|
||||
|
||||
@@ -642,6 +642,13 @@
|
||||
|
||||
#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */
|
||||
|
||||
#define LOONGARCH_CSR_ISR0 0xa0
|
||||
#define LOONGARCH_CSR_ISR1 0xa1
|
||||
#define LOONGARCH_CSR_ISR2 0xa2
|
||||
#define LOONGARCH_CSR_ISR3 0xa3
|
||||
|
||||
#define LOONGARCH_CSR_IRR 0xa4
|
||||
|
||||
#define LOONGARCH_CSR_PRID 0xc0
|
||||
|
||||
/* Shadow MCSR : 0xc0 ~ 0xff */
|
||||
@@ -1004,7 +1011,7 @@
|
||||
/*
|
||||
* CSR_ECFG IM
|
||||
*/
|
||||
#define ECFG0_IM 0x00001fff
|
||||
#define ECFG0_IM 0x00005fff
|
||||
#define ECFGB_SIP0 0
|
||||
#define ECFGF_SIP0 (_ULCAST_(1) << ECFGB_SIP0)
|
||||
#define ECFGB_SIP1 1
|
||||
@@ -1047,6 +1054,7 @@
|
||||
#define IOCSRF_EIODECODE BIT_ULL(9)
|
||||
#define IOCSRF_FLATMODE BIT_ULL(10)
|
||||
#define IOCSRF_VM BIT_ULL(11)
|
||||
#define IOCSRF_AVEC BIT_ULL(15)
|
||||
|
||||
#define LOONGARCH_IOCSR_VENDOR 0x10
|
||||
|
||||
@@ -1058,6 +1066,7 @@
|
||||
#define IOCSR_MISC_FUNC_SOFT_INT BIT_ULL(10)
|
||||
#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21)
|
||||
#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48)
|
||||
#define IOCSR_MISC_FUNC_AVEC_EN BIT_ULL(51)
|
||||
|
||||
#define LOONGARCH_IOCSR_CPUTEMP 0x428
|
||||
|
||||
@@ -1380,9 +1389,10 @@ __BUILD_CSR_OP(tlbidx)
|
||||
#define INT_TI 11 /* Timer */
|
||||
#define INT_IPI 12
|
||||
#define INT_NMI 13
|
||||
#define INT_AVEC 14
|
||||
|
||||
/* ExcCodes corresponding to interrupts */
|
||||
#define EXCCODE_INT_NUM (INT_NMI + 1)
|
||||
#define EXCCODE_INT_NUM (INT_AVEC + 1)
|
||||
#define EXCCODE_INT_START 64
|
||||
#define EXCCODE_INT_END (EXCCODE_INT_START + EXCCODE_INT_NUM - 1)
|
||||
|
||||
|
||||
@@ -70,10 +70,12 @@ extern int __cpu_logical_map[NR_CPUS];
|
||||
#define ACTION_RESCHEDULE 1
|
||||
#define ACTION_CALL_FUNCTION 2
|
||||
#define ACTION_IRQ_WORK 3
|
||||
#define ACTION_CLEAR_VECTOR 4
|
||||
#define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
|
||||
#define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
|
||||
#define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
|
||||
#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
|
||||
#define SMP_CLEAR_VECTOR BIT(ACTION_CLEAR_VECTOR)
|
||||
|
||||
struct secondary_data {
|
||||
unsigned long stack;
|
||||
|
||||
@@ -106,7 +106,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
elf_hwcap |= HWCAP_LOONGARCH_CRC32;
|
||||
}
|
||||
|
||||
|
||||
config = read_cpucfg(LOONGARCH_CPUCFG2);
|
||||
if (config & CPUCFG2_LAM) {
|
||||
c->options |= LOONGARCH_CPU_LAM;
|
||||
@@ -174,6 +173,8 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
c->options |= LOONGARCH_CPU_FLATMODE;
|
||||
if (config & IOCSRF_EIODECODE)
|
||||
c->options |= LOONGARCH_CPU_EIODECODE;
|
||||
if (config & IOCSRF_AVEC)
|
||||
c->options |= LOONGARCH_CPU_AVECINT;
|
||||
if (config & IOCSRF_VM)
|
||||
c->options |= LOONGARCH_CPU_HYPERVISOR;
|
||||
|
||||
|
||||
@@ -87,6 +87,18 @@ static void __init init_vec_parent_group(void)
|
||||
acpi_table_parse(ACPI_SIG_MCFG, early_pci_mcfg_parse);
|
||||
}
|
||||
|
||||
int __init arch_probe_nr_irqs(void)
|
||||
{
|
||||
int nr_io_pics = bitmap_weight(loongson_sysconf.cores_io_master, NR_CPUS);
|
||||
|
||||
if (!cpu_has_avecint)
|
||||
nr_irqs = (64 + NR_VECTORS * nr_io_pics);
|
||||
else
|
||||
nr_irqs = (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics));
|
||||
|
||||
return NR_IRQS_LEGACY;
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -135,6 +135,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
|
||||
info->ipi_irqs[IPI_IRQ_WORK]++;
|
||||
}
|
||||
|
||||
if (action & SMP_CLEAR_VECTOR) {
|
||||
complete_irq_moving();
|
||||
info->ipi_irqs[IPI_CLEAR_VECTOR]++;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
|
||||
[IPI_RESCHEDULE] = "Rescheduling interrupts",
|
||||
[IPI_CALL_FUNCTION] = "Function call interrupts",
|
||||
[IPI_IRQ_WORK] = "IRQ work interrupts",
|
||||
[IPI_CLEAR_VECTOR] = "Clear vector interrupts",
|
||||
};
|
||||
|
||||
void show_ipi_list(struct seq_file *p, int prec)
|
||||
@@ -248,6 +249,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
|
||||
per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
|
||||
}
|
||||
|
||||
if (action & SMP_CLEAR_VECTOR) {
|
||||
complete_irq_moving();
|
||||
per_cpu(irq_stat, cpu).ipi_irqs[IPI_CLEAR_VECTOR]++;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ void __init q40_init_IRQ(void)
|
||||
* this stuff doesn't really belong here..
|
||||
*/
|
||||
|
||||
int ql_ticks; /* 200Hz ticks since last jiffie */
|
||||
int ql_ticks; /* 200Hz ticks since last jiffy */
|
||||
static int sound_ticks;
|
||||
|
||||
#define SVOL 45
|
||||
|
||||
@@ -439,7 +439,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
}
|
||||
|
||||
/* preload SMP state for boot cpu */
|
||||
void smp_prepare_boot_cpu(void)
|
||||
void __init smp_prepare_boot_cpu(void)
|
||||
{
|
||||
if (mp_ops->prepare_boot_cpu)
|
||||
mp_ops->prepare_boot_cpu();
|
||||
|
||||
@@ -1166,7 +1166,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
cpu_smt_set_num_threads(num_threads, threads_per_core);
|
||||
}
|
||||
|
||||
void smp_prepare_boot_cpu(void)
|
||||
void __init smp_prepare_boot_cpu(void)
|
||||
{
|
||||
BUG_ON(smp_processor_id() != boot_cpuid);
|
||||
#ifdef CONFIG_PPC64
|
||||
|
||||
@@ -314,7 +314,7 @@ static ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
|
||||
|
||||
/*
|
||||
* Need to give user space some time to set everything up,
|
||||
* so do it a jiffie or two later everywhere.
|
||||
* so do it a jiffy or two later everywhere.
|
||||
*/
|
||||
schedule_timeout(2);
|
||||
|
||||
|
||||
+1
-1
@@ -1128,7 +1128,7 @@ static void blk_complete_reqs(struct llist_head *list)
|
||||
rq->q->mq_ops->complete(rq);
|
||||
}
|
||||
|
||||
static __latent_entropy void blk_done_softirq(struct softirq_action *h)
|
||||
static __latent_entropy void blk_done_softirq(void)
|
||||
{
|
||||
blk_complete_reqs(this_cpu_ptr(&blk_cpu_done));
|
||||
}
|
||||
|
||||
@@ -980,7 +980,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
|
||||
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||
start_get(ssif_info);
|
||||
} else {
|
||||
/* Wait a jiffie then request the next message */
|
||||
/* Wait a jiffy then request the next message */
|
||||
ssif_info->waiting_alert = true;
|
||||
ssif_info->retries_left = SSIF_RECV_RETRIES;
|
||||
if (!ssif_info->stopping)
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
static void *suspend_resume_cb_data;
|
||||
|
||||
static void (*suspend_resume_callback)(void *data, bool suspend);
|
||||
|
||||
/*
|
||||
* The I/O port the PMTMR resides at.
|
||||
* The location is detected during setup_arch(),
|
||||
@@ -58,6 +62,32 @@ u32 acpi_pm_read_verified(void)
|
||||
return v2;
|
||||
}
|
||||
|
||||
void acpi_pmtmr_register_suspend_resume_callback(void (*cb)(void *data, bool suspend), void *data)
|
||||
{
|
||||
suspend_resume_callback = cb;
|
||||
suspend_resume_cb_data = data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_pmtmr_register_suspend_resume_callback);
|
||||
|
||||
void acpi_pmtmr_unregister_suspend_resume_callback(void)
|
||||
{
|
||||
suspend_resume_callback = NULL;
|
||||
suspend_resume_cb_data = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_pmtmr_unregister_suspend_resume_callback);
|
||||
|
||||
static void acpi_pm_suspend(struct clocksource *cs)
|
||||
{
|
||||
if (suspend_resume_callback)
|
||||
suspend_resume_callback(suspend_resume_cb_data, true);
|
||||
}
|
||||
|
||||
static void acpi_pm_resume(struct clocksource *cs)
|
||||
{
|
||||
if (suspend_resume_callback)
|
||||
suspend_resume_callback(suspend_resume_cb_data, false);
|
||||
}
|
||||
|
||||
static u64 acpi_pm_read(struct clocksource *cs)
|
||||
{
|
||||
return (u64)read_pmtmr();
|
||||
@@ -69,6 +99,8 @@ static struct clocksource clocksource_acpi_pm = {
|
||||
.read = acpi_pm_read,
|
||||
.mask = (u64)ACPI_PM_MASK,
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
.suspend = acpi_pm_suspend,
|
||||
.resume = acpi_pm_resume,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1594,7 +1594,6 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
|
||||
{
|
||||
struct arch_timer_mem *timer_mem;
|
||||
struct arch_timer_mem_frame *frame;
|
||||
struct device_node *frame_node;
|
||||
struct resource res;
|
||||
int ret = -EINVAL;
|
||||
u32 rate;
|
||||
@@ -1608,33 +1607,29 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
|
||||
timer_mem->cntctlbase = res.start;
|
||||
timer_mem->size = resource_size(&res);
|
||||
|
||||
for_each_available_child_of_node(np, frame_node) {
|
||||
for_each_available_child_of_node_scoped(np, frame_node) {
|
||||
u32 n;
|
||||
struct arch_timer_mem_frame *frame;
|
||||
|
||||
if (of_property_read_u32(frame_node, "frame-number", &n)) {
|
||||
pr_err(FW_BUG "Missing frame-number.\n");
|
||||
of_node_put(frame_node);
|
||||
goto out;
|
||||
}
|
||||
if (n >= ARCH_TIMER_MEM_MAX_FRAMES) {
|
||||
pr_err(FW_BUG "Wrong frame-number, only 0-%u are permitted.\n",
|
||||
ARCH_TIMER_MEM_MAX_FRAMES - 1);
|
||||
of_node_put(frame_node);
|
||||
goto out;
|
||||
}
|
||||
frame = &timer_mem->frame[n];
|
||||
|
||||
if (frame->valid) {
|
||||
pr_err(FW_BUG "Duplicated frame-number.\n");
|
||||
of_node_put(frame_node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(frame_node, 0, &res)) {
|
||||
of_node_put(frame_node);
|
||||
if (of_address_to_resource(frame_node, 0, &res))
|
||||
goto out;
|
||||
}
|
||||
|
||||
frame->cntbase = res.start;
|
||||
frame->size = resource_size(&res);
|
||||
|
||||
|
||||
@@ -210,6 +210,7 @@ static int __init asm9260_timer_init(struct device_node *np)
|
||||
DRIVER_NAME, &event_dev);
|
||||
if (ret) {
|
||||
pr_err("Failed to setup irq!\n");
|
||||
clk_disable_unprepare(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,14 +93,10 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(map);
|
||||
}
|
||||
|
||||
ost->clk = devm_clk_get(dev, "ost");
|
||||
ost->clk = devm_clk_get_enabled(dev, "ost");
|
||||
if (IS_ERR(ost->clk))
|
||||
return PTR_ERR(ost->clk);
|
||||
|
||||
err = clk_prepare_enable(ost->clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Clear counter high/low registers */
|
||||
if (soc_info->is64bit)
|
||||
regmap_write(map, TCU_REG_OST_CNTL, 0);
|
||||
@@ -129,7 +125,6 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
|
||||
err = clocksource_register_hz(cs, rate);
|
||||
if (err) {
|
||||
dev_err(dev, "clocksource registration failed");
|
||||
clk_disable_unprepare(ost->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ static int jcore_pit_local_init(unsigned cpu)
|
||||
|
||||
static irqreturn_t jcore_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct jcore_pit *pit = this_cpu_ptr(dev_id);
|
||||
struct jcore_pit *pit = dev_id;
|
||||
|
||||
if (clockevent_state_oneshot(&pit->ced))
|
||||
jcore_pit_disable(pit);
|
||||
@@ -168,9 +168,8 @@ static int __init jcore_pit_init(struct device_node *node)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = request_irq(pit_irq, jcore_timer_interrupt,
|
||||
IRQF_TIMER | IRQF_PERCPU,
|
||||
"jcore_pit", jcore_pit_percpu);
|
||||
err = request_percpu_irq(pit_irq, jcore_timer_interrupt,
|
||||
"jcore_pit", jcore_pit_percpu);
|
||||
if (err) {
|
||||
pr_err("pit irq request failed: %d\n", err);
|
||||
free_percpu(jcore_pit_percpu);
|
||||
|
||||
@@ -435,7 +435,7 @@ static int __init ttc_setup_clockevent(struct clk *clk,
|
||||
&ttcce->ttc.clk_rate_change_nb);
|
||||
if (err) {
|
||||
pr_warn("Unable to register clock notifier.\n");
|
||||
goto out_kfree;
|
||||
goto out_clk_unprepare;
|
||||
}
|
||||
|
||||
ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk);
|
||||
@@ -465,13 +465,15 @@ static int __init ttc_setup_clockevent(struct clk *clk,
|
||||
err = request_irq(irq, ttc_clock_event_interrupt,
|
||||
IRQF_TIMER, ttcce->ce.name, ttcce);
|
||||
if (err)
|
||||
goto out_kfree;
|
||||
goto out_clk_unprepare;
|
||||
|
||||
clockevents_config_and_register(&ttcce->ce,
|
||||
ttcce->ttc.freq / PRESCALE, 1, 0xfffe);
|
||||
|
||||
return 0;
|
||||
|
||||
out_clk_unprepare:
|
||||
clk_disable_unprepare(ttcce->ttc.clk);
|
||||
out_kfree:
|
||||
kfree(ttcce);
|
||||
return err;
|
||||
|
||||
@@ -233,6 +233,7 @@ static int __init msm_dt_timer_init(struct device_node *np)
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &freq)) {
|
||||
iounmap(cpu0_base);
|
||||
pr_err("Unknown frequency\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -243,7 +244,11 @@ static int __init msm_dt_timer_init(struct device_node *np)
|
||||
freq /= 4;
|
||||
writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL);
|
||||
|
||||
return msm_timer_init(freq, 32, irq, !!percpu_offset);
|
||||
ret = msm_timer_init(freq, 32, irq, !!percpu_offset);
|
||||
if (ret)
|
||||
iounmap(cpu0_base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
TIMER_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init);
|
||||
TIMER_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
|
||||
|
||||
@@ -402,7 +402,7 @@ static int test_wait_timeout(void *arg)
|
||||
|
||||
if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) {
|
||||
if (timer_pending(&wt.timer)) {
|
||||
pr_notice("Timer did not fire within the jiffie!\n");
|
||||
pr_notice("Timer did not fire within the jiffy!\n");
|
||||
err = 0; /* not our fault! */
|
||||
} else {
|
||||
pr_err("Wait reported incomplete after timeout\n");
|
||||
|
||||
@@ -266,7 +266,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
if (ret == -ETIME && !nsecs_to_jiffies(args->timeout_ns))
|
||||
args->timeout_ns = 0;
|
||||
|
||||
/* Asked to wait beyond the jiffie/scheduler precision? */
|
||||
/* Asked to wait beyond the jiffy/scheduler precision? */
|
||||
if (ret == -ETIME && args->timeout_ns)
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static int wait_for_reset(struct intel_engine_cs *engine,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Give the request a jiffie to complete after flushing the worker */
|
||||
/* Give the request a jiffy to complete after flushing the worker */
|
||||
if (i915_request_wait(rq, 0,
|
||||
max(0l, (long)(timeout - jiffies)) + 1) < 0) {
|
||||
pr_err("%s: hanging request %llx:%lld did not complete\n",
|
||||
@@ -3426,7 +3426,7 @@ static int live_preempt_timeout(void *arg)
|
||||
cpu_relax();
|
||||
|
||||
saved_timeout = engine->props.preempt_timeout_ms;
|
||||
engine->props.preempt_timeout_ms = 1; /* in ms, -> 1 jiffie */
|
||||
engine->props.preempt_timeout_ms = 1; /* in ms, -> 1 jiffy */
|
||||
|
||||
i915_request_get(rq);
|
||||
i915_request_add(rq);
|
||||
|
||||
@@ -110,7 +110,7 @@ void set_timer_ms(struct timer_list *t, unsigned long timeout)
|
||||
* Paranoia to make sure the compiler computes the timeout before
|
||||
* loading 'jiffies' as jiffies is volatile and may be updated in
|
||||
* the background by a timer tick. All to reduce the complexity
|
||||
* of the addition and reduce the risk of losing a jiffie.
|
||||
* of the addition and reduce the risk of losing a jiffy.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
|
||||
else
|
||||
args->timeout_ns = 0;
|
||||
|
||||
/* Asked to wait beyond the jiffie/scheduler precision? */
|
||||
/* Asked to wait beyond the jiffy/scheduler precision? */
|
||||
if (ret == -ETIME && args->timeout_ns)
|
||||
ret = -EAGAIN;
|
||||
|
||||
|
||||
@@ -685,6 +685,7 @@ config LOONGSON_PCH_MSI
|
||||
depends on PCI
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select IRQ_MSI_LIB
|
||||
select PCI_MSI
|
||||
help
|
||||
Support for the Loongson PCH MSI Controller.
|
||||
|
||||
@@ -110,7 +110,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
|
||||
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
|
||||
obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
|
||||
obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o
|
||||
obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o
|
||||
obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-avec.o
|
||||
obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o
|
||||
obj-$(CONFIG_LOONGSON_EIOINTC) += irq-loongson-eiointc.o
|
||||
obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
|
||||
|
||||
@@ -234,7 +234,10 @@ enum fiq_hwirq {
|
||||
AIC_NR_FIQ
|
||||
};
|
||||
|
||||
/* True if UNCORE/UNCORE2 and Sn_... IPI registers are present and used (A11+) */
|
||||
static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
|
||||
/* True if SYS_IMP_APL_IPI_RR_LOCAL_EL1 exists for local fast IPIs (M1+) */
|
||||
static DEFINE_STATIC_KEY_TRUE(use_local_fast_ipi);
|
||||
|
||||
struct aic_info {
|
||||
int version;
|
||||
@@ -252,6 +255,7 @@ struct aic_info {
|
||||
|
||||
/* Features */
|
||||
bool fast_ipi;
|
||||
bool local_fast_ipi;
|
||||
};
|
||||
|
||||
static const struct aic_info aic1_info __initconst = {
|
||||
@@ -270,17 +274,32 @@ static const struct aic_info aic1_fipi_info __initconst = {
|
||||
.fast_ipi = true,
|
||||
};
|
||||
|
||||
static const struct aic_info aic1_local_fipi_info __initconst = {
|
||||
.version = 1,
|
||||
|
||||
.event = AIC_EVENT,
|
||||
.target_cpu = AIC_TARGET_CPU,
|
||||
|
||||
.fast_ipi = true,
|
||||
.local_fast_ipi = true,
|
||||
};
|
||||
|
||||
static const struct aic_info aic2_info __initconst = {
|
||||
.version = 2,
|
||||
|
||||
.irq_cfg = AIC2_IRQ_CFG,
|
||||
|
||||
.fast_ipi = true,
|
||||
.local_fast_ipi = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id aic_info_match[] = {
|
||||
{
|
||||
.compatible = "apple,t8103-aic",
|
||||
.data = &aic1_local_fipi_info,
|
||||
},
|
||||
{
|
||||
.compatible = "apple,t8015-aic",
|
||||
.data = &aic1_fipi_info,
|
||||
},
|
||||
{
|
||||
@@ -532,14 +551,9 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
|
||||
* we check for everything here, even things we don't support yet.
|
||||
*/
|
||||
|
||||
if (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) {
|
||||
if (static_branch_likely(&use_fast_ipi)) {
|
||||
aic_handle_ipi(regs);
|
||||
} else {
|
||||
pr_err_ratelimited("Fast IPI fired. Acking.\n");
|
||||
write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1);
|
||||
}
|
||||
}
|
||||
if (static_branch_likely(&use_fast_ipi) &&
|
||||
(read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING))
|
||||
aic_handle_ipi(regs);
|
||||
|
||||
if (TIMER_FIRING(read_sysreg(cntp_ctl_el0)))
|
||||
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||
@@ -574,8 +588,9 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
|
||||
AIC_FIQ_HWIRQ(irq));
|
||||
}
|
||||
|
||||
if (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ &&
|
||||
(read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) {
|
||||
if (static_branch_likely(&use_fast_ipi) &&
|
||||
(FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ) &&
|
||||
(read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) {
|
||||
/* Same story with uncore PMCs */
|
||||
pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n");
|
||||
sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE,
|
||||
@@ -750,12 +765,12 @@ static void aic_ipi_send_fast(int cpu)
|
||||
u64 cluster = MPIDR_CLUSTER(mpidr);
|
||||
u64 idx = MPIDR_CPU(mpidr);
|
||||
|
||||
if (MPIDR_CLUSTER(my_mpidr) == cluster)
|
||||
write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx),
|
||||
SYS_IMP_APL_IPI_RR_LOCAL_EL1);
|
||||
else
|
||||
if (static_branch_likely(&use_local_fast_ipi) && MPIDR_CLUSTER(my_mpidr) == cluster) {
|
||||
write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx), SYS_IMP_APL_IPI_RR_LOCAL_EL1);
|
||||
} else {
|
||||
write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx) | FIELD_PREP(IPI_RR_CLUSTER, cluster),
|
||||
SYS_IMP_APL_IPI_RR_GLOBAL_EL1);
|
||||
}
|
||||
isb();
|
||||
}
|
||||
|
||||
@@ -811,7 +826,8 @@ static int aic_init_cpu(unsigned int cpu)
|
||||
/* Mask all hard-wired per-CPU IRQ/FIQ sources */
|
||||
|
||||
/* Pending Fast IPI FIQs */
|
||||
write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1);
|
||||
if (static_branch_likely(&use_fast_ipi))
|
||||
write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1);
|
||||
|
||||
/* Timer FIQs */
|
||||
sysreg_clear_set(cntp_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK);
|
||||
@@ -832,8 +848,10 @@ static int aic_init_cpu(unsigned int cpu)
|
||||
FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF));
|
||||
|
||||
/* Uncore PMC FIQ */
|
||||
sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE,
|
||||
FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF));
|
||||
if (static_branch_likely(&use_fast_ipi)) {
|
||||
sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE,
|
||||
FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF));
|
||||
}
|
||||
|
||||
/* Commit all of the above */
|
||||
isb();
|
||||
@@ -987,11 +1005,12 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
|
||||
off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_CLR */
|
||||
off += sizeof(u32) * (irqc->max_irq >> 5); /* HW_STATE */
|
||||
|
||||
if (irqc->info.fast_ipi)
|
||||
static_branch_enable(&use_fast_ipi);
|
||||
else
|
||||
if (!irqc->info.fast_ipi)
|
||||
static_branch_disable(&use_fast_ipi);
|
||||
|
||||
if (!irqc->info.local_fast_ipi)
|
||||
static_branch_disable(&use_local_fast_ipi);
|
||||
|
||||
irqc->info.die_stride = off - start_off;
|
||||
|
||||
irqc->hw_domain = irq_domain_create_tree(of_node_to_fwnode(node),
|
||||
|
||||
+441
-424
File diff suppressed because it is too large
Load Diff
@@ -57,8 +57,7 @@
|
||||
|
||||
static struct irq_domain *aic_domain;
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
aic_handle(struct pt_regs *regs)
|
||||
static void __exception_irq_entry aic_handle(struct pt_regs *regs)
|
||||
{
|
||||
struct irq_domain_chip_generic *dgc = aic_domain->gc;
|
||||
struct irq_chip_generic *gc = dgc->gc[0];
|
||||
|
||||
@@ -67,8 +67,7 @@
|
||||
|
||||
static struct irq_domain *aic5_domain;
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
aic5_handle(struct pt_regs *regs)
|
||||
static void __exception_irq_entry aic5_handle(struct pt_regs *regs)
|
||||
{
|
||||
struct irq_chip_generic *bgc = irq_get_domain_generic_chip(aic5_domain, 0);
|
||||
u32 irqnr;
|
||||
|
||||
@@ -69,7 +69,7 @@ static struct {
|
||||
struct irq_domain_ops ops;
|
||||
} *clps711x_intc;
|
||||
|
||||
static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
|
||||
static void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
|
||||
{
|
||||
u32 irqstat;
|
||||
|
||||
|
||||
@@ -116,8 +116,7 @@ static struct irq_chip davinci_cp_intc_irq_chip = {
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
davinci_cp_intc_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry davinci_cp_intc_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
int gpir, irqnr, none;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ static struct irq_chip ft010_irq_chip = {
|
||||
/* Local static for the IRQ entry call */
|
||||
static struct ft010_irq_data firq;
|
||||
|
||||
static asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
struct ft010_irq_data *f = &firq;
|
||||
int irq;
|
||||
|
||||
@@ -931,7 +931,7 @@ static void __gic_handle_irq_from_irqsoff(struct pt_regs *regs)
|
||||
__gic_handle_nmi(irqnr, regs);
|
||||
}
|
||||
|
||||
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
if (unlikely(gic_supports_nmi() && !interrupts_enabled(regs)))
|
||||
__gic_handle_irq_from_irqsoff(regs);
|
||||
|
||||
@@ -97,7 +97,7 @@ bool gic_cpuif_has_vsgi(void)
|
||||
|
||||
fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_EL1_GIC_SHIFT);
|
||||
|
||||
return fld >= 0x3;
|
||||
return fld >= ID_AA64PFR0_EL1_GIC_V4P1;
|
||||
}
|
||||
#else
|
||||
bool gic_cpuif_has_vsgi(void)
|
||||
|
||||
@@ -105,8 +105,7 @@ static void ixp4xx_irq_unmask(struct irq_data *d)
|
||||
}
|
||||
}
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
ixp4xx_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
struct ixp4xx_irq *ixi = &ixirq;
|
||||
unsigned long status;
|
||||
|
||||
@@ -0,0 +1,425 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2024 Loongson Technologies, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/loongarch.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "irq-msi-lib.h"
|
||||
#include "irq-loongson.h"
|
||||
|
||||
#define VECTORS_PER_REG 64
|
||||
#define IRR_VECTOR_MASK 0xffUL
|
||||
#define IRR_INVALID_MASK 0x80000000UL
|
||||
#define AVEC_MSG_OFFSET 0x100000
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
struct pending_list {
|
||||
struct list_head head;
|
||||
};
|
||||
|
||||
static struct cpumask intersect_mask;
|
||||
static DEFINE_PER_CPU(struct pending_list, pending_list);
|
||||
#endif
|
||||
|
||||
static DEFINE_PER_CPU(struct irq_desc * [NR_VECTORS], irq_map);
|
||||
|
||||
struct avecintc_chip {
|
||||
raw_spinlock_t lock;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct irq_domain *domain;
|
||||
struct irq_matrix *vector_matrix;
|
||||
phys_addr_t msi_base_addr;
|
||||
};
|
||||
|
||||
static struct avecintc_chip loongarch_avec;
|
||||
|
||||
struct avecintc_data {
|
||||
struct list_head entry;
|
||||
unsigned int cpu;
|
||||
unsigned int vec;
|
||||
unsigned int prev_cpu;
|
||||
unsigned int prev_vec;
|
||||
unsigned int moving;
|
||||
};
|
||||
|
||||
static inline void avecintc_ack_irq(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void avecintc_mask_irq(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void avecintc_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline void pending_list_init(int cpu)
|
||||
{
|
||||
struct pending_list *plist = per_cpu_ptr(&pending_list, cpu);
|
||||
|
||||
INIT_LIST_HEAD(&plist->head);
|
||||
}
|
||||
|
||||
static void avecintc_sync(struct avecintc_data *adata)
|
||||
{
|
||||
struct pending_list *plist;
|
||||
|
||||
if (cpu_online(adata->prev_cpu)) {
|
||||
plist = per_cpu_ptr(&pending_list, adata->prev_cpu);
|
||||
list_add_tail(&adata->entry, &plist->head);
|
||||
adata->moving = 1;
|
||||
mp_ops.send_ipi_single(adata->prev_cpu, ACTION_CLEAR_VECTOR);
|
||||
}
|
||||
}
|
||||
|
||||
static int avecintc_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force)
|
||||
{
|
||||
int cpu, ret, vector;
|
||||
struct avecintc_data *adata;
|
||||
|
||||
scoped_guard(raw_spinlock, &loongarch_avec.lock) {
|
||||
adata = irq_data_get_irq_chip_data(data);
|
||||
|
||||
if (adata->moving)
|
||||
return -EBUSY;
|
||||
|
||||
if (cpu_online(adata->cpu) && cpumask_test_cpu(adata->cpu, dest))
|
||||
return 0;
|
||||
|
||||
cpumask_and(&intersect_mask, dest, cpu_online_mask);
|
||||
|
||||
ret = irq_matrix_alloc(loongarch_avec.vector_matrix, &intersect_mask, false, &cpu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
vector = ret;
|
||||
adata->cpu = cpu;
|
||||
adata->vec = vector;
|
||||
per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(data);
|
||||
avecintc_sync(adata);
|
||||
}
|
||||
|
||||
irq_data_update_effective_affinity(data, cpumask_of(cpu));
|
||||
|
||||
return IRQ_SET_MASK_OK;
|
||||
}
|
||||
|
||||
static int avecintc_cpu_online(unsigned int cpu)
|
||||
{
|
||||
if (!loongarch_avec.vector_matrix)
|
||||
return 0;
|
||||
|
||||
guard(raw_spinlock)(&loongarch_avec.lock);
|
||||
|
||||
irq_matrix_online(loongarch_avec.vector_matrix);
|
||||
|
||||
pending_list_init(cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avecintc_cpu_offline(unsigned int cpu)
|
||||
{
|
||||
struct pending_list *plist = per_cpu_ptr(&pending_list, cpu);
|
||||
|
||||
if (!loongarch_avec.vector_matrix)
|
||||
return 0;
|
||||
|
||||
guard(raw_spinlock)(&loongarch_avec.lock);
|
||||
|
||||
if (!list_empty(&plist->head))
|
||||
pr_warn("CPU#%d vector is busy\n", cpu);
|
||||
|
||||
irq_matrix_offline(loongarch_avec.vector_matrix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void complete_irq_moving(void)
|
||||
{
|
||||
struct pending_list *plist = this_cpu_ptr(&pending_list);
|
||||
struct avecintc_data *adata, *tdata;
|
||||
int cpu, vector, bias;
|
||||
uint64_t isr;
|
||||
|
||||
guard(raw_spinlock)(&loongarch_avec.lock);
|
||||
|
||||
list_for_each_entry_safe(adata, tdata, &plist->head, entry) {
|
||||
cpu = adata->prev_cpu;
|
||||
vector = adata->prev_vec;
|
||||
bias = vector / VECTORS_PER_REG;
|
||||
switch (bias) {
|
||||
case 0:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR0);
|
||||
break;
|
||||
case 1:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR1);
|
||||
break;
|
||||
case 2:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR2);
|
||||
break;
|
||||
case 3:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isr & (1UL << (vector % VECTORS_PER_REG))) {
|
||||
mp_ops.send_ipi_single(cpu, ACTION_CLEAR_VECTOR);
|
||||
continue;
|
||||
}
|
||||
list_del(&adata->entry);
|
||||
irq_matrix_free(loongarch_avec.vector_matrix, cpu, vector, false);
|
||||
this_cpu_write(irq_map[vector], NULL);
|
||||
adata->moving = 0;
|
||||
adata->prev_cpu = adata->cpu;
|
||||
adata->prev_vec = adata->vec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
{
|
||||
struct avecintc_data *adata = irq_data_get_irq_chip_data(d);
|
||||
|
||||
msg->address_hi = 0x0;
|
||||
msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4)
|
||||
| ((cpu_logical_map(adata->cpu & 0xffff)) << 12);
|
||||
msg->data = 0x0;
|
||||
}
|
||||
|
||||
static struct irq_chip avec_irq_controller = {
|
||||
.name = "AVECINTC",
|
||||
.irq_ack = avecintc_ack_irq,
|
||||
.irq_mask = avecintc_mask_irq,
|
||||
.irq_unmask = avecintc_unmask_irq,
|
||||
#ifdef CONFIG_SMP
|
||||
.irq_set_affinity = avecintc_set_affinity,
|
||||
#endif
|
||||
.irq_compose_msi_msg = avecintc_compose_msi_msg,
|
||||
};
|
||||
|
||||
static void avecintc_irq_dispatch(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct irq_desc *d;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
while (true) {
|
||||
unsigned long vector = csr_read64(LOONGARCH_CSR_IRR);
|
||||
if (vector & IRR_INVALID_MASK)
|
||||
break;
|
||||
|
||||
vector &= IRR_VECTOR_MASK;
|
||||
|
||||
d = this_cpu_read(irq_map[vector]);
|
||||
if (d) {
|
||||
generic_handle_irq_desc(d);
|
||||
} else {
|
||||
spurious_interrupt();
|
||||
pr_warn("Unexpected IRQ occurs on CPU#%d [vector %ld]\n", smp_processor_id(), vector);
|
||||
}
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int avecintc_alloc_vector(struct irq_data *irqd, struct avecintc_data *adata)
|
||||
{
|
||||
int cpu, ret;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&loongarch_avec.lock);
|
||||
|
||||
ret = irq_matrix_alloc(loongarch_avec.vector_matrix, cpu_online_mask, false, &cpu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adata->prev_cpu = adata->cpu = cpu;
|
||||
adata->prev_vec = adata->vec = ret;
|
||||
per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(irqd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avecintc_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
for (unsigned int i = 0; i < nr_irqs; i++) {
|
||||
struct irq_data *irqd = irq_domain_get_irq_data(domain, virq + i);
|
||||
struct avecintc_data *adata = kzalloc(sizeof(*adata), GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!adata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = avecintc_alloc_vector(irqd, adata);
|
||||
if (ret < 0) {
|
||||
kfree(adata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
irq_domain_set_info(domain, virq + i, virq + i, &avec_irq_controller,
|
||||
adata, handle_edge_irq, NULL, NULL);
|
||||
irqd_set_single_target(irqd);
|
||||
irqd_set_affinity_on_activate(irqd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avecintc_free_vector(struct irq_data *irqd, struct avecintc_data *adata)
|
||||
{
|
||||
guard(raw_spinlock_irqsave)(&loongarch_avec.lock);
|
||||
|
||||
per_cpu(irq_map, adata->cpu)[adata->vec] = NULL;
|
||||
irq_matrix_free(loongarch_avec.vector_matrix, adata->cpu, adata->vec, false);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (!adata->moving)
|
||||
return;
|
||||
|
||||
per_cpu(irq_map, adata->prev_cpu)[adata->prev_vec] = NULL;
|
||||
irq_matrix_free(loongarch_avec.vector_matrix, adata->prev_cpu, adata->prev_vec, false);
|
||||
list_del_init(&adata->entry);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void avecintc_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
for (unsigned int i = 0; i < nr_irqs; i++) {
|
||||
struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
|
||||
|
||||
if (d) {
|
||||
struct avecintc_data *adata = irq_data_get_irq_chip_data(d);
|
||||
|
||||
avecintc_free_vector(d, adata);
|
||||
irq_domain_reset_irq_data(d);
|
||||
kfree(adata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops avecintc_domain_ops = {
|
||||
.alloc = avecintc_domain_alloc,
|
||||
.free = avecintc_domain_free,
|
||||
.select = msi_lib_irq_domain_select,
|
||||
};
|
||||
|
||||
static int __init irq_matrix_init(void)
|
||||
{
|
||||
loongarch_avec.vector_matrix = irq_alloc_matrix(NR_VECTORS, 0, NR_VECTORS);
|
||||
if (!loongarch_avec.vector_matrix)
|
||||
return -ENOMEM;
|
||||
|
||||
for (int i = 0; i < NR_LEGACY_VECTORS; i++)
|
||||
irq_matrix_assign_system(loongarch_avec.vector_matrix, i, false);
|
||||
|
||||
irq_matrix_online(loongarch_avec.vector_matrix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init avecintc_init(struct irq_domain *parent)
|
||||
{
|
||||
int ret, parent_irq;
|
||||
unsigned long value;
|
||||
|
||||
raw_spin_lock_init(&loongarch_avec.lock);
|
||||
|
||||
loongarch_avec.fwnode = irq_domain_alloc_named_fwnode("AVECINTC");
|
||||
if (!loongarch_avec.fwnode) {
|
||||
pr_err("Unable to allocate domain handle\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
loongarch_avec.domain = irq_domain_create_tree(loongarch_avec.fwnode,
|
||||
&avecintc_domain_ops, NULL);
|
||||
if (!loongarch_avec.domain) {
|
||||
pr_err("Unable to create IRQ domain\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_handle;
|
||||
}
|
||||
|
||||
parent_irq = irq_create_mapping(parent, INT_AVEC);
|
||||
if (!parent_irq) {
|
||||
pr_err("Failed to mapping hwirq\n");
|
||||
ret = -EINVAL;
|
||||
goto out_remove_domain;
|
||||
}
|
||||
|
||||
ret = irq_matrix_init();
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to init irq matrix\n");
|
||||
goto out_remove_domain;
|
||||
}
|
||||
irq_set_chained_handler_and_data(parent_irq, avecintc_irq_dispatch, NULL);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
pending_list_init(0);
|
||||
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_AVECINTC_STARTING,
|
||||
"irqchip/loongarch/avecintc:starting",
|
||||
avecintc_cpu_online, avecintc_cpu_offline);
|
||||
#endif
|
||||
value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
|
||||
value |= IOCSR_MISC_FUNC_AVEC_EN;
|
||||
iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC);
|
||||
|
||||
return ret;
|
||||
|
||||
out_remove_domain:
|
||||
irq_domain_remove(loongarch_avec.domain);
|
||||
out_free_handle:
|
||||
irq_domain_free_fwnode(loongarch_avec.fwnode);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init pch_msi_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
|
||||
|
||||
loongarch_avec.msi_base_addr = pchmsi_entry->msg_address - AVEC_MSG_OFFSET;
|
||||
|
||||
return pch_msi_acpi_init_avec(loongarch_avec.domain);
|
||||
}
|
||||
|
||||
static inline int __init acpi_cascade_irqdomain_init(void)
|
||||
{
|
||||
return acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1);
|
||||
}
|
||||
|
||||
int __init avecintc_acpi_init(struct irq_domain *parent)
|
||||
{
|
||||
int ret = avecintc_init(parent);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to init IRQ domain\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to init cascade IRQ domain\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <asm/loongarch.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
static struct irq_domain *irq_domain;
|
||||
struct fwnode_handle *cpuintc_handle;
|
||||
|
||||
@@ -140,7 +142,10 @@ static int __init acpi_cascade_irqdomain_init(void)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
if (cpu_has_avecint)
|
||||
r = avecintc_acpi_init(irq_domain);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
#define EIOINTC_REG_NODEMAP 0x14a0
|
||||
#define EIOINTC_REG_IPMAP 0x14c0
|
||||
#define EIOINTC_REG_ENABLE 0x1600
|
||||
@@ -360,6 +362,9 @@ static int __init acpi_cascade_irqdomain_init(void)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (cpu_has_avecint)
|
||||
return 0;
|
||||
|
||||
r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -396,8 +401,8 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
|
||||
|
||||
if (nr_pics == 1) {
|
||||
register_syscore_ops(&eiointc_syscore_ops);
|
||||
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
|
||||
"irqchip/loongarch/intc:starting",
|
||||
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_EIOINTC_STARTING,
|
||||
"irqchip/loongarch/eiointc:starting",
|
||||
eiointc_router_init, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
/* Registers */
|
||||
#define HTVEC_EN_OFF 0x20
|
||||
#define HTVEC_MAX_PARENT_IRQ 8
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <asm/loongson.h>
|
||||
#endif
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
#define LIOINTC_CHIP_IRQ 32
|
||||
#define LIOINTC_NUM_PARENT 4
|
||||
#define LIOINTC_NUM_CORES 4
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
/* Registers */
|
||||
#define LPC_INT_CTL 0x00
|
||||
#define LPC_INT_ENA 0x04
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "irq-msi-lib.h"
|
||||
#include "irq-loongson.h"
|
||||
|
||||
static int nr_pics;
|
||||
|
||||
struct pch_msi_data {
|
||||
@@ -27,26 +30,6 @@ struct pch_msi_data {
|
||||
|
||||
static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
|
||||
|
||||
static void pch_msi_mask_msi_irq(struct irq_data *d)
|
||||
{
|
||||
pci_msi_mask_irq(d);
|
||||
irq_chip_mask_parent(d);
|
||||
}
|
||||
|
||||
static void pch_msi_unmask_msi_irq(struct irq_data *d)
|
||||
{
|
||||
irq_chip_unmask_parent(d);
|
||||
pci_msi_unmask_irq(d);
|
||||
}
|
||||
|
||||
static struct irq_chip pch_msi_irq_chip = {
|
||||
.name = "PCH PCI MSI",
|
||||
.irq_mask = pch_msi_mask_msi_irq,
|
||||
.irq_unmask = pch_msi_unmask_msi_irq,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
};
|
||||
|
||||
static int pch_msi_allocate_hwirq(struct pch_msi_data *priv, int num_req)
|
||||
{
|
||||
int first;
|
||||
@@ -85,12 +68,6 @@ static void pch_msi_compose_msi_msg(struct irq_data *data,
|
||||
msg->data = data->hwirq;
|
||||
}
|
||||
|
||||
static struct msi_domain_info pch_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &pch_msi_irq_chip,
|
||||
};
|
||||
|
||||
static struct irq_chip middle_irq_chip = {
|
||||
.name = "PCH MSI",
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
@@ -155,13 +132,31 @@ static void pch_msi_middle_domain_free(struct irq_domain *domain,
|
||||
static const struct irq_domain_ops pch_msi_middle_domain_ops = {
|
||||
.alloc = pch_msi_middle_domain_alloc,
|
||||
.free = pch_msi_middle_domain_free,
|
||||
.select = msi_lib_irq_domain_select,
|
||||
};
|
||||
|
||||
#define PCH_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT)
|
||||
|
||||
#define PCH_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static struct msi_parent_ops pch_msi_parent_ops = {
|
||||
.required_flags = PCH_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = PCH_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_mask = MATCH_PCI_MSI,
|
||||
.bus_select_token = DOMAIN_BUS_NEXUS,
|
||||
.prefix = "PCH-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int pch_msi_init_domains(struct pch_msi_data *priv,
|
||||
struct irq_domain *parent,
|
||||
struct fwnode_handle *domain_handle)
|
||||
{
|
||||
struct irq_domain *middle_domain, *msi_domain;
|
||||
struct irq_domain *middle_domain;
|
||||
|
||||
middle_domain = irq_domain_create_hierarchy(parent, 0, priv->num_irqs,
|
||||
domain_handle,
|
||||
@@ -174,14 +169,8 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
|
||||
|
||||
irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS);
|
||||
|
||||
msi_domain = pci_msi_create_irq_domain(domain_handle,
|
||||
&pch_msi_domain_info,
|
||||
middle_domain);
|
||||
if (!msi_domain) {
|
||||
pr_err("Failed to create PCI MSI domain\n");
|
||||
irq_domain_remove(middle_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
|
||||
middle_domain->msi_parent_ops = &pch_msi_parent_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -266,17 +255,17 @@ IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init);
|
||||
#ifdef CONFIG_ACPI
|
||||
struct fwnode_handle *get_pch_msi_handle(int pci_segment)
|
||||
{
|
||||
int i;
|
||||
if (cpu_has_avecint)
|
||||
return pch_msi_handle[0];
|
||||
|
||||
for (i = 0; i < MAX_IO_PICS; i++) {
|
||||
for (int i = 0; i < MAX_IO_PICS; i++) {
|
||||
if (msi_group[i].pci_segment == pci_segment)
|
||||
return pch_msi_handle[i];
|
||||
}
|
||||
return NULL;
|
||||
return pch_msi_handle[0];
|
||||
}
|
||||
|
||||
int __init pch_msi_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_msi_pic *acpi_pchmsi)
|
||||
int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_msi_pic *acpi_pchmsi)
|
||||
{
|
||||
int ret;
|
||||
struct fwnode_handle *domain_handle;
|
||||
@@ -289,4 +278,18 @@ int __init pch_msi_acpi_init(struct irq_domain *parent,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __init pch_msi_acpi_init_avec(struct irq_domain *parent)
|
||||
{
|
||||
if (pch_msi_handle[0])
|
||||
return 0;
|
||||
|
||||
pch_msi_handle[0] = parent->fwnode;
|
||||
irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
|
||||
|
||||
parent->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
|
||||
parent->msi_parent_ops = &pch_msi_parent_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include "irq-loongson.h"
|
||||
|
||||
/* Registers */
|
||||
#define PCH_PIC_MASK 0x20
|
||||
#define PCH_PIC_HTMSI_EN 0x40
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef _DRIVERS_IRQCHIP_IRQ_LOONGSON_H
|
||||
#define _DRIVERS_IRQCHIP_IRQ_LOONGSON_H
|
||||
|
||||
int find_pch_pic(u32 gsi);
|
||||
|
||||
int liointc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_lio_pic *acpi_liointc);
|
||||
int eiointc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_eio_pic *acpi_eiointc);
|
||||
int avecintc_acpi_init(struct irq_domain *parent);
|
||||
|
||||
int htvec_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_ht_pic *acpi_htvec);
|
||||
int pch_lpc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_lpc_pic *acpi_pchlpc);
|
||||
int pch_pic_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_bio_pic *acpi_pchpic);
|
||||
int pch_msi_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_msi_pic *acpi_pchmsi);
|
||||
int pch_msi_acpi_init_avec(struct irq_domain *parent);
|
||||
|
||||
#endif /* _DRIVERS_IRQCHIP_IRQ_LOONGSON_H */
|
||||
@@ -234,37 +234,27 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
|
||||
struct mbigen_device *mgn_chip)
|
||||
{
|
||||
struct platform_device *child;
|
||||
struct device_node *np;
|
||||
u32 num_pins;
|
||||
int ret = 0;
|
||||
|
||||
for_each_child_of_node(pdev->dev.of_node, np) {
|
||||
for_each_child_of_node_scoped(pdev->dev.of_node, np) {
|
||||
if (!of_property_read_bool(np, "interrupt-controller"))
|
||||
continue;
|
||||
|
||||
child = of_platform_device_create(np, NULL, NULL);
|
||||
if (!child) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if (!child)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(child->dev.of_node, "num-pins",
|
||||
&num_pins) < 0) {
|
||||
dev_err(&pdev->dev, "No num-pins property\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!mbigen_create_device_domain(&child->dev, num_pins, mgn_chip)) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if (!mbigen_create_device_domain(&child->dev, num_pins, mgn_chip))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
of_node_put(np);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
@@ -325,8 +325,7 @@ static int __init omap_init_irq(u32 base, struct device_node *node)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
omap_intc_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry omap_intc_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
extern unsigned long irq_err_count;
|
||||
u32 irqnr;
|
||||
|
||||
@@ -127,8 +127,7 @@ static int __init sa1100irq_init_devicefs(void)
|
||||
|
||||
device_initcall(sa1100irq_init_devicefs);
|
||||
|
||||
static asmlinkage void __exception_irq_entry
|
||||
sa1100_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry sa1100_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
uint32_t icip, icmr, mask;
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
|
||||
* Keep iterating over all registered FPGA IRQ controllers until there are
|
||||
* no pending interrupts.
|
||||
*/
|
||||
static asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs)
|
||||
static void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
int i, handled;
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
* - has multiple clocks.
|
||||
* - has no usable clock due to jitter or packet loss (VoIP).
|
||||
* In this case the system's clock is used. The clock resolution depends on
|
||||
* the jiffie resolution.
|
||||
* the jiffy resolution.
|
||||
*
|
||||
* If a member joins a conference:
|
||||
*
|
||||
|
||||
@@ -104,7 +104,7 @@ static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
|
||||
return 0;
|
||||
} else {
|
||||
/* wait_event_timeout does not guarantee a delay of at
|
||||
* least one whole jiffie, so timeout must be no less
|
||||
* least one whole jiffy, so timeout must be no less
|
||||
* than two.
|
||||
*/
|
||||
timeout = max(usecs_to_jiffies(MVMDIO_SMI_TIMEOUT), 2);
|
||||
|
||||
@@ -295,6 +295,8 @@ const struct pmc_reg_map adl_reg_map = {
|
||||
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_num_modes = ADL_LPM_NUM_MODES,
|
||||
.lpm_num_maps = ADL_LPM_NUM_MAPS,
|
||||
|
||||
@@ -200,6 +200,8 @@ const struct pmc_reg_map cnp_reg_map = {
|
||||
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi_pmtmr.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -1208,6 +1209,38 @@ static bool pmc_core_is_pson_residency_enabled(struct pmc_dev *pmcdev)
|
||||
return val == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable ACPI PM Timer
|
||||
*
|
||||
* This function is intended to be a callback for ACPI PM suspend/resume event.
|
||||
* The ACPI PM Timer is enabled on resume only if it was enabled during suspend.
|
||||
*/
|
||||
static void pmc_core_acpi_pm_timer_suspend_resume(void *data, bool suspend)
|
||||
{
|
||||
struct pmc_dev *pmcdev = data;
|
||||
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
|
||||
const struct pmc_reg_map *map = pmc->map;
|
||||
bool enabled;
|
||||
u32 reg;
|
||||
|
||||
if (!map->acpi_pm_tmr_ctl_offset)
|
||||
return;
|
||||
|
||||
guard(mutex)(&pmcdev->lock);
|
||||
|
||||
if (!suspend && !pmcdev->enable_acpi_pm_timer_on_resume)
|
||||
return;
|
||||
|
||||
reg = pmc_core_reg_read(pmc, map->acpi_pm_tmr_ctl_offset);
|
||||
enabled = !(reg & map->acpi_pm_tmr_disable_bit);
|
||||
if (suspend)
|
||||
reg |= map->acpi_pm_tmr_disable_bit;
|
||||
else
|
||||
reg &= ~map->acpi_pm_tmr_disable_bit;
|
||||
pmc_core_reg_write(pmc, map->acpi_pm_tmr_ctl_offset, reg);
|
||||
|
||||
pmcdev->enable_acpi_pm_timer_on_resume = suspend && enabled;
|
||||
}
|
||||
|
||||
static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
|
||||
{
|
||||
@@ -1404,6 +1437,7 @@ static int pmc_core_probe(struct platform_device *pdev)
|
||||
struct pmc_dev *pmcdev;
|
||||
const struct x86_cpu_id *cpu_id;
|
||||
int (*core_init)(struct pmc_dev *pmcdev);
|
||||
const struct pmc_reg_map *map;
|
||||
struct pmc *primary_pmc;
|
||||
int ret;
|
||||
|
||||
@@ -1462,6 +1496,11 @@ static int pmc_core_probe(struct platform_device *pdev)
|
||||
pm_report_max_hw_sleep(FIELD_MAX(SLP_S0_RES_COUNTER_MASK) *
|
||||
pmc_core_adjust_slp_s0_step(primary_pmc, 1));
|
||||
|
||||
map = primary_pmc->map;
|
||||
if (map->acpi_pm_tmr_ctl_offset)
|
||||
acpi_pmtmr_register_suspend_resume_callback(pmc_core_acpi_pm_timer_suspend_resume,
|
||||
pmcdev);
|
||||
|
||||
device_initialized = true;
|
||||
dev_info(&pdev->dev, " initialized\n");
|
||||
|
||||
@@ -1471,6 +1510,12 @@ static int pmc_core_probe(struct platform_device *pdev)
|
||||
static void pmc_core_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
|
||||
const struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
|
||||
const struct pmc_reg_map *map = pmc->map;
|
||||
|
||||
if (map->acpi_pm_tmr_ctl_offset)
|
||||
acpi_pmtmr_unregister_suspend_resume_callback();
|
||||
|
||||
pmc_core_dbgfs_unregister(pmcdev);
|
||||
pmc_core_clean_structure(pdev);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ struct telem_endpoint;
|
||||
#define SPT_PMC_LTR_SCC 0x3A0
|
||||
#define SPT_PMC_LTR_ISH 0x3A4
|
||||
|
||||
#define SPT_PMC_ACPI_PM_TMR_CTL_OFFSET 0x18FC
|
||||
|
||||
/* Sunrise Point: PGD PFET Enable Ack Status Registers */
|
||||
enum ppfear_regs {
|
||||
SPT_PMC_XRAM_PPFEAR0A = 0x590,
|
||||
@@ -148,6 +150,8 @@ enum ppfear_regs {
|
||||
#define SPT_PMC_VRIC1_SLPS0LVEN BIT(13)
|
||||
#define SPT_PMC_VRIC1_XTALSDQDIS BIT(22)
|
||||
|
||||
#define SPT_PMC_BIT_ACPI_PM_TMR_DISABLE BIT(1)
|
||||
|
||||
/* Cannonlake Power Management Controller register offsets */
|
||||
#define CNP_PMC_SLPS0_DBG_OFFSET 0x10B4
|
||||
#define CNP_PMC_PM_CFG_OFFSET 0x1818
|
||||
@@ -351,6 +355,8 @@ struct pmc_reg_map {
|
||||
const u8 *lpm_reg_index;
|
||||
const u32 pson_residency_offset;
|
||||
const u32 pson_residency_counter_step;
|
||||
const u32 acpi_pm_tmr_ctl_offset;
|
||||
const u32 acpi_pm_tmr_disable_bit;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -424,6 +430,8 @@ struct pmc_dev {
|
||||
u32 die_c6_offset;
|
||||
struct telem_endpoint *punit_ep;
|
||||
struct pmc_info *regmap_list;
|
||||
|
||||
bool enable_acpi_pm_timer_on_resume;
|
||||
};
|
||||
|
||||
enum pmc_index {
|
||||
|
||||
@@ -46,6 +46,8 @@ const struct pmc_reg_map icl_reg_map = {
|
||||
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
};
|
||||
|
||||
@@ -462,6 +462,8 @@ const struct pmc_reg_map mtl_socm_reg_map = {
|
||||
.ppfear_buckets = MTL_SOCM_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.lpm_num_maps = ADL_LPM_NUM_MAPS,
|
||||
.ltr_ignore_max = MTL_SOCM_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
|
||||
@@ -130,6 +130,8 @@ const struct pmc_reg_map spt_reg_map = {
|
||||
.ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED,
|
||||
.pm_vric1_offset = SPT_PMC_VRIC1_OFFSET,
|
||||
};
|
||||
|
||||
@@ -197,6 +197,8 @@ const struct pmc_reg_map tgl_reg_map = {
|
||||
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
|
||||
.acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
|
||||
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_num_maps = TGL_LPM_NUM_MAPS,
|
||||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
|
||||
@@ -423,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
|
||||
|
||||
port = &serial8250_ports[co->index].port;
|
||||
/* link port to console */
|
||||
port->cons = co;
|
||||
uart_port_set_cons(port, co);
|
||||
|
||||
retval = serial8250_console_setup(port, options, false);
|
||||
if (retval != 0)
|
||||
port->cons = NULL;
|
||||
uart_port_set_cons(port, NULL);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
|
||||
continue;
|
||||
|
||||
co->index = i;
|
||||
port->cons = co;
|
||||
uart_port_set_cons(port, co);
|
||||
return serial8250_console_setup(port, options, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -2480,7 +2480,7 @@ static int pl011_console_match(struct console *co, char *name, int idx,
|
||||
continue;
|
||||
|
||||
co->index = i;
|
||||
port->cons = co;
|
||||
uart_port_set_cons(port, co);
|
||||
return pl011_console_setup(co, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -3176,8 +3176,15 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
|
||||
state->uart_port = uport;
|
||||
uport->state = state;
|
||||
|
||||
/*
|
||||
* If this port is in use as a console then the spinlock is already
|
||||
* initialised.
|
||||
*/
|
||||
if (!uart_console_registered(uport))
|
||||
uart_port_spin_lock_init(uport);
|
||||
|
||||
state->pm_state = UART_PM_STATE_UNDEFINED;
|
||||
uport->cons = drv->cons;
|
||||
uart_port_set_cons(uport, drv->cons);
|
||||
uport->minor = drv->tty_driver->minor_start + uport->line;
|
||||
uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
|
||||
drv->tty_driver->name_base + uport->line);
|
||||
@@ -3186,13 +3193,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this port is in use as a console then the spinlock is already
|
||||
* initialised.
|
||||
*/
|
||||
if (!uart_console_registered(uport))
|
||||
uart_port_spin_lock_init(uport);
|
||||
|
||||
if (uport->cons && uport->dev)
|
||||
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
|
||||
|
||||
|
||||
@@ -3573,7 +3573,7 @@ static ssize_t show_cons_active(struct device *dev,
|
||||
for_each_console(c) {
|
||||
if (!c->device)
|
||||
continue;
|
||||
if (!c->write)
|
||||
if (!(c->flags & CON_NBCON) && !c->write)
|
||||
continue;
|
||||
if ((c->flags & CON_ENABLED) == 0)
|
||||
continue;
|
||||
|
||||
+8
-7
@@ -2514,13 +2514,13 @@ static void *timers_start(struct seq_file *m, loff_t *pos)
|
||||
if (!tp->sighand)
|
||||
return ERR_PTR(-ESRCH);
|
||||
|
||||
return seq_list_start(&tp->task->signal->posix_timers, *pos);
|
||||
return seq_hlist_start(&tp->task->signal->posix_timers, *pos);
|
||||
}
|
||||
|
||||
static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
struct timers_private *tp = m->private;
|
||||
return seq_list_next(v, &tp->task->signal->posix_timers, pos);
|
||||
return seq_hlist_next(v, &tp->task->signal->posix_timers, pos);
|
||||
}
|
||||
|
||||
static void timers_stop(struct seq_file *m, void *v)
|
||||
@@ -2549,7 +2549,7 @@ static int show_timer(struct seq_file *m, void *v)
|
||||
[SIGEV_THREAD] = "thread",
|
||||
};
|
||||
|
||||
timer = list_entry((struct list_head *)v, struct k_itimer, list);
|
||||
timer = hlist_entry((struct hlist_node *)v, struct k_itimer, list);
|
||||
notify = timer->it_sigev_notify;
|
||||
|
||||
seq_printf(m, "ID: %d\n", timer->it_id);
|
||||
@@ -2627,10 +2627,11 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
|
||||
}
|
||||
|
||||
task_lock(p);
|
||||
if (slack_ns == 0)
|
||||
p->timer_slack_ns = p->default_timer_slack_ns;
|
||||
else
|
||||
p->timer_slack_ns = slack_ns;
|
||||
if (task_is_realtime(p))
|
||||
slack_ns = 0;
|
||||
else if (slack_ns == 0)
|
||||
slack_ns = p->default_timer_slack_ns;
|
||||
p->timer_slack_ns = slack_ns;
|
||||
task_unlock(p);
|
||||
|
||||
out:
|
||||
|
||||
+5
-2
@@ -21,6 +21,7 @@ static int show_console_dev(struct seq_file *m, void *v)
|
||||
{ CON_ENABLED, 'E' },
|
||||
{ CON_CONSDEV, 'C' },
|
||||
{ CON_BOOT, 'B' },
|
||||
{ CON_NBCON, 'N' },
|
||||
{ CON_PRINTBUFFER, 'p' },
|
||||
{ CON_BRL, 'b' },
|
||||
{ CON_ANYTIME, 'a' },
|
||||
@@ -58,8 +59,8 @@ static int show_console_dev(struct seq_file *m, void *v)
|
||||
seq_printf(m, "%s%d", con->name, con->index);
|
||||
seq_pad(m, ' ');
|
||||
seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
|
||||
con->write ? 'W' : '-', con->unblank ? 'U' : '-',
|
||||
flags);
|
||||
((con->flags & CON_NBCON) || con->write) ? 'W' : '-',
|
||||
con->unblank ? 'U' : '-', flags);
|
||||
if (dev)
|
||||
seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
|
||||
|
||||
@@ -68,6 +69,7 @@ static int show_console_dev(struct seq_file *m, void *v)
|
||||
}
|
||||
|
||||
static void *c_start(struct seq_file *m, loff_t *pos)
|
||||
__acquires(&console_mutex)
|
||||
{
|
||||
struct console *con;
|
||||
loff_t off = 0;
|
||||
@@ -94,6 +96,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
}
|
||||
|
||||
static void c_stop(struct seq_file *m, void *v)
|
||||
__releases(&console_mutex)
|
||||
{
|
||||
console_list_unlock();
|
||||
}
|
||||
|
||||
+4
-7
@@ -77,19 +77,16 @@ u64 select_estimate_accuracy(struct timespec64 *tv)
|
||||
{
|
||||
u64 ret;
|
||||
struct timespec64 now;
|
||||
u64 slack = current->timer_slack_ns;
|
||||
|
||||
/*
|
||||
* Realtime tasks get a slack of 0 for obvious reasons.
|
||||
*/
|
||||
|
||||
if (rt_task(current))
|
||||
if (slack == 0)
|
||||
return 0;
|
||||
|
||||
ktime_get_ts64(&now);
|
||||
now = timespec64_sub(*tv, now);
|
||||
ret = __estimate_accuracy(&now);
|
||||
if (ret < current->timer_slack_ns)
|
||||
return current->timer_slack_ns;
|
||||
if (ret < slack)
|
||||
return slack;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -159,7 +159,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
ret = dequeue_signal(current, &ctx->sigmask, info, &type);
|
||||
ret = dequeue_signal(&ctx->sigmask, info, &type);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
if (!nonblock)
|
||||
@@ -174,7 +174,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info
|
||||
add_wait_queue(¤t->sighand->signalfd_wqh, &wait);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
ret = dequeue_signal(current, &ctx->sigmask, info, &type);
|
||||
ret = dequeue_signal(&ctx->sigmask, info, &type);
|
||||
if (ret != 0)
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
|
||||
+1
-1
@@ -210,7 +210,7 @@ struct xfs_buf {
|
||||
* success the write is considered to be failed permanently and the
|
||||
* iodone handler will take appropriate action.
|
||||
*
|
||||
* For retry timeouts, we record the jiffie of the first failure. This
|
||||
* For retry timeouts, we record the jiffy of the first failure. This
|
||||
* means that we can change the retry timeout for buffers already under
|
||||
* I/O and thus avoid getting stuck in a retry loop with a long timeout.
|
||||
*
|
||||
|
||||
@@ -26,6 +26,19 @@ static inline u32 acpi_pm_read_early(void)
|
||||
return acpi_pm_read_verified() & ACPI_PM_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register callback for suspend and resume event
|
||||
*
|
||||
* @cb Callback triggered on suspend and resume
|
||||
* @data Data passed with the callback
|
||||
*/
|
||||
void acpi_pmtmr_register_suspend_resume_callback(void (*cb)(void *data, bool suspend), void *data);
|
||||
|
||||
/**
|
||||
* Remove registered callback for suspend and resume event
|
||||
*/
|
||||
void acpi_pmtmr_unregister_suspend_resume_callback(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline u32 acpi_pm_read_early(void)
|
||||
|
||||
+143
-15
@@ -16,7 +16,9 @@
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcuwait.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vesa.h>
|
||||
|
||||
@@ -303,7 +305,7 @@ struct nbcon_write_context {
|
||||
/**
|
||||
* struct console - The console descriptor structure
|
||||
* @name: The name of the console driver
|
||||
* @write: Write callback to output messages (Optional)
|
||||
* @write: Legacy write callback to output messages (Optional)
|
||||
* @read: Read callback for console input (Optional)
|
||||
* @device: The underlying TTY device driver (Optional)
|
||||
* @unblank: Callback to unblank the console (Optional)
|
||||
@@ -320,10 +322,14 @@ struct nbcon_write_context {
|
||||
* @data: Driver private data
|
||||
* @node: hlist node for the console list
|
||||
*
|
||||
* @write_atomic: Write callback for atomic context
|
||||
* @nbcon_state: State for nbcon consoles
|
||||
* @nbcon_seq: Sequence number of the next record for nbcon to print
|
||||
* @nbcon_device_ctxt: Context available for non-printing operations
|
||||
* @nbcon_prev_seq: Seq num the previous nbcon owner was assigned to print
|
||||
* @pbufs: Pointer to nbcon private buffer
|
||||
* @kthread: Printer kthread for this console
|
||||
* @rcuwait: RCU-safe wait object for @kthread waking
|
||||
* @irq_work: Defer @kthread waking to IRQ work context
|
||||
*/
|
||||
struct console {
|
||||
char name[16];
|
||||
@@ -345,11 +351,121 @@ struct console {
|
||||
struct hlist_node node;
|
||||
|
||||
/* nbcon console specific members */
|
||||
bool (*write_atomic)(struct console *con,
|
||||
struct nbcon_write_context *wctxt);
|
||||
|
||||
/**
|
||||
* @write_atomic:
|
||||
*
|
||||
* NBCON callback to write out text in any context. (Optional)
|
||||
*
|
||||
* This callback is called with the console already acquired. However,
|
||||
* a higher priority context is allowed to take it over by default.
|
||||
*
|
||||
* The callback must call nbcon_enter_unsafe() and nbcon_exit_unsafe()
|
||||
* around any code where the takeover is not safe, for example, when
|
||||
* manipulating the serial port registers.
|
||||
*
|
||||
* nbcon_enter_unsafe() will fail if the context has lost the console
|
||||
* ownership in the meantime. In this case, the callback is no longer
|
||||
* allowed to go forward. It must back out immediately and carefully.
|
||||
* The buffer content is also no longer trusted since it no longer
|
||||
* belongs to the context.
|
||||
*
|
||||
* The callback should allow the takeover whenever it is safe. It
|
||||
* increases the chance to see messages when the system is in trouble.
|
||||
* If the driver must reacquire ownership in order to finalize or
|
||||
* revert hardware changes, nbcon_reacquire_nobuf() can be used.
|
||||
* However, on reacquire the buffer content is no longer available. A
|
||||
* reacquire cannot be used to resume printing.
|
||||
*
|
||||
* The callback can be called from any context (including NMI).
|
||||
* Therefore it must avoid usage of any locking and instead rely
|
||||
* on the console ownership for synchronization.
|
||||
*/
|
||||
void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
|
||||
|
||||
/**
|
||||
* @write_thread:
|
||||
*
|
||||
* NBCON callback to write out text in task context.
|
||||
*
|
||||
* This callback must be called only in task context with both
|
||||
* device_lock() and the nbcon console acquired with
|
||||
* NBCON_PRIO_NORMAL.
|
||||
*
|
||||
* The same rules for console ownership verification and unsafe
|
||||
* sections handling applies as with write_atomic().
|
||||
*
|
||||
* The console ownership handling is necessary for synchronization
|
||||
* against write_atomic() which is synchronized only via the context.
|
||||
*
|
||||
* The device_lock() provides the primary serialization for operations
|
||||
* on the device. It might be as relaxed (mutex)[*] or as tight
|
||||
* (disabled preemption and interrupts) as needed. It allows
|
||||
* the kthread to operate in the least restrictive mode[**].
|
||||
*
|
||||
* [*] Standalone nbcon_context_try_acquire() is not safe with
|
||||
* the preemption enabled, see nbcon_owner_matches(). But it
|
||||
* can be safe when always called in the preemptive context
|
||||
* under the device_lock().
|
||||
*
|
||||
* [**] The device_lock() makes sure that nbcon_context_try_acquire()
|
||||
* would never need to spin which is important especially with
|
||||
* PREEMPT_RT.
|
||||
*/
|
||||
void (*write_thread)(struct console *con, struct nbcon_write_context *wctxt);
|
||||
|
||||
/**
|
||||
* @device_lock:
|
||||
*
|
||||
* NBCON callback to begin synchronization with driver code.
|
||||
*
|
||||
* Console drivers typically must deal with access to the hardware
|
||||
* via user input/output (such as an interactive login shell) and
|
||||
* output of kernel messages via printk() calls. This callback is
|
||||
* called by the printk-subsystem whenever it needs to synchronize
|
||||
* with hardware access by the driver. It should be implemented to
|
||||
* use whatever synchronization mechanism the driver is using for
|
||||
* itself (for example, the port lock for uart serial consoles).
|
||||
*
|
||||
* The callback is always called from task context. It may use any
|
||||
* synchronization method required by the driver.
|
||||
*
|
||||
* IMPORTANT: The callback MUST disable migration. The console driver
|
||||
* may be using a synchronization mechanism that already takes
|
||||
* care of this (such as spinlocks). Otherwise this function must
|
||||
* explicitly call migrate_disable().
|
||||
*
|
||||
* The flags argument is provided as a convenience to the driver. It
|
||||
* will be passed again to device_unlock(). It can be ignored if the
|
||||
* driver does not need it.
|
||||
*/
|
||||
void (*device_lock)(struct console *con, unsigned long *flags);
|
||||
|
||||
/**
|
||||
* @device_unlock:
|
||||
*
|
||||
* NBCON callback to finish synchronization with driver code.
|
||||
*
|
||||
* It is the counterpart to device_lock().
|
||||
*
|
||||
* This callback is always called from task context. It must
|
||||
* appropriately re-enable migration (depending on how device_lock()
|
||||
* disabled migration).
|
||||
*
|
||||
* The flags argument is the value of the same variable that was
|
||||
* passed to device_lock().
|
||||
*/
|
||||
void (*device_unlock)(struct console *con, unsigned long flags);
|
||||
|
||||
atomic_t __private nbcon_state;
|
||||
atomic_long_t __private nbcon_seq;
|
||||
struct nbcon_context __private nbcon_device_ctxt;
|
||||
atomic_long_t __private nbcon_prev_seq;
|
||||
|
||||
struct printk_buffers *pbufs;
|
||||
struct task_struct *kthread;
|
||||
struct rcuwait rcuwait;
|
||||
struct irq_work irq_work;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
@@ -378,28 +494,34 @@ extern void console_list_unlock(void) __releases(console_mutex);
|
||||
extern struct hlist_head console_list;
|
||||
|
||||
/**
|
||||
* console_srcu_read_flags - Locklessly read the console flags
|
||||
* console_srcu_read_flags - Locklessly read flags of a possibly registered
|
||||
* console
|
||||
* @con: struct console pointer of console to read flags from
|
||||
*
|
||||
* This function provides the necessary READ_ONCE() and data_race()
|
||||
* notation for locklessly reading the console flags. The READ_ONCE()
|
||||
* in this function matches the WRITE_ONCE() when @flags are modified
|
||||
* for registered consoles with console_srcu_write_flags().
|
||||
* Locklessly reading @con->flags provides a consistent read value because
|
||||
* there is at most one CPU modifying @con->flags and that CPU is using only
|
||||
* read-modify-write operations to do so.
|
||||
*
|
||||
* Only use this function to read console flags when locklessly
|
||||
* iterating the console list via srcu.
|
||||
* Requires console_srcu_read_lock to be held, which implies that @con might
|
||||
* be a registered console. The purpose of holding console_srcu_read_lock is
|
||||
* to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
|
||||
* and that no exit/cleanup routines will run if the console is currently
|
||||
* undergoing unregistration.
|
||||
*
|
||||
* If the caller is holding the console_list_lock or it is _certain_ that
|
||||
* @con is not and will not become registered, the caller may read
|
||||
* @con->flags directly instead.
|
||||
*
|
||||
* Context: Any context.
|
||||
* Return: The current value of the @con->flags field.
|
||||
*/
|
||||
static inline short console_srcu_read_flags(const struct console *con)
|
||||
{
|
||||
WARN_ON_ONCE(!console_srcu_read_lock_is_held());
|
||||
|
||||
/*
|
||||
* Locklessly reading console->flags provides a consistent
|
||||
* read value because there is at most one CPU modifying
|
||||
* console->flags and that CPU is using only read-modify-write
|
||||
* operations to do so.
|
||||
* The READ_ONCE() matches the WRITE_ONCE() when @flags are modified
|
||||
* for registered consoles with console_srcu_write_flags().
|
||||
*/
|
||||
return data_race(READ_ONCE(con->flags));
|
||||
}
|
||||
@@ -477,13 +599,19 @@ static inline bool console_is_registered(const struct console *con)
|
||||
hlist_for_each_entry(con, &console_list, node)
|
||||
|
||||
#ifdef CONFIG_PRINTK
|
||||
extern void nbcon_cpu_emergency_enter(void);
|
||||
extern void nbcon_cpu_emergency_exit(void);
|
||||
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
|
||||
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
|
||||
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
|
||||
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
|
||||
#else
|
||||
static inline void nbcon_cpu_emergency_enter(void) { }
|
||||
static inline void nbcon_cpu_emergency_exit(void) { }
|
||||
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
|
||||
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
||||
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
||||
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
|
||||
#endif
|
||||
|
||||
extern int console_set_on_cmdline;
|
||||
|
||||
@@ -144,7 +144,8 @@ enum cpuhp_state {
|
||||
CPUHP_AP_IRQ_ARMADA_XP_STARTING,
|
||||
CPUHP_AP_IRQ_BCM2836_STARTING,
|
||||
CPUHP_AP_IRQ_MIPS_GIC_STARTING,
|
||||
CPUHP_AP_IRQ_LOONGARCH_STARTING,
|
||||
CPUHP_AP_IRQ_EIOINTC_STARTING,
|
||||
CPUHP_AP_IRQ_AVECINTC_STARTING,
|
||||
CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
|
||||
CPUHP_AP_IRQ_RISCV_IMSIC_STARTING,
|
||||
CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING,
|
||||
|
||||
@@ -276,7 +276,7 @@ struct irq_affinity_notify {
|
||||
#define IRQ_AFFINITY_MAX_SETS 4
|
||||
|
||||
/**
|
||||
* struct irq_affinity - Description for automatic irq affinity assignements
|
||||
* struct irq_affinity - Description for automatic irq affinity assignments
|
||||
* @pre_vectors: Don't apply affinity to @pre_vectors at beginning of
|
||||
* the MSI(-X) vector space
|
||||
* @post_vectors: Don't apply affinity to @post_vectors at end of
|
||||
@@ -594,7 +594,7 @@ extern const char * const softirq_to_name[NR_SOFTIRQS];
|
||||
|
||||
struct softirq_action
|
||||
{
|
||||
void (*action)(struct softirq_action *);
|
||||
void (*action)(void);
|
||||
};
|
||||
|
||||
asmlinkage void do_softirq(void);
|
||||
@@ -609,7 +609,7 @@ static inline void do_softirq_post_smp_call_flush(unsigned int unused)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void open_softirq(int nr, void (*action)(struct softirq_action *));
|
||||
extern void open_softirq(int nr, void (*action)(void));
|
||||
extern void softirq_init(void);
|
||||
extern void __raise_softirq_irqoff(unsigned int nr);
|
||||
|
||||
|
||||
@@ -991,7 +991,6 @@ void irq_init_desc(unsigned int irq);
|
||||
* @ack: Ack register offset to reg_base
|
||||
* @eoi: Eoi register offset to reg_base
|
||||
* @type: Type configuration register offset to reg_base
|
||||
* @polarity: Polarity configuration register offset to reg_base
|
||||
*/
|
||||
struct irq_chip_regs {
|
||||
unsigned long enable;
|
||||
@@ -1000,7 +999,6 @@ struct irq_chip_regs {
|
||||
unsigned long ack;
|
||||
unsigned long eoi;
|
||||
unsigned long type;
|
||||
unsigned long polarity;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1040,8 +1038,6 @@ struct irq_chip_type {
|
||||
* @irq_base: Interrupt base nr for this chip
|
||||
* @irq_cnt: Number of interrupts handled by this chip
|
||||
* @mask_cache: Cached mask register shared between all chip types
|
||||
* @type_cache: Cached type register
|
||||
* @polarity_cache: Cached polarity register
|
||||
* @wake_enabled: Interrupt can wakeup from suspend
|
||||
* @wake_active: Interrupt is marked as an wakeup from suspend source
|
||||
* @num_ct: Number of available irq_chip_type instances (usually 1)
|
||||
@@ -1068,8 +1064,6 @@ struct irq_chip_generic {
|
||||
unsigned int irq_base;
|
||||
unsigned int irq_cnt;
|
||||
u32 mask_cache;
|
||||
u32 type_cache;
|
||||
u32 polarity_cache;
|
||||
u32 wake_enabled;
|
||||
u32 wake_active;
|
||||
unsigned int num_ct;
|
||||
|
||||
@@ -291,7 +291,12 @@ struct irq_domain_chip_generic_info;
|
||||
* @hwirq_max: Maximum number of interrupts supported by controller
|
||||
* @direct_max: Maximum value of direct maps;
|
||||
* Use ~0 for no limit; 0 for no direct mapping
|
||||
* @hwirq_base: The first hardware interrupt number (legacy domains only)
|
||||
* @virq_base: The first Linux interrupt number for legacy domains to
|
||||
* immediately associate the interrupts after domain creation
|
||||
* @bus_token: Domain bus token
|
||||
* @name_suffix: Optional name suffix to avoid collisions when multiple
|
||||
* domains are added using same fwnode
|
||||
* @ops: Domain operation callbacks
|
||||
* @host_data: Controller private data pointer
|
||||
* @dgc_info: Geneneric chip information structure pointer used to
|
||||
@@ -307,7 +312,10 @@ struct irq_domain_info {
|
||||
unsigned int size;
|
||||
irq_hw_number_t hwirq_max;
|
||||
int direct_max;
|
||||
unsigned int hwirq_base;
|
||||
unsigned int virq_base;
|
||||
enum irq_domain_bus_token bus_token;
|
||||
const char *name_suffix;
|
||||
const struct irq_domain_ops *ops;
|
||||
void *host_data;
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
@@ -418,7 +418,7 @@ extern unsigned long preset_lpj;
|
||||
#define NSEC_CONVERSION ((unsigned long)((((u64)1 << NSEC_JIFFIE_SC) +\
|
||||
TICK_NSEC -1) / (u64)TICK_NSEC))
|
||||
/*
|
||||
* The maximum jiffie value is (MAX_INT >> 1). Here we translate that
|
||||
* The maximum jiffy value is (MAX_INT >> 1). Here we translate that
|
||||
* into seconds. The 64-bit case will overflow if we are not careful,
|
||||
* so use the messy SH_DIV macro to do it. Still all constants.
|
||||
*/
|
||||
|
||||
@@ -158,7 +158,7 @@ static inline void posix_cputimers_init_work(void) { }
|
||||
* @rcu: RCU head for freeing the timer.
|
||||
*/
|
||||
struct k_itimer {
|
||||
struct list_head list;
|
||||
struct hlist_node list;
|
||||
struct hlist_node t_hash;
|
||||
spinlock_t it_lock;
|
||||
const struct k_clock *kclock;
|
||||
|
||||
+29
-4
@@ -9,6 +9,8 @@
|
||||
#include <linux/ratelimit_types.h>
|
||||
#include <linux/once_lite.h>
|
||||
|
||||
struct console;
|
||||
|
||||
extern const char linux_banner[];
|
||||
extern const char linux_proc_banner[];
|
||||
|
||||
@@ -161,15 +163,16 @@ int _printk(const char *fmt, ...);
|
||||
*/
|
||||
__printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
|
||||
|
||||
extern void __printk_safe_enter(void);
|
||||
extern void __printk_safe_exit(void);
|
||||
extern void __printk_deferred_enter(void);
|
||||
extern void __printk_deferred_exit(void);
|
||||
|
||||
/*
|
||||
* The printk_deferred_enter/exit macros are available only as a hack for
|
||||
* some code paths that need to defer all printk console printing. Interrupts
|
||||
* must be disabled for the deferred duration.
|
||||
*/
|
||||
#define printk_deferred_enter __printk_safe_enter
|
||||
#define printk_deferred_exit __printk_safe_exit
|
||||
#define printk_deferred_enter() __printk_deferred_enter()
|
||||
#define printk_deferred_exit() __printk_deferred_exit()
|
||||
|
||||
/*
|
||||
* Please don't use printk_ratelimit(), because it shares ratelimiting state
|
||||
@@ -197,6 +200,10 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
|
||||
extern asmlinkage void dump_stack(void) __cold;
|
||||
void printk_trigger_flush(void);
|
||||
void console_try_replay_all(void);
|
||||
void printk_legacy_allow_panic_sync(void);
|
||||
extern bool nbcon_device_try_acquire(struct console *con);
|
||||
extern void nbcon_device_release(struct console *con);
|
||||
void nbcon_atomic_flush_unsafe(void);
|
||||
#else
|
||||
static inline __printf(1, 0)
|
||||
int vprintk(const char *s, va_list args)
|
||||
@@ -279,6 +286,24 @@ static inline void printk_trigger_flush(void)
|
||||
static inline void console_try_replay_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void printk_legacy_allow_panic_sync(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool nbcon_device_try_acquire(struct console *con)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void nbcon_device_release(struct console *con)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nbcon_atomic_flush_unsafe(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool this_cpu_in_panic(void);
|
||||
|
||||
@@ -137,7 +137,7 @@ struct signal_struct {
|
||||
|
||||
/* POSIX.1b Interval Timers */
|
||||
unsigned int next_posix_timer_id;
|
||||
struct list_head posix_timers;
|
||||
struct hlist_head posix_timers;
|
||||
|
||||
/* ITIMER_REAL timer for the process */
|
||||
struct hrtimer real_timer;
|
||||
@@ -276,8 +276,7 @@ static inline void signal_set_stop_flags(struct signal_struct *sig,
|
||||
extern void flush_signals(struct task_struct *);
|
||||
extern void ignore_signals(struct task_struct *);
|
||||
extern void flush_signal_handlers(struct task_struct *, int force_default);
|
||||
extern int dequeue_signal(struct task_struct *task, sigset_t *mask,
|
||||
kernel_siginfo_t *info, enum pid_type *type);
|
||||
extern int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type);
|
||||
|
||||
static inline int kernel_dequeue_signal(void)
|
||||
{
|
||||
@@ -287,7 +286,7 @@ static inline int kernel_dequeue_signal(void)
|
||||
int ret;
|
||||
|
||||
spin_lock_irq(&task->sighand->siglock);
|
||||
ret = dequeue_signal(task, &task->blocked, &__info, &__type);
|
||||
ret = dequeue_signal(&task->blocked, &__info, &__type);
|
||||
spin_unlock_irq(&task->sighand->siglock);
|
||||
|
||||
return ret;
|
||||
|
||||
+115
-2
@@ -11,6 +11,8 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
@@ -590,6 +592,95 @@ struct uart_port {
|
||||
void *private_data; /* generic platform data pointer */
|
||||
};
|
||||
|
||||
/*
|
||||
* Only for console->device_lock()/_unlock() callbacks and internal
|
||||
* port lock wrapper synchronization.
|
||||
*/
|
||||
static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
|
||||
{
|
||||
spin_lock_irqsave(&up->lock, *flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only for console->device_lock()/_unlock() callbacks and internal
|
||||
* port lock wrapper synchronization.
|
||||
*/
|
||||
static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_port_set_cons - Safely set the @cons field for a uart
|
||||
* @up: The uart port to set
|
||||
* @con: The new console to set to
|
||||
*
|
||||
* This function must be used to set @up->cons. It uses the port lock to
|
||||
* synchronize with the port lock wrappers in order to ensure that the console
|
||||
* cannot change or disappear while another context is holding the port lock.
|
||||
*/
|
||||
static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
__uart_port_lock_irqsave(up, &flags);
|
||||
up->cons = con;
|
||||
__uart_port_unlock_irqrestore(up, flags);
|
||||
}
|
||||
|
||||
/* Only for internal port lock wrapper usage. */
|
||||
static inline bool __uart_port_using_nbcon(struct uart_port *up)
|
||||
{
|
||||
lockdep_assert_held_once(&up->lock);
|
||||
|
||||
if (likely(!uart_console(up)))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* @up->cons is only modified under the port lock. Therefore it is
|
||||
* certain that it cannot disappear here.
|
||||
*
|
||||
* @up->cons->node is added/removed from the console list under the
|
||||
* port lock. Therefore it is certain that the registration status
|
||||
* cannot change here, thus @up->cons->flags can be read directly.
|
||||
*/
|
||||
if (hlist_unhashed_lockless(&up->cons->node) ||
|
||||
!(up->cons->flags & CON_NBCON) ||
|
||||
!up->cons->write_atomic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Only for internal port lock wrapper usage. */
|
||||
static inline bool __uart_port_nbcon_try_acquire(struct uart_port *up)
|
||||
{
|
||||
if (!__uart_port_using_nbcon(up))
|
||||
return true;
|
||||
|
||||
return nbcon_device_try_acquire(up->cons);
|
||||
}
|
||||
|
||||
/* Only for internal port lock wrapper usage. */
|
||||
static inline void __uart_port_nbcon_acquire(struct uart_port *up)
|
||||
{
|
||||
if (!__uart_port_using_nbcon(up))
|
||||
return;
|
||||
|
||||
while (!nbcon_device_try_acquire(up->cons))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
/* Only for internal port lock wrapper usage. */
|
||||
static inline void __uart_port_nbcon_release(struct uart_port *up)
|
||||
{
|
||||
if (!__uart_port_using_nbcon(up))
|
||||
return;
|
||||
|
||||
nbcon_device_release(up->cons);
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_port_lock - Lock the UART port
|
||||
* @up: Pointer to UART port structure
|
||||
@@ -597,6 +688,7 @@ struct uart_port {
|
||||
static inline void uart_port_lock(struct uart_port *up)
|
||||
{
|
||||
spin_lock(&up->lock);
|
||||
__uart_port_nbcon_acquire(up);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -606,6 +698,7 @@ static inline void uart_port_lock(struct uart_port *up)
|
||||
static inline void uart_port_lock_irq(struct uart_port *up)
|
||||
{
|
||||
spin_lock_irq(&up->lock);
|
||||
__uart_port_nbcon_acquire(up);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -616,6 +709,7 @@ static inline void uart_port_lock_irq(struct uart_port *up)
|
||||
static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
|
||||
{
|
||||
spin_lock_irqsave(&up->lock, *flags);
|
||||
__uart_port_nbcon_acquire(up);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -626,7 +720,15 @@ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *f
|
||||
*/
|
||||
static inline bool uart_port_trylock(struct uart_port *up)
|
||||
{
|
||||
return spin_trylock(&up->lock);
|
||||
if (!spin_trylock(&up->lock))
|
||||
return false;
|
||||
|
||||
if (!__uart_port_nbcon_try_acquire(up)) {
|
||||
spin_unlock(&up->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -638,7 +740,15 @@ static inline bool uart_port_trylock(struct uart_port *up)
|
||||
*/
|
||||
static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags)
|
||||
{
|
||||
return spin_trylock_irqsave(&up->lock, *flags);
|
||||
if (!spin_trylock_irqsave(&up->lock, *flags))
|
||||
return false;
|
||||
|
||||
if (!__uart_port_nbcon_try_acquire(up)) {
|
||||
spin_unlock_irqrestore(&up->lock, *flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,6 +757,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
|
||||
*/
|
||||
static inline void uart_port_unlock(struct uart_port *up)
|
||||
{
|
||||
__uart_port_nbcon_release(up);
|
||||
spin_unlock(&up->lock);
|
||||
}
|
||||
|
||||
@@ -656,6 +767,7 @@ static inline void uart_port_unlock(struct uart_port *up)
|
||||
*/
|
||||
static inline void uart_port_unlock_irq(struct uart_port *up)
|
||||
{
|
||||
__uart_port_nbcon_release(up);
|
||||
spin_unlock_irq(&up->lock);
|
||||
}
|
||||
|
||||
@@ -666,6 +778,7 @@ static inline void uart_port_unlock_irq(struct uart_port *up)
|
||||
*/
|
||||
static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
|
||||
{
|
||||
__uart_port_nbcon_release(up);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ static inline void on_each_cpu_cond(smp_cond_func_t cond_func,
|
||||
* Architecture specific boot CPU setup. Defined as empty weak function in
|
||||
* init/main.c. Architectures can override it.
|
||||
*/
|
||||
void smp_prepare_boot_cpu(void);
|
||||
void __init smp_prepare_boot_cpu(void);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ struct tk_read_base {
|
||||
* @overflow_seen: Overflow warning flag (DEBUG_TIMEKEEPING)
|
||||
*
|
||||
* Note: For timespec(64) based interfaces wall_to_monotonic is what
|
||||
* we need to add to xtime (or xtime corrected for sub jiffie times)
|
||||
* we need to add to xtime (or xtime corrected for sub jiffy times)
|
||||
* to get to monotonic time. Monotonic is pegged at zero at system
|
||||
* boot time, so wall_to_monotonic will be negative, however, we will
|
||||
* ALWAYS keep the tv_nsec part positive so we can use the usual
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ static struct signal_struct init_signals = {
|
||||
.cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex),
|
||||
.exec_update_lock = __RWSEM_INITIALIZER(init_signals.exec_update_lock),
|
||||
#ifdef CONFIG_POSIX_TIMERS
|
||||
.posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
|
||||
.posix_timers = HLIST_HEAD_INIT,
|
||||
.cputimer = {
|
||||
.cputime_atomic = INIT_CPUTIME_ATOMIC,
|
||||
},
|
||||
|
||||
+18
-4
@@ -330,7 +330,7 @@ static bool cpuhp_wait_for_sync_state(unsigned int cpu, enum cpuhp_sync_state st
|
||||
/* Poll for one millisecond */
|
||||
arch_cpuhp_sync_state_poll();
|
||||
} else {
|
||||
usleep_range_state(USEC_PER_MSEC, 2 * USEC_PER_MSEC, TASK_UNINTERRUPTIBLE);
|
||||
usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
|
||||
}
|
||||
sync = atomic_read(st);
|
||||
}
|
||||
@@ -1808,6 +1808,7 @@ static int __init parallel_bringup_parse_param(char *arg)
|
||||
}
|
||||
early_param("cpuhp.parallel", parallel_bringup_parse_param);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
static inline bool cpuhp_smt_aware(void)
|
||||
{
|
||||
return cpu_smt_max_threads > 1;
|
||||
@@ -1817,6 +1818,21 @@ static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
|
||||
{
|
||||
return cpu_primary_thread_mask;
|
||||
}
|
||||
#else
|
||||
static inline bool cpuhp_smt_aware(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
|
||||
{
|
||||
return cpu_none_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool __weak arch_cpuhp_init_parallel_bringup(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* On architectures which have enabled parallel bringup this invokes all BP
|
||||
@@ -2689,9 +2705,7 @@ int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the core a CPU belongs to is online
|
||||
*/
|
||||
/* Check if the core a CPU belongs to is online */
|
||||
#if !defined(topology_is_core_online)
|
||||
static inline bool topology_is_core_online(unsigned int cpu)
|
||||
{
|
||||
|
||||
+1
-1
@@ -1892,7 +1892,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
prev_cputime_init(&sig->prev_cputime);
|
||||
|
||||
#ifdef CONFIG_POSIX_TIMERS
|
||||
INIT_LIST_HEAD(&sig->posix_timers);
|
||||
INIT_HLIST_HEAD(&sig->posix_timers);
|
||||
hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
sig->real_timer.function = it_real_fn;
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ __irq_startup_managed(struct irq_desc *desc, const struct cpumask *aff,
|
||||
|
||||
irqd_clr_managed_shutdown(d);
|
||||
|
||||
if (cpumask_any_and(aff, cpu_online_mask) >= nr_cpu_ids) {
|
||||
if (!cpumask_intersects(aff, cpu_online_mask)) {
|
||||
/*
|
||||
* Catch code which fiddles with enable_irq() on a managed
|
||||
* and potentially shutdown IRQ. Chained interrupt
|
||||
|
||||
@@ -37,7 +37,7 @@ static inline bool irq_needs_fixup(struct irq_data *d)
|
||||
* has been removed from the online mask already.
|
||||
*/
|
||||
if (cpumask_any_but(m, cpu) < nr_cpu_ids &&
|
||||
cpumask_any_and(m, cpu_online_mask) >= nr_cpu_ids) {
|
||||
!cpumask_intersects(m, cpu_online_mask)) {
|
||||
/*
|
||||
* If this happens then there was a missed IRQ fixup at some
|
||||
* point. Warn about it and enforce fixup.
|
||||
@@ -110,7 +110,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
|
||||
if (maskchip && chip->irq_mask)
|
||||
chip->irq_mask(d);
|
||||
|
||||
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
|
||||
if (!cpumask_intersects(affinity, cpu_online_mask)) {
|
||||
/*
|
||||
* If the interrupt is managed, then shut it down and leave
|
||||
* the affinity untouched.
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
struct irq_sim_work_ctx {
|
||||
struct irq_work work;
|
||||
int irq_base;
|
||||
unsigned int irq_count;
|
||||
unsigned long *pending;
|
||||
struct irq_domain *domain;
|
||||
|
||||
+124
-86
@@ -128,72 +128,98 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
|
||||
|
||||
static int irq_domain_set_name(struct irq_domain *domain,
|
||||
const struct fwnode_handle *fwnode,
|
||||
enum irq_domain_bus_token bus_token)
|
||||
static int alloc_name(struct irq_domain *domain, char *base, enum irq_domain_bus_token bus_token)
|
||||
{
|
||||
if (bus_token == DOMAIN_BUS_ANY)
|
||||
domain->name = kasprintf(GFP_KERNEL, "%s", base);
|
||||
else
|
||||
domain->name = kasprintf(GFP_KERNEL, "%s-%d", base, bus_token);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_fwnode_name(struct irq_domain *domain, const struct fwnode_handle *fwnode,
|
||||
enum irq_domain_bus_token bus_token, const char *suffix)
|
||||
{
|
||||
const char *sep = suffix ? "-" : "";
|
||||
const char *suf = suffix ? : "";
|
||||
char *name;
|
||||
|
||||
if (bus_token == DOMAIN_BUS_ANY)
|
||||
name = kasprintf(GFP_KERNEL, "%pfw%s%s", fwnode, sep, suf);
|
||||
else
|
||||
name = kasprintf(GFP_KERNEL, "%pfw%s%s-%d", fwnode, sep, suf, bus_token);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* fwnode paths contain '/', which debugfs is legitimately unhappy
|
||||
* about. Replace them with ':', which does the trick and is not as
|
||||
* offensive as '\'...
|
||||
*/
|
||||
domain->name = strreplace(name, '/', ':');
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_unknown_name(struct irq_domain *domain, enum irq_domain_bus_token bus_token)
|
||||
{
|
||||
static atomic_t unknown_domains;
|
||||
struct irqchip_fwid *fwid;
|
||||
int id = atomic_inc_return(&unknown_domains);
|
||||
|
||||
if (bus_token == DOMAIN_BUS_ANY)
|
||||
domain->name = kasprintf(GFP_KERNEL, "unknown-%d", id);
|
||||
else
|
||||
domain->name = kasprintf(GFP_KERNEL, "unknown-%d-%d", id, bus_token);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int irq_domain_set_name(struct irq_domain *domain, const struct irq_domain_info *info)
|
||||
{
|
||||
enum irq_domain_bus_token bus_token = info->bus_token;
|
||||
const struct fwnode_handle *fwnode = info->fwnode;
|
||||
|
||||
if (is_fwnode_irqchip(fwnode)) {
|
||||
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
|
||||
struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
|
||||
|
||||
/*
|
||||
* The name_suffix is only intended to be used to avoid a name
|
||||
* collision when multiple domains are created for a single
|
||||
* device and the name is picked using a real device node.
|
||||
* (Typical use-case is regmap-IRQ controllers for devices
|
||||
* providing more than one physical IRQ.) There should be no
|
||||
* need to use name_suffix with irqchip-fwnode.
|
||||
*/
|
||||
if (info->name_suffix)
|
||||
return -EINVAL;
|
||||
|
||||
switch (fwid->type) {
|
||||
case IRQCHIP_FWNODE_NAMED:
|
||||
case IRQCHIP_FWNODE_NAMED_ID:
|
||||
domain->name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "%s-%d",
|
||||
fwid->name, bus_token) :
|
||||
kstrdup(fwid->name, GFP_KERNEL);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
break;
|
||||
return alloc_name(domain, fwid->name, bus_token);
|
||||
default:
|
||||
domain->name = fwid->name;
|
||||
if (bus_token) {
|
||||
domain->name = kasprintf(GFP_KERNEL, "%s-%d",
|
||||
fwid->name, bus_token);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
}
|
||||
break;
|
||||
if (bus_token != DOMAIN_BUS_ANY)
|
||||
return alloc_name(domain, fwid->name, bus_token);
|
||||
}
|
||||
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) ||
|
||||
is_software_node(fwnode)) {
|
||||
char *name;
|
||||
|
||||
/*
|
||||
* fwnode paths contain '/', which debugfs is legitimately
|
||||
* unhappy about. Replace them with ':', which does
|
||||
* the trick and is not as offensive as '\'...
|
||||
*/
|
||||
name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) :
|
||||
kasprintf(GFP_KERNEL, "%pfw", fwnode);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
domain->name = strreplace(name, '/', ':');
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || is_software_node(fwnode)) {
|
||||
return alloc_fwnode_name(domain, fwnode, bus_token, info->name_suffix);
|
||||
}
|
||||
|
||||
if (!domain->name) {
|
||||
if (fwnode)
|
||||
pr_err("Invalid fwnode type for irqdomain\n");
|
||||
domain->name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "unknown-%d-%d",
|
||||
atomic_inc_return(&unknown_domains),
|
||||
bus_token) :
|
||||
kasprintf(GFP_KERNEL, "unknown-%d",
|
||||
atomic_inc_return(&unknown_domains));
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
}
|
||||
if (domain->name)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
if (fwnode)
|
||||
pr_err("Invalid fwnode type for irqdomain\n");
|
||||
return alloc_unknown_name(domain, bus_token);
|
||||
}
|
||||
|
||||
static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info)
|
||||
@@ -211,7 +237,7 @@ static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info
|
||||
if (!domain)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = irq_domain_set_name(domain, info->fwnode, info->bus_token);
|
||||
err = irq_domain_set_name(domain, info);
|
||||
if (err) {
|
||||
kfree(domain);
|
||||
return ERR_PTR(err);
|
||||
@@ -267,13 +293,20 @@ static void irq_domain_free(struct irq_domain *domain)
|
||||
kfree(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_instantiate() - Instantiate a new irq domain data structure
|
||||
* @info: Domain information pointer pointing to the information for this domain
|
||||
*
|
||||
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
|
||||
*/
|
||||
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
static void irq_domain_instantiate_descs(const struct irq_domain_info *info)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_SPARSE_IRQ))
|
||||
return;
|
||||
|
||||
if (irq_alloc_descs(info->virq_base, info->virq_base, info->size,
|
||||
of_node_to_nid(to_of_node(info->fwnode))) < 0) {
|
||||
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||
info->virq_base);
|
||||
}
|
||||
}
|
||||
|
||||
static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info *info,
|
||||
bool cond_alloc_descs, bool force_associate)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
int err;
|
||||
@@ -306,6 +339,19 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
|
||||
__irq_domain_publish(domain);
|
||||
|
||||
if (cond_alloc_descs && info->virq_base > 0)
|
||||
irq_domain_instantiate_descs(info);
|
||||
|
||||
/*
|
||||
* Legacy interrupt domains have a fixed Linux interrupt number
|
||||
* associated. Other interrupt domains can request association by
|
||||
* providing a Linux interrupt number > 0.
|
||||
*/
|
||||
if (force_associate || info->virq_base > 0) {
|
||||
irq_domain_associate_many(domain, info->virq_base, info->hwirq_base,
|
||||
info->size - info->hwirq_base);
|
||||
}
|
||||
|
||||
return domain;
|
||||
|
||||
err_domain_gc_remove:
|
||||
@@ -315,6 +361,17 @@ err_domain_free:
|
||||
irq_domain_free(domain);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_instantiate() - Instantiate a new irq domain data structure
|
||||
* @info: Domain information pointer pointing to the information for this domain
|
||||
*
|
||||
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
|
||||
*/
|
||||
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
{
|
||||
return __irq_domain_instantiate(info, false, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_instantiate);
|
||||
|
||||
/**
|
||||
@@ -413,28 +470,13 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
|
||||
.fwnode = fwnode,
|
||||
.size = size,
|
||||
.hwirq_max = size,
|
||||
.virq_base = first_irq,
|
||||
.ops = ops,
|
||||
.host_data = host_data,
|
||||
};
|
||||
struct irq_domain *domain;
|
||||
struct irq_domain *domain = __irq_domain_instantiate(&info, true, false);
|
||||
|
||||
domain = irq_domain_instantiate(&info);
|
||||
if (IS_ERR(domain))
|
||||
return NULL;
|
||||
|
||||
if (first_irq > 0) {
|
||||
if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
|
||||
/* attempt to allocated irq_descs */
|
||||
int rc = irq_alloc_descs(first_irq, first_irq, size,
|
||||
of_node_to_nid(to_of_node(fwnode)));
|
||||
if (rc < 0)
|
||||
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||
first_irq);
|
||||
}
|
||||
irq_domain_associate_many(domain, first_irq, 0, size);
|
||||
}
|
||||
|
||||
return domain;
|
||||
return IS_ERR(domain) ? NULL : domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_simple);
|
||||
|
||||
@@ -476,18 +518,14 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
|
||||
.fwnode = fwnode,
|
||||
.size = first_hwirq + size,
|
||||
.hwirq_max = first_hwirq + size,
|
||||
.hwirq_base = first_hwirq,
|
||||
.virq_base = first_irq,
|
||||
.ops = ops,
|
||||
.host_data = host_data,
|
||||
};
|
||||
struct irq_domain *domain;
|
||||
struct irq_domain *domain = __irq_domain_instantiate(&info, false, true);
|
||||
|
||||
domain = irq_domain_instantiate(&info);
|
||||
if (IS_ERR(domain))
|
||||
return NULL;
|
||||
|
||||
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
|
||||
|
||||
return domain;
|
||||
return IS_ERR(domain) ? NULL : domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_legacy);
|
||||
|
||||
@@ -1365,7 +1403,7 @@ static int irq_domain_trim_hierarchy(unsigned int virq)
|
||||
tail = NULL;
|
||||
|
||||
/* The first entry must have a valid irqchip */
|
||||
if (!irq_data->chip || IS_ERR(irq_data->chip))
|
||||
if (IS_ERR_OR_NULL(irq_data->chip))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
||||
+9
-12
@@ -218,21 +218,20 @@ static void irq_validate_effective_affinity(struct irq_data *data)
|
||||
static inline void irq_validate_effective_affinity(struct irq_data *data) { }
|
||||
#endif
|
||||
|
||||
static DEFINE_PER_CPU(struct cpumask, __tmp_mask);
|
||||
|
||||
int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
bool force)
|
||||
{
|
||||
struct cpumask *tmp_mask = this_cpu_ptr(&__tmp_mask);
|
||||
struct irq_desc *desc = irq_data_to_desc(data);
|
||||
struct irq_chip *chip = irq_data_get_irq_chip(data);
|
||||
const struct cpumask *prog_mask;
|
||||
int ret;
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(tmp_mask_lock);
|
||||
static struct cpumask tmp_mask;
|
||||
|
||||
if (!chip || !chip->irq_set_affinity)
|
||||
return -EINVAL;
|
||||
|
||||
raw_spin_lock(&tmp_mask_lock);
|
||||
/*
|
||||
* If this is a managed interrupt and housekeeping is enabled on
|
||||
* it check whether the requested affinity mask intersects with
|
||||
@@ -258,11 +257,11 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
|
||||
hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ);
|
||||
|
||||
cpumask_and(&tmp_mask, mask, hk_mask);
|
||||
if (!cpumask_intersects(&tmp_mask, cpu_online_mask))
|
||||
cpumask_and(tmp_mask, mask, hk_mask);
|
||||
if (!cpumask_intersects(tmp_mask, cpu_online_mask))
|
||||
prog_mask = mask;
|
||||
else
|
||||
prog_mask = &tmp_mask;
|
||||
prog_mask = tmp_mask;
|
||||
} else {
|
||||
prog_mask = mask;
|
||||
}
|
||||
@@ -272,16 +271,14 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
* unless we are being asked to force the affinity (in which
|
||||
* case we do as we are told).
|
||||
*/
|
||||
cpumask_and(&tmp_mask, prog_mask, cpu_online_mask);
|
||||
if (!force && !cpumask_empty(&tmp_mask))
|
||||
ret = chip->irq_set_affinity(data, &tmp_mask, force);
|
||||
cpumask_and(tmp_mask, prog_mask, cpu_online_mask);
|
||||
if (!force && !cpumask_empty(tmp_mask))
|
||||
ret = chip->irq_set_affinity(data, tmp_mask, force);
|
||||
else if (force)
|
||||
ret = chip->irq_set_affinity(data, mask, force);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
raw_spin_unlock(&tmp_mask_lock);
|
||||
|
||||
switch (ret) {
|
||||
case IRQ_SET_MASK_OK:
|
||||
case IRQ_SET_MASK_OK_DONE:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user