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