162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common definitions across all variants of ICP and ICS interrupt 462306a36Sopenharmony_ci * controllers. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef _XICS_H 862306a36Sopenharmony_ci#define _XICS_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define XICS_IPI 2 1362306a36Sopenharmony_ci#define XICS_IRQ_SPURIOUS 0 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Want a priority other than 0. Various HW issues require this. */ 1662306a36Sopenharmony_ci#define DEFAULT_PRIORITY 5 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * Mark IPIs as higher priority so we can take them inside interrupts 2062306a36Sopenharmony_ci * FIXME: still true now? 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci#define IPI_PRIORITY 4 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* The least favored priority */ 2562306a36Sopenharmony_ci#define LOWEST_PRIORITY 0xFF 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* The number of priorities defined above */ 2862306a36Sopenharmony_ci#define MAX_NUM_PRIORITIES 3 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Native ICP */ 3162306a36Sopenharmony_ci#ifdef CONFIG_PPC_ICP_NATIVE 3262306a36Sopenharmony_ciextern int icp_native_init(void); 3362306a36Sopenharmony_ciextern void icp_native_flush_interrupt(void); 3462306a36Sopenharmony_ciextern void icp_native_cause_ipi_rm(int cpu); 3562306a36Sopenharmony_ci#else 3662306a36Sopenharmony_cistatic inline int icp_native_init(void) { return -ENODEV; } 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* PAPR ICP */ 4062306a36Sopenharmony_ci#ifdef CONFIG_PPC_ICP_HV 4162306a36Sopenharmony_ciint __init icp_hv_init(void); 4262306a36Sopenharmony_ci#else 4362306a36Sopenharmony_cistatic inline int icp_hv_init(void) { return -ENODEV; } 4462306a36Sopenharmony_ci#endif 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV 4762306a36Sopenharmony_ciint __init icp_opal_init(void); 4862306a36Sopenharmony_ciextern void icp_opal_flush_interrupt(void); 4962306a36Sopenharmony_ci#else 5062306a36Sopenharmony_cistatic inline int icp_opal_init(void) { return -ENODEV; } 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* ICP ops */ 5462306a36Sopenharmony_cistruct icp_ops { 5562306a36Sopenharmony_ci unsigned int (*get_irq)(void); 5662306a36Sopenharmony_ci void (*eoi)(struct irq_data *d); 5762306a36Sopenharmony_ci void (*set_priority)(unsigned char prio); 5862306a36Sopenharmony_ci void (*teardown_cpu)(void); 5962306a36Sopenharmony_ci void (*flush_ipi)(void); 6062306a36Sopenharmony_ci#ifdef CONFIG_SMP 6162306a36Sopenharmony_ci void (*cause_ipi)(int cpu); 6262306a36Sopenharmony_ci irq_handler_t ipi_action; 6362306a36Sopenharmony_ci#endif 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciextern const struct icp_ops *icp_ops; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#ifdef CONFIG_PPC_ICS_NATIVE 6962306a36Sopenharmony_ci/* Native ICS */ 7062306a36Sopenharmony_ciextern int ics_native_init(void); 7162306a36Sopenharmony_ci#else 7262306a36Sopenharmony_cistatic inline int ics_native_init(void) { return -ENODEV; } 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* RTAS ICS */ 7662306a36Sopenharmony_ci#ifdef CONFIG_PPC_ICS_RTAS 7762306a36Sopenharmony_ciextern int ics_rtas_init(void); 7862306a36Sopenharmony_ci#else 7962306a36Sopenharmony_cistatic inline int ics_rtas_init(void) { return -ENODEV; } 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* HAL ICS */ 8362306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV 8462306a36Sopenharmony_ciextern int ics_opal_init(void); 8562306a36Sopenharmony_ci#else 8662306a36Sopenharmony_cistatic inline int ics_opal_init(void) { return -ENODEV; } 8762306a36Sopenharmony_ci#endif 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* ICS instance, hooked up to chip_data of an irq */ 9062306a36Sopenharmony_cistruct ics { 9162306a36Sopenharmony_ci struct list_head link; 9262306a36Sopenharmony_ci int (*check)(struct ics *ics, unsigned int hwirq); 9362306a36Sopenharmony_ci void (*mask_unknown)(struct ics *ics, unsigned long vec); 9462306a36Sopenharmony_ci long (*get_server)(struct ics *ics, unsigned long vec); 9562306a36Sopenharmony_ci int (*host_match)(struct ics *ics, struct device_node *node); 9662306a36Sopenharmony_ci struct irq_chip *chip; 9762306a36Sopenharmony_ci char data[]; 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Commons */ 10162306a36Sopenharmony_ciextern unsigned int xics_default_server; 10262306a36Sopenharmony_ciextern unsigned int xics_default_distrib_server; 10362306a36Sopenharmony_ciextern unsigned int xics_interrupt_server_size; 10462306a36Sopenharmony_ciextern struct irq_domain *xics_host; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct xics_cppr { 10762306a36Sopenharmony_ci unsigned char stack[MAX_NUM_PRIORITIES]; 10862306a36Sopenharmony_ci int index; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciDECLARE_PER_CPU(struct xics_cppr, xics_cppr); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline void xics_push_cppr(unsigned int vec) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) 11862306a36Sopenharmony_ci return; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (vec == XICS_IPI) 12162306a36Sopenharmony_ci os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic inline unsigned char xics_pop_cppr(void) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (WARN_ON(os_cppr->index < 1)) 13162306a36Sopenharmony_ci return LOWEST_PRIORITY; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return os_cppr->stack[--os_cppr->index]; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic inline void xics_set_base_cppr(unsigned char cppr) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* we only really want to set the priority when there's 14162306a36Sopenharmony_ci * just one cppr value on the stack 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci WARN_ON(os_cppr->index != 0); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci os_cppr->stack[0] = cppr; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline unsigned char xics_cppr_top(void) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return os_cppr->stack[os_cppr->index]; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciDECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciextern void xics_init(void); 15862306a36Sopenharmony_ciextern void xics_setup_cpu(void); 15962306a36Sopenharmony_ciextern void xics_update_irq_servers(void); 16062306a36Sopenharmony_ciextern void xics_set_cpu_giq(unsigned int gserver, unsigned int join); 16162306a36Sopenharmony_ciextern void xics_mask_unknown_vec(unsigned int vec); 16262306a36Sopenharmony_ciextern void xics_smp_probe(void); 16362306a36Sopenharmony_ciextern void xics_register_ics(struct ics *ics); 16462306a36Sopenharmony_ciextern void xics_teardown_cpu(void); 16562306a36Sopenharmony_ciextern void xics_kexec_teardown_cpu(int secondary); 16662306a36Sopenharmony_ciextern void xics_migrate_irqs_away(void); 16762306a36Sopenharmony_ciextern void icp_native_eoi(struct irq_data *d); 16862306a36Sopenharmony_ciextern int xics_set_irq_type(struct irq_data *d, unsigned int flow_type); 16962306a36Sopenharmony_ciextern int xics_retrigger(struct irq_data *data); 17062306a36Sopenharmony_ci#ifdef CONFIG_SMP 17162306a36Sopenharmony_ciextern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, 17262306a36Sopenharmony_ci unsigned int strict_check); 17362306a36Sopenharmony_ci#else 17462306a36Sopenharmony_ci#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server) 17562306a36Sopenharmony_ci#endif 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#endif /* _XICS_H */ 179