1219820Sjeff/* SPDX-License-Identifier: GPL-2.0 */
2219820Sjeff#ifndef _X86_POSTED_INTR_H
3219820Sjeff#define _X86_POSTED_INTR_H
4272027Shselasky#include <asm/irq_vectors.h>
5219820Sjeff
6219820Sjeff#define POSTED_INTR_ON  0
7219820Sjeff#define POSTED_INTR_SN  1
8219820Sjeff
9219820Sjeff#define PID_TABLE_ENTRY_VALID 1
10219820Sjeff
11219820Sjeff/* Posted-Interrupt Descriptor */
12219820Sjeffstruct pi_desc {
13219820Sjeff	union {
14219820Sjeff		u32 pir[8];     /* Posted interrupt requested */
15219820Sjeff		u64 pir64[4];
16219820Sjeff	};
17219820Sjeff	union {
18219820Sjeff		struct {
19219820Sjeff			u16	notifications; /* Suppress and outstanding bits */
20219820Sjeff			u8	nv;
21219820Sjeff			u8	rsvd_2;
22219820Sjeff			u32	ndst;
23219820Sjeff		};
24219820Sjeff		u64 control;
25219820Sjeff	};
26219820Sjeff	u32 rsvd[6];
27219820Sjeff} __aligned(64);
28219820Sjeff
29219820Sjeffstatic inline bool pi_test_and_set_on(struct pi_desc *pi_desc)
30219820Sjeff{
31219820Sjeff	return test_and_set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
32219820Sjeff}
33219820Sjeff
34219820Sjeffstatic inline bool pi_test_and_clear_on(struct pi_desc *pi_desc)
35219820Sjeff{
36272027Shselasky	return test_and_clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
37272027Shselasky}
38272027Shselasky
39272027Shselaskystatic inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc)
40306486Shselasky{
41306486Shselasky	return test_and_clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
42219820Sjeff}
43219820Sjeff
44219820Sjeffstatic inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc)
45219820Sjeff{
46255932Salfred	return test_and_set_bit(vector, (unsigned long *)pi_desc->pir);
47255932Salfred}
48255932Salfred
49255932Salfredstatic inline bool pi_is_pir_empty(struct pi_desc *pi_desc)
50255932Salfred{
51255932Salfred	return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS);
52219820Sjeff}
53219820Sjeff
54219820Sjeffstatic inline void pi_set_sn(struct pi_desc *pi_desc)
55219820Sjeff{
56219820Sjeff	set_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
57219820Sjeff}
58219820Sjeff
59219820Sjeffstatic inline void pi_set_on(struct pi_desc *pi_desc)
60219820Sjeff{
61219820Sjeff	set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
62219820Sjeff}
63219820Sjeff
64219820Sjeffstatic inline void pi_clear_on(struct pi_desc *pi_desc)
65219820Sjeff{
66255932Salfred	clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
67219820Sjeff}
68219820Sjeff
69219820Sjeffstatic inline void pi_clear_sn(struct pi_desc *pi_desc)
70219820Sjeff{
71219820Sjeff	clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
72219820Sjeff}
73219820Sjeff
74219820Sjeffstatic inline bool pi_test_on(struct pi_desc *pi_desc)
75219820Sjeff{
76255932Salfred	return test_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control);
77255932Salfred}
78219820Sjeff
79255932Salfredstatic inline bool pi_test_sn(struct pi_desc *pi_desc)
80255932Salfred{
81255932Salfred	return test_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control);
82255932Salfred}
83255932Salfred
84255932Salfred/* Non-atomic helpers */
85255932Salfredstatic inline void __pi_set_sn(struct pi_desc *pi_desc)
86255932Salfred{
87255932Salfred	pi_desc->notifications |= BIT(POSTED_INTR_SN);
88255932Salfred}
89255932Salfred
90255932Salfredstatic inline void __pi_clear_sn(struct pi_desc *pi_desc)
91255932Salfred{
92255932Salfred	pi_desc->notifications &= ~BIT(POSTED_INTR_SN);
93255932Salfred}
94255932Salfred
95255932Salfred#ifdef CONFIG_X86_POSTED_MSI
96219820Sjeff/*
97219820Sjeff * Not all external vectors are subject to interrupt remapping, e.g. IOMMU's
98219820Sjeff * own interrupts. Here we do not distinguish them since those vector bits in
99219820Sjeff * PIR will always be zero.
100219820Sjeff */
101219820Sjeffstatic inline bool pi_pending_this_cpu(unsigned int vector)
102219820Sjeff{
103219820Sjeff	struct pi_desc *pid = this_cpu_ptr(&posted_msi_pi_desc);
104219820Sjeff
105219820Sjeff	if (WARN_ON_ONCE(vector > NR_VECTORS || vector < FIRST_EXTERNAL_VECTOR))
106219820Sjeff		return false;
107219820Sjeff
108219820Sjeff	return test_bit(vector, (unsigned long *)pid->pir);
109219820Sjeff}
110219820Sjeff
111219820Sjeffextern void intel_posted_msi_init(void);
112219820Sjeff#else
113219820Sjeffstatic inline bool pi_pending_this_cpu(unsigned int vector) { return false; }
114219820Sjeff
115219820Sjeffstatic inline void intel_posted_msi_init(void) {};
116219820Sjeff#endif /* X86_POSTED_MSI */
117219820Sjeff
118219820Sjeff#endif /* _X86_POSTED_INTR_H */
119219820Sjeff