Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4f54c38b
Commit
4f54c38b
authored
Apr 10, 2002
by
David Mosberger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
acpi.c:
Paul's ACPI update.
parent
e19ca5df
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
414 additions
and
499 deletions
+414
-499
arch/ia64/kernel/acpi.c
arch/ia64/kernel/acpi.c
+414
-499
No files found.
arch/ia64/kernel/acpi.c
View file @
4f54c38b
/*
/*
*
Advanced Configuration and Power Interface
*
acpi.c - Architecture-Specific Low-Level ACPI Support
*
*
* Based on 'ACPI Specification 1.0b' February 2, 1999 and
* Copyright (C) 1999 VA Linux Systems
* 'IA-64 Extensions to ACPI Specification' Revision 0.6
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
* Copyright (C) 2000 Hewlett-Packard Co.
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 2000 Intel Corp.
* Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
*
* Copyright (C) 1999 VA Linux Systems
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
*
* Copyright (C) 2000 Hewlett-Packard Co.
* This program is free software; you can redistribute it and/or modify
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
* it under the terms of the GNU General Public License as published by
* Copyright (C) 2000 Intel Corp.
* the Free Software Foundation; either version 2 of the License, or
* Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
* (at your option) any later version.
* ACPI based kernel configuration manager.
*
* ACPI 2.0 & IA64 ext 0.71
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
...
@@ -23,29 +36,16 @@
...
@@ -23,29 +36,16 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/irq.h>
#ifdef CONFIG_SERIAL_ACPI
#include <linux/acpi.h>
#include <linux/acpi_serial.h>
#endif
#include <asm/acpi-ext.h>
#include <asm/acpikcfg.h>
#include <asm/efi.h>
#include <asm/efi.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/iosapic.h>
#include <asm/iosapic.h>
#include <asm/machvec.h>
#include <asm/machvec.h>
#include <asm/page.h>
#include <asm/page.h>
#include <asm/system.h>
#undef ACPI_DEBUG
/* Guess what this does? */
/* global array to record platform interrupt vectors for generic int routing */
int
platform_irq_list
[
ACPI_MAX_PLATFORM_IRQS
];
/* These are ugly but will be reclaimed by the kernel */
#define PREFIX "ACPI: "
int
__initdata
available_cpus
;
int
__initdata
total_cpus
;
void
(
*
pm_idle
)
(
void
);
void
(
*
pm_power_off
)
(
void
);
asm
(
".weak iosapic_register_irq"
);
asm
(
".weak iosapic_register_irq"
);
asm
(
".weak iosapic_register_legacy_irq"
);
asm
(
".weak iosapic_register_legacy_irq"
);
...
@@ -53,10 +53,16 @@ asm (".weak iosapic_register_platform_irq");
...
@@ -53,10 +53,16 @@ asm (".weak iosapic_register_platform_irq");
asm
(
".weak iosapic_init"
);
asm
(
".weak iosapic_init"
);
asm
(
".weak iosapic_version"
);
asm
(
".weak iosapic_version"
);
void
(
*
pm_idle
)
(
void
);
void
(
*
pm_power_off
)
(
void
);
/*
* TBD: Should go away once we have an ACPI parser.
*/
const
char
*
const
char
*
acpi_get_sysname
(
void
)
acpi_get_sysname
(
void
)
{
{
/* the following should go away once we have an ACPI parser: */
#ifdef CONFIG_IA64_GENERIC
#ifdef CONFIG_IA64_GENERIC
return
"hpsim"
;
return
"hpsim"
;
#else
#else
...
@@ -72,16 +78,19 @@ acpi_get_sysname (void)
...
@@ -72,16 +78,19 @@ acpi_get_sysname (void)
# error Unknown platform. Fix acpi.c.
# error Unknown platform. Fix acpi.c.
# endif
# endif
#endif
#endif
}
}
#define ACPI_MAX_PLATFORM_IRQS 256
/* Array to record platform interrupt vectors for generic interrupt routing. */
int
platform_irq_list
[
ACPI_MAX_PLATFORM_IRQS
];
/*
/*
* Interrupt routing API for device drivers.
* Interrupt routing API for device drivers. Provides interrupt vector for
* Provides the interrupt vector for a generic platform event
* a generic platform event. Currently only CPEI is implemented.
* (currently only CPEI implemented)
*/
*/
int
int
acpi_request_vector
(
u32
int_type
)
acpi_request_vector
(
u32
int_type
)
{
{
int
vector
=
-
1
;
int
vector
=
-
1
;
...
@@ -94,586 +103,492 @@ acpi_request_vector(u32 int_type)
...
@@ -94,586 +103,492 @@ acpi_request_vector(u32 int_type)
return
vector
;
return
vector
;
}
}
/*
* Configure legacy IRQ information.
*/
static
void
__init
acpi_legacy_irq
(
char
*
p
)
{
acpi_entry_int_override_t
*
legacy
=
(
acpi_entry_int_override_t
*
)
p
;
unsigned
long
polarity
=
0
,
edge_triggered
=
0
;
/*
/* --------------------------------------------------------------------------
* If the platform we're running doesn't define
Boot-time Table Parsing
* iosapic_register_legacy_irq(), we ignore this info...
-------------------------------------------------------------------------- */
*/
if
(
!
iosapic_register_legacy_irq
)
return
;
switch
(
legacy
->
flags
)
{
case
0x5
:
polarity
=
1
;
edge_triggered
=
1
;
break
;
case
0x7
:
polarity
=
0
;
edge_triggered
=
1
;
break
;
case
0xd
:
polarity
=
1
;
edge_triggered
=
0
;
break
;
case
0xf
:
polarity
=
0
;
edge_triggered
=
0
;
break
;
default:
printk
(
" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x
\n
"
,
legacy
->
isa_irq
,
legacy
->
flags
);
break
;
}
iosapic_register_legacy_irq
(
legacy
->
isa_irq
,
legacy
->
pin
,
polarity
,
edge_triggered
);
}
/*
static
int
total_cpus
__initdata
;
* ACPI 2.0 tables parsing functions
static
int
available_cpus
__initdata
;
*/
struct
acpi_table_madt
*
acpi_madt
__initdata
;
static
unsigned
long
readl_unaligned
(
void
*
p
)
static
int
__init
acpi_parse_lapic_addr_ovr
(
acpi_table_entry_header
*
header
)
{
{
unsigned
long
ret
;
struct
acpi_table_lapic_addr_ovr
*
lapic
=
NULL
;
lapic
=
(
struct
acpi_table_lapic_addr_ovr
*
)
header
;
if
(
!
lapic
)
return
-
EINVAL
;
acpi_table_print_madt_entry
(
header
);
memcpy
(
&
ret
,
p
,
sizeof
(
long
));
if
(
lapic
->
address
)
{
return
ret
;
iounmap
((
void
*
)
ipi_base_addr
);
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
lapic
->
address
,
0
);
}
return
0
;
}
}
/*
* Identify usable CPU's and remember them for SMP bringup later.
static
int
__init
*/
acpi_parse_lsapic
(
acpi_table_entry_header
*
header
)
static
void
__init
acpi20_lsapic
(
char
*
p
)
{
{
int
add
=
1
;
struct
acpi_table_lsapic
*
lsapic
=
NULL
;
acpi20_entry_lsapic_t
*
lsapic
=
(
acpi20_entry_lsapic_t
*
)
p
;
lsapic
=
(
struct
acpi_table_lsapic
*
)
header
;
printk
(
" CPU %.04x:%.04x: "
,
lsapic
->
eid
,
lsapic
->
id
);
if
(
!
lsapic
)
return
-
EINVAL
;
if
((
lsapic
->
flags
&
LSAPIC_ENABLED
)
==
0
)
{
acpi_table_print_madt_entry
(
header
);
printk
(
"disabled.
\n
"
);
add
=
0
;
}
#ifdef CONFIG_SMP
printk
(
"CPU %d (0x%04x)"
,
total_cpus
,
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
);
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
#endif
if
(
lsapic
->
flags
.
enabled
)
{
if
(
add
)
{
available_cpus
++
;
available_cpus
++
;
printk
(
"
available
"
);
printk
(
"
enabled
"
);
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
;
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
;
if
(
hard_smp_processor_id
()
==
smp_boot_data
.
cpu_phys_id
[
total_cpus
])
if
(
hard_smp_processor_id
()
==
smp_boot_data
.
cpu_phys_id
[
total_cpus
])
printk
(
" (BSP)"
);
printk
(
" (BSP)"
);
#endif
#endif
printk
(
".
\n
"
);
}
}
else
{
printk
(
" disabled"
);
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
#endif
}
printk
(
"
\n
"
);
total_cpus
++
;
total_cpus
++
;
return
0
;
}
}
/*
* Extract iosapic info from madt (again) to determine which iosapic
static
int
__init
* this platform interrupt resides in
acpi_parse_lapic_nmi
(
acpi_table_entry_header
*
header
)
*/
{
struct
acpi_table_lapic_nmi
*
lacpi_nmi
=
NULL
;
lacpi_nmi
=
(
struct
acpi_table_lapic_nmi
*
)
header
;
if
(
!
lacpi_nmi
)
return
-
EINVAL
;
acpi_table_print_madt_entry
(
header
);
/* TBD: Support lapic_nmi entries */
return
0
;
}
static
int
__init
static
int
__init
acpi
20_which_iosapic
(
int
global_vector
,
acpi_madt_t
*
madt
,
u32
*
irq_base
,
char
**
iosapic_address
)
acpi
_find_iosapic
(
int
global_vector
,
u32
*
irq_base
,
char
**
iosapic_address
)
{
{
acpi_entry_iosapic_t
*
iosapic
;
struct
acpi_table_iosapic
*
iosapic
=
NULL
;
char
*
p
,
*
end
;
int
ver
=
0
;
int
ver
,
max_pin
;
int
max_pin
=
0
;
char
*
p
=
0
;
char
*
end
=
0
;
p
=
(
char
*
)
(
madt
+
1
);
if
(
!
irq_base
||
!
iosapic_address
)
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
return
-
ENODEV
;
p
=
(
char
*
)
(
acpi_madt
+
1
);
end
=
p
+
(
acpi_madt
->
header
.
length
-
sizeof
(
struct
acpi_table_madt
));
while
(
p
<
end
)
{
while
(
p
<
end
)
{
switch
(
*
p
)
{
if
(
*
p
==
ACPI_MADT_IOSAPIC
)
{
case
ACPI20_ENTRY_IO_SAPIC
:
iosapic
=
(
struct
acpi_table_iosapic
*
)
p
;
/* collect IOSAPIC info for platform int use later */
iosapic
=
(
acpi_entry_iosapic_t
*
)
p
;
*
irq_base
=
iosapic
->
global_irq_base
;
*
irq_base
=
iosapic
->
irq_base
;
*
iosapic_address
=
ioremap
(
iosapic
->
address
,
0
);
*
iosapic_address
=
ioremap
(
iosapic
->
address
,
0
);
/* is this the iosapic we're looking for? */
ver
=
iosapic_version
(
*
iosapic_address
);
ver
=
iosapic_version
(
*
iosapic_address
);
max_pin
=
(
ver
>>
16
)
&
0xff
;
max_pin
=
(
ver
>>
16
)
&
0xff
;
if
((
global_vector
-
*
irq_base
)
<=
max_pin
)
if
((
global_vector
-
*
irq_base
)
<=
max_pin
)
return
0
;
/* found it! */
return
0
;
/* Found it! */
break
;
default:
break
;
}
}
p
+=
p
[
1
];
p
+=
p
[
1
];
}
}
return
1
;
return
-
ENODEV
;
}
}
/*
* Info on platform interrupt sources: NMI, PMI, INIT, etc.
static
int
__init
*/
acpi_parse_iosapic
(
acpi_table_entry_header
*
header
)
static
void
__init
acpi20_platform
(
char
*
p
,
acpi_madt_t
*
madt
)
{
{
int
vector
;
struct
acpi_table_iosapic
*
iosapic
;
u32
irq_base
;
char
*
iosapic_address
;
unsigned
long
polarity
=
0
,
trigger
=
0
;
acpi20_entry_platform_src_t
*
plat
=
(
acpi20_entry_platform_src_t
*
)
p
;
printk
(
"PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u
\n
"
,
iosapic
=
(
struct
acpi_table_iosapic
*
)
header
;
plat
->
iosapic_vector
,
plat
->
global_vector
,
plat
->
eid
,
plat
->
id
);
if
(
!
iosapic
)
return
-
EINVAL
;
/* record platform interrupt vectors for generic int routing code */
acpi_table_print_madt_entry
(
header
);
if
(
!
iosapic_register_platform_irq
)
{
if
(
iosapic_init
)
{
printk
(
"acpi20_platform(): no ACPI platform IRQ support
\n
"
);
#ifndef CONFIG_ITANIUM
return
;
/* PCAT_COMPAT flag indicates dual-8259 setup */
iosapic_init
(
iosapic
->
address
,
iosapic
->
global_irq_base
,
acpi_madt
->
flags
.
pcat_compat
);
#else
/* Firmware on old Itanium systems is broken */
iosapic_init
(
iosapic
->
address
,
iosapic
->
global_irq_base
,
1
);
#endif
}
}
return
0
;
}
static
int
__init
acpi_parse_plat_int_src
(
acpi_table_entry_header
*
header
)
{
struct
acpi_table_plat_int_src
*
plintsrc
=
NULL
;
int
vector
=
0
;
u32
irq_base
=
0
;
char
*
iosapic_address
=
NULL
;
/* extract polarity and trigger info from flags */
plintsrc
=
(
struct
acpi_table_plat_int_src
*
)
header
;
switch
(
plat
->
flags
)
{
if
(
!
plintsrc
)
case
0x5
:
polarity
=
1
;
trigger
=
1
;
break
;
return
-
EINVAL
;
case
0x7
:
polarity
=
0
;
trigger
=
1
;
break
;
case
0xd
:
polarity
=
1
;
trigger
=
0
;
break
;
acpi_table_print_madt_entry
(
header
)
;
case
0xf
:
polarity
=
0
;
trigger
=
0
;
break
;
default:
if
(
!
iosapic_register_platform_irq
)
{
printk
(
"acpi20_platform(): unknown flags 0x%x
\n
"
,
plat
->
flags
);
printk
(
KERN_WARNING
PREFIX
"No ACPI platform IRQ support
\n
"
);
break
;
return
-
ENODEV
;
}
}
/* which iosapic does this IRQ belong to? */
if
(
0
!=
acpi_find_iosapic
(
plintsrc
->
global_irq
,
&
irq_base
,
&
iosapic_address
))
{
if
(
acpi20_which_iosapic
(
plat
->
global_vector
,
madt
,
&
irq_base
,
&
iosapic_address
))
{
printk
(
KERN_WARNING
PREFIX
"IOSAPIC not found
\n
"
);
printk
(
"acpi20_platform(): I/O SAPIC not found!
\n
"
);
return
-
ENODEV
;
return
;
}
}
/*
/*
*
get vector assignment for this IRQ, set attributes, and program the IOSAPIC
*
Get vector assignment for this IRQ, set attributes, and program the
*
routing table
*
IOSAPIC routing table.
*/
*/
vector
=
iosapic_register_platform_irq
(
plat
->
int_type
,
vector
=
iosapic_register_platform_irq
(
plintsrc
->
type
,
plat
->
global_vector
,
plintsrc
->
global_irq
,
plat
->
iosapic_vector
,
plintsrc
->
iosapic_vector
,
plat
->
eid
,
plintsrc
->
eid
,
plat
->
id
,
plintsrc
->
id
,
polarity
,
(
plintsrc
->
flags
.
polarity
==
1
)
?
1
:
0
,
trigger
,
(
plintsrc
->
flags
.
trigger
==
1
)
?
1
:
0
,
irq_base
,
irq_base
,
iosapic_address
);
iosapic_address
);
platform_irq_list
[
plat
->
int_type
]
=
vector
;
platform_irq_list
[
plintsrc
->
type
]
=
vector
;
return
0
;
}
}
/*
* Override the physical address of the local APIC in the MADT stable header.
static
int
__init
*/
acpi_parse_int_src_ovr
(
acpi_table_entry_header
*
header
)
static
void
__init
acpi20_lapic_addr_override
(
char
*
p
)
{
{
acpi20_entry_lapic_addr_override_t
*
lapic
=
(
acpi20_entry_lapic_addr_override_t
*
)
p
;
struct
acpi_table_int_src_ovr
*
p
=
NULL
;
if
(
lapic
->
lapic_address
)
{
p
=
(
struct
acpi_table_int_src_ovr
*
)
header
;
iounmap
((
void
*
)
ipi_base_addr
);
if
(
!
p
)
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
lapic
->
lapic_address
,
0
)
;
return
-
EINVAL
;
printk
(
"LOCAL ACPI override to 0x%lx(p=0x%lx)
\n
"
,
acpi_table_print_madt_entry
(
header
);
ipi_base_addr
,
lapic
->
lapic_address
);
}
/* Ignore if the platform doesn't support overrides */
if
(
!
iosapic_register_legacy_irq
)
return
0
;
iosapic_register_legacy_irq
(
p
->
bus_irq
,
p
->
global_irq
,
(
p
->
flags
.
polarity
==
1
)
?
1
:
0
,
(
p
->
flags
.
trigger
==
1
)
?
1
:
0
);
return
0
;
}
}
/*
* Parse the ACPI Multiple APIC Description Table
static
int
__init
*/
acpi_parse_nmi_src
(
acpi_table_entry_header
*
header
)
static
void
__init
acpi20_parse_madt
(
acpi_madt_t
*
madt
)
{
{
acpi_entry_iosapic_t
*
iosapic
=
NULL
;
struct
acpi_table_nmi_src
*
nmi_src
=
NULL
;
acpi20_entry_lsapic_t
*
lsapic
=
NULL
;
char
*
p
,
*
end
;
int
i
;
/* Base address of IPI Message Block */
if
(
madt
->
lapic_address
)
{
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
madt
->
lapic_address
,
0
);
printk
(
"Lapic address set to 0x%lx
\n
"
,
ipi_base_addr
);
}
else
printk
(
"Lapic address set to default 0x%lx
\n
"
,
ipi_base_addr
);
p
=
(
char
*
)
(
madt
+
1
);
nmi_src
=
(
struct
acpi_table_nmi_src
*
)
header
;
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
if
(
!
nmi_src
)
return
-
EINVAL
;
/* Initialize platform interrupt vector array */
acpi_table_print_madt_entry
(
header
);
for
(
i
=
0
;
i
<
ACPI_MAX_PLATFORM_IRQS
;
i
++
)
platform_irq_list
[
i
]
=
-
1
;
/*
/* TBD: Support nimsrc entries */
* Split-up entry parsing to ensure ordering.
*/
while
(
p
<
end
)
{
switch
(
*
p
)
{
case
ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE
:
printk
(
"ACPI 2.0 MADT: LOCAL APIC Override
\n
"
);
acpi20_lapic_addr_override
(
p
);
break
;
case
ACPI20_ENTRY_LOCAL_SAPIC
:
printk
(
"ACPI 2.0 MADT: LOCAL SAPIC
\n
"
);
lsapic
=
(
acpi20_entry_lsapic_t
*
)
p
;
acpi20_lsapic
(
p
);
break
;
case
ACPI20_ENTRY_IO_SAPIC
:
iosapic
=
(
acpi_entry_iosapic_t
*
)
p
;
if
(
iosapic_init
)
/*
* The PCAT_COMPAT flag indicates that the system has a
* dual-8259 compatible setup.
*/
iosapic_init
(
iosapic
->
address
,
iosapic
->
irq_base
,
#ifdef CONFIG_ITANIUM
1
/* fw on some Itanium systems is broken... */
#else
(
madt
->
flags
&
MADT_PCAT_COMPAT
)
#endif
);
break
;
case
ACPI20_ENTRY_PLATFORM_INT_SOURCE
:
printk
(
"ACPI 2.0 MADT: PLATFORM INT SOURCE
\n
"
);
acpi20_platform
(
p
,
madt
);
break
;
case
ACPI20_ENTRY_LOCAL_APIC
:
printk
(
"ACPI 2.0 MADT: LOCAL APIC entry
\n
"
);
break
;
case
ACPI20_ENTRY_IO_APIC
:
printk
(
"ACPI 2.0 MADT: IO APIC entry
\n
"
);
break
;
case
ACPI20_ENTRY_NMI_SOURCE
:
printk
(
"ACPI 2.0 MADT: NMI SOURCE entry
\n
"
);
break
;
case
ACPI20_ENTRY_LOCAL_APIC_NMI
:
printk
(
"ACPI 2.0 MADT: LOCAL APIC NMI entry
\n
"
);
break
;
case
ACPI20_ENTRY_INT_SRC_OVERRIDE
:
break
;
default:
printk
(
"ACPI 2.0 MADT: unknown entry skip
\n
"
);
break
;
break
;
}
p
+=
p
[
1
];
}
p
=
(
char
*
)
(
madt
+
1
)
;
return
0
;
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
}
while
(
p
<
end
)
{
switch
(
*
p
)
{
case
ACPI20_ENTRY_LOCAL_APIC
:
if
(
lsapic
)
break
;
printk
(
"ACPI 2.0 MADT: LOCAL APIC entry
\n
"
);
/* parse local apic if there's no local Sapic */
break
;
case
ACPI20_ENTRY_IO_APIC
:
if
(
iosapic
)
break
;
printk
(
"ACPI 2.0 MADT: IO APIC entry
\n
"
);
/* parse ioapic if there's no ioSapic */
break
;
default:
break
;
}
p
+=
p
[
1
];
}
p
=
(
char
*
)
(
madt
+
1
);
static
int
__init
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
acpi_parse_madt
(
unsigned
long
phys_addr
,
unsigned
long
size
)
{
int
i
=
0
;
while
(
p
<
end
)
{
if
(
!
phys_addr
||
!
size
)
switch
(
*
p
)
{
return
-
EINVAL
;
case
ACPI20_ENTRY_INT_SRC_OVERRIDE
:
printk
(
"ACPI 2.0 MADT: INT SOURCE Override
\n
"
);
acpi_madt
=
(
struct
acpi_table_madt
*
)
__va
(
phys_addr
);
acpi_legacy_irq
(
p
);
if
(
!
acpi_madt
)
{
break
;
printk
(
KERN_WARNING
PREFIX
"Unable to map MADT
\n
"
);
default:
return
-
ENODEV
;
break
;
}
p
+=
p
[
1
];
}
}
/* Make bootup pretty */
/* Initialize platform interrupt vector array */
printk
(
" %d CPUs available, %d CPUs total
\n
"
,
available_cpus
,
total_cpus
);
for
(
i
=
0
;
i
<
ACPI_MAX_PLATFORM_IRQS
;
i
++
)
platform_irq_list
[
i
]
=
-
1
;
/* Get base address of IPI Message Block */
if
(
acpi_madt
->
lapic_address
)
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
acpi_madt
->
lapic_address
,
0
);
printk
(
KERN_INFO
PREFIX
"Local APIC address 0x%lx
\n
"
,
ipi_base_addr
);
return
0
;
}
}
int
__init
int
__init
acpi
20_parse
(
acpi20_rsdp_t
*
rsdp20
)
acpi
_find_rsdp
(
unsigned
long
*
rsdp_phys
)
{
{
# ifdef CONFIG_ACPI
if
(
!
rsdp_phys
)
acpi_xsdt_t
*
xsdt
;
return
-
EINVAL
;
acpi_desc_table_hdr_t
*
hdrp
;
acpi_madt_t
*
madt
;
int
tables
,
i
;
if
(
strncmp
(
rsdp20
->
signature
,
ACPI_RSDP_SIG
,
ACPI_RSDP_SIG_LEN
))
{
printk
(
"ACPI 2.0 RSDP signature incorrect!
\n
"
);
return
0
;
}
else
{
printk
(
"ACPI 2.0 Root System Description Ptr at 0x%lx
\n
"
,
(
unsigned
long
)
rsdp20
);
}
xsdt
=
__va
(
rsdp20
->
xsdt
);
if
(
efi
.
acpi20
)
{
hdrp
=
&
xsdt
->
header
;
(
*
rsdp_phys
)
=
__pa
(
efi
.
acpi20
);
if
(
strncmp
(
hdrp
->
signature
,
ACPI_XSDT_SIG
,
ACPI_XSDT_SIG_LEN
))
{
printk
(
"ACPI 2.0 XSDT signature incorrect. Trying RSDT
\n
"
);
/* RSDT parsing here */
return
0
;
return
0
;
}
else
{
printk
(
"ACPI 2.0 XSDT at 0x%lx (p=0x%lx)
\n
"
,
(
unsigned
long
)
xsdt
,
(
unsigned
long
)
rsdp20
->
xsdt
);
}
}
else
if
(
efi
.
acpi
)
{
printk
(
KERN_WARNING
PREFIX
"v1.0/r0.71 tables no longer supported
\n
"
);
}
return
-
ENODEV
;
}
printk
(
"ACPI 2.0: %.6s %.8s %d.%d
\n
"
,
hdrp
->
oem_id
,
hdrp
->
oem_table_id
,
hdrp
->
oem_revision
>>
16
,
hdrp
->
oem_revision
&
0xffff
);
acpi_cf_init
((
void
*
)
rsdp20
);
#ifdef CONFIG_SERIAL_ACPI
tables
=
(
hdrp
->
length
-
sizeof
(
acpi_desc_table_hdr_t
))
>>
3
;
#include <linux/acpi_serial.h>
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
static
int
__init
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
readl_unaligned
(
&
xsdt
->
entry_ptrs
[
i
]));
acpi_parse_spcr
(
unsigned
long
phys_addr
,
unsigned
long
size
)
printk
(
" :table %4.4s found
\n
"
,
hdrp
->
signature
);
{
acpi_ser_t
*
spcr
=
NULL
;
unsigned
long
global_int
=
0
;
/* Only interested int the MADT table for now ... */
if
(
!
phys_addr
||
!
size
)
if
(
strncmp
(
hdrp
->
signature
,
return
-
EINVAL
;
ACPI_MADT_SIG
,
ACPI_MADT_SIG_LEN
)
!=
0
)
continue
;
/* Save MADT pointer for later */
if
(
!
iosapic_register_irq
)
madt
=
(
acpi_madt_t
*
)
hdrp
;
return
-
ENODEV
;
acpi20_parse_madt
(
madt
);
}
#ifdef CONFIG_SERIAL_ACPI
/*
/*
* Now we're interested in other tables. We want the iosapics already
* ACPI is able to describe serial ports that live at non-standard
* initialized, so we do it in a separate loop.
* memory addresses and use non-standard interrupts, either via
* direct SAPIC mappings or via PCI interrupts. We handle interrupt
* routing for SAPIC-based (non-PCI) devices here. Interrupt routing
* for PCI devices will be handled when processing the PCI Interrupt
* Routing Table (PRT).
*/
*/
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
readl_unaligned
(
&
xsdt
->
entry_ptrs
[
i
]));
spcr
=
(
acpi_ser_t
*
)
__va
(
phys_addr
);
/*
if
(
!
spcr
)
{
* search for SPCR and DBGP table entries so we can enable
printk
(
KERN_WARNING
PREFIX
"Unable to map SPCR
\n
"
);
* non-pci interrupts to IO-SAPICs.
return
-
ENODEV
;
*/
if
(
!
strncmp
(
hdrp
->
signature
,
ACPI_SPCRT_SIG
,
ACPI_SPCRT_SIG_LEN
)
||
!
strncmp
(
hdrp
->
signature
,
ACPI_DBGPT_SIG
,
ACPI_DBGPT_SIG_LEN
))
{
acpi_ser_t
*
spcr
=
(
void
*
)
hdrp
;
unsigned
long
global_int
;
setup_serial_acpi
(
hdrp
);
/*
* ACPI is able to describe serial ports that live at non-standard
* memory space addresses and use SAPIC interrupts. If not also
* PCI devices, there would be no interrupt vector information for
* them. This checks for and fixes that situation.
*/
if
(
spcr
->
length
<
sizeof
(
acpi_ser_t
))
/* table is not long enough for full info, thus no int */
break
;
/*
* If the device is not in PCI space, but uses a SAPIC interrupt,
* we need to program the SAPIC so that serial can autoprobe for
* the IA64 interrupt vector later on. If the device is in PCI
* space, it should already be setup via the PCI vectors
*/
if
(
spcr
->
base_addr
.
space_id
!=
ACPI_SERIAL_PCICONF_SPACE
&&
spcr
->
int_type
==
ACPI_SERIAL_INT_SAPIC
)
{
u32
irq_base
;
char
*
iosapic_address
;
int
vector
;
/* We have a UART in memory space with a SAPIC interrupt */
global_int
=
(
(
spcr
->
global_int
[
3
]
<<
24
)
|
(
spcr
->
global_int
[
2
]
<<
16
)
|
(
spcr
->
global_int
[
1
]
<<
8
)
|
spcr
->
global_int
[
0
]);
if
(
!
iosapic_register_irq
)
continue
;
/* which iosapic does this IRQ belong to? */
if
(
acpi20_which_iosapic
(
global_int
,
madt
,
&
irq_base
,
&
iosapic_address
)
==
0
)
{
vector
=
iosapic_register_irq
(
global_int
,
1
,
/* active high polarity */
1
,
/* edge triggered */
irq_base
,
iosapic_address
);
}
}
}
}
}
#endif
acpi_cf_terminate
();
# ifdef CONFIG_SMP
setup_serial_acpi
(
spcr
);
if
(
available_cpus
==
0
)
{
printk
(
"ACPI: Found 0 CPUS; assuming 1
\n
"
);
if
(
spcr
->
length
<
sizeof
(
acpi_ser_t
))
available_cpus
=
1
;
/* We've got at least one of these, no? */
/* Table not long enough for full info, thus no interrupt */
return
-
ENODEV
;
if
((
spcr
->
base_addr
.
space_id
!=
ACPI_SERIAL_PCICONF_SPACE
)
&&
(
spcr
->
int_type
==
ACPI_SERIAL_INT_SAPIC
))
{
u32
irq_base
=
0
;
char
*
iosapic_address
=
NULL
;
int
vector
=
0
;
/* We have a UART in memory space with an SAPIC interrupt */
global_int
=
(
(
spcr
->
global_int
[
3
]
<<
24
)
|
(
spcr
->
global_int
[
2
]
<<
16
)
|
(
spcr
->
global_int
[
1
]
<<
8
)
|
(
spcr
->
global_int
[
0
])
);
/* Which iosapic does this IRQ belong to? */
if
(
0
==
acpi_find_iosapic
(
global_int
,
&
irq_base
,
&
iosapic_address
))
{
vector
=
iosapic_register_irq
(
global_int
,
1
,
1
,
irq_base
,
iosapic_address
);
}
}
}
smp_boot_data
.
cpu_count
=
total_cpus
;
return
0
;
# endif
# endif
/* CONFIG_ACPI */
return
1
;
}
}
/*
* ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
* platforms start supporting ACPI 2.0
*/
/*
#endif
/*CONFIG_SERIAL_ACPI*/
* Identify usable CPU's and remember them for SMP bringup later.
*/
static
void
__init
int
__init
acpi_
lsapic
(
char
*
p
)
acpi_
boot_init
(
char
*
cmdline
)
{
{
int
add
=
1
;
int
result
=
0
;
/* Initialize the ACPI boot-time table parser */
result
=
acpi_table_init
(
cmdline
);
if
(
0
!=
result
)
return
result
;
acpi_entry_lsapic_t
*
lsapic
=
(
acpi_entry_lsapic_t
*
)
p
;
/*
* MADT
* ----
* Parse the Multiple APIC Description Table (MADT), if exists.
* Note that this table provides platform SMP configuration
* information -- the successor to MPS tables.
*/
if
((
lsapic
->
flags
&
LSAPIC_PRESENT
)
==
0
)
result
=
acpi_table_parse
(
ACPI_APIC
,
acpi_parse_madt
);
return
;
if
(
1
>
result
)
return
result
;
printk
(
" CPU %d (%.04x:%.04x): "
,
total_cpus
,
lsapic
->
eid
,
lsapic
->
id
);
/* Local APIC */
if
((
lsapic
->
flags
&
LSAPIC_ENABLED
)
==
0
)
{
result
=
acpi_table_parse_madt
(
ACPI_MADT_LAPIC_ADDR_OVR
,
acpi_parse_lapic_addr_ovr
);
printk
(
"Disabled.
\n
"
);
if
(
0
>
result
)
{
add
=
0
;
printk
(
KERN_ERR
PREFIX
"Error parsing LAPIC address override entry
\n
"
);
}
else
if
(
lsapic
->
flags
&
LSAPIC_PERFORMANCE_RESTRICTED
)
{
return
result
;
printk
(
"Performance Restricted; ignoring.
\n
"
);
add
=
0
;
}
}
#ifdef CONFIG_SMP
result
=
acpi_table_parse_madt
(
ACPI_MADT_LSAPIC
,
acpi_parse_lsapic
);
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
if
(
1
>
result
)
{
#endif
printk
(
KERN_ERR
PREFIX
"Error parsing MADT - no LAPIC entries!
\n
"
);
if
(
add
)
{
return
-
ENODEV
;
printk
(
"Available.
\n
"
);
available_cpus
++
;
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
;
#endif
/* CONFIG_SMP */
}
}
total_cpus
++
;
}
/*
result
=
acpi_table_parse_madt
(
ACPI_MADT_LAPIC_NMI
,
acpi_parse_lapic_nmi
);
* Info on platform interrupt sources: NMI. PMI, INIT, etc.
if
(
0
>
result
)
{
*/
printk
(
KERN_ERR
PREFIX
"Error parsing LAPIC NMI entry
\n
"
);
static
void
__init
return
result
;
acpi_platform
(
char
*
p
)
}
{
acpi_entry_platform_src_t
*
plat
=
(
acpi_entry_platform_src_t
*
)
p
;
printk
(
"PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u
\n
"
,
/* I/O APIC */
plat
->
iosapic_vector
,
plat
->
global_vector
,
plat
->
eid
,
plat
->
id
);
}
/*
result
=
acpi_table_parse_madt
(
ACPI_MADT_IOSAPIC
,
acpi_parse_iosapic
);
* Parse the ACPI Multiple SAPIC Table
if
(
1
>
result
)
{
*/
printk
(
KERN_ERR
PREFIX
"Error parsing MADT - no IOAPIC entries!
\n
"
);
static
void
__init
return
((
result
==
0
)
?
-
ENODEV
:
result
);
acpi_parse_msapic
(
acpi_sapic_t
*
msapic
)
}
{
acpi_entry_iosapic_t
*
iosapic
;
char
*
p
,
*
end
;
/* Base address of IPI Message Block */
/* System-Level Interrupt Routing */
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
msapic
->
interrupt_block
,
0
);
p
=
(
char
*
)
(
msapic
+
1
);
result
=
acpi_table_parse_madt
(
ACPI_MADT_PLAT_INT_SRC
,
acpi_parse_plat_int_src
);
end
=
p
+
(
msapic
->
header
.
length
-
sizeof
(
acpi_sapic_t
));
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing platform interrupt source entry
\n
"
);
return
result
;
}
while
(
p
<
end
)
{
result
=
acpi_table_parse_madt
(
ACPI_MADT_INT_SRC_OVR
,
acpi_parse_int_src_ovr
);
switch
(
*
p
)
{
if
(
0
>
result
)
{
case
ACPI_ENTRY_LOCAL_SAPIC
:
printk
(
KERN_ERR
PREFIX
"Error parsing interrupt source overrides entry
\n
"
);
acpi_lsapic
(
p
);
return
result
;
break
;
}
case
ACPI_ENTRY_IO_SAPIC
:
iosapic
=
(
acpi_entry_iosapic_t
*
)
p
;
if
(
iosapic_init
)
/*
* The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT
* flag like the MADT table, but we can safely assume that
* ACPI 1.0b systems have a dual-8259 setup.
*/
iosapic_init
(
iosapic
->
address
,
iosapic
->
irq_base
,
1
);
break
;
case
ACPI_ENTRY_INT_SRC_OVERRIDE
:
acpi_legacy_irq
(
p
);
break
;
case
ACPI_ENTRY_PLATFORM_INT_SOURCE
:
acpi_platform
(
p
);
break
;
default:
break
;
}
/* Move to next table entry. */
result
=
acpi_table_parse_madt
(
ACPI_MADT_NMI_SRC
,
acpi_parse_nmi_src
);
p
+=
p
[
1
];
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing NMI SRC entry
\n
"
);
return
result
;
}
}
/* Make bootup pretty */
#ifdef CONFIG_SERIAL_ACPI
printk
(
" %d CPUs available, %d CPUs total
\n
"
,
available_cpus
,
total_cpus
);
/*
* TBD: Need phased approach to table parsing (only do those absolutely
* required during boot-up). Recommend expanding concept of fix-
* feature devices (LDM) to include table-based devices such as
* serial ports, EC, SMBus, etc.
*/
acpi_table_parse
(
ACPI_SPCR
,
acpi_parse_spcr
);
#endif
/*CONFIG_SERIAL_ACPI*/
#ifdef CONFIG_SMP
if
(
available_cpus
==
0
)
{
printk
(
"ACPI: Found 0 CPUS; assuming 1
\n
"
);
available_cpus
=
1
;
/* We've got at least one of these, no? */
}
smp_boot_data
.
cpu_count
=
total_cpus
;
#endif
/* Make boot-up look pretty */
printk
(
"%d CPUs available, %d CPUs total
\n
"
,
available_cpus
,
total_cpus
);
return
0
;
}
}
/* --------------------------------------------------------------------------
PCI Interrupt Routing
-------------------------------------------------------------------------- */
int
__init
int
__init
acpi_
parse
(
acpi_rsdp_t
*
rsdp
)
acpi_
get_prt
(
struct
pci_vector_struct
**
vectors
,
int
*
count
)
{
{
# ifdef CONFIG_ACPI
struct
pci_vector_struct
*
vector
=
NULL
;
acpi_rsdt_t
*
rsdt
;
struct
list_head
*
node
=
NULL
;
acpi_desc_table_hdr_t
*
hdrp
;
struct
acpi_prt_entry
*
entry
=
NULL
;
long
tables
,
i
;
int
i
=
0
;
if
(
strncmp
(
rsdp
->
signature
,
ACPI_RSDP_SIG
,
ACPI_RSDP_SIG_LEN
))
{
if
(
!
vectors
||
!
count
)
printk
(
"Uh-oh, ACPI RSDP signature incorrect!
\n
"
);
return
-
EINVAL
;
return
0
;
}
rsdt
=
__va
(
rsdp
->
rsdt
);
*
vectors
=
NULL
;
if
(
strncmp
(
rsdt
->
header
.
signature
,
ACPI_RSDT_SIG
,
ACPI_RSDT_SIG_LEN
))
{
*
count
=
0
;
printk
(
"Uh-oh, ACPI RDST signature incorrect!
\n
"
);
return
0
;
if
(
acpi_prts
.
count
<
0
)
{
printk
(
KERN_ERR
PREFIX
"No PCI IRQ routing entries
\n
"
);
return
-
ENODEV
;
}
}
printk
(
"ACPI: %.6s %.8s %d.%d
\n
"
,
rsdt
->
header
.
oem_id
,
rsdt
->
header
.
oem_table_id
,
/* Allocate vectors */
rsdt
->
header
.
oem_revision
>>
16
,
rsdt
->
header
.
oem_revision
&
0xffff
);
acpi_cf_init
(
rsdp
);
*
vectors
=
kmalloc
(
sizeof
(
struct
pci_vector_struct
)
*
acpi_prts
.
count
,
GFP_KERNEL
);
if
(
!
(
*
vectors
))
return
-
ENOMEM
;
tables
=
(
rsdt
->
header
.
length
-
sizeof
(
acpi_desc_table_hdr_t
))
/
8
;
/* Convert PRT entries to IOSAPIC PCI vectors */
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
rsdt
->
entry_ptrs
[
i
]);
/* Only interested int the MSAPIC table for now ... */
vector
=
*
vectors
;
if
(
strncmp
(
hdrp
->
signature
,
ACPI_SAPIC_SIG
,
ACPI_SAPIC_SIG_LEN
)
!=
0
)
continue
;
acpi_parse_msapic
((
acpi_sapic_t
*
)
hdrp
);
list_for_each
(
node
,
&
acpi_prts
.
entries
)
{
entry
=
(
struct
acpi_prt_entry
*
)
node
;
vector
[
i
].
bus
=
(
u16
)
entry
->
id
.
bus
;
vector
[
i
].
pci_id
=
(
u32
)
entry
->
id
.
dev
<<
16
|
0xffff
;
vector
[
i
].
pin
=
(
u8
)
entry
->
id
.
pin
;
vector
[
i
].
irq
=
(
u8
)
entry
->
source
.
index
;
i
++
;
}
}
*
count
=
acpi_prts
.
count
;
return
0
;
}
acpi_cf_terminate
();
/* Assume IA64 always use I/O SAPIC */
# ifdef CONFIG_SMP
int
__init
if
(
available_cpus
==
0
)
{
acpi_get_interrupt_model
(
int
*
type
)
printk
(
"ACPI: Found 0 CPUS; assuming 1
\n
"
);
{
available_cpus
=
1
;
/* We've got at least one of these, no? */
if
(
!
type
)
}
return
-
EINVAL
;
smp_boot_data
.
cpu_count
=
total_cpus
;
# endif
*
type
=
ACPI_INT_MODEL_IOSAPIC
;
# endif
/* CONFIG_ACPI */
return
1
;
return
0
;
}
}
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