18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Common definitions across all variants of ICP and ICS interrupt
48c2ecf20Sopenharmony_ci * controllers.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#ifndef _XICS_H
88c2ecf20Sopenharmony_ci#define _XICS_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define XICS_IPI		2
138c2ecf20Sopenharmony_ci#define XICS_IRQ_SPURIOUS	0
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* Want a priority other than 0.  Various HW issues require this. */
168c2ecf20Sopenharmony_ci#define	DEFAULT_PRIORITY	5
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * Mark IPIs as higher priority so we can take them inside interrupts
208c2ecf20Sopenharmony_ci * FIXME: still true now?
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci#define IPI_PRIORITY		4
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* The least favored priority */
258c2ecf20Sopenharmony_ci#define LOWEST_PRIORITY		0xFF
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* The number of priorities defined above */
288c2ecf20Sopenharmony_ci#define MAX_NUM_PRIORITIES	3
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* Native ICP */
318c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_ICP_NATIVE
328c2ecf20Sopenharmony_ciextern int icp_native_init(void);
338c2ecf20Sopenharmony_ciextern void icp_native_flush_interrupt(void);
348c2ecf20Sopenharmony_ciextern void icp_native_cause_ipi_rm(int cpu);
358c2ecf20Sopenharmony_ci#else
368c2ecf20Sopenharmony_cistatic inline int icp_native_init(void) { return -ENODEV; }
378c2ecf20Sopenharmony_ci#endif
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* PAPR ICP */
408c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_ICP_HV
418c2ecf20Sopenharmony_ciextern int icp_hv_init(void);
428c2ecf20Sopenharmony_ci#else
438c2ecf20Sopenharmony_cistatic inline int icp_hv_init(void) { return -ENODEV; }
448c2ecf20Sopenharmony_ci#endif
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
478c2ecf20Sopenharmony_ciextern int icp_opal_init(void);
488c2ecf20Sopenharmony_ciextern void icp_opal_flush_interrupt(void);
498c2ecf20Sopenharmony_ci#else
508c2ecf20Sopenharmony_cistatic inline int icp_opal_init(void) { return -ENODEV; }
518c2ecf20Sopenharmony_ci#endif
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* ICP ops */
548c2ecf20Sopenharmony_cistruct icp_ops {
558c2ecf20Sopenharmony_ci	unsigned int (*get_irq)(void);
568c2ecf20Sopenharmony_ci	void (*eoi)(struct irq_data *d);
578c2ecf20Sopenharmony_ci	void (*set_priority)(unsigned char prio);
588c2ecf20Sopenharmony_ci	void (*teardown_cpu)(void);
598c2ecf20Sopenharmony_ci	void (*flush_ipi)(void);
608c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
618c2ecf20Sopenharmony_ci	void (*cause_ipi)(int cpu);
628c2ecf20Sopenharmony_ci	irq_handler_t ipi_action;
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciextern const struct icp_ops *icp_ops;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* Native ICS */
698c2ecf20Sopenharmony_ciextern int ics_native_init(void);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* RTAS ICS */
728c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_ICS_RTAS
738c2ecf20Sopenharmony_ciextern int ics_rtas_init(void);
748c2ecf20Sopenharmony_ci#else
758c2ecf20Sopenharmony_cistatic inline int ics_rtas_init(void) { return -ENODEV; }
768c2ecf20Sopenharmony_ci#endif
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* HAL ICS */
798c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
808c2ecf20Sopenharmony_ciextern int ics_opal_init(void);
818c2ecf20Sopenharmony_ci#else
828c2ecf20Sopenharmony_cistatic inline int ics_opal_init(void) { return -ENODEV; }
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* ICS instance, hooked up to chip_data of an irq */
868c2ecf20Sopenharmony_cistruct ics {
878c2ecf20Sopenharmony_ci	struct list_head link;
888c2ecf20Sopenharmony_ci	int (*map)(struct ics *ics, unsigned int virq);
898c2ecf20Sopenharmony_ci	void (*mask_unknown)(struct ics *ics, unsigned long vec);
908c2ecf20Sopenharmony_ci	long (*get_server)(struct ics *ics, unsigned long vec);
918c2ecf20Sopenharmony_ci	int (*host_match)(struct ics *ics, struct device_node *node);
928c2ecf20Sopenharmony_ci	char data[];
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* Commons */
968c2ecf20Sopenharmony_ciextern unsigned int xics_default_server;
978c2ecf20Sopenharmony_ciextern unsigned int xics_default_distrib_server;
988c2ecf20Sopenharmony_ciextern unsigned int xics_interrupt_server_size;
998c2ecf20Sopenharmony_ciextern struct irq_domain *xics_host;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistruct xics_cppr {
1028c2ecf20Sopenharmony_ci	unsigned char stack[MAX_NUM_PRIORITIES];
1038c2ecf20Sopenharmony_ci	int index;
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciDECLARE_PER_CPU(struct xics_cppr, xics_cppr);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic inline void xics_push_cppr(unsigned int vec)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1))
1138c2ecf20Sopenharmony_ci		return;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (vec == XICS_IPI)
1168c2ecf20Sopenharmony_ci		os_cppr->stack[++os_cppr->index] = IPI_PRIORITY;
1178c2ecf20Sopenharmony_ci	else
1188c2ecf20Sopenharmony_ci		os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic inline unsigned char xics_pop_cppr(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (WARN_ON(os_cppr->index < 1))
1268c2ecf20Sopenharmony_ci		return LOWEST_PRIORITY;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return os_cppr->stack[--os_cppr->index];
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic inline void xics_set_base_cppr(unsigned char cppr)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* we only really want to set the priority when there's
1368c2ecf20Sopenharmony_ci	 * just one cppr value on the stack
1378c2ecf20Sopenharmony_ci	 */
1388c2ecf20Sopenharmony_ci	WARN_ON(os_cppr->index != 0);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	os_cppr->stack[0] = cppr;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic inline unsigned char xics_cppr_top(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return os_cppr->stack[os_cppr->index];
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ciDECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ciextern void xics_init(void);
1538c2ecf20Sopenharmony_ciextern void xics_setup_cpu(void);
1548c2ecf20Sopenharmony_ciextern void xics_update_irq_servers(void);
1558c2ecf20Sopenharmony_ciextern void xics_set_cpu_giq(unsigned int gserver, unsigned int join);
1568c2ecf20Sopenharmony_ciextern void xics_mask_unknown_vec(unsigned int vec);
1578c2ecf20Sopenharmony_ciextern irqreturn_t xics_ipi_dispatch(int cpu);
1588c2ecf20Sopenharmony_ciextern void xics_smp_probe(void);
1598c2ecf20Sopenharmony_ciextern void xics_register_ics(struct ics *ics);
1608c2ecf20Sopenharmony_ciextern void xics_teardown_cpu(void);
1618c2ecf20Sopenharmony_ciextern void xics_kexec_teardown_cpu(int secondary);
1628c2ecf20Sopenharmony_ciextern void xics_migrate_irqs_away(void);
1638c2ecf20Sopenharmony_ciextern void icp_native_eoi(struct irq_data *d);
1648c2ecf20Sopenharmony_ciextern int xics_set_irq_type(struct irq_data *d, unsigned int flow_type);
1658c2ecf20Sopenharmony_ciextern int xics_retrigger(struct irq_data *data);
1668c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
1678c2ecf20Sopenharmony_ciextern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
1688c2ecf20Sopenharmony_ci			       unsigned int strict_check);
1698c2ecf20Sopenharmony_ci#else
1708c2ecf20Sopenharmony_ci#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server)
1718c2ecf20Sopenharmony_ci#endif
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#endif /* _XICS_H */
175