aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/irq_remapping.c
blob: 19381b90e619175028fdabfb806ffe791d3fed19 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/cpumask.h>
#include <linux/errno.h>
#include <linux/msi.h>

#include <asm/hw_irq.h>
#include <asm/irq_remapping.h>

#include "irq_remapping.h"

int irq_remapping_enabled;

int disable_irq_remap;
int disable_sourceid_checking;
int no_x2apic_optout;

static struct irq_remap_ops *remap_ops;

static __init int setup_nointremap(char *str)
{
	disable_irq_remap = 1;
	return 0;
}
early_param("nointremap", setup_nointremap);

static __init int setup_irqremap(char *str)
{
	if (!str)
		return -EINVAL;

	while (*str) {
		if (!strncmp(str, "on", 2))
			disable_irq_remap = 0;
		else if (!strncmp(str, "off", 3))
			disable_irq_remap = 1;
		else if (!strncmp(str, "nosid", 5))
			disable_sourceid_checking = 1;
		else if (!strncmp(str, "no_x2apic_optout", 16))
			no_x2apic_optout = 1;

		str += strcspn(str, ",");
		while (*str == ',')
			str++;
	}

	return 0;
}
early_param("intremap", setup_irqremap);

void __init setup_irq_remapping_ops(void)
{
	remap_ops = &intel_irq_remap_ops;

#ifdef CONFIG_AMD_IOMMU
	if (amd_iommu_irq_ops.prepare() == 0)
		remap_ops = &amd_iommu_irq_ops;
#endif
}

int irq_remapping_supported(void)
{
	if (disable_irq_remap)
		return 0;

	if (!remap_ops || !remap_ops->supported)
		return 0;

	return remap_ops->supported();
}

int __init irq_remapping_prepare(void)
{
	if (!remap_ops || !remap_ops->prepare)
		return -ENODEV;

	return remap_ops->prepare();
}

int __init irq_remapping_enable(void)
{
	if (!remap_ops || !remap_ops->enable)
		return -ENODEV;

	return remap_ops->enable();
}

void irq_remapping_disable(void)
{
	if (!irq_remapping_enabled ||
	    !remap_ops ||
	    !remap_ops->disable)
		return;

	remap_ops->disable();
}

int irq_remapping_reenable(int mode)
{
	if (!irq_remapping_enabled ||
	    !remap_ops ||
	    !remap_ops->reenable)
		return 0;

	return remap_ops->reenable(mode);
}

int __init irq_remap_enable_fault_handling(void)
{
	if (!irq_remapping_enabled)
		return 0;

	if (!remap_ops || !remap_ops->enable_faulting)
		return -ENODEV;

	return remap_ops->enable_faulting();
}

int setup_ioapic_remapped_entry(int irq,
				struct IO_APIC_route_entry *entry,
				unsigned int destination, int vector,
				struct io_apic_irq_attr *attr)
{
	if (!remap_ops || !remap_ops->setup_ioapic_entry)
		return -ENODEV;

	return remap_ops->setup_ioapic_entry(irq, entry, destination,
					     vector, attr);
}

int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
			      bool force)
{
	if (!config_enabled(CONFIG_SMP) || !remap_ops ||
	    !remap_ops->set_affinity)
		return 0;

	return remap_ops->set_affinity(data, mask, force);
}

void free_remapped_irq(int irq)
{
	if (!remap_ops || !remap_ops->free_irq)
		return;

	remap_ops->free_irq(irq);
}

void compose_remapped_msi_msg(struct pci_dev *pdev,
			      unsigned int irq, unsigned int dest,
			      struct msi_msg *msg, u8 hpet_id)
{
	if (!remap_ops || !remap_ops->compose_msi_msg)
		return;

	remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
}

int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{
	if (!remap_ops || !remap_ops->msi_alloc_irq)
		return -ENODEV;

	return remap_ops->msi_alloc_irq(pdev, irq, nvec);
}

int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
			   int index, int sub_handle)
{
	if (!remap_ops || !remap_ops->msi_setup_irq)
		return -ENODEV;

	return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
}

int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{
	if (!remap_ops || !remap_ops->setup_hpet_msi)
		return -ENODEV;

	return remap_ops->setup_hpet_msi(irq, id);
}