msi_ia64.c 4.4 KB
Newer Older
1 2 3 4 5 6
/*
 * MSI hooks for standard x86 apic
 */

#include <linux/pci.h>
#include <linux/irq.h>
7
#include <linux/msi.h>
8
#include <linux/dmar.h>
9
#include <asm/smp.h>
10
#include <asm/msidef.h>
11

12
static struct irq_chip	ia64_msi_chip;
13

14
#ifdef CONFIG_SMP
15 16
static int ia64_set_msi_irq_affinity(struct irq_data *idata,
				     const cpumask_t *cpu_mask, bool force)
17
{
18
	struct msi_msg msg;
19
	u32 addr, data;
20
	int cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
21
	unsigned int irq = idata->irq;
22

23
	if (irq_prepare_move(irq, cpu))
24
		return -1;
25

26
	__get_cached_msi_msg(idata->msi_desc, &msg);
27

28
	addr = msg.address_lo;
29 30
	addr &= MSI_ADDR_DEST_ID_MASK;
	addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
31
	msg.address_lo = addr;
32

33 34 35 36 37
	data = msg.data;
	data &= MSI_DATA_VECTOR_MASK;
	data |= MSI_DATA_VECTOR(irq_to_vector(irq));
	msg.data = data;

38
	pci_write_msi_msg(irq, &msg);
39
	cpumask_copy(idata->affinity, cpumask_of(cpu));
40 41

	return 0;
42
}
43
#endif /* CONFIG_SMP */
44

45
int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
46
{
47
	struct msi_msg	msg;
48
	unsigned long	dest_phys_id;
49
	int	irq, vector;
50
	cpumask_t mask;
51

52 53 54 55
	irq = create_irq();
	if (irq < 0)
		return irq;

56
	irq_set_msi_desc(irq, desc);
57
	cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
58
	dest_phys_id = cpu_physical_id(first_cpu(mask));
59
	vector = irq_to_vector(irq);
60

61 62
	msg.address_hi = 0;
	msg.address_lo =
63
		MSI_ADDR_HEADER |
64
		MSI_ADDR_DEST_MODE_PHYS |
65
		MSI_ADDR_REDIRECTION_CPU |
66
		MSI_ADDR_DEST_ID_CPU(dest_phys_id);
67

68
	msg.data =
69
		MSI_DATA_TRIGGER_EDGE |
70 71 72 73
		MSI_DATA_LEVEL_ASSERT |
		MSI_DATA_DELIVERY_FIXED |
		MSI_DATA_VECTOR(vector);

74
	pci_write_msi_msg(irq, &msg);
75
	irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
76

77
	return 0;
78 79
}

80
void ia64_teardown_msi_irq(unsigned int irq)
81
{
82
	destroy_irq(irq);
83 84
}

85
static void ia64_ack_msi_irq(struct irq_data *data)
86
{
87
	irq_complete_move(data->irq);
T
Thomas Gleixner 已提交
88
	irq_move_irq(data);
89 90 91
	ia64_eoi();
}

92
static int ia64_msi_retrigger_irq(struct irq_data *data)
93
{
94
	unsigned int vector = irq_to_vector(data->irq);
95 96 97 98 99
	ia64_resend_irq(vector);

	return 1;
}

100
/*
101
 * Generic ops used on most IA64 platforms.
102
 */
103
static struct irq_chip ia64_msi_chip = {
104
	.name			= "PCI-MSI",
105 106
	.irq_mask		= pci_msi_mask_irq,
	.irq_unmask		= pci_msi_unmask_irq,
107
	.irq_ack		= ia64_ack_msi_irq,
108
#ifdef CONFIG_SMP
109
	.irq_set_affinity	= ia64_set_msi_irq_affinity,
110
#endif
111
	.irq_retrigger		= ia64_msi_retrigger_irq,
112
};
113 114


115
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
116 117
{
	if (platform_setup_msi_irq)
118
		return platform_setup_msi_irq(pdev, desc);
119

120
	return ia64_setup_msi_irq(pdev, desc);
121 122 123 124 125 126 127 128 129
}

void arch_teardown_msi_irq(unsigned int irq)
{
	if (platform_teardown_msi_irq)
		return platform_teardown_msi_irq(irq);

	return ia64_teardown_msi_irq(irq);
}
130

131
#ifdef CONFIG_INTEL_IOMMU
132
#ifdef CONFIG_SMP
133 134
static int dmar_msi_set_affinity(struct irq_data *data,
				 const struct cpumask *mask, bool force)
135
{
136
	unsigned int irq = data->irq;
137 138
	struct irq_cfg *cfg = irq_cfg + irq;
	struct msi_msg msg;
139
	int cpu = cpumask_first_and(mask, cpu_online_mask);
140 141

	if (irq_prepare_move(irq, cpu))
142
		return -1;
143 144 145 146 147

	dmar_msi_read(irq, &msg);

	msg.data &= ~MSI_DATA_VECTOR_MASK;
	msg.data |= MSI_DATA_VECTOR(cfg->vector);
148 149
	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
	msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
150 151

	dmar_msi_write(irq, &msg);
152
	cpumask_copy(data->affinity, mask);
153 154

	return 0;
155 156 157
}
#endif /* CONFIG_SMP */

158
static struct irq_chip dmar_msi_type = {
159
	.name = "DMAR_MSI",
160 161
	.irq_unmask = dmar_msi_unmask,
	.irq_mask = dmar_msi_mask,
162
	.irq_ack = ia64_ack_msi_irq,
163
#ifdef CONFIG_SMP
164
	.irq_set_affinity = dmar_msi_set_affinity,
165
#endif
166
	.irq_retrigger = ia64_msi_retrigger_irq,
167 168 169 170 171 172 173 174 175
};

static int
msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
{
	struct irq_cfg *cfg = irq_cfg + irq;
	unsigned dest;
	cpumask_t mask;

176
	cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
177 178 179 180 181
	dest = cpu_physical_id(first_cpu(mask));

	msg->address_hi = 0;
	msg->address_lo =
		MSI_ADDR_HEADER |
182
		MSI_ADDR_DEST_MODE_PHYS |
183
		MSI_ADDR_REDIRECTION_CPU |
184
		MSI_ADDR_DEST_ID_CPU(dest);
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

	msg->data =
		MSI_DATA_TRIGGER_EDGE |
		MSI_DATA_LEVEL_ASSERT |
		MSI_DATA_DELIVERY_FIXED |
		MSI_DATA_VECTOR(cfg->vector);
	return 0;
}

int arch_setup_dmar_msi(unsigned int irq)
{
	int ret;
	struct msi_msg msg;

	ret = msi_compose_msg(NULL, irq, &msg);
	if (ret < 0)
		return ret;
	dmar_msi_write(irq, &msg);
203 204
	irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
				      "edge");
205 206
	return 0;
}
207
#endif /* CONFIG_INTEL_IOMMU */
208