Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
54168ed7
Commit
54168ed7
authored
Aug 20, 2008
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
x86: make io_apic_32.c the same as io_apic_64.c
Signed-off-by:
Ingo Molnar
<
mingo@elte.hu
>
parent
047c8fdb
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1104 additions
and
417 deletions
+1104
-417
arch/x86/kernel/io_apic_32.c
arch/x86/kernel/io_apic_32.c
+1104
-417
No files found.
arch/x86/kernel/io_apic_32.c
View file @
54168ed7
...
...
@@ -35,7 +35,7 @@
#include <linux/htirq.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
/* time_after() */
#include <linux/jiffies.h>
/* time_after() */
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
...
...
@@ -64,8 +64,8 @@
#define __apicdebuginit(type) static type __init
/*
*
Is the SiS APIC rmw bug present ?
*
-1 = don't know, 0 = no, 1 = yes
*
Is the SiS APIC rmw bug present ?
*
-1 = don't know, 0 = no, 1 = yes
*/
int
sis_apic_bug
=
-
1
;
...
...
@@ -102,7 +102,7 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
int
skip_ioapic_setup
;
static
int
__init
parse_noapic
(
char
*
arg
)
static
int
__init
parse_noapic
(
char
*
str
)
{
/* disable IO-APIC */
disable_ioapic_setup
();
...
...
@@ -188,7 +188,7 @@ static void __init init_work(void *data)
irq_cfgx
[
legacy_count
-
1
].
next
=
NULL
;
}
#define for_each_irq_cfg(cfg)
\
#define for_each_irq_cfg(cfg)
\
for (cfg = irq_cfgx; cfg; cfg = cfg->next)
DEFINE_DYN_ARRAY
(
irq_cfgx
,
sizeof
(
struct
irq_cfg
),
nr_irq_cfg
,
PAGE_SIZE
,
init_work
);
...
...
@@ -262,7 +262,6 @@ static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
irq_cfgx
=
cfg
;
cfg
->
irq
=
irq
;
printk
(
KERN_DEBUG
"found new irq_cfg for irq %d
\n
"
,
cfg
->
irq
);
#ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG
{
/* dump the results */
...
...
@@ -384,9 +383,9 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i
*/
static
inline
void
io_apic_modify
(
unsigned
int
apic
,
unsigned
int
reg
,
unsigned
int
value
)
{
volatile
struct
io_apic
__iomem
*
io_apic
=
io_apic_base
(
apic
);
if
(
sis_apic_bug
)
writel
(
reg
,
&
io_apic
->
index
);
struct
io_apic
__iomem
*
io_apic
=
io_apic_base
(
apic
);
if
(
sis_apic_bug
)
writel
(
reg
,
&
io_apic
->
index
);
writel
(
value
,
&
io_apic
->
data
);
}
...
...
@@ -494,11 +493,20 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
apic
=
entry
->
apic
;
pin
=
entry
->
pin
;
#ifdef CONFIG_INTR_REMAP
/*
* With interrupt-remapping, destination information comes
* from interrupt-remapping table entry.
*/
if
(
!
irq_remapped
(
irq
))
io_apic_write
(
apic
,
0x11
+
pin
*
2
,
dest
);
#else
io_apic_write
(
apic
,
0x11
+
pin
*
2
,
dest
);
#endif
reg
=
io_apic_read
(
apic
,
0x10
+
pin
*
2
);
reg
&=
~
IO_APIC_REDIR_VECTOR_MASK
;
reg
|=
vector
;
io_apic_modify
(
apic
,
0x10
+
pin
*
2
,
reg
);
io_apic_modify
(
apic
,
0x10
+
pin
*
2
,
reg
);
if
(
!
entry
->
next
)
break
;
entry
=
entry
->
next
;
...
...
@@ -513,6 +521,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
unsigned
long
flags
;
unsigned
int
dest
;
cpumask_t
tmp
;
struct
irq_desc
*
desc
;
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
...
...
@@ -529,12 +538,12 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
*/
dest
=
SET_APIC_LOGICAL_ID
(
dest
);
desc
=
irq_to_desc
(
irq
);
spin_lock_irqsave
(
&
ioapic_lock
,
flags
);
__target_IO_APIC_irq
(
irq
,
dest
,
cfg
->
vector
);
irq_to_desc
(
irq
)
->
affinity
=
mask
;
desc
->
affinity
=
mask
;
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
}
#endif
/* CONFIG_SMP */
/*
...
...
@@ -699,7 +708,7 @@ static void __unmask_and_level_IO_APIC_irq(unsigned int irq)
#endif
static
void
mask_IO_APIC_irq
(
unsigned
int
irq
)
static
void
mask_IO_APIC_irq
(
unsigned
int
irq
)
{
unsigned
long
flags
;
...
...
@@ -708,7 +717,7 @@ static void mask_IO_APIC_irq(unsigned int irq)
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
}
static
void
unmask_IO_APIC_irq
(
unsigned
int
irq
)
static
void
unmask_IO_APIC_irq
(
unsigned
int
irq
)
{
unsigned
long
flags
;
...
...
@@ -725,14 +734,13 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
entry
=
ioapic_read_entry
(
apic
,
pin
);
if
(
entry
.
delivery_mode
==
dest_SMI
)
return
;
/*
* Disable it in the IO-APIC irq-routing table:
*/
ioapic_mask_entry
(
apic
,
pin
);
}
static
void
clear_IO_APIC
(
void
)
static
void
clear_IO_APIC
(
void
)
{
int
apic
,
pin
;
...
...
@@ -741,7 +749,7 @@ static void clear_IO_APIC(void)
clear_IO_APIC_pin
(
apic
,
pin
);
}
#if
ndef CONFIG_SMP
#if
!defined(CONFIG_SMP) && defined(CONFIG_X86_32)
void
send_IPI_self
(
int
vector
)
{
unsigned
int
cfg
;
...
...
@@ -756,9 +764,9 @@ void send_IPI_self(int vector)
*/
apic_write
(
APIC_ICR
,
cfg
);
}
#endif
/* !CONFIG_SMP */
#endif
/* !CONFIG_SMP && CONFIG_X86_32*/
#ifdef CONFIG_X86_32
/*
* support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
* specific CPU-side IRQs.
...
...
@@ -797,6 +805,75 @@ static int __init ioapic_pirq_setup(char *str)
}
__setup
(
"pirq="
,
ioapic_pirq_setup
);
#endif
/* CONFIG_X86_32 */
#ifdef CONFIG_INTR_REMAP
/* I/O APIC RTE contents at the OS boot up */
static
struct
IO_APIC_route_entry
*
early_ioapic_entries
[
MAX_IO_APICS
];
/*
* Saves and masks all the unmasked IO-APIC RTE's
*/
int
save_mask_IO_APIC_setup
(
void
)
{
union
IO_APIC_reg_01
reg_01
;
unsigned
long
flags
;
int
apic
,
pin
;
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
spin_lock_irqsave
(
&
ioapic_lock
,
flags
);
reg_01
.
raw
=
io_apic_read
(
apic
,
1
);
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
nr_ioapic_registers
[
apic
]
=
reg_01
.
bits
.
entries
+
1
;
}
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
early_ioapic_entries
[
apic
]
=
kzalloc
(
sizeof
(
struct
IO_APIC_route_entry
)
*
nr_ioapic_registers
[
apic
],
GFP_KERNEL
);
if
(
!
early_ioapic_entries
[
apic
])
return
-
ENOMEM
;
}
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
for
(
pin
=
0
;
pin
<
nr_ioapic_registers
[
apic
];
pin
++
)
{
struct
IO_APIC_route_entry
entry
;
entry
=
early_ioapic_entries
[
apic
][
pin
]
=
ioapic_read_entry
(
apic
,
pin
);
if
(
!
entry
.
mask
)
{
entry
.
mask
=
1
;
ioapic_write_entry
(
apic
,
pin
,
entry
);
}
}
return
0
;
}
void
restore_IO_APIC_setup
(
void
)
{
int
apic
,
pin
;
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
for
(
pin
=
0
;
pin
<
nr_ioapic_registers
[
apic
];
pin
++
)
ioapic_write_entry
(
apic
,
pin
,
early_ioapic_entries
[
apic
][
pin
]);
}
void
reinit_intr_remapped_IO_APIC
(
int
intr_remapping
)
{
/*
* for now plain restore of previous settings.
* TBD: In the case of OS enabling interrupt-remapping,
* IO-APIC RTE's need to be setup to point to interrupt-remapping
* table entries. for now, do a plain restore, and wait for
* the setup_IO_APIC_irqs() to do proper initialization.
*/
restore_IO_APIC_setup
();
}
#endif
/*
* Find the IRQ entry number of a certain pin.
...
...
@@ -848,7 +925,7 @@ static int __init find_isa_irq_apic(int irq, int type)
}
if
(
i
<
mp_irq_entries
)
{
int
apic
;
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
if
(
mp_ioapics
[
apic
].
mp_apicid
==
mp_irqs
[
i
].
mp_dstapic
)
return
apic
;
}
...
...
@@ -867,10 +944,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
{
int
apic
,
i
,
best_guess
=
-
1
;
apic_printk
(
APIC_DEBUG
,
"querying PCI -> IRQ mapping bus:%d,
"
"slot:%d, pin:%d.
\n
"
,
bus
,
slot
,
pin
);
apic_printk
(
APIC_DEBUG
,
"querying PCI -> IRQ mapping bus:%d,
slot:%d, pin:%d.
\n
"
,
bus
,
slot
,
pin
);
if
(
test_bit
(
bus
,
mp_bus_not_pci
))
{
printk
(
KERN_WARNING
"PCI BIOS passed nonexistent PCI bus %d!
\n
"
,
bus
);
apic_printk
(
APIC_VERBOSE
,
"PCI BIOS passed nonexistent PCI bus %d!
\n
"
,
bus
);
return
-
1
;
}
for
(
i
=
0
;
i
<
mp_irq_entries
;
i
++
)
{
...
...
@@ -885,7 +962,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
!
mp_irqs
[
i
].
mp_irqtype
&&
(
bus
==
lbus
)
&&
(
slot
==
((
mp_irqs
[
i
].
mp_srcbusirq
>>
2
)
&
0x1f
)))
{
int
irq
=
pin_2_irq
(
i
,
apic
,
mp_irqs
[
i
].
mp_dstirq
);
int
irq
=
pin_2_irq
(
i
,
apic
,
mp_irqs
[
i
].
mp_dstirq
);
if
(
!
(
apic
||
IO_APIC_IRQ
(
irq
)))
continue
;
...
...
@@ -902,6 +979,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
}
return
best_guess
;
}
EXPORT_SYMBOL
(
IO_APIC_get_PCI_irq_vector
);
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
...
...
@@ -918,6 +996,7 @@ static int EISA_ELCR(unsigned int irq)
"Broken MPtable reports ISA irq %d
\n
"
,
irq
);
return
0
;
}
#endif
/* ISA interrupts are always polarity zero edge triggered,
...
...
@@ -954,36 +1033,36 @@ static int MPBIOS_polarity(int idx)
/*
* Determine IRQ line polarity (high active or low active):
*/
switch
(
mp_irqs
[
idx
].
mp_irqflag
&
3
)
{
case
0
:
/* conforms, ie. bus-type dependent polarity */
{
polarity
=
test_bit
(
bus
,
mp_bus_not_pci
)
?
default_ISA_polarity
(
idx
)
:
default_PCI_polarity
(
idx
);
break
;
}
case
1
:
/* high active */
{
polarity
=
0
;
break
;
}
case
2
:
/* reserved */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
polarity
=
1
;
break
;
}
case
3
:
/* low active */
{
polarity
=
1
;
break
;
}
default:
/* invalid */
switch
(
mp_irqs
[
idx
].
mp_irqflag
&
3
)
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
polarity
=
1
;
break
;
}
case
0
:
/* conforms, ie. bus-type dependent polarity */
if
(
test_bit
(
bus
,
mp_bus_not_pci
))
polarity
=
default_ISA_polarity
(
idx
);
else
polarity
=
default_PCI_polarity
(
idx
);
break
;
case
1
:
/* high active */
{
polarity
=
0
;
break
;
}
case
2
:
/* reserved */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
polarity
=
1
;
break
;
}
case
3
:
/* low active */
{
polarity
=
1
;
break
;
}
default:
/* invalid */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
polarity
=
1
;
break
;
}
}
return
polarity
;
}
...
...
@@ -996,67 +1075,67 @@ static int MPBIOS_trigger(int idx)
/*
* Determine IRQ trigger mode (edge or level sensitive):
*/
switch
((
mp_irqs
[
idx
].
mp_irqflag
>>
2
)
&
3
)
{
case
0
:
/* conforms, ie. bus-type dependent */
switch
((
mp_irqs
[
idx
].
mp_irqflag
>>
2
)
&
3
)
{
trigger
=
test_bit
(
bus
,
mp_bus_not_pci
)
?
default_ISA_trigger
(
idx
)
:
default_PCI_trigger
(
idx
);
case
0
:
/* conforms, ie. bus-type dependent */
if
(
test_bit
(
bus
,
mp_bus_not_pci
))
trigger
=
default_ISA_trigger
(
idx
);
else
trigger
=
default_PCI_trigger
(
idx
);
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
switch
(
mp_bus_id_to_type
[
bus
])
{
case
MP_BUS_ISA
:
/* ISA pin */
{
/* set before the switch */
switch
(
mp_bus_id_to_type
[
bus
])
{
case
MP_BUS_ISA
:
/* ISA pin */
{
/* set before the switch */
break
;
}
case
MP_BUS_EISA
:
/* EISA pin */
{
trigger
=
default_EISA_trigger
(
idx
);
break
;
}
case
MP_BUS_PCI
:
/* PCI pin */
{
/* set before the switch */
break
;
}
case
MP_BUS_MCA
:
/* MCA pin */
{
trigger
=
default_MCA_trigger
(
idx
);
break
;
}
default:
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
trigger
=
1
;
break
;
}
}
#endif
break
;
}
case
MP_BUS_EISA
:
/* EISA pin */
case
1
:
/* edge */
{
trigger
=
default_EISA_trigger
(
idx
)
;
trigger
=
0
;
break
;
}
case
MP_BUS_PCI
:
/* PCI pin
*/
case
2
:
/* reserved
*/
{
/* set before the switch */
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
trigger
=
1
;
break
;
}
case
MP_BUS_MCA
:
/* MCA pin
*/
case
3
:
/* level
*/
{
trigger
=
default_MCA_trigger
(
idx
)
;
trigger
=
1
;
break
;
}
default:
default:
/* invalid */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
trigger
=
1
;
trigger
=
0
;
break
;
}
}
#endif
break
;
}
case
1
:
/* edge */
{
trigger
=
0
;
break
;
}
case
2
:
/* reserved */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
trigger
=
1
;
break
;
}
case
3
:
/* level */
{
trigger
=
1
;
break
;
}
default:
/* invalid */
{
printk
(
KERN_WARNING
"broken BIOS!!
\n
"
);
trigger
=
0
;
break
;
}
}
return
trigger
;
}
...
...
@@ -1082,9 +1161,9 @@ static int pin_2_irq(int idx, int apic, int pin)
if
(
mp_irqs
[
idx
].
mp_dstirq
!=
pin
)
printk
(
KERN_ERR
"broken BIOS or MPTABLE parser, ayiee!!
\n
"
);
if
(
test_bit
(
bus
,
mp_bus_not_pci
))
if
(
test_bit
(
bus
,
mp_bus_not_pci
))
{
irq
=
mp_irqs
[
idx
].
mp_srcbusirq
;
else
{
}
else
{
/*
* PCI IRQs are mapped in order
*/
...
...
@@ -1092,14 +1171,14 @@ static int pin_2_irq(int idx, int apic, int pin)
while
(
i
<
apic
)
irq
+=
nr_ioapic_registers
[
i
++
];
irq
+=
pin
;
/*
* For MPS mode, so far only needed by ES7000 platform
*/
if
(
ioapic_renumber_irq
)
irq
=
ioapic_renumber_irq
(
apic
,
irq
);
/*
* For MPS mode, so far only needed by ES7000 platform
*/
if
(
ioapic_renumber_irq
)
irq
=
ioapic_renumber_irq
(
apic
,
irq
);
}
#ifdef CONFIG_X86_32
/*
* PCI IRQ command line redirection. Yes, limits are hardcoded.
*/
...
...
@@ -1116,6 +1195,8 @@ static int pin_2_irq(int idx, int apic, int pin)
}
}
}
#endif
return
irq
;
}
...
...
@@ -1145,74 +1226,70 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
* Also, we've got to be careful not to trash gate
* 0x80, because int 0x80 is hm, kind of importantish. ;)
*/
static
int
current_vector
=
FIRST_DEVICE_VECTOR
,
current_offset
=
0
;
unsigned
int
old_vector
;
int
cpu
;
struct
irq_cfg
*
cfg
;
static
int
current_vector
=
FIRST_DEVICE_VECTOR
,
current_offset
=
0
;
unsigned
int
old_vector
;
int
cpu
;
struct
irq_cfg
*
cfg
;
cfg
=
irq_cfg
(
irq
);
cfg
=
irq_cfg
(
irq
);
/* Only try and allocate irqs on cpus that are present */
cpus_and
(
mask
,
mask
,
cpu_online_map
);
/* Only try and allocate irqs on cpus that are present */
cpus_and
(
mask
,
mask
,
cpu_online_map
);
if
((
cfg
->
move_in_progress
)
||
cfg
->
move_cleanup_count
)
return
-
EBUSY
;
if
((
cfg
->
move_in_progress
)
||
cfg
->
move_cleanup_count
)
return
-
EBUSY
;
old_vector
=
cfg
->
vector
;
if
(
old_vector
)
{
cpumask_t
tmp
;
cpus_and
(
tmp
,
cfg
->
domain
,
mask
);
if
(
!
cpus_empty
(
tmp
))
return
0
;
}
old_vector
=
cfg
->
vector
;
if
(
old_vector
)
{
cpumask_t
tmp
;
cpus_and
(
tmp
,
cfg
->
domain
,
mask
);
if
(
!
cpus_empty
(
tmp
))
return
0
;
}
for_each_cpu_mask_nr
(
cpu
,
mask
)
{
cpumask_t
domain
,
new_mask
;
int
new_cpu
;
int
vector
,
offset
;
for_each_cpu_mask_nr
(
cpu
,
mask
)
{
cpumask_t
domain
,
new_mask
;
int
new_cpu
;
int
vector
,
offset
;
domain
=
vector_allocation_domain
(
cpu
);
cpus_and
(
new_mask
,
domain
,
cpu_online_map
);
domain
=
vector_allocation_domain
(
cpu
);
cpus_and
(
new_mask
,
domain
,
cpu_online_map
);
vector
=
current_vector
;
offset
=
current_offset
;
vector
=
current_vector
;
offset
=
current_offset
;
next:
vector
+=
8
;
if
(
vector
>=
first_system_vector
)
{
/* If we run out of vectors on large boxen, must share them. */
offset
=
(
offset
+
1
)
%
8
;
vector
=
FIRST_DEVICE_VECTOR
+
offset
;
}
if
(
unlikely
(
current_vector
==
vector
))
continue
;
vector
+=
8
;
if
(
vector
>=
first_system_vector
)
{
/* If we run out of vectors on large boxen, must share them. */
offset
=
(
offset
+
1
)
%
8
;
vector
=
FIRST_DEVICE_VECTOR
+
offset
;
}
if
(
unlikely
(
current_vector
==
vector
))
continue
;
#ifdef CONFIG_X86_64
if
(
vector
==
IA32_SYSCALL_VECTOR
)
goto
next
;
if
(
vector
==
IA32_SYSCALL_VECTOR
)
goto
next
;
#else
if
(
vector
==
SYSCALL_VECTOR
)
goto
next
;
if
(
vector
==
SYSCALL_VECTOR
)
goto
next
;
#endif
for_each_cpu_mask_nr
(
new_cpu
,
new_mask
)
if
(
per_cpu
(
vector_irq
,
new_cpu
)[
vector
]
!=
-
1
)
goto
next
;
/* Found one! */
current_vector
=
vector
;
current_offset
=
offset
;
if
(
old_vector
)
{
cfg
->
move_in_progress
=
1
;
cfg
->
old_domain
=
cfg
->
domain
;
}
printk
(
KERN_DEBUG
"assign_irq_vector: irq %d vector %#x cpu "
,
irq
,
vector
);
for_each_cpu_mask_nr
(
new_cpu
,
new_mask
)
{
per_cpu
(
vector_irq
,
new_cpu
)[
vector
]
=
irq
;
printk
(
KERN_CONT
" %d "
,
new_cpu
);
for_each_cpu_mask_nr
(
new_cpu
,
new_mask
)
if
(
per_cpu
(
vector_irq
,
new_cpu
)[
vector
]
!=
-
1
)
goto
next
;
/* Found one! */
current_vector
=
vector
;
current_offset
=
offset
;
if
(
old_vector
)
{
cfg
->
move_in_progress
=
1
;
cfg
->
old_domain
=
cfg
->
domain
;
}
printk
(
KERN_CONT
"
\n
"
);
cfg
->
vector
=
vector
;
cfg
->
domain
=
domain
;
return
0
;
}
return
-
ENOSPC
;
for_each_cpu_mask_nr
(
new_cpu
,
new_mask
)
per_cpu
(
vector_irq
,
new_cpu
)[
vector
]
=
irq
;
cfg
->
vector
=
vector
;
cfg
->
domain
=
domain
;
return
0
;
}
return
-
ENOSPC
;
}
static
int
assign_irq_vector
(
int
irq
,
cpumask_t
mask
)
...
...
@@ -1223,7 +1300,6 @@ static int assign_irq_vector(int irq, cpumask_t mask)
spin_lock_irqsave
(
&
vector_lock
,
flags
);
err
=
__assign_irq_vector
(
irq
,
mask
);
spin_unlock_irqrestore
(
&
vector_lock
,
flags
);
return
err
;
}
...
...
@@ -1269,36 +1345,39 @@ void __setup_vector_irq(int cpu)
cfg
=
irq_cfg
(
irq
);
if
(
!
cpu_isset
(
cpu
,
cfg
->
domain
))
per_cpu
(
vector_irq
,
cpu
)[
vector
]
=
-
1
;
}
}
}
static
struct
irq_chip
ioapic_chip
;
#ifdef CONFIG_INTR_REMAP
static
struct
irq_chip
ir_ioapic_chip
;
#endif
#define IOAPIC_AUTO
-1
#define IOAPIC_EDGE
0
#define IOAPIC_LEVEL
1
#define IOAPIC_AUTO
-1
#define IOAPIC_EDGE
0
#define IOAPIC_LEVEL
1
#ifdef CONFIG_X86_32
static
inline
int
IO_APIC_irq_trigger
(
int
irq
)
{
int
apic
,
idx
,
pin
;
int
apic
,
idx
,
pin
;
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
for
(
pin
=
0
;
pin
<
nr_ioapic_registers
[
apic
];
pin
++
)
{
idx
=
find_irq_entry
(
apic
,
pin
,
mp_INT
);
if
((
idx
!=
-
1
)
&&
(
irq
==
pin_2_irq
(
idx
,
apic
,
pin
)))
return
irq_trigger
(
idx
);
}
}
/*
* nonexistent IRQs are edge default
*/
return
0
;
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
for
(
pin
=
0
;
pin
<
nr_ioapic_registers
[
apic
];
pin
++
)
{
idx
=
find_irq_entry
(
apic
,
pin
,
mp_INT
);
if
((
idx
!=
-
1
)
&&
(
irq
==
pin_2_irq
(
idx
,
apic
,
pin
)))
return
irq_trigger
(
idx
);
}
}
/*
* nonexistent IRQs are edge default
*/
return
0
;
}
#else
static
inline
int
IO_APIC_irq_trigger
(
int
irq
)
{
return
1
;
return
1
;
}
#endif
...
...
@@ -1318,13 +1397,27 @@ static void ioapic_register_intr(int irq, unsigned long trigger)
else
desc
->
status
&=
~
IRQ_LEVEL
;
#ifdef CONFIG_INTR_REMAP
if
(
irq_remapped
(
irq
))
{
desc
->
status
|=
IRQ_MOVE_PCNTXT
;
if
(
trigger
)
set_irq_chip_and_handler_name
(
irq
,
&
ir_ioapic_chip
,
handle_fasteoi_irq
,
"fasteoi"
);
else
set_irq_chip_and_handler_name
(
irq
,
&
ir_ioapic_chip
,
handle_edge_irq
,
"edge"
);
return
;
}
#endif
if
((
trigger
==
IOAPIC_AUTO
&&
IO_APIC_irq_trigger
(
irq
))
||
trigger
==
IOAPIC_LEVEL
)
set_irq_chip_and_handler_name
(
irq
,
&
ioapic_chip
,
handle_fasteoi_irq
,
"fasteoi"
);
handle_fasteoi_irq
,
"fasteoi"
);
else
set_irq_chip_and_handler_name
(
irq
,
&
ioapic_chip
,
handle_edge_irq
,
"edge"
);
handle_edge_irq
,
"edge"
);
}
static
int
setup_ioapic_entry
(
int
apic
,
int
irq
,
...
...
@@ -1337,11 +1430,45 @@ static int setup_ioapic_entry(int apic, int irq,
*/
memset
(
entry
,
0
,
sizeof
(
*
entry
));
entry
->
delivery_mode
=
INT_DELIVERY_MODE
;
entry
->
dest_mode
=
INT_DEST_MODE
;
entry
->
dest
=
destination
;
#ifdef CONFIG_INTR_REMAP
if
(
intr_remapping_enabled
)
{
struct
intel_iommu
*
iommu
=
map_ioapic_to_ir
(
apic
);
struct
irte
irte
;
struct
IR_IO_APIC_route_entry
*
ir_entry
=
(
struct
IR_IO_APIC_route_entry
*
)
entry
;
int
index
;
if
(
!
iommu
)
panic
(
"No mapping iommu for ioapic %d
\n
"
,
apic
);
index
=
alloc_irte
(
iommu
,
irq
,
1
);
if
(
index
<
0
)
panic
(
"Failed to allocate IRTE for ioapic %d
\n
"
,
apic
);
memset
(
&
irte
,
0
,
sizeof
(
irte
));
irte
.
present
=
1
;
irte
.
dst_mode
=
INT_DEST_MODE
;
irte
.
trigger_mode
=
trigger
;
irte
.
dlvry_mode
=
INT_DELIVERY_MODE
;
irte
.
vector
=
vector
;
irte
.
dest_id
=
IRTE_DEST
(
destination
);
modify_irte
(
irq
,
&
irte
);
ir_entry
->
index2
=
(
index
>>
15
)
&
0x1
;
ir_entry
->
zero
=
0
;
ir_entry
->
format
=
1
;
ir_entry
->
index
=
(
index
&
0x7fff
);
}
else
#endif
{
entry
->
delivery_mode
=
INT_DELIVERY_MODE
;
entry
->
dest_mode
=
INT_DEST_MODE
;
entry
->
dest
=
destination
;
}
entry
->
mask
=
0
;
/* enable IRQ */
entry
->
mask
=
0
;
/* enable IRQ */
entry
->
trigger
=
trigger
;
entry
->
polarity
=
polarity
;
entry
->
vector
=
vector
;
...
...
@@ -1351,12 +1478,11 @@ static int setup_ioapic_entry(int apic, int irq,
*/
if
(
trigger
)
entry
->
mask
=
1
;
return
0
;
}
static
void
setup_IO_APIC_irq
(
int
apic
,
int
pin
,
unsigned
int
irq
,
int
trigger
,
int
polarity
)
int
trigger
,
int
polarity
)
{
struct
irq_cfg
*
cfg
;
struct
IO_APIC_route_entry
entry
;
...
...
@@ -1420,10 +1546,10 @@ static void __init setup_IO_APIC_irqs(void)
}
irq
=
pin_2_irq
(
idx
,
apic
,
pin
);
#ifdef CONFIG_X86_32
if
(
multi_timer_check
(
apic
,
irq
))
continue
;
#endif
add_pin_to_irq
(
irq
,
apic
,
pin
);
setup_IO_APIC_irq
(
apic
,
pin
,
irq
,
...
...
@@ -1443,6 +1569,11 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
{
struct
IO_APIC_route_entry
entry
;
#ifdef CONFIG_INTR_REMAP
if
(
intr_remapping_enabled
)
return
;
#endif
memset
(
&
entry
,
0
,
sizeof
(
entry
));
/*
...
...
@@ -1461,7 +1592,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
* The timer IRQ doesn't have to know that behind the
* scene we may have a 8259A-master in AEOI mode ...
*/
ioapic_register_intr
(
0
,
IOAPIC_EDGE
);
set_irq_chip_and_handler_name
(
0
,
&
ioapic_chip
,
handle_edge_irq
,
"edge"
);
/*
* Add it to the IO-APIC irq-routing table:
...
...
@@ -1501,17 +1632,18 @@ __apicdebuginit(void) print_IO_APIC(void)
reg_01
.
raw
=
io_apic_read
(
apic
,
1
);
if
(
reg_01
.
bits
.
version
>=
0x10
)
reg_02
.
raw
=
io_apic_read
(
apic
,
2
);
if
(
reg_01
.
bits
.
version
>=
0x20
)
reg_03
.
raw
=
io_apic_read
(
apic
,
3
);
if
(
reg_01
.
bits
.
version
>=
0x20
)
reg_03
.
raw
=
io_apic_read
(
apic
,
3
);
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
printk
(
"
\n
"
);
printk
(
KERN_DEBUG
"IO APIC #%d......
\n
"
,
mp_ioapics
[
apic
].
mp_apicid
);
printk
(
KERN_DEBUG
".... register #00: %08X
\n
"
,
reg_00
.
raw
);
printk
(
KERN_DEBUG
"....... : physical APIC id: %02X
\n
"
,
reg_00
.
bits
.
ID
);
printk
(
KERN_DEBUG
"....... : Delivery Type: %X
\n
"
,
reg_00
.
bits
.
delivery_type
);
printk
(
KERN_DEBUG
"....... : LTS : %X
\n
"
,
reg_00
.
bits
.
LTS
);
printk
(
KERN_DEBUG
".... register #01: %08X
\n
"
,
reg_01
.
raw
);
printk
(
KERN_DEBUG
".... register #01: %08X
\n
"
,
*
(
int
*
)
&
reg_01
);
printk
(
KERN_DEBUG
"....... : max redirection entries: %04X
\n
"
,
reg_01
.
bits
.
entries
);
printk
(
KERN_DEBUG
"....... : PRQ implemented: %X
\n
"
,
reg_01
.
bits
.
PRQ
);
...
...
@@ -1548,7 +1680,10 @@ __apicdebuginit(void) print_IO_APIC(void)
entry
=
ioapic_read_entry
(
apic
,
i
);
printk
(
KERN_DEBUG
" %02x %02X "
,
i
,
entry
.
dest
);
printk
(
KERN_DEBUG
" %02x %03X "
,
i
,
entry
.
dest
);
printk
(
"%1d %1d %1d %1d %1d %1d %1d %02X
\n
"
,
entry
.
mask
,
...
...
@@ -1567,7 +1702,7 @@ __apicdebuginit(void) print_IO_APIC(void)
struct
irq_pin_list
*
entry
=
cfg
->
irq_2_pin
;
if
(
!
entry
)
continue
;
printk
(
KERN_DEBUG
"IRQ%d "
,
i
);
printk
(
KERN_DEBUG
"IRQ%d "
,
cfg
->
irq
);
for
(;;)
{
printk
(
"-> %d:%d"
,
entry
->
apic
,
entry
->
pin
);
if
(
!
entry
->
next
)
...
...
@@ -1614,8 +1749,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk
(
"
\n
"
KERN_DEBUG
"printing local APIC contents on CPU#%d/%d:
\n
"
,
smp_processor_id
(),
hard_smp_processor_id
());
v
=
apic_read
(
APIC_ID
);
printk
(
KERN_INFO
"... APIC ID: %08x (%01x)
\n
"
,
v
,
GET_APIC_ID
(
v
));
printk
(
KERN_INFO
"... APIC ID: %08x (%01x)
\n
"
,
v
,
read_apic_id
());
v
=
apic_read
(
APIC_LVR
);
printk
(
KERN_INFO
"... APIC VERSION: %08x
\n
"
,
v
);
ver
=
GET_APIC_VERSION
(
v
);
...
...
@@ -1624,7 +1758,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
v
=
apic_read
(
APIC_TASKPRI
);
printk
(
KERN_DEBUG
"... APIC TASKPRI: %08x (%02x)
\n
"
,
v
,
v
&
APIC_TPRI_MASK
);
if
(
APIC_INTEGRATED
(
ver
))
{
/* !82489DX */
if
(
APIC_INTEGRATED
(
ver
))
{
/* !82489DX */
v
=
apic_read
(
APIC_ARBPRI
);
printk
(
KERN_DEBUG
"... APIC ARBPRI: %08x (%02x)
\n
"
,
v
,
v
&
APIC_ARBPRI_MASK
);
...
...
@@ -1650,9 +1784,10 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk
(
KERN_DEBUG
"... APIC IRR field:
\n
"
);
print_APIC_bitfield
(
APIC_IRR
);
if
(
APIC_INTEGRATED
(
ver
))
{
/* !82489DX */
if
(
maxlvt
>
3
)
/* Due to the Pentium erratum 3AP. */
if
(
APIC_INTEGRATED
(
ver
))
{
/* !82489DX */
if
(
maxlvt
>
3
)
/* Due to the Pentium erratum 3AP. */
apic_write
(
APIC_ESR
,
0
);
v
=
apic_read
(
APIC_ESR
);
printk
(
KERN_DEBUG
"... APIC ESR: %08x
\n
"
,
v
);
}
...
...
@@ -1710,11 +1845,11 @@ __apicdebuginit(void) print_PIC(void)
v
=
inb
(
0xa0
)
<<
8
|
inb
(
0x20
);
printk
(
KERN_DEBUG
"... PIC IRR: %04x
\n
"
,
v
);
outb
(
0x0b
,
0xa0
);
outb
(
0x0b
,
0x20
);
outb
(
0x0b
,
0xa0
);
outb
(
0x0b
,
0x20
);
v
=
inb
(
0xa0
)
<<
8
|
inb
(
0x20
);
outb
(
0x0a
,
0xa0
);
outb
(
0x0a
,
0x20
);
outb
(
0x0a
,
0xa0
);
outb
(
0x0a
,
0x20
);
spin_unlock_irqrestore
(
&
i8259A_lock
,
flags
);
...
...
@@ -1739,16 +1874,19 @@ fs_initcall(print_all_ICs);
/* Where if anywhere is the i8259 connect in external int mode */
static
struct
{
int
pin
,
apic
;
}
ioapic_i8259
=
{
-
1
,
-
1
};
static
void
__init
enable_IO_APIC
(
void
)
void
__init
enable_IO_APIC
(
void
)
{
union
IO_APIC_reg_01
reg_01
;
int
i8259_apic
,
i8259_pin
;
int
i
,
apic
;
int
apic
;
unsigned
long
flags
;
#ifdef CONFIG_X86_32
int
i
;
if
(
!
pirqs_enabled
)
for
(
i
=
0
;
i
<
MAX_PIRQS
;
i
++
)
pirq_entries
[
i
]
=
-
1
;
#endif
/*
* The number of IO-APIC IRQ registers (== #pins):
...
...
@@ -1759,7 +1897,7 @@ static void __init enable_IO_APIC(void)
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
nr_ioapic_registers
[
apic
]
=
reg_01
.
bits
.
entries
+
1
;
}
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
for
(
apic
=
0
;
apic
<
nr_ioapics
;
apic
++
)
{
int
pin
;
/* See if any of the pins is in ExtINT mode */
for
(
pin
=
0
;
pin
<
nr_ioapic_registers
[
apic
];
pin
++
)
{
...
...
@@ -1830,16 +1968,18 @@ void disable_IO_APIC(void)
entry
.
dest_mode
=
0
;
/* Physical */
entry
.
delivery_mode
=
dest_ExtINT
;
/* ExtInt */
entry
.
vector
=
0
;
entry
.
dest
=
read_apic_id
();
entry
.
dest
=
read_apic_id
();
/*
* Add it to the IO-APIC irq-routing table:
*/
ioapic_write_entry
(
ioapic_i8259
.
apic
,
ioapic_i8259
.
pin
,
entry
);
}
disconnect_bsp_APIC
(
ioapic_i8259
.
pin
!=
-
1
);
}
#ifdef CONFIG_X86_32
/*
* function to set the IO-APIC physical IDs based on the
* values stored in the MPC table.
...
...
@@ -1940,8 +2080,6 @@ static void __init setup_ioapic_ids_from_mpc(void)
reg_00
.
bits
.
ID
=
mp_ioapics
[
apic
].
mp_apicid
;
spin_lock_irqsave
(
&
ioapic_lock
,
flags
);
io_apic_write
(
apic
,
0
,
reg_00
.
raw
);
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
/*
* Sanity check
...
...
@@ -1955,6 +2093,7 @@ static void __init setup_ioapic_ids_from_mpc(void)
apic_printk
(
APIC_VERBOSE
,
" ok.
\n
"
);
}
}
#endif
int
no_timer_check
__initdata
;
...
...
@@ -1994,9 +2133,10 @@ static int __init timer_irq_works(void)
* might have cached one ExtINT interrupt. Finally, at
* least one tick may be lost due to delays.
*/
/* jiffies wrap? */
if
(
time_after
(
jiffies
,
t1
+
4
))
return
1
;
return
0
;
}
...
...
@@ -2014,8 +2154,6 @@ static int __init timer_irq_works(void)
*/
/*
* Startup quirk:
*
* Starting up a edge-triggered IO-APIC interrupt is
* nasty - we need to make sure that we get the edge.
* If it is already asserted for some reason, we need
...
...
@@ -2023,9 +2161,8 @@ static int __init timer_irq_works(void)
*
* This is not complete - we should be able to fake
* an edge even if it isn't on the 8259A...
*
* (We do this for level-triggered IRQs too - it cannot hurt.)
*/
static
unsigned
int
startup_ioapic_irq
(
unsigned
int
irq
)
{
int
was_pending
=
0
;
...
...
@@ -2043,70 +2180,254 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
return
was_pending
;
}
#ifdef CONFIG_X86_64
static
int
ioapic_retrigger_irq
(
unsigned
int
irq
)
{
send_IPI_self
(
irq_cfg
(
irq
)
->
vector
);
struct
irq_cfg
*
cfg
=
irq_cfg
(
irq
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
vector_lock
,
flags
);
send_IPI_mask
(
cpumask_of_cpu
(
first_cpu
(
cfg
->
domain
)),
cfg
->
vector
);
spin_unlock_irqrestore
(
&
vector_lock
,
flags
);
return
1
;
}
#ifdef CONFIG_SMP
asmlinkage
void
smp_irq_move_cleanup_interrupt
(
void
)
#else
static
int
ioapic_retrigger_irq
(
unsigned
int
irq
)
{
unsigned
vector
,
me
;
ack_APIC_irq
();
irq_enter
();
me
=
smp_processor_id
();
for
(
vector
=
FIRST_EXTERNAL_VECTOR
;
vector
<
NR_VECTORS
;
vector
++
)
{
unsigned
int
irq
;
struct
irq_desc
*
desc
;
struct
irq_cfg
*
cfg
;
irq
=
__get_cpu_var
(
vector_irq
)[
vector
];
send_IPI_self
(
irq_cfg
(
irq
)
->
vector
);
desc
=
irq_to_desc
(
irq
)
;
if
(
!
desc
)
continue
;
return
1
;
}
#endif
cfg
=
irq_cfg
(
irq
);
spin_lock
(
&
desc
->
lock
);
if
(
!
cfg
->
move_cleanup_count
)
goto
unlock
;
/*
* Level and edge triggered IO-APIC interrupts need different handling,
* so we use two separate IRQ descriptors. Edge triggered IRQs can be
* handled with the level-triggered descriptor, but that one has slightly
* more overhead. Level-triggered interrupts cannot be handled with the
* edge-triggered handler, without risking IRQ storms and other ugly
* races.
*/
if
((
vector
==
cfg
->
vector
)
&&
cpu_isset
(
me
,
cfg
->
domain
))
goto
unlock
;
#ifdef CONFIG_SMP
__get_cpu_var
(
vector_irq
)[
vector
]
=
-
1
;
cfg
->
move_cleanup_count
--
;
unlock:
spin_unlock
(
&
desc
->
lock
);
}
#ifdef CONFIG_INTR_REMAP
static
void
ir_irq_migration
(
struct
work_struct
*
work
);
irq_exit
();
}
static
DECLARE_DELAYED_WORK
(
ir_migration_work
,
ir_irq_migration
);
static
void
irq_complete_move
(
unsigned
int
irq
)
/*
* Migrate the IO-APIC irq in the presence of intr-remapping.
*
* For edge triggered, irq migration is a simple atomic update(of vector
* and cpu destination) of IRTE and flush the hardware cache.
*
* For level triggered, we need to modify the io-apic RTE aswell with the update
* vector information, along with modifying IRTE with vector and destination.
* So irq migration for level triggered is little bit more complex compared to
* edge triggered migration. But the good news is, we use the same algorithm
* for level triggered migration as we have today, only difference being,
* we now initiate the irq migration from process context instead of the
* interrupt context.
*
* In future, when we do a directed EOI (combined with cpu EOI broadcast
* suppression) to the IO-APIC, level triggered irq migration will also be
* as simple as edge triggered migration and we can do the irq migration
* with a simple atomic update to IO-APIC RTE.
*/
static
void
migrate_ioapic_irq
(
int
irq
,
cpumask_t
mask
)
{
struct
irq_cfg
*
cfg
=
irq_cfg
(
irq
);
unsigned
vector
,
me
;
struct
irq_cfg
*
cfg
;
struct
irq_desc
*
desc
;
cpumask_t
tmp
,
cleanup_mask
;
struct
irte
irte
;
int
modify_ioapic_rte
;
unsigned
int
dest
;
unsigned
long
flags
;
if
(
likely
(
!
cfg
->
move_in_progress
))
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
return
;
vector
=
~
get_irq_regs
()
->
orig_ax
;
me
=
smp_processor_id
();
if
((
vector
==
cfg
->
vector
)
&&
cpu_isset
(
me
,
cfg
->
domain
))
{
cpumask_t
cleanup_mask
;
if
(
get_irte
(
irq
,
&
irte
))
return
;
cpus_and
(
cleanup_mask
,
cfg
->
old_domain
,
cpu_online_map
);
cfg
->
move_cleanup_count
=
cpus_weight
(
cleanup_mask
);
send_IPI_mask
(
cleanup_mask
,
IRQ_MOVE_CLEANUP_VECTOR
);
if
(
assign_irq_vector
(
irq
,
mask
))
return
;
cfg
=
irq_cfg
(
irq
);
cpus_and
(
tmp
,
cfg
->
domain
,
mask
);
dest
=
cpu_mask_to_apicid
(
tmp
);
desc
=
irq_to_desc
(
irq
);
modify_ioapic_rte
=
desc
->
status
&
IRQ_LEVEL
;
if
(
modify_ioapic_rte
)
{
spin_lock_irqsave
(
&
ioapic_lock
,
flags
);
__target_IO_APIC_irq
(
irq
,
dest
,
cfg
->
vector
);
spin_unlock_irqrestore
(
&
ioapic_lock
,
flags
);
}
irte
.
vector
=
cfg
->
vector
;
irte
.
dest_id
=
IRTE_DEST
(
dest
);
/*
* Modified the IRTE and flushes the Interrupt entry cache.
*/
modify_irte
(
irq
,
&
irte
);
if
(
cfg
->
move_in_progress
)
{
cpus_and
(
cleanup_mask
,
cfg
->
old_domain
,
cpu_online_map
);
cfg
->
move_cleanup_count
=
cpus_weight
(
cleanup_mask
);
send_IPI_mask
(
cleanup_mask
,
IRQ_MOVE_CLEANUP_VECTOR
);
cfg
->
move_in_progress
=
0
;
}
desc
->
affinity
=
mask
;
}
static
int
migrate_irq_remapped_level
(
int
irq
)
{
int
ret
=
-
1
;
struct
irq_desc
*
desc
=
irq_to_desc
(
irq
);
mask_IO_APIC_irq
(
irq
);
if
(
io_apic_level_ack_pending
(
irq
))
{
/*
* Interrupt in progress. Migrating irq now will change the
* vector information in the IO-APIC RTE and that will confuse
* the EOI broadcast performed by cpu.
* So, delay the irq migration to the next instance.
*/
schedule_delayed_work
(
&
ir_migration_work
,
1
);
goto
unmask
;
}
/* everthing is clear. we have right of way */
migrate_ioapic_irq
(
irq
,
desc
->
pending_mask
);
ret
=
0
;
desc
->
status
&=
~
IRQ_MOVE_PENDING
;
cpus_clear
(
desc
->
pending_mask
);
unmask:
unmask_IO_APIC_irq
(
irq
);
return
ret
;
}
static
void
ir_irq_migration
(
struct
work_struct
*
work
)
{
unsigned
int
irq
;
struct
irq_desc
*
desc
;
for_each_irq_desc
(
irq
,
desc
)
{
if
(
desc
->
status
&
IRQ_MOVE_PENDING
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
desc
->
lock
,
flags
);
if
(
!
desc
->
chip
->
set_affinity
||
!
(
desc
->
status
&
IRQ_MOVE_PENDING
))
{
desc
->
status
&=
~
IRQ_MOVE_PENDING
;
spin_unlock_irqrestore
(
&
desc
->
lock
,
flags
);
continue
;
}
desc
->
chip
->
set_affinity
(
irq
,
desc
->
pending_mask
);
spin_unlock_irqrestore
(
&
desc
->
lock
,
flags
);
}
}
}
/*
* Migrates the IRQ destination in the process context.
*/
static
void
set_ir_ioapic_affinity_irq
(
unsigned
int
irq
,
cpumask_t
mask
)
{
struct
irq_desc
*
desc
=
irq_to_desc
(
irq
);
if
(
desc
->
status
&
IRQ_LEVEL
)
{
desc
->
status
|=
IRQ_MOVE_PENDING
;
desc
->
pending_mask
=
mask
;
migrate_irq_remapped_level
(
irq
);
return
;
}
migrate_ioapic_irq
(
irq
,
mask
);
}
#endif
asmlinkage
void
smp_irq_move_cleanup_interrupt
(
void
)
{
unsigned
vector
,
me
;
ack_APIC_irq
();
#ifdef CONFIG_X86_64
exit_idle
();
#endif
irq_enter
();
me
=
smp_processor_id
();
for
(
vector
=
FIRST_EXTERNAL_VECTOR
;
vector
<
NR_VECTORS
;
vector
++
)
{
unsigned
int
irq
;
struct
irq_desc
*
desc
;
struct
irq_cfg
*
cfg
;
irq
=
__get_cpu_var
(
vector_irq
)[
vector
];
desc
=
irq_to_desc
(
irq
);
if
(
!
desc
)
continue
;
cfg
=
irq_cfg
(
irq
);
spin_lock
(
&
desc
->
lock
);
if
(
!
cfg
->
move_cleanup_count
)
goto
unlock
;
if
((
vector
==
cfg
->
vector
)
&&
cpu_isset
(
me
,
cfg
->
domain
))
goto
unlock
;
__get_cpu_var
(
vector_irq
)[
vector
]
=
-
1
;
cfg
->
move_cleanup_count
--
;
unlock:
spin_unlock
(
&
desc
->
lock
);
}
irq_exit
();
}
static
void
irq_complete_move
(
unsigned
int
irq
)
{
struct
irq_cfg
*
cfg
=
irq_cfg
(
irq
);
unsigned
vector
,
me
;
if
(
likely
(
!
cfg
->
move_in_progress
))
return
;
vector
=
~
get_irq_regs
()
->
orig_ax
;
me
=
smp_processor_id
();
if
((
vector
==
cfg
->
vector
)
&&
cpu_isset
(
me
,
cfg
->
domain
))
{
cpumask_t
cleanup_mask
;
cpus_and
(
cleanup_mask
,
cfg
->
old_domain
,
cpu_online_map
);
cfg
->
move_cleanup_count
=
cpus_weight
(
cleanup_mask
);
send_IPI_mask
(
cleanup_mask
,
IRQ_MOVE_CLEANUP_VECTOR
);
cfg
->
move_in_progress
=
0
;
}
}
#else
static
inline
void
irq_complete_move
(
unsigned
int
irq
)
{}
#endif
#ifdef CONFIG_INTR_REMAP
static
void
ack_x2apic_level
(
unsigned
int
irq
)
{
ack_x2APIC_irq
();
}
static
void
ack_x2apic_edge
(
unsigned
int
irq
)
{
ack_x2APIC_irq
();
}
#endif
static
void
ack_apic_edge
(
unsigned
int
irq
)
{
...
...
@@ -2118,55 +2439,55 @@ static void ack_apic_edge(unsigned int irq)
#ifdef CONFIG_X86_64
static
void
ack_apic_level
(
unsigned
int
irq
)
{
int
do_unmask_irq
=
0
;
int
do_unmask_irq
=
0
;
irq_complete_move
(
irq
);
irq_complete_move
(
irq
);
#ifdef CONFIG_GENERIC_PENDING_IRQ
/* If we are moving the irq we need to mask it */
if
(
unlikely
(
desc
->
status
&
IRQ_MOVE_PENDING
))
{
do_unmask_irq
=
1
;
mask_IO_APIC_irq
(
irq
);
}
/* If we are moving the irq we need to mask it */
if
(
unlikely
(
irq_to_desc
(
irq
)
->
status
&
IRQ_MOVE_PENDING
))
{
do_unmask_irq
=
1
;
mask_IO_APIC_irq
(
irq
);
}
#endif
/*
* We must acknowledge the irq before we move it or the acknowledge will
* not propagate properly.
*/
ack_APIC_irq
();
/* Now we can move and renable the irq */
if
(
unlikely
(
do_unmask_irq
))
{
/* Only migrate the irq if the ack has been received.
*
* On rare occasions the broadcast level triggered ack gets
* delayed going to ioapics, and if we reprogram the
* vector while Remote IRR is still set the irq will never
* fire again.
*
* To prevent this scenario we read the Remote IRR bit
* of the ioapic. This has two effects.
* - On any sane system the read of the ioapic will
* flush writes (and acks) going to the ioapic from
* this cpu.
* - We get to see if the ACK has actually been delivered.
*
* Based on failed experiments of reprogramming the
* ioapic entry from outside of irq context starting
* with masking the ioapic entry and then polling until
* Remote IRR was clear before reprogramming the
* ioapic I don't trust the Remote IRR bit to be
* completey accurate.
*
* However there appears to be no other way to plug
* this race, so if the Remote IRR bit is not
* accurate and is causing problems then it is a hardware bug
* and you can go talk to the chipset vendor about it.
*/
if
(
!
io_apic_level_ack_pending
(
irq
))
move_masked_irq
(
irq
,
desc
);
unmask_IO_APIC_irq
(
irq
);
}
/*
* We must acknowledge the irq before we move it or the acknowledge will
* not propagate properly.
*/
ack_APIC_irq
();
/* Now we can move and renable the irq */
if
(
unlikely
(
do_unmask_irq
))
{
/* Only migrate the irq if the ack has been received.
*
* On rare occasions the broadcast level triggered ack gets
* delayed going to ioapics, and if we reprogram the
* vector while Remote IRR is still set the irq will never
* fire again.
*
* To prevent this scenario we read the Remote IRR bit
* of the ioapic. This has two effects.
* - On any sane system the read of the ioapic will
* flush writes (and acks) going to the ioapic from
* this cpu.
* - We get to see if the ACK has actually been delivered.
*
* Based on failed experiments of reprogramming the
* ioapic entry from outside of irq context starting
* with masking the ioapic entry and then polling until
* Remote IRR was clear before reprogramming the
* ioapic I don't trust the Remote IRR bit to be
* completey accurate.
*
* However there appears to be no other way to plug
* this race, so if the Remote IRR bit is not
* accurate and is causing problems then it is a hardware bug
* and you can go talk to the chipset vendor about it.
*/
if
(
!
io_apic_level_ack_pending
(
irq
))
move_masked_irq
(
irq
);
unmask_IO_APIC_irq
(
irq
);
}
}
#else
atomic_t
irq_mis_count
;
...
...
@@ -2177,25 +2498,25 @@ static void ack_apic_level(unsigned int irq)
irq_complete_move
(
irq
);
move_native_irq
(
irq
);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
* chipsets). Under certain conditions a level-triggered interrupt is
* erroneously delivered as edge-triggered one but the respective IRR
* bit gets set nevertheless. As a result the I/O unit expects an EOI
* message but it will never arrive and further interrupts are blocked
* from the source. The exact reason is so far unknown, but the
* phenomenon was observed when two consecutive interrupt requests
* from a given source get delivered to the same CPU and the source is
* temporarily disabled in between.
*
* A workaround is to simulate an EOI message manually. We achieve it
* by setting the trigger mode to edge and then to level when the edge
* trigger mode gets detected in the TMR of a local APIC for a
* level-triggered interrupt. We mask the source for the time of the
* operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro
*/
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
* chipsets). Under certain conditions a level-triggered interrupt is
* erroneously delivered as edge-triggered one but the respective IRR
* bit gets set nevertheless. As a result the I/O unit expects an EOI
* message but it will never arrive and further interrupts are blocked
* from the source. The exact reason is so far unknown, but the
* phenomenon was observed when two consecutive interrupt requests
* from a given source get delivered to the same CPU and the source is
* temporarily disabled in between.
*
* A workaround is to simulate an EOI message manually. We achieve it
* by setting the trigger mode to edge and then to level when the edge
* trigger mode gets detected in the TMR of a local APIC for a
* level-triggered interrupt. We mask the source for the time of the
* operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro
*/
i
=
irq_cfg
(
irq
)
->
vector
;
v
=
apic_read
(
APIC_TMR
+
((
i
&
~
0x1f
)
>>
1
));
...
...
@@ -2225,6 +2546,20 @@ static struct irq_chip ioapic_chip __read_mostly = {
.
retrigger
=
ioapic_retrigger_irq
,
};
#ifdef CONFIG_INTR_REMAP
static
struct
irq_chip
ir_ioapic_chip
__read_mostly
=
{
.
name
=
"IR-IO-APIC"
,
.
startup
=
startup_ioapic_irq
,
.
mask
=
mask_IO_APIC_irq
,
.
unmask
=
unmask_IO_APIC_irq
,
.
ack
=
ack_x2apic_edge
,
.
eoi
=
ack_x2apic_level
,
#ifdef CONFIG_SMP
.
set_affinity
=
set_ir_ioapic_affinity_irq
,
#endif
.
retrigger
=
ioapic_retrigger_irq
,
};
#endif
static
inline
void
init_IO_APIC_traps
(
void
)
{
...
...
@@ -2282,7 +2617,7 @@ static void unmask_lapic_irq(unsigned int irq)
apic_write
(
APIC_LVT0
,
v
&
~
APIC_LVT_MASKED
);
}
static
void
ack_lapic_irq
(
unsigned
int
irq
)
static
void
ack_lapic_irq
(
unsigned
int
irq
)
{
ack_APIC_irq
();
}
...
...
@@ -2383,12 +2718,12 @@ static inline void __init unlock_ExtINT_logic(void)
static
int
disable_timer_pin_1
__initdata
;
/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
static
int
__init
parse_disable_timer_pin_1
(
char
*
arg
)
static
int
__init
disable_timer_pin_setup
(
char
*
arg
)
{
disable_timer_pin_1
=
1
;
return
0
;
}
early_param
(
"disable_timer_pin_1"
,
parse_disable_timer_pin_1
);
early_param
(
"disable_timer_pin_1"
,
disable_timer_pin_setup
);
int
timer_through_8259
__initdata
;
...
...
@@ -2397,6 +2732,8 @@ int timer_through_8259 __initdata;
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
* is so screwy. Thanks to Brian Perkins for testing/hacking this beast
* fanatically on his truly buggy board.
*
* FIXME: really need to revamp this for all platforms.
*/
static
inline
void
__init
check_timer
(
void
)
{
...
...
@@ -2408,8 +2745,8 @@ static inline void __init check_timer(void)
local_irq_save
(
flags
);
ver
=
apic_read
(
APIC_LVR
);
ver
=
GET_APIC_VERSION
(
ver
);
ver
=
apic_read
(
APIC_LVR
);
ver
=
GET_APIC_VERSION
(
ver
);
/*
* get/set the timer IRQ vector:
...
...
@@ -2428,7 +2765,9 @@ static inline void __init check_timer(void)
*/
apic_write
(
APIC_LVT0
,
APIC_LVT_MASKED
|
APIC_DM_EXTINT
);
init_8259A
(
1
);
#ifdef CONFIG_X86_32
timer_ack
=
(
nmi_watchdog
==
NMI_IO_APIC
&&
!
APIC_INTEGRATED
(
ver
));
#endif
pin1
=
find_isa_irq_pin
(
0
,
mp_INT
);
apic1
=
find_isa_irq_apic
(
0
,
mp_INT
);
...
...
@@ -2447,6 +2786,10 @@ static inline void __init check_timer(void)
* 8259A.
*/
if
(
pin1
==
-
1
)
{
#ifdef CONFIG_INTR_REMAP
if
(
intr_remapping_enabled
)
panic
(
"BIOS bug: timer not connected to IO-APIC"
);
#endif
pin1
=
pin2
;
apic1
=
apic2
;
no_pin1
=
1
;
...
...
@@ -2473,6 +2816,10 @@ static inline void __init check_timer(void)
clear_IO_APIC_pin
(
0
,
pin1
);
goto
out
;
}
#ifdef CONFIG_INTR_REMAP
if
(
intr_remapping_enabled
)
panic
(
"timer doesn't work through Interrupt-remapped IO-APIC"
);
#endif
clear_IO_APIC_pin
(
apic1
,
pin1
);
if
(
!
no_pin1
)
apic_printk
(
APIC_QUIET
,
KERN_ERR
"..MP-BIOS bug: "
...
...
@@ -2512,7 +2859,9 @@ static inline void __init check_timer(void)
"through the IO-APIC - disabling NMI Watchdog!
\n
"
);
nmi_watchdog
=
NMI_NONE
;
}
#ifdef CONFIG_X86_32
timer_ack
=
0
;
#endif
apic_printk
(
APIC_QUIET
,
KERN_INFO
"...trying to set up timer as Virtual Wire IRQ...
\n
"
);
...
...
@@ -2570,17 +2919,25 @@ out:
void
__init
setup_IO_APIC
(
void
)
{
#ifdef CONFIG_X86_32
enable_IO_APIC
();
#else
/*
* calling enable_IO_APIC() is moved to setup_local_APIC for BP
*/
#endif
io_apic_irqs
=
~
PIC_IRQS
;
printk
(
"ENABLING IO-APIC IRQs
\n
"
);
/*
* Set up IO-APIC IRQ routing.
*/
if
(
!
acpi_ioapic
)
setup_ioapic_ids_from_mpc
();
apic_printk
(
APIC_VERBOSE
,
"ENABLING IO-APIC IRQs
\n
"
);
/*
* Set up IO-APIC IRQ routing.
*/
#ifdef CONFIG_X86_32
if
(
!
acpi_ioapic
)
setup_ioapic_ids_from_mpc
();
#endif
sync_Arb_IDs
();
setup_IO_APIC_irqs
();
init_IO_APIC_traps
();
...
...
@@ -2588,15 +2945,15 @@ void __init setup_IO_APIC(void)
}
/*
*
Called after all the initialization is done. If we didnt find any
*
APIC bugs then we can allow the modify fast path
*
Called after all the initialization is done. If we didnt find any
*
APIC bugs then we can allow the modify fast path
*/
static
int
__init
io_apic_bug_finalize
(
void
)
{
if
(
sis_apic_bug
==
-
1
)
sis_apic_bug
=
0
;
return
0
;
if
(
sis_apic_bug
==
-
1
)
sis_apic_bug
=
0
;
return
0
;
}
late_initcall
(
io_apic_bug_finalize
);
...
...
@@ -2605,7 +2962,7 @@ struct sysfs_ioapic_data {
struct
sys_device
dev
;
struct
IO_APIC_route_entry
entry
[
0
];
};
static
struct
sysfs_ioapic_data
*
mp_ioapic_data
[
MAX_IO_APICS
];
static
struct
sysfs_ioapic_data
*
mp_ioapic_data
[
MAX_IO_APICS
];
static
int
ioapic_suspend
(
struct
sys_device
*
dev
,
pm_message_t
state
)
{
...
...
@@ -2615,8 +2972,8 @@ static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
data
=
container_of
(
dev
,
struct
sysfs_ioapic_data
,
dev
);
entry
=
data
->
entry
;
for
(
i
=
0
;
i
<
nr_ioapic_registers
[
dev
->
id
];
i
++
)
entry
[
i
]
=
ioapic_read_entry
(
dev
->
id
,
i
);
for
(
i
=
0
;
i
<
nr_ioapic_registers
[
dev
->
id
];
i
++
,
entry
++
)
*
entry
=
ioapic_read_entry
(
dev
->
id
,
i
);
return
0
;
}
...
...
@@ -2653,14 +3010,14 @@ static struct sysdev_class ioapic_sysdev_class = {
static
int
__init
ioapic_init_sysfs
(
void
)
{
struct
sys_device
*
dev
;
int
i
,
size
,
error
=
0
;
struct
sys_device
*
dev
;
int
i
,
size
,
error
;
error
=
sysdev_class_register
(
&
ioapic_sysdev_class
);
if
(
error
)
return
error
;
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
size
=
sizeof
(
struct
sys_device
)
+
nr_ioapic_registers
[
i
]
*
sizeof
(
struct
IO_APIC_route_entry
);
mp_ioapic_data
[
i
]
=
kzalloc
(
size
,
GFP_KERNEL
);
...
...
@@ -2691,18 +3048,18 @@ device_initcall(ioapic_init_sysfs);
unsigned
int
create_irq_nr
(
unsigned
int
irq_want
)
{
/* Allocate an unused irq */
unsigned
int
irq
,
new
;
unsigned
int
irq
;
unsigned
int
new
;
unsigned
long
flags
;
struct
irq_cfg
*
cfg_new
;
#ifndef CONFIG_HAVE_SPARSE_IRQ
/* only can use bus/dev/fn.. when per_cpu vector is used */
irq_want
=
nr_irqs
-
1
;
#endif
irq
=
0
;
spin_lock_irqsave
(
&
vector_lock
,
flags
);
for
(
new
=
(
nr_irqs
-
1
)
;
new
>
0
;
new
--
)
{
for
(
new
=
irq_want
;
new
>
0
;
new
--
)
{
if
(
platform_legacy_irq
(
new
))
continue
;
cfg_new
=
irq_cfg
(
new
);
...
...
@@ -2725,7 +3082,14 @@ unsigned int create_irq_nr(unsigned int irq_want)
int
create_irq
(
void
)
{
return
create_irq_nr
(
nr_irqs
-
1
);
int
irq
;
irq
=
create_irq_nr
(
nr_irqs
-
1
);
if
(
irq
==
0
)
irq
=
-
1
;
return
irq
;
}
void
destroy_irq
(
unsigned
int
irq
)
...
...
@@ -2734,6 +3098,9 @@ void destroy_irq(unsigned int irq)
dynamic_irq_cleanup
(
irq
);
#ifdef CONFIG_INTR_REMAP
free_irte
(
irq
);
#endif
spin_lock_irqsave
(
&
vector_lock
,
flags
);
__clear_irq_vector
(
irq
);
spin_unlock_irqrestore
(
&
vector_lock
,
flags
);
...
...
@@ -2759,25 +3126,54 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
cpus_and
(
tmp
,
cfg
->
domain
,
tmp
);
dest
=
cpu_mask_to_apicid
(
tmp
);
msg
->
address_hi
=
MSI_ADDR_BASE_HI
;
msg
->
address_lo
=
MSI_ADDR_BASE_LO
|
((
INT_DEST_MODE
==
0
)
?
MSI_ADDR_DEST_MODE_PHYSICAL:
MSI_ADDR_DEST_MODE_LOGICAL
)
|
((
INT_DELIVERY_MODE
!=
dest_LowestPrio
)
?
MSI_ADDR_REDIRECTION_CPU:
MSI_ADDR_REDIRECTION_LOWPRI
)
|
MSI_ADDR_DEST_ID
(
dest
);
msg
->
data
=
MSI_DATA_TRIGGER_EDGE
|
MSI_DATA_LEVEL_ASSERT
|
((
INT_DELIVERY_MODE
!=
dest_LowestPrio
)
?
MSI_DATA_DELIVERY_FIXED:
MSI_DATA_DELIVERY_LOWPRI
)
|
MSI_DATA_VECTOR
(
cfg
->
vector
);
#ifdef CONFIG_INTR_REMAP
if
(
irq_remapped
(
irq
))
{
struct
irte
irte
;
int
ir_index
;
u16
sub_handle
;
ir_index
=
map_irq_to_irte_handle
(
irq
,
&
sub_handle
);
BUG_ON
(
ir_index
==
-
1
);
memset
(
&
irte
,
0
,
sizeof
(
irte
));
irte
.
present
=
1
;
irte
.
dst_mode
=
INT_DEST_MODE
;
irte
.
trigger_mode
=
0
;
/* edge */
irte
.
dlvry_mode
=
INT_DELIVERY_MODE
;
irte
.
vector
=
cfg
->
vector
;
irte
.
dest_id
=
IRTE_DEST
(
dest
);
modify_irte
(
irq
,
&
irte
);
msg
->
address_hi
=
MSI_ADDR_BASE_HI
;
msg
->
data
=
sub_handle
;
msg
->
address_lo
=
MSI_ADDR_BASE_LO
|
MSI_ADDR_IR_EXT_INT
|
MSI_ADDR_IR_SHV
|
MSI_ADDR_IR_INDEX1
(
ir_index
)
|
MSI_ADDR_IR_INDEX2
(
ir_index
);
}
else
#endif
{
msg
->
address_hi
=
MSI_ADDR_BASE_HI
;
msg
->
address_lo
=
MSI_ADDR_BASE_LO
|
((
INT_DEST_MODE
==
0
)
?
MSI_ADDR_DEST_MODE_PHYSICAL:
MSI_ADDR_DEST_MODE_LOGICAL
)
|
((
INT_DELIVERY_MODE
!=
dest_LowestPrio
)
?
MSI_ADDR_REDIRECTION_CPU:
MSI_ADDR_REDIRECTION_LOWPRI
)
|
MSI_ADDR_DEST_ID
(
dest
);
msg
->
data
=
MSI_DATA_TRIGGER_EDGE
|
MSI_DATA_LEVEL_ASSERT
|
((
INT_DELIVERY_MODE
!=
dest_LowestPrio
)
?
MSI_DATA_DELIVERY_FIXED:
MSI_DATA_DELIVERY_LOWPRI
)
|
MSI_DATA_VECTOR
(
cfg
->
vector
);
}
return
err
;
}
...
...
@@ -2788,6 +3184,7 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
struct
msi_msg
msg
;
unsigned
int
dest
;
cpumask_t
tmp
;
struct
irq_desc
*
desc
;
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
...
...
@@ -2808,8 +3205,61 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
msg
.
address_lo
|=
MSI_ADDR_DEST_ID
(
dest
);
write_msi_msg
(
irq
,
&
msg
);
irq_to_desc
(
irq
)
->
affinity
=
mask
;
desc
=
irq_to_desc
(
irq
);
desc
->
affinity
=
mask
;
}
#ifdef CONFIG_INTR_REMAP
/*
* Migrate the MSI irq to another cpumask. This migration is
* done in the process context using interrupt-remapping hardware.
*/
static
void
ir_set_msi_irq_affinity
(
unsigned
int
irq
,
cpumask_t
mask
)
{
struct
irq_cfg
*
cfg
;
unsigned
int
dest
;
cpumask_t
tmp
,
cleanup_mask
;
struct
irte
irte
;
struct
irq_desc
*
desc
;
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
return
;
if
(
get_irte
(
irq
,
&
irte
))
return
;
if
(
assign_irq_vector
(
irq
,
mask
))
return
;
cfg
=
irq_cfg
(
irq
);
cpus_and
(
tmp
,
cfg
->
domain
,
mask
);
dest
=
cpu_mask_to_apicid
(
tmp
);
irte
.
vector
=
cfg
->
vector
;
irte
.
dest_id
=
IRTE_DEST
(
dest
);
/*
* atomically update the IRTE with the new destination and vector.
*/
modify_irte
(
irq
,
&
irte
);
/*
* After this point, all the interrupts will start arriving
* at the new destination. So, time to cleanup the previous
* vector allocation.
*/
if
(
cfg
->
move_in_progress
)
{
cpus_and
(
cleanup_mask
,
cfg
->
old_domain
,
cpu_online_map
);
cfg
->
move_cleanup_count
=
cpus_weight
(
cleanup_mask
);
send_IPI_mask
(
cleanup_mask
,
IRQ_MOVE_CLEANUP_VECTOR
);
cfg
->
move_in_progress
=
0
;
}
desc
=
irq_to_desc
(
irq
);
desc
->
affinity
=
mask
;
}
#endif
#endif
/* CONFIG_SMP */
/*
...
...
@@ -2827,6 +3277,45 @@ static struct irq_chip msi_chip = {
.
retrigger
=
ioapic_retrigger_irq
,
};
#ifdef CONFIG_INTR_REMAP
static
struct
irq_chip
msi_ir_chip
=
{
.
name
=
"IR-PCI-MSI"
,
.
unmask
=
unmask_msi_irq
,
.
mask
=
mask_msi_irq
,
.
ack
=
ack_x2apic_edge
,
#ifdef CONFIG_SMP
.
set_affinity
=
ir_set_msi_irq_affinity
,
#endif
.
retrigger
=
ioapic_retrigger_irq
,
};
/*
* Map the PCI dev to the corresponding remapping hardware unit
* and allocate 'nvec' consecutive interrupt-remapping table entries
* in it.
*/
static
int
msi_alloc_irte
(
struct
pci_dev
*
dev
,
int
irq
,
int
nvec
)
{
struct
intel_iommu
*
iommu
;
int
index
;
iommu
=
map_dev_to_ir
(
dev
);
if
(
!
iommu
)
{
printk
(
KERN_ERR
"Unable to map PCI %s to iommu
\n
"
,
pci_name
(
dev
));
return
-
ENOENT
;
}
index
=
alloc_irte
(
iommu
,
irq
,
nvec
);
if
(
index
<
0
)
{
printk
(
KERN_ERR
"Unable to allocate %d IRTE for PCI %s
\n
"
,
nvec
,
pci_name
(
dev
));
return
-
ENOSPC
;
}
return
index
;
}
#endif
static
int
setup_msi_irq
(
struct
pci_dev
*
dev
,
struct
msi_desc
*
desc
,
int
irq
)
{
...
...
@@ -2840,7 +3329,17 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
set_irq_msi
(
irq
,
desc
);
write_msi_msg
(
irq
,
&
msg
);
set_irq_chip_and_handler_name
(
irq
,
&
msi_chip
,
handle_edge_irq
,
"edge"
);
#ifdef CONFIG_INTR_REMAP
if
(
irq_remapped
(
irq
))
{
struct
irq_desc
*
desc
=
irq_to_desc
(
irq
);
/*
* irq migration in process context
*/
desc
->
status
|=
IRQ_MOVE_PCNTXT
;
set_irq_chip_and_handler_name
(
irq
,
&
msi_ir_chip
,
handle_edge_irq
,
"edge"
);
}
else
#endif
set_irq_chip_and_handler_name
(
irq
,
&
msi_chip
,
handle_edge_irq
,
"edge"
);
return
0
;
}
...
...
@@ -2859,59 +3358,164 @@ static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
int
arch_setup_msi_irq
(
struct
pci_dev
*
dev
,
struct
msi_desc
*
desc
)
{
int
irq
,
ret
;
unsigned
int
irq
;
int
ret
;
unsigned
int
irq_want
;
irq_want
=
build_irq_for_pci_dev
(
dev
)
+
0x100
;
irq
=
create_irq_nr
(
irq_want
);
if
(
irq
==
0
)
return
-
1
;
#ifdef CONFIG_INTR_REMAP
if
(
!
intr_remapping_enabled
)
goto
no_ir
;
ret
=
msi_alloc_irte
(
dev
,
irq
,
1
);
if
(
ret
<
0
)
goto
error
;
no_ir:
#endif
ret
=
setup_msi_irq
(
dev
,
desc
,
irq
);
if
(
ret
<
0
)
{
destroy_irq
(
irq
);
return
ret
;
}
}
return
0
;
#ifdef CONFIG_INTR_REMAP
error:
destroy_irq
(
irq
);
return
ret
;
#endif
}
int
arch_setup_msi_irqs
(
struct
pci_dev
*
dev
,
int
nvec
,
int
type
)
{
unsigned
int
irq
;
int
ret
,
sub_handle
;
struct
msi_desc
*
desc
;
unsigned
int
irq_want
;
irq_want
=
build_irq_for_pci_dev
(
dev
)
+
0x100
;
sub_handle
=
0
;
list_for_each_entry
(
desc
,
&
dev
->
msi_list
,
list
)
{
irq
=
create_irq_nr
(
irq_want
--
);
if
(
irq
==
0
)
return
-
1
;
ret
=
setup_msi_irq
(
dev
,
desc
,
irq
);
if
(
ret
<
0
)
goto
error
;
sub_handle
++
;
}
return
0
;
unsigned
int
irq
;
int
ret
,
sub_handle
;
struct
msi_desc
*
desc
;
unsigned
int
irq_want
;
#ifdef CONFIG_INTR_REMAP
struct
intel_iommu
*
iommu
=
0
;
int
index
=
0
;
#endif
irq_want
=
build_irq_for_pci_dev
(
dev
)
+
0x100
;
sub_handle
=
0
;
list_for_each_entry
(
desc
,
&
dev
->
msi_list
,
list
)
{
irq
=
create_irq_nr
(
irq_want
--
);
if
(
irq
==
0
)
return
-
1
;
#ifdef CONFIG_INTR_REMAP
if
(
!
intr_remapping_enabled
)
goto
no_ir
;
if
(
!
sub_handle
)
{
/*
* allocate the consecutive block of IRTE's
* for 'nvec'
*/
index
=
msi_alloc_irte
(
dev
,
irq
,
nvec
);
if
(
index
<
0
)
{
ret
=
index
;
goto
error
;
}
}
else
{
iommu
=
map_dev_to_ir
(
dev
);
if
(
!
iommu
)
{
ret
=
-
ENOENT
;
goto
error
;
}
/*
* setup the mapping between the irq and the IRTE
* base index, the sub_handle pointing to the
* appropriate interrupt remap table entry.
*/
set_irte_irq
(
irq
,
iommu
,
index
,
sub_handle
);
}
no_ir:
#endif
ret
=
setup_msi_irq
(
dev
,
desc
,
irq
);
if
(
ret
<
0
)
goto
error
;
sub_handle
++
;
}
return
0
;
error:
destroy_irq
(
irq
);
return
ret
;
destroy_irq
(
irq
);
return
ret
;
}
void
arch_teardown_msi_irq
(
unsigned
int
irq
)
{
destroy_irq
(
irq
);
}
#endif
/* CONFIG_PCI_MSI */
#ifdef CONFIG_DMAR
#ifdef CONFIG_SMP
static
void
dmar_msi_set_affinity
(
unsigned
int
irq
,
cpumask_t
mask
)
{
struct
irq_cfg
*
cfg
;
struct
msi_msg
msg
;
unsigned
int
dest
;
cpumask_t
tmp
;
struct
irq_desc
*
desc
;
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
return
;
if
(
assign_irq_vector
(
irq
,
mask
))
return
;
cfg
=
irq_cfg
(
irq
);
cpus_and
(
tmp
,
cfg
->
domain
,
mask
);
dest
=
cpu_mask_to_apicid
(
tmp
);
dmar_msi_read
(
irq
,
&
msg
);
msg
.
data
&=
~
MSI_DATA_VECTOR_MASK
;
msg
.
data
|=
MSI_DATA_VECTOR
(
cfg
->
vector
);
msg
.
address_lo
&=
~
MSI_ADDR_DEST_ID_MASK
;
msg
.
address_lo
|=
MSI_ADDR_DEST_ID
(
dest
);
dmar_msi_write
(
irq
,
&
msg
);
desc
=
irq_to_desc
(
irq
);
desc
->
affinity
=
mask
;
}
#endif
/* CONFIG_SMP */
struct
irq_chip
dmar_msi_type
=
{
.
name
=
"DMAR_MSI"
,
.
unmask
=
dmar_msi_unmask
,
.
mask
=
dmar_msi_mask
,
.
ack
=
ack_apic_edge
,
#ifdef CONFIG_SMP
.
set_affinity
=
dmar_msi_set_affinity
,
#endif
.
retrigger
=
ioapic_retrigger_irq
,
};
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
);
set_irq_chip_and_handler_name
(
irq
,
&
dmar_msi_type
,
handle_edge_irq
,
"edge"
);
return
0
;
}
#endif
#endif
/* CONFIG_PCI_MSI */
/*
* Hypertransport interrupt support
*/
...
...
@@ -2938,6 +3542,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
struct
irq_cfg
*
cfg
;
unsigned
int
dest
;
cpumask_t
tmp
;
struct
irq_desc
*
desc
;
cpus_and
(
tmp
,
mask
,
cpu_online_map
);
if
(
cpus_empty
(
tmp
))
...
...
@@ -2951,7 +3556,8 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
dest
=
cpu_mask_to_apicid
(
tmp
);
target_ht_irq
(
irq
,
dest
,
cfg
->
vector
);
irq_to_desc
(
irq
)
->
affinity
=
mask
;
desc
=
irq_to_desc
(
irq
);
desc
->
affinity
=
mask
;
}
#endif
...
...
@@ -2974,7 +3580,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
tmp
=
TARGET_CPUS
;
err
=
assign_irq_vector
(
irq
,
tmp
);
if
(
!
err
)
{
if
(
!
err
)
{
struct
ht_irq_msg
msg
;
unsigned
dest
;
...
...
@@ -3007,11 +3613,12 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
#endif
/* CONFIG_HT_IRQ */
/* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration
ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI
#ifdef CONFIG_X86_32
int
__init
io_apic_get_unique_id
(
int
ioapic
,
int
apic_id
)
{
union
IO_APIC_reg_00
reg_00
;
...
...
@@ -3086,7 +3693,6 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
return
apic_id
;
}
int
__init
io_apic_get_version
(
int
ioapic
)
{
union
IO_APIC_reg_01
reg_01
;
...
...
@@ -3098,9 +3704,9 @@ int __init io_apic_get_version(int ioapic)
return
reg_01
.
bits
.
version
;
}
#endif
int
__init
io_apic_get_redir_entries
(
int
ioapic
)
int
__init
io_apic_get_redir_entries
(
int
ioapic
)
{
union
IO_APIC_reg_01
reg_01
;
unsigned
long
flags
;
...
...
@@ -3113,10 +3719,10 @@ int __init io_apic_get_redir_entries(int ioapic)
}
int
io_apic_set_pci_routing
(
int
ioapic
,
int
pin
,
int
irq
,
int
triggering
,
int
polarity
)
int
io_apic_set_pci_routing
(
int
ioapic
,
int
pin
,
int
irq
,
int
triggering
,
int
polarity
)
{
if
(
!
IO_APIC_IRQ
(
irq
))
{
printk
(
KERN_ERR
"IOAPIC[%d]: Invalid reference to IRQ 0
\n
"
,
apic_printk
(
APIC_QUIET
,
KERN_ERR
"IOAPIC[%d]: Invalid reference to IRQ 0
\n
"
,
ioapic
);
return
-
EINVAL
;
}
...
...
@@ -3132,6 +3738,7 @@ int io_apic_set_pci_routing(int ioapic, int pin, int irq, int triggering, int po
return
0
;
}
int
acpi_get_override_irq
(
int
bus_irq
,
int
*
trigger
,
int
*
polarity
)
{
int
i
;
...
...
@@ -3163,7 +3770,6 @@ void __init setup_ioapic_dest(void)
{
int
pin
,
ioapic
,
irq
,
irq_entry
;
struct
irq_cfg
*
cfg
;
struct
irq_desc
*
desc
;
if
(
skip_ioapic_setup
==
1
)
return
;
...
...
@@ -3184,43 +3790,124 @@ void __init setup_ioapic_dest(void)
setup_IO_APIC_irq
(
ioapic
,
pin
,
irq
,
irq_trigger
(
irq_entry
),
irq_polarity
(
irq_entry
));
else
{
desc
=
irq_to_desc
(
irq
);
#ifdef CONFIG_INTR_REMAP
else
if
(
intr_remapping_enabled
)
set_ir_ioapic_affinity_irq
(
irq
,
TARGET_CPUS
);
#endif
else
set_ioapic_affinity_irq
(
irq
,
TARGET_CPUS
);
}
}
}
}
#endif
#ifdef CONFIG_X86_64
#define IOAPIC_RESOURCE_NAME_SIZE 11
static
struct
resource
*
ioapic_resources
;
static
struct
resource
*
__init
ioapic_setup_resources
(
void
)
{
unsigned
long
n
;
struct
resource
*
res
;
char
*
mem
;
int
i
;
if
(
nr_ioapics
<=
0
)
return
NULL
;
n
=
IOAPIC_RESOURCE_NAME_SIZE
+
sizeof
(
struct
resource
);
n
*=
nr_ioapics
;
mem
=
alloc_bootmem
(
n
);
res
=
(
void
*
)
mem
;
if
(
mem
!=
NULL
)
{
mem
+=
sizeof
(
struct
resource
)
*
nr_ioapics
;
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
res
[
i
].
name
=
mem
;
res
[
i
].
flags
=
IORESOURCE_MEM
|
IORESOURCE_BUSY
;
sprintf
(
mem
,
"IOAPIC %u"
,
i
);
mem
+=
IOAPIC_RESOURCE_NAME_SIZE
;
}
}
ioapic_resources
=
res
;
return
res
;
}
#endif
void
__init
ioapic_init_mappings
(
void
)
{
unsigned
long
ioapic_phys
,
idx
=
FIX_IO_APIC_BASE_0
;
int
i
;
#ifdef CONFIG_X86_64
struct
resource
*
ioapic_res
;
ioapic_res
=
ioapic_setup_resources
();
#endif
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
if
(
smp_found_config
)
{
ioapic_phys
=
mp_ioapics
[
i
].
mp_apicaddr
;
if
(
!
ioapic_phys
)
{
printk
(
KERN_ERR
"WARNING: bogus zero IO-APIC "
"address found in MPTABLE, "
"disabling IO/APIC support!
\n
"
);
smp_found_config
=
0
;
skip_ioapic_setup
=
1
;
goto
fake_ioapic_page
;
}
#ifdef CONFIG_X86_32
if
(
!
ioapic_phys
)
{
printk
(
KERN_ERR
"WARNING: bogus zero IO-APIC "
"address found in MPTABLE, "
"disabling IO/APIC support!
\n
"
);
smp_found_config
=
0
;
skip_ioapic_setup
=
1
;
goto
fake_ioapic_page
;
}
#endif
}
else
{
#ifdef CONFIG_X86_32
fake_ioapic_page:
#endif
ioapic_phys
=
(
unsigned
long
)
alloc_bootmem_pages
(
PAGE_SIZE
);
alloc_bootmem_pages
(
PAGE_SIZE
);
ioapic_phys
=
__pa
(
ioapic_phys
);
}
set_fixmap_nocache
(
idx
,
ioapic_phys
);
printk
(
KERN_DEBUG
"mapped IOAPIC to %08lx (%08lx)
\n
"
,
__fix_to_virt
(
idx
),
ioapic_phys
);
apic_printk
(
APIC_VERBOSE
,
"mapped IOAPIC to %08lx (%08lx)
\n
"
,
__fix_to_virt
(
idx
),
ioapic_phys
);
idx
++
;
#ifdef CONFIG_X86_64
if
(
ioapic_res
!=
NULL
)
{
ioapic_res
->
start
=
ioapic_phys
;
ioapic_res
->
end
=
ioapic_phys
+
(
4
*
1024
)
-
1
;
ioapic_res
++
;
}
#endif
}
}
#ifdef CONFIG_X86_64
static
int
__init
ioapic_insert_resources
(
void
)
{
int
i
;
struct
resource
*
r
=
ioapic_resources
;
if
(
!
r
)
{
printk
(
KERN_ERR
"IO APIC resources could be not be allocated.
\n
"
);
return
-
1
;
}
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
insert_resource
(
&
iomem_resource
,
r
);
r
++
;
}
return
0
;
}
/* Insert the IO APIC resources after PCI initialization has occured to handle
* IO APICS that are mapped in on a BAR in PCI space. */
late_initcall
(
ioapic_insert_resources
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment