msi_ia64.c 3.3 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 <asm/smp.h>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

/*
 * Shifts for APIC-based data
 */

#define MSI_DATA_VECTOR_SHIFT		0
#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)

#define MSI_DATA_DELIVERY_SHIFT		8
#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)

#define MSI_DATA_LEVEL_SHIFT		14
#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)

#define MSI_DATA_TRIGGER_SHIFT		15
#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)

/*
 * Shift/mask fields for APIC-based bus address
 */

33
#define MSI_TARGET_CPU_SHIFT		4
34 35 36 37 38 39 40 41 42 43 44 45 46
#define MSI_ADDR_HEADER			0xfee00000

#define MSI_ADDR_DESTID_MASK		0xfff0000f
#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)

#define MSI_ADDR_DESTMODE_SHIFT		2
#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)

#define MSI_ADDR_REDIRECTION_SHIFT	3
#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)

47
static struct irq_chip	ia64_msi_chip;
48

49 50
#ifdef CONFIG_SMP
static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
51
{
52 53 54 55
	struct msi_msg msg;
	u32 addr;

	read_msi_msg(irq, &msg);
56

57
	addr = msg.address_lo;
58
	addr &= MSI_ADDR_DESTID_MASK;
59
	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
60
	msg.address_lo = addr;
61

62
	write_msi_msg(irq, &msg);
63
	irq_desc[irq].affinity = cpu_mask;
64
}
65
#endif /* CONFIG_SMP */
66

67
int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
68
{
69
	struct msi_msg	msg;
70
	unsigned long	dest_phys_id;
71
	int	irq, vector;
72

73 74 75 76 77
	irq = create_irq();
	if (irq < 0)
		return irq;

	set_irq_msi(irq, desc);
78
	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
79
	vector = irq;
80

81 82
	msg.address_hi = 0;
	msg.address_lo =
83 84 85 86
		MSI_ADDR_HEADER |
		MSI_ADDR_DESTMODE_PHYS |
		MSI_ADDR_REDIRECTION_CPU |
		MSI_ADDR_DESTID_CPU(dest_phys_id);
87

88
	msg.data =
89
		MSI_DATA_TRIGGER_EDGE |
90 91 92 93
		MSI_DATA_LEVEL_ASSERT |
		MSI_DATA_DELIVERY_FIXED |
		MSI_DATA_VECTOR(vector);

94 95 96
	write_msi_msg(irq, &msg);
	set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);

97
	return irq;
98 99
}

100
void ia64_teardown_msi_irq(unsigned int irq)
101
{
102
	destroy_irq(irq);
103 104
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118
static void ia64_ack_msi_irq(unsigned int irq)
{
	move_native_irq(irq);
	ia64_eoi();
}

static int ia64_msi_retrigger_irq(unsigned int irq)
{
	unsigned int vector = irq;
	ia64_resend_irq(vector);

	return 1;
}

119
/*
120
 * Generic ops used on most IA64 platforms.
121
 */
122 123 124 125 126 127 128 129 130
static struct irq_chip ia64_msi_chip = {
	.name		= "PCI-MSI",
	.mask		= mask_msi_irq,
	.unmask		= unmask_msi_irq,
	.ack		= ia64_ack_msi_irq,
#ifdef CONFIG_SMP
	.set_affinity	= ia64_set_msi_irq_affinity,
#endif
	.retrigger	= ia64_msi_retrigger_irq,
131
};
132 133


134
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
135 136
{
	if (platform_setup_msi_irq)
137
		return platform_setup_msi_irq(pdev, desc);
138

139
	return ia64_setup_msi_irq(pdev, desc);
140 141 142 143 144 145 146 147 148
}

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);
}