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
Show 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
*
* Based on 'ACPI Specification 1.0b' February 2, 1999 and
* 'IA-64 Extensions to ACPI Specification' Revision 0.6
* acpi.c - Architecture-Specific Low-Level ACPI Support
*
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
...
...
@@ -10,12 +7,28 @@
* 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>
* ACPI based kernel configuration manager.
* ACPI 2.0 & IA64 ext 0.71
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
...
...
@@ -23,29 +36,16 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/irq.h>
#ifdef CONFIG_SERIAL_ACPI
#include <linux/acpi_serial.h>
#endif
#include <asm/acpi-ext.h>
#include <asm/acpikcfg.h>
#include <linux/acpi.h>
#include <asm/efi.h>
#include <asm/io.h>
#include <asm/iosapic.h>
#include <asm/machvec.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 */
int
__initdata
available_cpus
;
int
__initdata
total_cpus
;
void
(
*
pm_idle
)
(
void
);
void
(
*
pm_power_off
)
(
void
);
#define PREFIX "ACPI: "
asm
(
".weak iosapic_register_irq"
);
asm
(
".weak iosapic_register_legacy_irq"
);
...
...
@@ -53,10 +53,16 @@ asm (".weak iosapic_register_platform_irq");
asm
(
".weak iosapic_init"
);
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
*
acpi_get_sysname
(
void
)
{
/* the following should go away once we have an ACPI parser: */
#ifdef CONFIG_IA64_GENERIC
return
"hpsim"
;
#else
...
...
@@ -72,16 +78,19 @@ acpi_get_sysname (void)
# error Unknown platform. Fix acpi.c.
# 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.
* Provides the interrupt vector for a generic platform event
* (currently only CPEI implemented)
* Interrupt routing API for device drivers. Provides interrupt vector for
* a generic platform event. Currently only CPEI is implemented.
*/
int
acpi_request_vector
(
u32
int_type
)
acpi_request_vector
(
u32
int_type
)
{
int
vector
=
-
1
;
...
...
@@ -94,586 +103,492 @@ acpi_request_vector(u32 int_type)
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
* 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
);
}
/* --------------------------------------------------------------------------
Boot-time Table Parsing
-------------------------------------------------------------------------- */
/*
* ACPI 2.0 tables parsing functions
*/
static
int
total_cpus
__initdata
;
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
));
return
ret
;
if
(
lapic
->
address
)
{
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
void
__init
acpi20_lsapic
(
char
*
p
)
static
int
__init
acpi_parse_lsapic
(
acpi_table_entry_header
*
header
)
{
int
add
=
1
;
struct
acpi_table_lsapic
*
lsapic
=
NULL
;
acpi20_entry_lsapic_t
*
lsapic
=
(
acpi20_entry_lsapic_t
*
)
p
;
printk
(
" CPU %.04x:%.04x: "
,
lsapic
->
eid
,
lsapic
->
id
);
lsapic
=
(
struct
acpi_table_lsapic
*
)
header
;
if
(
!
lsapic
)
return
-
EINVAL
;
if
((
lsapic
->
flags
&
LSAPIC_ENABLED
)
==
0
)
{
printk
(
"disabled.
\n
"
);
add
=
0
;
}
acpi_table_print_madt_entry
(
header
);
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
#endif
if
(
add
)
{
printk
(
"CPU %d (0x%04x)"
,
total_cpus
,
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
);
if
(
lsapic
->
flags
.
enabled
)
{
available_cpus
++
;
printk
(
"
available
"
);
printk
(
"
enabled
"
);
#ifdef CONFIG_SMP
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
])
printk
(
" (BSP)"
);
#endif
printk
(
".
\n
"
);
}
else
{
printk
(
" disabled"
);
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
#endif
}
printk
(
"
\n
"
);
total_cpus
++
;
return
0
;
}
/*
* Extract iosapic info from madt (again) to determine which iosapic
* this platform interrupt resides in
*/
static
int
__init
acpi
20_which_iosapic
(
int
global_vector
,
acpi_madt_t
*
madt
,
u32
*
irq_base
,
char
**
iosapic_address
)
acpi
_parse_lapic_nmi
(
acpi_table_entry_header
*
header
)
{
acpi_entry_iosapic_t
*
iosapic
;
char
*
p
,
*
end
;
int
ver
,
max_pin
;
struct
acpi_table_lapic_nmi
*
lacpi_nmi
=
NULL
;
lacpi_nmi
=
(
struct
acpi_table_lapic_nmi
*
)
header
;
if
(
!
lacpi_nmi
)
return
-
EINVAL
;
p
=
(
char
*
)
(
madt
+
1
);
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
acpi_table_print_madt_entry
(
header
);
/* TBD: Support lapic_nmi entries */
return
0
;
}
static
int
__init
acpi_find_iosapic
(
int
global_vector
,
u32
*
irq_base
,
char
**
iosapic_address
)
{
struct
acpi_table_iosapic
*
iosapic
=
NULL
;
int
ver
=
0
;
int
max_pin
=
0
;
char
*
p
=
0
;
char
*
end
=
0
;
if
(
!
irq_base
||
!
iosapic_address
)
return
-
ENODEV
;
p
=
(
char
*
)
(
acpi_madt
+
1
);
end
=
p
+
(
acpi_madt
->
header
.
length
-
sizeof
(
struct
acpi_table_madt
));
while
(
p
<
end
)
{
switch
(
*
p
)
{
case
ACPI20_ENTRY_IO_SAPIC
:
/* collect IOSAPIC info for platform int use later */
iosapic
=
(
acpi_entry_iosapic_t
*
)
p
;
*
irq_base
=
iosapic
->
irq_base
;
if
(
*
p
==
ACPI_MADT_IOSAPIC
)
{
iosapic
=
(
struct
acpi_table_iosapic
*
)
p
;
*
irq_base
=
iosapic
->
global_irq_base
;
*
iosapic_address
=
ioremap
(
iosapic
->
address
,
0
);
/* is this the iosapic we're looking for? */
ver
=
iosapic_version
(
*
iosapic_address
);
max_pin
=
(
ver
>>
16
)
&
0xff
;
if
((
global_vector
-
*
irq_base
)
<=
max_pin
)
return
0
;
/* found it! */
break
;
default:
break
;
return
0
;
/* Found it! */
}
p
+=
p
[
1
];
}
return
1
;
return
-
ENODEV
;
}
/*
* Info on platform interrupt sources: NMI, PMI, INIT, etc.
*/
static
void
__init
acpi20_platform
(
char
*
p
,
acpi_madt_t
*
madt
)
static
int
__init
acpi_parse_iosapic
(
acpi_table_entry_header
*
header
)
{
int
vector
;
u32
irq_base
;
char
*
iosapic_address
;
unsigned
long
polarity
=
0
,
trigger
=
0
;
acpi20_entry_platform_src_t
*
plat
=
(
acpi20_entry_platform_src_t
*
)
p
;
struct
acpi_table_iosapic
*
iosapic
;
printk
(
"PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u
\n
"
,
plat
->
iosapic_vector
,
plat
->
global_vector
,
plat
->
eid
,
plat
->
id
);
iosapic
=
(
struct
acpi_table_iosapic
*
)
header
;
if
(
!
iosapic
)
return
-
EINVAL
;
/* record platform interrupt vectors for generic int routing code */
acpi_table_print_madt_entry
(
header
);
if
(
!
iosapic_register_platform_irq
)
{
printk
(
"acpi20_platform(): no ACPI platform IRQ support
\n
"
);
return
;
if
(
iosapic_init
)
{
#ifndef CONFIG_ITANIUM
/* 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
;
}
/* extract polarity and trigger info from flags */
switch
(
plat
->
flags
)
{
case
0x5
:
polarity
=
1
;
trigger
=
1
;
break
;
case
0x7
:
polarity
=
0
;
trigger
=
1
;
break
;
case
0xd
:
polarity
=
1
;
trigger
=
0
;
break
;
case
0xf
:
polarity
=
0
;
trigger
=
0
;
break
;
default:
printk
(
"acpi20_platform(): unknown flags 0x%x
\n
"
,
plat
->
flags
);
break
;
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
;
plintsrc
=
(
struct
acpi_table_plat_int_src
*
)
header
;
if
(
!
plintsrc
)
return
-
EINVAL
;
acpi_table_print_madt_entry
(
header
);
if
(
!
iosapic_register_platform_irq
)
{
printk
(
KERN_WARNING
PREFIX
"No ACPI platform IRQ support
\n
"
);
return
-
ENODEV
;
}
/* which iosapic does this IRQ belong to? */
if
(
acpi20_which_iosapic
(
plat
->
global_vector
,
madt
,
&
irq_base
,
&
iosapic_address
))
{
printk
(
"acpi20_platform(): I/O SAPIC not found!
\n
"
);
return
;
if
(
0
!=
acpi_find_iosapic
(
plintsrc
->
global_irq
,
&
irq_base
,
&
iosapic_address
))
{
printk
(
KERN_WARNING
PREFIX
"IOSAPIC not found
\n
"
);
return
-
ENODEV
;
}
/*
*
get vector assignment for this IRQ, set attributes, and program the IOSAPIC
*
routing table
*
Get vector assignment for this IRQ, set attributes, and program the
*
IOSAPIC routing table.
*/
vector
=
iosapic_register_platform_irq
(
plat
->
int_
type
,
plat
->
global_vector
,
plat
->
iosapic_vector
,
plat
->
eid
,
plat
->
id
,
polarity
,
trigger
,
vector
=
iosapic_register_platform_irq
(
plintsrc
->
type
,
plintsrc
->
global_irq
,
plintsrc
->
iosapic_vector
,
plintsrc
->
eid
,
plintsrc
->
id
,
(
plintsrc
->
flags
.
polarity
==
1
)
?
1
:
0
,
(
plintsrc
->
flags
.
trigger
==
1
)
?
1
:
0
,
irq_base
,
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
void
__init
acpi20_lapic_addr_override
(
char
*
p
)
static
int
__init
acpi_parse_int_src_ovr
(
acpi_table_entry_header
*
header
)
{
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
)
{
iounmap
((
void
*
)
ipi_base_addr
);
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
lapic
->
lapic_address
,
0
)
;
p
=
(
struct
acpi_table_int_src_ovr
*
)
header
;
if
(
!
p
)
return
-
EINVAL
;
printk
(
"LOCAL ACPI override to 0x%lx(p=0x%lx)
\n
"
,
ipi_base_addr
,
lapic
->
lapic_address
);
}
acpi_table_print_madt_entry
(
header
);
/* 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
void
__init
acpi20_parse_madt
(
acpi_madt_t
*
madt
)
static
int
__init
acpi_parse_nmi_src
(
acpi_table_entry_header
*
header
)
{
acpi_entry_iosapic_t
*
iosapic
=
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
);
struct
acpi_table_nmi_src
*
nmi_src
=
NULL
;
p
=
(
char
*
)
(
madt
+
1
);
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
nmi_src
=
(
struct
acpi_table_nmi_src
*
)
header
;
if
(
!
nmi_src
)
return
-
EINVAL
;
/* Initialize platform interrupt vector array */
for
(
i
=
0
;
i
<
ACPI_MAX_PLATFORM_IRQS
;
i
++
)
platform_irq_list
[
i
]
=
-
1
;
acpi_table_print_madt_entry
(
header
);
/*
* 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
];
}
/* TBD: Support nimsrc entries */
p
=
(
char
*
)
(
madt
+
1
)
;
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
return
0
;
}
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
);
end
=
p
+
(
madt
->
header
.
length
-
sizeof
(
acpi_madt_t
));
static
int
__init
acpi_parse_madt
(
unsigned
long
phys_addr
,
unsigned
long
size
)
{
int
i
=
0
;
while
(
p
<
end
)
{
switch
(
*
p
)
{
case
ACPI20_ENTRY_INT_SRC_OVERRIDE
:
printk
(
"ACPI 2.0 MADT: INT SOURCE Override
\n
"
);
acpi_legacy_irq
(
p
);
break
;
default:
break
;
}
p
+=
p
[
1
];
if
(
!
phys_addr
||
!
size
)
return
-
EINVAL
;
acpi_madt
=
(
struct
acpi_table_madt
*
)
__va
(
phys_addr
);
if
(
!
acpi_madt
)
{
printk
(
KERN_WARNING
PREFIX
"Unable to map MADT
\n
"
);
return
-
ENODEV
;
}
/* Make bootup pretty */
printk
(
" %d CPUs available, %d CPUs total
\n
"
,
available_cpus
,
total_cpus
);
/* Initialize platform interrupt vector array */
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
acpi
20_parse
(
acpi20_rsdp_t
*
rsdp20
)
acpi
_find_rsdp
(
unsigned
long
*
rsdp_phys
)
{
# ifdef CONFIG_ACPI
acpi_xsdt_t
*
xsdt
;
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
);
}
if
(
!
rsdp_phys
)
return
-
EINVAL
;
xsdt
=
__va
(
rsdp20
->
xsdt
);
hdrp
=
&
xsdt
->
header
;
if
(
strncmp
(
hdrp
->
signature
,
ACPI_XSDT_SIG
,
ACPI_XSDT_SIG_LEN
))
{
printk
(
"ACPI 2.0 XSDT signature incorrect. Trying RSDT
\n
"
);
/* RSDT parsing here */
if
(
efi
.
acpi20
)
{
(
*
rsdp_phys
)
=
__pa
(
efi
.
acpi20
);
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
"
);
}
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
);
return
-
ENODEV
;
}
tables
=
(
hdrp
->
length
-
sizeof
(
acpi_desc_table_hdr_t
))
>>
3
;
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
readl_unaligned
(
&
xsdt
->
entry_ptrs
[
i
]));
printk
(
" :table %4.4s found
\n
"
,
hdrp
->
signature
);
#ifdef CONFIG_SERIAL_ACPI
/* Only interested int the MADT table for now ... */
if
(
strncmp
(
hdrp
->
signature
,
ACPI_MADT_SIG
,
ACPI_MADT_SIG_LEN
)
!=
0
)
continue
;
#include <linux/acpi_serial.h>
/* Save MADT pointer for later */
madt
=
(
acpi_madt_t
*
)
hdrp
;
acpi20_parse_madt
(
madt
);
}
static
int
__init
acpi_parse_spcr
(
unsigned
long
phys_addr
,
unsigned
long
size
)
{
acpi_ser_t
*
spcr
=
NULL
;
unsigned
long
global_int
=
0
;
#ifdef CONFIG_SERIAL_ACPI
/*
* Now we're interested in other tables. We want the iosapics already
* initialized, so we do it in a separate loop.
*/
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
readl_unaligned
(
&
xsdt
->
entry_ptrs
[
i
]));
/*
* search for SPCR and DBGP table entries so we can enable
* non-pci interrupts to IO-SAPICs.
*/
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
;
if
(
!
phys_addr
||
!
size
)
return
-
EINVAL
;
setup_serial_acpi
(
hdrp
);
if
(
!
iosapic_register_irq
)
return
-
ENODEV
;
/*
* 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.
* 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).
*/
spcr
=
(
acpi_ser_t
*
)
__va
(
phys_addr
);
if
(
!
spcr
)
{
printk
(
KERN_WARNING
PREFIX
"Unable to map SPCR
\n
"
);
return
-
ENODEV
;
}
setup_serial_acpi
(
spcr
);
if
(
spcr
->
length
<
sizeof
(
acpi_ser_t
))
/* table is not long enough for full info, thus no in
t */
break
;
/* Table not long enough for full info, thus no interrup
t */
return
-
ENODEV
;
/*
* 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
)
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
;
u32
irq_base
=
0
;
char
*
iosapic_address
=
NULL
;
int
vector
=
0
;
/* 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
]);
/* We have a UART in memory space with an SAPIC interrupt */
if
(
!
iosapic_register_irq
)
continue
;
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
(
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
();
/* Which iosapic does this IRQ belong to? */
# 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? */
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
;
# endif
# endif
/* CONFIG_ACPI */
return
1
;
}
return
0
;
}
/*
* ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
* platforms start supporting ACPI 2.0
*/
/*
* Identify usable CPU's and remember them for SMP bringup later.
*/
static
void
__init
acpi_
lsapic
(
char
*
p
)
#endif
/*CONFIG_SERIAL_ACPI*/
int
__init
acpi_
boot_init
(
char
*
cmdline
)
{
int
add
=
1
;
int
result
=
0
;
acpi_entry_lsapic_t
*
lsapic
=
(
acpi_entry_lsapic_t
*
)
p
;
/* Initialize the ACPI boot-time table parser */
result
=
acpi_table_init
(
cmdline
);
if
(
0
!=
result
)
return
result
;
if
((
lsapic
->
flags
&
LSAPIC_PRESENT
)
==
0
)
return
;
/*
* MADT
* ----
* Parse the Multiple APIC Description Table (MADT), if exists.
* Note that this table provides platform SMP configuration
* information -- the successor to MPS tables.
*/
printk
(
" CPU %d (%.04x:%.04x): "
,
total_cpus
,
lsapic
->
eid
,
lsapic
->
id
);
result
=
acpi_table_parse
(
ACPI_APIC
,
acpi_parse_madt
);
if
(
1
>
result
)
return
result
;
if
((
lsapic
->
flags
&
LSAPIC_ENABLED
)
==
0
)
{
printk
(
"Disabled.
\n
"
);
add
=
0
;
}
else
if
(
lsapic
->
flags
&
LSAPIC_PERFORMANCE_RESTRICTED
)
{
printk
(
"Performance Restricted; ignoring.
\n
"
);
add
=
0
;
}
/* Local APIC */
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
-
1
;
#endif
if
(
add
)
{
printk
(
"Available.
\n
"
);
available_cpus
++
;
#ifdef CONFIG_SMP
smp_boot_data
.
cpu_phys_id
[
total_cpus
]
=
(
lsapic
->
id
<<
8
)
|
lsapic
->
eid
;
#endif
/* CONFIG_SMP */
result
=
acpi_table_parse_madt
(
ACPI_MADT_LAPIC_ADDR_OVR
,
acpi_parse_lapic_addr_ovr
);
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing LAPIC address override entry
\n
"
);
return
result
;
}
total_cpus
++
;
}
/*
* Info on platform interrupt sources: NMI. PMI, INIT, etc.
*/
static
void
__init
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
"
,
plat
->
iosapic_vector
,
plat
->
global_vector
,
plat
->
eid
,
plat
->
id
);
}
result
=
acpi_table_parse_madt
(
ACPI_MADT_LSAPIC
,
acpi_parse_lsapic
);
if
(
1
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing MADT - no LAPIC entries!
\n
"
);
return
-
ENODEV
;
}
/*
* Parse the ACPI Multiple SAPIC Table
*/
static
void
__init
acpi_parse_msapic
(
acpi_sapic_t
*
msapic
)
{
acpi_entry_iosapic_t
*
iosapic
;
char
*
p
,
*
end
;
result
=
acpi_table_parse_madt
(
ACPI_MADT_LAPIC_NMI
,
acpi_parse_lapic_nmi
);
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing LAPIC NMI entry
\n
"
);
return
result
;
}
/* Base address of IPI Message Block */
ipi_base_addr
=
(
unsigned
long
)
ioremap
(
msapic
->
interrupt_block
,
0
);
/* I/O APIC */
p
=
(
char
*
)
(
msapic
+
1
);
end
=
p
+
(
msapic
->
header
.
length
-
sizeof
(
acpi_sapic_t
));
result
=
acpi_table_parse_madt
(
ACPI_MADT_IOSAPIC
,
acpi_parse_iosapic
);
if
(
1
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing MADT - no IOAPIC entries!
\n
"
);
return
((
result
==
0
)
?
-
ENODEV
:
result
);
}
while
(
p
<
end
)
{
switch
(
*
p
)
{
case
ACPI_ENTRY_LOCAL_SAPIC
:
acpi_lsapic
(
p
);
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
;
/* System-Level Interrupt Routing */
case
ACPI_ENTRY_INT_SRC_OVERRIDE
:
acpi_legacy_irq
(
p
);
break
;
result
=
acpi_table_parse_madt
(
ACPI_MADT_PLAT_INT_SRC
,
acpi_parse_plat_int_src
);
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing platform interrupt source entry
\n
"
);
return
result
;
}
case
ACPI_ENTRY_PLATFORM_INT_SOURCE
:
acpi_platform
(
p
);
break
;
result
=
acpi_table_parse_madt
(
ACPI_MADT_INT_SRC_OVR
,
acpi_parse_int_src_ovr
);
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing interrupt source overrides entry
\n
"
);
return
result
;
}
default:
break
;
result
=
acpi_table_parse_madt
(
ACPI_MADT_NMI_SRC
,
acpi_parse_nmi_src
);
if
(
0
>
result
)
{
printk
(
KERN_ERR
PREFIX
"Error parsing NMI SRC entry
\n
"
);
return
result
;
}
/* Move to next table entry. */
p
+=
p
[
1
];
#ifdef CONFIG_SERIAL_ACPI
/*
* 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
);
/* Make bootup pretty */
printk
(
" %d CPUs available, %d CPUs total
\n
"
,
available_cpus
,
total_cpus
);
return
0
;
}
/* --------------------------------------------------------------------------
PCI Interrupt Routing
-------------------------------------------------------------------------- */
int
__init
acpi_
parse
(
acpi_rsdp_t
*
rsdp
)
acpi_
get_prt
(
struct
pci_vector_struct
**
vectors
,
int
*
count
)
{
# ifdef CONFIG_ACPI
acpi_rsdt_t
*
rsdt
;
acpi_desc_table_hdr_t
*
hdrp
;
long
tables
,
i
;
struct
pci_vector_struct
*
vector
=
NULL
;
struct
list_head
*
node
=
NULL
;
struct
acpi_prt_entry
*
entry
=
NULL
;
int
i
=
0
;
if
(
strncmp
(
rsdp
->
signature
,
ACPI_RSDP_SIG
,
ACPI_RSDP_SIG_LEN
))
{
printk
(
"Uh-oh, ACPI RSDP signature incorrect!
\n
"
);
return
0
;
}
if
(
!
vectors
||
!
count
)
return
-
EINVAL
;
rsdt
=
__va
(
rsdp
->
rsdt
);
if
(
strncmp
(
rsdt
->
header
.
signature
,
ACPI_RSDT_SIG
,
ACPI_RSDT_SIG_LEN
))
{
printk
(
"Uh-oh, ACPI RDST signature incorrect!
\n
"
);
return
0
;
*
vectors
=
NULL
;
*
count
=
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
,
rsdt
->
header
.
oem_revision
>>
16
,
rsdt
->
header
.
oem_revision
&
0xffff
);
/* Allocate vectors */
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
;
for
(
i
=
0
;
i
<
tables
;
i
++
)
{
hdrp
=
(
acpi_desc_table_hdr_t
*
)
__va
(
rsdt
->
entry_ptrs
[
i
]);
/* Convert PRT entries to IOSAPIC PCI vectors */
/* Only interested int the MSAPIC table for now ... */
if
(
strncmp
(
hdrp
->
signature
,
ACPI_SAPIC_SIG
,
ACPI_SAPIC_SIG_LEN
)
!=
0
)
continue
;
vector
=
*
vectors
;
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
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
# endif
/* CONFIG_ACPI */
return
1
;
int
__init
acpi_get_interrupt_model
(
int
*
type
)
{
if
(
!
type
)
return
-
EINVAL
;
*
type
=
ACPI_INT_MODEL_IOSAPIC
;
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