1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _X86_POSTED_INTR_H
3 #define _X86_POSTED_INTR_H
4 #include <asm/irq_vectors.h>
5 
6 #define POSTED_INTR_ON  0
7 #define POSTED_INTR_SN  1
8 
9 #define PID_TABLE_ENTRY_VALID 1
10 
11 /* Posted-Interrupt Descriptor */
12 struct pi_desc {
13 	union {
14 		u32 pir[8];     /* Posted interrupt requested */
15 		u64 pir64[4];
16 	};
17 	union {
18 		struct {
19 			u16	notifications; /* Suppress and outstanding bits */
20 			u8	nv;
21 			u8	rsvd_2;
22 			u32	ndst;
23 		};
24 		u64 control;
25 	};
26 	u32 rsvd[6];
27 } __aligned(64);
28 
pi_test_and_set_on(struct pi_desc * pi_desc)29 static inline bool pi_test_and_set_on(struct pi_desc *pi_desc)
30 {
31 	return test_and_set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
32 }
33 
pi_test_and_clear_on(struct pi_desc * pi_desc)34 static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc)
35 {
36 	return test_and_clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
37 }
38 
pi_test_and_clear_sn(struct pi_desc * pi_desc)39 static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc)
40 {
41 	return test_and_clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
42 }
43 
pi_test_and_set_pir(int vector,struct pi_desc * pi_desc)44 static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc)
45 {
46 	return test_and_set_bit(vector, (unsigned long *)pi_desc->pir);
47 }
48 
pi_is_pir_empty(struct pi_desc * pi_desc)49 static inline bool pi_is_pir_empty(struct pi_desc *pi_desc)
50 {
51 	return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS);
52 }
53 
pi_set_sn(struct pi_desc * pi_desc)54 static inline void pi_set_sn(struct pi_desc *pi_desc)
55 {
56 	set_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
57 }
58 
pi_set_on(struct pi_desc * pi_desc)59 static inline void pi_set_on(struct pi_desc *pi_desc)
60 {
61 	set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
62 }
63 
pi_clear_on(struct pi_desc * pi_desc)64 static inline void pi_clear_on(struct pi_desc *pi_desc)
65 {
66 	clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
67 }
68 
pi_clear_sn(struct pi_desc * pi_desc)69 static inline void pi_clear_sn(struct pi_desc *pi_desc)
70 {
71 	clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
72 }
73 
pi_test_on(struct pi_desc * pi_desc)74 static inline bool pi_test_on(struct pi_desc *pi_desc)
75 {
76 	return test_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
77 }
78 
pi_test_sn(struct pi_desc * pi_desc)79 static inline bool pi_test_sn(struct pi_desc *pi_desc)
80 {
81 	return test_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
82 }
83 
84 /* Non-atomic helpers */
__pi_set_sn(struct pi_desc * pi_desc)85 static inline void __pi_set_sn(struct pi_desc *pi_desc)
86 {
87 	pi_desc->notifications |= BIT(POSTED_INTR_SN);
88 }
89 
__pi_clear_sn(struct pi_desc * pi_desc)90 static inline void __pi_clear_sn(struct pi_desc *pi_desc)
91 {
92 	pi_desc->notifications &= ~BIT(POSTED_INTR_SN);
93 }
94 
95 #ifdef CONFIG_X86_POSTED_MSI
96 /*
97  * Not all external vectors are subject to interrupt remapping, e.g. IOMMU's
98  * own interrupts. Here we do not distinguish them since those vector bits in
99  * PIR will always be zero.
100  */
pi_pending_this_cpu(unsigned int vector)101 static inline bool pi_pending_this_cpu(unsigned int vector)
102 {
103 	struct pi_desc *pid = this_cpu_ptr(&posted_msi_pi_desc);
104 
105 	if (WARN_ON_ONCE(vector > NR_VECTORS || vector < FIRST_EXTERNAL_VECTOR))
106 		return false;
107 
108 	return test_bit(vector, (unsigned long *)pid->pir);
109 }
110 
111 extern void intel_posted_msi_init(void);
112 #else
pi_pending_this_cpu(unsigned int vector)113 static inline bool pi_pending_this_cpu(unsigned int vector) { return false; }
114 
intel_posted_msi_init(void)115 static inline void intel_posted_msi_init(void) {};
116 #endif /* X86_POSTED_MSI */
117 
118 #endif /* _X86_POSTED_INTR_H */
119