1699f6751SJacob Pan /* SPDX-License-Identifier: GPL-2.0 */
2699f6751SJacob Pan #ifndef _X86_POSTED_INTR_H
3699f6751SJacob Pan #define _X86_POSTED_INTR_H
4*ce0a9287SJacob Pan #include <asm/irq_vectors.h>
5699f6751SJacob Pan
6699f6751SJacob Pan #define POSTED_INTR_ON 0
7699f6751SJacob Pan #define POSTED_INTR_SN 1
8699f6751SJacob Pan
9699f6751SJacob Pan #define PID_TABLE_ENTRY_VALID 1
10699f6751SJacob Pan
11699f6751SJacob Pan /* Posted-Interrupt Descriptor */
12699f6751SJacob Pan struct pi_desc {
134ec8fd03SJacob Pan union {
14699f6751SJacob Pan u32 pir[8]; /* Posted interrupt requested */
154ec8fd03SJacob Pan u64 pir64[4];
164ec8fd03SJacob Pan };
17699f6751SJacob Pan union {
18699f6751SJacob Pan struct {
192254808bSJacob Pan u16 notifications; /* Suppress and outstanding bits */
20699f6751SJacob Pan u8 nv;
21699f6751SJacob Pan u8 rsvd_2;
22699f6751SJacob Pan u32 ndst;
23699f6751SJacob Pan };
24699f6751SJacob Pan u64 control;
25699f6751SJacob Pan };
26699f6751SJacob Pan u32 rsvd[6];
27699f6751SJacob Pan } __aligned(64);
28699f6751SJacob Pan
pi_test_and_set_on(struct pi_desc * pi_desc)29699f6751SJacob Pan static inline bool pi_test_and_set_on(struct pi_desc *pi_desc)
30699f6751SJacob Pan {
31699f6751SJacob Pan return test_and_set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
32699f6751SJacob Pan }
33699f6751SJacob Pan
pi_test_and_clear_on(struct pi_desc * pi_desc)34699f6751SJacob Pan static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc)
35699f6751SJacob Pan {
36699f6751SJacob Pan return test_and_clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
37699f6751SJacob Pan }
38699f6751SJacob Pan
pi_test_and_clear_sn(struct pi_desc * pi_desc)39699f6751SJacob Pan static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc)
40699f6751SJacob Pan {
41699f6751SJacob Pan return test_and_clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
42699f6751SJacob Pan }
43699f6751SJacob Pan
pi_test_and_set_pir(int vector,struct pi_desc * pi_desc)44699f6751SJacob Pan static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc)
45699f6751SJacob Pan {
46699f6751SJacob Pan return test_and_set_bit(vector, (unsigned long *)pi_desc->pir);
47699f6751SJacob Pan }
48699f6751SJacob Pan
pi_is_pir_empty(struct pi_desc * pi_desc)49699f6751SJacob Pan static inline bool pi_is_pir_empty(struct pi_desc *pi_desc)
50699f6751SJacob Pan {
51699f6751SJacob Pan return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS);
52699f6751SJacob Pan }
53699f6751SJacob Pan
pi_set_sn(struct pi_desc * pi_desc)54699f6751SJacob Pan static inline void pi_set_sn(struct pi_desc *pi_desc)
55699f6751SJacob Pan {
56699f6751SJacob Pan set_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
57699f6751SJacob Pan }
58699f6751SJacob Pan
pi_set_on(struct pi_desc * pi_desc)59699f6751SJacob Pan static inline void pi_set_on(struct pi_desc *pi_desc)
60699f6751SJacob Pan {
61699f6751SJacob Pan set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
62699f6751SJacob Pan }
63699f6751SJacob Pan
pi_clear_on(struct pi_desc * pi_desc)64699f6751SJacob Pan static inline void pi_clear_on(struct pi_desc *pi_desc)
65699f6751SJacob Pan {
66699f6751SJacob Pan clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
67699f6751SJacob Pan }
68699f6751SJacob Pan
pi_clear_sn(struct pi_desc * pi_desc)69699f6751SJacob Pan static inline void pi_clear_sn(struct pi_desc *pi_desc)
70699f6751SJacob Pan {
71699f6751SJacob Pan clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
72699f6751SJacob Pan }
73699f6751SJacob Pan
pi_test_on(struct pi_desc * pi_desc)74699f6751SJacob Pan static inline bool pi_test_on(struct pi_desc *pi_desc)
75699f6751SJacob Pan {
76699f6751SJacob Pan return test_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
77699f6751SJacob Pan }
78699f6751SJacob Pan
pi_test_sn(struct pi_desc * pi_desc)79699f6751SJacob Pan static inline bool pi_test_sn(struct pi_desc *pi_desc)
80699f6751SJacob Pan {
81699f6751SJacob Pan return test_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
82699f6751SJacob Pan }
83699f6751SJacob Pan
842254808bSJacob Pan /* Non-atomic helpers */
__pi_set_sn(struct pi_desc * pi_desc)852254808bSJacob Pan static inline void __pi_set_sn(struct pi_desc *pi_desc)
862254808bSJacob Pan {
872254808bSJacob Pan pi_desc->notifications |= BIT(POSTED_INTR_SN);
882254808bSJacob Pan }
892254808bSJacob Pan
__pi_clear_sn(struct pi_desc * pi_desc)902254808bSJacob Pan static inline void __pi_clear_sn(struct pi_desc *pi_desc)
912254808bSJacob Pan {
922254808bSJacob Pan pi_desc->notifications &= ~BIT(POSTED_INTR_SN);
932254808bSJacob Pan }
942254808bSJacob Pan
9543650dcfSJacob Pan #ifdef CONFIG_X86_POSTED_MSI
96*ce0a9287SJacob Pan /*
97*ce0a9287SJacob Pan * Not all external vectors are subject to interrupt remapping, e.g. IOMMU's
98*ce0a9287SJacob Pan * own interrupts. Here we do not distinguish them since those vector bits in
99*ce0a9287SJacob Pan * PIR will always be zero.
100*ce0a9287SJacob Pan */
pi_pending_this_cpu(unsigned int vector)101*ce0a9287SJacob Pan static inline bool pi_pending_this_cpu(unsigned int vector)
102*ce0a9287SJacob Pan {
103*ce0a9287SJacob Pan struct pi_desc *pid = this_cpu_ptr(&posted_msi_pi_desc);
104*ce0a9287SJacob Pan
105*ce0a9287SJacob Pan if (WARN_ON_ONCE(vector > NR_VECTORS || vector < FIRST_EXTERNAL_VECTOR))
106*ce0a9287SJacob Pan return false;
107*ce0a9287SJacob Pan
108*ce0a9287SJacob Pan return test_bit(vector, (unsigned long *)pid->pir);
109*ce0a9287SJacob Pan }
110*ce0a9287SJacob Pan
11143650dcfSJacob Pan extern void intel_posted_msi_init(void);
11243650dcfSJacob Pan #else
pi_pending_this_cpu(unsigned int vector)113*ce0a9287SJacob Pan static inline bool pi_pending_this_cpu(unsigned int vector) { return false; }
114*ce0a9287SJacob Pan
intel_posted_msi_init(void)11543650dcfSJacob Pan static inline void intel_posted_msi_init(void) {};
11643650dcfSJacob Pan #endif /* X86_POSTED_MSI */
11743650dcfSJacob Pan
118699f6751SJacob Pan #endif /* _X86_POSTED_INTR_H */
119