xref: /linux/arch/x86/include/asm/posted_intr.h (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 */
85 static inline void __pi_set_sn(struct pi_desc *pi_desc)
86 {
87 	pi_desc->notifications |= BIT(POSTED_INTR_SN);
88 }
89 
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  */
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
113 static inline bool pi_pending_this_cpu(unsigned int vector) { return false; }
114 
115 static inline void intel_posted_msi_init(void) {};
116 #endif /* X86_POSTED_MSI */
117 
118 #endif /* _X86_POSTED_INTR_H */
119