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