13b20eb23SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
210e5247fSKeshavamurthy, Anil S /*
310e5247fSKeshavamurthy, Anil S * Copyright (c) 2006, Intel Corporation.
410e5247fSKeshavamurthy, Anil S *
510e5247fSKeshavamurthy, Anil S * Copyright (C) Ashok Raj <[email protected]>
610e5247fSKeshavamurthy, Anil S * Copyright (C) Shaohua Li <[email protected]>
710e5247fSKeshavamurthy, Anil S */
810e5247fSKeshavamurthy, Anil S
910e5247fSKeshavamurthy, Anil S #ifndef __DMAR_H__
1010e5247fSKeshavamurthy, Anil S #define __DMAR_H__
1110e5247fSKeshavamurthy, Anil S
1210e5247fSKeshavamurthy, Anil S #include <linux/acpi.h>
1310e5247fSKeshavamurthy, Anil S #include <linux/types.h>
14ba395927SKeshavamurthy, Anil S #include <linux/msi.h>
151531a6a6SSuresh Siddha #include <linux/irqreturn.h>
163a5670e8SJiang Liu #include <linux/rwsem.h>
17b2d09103SIngo Molnar #include <linux/rculist.h>
1810e5247fSKeshavamurthy, Anil S
196eea69ddSAndrew Morton struct acpi_dmar_header;
206eea69ddSAndrew Morton
2125357900SLu Baolu #define DMAR_UNITS_SUPPORTED 1024
2278d8e704SJiang Liu
2341750d31SSuresh Siddha /* DMAR Flags */
2441750d31SSuresh Siddha #define DMAR_INTR_REMAP 0x1
2541750d31SSuresh Siddha #define DMAR_X2APIC_OPT_OUT 0x2
2689a6079dSLu Baolu #define DMAR_PLATFORM_OPT_IN 0x4
2741750d31SSuresh Siddha
28ba395927SKeshavamurthy, Anil S struct intel_iommu;
29694835dcSJiang Liu
30832bd858SDavid Woodhouse struct dmar_dev_scope {
31832bd858SDavid Woodhouse struct device __rcu *dev;
32832bd858SDavid Woodhouse u8 bus;
33832bd858SDavid Woodhouse u8 devfn;
34832bd858SDavid Woodhouse };
35832bd858SDavid Woodhouse
36d3f13810SSuresh Siddha #ifdef CONFIG_DMAR_TABLE
3741750d31SSuresh Siddha extern struct acpi_table_header *dmar_tbl;
3810e5247fSKeshavamurthy, Anil S struct dmar_drhd_unit {
3910e5247fSKeshavamurthy, Anil S struct list_head list; /* list of drhd units */
401886e8a9SSuresh Siddha struct acpi_dmar_header *hdr; /* ACPI header */
4110e5247fSKeshavamurthy, Anil S u64 reg_base_addr; /* register base address*/
424db96bfeSKan Liang unsigned long reg_size; /* size of register set */
43832bd858SDavid Woodhouse struct dmar_dev_scope *devices;/* target device array */
4410e5247fSKeshavamurthy, Anil S int devices_cnt; /* target device count */
45276dbf99SDavid Woodhouse u16 segment; /* PCI domain */
4610e5247fSKeshavamurthy, Anil S u8 ignored:1; /* ignore drhd */
4710e5247fSKeshavamurthy, Anil S u8 include_all:1;
48b1012ca8SLu Baolu u8 gfx_dedicated:1; /* graphic dedicated */
4910e5247fSKeshavamurthy, Anil S struct intel_iommu *iommu;
5010e5247fSKeshavamurthy, Anil S };
5110e5247fSKeshavamurthy, Anil S
5257384592SJoerg Roedel struct dmar_pci_path {
5357384592SJoerg Roedel u8 bus;
5457384592SJoerg Roedel u8 device;
5557384592SJoerg Roedel u8 function;
5657384592SJoerg Roedel };
5757384592SJoerg Roedel
5859ce0515SJiang Liu struct dmar_pci_notify_info {
5959ce0515SJiang Liu struct pci_dev *dev;
6059ce0515SJiang Liu unsigned long event;
6159ce0515SJiang Liu int bus;
6259ce0515SJiang Liu u16 seg;
6359ce0515SJiang Liu u16 level;
6457384592SJoerg Roedel struct dmar_pci_path path[];
6559ce0515SJiang Liu } __attribute__((packed));
6659ce0515SJiang Liu
673a5670e8SJiang Liu extern struct rw_semaphore dmar_global_lock;
682ae21010SSuresh Siddha extern struct list_head dmar_drhd_units;
692ae21010SSuresh Siddha
702ae21010SSuresh Siddha #define for_each_drhd_unit(drhd) \
7102d715b4SAmol Grover list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
7202d715b4SAmol Grover dmar_rcu_check())
732ae21010SSuresh Siddha
747c919779SJiang Liu #define for_each_active_drhd_unit(drhd) \
75f5152416SQian Cai list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
76f5152416SQian Cai dmar_rcu_check()) \
777c919779SJiang Liu if (drhd->ignored) {} else
787c919779SJiang Liu
798f912ba4SDavid Woodhouse #define for_each_active_iommu(i, drhd) \
80f5152416SQian Cai list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
81f5152416SQian Cai dmar_rcu_check()) \
828f912ba4SDavid Woodhouse if (i=drhd->iommu, drhd->ignored) {} else
838f912ba4SDavid Woodhouse
848f912ba4SDavid Woodhouse #define for_each_iommu(i, drhd) \
8502d715b4SAmol Grover list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, \
8602d715b4SAmol Grover dmar_rcu_check()) \
878f912ba4SDavid Woodhouse if (i=drhd->iommu, 0) {} else
888f912ba4SDavid Woodhouse
dmar_rcu_check(void)890e242612SJiang Liu static inline bool dmar_rcu_check(void)
900e242612SJiang Liu {
910e242612SJiang Liu return rwsem_is_locked(&dmar_global_lock) ||
927ebb5f8eSLu Baolu system_state == SYSTEM_BOOTING;
930e242612SJiang Liu }
940e242612SJiang Liu
950e242612SJiang Liu #define dmar_rcu_dereference(p) rcu_dereference_check((p), dmar_rcu_check())
960e242612SJiang Liu
97a760f8a6SQian Cai #define for_each_dev_scope(devs, cnt, i, tmp) \
98a760f8a6SQian Cai for ((i) = 0; ((tmp) = (i) < (cnt) ? \
99a760f8a6SQian Cai dmar_rcu_dereference((devs)[(i)].dev) : NULL, (i) < (cnt)); \
100a760f8a6SQian Cai (i)++)
101b683b230SJiang Liu
102a760f8a6SQian Cai #define for_each_active_dev_scope(devs, cnt, i, tmp) \
103a760f8a6SQian Cai for_each_dev_scope((devs), (cnt), (i), (tmp)) \
104a760f8a6SQian Cai if (!(tmp)) { continue; } else
105b683b230SJiang Liu
1062ae21010SSuresh Siddha extern int dmar_table_init(void);
1072ae21010SSuresh Siddha extern int dmar_dev_scope_init(void);
108ec154bf5SJoerg Roedel extern void dmar_register_bus_notifier(void);
109bb3a6b78SJiang Liu extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt);
110832bd858SDavid Woodhouse extern void dmar_free_dev_scope(struct dmar_dev_scope **devices, int *cnt);
11159ce0515SJiang Liu extern int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
11259ce0515SJiang Liu void *start, void*end, u16 segment,
113832bd858SDavid Woodhouse struct dmar_dev_scope *devices,
11459ce0515SJiang Liu int devices_cnt);
11559ce0515SJiang Liu extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info,
116832bd858SDavid Woodhouse u16 segment, struct dmar_dev_scope *devices,
11759ce0515SJiang Liu int count);
1182ae21010SSuresh Siddha /* Intel IOMMU detection */
11978013eaaSChristoph Hellwig void detect_intel_iommu(void);
120*d74169ceSDimitri Sivanich extern int enable_drhd_fault_handling(unsigned int cpu);
1216b197249SJiang Liu extern int dmar_device_add(acpi_handle handle);
1226b197249SJiang Liu extern int dmar_device_remove(acpi_handle handle);
1232ae21010SSuresh Siddha
dmar_res_noop(struct acpi_dmar_header * hdr,void * arg)124c2a0b538SJiang Liu static inline int dmar_res_noop(struct acpi_dmar_header *hdr, void *arg)
125c2a0b538SJiang Liu {
126c2a0b538SJiang Liu return 0;
127c2a0b538SJiang Liu }
128c2a0b538SJiang Liu
129914ff771SKyung Min Park #ifdef CONFIG_DMAR_DEBUG
130914ff771SKyung Min Park void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
131914ff771SKyung Min Park unsigned long long addr, u32 pasid);
132914ff771SKyung Min Park #else
dmar_fault_dump_ptes(struct intel_iommu * iommu,u16 source_id,unsigned long long addr,u32 pasid)133914ff771SKyung Min Park static inline void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
134914ff771SKyung Min Park unsigned long long addr, u32 pasid) {}
135914ff771SKyung Min Park #endif
136914ff771SKyung Min Park
1378594d832SJiang Liu #ifdef CONFIG_INTEL_IOMMU
1388594d832SJiang Liu extern int iommu_detected, no_iommu;
1398594d832SJiang Liu extern int intel_iommu_init(void);
1406c3a44edSDeepa Dinamani extern void intel_iommu_shutdown(void);
141c2a0b538SJiang Liu extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg);
142c2a0b538SJiang Liu extern int dmar_parse_one_atsr(struct acpi_dmar_header *header, void *arg);
1436b197249SJiang Liu extern int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg);
14431a75cbbSYian Chen extern int dmar_parse_one_satc(struct acpi_dmar_header *hdr, void *arg);
1456b197249SJiang Liu extern int dmar_release_one_atsr(struct acpi_dmar_header *hdr, void *arg);
1466b197249SJiang Liu extern int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert);
1478594d832SJiang Liu extern int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
1488594d832SJiang Liu #else /* !CONFIG_INTEL_IOMMU: */
intel_iommu_init(void)1498594d832SJiang Liu static inline int intel_iommu_init(void) { return -ENODEV; }
intel_iommu_shutdown(void)1506c3a44edSDeepa Dinamani static inline void intel_iommu_shutdown(void) { }
1516b197249SJiang Liu
152c2a0b538SJiang Liu #define dmar_parse_one_rmrr dmar_res_noop
153c2a0b538SJiang Liu #define dmar_parse_one_atsr dmar_res_noop
1546b197249SJiang Liu #define dmar_check_one_atsr dmar_res_noop
1556b197249SJiang Liu #define dmar_release_one_atsr dmar_res_noop
15631a75cbbSYian Chen #define dmar_parse_one_satc dmar_res_noop
1576b197249SJiang Liu
dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info * info)1588594d832SJiang Liu static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
1598594d832SJiang Liu {
1608594d832SJiang Liu return 0;
1618594d832SJiang Liu }
1626b197249SJiang Liu
dmar_iommu_hotplug(struct dmar_drhd_unit * dmaru,bool insert)1636b197249SJiang Liu static inline int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert)
1646b197249SJiang Liu {
1656b197249SJiang Liu return 0;
1666b197249SJiang Liu }
1678594d832SJiang Liu #endif /* CONFIG_INTEL_IOMMU */
1688594d832SJiang Liu
1696b197249SJiang Liu #ifdef CONFIG_IRQ_REMAP
1706b197249SJiang Liu extern int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool insert);
1716b197249SJiang Liu #else /* CONFIG_IRQ_REMAP */
dmar_ir_hotplug(struct dmar_drhd_unit * dmaru,bool insert)1726b197249SJiang Liu static inline int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool insert)
1736b197249SJiang Liu { return 0; }
1746b197249SJiang Liu #endif /* CONFIG_IRQ_REMAP */
1756b197249SJiang Liu
17689a6079dSLu Baolu extern bool dmar_platform_optin(void);
17789a6079dSLu Baolu
1786b197249SJiang Liu #else /* CONFIG_DMAR_TABLE */
1796b197249SJiang Liu
dmar_device_add(void * handle)1806b197249SJiang Liu static inline int dmar_device_add(void *handle)
1816b197249SJiang Liu {
1826b197249SJiang Liu return 0;
1836b197249SJiang Liu }
1846b197249SJiang Liu
dmar_device_remove(void * handle)1856b197249SJiang Liu static inline int dmar_device_remove(void *handle)
1866b197249SJiang Liu {
1876b197249SJiang Liu return 0;
1886b197249SJiang Liu }
1896b197249SJiang Liu
dmar_platform_optin(void)19089a6079dSLu Baolu static inline bool dmar_platform_optin(void)
19189a6079dSLu Baolu {
19289a6079dSLu Baolu return false;
19389a6079dSLu Baolu }
19489a6079dSLu Baolu
detect_intel_iommu(void)19578013eaaSChristoph Hellwig static inline void detect_intel_iommu(void)
19678013eaaSChristoph Hellwig {
19778013eaaSChristoph Hellwig }
19878013eaaSChristoph Hellwig
1998594d832SJiang Liu #endif /* CONFIG_DMAR_TABLE */
2002ae21010SSuresh Siddha
2012ae21010SSuresh Siddha struct irte {
2022ae21010SSuresh Siddha union {
203b1fe7f2cSPeter Zijlstra struct {
204b1fe7f2cSPeter Zijlstra union {
2053bf17472SThomas Gleixner /* Shared between remapped and posted mode*/
2062ae21010SSuresh Siddha struct {
2073bf17472SThomas Gleixner __u64 present : 1, /* 0 */
2083bf17472SThomas Gleixner fpd : 1, /* 1 */
2093bf17472SThomas Gleixner __res0 : 6, /* 2 - 6 */
2103bf17472SThomas Gleixner avail : 4, /* 8 - 11 */
2113bf17472SThomas Gleixner __res1 : 3, /* 12 - 14 */
2123bf17472SThomas Gleixner pst : 1, /* 15 */
2133bf17472SThomas Gleixner vector : 8, /* 16 - 23 */
2143bf17472SThomas Gleixner __res2 : 40; /* 24 - 63 */
2153bf17472SThomas Gleixner };
2163bf17472SThomas Gleixner
2173bf17472SThomas Gleixner /* Remapped mode */
2183bf17472SThomas Gleixner struct {
2193bf17472SThomas Gleixner __u64 r_present : 1, /* 0 */
2203bf17472SThomas Gleixner r_fpd : 1, /* 1 */
2213bf17472SThomas Gleixner dst_mode : 1, /* 2 */
2223bf17472SThomas Gleixner redir_hint : 1, /* 3 */
2233bf17472SThomas Gleixner trigger_mode : 1, /* 4 */
2243bf17472SThomas Gleixner dlvry_mode : 3, /* 5 - 7 */
2253bf17472SThomas Gleixner r_avail : 4, /* 8 - 11 */
2263bf17472SThomas Gleixner r_res0 : 4, /* 12 - 15 */
2273bf17472SThomas Gleixner r_vector : 8, /* 16 - 23 */
2283bf17472SThomas Gleixner r_res1 : 8, /* 24 - 31 */
2293bf17472SThomas Gleixner dest_id : 32; /* 32 - 63 */
2303bf17472SThomas Gleixner };
2313bf17472SThomas Gleixner
2323bf17472SThomas Gleixner /* Posted mode */
2333bf17472SThomas Gleixner struct {
2343bf17472SThomas Gleixner __u64 p_present : 1, /* 0 */
2353bf17472SThomas Gleixner p_fpd : 1, /* 1 */
2363bf17472SThomas Gleixner p_res0 : 6, /* 2 - 7 */
2373bf17472SThomas Gleixner p_avail : 4, /* 8 - 11 */
2383bf17472SThomas Gleixner p_res1 : 2, /* 12 - 13 */
2393bf17472SThomas Gleixner p_urgent : 1, /* 14 */
2403bf17472SThomas Gleixner p_pst : 1, /* 15 */
2413bf17472SThomas Gleixner p_vector : 8, /* 16 - 23 */
2423bf17472SThomas Gleixner p_res2 : 14, /* 24 - 37 */
2433bf17472SThomas Gleixner pda_l : 26; /* 38 - 63 */
2442ae21010SSuresh Siddha };
2452ae21010SSuresh Siddha __u64 low;
2462ae21010SSuresh Siddha };
2472ae21010SSuresh Siddha
2482ae21010SSuresh Siddha union {
2493bf17472SThomas Gleixner /* Shared between remapped and posted mode*/
2502ae21010SSuresh Siddha struct {
2513bf17472SThomas Gleixner __u64 sid : 16, /* 64 - 79 */
2523bf17472SThomas Gleixner sq : 2, /* 80 - 81 */
2533bf17472SThomas Gleixner svt : 2, /* 82 - 83 */
2543bf17472SThomas Gleixner __res3 : 44; /* 84 - 127 */
2553bf17472SThomas Gleixner };
2563bf17472SThomas Gleixner
2573bf17472SThomas Gleixner /* Posted mode*/
2583bf17472SThomas Gleixner struct {
2593bf17472SThomas Gleixner __u64 p_sid : 16, /* 64 - 79 */
2603bf17472SThomas Gleixner p_sq : 2, /* 80 - 81 */
2613bf17472SThomas Gleixner p_svt : 2, /* 82 - 83 */
2623bf17472SThomas Gleixner p_res3 : 12, /* 84 - 95 */
2633bf17472SThomas Gleixner pda_h : 32; /* 96 - 127 */
2642ae21010SSuresh Siddha };
2652ae21010SSuresh Siddha __u64 high;
2662ae21010SSuresh Siddha };
2672ae21010SSuresh Siddha };
268b1fe7f2cSPeter Zijlstra #ifdef CONFIG_IRQ_REMAP
269b1fe7f2cSPeter Zijlstra __u128 irte;
270b1fe7f2cSPeter Zijlstra #endif
271b1fe7f2cSPeter Zijlstra };
272b1fe7f2cSPeter Zijlstra };
273423f0859SThomas Gleixner
dmar_copy_shared_irte(struct irte * dst,struct irte * src)274bf56027fSThomas Gleixner static inline void dmar_copy_shared_irte(struct irte *dst, struct irte *src)
275bf56027fSThomas Gleixner {
276bf56027fSThomas Gleixner dst->present = src->present;
277bf56027fSThomas Gleixner dst->fpd = src->fpd;
278bf56027fSThomas Gleixner dst->avail = src->avail;
279bf56027fSThomas Gleixner dst->pst = src->pst;
280bf56027fSThomas Gleixner dst->vector = src->vector;
281bf56027fSThomas Gleixner dst->sid = src->sid;
282bf56027fSThomas Gleixner dst->sq = src->sq;
283bf56027fSThomas Gleixner dst->svt = src->svt;
284bf56027fSThomas Gleixner }
285bf56027fSThomas Gleixner
2863bf17472SThomas Gleixner #define PDA_LOW_BIT 26
2873bf17472SThomas Gleixner #define PDA_HIGH_BIT 32
2883bf17472SThomas Gleixner
2892ae21010SSuresh Siddha /* Can't use the common MSI interrupt functions
2902ae21010SSuresh Siddha * since DMAR is not a pci device
2912ae21010SSuresh Siddha */
2925c2837fbSThomas Gleixner struct irq_data;
2935c2837fbSThomas Gleixner extern void dmar_msi_unmask(struct irq_data *data);
2945c2837fbSThomas Gleixner extern void dmar_msi_mask(struct irq_data *data);
2952ae21010SSuresh Siddha extern void dmar_msi_write(int irq, struct msi_msg *msg);
2962ae21010SSuresh Siddha extern int dmar_set_interrupt(struct intel_iommu *iommu);
2971531a6a6SSuresh Siddha extern irqreturn_t dmar_fault(int irq, void *dev_id);
29834742db8SJiang Liu extern int dmar_alloc_hwirq(int id, int node, void *arg);
29934742db8SJiang Liu extern void dmar_free_hwirq(int irq);
3002ae21010SSuresh Siddha
30110e5247fSKeshavamurthy, Anil S #endif /* __DMAR_H__ */
302