mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-14 13:02:58 +02:00
Updated xen patches taken from suse.
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
This commit is contained in:
committed by
Michael Tremer
parent
4935eb8b91
commit
00e5a55c3c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,848 +0,0 @@
|
||||
Subject: xen3 xen-kconfig
|
||||
From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 728:832aac894efd)
|
||||
Patch-mainline: obsolete
|
||||
Acked-by: jbeulich@novell.com
|
||||
|
||||
Index: head-2008-11-25/arch/x86/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/Kconfig 2008-11-17 13:39:31.000000000 +0100
|
||||
@@ -44,6 +44,7 @@ config GENERIC_LOCKBREAK
|
||||
|
||||
config GENERIC_TIME
|
||||
def_bool y
|
||||
+ depends on !X86_XEN
|
||||
|
||||
config GENERIC_CMOS_UPDATE
|
||||
def_bool y
|
||||
@@ -188,7 +189,7 @@ config X86_64_SMP
|
||||
|
||||
config X86_HT
|
||||
bool
|
||||
- depends on SMP
|
||||
+ depends on SMP && !XEN
|
||||
depends on (X86_32 && !X86_VOYAGER) || X86_64
|
||||
default y
|
||||
|
||||
@@ -200,6 +201,17 @@ config X86_BIOS_REBOOT
|
||||
config X86_TRAMPOLINE
|
||||
bool
|
||||
depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
|
||||
+ depends on !XEN
|
||||
+ default y
|
||||
+
|
||||
+config X86_NO_TSS
|
||||
+ bool
|
||||
+ depends on X86_XEN || X86_64_XEN
|
||||
+ default y
|
||||
+
|
||||
+config X86_NO_IDT
|
||||
+ bool
|
||||
+ depends on X86_XEN || X86_64_XEN
|
||||
default y
|
||||
|
||||
config KTIME_SCALAR
|
||||
@@ -267,6 +279,17 @@ config X86_PC
|
||||
help
|
||||
Choose this option if your computer is a standard PC or compatible.
|
||||
|
||||
+config X86_XEN
|
||||
+ bool "Xen-compatible"
|
||||
+ select XEN
|
||||
+ select X86_PAE
|
||||
+ select X86_UP_APIC if !SMP && XEN_PRIVILEGED_GUEST
|
||||
+ select X86_UP_IOAPIC if !SMP && XEN_PRIVILEGED_GUEST
|
||||
+ select SWIOTLB
|
||||
+ help
|
||||
+ Choose this option if you plan to run this kernel on top of the
|
||||
+ Xen Hypervisor.
|
||||
+
|
||||
config X86_ELAN
|
||||
bool "AMD Elan"
|
||||
depends on X86_32
|
||||
@@ -334,6 +357,13 @@ config X86_BIGSMP
|
||||
|
||||
endif
|
||||
|
||||
+config X86_64_XEN
|
||||
+ bool "Enable Xen compatible kernel"
|
||||
+ select XEN
|
||||
+ select SWIOTLB
|
||||
+ help
|
||||
+ This option will compile a kernel compatible with Xen hypervisor
|
||||
+
|
||||
config X86_VSMP
|
||||
bool "Support for ScaleMP vSMP"
|
||||
select PARAVIRT
|
||||
@@ -474,6 +504,7 @@ source "arch/x86/Kconfig.cpu"
|
||||
config HPET_TIMER
|
||||
def_bool X86_64
|
||||
prompt "HPET Timer Support" if X86_32
|
||||
+ depends on !X86_XEN && !X86_64_XEN
|
||||
help
|
||||
Use the IA-PC HPET (High Precision Event Timer) to manage
|
||||
time in preference to the PIT and RTC, if a HPET is
|
||||
@@ -510,7 +541,7 @@ config GART_IOMMU
|
||||
default y
|
||||
select SWIOTLB
|
||||
select AGP
|
||||
- depends on X86_64 && PCI
|
||||
+ depends on X86_64 && PCI && !X86_64_XEN
|
||||
help
|
||||
Support for full DMA access of devices with 32bit memory access only
|
||||
on systems with more than 3GB. This is usually needed for USB,
|
||||
@@ -525,7 +556,7 @@ config GART_IOMMU
|
||||
config CALGARY_IOMMU
|
||||
bool "IBM Calgary IOMMU support"
|
||||
select SWIOTLB
|
||||
- depends on X86_64 && PCI && EXPERIMENTAL
|
||||
+ depends on X86_64 && PCI && !X86_64_XEN && EXPERIMENTAL
|
||||
help
|
||||
Support for hardware IOMMUs in IBM's xSeries x366 and x460
|
||||
systems. Needed to run systems with more than 3GB of memory
|
||||
@@ -593,6 +624,7 @@ config NR_CPUS
|
||||
depends on SMP
|
||||
default "4096" if MAXSMP
|
||||
default "32" if X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000
|
||||
+ default "16" if X86_64_XEN
|
||||
default "8"
|
||||
help
|
||||
This allows you to specify the maximum number of CPUs which this
|
||||
@@ -648,7 +680,7 @@ config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
|
||||
|
||||
config X86_UP_APIC
|
||||
bool "Local APIC support on uniprocessors"
|
||||
- depends on X86_32 && !SMP && !(X86_VOYAGER || X86_GENERICARCH)
|
||||
+ depends on X86_32 && !SMP && !(X86_VOYAGER || X86_GENERICARCH || XEN_UNPRIVILEGED_GUEST)
|
||||
help
|
||||
A local APIC (Advanced Programmable Interrupt Controller) is an
|
||||
integrated interrupt controller in the CPU. If you have a single-CPU
|
||||
@@ -674,18 +706,25 @@ config X86_UP_IOAPIC
|
||||
config X86_LOCAL_APIC
|
||||
def_bool y
|
||||
depends on X86_64 || (X86_32 && (X86_UP_APIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
|
||||
+ depends on !XEN_UNPRIVILEGED_GUEST
|
||||
|
||||
config X86_IO_APIC
|
||||
def_bool y
|
||||
depends on X86_64 || (X86_32 && (X86_UP_IOAPIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
|
||||
+ depends on !XEN_UNPRIVILEGED_GUEST
|
||||
|
||||
config X86_VISWS_APIC
|
||||
def_bool y
|
||||
depends on X86_32 && X86_VISWS
|
||||
|
||||
+config X86_XEN_GENAPIC
|
||||
+ bool
|
||||
+ depends on X86_64_XEN
|
||||
+ default y
|
||||
+
|
||||
config X86_MCE
|
||||
bool "Machine Check Exception"
|
||||
- depends on !X86_VOYAGER
|
||||
+ depends on !(X86_VOYAGER || XEN)
|
||||
---help---
|
||||
Machine Check Exception support allows the processor to notify the
|
||||
kernel if it detects a problem (e.g. overheating, component failure).
|
||||
@@ -785,7 +824,7 @@ config I8K
|
||||
config X86_REBOOTFIXUPS
|
||||
def_bool n
|
||||
prompt "Enable X86 board specific fixups for reboot"
|
||||
- depends on X86_32 && X86
|
||||
+ depends on X86_32 && !X86_XEN
|
||||
---help---
|
||||
This enables chipset and/or board specific fixups to be done
|
||||
in order to get reboot to work correctly. This is only needed on
|
||||
@@ -802,6 +841,7 @@ config X86_REBOOTFIXUPS
|
||||
|
||||
config MICROCODE
|
||||
tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
|
||||
+ depends on !XEN_UNPRIVILEGED_GUEST
|
||||
select FW_LOADER
|
||||
---help---
|
||||
If you say Y here, you will be able to update the microcode on
|
||||
@@ -969,7 +1009,7 @@ config DIRECT_GBPAGES
|
||||
# Common NUMA Features
|
||||
config NUMA
|
||||
bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)"
|
||||
- depends on SMP
|
||||
+ depends on SMP && !XEN
|
||||
depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL)
|
||||
default n if X86_PC
|
||||
default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
|
||||
@@ -1071,7 +1111,7 @@ config ARCH_SPARSEMEM_DEFAULT
|
||||
|
||||
config ARCH_SPARSEMEM_ENABLE
|
||||
def_bool y
|
||||
- depends on X86_64 || NUMA || (EXPERIMENTAL && X86_PC)
|
||||
+ depends on (X86_64 && !X86_64_XEN) || NUMA || (EXPERIMENTAL && X86_PC)
|
||||
select SPARSEMEM_STATIC if X86_32
|
||||
select SPARSEMEM_VMEMMAP_ENABLE if X86_64
|
||||
|
||||
@@ -1117,6 +1157,7 @@ config X86_RESERVE_LOW_64K
|
||||
config MATH_EMULATION
|
||||
bool
|
||||
prompt "Math emulation" if X86_32
|
||||
+ depends on !X86_XEN
|
||||
---help---
|
||||
Linux can emulate a math coprocessor (used for floating point
|
||||
operations) if you don't have one. 486DX and Pentium processors have
|
||||
@@ -1142,6 +1183,7 @@ config MATH_EMULATION
|
||||
|
||||
config MTRR
|
||||
bool "MTRR (Memory Type Range Register) support"
|
||||
+ depends on !XEN_UNPRIVILEGED_GUEST
|
||||
---help---
|
||||
On Intel P6 family processors (Pentium Pro, Pentium II and later)
|
||||
the Memory Type Range Registers (MTRRs) may be used to control
|
||||
@@ -1223,7 +1265,7 @@ config X86_PAT
|
||||
config EFI
|
||||
def_bool n
|
||||
prompt "EFI runtime service support"
|
||||
- depends on ACPI
|
||||
+ depends on ACPI && !X86_XEN && !X86_64_XEN
|
||||
---help---
|
||||
This enables the kernel to use EFI runtime services that are
|
||||
available (such as the EFI variable services).
|
||||
@@ -1238,7 +1280,7 @@ config EFI
|
||||
config IRQBALANCE
|
||||
def_bool y
|
||||
prompt "Enable kernel irq balancing"
|
||||
- depends on X86_32 && SMP && X86_IO_APIC
|
||||
+ depends on X86_32 && SMP && X86_IO_APIC && !X86_XEN
|
||||
help
|
||||
The default yes will allow the kernel to do irq load balancing.
|
||||
Saying no will keep the kernel from doing irq load balancing.
|
||||
@@ -1301,6 +1343,7 @@ source kernel/Kconfig.hz
|
||||
config KEXEC
|
||||
bool "kexec system call"
|
||||
depends on X86_BIOS_REBOOT
|
||||
+ depends on !XEN_UNPRIVILEGED_GUEST
|
||||
help
|
||||
kexec is a system call that implements the ability to shutdown your
|
||||
current kernel, and to start another kernel. It is like a reboot
|
||||
@@ -1318,6 +1361,7 @@ config KEXEC
|
||||
config CRASH_DUMP
|
||||
bool "kernel crash dumps"
|
||||
depends on X86_64 || (X86_32 && HIGHMEM)
|
||||
+ depends on !XEN
|
||||
help
|
||||
Generate crash dump after being started by kexec.
|
||||
This should be normally only set in special crash dump kernels
|
||||
@@ -1436,6 +1480,7 @@ config COMPAT_VDSO
|
||||
def_bool y
|
||||
prompt "Compat VDSO support"
|
||||
depends on X86_32 || IA32_EMULATION
|
||||
+ depends on !X86_XEN
|
||||
help
|
||||
Map the 32-bit VDSO to the predictable old-style address too.
|
||||
---help---
|
||||
@@ -1458,7 +1503,7 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
|
||||
depends on NUMA
|
||||
|
||||
menu "Power management options"
|
||||
- depends on !X86_VOYAGER
|
||||
+ depends on !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)
|
||||
|
||||
config ARCH_HIBERNATION_HEADER
|
||||
def_bool y
|
||||
@@ -1475,7 +1520,7 @@ config X86_APM_BOOT
|
||||
|
||||
menuconfig APM
|
||||
tristate "APM (Advanced Power Management) BIOS support"
|
||||
- depends on X86_32 && PM_SLEEP
|
||||
+ depends on X86_32 && PM_SLEEP && !XEN
|
||||
---help---
|
||||
APM is a BIOS specification for saving power using several different
|
||||
techniques. This is mostly useful for battery powered laptops with
|
||||
@@ -1641,6 +1686,7 @@ choice
|
||||
|
||||
config PCI_GOBIOS
|
||||
bool "BIOS"
|
||||
+ depends on !X86_XEN
|
||||
|
||||
config PCI_GOMMCONFIG
|
||||
bool "MMConfig"
|
||||
@@ -1652,6 +1698,13 @@ config PCI_GOOLPC
|
||||
bool "OLPC"
|
||||
depends on OLPC
|
||||
|
||||
+config PCI_GOXEN_FE
|
||||
+ bool "Xen PCI Frontend"
|
||||
+ depends on X86_XEN
|
||||
+ help
|
||||
+ The PCI device frontend driver allows the kernel to import arbitrary
|
||||
+ PCI devices from a PCI backend to support PCI driver domains.
|
||||
+
|
||||
config PCI_GOANY
|
||||
bool "Any"
|
||||
|
||||
@@ -1659,7 +1712,7 @@ endchoice
|
||||
|
||||
config PCI_BIOS
|
||||
def_bool y
|
||||
- depends on X86_32 && PCI && (PCI_GOBIOS || PCI_GOANY)
|
||||
+ depends on X86_32 && PCI && !XEN && (PCI_GOBIOS || PCI_GOANY)
|
||||
|
||||
# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
|
||||
config PCI_DIRECT
|
||||
@@ -1682,6 +1735,22 @@ config PCI_MMCONFIG
|
||||
bool "Support mmconfig PCI config space access"
|
||||
depends on X86_64 && PCI && ACPI
|
||||
|
||||
+config XEN_PCIDEV_FRONTEND
|
||||
+ bool "Xen PCI Frontend" if X86_64
|
||||
+ depends on PCI && ((X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)) || X86_64_XEN)
|
||||
+ select HOTPLUG
|
||||
+ default y
|
||||
+ help
|
||||
+ The PCI device frontend driver allows the kernel to import arbitrary
|
||||
+ PCI devices from a PCI backend to support PCI driver domains.
|
||||
+
|
||||
+config XEN_PCIDEV_FE_DEBUG
|
||||
+ bool "Xen PCI Frontend Debugging"
|
||||
+ depends on XEN_PCIDEV_FRONTEND
|
||||
+ default n
|
||||
+ help
|
||||
+ Enables some debug statements within the PCI Frontend.
|
||||
+
|
||||
config DMAR
|
||||
bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
|
||||
depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL
|
||||
@@ -1732,7 +1801,7 @@ if X86_32
|
||||
|
||||
config ISA
|
||||
bool "ISA support"
|
||||
- depends on !X86_VOYAGER
|
||||
+ depends on !X86_VOYAGER && !XEN
|
||||
help
|
||||
Find out whether you have ISA slots on your motherboard. ISA is the
|
||||
name of a bus system, i.e. the way the CPU talks to the other stuff
|
||||
@@ -1759,7 +1828,7 @@ config EISA
|
||||
source "drivers/eisa/Kconfig"
|
||||
|
||||
config MCA
|
||||
- bool "MCA support" if !X86_VOYAGER
|
||||
+ bool "MCA support" if !X86_VOYAGER && !XEN
|
||||
default y if X86_VOYAGER
|
||||
help
|
||||
MicroChannel Architecture is found in some IBM PS/2 machines and
|
||||
@@ -1871,4 +1940,6 @@ source "crypto/Kconfig"
|
||||
|
||||
source "arch/x86/kvm/Kconfig"
|
||||
|
||||
+source "drivers/xen/Kconfig"
|
||||
+
|
||||
source "lib/Kconfig"
|
||||
Index: head-2008-11-25/arch/x86/Kconfig.cpu
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/Kconfig.cpu 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/Kconfig.cpu 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -340,7 +340,7 @@ config X86_PPRO_FENCE
|
||||
|
||||
config X86_F00F_BUG
|
||||
def_bool y
|
||||
- depends on M586MMX || M586TSC || M586 || M486 || M386
|
||||
+ depends on (M586MMX || M586TSC || M586 || M486 || M386) && !X86_NO_IDT
|
||||
|
||||
config X86_WP_WORKS_OK
|
||||
def_bool y
|
||||
@@ -397,6 +397,7 @@ config X86_P6_NOP
|
||||
config X86_TSC
|
||||
def_bool y
|
||||
depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
|
||||
+ depends on !XEN
|
||||
|
||||
config X86_CMPXCHG64
|
||||
def_bool y
|
||||
Index: head-2008-11-25/arch/x86/Kconfig.debug
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/Kconfig.debug 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/Kconfig.debug 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -130,7 +130,7 @@ config 4KSTACKS
|
||||
config DOUBLEFAULT
|
||||
default y
|
||||
bool "Enable doublefault exception handler" if EMBEDDED
|
||||
- depends on X86_32
|
||||
+ depends on X86_32 && !X86_NO_TSS
|
||||
help
|
||||
This option allows trapping of rare doublefault exceptions that
|
||||
would otherwise cause a system to silently reboot. Disabling this
|
||||
Index: head-2008-11-25/drivers/acpi/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/acpi/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/acpi/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -362,6 +362,7 @@ config ACPI_SYSTEM
|
||||
config X86_PM_TIMER
|
||||
bool "Power Management Timer Support" if EMBEDDED
|
||||
depends on X86
|
||||
+ depends on !XEN
|
||||
default y
|
||||
help
|
||||
The Power Management Timer is available on all ACPI-capable,
|
||||
@@ -415,4 +416,13 @@ config ACPI_SBS
|
||||
This driver adds support for the Smart Battery System, another
|
||||
type of access to battery information, found on some laptops.
|
||||
|
||||
+config ACPI_PV_SLEEP
|
||||
+ bool
|
||||
+ depends on X86 && XEN && ACPI_SLEEP
|
||||
+ default y
|
||||
+
|
||||
+config PROCESSOR_EXTERNAL_CONTROL
|
||||
+ bool
|
||||
+ depends on (X86 || IA64) && XEN
|
||||
+ default y
|
||||
endif # ACPI
|
||||
Index: head-2008-11-25/drivers/char/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/char/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/char/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -1037,7 +1037,7 @@ config MAX_RAW_DEVS
|
||||
config HPET
|
||||
bool "HPET - High Precision Event Timer" if (X86 || IA64)
|
||||
default n
|
||||
- depends on ACPI
|
||||
+ depends on ACPI && !XEN
|
||||
help
|
||||
If you say Y here, you will have a miscdevice named "/dev/hpet/". Each
|
||||
open selects one of the timers supported by the HPET. The timers are
|
||||
Index: head-2008-11-25/drivers/char/tpm/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/char/tpm/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/char/tpm/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -57,4 +57,13 @@ config TCG_INFINEON
|
||||
Further information on this driver and the supported hardware
|
||||
can be found at http://www.prosec.rub.de/tpm
|
||||
|
||||
+config TCG_XEN
|
||||
+ tristate "XEN TPM Interface"
|
||||
+ depends on XEN
|
||||
+ ---help---
|
||||
+ If you want to make TPM support available to a Xen user domain,
|
||||
+ say Yes and it will be accessible from within Linux.
|
||||
+ To compile this driver as a module, choose M here; the module
|
||||
+ will be called tpm_xenu.
|
||||
+
|
||||
endif # TCG_TPM
|
||||
Index: head-2008-11-25/drivers/cpufreq/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/cpufreq/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/cpufreq/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -1,5 +1,6 @@
|
||||
config CPU_FREQ
|
||||
bool "CPU Frequency scaling"
|
||||
+ depends on !PROCESSOR_EXTERNAL_CONTROL
|
||||
help
|
||||
CPU Frequency scaling allows you to change the clock speed of
|
||||
CPUs on the fly. This is a nice method to save power, because
|
||||
Index: head-2008-11-25/drivers/pci/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/pci/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/pci/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -21,6 +21,9 @@ config PCI_MSI
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
+config PCI_REASSIGN
|
||||
+ bool
|
||||
+
|
||||
config PCI_LEGACY
|
||||
bool "Enable deprecated pci_find_* API"
|
||||
depends on PCI
|
||||
Index: head-2008-11-25/drivers/serial/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/serial/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/serial/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -10,6 +10,7 @@ menu "Serial drivers"
|
||||
config SERIAL_8250
|
||||
tristate "8250/16550 and compatible serial support"
|
||||
depends on (BROKEN || !SPARC)
|
||||
+ depends on !XEN_DISABLE_SERIAL
|
||||
select SERIAL_CORE
|
||||
---help---
|
||||
This selects whether you want to include the driver for the standard
|
||||
Index: head-2008-11-25/drivers/video/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/video/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/video/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -1601,7 +1601,7 @@ config FB_CYBLA
|
||||
tristate "Cyberblade/i1 support"
|
||||
depends on FB && PCI && X86_32 && !64BIT
|
||||
select FB_CFB_IMAGEBLIT
|
||||
- select VIDEO_SELECT
|
||||
+ select VIDEO_SELECT if !XEN
|
||||
---help---
|
||||
This driver is supposed to support the Trident Cyberblade/i1
|
||||
graphics core integrated in the VIA VT8601A North Bridge,
|
||||
Index: head-2008-11-25/drivers/video/console/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/video/console/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/video/console/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -46,6 +46,7 @@ config VGACON_SOFT_SCROLLBACK_SIZE
|
||||
config VIDEO_SELECT
|
||||
bool "Video mode selection support"
|
||||
depends on X86 && VGA_CONSOLE
|
||||
+ depends on !XEN
|
||||
---help---
|
||||
This enables support for text mode selection on kernel startup. If
|
||||
you want to take advantage of some high-resolution text mode your
|
||||
Index: head-2008-11-25/drivers/xen/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/drivers/xen/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/drivers/xen/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -1,6 +1,307 @@
|
||||
+#
|
||||
+# This Kconfig describe xen options
|
||||
+#
|
||||
+
|
||||
+mainmenu "Xen Configuration"
|
||||
+
|
||||
+config XEN
|
||||
+ bool
|
||||
+
|
||||
+if XEN
|
||||
+config XEN_INTERFACE_VERSION
|
||||
+ hex
|
||||
+ default 0x00030207
|
||||
+
|
||||
+menu "XEN"
|
||||
+
|
||||
+config XEN_PRIVILEGED_GUEST
|
||||
+ bool "Privileged Guest (domain 0)"
|
||||
+ select PCI_REASSIGN if PCI
|
||||
+ help
|
||||
+ Support for privileged operation (domain 0)
|
||||
+
|
||||
+config XEN_UNPRIVILEGED_GUEST
|
||||
+ def_bool !XEN_PRIVILEGED_GUEST
|
||||
+
|
||||
+config XEN_PRIVCMD
|
||||
+ def_bool y
|
||||
+ depends on PROC_FS
|
||||
+
|
||||
+config XEN_XENBUS_DEV
|
||||
+ def_bool y
|
||||
+ depends on PROC_FS
|
||||
+
|
||||
+config XEN_NETDEV_ACCEL_SFC_UTIL
|
||||
+ depends on X86
|
||||
+ tristate
|
||||
+
|
||||
+config XEN_BACKEND
|
||||
+ tristate "Backend driver support"
|
||||
+ default XEN_PRIVILEGED_GUEST
|
||||
+ help
|
||||
+ Support for backend device drivers that provide I/O services
|
||||
+ to other virtual machines.
|
||||
+
|
||||
+config XEN_BLKDEV_BACKEND
|
||||
+ tristate "Block-device backend driver"
|
||||
+ depends on XEN_BACKEND
|
||||
+ default XEN_BACKEND
|
||||
+ help
|
||||
+ The block-device backend driver allows the kernel to export its
|
||||
+ block devices to other guests via a high-performance shared-memory
|
||||
+ interface.
|
||||
+
|
||||
+config XEN_BLKDEV_TAP
|
||||
+ tristate "Block-device tap backend driver"
|
||||
+ depends on XEN_BACKEND
|
||||
+ default XEN_BACKEND
|
||||
+ help
|
||||
+ The block tap driver is an alternative to the block back driver
|
||||
+ and allows VM block requests to be redirected to userspace through
|
||||
+ a device interface. The tap allows user-space development of
|
||||
+ high-performance block backends, where disk images may be implemented
|
||||
+ as files, in memory, or on other hosts across the network. This
|
||||
+ driver can safely coexist with the existing blockback driver.
|
||||
+
|
||||
+config XEN_NETDEV_BACKEND
|
||||
+ tristate "Network-device backend driver"
|
||||
+ depends on XEN_BACKEND && NET
|
||||
+ default XEN_BACKEND
|
||||
+ help
|
||||
+ The network-device backend driver allows the kernel to export its
|
||||
+ network devices to other guests via a high-performance shared-memory
|
||||
+ interface.
|
||||
+
|
||||
+config XEN_NETDEV_PIPELINED_TRANSMITTER
|
||||
+ bool "Pipelined transmitter (DANGEROUS)"
|
||||
+ depends on XEN_NETDEV_BACKEND
|
||||
+ help
|
||||
+ If the net backend is a dumb domain, such as a transparent Ethernet
|
||||
+ bridge with no local IP interface, it is safe to say Y here to get
|
||||
+ slightly lower network overhead.
|
||||
+ If the backend has a local IP interface; or may be doing smart things
|
||||
+ like reassembling packets to perform firewall filtering; or if you
|
||||
+ are unsure; or if you experience network hangs when this option is
|
||||
+ enabled; then you must say N here.
|
||||
+
|
||||
+config XEN_NETDEV_ACCEL_SFC_BACKEND
|
||||
+ tristate "Network-device backend driver acceleration for Solarflare NICs"
|
||||
+ depends on XEN_NETDEV_BACKEND && SFC && SFC_RESOURCE && X86
|
||||
+ select XEN_NETDEV_ACCEL_SFC_UTIL
|
||||
+ default m
|
||||
+
|
||||
+config XEN_NETDEV_LOOPBACK
|
||||
+ tristate "Network-device loopback driver"
|
||||
+ depends on XEN_NETDEV_BACKEND
|
||||
+ help
|
||||
+ A two-interface loopback device to emulate a local netfront-netback
|
||||
+ connection. If unsure, it is probably safe to say N here.
|
||||
+
|
||||
+config XEN_PCIDEV_BACKEND
|
||||
+ tristate "PCI-device backend driver"
|
||||
+ depends on PCI && XEN_BACKEND
|
||||
+ default XEN_BACKEND
|
||||
+ help
|
||||
+ The PCI device backend driver allows the kernel to export arbitrary
|
||||
+ PCI devices to other guests. If you select this to be a module, you
|
||||
+ will need to make sure no other driver has bound to the device(s)
|
||||
+ you want to make visible to other guests.
|
||||
+
|
||||
+choice
|
||||
+ prompt "PCI Backend Mode"
|
||||
+ depends on XEN_PCIDEV_BACKEND
|
||||
+ default XEN_PCIDEV_BACKEND_VPCI if !IA64
|
||||
+ default XEN_PCIDEV_BACKEND_CONTROLLER if IA64
|
||||
+
|
||||
+config XEN_PCIDEV_BACKEND_VPCI
|
||||
+ bool "Virtual PCI"
|
||||
+ ---help---
|
||||
+ This PCI Backend hides the true PCI topology and makes the frontend
|
||||
+ think there is a single PCI bus with only the exported devices on it.
|
||||
+ For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
|
||||
+ second device at 02:1a.1 will be re-assigned to 00:01.1.
|
||||
+
|
||||
+config XEN_PCIDEV_BACKEND_PASS
|
||||
+ bool "Passthrough"
|
||||
+ ---help---
|
||||
+ This PCI Backend provides a real view of the PCI topology to the
|
||||
+ frontend (for example, a device at 06:01.b will still appear at
|
||||
+ 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
|
||||
+ PCI devices to its driver domains. This may be required for drivers
|
||||
+ which depend on finding their hardward in certain bus/slot
|
||||
+ locations.
|
||||
+
|
||||
+config XEN_PCIDEV_BACKEND_SLOT
|
||||
+ bool "Slot"
|
||||
+ ---help---
|
||||
+ This PCI Backend hides the true PCI topology and makes the frontend
|
||||
+ think there is a single PCI bus with only the exported devices on it.
|
||||
+ Contrary to the virtual PCI backend, a function becomes a new slot.
|
||||
+ For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
|
||||
+ second device at 02:1a.1 will be re-assigned to 00:01.0.
|
||||
+
|
||||
+config XEN_PCIDEV_BACKEND_CONTROLLER
|
||||
+ bool "Controller"
|
||||
+ depends on IA64
|
||||
+ ---help---
|
||||
+ This PCI backend virtualizes the PCI bus topology by providing a
|
||||
+ virtual bus per PCI root device. Devices which are physically under
|
||||
+ the same root bus will appear on the same virtual bus. For systems
|
||||
+ with complex I/O addressing, this is the only backend which supports
|
||||
+ extended I/O port spaces and MMIO translation offsets. This backend
|
||||
+ also supports slot virtualization. For example, a device at
|
||||
+ 0000:01:02.1 will be re-assigned to 0000:00:00.0. A second device
|
||||
+ at 0000:02:05.0 (behind a P2P bridge on bus 0000:01) will be
|
||||
+ re-assigned to 0000:00:01.0. A third device at 0000:16:05.0 (under
|
||||
+ a different PCI root bus) will be re-assigned to 0000:01:00.0.
|
||||
+
|
||||
+endchoice
|
||||
+
|
||||
+config XEN_PCIDEV_BE_DEBUG
|
||||
+ bool "PCI Backend Debugging"
|
||||
+ depends on XEN_PCIDEV_BACKEND
|
||||
+
|
||||
+config XEN_TPMDEV_BACKEND
|
||||
+ tristate "TPM-device backend driver"
|
||||
+ depends on XEN_BACKEND
|
||||
+ help
|
||||
+ The TPM-device backend driver
|
||||
+
|
||||
+config XEN_SCSI_BACKEND
|
||||
+ tristate "SCSI backend driver"
|
||||
+ depends on SCSI && XEN_BACKEND
|
||||
+ default m
|
||||
+ help
|
||||
+ The SCSI backend driver allows the kernel to export its SCSI Devices
|
||||
+ to other guests via a high-performance shared-memory interface.
|
||||
+
|
||||
+config XEN_BLKDEV_FRONTEND
|
||||
+ tristate "Block-device frontend driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ The block-device frontend driver allows the kernel to access block
|
||||
+ devices mounted within another guest OS. Unless you are building a
|
||||
+ dedicated device-driver domain, or your master control domain
|
||||
+ (domain 0), then you almost certainly want to say Y here.
|
||||
+
|
||||
+config XEN_NETDEV_FRONTEND
|
||||
+ tristate "Network-device frontend driver"
|
||||
+ depends on NET
|
||||
+ default y
|
||||
+ help
|
||||
+ The network-device frontend driver allows the kernel to access
|
||||
+ network interfaces within another guest OS. Unless you are building a
|
||||
+ dedicated device-driver domain, or your master control domain
|
||||
+ (domain 0), then you almost certainly want to say Y here.
|
||||
+
|
||||
+config XEN_NETDEV_ACCEL_SFC_FRONTEND
|
||||
+ tristate "Network-device frontend driver acceleration for Solarflare NICs"
|
||||
+ depends on XEN_NETDEV_FRONTEND && X86
|
||||
+ select XEN_NETDEV_ACCEL_SFC_UTIL
|
||||
+ default m
|
||||
+
|
||||
+config XEN_SCSI_FRONTEND
|
||||
+ tristate "SCSI frontend driver"
|
||||
+ depends on SCSI
|
||||
+ default m
|
||||
+ help
|
||||
+ The SCSI frontend driver allows the kernel to access SCSI Devices
|
||||
+ within another guest OS.
|
||||
+
|
||||
+config XEN_GRANT_DEV
|
||||
+ tristate "User-space granted page access driver"
|
||||
+ default XEN_PRIVILEGED_GUEST
|
||||
+ help
|
||||
+ Device for accessing (in user-space) pages that have been granted
|
||||
+ by other domains.
|
||||
+
|
||||
+config XEN_FRAMEBUFFER
|
||||
+ tristate "Framebuffer-device frontend driver"
|
||||
+ depends on FB
|
||||
+ select FB_CFB_FILLRECT
|
||||
+ select FB_CFB_COPYAREA
|
||||
+ select FB_CFB_IMAGEBLIT
|
||||
+ default y
|
||||
+ help
|
||||
+ The framebuffer-device frontend drivers allows the kernel to create a
|
||||
+ virtual framebuffer. This framebuffer can be viewed in another
|
||||
+ domain. Unless this domain has access to a real video card, you
|
||||
+ probably want to say Y here.
|
||||
+
|
||||
+config XEN_KEYBOARD
|
||||
+ tristate "Keyboard-device frontend driver"
|
||||
+ depends on XEN_FRAMEBUFFER && INPUT
|
||||
+ default y
|
||||
+ help
|
||||
+ The keyboard-device frontend driver allows the kernel to create a
|
||||
+ virtual keyboard. This keyboard can then be driven by another
|
||||
+ domain. If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
|
||||
+ want to say Y here.
|
||||
+
|
||||
+config XEN_DISABLE_SERIAL
|
||||
+ bool "Disable serial port drivers"
|
||||
+ default y
|
||||
+ help
|
||||
+ Disable serial port drivers, allowing the Xen console driver
|
||||
+ to provide a serial console at ttyS0.
|
||||
+
|
||||
+config XEN_SYSFS
|
||||
+ tristate "Export Xen attributes in sysfs"
|
||||
+ depends on SYSFS
|
||||
+ select SYS_HYPERVISOR
|
||||
+ default y
|
||||
+ help
|
||||
+ Xen hypervisor attributes will show up under /sys/hypervisor/.
|
||||
+
|
||||
+choice
|
||||
+ prompt "Xen version compatibility"
|
||||
+ default XEN_COMPAT_030002_AND_LATER
|
||||
+
|
||||
+ config XEN_COMPAT_030002_AND_LATER
|
||||
+ bool "3.0.2 and later"
|
||||
+
|
||||
+ config XEN_COMPAT_030004_AND_LATER
|
||||
+ bool "3.0.4 and later"
|
||||
+
|
||||
+ config XEN_COMPAT_030100_AND_LATER
|
||||
+ bool "3.1.0 and later"
|
||||
+
|
||||
+ config XEN_COMPAT_LATEST_ONLY
|
||||
+ bool "no compatibility code"
|
||||
+
|
||||
+endchoice
|
||||
+
|
||||
+config XEN_COMPAT
|
||||
+ hex
|
||||
+ default 0xffffff if XEN_COMPAT_LATEST_ONLY
|
||||
+ default 0x030100 if XEN_COMPAT_030100_AND_LATER
|
||||
+ default 0x030004 if XEN_COMPAT_030004_AND_LATER
|
||||
+ default 0x030002 if XEN_COMPAT_030002_AND_LATER
|
||||
+ default 0
|
||||
+
|
||||
+endmenu
|
||||
+
|
||||
+config HAVE_IRQ_IGNORE_UNHANDLED
|
||||
+ def_bool y
|
||||
+
|
||||
+config NO_IDLE_HZ
|
||||
+ def_bool y
|
||||
+
|
||||
+config XEN_SMPBOOT
|
||||
+ def_bool y
|
||||
+ depends on SMP && !PPC_XEN
|
||||
+
|
||||
+config XEN_XENCOMM
|
||||
+ bool
|
||||
+
|
||||
+config XEN_DEVMEM
|
||||
+ def_bool y
|
||||
+
|
||||
+endif
|
||||
+
|
||||
config XEN_BALLOON
|
||||
- bool "Xen memory balloon driver"
|
||||
- depends on XEN
|
||||
+ bool "Xen memory balloon driver" if PARAVIRT_XEN
|
||||
+ depends on (XEN && !PPC_XEN) || PARAVIRT_XEN
|
||||
default y
|
||||
help
|
||||
The balloon driver allows the Xen domain to request more memory from
|
||||
@@ -8,12 +309,14 @@ config XEN_BALLOON
|
||||
return unneeded memory to the system.
|
||||
|
||||
config XEN_SCRUB_PAGES
|
||||
- bool "Scrub pages before returning them to system"
|
||||
- depends on XEN_BALLOON
|
||||
+ bool "Scrub memory before freeing it to Xen"
|
||||
+ depends on XEN || XEN_BALLOON
|
||||
default y
|
||||
help
|
||||
- Scrub pages before returning them to the system for reuse by
|
||||
- other domains. This makes sure that any confidential data
|
||||
- is not accidentally visible to other domains. Is it more
|
||||
- secure, but slightly less efficient.
|
||||
+ Erase memory contents before freeing it back to Xen's global
|
||||
+ pool. This ensures that any secrets contained within that
|
||||
+ memory (e.g., private keys) cannot be found by other guests that
|
||||
+ may be running on the machine. Most people will want to say Y here.
|
||||
+ If security is not a concern then you may increase performance by
|
||||
+ saying N.
|
||||
If in doubt, say yes.
|
||||
Index: head-2008-11-25/fs/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/fs/Kconfig 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/fs/Kconfig 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -1011,6 +1011,7 @@ config HUGETLBFS
|
||||
bool "HugeTLB file system support"
|
||||
depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \
|
||||
(S390 && 64BIT) || BROKEN
|
||||
+ depends on !XEN
|
||||
help
|
||||
hugetlbfs is a filesystem backing for HugeTLB pages, based on
|
||||
ramfs. For architectures that support it, say Y here and read
|
||||
Index: head-2008-11-25/kernel/Kconfig.preempt
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/kernel/Kconfig.preempt 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/kernel/Kconfig.preempt 2008-11-10 11:49:15.000000000 +0100
|
||||
@@ -35,6 +35,7 @@ config PREEMPT_VOLUNTARY
|
||||
|
||||
config PREEMPT
|
||||
bool "Preemptible Kernel (Low-Latency Desktop)"
|
||||
+ depends on !XEN
|
||||
help
|
||||
This option reduces the latency of the kernel by making
|
||||
all kernel code (that is not executing in a critical section)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,357 +0,0 @@
|
||||
Subject: xen3 arch-x86
|
||||
From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 728:832aac894efd)
|
||||
Patch-mainline: obsolete
|
||||
Acked-by: jbeulich@novell.com
|
||||
|
||||
Index: head-2008-12-01/arch/x86/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -115,6 +115,10 @@ mcore-y := arch/x86/mach-default/
|
||||
mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-x86/mach-voyager
|
||||
mcore-$(CONFIG_X86_VOYAGER) := arch/x86/mach-voyager/
|
||||
|
||||
+# Xen subarch support
|
||||
+mflags-$(CONFIG_X86_XEN) := -Iinclude/asm-x86/mach-xen
|
||||
+mcore-$(CONFIG_X86_XEN) := arch/x86/mach-xen/
|
||||
+
|
||||
# generic subarchitecture
|
||||
mflags-$(CONFIG_X86_GENERICARCH):= -Iinclude/asm-x86/mach-generic
|
||||
fcore-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/
|
||||
@@ -183,9 +187,26 @@ drivers-$(CONFIG_KDB) += arch/x86/kdb/
|
||||
|
||||
boot := arch/x86/boot
|
||||
|
||||
-PHONY += zImage bzImage compressed zlilo bzlilo \
|
||||
+PHONY += zImage bzImage vmlinuz compressed zlilo bzlilo \
|
||||
zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
|
||||
|
||||
+ifdef CONFIG_XEN
|
||||
+CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \
|
||||
+ -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
|
||||
+
|
||||
+ifdef CONFIG_X86_64
|
||||
+LDFLAGS_vmlinux := -e startup_64
|
||||
+endif
|
||||
+
|
||||
+# Default kernel to build
|
||||
+all: vmlinuz
|
||||
+
|
||||
+# KBUILD_IMAGE specifies the target image being built
|
||||
+KBUILD_IMAGE := $(boot)/vmlinuz
|
||||
+
|
||||
+vmlinuz: vmlinux
|
||||
+ $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
|
||||
+else
|
||||
# Default kernel to build
|
||||
all: bzImage
|
||||
|
||||
@@ -208,6 +229,7 @@ zdisk bzdisk: vmlinux
|
||||
|
||||
fdimage fdimage144 fdimage288 isoimage: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
|
||||
+endif
|
||||
|
||||
install:
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
|
||||
Index: head-2008-12-01/arch/x86/boot/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/boot/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/boot/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -25,7 +25,7 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
|
||||
|
||||
#RAMDISK := -DRAMDISK=512
|
||||
|
||||
-targets := vmlinux.bin setup.bin setup.elf zImage bzImage
|
||||
+targets := vmlinux.bin setup.bin setup.elf zImage bzImage vmlinuz vmlinux-stripped
|
||||
subdir- := compressed
|
||||
|
||||
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
|
||||
@@ -190,5 +190,13 @@ zlilo: $(BOOTIMAGE)
|
||||
cp System.map $(INSTALL_PATH)/
|
||||
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
|
||||
|
||||
+$(obj)/vmlinuz: $(obj)/vmlinux-stripped FORCE
|
||||
+ $(call if_changed,gzip)
|
||||
+ @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
||||
+
|
||||
+$(obj)/vmlinux-stripped: OBJCOPYFLAGS := -g --strip-unneeded
|
||||
+$(obj)/vmlinux-stripped: vmlinux FORCE
|
||||
+ $(call if_changed,objcopy)
|
||||
+
|
||||
install:
|
||||
sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
|
||||
Index: head-2008-12-01/arch/x86/kernel/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/Makefile 2008-12-01 11:14:33.000000000 +0100
|
||||
@@ -99,10 +99,13 @@ scx200-y += scx200_32.o
|
||||
|
||||
obj-$(CONFIG_OLPC) += olpc.o
|
||||
|
||||
+obj-$(CONFIG_X86_XEN) += fixup.o
|
||||
+
|
||||
###
|
||||
# 64 bit specific files
|
||||
ifeq ($(CONFIG_X86_64),y)
|
||||
obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o
|
||||
+ obj-$(CONFIG_X86_XEN_GENAPIC) += genapic_xen_64.o
|
||||
obj-y += bios_uv.o
|
||||
obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o
|
||||
obj-$(CONFIG_AUDIT) += audit_64.o
|
||||
@@ -116,4 +119,10 @@ ifeq ($(CONFIG_X86_64),y)
|
||||
obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o
|
||||
|
||||
obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o
|
||||
+
|
||||
+ time_64-$(CONFIG_XEN) += time_32.o
|
||||
+ pci-dma_64-$(CONFIG_XEN) += pci-dma_32.o
|
||||
endif
|
||||
+
|
||||
+disabled-obj-$(CONFIG_XEN) := i8259_$(BITS).o reboot.o smpboot_$(BITS).o
|
||||
+%/head_$(BITS).o %/head_$(BITS).s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) :=
|
||||
Index: head-2008-12-01/arch/x86/kernel/acpi/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/acpi/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/acpi/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -5,6 +5,9 @@ obj-$(CONFIG_ACPI_SLEEP) += sleep.o wake
|
||||
|
||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||
obj-y += cstate.o processor.o
|
||||
+ifneq ($(CONFIG_PROCESSOR_EXTERNAL_CONTROL),)
|
||||
+obj-$(CONFIG_XEN) += processor_extcntl_xen.o
|
||||
+endif
|
||||
endif
|
||||
|
||||
$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin
|
||||
@@ -12,3 +15,4 @@ $(obj)/wakeup_rm.o: $(obj)/realmode/w
|
||||
$(obj)/realmode/wakeup.bin: FORCE
|
||||
$(Q)$(MAKE) $(build)=$(obj)/realmode
|
||||
|
||||
+disabled-obj-$(CONFIG_XEN) := cstate.o wakeup_$(BITS).o
|
||||
Index: head-2008-12-01/arch/x86/kernel/acpi/boot.c
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/acpi/boot.c 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/acpi/boot.c 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -130,8 +130,10 @@ char *__init __acpi_map_table(unsigned l
|
||||
if (!phys || !size)
|
||||
return NULL;
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
if (phys+size <= (max_low_pfn_mapped << PAGE_SHIFT))
|
||||
return __va(phys);
|
||||
+#endif
|
||||
|
||||
offset = phys & (PAGE_SIZE - 1);
|
||||
mapped_size = PAGE_SIZE - offset;
|
||||
Index: head-2008-12-01/arch/x86/kernel/acpi/processor.c
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/acpi/processor.c 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/acpi/processor.c 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -75,7 +75,18 @@ static void init_intel_pdc(struct acpi_p
|
||||
/* Initialize _PDC data based on the CPU vendor */
|
||||
void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
|
||||
{
|
||||
+#ifdef CONFIG_XEN
|
||||
+ /*
|
||||
+ * As a work-around, just use cpu0's cpuinfo for all processors.
|
||||
+ * Further work is required to expose xen hypervisor interface of
|
||||
+ * getting physical cpuinfo to dom0 kernel and then
|
||||
+ * arch_acpi_processor_init_pdc can set _PDC parameters according
|
||||
+ * to Xen's phys information.
|
||||
+ */
|
||||
+ struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
+#else
|
||||
struct cpuinfo_x86 *c = &cpu_data(pr->id);
|
||||
+#endif
|
||||
|
||||
pr->pdc = NULL;
|
||||
if (c->x86_vendor == X86_VENDOR_INTEL)
|
||||
Index: head-2008-12-01/arch/x86/kernel/cpu/mtrr/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/cpu/mtrr/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/cpu/mtrr/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-y := main.o if.o generic.o state.o
|
||||
obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o
|
||||
|
||||
+obj-$(CONFIG_XEN) := main.o if.o
|
||||
Index: head-2008-12-01/arch/x86/kernel/crash.c
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/kernel/crash.c 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/kernel/crash.c 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -32,6 +32,7 @@
|
||||
/* This keeps a track of which one is crashing cpu. */
|
||||
static int crashing_cpu;
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
|
||||
static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
@@ -190,6 +191,7 @@ static void halt_current_cpu(struct pt_r
|
||||
/* There are no cpus to shootdown */
|
||||
}
|
||||
#endif
|
||||
+#endif /* CONFIG_XEN */
|
||||
|
||||
void native_machine_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
@@ -206,11 +208,13 @@ void native_machine_crash_shutdown(struc
|
||||
|
||||
/* Make a note of crashing cpu. Will be used in NMI callback.*/
|
||||
crashing_cpu = safe_smp_processor_id();
|
||||
+#ifndef CONFIG_XEN
|
||||
nmi_shootdown_cpus();
|
||||
lapic_shutdown();
|
||||
#if defined(CONFIG_X86_IO_APIC)
|
||||
disable_IO_APIC();
|
||||
#endif
|
||||
+#endif /* CONFIG_XEN */
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
hpet_disable();
|
||||
#endif
|
||||
Index: head-2008-12-01/arch/x86/lib/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/lib/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/lib/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -25,3 +25,5 @@ else
|
||||
lib-y += memmove_64.o memset_64.o
|
||||
lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o
|
||||
endif
|
||||
+
|
||||
+lib-$(CONFIG_XEN_SCRUB_PAGES) += scrub.o
|
||||
Index: head-2008-12-01/arch/x86/mm/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/mm/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/mm/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -21,4 +21,6 @@ obj-$(CONFIG_K8_NUMA) += k8topology_64.
|
||||
endif
|
||||
obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o
|
||||
|
||||
+obj-$(CONFIG_XEN) += hypervisor.o
|
||||
+
|
||||
obj-$(CONFIG_MEMTEST) += memtest.o
|
||||
Index: head-2008-12-01/arch/x86/oprofile/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/oprofile/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/oprofile/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -6,7 +6,14 @@ DRIVER_OBJS = $(addprefix ../../../drive
|
||||
oprofilefs.o oprofile_stats.o \
|
||||
timer_int.o )
|
||||
|
||||
+ifdef CONFIG_XEN
|
||||
+XENOPROF_COMMON_OBJS = $(addprefix ../../../drivers/xen/xenoprof/, \
|
||||
+ xenoprofile.o)
|
||||
+oprofile-y := $(DRIVER_OBJS) \
|
||||
+ $(XENOPROF_COMMON_OBJS) xenoprof.o
|
||||
+else
|
||||
oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
|
||||
oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
|
||||
op_model_ppro.o op_model_p4.o
|
||||
oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
|
||||
+endif
|
||||
Index: head-2008-12-01/arch/x86/pci/Makefile
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/arch/x86/pci/Makefile 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/arch/x86/pci/Makefile 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -4,6 +4,9 @@ obj-$(CONFIG_PCI_BIOS) += pcbios.o
|
||||
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_$(BITS).o direct.o mmconfig-shared.o
|
||||
obj-$(CONFIG_PCI_DIRECT) += direct.o
|
||||
obj-$(CONFIG_PCI_OLPC) += olpc.o
|
||||
+# pcifront should be after mmconfig.o and direct.o as it should only
|
||||
+# take over if direct access to the PCI bus is unavailable
|
||||
+obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o
|
||||
|
||||
obj-y += fixup.o
|
||||
obj-$(CONFIG_ACPI) += acpi.o
|
||||
Index: head-2008-12-01/include/asm-x86/acpi.h
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/include/asm-x86/acpi.h 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/include/asm-x86/acpi.h 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -30,6 +30,10 @@
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/mpspec.h>
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+#include <xen/interface/platform.h>
|
||||
+#endif
|
||||
+
|
||||
#define COMPILER_DEPENDENT_INT64 long long
|
||||
#define COMPILER_DEPENDENT_UINT64 unsigned long long
|
||||
|
||||
@@ -124,6 +128,27 @@ extern unsigned long acpi_wakeup_address
|
||||
/* early initialization routine */
|
||||
extern void acpi_reserve_bootmem(void);
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+static inline int acpi_notify_hypervisor_state(u8 sleep_state,
|
||||
+ u32 pm1a_cnt_val,
|
||||
+ u32 pm1b_cnt_val)
|
||||
+{
|
||||
+ struct xen_platform_op op = {
|
||||
+ .cmd = XENPF_enter_acpi_sleep,
|
||||
+ .interface_version = XENPF_INTERFACE_VERSION,
|
||||
+ .u = {
|
||||
+ .enter_acpi_sleep = {
|
||||
+ .pm1a_cnt_val = pm1a_cnt_val,
|
||||
+ .pm1b_cnt_val = pm1b_cnt_val,
|
||||
+ .sleep_state = sleep_state,
|
||||
+ },
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ return HYPERVISOR_platform_op(&op);
|
||||
+}
|
||||
+#endif /* CONFIG_XEN */
|
||||
+
|
||||
/*
|
||||
* Check if the CPU can handle C2 and deeper
|
||||
*/
|
||||
@@ -156,7 +181,9 @@ static inline void disable_acpi(void) {
|
||||
|
||||
#endif /* !CONFIG_ACPI */
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
#define ARCH_HAS_POWER_INIT 1
|
||||
+#endif
|
||||
|
||||
struct bootnode;
|
||||
|
||||
Index: head-2008-12-01/include/asm-x86/apic.h
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/include/asm-x86/apic.h 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/include/asm-x86/apic.h 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -12,7 +12,9 @@
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
#define ARCH_APICTIMER_STOPS_ON_C3 1
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
Index: head-2008-12-01/include/asm-x86/kexec.h
|
||||
===================================================================
|
||||
--- head-2008-12-01.orig/include/asm-x86/kexec.h 2008-12-01 10:53:14.000000000 +0100
|
||||
+++ head-2008-12-01/include/asm-x86/kexec.h 2008-12-01 11:11:08.000000000 +0100
|
||||
@@ -170,6 +170,19 @@ relocate_kernel(unsigned long indirectio
|
||||
unsigned long start_address) ATTRIB_NORET;
|
||||
#endif
|
||||
|
||||
+/* Under Xen we need to work with machine addresses. These macros give the
|
||||
+ * machine address of a certain page to the generic kexec code instead of
|
||||
+ * the pseudo physical address which would be given by the default macros.
|
||||
+ */
|
||||
+
|
||||
+#ifdef CONFIG_XEN
|
||||
+#define KEXEC_ARCH_HAS_PAGE_MACROS
|
||||
+#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page))
|
||||
+#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn))
|
||||
+#define kexec_virt_to_phys(addr) virt_to_machine(addr)
|
||||
+#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr))
|
||||
+#endif
|
||||
+
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _KEXEC_H */
|
||||
@@ -1,280 +0,0 @@
|
||||
Subject: xen3 arch-i386
|
||||
From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 728:832aac894efd)
|
||||
Patch-mainline: obsolete
|
||||
Acked-by: jbeulich@novell.com
|
||||
|
||||
Index: head-2008-11-25/arch/x86/kernel/asm-offsets_32.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/asm-offsets_32.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/asm-offsets_32.c 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -91,9 +91,14 @@ void foo(void)
|
||||
OFFSET(pbe_orig_address, pbe, orig_address);
|
||||
OFFSET(pbe_next, pbe, next);
|
||||
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
/* Offset from the sysenter stack to tss.sp0 */
|
||||
- DEFINE(TSS_sysenter_sp0, offsetof(struct tss_struct, x86_tss.sp0) -
|
||||
+ DEFINE(SYSENTER_stack_sp0, offsetof(struct tss_struct, x86_tss.sp0) -
|
||||
sizeof(struct tss_struct));
|
||||
+#else
|
||||
+ /* sysenter stack points directly to sp0 */
|
||||
+ DEFINE(SYSENTER_stack_sp0, 0);
|
||||
+#endif
|
||||
|
||||
DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
|
||||
DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
|
||||
Index: head-2008-11-25/arch/x86/kernel/entry_32.S
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/entry_32.S 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/entry_32.S 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -293,7 +293,7 @@ ENTRY(ia32_sysenter_target)
|
||||
CFI_SIGNAL_FRAME
|
||||
CFI_DEF_CFA esp, 0
|
||||
CFI_REGISTER esp, ebp
|
||||
- movl TSS_sysenter_sp0(%esp),%esp
|
||||
+ movl SYSENTER_stack_sp0(%esp),%esp
|
||||
sysenter_past_esp:
|
||||
/*
|
||||
* Interrupts are disabled here, but we can't trace it until
|
||||
@@ -782,7 +782,7 @@ END(device_not_available)
|
||||
* that sets up the real kernel stack. Check here, since we can't
|
||||
* allow the wrong stack to be used.
|
||||
*
|
||||
- * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
|
||||
+ * "SYSENTER_stack_sp0+12" is because the NMI/debug handler will have
|
||||
* already pushed 3 words if it hits on the sysenter instruction:
|
||||
* eflags, cs and eip.
|
||||
*
|
||||
@@ -794,7 +794,7 @@ END(device_not_available)
|
||||
cmpw $__KERNEL_CS,4(%esp); \
|
||||
jne ok; \
|
||||
label: \
|
||||
- movl TSS_sysenter_sp0+offset(%esp),%esp; \
|
||||
+ movl SYSENTER_stack_sp0+offset(%esp),%esp; \
|
||||
CFI_DEF_CFA esp, 0; \
|
||||
CFI_UNDEFINED eip; \
|
||||
pushfl; \
|
||||
Index: head-2008-11-25/arch/x86/kernel/machine_kexec_32.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/machine_kexec_32.c 2008-11-17 13:38:03.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/machine_kexec_32.c 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -25,6 +25,10 @@
|
||||
#include <asm/system.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+#include <xen/interface/kexec.h>
|
||||
+#endif
|
||||
+
|
||||
#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
|
||||
static u32 kexec_pgd[1024] PAGE_ALIGNED;
|
||||
#ifdef CONFIG_X86_PAE
|
||||
@@ -34,6 +38,55 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED
|
||||
static u32 kexec_pte0[1024] PAGE_ALIGNED;
|
||||
static u32 kexec_pte1[1024] PAGE_ALIGNED;
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+
|
||||
+#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT)
|
||||
+
|
||||
+#if PAGES_NR > KEXEC_XEN_NO_PAGES
|
||||
+#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break
|
||||
+#endif
|
||||
+
|
||||
+#if PA_CONTROL_PAGE != 0
|
||||
+#error PA_CONTROL_PAGE is non zero - Xen support will break
|
||||
+#endif
|
||||
+
|
||||
+void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
|
||||
+{
|
||||
+ void *control_page;
|
||||
+
|
||||
+ memset(xki->page_list, 0, sizeof(xki->page_list));
|
||||
+
|
||||
+ control_page = page_address(image->control_code_page);
|
||||
+ memcpy(control_page, relocate_kernel, PAGE_SIZE);
|
||||
+
|
||||
+ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page);
|
||||
+ xki->page_list[PA_PGD] = __ma(kexec_pgd);
|
||||
+#ifdef CONFIG_X86_PAE
|
||||
+ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0);
|
||||
+ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1);
|
||||
+#endif
|
||||
+ xki->page_list[PA_PTE_0] = __ma(kexec_pte0);
|
||||
+ xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+int __init machine_kexec_setup_resources(struct resource *hypervisor,
|
||||
+ struct resource *phys_cpus,
|
||||
+ int nr_phys_cpus)
|
||||
+{
|
||||
+ int k;
|
||||
+
|
||||
+ /* The per-cpu crash note resources belong to the hypervisor resource */
|
||||
+ for (k = 0; k < nr_phys_cpus; k++)
|
||||
+ request_resource(hypervisor, phys_cpus + k);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void machine_kexec_register_resources(struct resource *res) { ; }
|
||||
+
|
||||
+#endif /* CONFIG_XEN */
|
||||
+
|
||||
/*
|
||||
* A architecture hook called to validate the
|
||||
* proposed image and prepare the control pages
|
||||
@@ -64,6 +117,7 @@ void machine_kexec_cleanup(struct kimage
|
||||
set_pages_nx(image->control_code_page, 1);
|
||||
}
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
/*
|
||||
* Do not allocate memory (or fail in any way) in machine_kexec().
|
||||
* We are past the point of no return, committed to rebooting now.
|
||||
@@ -137,6 +191,7 @@ void machine_kexec(struct kimage *image)
|
||||
|
||||
__ftrace_enabled_restore(save_ftrace_enabled);
|
||||
}
|
||||
+#endif
|
||||
|
||||
void arch_crash_save_vmcoreinfo(void)
|
||||
{
|
||||
Index: head-2008-11-25/arch/x86/kernel/vm86_32.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/vm86_32.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/vm86_32.c 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -124,7 +124,9 @@ static int copy_vm86_regs_from_user(stru
|
||||
|
||||
struct pt_regs *save_v86_state(struct kernel_vm86_regs *regs)
|
||||
{
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
struct tss_struct *tss;
|
||||
+#endif
|
||||
struct pt_regs *ret;
|
||||
unsigned long tmp;
|
||||
|
||||
@@ -147,12 +149,16 @@ struct pt_regs *save_v86_state(struct ke
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
tss = &per_cpu(init_tss, get_cpu());
|
||||
+#endif
|
||||
current->thread.sp0 = current->thread.saved_sp0;
|
||||
current->thread.sysenter_cs = __KERNEL_CS;
|
||||
load_sp0(tss, ¤t->thread);
|
||||
current->thread.saved_sp0 = 0;
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
put_cpu();
|
||||
+#endif
|
||||
|
||||
ret = KVM86->regs32;
|
||||
|
||||
@@ -279,7 +285,9 @@ out:
|
||||
|
||||
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
|
||||
{
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
struct tss_struct *tss;
|
||||
+#endif
|
||||
/*
|
||||
* make sure the vm86() system call doesn't try to do anything silly
|
||||
*/
|
||||
@@ -324,12 +332,16 @@ static void do_sys_vm86(struct kernel_vm
|
||||
tsk->thread.saved_fs = info->regs32->fs;
|
||||
savesegment(gs, tsk->thread.saved_gs);
|
||||
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
tss = &per_cpu(init_tss, get_cpu());
|
||||
+#endif
|
||||
tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0;
|
||||
if (cpu_has_sep)
|
||||
tsk->thread.sysenter_cs = 0;
|
||||
load_sp0(tss, &tsk->thread);
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
put_cpu();
|
||||
+#endif
|
||||
|
||||
tsk->thread.screen_bitmap = info->screen_bitmap;
|
||||
if (info->flags & VM86_SCREEN_BITMAP)
|
||||
Index: head-2008-11-25/arch/x86/power/cpu_32.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/power/cpu_32.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/power/cpu_32.c 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -65,6 +65,7 @@ static void do_fpu_end(void)
|
||||
|
||||
static void fix_processor_context(void)
|
||||
{
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
int cpu = smp_processor_id();
|
||||
struct tss_struct *t = &per_cpu(init_tss, cpu);
|
||||
|
||||
@@ -74,6 +75,7 @@ static void fix_processor_context(void)
|
||||
* 386 hardware has concept of busy TSS or some
|
||||
* similar stupidity.
|
||||
*/
|
||||
+#endif
|
||||
|
||||
load_TR_desc(); /* This does ltr */
|
||||
load_LDT(¤t->active_mm->context); /* This does lldt */
|
||||
Index: head-2008-11-25/arch/x86/vdso/vdso32-setup.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/vdso/vdso32-setup.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/vdso/vdso32-setup.c 2008-11-25 12:35:53.000000000 +0100
|
||||
@@ -26,6 +26,10 @@
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/proto.h>
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+#include <xen/interface/callback.h>
|
||||
+#endif
|
||||
+
|
||||
enum {
|
||||
VDSO_DISABLED = 0,
|
||||
VDSO_ENABLED = 1,
|
||||
@@ -225,6 +229,7 @@ static inline void map_compat_vdso(int m
|
||||
|
||||
void enable_sep_cpu(void)
|
||||
{
|
||||
+#ifndef CONFIG_XEN
|
||||
int cpu = get_cpu();
|
||||
struct tss_struct *tss = &per_cpu(init_tss, cpu);
|
||||
|
||||
@@ -239,6 +244,35 @@ void enable_sep_cpu(void)
|
||||
wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0);
|
||||
put_cpu();
|
||||
+#else
|
||||
+ extern asmlinkage void ia32pv_sysenter_target(void);
|
||||
+ static struct callback_register sysenter = {
|
||||
+ .type = CALLBACKTYPE_sysenter,
|
||||
+ .address = { __KERNEL_CS, (unsigned long)ia32pv_sysenter_target },
|
||||
+ };
|
||||
+
|
||||
+ if (!boot_cpu_has(X86_FEATURE_SEP))
|
||||
+ return;
|
||||
+
|
||||
+ get_cpu();
|
||||
+
|
||||
+ if (xen_feature(XENFEAT_supervisor_mode_kernel))
|
||||
+ sysenter.address.eip = (unsigned long)ia32_sysenter_target;
|
||||
+
|
||||
+ switch (HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter)) {
|
||||
+ case 0:
|
||||
+ break;
|
||||
+#if CONFIG_XEN_COMPAT < 0x030200
|
||||
+ case -ENOSYS:
|
||||
+ sysenter.type = CALLBACKTYPE_sysenter_deprecated;
|
||||
+ if (HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) == 0)
|
||||
+ break;
|
||||
+#endif
|
||||
+ default:
|
||||
+ clear_bit(X86_FEATURE_SEP, boot_cpu_data.x86_capability);
|
||||
+ break;
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
|
||||
static struct vm_area_struct gate_vma;
|
||||
@@ -1,248 +0,0 @@
|
||||
Subject: xen3 arch-x86_64
|
||||
From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 728:832aac894efd)
|
||||
Patch-mainline: obsolete
|
||||
Acked-by: jbeulich@novell.com
|
||||
|
||||
Index: head-2008-11-25/arch/x86/kernel/asm-offsets_64.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/asm-offsets_64.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/asm-offsets_64.c 2008-11-25 12:35:54.000000000 +0100
|
||||
@@ -122,8 +122,10 @@ int main(void)
|
||||
ENTRY(cr8);
|
||||
BLANK();
|
||||
#undef ENTRY
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
DEFINE(TSS_ist, offsetof(struct tss_struct, x86_tss.ist));
|
||||
BLANK();
|
||||
+#endif
|
||||
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
|
||||
BLANK();
|
||||
DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
|
||||
Index: head-2008-11-25/arch/x86/kernel/machine_kexec_64.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/machine_kexec_64.c 2008-08-18 10:13:08.000000000 +0200
|
||||
+++ head-2008-11-25/arch/x86/kernel/machine_kexec_64.c 2008-11-25 12:35:54.000000000 +0100
|
||||
@@ -27,6 +27,119 @@ static u64 kexec_pud1[512] PAGE_ALIGNED;
|
||||
static u64 kexec_pmd1[512] PAGE_ALIGNED;
|
||||
static u64 kexec_pte1[512] PAGE_ALIGNED;
|
||||
|
||||
+#ifdef CONFIG_XEN
|
||||
+
|
||||
+/* In the case of Xen, override hypervisor functions to be able to create
|
||||
+ * a regular identity mapping page table...
|
||||
+ */
|
||||
+
|
||||
+#include <xen/interface/kexec.h>
|
||||
+#include <xen/interface/memory.h>
|
||||
+
|
||||
+#define x__pmd(x) ((pmd_t) { (x) } )
|
||||
+#define x__pud(x) ((pud_t) { (x) } )
|
||||
+#define x__pgd(x) ((pgd_t) { (x) } )
|
||||
+
|
||||
+#define x_pmd_val(x) ((x).pmd)
|
||||
+#define x_pud_val(x) ((x).pud)
|
||||
+#define x_pgd_val(x) ((x).pgd)
|
||||
+
|
||||
+static inline void x_set_pmd(pmd_t *dst, pmd_t val)
|
||||
+{
|
||||
+ x_pmd_val(*dst) = x_pmd_val(val);
|
||||
+}
|
||||
+
|
||||
+static inline void x_set_pud(pud_t *dst, pud_t val)
|
||||
+{
|
||||
+ x_pud_val(*dst) = phys_to_machine(x_pud_val(val));
|
||||
+}
|
||||
+
|
||||
+static inline void x_pud_clear (pud_t *pud)
|
||||
+{
|
||||
+ x_pud_val(*pud) = 0;
|
||||
+}
|
||||
+
|
||||
+static inline void x_set_pgd(pgd_t *dst, pgd_t val)
|
||||
+{
|
||||
+ x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val));
|
||||
+}
|
||||
+
|
||||
+static inline void x_pgd_clear (pgd_t * pgd)
|
||||
+{
|
||||
+ x_pgd_val(*pgd) = 0;
|
||||
+}
|
||||
+
|
||||
+#define X__PAGE_KERNEL_LARGE_EXEC \
|
||||
+ _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE
|
||||
+#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY
|
||||
+
|
||||
+#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT)
|
||||
+
|
||||
+#if PAGES_NR > KEXEC_XEN_NO_PAGES
|
||||
+#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break
|
||||
+#endif
|
||||
+
|
||||
+#if PA_CONTROL_PAGE != 0
|
||||
+#error PA_CONTROL_PAGE is non zero - Xen support will break
|
||||
+#endif
|
||||
+
|
||||
+void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
|
||||
+{
|
||||
+ void *control_page;
|
||||
+ void *table_page;
|
||||
+
|
||||
+ memset(xki->page_list, 0, sizeof(xki->page_list));
|
||||
+
|
||||
+ control_page = page_address(image->control_code_page) + PAGE_SIZE;
|
||||
+ memcpy(control_page, relocate_kernel, PAGE_SIZE);
|
||||
+
|
||||
+ table_page = page_address(image->control_code_page);
|
||||
+
|
||||
+ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page);
|
||||
+ xki->page_list[PA_TABLE_PAGE] = __ma(table_page);
|
||||
+
|
||||
+ xki->page_list[PA_PGD] = __ma(kexec_pgd);
|
||||
+ xki->page_list[PA_PUD_0] = __ma(kexec_pud0);
|
||||
+ xki->page_list[PA_PUD_1] = __ma(kexec_pud1);
|
||||
+ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0);
|
||||
+ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1);
|
||||
+ xki->page_list[PA_PTE_0] = __ma(kexec_pte0);
|
||||
+ xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
|
||||
+}
|
||||
+
|
||||
+int __init machine_kexec_setup_resources(struct resource *hypervisor,
|
||||
+ struct resource *phys_cpus,
|
||||
+ int nr_phys_cpus)
|
||||
+{
|
||||
+ int k;
|
||||
+
|
||||
+ /* The per-cpu crash note resources belong to the hypervisor resource */
|
||||
+ for (k = 0; k < nr_phys_cpus; k++)
|
||||
+ request_resource(hypervisor, phys_cpus + k);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void machine_kexec_register_resources(struct resource *res) { ; }
|
||||
+
|
||||
+#else /* CONFIG_XEN */
|
||||
+
|
||||
+#define x__pmd(x) __pmd(x)
|
||||
+#define x__pud(x) __pud(x)
|
||||
+#define x__pgd(x) __pgd(x)
|
||||
+
|
||||
+#define x_set_pmd(x, y) set_pmd(x, y)
|
||||
+#define x_set_pud(x, y) set_pud(x, y)
|
||||
+#define x_set_pgd(x, y) set_pgd(x, y)
|
||||
+
|
||||
+#define x_pud_clear(x) pud_clear(x)
|
||||
+#define x_pgd_clear(x) pgd_clear(x)
|
||||
+
|
||||
+#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC
|
||||
+#define X_KERNPG_TABLE _KERNPG_TABLE
|
||||
+
|
||||
+#endif /* CONFIG_XEN */
|
||||
+
|
||||
static void init_level2_page(pmd_t *level2p, unsigned long addr)
|
||||
{
|
||||
unsigned long end_addr;
|
||||
@@ -34,7 +147,7 @@ static void init_level2_page(pmd_t *leve
|
||||
addr &= PAGE_MASK;
|
||||
end_addr = addr + PUD_SIZE;
|
||||
while (addr < end_addr) {
|
||||
- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
|
||||
+ x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC));
|
||||
addr += PMD_SIZE;
|
||||
}
|
||||
}
|
||||
@@ -59,12 +172,12 @@ static int init_level3_page(struct kimag
|
||||
}
|
||||
level2p = (pmd_t *)page_address(page);
|
||||
init_level2_page(level2p, addr);
|
||||
- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE));
|
||||
+ x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE));
|
||||
addr += PUD_SIZE;
|
||||
}
|
||||
/* clear the unused entries */
|
||||
while (addr < end_addr) {
|
||||
- pud_clear(level3p++);
|
||||
+ x_pud_clear(level3p++);
|
||||
addr += PUD_SIZE;
|
||||
}
|
||||
out:
|
||||
@@ -95,12 +208,12 @@ static int init_level4_page(struct kimag
|
||||
if (result) {
|
||||
goto out;
|
||||
}
|
||||
- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE));
|
||||
+ x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE));
|
||||
addr += PGDIR_SIZE;
|
||||
}
|
||||
/* clear the unused entries */
|
||||
while (addr < end_addr) {
|
||||
- pgd_clear(level4p++);
|
||||
+ x_pgd_clear(level4p++);
|
||||
addr += PGDIR_SIZE;
|
||||
}
|
||||
out:
|
||||
@@ -111,8 +224,14 @@ out:
|
||||
static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
|
||||
{
|
||||
pgd_t *level4p;
|
||||
+ unsigned long x_max_pfn = max_pfn;
|
||||
+
|
||||
+#ifdef CONFIG_XEN
|
||||
+ x_max_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
|
||||
+#endif
|
||||
+
|
||||
level4p = (pgd_t *)__va(start_pgtable);
|
||||
- return init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
|
||||
+ return init_level4_page(image, level4p, 0, x_max_pfn << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
int machine_kexec_prepare(struct kimage *image)
|
||||
@@ -136,6 +255,7 @@ void machine_kexec_cleanup(struct kimage
|
||||
return;
|
||||
}
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
/*
|
||||
* Do not allocate memory (or fail in any way) in machine_kexec().
|
||||
* We are past the point of no return, committed to rebooting now.
|
||||
@@ -176,6 +296,7 @@ void machine_kexec(struct kimage *image)
|
||||
relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
|
||||
image->start);
|
||||
}
|
||||
+#endif
|
||||
|
||||
void arch_crash_save_vmcoreinfo(void)
|
||||
{
|
||||
Index: head-2008-11-25/arch/x86/power/cpu_64.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/power/cpu_64.c 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/power/cpu_64.c 2008-11-25 12:35:54.000000000 +0100
|
||||
@@ -135,6 +135,7 @@ void restore_processor_state(void)
|
||||
|
||||
static void fix_processor_context(void)
|
||||
{
|
||||
+#ifndef CONFIG_X86_NO_TSS
|
||||
int cpu = smp_processor_id();
|
||||
struct tss_struct *t = &per_cpu(init_tss, cpu);
|
||||
|
||||
@@ -146,6 +147,7 @@ static void fix_processor_context(void)
|
||||
set_tss_desc(cpu, t);
|
||||
|
||||
get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
|
||||
+#endif
|
||||
|
||||
syscall_init(); /* This sets MSR_*STAR and related */
|
||||
load_TR_desc(); /* This does ltr */
|
||||
Index: head-2008-11-25/arch/x86/vdso/Makefile
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/vdso/Makefile 2008-11-25 12:33:06.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/vdso/Makefile 2008-11-25 12:35:54.000000000 +0100
|
||||
@@ -65,6 +65,8 @@ obj-$(VDSO32-y) += vdso32-syms.lds
|
||||
vdso32.so-$(VDSO32-y) += int80
|
||||
vdso32.so-$(CONFIG_COMPAT) += syscall
|
||||
vdso32.so-$(VDSO32-y) += sysenter
|
||||
+xen-vdso32-$(subst 1,$(CONFIG_COMPAT),$(shell expr $(CONFIG_XEN_COMPAT)0 '<' 0x0302000)) += int80
|
||||
+vdso32.so-$(CONFIG_XEN) += $(xen-vdso32-y)
|
||||
|
||||
vdso32-images = $(vdso32.so-y:%=vdso32-%.so)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
Subject: Fix xen configuration.
|
||||
From: jbeulich@novell.com
|
||||
Patch-mainline: obsolete
|
||||
|
||||
Index: head-2008-10-24/arch/x86/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-10-24.orig/arch/x86/Kconfig 2008-10-24 10:43:32.000000000 +0200
|
||||
+++ head-2008-10-24/arch/x86/Kconfig 2008-10-24 10:44:52.000000000 +0200
|
||||
@@ -137,6 +137,7 @@ config HAVE_CPUMASK_OF_CPU_MAP
|
||||
config ARCH_HIBERNATION_POSSIBLE
|
||||
def_bool y
|
||||
depends on !SMP || !X86_VOYAGER
|
||||
+ depends on !XEN
|
||||
|
||||
config ARCH_SUSPEND_POSSIBLE
|
||||
def_bool y
|
||||
@@ -195,7 +196,7 @@ config X86_HT
|
||||
|
||||
config X86_BIOS_REBOOT
|
||||
bool
|
||||
- depends on !X86_VOYAGER
|
||||
+ depends on !X86_VOYAGER && !XEN
|
||||
default y
|
||||
|
||||
config X86_TRAMPOLINE
|
||||
Index: head-2008-10-24/drivers/xen/Kconfig
|
||||
===================================================================
|
||||
--- head-2008-10-24.orig/drivers/xen/Kconfig 2008-10-24 10:43:32.000000000 +0200
|
||||
+++ head-2008-10-24/drivers/xen/Kconfig 2008-10-24 10:44:52.000000000 +0200
|
||||
@@ -22,6 +22,9 @@ config XEN_PRIVILEGED_GUEST
|
||||
|
||||
config XEN_UNPRIVILEGED_GUEST
|
||||
def_bool !XEN_PRIVILEGED_GUEST
|
||||
+ select PM
|
||||
+ select PM_SLEEP
|
||||
+ select PM_SLEEP_SMP if SMP
|
||||
|
||||
config XEN_PRIVCMD
|
||||
def_bool y
|
||||
@@ -1,60 +0,0 @@
|
||||
Subject: xen3 x86 build fixes.
|
||||
From: jbeulich@novell.com
|
||||
Patch-mainline: obsolete
|
||||
|
||||
Index: head-2008-11-25/arch/x86/kernel/crash.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/crash.c 2008-11-25 14:34:12.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/crash.c 2008-11-25 12:41:33.000000000 +0100
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
#include <mach_ipi.h>
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
/* This keeps a track of which one is crashing cpu. */
|
||||
static int crashing_cpu;
|
||||
|
||||
-#ifndef CONFIG_XEN
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
|
||||
static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
@@ -206,9 +206,9 @@ void native_machine_crash_shutdown(struc
|
||||
/* The kernel is broken so disable interrupts */
|
||||
local_irq_disable();
|
||||
|
||||
+#ifndef CONFIG_XEN
|
||||
/* Make a note of crashing cpu. Will be used in NMI callback.*/
|
||||
crashing_cpu = safe_smp_processor_id();
|
||||
-#ifndef CONFIG_XEN
|
||||
nmi_shootdown_cpus();
|
||||
lapic_shutdown();
|
||||
#if defined(CONFIG_X86_IO_APIC)
|
||||
Index: head-2008-11-25/arch/x86/power/Makefile
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/power/Makefile 2008-11-25 14:34:12.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/power/Makefile 2008-11-25 12:41:33.000000000 +0100
|
||||
@@ -1,2 +1,4 @@
|
||||
obj-$(CONFIG_PM_SLEEP) += cpu_$(BITS).o
|
||||
obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o
|
||||
+
|
||||
+disabled-obj-$(CONFIG_XEN) := cpu_$(BITS).o
|
||||
Index: head-2008-11-25/arch/x86/power/cpu_64.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/power/cpu_64.c 2008-11-25 14:34:12.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/power/cpu_64.c 2008-11-25 12:41:33.000000000 +0100
|
||||
@@ -135,7 +135,6 @@ void restore_processor_state(void)
|
||||
|
||||
static void fix_processor_context(void)
|
||||
{
|
||||
-#ifndef CONFIG_X86_NO_TSS
|
||||
int cpu = smp_processor_id();
|
||||
struct tss_struct *t = &per_cpu(init_tss, cpu);
|
||||
|
||||
@@ -147,7 +146,6 @@ static void fix_processor_context(void)
|
||||
set_tss_desc(cpu, t);
|
||||
|
||||
get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
|
||||
-#endif
|
||||
|
||||
syscall_init(); /* This sets MSR_*STAR and related */
|
||||
load_TR_desc(); /* This does ltr */
|
||||
@@ -1,63 +0,0 @@
|
||||
Subject: Fix Xen build wrt. SFC files coming from Solarflare.
|
||||
From: jbeulich@novell.com
|
||||
Patch-mainline: obsolete
|
||||
|
||||
Index: head-2008-04-15/drivers/xen/sfc_netback/accel_solarflare.c
|
||||
===================================================================
|
||||
--- head-2008-04-15.orig/drivers/xen/sfc_netback/accel_solarflare.c 2008-04-18 18:23:11.000000000 +0200
|
||||
+++ head-2008-04-15/drivers/xen/sfc_netback/accel_solarflare.c 2008-04-18 18:24:46.000000000 +0200
|
||||
@@ -173,7 +173,7 @@ static int efx_device_to_efab_nic_index(
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EFHW_MAX_NR_DEVS; i++) {
|
||||
- struct efhw_nic *nic = efrm_nic_table.nic[i];
|
||||
+ struct efhw_nic *nic = efrm_nic_tablep->nic[i];
|
||||
|
||||
/*
|
||||
* It's possible for the nic structure to have not
|
||||
Index: head-2008-04-15/drivers/xen/sfc_netback/ci/efrm/nic_table.h
|
||||
===================================================================
|
||||
--- head-2008-04-15.orig/drivers/xen/sfc_netback/ci/efrm/nic_table.h 2008-02-20 09:32:49.000000000 +0100
|
||||
+++ head-2008-04-15/drivers/xen/sfc_netback/ci/efrm/nic_table.h 2008-04-18 18:25:47.000000000 +0200
|
||||
@@ -62,21 +62,21 @@ struct efrm_nic_table {
|
||||
};
|
||||
|
||||
/* Resource driver structures used by other drivers as well */
|
||||
-extern struct efrm_nic_table efrm_nic_table;
|
||||
+extern struct efrm_nic_table *efrm_nic_tablep;
|
||||
|
||||
static inline void efrm_nic_table_hold(void)
|
||||
{
|
||||
- atomic_inc(&efrm_nic_table.ref_count);
|
||||
+ atomic_inc(&efrm_nic_tablep->ref_count);
|
||||
}
|
||||
|
||||
static inline void efrm_nic_table_rele(void)
|
||||
{
|
||||
- atomic_dec(&efrm_nic_table.ref_count);
|
||||
+ atomic_dec(&efrm_nic_tablep->ref_count);
|
||||
}
|
||||
|
||||
static inline int efrm_nic_table_held(void)
|
||||
{
|
||||
- return (atomic_read(&efrm_nic_table.ref_count) != 0);
|
||||
+ return (atomic_read(&efrm_nic_tablep->ref_count) != 0);
|
||||
}
|
||||
|
||||
/* Run code block _x multiple times with variable nic set to each
|
||||
@@ -86,13 +86,13 @@ static inline int efrm_nic_table_held(vo
|
||||
for ((_nic_i) = (efrm_nic_table_hold(), 0); \
|
||||
(_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
|
||||
(_nic_i)++) \
|
||||
- if (((_nic) = efrm_nic_table.nic[_nic_i]))
|
||||
+ if (((_nic) = efrm_nic_tablep->nic[_nic_i]))
|
||||
|
||||
#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic) \
|
||||
for ((_i) = (efrm_nic_table_hold(), 0); \
|
||||
(_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
|
||||
++(_i)) \
|
||||
- if (((_nic) = efrm_nic_table.nic[_i]) && \
|
||||
+ if (((_nic) = efrm_nic_tablep->nic[_i]) && \
|
||||
efrm_nic_set_read((_set), (_i)))
|
||||
|
||||
#endif /* __CI_EFRM_NIC_TABLE_H__ */
|
||||
@@ -1,66 +0,0 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: [PATCH] X86: sysctl to allow panic on IOCK NMI error
|
||||
References: bnc427979
|
||||
|
||||
This patch introduces a sysctl /proc/sys/kernel/panic_on_io_nmi.,
|
||||
which defaults to 0 (off).
|
||||
When enabled, the kernel panics when the kernel receives an NMI
|
||||
caused by an IO error.
|
||||
|
||||
The IO error triggered NMI indicates a serious system condition,
|
||||
which could result in IO data corruption. Rather than contiuing,
|
||||
panicing and dumping might be a better choice, so one can figure
|
||||
out what's causing the IO error.
|
||||
This could be especially important to companies running IO intensive
|
||||
applications where corruption must be avoided, e.g. a banks databases.
|
||||
|
||||
|
||||
Signed-off-by: Roberto Angelino <robertangelino@gmail.com>
|
||||
|
||||
|
||||
Automatically created from "patches.suse/panic-on-io-nmi.diff" by xen-port-patches.py
|
||||
|
||||
Index: head-2008-11-25/arch/x86/kernel/traps_32-xen.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/traps_32-xen.c 2008-11-25 12:57:05.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/traps_32-xen.c 2008-11-25 13:13:12.000000000 +0100
|
||||
@@ -83,6 +83,7 @@ gate_desc idt_table[256]
|
||||
#endif
|
||||
|
||||
int panic_on_unrecovered_nmi;
|
||||
+int panic_on_io_nmi;
|
||||
int kstack_depth_to_print = 24;
|
||||
static unsigned int code_bytes = 64;
|
||||
static int ignore_nmis;
|
||||
@@ -670,6 +671,9 @@ io_check_error(unsigned char reason, str
|
||||
printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
|
||||
show_registers(regs);
|
||||
|
||||
+ if (panic_on_io_nmi)
|
||||
+ panic("NMI IOCK error: Not continuing");
|
||||
+
|
||||
/* Re-enable the IOCK line, wait for a few seconds */
|
||||
clear_io_check_error(reason);
|
||||
}
|
||||
Index: head-2008-11-25/arch/x86/kernel/traps_64-xen.c
|
||||
===================================================================
|
||||
--- head-2008-11-25.orig/arch/x86/kernel/traps_64-xen.c 2008-11-25 12:57:05.000000000 +0100
|
||||
+++ head-2008-11-25/arch/x86/kernel/traps_64-xen.c 2008-11-25 13:13:12.000000000 +0100
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <mach_traps.h>
|
||||
|
||||
int panic_on_unrecovered_nmi;
|
||||
+int panic_on_io_nmi;
|
||||
int kstack_depth_to_print = 12;
|
||||
static unsigned int code_bytes = 64;
|
||||
static int ignore_nmis;
|
||||
@@ -772,6 +773,9 @@ io_check_error(unsigned char reason, str
|
||||
printk("NMI: IOCK error (debug interrupt?)\n");
|
||||
show_registers(regs);
|
||||
|
||||
+ if (panic_on_io_nmi)
|
||||
+ panic("NMI IOCK error: Not continuing");
|
||||
+
|
||||
/* Re-enable the IOCK line, wait for a few seconds */
|
||||
clear_io_check_error(reason);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
From: jbeulich@novell.com
|
||||
Subject: fix issue with Windows-style types used in rt2680
|
||||
Patch-mainline: obsolete
|
||||
|
||||
Index: head-2008-11-17/include/asm-x86/mach-xen/asm/hypervisor.h
|
||||
===================================================================
|
||||
--- head-2008-11-17.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2008-11-17 14:06:21.000000000 +0100
|
||||
+++ head-2008-11-17/include/asm-x86/mach-xen/asm/hypervisor.h 2008-11-18 14:12:19.000000000 +0100
|
||||
@@ -340,4 +340,9 @@ MULTI_grant_table_op(multicall_entry_t *
|
||||
|
||||
#endif
|
||||
|
||||
+#ifdef LINUX
|
||||
+/* drivers/staging/rt2860/ uses Windows-style types, including VOID */
|
||||
+#undef VOID
|
||||
+#endif
|
||||
+
|
||||
#endif /* __HYPERVISOR_H__ */
|
||||
65
src/patches/imq-skbuff.patch
Normal file
65
src/patches/imq-skbuff.patch
Normal file
@@ -0,0 +1,65 @@
|
||||
--- linux-2.6.27.21/include/linux/skbuff.h 2009-07-22 08:06:40.000000000 +0000
|
||||
+++ linux-2.6.27.21/include/linux/skbuff.h.imq 2009-07-22 08:12:55.000000000 +0000
|
||||
@@ -28,6 +28,9 @@
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/hrtimer.h>
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+#include <linux/imq.h>
|
||||
+#endif
|
||||
|
||||
#define HAVE_ALLOC_SKB /* For the drivers to know */
|
||||
#define HAVE_ALIGNABLE_SKB /* Ditto 8) */
|
||||
@@ -274,6 +277,9 @@
|
||||
* first. This is owned by whoever has the skb queued ATM.
|
||||
*/
|
||||
char cb[48];
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+ void *cb_next;
|
||||
+#endif
|
||||
|
||||
unsigned int len,
|
||||
data_len;
|
||||
@@ -304,6 +310,9 @@
|
||||
struct nf_conntrack *nfct;
|
||||
struct sk_buff *nfct_reasm;
|
||||
#endif
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+ struct nf_queue_entry *nf_queue_entry;
|
||||
+#endif
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
struct nf_bridge_info *nf_bridge;
|
||||
#endif
|
||||
@@ -330,6 +339,9 @@
|
||||
proto_csum_blank:1;
|
||||
#endif
|
||||
/* 10-16 bit hole */
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+ __u8 imq_flags:IMQ_F_BITS;
|
||||
+#endif
|
||||
|
||||
#ifdef CONFIG_NET_DMA
|
||||
dma_cookie_t dma_cookie;
|
||||
@@ -374,6 +386,11 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+extern int skb_save_cb(struct sk_buff *skb);
|
||||
+extern int skb_restore_cb(struct sk_buff *skb);
|
||||
+#endif
|
||||
+
|
||||
extern void kfree_skb(struct sk_buff *skb);
|
||||
extern void __kfree_skb(struct sk_buff *skb);
|
||||
extern struct sk_buff *__alloc_skb(unsigned int size,
|
||||
@@ -1688,6 +1705,10 @@
|
||||
dst->nfct_reasm = src->nfct_reasm;
|
||||
nf_conntrack_get_reasm(src->nfct_reasm);
|
||||
#endif
|
||||
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
|
||||
+ dst->imq_flags = src->imq_flags;
|
||||
+ dst->nf_queue_entry = src->nf_queue_entry;
|
||||
+#endif
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
dst->nf_bridge = src->nf_bridge;
|
||||
nf_bridge_get(src->nf_bridge);
|
||||
1212
src/patches/linux-2.6.27.21-imq-test3-xen.patch
Normal file
1212
src/patches/linux-2.6.27.21-imq-test3-xen.patch
Normal file
File diff suppressed because it is too large
Load Diff
35
src/patches/suse-2.6.27.25/arch-symbols
Executable file
35
src/patches/suse-2.6.27.25/arch-symbols
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Generate architecture specific patch selection symbols
|
||||
|
||||
if [ "$1" = "--list" ]; then
|
||||
# List all known architectures
|
||||
echo i386 mips{,64} sparc{,64} ppc{,64} s390{,x} ia64 x86_64 alpha parisc
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$SYMBOLS" ]; then
|
||||
if [ -n "$1" ]; then
|
||||
ARCH="$1"
|
||||
elif [ -n "$PATCH_ARCH" ]; then
|
||||
ARCH="$PATCH_ARCH"
|
||||
else
|
||||
ARCH="`arch`"
|
||||
fi
|
||||
SYMBOLS="$ARCH"
|
||||
case "$ARCH" in
|
||||
(i?86) SYMBOLS="$SYMBOLS IA32" ;;
|
||||
(mips*) SYMBOLS="$SYMBOLS MIPS" ;;
|
||||
(sparc*) SYMBOLS="$SYMBOLS SPARC" ;;
|
||||
(ppc*) SYMBOLS="$SYMBOLS PPC" ;;
|
||||
(s390*) SYMBOLS="$SYMBOLS S390" ;;
|
||||
(ia64) ;;
|
||||
(x86_64) ;;
|
||||
(alpha) ;;
|
||||
(parisc) ;;
|
||||
(*) # not a recognized architeture!
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo $SYMBOLS
|
||||
287
src/patches/suse-2.6.27.25/guards
Executable file
287
src/patches/suse-2.6.27.25/guards
Executable file
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
#
|
||||
# Guards:
|
||||
#
|
||||
# +xxx include if xxx is defined
|
||||
# -xxx exclude if xxx is defined
|
||||
# +!xxx include if xxx is not defined
|
||||
# -!xxx exclude if xxx is not defined
|
||||
#
|
||||
|
||||
use FileHandle;
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
|
||||
# Prototypes
|
||||
sub files_in($$);
|
||||
sub parse($$);
|
||||
sub help();
|
||||
|
||||
#sub strip_ext($) {
|
||||
# local ($_) = @_;
|
||||
# s/\.(diff?|patch)$//;
|
||||
#}
|
||||
|
||||
#sub try_ext($) {
|
||||
# my ($path) = @_;
|
||||
# for my $p in (($path, "$path.diff", "$path.dif", "$path.patch")) {
|
||||
# return $p
|
||||
# if (-f $p);
|
||||
# }
|
||||
# return undef;
|
||||
#}
|
||||
|
||||
sub slashme($) {
|
||||
my ($dir) = @_;
|
||||
$dir =~ s#([^/])$#$&/#; # append a slash if necessary
|
||||
if ($dir eq './') {
|
||||
return '';
|
||||
} else {
|
||||
return $dir;
|
||||
}
|
||||
}
|
||||
|
||||
# Generate a list of files in a directory
|
||||
#
|
||||
sub files_in($$) {
|
||||
my ($dir, $path) = @_;
|
||||
my $dh = new FileHandle;
|
||||
my (@files, $file);
|
||||
|
||||
|
||||
opendir $dh, length("$dir$path") ? "$dir$path" : '.'
|
||||
or die "$dir$path: $!\n";
|
||||
while ($file = readdir($dh)) {
|
||||
next if $file =~ /^(\.|\.\.|\.#.*|CVS|.*~)$/;
|
||||
if (-d "$dir$path$file") {
|
||||
@files = (@files, files_in($dir, "$path$file/"));
|
||||
} else {
|
||||
#print "[$path$file]\n";
|
||||
push @files, "$path$file";
|
||||
}
|
||||
}
|
||||
closedir $dh;
|
||||
return @files;
|
||||
}
|
||||
|
||||
# Parse a configuration file
|
||||
# Callback called with ($patch, @guards) arguments
|
||||
#
|
||||
sub parse($$) {
|
||||
my ($fh, $callback) = @_;
|
||||
|
||||
my $line = "";
|
||||
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
s/(^|\s+)#.*//;
|
||||
if (s/\\$/ /) {
|
||||
$line .= $_;
|
||||
next;
|
||||
}
|
||||
$line .= $_;
|
||||
my @guards = ();
|
||||
foreach my $token (split /[\s\t\n]+/, $line) {
|
||||
next if $token eq "";
|
||||
if ($token =~ /^[-+]/) {
|
||||
push @guards, $token;
|
||||
} else {
|
||||
#print "[" . join(",", @guards) . "] $token\n";
|
||||
&$callback($token, @guards);
|
||||
}
|
||||
}
|
||||
$line = "";
|
||||
}
|
||||
}
|
||||
|
||||
# Command line options
|
||||
#
|
||||
my ($dir, $config, $default, $check, $list, $invert_match, $with_guards) =
|
||||
( '', '-', 1, 0, 0, 0, 0);
|
||||
my @path;
|
||||
|
||||
# Help text
|
||||
#
|
||||
sub help() {
|
||||
print "$0 - select from a list of files guarded by conditions\n";
|
||||
print "SYNOPSIS: $0 [--prefix=dir] [--path=dir1:dir2:...]\n" .
|
||||
" [--default=0|1] [--check|--list] [--invert-match]\n" .
|
||||
" [--with-guards] [--config=file] symbol ...\n\n" .
|
||||
" (Default values: --path='" . join(':', @path) . "', " .
|
||||
"--default=$default)\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Parse command line options
|
||||
#
|
||||
Getopt::Long::Configure ("bundling");
|
||||
eval {
|
||||
unless (GetOptions (
|
||||
'd|prefix=s' => \$dir,
|
||||
'c|config=s' => \$config,
|
||||
'C|check' => \$check,
|
||||
'l|list' => \$list,
|
||||
'w|with-guards' => \$with_guards,
|
||||
'p|path=s' => \@path,
|
||||
'D|default=i' => \$default,
|
||||
'v|invert-match' => \$invert_match,
|
||||
'h|help' => sub { help(); exit 0; })) {
|
||||
help();
|
||||
exit 1;
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
print "$@";
|
||||
help();
|
||||
exit 1;
|
||||
}
|
||||
|
||||
@path = ('.')
|
||||
unless (@path);
|
||||
@path = split(/:/, join(':', @path));
|
||||
|
||||
my $fh = ($config eq '-') ? \*STDIN : new FileHandle($config)
|
||||
or die "$config: $!\n";
|
||||
|
||||
$dir = slashme($dir);
|
||||
|
||||
if ($check) {
|
||||
# Check for duplicate files, or for files that are not referenced by
|
||||
# the specification.
|
||||
|
||||
my $problems = 0;
|
||||
my @files;
|
||||
|
||||
foreach (@path) {
|
||||
@files = (@files, files_in($dir, slashme($_)));
|
||||
}
|
||||
my %files = map { $_ => 0 } @files;
|
||||
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
if (exists $files{$patch}) {
|
||||
$files{$patch}++;
|
||||
} else {
|
||||
print "Not found: $dir$patch\n";
|
||||
$problems++;
|
||||
}});
|
||||
|
||||
$fh->close();
|
||||
|
||||
my ($file, $ref);
|
||||
while (($file, $ref) = each %files) {
|
||||
next if $ref == 1;
|
||||
|
||||
if ($ref == 0) {
|
||||
print "Unused: $file\n" if $ref == 0;
|
||||
$problems++;
|
||||
}
|
||||
if ($ref > 1) {
|
||||
print "Warning: multiple uses: $file\n" if $ref > 1;
|
||||
# This is not an error if the entries are mutually exclusive...
|
||||
}
|
||||
}
|
||||
exit $problems ? 1 : 0;
|
||||
|
||||
} elsif ($list) {
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
print join(' ', @guards), ' '
|
||||
if (@guards && $with_guards);
|
||||
print "$dir$patch\n";
|
||||
});
|
||||
} else {
|
||||
# Generate a list of patches to apply.
|
||||
|
||||
my %symbols = map { $_ => 1 } @ARGV;
|
||||
|
||||
parse($fh, sub {
|
||||
my ($patch, @guards) = @_;
|
||||
|
||||
my $selected;
|
||||
if (@guards) {
|
||||
# If the first guard is -xxx, the patch is included by default;
|
||||
# if it is +xxx, the patch is excluded by default.
|
||||
$selected = ($guards[0] =~ /^-/);
|
||||
|
||||
foreach (@guards) {
|
||||
/^([-+])(!?)(.*)?/
|
||||
or die "Bad guard '$_'\n";
|
||||
|
||||
# Check if the guard matches
|
||||
if (($2 eq '!' && !exists $symbols{$3}) ||
|
||||
($2 eq '' && ( $3 eq '' || exists $symbols{$3}))) {
|
||||
# Include or exclude
|
||||
$selected = ($1 eq '+');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# If there are no guards, use the specified default result.
|
||||
$selected = $default;
|
||||
}
|
||||
|
||||
print "$dir$patch\n"
|
||||
if $selected ^ $invert_match;
|
||||
});
|
||||
|
||||
$fh->close();
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
guards - select from a list of files guarded by conditions
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
F<guards> [--prefix=F<dir>] [--path=F<dir1:dir2:...>] [--default=<0|1>]
|
||||
[--check|--list] [--invert-match] [--with-guards] [--config=<file>]
|
||||
I<symbol> ...
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The script reads a configuration file that may contain so-called guards, file
|
||||
names, and comments, and writes those file names that satisfy all guards to
|
||||
standard output. The script takes a list of symbols as its arguments. Each line
|
||||
in the configuration file is processed separately. Lines may start with a
|
||||
number of guards. The following guards are defined:
|
||||
|
||||
=over
|
||||
|
||||
+I<xxx> Include the file(s) on this line if the symbol I<xxx> is defined.
|
||||
|
||||
-I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is defined.
|
||||
|
||||
+!I<xxx> Include the file(s) on this line if the symbol I<xxx> is not defined.
|
||||
|
||||
-!I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is not defined.
|
||||
|
||||
- Exclude this file. Used to avoid spurious I<--check> messages.
|
||||
|
||||
=back
|
||||
|
||||
The guards are processed left to right. The last guard that matches determines
|
||||
if the file is included. If no guard is specified, the I<--default>
|
||||
setting determines if the file is included.
|
||||
|
||||
If no configuration file is specified, the script reads from standard input.
|
||||
|
||||
The I<--check> option is used to compare the specification file against the
|
||||
file system. If files are referenced in the specification that do not exist, or
|
||||
if files are not enlisted in the specification file warnings are printed. The
|
||||
I<--path> option can be used to specify which directory or directories to scan.
|
||||
Multiple directories are eparated by a colon (C<:>) character. The
|
||||
I<--prefix> option specifies the location of the files.
|
||||
|
||||
Use I<--list> to list all files independend of any rules. Use I<--invert-match>
|
||||
to list only the excluded patches. Use I<--with-guards> to also include all
|
||||
inclusion and exclusion rules.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andreas Gruenbacher <agruen@suse.de>, SUSE Labs
|
||||
@@ -0,0 +1,109 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] security: add ->path_permission
|
||||
|
||||
This patch adds a security_ops->path_permission hook that is identical to
|
||||
security_ops->inode_permission except that it is passed a struct path
|
||||
instead of a struct inode.
|
||||
|
||||
LSMs which don't implement it will have their ->inode_permission call
|
||||
used instead.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
|
||||
include/linux/security.h | 21 +++++++++++++++++++++
|
||||
security/capability.c | 6 ++++++
|
||||
security/security.c | 9 +++++++++
|
||||
3 files changed, 36 insertions(+)
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -592,6 +592,20 @@ static inline void security_free_mnt_opt
|
||||
* file_permission, and recheck access if anything has changed
|
||||
* since inode_permission.
|
||||
*
|
||||
+ * Security hook for path
|
||||
+ *
|
||||
+ * @path_permission:
|
||||
+ * Check permission before accessing a path. This hook is called by the
|
||||
+ * existing Linux permission function, so a security module can use it to
|
||||
+ * provide additional checking for existing Linux permission checks.
|
||||
+ * Notice that this hook is called when a file is opened (as well as many
|
||||
+ * other operations), whereas the file_security_ops permission hook is
|
||||
+ * called when the actual read/write operations are performed. This
|
||||
+ * hook is optional and if absent, inode_permission will be substituted.
|
||||
+ * @path contains the path structure to check.
|
||||
+ * @mask contains the permission mask.
|
||||
+ * Return 0 if permission is granted.
|
||||
+
|
||||
* Security hooks for task operations.
|
||||
*
|
||||
* @task_create:
|
||||
@@ -1434,6 +1448,7 @@ struct security_operations {
|
||||
struct fown_struct *fown, int sig);
|
||||
int (*file_receive) (struct file *file);
|
||||
int (*dentry_open) (struct file *file);
|
||||
+ int (*path_permission) (struct path *path, int mask);
|
||||
|
||||
int (*task_create) (unsigned long clone_flags);
|
||||
int (*task_alloc_security) (struct task_struct *p);
|
||||
@@ -1708,6 +1723,7 @@ int security_file_send_sigiotask(struct
|
||||
struct fown_struct *fown, int sig);
|
||||
int security_file_receive(struct file *file);
|
||||
int security_dentry_open(struct file *file);
|
||||
+int security_path_permission(struct path *path, int mask);
|
||||
int security_task_create(unsigned long clone_flags);
|
||||
int security_task_alloc(struct task_struct *p);
|
||||
void security_task_free(struct task_struct *p);
|
||||
@@ -2240,6 +2256,11 @@ static inline int security_dentry_open(s
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+static inline int security_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
static inline int security_task_create(unsigned long clone_flags)
|
||||
{
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -343,6 +343,11 @@ static int cap_dentry_open(struct file *
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int cap_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ return security_inode_permission(path->dentry->d_inode, mask);
|
||||
+}
|
||||
+
|
||||
static int cap_task_create(unsigned long clone_flags)
|
||||
{
|
||||
return 0;
|
||||
@@ -897,6 +902,7 @@ void security_fixup_ops(struct security_
|
||||
set_to_cap_if_null(ops, file_send_sigiotask);
|
||||
set_to_cap_if_null(ops, file_receive);
|
||||
set_to_cap_if_null(ops, dentry_open);
|
||||
+ set_to_cap_if_null(ops, path_permission);
|
||||
set_to_cap_if_null(ops, task_create);
|
||||
set_to_cap_if_null(ops, task_alloc_security);
|
||||
set_to_cap_if_null(ops, task_free_security);
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -615,6 +615,15 @@ int security_dentry_open(struct file *fi
|
||||
return security_ops->dentry_open(file);
|
||||
}
|
||||
|
||||
+int security_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ struct inode *inode = path->dentry->d_inode;
|
||||
+ if (unlikely(IS_PRIVATE(inode)))
|
||||
+ return 0;
|
||||
+
|
||||
+ return security_ops->path_permission(path, mask);
|
||||
+}
|
||||
+
|
||||
int security_task_create(unsigned long clone_flags)
|
||||
{
|
||||
return security_ops->task_create(clone_flags);
|
||||
@@ -0,0 +1,78 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] apparmor: convert apparmor_inode_permission to path
|
||||
|
||||
patches.apparmor/add-security_path_permission added the ->path_permission
|
||||
call. This patch converts apparmor_inode_permission to
|
||||
apparmor_path_permission. The former is now a pass-all, which is how
|
||||
it behaved in 2.6.26 if a NULL nameidata was passed.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/apparmor/lsm.c | 41 +++++++++++++++++++++++++++--------------
|
||||
1 file changed, 27 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -448,21 +448,9 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
-static int apparmor_inode_permission(struct inode *inode, int mask,
|
||||
- struct nameidata *nd)
|
||||
+static int apparmor_inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
- int check = 0;
|
||||
-
|
||||
- if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
|
||||
- return 0;
|
||||
- mask = aa_mask_permissions(mask);
|
||||
- if (S_ISDIR(inode->i_mode)) {
|
||||
- check |= AA_CHECK_DIR;
|
||||
- /* allow traverse accesses to directories */
|
||||
- mask &= ~MAY_EXEC;
|
||||
- }
|
||||
- return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
|
||||
- mask, check);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
@@ -656,6 +644,29 @@ static int apparmor_file_mprotect(struct
|
||||
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
}
|
||||
|
||||
+static int apparmor_path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ struct inode *inode;
|
||||
+ int check = 0;
|
||||
+
|
||||
+ if (!path)
|
||||
+ return 0;
|
||||
+
|
||||
+ inode = path->dentry->d_inode;
|
||||
+
|
||||
+ mask = aa_mask_permissions(mask);
|
||||
+ if (S_ISDIR(inode->i_mode)) {
|
||||
+ check |= AA_CHECK_DIR;
|
||||
+ /* allow traverse accesses to directories */
|
||||
+ mask &= ~MAY_EXEC;
|
||||
+ if (!mask)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return aa_permission("inode_permission", inode, path->dentry,
|
||||
+ path->mnt, mask, check);
|
||||
+}
|
||||
+
|
||||
static int apparmor_task_alloc_security(struct task_struct *task)
|
||||
{
|
||||
return aa_clone(task);
|
||||
@@ -800,6 +811,8 @@ struct security_operations apparmor_ops
|
||||
.file_mprotect = apparmor_file_mprotect,
|
||||
.file_lock = apparmor_file_lock,
|
||||
|
||||
+ .path_permission = apparmor_path_permission,
|
||||
+
|
||||
.task_alloc_security = apparmor_task_alloc_security,
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
.task_post_setuid = cap_task_post_setuid,
|
||||
@@ -0,0 +1,26 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] LSM: Export security_inode_permission for aufs
|
||||
Patch-mainline: Never
|
||||
References: 356902
|
||||
|
||||
In order for aufs to work with AppArmor, it needs to be able to call
|
||||
security_inode_permission itself.
|
||||
|
||||
This patch is a _workaround_ since the author will need to find a
|
||||
mainline-compatible solution moving forward.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/security.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -415,6 +415,7 @@ int security_inode_mknod(struct inode *d
|
||||
return 0;
|
||||
return security_ops->inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(security_inode_permission);
|
||||
|
||||
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct vfsmount *old_mnt, struct inode *new_dir,
|
||||
@@ -0,0 +1,118 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: ACPI: video: Ignore devices that aren't present in hardware
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit ad9ed8385ed6ec5be8da7094db911c824258ceec
|
||||
|
||||
This is a reimplemention of commit
|
||||
0119509c4fbc9adcef1472817fda295334612976
|
||||
from Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
|
||||
This patch got removed because of a regression: ThinkPads with a
|
||||
Intel graphics card and an Integrated Graphics Device BIOS implementation
|
||||
stopped working.
|
||||
In fact, they only worked because the ACPI device of the discrete, the
|
||||
wrong one, got used (via int10). So ACPI functions were poking on the wrong
|
||||
hardware used which is a sever bug.
|
||||
The next patch provides support for above ThinkPads to be able to
|
||||
switch brightness via the legacy thinkpad_acpi driver and automatically
|
||||
detect when to use it.
|
||||
|
||||
Original commit message from Matthew Garrett:
|
||||
Vendors often ship machines with a choice of integrated or discrete
|
||||
graphics, and use the same DSDT for both. As a result, the ACPI video
|
||||
module will locate devices that may not exist on this specific platform.
|
||||
Attempt to determine whether the device exists or not, and abort the
|
||||
device creation if it doesn't.
|
||||
|
||||
http://bugzilla.kernel.org/show_bug.cgi?id=9614
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/glue.c | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/acpi/video.c | 7 ++++++-
|
||||
include/acpi/acpi_bus.h | 2 ++
|
||||
3 files changed, 48 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/glue.c
|
||||
+++ b/drivers/acpi/glue.c
|
||||
@@ -140,6 +140,46 @@ struct device *acpi_get_physical_device(
|
||||
|
||||
EXPORT_SYMBOL(acpi_get_physical_device);
|
||||
|
||||
+/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge
|
||||
+ * This should work in general, but did not on a Lenovo T61 for the
|
||||
+ * graphics card. But this must be fixed when the PCI device is
|
||||
+ * bound and the kernel device struct is attached to the acpi device
|
||||
+ * Note: A success call will increase reference count by one
|
||||
+ * Do call put_device(dev) on the returned device then
|
||||
+ */
|
||||
+struct device *acpi_get_physical_pci_device(acpi_handle handle)
|
||||
+{
|
||||
+ struct device *dev;
|
||||
+ long long device_id;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ status =
|
||||
+ acpi_evaluate_integer(handle, "_ADR", NULL, &device_id);
|
||||
+
|
||||
+ if (ACPI_FAILURE(status))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* We need to attempt to determine whether the _ADR refers to a
|
||||
+ PCI device or not. There's no terribly good way to do this,
|
||||
+ so the best we can hope for is to assume that there'll never
|
||||
+ be a device in the host bridge */
|
||||
+ if (device_id >= 0x10000) {
|
||||
+ /* It looks like a PCI device. Does it exist? */
|
||||
+ dev = acpi_get_physical_device(handle);
|
||||
+ } else {
|
||||
+ /* It doesn't look like a PCI device. Does its parent
|
||||
+ exist? */
|
||||
+ acpi_handle phandle;
|
||||
+ if (acpi_get_parent(handle, &phandle))
|
||||
+ return NULL;
|
||||
+ dev = acpi_get_physical_device(phandle);
|
||||
+ }
|
||||
+ if (!dev)
|
||||
+ return NULL;
|
||||
+ return dev;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_get_physical_pci_device);
|
||||
+
|
||||
static int acpi_bind_one(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *acpi_dev;
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -862,11 +862,16 @@ static void acpi_video_bus_find_cap(stru
|
||||
static int acpi_video_bus_check(struct acpi_video_bus *video)
|
||||
{
|
||||
acpi_status status = -ENOENT;
|
||||
-
|
||||
+ struct device *dev;
|
||||
|
||||
if (!video)
|
||||
return -EINVAL;
|
||||
|
||||
+ dev = acpi_get_physical_pci_device(video->device->handle);
|
||||
+ if (!dev)
|
||||
+ return -ENODEV;
|
||||
+ put_device(dev);
|
||||
+
|
||||
/* Since there is no HID, CID and so on for VGA driver, we have
|
||||
* to check well known required nodes.
|
||||
*/
|
||||
--- a/include/acpi/acpi_bus.h
|
||||
+++ b/include/acpi/acpi_bus.h
|
||||
@@ -373,6 +373,8 @@ struct acpi_bus_type {
|
||||
int register_acpi_bus_type(struct acpi_bus_type *);
|
||||
int unregister_acpi_bus_type(struct acpi_bus_type *);
|
||||
struct device *acpi_get_physical_device(acpi_handle);
|
||||
+struct device *acpi_get_physical_pci_device(acpi_handle);
|
||||
+
|
||||
/* helper */
|
||||
acpi_handle acpi_get_child(acpi_handle, acpi_integer);
|
||||
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
|
||||
@@ -0,0 +1,489 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] Check for ACPI backlight support otherwise use vendor ACPI drivers
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit f43d728731c691772ddc29e50d25c68a859935b5
|
||||
|
||||
If an ACPI graphics device supports backlight brightness functions (cmp. with
|
||||
latest ACPI spec Appendix B), let the ACPI video driver control backlight and
|
||||
switch backlight control off in vendor specific ACPI drivers (asus_acpi,
|
||||
thinkpad_acpi, eeepc, fujitsu_laptop, msi_laptop, sony_laptop, acer-wmi).
|
||||
|
||||
Currently it is possible to load above drivers and let both poke on the
|
||||
brightness HW registers, the video and vendor specific ACPI drivers -> bad.
|
||||
|
||||
This patch provides the basic support to check for BIOS capabilities before
|
||||
driver loading time. Driver specific modifications are in separate follow up
|
||||
patches.
|
||||
|
||||
acpi_backlight=vendor/video
|
||||
boot params forces video.ko or vendor specific drivers to keep its
|
||||
fingers off backlight control even it would find needed functions.
|
||||
The corresponding vendor specific driver be used then.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
Documentation/kernel-parameters.txt | 13 +
|
||||
drivers/acpi/Makefile | 5
|
||||
drivers/acpi/scan.c | 32 ----
|
||||
drivers/acpi/video.c | 28 ++-
|
||||
drivers/acpi/video_detect.c | 268 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/acpi.h | 44 +++++
|
||||
6 files changed, 347 insertions(+), 43 deletions(-)
|
||||
create mode 100644 drivers/acpi/video_detect.c
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -200,6 +200,19 @@ and is between 256 and 4096 characters.
|
||||
that require a timer override, but don't have
|
||||
HPET
|
||||
|
||||
+ acpi_backlight= [HW,ACPI]
|
||||
+ acpi_backlight=vendor
|
||||
+ acpi_backlight=video
|
||||
+ If set to vendor, it enforces the use of a
|
||||
+ vendor specific ACPI driver for backlight switching
|
||||
+ (e.g. thinkpad_acpi, sony_acpi, etc.) instead
|
||||
+ of the video.ko driver.
|
||||
+
|
||||
+ acpi_display_output= [HW,ACPI]
|
||||
+ acpi_display_output=vendor
|
||||
+ acpi_display_output=video
|
||||
+ See above.
|
||||
+
|
||||
acpi.debug_layer= [HW,ACPI]
|
||||
Format: <int>
|
||||
Each bit of the <int> indicates an ACPI debug layer,
|
||||
--- a/drivers/acpi/Makefile
|
||||
+++ b/drivers/acpi/Makefile
|
||||
@@ -46,7 +46,12 @@ obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
+
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
+ifdef CONFIG_ACPI_VIDEO
|
||||
+obj-y += video_detect.o
|
||||
+endif
|
||||
+
|
||||
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
|
||||
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
|
||||
obj-$(CONFIG_ACPI_POWER) += power.o
|
||||
--- a/drivers/acpi/scan.c
|
||||
+++ b/drivers/acpi/scan.c
|
||||
@@ -908,36 +908,6 @@ static void acpi_device_get_busid(struct
|
||||
}
|
||||
}
|
||||
|
||||
-static int
|
||||
-acpi_video_bus_match(struct acpi_device *device)
|
||||
-{
|
||||
- acpi_handle h_dummy;
|
||||
-
|
||||
- if (!device)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- /* Since there is no HID, CID for ACPI Video drivers, we have
|
||||
- * to check well known required nodes for each feature we support.
|
||||
- */
|
||||
-
|
||||
- /* Does this device able to support video switching ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- /* Does this device able to retrieve a video ROM ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- /* Does this device able to configure which video head to be POSTed ? */
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
|
||||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
|
||||
- return 0;
|
||||
-
|
||||
- return -ENODEV;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* acpi_bay_match - see if a device is an ejectable driver bay
|
||||
*
|
||||
@@ -1020,7 +990,7 @@ static void acpi_device_set_id(struct ac
|
||||
will get autoloaded and the device might still match
|
||||
against another driver.
|
||||
*/
|
||||
- if (ACPI_SUCCESS(acpi_video_bus_match(device)))
|
||||
+ if (acpi_is_video_device(device))
|
||||
cid_add = ACPI_VIDEO_HID;
|
||||
else if (ACPI_SUCCESS(acpi_bay_match(device)))
|
||||
cid_add = ACPI_BAY_HID;
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -759,7 +759,8 @@ static void acpi_video_device_find_cap(s
|
||||
device->cap._DSS = 1;
|
||||
}
|
||||
|
||||
- max_level = acpi_video_init_brightness(device);
|
||||
+ if (acpi_video_backlight_support())
|
||||
+ max_level = acpi_video_init_brightness(device);
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && max_level > 0) {
|
||||
int result;
|
||||
@@ -805,18 +806,21 @@ static void acpi_video_device_find_cap(s
|
||||
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
||||
|
||||
}
|
||||
- if (device->cap._DCS && device->cap._DSS){
|
||||
- static int count = 0;
|
||||
- char *name;
|
||||
- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
- if (!name)
|
||||
- return;
|
||||
- sprintf(name, "acpi_video%d", count++);
|
||||
- device->output_dev = video_output_register(name,
|
||||
- NULL, device, &acpi_output_properties);
|
||||
- kfree(name);
|
||||
+
|
||||
+ if (acpi_video_display_switch_support()) {
|
||||
+
|
||||
+ if (device->cap._DCS && device->cap._DSS) {
|
||||
+ static int count;
|
||||
+ char *name;
|
||||
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
+ if (!name)
|
||||
+ return;
|
||||
+ sprintf(name, "acpi_video%d", count++);
|
||||
+ device->output_dev = video_output_register(name,
|
||||
+ NULL, device, &acpi_output_properties);
|
||||
+ kfree(name);
|
||||
+ }
|
||||
}
|
||||
- return;
|
||||
}
|
||||
|
||||
/*
|
||||
--- /dev/null
|
||||
+++ b/drivers/acpi/video_detect.c
|
||||
@@ -0,0 +1,268 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2008 SuSE Linux Products GmbH
|
||||
+ * Thomas Renninger <trenn@suse.de>
|
||||
+ *
|
||||
+ * May be copied or modified under the terms of the GNU General Public License
|
||||
+ *
|
||||
+ * video_detect.c:
|
||||
+ * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
|
||||
+ * There a Linux specific (Spec does not provide a HID for video devices) is
|
||||
+ * assinged
|
||||
+ *
|
||||
+ * After PCI devices are glued with ACPI devices
|
||||
+ * acpi_get_physical_pci_device() can be called to identify ACPI graphics
|
||||
+ * devices for which a real graphics card is plugged in
|
||||
+ *
|
||||
+ * Now acpi_video_get_capabilities() can be called to check which
|
||||
+ * capabilities the graphics cards plugged in support. The check for general
|
||||
+ * video capabilities will be triggered by the first caller of
|
||||
+ * acpi_video_get_capabilities(NULL); which will happen when the first
|
||||
+ * backlight (or display output) switching supporting driver calls:
|
||||
+ * acpi_video_backlight_support();
|
||||
+ *
|
||||
+ * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
|
||||
+ * are available, video.ko should be used to handle the device.
|
||||
+ *
|
||||
+ * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
|
||||
+ * sony_acpi,... can take care about backlight brightness and display output
|
||||
+ * switching.
|
||||
+ *
|
||||
+ * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
|
||||
+ * this file will not be compiled, acpi_video_get_capabilities() and
|
||||
+ * acpi_video_backlight_support() will always return 0 and vendor specific
|
||||
+ * drivers always can handle backlight.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/dmi.h>
|
||||
+
|
||||
+ACPI_MODULE_NAME("video");
|
||||
+#define ACPI_VIDEO_COMPONENT 0x08000000
|
||||
+#define _COMPONENT ACPI_VIDEO_COMPONENT
|
||||
+
|
||||
+static long acpi_video_support;
|
||||
+static bool acpi_video_caps_checked;
|
||||
+
|
||||
+static acpi_status
|
||||
+acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
|
||||
+ void **retyurn_value)
|
||||
+{
|
||||
+ long *cap = context;
|
||||
+ acpi_handle h_dummy;
|
||||
+
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
|
||||
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
|
||||
+ "support\n"));
|
||||
+ *cap |= ACPI_VIDEO_BACKLIGHT;
|
||||
+ /* We have backlight support, no need to scan further */
|
||||
+ return AE_CTRL_TERMINATE;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Returns true if the device is a video device which can be handled by
|
||||
+ * video.ko.
|
||||
+ * The device will get a Linux specific CID added in scan.c to
|
||||
+ * identify the device as an ACPI graphics device
|
||||
+ * Be aware that the graphics device may not be physically present
|
||||
+ * Use acpi_video_get_capabilities() to detect general ACPI video
|
||||
+ * capabilities of present cards
|
||||
+ */
|
||||
+long acpi_is_video_device(struct acpi_device *device)
|
||||
+{
|
||||
+ acpi_handle h_dummy;
|
||||
+ long video_caps = 0;
|
||||
+
|
||||
+ if (!device)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Does this device able to support video switching ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||
+
|
||||
+ /* Does this device able to retrieve a video ROM ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
|
||||
+
|
||||
+ /* Does this device able to configure which video head to be POSTed ? */
|
||||
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
|
||||
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
|
||||
+ video_caps |= ACPI_VIDEO_DEVICE_POSTING;
|
||||
+
|
||||
+ /* Only check for backlight functionality if one of the above hit. */
|
||||
+ if (video_caps)
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
|
||||
+ ACPI_UINT32_MAX, acpi_backlight_cap_match,
|
||||
+ &video_caps, NULL);
|
||||
+
|
||||
+ return video_caps;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_is_video_device);
|
||||
+
|
||||
+static acpi_status
|
||||
+find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
+{
|
||||
+ long *cap = context;
|
||||
+ struct device *dev;
|
||||
+ struct acpi_device *acpi_dev;
|
||||
+
|
||||
+ const struct acpi_device_id video_ids[] = {
|
||||
+ {ACPI_VIDEO_HID, 0},
|
||||
+ {"", 0},
|
||||
+ };
|
||||
+ if (acpi_bus_get_device(handle, &acpi_dev))
|
||||
+ return AE_OK;
|
||||
+
|
||||
+ if (!acpi_match_device_ids(acpi_dev, video_ids)) {
|
||||
+ dev = acpi_get_physical_pci_device(handle);
|
||||
+ if (!dev)
|
||||
+ return AE_OK;
|
||||
+ put_device(dev);
|
||||
+ *cap |= acpi_is_video_device(acpi_dev);
|
||||
+ }
|
||||
+ return AE_OK;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Returns the video capabilities of a specific ACPI graphics device
|
||||
+ *
|
||||
+ * if NULL is passed as argument all ACPI devices are enumerated and
|
||||
+ * all graphics capabilities of physically present devices are
|
||||
+ * summerized and returned. This is cached and done only once.
|
||||
+ */
|
||||
+long acpi_video_get_capabilities(acpi_handle graphics_handle)
|
||||
+{
|
||||
+ long caps = 0;
|
||||
+ struct acpi_device *tmp_dev;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ if (acpi_video_caps_checked && graphics_handle == NULL)
|
||||
+ return acpi_video_support;
|
||||
+
|
||||
+ if (!graphics_handle) {
|
||||
+ /* Only do the global walk through all graphics devices once */
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
+ ACPI_UINT32_MAX, find_video,
|
||||
+ &caps, NULL);
|
||||
+ /* There might be boot param flags set already... */
|
||||
+ acpi_video_support |= caps;
|
||||
+ acpi_video_caps_checked = 1;
|
||||
+ /* Add blacklists here. Be careful to use the right *DMI* bits
|
||||
+ * to still be able to override logic via boot params, e.g.:
|
||||
+ *
|
||||
+ * if (dmi_name_in_vendors("XY")) {
|
||||
+ * acpi_video_support |=
|
||||
+ * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
|
||||
+ * acpi_video_support |=
|
||||
+ * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
|
||||
+ *}
|
||||
+ */
|
||||
+ } else {
|
||||
+ status = acpi_bus_get_device(graphics_handle, &tmp_dev);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
|
||||
+ ACPI_UINT32_MAX, find_video,
|
||||
+ &caps, NULL);
|
||||
+ }
|
||||
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
|
||||
+ graphics_handle ? caps : acpi_video_support,
|
||||
+ graphics_handle ? "on device " : "in general",
|
||||
+ graphics_handle ? acpi_device_bid(tmp_dev) : ""));
|
||||
+ return caps;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_get_capabilities);
|
||||
+
|
||||
+/* Returns true if video.ko can do backlight switching */
|
||||
+int acpi_video_backlight_support(void)
|
||||
+{
|
||||
+ /*
|
||||
+ * We must check whether the ACPI graphics device is physically plugged
|
||||
+ * in. Therefore this must be called after binding PCI and ACPI devices
|
||||
+ */
|
||||
+ if (!acpi_video_caps_checked)
|
||||
+ acpi_video_get_capabilities(NULL);
|
||||
+
|
||||
+ /* First check for boot param -> highest prio */
|
||||
+ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Then check for DMI blacklist -> second highest prio */
|
||||
+ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Then go the default way */
|
||||
+ return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_backlight_support);
|
||||
+
|
||||
+/*
|
||||
+ * Returns true if video.ko can do display output switching.
|
||||
+ * This does not work well/at all with binary graphics drivers
|
||||
+ * which disable system io ranges and do it on their own.
|
||||
+ */
|
||||
+int acpi_video_display_switch_support(void)
|
||||
+{
|
||||
+ if (!acpi_video_caps_checked)
|
||||
+ acpi_video_get_capabilities(NULL);
|
||||
+
|
||||
+ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
|
||||
+ return 0;
|
||||
+ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
|
||||
+ return 1;
|
||||
+
|
||||
+ return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||
+}
|
||||
+EXPORT_SYMBOL(acpi_video_display_switch_support);
|
||||
+
|
||||
+/*
|
||||
+ * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video
|
||||
+ * To force that backlight or display output switching is processed by vendor
|
||||
+ * specific acpi drivers or video.ko driver.
|
||||
+ */
|
||||
+int __init acpi_backlight(char *str)
|
||||
+{
|
||||
+ if (str == NULL || *str == '\0')
|
||||
+ return 1;
|
||||
+ else {
|
||||
+ if (!strcmp("vendor", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
|
||||
+ if (!strcmp("video", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("acpi_backlight=", acpi_backlight);
|
||||
+
|
||||
+int __init acpi_display_output(char *str)
|
||||
+{
|
||||
+ if (str == NULL || *str == '\0')
|
||||
+ return 1;
|
||||
+ else {
|
||||
+ if (!strcmp("vendor", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
|
||||
+ if (!strcmp("video", str))
|
||||
+ acpi_video_support |=
|
||||
+ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("acpi_display_output=", acpi_display_output);
|
||||
--- a/include/linux/acpi.h
|
||||
+++ b/include/linux/acpi.h
|
||||
@@ -202,6 +202,50 @@ extern bool wmi_has_guid(const char *gui
|
||||
|
||||
#endif /* CONFIG_ACPI_WMI */
|
||||
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001
|
||||
+#define ACPI_VIDEO_DEVICE_POSTING 0x0002
|
||||
+#define ACPI_VIDEO_ROM_AVAILABLE 0x0004
|
||||
+#define ACPI_VIDEO_BACKLIGHT 0x0008
|
||||
+#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010
|
||||
+#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080
|
||||
+#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100
|
||||
+#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
|
||||
+#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
|
||||
+
|
||||
+#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
|
||||
+
|
||||
+extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
|
||||
+extern long acpi_is_video_device(struct acpi_device *device);
|
||||
+extern int acpi_video_backlight_support(void);
|
||||
+extern int acpi_video_display_switch_support(void);
|
||||
+
|
||||
+#else
|
||||
+
|
||||
+static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline long acpi_is_video_device(struct acpi_device *device)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int acpi_video_backlight_support(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int acpi_video_display_switch_support(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */
|
||||
+
|
||||
extern int acpi_blacklisted(void);
|
||||
#ifdef CONFIG_DMI
|
||||
extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] Acer-WMI: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 017f8ecd1cedb482392f0500ee3701b8c50a46f9
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/acer-wmi.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/drivers/misc/acer-wmi.c
|
||||
+++ b/drivers/misc/acer-wmi.c
|
||||
@@ -1242,6 +1242,12 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
set_quirks();
|
||||
|
||||
+ if (!acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
|
||||
+ interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
+ printk(ACER_INFO "Brightness must be controlled by "
|
||||
+ "generic video driver\n");
|
||||
+ }
|
||||
+
|
||||
if (platform_driver_register(&acer_platform_driver)) {
|
||||
printk(ACER_ERR "Unable to register platform driver.\n");
|
||||
goto error_platform_register;
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] asus-acpi: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit aaa47082a287d66fad32e3289e01bb9419ab18da
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/asus-laptop.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/misc/asus-laptop.c
|
||||
+++ b/drivers/misc/asus-laptop.c
|
||||
@@ -1208,9 +1208,13 @@ static int __init asus_laptop_init(void)
|
||||
|
||||
dev = acpi_get_physical_device(hotk->device->handle);
|
||||
|
||||
- result = asus_backlight_init(dev);
|
||||
- if (result)
|
||||
- goto fail_backlight;
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ result = asus_backlight_init(dev);
|
||||
+ if (result)
|
||||
+ goto fail_backlight;
|
||||
+ } else
|
||||
+ printk(ASUS_INFO "Brightness ignored, must be controlled by "
|
||||
+ "ACPI video driver\n");
|
||||
|
||||
result = asus_led_init(dev);
|
||||
if (result)
|
||||
@@ -0,0 +1,39 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] compal: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit efbc58e3236022d040e1c1f177ee5971d46b034f
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/compal-laptop.c | 12 +++++++-----
|
||||
1 files changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c
|
||||
index 344b790..11003bb 100644
|
||||
--- a/drivers/misc/compal-laptop.c
|
||||
+++ b/drivers/misc/compal-laptop.c
|
||||
@@ -326,12 +326,14 @@ static int __init compal_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
|
||||
- &compalbl_ops);
|
||||
- if (IS_ERR(compalbl_device))
|
||||
- return PTR_ERR(compalbl_device);
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
|
||||
+ &compalbl_ops);
|
||||
+ if (IS_ERR(compalbl_device))
|
||||
+ return PTR_ERR(compalbl_device);
|
||||
|
||||
- compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
|
||||
+ compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&compal_driver);
|
||||
if (ret)
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] eeepc-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
commit bb7e1665304cba64b1178237c966308d06b33182
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/eeepc-laptop.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/misc/eeepc-laptop.c
|
||||
+++ b/drivers/misc/eeepc-laptop.c
|
||||
@@ -636,9 +636,15 @@ static int __init eeepc_laptop_init(void
|
||||
return -ENODEV;
|
||||
}
|
||||
dev = acpi_get_physical_device(ehotk->device->handle);
|
||||
- result = eeepc_backlight_init(dev);
|
||||
- if (result)
|
||||
- goto fail_backlight;
|
||||
+
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ result = eeepc_backlight_init(dev);
|
||||
+ if (result)
|
||||
+ goto fail_backlight;
|
||||
+ } else
|
||||
+ printk(EEEPC_INFO "Backlight controlled by ACPI video "
|
||||
+ "driver\n");
|
||||
+
|
||||
result = eeepc_hwmon_init(dev);
|
||||
if (result)
|
||||
goto fail_hwmon;
|
||||
@@ -0,0 +1,61 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] fujitsu-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 44cce15b053d27477980e34b1086e0c3ce642afe
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/fujitsu-laptop.c | 26 ++++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/misc/fujitsu-laptop.c
|
||||
+++ b/drivers/misc/fujitsu-laptop.c
|
||||
@@ -970,16 +970,16 @@ static int __init fujitsu_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- fujitsu->bl_device =
|
||||
- backlight_device_register("fujitsu-laptop", NULL, NULL,
|
||||
- &fujitsubl_ops);
|
||||
- if (IS_ERR(fujitsu->bl_device))
|
||||
- return PTR_ERR(fujitsu->bl_device);
|
||||
-
|
||||
- max_brightness = fujitsu->max_brightness;
|
||||
-
|
||||
- fujitsu->bl_device->props.max_brightness = max_brightness - 1;
|
||||
- fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
|
||||
+ if (!acpi_video_backlight_support()) {
|
||||
+ fujitsu->bl_device =
|
||||
+ backlight_device_register("fujitsu-laptop", NULL, NULL,
|
||||
+ &fujitsubl_ops);
|
||||
+ if (IS_ERR(fujitsu->bl_device))
|
||||
+ return PTR_ERR(fujitsu->bl_device);
|
||||
+ max_brightness = fujitsu->max_brightness;
|
||||
+ fujitsu->bl_device->props.max_brightness = max_brightness - 1;
|
||||
+ fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&fujitsupf_driver);
|
||||
if (ret)
|
||||
@@ -1015,7 +1015,8 @@ fail_hotkey:
|
||||
|
||||
fail_backlight:
|
||||
|
||||
- backlight_device_unregister(fujitsu->bl_device);
|
||||
+ if (fujitsu->bl_device)
|
||||
+ backlight_device_unregister(fujitsu->bl_device);
|
||||
|
||||
fail_platform_device2:
|
||||
|
||||
@@ -1042,7 +1043,8 @@ static void __exit fujitsu_cleanup(void)
|
||||
&fujitsupf_attribute_group);
|
||||
platform_device_unregister(fujitsu->pf_device);
|
||||
platform_driver_unregister(&fujitsupf_driver);
|
||||
- backlight_device_unregister(fujitsu->bl_device);
|
||||
+ if (fujitsu->bl_device)
|
||||
+ backlight_device_unregister(fujitsu->bl_device);
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_driver);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] msi-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit a8c338259a436627d2427d70dc31fac67b86b9e6
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/msi-laptop.c | 16 ++++++++++------
|
||||
1 files changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
|
||||
index de898c6..759763d 100644
|
||||
--- a/drivers/misc/msi-laptop.c
|
||||
+++ b/drivers/misc/msi-laptop.c
|
||||
@@ -347,12 +347,16 @@ static int __init msi_init(void)
|
||||
|
||||
/* Register backlight stuff */
|
||||
|
||||
- msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
|
||||
- &msibl_ops);
|
||||
- if (IS_ERR(msibl_device))
|
||||
- return PTR_ERR(msibl_device);
|
||||
-
|
||||
- msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ printk(KERN_INFO "MSI: Brightness ignored, must be controlled "
|
||||
+ "by ACPI video driver\n");
|
||||
+ } else {
|
||||
+ msibl_device = backlight_device_register("msi-laptop-bl", NULL,
|
||||
+ NULL, &msibl_ops);
|
||||
+ if (IS_ERR(msibl_device))
|
||||
+ return PTR_ERR(msibl_device);
|
||||
+ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
|
||||
+ }
|
||||
|
||||
ret = platform_driver_register(&msipf_driver);
|
||||
if (ret)
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] sony-laptop: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit 1d38a0697573617e7f4d184207cced6cbe8d54d5
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/sony-laptop.c | 6 +++++-
|
||||
1 files changed, 5 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
|
||||
index 60775be..3d178ab 100644
|
||||
--- a/drivers/misc/sony-laptop.c
|
||||
+++ b/drivers/misc/sony-laptop.c
|
||||
@@ -1038,7 +1038,11 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
goto outinput;
|
||||
}
|
||||
|
||||
- if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ printk(KERN_INFO DRV_PFX "Sony: Brightness ignored, must be "
|
||||
+ "controlled by ACPI video driver\n");
|
||||
+ } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
|
||||
+ &handle))) {
|
||||
sony_backlight_device = backlight_device_register("sony", NULL,
|
||||
NULL,
|
||||
&sony_backlight_ops);
|
||||
--
|
||||
1.5.4.5
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: [PATCH] thinkpad_acpi: fingers off backlight if video.ko is serving this functionality
|
||||
Patch-Mainline: queued for .28 in Len's/ak's ACPI tree
|
||||
|
||||
commit bcca9a4a97b6e270793003d745d6f9439e1357a8
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
---
|
||||
drivers/misc/thinkpad_acpi.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/misc/thinkpad_acpi.c
|
||||
+++ b/drivers/misc/thinkpad_acpi.c
|
||||
@@ -4918,16 +4918,25 @@ static int __init brightness_init(struct
|
||||
*/
|
||||
b = tpacpi_check_std_acpi_brightness_support();
|
||||
if (b > 0) {
|
||||
- if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
|
||||
- printk(TPACPI_NOTICE
|
||||
- "Lenovo BIOS switched to ACPI backlight "
|
||||
- "control mode\n");
|
||||
- }
|
||||
- if (brightness_enable > 1) {
|
||||
- printk(TPACPI_NOTICE
|
||||
- "standard ACPI backlight interface "
|
||||
- "available, not loading native one...\n");
|
||||
- return 1;
|
||||
+
|
||||
+ if (acpi_video_backlight_support()) {
|
||||
+ if (brightness_enable > 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Standard ACPI backlight interface "
|
||||
+ "available, not loading native one.\n");
|
||||
+ return 1;
|
||||
+ } else if (brightness_enable == 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Backlight control force, even standard "
|
||||
+ "ACPI backlight interface available\n");
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (brightness_enable > 1) {
|
||||
+ printk(TPACPI_NOTICE
|
||||
+ "Standard ACPI backlight interface not "
|
||||
+ "available, thinkpad_acpi driver "
|
||||
+ "will take over control\n");
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: acpi: remove bay.c from makefile
|
||||
|
||||
patches.fixes/acpi-bay-remove-useless-code.patch removed drivers/acpi/bay.c.
|
||||
This patch removes the build infrastructure for it.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
drivers/acpi/Kconfig | 8 --------
|
||||
drivers/acpi/Makefile | 1 -
|
||||
2 files changed, 9 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/Kconfig
|
||||
+++ b/drivers/acpi/Kconfig
|
||||
@@ -162,14 +162,6 @@ config ACPI_DOCK
|
||||
help
|
||||
This driver adds support for ACPI controlled docking stations
|
||||
|
||||
-config ACPI_BAY
|
||||
- tristate "Removable Drive Bay (EXPERIMENTAL)"
|
||||
- depends on EXPERIMENTAL
|
||||
- depends on ACPI_DOCK
|
||||
- help
|
||||
- This driver adds support for ACPI controlled removable drive
|
||||
- bays such as the IBM ultrabay or the Dell Module Bay.
|
||||
-
|
||||
config ACPI_PROCESSOR
|
||||
tristate "Processor"
|
||||
select THERMAL
|
||||
--- a/drivers/acpi/Makefile
|
||||
+++ b/drivers/acpi/Makefile
|
||||
@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
|
||||
obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
-obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
ifdef CONFIG_ACPI_VIDEO
|
||||
@@ -0,0 +1,425 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: remove useless code
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Bay driver is replaced by dock driver, remove it.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
--- linux-2.6.26.orig/drivers/acpi/bay.c 2008-07-13 23:51:29.000000000 +0200
|
||||
+++ linux-2.6.26/drivers/acpi/bay.c 1970-01-01 01:00:00.000000000 +0100
|
||||
@@ -1,411 +0,0 @@
|
||||
-/*
|
||||
- * bay.c - ACPI removable drive bay driver
|
||||
- *
|
||||
- * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@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/kernel.h>
|
||||
-#include <linux/module.h>
|
||||
-#include <linux/init.h>
|
||||
-#include <linux/types.h>
|
||||
-#include <linux/notifier.h>
|
||||
-#include <acpi/acpi_bus.h>
|
||||
-#include <acpi/acpi_drivers.h>
|
||||
-#include <linux/seq_file.h>
|
||||
-#include <asm/uaccess.h>
|
||||
-#include <linux/platform_device.h>
|
||||
-
|
||||
-ACPI_MODULE_NAME("bay");
|
||||
-MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
-MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
|
||||
-MODULE_LICENSE("GPL");
|
||||
-#define ACPI_BAY_CLASS "bay"
|
||||
-#define ACPI_BAY_COMPONENT 0x10000000
|
||||
-#define _COMPONENT ACPI_BAY_COMPONENT
|
||||
-#define bay_dprintk(h,s) {\
|
||||
- char prefix[80] = {'\0'};\
|
||||
- struct acpi_buffer buffer = {sizeof(prefix), prefix};\
|
||||
- acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
|
||||
- printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
|
||||
-static void bay_notify(acpi_handle handle, u32 event, void *data);
|
||||
-
|
||||
-static const struct acpi_device_id bay_device_ids[] = {
|
||||
- {"LNXIOBAY", 0},
|
||||
- {"", 0},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(acpi, bay_device_ids);
|
||||
-
|
||||
-struct bay {
|
||||
- acpi_handle handle;
|
||||
- char *name;
|
||||
- struct list_head list;
|
||||
- struct platform_device *pdev;
|
||||
-};
|
||||
-
|
||||
-static LIST_HEAD(drive_bays);
|
||||
-
|
||||
-
|
||||
-/*****************************************************************************
|
||||
- * Drive Bay functions *
|
||||
- *****************************************************************************/
|
||||
-/**
|
||||
- * is_ejectable - see if a device is ejectable
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object has a _EJ0 method, then it is ejectable
|
||||
- */
|
||||
-static int is_ejectable(acpi_handle handle)
|
||||
-{
|
||||
- acpi_status status;
|
||||
- acpi_handle tmp;
|
||||
-
|
||||
- status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- return 0;
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * bay_present - see if the bay device is present
|
||||
- * @bay: the drive bay
|
||||
- *
|
||||
- * execute the _STA method.
|
||||
- */
|
||||
-static int bay_present(struct bay *bay)
|
||||
-{
|
||||
- unsigned long long sta;
|
||||
- acpi_status status;
|
||||
-
|
||||
- if (bay) {
|
||||
- status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
|
||||
- if (ACPI_SUCCESS(status) && sta)
|
||||
- return 1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * eject_device - respond to an eject request
|
||||
- * @handle - the device to eject
|
||||
- *
|
||||
- * Call this devices _EJ0 method.
|
||||
- */
|
||||
-static void eject_device(acpi_handle handle)
|
||||
-{
|
||||
- struct acpi_object_list arg_list;
|
||||
- union acpi_object arg;
|
||||
-
|
||||
- bay_dprintk(handle, "Ejecting device");
|
||||
-
|
||||
- arg_list.count = 1;
|
||||
- arg_list.pointer = &arg;
|
||||
- arg.type = ACPI_TYPE_INTEGER;
|
||||
- arg.integer.value = 1;
|
||||
-
|
||||
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
- &arg_list, NULL)))
|
||||
- pr_debug("Failed to evaluate _EJ0!\n");
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * show_present - read method for "present" file in sysfs
|
||||
- */
|
||||
-static ssize_t show_present(struct device *dev,
|
||||
- struct device_attribute *attr, char *buf)
|
||||
-{
|
||||
- struct bay *bay = dev_get_drvdata(dev);
|
||||
- return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
|
||||
-
|
||||
-}
|
||||
-static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
|
||||
-
|
||||
-/*
|
||||
- * write_eject - write method for "eject" file in sysfs
|
||||
- */
|
||||
-static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
|
||||
- const char *buf, size_t count)
|
||||
-{
|
||||
- struct bay *bay = dev_get_drvdata(dev);
|
||||
-
|
||||
- if (!count)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- eject_device(bay->handle);
|
||||
- return count;
|
||||
-}
|
||||
-static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
|
||||
-
|
||||
-/**
|
||||
- * is_ata - see if a device is an ata device
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object has one of 4 ATA ACPI methods defined,
|
||||
- * then it is an ATA device
|
||||
- */
|
||||
-static int is_ata(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle tmp;
|
||||
-
|
||||
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
- return 1;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * parent_is_ata(acpi_handle handle)
|
||||
- *
|
||||
- */
|
||||
-static int parent_is_ata(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle phandle;
|
||||
-
|
||||
- if (acpi_get_parent(handle, &phandle))
|
||||
- return 0;
|
||||
-
|
||||
- return is_ata(phandle);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * is_ejectable_bay - see if a device is an ejectable drive bay
|
||||
- * @handle: acpi handle of the device
|
||||
- *
|
||||
- * If an acpi object is ejectable and has one of the ACPI ATA
|
||||
- * methods defined, then we can safely call it an ejectable
|
||||
- * drive bay
|
||||
- */
|
||||
-static int is_ejectable_bay(acpi_handle handle)
|
||||
-{
|
||||
- if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
|
||||
- return 1;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-#if 0
|
||||
-/**
|
||||
- * eject_removable_drive - try to eject this drive
|
||||
- * @dev : the device structure of the drive
|
||||
- *
|
||||
- * If a device is a removable drive that requires an _EJ0 method
|
||||
- * to be executed in order to safely remove from the system, do
|
||||
- * it. ATM - always returns success
|
||||
- */
|
||||
-int eject_removable_drive(struct device *dev)
|
||||
-{
|
||||
- acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
|
||||
-
|
||||
- if (handle) {
|
||||
- bay_dprintk(handle, "Got device handle");
|
||||
- if (is_ejectable_bay(handle))
|
||||
- eject_device(handle);
|
||||
- } else {
|
||||
- printk("No acpi handle for device\n");
|
||||
- }
|
||||
-
|
||||
- /* should I return an error code? */
|
||||
- return 0;
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(eject_removable_drive);
|
||||
-#endif /* 0 */
|
||||
-
|
||||
-static int acpi_bay_add_fs(struct bay *bay)
|
||||
-{
|
||||
- int ret;
|
||||
- struct device *dev = &bay->pdev->dev;
|
||||
-
|
||||
- ret = device_create_file(dev, &dev_attr_present);
|
||||
- if (ret)
|
||||
- goto add_fs_err;
|
||||
- ret = device_create_file(dev, &dev_attr_eject);
|
||||
- if (ret) {
|
||||
- device_remove_file(dev, &dev_attr_present);
|
||||
- goto add_fs_err;
|
||||
- }
|
||||
- return 0;
|
||||
-
|
||||
- add_fs_err:
|
||||
- bay_dprintk(bay->handle, "Error adding sysfs files\n");
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static void acpi_bay_remove_fs(struct bay *bay)
|
||||
-{
|
||||
- struct device *dev = &bay->pdev->dev;
|
||||
-
|
||||
- /* cleanup sysfs */
|
||||
- device_remove_file(dev, &dev_attr_present);
|
||||
- device_remove_file(dev, &dev_attr_eject);
|
||||
-}
|
||||
-
|
||||
-static int bay_is_dock_device(acpi_handle handle)
|
||||
-{
|
||||
- acpi_handle parent;
|
||||
-
|
||||
- acpi_get_parent(handle, &parent);
|
||||
-
|
||||
- /* if the device or it's parent is dependent on the
|
||||
- * dock, then we are a dock device
|
||||
- */
|
||||
- return (is_dock_device(handle) || is_dock_device(parent));
|
||||
-}
|
||||
-
|
||||
-static int bay_add(acpi_handle handle, int id)
|
||||
-{
|
||||
- acpi_status status;
|
||||
- struct bay *new_bay;
|
||||
- struct platform_device *pdev;
|
||||
- struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
|
||||
-
|
||||
- bay_dprintk(handle, "Adding notify handler");
|
||||
-
|
||||
- /*
|
||||
- * Initialize bay device structure
|
||||
- */
|
||||
- new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
|
||||
- INIT_LIST_HEAD(&new_bay->list);
|
||||
- new_bay->handle = handle;
|
||||
- new_bay->name = (char *)nbuffer.pointer;
|
||||
-
|
||||
- /* initialize platform device stuff */
|
||||
- pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
|
||||
- if (IS_ERR(pdev)) {
|
||||
- printk(KERN_ERR PREFIX "Error registering bay device\n");
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
- new_bay->pdev = pdev;
|
||||
- platform_set_drvdata(pdev, new_bay);
|
||||
-
|
||||
- /*
|
||||
- * we want the bay driver to be able to send uevents
|
||||
- */
|
||||
- pdev->dev.uevent_suppress = 0;
|
||||
-
|
||||
- /* register for events on this device */
|
||||
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify, new_bay);
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
|
||||
- platform_device_unregister(new_bay->pdev);
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
-
|
||||
- if (acpi_bay_add_fs(new_bay)) {
|
||||
- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify);
|
||||
- platform_device_unregister(new_bay->pdev);
|
||||
- goto bay_add_err;
|
||||
- }
|
||||
-
|
||||
- /* if we are on a dock station, we should register for dock
|
||||
- * notifications.
|
||||
- */
|
||||
- if (bay_is_dock_device(handle)) {
|
||||
- bay_dprintk(handle, "Is dependent on dock\n");
|
||||
- register_hotplug_dock_device(handle, bay_notify, new_bay);
|
||||
- }
|
||||
- list_add(&new_bay->list, &drive_bays);
|
||||
- printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
|
||||
- return 0;
|
||||
-
|
||||
-bay_add_err:
|
||||
- kfree(new_bay->name);
|
||||
- kfree(new_bay);
|
||||
- return -ENODEV;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * bay_notify - act upon an acpi bay notification
|
||||
- * @handle: the bay handle
|
||||
- * @event: the acpi event
|
||||
- * @data: our driver data struct
|
||||
- *
|
||||
- */
|
||||
-static void bay_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct bay *bay_dev = (struct bay *)data;
|
||||
- struct device *dev = &bay_dev->pdev->dev;
|
||||
- char event_string[12];
|
||||
- char *envp[] = { event_string, NULL };
|
||||
-
|
||||
- bay_dprintk(handle, "Bay event");
|
||||
- sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
-}
|
||||
-
|
||||
-static acpi_status
|
||||
-find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
-{
|
||||
- int *count = (int *)context;
|
||||
-
|
||||
- /*
|
||||
- * there could be more than one ejectable bay.
|
||||
- * so, just return AE_OK always so that every object
|
||||
- * will be checked.
|
||||
- */
|
||||
- if (is_ejectable_bay(handle)) {
|
||||
- bay_dprintk(handle, "found ejectable bay");
|
||||
- if (!bay_add(handle, *count))
|
||||
- (*count)++;
|
||||
- }
|
||||
- return AE_OK;
|
||||
-}
|
||||
-
|
||||
-static int __init bay_init(void)
|
||||
-{
|
||||
- int bays = 0;
|
||||
-
|
||||
- INIT_LIST_HEAD(&drive_bays);
|
||||
-
|
||||
- if (acpi_disabled)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- /* look for dockable drive bays */
|
||||
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
- ACPI_UINT32_MAX, find_bay, &bays, NULL);
|
||||
-
|
||||
- if (!bays)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void __exit bay_exit(void)
|
||||
-{
|
||||
- struct bay *bay, *tmp;
|
||||
-
|
||||
- list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
|
||||
- if (is_dock_device(bay->handle))
|
||||
- unregister_hotplug_dock_device(bay->handle);
|
||||
- acpi_bay_remove_fs(bay);
|
||||
- acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
|
||||
- bay_notify);
|
||||
- platform_device_unregister(bay->pdev);
|
||||
- kfree(bay->name);
|
||||
- kfree(bay);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-postcore_initcall(bay_init);
|
||||
-module_exit(bay_exit);
|
||||
-
|
||||
@@ -0,0 +1,164 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: Fix duplicate notification handler register
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Battery driver already registers notification handler. To avoid register
|
||||
notification handler again, the patch introduced a notifier chain in
|
||||
global system notifier handler and use it in dock driver, so we can
|
||||
avoid register notification handler.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/bus.c | 15 +++++++++++++++
|
||||
drivers/acpi/dock.c | 46 ++++++++++++++++++++++++----------------------
|
||||
include/acpi/acpi_bus.h | 3 +++
|
||||
3 files changed, 42 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/bus.c
|
||||
+++ b/drivers/acpi/bus.c
|
||||
@@ -496,6 +496,19 @@ static int acpi_bus_check_scope(struct a
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
|
||||
+int register_acpi_bus_notifier(struct notifier_block *nb)
|
||||
+{
|
||||
+ return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
|
||||
+
|
||||
+void unregister_acpi_bus_notifier(struct notifier_block *nb)
|
||||
+{
|
||||
+ blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
|
||||
+
|
||||
/**
|
||||
* acpi_bus_notify
|
||||
* ---------------
|
||||
@@ -506,6 +519,8 @@ static void acpi_bus_notify(acpi_handle
|
||||
int result = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
+ blocking_notifier_call_chain(&acpi_bus_notify_list,
|
||||
+ type, (void *)handle);
|
||||
|
||||
if (acpi_bus_get_device(handle, &device))
|
||||
return;
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -748,6 +748,28 @@ static void dock_notify(acpi_handle hand
|
||||
}
|
||||
}
|
||||
|
||||
+static int acpi_dock_notifier_call(struct notifier_block *this,
|
||||
+ unsigned long event, void *data)
|
||||
+{
|
||||
+ struct dock_station *dock_station;
|
||||
+ acpi_handle handle = (acpi_handle)data;
|
||||
+
|
||||
+ if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
||||
+ && event != ACPI_NOTIFY_EJECT_REQUEST)
|
||||
+ return 0;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ if (dock_station->handle == handle) {
|
||||
+ dock_notify(handle, event, dock_station);
|
||||
+ return 0 ;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block dock_acpi_notifier = {
|
||||
+ .notifier_call = acpi_dock_notifier_call,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* find_dock_devices - find devices on the dock station
|
||||
* @handle: the handle of the device we are examining
|
||||
@@ -859,7 +881,6 @@ static DEVICE_ATTR(uid, S_IRUGO, show_do
|
||||
static int dock_add(acpi_handle handle)
|
||||
{
|
||||
int ret;
|
||||
- acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
struct platform_device *dock_device;
|
||||
@@ -954,23 +975,10 @@ static int dock_add(acpi_handle handle)
|
||||
}
|
||||
add_dock_dependent_device(dock_station, dd);
|
||||
|
||||
- /* register for dock events */
|
||||
- status = acpi_install_notify_handler(dock_station->handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- dock_notify, dock_station);
|
||||
-
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_ERR PREFIX "Error installing notify handler\n");
|
||||
- ret = -ENODEV;
|
||||
- goto dock_add_err;
|
||||
- }
|
||||
-
|
||||
dock_station_count++;
|
||||
list_add(&dock_station->sibiling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
-dock_add_err:
|
||||
- kfree(dd);
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
@@ -988,7 +996,6 @@ dock_add_err_unregister:
|
||||
static int dock_remove(struct dock_station *dock_station)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
- acpi_status status;
|
||||
struct platform_device *dock_device = dock_station->dock_device;
|
||||
|
||||
if (!dock_station_count)
|
||||
@@ -999,13 +1006,6 @@ static int dock_remove(struct dock_stati
|
||||
list)
|
||||
kfree(dd);
|
||||
|
||||
- /* remove dock notify handler */
|
||||
- status = acpi_remove_notify_handler(dock_station->handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- dock_notify);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- printk(KERN_ERR "Error removing notify handler\n");
|
||||
-
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
@@ -1067,6 +1067,7 @@ static int __init dock_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ register_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
||||
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||
return 0;
|
||||
@@ -1076,6 +1077,7 @@ static void __exit dock_exit(void)
|
||||
{
|
||||
struct dock_station *dock_station;
|
||||
|
||||
+ unregister_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling)
|
||||
dock_remove(dock_station);
|
||||
}
|
||||
--- a/include/acpi/acpi_bus.h
|
||||
+++ b/include/acpi/acpi_bus.h
|
||||
@@ -327,6 +327,9 @@ int acpi_bus_get_private_data(acpi_handl
|
||||
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
|
||||
extern int register_acpi_notifier(struct notifier_block *);
|
||||
extern int unregister_acpi_notifier(struct notifier_block *);
|
||||
+
|
||||
+extern int register_acpi_bus_notifier(struct notifier_block *nb);
|
||||
+extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
|
||||
/*
|
||||
* External Functions
|
||||
*/
|
||||
@@ -0,0 +1,57 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: add _LCK support for dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
support _LCK method, which is a optional method for hotplug
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 78d27ce..7bdf93b 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -452,6 +452,25 @@ static inline void complete_undock(struct dock_station *ds)
|
||||
ds->flags &= ~(DOCK_UNDOCKING);
|
||||
}
|
||||
|
||||
+static void dock_lock(struct dock_station *ds, int lock)
|
||||
+{
|
||||
+ struct acpi_object_list arg_list;
|
||||
+ union acpi_object arg;
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ arg_list.count = 1;
|
||||
+ arg_list.pointer = &arg;
|
||||
+ arg.type = ACPI_TYPE_INTEGER;
|
||||
+ arg.integer.value = !!lock;
|
||||
+ status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
||||
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
+ if (lock)
|
||||
+ printk(KERN_WARNING PREFIX "Locking device failed\n");
|
||||
+ else
|
||||
+ printk(KERN_WARNING PREFIX "Unlocking device failed\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* dock_in_progress - see if we are in the middle of handling a dock event
|
||||
* @ds: the dock station
|
||||
@@ -577,6 +596,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
+ dock_lock(ds, 0);
|
||||
eject_dock(ds);
|
||||
if (dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
||||
@@ -617,6 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
hotplug_dock_devices(ds, event);
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
+ dock_lock(ds, 1);
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
@@ -0,0 +1,70 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: add 'type' sysfs file for dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
add a sysfs file to present dock type. Suggested by Holger.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -909,6 +909,26 @@ static ssize_t show_dock_uid(struct devi
|
||||
}
|
||||
static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
||||
|
||||
+static ssize_t show_dock_type(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
+ char *type;
|
||||
+
|
||||
+ if (dock_station->flags & DOCK_IS_DOCK)
|
||||
+ type = "dock_station";
|
||||
+ else if (dock_station->flags & DOCK_IS_ATA)
|
||||
+ type = "ata_bay";
|
||||
+ else if (dock_station->flags & DOCK_IS_BAT)
|
||||
+ type = "battery_bay";
|
||||
+ else
|
||||
+ type = "unknown";
|
||||
+
|
||||
+ return snprintf(buf, PAGE_SIZE, "%s\n", type);
|
||||
+}
|
||||
+static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
|
||||
+
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
@@ -997,6 +1017,9 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
+ ret = device_create_file(&dock_device->dev, &dev_attr_type);
|
||||
+ if (ret)
|
||||
+ printk(KERN_ERR"Error %d adding sysfs file\n", ret);
|
||||
|
||||
/* Find dependent devices */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
@@ -1018,6 +1041,7 @@ static int dock_add(acpi_handle handle)
|
||||
return 0;
|
||||
|
||||
dock_add_err_unregister:
|
||||
+ device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@@ -1045,6 +1069,7 @@ static int dock_remove(struct dock_stati
|
||||
kfree(dd);
|
||||
|
||||
/* cleanup sysfs */
|
||||
+ device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@@ -0,0 +1,47 @@
|
||||
From 1d672ef324e78a467603ef55aa4558cac9f895ba Mon Sep 17 00:00:00 2001
|
||||
From: Holger Macht <hmacht@suse.de>
|
||||
Date: Tue, 20 Jan 2009 12:18:24 +0100
|
||||
Subject: ACPI: dock: Don't eval _STA on every show_docked sysfs read
|
||||
|
||||
From: Holger Macht <hmacht@suse.de>
|
||||
|
||||
commit fc5a9f8841ee87d93376ada5d73117d4d6a373ea upstream.
|
||||
|
||||
Some devices trigger a DEVICE_CHECK on every evalutation of _STA. This
|
||||
can also be seen in commit 8b59560a3baf2e7c24e0fb92ea5d09eca92805db
|
||||
(ACPI: dock: avoid check _STA method). If an undock is processed, the
|
||||
dock driver sends a uevent and userspace might read the show_docked
|
||||
property in sysfs. This causes an evaluation of _STA of the particular
|
||||
device which causes the dock driver to immediately dock again.
|
||||
|
||||
In any case, evaluation of _STA (show_docked) does not necessarily mean
|
||||
that we are docked, so check with the internal device structure.
|
||||
|
||||
http://bugzilla.kernel.org/show_bug.cgi?id=12360
|
||||
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -854,8 +854,14 @@ fdd_out:
|
||||
static ssize_t show_docked(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
- return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
|
||||
+ struct acpi_device *tmp;
|
||||
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
+
|
||||
+ if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
|
||||
+ return snprintf(buf, PAGE_SIZE, "1\n");
|
||||
+ return snprintf(buf, PAGE_SIZE, "0\n");
|
||||
}
|
||||
static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix eject request process
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
commit 2a7feab28d3fc060d320eaba192e49dad1079b7e introduces a bug.
|
||||
My thinkpad actually will send an eject_request and we should follow the
|
||||
eject process to finish the eject, otherwise system still thinks the bay
|
||||
is present.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 25d2161..78d27ce 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -575,11 +575,6 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
*/
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
|
||||
- if (!dock_present(ds)) {
|
||||
- complete_undock(ds);
|
||||
- return -ENODEV;
|
||||
- }
|
||||
-
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
eject_dock(ds);
|
||||
@@ -0,0 +1,61 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix for bay in a dock station
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
an ATA bay can be in a dock and itself can be ejected separately. The
|
||||
patch handles such eject bay. Found by Holger.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 14 ++++++++++----
|
||||
1 file changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -609,6 +609,7 @@ register_hotplug_dock_device(acpi_handle
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
+ int ret = -EINVAL;
|
||||
|
||||
if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
@@ -618,16 +619,21 @@ register_hotplug_dock_device(acpi_handle
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ /*
|
||||
+ * An ATA bay can be in a dock and itself can be ejected
|
||||
+ * seperately, so there are two 'dock stations' which need the
|
||||
+ * ops
|
||||
+ */
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
dd->ops = ops;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
- return 0;
|
||||
+ ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- return -EINVAL;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
@@ -1076,8 +1082,8 @@ find_dock(acpi_handle handle, u32 lvl, v
|
||||
static acpi_status
|
||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- /* If bay is in a dock, it's already handled */
|
||||
- if (is_ejectable_bay(handle) && !is_dock_device(handle))
|
||||
+ /* If bay is a dock, it's already handled */
|
||||
+ if (is_ejectable_bay(handle) && !is_dock(handle))
|
||||
dock_add(handle);
|
||||
return AE_OK;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: fix hotplug race
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
hotplug notification handler and drivers' notification handler are all
|
||||
running in one workqueue. Before hotplug removes an acpi device, the
|
||||
device driver's notification handler is already be recorded to run just
|
||||
after global notification handler. After hotplug notification handler
|
||||
runs, acpica will notice a NULL notification handler and crash. This
|
||||
patch runs hotplug in other workqueue and wait for all acpi notication
|
||||
handlers finish. This is found in battery hotplug, but actually all
|
||||
hotplug can be affected.
|
||||
|
||||
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 25 ++++++++++++++++++++++++-
|
||||
drivers/acpi/osl.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
|
||||
include/acpi/acpiosxf.h | 3 +++
|
||||
3 files changed, 68 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -748,6 +748,20 @@ static void dock_notify(acpi_handle hand
|
||||
}
|
||||
}
|
||||
|
||||
+struct dock_data {
|
||||
+ acpi_handle handle;
|
||||
+ unsigned long event;
|
||||
+ struct dock_station *ds;
|
||||
+};
|
||||
+
|
||||
+static void acpi_dock_deferred_cb(void *context)
|
||||
+{
|
||||
+ struct dock_data *data = (struct dock_data *)context;
|
||||
+
|
||||
+ dock_notify(data->handle, data->event, data->ds);
|
||||
+ kfree(data);
|
||||
+}
|
||||
+
|
||||
static int acpi_dock_notifier_call(struct notifier_block *this,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
@@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struc
|
||||
return 0;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
if (dock_station->handle == handle) {
|
||||
- dock_notify(handle, event, dock_station);
|
||||
+ struct dock_data *dock_data;
|
||||
+
|
||||
+ dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
|
||||
+ if (!dock_data)
|
||||
+ return 0;
|
||||
+ dock_data->handle = handle;
|
||||
+ dock_data->event = event;
|
||||
+ dock_data->ds = dock_station;
|
||||
+ acpi_os_hotplug_execute(acpi_dock_deferred_cb,
|
||||
+ dock_data);
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
--- a/drivers/acpi/osl.c
|
||||
+++ b/drivers/acpi/osl.c
|
||||
@@ -705,6 +705,22 @@ static void acpi_os_execute_deferred(str
|
||||
return;
|
||||
}
|
||||
|
||||
+static void acpi_os_execute_hp_deferred(struct work_struct *work)
|
||||
+{
|
||||
+ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
||||
+ if (!dpc) {
|
||||
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ acpi_os_wait_events_complete(NULL);
|
||||
+
|
||||
+ dpc->function(dpc->context);
|
||||
+ kfree(dpc);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_os_execute
|
||||
@@ -720,12 +736,13 @@ static void acpi_os_execute_deferred(str
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
-acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
- acpi_osd_exec_callback function, void *context)
|
||||
+static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
+ acpi_osd_exec_callback function, void *context, int hp)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_os_dpc *dpc;
|
||||
struct workqueue_struct *queue;
|
||||
+ int ret;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p)] for deferred execution.\n",
|
||||
function, context));
|
||||
@@ -749,9 +766,17 @@ acpi_status acpi_os_execute(acpi_execute
|
||||
dpc->function = function;
|
||||
dpc->context = context;
|
||||
|
||||
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
- queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
|
||||
- if (!queue_work(queue, &dpc->work)) {
|
||||
+ if (!hp) {
|
||||
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
+ queue = (type == OSL_NOTIFY_HANDLER) ?
|
||||
+ kacpi_notify_wq : kacpid_wq;
|
||||
+ ret = queue_work(queue, &dpc->work);
|
||||
+ } else {
|
||||
+ INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
|
||||
+ ret = schedule_work(&dpc->work);
|
||||
+ }
|
||||
+
|
||||
+ if (!ret) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Call to queue_work() failed.\n"));
|
||||
status = AE_ERROR;
|
||||
@@ -760,8 +785,19 @@ acpi_status acpi_os_execute(acpi_execute
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
+acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
+ acpi_osd_exec_callback function, void *context)
|
||||
+{
|
||||
+ return __acpi_os_execute(type, function, context, 0);
|
||||
+}
|
||||
EXPORT_SYMBOL(acpi_os_execute);
|
||||
|
||||
+acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
|
||||
+ void *context)
|
||||
+{
|
||||
+ return __acpi_os_execute(0, function, context, 1);
|
||||
+}
|
||||
+
|
||||
void acpi_os_wait_events_complete(void *context)
|
||||
{
|
||||
flush_workqueue(kacpid_wq);
|
||||
--- a/include/acpi/acpiosxf.h
|
||||
+++ b/include/acpi/acpiosxf.h
|
||||
@@ -193,6 +193,9 @@ acpi_status
|
||||
acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context);
|
||||
|
||||
+acpi_status
|
||||
+acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context);
|
||||
+
|
||||
void acpi_os_wait_events_complete(void *context);
|
||||
|
||||
void acpi_os_sleep(acpi_integer milliseconds);
|
||||
@@ -0,0 +1,214 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: introduce .uevent for devices in dock
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
dock's uevent reported itself, not ata. It might be difficult to find an
|
||||
ata device just according to a dock. This patch introduces docking ops
|
||||
for each device in a dock. when docking, dock driver can send device
|
||||
specific uevent. This should help dock station too (not just bay)
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index f19f643..ac7dfef 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -75,7 +75,7 @@ struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
struct list_head hotplug_list;
|
||||
acpi_handle handle;
|
||||
- acpi_notify_handler handler;
|
||||
+ struct acpi_dock_ops *ops;
|
||||
void *context;
|
||||
};
|
||||
|
||||
@@ -385,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
* First call driver specific hotplug functions
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
|
||||
- if (dd->handler)
|
||||
- dd->handler(dd->handle, event, dd->context);
|
||||
+ if (dd->ops && dd->ops->handler)
|
||||
+ dd->ops->handler(dd->handle, event, dd->context);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -409,6 +409,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
struct device *dev = &ds->dock_device->dev;
|
||||
char event_string[13];
|
||||
char *envp[] = { event_string, NULL };
|
||||
+ struct dock_dependent_device *dd;
|
||||
|
||||
if (num == UNDOCK_EVENT)
|
||||
sprintf(event_string, "EVENT=undock");
|
||||
@@ -419,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
* Indicate that the status of the dock station has
|
||||
* changed.
|
||||
*/
|
||||
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
+ if (num == DOCK_EVENT)
|
||||
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
+
|
||||
+ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
|
||||
+ if (dd->ops && dd->ops->uevent)
|
||||
+ dd->ops->uevent(dd->handle, event, dd->context);
|
||||
+ if (num != DOCK_EVENT)
|
||||
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,7 +596,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
/**
|
||||
* register_hotplug_dock_device - register a hotplug function
|
||||
* @handle: the handle of the device
|
||||
- * @handler: the acpi_notifier_handler to call after docking
|
||||
+ * @ops: handlers to call after docking
|
||||
* @context: device specific data
|
||||
*
|
||||
* If a driver would like to perform a hotplug operation after a dock
|
||||
@@ -596,7 +604,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
* the dock driver after _DCK is executed.
|
||||
*/
|
||||
int
|
||||
-register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
+register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
@@ -612,7 +620,7 @@ register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
- dd->handler = handler;
|
||||
+ dd->ops = ops;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
return 0;
|
||||
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
|
||||
index 97727be..c012307 100644
|
||||
--- a/drivers/ata/libata-acpi.c
|
||||
+++ b/drivers/ata/libata-acpi.c
|
||||
@@ -209,6 +209,46 @@ static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
ata_acpi_handle_hotplug(ap, NULL, event);
|
||||
}
|
||||
|
||||
+static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
|
||||
+ u32 event)
|
||||
+{
|
||||
+ struct kobject *kobj = NULL;
|
||||
+ char event_string[20];
|
||||
+ char *envp[] = { event_string, NULL };
|
||||
+
|
||||
+ if (dev) {
|
||||
+ if (dev->sdev)
|
||||
+ kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
+ } else
|
||||
+ kobj = &ap->dev->kobj;
|
||||
+
|
||||
+ if (kobj) {
|
||||
+ snprintf(event_string, 20, "BAY_EVENT=%d", event);
|
||||
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
|
||||
+{
|
||||
+ ata_acpi_uevent(data, NULL, event);
|
||||
+}
|
||||
+
|
||||
+static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
|
||||
+{
|
||||
+ struct ata_device *dev = data;
|
||||
+ ata_acpi_uevent(dev->link->ap, dev, event);
|
||||
+}
|
||||
+
|
||||
+static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
|
||||
+ .handler = ata_acpi_dev_notify_dock,
|
||||
+ .uevent = ata_acpi_dev_uevent,
|
||||
+};
|
||||
+
|
||||
+static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
|
||||
+ .handler = ata_acpi_ap_notify_dock,
|
||||
+ .uevent = ata_acpi_ap_uevent,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* ata_acpi_associate - associate ATA host with ACPI objects
|
||||
* @host: target ATA host
|
||||
@@ -244,7 +284,7 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
if (ap->acpi_handle) {
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(ap->acpi_handle,
|
||||
- ata_acpi_ap_notify_dock, ap);
|
||||
+ &ata_acpi_ap_dock_ops, ap);
|
||||
}
|
||||
|
||||
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
|
||||
@@ -253,7 +293,7 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
if (dev->acpi_handle) {
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(dev->acpi_handle,
|
||||
- ata_acpi_dev_notify_dock, dev);
|
||||
+ &ata_acpi_dev_dock_ops, dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
|
||||
index a3e4705..db54c5e 100644
|
||||
--- a/drivers/pci/hotplug/acpiphp_glue.c
|
||||
+++ b/drivers/pci/hotplug/acpiphp_glue.c
|
||||
@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
|
||||
}
|
||||
|
||||
|
||||
-
|
||||
+static struct acpi_dock_ops acpiphp_dock_ops = {
|
||||
+ .handler = handle_hotplug_event_func,
|
||||
+};
|
||||
|
||||
/* callback routine to register each ACPI PCI slot object */
|
||||
static acpi_status
|
||||
@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
*/
|
||||
newfunc->flags &= ~FUNC_HAS_EJ0;
|
||||
if (register_hotplug_dock_device(handle,
|
||||
- handle_hotplug_event_func, newfunc))
|
||||
+ &acpiphp_dock_ops, newfunc))
|
||||
dbg("failed to register dock device\n");
|
||||
|
||||
/* we need to be notified when dock events happen
|
||||
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
|
||||
index e5f38e5..4f5042a 100644
|
||||
--- a/include/acpi/acpi_drivers.h
|
||||
+++ b/include/acpi/acpi_drivers.h
|
||||
@@ -115,12 +115,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
|
||||
/*--------------------------------------------------------------------------
|
||||
Dock Station
|
||||
-------------------------------------------------------------------------- */
|
||||
+struct acpi_dock_ops {
|
||||
+ acpi_notify_handler handler;
|
||||
+ acpi_notify_handler uevent;
|
||||
+};
|
||||
+
|
||||
#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
|
||||
extern int is_dock_device(acpi_handle handle);
|
||||
extern int register_dock_notifier(struct notifier_block *nb);
|
||||
extern void unregister_dock_notifier(struct notifier_block *nb);
|
||||
extern int register_hotplug_dock_device(acpi_handle handle,
|
||||
- acpi_notify_handler handler,
|
||||
+ struct acpi_dock_ops *ops,
|
||||
void *context);
|
||||
extern void unregister_hotplug_dock_device(acpi_handle handle);
|
||||
#else
|
||||
@@ -136,7 +141,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
}
|
||||
static inline int register_hotplug_dock_device(acpi_handle handle,
|
||||
- acpi_notify_handler handler,
|
||||
+ struct acpi_dock_ops *ops,
|
||||
void *context)
|
||||
{
|
||||
return -ENODEV;
|
||||
@@ -0,0 +1,451 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: makeing dock driver supports bay and battery hotplug
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
Making dock driver supports bay and battery hotplug. They are all
|
||||
regarded as dock, and unified handled.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
---
|
||||
drivers/acpi/dock.c | 221 ++++++++++++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 173 insertions(+), 48 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (d
|
||||
" before undocking");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
-static struct platform_device *dock_device;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
static const struct acpi_device_id dock_device_ids[] = {
|
||||
@@ -65,7 +64,12 @@ struct dock_station {
|
||||
struct mutex hp_lock;
|
||||
struct list_head dependent_devices;
|
||||
struct list_head hotplug_devices;
|
||||
+
|
||||
+ struct list_head sibiling;
|
||||
+ struct platform_device *dock_device;
|
||||
};
|
||||
+static LIST_HEAD(dock_stations);
|
||||
+static int dock_station_count;
|
||||
|
||||
struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
@@ -77,11 +81,12 @@ struct dock_dependent_device {
|
||||
|
||||
#define DOCK_DOCKING 0x00000001
|
||||
#define DOCK_UNDOCKING 0x00000002
|
||||
+#define DOCK_IS_DOCK 0x00000010
|
||||
+#define DOCK_IS_ATA 0x00000020
|
||||
+#define DOCK_IS_BAT 0x00000040
|
||||
#define DOCK_EVENT 3
|
||||
#define UNDOCK_EVENT 2
|
||||
|
||||
-static struct dock_station *dock_station;
|
||||
-
|
||||
/*****************************************************************************
|
||||
* Dock Dependent device functions *
|
||||
*****************************************************************************/
|
||||
@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static int is_ejectable(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_status status;
|
||||
+ acpi_handle tmp;
|
||||
+
|
||||
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
+ if (ACPI_FAILURE(status))
|
||||
+ return 0;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int is_ata(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_handle tmp;
|
||||
+
|
||||
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int is_battery(acpi_handle handle)
|
||||
+{
|
||||
+ struct acpi_device_info *info;
|
||||
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
+ int ret = 1;
|
||||
+
|
||||
+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
|
||||
+ return 0;
|
||||
+ info = buffer.pointer;
|
||||
+ if (!(info->valid & ACPI_VALID_HID))
|
||||
+ ret = 0;
|
||||
+ else
|
||||
+ ret = !strcmp("PNP0C0A", info->hardware_id.value);
|
||||
+
|
||||
+ kfree(buffer.pointer);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int is_ejectable_bay(acpi_handle handle)
|
||||
+{
|
||||
+ acpi_handle phandle;
|
||||
+ if (!is_ejectable(handle))
|
||||
+ return 0;
|
||||
+ if (is_battery(handle) || is_ata(handle))
|
||||
+ return 1;
|
||||
+ if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* is_dock_device - see if a device is on a dock station
|
||||
* @handle: acpi handle of the device
|
||||
@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
|
||||
*/
|
||||
int is_dock_device(acpi_handle handle)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ struct dock_station *dock_station;
|
||||
+
|
||||
+ if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
- if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
|
||||
+ if (is_dock(handle))
|
||||
return 1;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ if (find_dock_dependent_device(dock_station, handle))
|
||||
+ return 1;
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct
|
||||
|
||||
static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
{
|
||||
- struct device *dev = &dock_device->dev;
|
||||
+ struct device *dev = &ds->dock_device->dev;
|
||||
char event_string[13];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
@@ -414,7 +479,7 @@ static void handle_dock(struct dock_stat
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = dock;
|
||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||
- if (ACPI_FAILURE(status))
|
||||
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||
printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
|
||||
(char *)name_buffer.pointer);
|
||||
kfree(buffer.pointer);
|
||||
@@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_
|
||||
*/
|
||||
int register_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
||||
@@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier
|
||||
*/
|
||||
void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return;
|
||||
|
||||
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
||||
@@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* make sure this handle is for a device dependent on the dock,
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
- dd = find_dock_dependent_device(dock_station, handle);
|
||||
- if (dd) {
|
||||
- dd->handler = handler;
|
||||
- dd->context = context;
|
||||
- dock_add_hotplug_device(dock_station, dd);
|
||||
- return 0;
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ dd = find_dock_dependent_device(dock_station, handle);
|
||||
+ if (dd) {
|
||||
+ dd->handler = handler;
|
||||
+ dd->context = context;
|
||||
+ dock_add_hotplug_device(dock_station, dd);
|
||||
+ return 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
@@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_
|
||||
void unregister_hotplug_dock_device(acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return;
|
||||
|
||||
- dd = find_dock_dependent_device(dock_station, handle);
|
||||
- if (dd)
|
||||
- dock_del_hotplug_device(dock_station, dd);
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
+ dd = find_dock_dependent_device(dock_station, handle);
|
||||
+ if (dd)
|
||||
+ dock_del_hotplug_device(dock_station, dd);
|
||||
+ }
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
|
||||
@@ -620,9 +691,28 @@ static void dock_notify(acpi_handle hand
|
||||
{
|
||||
struct dock_station *ds = data;
|
||||
struct acpi_device *tmp;
|
||||
+ int surprise_removal = 0;
|
||||
|
||||
+ /*
|
||||
+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
+ * is sent and _DCK is present, it is assumed to mean an undock
|
||||
+ * request.
|
||||
+ */
|
||||
+ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
+ event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
+
|
||||
+ /*
|
||||
+ * dock station: BUS_CHECK - docked or surprise removal
|
||||
+ * DEVICE_CHECK - undocked
|
||||
+ * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
|
||||
+ *
|
||||
+ * To simplify event handling, dock dependent device handler always
|
||||
+ * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
+ * ACPI_NOTIFY_EJECT_REQUEST for removal
|
||||
+ */
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
+ case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
|
||||
&tmp)) {
|
||||
begin_dock(ds);
|
||||
@@ -638,20 +728,17 @@ static void dock_notify(acpi_handle hand
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
dock_lock(ds, 1);
|
||||
+ break;
|
||||
}
|
||||
- break;
|
||||
- case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
- /*
|
||||
- * According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
- * is sent and _DCK is present, it is assumed to mean an
|
||||
- * undock request. This notify routine will only be called
|
||||
- * for objects defining _DCK, so we will fall through to eject
|
||||
- * request here. However, we will pass an eject request through
|
||||
- * to the driver who wish to hotplug.
|
||||
- */
|
||||
+ if (dock_present(ds) || dock_in_progress(ds))
|
||||
+ break;
|
||||
+ /* This is a surprise removal */
|
||||
+ surprise_removal = 1;
|
||||
+ event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
+ /* Fall back */
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
begin_undock(ds);
|
||||
- if (immediate_undock)
|
||||
+ if (immediate_undock || surprise_removal)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
@@ -718,6 +805,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show
|
||||
static ssize_t show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
|
||||
|
||||
}
|
||||
@@ -730,6 +819,8 @@ static ssize_t write_undock(struct devic
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
@@ -747,6 +838,8 @@ static ssize_t show_dock_uid(struct devi
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long long lbuf;
|
||||
+ struct dock_station *dock_station = *((struct dock_station **)
|
||||
+ dev->platform_data);
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle,
|
||||
"_UID", NULL, &lbuf);
|
||||
if (ACPI_FAILURE(status))
|
||||
@@ -768,6 +861,8 @@ static int dock_add(acpi_handle handle)
|
||||
int ret;
|
||||
acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
+ struct dock_station *dock_station;
|
||||
+ struct platform_device *dock_device;
|
||||
|
||||
/* allocate & initialize the dock_station private data */
|
||||
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
|
||||
@@ -777,22 +872,34 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station->last_dock_time = jiffies - HZ;
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
+ INIT_LIST_HEAD(&dock_station->sibiling);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
- dock_device =
|
||||
- platform_device_register_simple(dock_device_name, 0, NULL, 0);
|
||||
+ dock_station->dock_device =
|
||||
+ platform_device_register_simple(dock_device_name,
|
||||
+ dock_station_count, NULL, 0);
|
||||
+ dock_device = dock_station->dock_device;
|
||||
if (IS_ERR(dock_device)) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return PTR_ERR(dock_device);
|
||||
}
|
||||
+ platform_device_add_data(dock_device, &dock_station,
|
||||
+ sizeof(struct dock_station *));
|
||||
|
||||
/* we want the dock device to send uevents */
|
||||
dock_device->dev.uevent_suppress = 0;
|
||||
|
||||
+ if (is_dock(handle))
|
||||
+ dock_station->flags |= DOCK_IS_DOCK;
|
||||
+ if (is_ata(handle))
|
||||
+ dock_station->flags |= DOCK_IS_ATA;
|
||||
+ if (is_battery(handle))
|
||||
+ dock_station->flags |= DOCK_IS_BAT;
|
||||
+
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
@@ -858,8 +965,8 @@ static int dock_add(acpi_handle handle)
|
||||
goto dock_add_err;
|
||||
}
|
||||
|
||||
- printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
-
|
||||
+ dock_station_count++;
|
||||
+ list_add(&dock_station->sibiling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
dock_add_err:
|
||||
@@ -878,12 +985,13 @@ dock_add_err_unregister:
|
||||
/**
|
||||
* dock_remove - free up resources related to the dock station
|
||||
*/
|
||||
-static int dock_remove(void)
|
||||
+static int dock_remove(struct dock_station *dock_station)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
acpi_status status;
|
||||
+ struct platform_device *dock_device = dock_station->dock_device;
|
||||
|
||||
- if (!dock_station)
|
||||
+ if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
/* remove dependent devices */
|
||||
@@ -923,41 +1031,58 @@ static int dock_remove(void)
|
||||
static acpi_status
|
||||
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- int *count = context;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (is_dock(handle)) {
|
||||
if (dock_add(handle) >= 0) {
|
||||
- (*count)++;
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
-static int __init dock_init(void)
|
||||
+static acpi_status
|
||||
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
- int num = 0;
|
||||
-
|
||||
- dock_station = NULL;
|
||||
+ /* If bay is in a dock, it's already handled */
|
||||
+ if (is_ejectable_bay(handle) && !is_dock_device(handle))
|
||||
+ dock_add(handle);
|
||||
+ return AE_OK;
|
||||
+}
|
||||
|
||||
+static int __init dock_init(void)
|
||||
+{
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* look for a dock station */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
- ACPI_UINT32_MAX, find_dock, &num, NULL);
|
||||
+ ACPI_UINT32_MAX, find_dock, NULL, NULL);
|
||||
|
||||
- if (!num)
|
||||
- printk(KERN_INFO "No dock devices found.\n");
|
||||
+ /* look for bay */
|
||||
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
+ ACPI_UINT32_MAX, find_bay, NULL, NULL);
|
||||
+ if (!dock_station_count) {
|
||||
+ printk(KERN_INFO PREFIX "No dock devices found.\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
+ printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
||||
+ ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dock_exit(void)
|
||||
{
|
||||
- dock_remove();
|
||||
+ struct dock_station *dock_station;
|
||||
+
|
||||
+ list_for_each_entry(dock_station, &dock_stations, sibiling)
|
||||
+ dock_remove(dock_station);
|
||||
}
|
||||
|
||||
-postcore_initcall(dock_init);
|
||||
+/*
|
||||
+ * Must be called before drivers of devices in dock, otherwise we can't know
|
||||
+ * which devices are in a dock
|
||||
+ */
|
||||
+subsys_initcall(dock_init);
|
||||
module_exit(dock_exit);
|
||||
@@ -0,0 +1,23 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: acpi: export acpi_os_hotplug_execute
|
||||
|
||||
The ACPI dock driver changes require acpi_os_hotplug_execute,
|
||||
which wasn't exported.
|
||||
|
||||
This patch exports it.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
drivers/acpi/osl.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/acpi/osl.c
|
||||
+++ b/drivers/acpi/osl.c
|
||||
@@ -797,6 +797,7 @@ acpi_status acpi_os_hotplug_execute(acpi
|
||||
{
|
||||
return __acpi_os_execute(0, function, context, 1);
|
||||
}
|
||||
+EXPORT_SYMBOL(acpi_os_hotplug_execute);
|
||||
|
||||
void acpi_os_wait_events_complete(void *context)
|
||||
{
|
||||
@@ -0,0 +1,211 @@
|
||||
From: Shaohua Li <shaohua.li@intel.com>
|
||||
Subject: libata hotplug to align with dock driver
|
||||
Patch-mainline: submitted 2008-08-28
|
||||
References: fate#304731,bnc#401740
|
||||
|
||||
dock driver can handle ata(bay) hotplug now. dock driver already handles
|
||||
_EJ0 and _STA, so remove them. Also libata doesn't need register
|
||||
notification handler anymore.
|
||||
|
||||
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
|
||||
Signed-off-by: Holger Macht <hmacht@suse.de>
|
||||
---
|
||||
|
||||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
|
||||
index 4b395b1..f19f643 100644
|
||||
--- a/drivers/acpi/dock.c
|
||||
+++ b/drivers/acpi/dock.c
|
||||
@@ -738,7 +738,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
/* Fall back */
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
begin_undock(ds);
|
||||
- if (immediate_undock || surprise_removal)
|
||||
+ if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
|
||||
+ || surprise_removal)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
|
||||
index 9330b79..97727be 100644
|
||||
--- a/drivers/ata/libata-acpi.c
|
||||
+++ b/drivers/ata/libata-acpi.c
|
||||
@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
|
||||
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
||||
}
|
||||
|
||||
-static void ata_acpi_eject_device(acpi_handle handle)
|
||||
-{
|
||||
- struct acpi_object_list arg_list;
|
||||
- union acpi_object arg;
|
||||
-
|
||||
- arg_list.count = 1;
|
||||
- arg_list.pointer = &arg;
|
||||
- arg.type = ACPI_TYPE_INTEGER;
|
||||
- arg.integer.value = 1;
|
||||
-
|
||||
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
- &arg_list, NULL)))
|
||||
- printk(KERN_ERR "Failed to evaluate _EJ0!\n");
|
||||
-}
|
||||
-
|
||||
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
|
||||
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* @ap: ATA port ACPI event occurred
|
||||
* @dev: ATA device ACPI event occurred (can be NULL)
|
||||
* @event: ACPI event which occurred
|
||||
- * @is_dock_event: boolean indicating whether the event was a dock one
|
||||
*
|
||||
* All ACPI bay / device realted events end up in this function. If
|
||||
* the event is port-wide @dev is NULL. If the event is specific to a
|
||||
@@ -171,115 +155,58 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* ACPI notify handler context. May sleep.
|
||||
*/
|
||||
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
|
||||
- u32 event, int is_dock_event)
|
||||
+ u32 event)
|
||||
{
|
||||
- char event_string[12];
|
||||
- char *envp[] = { event_string, NULL };
|
||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||
- struct kobject *kobj = NULL;
|
||||
int wait = 0;
|
||||
unsigned long flags;
|
||||
- acpi_handle handle, tmphandle;
|
||||
- unsigned long long sta;
|
||||
- acpi_status status;
|
||||
+ acpi_handle handle;
|
||||
|
||||
- if (dev) {
|
||||
- if (dev->sdev)
|
||||
- kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
+ if (dev)
|
||||
handle = dev->acpi_handle;
|
||||
- } else {
|
||||
- kobj = &ap->dev->kobj;
|
||||
+ else
|
||||
handle = ap->acpi_handle;
|
||||
- }
|
||||
-
|
||||
- status = acpi_get_handle(handle, "_EJ0", &tmphandle);
|
||||
- if (ACPI_FAILURE(status))
|
||||
- /* This device does not support hotplug */
|
||||
- return;
|
||||
-
|
||||
- if (event == ACPI_NOTIFY_BUS_CHECK ||
|
||||
- event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
-
|
||||
+ /*
|
||||
+ * When dock driver calls into the routine, it will always use
|
||||
+ * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
+ * ACPI_NOTIFY_EJECT_REQUEST for remove
|
||||
+ */
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
- if (ACPI_FAILURE(status)) {
|
||||
- ata_port_printk(ap, KERN_ERR,
|
||||
- "acpi: failed to determine bay status (0x%x)\n",
|
||||
- status);
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- if (sta) {
|
||||
- ata_ehi_hotplugged(ehi);
|
||||
- ata_port_freeze(ap);
|
||||
- } else {
|
||||
- /* The device has gone - unplug it */
|
||||
- ata_acpi_detach_device(ap, dev);
|
||||
- wait = 1;
|
||||
- }
|
||||
+ ata_ehi_hotplugged(ehi);
|
||||
+ ata_port_freeze(ap);
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
- if (!is_dock_event)
|
||||
- break;
|
||||
-
|
||||
- /* undock event - immediate unplug */
|
||||
ata_acpi_detach_device(ap, dev);
|
||||
wait = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
- /* make sure kobj doesn't go away while ap->lock is released */
|
||||
- kobject_get(kobj);
|
||||
-
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
- if (wait) {
|
||||
+ if (wait)
|
||||
ata_port_wait_eh(ap);
|
||||
- ata_acpi_eject_device(handle);
|
||||
- }
|
||||
-
|
||||
- if (kobj && !is_dock_event) {
|
||||
- sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
- kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
- }
|
||||
-
|
||||
- kobject_put(kobj);
|
||||
}
|
||||
|
||||
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_device *dev = data;
|
||||
|
||||
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
|
||||
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_port *ap = data;
|
||||
|
||||
- ata_acpi_handle_hotplug(ap, NULL, event, 1);
|
||||
-}
|
||||
-
|
||||
-static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct ata_device *dev = data;
|
||||
-
|
||||
- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
|
||||
-}
|
||||
-
|
||||
-static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
|
||||
-{
|
||||
- struct ata_port *ap = data;
|
||||
-
|
||||
- ata_acpi_handle_hotplug(ap, NULL, event, 0);
|
||||
+ ata_acpi_handle_hotplug(ap, NULL, event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,9 +242,6 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
ata_acpi_associate_ide_port(ap);
|
||||
|
||||
if (ap->acpi_handle) {
|
||||
- acpi_install_notify_handler(ap->acpi_handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- ata_acpi_ap_notify, ap);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(ap->acpi_handle,
|
||||
ata_acpi_ap_notify_dock, ap);
|
||||
@@ -327,9 +251,6 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
struct ata_device *dev = &ap->link.device[j];
|
||||
|
||||
if (dev->acpi_handle) {
|
||||
- acpi_install_notify_handler(dev->acpi_handle,
|
||||
- ACPI_SYSTEM_NOTIFY,
|
||||
- ata_acpi_dev_notify, dev);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(dev->acpi_handle,
|
||||
ata_acpi_dev_notify_dock, dev);
|
||||
@@ -0,0 +1,206 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: Behave uniquely based on processor declaration definition type
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: b26e9286fb438eb78bcdb68b67a3dbb8bc539125
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Associating a Local SAPIC with a processor object is dependent upon the
|
||||
processor object's definition type. CPUs declared as "Processor" should
|
||||
use the Local SAPIC's 'processor_id', and CPUs declared as "Device"
|
||||
should use the 'uid'. Note that for "Processor" declarations, even if a
|
||||
'_UID' child object exists, it has no bearing with respect to mapping
|
||||
Local SAPICs (see section 5.2.11.13 - Local SAPIC Structure; "Advanced
|
||||
Configuration and Power Interface Specification", Revision 3.0b).
|
||||
|
||||
This patch changes the lsapic mapping logic to rely on the distinction of
|
||||
how the processor object was declared - the mapping can't just try both
|
||||
types of matches regardless of declaration type and rely on one failing
|
||||
as is currently being done.
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/processor_core.c | 78 +++++++++++++++++++++++-------------------
|
||||
1 file changed, 44 insertions(+), 34 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/drivers/acpi/processor_core.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/drivers/acpi/processor_core.c
|
||||
+++ linux-2.6.27/drivers/acpi/processor_core.c
|
||||
@@ -410,7 +410,7 @@ static int acpi_processor_remove_fs(stru
|
||||
/* Use the acpiid in MADT to map cpus in case of SMP */
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
-static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
|
||||
+static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; }
|
||||
#else
|
||||
|
||||
static struct acpi_table_madt *madt;
|
||||
@@ -429,27 +429,35 @@ static int map_lapic_id(struct acpi_subt
|
||||
}
|
||||
|
||||
static int map_lsapic_id(struct acpi_subtable_header *entry,
|
||||
- u32 acpi_id, int *apic_id)
|
||||
+ int device_declaration, u32 acpi_id, int *apic_id)
|
||||
{
|
||||
struct acpi_madt_local_sapic *lsapic =
|
||||
(struct acpi_madt_local_sapic *)entry;
|
||||
+ u32 tmp = (lsapic->id << 8) | lsapic->eid;
|
||||
+
|
||||
/* Only check enabled APICs*/
|
||||
- if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
|
||||
- /* First check against id */
|
||||
- if (lsapic->processor_id == acpi_id) {
|
||||
- *apic_id = (lsapic->id << 8) | lsapic->eid;
|
||||
- return 1;
|
||||
- /* Check against optional uid */
|
||||
- } else if (entry->length >= 16 &&
|
||||
- lsapic->uid == acpi_id) {
|
||||
- *apic_id = lsapic->uid;
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
+ if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Device statement declaration type */
|
||||
+ if (device_declaration) {
|
||||
+ if (entry->length < 16)
|
||||
+ printk(KERN_ERR PREFIX
|
||||
+ "Invalid LSAPIC with Device type processor (SAPIC ID %#x)\n",
|
||||
+ tmp);
|
||||
+ else if (lsapic->uid == acpi_id)
|
||||
+ goto found;
|
||||
+ /* Processor statement declaration type */
|
||||
+ } else if (lsapic->processor_id == acpi_id)
|
||||
+ goto found;
|
||||
+
|
||||
return 0;
|
||||
+found:
|
||||
+ *apic_id = tmp;
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
-static int map_madt_entry(u32 acpi_id)
|
||||
+static int map_madt_entry(int type, u32 acpi_id)
|
||||
{
|
||||
unsigned long madt_end, entry;
|
||||
int apic_id = -1;
|
||||
@@ -470,7 +478,7 @@ static int map_madt_entry(u32 acpi_id)
|
||||
if (map_lapic_id(header, acpi_id, &apic_id))
|
||||
break;
|
||||
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
|
||||
- if (map_lsapic_id(header, acpi_id, &apic_id))
|
||||
+ if (map_lsapic_id(header, type, acpi_id, &apic_id))
|
||||
break;
|
||||
}
|
||||
entry += header->length;
|
||||
@@ -478,7 +486,7 @@ static int map_madt_entry(u32 acpi_id)
|
||||
return apic_id;
|
||||
}
|
||||
|
||||
-static int map_mat_entry(acpi_handle handle, u32 acpi_id)
|
||||
+static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
@@ -501,7 +509,7 @@ static int map_mat_entry(acpi_handle han
|
||||
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
|
||||
map_lapic_id(header, acpi_id, &apic_id);
|
||||
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
|
||||
- map_lsapic_id(header, acpi_id, &apic_id);
|
||||
+ map_lsapic_id(header, type, acpi_id, &apic_id);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -510,14 +518,14 @@ exit:
|
||||
return apic_id;
|
||||
}
|
||||
|
||||
-static int get_cpu_id(acpi_handle handle, u32 acpi_id)
|
||||
+static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id)
|
||||
{
|
||||
int i;
|
||||
int apic_id = -1;
|
||||
|
||||
- apic_id = map_mat_entry(handle, acpi_id);
|
||||
+ apic_id = map_mat_entry(handle, type, acpi_id);
|
||||
if (apic_id == -1)
|
||||
- apic_id = map_madt_entry(acpi_id);
|
||||
+ apic_id = map_madt_entry(type, acpi_id);
|
||||
if (apic_id == -1)
|
||||
return apic_id;
|
||||
|
||||
@@ -533,15 +541,16 @@ static int get_cpu_id(acpi_handle handle
|
||||
Driver Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
-static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
|
||||
+static int acpi_processor_get_info(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
union acpi_object object = { 0 };
|
||||
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
|
||||
- int cpu_index;
|
||||
+ struct acpi_processor *pr;
|
||||
+ int cpu_index, device_declaration = 0;
|
||||
static int cpu0_initialized;
|
||||
|
||||
-
|
||||
+ pr = acpi_driver_data(device);
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -562,22 +571,23 @@ static int acpi_processor_get_info(struc
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"No bus mastering arbitration control\n"));
|
||||
|
||||
- /* Check if it is a Device with HID and UID */
|
||||
- if (has_uid) {
|
||||
+ if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_HID)) {
|
||||
+ /*
|
||||
+ * Declared with "Device" statement; match _UID.
|
||||
+ * Note that we don't handle string _UIDs yet.
|
||||
+ */
|
||||
unsigned long long value;
|
||||
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
|
||||
NULL, &value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
- printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
|
||||
+ printk(KERN_ERR PREFIX
|
||||
+ "Evaluating processor _UID [%#x]\n", status);
|
||||
return -ENODEV;
|
||||
}
|
||||
+ device_declaration = 1;
|
||||
pr->acpi_id = value;
|
||||
} else {
|
||||
- /*
|
||||
- * Evalute the processor object. Note that it is common on SMP to
|
||||
- * have the first (boot) processor with a valid PBLK address while
|
||||
- * all others have a NULL address.
|
||||
- */
|
||||
+ /* Declared with "Processor" statement; match ProcessorID */
|
||||
status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Evaluating processor object\n");
|
||||
@@ -590,7 +600,7 @@ static int acpi_processor_get_info(struc
|
||||
*/
|
||||
pr->acpi_id = object.processor.proc_id;
|
||||
}
|
||||
- cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
|
||||
+ cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
|
||||
|
||||
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
|
||||
if (!cpu0_initialized && (cpu_index == -1) &&
|
||||
@@ -662,7 +672,7 @@ static int __cpuinit acpi_processor_star
|
||||
|
||||
pr = acpi_driver_data(device);
|
||||
|
||||
- result = acpi_processor_get_info(pr, device->flags.unique_id);
|
||||
+ result = acpi_processor_get_info(device);
|
||||
if (result) {
|
||||
/* Processor is physically not present */
|
||||
return 0;
|
||||
@@ -0,0 +1,58 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: Disambiguate processor declaration type
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: ad93a765c1834db031b5bf1c2baf2a50d0462ca4
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Declaring processors in ACPI namespace can be done using either a
|
||||
"Processor" definition or a "Device" definition (see section 8.4 -
|
||||
Declaring Processors; "Advanced Configuration and Power Interface
|
||||
Specification", Revision 3.0b). Currently the two processor
|
||||
declaration types are conflated.
|
||||
|
||||
This patch disambiguates the processor declaration's definition type
|
||||
enabling subsequent code to behave uniquely based explicitly on the
|
||||
declaration's type.
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/processor_core.c | 1 +
|
||||
drivers/acpi/scan.c | 2 +-
|
||||
include/acpi/acpi_drivers.h | 1 +
|
||||
3 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/processor_core.c
|
||||
+++ b/drivers/acpi/processor_core.c
|
||||
@@ -89,6 +89,7 @@ static int acpi_processor_handle_eject(s
|
||||
|
||||
|
||||
static const struct acpi_device_id processor_device_ids[] = {
|
||||
+ {ACPI_PROCESSOR_OBJECT_HID, 0},
|
||||
{ACPI_PROCESSOR_HID, 0},
|
||||
{"", 0},
|
||||
};
|
||||
--- a/drivers/acpi/scan.c
|
||||
+++ b/drivers/acpi/scan.c
|
||||
@@ -1002,7 +1002,7 @@ static void acpi_device_set_id(struct ac
|
||||
hid = ACPI_POWER_HID;
|
||||
break;
|
||||
case ACPI_BUS_TYPE_PROCESSOR:
|
||||
- hid = ACPI_PROCESSOR_HID;
|
||||
+ hid = ACPI_PROCESSOR_OBJECT_HID;
|
||||
break;
|
||||
case ACPI_BUS_TYPE_SYSTEM:
|
||||
hid = ACPI_SYSTEM_HID;
|
||||
--- a/include/acpi/acpi_drivers.h
|
||||
+++ b/include/acpi/acpi_drivers.h
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
|
||||
#define ACPI_POWER_HID "LNXPOWER"
|
||||
+#define ACPI_PROCESSOR_OBJECT_HID "ACPI_CPU"
|
||||
#define ACPI_PROCESSOR_HID "ACPI0007"
|
||||
#define ACPI_SYSTEM_HID "LNXSYSTM"
|
||||
#define ACPI_THERMAL_HID "LNXTHERM"
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
Subject: ACPI: EC: Limit workaround for ASUS notebooks even more
|
||||
References: bnc#492658 bnc#496871 and others
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: 235c4a59278eb07e61d909f1f0c233733034a8b3
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=11884
|
||||
|
||||
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
---
|
||||
drivers/acpi/ec.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
Index: linux-2.6.27-SLE11_BRANCH/drivers/acpi/ec.c
|
||||
===================================================================
|
||||
--- linux-2.6.27-SLE11_BRANCH.orig/drivers/acpi/ec.c
|
||||
+++ linux-2.6.27-SLE11_BRANCH/drivers/acpi/ec.c
|
||||
@@ -1017,7 +1017,8 @@ int __init acpi_ec_ecdt_probe(void)
|
||||
* which needs it, has fake EC._INI method, so use it as flag.
|
||||
* Keep boot_ec struct as it will be needed soon.
|
||||
*/
|
||||
- if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy)))
|
||||
+ if (!dmi_name_in_vendors("ASUS") ||
|
||||
+ ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy)))
|
||||
return -ENODEV;
|
||||
install:
|
||||
if (!ec_install_handlers(boot_ec)) {
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
Subject: ACPI: EC: Don't degrade to poll mode at storm automatically.
|
||||
References: bnc#446142
|
||||
Patch-Mainline: no
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Not all users of semi-broken EC devices want to degrade to poll mode, so
|
||||
give them right to choose.
|
||||
|
||||
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
---
|
||||
|
||||
Documentation/kernel-parameters.txt | 5 +++++
|
||||
drivers/acpi/ec.c | 15 +++++++++++++++
|
||||
2 files changed, 20 insertions(+)
|
||||
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -699,6 +699,11 @@ and is between 256 and 4096 characters.
|
||||
|
||||
eata= [HW,SCSI]
|
||||
|
||||
+ ec_intr= [HW,ACPI] ACPI Embedded Controller interrupt mode
|
||||
+ Format: <int>
|
||||
+ 0: polling mode
|
||||
+ non-0: interrupt mode (default)
|
||||
+
|
||||
edd= [EDD]
|
||||
Format: {"off" | "on" | "skip[mbr]"}
|
||||
|
||||
--- a/drivers/acpi/ec.c
|
||||
+++ b/drivers/acpi/ec.c
|
||||
@@ -121,6 +121,8 @@ static struct acpi_ec {
|
||||
spinlock_t curr_lock;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
+int acpi_ec_intr = 1; /* Default is interrupt mode */
|
||||
+
|
||||
/*
|
||||
* Some Asus system have exchanged ECDT data/command IO addresses.
|
||||
*/
|
||||
@@ -902,6 +904,8 @@ static int ec_install_handlers(struct ac
|
||||
&acpi_ec_gpe_handler, ec);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
+ if (!acpi_ec_intr)
|
||||
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
|
||||
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
|
||||
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
status = acpi_install_address_space_handler(ec->handle,
|
||||
@@ -1094,3 +1098,14 @@ static void __exit acpi_ec_exit(void)
|
||||
return;
|
||||
}
|
||||
#endif /* 0 */
|
||||
+
|
||||
+static int __init acpi_ec_set_intr_mode(char *str)
|
||||
+{
|
||||
+ if (!get_option(&str, &acpi_ec_intr)) {
|
||||
+ acpi_ec_intr = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+__setup("ec_intr=", acpi_ec_set_intr_mode);
|
||||
@@ -0,0 +1,29 @@
|
||||
From: Myron Stowe <myron.stowe@hp.com>
|
||||
Subject: ACPI: 80 column adherence and spelling fix (no functional change)
|
||||
References: bnc#440062
|
||||
Patch-Mainline: yes
|
||||
Commit-ID: 5b53ed69158eeff115004f246193d07a083445f6
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
|
||||
index bc332fc..b57b1f0 100644
|
||||
--- a/drivers/acpi/processor_core.c
|
||||
+++ b/drivers/acpi/processor_core.c
|
||||
@@ -595,9 +595,10 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
|
||||
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
|
||||
- */
|
||||
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
|
||||
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in
|
||||
+ * arch/xxx/acpi.c
|
||||
+ */
|
||||
pr->acpi_id = object.processor.proc_id;
|
||||
}
|
||||
cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id);
|
||||
@@ -0,0 +1,58 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Use SRAT table rev to use 8bit or 16/32bit PXM fields (ia64)
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
|
||||
ia64 did handle the PXM fields almost consistently, but depending on
|
||||
sgi's sn2 platform. This patch leaves the sn2 logic in, but does also
|
||||
use 16/32 bits for PXM if the SRAT has rev 2 or higher.
|
||||
|
||||
The patch also adds __init to the two pxm accessor functions, as they
|
||||
access __initdata now and are called from an __init function only anyway.
|
||||
|
||||
Note that the code only uses 16 bits for the PXM field in the processor
|
||||
proximity field; the patch does not address this as 16 bits are more than
|
||||
enough.
|
||||
|
||||
This is patch 3/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
arch/ia64/kernel/acpi.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/ia64/kernel/acpi.c
|
||||
+++ b/arch/ia64/kernel/acpi.c
|
||||
@@ -430,22 +430,24 @@ static u32 __devinitdata pxm_flag[PXM_FL
|
||||
static struct acpi_table_slit __initdata *slit_table;
|
||||
cpumask_t early_cpu_possible_map = CPU_MASK_NONE;
|
||||
|
||||
-static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
|
||||
+static int __init
|
||||
+get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
|
||||
{
|
||||
int pxm;
|
||||
|
||||
pxm = pa->proximity_domain_lo;
|
||||
- if (ia64_platform_is("sn2"))
|
||||
+ if (ia64_platform_is("sn2") || acpi_srat_revision >= 2)
|
||||
pxm += pa->proximity_domain_hi[0] << 8;
|
||||
return pxm;
|
||||
}
|
||||
|
||||
-static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
|
||||
+static int __init
|
||||
+get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
|
||||
{
|
||||
int pxm;
|
||||
|
||||
pxm = ma->proximity_domain;
|
||||
- if (!ia64_platform_is("sn2"))
|
||||
+ if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1)
|
||||
pxm &= 0xff;
|
||||
|
||||
return pxm;
|
||||
@@ -0,0 +1,51 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Store SRAT table revision
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
In order to know whether or not, we must know what version the SRAT
|
||||
table has.
|
||||
|
||||
This patch stores the SRAT table revision for later consumption
|
||||
by arch specific __init functions.
|
||||
|
||||
This is patch 1/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
drivers/acpi/numa.c | 3 +++
|
||||
include/acpi/acpi_numa.h | 1 +
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/numa.c
|
||||
+++ b/drivers/acpi/numa.c
|
||||
@@ -43,6 +43,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAI
|
||||
static int node_to_pxm_map[MAX_NUMNODES]
|
||||
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
|
||||
|
||||
+unsigned char acpi_srat_revision __initdata;
|
||||
+
|
||||
int pxm_to_node(int pxm)
|
||||
{
|
||||
if (pxm < 0)
|
||||
@@ -225,6 +227,7 @@ static int __init acpi_parse_srat(struct
|
||||
return -EINVAL;
|
||||
|
||||
srat = (struct acpi_table_srat *)table;
|
||||
+ acpi_srat_revision = srat->header.revision;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/include/acpi/acpi_numa.h
|
||||
+++ b/include/acpi/acpi_numa.h
|
||||
@@ -15,6 +15,7 @@ extern int pxm_to_node(int);
|
||||
extern int node_to_pxm(int);
|
||||
extern void __acpi_map_pxm_to_node(int, int);
|
||||
extern int acpi_map_pxm_to_node(int);
|
||||
+extern unsigned char acpi_srat_revision;
|
||||
|
||||
#endif /* CONFIG_ACPI_NUMA */
|
||||
#endif /* __ACP_NUMA_H */
|
||||
@@ -0,0 +1,41 @@
|
||||
From: Kurt Garloff <garloff@suse.de>
|
||||
Subject: Use SRAT table rev to use 8bit or 32bit PXM fields (x86-64)
|
||||
References: bnc#503038
|
||||
|
||||
In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides
|
||||
32bits for these. The new fields were reserved before.
|
||||
According to the ACPI spec, the OS must disregrard reserved fields.
|
||||
|
||||
x86-64 was rather inconsistent prior to this patch; it used 8 bits
|
||||
for the pxm field in cpu_affinity, but 32 bits in mem_affinity.
|
||||
This patch makes it consistent: Either use 8 bits consistently (SRAT
|
||||
rev 1 or lower) or 32 bits (SRAT rev 2 or higher).
|
||||
|
||||
This is patch 2/3.
|
||||
|
||||
Signed-off-by: Kurt Garloff <garloff@suse.de>
|
||||
|
||||
---
|
||||
arch/x86/mm/srat_64.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/arch/x86/mm/srat_64.c
|
||||
+++ b/arch/x86/mm/srat_64.c
|
||||
@@ -131,6 +131,8 @@ acpi_numa_processor_affinity_init(struct
|
||||
if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
|
||||
return;
|
||||
pxm = pa->proximity_domain_lo;
|
||||
+ if (acpi_srat_revision >= 2)
|
||||
+ pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
|
||||
node = setup_node(pxm);
|
||||
if (node < 0) {
|
||||
printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
|
||||
@@ -241,6 +243,8 @@ acpi_numa_memory_affinity_init(struct ac
|
||||
start = ma->base_address;
|
||||
end = start + ma->length;
|
||||
pxm = ma->proximity_domain;
|
||||
+ if (acpi_srat_revision <= 1)
|
||||
+ pxm &= 0xff;
|
||||
node = setup_node(pxm);
|
||||
if (node < 0) {
|
||||
printk(KERN_ERR "SRAT: Too many proximity domains.\n");
|
||||
@@ -0,0 +1,104 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Avoid critical temp shutdowns on specific ThinkPad T4x(p) and R40
|
||||
References: https://bugzilla.novell.com/show_bug.cgi?id=333043
|
||||
|
||||
---
|
||||
drivers/acpi/thermal.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 73 insertions(+)
|
||||
|
||||
--- a/drivers/acpi/thermal.c
|
||||
+++ b/drivers/acpi/thermal.c
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/reboot.h>
|
||||
+#include <linux/dmi.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
@@ -1640,6 +1641,66 @@ static int acpi_thermal_get_info(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static struct dmi_system_id thermal_psv_dmi_table[] = {
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T41",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T42",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T43",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T41p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T42p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad T43p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad R40",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R40"),
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "IBM ThinkPad R50p",
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
+ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R50p"),
|
||||
+ },
|
||||
+ },
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
static int acpi_thermal_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
@@ -1670,6 +1731,18 @@ static int acpi_thermal_add(struct acpi_
|
||||
if (result)
|
||||
goto free_memory;
|
||||
|
||||
+ if (dmi_check_system(thermal_psv_dmi_table)) {
|
||||
+ if (tz->trips.passive.flags.valid &&
|
||||
+ tz->trips.passive.temperature > CELSIUS_TO_KELVIN(85)) {
|
||||
+ printk (KERN_INFO "Adjust passive trip point from %lu"
|
||||
+ " to %lu\n",
|
||||
+ KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
|
||||
+ KELVIN_TO_CELSIUS(tz->trips.passive.temperature - 150));
|
||||
+ tz->trips.passive.temperature -= 150;
|
||||
+ acpi_thermal_set_polling(tz, 5);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
result = acpi_thermal_add_fs(device);
|
||||
if (result)
|
||||
goto unregister_thermal_zone;
|
||||
@@ -0,0 +1,96 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Introduce acpi_root_table=rsdt boot param and dmi list to force rsdt
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
Blacklist R40e, R51e and T40, T40p, T41, T41p, T42, T42p, R50 and R50p
|
||||
ThinkPads to use the RSDT instead of the XSDT.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
CC: Yakui Zhao <yakui.zhao@intel.com>
|
||||
|
||||
---
|
||||
Documentation/kernel-parameters.txt | 5 ++++
|
||||
drivers/acpi/tables.c | 37 ++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -237,6 +237,11 @@ and is between 256 and 4096 characters.
|
||||
to assume that this machine's pmtimer latches its value
|
||||
and always returns good values.
|
||||
|
||||
+ acpi_root_table= [X86,ACPI]
|
||||
+ { rsdt }
|
||||
+ rsdt: Take RSDT address for fetching
|
||||
+ ACPI tables (instead of XSDT)
|
||||
+
|
||||
agp= [AGP]
|
||||
{ off | try_unsupported }
|
||||
off: disable AGP support
|
||||
--- a/drivers/acpi/tables.c
|
||||
+++ b/drivers/acpi/tables.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bootmem.h>
|
||||
+#include <linux/dmi.h>
|
||||
|
||||
#define PREFIX "ACPI: "
|
||||
|
||||
@@ -282,6 +283,37 @@ static void __init check_multiple_madt(v
|
||||
return;
|
||||
}
|
||||
|
||||
+static struct dmi_system_id __initdata acpi_rsdt_dmi_table[] = {
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* R40e, broken C-states */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1SET")},
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* R50e, slow booting */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1WET")},
|
||||
+ },
|
||||
+ {
|
||||
+ .ident = "ThinkPad ", /* T40, T40p, T41, T41p, T42, T42p
|
||||
+ R50, R50p */
|
||||
+ .matches = {
|
||||
+ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"),
|
||||
+ DMI_MATCH(DMI_BIOS_VERSION, "1RET")},
|
||||
+ },
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
+static int __init acpi_force_rsdt(char *opt)
|
||||
+{
|
||||
+ if (!strcmp(opt, "rsdt"))
|
||||
+ acpi_gbl_force_rsdt = 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+early_param("acpi_root_table", acpi_force_rsdt);
|
||||
+
|
||||
/*
|
||||
* acpi_table_init()
|
||||
*
|
||||
@@ -295,6 +327,11 @@ int __init acpi_table_init(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
+ if (dmi_check_system(acpi_rsdt_dmi_table))
|
||||
+ acpi_gbl_force_rsdt = 1;
|
||||
+ if (acpi_gbl_force_rsdt)
|
||||
+ printk(KERN_INFO "Using RSDT as ACPI root table\n");
|
||||
+
|
||||
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 1;
|
||||
@@ -0,0 +1,53 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: ACPICA: Add acpi_gbl_force_rsdt variable
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
|
||||
|
||||
---
|
||||
drivers/acpi/tables/tbutils.c | 3 ++-
|
||||
drivers/acpi/utilities/utglobal.c | 1 +
|
||||
include/acpi/acglobal.h | 1 +
|
||||
3 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/acpi/tables/tbutils.c
|
||||
+++ b/drivers/acpi/tables/tbutils.c
|
||||
@@ -420,7 +420,8 @@ acpi_tb_parse_root_table(acpi_physical_a
|
||||
|
||||
/* Differentiate between RSDT and XSDT root tables */
|
||||
|
||||
- if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
|
||||
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address
|
||||
+ && !acpi_gbl_force_rsdt) {
|
||||
/*
|
||||
* Root table is an XSDT (64-bit physical addresses). We must use the
|
||||
* XSDT if the revision is > 1 and the XSDT pointer is present, as per
|
||||
--- a/drivers/acpi/utilities/utglobal.c
|
||||
+++ b/drivers/acpi/utilities/utglobal.c
|
||||
@@ -76,6 +76,7 @@ u8 acpi_gbl_method_executing = FALSE;
|
||||
/* System flags */
|
||||
|
||||
u32 acpi_gbl_startup_flags = 0;
|
||||
+int acpi_gbl_force_rsdt = 0;
|
||||
|
||||
/* System starts uninitialized */
|
||||
|
||||
--- a/include/acpi/acglobal.h
|
||||
+++ b/include/acpi/acglobal.h
|
||||
@@ -246,6 +246,7 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and
|
||||
|
||||
extern u8 acpi_gbl_shutdown;
|
||||
extern u32 acpi_gbl_startup_flags;
|
||||
+extern int acpi_gbl_force_rsdt;
|
||||
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
|
||||
extern const char *acpi_gbl_highest_dstate_names[4];
|
||||
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
|
||||
@@ -0,0 +1,98 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Remove R40e c-state blacklist
|
||||
Patch-mainline: not yet
|
||||
References: http://bugzilla.kernel.org/show_bug.cgi?id=8246
|
||||
|
||||
This one is part of a patch series:
|
||||
acpi_thinkpad_introduce_acpi_root_table_boot_param.patch
|
||||
acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch
|
||||
acpi_thinkpad_remove_R40e_c-state_blacklist.patch
|
||||
|
||||
|
||||
The FADT pointed to through XSDT is wrong on this (and similar)
|
||||
machines.
|
||||
The HW addresses to switch C-states are coming from the FADT.
|
||||
When using the FADT pointed to in the RSDT the info is correct.
|
||||
Previous patches blacklist this machine to use the right FADT and
|
||||
C-states finally work fine.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
|
||||
Remove R40e c-state blacklist
|
||||
|
||||
The FADT pointed to through XSDT is wrong on this (and similar) machines.
|
||||
The HW addresses to switch C-states are coming from the FADT.
|
||||
When using the FADT pointed to in the RSDT the info is correct.
|
||||
Previous patches blacklist this machine to use the right FADT and
|
||||
C-states finally work fine.
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Tested-by: Mark Doughty <me@markdoughty.co.uk>
|
||||
CC: Yakui Zhao <yakui.zhao@intel.com>
|
||||
|
||||
|
||||
---
|
||||
drivers/acpi/processor_idle.c | 51 ------------------------------------------
|
||||
1 file changed, 51 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/processor_idle.c
|
||||
+++ b/drivers/acpi/processor_idle.c
|
||||
@@ -127,57 +127,6 @@ static int set_max_cstate(const struct d
|
||||
/* Actually this shouldn't be __cpuinitdata, would be better to fix the
|
||||
callers to only run once -AK */
|
||||
static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1},
|
||||
- { set_max_cstate, "IBM ThinkPad R40e", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1},
|
||||
- { set_max_cstate, "Medion 41700", {
|
||||
- DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
|
||||
- DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1},
|
||||
{ set_max_cstate, "Clevo 5600D", {
|
||||
DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
|
||||
@@ -0,0 +1,56 @@
|
||||
From: Thomas Renninger <trenn@suse.de>
|
||||
Subject: Do not use video backlight switching for Lenovo ThinkPads
|
||||
Patch-Mainline: never
|
||||
|
||||
Mainline will go the IGD driver way which is too new and untested for
|
||||
SLE11.
|
||||
|
||||
---
|
||||
drivers/acpi/video.c | 17 ++++++++++++++---
|
||||
drivers/acpi/video_detect.c | 2 +-
|
||||
2 files changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/acpi/video.c
|
||||
+++ b/drivers/acpi/video.c
|
||||
@@ -731,7 +731,7 @@ static void acpi_video_device_find_cap(s
|
||||
{
|
||||
acpi_handle h_dummy1;
|
||||
u32 max_level = 0;
|
||||
-
|
||||
+ unsigned long acpi_video_support;
|
||||
|
||||
memset(&device->cap, 0, sizeof(device->cap));
|
||||
|
||||
@@ -759,8 +759,19 @@ static void acpi_video_device_find_cap(s
|
||||
device->cap._DSS = 1;
|
||||
}
|
||||
|
||||
- if (acpi_video_backlight_support())
|
||||
- max_level = acpi_video_init_brightness(device);
|
||||
+ acpi_video_support = acpi_video_backlight_support();
|
||||
+ if (acpi_video_support) {
|
||||
+ /*
|
||||
+ * Ugly SLE11 hack to let thinkpad_acpi handle brightness on
|
||||
+ * ThinkPad IGD devices
|
||||
+ */
|
||||
+ if (dmi_name_in_vendors("LENOVO") &&
|
||||
+ (acpi_video_support & ACPI_VIDEO_IGD))
|
||||
+ brightness_switch_enabled = 0;
|
||||
+ else
|
||||
+ max_level = acpi_video_init_brightness(device);
|
||||
+ } else
|
||||
+ brightness_switch_enabled = 0;
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && max_level > 0) {
|
||||
int result;
|
||||
--- a/drivers/acpi/video_detect.c
|
||||
+++ b/drivers/acpi/video_detect.c
|
||||
@@ -217,7 +217,7 @@ int acpi_video_backlight_support(void)
|
||||
return 1;
|
||||
|
||||
/* Then go the default way */
|
||||
- return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
|
||||
+ return acpi_video_support & (ACPI_VIDEO_BACKLIGHT | ACPI_VIDEO_IGD);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_video_backlight_support);
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
From: Bob Moore <robert.moore@intel.com>
|
||||
Subject: ACPICA: x2APIC support: changes for MADT and SRAT ACPI tables
|
||||
References: fate 303948 and fate 303984
|
||||
Patch-Mainline: in 2.6.28
|
||||
Commit-ID: 1d7cc03049f7c9c5cced9208a39316c5245ef314
|
||||
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
|
||||
Support for the x2APIC. There are 2 new subtables for the MADT and
|
||||
one new subtable for the SRAT. Includes disassembler and acpisrc
|
||||
support. Data from the Intel 64 Architecture x2APIC Specification,
|
||||
June 2008.
|
||||
|
||||
Signed-off-by: Bob Moore <robert.moore@intel.com>
|
||||
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
|
||||
Signed-off-by: Andi Kleen <ak@linux.intel.com>
|
||||
Signed-off-by: Len Brown <len.brown@intel.com>
|
||||
|
||||
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
|
||||
index f53faca..0c1ed38 100644
|
||||
--- a/include/acpi/acdisasm.h
|
||||
+++ b/include/acpi/acdisasm.h
|
||||
@@ -186,6 +186,8 @@ extern struct acpi_dmtable_info acpi_dm_table_info_madt5[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt6[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt7[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt8[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_madt9[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_madt10[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[];
|
||||
@@ -197,8 +199,10 @@ extern struct acpi_dmtable_info acpi_dm_table_info_slit[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_spcr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_spmi[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_srat_hdr[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat0[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_srat1[];
|
||||
+extern struct acpi_dmtable_info acpi_dm_table_info_srat2[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[];
|
||||
extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[];
|
||||
|
||||
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
|
||||
index d38f9be..63f5b4c 100644
|
||||
--- a/include/acpi/actbl1.h
|
||||
+++ b/include/acpi/actbl1.h
|
||||
@@ -908,7 +908,9 @@ enum acpi_madt_type {
|
||||
ACPI_MADT_TYPE_IO_SAPIC = 6,
|
||||
ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
|
||||
ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
|
||||
- ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */
|
||||
+ ACPI_MADT_TYPE_LOCAL_X2APIC = 9,
|
||||
+ ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10,
|
||||
+ ACPI_MADT_TYPE_RESERVED = 11 /* 11 and greater are reserved */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1009,6 +1011,26 @@ struct acpi_madt_interrupt_source {
|
||||
|
||||
#define ACPI_MADT_CPEI_OVERRIDE (1)
|
||||
|
||||
+/* 9: Processor Local X2_APIC (07/2008) */
|
||||
+
|
||||
+struct acpi_madt_local_x2apic {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 reserved; /* Reserved - must be zero */
|
||||
+ u32 local_apic_id; /* Processor X2_APIC ID */
|
||||
+ u32 lapic_flags;
|
||||
+ u32 uid; /* Extended X2_APIC processor ID */
|
||||
+};
|
||||
+
|
||||
+/* 10: Local X2APIC NMI (07/2008) */
|
||||
+
|
||||
+struct acpi_madt_local_x2apic_nmi {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 inti_flags;
|
||||
+ u32 uid; /* Processor X2_APIC ID */
|
||||
+ u8 lint; /* LINTn to which NMI is connected */
|
||||
+ u8 reserved[3];
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* Common flags fields for MADT subtables
|
||||
*/
|
||||
@@ -1150,10 +1172,15 @@ struct acpi_table_srat {
|
||||
enum acpi_srat_type {
|
||||
ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
|
||||
ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
|
||||
- ACPI_SRAT_TYPE_RESERVED = 2
|
||||
+ ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2,
|
||||
+ ACPI_SRAT_TYPE_RESERVED = 3 /* 3 and greater are reserved */
|
||||
};
|
||||
|
||||
-/* SRAT sub-tables */
|
||||
+/*
|
||||
+ * SRAT Sub-tables, correspond to Type in struct acpi_subtable_header
|
||||
+ */
|
||||
+
|
||||
+/* 0: Processor Local APIC/SAPIC Affinity */
|
||||
|
||||
struct acpi_srat_cpu_affinity {
|
||||
struct acpi_subtable_header header;
|
||||
@@ -1165,9 +1192,7 @@ struct acpi_srat_cpu_affinity {
|
||||
u32 reserved; /* Reserved, must be zero */
|
||||
};
|
||||
|
||||
-/* Flags */
|
||||
-
|
||||
-#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
||||
+/* 1: Memory Affinity */
|
||||
|
||||
struct acpi_srat_mem_affinity {
|
||||
struct acpi_subtable_header header;
|
||||
@@ -1186,6 +1211,20 @@ struct acpi_srat_mem_affinity {
|
||||
#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
|
||||
#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */
|
||||
|
||||
+/* 2: Processor Local X2_APIC Affinity (07/2008) */
|
||||
+
|
||||
+struct acpi_srat_x2apic_cpu_affinity {
|
||||
+ struct acpi_subtable_header header;
|
||||
+ u16 reserved; /* Reserved, must be zero */
|
||||
+ u32 proximity_domain;
|
||||
+ u32 apic_id;
|
||||
+ u32 flags;
|
||||
+};
|
||||
+
|
||||
+/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */
|
||||
+
|
||||
+#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
|
||||
+
|
||||
/*******************************************************************************
|
||||
*
|
||||
* TCPA - Trusted Computing Platform Alliance table
|
||||
@@ -0,0 +1,335 @@
|
||||
From: Jean Delvare <jdelvare@suse.de>
|
||||
Subject: Check for ACPI resource conflicts in hwmon drivers.
|
||||
Patch-mainline: 2.6.24-rc3-mm1
|
||||
|
||||
I've included all Super-I/O and PCI drivers.
|
||||
|
||||
I've voluntarily left out:
|
||||
* Laptop specific and vendor-specific drivers: if they conflicted
|
||||
on any system, this would pretty much mean that they conflict on all
|
||||
systems, and we would know by now.
|
||||
* Legacy ISA drivers (lm78 and w83781d): they only support chips found
|
||||
on old designs were ACPI either wasn't supported or didn't deal with
|
||||
thermal management.
|
||||
* Drivers accessing the I/O resources indirectly (e.g. through SMBus):
|
||||
the check will be added where it belongs, i.e. in the bus drivers.
|
||||
|
||||
Signed-off-by: Jean Delvare <jdelvare@suse.de>
|
||||
Signed-off-by: Thomas Renninger <trenn@suse.de>
|
||||
Cc: "Mark M. Hoffman" <mhoffman@lightlink.com>
|
||||
Cc: Len Brown <lenb@kernel.org>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
drivers/hwmon/dme1737.c | 5 +++++
|
||||
drivers/hwmon/f71805f.c | 5 +++++
|
||||
drivers/hwmon/f71882fg.c | 5 +++++
|
||||
drivers/hwmon/it87.c | 5 +++++
|
||||
drivers/hwmon/pc87360.c | 6 ++++++
|
||||
drivers/hwmon/pc87427.c | 5 +++++
|
||||
drivers/hwmon/sis5595.c | 5 +++++
|
||||
drivers/hwmon/smsc47b397.c | 5 +++++
|
||||
drivers/hwmon/smsc47m1.c | 5 +++++
|
||||
drivers/hwmon/via686a.c | 5 +++++
|
||||
drivers/hwmon/vt1211.c | 5 +++++
|
||||
drivers/hwmon/vt8231.c | 5 +++++
|
||||
drivers/hwmon/w83627ehf.c | 6 ++++++
|
||||
drivers/hwmon/w83627hf.c | 5 +++++
|
||||
14 files changed, 72 insertions(+)
|
||||
|
||||
--- a/drivers/hwmon/dme1737.c
|
||||
+++ b/drivers/hwmon/dme1737.c
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* ISA device, if found */
|
||||
@@ -2372,6 +2373,10 @@ static int __init dme1737_isa_device_add
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
if (!(pdev = platform_device_alloc("dme1737", addr))) {
|
||||
printk(KERN_ERR "dme1737: Failed to allocate device.\n");
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/f71805f.c
|
||||
+++ b/drivers/hwmon/f71805f.c
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static unsigned short force_id;
|
||||
@@ -1455,6 +1456,10 @@ static int __init f71805f_device_add(uns
|
||||
}
|
||||
|
||||
res.name = pdev->name;
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit_device_put;
|
||||
+
|
||||
err = platform_device_add_resources(pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed "
|
||||
--- a/drivers/hwmon/f71882fg.c
|
||||
+++ b/drivers/hwmon/f71882fg.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRVNAME "f71882fg"
|
||||
@@ -892,6 +893,10 @@ static int __init f71882fg_device_add(un
|
||||
return -ENOMEM;
|
||||
|
||||
res.name = f71882fg_pdev->name;
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
err = platform_device_add_resources(f71882fg_pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
|
||||
--- a/drivers/hwmon/it87.c
|
||||
+++ b/drivers/hwmon/it87.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dmi.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRVNAME "it87"
|
||||
@@ -1535,6 +1536,10 @@ static int __init it87_device_add(unsign
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/pc87360.c
|
||||
+++ b/drivers/hwmon/pc87360.c
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static u8 devid;
|
||||
@@ -1425,6 +1426,11 @@ static int __init pc87360_device_add(uns
|
||||
continue;
|
||||
res.start = extra_isa[i];
|
||||
res.end = extra_isa[i] + PC87360_EXTENT - 1;
|
||||
+
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit_device_put;
|
||||
+
|
||||
err = platform_device_add_resources(pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR "pc87360: Device resource[%d] "
|
||||
--- a/drivers/hwmon/pc87427.c
|
||||
+++ b/drivers/hwmon/pc87427.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static unsigned short force_id;
|
||||
@@ -524,6 +525,10 @@ static int __init pc87427_device_add(uns
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/sis5595.c
|
||||
+++ b/drivers/hwmon/sis5595.c
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@@ -727,6 +728,10 @@ static int __devinit sis5595_device_add(
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc("sis5595", address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/smsc47b397.c
|
||||
+++ b/drivers/hwmon/smsc47b397.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static unsigned short force_id;
|
||||
@@ -303,6 +304,10 @@ static int __init smsc47b397_device_add(
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/smsc47m1.c
|
||||
+++ b/drivers/hwmon/smsc47m1.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static unsigned short force_id;
|
||||
@@ -705,6 +706,10 @@ static int __init smsc47m1_device_add(un
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/via686a.c
|
||||
+++ b/drivers/hwmon/via686a.c
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@@ -783,6 +784,10 @@ static int __devinit via686a_device_add(
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc("via686a", address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/vt1211.c
|
||||
+++ b/drivers/hwmon/vt1211.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static int uch_config = -1;
|
||||
@@ -1259,6 +1260,10 @@ static int __init vt1211_device_add(unsi
|
||||
}
|
||||
|
||||
res.name = pdev->name;
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto EXIT;
|
||||
+
|
||||
err = platform_device_add_resources(pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed "
|
||||
--- a/drivers/hwmon/vt8231.c
|
||||
+++ b/drivers/hwmon/vt8231.c
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static int force_addr;
|
||||
@@ -894,6 +895,10 @@ static int __devinit vt8231_device_add(u
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc("vt8231", address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
--- a/drivers/hwmon/w83627ehf.c
|
||||
+++ b/drivers/hwmon/w83627ehf.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
#include "lm75.h"
|
||||
|
||||
@@ -1544,6 +1545,11 @@ static int __init sensors_w83627ehf_init
|
||||
res.start = address + IOREGION_OFFSET;
|
||||
res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
|
||||
res.flags = IORESOURCE_IO;
|
||||
+
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
err = platform_device_add_resources(pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed "
|
||||
--- a/drivers/hwmon/w83627hf.c
|
||||
+++ b/drivers/hwmon/w83627hf.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <asm/io.h>
|
||||
#include "lm75.h"
|
||||
|
||||
@@ -1793,6 +1794,10 @@ static int __init w83627hf_device_add(un
|
||||
};
|
||||
int err;
|
||||
|
||||
+ err = acpi_check_resource_conflict(&res);
|
||||
+ if (err)
|
||||
+ goto exit;
|
||||
+
|
||||
pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
@@ -0,0 +1,38 @@
|
||||
From: schwab@suse.de
|
||||
Subject: Fix msr check in compat_sys_swapcontext
|
||||
References: 441498
|
||||
|
||||
The new context may not be 16-byte aligned, so the real address of the
|
||||
mcontext structure should be read from the uc_regs pointer instead of
|
||||
directly using the (unaligned) uc_mcontext field.
|
||||
|
||||
Signed-off-by: Andreas Schwab <schwab@suse.de>
|
||||
|
||||
---
|
||||
---
|
||||
arch/powerpc/kernel/signal_32.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/signal_32.c
|
||||
+++ b/arch/powerpc/kernel/signal_32.c
|
||||
@@ -941,9 +941,17 @@ long sys_swapcontext(struct ucontext __u
|
||||
#ifdef CONFIG_PPC64
|
||||
unsigned long new_msr = 0;
|
||||
|
||||
- if (new_ctx &&
|
||||
- get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR]))
|
||||
- return -EFAULT;
|
||||
+ if (new_ctx) {
|
||||
+ struct mcontext __user *mcp;
|
||||
+ u32 cmcp;
|
||||
+
|
||||
+ /* Get pointer to the real mcontext. */
|
||||
+ if (get_user(cmcp, &new_ctx->uc_regs))
|
||||
+ return -EFAULT;
|
||||
+ mcp = (struct mcontext __user *)(u64)cmcp;
|
||||
+ if (get_user(new_msr, &mcp->mc_gregs[PT_MSR]))
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
/*
|
||||
* Check that the context is not smaller than the original
|
||||
* size (with VMX but without VSX)
|
||||
43
src/patches/suse-2.6.27.25/patches.arch/disable-apic-error
Normal file
43
src/patches/suse-2.6.27.25/patches.arch/disable-apic-error
Normal file
@@ -0,0 +1,43 @@
|
||||
From: ak@suse.de
|
||||
Subject: Disable APIC error printing
|
||||
References: 156576
|
||||
Patch-mainline: not planned
|
||||
|
||||
ATI chipsets currently do this all the time. It's probably
|
||||
mostly harmless
|
||||
|
||||
We keep it enabled in mainline to make sure the (hardware?) bug
|
||||
is tracked down, but don't bother in the distribution kernels
|
||||
with it.
|
||||
|
||||
---
|
||||
arch/x86/kernel/apic_32.c | 2 ++
|
||||
arch/x86/kernel/apic_64.c | 2 ++
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
--- a/arch/x86/kernel/apic_32.c
|
||||
+++ b/arch/x86/kernel/apic_32.c
|
||||
@@ -1316,8 +1316,10 @@ void smp_error_interrupt(struct pt_regs
|
||||
6: Received illegal vector
|
||||
7: Illegal register address
|
||||
*/
|
||||
+#if 0
|
||||
printk(KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n",
|
||||
smp_processor_id(), v , v1);
|
||||
+#endif
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
--- a/arch/x86/kernel/apic_64.c
|
||||
+++ b/arch/x86/kernel/apic_64.c
|
||||
@@ -998,8 +998,10 @@ asmlinkage void smp_error_interrupt(void
|
||||
6: Received illegal vector
|
||||
7: Illegal register address
|
||||
*/
|
||||
+#if 0
|
||||
printk(KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
|
||||
smp_processor_id(), v , v1);
|
||||
+#endif
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
30
src/patches/suse-2.6.27.25/patches.arch/ia64-cpu_disable-fix
Normal file
30
src/patches/suse-2.6.27.25/patches.arch/ia64-cpu_disable-fix
Normal file
@@ -0,0 +1,30 @@
|
||||
From: Alex Chiang <achiang@hp.com>
|
||||
Subject: IA64: first clear CPU from online map, then fixup IRQs.
|
||||
References: bnc#386714
|
||||
|
||||
Acked-by: Raymund Will <rw@suse.de>
|
||||
|
||||
---
|
||||
arch/ia64/kernel/smpboot.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/arch/ia64/kernel/smpboot.c
|
||||
+++ b/arch/ia64/kernel/smpboot.c
|
||||
@@ -741,14 +741,12 @@ int __cpu_disable(void)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
- if (migrate_platform_irqs(cpu)) {
|
||||
- cpu_set(cpu, cpu_online_map);
|
||||
- return (-EBUSY);
|
||||
- }
|
||||
+ if (migrate_platform_irqs(cpu))
|
||||
+ return -EBUSY;
|
||||
|
||||
remove_siblinginfo(cpu);
|
||||
- fixup_irqs();
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
+ fixup_irqs();
|
||||
local_flush_tlb_all();
|
||||
cpu_clear(cpu, cpu_callin_map);
|
||||
return 0;
|
||||
598
src/patches/suse-2.6.27.25/patches.arch/ia64-page-migration
Normal file
598
src/patches/suse-2.6.27.25/patches.arch/ia64-page-migration
Normal file
@@ -0,0 +1,598 @@
|
||||
From: Russ Anderson <rja@sgi.com>
|
||||
Subject: ia64: Call migration code on correctable errors v8
|
||||
References: 415829
|
||||
Acked-by: schwab@suse.de
|
||||
|
||||
Migrate data off pages with correctable memory errors. This patch is the
|
||||
ia64 specific piece. It connects the CPE handler to the page migration
|
||||
code. It is implemented as a kernel loadable module, similar to the mca
|
||||
recovery code (mca_recovery.ko). This allows the feature to be turned off
|
||||
by uninstalling the module.
|
||||
|
||||
|
||||
Signed-off-by: Russ Anderson <rja@sgi.com>
|
||||
|
||||
---
|
||||
arch/ia64/Kconfig | 9
|
||||
arch/ia64/include/asm/mca.h | 6
|
||||
arch/ia64/include/asm/page.h | 1
|
||||
arch/ia64/kernel/Makefile | 1
|
||||
arch/ia64/kernel/cpe_migrate.c | 434 +++++++++++++++++++++++++++++++++++++++++
|
||||
arch/ia64/kernel/mca.c | 37 +++
|
||||
6 files changed, 487 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/ia64/include/asm/mca.h
|
||||
+++ b/arch/ia64/include/asm/mca.h
|
||||
@@ -137,6 +137,7 @@ extern unsigned long __per_cpu_mca[NR_CP
|
||||
|
||||
extern int cpe_vector;
|
||||
extern int ia64_cpe_irq;
|
||||
+extern int cpe_poll_enabled;
|
||||
extern void ia64_mca_init(void);
|
||||
extern void ia64_mca_cpu_init(void *);
|
||||
extern void ia64_os_mca_dispatch(void);
|
||||
@@ -150,10 +151,15 @@ extern void ia64_slave_init_handler(void
|
||||
extern void ia64_mca_cmc_vector_setup(void);
|
||||
extern int ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *));
|
||||
extern void ia64_unreg_MCA_extension(void);
|
||||
+extern int ia64_reg_CE_extension(int (*fn)(void *));
|
||||
+extern void ia64_unreg_CE_extension(void);
|
||||
extern u64 ia64_get_rnat(u64 *);
|
||||
extern void ia64_mca_printk(const char * fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
+extern struct list_head badpagelist;
|
||||
+extern unsigned int total_badpages;
|
||||
+
|
||||
struct ia64_mca_notify_die {
|
||||
struct ia64_sal_os_state *sos;
|
||||
int *monarch_cpu;
|
||||
--- a/arch/ia64/include/asm/page.h
|
||||
+++ b/arch/ia64/include/asm/page.h
|
||||
@@ -121,6 +121,7 @@ extern unsigned long max_low_pfn;
|
||||
#endif
|
||||
|
||||
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
|
||||
+#define phys_to_page(kaddr) (pfn_to_page(kaddr >> PAGE_SHIFT))
|
||||
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
|
||||
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
|
||||
--- a/arch/ia64/Kconfig
|
||||
+++ b/arch/ia64/Kconfig
|
||||
@@ -470,6 +470,15 @@ config COMPAT_FOR_U64_ALIGNMENT
|
||||
config IA64_MCA_RECOVERY
|
||||
tristate "MCA recovery from errors other than TLB."
|
||||
|
||||
+config IA64_CPE_MIGRATE
|
||||
+ tristate "Migrate data off pages with correctable errors"
|
||||
+ default m
|
||||
+ help
|
||||
+ Migrate data off pages with correctable memory errors. Selecting
|
||||
+ Y will build this functionality into the kernel. Selecting M will
|
||||
+ build this functionality as a kernel loadable module. Installing
|
||||
+ the module will turn on the functionality.
|
||||
+
|
||||
config PERFMON
|
||||
bool "Performance monitor support"
|
||||
help
|
||||
--- /dev/null
|
||||
+++ b/arch/ia64/kernel/cpe_migrate.c
|
||||
@@ -0,0 +1,434 @@
|
||||
+/*
|
||||
+ * File: cpe_migrate.c
|
||||
+ * Purpose: Migrate data from physical pages with excessive correctable
|
||||
+ * errors to new physical pages. Keep the old pages on a discard
|
||||
+ * list.
|
||||
+ *
|
||||
+ * Copyright (C) 2008 SGI - Silicon Graphics Inc.
|
||||
+ * Copyright (C) 2008 Russ Anderson <rja@sgi.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/sysdev.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/smp.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/swap.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+#include <linux/migrate.h>
|
||||
+#include <linux/page-isolation.h>
|
||||
+#include <linux/memcontrol.h>
|
||||
+#include <linux/kobject.h>
|
||||
+
|
||||
+#include <asm/page.h>
|
||||
+#include <asm/system.h>
|
||||
+#include <asm/sn/sn_cpuid.h>
|
||||
+#include <asm/mca.h>
|
||||
+
|
||||
+#define BADRAM_BASENAME "badram"
|
||||
+#define CE_HISTORY_LENGTH 30
|
||||
+
|
||||
+struct cpe_info {
|
||||
+ u64 paddr;
|
||||
+ u16 node;
|
||||
+};
|
||||
+static struct cpe_info cpe[CE_HISTORY_LENGTH];
|
||||
+
|
||||
+static int cpe_polling_enabled = 1;
|
||||
+static int cpe_head;
|
||||
+static int cpe_tail;
|
||||
+static int work_scheduled;
|
||||
+static int mstat_cannot_isolate;
|
||||
+static int mstat_failed_to_discard;
|
||||
+static int mstat_already_marked;
|
||||
+static int mstat_already_on_list;
|
||||
+
|
||||
+DEFINE_SPINLOCK(cpe_migrate_lock);
|
||||
+
|
||||
+static void
|
||||
+get_physical_address(void *buffer, u64 *paddr, u16 *node)
|
||||
+{
|
||||
+ sal_log_record_header_t *rh;
|
||||
+ sal_log_mem_dev_err_info_t *mdei;
|
||||
+ ia64_err_rec_t *err_rec;
|
||||
+ sal_log_platform_err_info_t *plat_err;
|
||||
+ efi_guid_t guid;
|
||||
+
|
||||
+ err_rec = buffer;
|
||||
+ rh = &err_rec->sal_elog_header;
|
||||
+ *paddr = 0;
|
||||
+ *node = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure it is a corrected error.
|
||||
+ */
|
||||
+ if (rh->severity != sal_log_severity_corrected)
|
||||
+ return;
|
||||
+
|
||||
+ plat_err = (sal_log_platform_err_info_t *)&err_rec->proc_err;
|
||||
+
|
||||
+ guid = plat_err->mem_dev_err.header.guid;
|
||||
+ if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
|
||||
+ /*
|
||||
+ * Memory cpe
|
||||
+ */
|
||||
+ mdei = &plat_err->mem_dev_err;
|
||||
+ if (mdei->valid.oem_data) {
|
||||
+ if (mdei->valid.physical_addr)
|
||||
+ *paddr = mdei->physical_addr;
|
||||
+
|
||||
+ if (mdei->valid.node) {
|
||||
+ if (ia64_platform_is("sn2"))
|
||||
+ *node = nasid_to_cnodeid(mdei->node);
|
||||
+ else
|
||||
+ *node = mdei->node;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static struct page *
|
||||
+alloc_migrate_page(struct page *ignored, unsigned long node, int **x)
|
||||
+{
|
||||
+
|
||||
+ return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+validate_paddr_page(u64 paddr)
|
||||
+{
|
||||
+ struct page *page;
|
||||
+
|
||||
+ if (!paddr)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!ia64_phys_addr_valid(paddr))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!pfn_valid(paddr >> PAGE_SHIFT))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ page = phys_to_page(paddr);
|
||||
+ if (PageMemError(page))
|
||||
+ mstat_already_marked++;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+ia64_mca_cpe_move_page(u64 paddr, u32 node)
|
||||
+{
|
||||
+ LIST_HEAD(pagelist);
|
||||
+ struct page *page;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = validate_paddr_page(paddr);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * convert physical address to page number
|
||||
+ */
|
||||
+ page = phys_to_page(paddr);
|
||||
+
|
||||
+ migrate_prep();
|
||||
+ ret = isolate_lru_page(page, &pagelist);
|
||||
+ if (ret) {
|
||||
+ mstat_cannot_isolate++;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ SetPageMemError(page); /* Mark the page as bad */
|
||||
+ ret = migrate_pages(&pagelist, alloc_migrate_page, node);
|
||||
+ if (ret == 0) {
|
||||
+ total_badpages++;
|
||||
+ list_add_tail(&page->lru, &badpagelist);
|
||||
+ } else {
|
||||
+ mstat_failed_to_discard++;
|
||||
+ /*
|
||||
+ * The page failed to migrate and is not on the bad page list.
|
||||
+ * Clearing the error bit will allow another attempt to migrate
|
||||
+ * if it gets another correctable error.
|
||||
+ */
|
||||
+ ClearPageMemError(page);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * ia64_mca_cpe_migrate
|
||||
+ * The worker that does the actual migration. It pulls a
|
||||
+ * physical address off the list and calls the migration code.
|
||||
+ */
|
||||
+static void
|
||||
+ia64_mca_cpe_migrate(struct work_struct *unused)
|
||||
+{
|
||||
+ int ret;
|
||||
+ u64 paddr;
|
||||
+ u16 node;
|
||||
+
|
||||
+ do {
|
||||
+ paddr = cpe[cpe_tail].paddr;
|
||||
+ if (paddr) {
|
||||
+ /*
|
||||
+ * There is a valid entry that needs processing.
|
||||
+ */
|
||||
+ node = cpe[cpe_tail].node;
|
||||
+
|
||||
+ ret = ia64_mca_cpe_move_page(paddr, node);
|
||||
+ if (ret <= 0)
|
||||
+ /*
|
||||
+ * Even though the return status is negative,
|
||||
+ * clear the entry. If the same address has
|
||||
+ * another CPE it will be re-added to the list.
|
||||
+ */
|
||||
+ cpe[cpe_tail].paddr = 0;
|
||||
+
|
||||
+ }
|
||||
+ if (++cpe_tail >= CE_HISTORY_LENGTH)
|
||||
+ cpe_tail = 0;
|
||||
+
|
||||
+ } while (cpe_tail != cpe_head);
|
||||
+ work_scheduled = 0;
|
||||
+}
|
||||
+
|
||||
+static DECLARE_WORK(cpe_enable_work, ia64_mca_cpe_migrate);
|
||||
+DEFINE_SPINLOCK(cpe_list_lock);
|
||||
+
|
||||
+/*
|
||||
+ * cpe_setup_migrate
|
||||
+ * Get the physical address out of the CPE record, add it
|
||||
+ * to the list of addresses to migrate (if not already on),
|
||||
+ * and schedule the back end worker task. This is called
|
||||
+ * in interrupt context so cannot directly call the migration
|
||||
+ * code.
|
||||
+ *
|
||||
+ * Inputs
|
||||
+ * rec The CPE record
|
||||
+ * Outputs
|
||||
+ * 1 on Success, -1 on failure
|
||||
+ */
|
||||
+static int
|
||||
+cpe_setup_migrate(void *rec)
|
||||
+{
|
||||
+ u64 paddr;
|
||||
+ u16 node;
|
||||
+ /* int head, tail; */
|
||||
+ int i, ret;
|
||||
+
|
||||
+ if (!rec)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ get_physical_address(rec, &paddr, &node);
|
||||
+ ret = validate_paddr_page(paddr);
|
||||
+ if (ret < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((cpe_head != cpe_tail) || (cpe[cpe_head].paddr != 0))
|
||||
+ /*
|
||||
+ * List not empty
|
||||
+ */
|
||||
+ for (i = 0; i < CE_HISTORY_LENGTH; i++) {
|
||||
+ if (PAGE_ALIGN(cpe[i].paddr) == PAGE_ALIGN(paddr)) {
|
||||
+ mstat_already_on_list++;
|
||||
+ return 1; /* already on the list */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!spin_trylock(&cpe_list_lock)) {
|
||||
+ /*
|
||||
+ * Someone else has the lock. To avoid spinning in interrupt
|
||||
+ * handler context, bail.
|
||||
+ */
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (cpe[cpe_head].paddr == 0) {
|
||||
+ cpe[cpe_head].node = node;
|
||||
+ cpe[cpe_head].paddr = paddr;
|
||||
+
|
||||
+ if (++cpe_head >= CE_HISTORY_LENGTH)
|
||||
+ cpe_head = 0;
|
||||
+ }
|
||||
+ spin_unlock(&cpe_list_lock);
|
||||
+
|
||||
+ if (!work_scheduled) {
|
||||
+ work_scheduled = 1;
|
||||
+ schedule_work(&cpe_enable_work);
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * =============================================================================
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * free_one_bad_page
|
||||
+ * Free one page from the list of bad pages.
|
||||
+ */
|
||||
+static int
|
||||
+free_one_bad_page(unsigned long paddr)
|
||||
+{
|
||||
+ LIST_HEAD(pagelist);
|
||||
+ struct page *page, *page2, *target;
|
||||
+
|
||||
+ /*
|
||||
+ * Verify page address
|
||||
+ */
|
||||
+ target = phys_to_page(paddr);
|
||||
+ list_for_each_entry_safe(page, page2, &badpagelist, lru) {
|
||||
+ if (page != target)
|
||||
+ continue;
|
||||
+
|
||||
+ ClearPageMemError(page); /* Mark the page as good */
|
||||
+ total_badpages--;
|
||||
+ list_move_tail(&page->lru, &pagelist);
|
||||
+ putback_lru_pages(&pagelist);
|
||||
+ break;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * free_all_bad_pages
|
||||
+ * Free all of the pages on the bad pages list.
|
||||
+ */
|
||||
+static int
|
||||
+free_all_bad_pages(void)
|
||||
+{
|
||||
+ struct page *page, *page2;
|
||||
+
|
||||
+ list_for_each_entry_safe(page, page2, &badpagelist, lru) {
|
||||
+ ClearPageMemError(page); /* Mark the page as good */
|
||||
+ total_badpages--;
|
||||
+ }
|
||||
+ putback_lru_pages(&badpagelist);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#define OPT_LEN 16
|
||||
+
|
||||
+static ssize_t
|
||||
+badpage_store(struct kobject *kobj,
|
||||
+ struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
+{
|
||||
+ char optstr[OPT_LEN];
|
||||
+ unsigned long opt;
|
||||
+ int len = OPT_LEN;
|
||||
+ int err;
|
||||
+
|
||||
+ if (count < len)
|
||||
+ len = count;
|
||||
+
|
||||
+ strlcpy(optstr, buf, len);
|
||||
+
|
||||
+ err = strict_strtoul(optstr, 16, &opt);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (opt == 0)
|
||||
+ free_all_bad_pages();
|
||||
+ else
|
||||
+ free_one_bad_page(opt);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * badpage_show
|
||||
+ * Display the number, size, and addresses of all the pages on the
|
||||
+ * bad page list.
|
||||
+ *
|
||||
+ * Note that sysfs provides buf of PAGE_SIZE length. bufend tracks
|
||||
+ * the remaining space in buf to avoid overflowing.
|
||||
+ */
|
||||
+static ssize_t
|
||||
+badpage_show(struct kobject *kobj,
|
||||
+ struct kobj_attribute *attr, char *buf)
|
||||
+
|
||||
+{
|
||||
+ struct page *page, *page2;
|
||||
+ int i = 0, cnt = 0;
|
||||
+ char *bufend = buf + PAGE_SIZE;
|
||||
+
|
||||
+ cnt = snprintf(buf, bufend - (buf + cnt),
|
||||
+ "Memory marked bad: %d kB\n"
|
||||
+ "Pages marked bad: %d\n"
|
||||
+ "Unable to isolate on LRU: %d\n"
|
||||
+ "Unable to migrate: %d\n"
|
||||
+ "Already marked bad: %d\n"
|
||||
+ "Already on list: %d\n"
|
||||
+ "List of bad physical pages\n",
|
||||
+ total_badpages << (PAGE_SHIFT - 10), total_badpages,
|
||||
+ mstat_cannot_isolate, mstat_failed_to_discard,
|
||||
+ mstat_already_marked, mstat_already_on_list
|
||||
+ );
|
||||
+
|
||||
+ list_for_each_entry_safe(page, page2, &badpagelist, lru) {
|
||||
+ if (bufend - (buf + cnt) < 20)
|
||||
+ break; /* Avoid overflowing the buffer */
|
||||
+ cnt += snprintf(buf + cnt, bufend - (buf + cnt),
|
||||
+ " 0x%011lx", page_to_phys(page));
|
||||
+ if (!(++i % 5))
|
||||
+ cnt += snprintf(buf + cnt, bufend - (buf + cnt), "\n");
|
||||
+ }
|
||||
+ cnt += snprintf(buf + cnt, bufend - (buf + cnt), "\n");
|
||||
+
|
||||
+ return cnt;
|
||||
+}
|
||||
+
|
||||
+static struct kobj_attribute badram_attr = {
|
||||
+ .attr = {
|
||||
+ .name = "badram",
|
||||
+ .mode = S_IWUSR | S_IRUGO,
|
||||
+ },
|
||||
+ .show = badpage_show,
|
||||
+ .store = badpage_store,
|
||||
+};
|
||||
+
|
||||
+static int __init
|
||||
+cpe_migrate_external_handler_init(void)
|
||||
+{
|
||||
+ int error;
|
||||
+
|
||||
+ error = sysfs_create_file(kernel_kobj, &badram_attr.attr);
|
||||
+ if (error)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /*
|
||||
+ * register external ce handler
|
||||
+ */
|
||||
+ if (ia64_reg_CE_extension(cpe_setup_migrate)) {
|
||||
+ printk(KERN_ERR "ia64_reg_CE_extension failed.\n");
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ cpe_poll_enabled = cpe_polling_enabled;
|
||||
+
|
||||
+ printk(KERN_INFO "Registered badram Driver\n");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __exit
|
||||
+cpe_migrate_external_handler_exit(void)
|
||||
+{
|
||||
+ /* unregister external mca handlers */
|
||||
+ ia64_unreg_CE_extension();
|
||||
+
|
||||
+ sysfs_remove_file(kernel_kobj, &badram_attr.attr);
|
||||
+}
|
||||
+
|
||||
+module_init(cpe_migrate_external_handler_init);
|
||||
+module_exit(cpe_migrate_external_handler_exit);
|
||||
+
|
||||
+module_param(cpe_polling_enabled, int, 0644);
|
||||
+MODULE_PARM_DESC(cpe_polling_enabled,
|
||||
+ "Enable polling with migration");
|
||||
+
|
||||
+MODULE_AUTHOR("Russ Anderson <rja@sgi.com>");
|
||||
+MODULE_DESCRIPTION("ia64 Corrected Error page migration driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/arch/ia64/kernel/Makefile
|
||||
+++ b/arch/ia64/kernel/Makefile
|
||||
@@ -27,6 +27,7 @@ obj-$(CONFIG_PERFMON) += perfmon_defaul
|
||||
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
|
||||
+obj-$(CONFIG_IA64_CPE_MIGRATE) += cpe_migrate.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
--- a/arch/ia64/kernel/mca.c
|
||||
+++ b/arch/ia64/kernel/mca.c
|
||||
@@ -68,6 +68,9 @@
|
||||
*
|
||||
* 2007-04-27 Russ Anderson <rja@sgi.com>
|
||||
* Support multiple cpus going through OS_MCA in the same event.
|
||||
+ *
|
||||
+ * 2008-04-22 Russ Anderson <rja@sgi.com>
|
||||
+ * Migrate data off pages with correctable memory errors.
|
||||
*/
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/types.h>
|
||||
@@ -163,7 +166,14 @@ static int cmc_polling_enabled = 1;
|
||||
* but encounters problems retrieving CPE logs. This should only be
|
||||
* necessary for debugging.
|
||||
*/
|
||||
-static int cpe_poll_enabled = 1;
|
||||
+int cpe_poll_enabled = 1;
|
||||
+EXPORT_SYMBOL(cpe_poll_enabled);
|
||||
+
|
||||
+unsigned int total_badpages;
|
||||
+EXPORT_SYMBOL(total_badpages);
|
||||
+
|
||||
+LIST_HEAD(badpagelist);
|
||||
+EXPORT_SYMBOL(badpagelist);
|
||||
|
||||
extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
|
||||
|
||||
@@ -523,6 +533,28 @@ int mca_recover_range(unsigned long addr
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mca_recover_range);
|
||||
|
||||
+/* Function pointer to Corrected Error memory migration driver */
|
||||
+int (*ia64_mca_ce_extension)(void *);
|
||||
+
|
||||
+int
|
||||
+ia64_reg_CE_extension(int (*fn)(void *))
|
||||
+{
|
||||
+ if (ia64_mca_ce_extension)
|
||||
+ return 1;
|
||||
+
|
||||
+ ia64_mca_ce_extension = fn;
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ia64_reg_CE_extension);
|
||||
+
|
||||
+void
|
||||
+ia64_unreg_CE_extension(void)
|
||||
+{
|
||||
+ if (ia64_mca_ce_extension)
|
||||
+ ia64_mca_ce_extension = NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ia64_unreg_CE_extension);
|
||||
+
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
int cpe_vector = -1;
|
||||
@@ -534,6 +566,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, v
|
||||
static unsigned long cpe_history[CPE_HISTORY_LENGTH];
|
||||
static int index;
|
||||
static DEFINE_SPINLOCK(cpe_history_lock);
|
||||
+ int recover;
|
||||
|
||||
IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n",
|
||||
__func__, cpe_irq, smp_processor_id());
|
||||
@@ -580,6 +613,8 @@ ia64_mca_cpe_int_handler (int cpe_irq, v
|
||||
out:
|
||||
/* Get the CPE error record and log it */
|
||||
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
|
||||
+ recover = (ia64_mca_ce_extension && ia64_mca_ce_extension(
|
||||
+ IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_CPE)));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
161
src/patches/suse-2.6.27.25/patches.arch/ia64-page-migration.fix
Normal file
161
src/patches/suse-2.6.27.25/patches.arch/ia64-page-migration.fix
Normal file
@@ -0,0 +1,161 @@
|
||||
From: Russ Anderson <rja@sgi.com>
|
||||
Subject: ia64: cpe_migrate.ko causes deadlock.
|
||||
References: bnc#464676
|
||||
|
||||
schedule_on_each_cpu() deadlocks when called from an event thread.
|
||||
Change cpe_migrate to use a kthread to avoid the problem.
|
||||
|
||||
Signed-off-by: Russ Anderson <rja@sgi.com>
|
||||
Acked-by: Raymund Will <rw@suse.de>
|
||||
|
||||
---
|
||||
arch/ia64/kernel/cpe_migrate.c | 72 +++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 56 insertions(+), 16 deletions(-)
|
||||
|
||||
Index: linux/arch/ia64/kernel/cpe_migrate.c
|
||||
===================================================================
|
||||
--- linux.orig/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:37:47.130269369 -0600
|
||||
+++ linux/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:44:43.658280930 -0600
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/page-isolation.h>
|
||||
#include <linux/memcontrol.h>
|
||||
#include <linux/kobject.h>
|
||||
+#include <linux/kthread.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/system.h>
|
||||
@@ -40,12 +41,15 @@ static struct cpe_info cpe[CE_HISTORY_LE
|
||||
static int cpe_polling_enabled = 1;
|
||||
static int cpe_head;
|
||||
static int cpe_tail;
|
||||
-static int work_scheduled;
|
||||
static int mstat_cannot_isolate;
|
||||
static int mstat_failed_to_discard;
|
||||
static int mstat_already_marked;
|
||||
static int mstat_already_on_list;
|
||||
|
||||
+/* IRQ handler notifies this wait queue on receipt of an IRQ */
|
||||
+DECLARE_WAIT_QUEUE_HEAD(cpe_activate_IRQ_wq);
|
||||
+static DECLARE_COMPLETION(kthread_cpe_migrated_exited);
|
||||
+int cpe_active;
|
||||
DEFINE_SPINLOCK(cpe_migrate_lock);
|
||||
|
||||
static void
|
||||
@@ -159,12 +163,12 @@ ia64_mca_cpe_move_page(u64 paddr, u32 no
|
||||
}
|
||||
|
||||
/*
|
||||
- * ia64_mca_cpe_migrate
|
||||
- * The worker that does the actual migration. It pulls a
|
||||
- * physical address off the list and calls the migration code.
|
||||
+ * cpe_process_queue
|
||||
+ * Pulls the physical address off the list and calls the migration code.
|
||||
+ * Will process all the addresses on the list.
|
||||
*/
|
||||
-static void
|
||||
-ia64_mca_cpe_migrate(struct work_struct *unused)
|
||||
+void
|
||||
+cpe_process_queue(void)
|
||||
{
|
||||
int ret;
|
||||
u64 paddr;
|
||||
@@ -192,10 +196,36 @@ ia64_mca_cpe_migrate(struct work_struct
|
||||
cpe_tail = 0;
|
||||
|
||||
} while (cpe_tail != cpe_head);
|
||||
- work_scheduled = 0;
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+inline int
|
||||
+cpe_list_empty(void)
|
||||
+{
|
||||
+ return (cpe_head == cpe_tail) && (!cpe[cpe_head].paddr);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * kthread_cpe_migrate
|
||||
+ * kthread_cpe_migrate is created at module load time and lives
|
||||
+ * until the module is removed. When not active, it will sleep.
|
||||
+ */
|
||||
+static int
|
||||
+kthread_cpe_migrate(void *ignore)
|
||||
+{
|
||||
+ while (cpe_active) {
|
||||
+ /*
|
||||
+ * wait for work
|
||||
+ */
|
||||
+ (void)wait_event_interruptible(cpe_activate_IRQ_wq,
|
||||
+ (!cpe_list_empty() ||
|
||||
+ !cpe_active));
|
||||
+ cpe_process_queue(); /* process work */
|
||||
+ }
|
||||
+ complete(&kthread_cpe_migrated_exited);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-static DECLARE_WORK(cpe_enable_work, ia64_mca_cpe_migrate);
|
||||
DEFINE_SPINLOCK(cpe_list_lock);
|
||||
|
||||
/*
|
||||
@@ -227,10 +257,7 @@ cpe_setup_migrate(void *rec)
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
- if ((cpe_head != cpe_tail) || (cpe[cpe_head].paddr != 0))
|
||||
- /*
|
||||
- * List not empty
|
||||
- */
|
||||
+ if (!cpe_list_empty())
|
||||
for (i = 0; i < CE_HISTORY_LENGTH; i++) {
|
||||
if (PAGE_ALIGN(cpe[i].paddr) == PAGE_ALIGN(paddr)) {
|
||||
mstat_already_on_list++;
|
||||
@@ -255,10 +282,7 @@ cpe_setup_migrate(void *rec)
|
||||
}
|
||||
spin_unlock(&cpe_list_lock);
|
||||
|
||||
- if (!work_scheduled) {
|
||||
- work_scheduled = 1;
|
||||
- schedule_work(&cpe_enable_work);
|
||||
- }
|
||||
+ wake_up_interruptible(&cpe_activate_IRQ_wq);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -395,12 +419,23 @@ static int __init
|
||||
cpe_migrate_external_handler_init(void)
|
||||
{
|
||||
int error;
|
||||
+ struct task_struct *kthread;
|
||||
|
||||
error = sysfs_create_file(kernel_kobj, &badram_attr.attr);
|
||||
if (error)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
+ * set up the kthread
|
||||
+ */
|
||||
+ cpe_active = 1;
|
||||
+ kthread = kthread_run(kthread_cpe_migrate, NULL, "cpe_migrate");
|
||||
+ if (IS_ERR(kthread)) {
|
||||
+ complete(&kthread_cpe_migrated_exited);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
* register external ce handler
|
||||
*/
|
||||
if (ia64_reg_CE_extension(cpe_setup_migrate)) {
|
||||
@@ -418,6 +453,11 @@ cpe_migrate_external_handler_exit(void)
|
||||
{
|
||||
/* unregister external mca handlers */
|
||||
ia64_unreg_CE_extension();
|
||||
+
|
||||
+ /* Stop kthread */
|
||||
+ cpe_active = 0; /* tell kthread_cpe_migrate to exit */
|
||||
+ wake_up_interruptible(&cpe_activate_IRQ_wq);
|
||||
+ wait_for_completion(&kthread_cpe_migrated_exited);
|
||||
|
||||
sysfs_remove_file(kernel_kobj, &badram_attr.attr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
From: Petr Tesarik <ptesarik@suse.cz>
|
||||
Subject: [ia64] re-enable interrupts when waiting for a rwlock
|
||||
References: bnc#387784
|
||||
Mainline: no
|
||||
|
||||
Re-enable interrupts for _read_lock_irqsave() and _write_lock_irqsave()
|
||||
while waiting for the lock if interrupts were enabled in the caller.
|
||||
|
||||
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
|
||||
|
||||
---
|
||||
arch/ia64/include/asm/spinlock.h | 49 ++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 43 insertions(+), 6 deletions(-)
|
||||
|
||||
--- linux-2.6.26.orig/arch/ia64/include/asm/spinlock.h 2008-09-26 13:02:50.000000000 +0200
|
||||
+++ linux-2.6.26/arch/ia64/include/asm/spinlock.h 2008-09-26 15:54:11.000000000 +0200
|
||||
@@ -120,6 +120,35 @@ do { \
|
||||
#define __raw_read_can_lock(rw) (*(volatile int *)(rw) >= 0)
|
||||
#define __raw_write_can_lock(rw) (*(volatile int *)(rw) == 0)
|
||||
|
||||
+#ifdef ASM_SUPPORTED
|
||||
+#define __raw_read_lock_flags(rw, flags) \
|
||||
+do { \
|
||||
+ __asm__ __volatile__ ( \
|
||||
+ "tbit.nz p6,p0 = %1,%2\n" \
|
||||
+ "br.few 3f\n" \
|
||||
+ "1:\n" \
|
||||
+ "fetchadd4.rel r2 = [%0],-1;;\n" \
|
||||
+ "(p6) ssm psr.i\n" \
|
||||
+ "2:\n" \
|
||||
+ "hint @pause\n" \
|
||||
+ "ld4 r2 = [%0];;\n" \
|
||||
+ "cmp4.lt p7,p0 = r2,r0\n" \
|
||||
+ "(p7) br.cond.spnt.few 2b\n" \
|
||||
+ "(p6) rsm psr.i;;\n" \
|
||||
+ "3:\n" \
|
||||
+ "fetchadd4.acq r2 = [%0],1;;\n" \
|
||||
+ "cmp4.lt p7,p0 = r2,r0\n" \
|
||||
+ "(p7) br.cond.spnt.few 1b\n" \
|
||||
+ :: "r"(rw), "r"(flags), "i"(IA64_PSR_I_BIT) \
|
||||
+ : "p6", "p7", "r2", "memory"); \
|
||||
+} while(0)
|
||||
+
|
||||
+#define __raw_read_lock(lock) __raw_read_lock_flags(lock, 0)
|
||||
+
|
||||
+#else /* !ASM_SUPPORTED */
|
||||
+
|
||||
+#define __raw_read_lock_flags(rw, flags) __raw_read_lock(rw)
|
||||
+
|
||||
#define __raw_read_lock(rw) \
|
||||
do { \
|
||||
raw_rwlock_t *__read_lock_ptr = (rw); \
|
||||
@@ -131,6 +160,8 @@ do { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
+#endif /* !ASM_SUPPORTED */
|
||||
+
|
||||
#define __raw_read_unlock(rw) \
|
||||
do { \
|
||||
raw_rwlock_t *__read_lock_ptr = (rw); \
|
||||
@@ -138,21 +169,28 @@ do { \
|
||||
} while (0)
|
||||
|
||||
#ifdef ASM_SUPPORTED
|
||||
-#define __raw_write_lock(rw) \
|
||||
+#define __raw_write_lock_flags(rw, flags) \
|
||||
do { \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov ar.ccv = r0\n" \
|
||||
+ "tbit.nz p6,p0 = %1,%2\n" \
|
||||
"dep r29 = -1, r0, 31, 1;;\n" \
|
||||
"1:\n" \
|
||||
+ "(p6) ssm psr.i\n" \
|
||||
+ "2:\n" \
|
||||
"ld4 r2 = [%0];;\n" \
|
||||
"cmp4.eq p0,p7 = r0,r2\n" \
|
||||
- "(p7) br.cond.spnt.few 1b \n" \
|
||||
+ "(p7) br.cond.spnt.few 2b \n" \
|
||||
+ "(p6) rsm psr.i;;\n" \
|
||||
"cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n" \
|
||||
"cmp4.eq p0,p7 = r0, r2\n" \
|
||||
"(p7) br.cond.spnt.few 1b;;\n" \
|
||||
- :: "r"(rw) : "ar.ccv", "p7", "r2", "r29", "memory"); \
|
||||
+ :: "r"(rw), "r"(flags), "i"(IA64_PSR_I_BIT) \
|
||||
+ : "ar.ccv", "p6", "p7", "r2", "r29", "memory"); \
|
||||
} while(0)
|
||||
|
||||
+#define __raw_write_lock(rw) __raw_write_lock_flags(rw, 0)
|
||||
+
|
||||
#define __raw_write_trylock(rw) \
|
||||
({ \
|
||||
register long result; \
|
||||
@@ -174,6 +212,8 @@ static inline void __raw_write_unlock(ra
|
||||
|
||||
#else /* !ASM_SUPPORTED */
|
||||
|
||||
+#define __raw_write_lock_flags(l, flags) __raw_write_lock(l)
|
||||
+
|
||||
#define __raw_write_lock(l) \
|
||||
({ \
|
||||
__u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1); \
|
||||
@@ -213,9 +253,6 @@ static inline int __raw_read_trylock(raw
|
||||
return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word;
|
||||
}
|
||||
|
||||
-#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
|
||||
-#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
|
||||
-
|
||||
#define _raw_spin_relax(lock) cpu_relax()
|
||||
#define _raw_read_relax(lock) cpu_relax()
|
||||
#define _raw_write_relax(lock) cpu_relax()
|
||||
@@ -0,0 +1,49 @@
|
||||
From: Dimitri Sivanich <sivanich@sgi.com>
|
||||
Date: Wed, 15 Apr 2009 15:56:25 +0000 (-0500)
|
||||
Subject: ia64: smp_flush_tlb_mm() should only send IPI's to cpus in cpu_vm_mask
|
||||
Patch-mainline: 2.6.30-rc3
|
||||
Git-commit: edb91dc01a216e84b78721b71a06db1e0db141b7
|
||||
References: bnc#497807
|
||||
|
||||
[IA64] smp_flush_tlb_mm() should only send IPI's to cpus in cpu_vm_mask
|
||||
|
||||
Having flush_tlb_mm->smp_flush_tlb_mm() send an IPI to every cpu
|
||||
on the system is occasionally triggering spin_lock contention in
|
||||
generic_smp_call_function_interrupt().
|
||||
|
||||
Follow x86 arch's lead and only sends IPIs to the cpus in mm->cpu_vm_mask.
|
||||
|
||||
Experiments with this change have shown significant improvement in this
|
||||
contention issue.
|
||||
|
||||
Signed-off-by: Dimitri Sivanich <sivanich@sgi.com>
|
||||
Signed-off-by: Tony Luck <tony.luck@intel.com>
|
||||
Acked-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
|
||||
arch/ia64/kernel/smp.c | 13 +++++--------
|
||||
1 file changed, 5 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/ia64/kernel/smp.c
|
||||
+++ b/arch/ia64/kernel/smp.c
|
||||
@@ -300,15 +300,12 @@ smp_flush_tlb_mm (struct mm_struct *mm)
|
||||
return;
|
||||
}
|
||||
|
||||
+ smp_call_function_mask(mm->cpu_vm_mask,
|
||||
+ (void (*)(void *))local_finish_flush_tlb_mm, mm, 1);
|
||||
+ local_irq_disable();
|
||||
+ local_finish_flush_tlb_mm(mm);
|
||||
+ local_irq_enable();
|
||||
preempt_enable();
|
||||
- /*
|
||||
- * We could optimize this further by using mm->cpu_vm_mask to track which CPUs
|
||||
- * have been running in the address space. It's not clear that this is worth the
|
||||
- * trouble though: to avoid races, we have to raise the IPI on the target CPU
|
||||
- * anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is
|
||||
- * rather trivial.
|
||||
- */
|
||||
- on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1);
|
||||
}
|
||||
|
||||
void arch_send_call_function_single_ipi(int cpu)
|
||||
64
src/patches/suse-2.6.27.25/patches.arch/ia64-sn-BTE_MAX_XFER
Normal file
64
src/patches/suse-2.6.27.25/patches.arch/ia64-sn-BTE_MAX_XFER
Normal file
@@ -0,0 +1,64 @@
|
||||
Date: Wed, 4 Feb 2009 10:47:37 -0600
|
||||
From: Robin Holt <holt@sgi.com>
|
||||
Subject: bte_copy of BTE_MAX_XFER trips BUG_ON -V2
|
||||
References: bnc#472894
|
||||
|
||||
BTE_MAX_XFER is wrong. It is one greater than the number of cache
|
||||
lines the BTE is actually able to transfer. If you request a transfer
|
||||
of exactly BTE_MAX_XFER size, you trip a very cryptic BUG_ON() which
|
||||
should certainly be made more clear.
|
||||
|
||||
This patch fixes that constant and also cleans up the BUG_ON()s in
|
||||
arch/ia64/sn/kernel/bte.c to test one condition per line.
|
||||
|
||||
Signed-off-by: Robin Holt <holt@sgi.com>
|
||||
Acked-by: Raymund Will <rw@suse.de>
|
||||
|
||||
---
|
||||
|
||||
Changes since -V1:
|
||||
Base the BTE_LEN_MASK upon a 1UL instead of 1 for correctness.
|
||||
|
||||
|
||||
arch/ia64/include/asm/sn/bte.h | 4 ++--
|
||||
arch/ia64/sn/kernel/bte.c | 7 ++++---
|
||||
2 files changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
Index: bte_fixup/arch/ia64/include/asm/sn/bte.h
|
||||
===================================================================
|
||||
--- bte_fixup.orig/arch/ia64/include/asm/sn/bte.h 2009-02-04 10:37:29.594750841 -0600
|
||||
+++ bte_fixup/arch/ia64/include/asm/sn/bte.h 2009-02-04 10:40:32.495791608 -0600
|
||||
@@ -38,8 +38,8 @@
|
||||
|
||||
/* BTE status register only supports 16 bits for length field */
|
||||
#define BTE_LEN_BITS (16)
|
||||
-#define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1)
|
||||
-#define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES)
|
||||
+#define BTE_LEN_MASK ((1UL << BTE_LEN_BITS) - 1)
|
||||
+#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT)
|
||||
|
||||
|
||||
/* Define hardware */
|
||||
Index: bte_fixup/arch/ia64/sn/kernel/bte.c
|
||||
===================================================================
|
||||
--- bte_fixup.orig/arch/ia64/sn/kernel/bte.c 2009-02-04 10:37:30.026753839 -0600
|
||||
+++ bte_fixup/arch/ia64/sn/kernel/bte.c 2009-02-04 10:40:11.711701203 -0600
|
||||
@@ -97,9 +97,10 @@ bte_result_t bte_copy(u64 src, u64 dest,
|
||||
return BTE_SUCCESS;
|
||||
}
|
||||
|
||||
- BUG_ON((len & L1_CACHE_MASK) ||
|
||||
- (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
|
||||
- BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
|
||||
+ BUG_ON(len & L1_CACHE_MASK);
|
||||
+ BUG_ON(src & L1_CACHE_MASK);
|
||||
+ BUG_ON(dest & L1_CACHE_MASK);
|
||||
+ BUG_ON(len > BTE_MAX_XFER);
|
||||
|
||||
/*
|
||||
* Start with interface corresponding to cpu number
|
||||
--
|
||||
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
|
||||
the body of a message to majordomo@vger.kernel.org
|
||||
More majordomo info at http://vger.kernel.org/majordomo-info.html
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
From: Jeremy Higdon <jeremy@sgi.com>
|
||||
Subject: ia64: sn: fix pci attribute propagation bug
|
||||
Patch-mainline: 2.6.29
|
||||
References: bnc#480591
|
||||
|
||||
Customer backups were no longer able to complete within 24 hours after
|
||||
upgrading from SLES10 SP1 to SLES10 SP2. Further investigation demonstrated
|
||||
tape streaming bandwidth reduced when the scsi controller is operating at PCI
|
||||
66 mhz. Operating both ports simultaneously caused the reduced bandwidth to
|
||||
reduce in half to each tape drive. If the controller is operating at PCI-X
|
||||
100mhz, there is no reduction in the tape performance.
|
||||
|
||||
Performance degradation is noticeable with a single tape drive writing highly
|
||||
compressible data and the controller operating in PCI-66. This only affects
|
||||
PCI mode, not PCIx.
|
||||
|
||||
kotd SP2 baseline: 4194304000 bytes (4.2 GB) copied, 70.7747 seconds, 59.3 MB/s
|
||||
kotd SP1 baseline: 4194304000 bytes (4.2 GB) copied, 26.7403 seconds, 157 MB/s
|
||||
|
||||
The culprit patch is:
|
||||
patches.fixes/fix-ia64-sn-msi-support
|
||||
|
||||
The patch is a backport of the following upstream patch:
|
||||
|
||||
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=83821d3f558dc651e555d62182ed0c95651f41a6
|
||||
|
||||
The fact that the patch is sn2 specific, and that the problem shows up only in
|
||||
PCI mode, would easily explain how the performance regression managed to go
|
||||
unnoticed for this long.
|
||||
|
||||
The problem is that DMA attributes are not getting set on 64bit DMA addresses
|
||||
on our PIC ASIC based PCI busses (i.e. O350 and O3000 systems). This only
|
||||
affects devices running in PCI mode, not PCIx mode. The result is anything
|
||||
from poor performance to data corruption -- so this is a mustfix type problem.
|
||||
|
||||
This is a _regression_ in SLES10SP2 introduced _accidentally_ by the patch
|
||||
patches.fixes/fix-ia64-sn-msi-support
|
||||
That implemented MSI support on IA64 SN2 systems.
|
||||
|
||||
The broken code is located in the changes to the pcibr_dmatrans_direct64()
|
||||
routine in arch/ia64/sn/pci/pcibr/pcibr_dma.c.
|
||||
|
||||
The bug is also present in upstream code which means that SLES11 too suffers
|
||||
from the same problem: git commit that introduced the bug is
|
||||
83821d3f558dc651e555d62182ed0c95651f41a6
|
||||
|
||||
This patch resolves the problem.
|
||||
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
|
||||
---
|
||||
arch/ia64/sn/pci/pcibr/pcibr_dma.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
|
||||
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
|
||||
@@ -135,11 +135,10 @@ pcibr_dmatrans_direct64(struct pcidev_in
|
||||
if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
|
||||
pci_addr = IS_PIC_SOFT(pcibus_info) ?
|
||||
PHYS_TO_DMA(paddr) :
|
||||
- PHYS_TO_TIODMA(paddr) | dma_attributes;
|
||||
+ PHYS_TO_TIODMA(paddr);
|
||||
else
|
||||
- pci_addr = IS_PIC_SOFT(pcibus_info) ?
|
||||
- paddr :
|
||||
- paddr | dma_attributes;
|
||||
+ pci_addr = paddr;
|
||||
+ pci_addr |= dma_attributes;
|
||||
|
||||
/* Handle Bus mode */
|
||||
if (IS_PCIX(pcibus_info))
|
||||
150
src/patches/suse-2.6.27.25/patches.arch/mm-avoid-bad-page-on-lru
Normal file
150
src/patches/suse-2.6.27.25/patches.arch/mm-avoid-bad-page-on-lru
Normal file
@@ -0,0 +1,150 @@
|
||||
From: Russ Anderson <rja@sgi.com>
|
||||
Subject: mm: Avoid putting a bad page back on the LRU v8
|
||||
References: 415829
|
||||
Acked-by: schwab@suse.de
|
||||
|
||||
Prevent a page with a physical memory error from being placed back
|
||||
on the LRU. A new page flag (PG_memerror) is added if
|
||||
CONFIG_PAGEFLAGS_EXTENDED is defined.
|
||||
|
||||
Version 8 change: Removed hot path check for pages with memory
|
||||
errors on the free list.
|
||||
|
||||
Signed-off-by: Russ Anderson <rja@sgi.com>
|
||||
Reviewed-by: Christoph Lameter <cl@linux-foundation.org>
|
||||
|
||||
---
|
||||
include/linux/page-flags.h | 15 ++++++++++++++-
|
||||
mm/migrate.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 49 insertions(+), 2 deletions(-)
|
||||
|
||||
Index: linux/mm/migrate.c
|
||||
===================================================================
|
||||
--- linux.orig/mm/migrate.c 2008-07-29 13:18:23.000000000 -0500
|
||||
+++ linux/mm/migrate.c 2008-07-29 13:21:03.000000000 -0500
|
||||
@@ -65,6 +65,7 @@ int isolate_lru_page(struct page *page,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(isolate_lru_page);
|
||||
|
||||
/*
|
||||
* migrate_prep() needs to be called before we start compiling a list of pages
|
||||
@@ -82,6 +83,7 @@ int migrate_prep(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
+EXPORT_SYMBOL(migrate_prep);
|
||||
|
||||
static inline void move_to_lru(struct page *page)
|
||||
{
|
||||
@@ -116,6 +118,7 @@ int putback_lru_pages(struct list_head *
|
||||
}
|
||||
return count;
|
||||
}
|
||||
+EXPORT_SYMBOL(putback_lru_pages);
|
||||
|
||||
/*
|
||||
* Restore a potential migration pte to a working pte entry
|
||||
@@ -741,7 +744,26 @@ unlock:
|
||||
* restored.
|
||||
*/
|
||||
list_del(&page->lru);
|
||||
- move_to_lru(page);
|
||||
+ if (PageMemError(page)) {
|
||||
+ if (rc == 0)
|
||||
+ /*
|
||||
+ * A page with a memory error that has
|
||||
+ * been migrated will not be moved to
|
||||
+ * the LRU.
|
||||
+ */
|
||||
+ goto move_newpage;
|
||||
+ else
|
||||
+ /*
|
||||
+ * The page failed to migrate and will not
|
||||
+ * be added to the bad page list. Clearing
|
||||
+ * the error bit will allow another attempt
|
||||
+ * to migrate if it gets another correctable
|
||||
+ * error.
|
||||
+ */
|
||||
+ ClearPageMemError(page);
|
||||
+ }
|
||||
+
|
||||
+ move_to_lru(page);
|
||||
}
|
||||
|
||||
move_newpage:
|
||||
@@ -813,6 +835,17 @@ int migrate_pages(struct list_head *from
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (rc != 0)
|
||||
+ list_for_each_entry_safe(page, page2, from, lru)
|
||||
+ if (PageMemError(page))
|
||||
+ /*
|
||||
+ * The page failed to migrate. Clearing
|
||||
+ * the error bit will allow another attempt
|
||||
+ * to migrate if it gets another correctable
|
||||
+ * error.
|
||||
+ */
|
||||
+ ClearPageMemError(page);
|
||||
rc = 0;
|
||||
out:
|
||||
if (!swapwrite)
|
||||
@@ -825,6 +858,7 @@ out:
|
||||
|
||||
return nr_failed + retry;
|
||||
}
|
||||
+EXPORT_SYMBOL(migrate_pages);
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
/*
|
||||
Index: linux/include/linux/page-flags.h
|
||||
===================================================================
|
||||
--- linux.orig/include/linux/page-flags.h 2008-07-29 13:18:23.000000000 -0500
|
||||
+++ linux/include/linux/page-flags.h 2008-07-29 13:21:03.000000000 -0500
|
||||
@@ -84,6 +84,7 @@ enum pageflags {
|
||||
PG_private, /* If pagecache, has fs-private data */
|
||||
PG_writeback, /* Page is under writeback */
|
||||
#ifdef CONFIG_PAGEFLAGS_EXTENDED
|
||||
+ PG_memerror, /* Page has a physical memory error */
|
||||
PG_head, /* A head page */
|
||||
PG_tail, /* A tail page */
|
||||
#else
|
||||
@@ -147,15 +148,21 @@ static inline int TestSetPage##uname(str
|
||||
static inline int TestClearPage##uname(struct page *page) \
|
||||
{ return test_and_clear_bit(PG_##lname, &page->flags); }
|
||||
|
||||
+#define PAGEFLAGMASK(uname, lname) \
|
||||
+static inline int PAGEMASK_##uname(void) \
|
||||
+ { return (1 << PG_##lname); }
|
||||
|
||||
#define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
|
||||
- SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname)
|
||||
+ SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) \
|
||||
+ PAGEFLAGMASK(uname, lname)
|
||||
|
||||
#define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
|
||||
__SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname)
|
||||
|
||||
#define PAGEFLAG_FALSE(uname) \
|
||||
static inline int Page##uname(struct page *page) \
|
||||
+ { return 0; } \
|
||||
+static inline int PAGEMASK_##uname(void) \
|
||||
{ return 0; }
|
||||
|
||||
#define TESTSCFLAG(uname, lname) \
|
||||
@@ -325,6 +332,12 @@ static inline void __ClearPageTail(struc
|
||||
}
|
||||
|
||||
#endif /* !PAGEFLAGS_EXTENDED */
|
||||
+
|
||||
+#ifdef CONFIG_PAGEFLAGS_EXTENDED
|
||||
+PAGEFLAG(MemError, memerror)
|
||||
+#else
|
||||
+PAGEFLAG_FALSE(MemError)
|
||||
+#endif
|
||||
|
||||
#define PAGE_FLAGS (1 << PG_lru | 1 << PG_private | 1 << PG_locked | \
|
||||
1 << PG_buddy | 1 << PG_writeback | \
|
||||
@@ -0,0 +1,119 @@
|
||||
From 14f966e79445015cd89d0fa0ceb6b33702e951b6 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Jennings <rcj@linux.vnet.ibm.com>
|
||||
Date: Wed, 15 Apr 2009 05:55:32 +0000
|
||||
Subject: powerpc/pseries: CMO unused page hinting
|
||||
Patch-mainline: 2.6.31
|
||||
References: bnc#495091
|
||||
|
||||
From: Robert Jennings <rcj@linux.vnet.ibm.com>
|
||||
|
||||
commit 14f966e79445015cd89d0fa0ceb6b33702e951b6 upstream.
|
||||
|
||||
Adds support for the "unused" page hint which can be used in shared
|
||||
memory partitions to flag pages not in use, which will then be stolen
|
||||
before active pages by the hypervisor when memory needs to be moved to
|
||||
LPARs in need of additional memory. Failure to mark pages as 'unused'
|
||||
makes the LPAR slower to give up unused memory to other partitions.
|
||||
|
||||
This adds the kernel parameter 'cmo_free_hint' to disable this
|
||||
functionality.
|
||||
|
||||
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
|
||||
Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com>
|
||||
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---
|
||||
Documentation/kernel-parameters.txt | 7 ++++
|
||||
arch/powerpc/include/asm/page.h | 5 +++
|
||||
arch/powerpc/platforms/pseries/lpar.c | 52 ++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 64 insertions(+)
|
||||
|
||||
--- a/Documentation/kernel-parameters.txt
|
||||
+++ b/Documentation/kernel-parameters.txt
|
||||
@@ -458,6 +458,13 @@ and is between 256 and 4096 characters.
|
||||
Also note the kernel might malfunction if you disable
|
||||
some critical bits.
|
||||
|
||||
+ cmo_free_hint= [PPC] Format: { yes | no }
|
||||
+ Specify whether pages are marked as being inactive
|
||||
+ when they are freed. This is used in CMO environments
|
||||
+ to determine OS memory pressure for page stealing by
|
||||
+ a hypervisor.
|
||||
+ Default: yes
|
||||
+
|
||||
code_bytes [IA32/X86_64] How many bytes of object code to print
|
||||
in an oops report.
|
||||
Range: 0 - 8192
|
||||
--- a/arch/powerpc/include/asm/page.h
|
||||
+++ b/arch/powerpc/include/asm/page.h
|
||||
@@ -215,6 +215,11 @@ extern void copy_user_page(void *to, voi
|
||||
struct page *p);
|
||||
extern int page_is_ram(unsigned long pfn);
|
||||
|
||||
+#ifdef CONFIG_PPC_SMLPAR
|
||||
+void arch_free_page(struct page *page, int order);
|
||||
+#define HAVE_ARCH_FREE_PAGE
|
||||
+#endif
|
||||
+
|
||||
struct vm_area_struct;
|
||||
|
||||
typedef struct page *pgtable_t;
|
||||
--- a/arch/powerpc/platforms/pseries/lpar.c
|
||||
+++ b/arch/powerpc/platforms/pseries/lpar.c
|
||||
@@ -609,3 +609,55 @@ void __init hpte_init_lpar(void)
|
||||
ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range;
|
||||
ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear;
|
||||
}
|
||||
+
|
||||
+#ifdef CONFIG_PPC_SMLPAR
|
||||
+#define CMO_FREE_HINT_DEFAULT 1
|
||||
+static int cmo_free_hint_flag = CMO_FREE_HINT_DEFAULT;
|
||||
+
|
||||
+static int __init cmo_free_hint(char *str)
|
||||
+{
|
||||
+ char *parm;
|
||||
+ parm = strstrip(str);
|
||||
+
|
||||
+ if (strcasecmp(parm, "no") == 0 || strcasecmp(parm, "off") == 0) {
|
||||
+ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is not active.\n");
|
||||
+ cmo_free_hint_flag = 0;
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ cmo_free_hint_flag = 1;
|
||||
+ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is active.\n");
|
||||
+
|
||||
+ if (strcasecmp(parm, "yes") == 0 || strcasecmp(parm, "on") == 0)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+__setup("cmo_free_hint=", cmo_free_hint);
|
||||
+
|
||||
+static void pSeries_set_page_state(struct page *page, int order,
|
||||
+ unsigned long state)
|
||||
+{
|
||||
+ int i, j;
|
||||
+ unsigned long cmo_page_sz, addr;
|
||||
+
|
||||
+ cmo_page_sz = cmo_get_page_size();
|
||||
+ addr = __pa((unsigned long)page_address(page));
|
||||
+
|
||||
+ for (i = 0; i < (1 << order); i++, addr += PAGE_SIZE) {
|
||||
+ for (j = 0; j < PAGE_SIZE; j += cmo_page_sz)
|
||||
+ plpar_hcall_norets(H_PAGE_INIT, state, addr + j, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void arch_free_page(struct page *page, int order)
|
||||
+{
|
||||
+ if (!cmo_free_hint_flag || !firmware_has_feature(FW_FEATURE_CMO))
|
||||
+ return;
|
||||
+
|
||||
+ pSeries_set_page_state(page, order, H_PAGE_SET_UNUSED);
|
||||
+}
|
||||
+EXPORT_SYMBOL(arch_free_page);
|
||||
+
|
||||
+#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
From: Michael Neuling <mikey@neuling.org>
|
||||
Subject: change giveup_fpu/altivec to disable VSX for current
|
||||
Patch-mainline: 2.6.30
|
||||
References: bnc#492324
|
||||
|
||||
[PATCH] powerpc: change giveup_fpu/altivec to disable VSX for current
|
||||
|
||||
When we call giveup_fpu, we need to need to turn off VSX in current.
|
||||
If we don't, on return to current it may execute a VSX instruction
|
||||
(before the next FP), and not have it's register state refreshed
|
||||
correctly from the thread_struct. Ditto for altivec.
|
||||
|
||||
This caused a bug where an unaligned lfs or stfs (which calls
|
||||
giveup_fpu so it can use the FPRs) to return to userspace with FP off
|
||||
but VSX on. Then if a VSX instruction is executed, before another FP
|
||||
instruction, it will proceed without another exception and hence have
|
||||
the incorrect register state for VSX registers 0-31.
|
||||
|
||||
lfs unaligned <- alignment exception turns FP off but leaves VSX on
|
||||
|
||||
VSX instruction <- no exception since VSX on, hence we get the
|
||||
wrong VSX register values for VSX registers 0-31
|
||||
(overlapping the FPRs)
|
||||
|
||||
Signed-off-by: Michael Neuling <mikey@neuling.org>
|
||||
Acked-by: duwe@suse.de
|
||||
|
||||
---
|
||||
arch/powerpc/kernel/fpu.S | 5 +++++
|
||||
arch/powerpc/kernel/misc_64.S | 8 ++++++++
|
||||
2 files changed, 13 insertions(+)
|
||||
|
||||
Index: clone3/arch/powerpc/kernel/fpu.S
|
||||
===================================================================
|
||||
--- clone3.orig/arch/powerpc/kernel/fpu.S
|
||||
+++ clone3/arch/powerpc/kernel/fpu.S
|
||||
@@ -145,6 +145,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
|
||||
beq 1f
|
||||
PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
|
||||
li r3,MSR_FP|MSR_FE0|MSR_FE1
|
||||
+#ifdef CONFIG_VSX
|
||||
+BEGIN_FTR_SECTION
|
||||
+ oris r3,r3,MSR_VSX@h
|
||||
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
|
||||
+#endif
|
||||
andc r4,r4,r3 /* disable FP for previous task */
|
||||
PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
|
||||
1:
|
||||
Index: clone3/arch/powerpc/kernel/misc_64.S
|
||||
===================================================================
|
||||
--- clone3.orig/arch/powerpc/kernel/misc_64.S
|
||||
+++ clone3/arch/powerpc/kernel/misc_64.S
|
||||
@@ -493,7 +493,15 @@ _GLOBAL(giveup_altivec)
|
||||
stvx vr0,r4,r3
|
||||
beq 1f
|
||||
ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
|
||||
+#ifdef CONFIG_VSX
|
||||
+BEGIN_FTR_SECTION
|
||||
+ lis r3,(MSR_VEC|MSR_VSX)@h
|
||||
+FTR_SECTION_ELSE
|
||||
+ lis r3,MSR_VEC@h
|
||||
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
|
||||
+#else
|
||||
lis r3,MSR_VEC@h
|
||||
+#endif
|
||||
andc r4,r4,r3 /* disable FP for previous task */
|
||||
std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
|
||||
1:
|
||||
@@ -0,0 +1,50 @@
|
||||
Subject: Fix GDB watchpoints on Cell
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
References: 456405 - LTC50396
|
||||
|
||||
An earlier patch from Jens Osterkamp attempted to fix GDB
|
||||
watchpoints by enabling the DABRX register at boot time.
|
||||
Unfortunately, this did not work on SMP setups, where
|
||||
secondary CPUs were still using the power-on DABRX value.
|
||||
|
||||
This introduces the same change for secondary CPUs on cell
|
||||
as well.
|
||||
|
||||
Reported-by: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||
Tested-by: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Paul Mackerras <paulus@samba.org>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/cell/smp.c | 9 +++++++--
|
||||
1 file changed, 7 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/cell/smp.c
|
||||
+++ b/arch/powerpc/platforms/cell/smp.c
|
||||
@@ -129,10 +129,15 @@ static int __init smp_iic_probe(void)
|
||||
return cpus_weight(cpu_possible_map);
|
||||
}
|
||||
|
||||
-static void __devinit smp_iic_setup_cpu(int cpu)
|
||||
+static void __devinit smp_cell_setup_cpu(int cpu)
|
||||
{
|
||||
if (cpu != boot_cpuid)
|
||||
iic_setup_cpu();
|
||||
+
|
||||
+ /*
|
||||
+ * change default DABRX to allow user watchpoints
|
||||
+ */
|
||||
+ mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(timebase_lock);
|
||||
@@ -192,7 +197,7 @@ static struct smp_ops_t bpa_iic_smp_ops
|
||||
.message_pass = smp_iic_message_pass,
|
||||
.probe = smp_iic_probe,
|
||||
.kick_cpu = smp_cell_kick_cpu,
|
||||
- .setup_cpu = smp_iic_setup_cpu,
|
||||
+ .setup_cpu = smp_cell_setup_cpu,
|
||||
.cpu_bootable = smp_cell_cpu_bootable,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,513 @@
|
||||
From: Tony Breeds <tony@bakeyournoodle.com>
|
||||
Subject: [PATCH] powerpc: Improve resolution of VDSO clock_gettime
|
||||
References: 439908 - LTC49499
|
||||
|
||||
Currently the clock_gettime implementation in the VDSO produces a
|
||||
result with microsecond resolution for the cases that are handled
|
||||
without a system call, i.e. CLOCK_REALTIME and CLOCK_MONOTONIC. The
|
||||
nanoseconds field of the result is obtained by computing a
|
||||
microseconds value and multiplying by 1000.
|
||||
|
||||
This changes the code in the VDSO to do the computation for
|
||||
clock_gettime with nanosecond resolution. That means that the
|
||||
resolution of the result will ultimately depend on the timebase
|
||||
frequency.
|
||||
|
||||
Because the timestamp in the VDSO datapage (stamp_xsec, the real time
|
||||
corresponding to the timebase count in tb_orig_stamp) is in units of
|
||||
2^-20 seconds, it doesn't have sufficient resolution for computing a
|
||||
result with nanosecond resolution. Therefore this adds a copy of
|
||||
xtime to the VDSO datapage and updates it in update_gtod() along with
|
||||
the other time-related fields.
|
||||
|
||||
Signed-off-by: Paul Mackerras <paulus@samba.org>
|
||||
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
---
|
||||
arch/powerpc/include/asm/vdso_datapage.h | 3
|
||||
arch/powerpc/kernel/asm-offsets.c | 1
|
||||
arch/powerpc/kernel/time.c | 1
|
||||
arch/powerpc/kernel/vdso32/gettimeofday.S | 196 ++++++++++++++++++------------
|
||||
arch/powerpc/kernel/vdso64/gettimeofday.S | 143 +++++++++++----------
|
||||
5 files changed, 205 insertions(+), 139 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/vdso_datapage.h
|
||||
+++ b/arch/powerpc/include/asm/vdso_datapage.h
|
||||
@@ -39,6 +39,7 @@
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/unistd.h>
|
||||
+#include <linux/time.h>
|
||||
|
||||
#define SYSCALL_MAP_SIZE ((__NR_syscalls + 31) / 32)
|
||||
|
||||
@@ -83,6 +84,7 @@ struct vdso_data {
|
||||
__u32 icache_log_block_size; /* L1 i-cache log block size */
|
||||
__s32 wtom_clock_sec; /* Wall to monotonic clock */
|
||||
__s32 wtom_clock_nsec;
|
||||
+ struct timespec stamp_xtime; /* xtime value for tb_orig_stamp */
|
||||
__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */
|
||||
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
|
||||
};
|
||||
@@ -102,6 +104,7 @@ struct vdso_data {
|
||||
__u32 tz_dsttime; /* Type of dst correction 0x5C */
|
||||
__s32 wtom_clock_sec; /* Wall to monotonic clock */
|
||||
__s32 wtom_clock_nsec;
|
||||
+ struct timespec stamp_xtime; /* xtime value for tb_orig_stamp */
|
||||
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
|
||||
__u32 dcache_block_size; /* L1 d-cache block size */
|
||||
__u32 icache_block_size; /* L1 i-cache block size */
|
||||
--- a/arch/powerpc/kernel/asm-offsets.c
|
||||
+++ b/arch/powerpc/kernel/asm-offsets.c
|
||||
@@ -304,6 +304,7 @@ int main(void)
|
||||
DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32));
|
||||
DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
|
||||
DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
|
||||
+ DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime));
|
||||
DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
|
||||
DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
|
||||
DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
|
||||
--- a/arch/powerpc/kernel/time.c
|
||||
+++ b/arch/powerpc/kernel/time.c
|
||||
@@ -456,6 +456,7 @@ static inline void update_gtod(u64 new_t
|
||||
vdso_data->tb_to_xs = new_tb_to_xs;
|
||||
vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
|
||||
vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
|
||||
+ vdso_data->stamp_xtime = xtime;
|
||||
smp_wmb();
|
||||
++(vdso_data->tb_update_count);
|
||||
}
|
||||
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
|
||||
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
|
||||
@@ -16,6 +16,13 @@
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
+/* Offset for the low 32-bit part of a field of long type */
|
||||
+#ifdef CONFIG_PPC64
|
||||
+#define LOPART 4
|
||||
+#else
|
||||
+#define LOPART 0
|
||||
+#endif
|
||||
+
|
||||
.text
|
||||
/*
|
||||
* Exact prototype of gettimeofday
|
||||
@@ -90,101 +97,53 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
|
||||
|
||||
mflr r12 /* r12 saves lr */
|
||||
.cfi_register lr,r12
|
||||
- mr r10,r3 /* r10 saves id */
|
||||
mr r11,r4 /* r11 saves tp */
|
||||
bl __get_datapage@local /* get data page */
|
||||
mr r9,r3 /* datapage ptr in r9 */
|
||||
- beq cr1,50f /* if monotonic -> jump there */
|
||||
-
|
||||
- /*
|
||||
- * CLOCK_REALTIME
|
||||
- */
|
||||
-
|
||||
- bl __do_get_xsec@local /* get xsec from tb & kernel */
|
||||
- bne- 98f /* out of line -> do syscall */
|
||||
-
|
||||
- /* seconds are xsec >> 20 */
|
||||
- rlwinm r5,r4,12,20,31
|
||||
- rlwimi r5,r3,12,0,19
|
||||
- stw r5,TSPC32_TV_SEC(r11)
|
||||
|
||||
- /* get remaining xsec and convert to nsec. we scale
|
||||
- * up remaining xsec by 12 bits and get the top 32 bits
|
||||
- * of the multiplication, then we multiply by 1000
|
||||
- */
|
||||
- rlwinm r5,r4,12,0,19
|
||||
- lis r6,1000000@h
|
||||
- ori r6,r6,1000000@l
|
||||
- mulhwu r5,r5,r6
|
||||
- mulli r5,r5,1000
|
||||
- stw r5,TSPC32_TV_NSEC(r11)
|
||||
- mtlr r12
|
||||
- crclr cr0*4+so
|
||||
- li r3,0
|
||||
- blr
|
||||
+50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */
|
||||
+ bne cr1,80f /* not monotonic -> all done */
|
||||
|
||||
/*
|
||||
* CLOCK_MONOTONIC
|
||||
*/
|
||||
|
||||
-50: bl __do_get_xsec@local /* get xsec from tb & kernel */
|
||||
- bne- 98f /* out of line -> do syscall */
|
||||
-
|
||||
- /* seconds are xsec >> 20 */
|
||||
- rlwinm r6,r4,12,20,31
|
||||
- rlwimi r6,r3,12,0,19
|
||||
-
|
||||
- /* get remaining xsec and convert to nsec. we scale
|
||||
- * up remaining xsec by 12 bits and get the top 32 bits
|
||||
- * of the multiplication, then we multiply by 1000
|
||||
- */
|
||||
- rlwinm r7,r4,12,0,19
|
||||
- lis r5,1000000@h
|
||||
- ori r5,r5,1000000@l
|
||||
- mulhwu r7,r7,r5
|
||||
- mulli r7,r7,1000
|
||||
-
|
||||
/* now we must fixup using wall to monotonic. We need to snapshot
|
||||
* that value and do the counter trick again. Fortunately, we still
|
||||
* have the counter value in r8 that was returned by __do_get_xsec.
|
||||
- * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
|
||||
- * can be used
|
||||
+ * At this point, r3,r4 contain our sec/nsec values, r5 and r6
|
||||
+ * can be used, r7 contains NSEC_PER_SEC.
|
||||
*/
|
||||
|
||||
- lwz r3,WTOM_CLOCK_SEC(r9)
|
||||
- lwz r4,WTOM_CLOCK_NSEC(r9)
|
||||
+ lwz r5,WTOM_CLOCK_SEC(r9)
|
||||
+ lwz r6,WTOM_CLOCK_NSEC(r9)
|
||||
|
||||
- /* We now have our result in r3,r4. We create a fake dependency
|
||||
- * on that result and re-check the counter
|
||||
+ /* We now have our offset in r5,r6. We create a fake dependency
|
||||
+ * on that value and re-check the counter
|
||||
*/
|
||||
- or r5,r4,r3
|
||||
- xor r0,r5,r5
|
||||
+ or r0,r6,r5
|
||||
+ xor r0,r0,r0
|
||||
add r9,r9,r0
|
||||
-#ifdef CONFIG_PPC64
|
||||
- lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9)
|
||||
-#else
|
||||
- lwz r0,(CFG_TB_UPDATE_COUNT)(r9)
|
||||
-#endif
|
||||
+ lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
|
||||
cmpl cr0,r8,r0 /* check if updated */
|
||||
bne- 50b
|
||||
|
||||
- /* Calculate and store result. Note that this mimmics the C code,
|
||||
+ /* Calculate and store result. Note that this mimics the C code,
|
||||
* which may cause funny results if nsec goes negative... is that
|
||||
* possible at all ?
|
||||
*/
|
||||
- add r3,r3,r6
|
||||
- add r4,r4,r7
|
||||
- lis r5,NSEC_PER_SEC@h
|
||||
- ori r5,r5,NSEC_PER_SEC@l
|
||||
- cmpl cr0,r4,r5
|
||||
- cmpli cr1,r4,0
|
||||
+ add r3,r3,r5
|
||||
+ add r4,r4,r6
|
||||
+ cmpw cr0,r4,r7
|
||||
+ cmpwi cr1,r4,0
|
||||
blt 1f
|
||||
- subf r4,r5,r4
|
||||
+ subf r4,r7,r4
|
||||
addi r3,r3,1
|
||||
-1: bge cr1,1f
|
||||
+1: bge cr1,80f
|
||||
addi r3,r3,-1
|
||||
- add r4,r4,r5
|
||||
-1: stw r3,TSPC32_TV_SEC(r11)
|
||||
+ add r4,r4,r7
|
||||
+
|
||||
+80: stw r3,TSPC32_TV_SEC(r11)
|
||||
stw r4,TSPC32_TV_NSEC(r11)
|
||||
|
||||
mtlr r12
|
||||
@@ -195,10 +154,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
|
||||
/*
|
||||
* syscall fallback
|
||||
*/
|
||||
-98:
|
||||
- mtlr r12
|
||||
- mr r3,r10
|
||||
- mr r4,r11
|
||||
99:
|
||||
li r0,__NR_clock_gettime
|
||||
sc
|
||||
@@ -322,3 +277,98 @@ __do_get_xsec:
|
||||
*/
|
||||
3: blr
|
||||
.cfi_endproc
|
||||
+
|
||||
+/*
|
||||
+ * This is the core of clock_gettime(), it returns the current
|
||||
+ * time in seconds and nanoseconds in r3 and r4.
|
||||
+ * It expects the datapage ptr in r9 and doesn't clobber it.
|
||||
+ * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7.
|
||||
+ * On return, r8 contains the counter value that can be reused.
|
||||
+ * This clobbers cr0 but not any other cr field.
|
||||
+ */
|
||||
+__do_get_tspec:
|
||||
+ .cfi_startproc
|
||||
+ /* Check for update count & load values. We use the low
|
||||
+ * order 32 bits of the update count
|
||||
+ */
|
||||
+1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
|
||||
+ andi. r0,r8,1 /* pending update ? loop */
|
||||
+ bne- 1b
|
||||
+ xor r0,r8,r8 /* create dependency */
|
||||
+ add r9,r9,r0
|
||||
+
|
||||
+ /* Load orig stamp (offset to TB) */
|
||||
+ lwz r5,CFG_TB_ORIG_STAMP(r9)
|
||||
+ lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
|
||||
+
|
||||
+ /* Get a stable TB value */
|
||||
+2: mftbu r3
|
||||
+ mftbl r4
|
||||
+ mftbu r0
|
||||
+ cmpl cr0,r3,r0
|
||||
+ bne- 2b
|
||||
+
|
||||
+ /* Subtract tb orig stamp and shift left 12 bits.
|
||||
+ */
|
||||
+ subfc r7,r6,r4
|
||||
+ subfe r0,r5,r3
|
||||
+ slwi r0,r0,12
|
||||
+ rlwimi. r0,r7,12,20,31
|
||||
+ slwi r7,r7,12
|
||||
+
|
||||
+ /* Load scale factor & do multiplication */
|
||||
+ lwz r5,CFG_TB_TO_XS(r9) /* load values */
|
||||
+ lwz r6,(CFG_TB_TO_XS+4)(r9)
|
||||
+ mulhwu r3,r7,r6
|
||||
+ mullw r10,r7,r5
|
||||
+ mulhwu r4,r7,r5
|
||||
+ addc r10,r3,r10
|
||||
+ li r3,0
|
||||
+
|
||||
+ beq+ 4f /* skip high part computation if 0 */
|
||||
+ mulhwu r3,r0,r5
|
||||
+ mullw r7,r0,r5
|
||||
+ mulhwu r5,r0,r6
|
||||
+ mullw r6,r0,r6
|
||||
+ adde r4,r4,r7
|
||||
+ addze r3,r3
|
||||
+ addc r4,r4,r5
|
||||
+ addze r3,r3
|
||||
+ addc r10,r10,r6
|
||||
+
|
||||
+4: addze r4,r4 /* add in carry */
|
||||
+ lis r7,NSEC_PER_SEC@h
|
||||
+ ori r7,r7,NSEC_PER_SEC@l
|
||||
+ mulhwu r4,r4,r7 /* convert to nanoseconds */
|
||||
+
|
||||
+ /* At this point, we have seconds & nanoseconds since the xtime
|
||||
+ * stamp in r3+CA and r4. Load & add the xtime stamp.
|
||||
+ */
|
||||
+#ifdef CONFIG_PPC64
|
||||
+ lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9)
|
||||
+ lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9)
|
||||
+#else
|
||||
+ lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9)
|
||||
+ lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9)
|
||||
+#endif
|
||||
+ add r4,r4,r6
|
||||
+ adde r3,r3,r5
|
||||
+
|
||||
+ /* We now have our result in r3,r4. We create a fake dependency
|
||||
+ * on that result and re-check the counter
|
||||
+ */
|
||||
+ or r6,r4,r3
|
||||
+ xor r0,r6,r6
|
||||
+ add r9,r9,r0
|
||||
+ lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
|
||||
+ cmpl cr0,r8,r0 /* check if updated */
|
||||
+ bne- 1b
|
||||
+
|
||||
+ /* check for nanosecond overflow and adjust if necessary */
|
||||
+ cmpw r4,r7
|
||||
+ bltlr /* all done if no overflow */
|
||||
+ subf r4,r7,r4 /* adjust if overflow */
|
||||
+ addi r3,r3,1
|
||||
+
|
||||
+ blr
|
||||
+ .cfi_endproc
|
||||
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
|
||||
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
|
||||
@@ -75,90 +75,49 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
|
||||
|
||||
mflr r12 /* r12 saves lr */
|
||||
.cfi_register lr,r12
|
||||
- mr r10,r3 /* r10 saves id */
|
||||
mr r11,r4 /* r11 saves tp */
|
||||
bl V_LOCAL_FUNC(__get_datapage) /* get data page */
|
||||
- beq cr1,50f /* if monotonic -> jump there */
|
||||
-
|
||||
- /*
|
||||
- * CLOCK_REALTIME
|
||||
- */
|
||||
-
|
||||
- bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
|
||||
-
|
||||
- lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
|
||||
- ori r7,r7,16960
|
||||
- rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
|
||||
- rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
|
||||
- std r5,TSPC64_TV_SEC(r11) /* store sec in tv */
|
||||
- subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
|
||||
- mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
|
||||
- * XSEC_PER_SEC
|
||||
- */
|
||||
- rldicl r0,r0,44,20
|
||||
- mulli r0,r0,1000 /* nsec = usec * 1000 */
|
||||
- std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */
|
||||
-
|
||||
- mtlr r12
|
||||
- crclr cr0*4+so
|
||||
- li r3,0
|
||||
- blr
|
||||
+50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */
|
||||
+ bne cr1,80f /* if not monotonic, all done */
|
||||
|
||||
/*
|
||||
* CLOCK_MONOTONIC
|
||||
*/
|
||||
|
||||
-50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
|
||||
-
|
||||
- lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
|
||||
- ori r7,r7,16960
|
||||
- rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
|
||||
- rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
|
||||
- subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
|
||||
- mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
|
||||
- * XSEC_PER_SEC
|
||||
- */
|
||||
- rldicl r6,r0,44,20
|
||||
- mulli r6,r6,1000 /* nsec = usec * 1000 */
|
||||
-
|
||||
/* now we must fixup using wall to monotonic. We need to snapshot
|
||||
* that value and do the counter trick again. Fortunately, we still
|
||||
- * have the counter value in r8 that was returned by __do_get_xsec.
|
||||
- * At this point, r5,r6 contain our sec/nsec values.
|
||||
- * can be used
|
||||
+ * have the counter value in r8 that was returned by __do_get_tspec.
|
||||
+ * At this point, r4,r5 contain our sec/nsec values.
|
||||
*/
|
||||
|
||||
- lwa r4,WTOM_CLOCK_SEC(r3)
|
||||
- lwa r7,WTOM_CLOCK_NSEC(r3)
|
||||
+ lwa r6,WTOM_CLOCK_SEC(r3)
|
||||
+ lwa r9,WTOM_CLOCK_NSEC(r3)
|
||||
|
||||
- /* We now have our result in r4,r7. We create a fake dependency
|
||||
+ /* We now have our result in r6,r9. We create a fake dependency
|
||||
* on that result and re-check the counter
|
||||
*/
|
||||
- or r9,r4,r7
|
||||
- xor r0,r9,r9
|
||||
+ or r0,r6,r9
|
||||
+ xor r0,r0,r0
|
||||
add r3,r3,r0
|
||||
ld r0,CFG_TB_UPDATE_COUNT(r3)
|
||||
cmpld cr0,r0,r8 /* check if updated */
|
||||
bne- 50b
|
||||
|
||||
- /* Calculate and store result. Note that this mimmics the C code,
|
||||
- * which may cause funny results if nsec goes negative... is that
|
||||
- * possible at all ?
|
||||
- */
|
||||
- add r4,r4,r5
|
||||
- add r7,r7,r6
|
||||
- lis r9,NSEC_PER_SEC@h
|
||||
- ori r9,r9,NSEC_PER_SEC@l
|
||||
- cmpl cr0,r7,r9
|
||||
- cmpli cr1,r7,0
|
||||
+ /* Add wall->monotonic offset and check for overflow or underflow.
|
||||
+ */
|
||||
+ add r4,r4,r6
|
||||
+ add r5,r5,r9
|
||||
+ cmpd cr0,r5,r7
|
||||
+ cmpdi cr1,r5,0
|
||||
blt 1f
|
||||
- subf r7,r9,r7
|
||||
+ subf r5,r7,r5
|
||||
addi r4,r4,1
|
||||
-1: bge cr1,1f
|
||||
+1: bge cr1,80f
|
||||
addi r4,r4,-1
|
||||
- add r7,r7,r9
|
||||
-1: std r4,TSPC64_TV_SEC(r11)
|
||||
- std r7,TSPC64_TV_NSEC(r11)
|
||||
+ add r5,r5,r7
|
||||
+
|
||||
+80: std r4,TSPC64_TV_SEC(r11)
|
||||
+ std r5,TSPC64_TV_NSEC(r11)
|
||||
|
||||
mtlr r12
|
||||
crclr cr0*4+so
|
||||
@@ -168,10 +127,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
|
||||
/*
|
||||
* syscall fallback
|
||||
*/
|
||||
-98:
|
||||
- mtlr r12
|
||||
- mr r3,r10
|
||||
- mr r4,r11
|
||||
99:
|
||||
li r0,__NR_clock_gettime
|
||||
sc
|
||||
@@ -253,3 +208,59 @@ V_FUNCTION_BEGIN(__do_get_xsec)
|
||||
blr
|
||||
.cfi_endproc
|
||||
V_FUNCTION_END(__do_get_xsec)
|
||||
+
|
||||
+/*
|
||||
+ * This is the core of clock_gettime(), it returns the current
|
||||
+ * time in seconds and nanoseconds in r4 and r5.
|
||||
+ * It expects the datapage ptr in r3 and doesn't clobber it.
|
||||
+ * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7.
|
||||
+ * On return, r8 contains the counter value that can be reused.
|
||||
+ * This clobbers cr0 but not any other cr field.
|
||||
+ */
|
||||
+V_FUNCTION_BEGIN(__do_get_tspec)
|
||||
+ .cfi_startproc
|
||||
+ /* check for update count & load values */
|
||||
+1: ld r8,CFG_TB_UPDATE_COUNT(r3)
|
||||
+ andi. r0,r8,1 /* pending update ? loop */
|
||||
+ bne- 1b
|
||||
+ xor r0,r8,r8 /* create dependency */
|
||||
+ add r3,r3,r0
|
||||
+
|
||||
+ /* Get TB & offset it. We use the MFTB macro which will generate
|
||||
+ * workaround code for Cell.
|
||||
+ */
|
||||
+ MFTB(r7)
|
||||
+ ld r9,CFG_TB_ORIG_STAMP(r3)
|
||||
+ subf r7,r9,r7
|
||||
+
|
||||
+ /* Scale result */
|
||||
+ ld r5,CFG_TB_TO_XS(r3)
|
||||
+ sldi r7,r7,12 /* compute time since stamp_xtime */
|
||||
+ mulhdu r6,r7,r5 /* in units of 2^-32 seconds */
|
||||
+
|
||||
+ /* Add stamp since epoch */
|
||||
+ ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
|
||||
+ ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3)
|
||||
+ or r0,r4,r5
|
||||
+ or r0,r0,r6
|
||||
+ xor r0,r0,r0
|
||||
+ add r3,r3,r0
|
||||
+ ld r0,CFG_TB_UPDATE_COUNT(r3)
|
||||
+ cmpld r0,r8 /* check if updated */
|
||||
+ bne- 1b /* reload if so */
|
||||
+
|
||||
+ /* convert to seconds & nanoseconds and add to stamp */
|
||||
+ lis r7,NSEC_PER_SEC@h
|
||||
+ ori r7,r7,NSEC_PER_SEC@l
|
||||
+ mulhwu r0,r6,r7 /* compute nanoseconds and */
|
||||
+ srdi r6,r6,32 /* seconds since stamp_xtime */
|
||||
+ clrldi r0,r0,32
|
||||
+ add r5,r5,r0 /* add nanoseconds together */
|
||||
+ cmpd r5,r7 /* overflow? */
|
||||
+ add r4,r4,r6
|
||||
+ bltlr /* all done if no overflow */
|
||||
+ subf r5,r7,r5 /* if overflow, adjust */
|
||||
+ addi r4,r4,1
|
||||
+ blr
|
||||
+ .cfi_endproc
|
||||
+V_FUNCTION_END(__do_get_tspec)
|
||||
@@ -0,0 +1,755 @@
|
||||
Subject: Efika ATA DMA
|
||||
From: Matt Sealey <matt@genesi-usa.com>
|
||||
References: 445856
|
||||
|
||||
Enables UDMA operation for ATA disks on Efika, meaning faster (up to
|
||||
~33MB/s, from ~1.2MB/s) access and lower (5-10% from 40-80%) CPU usage.
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/sysdev/bestcomm/ata.c | 3
|
||||
arch/powerpc/sysdev/bestcomm/ata.h | 2
|
||||
arch/powerpc/sysdev/bestcomm/bestcomm.c | 7
|
||||
arch/powerpc/sysdev/bestcomm/bestcomm.h | 33 +-
|
||||
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 20 +
|
||||
drivers/ata/pata_mpc52xx.c | 440 +++++++++++++++++++++++++--
|
||||
6 files changed, 473 insertions(+), 32 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/sysdev/bestcomm/ata.c
|
||||
+++ b/arch/powerpc/sysdev/bestcomm/ata.c
|
||||
@@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufs
|
||||
struct bcom_ata_var *var;
|
||||
struct bcom_ata_inc *inc;
|
||||
|
||||
+ /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */
|
||||
+ bcom_disable_prefetch();
|
||||
+
|
||||
tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0);
|
||||
if (!tsk)
|
||||
return NULL;
|
||||
--- a/arch/powerpc/sysdev/bestcomm/ata.h
|
||||
+++ b/arch/powerpc/sysdev/bestcomm/ata.h
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
struct bcom_ata_bd {
|
||||
u32 status;
|
||||
- u32 dst_pa;
|
||||
u32 src_pa;
|
||||
+ u32 dst_pa;
|
||||
};
|
||||
|
||||
extern struct bcom_task *
|
||||
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
|
||||
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
|
||||
@@ -279,7 +279,6 @@ bcom_engine_init(void)
|
||||
int task;
|
||||
phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
|
||||
unsigned int tdt_size, ctx_size, var_size, fdt_size;
|
||||
- u16 regval;
|
||||
|
||||
/* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
|
||||
tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
|
||||
@@ -331,10 +330,8 @@ bcom_engine_init(void)
|
||||
out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
|
||||
|
||||
/* Disable COMM Bus Prefetch on the original 5200; it's broken */
|
||||
- if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) {
|
||||
- regval = in_be16(&bcom_eng->regs->PtdCntrl);
|
||||
- out_be16(&bcom_eng->regs->PtdCntrl, regval | 1);
|
||||
- }
|
||||
+ if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
|
||||
+ bcom_disable_prefetch();
|
||||
|
||||
/* Init lock */
|
||||
spin_lock_init(&bcom_eng->lock);
|
||||
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.h
|
||||
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
|
||||
@@ -140,15 +140,29 @@ bcom_queue_full(struct bcom_task *tsk)
|
||||
}
|
||||
|
||||
/**
|
||||
+ * bcom_get_bd - Get a BD from the queue
|
||||
+ * @tsk: The BestComm task structure
|
||||
+ * index: Index of the BD to fetch
|
||||
+ */
|
||||
+static inline struct bcom_bd
|
||||
+*bcom_get_bd(struct bcom_task *tsk, unsigned int index)
|
||||
+{
|
||||
+ return tsk->bd + index * tsk->bd_size;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* bcom_buffer_done - Checks if a BestComm
|
||||
* @tsk: The BestComm task structure
|
||||
*/
|
||||
static inline int
|
||||
bcom_buffer_done(struct bcom_task *tsk)
|
||||
{
|
||||
+ struct bcom_bd *bd;
|
||||
if (bcom_queue_empty(tsk))
|
||||
return 0;
|
||||
- return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
|
||||
+
|
||||
+ bd = bcom_get_bd(tsk, tsk->outdex);
|
||||
+ return !(bd->status & BCOM_BD_READY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,16 +174,21 @@ bcom_buffer_done(struct bcom_task *tsk)
|
||||
static inline struct bcom_bd *
|
||||
bcom_prepare_next_buffer(struct bcom_task *tsk)
|
||||
{
|
||||
- tsk->bd[tsk->index].status = 0; /* cleanup last status */
|
||||
- return &tsk->bd[tsk->index];
|
||||
+ struct bcom_bd *bd;
|
||||
+
|
||||
+ bd = bcom_get_bd(tsk, tsk->index);
|
||||
+ bd->status = 0; /* cleanup last status */
|
||||
+ return bd;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
|
||||
{
|
||||
+ struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
|
||||
+
|
||||
tsk->cookie[tsk->index] = cookie;
|
||||
mb(); /* ensure the bd is really up-to-date */
|
||||
- tsk->bd[tsk->index].status |= BCOM_BD_READY;
|
||||
+ bd->status |= BCOM_BD_READY;
|
||||
tsk->index = _bcom_next_index(tsk);
|
||||
if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
|
||||
bcom_enable(tsk);
|
||||
@@ -179,10 +198,12 @@ static inline void *
|
||||
bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
|
||||
{
|
||||
void *cookie = tsk->cookie[tsk->outdex];
|
||||
+ struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
|
||||
+
|
||||
if (p_status)
|
||||
- *p_status = tsk->bd[tsk->outdex].status;
|
||||
+ *p_status = bd->status;
|
||||
if (p_bd)
|
||||
- *p_bd = &tsk->bd[tsk->outdex];
|
||||
+ *p_bd = bd;
|
||||
tsk->outdex = _bcom_next_outdex(tsk);
|
||||
return cookie;
|
||||
}
|
||||
--- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
|
||||
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
|
||||
@@ -198,8 +198,8 @@ struct bcom_task_header {
|
||||
#define BCOM_IPR_SCTMR_1 2
|
||||
#define BCOM_IPR_FEC_RX 6
|
||||
#define BCOM_IPR_FEC_TX 5
|
||||
-#define BCOM_IPR_ATA_RX 4
|
||||
-#define BCOM_IPR_ATA_TX 3
|
||||
+#define BCOM_IPR_ATA_RX 7
|
||||
+#define BCOM_IPR_ATA_TX 7
|
||||
#define BCOM_IPR_SCPCI_RX 2
|
||||
#define BCOM_IPR_SCPCI_TX 2
|
||||
#define BCOM_IPR_PSC3_RX 2
|
||||
@@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task,
|
||||
|
||||
#define TASK_ENABLE 0x8000
|
||||
|
||||
+/**
|
||||
+ * bcom_disable_prefetch - Hook to disable bus prefetching
|
||||
+ *
|
||||
+ * ATA DMA and the original MPC5200 need this due to silicon bugs. At the
|
||||
+ * moment disabling prefetch is a one-way street. There is no mechanism
|
||||
+ * in place to turn prefetch back on after it has been disabled. There is
|
||||
+ * no reason it couldn't be done, it would just be more complex to implement.
|
||||
+ */
|
||||
+static inline void bcom_disable_prefetch(void)
|
||||
+{
|
||||
+ u16 regval;
|
||||
+
|
||||
+ regval = in_be16(&bcom_eng->regs->PtdCntrl);
|
||||
+ out_be16(&bcom_eng->regs->PtdCntrl, regval | 1);
|
||||
+};
|
||||
+
|
||||
static inline void
|
||||
bcom_enable_task(int task)
|
||||
{
|
||||
--- a/drivers/ata/pata_mpc52xx.c
|
||||
+++ b/drivers/ata/pata_mpc52xx.c
|
||||
@@ -6,6 +6,9 @@
|
||||
* Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
|
||||
* Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
|
||||
*
|
||||
+ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
|
||||
+ * Domen Puncer and Tim Yamin.
|
||||
+ *
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
@@ -18,27 +21,46 @@
|
||||
#include <linux/libata.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
+#include <asm/cacheflush.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/mpc52xx.h>
|
||||
|
||||
+#include <sysdev/bestcomm/bestcomm.h>
|
||||
+#include <sysdev/bestcomm/bestcomm_priv.h>
|
||||
+#include <sysdev/bestcomm/ata.h>
|
||||
|
||||
#define DRV_NAME "mpc52xx_ata"
|
||||
#define DRV_VERSION "0.1.2"
|
||||
|
||||
-
|
||||
/* Private structures used by the driver */
|
||||
struct mpc52xx_ata_timings {
|
||||
u32 pio1;
|
||||
u32 pio2;
|
||||
+ u32 mdma1;
|
||||
+ u32 mdma2;
|
||||
+ u32 udma1;
|
||||
+ u32 udma2;
|
||||
+ u32 udma3;
|
||||
+ u32 udma4;
|
||||
+ u32 udma5;
|
||||
+ int using_udma;
|
||||
};
|
||||
|
||||
struct mpc52xx_ata_priv {
|
||||
unsigned int ipb_period;
|
||||
struct mpc52xx_ata __iomem * ata_regs;
|
||||
+ phys_addr_t ata_regs_pa;
|
||||
int ata_irq;
|
||||
struct mpc52xx_ata_timings timings[2];
|
||||
int csel;
|
||||
+
|
||||
+ /* DMA */
|
||||
+ struct bcom_task *dmatsk;
|
||||
+ const struct udmaspec *udmaspec;
|
||||
+ const struct mdmaspec *mdmaspec;
|
||||
+ int mpc52xx_ata_dma_last_write;
|
||||
+ int waiting_for_dma;
|
||||
};
|
||||
|
||||
|
||||
@@ -53,6 +75,107 @@ static const int ataspec_ta[5] = { 35
|
||||
|
||||
#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
|
||||
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+/* ATAPI-4 MDMA specs (in clocks) */
|
||||
+struct mdmaspec {
|
||||
+ u32 t0M;
|
||||
+ u32 td;
|
||||
+ u32 th;
|
||||
+ u32 tj;
|
||||
+ u32 tkw;
|
||||
+ u32 tm;
|
||||
+ u32 tn;
|
||||
+};
|
||||
+
|
||||
+static const struct mdmaspec mdmaspec66[3] = {
|
||||
+ { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 },
|
||||
+ { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 },
|
||||
+ { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 },
|
||||
+};
|
||||
+
|
||||
+static const struct mdmaspec mdmaspec132[3] = {
|
||||
+ { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 },
|
||||
+ { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 },
|
||||
+ { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 },
|
||||
+};
|
||||
+
|
||||
+/* ATAPI-4 UDMA specs (in clocks) */
|
||||
+struct udmaspec {
|
||||
+ u32 tcyc;
|
||||
+ u32 t2cyc;
|
||||
+ u32 tds;
|
||||
+ u32 tdh;
|
||||
+ u32 tdvs;
|
||||
+ u32 tdvh;
|
||||
+ u32 tfs;
|
||||
+ u32 tli;
|
||||
+ u32 tmli;
|
||||
+ u32 taz;
|
||||
+ u32 tzah;
|
||||
+ u32 tenv;
|
||||
+ u32 tsr;
|
||||
+ u32 trfs;
|
||||
+ u32 trp;
|
||||
+ u32 tack;
|
||||
+ u32 tss;
|
||||
+};
|
||||
+
|
||||
+static const struct udmaspec udmaspec66[6] = {
|
||||
+ { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
|
||||
+ .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+ { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1,
|
||||
+ .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+ { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
|
||||
+ .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1,
|
||||
+ .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+ { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
|
||||
+ .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+ { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
|
||||
+ .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct udmaspec udmaspec132[6] = {
|
||||
+ { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1,
|
||||
+ .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
|
||||
+ .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7,
|
||||
+ },
|
||||
+ { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1,
|
||||
+ .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
|
||||
+ .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7,
|
||||
+ },
|
||||
+ { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
|
||||
+ .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
|
||||
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
|
||||
+ },
|
||||
+ { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
|
||||
+ .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
|
||||
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
|
||||
+ },
|
||||
+ { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1,
|
||||
+ .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
|
||||
+ .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6,
|
||||
+ },
|
||||
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
|
||||
+ .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
|
||||
+ .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
|
||||
/* Bit definitions inside the registers */
|
||||
#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
|
||||
@@ -66,6 +189,7 @@ static const int ataspec_ta[5] = { 35
|
||||
#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
|
||||
|
||||
#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
|
||||
+#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */
|
||||
|
||||
#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
|
||||
#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
|
||||
@@ -75,6 +199,8 @@ static const int ataspec_ta[5] = { 35
|
||||
#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
|
||||
#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
|
||||
|
||||
+#define MAX_DMA_BUFFERS 128
|
||||
+#define MAX_DMA_BUFFER_SIZE 0x20000u
|
||||
|
||||
/* Structure of the hardware registers */
|
||||
struct mpc52xx_ata {
|
||||
@@ -140,7 +266,6 @@ struct mpc52xx_ata {
|
||||
|
||||
|
||||
/* MPC52xx low level hw control */
|
||||
-
|
||||
static int
|
||||
mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
|
||||
{
|
||||
@@ -165,6 +290,42 @@ mpc52xx_ata_compute_pio_timings(struct m
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev,
|
||||
+ int speed)
|
||||
+{
|
||||
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
|
||||
+ const struct mdmaspec *s = &priv->mdmaspec[speed];
|
||||
+
|
||||
+ if (speed < 0 || speed > 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm);
|
||||
+ t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8);
|
||||
+ t->using_udma = 0;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed)
|
||||
+{
|
||||
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
|
||||
+ const struct udmaspec *s = &priv->udmaspec[speed];
|
||||
+
|
||||
+ if (speed < 0 || speed > 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh;
|
||||
+ t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli;
|
||||
+ t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr;
|
||||
+ t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack;
|
||||
+ t->udma5 = (s->tzah << 24);
|
||||
+ t->using_udma = 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
|
||||
{
|
||||
@@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx
|
||||
|
||||
out_be32(®s->pio1, timing->pio1);
|
||||
out_be32(®s->pio2, timing->pio2);
|
||||
- out_be32(®s->mdma1, 0);
|
||||
- out_be32(®s->mdma2, 0);
|
||||
- out_be32(®s->udma1, 0);
|
||||
- out_be32(®s->udma2, 0);
|
||||
- out_be32(®s->udma3, 0);
|
||||
- out_be32(®s->udma4, 0);
|
||||
- out_be32(®s->udma5, 0);
|
||||
-
|
||||
+ out_be32(®s->mdma1, timing->mdma1);
|
||||
+ out_be32(®s->mdma2, timing->mdma2);
|
||||
+ out_be32(®s->udma1, timing->udma1);
|
||||
+ out_be32(®s->udma2, timing->udma2);
|
||||
+ out_be32(®s->udma3, timing->udma3);
|
||||
+ out_be32(®s->udma4, timing->udma4);
|
||||
+ out_be32(®s->udma5, timing->udma5);
|
||||
priv->csel = device;
|
||||
}
|
||||
|
||||
@@ -244,6 +404,31 @@ mpc52xx_ata_set_piomode(struct ata_port
|
||||
|
||||
mpc52xx_ata_apply_timings(priv, adev->devno);
|
||||
}
|
||||
+
|
||||
+static void
|
||||
+mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
||||
+{
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+ int rv;
|
||||
+
|
||||
+ if (adev->dma_mode >= XFER_UDMA_0) {
|
||||
+ int dma = adev->dma_mode - XFER_UDMA_0;
|
||||
+ rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma);
|
||||
+ } else {
|
||||
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
|
||||
+ rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma);
|
||||
+ }
|
||||
+
|
||||
+ if (rv) {
|
||||
+ dev_alert(ap->dev,
|
||||
+ "Trying to select invalid DMA mode %d\n",
|
||||
+ adev->dma_mode);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ mpc52xx_ata_apply_timings(priv, adev->devno);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
|
||||
{
|
||||
@@ -255,6 +440,172 @@ mpc52xx_ata_dev_select(struct ata_port *
|
||||
ata_sff_dev_select(ap,device);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc)
|
||||
+{
|
||||
+ struct ata_port *ap = qc->ap;
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+ struct bcom_ata_bd *bd;
|
||||
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si;
|
||||
+ struct scatterlist *sg;
|
||||
+ int count = 0;
|
||||
+
|
||||
+ if (read)
|
||||
+ bcom_ata_rx_prepare(priv->dmatsk);
|
||||
+ else
|
||||
+ bcom_ata_tx_prepare(priv->dmatsk);
|
||||
+
|
||||
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
|
||||
+ dma_addr_t cur_addr = sg_dma_address(sg);
|
||||
+ u32 cur_len = sg_dma_len(sg);
|
||||
+
|
||||
+ while (cur_len) {
|
||||
+ unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE);
|
||||
+ bd = (struct bcom_ata_bd *)
|
||||
+ bcom_prepare_next_buffer(priv->dmatsk);
|
||||
+
|
||||
+ if (read) {
|
||||
+ bd->status = tc;
|
||||
+ bd->src_pa = (__force u32) priv->ata_regs_pa +
|
||||
+ offsetof(struct mpc52xx_ata, fifo_data);
|
||||
+ bd->dst_pa = (__force u32) cur_addr;
|
||||
+ } else {
|
||||
+ bd->status = tc;
|
||||
+ bd->src_pa = (__force u32) cur_addr;
|
||||
+ bd->dst_pa = (__force u32) priv->ata_regs_pa +
|
||||
+ offsetof(struct mpc52xx_ata, fifo_data);
|
||||
+ }
|
||||
+
|
||||
+ bcom_submit_next_buffer(priv->dmatsk, NULL);
|
||||
+
|
||||
+ cur_addr += tc;
|
||||
+ cur_len -= tc;
|
||||
+ count++;
|
||||
+
|
||||
+ if (count > MAX_DMA_BUFFERS) {
|
||||
+ dev_alert(ap->dev, "dma table"
|
||||
+ "too small\n");
|
||||
+ goto use_pio_instead;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+
|
||||
+ use_pio_instead:
|
||||
+ bcom_ata_reset_bd(priv->dmatsk);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mpc52xx_bmdma_setup(struct ata_queued_cmd *qc)
|
||||
+{
|
||||
+ struct ata_port *ap = qc->ap;
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
|
||||
+
|
||||
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE);
|
||||
+ u8 dma_mode;
|
||||
+
|
||||
+ if (!mpc52xx_ata_build_dmatable(qc))
|
||||
+ dev_alert(ap->dev, "%s: %i, return 1?\n",
|
||||
+ __func__, __LINE__);
|
||||
+
|
||||
+ /* Check FIFO is OK... */
|
||||
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
|
||||
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
|
||||
+ __func__, in_8(&priv->ata_regs->fifo_status));
|
||||
+
|
||||
+ if (read) {
|
||||
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
|
||||
+ MPC52xx_ATA_DMAMODE_FE;
|
||||
+
|
||||
+ /* Setup FIFO if direction changed */
|
||||
+ if (priv->mpc52xx_ata_dma_last_write != 0) {
|
||||
+ priv->mpc52xx_ata_dma_last_write = 0;
|
||||
+
|
||||
+ /* Configure FIFO with granularity to 7 */
|
||||
+ out_8(®s->fifo_control, 7);
|
||||
+ out_be16(®s->fifo_alarm, 128);
|
||||
+
|
||||
+ /* Set FIFO Reset bit (FR) */
|
||||
+ out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR);
|
||||
+ }
|
||||
+ } else {
|
||||
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
|
||||
+
|
||||
+ /* Setup FIFO if direction changed */
|
||||
+ if (priv->mpc52xx_ata_dma_last_write != 1) {
|
||||
+ priv->mpc52xx_ata_dma_last_write = 1;
|
||||
+
|
||||
+ /* Configure FIFO with granularity to 4 */
|
||||
+ out_8(®s->fifo_control, 4);
|
||||
+ out_be16(®s->fifo_alarm, 128);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (priv->timings[qc->dev->devno].using_udma)
|
||||
+ dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
|
||||
+
|
||||
+ out_8(®s->dma_mode, dma_mode);
|
||||
+ priv->waiting_for_dma = ATA_DMA_ACTIVE;
|
||||
+
|
||||
+ ata_wait_idle(ap);
|
||||
+ ap->ops->sff_exec_command(ap, &qc->tf);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
|
||||
+{
|
||||
+ struct ata_port *ap = qc->ap;
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+
|
||||
+ bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum);
|
||||
+ bcom_enable(priv->dmatsk);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mpc52xx_bmdma_stop(struct ata_queued_cmd *qc)
|
||||
+{
|
||||
+ struct ata_port *ap = qc->ap;
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+
|
||||
+ bcom_disable(priv->dmatsk);
|
||||
+ bcom_ata_reset_bd(priv->dmatsk);
|
||||
+ priv->waiting_for_dma = 0;
|
||||
+
|
||||
+ /* Check FIFO is OK... */
|
||||
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
|
||||
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
|
||||
+ __func__, in_8(&priv->ata_regs->fifo_status));
|
||||
+}
|
||||
+
|
||||
+static u8
|
||||
+mpc52xx_bmdma_status(struct ata_port *ap)
|
||||
+{
|
||||
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
+
|
||||
+ /* Check FIFO is OK... */
|
||||
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) {
|
||||
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
|
||||
+ __func__, in_8(&priv->ata_regs->fifo_status));
|
||||
+ return priv->waiting_for_dma | ATA_DMA_ERR;
|
||||
+ }
|
||||
+
|
||||
+ return priv->waiting_for_dma;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t
|
||||
+mpc52xx_ata_task_irq(int irq, void *vpriv)
|
||||
+{
|
||||
+ struct mpc52xx_ata_priv *priv = vpriv;
|
||||
+ while (bcom_buffer_done(priv->dmatsk))
|
||||
+ bcom_retrieve_buffer(priv->dmatsk, NULL, NULL);
|
||||
+
|
||||
+ priv->waiting_for_dma |= ATA_DMA_INTR;
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
static struct scsi_host_template mpc52xx_ata_sht = {
|
||||
ATA_PIO_SHT(DRV_NAME),
|
||||
};
|
||||
@@ -262,14 +613,18 @@ static struct scsi_host_template mpc52xx
|
||||
static struct ata_port_operations mpc52xx_ata_port_ops = {
|
||||
.inherits = &ata_sff_port_ops,
|
||||
.sff_dev_select = mpc52xx_ata_dev_select,
|
||||
- .cable_detect = ata_cable_40wire,
|
||||
.set_piomode = mpc52xx_ata_set_piomode,
|
||||
- .post_internal_cmd = ATA_OP_NULL,
|
||||
+ .set_dmamode = mpc52xx_ata_set_dmamode,
|
||||
+ .bmdma_setup = mpc52xx_bmdma_setup,
|
||||
+ .bmdma_start = mpc52xx_bmdma_start,
|
||||
+ .bmdma_stop = mpc52xx_bmdma_stop,
|
||||
+ .bmdma_status = mpc52xx_bmdma_status,
|
||||
+ .qc_prep = ata_noop_qc_prep,
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
|
||||
- unsigned long raw_ata_regs)
|
||||
+ unsigned long raw_ata_regs, int mwdma_mask, int udma_mask)
|
||||
{
|
||||
struct ata_host *host;
|
||||
struct ata_port *ap;
|
||||
@@ -281,9 +636,9 @@ mpc52xx_ata_init_one(struct device *dev,
|
||||
|
||||
ap = host->ports[0];
|
||||
ap->flags |= ATA_FLAG_SLAVE_POSS;
|
||||
- ap->pio_mask = 0x1f; /* Up to PIO4 */
|
||||
- ap->mwdma_mask = 0x00; /* No MWDMA */
|
||||
- ap->udma_mask = 0x00; /* No UDMA */
|
||||
+ ap->pio_mask = ATA_PIO4;
|
||||
+ ap->mwdma_mask = mwdma_mask;
|
||||
+ ap->udma_mask = udma_mask;
|
||||
ap->ops = &mpc52xx_ata_port_ops;
|
||||
host->private_data = priv;
|
||||
|
||||
@@ -333,7 +688,10 @@ mpc52xx_ata_probe(struct of_device *op,
|
||||
int ata_irq;
|
||||
struct mpc52xx_ata __iomem *ata_regs;
|
||||
struct mpc52xx_ata_priv *priv;
|
||||
- int rv;
|
||||
+ int rv, ret, task_irq;
|
||||
+ int mwdma_mask = 0, udma_mask = 0;
|
||||
+ const __be32 *prop;
|
||||
+ int proplen;
|
||||
|
||||
/* Get ipb frequency */
|
||||
ipb_freq = mpc52xx_find_ipb_freq(op->node);
|
||||
@@ -351,6 +709,27 @@ mpc52xx_ata_probe(struct of_device *op,
|
||||
return rv;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * By default, all DMA modes are disabled for the MPC5200. Some
|
||||
+ * boards don't have the required signals routed to make DMA work.
|
||||
+ * Also, the MPC5200B has a silicon bug that causes data corruption
|
||||
+ * with UDMA if it is used at the same time as the LocalPlus bus.
|
||||
+ *
|
||||
+ * Instead of trying to guess what modes are usable, check the
|
||||
+ * ATA device tree node to find out what DMA modes work on the board.
|
||||
+ * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>"
|
||||
+ * to the kernel boot parameters.
|
||||
+ *
|
||||
+ * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and
|
||||
+ * UDMA modes 0, 1 and 2.
|
||||
+ */
|
||||
+ prop = of_get_property(op->node, "mwdma-mode", &proplen);
|
||||
+ if ((prop) && (proplen >= 4))
|
||||
+ mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
|
||||
+ prop = of_get_property(op->node, "udma-mode", &proplen);
|
||||
+ if ((prop) && (proplen >= 4))
|
||||
+ udma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
|
||||
+
|
||||
ata_irq = irq_of_parse_and_map(op->node, 0);
|
||||
if (ata_irq == NO_IRQ) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
@@ -389,8 +768,32 @@ mpc52xx_ata_probe(struct of_device *op,
|
||||
|
||||
priv->ipb_period = 1000000000 / (ipb_freq / 1000);
|
||||
priv->ata_regs = ata_regs;
|
||||
+ priv->ata_regs_pa = res_mem.start;
|
||||
priv->ata_irq = ata_irq;
|
||||
priv->csel = -1;
|
||||
+ priv->mpc52xx_ata_dma_last_write = -1;
|
||||
+
|
||||
+ if (ipb_freq/1000000 == 66) {
|
||||
+ priv->mdmaspec = mdmaspec66;
|
||||
+ priv->udmaspec = udmaspec66;
|
||||
+ } else {
|
||||
+ priv->mdmaspec = mdmaspec132;
|
||||
+ priv->udmaspec = udmaspec132;
|
||||
+ }
|
||||
+
|
||||
+ priv->dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE);
|
||||
+ if (!priv->dmatsk) {
|
||||
+ dev_err(&op->dev, "bestcomm initialization failed\n");
|
||||
+ rv = -ENOMEM;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ task_irq = bcom_get_task_irq(priv->dmatsk);
|
||||
+ ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED,
|
||||
+ "ATA task", priv);
|
||||
+ if (ret)
|
||||
+ dev_alert(&op->dev, "request_irq failed with: "
|
||||
+ "%i\n", ret);
|
||||
|
||||
/* Init the hw */
|
||||
rv = mpc52xx_ata_hw_init(priv);
|
||||
@@ -400,7 +803,8 @@ mpc52xx_ata_probe(struct of_device *op,
|
||||
}
|
||||
|
||||
/* Register ourselves to libata */
|
||||
- rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
|
||||
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start,
|
||||
+ mwdma_mask, udma_mask);
|
||||
if (rv) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while registering to ATA layer\n");
|
||||
@@ -0,0 +1,892 @@
|
||||
From: Juergen Beisert <jbe@pengutronix.de>
|
||||
Subject: RFC: MPC5200 PSC AC97 driver
|
||||
|
||||
if someone is interested: Here the full patch to get sound support for
|
||||
MPC5200b and a current 2.6.25 kernel.
|
||||
|
||||
Acked-by: Olaf Hering <olh@novell.com>
|
||||
|
||||
---
|
||||
arch/powerpc/include/asm/mpc52xx_psc.h | 4
|
||||
arch/powerpc/kernel/prom_init.c | 3
|
||||
sound/ppc/Kconfig | 15
|
||||
sound/ppc/Makefile | 2
|
||||
sound/ppc/mpc52xx_ac97.c | 807 +++++++++++++++++++++++++++++++++
|
||||
5 files changed, 831 insertions(+)
|
||||
|
||||
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
|
||||
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
|
||||
@@ -28,6 +28,10 @@
|
||||
#define MPC52xx_PSC_MAXNUM 6
|
||||
|
||||
/* Programmable Serial Controller (PSC) status register bits */
|
||||
+#define MPC52xx_PSC_SR_UNEX_RX 0x0001
|
||||
+#define MPC52xx_PSC_SR_DATA_VAL 0x0002
|
||||
+#define MPC52xx_PSC_SR_DATA_OVR 0x0004
|
||||
+#define MPC52xx_PSC_SR_CMDSEND 0x0008
|
||||
#define MPC52xx_PSC_SR_CDE 0x0080
|
||||
#define MPC52xx_PSC_SR_RXRDY 0x0100
|
||||
#define MPC52xx_PSC_SR_RXFULL 0x0200
|
||||
--- a/arch/powerpc/kernel/prom_init.c
|
||||
+++ b/arch/powerpc/kernel/prom_init.c
|
||||
@@ -2189,6 +2189,7 @@ static void __init fixup_device_tree_efi
|
||||
|
||||
static void __init fixup_device_tree_efika(void)
|
||||
{
|
||||
+ int sound_cell[1] = { 1 };
|
||||
int sound_irq[3] = { 2, 2, 0 };
|
||||
int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
|
||||
3,4,0, 3,5,0, 3,6,0, 3,7,0,
|
||||
@@ -2244,6 +2245,8 @@ static void __init fixup_device_tree_efi
|
||||
prom_printf("Adding sound interrupts property\n");
|
||||
prom_setprop(node, "/builtin/sound", "interrupts",
|
||||
sound_irq, sizeof(sound_irq));
|
||||
+ prom_setprop(node, "/builtin/sound", "cell-index",
|
||||
+ sound_cell, sizeof(sound_cell));
|
||||
}
|
||||
}
|
||||
|
||||
--- a/sound/ppc/Kconfig
|
||||
+++ b/sound/ppc/Kconfig
|
||||
@@ -48,4 +48,19 @@ config SND_PS3_DEFAULT_START_DELAY
|
||||
depends on SND_PS3
|
||||
default "2000"
|
||||
|
||||
+
|
||||
+# ALSA ppc drivers
|
||||
+
|
||||
+menu "ALSA PPC devices"
|
||||
+ depends on SND!=n && PPC
|
||||
+
|
||||
+config SND_PPC_MPC52xx_AC97
|
||||
+ tristate "Freescale MPC52xx AC97 interface support"
|
||||
+ depends on SND && PPC_MPC52xx
|
||||
+ select SND_AC97_CODEC
|
||||
+ help
|
||||
+ Say Y or M if you want to support any AC97 codec attached to
|
||||
+ the Freescqle MPC52xx AC97 interface.
|
||||
+endmenu
|
||||
+
|
||||
endif # SND_PPC
|
||||
--- a/sound/ppc/Makefile
|
||||
+++ b/sound/ppc/Makefile
|
||||
@@ -4,7 +4,9 @@
|
||||
#
|
||||
|
||||
snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
|
||||
+snd-mpc52xx-ac97-objs := mpc52xx_ac97.o
|
||||
|
||||
# Toplevel Module Dependency
|
||||
obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
|
||||
obj-$(CONFIG_SND_PS3) += snd_ps3.o
|
||||
+obj-$(CONFIG_SND_PPC_MPC52xx_AC97) += snd-mpc52xx-ac97.o
|
||||
--- /dev/null
|
||||
+++ b/sound/ppc/mpc52xx_ac97.c
|
||||
@@ -0,0 +1,807 @@
|
||||
+/*
|
||||
+ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface
|
||||
+ *
|
||||
+ *
|
||||
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
|
||||
+ *
|
||||
+ * This file is licensed under the terms of the GNU General Public License
|
||||
+ * version 2. This program is licensed "as is" without any warranty of any
|
||||
+ * kind, whether express or implied.
|
||||
+ */
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/initval.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/ac97_codec.h>
|
||||
+
|
||||
+#include <asm/of_platform.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <asm/mpc52xx_psc.h>
|
||||
+
|
||||
+#include <sysdev/bestcomm/bestcomm.h>
|
||||
+#include <sysdev/bestcomm/gen_bd.h>
|
||||
+
|
||||
+
|
||||
+#define DRV_NAME "mpc52xx-psc-ac97"
|
||||
+
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* Structs / Defines */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+/* Private structure */
|
||||
+struct mpc52xx_ac97_priv {
|
||||
+ struct device *dev;
|
||||
+ resource_size_t mem_start;
|
||||
+ resource_size_t mem_len;
|
||||
+ int irq;
|
||||
+ struct mpc52xx_psc __iomem *psc;
|
||||
+ struct mpc52xx_psc_fifo __iomem *fifo;
|
||||
+
|
||||
+ struct bcom_task *tsk_tx;
|
||||
+ spinlock_t dma_lock;
|
||||
+
|
||||
+ struct snd_card *card;
|
||||
+ struct snd_pcm *pcm;
|
||||
+ struct snd_ac97 *ac97;
|
||||
+
|
||||
+ struct snd_pcm_substream *substream_playback;
|
||||
+
|
||||
+ int period_byte_size;
|
||||
+ u32 period_start, period_end, period_next_p;
|
||||
+};
|
||||
+
|
||||
+/* Register bit definition (AC97 mode specific) */
|
||||
+#define PSC_AC97_SLOT_BIT(n) (1<<(12-n))
|
||||
+#define PSC_AC97_SLOTS_XMIT_SHIFT 16
|
||||
+#define PSC_AC97_SLOTS_RECV_SHIFT 0
|
||||
+
|
||||
+/* Bestcomm options */
|
||||
+#define AC97_TX_NUM_BD 32
|
||||
+#define AC97_RX_NUM_BD 32
|
||||
+
|
||||
+static int mpc52xx_ac97_tx_fill(struct mpc52xx_ac97_priv *priv)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *rt;
|
||||
+
|
||||
+ u32 dma_data_ptr;
|
||||
+
|
||||
+ rt = priv->substream_playback->runtime;
|
||||
+
|
||||
+ dma_data_ptr = virt_to_phys(rt->dma_area);
|
||||
+
|
||||
+ priv->period_byte_size = frames_to_bytes(rt, rt->period_size);
|
||||
+ priv->period_start = dma_data_ptr;
|
||||
+ priv->period_end = dma_data_ptr + priv->period_byte_size * rt->periods;
|
||||
+ priv->period_next_p = dma_data_ptr;
|
||||
+
|
||||
+ spin_lock(&priv->dma_lock);
|
||||
+ while (!bcom_queue_full(priv->tsk_tx)) {
|
||||
+ struct bcom_gen_bd *bd;
|
||||
+
|
||||
+ /* Submit a new one */
|
||||
+ bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
|
||||
+ bd->status = priv->period_byte_size;
|
||||
+ bd->buf_pa = priv->period_next_p;
|
||||
+ bcom_submit_next_buffer(priv->tsk_tx, NULL);
|
||||
+
|
||||
+ /* Next pointer */
|
||||
+ priv->period_next_p += priv->period_byte_size;
|
||||
+ if (priv->period_next_p >= priv->period_end)
|
||||
+ priv->period_next_p = priv->period_start;
|
||||
+ }
|
||||
+ spin_unlock(&priv->dma_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* ISR routine */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+static irqreturn_t mpc52xx_ac97_tx_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = dev_id;
|
||||
+ struct snd_pcm_runtime *rt;
|
||||
+ struct bcom_gen_bd *bd;
|
||||
+
|
||||
+ rt = priv->substream_playback->runtime;
|
||||
+
|
||||
+ if (!bcom_buffer_done(priv->tsk_tx)) {
|
||||
+ dev_dbg(priv->dev, "tx mismatch? Check correct output PSC\n");
|
||||
+ bcom_disable(priv->tsk_tx);
|
||||
+ }
|
||||
+
|
||||
+ spin_lock(&priv->dma_lock);
|
||||
+ while (bcom_buffer_done(priv->tsk_tx)) {
|
||||
+ /* Get the buffer back */
|
||||
+ bcom_retrieve_buffer(priv->tsk_tx, NULL, NULL);
|
||||
+
|
||||
+ /* Submit a new one */
|
||||
+ bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
|
||||
+ bd->status = priv->period_byte_size;
|
||||
+ bd->buf_pa = priv->period_next_p;
|
||||
+ bcom_submit_next_buffer(priv->tsk_tx, NULL);
|
||||
+ bcom_enable(priv->tsk_tx);
|
||||
+
|
||||
+ /* Next pointer */
|
||||
+ priv->period_next_p += priv->period_byte_size;
|
||||
+ if (priv->period_next_p >= priv->period_end)
|
||||
+ priv->period_next_p = priv->period_start;
|
||||
+ }
|
||||
+ spin_unlock(&priv->dma_lock);
|
||||
+
|
||||
+ snd_pcm_period_elapsed(priv->substream_playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static irqreturn_t mpc52xx_ac97_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = dev_id;
|
||||
+
|
||||
+ static int icnt = 0;
|
||||
+
|
||||
+#if 1
|
||||
+ /* Anti Crash during dev ;) */
|
||||
+ if ((icnt++) > 5000)
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0);
|
||||
+#endif
|
||||
+
|
||||
+ /* Print statuts */
|
||||
+ dev_dbg(priv->dev, "isr: %04x", in_be16(&priv->psc->mpc52xx_psc_imr));
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* PCM interface */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+/* HW desc */
|
||||
+
|
||||
+static struct snd_pcm_hardware mpc52xx_ac97_hw = {
|
||||
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S32_BE,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_48000,
|
||||
+ .rate_min = 8000,
|
||||
+ .rate_max = 48000,
|
||||
+ .channels_min = 1,
|
||||
+ .channels_max = 2, /* Support for more ? */
|
||||
+ .buffer_bytes_max = 1024*1024,
|
||||
+ .period_bytes_min = 512,
|
||||
+ .period_bytes_max = 16*1024,
|
||||
+ .periods_min = 8,
|
||||
+ .periods_max = 1024,
|
||||
+ .fifo_size = 512,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/* Playback */
|
||||
+
|
||||
+static int mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream);
|
||||
+
|
||||
+ substream->runtime->hw = mpc52xx_ac97_hw;
|
||||
+
|
||||
+ priv->substream_playback = substream;
|
||||
+
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream);
|
||||
+ priv->substream_playback = NULL;
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream);
|
||||
+
|
||||
+ /* FIXME, need a spinlock to protect access */
|
||||
+ if (substream->runtime->channels == 1)
|
||||
+ out_be32(&priv->psc->ac97_slots, 0x01000000);
|
||||
+ else
|
||||
+ out_be32(&priv->psc->ac97_slots, 0x03000000);
|
||||
+
|
||||
+ snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE,
|
||||
+ substream->runtime->rate);
|
||||
+
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Capture */
|
||||
+
|
||||
+static int mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
|
||||
+ return 0; /* FIXME */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Common */
|
||||
+
|
||||
+static int mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+ int rv;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream);
|
||||
+
|
||||
+ rv = snd_pcm_lib_malloc_pages(substream,
|
||||
+ params_buffer_bytes(params));
|
||||
+ if (rv < 0) {
|
||||
+ printk(KERN_ERR "hw params failes\n"); /* FIXME */
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%d %d %d\n", params_buffer_bytes(params),
|
||||
+ params_period_bytes(params), params_periods(params));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream);
|
||||
+
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+ int rv = 0;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ /* Enable TX taks */
|
||||
+ bcom_gen_bd_tx_reset(priv->tsk_tx);
|
||||
+ mpc52xx_ac97_tx_fill(priv);
|
||||
+ bcom_enable(priv->tsk_tx);
|
||||
+/*
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0800); // 0x0100
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
|
||||
+*/
|
||||
+ /* FIXME: Shouldn't we check for overrun too ? */
|
||||
+ /* also, shouldn't we just activate TX here ? */
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ /* Disable TX task */
|
||||
+ bcom_disable(priv->tsk_tx);
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); // 0x0100
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ rv = -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* FIXME */
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t mpc52xx_ac97_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
|
||||
+ u32 count;
|
||||
+
|
||||
+ count = priv->tsk_tx->bd[priv->tsk_tx->outdex].data[0] - priv->period_start;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, count);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Ops */
|
||||
+
|
||||
+static struct snd_pcm_ops mpc52xx_ac97_playback_ops = {
|
||||
+ .open = mpc52xx_ac97_playback_open,
|
||||
+ .close = mpc52xx_ac97_playback_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = mpc52xx_ac97_hw_params,
|
||||
+ .hw_free = mpc52xx_ac97_hw_free,
|
||||
+ .prepare = mpc52xx_ac97_playback_prepare,
|
||||
+ .trigger = mpc52xx_ac97_trigger,
|
||||
+ .pointer = mpc52xx_ac97_pointer,
|
||||
+};
|
||||
+
|
||||
+static struct snd_pcm_ops mpc52xx_ac97_capture_ops = {
|
||||
+ .open = mpc52xx_ac97_capture_open,
|
||||
+ .close = mpc52xx_ac97_capture_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = mpc52xx_ac97_hw_params,
|
||||
+ .hw_free = mpc52xx_ac97_hw_free,
|
||||
+ .prepare = mpc52xx_ac97_capture_prepare,
|
||||
+ .trigger = mpc52xx_ac97_trigger,
|
||||
+ .pointer = mpc52xx_ac97_pointer,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* AC97 Bus interface */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+static unsigned short mpc52xx_ac97_bus_read(struct snd_ac97 *ac97,
|
||||
+ unsigned short reg)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = ac97->private_data;
|
||||
+ int timeout;
|
||||
+ unsigned int val;
|
||||
+
|
||||
+ /* Wait for it to be ready */
|
||||
+ timeout = 1000;
|
||||
+ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
|
||||
+ MPC52xx_PSC_SR_CMDSEND) )
|
||||
+ udelay(10);
|
||||
+
|
||||
+ if (!timeout) {
|
||||
+ printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n");
|
||||
+ return 0xffff;
|
||||
+ }
|
||||
+
|
||||
+ /* Do the read */
|
||||
+ out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
|
||||
+
|
||||
+ /* Wait for the answer */
|
||||
+ timeout = 1000;
|
||||
+ while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) &
|
||||
+ MPC52xx_PSC_SR_DATA_VAL) )
|
||||
+ udelay(10);
|
||||
+
|
||||
+ if (!timeout) {
|
||||
+ printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n");
|
||||
+ return 0xffff;
|
||||
+ }
|
||||
+
|
||||
+ /* Get the data */
|
||||
+ val = in_be32(&priv->psc->ac97_data);
|
||||
+ if ( ((val>>24) & 0x7f) != reg ) {
|
||||
+ printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n");
|
||||
+ return 0xffff;
|
||||
+ }
|
||||
+ val = (val >> 8) & 0xffff;
|
||||
+
|
||||
+ return (unsigned short) val;
|
||||
+}
|
||||
+
|
||||
+static void mpc52xx_ac97_bus_write(struct snd_ac97 *ac97,
|
||||
+ unsigned short reg, unsigned short val)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = ac97->private_data;
|
||||
+ int timeout;
|
||||
+
|
||||
+ /* Wait for it to be ready */
|
||||
+ timeout = 1000;
|
||||
+ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
|
||||
+ MPC52xx_PSC_SR_CMDSEND) )
|
||||
+ udelay(10);
|
||||
+
|
||||
+ if (!timeout) {
|
||||
+ printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Write data */
|
||||
+ out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8));
|
||||
+}
|
||||
+
|
||||
+static void mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv = ac97->private_data;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "ac97 codec reset\n");
|
||||
+
|
||||
+ /* Do a cold reset */
|
||||
+ /*
|
||||
+ * Note: This could interfere with some external AC97 mixers, as it
|
||||
+ * could switch them into test mode, when SYNC or SDATA_OUT are not
|
||||
+ * low while RES is low!
|
||||
+ */
|
||||
+ out_8(&priv->psc->op1, 0x02);
|
||||
+ udelay(10);
|
||||
+ out_8(&priv->psc->op0, 0x02);
|
||||
+ udelay(50);
|
||||
+
|
||||
+ /* PSC recover from cold reset (cfr user manual, not sure if useful) */
|
||||
+ out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr));
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = {
|
||||
+ .read = mpc52xx_ac97_bus_read,
|
||||
+ .write = mpc52xx_ac97_bus_write,
|
||||
+ .reset = mpc52xx_ac97_bus_reset,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* Sound driver setup */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+static int mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv)
|
||||
+{
|
||||
+ int rv;
|
||||
+
|
||||
+ rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm);
|
||||
+ if (rv) {
|
||||
+ dev_dbg(priv->dev, "%s: snd_pcm_new failed\n", DRV_NAME);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm,
|
||||
+ SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL),
|
||||
+ 128*1024, 128*1024);
|
||||
+ if (rv) {
|
||||
+ dev_dbg(priv->dev,
|
||||
+ "%s: snd_pcm_lib_preallocate_pages_for_all failed\n",
|
||||
+ DRV_NAME);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
+ &mpc52xx_ac97_playback_ops);
|
||||
+ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE,
|
||||
+ &mpc52xx_ac97_capture_ops);
|
||||
+
|
||||
+ priv->pcm->private_data = priv;
|
||||
+ priv->pcm->info_flags = 0;
|
||||
+
|
||||
+ strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv)
|
||||
+{
|
||||
+ struct snd_ac97_bus *ac97_bus;
|
||||
+ struct snd_ac97_template ac97_template;
|
||||
+ int rv;
|
||||
+
|
||||
+ rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, &ac97_bus);
|
||||
+ if (rv) {
|
||||
+ printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n");
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
|
||||
+ ac97_template.private_data = priv;
|
||||
+
|
||||
+ rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97);
|
||||
+ if (rv) {
|
||||
+ printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n");
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv)
|
||||
+{
|
||||
+ /* Reset everything first by safety */
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
|
||||
+
|
||||
+ /* Do a cold reset of codec */
|
||||
+ /*
|
||||
+ * Note: This could interfere with some external AC97 mixers, as it
|
||||
+ * could switch them into test mode, when SYNC or SDATA_OUT are not
|
||||
+ * low while RES is low!
|
||||
+ */
|
||||
+ out_8(&priv->psc->op1, 0x02);
|
||||
+ udelay(10);
|
||||
+ out_8(&priv->psc->op0, 0x02);
|
||||
+ udelay(50);
|
||||
+
|
||||
+ /* Configure AC97 enhanced mode */
|
||||
+ out_be32(&priv->psc->sicr, 0x03010000);
|
||||
+
|
||||
+ /* No slots active */
|
||||
+ out_be32(&priv->psc->ac97_slots, 0x00000000);
|
||||
+
|
||||
+ /* No IRQ */
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
|
||||
+
|
||||
+ /* FIFO levels */
|
||||
+ out_8(&priv->fifo->rfcntl, 0x07);
|
||||
+ out_8(&priv->fifo->tfcntl, 0x07);
|
||||
+ out_be16(&priv->fifo->rfalarm, 0x80);
|
||||
+ out_be16(&priv->fifo->tfalarm, 0x80);
|
||||
+
|
||||
+ /* Go */
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE);
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv)
|
||||
+{
|
||||
+ /* No IRQ */
|
||||
+ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
|
||||
+
|
||||
+ /* Disable TB & RX */
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
|
||||
+ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
|
||||
+
|
||||
+ /* FIXME : Reset or put codec in low power ? */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* OF Platform Driver */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+static int __devinit
|
||||
+mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match)
|
||||
+{
|
||||
+ struct device_node *dn = op->node;
|
||||
+ struct mpc52xx_ac97_priv *priv;
|
||||
+ struct snd_card *card;
|
||||
+ struct resource res;
|
||||
+ int tx_initiator;
|
||||
+ int rv;
|
||||
+ const unsigned int *devno;
|
||||
+
|
||||
+ dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n");
|
||||
+
|
||||
+ /* Get card structure */
|
||||
+ rv = -ENOMEM;
|
||||
+ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
|
||||
+ THIS_MODULE, sizeof(struct mpc52xx_ac97_priv));
|
||||
+ if (!card)
|
||||
+ goto err_early;
|
||||
+
|
||||
+ priv = card->private_data;
|
||||
+
|
||||
+ /* Init our private structure */
|
||||
+ priv->card = card;
|
||||
+ priv->dev = &op->dev;
|
||||
+
|
||||
+ /* Get resources (mem,irq,...) */
|
||||
+ rv = of_address_to_resource(dn, 0, &res);
|
||||
+ if (rv)
|
||||
+ goto err_early;
|
||||
+
|
||||
+ priv->mem_start = res.start;
|
||||
+ priv->mem_len = res.end - res.start + 1;
|
||||
+
|
||||
+ if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) {
|
||||
+ dev_err(&op->dev, "%s: request_mem_region failed\n", DRV_NAME);
|
||||
+ rv = -EBUSY;
|
||||
+ goto err_early;
|
||||
+ }
|
||||
+
|
||||
+ priv->psc = ioremap(priv->mem_start, priv->mem_len);
|
||||
+ if (!priv->psc) {
|
||||
+ dev_err(&op->dev, "%s: ioremap failed\n", DRV_NAME);
|
||||
+ rv = -ENOMEM;
|
||||
+ goto err_iomap;
|
||||
+ }
|
||||
+ /* the fifo starts right after psc ends */
|
||||
+ priv->fifo = (struct mpc52xx_psc_fifo*)&priv->psc[1]; /* FIXME */
|
||||
+
|
||||
+ priv->irq = irq_of_parse_and_map(dn, 0);
|
||||
+ if (priv->irq == NO_IRQ) {
|
||||
+ dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
|
||||
+ DRV_NAME);
|
||||
+ rv = -EBUSY;
|
||||
+ goto err_irqmap;
|
||||
+ }
|
||||
+
|
||||
+ /* Setup Bestcomm tasks */
|
||||
+ spin_lock_init(&priv->dma_lock);
|
||||
+
|
||||
+ /*
|
||||
+ * PSC1 or PSC2 can be configured for AC97 usage. Select the right
|
||||
+ * channel, to let the BCOMM unit does its job correctly.
|
||||
+ */
|
||||
+ devno = of_get_property(dn, "cell-index", NULL);
|
||||
+ switch (*devno) {
|
||||
+ case 0: /* PSC1 */
|
||||
+ tx_initiator = 14;
|
||||
+ break;
|
||||
+ case 1: /* PSC2 */
|
||||
+ tx_initiator = 12;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_dbg(priv->dev, "Unknown PSC unit for AC97 usage!\n");
|
||||
+ rv = -ENODEV;
|
||||
+ goto err_irq;
|
||||
+ }
|
||||
+
|
||||
+ priv->tsk_tx = bcom_gen_bd_tx_init(AC97_TX_NUM_BD,
|
||||
+ priv->mem_start + sizeof(struct mpc52xx_psc) +
|
||||
+ offsetof(struct mpc52xx_psc_fifo, tfdata),
|
||||
+ tx_initiator,
|
||||
+ 2); /* ipr : FIXME */
|
||||
+ if (!priv->tsk_tx) {
|
||||
+ dev_err(&op->dev, "%s: bcom_gen_bd_tx_init failed\n",
|
||||
+ DRV_NAME);
|
||||
+ rv = -ENOMEM;
|
||||
+ goto err_bcomm;
|
||||
+ }
|
||||
+
|
||||
+ /* Low level HW Init */
|
||||
+ mpc52xx_ac97_hwinit(priv);
|
||||
+
|
||||
+ /* Request IRQ now that we're 'stable' */
|
||||
+ rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv);
|
||||
+ if (rv < 0) {
|
||||
+ dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
|
||||
+ goto err_irqreq;
|
||||
+ }
|
||||
+
|
||||
+ rv = request_irq(bcom_get_task_irq(priv->tsk_tx),
|
||||
+ mpc52xx_ac97_tx_irq, 0, DRV_NAME "_tx", priv);
|
||||
+ if (rv < 0) {
|
||||
+ dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
|
||||
+ goto err_txirqreq;
|
||||
+ }
|
||||
+
|
||||
+ /* Prepare sound stuff */
|
||||
+ rv = mpc52xx_ac97_setup_mixer(priv);
|
||||
+ if (rv)
|
||||
+ goto err_late;
|
||||
+
|
||||
+ rv = mpc52xx_ac97_setup_pcm(priv);
|
||||
+ if (rv)
|
||||
+ goto err_late;
|
||||
+
|
||||
+ /* Finally register the card */
|
||||
+ snprintf(card->shortname, sizeof(card->shortname), DRV_NAME);
|
||||
+ snprintf(card->longname, sizeof(card->longname),
|
||||
+ "Freescale MPC52xx PSC-AC97 (%s)", card->mixername);
|
||||
+
|
||||
+ rv = snd_card_register(card);
|
||||
+ if (rv) {
|
||||
+ dev_err(&op->dev, "%s: snd_card_register failed\n", DRV_NAME);
|
||||
+ goto err_late;
|
||||
+ }
|
||||
+
|
||||
+ dev_set_drvdata(&op->dev, priv);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_late:
|
||||
+ free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
|
||||
+err_txirqreq:
|
||||
+ free_irq(priv->irq, priv);
|
||||
+err_irqreq:
|
||||
+ bcom_gen_bd_tx_release(priv->tsk_tx);
|
||||
+err_bcomm:
|
||||
+ mpc52xx_ac97_hwshutdown(priv);
|
||||
+err_irq:
|
||||
+ irq_dispose_mapping(priv->irq);
|
||||
+err_irqmap:
|
||||
+ iounmap(priv->psc);
|
||||
+err_iomap:
|
||||
+ release_mem_region(priv->mem_start, priv->mem_len);
|
||||
+err_early:
|
||||
+ if (card)
|
||||
+ snd_card_free(card);
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
+static int mpc52xx_ac97_remove(struct of_device *op)
|
||||
+{
|
||||
+ struct mpc52xx_ac97_priv *priv;
|
||||
+
|
||||
+ dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n");
|
||||
+
|
||||
+ priv = dev_get_drvdata(&op->dev);
|
||||
+ if (priv) {
|
||||
+ /* Sound subsys shutdown */
|
||||
+ snd_card_free(priv->card);
|
||||
+
|
||||
+ /* Low level HW shutdown */
|
||||
+ mpc52xx_ac97_hwshutdown(priv);
|
||||
+
|
||||
+ /* Release bestcomm tasks */
|
||||
+ free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
|
||||
+ bcom_gen_bd_tx_release(priv->tsk_tx);
|
||||
+
|
||||
+ /* Release resources */
|
||||
+ iounmap(priv->psc);
|
||||
+ free_irq(priv->irq, priv);
|
||||
+ irq_dispose_mapping(priv->irq);
|
||||
+ release_mem_region(priv->mem_start, priv->mem_len);
|
||||
+ }
|
||||
+
|
||||
+ dev_set_drvdata(&op->dev, NULL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct of_device_id mpc52xx_ac97_of_match[] = {
|
||||
+ {
|
||||
+ .type = "sound",
|
||||
+ .compatible = "mpc5200b-psc-ac97", /* B only for now */
|
||||
+ }, { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match);
|
||||
+static struct of_platform_driver mpc52xx_ac97_of_driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .name = DRV_NAME,
|
||||
+ .match_table = mpc52xx_ac97_of_match,
|
||||
+ .probe = mpc52xx_ac97_probe,
|
||||
+ .remove = mpc52xx_ac97_remove,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+/* ======================================================================== */
|
||||
+/* Module */
|
||||
+/* ======================================================================== */
|
||||
+
|
||||
+static int __init mpc52xx_ac97_init(void)
|
||||
+{
|
||||
+ int rv;
|
||||
+
|
||||
+ printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n");
|
||||
+
|
||||
+ rv = of_register_platform_driver(&mpc52xx_ac97_of_driver);
|
||||
+ if (rv) {
|
||||
+ printk(KERN_ERR DRV_NAME ": "
|
||||
+ "of_register_platform_driver failed (%i)\n", rv);
|
||||
+ return rv;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __exit mpc52xx_ac97_exit(void)
|
||||
+{
|
||||
+ of_unregister_platform_driver(&mpc52xx_ac97_of_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(mpc52xx_ac97_init);
|
||||
+module_exit(mpc52xx_ac97_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
|
||||
+MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
@@ -0,0 +1,83 @@
|
||||
Subject: [PATCH] autodetect serial console on efika
|
||||
From: Olaf Hering <olh@suse.de>
|
||||
|
||||
Efika boards have to be booted with console=ttyPSC0 unless there is a
|
||||
graphics card plugged in. Detect if the firmware stdout is the serial
|
||||
connector.
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/52xx/efika.c | 50 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 50 insertions(+)
|
||||
|
||||
--- a/arch/powerpc/platforms/52xx/efika.c
|
||||
+++ b/arch/powerpc/platforms/52xx/efika.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/utsrelease.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/console.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/machdep.h>
|
||||
@@ -211,12 +212,61 @@ static int __init efika_probe(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Per default, input/output-device points to the keyboard/screen
|
||||
+ * If no card is installed, the built-in serial port is used as a fallback.
|
||||
+ * But unfortunately, the firmware does not connect /chosen/{stdin,stdout}
|
||||
+ * the the built-in serial node. Instead, a /failsafe node is created.
|
||||
+ * More advanced hardware configurations cant be detected,
|
||||
+ * boot with console=xyz123 to point the kernel to the correct device
|
||||
+ */
|
||||
+static void __init efika_init_early(void)
|
||||
+{
|
||||
+#ifdef CONFIG_SERIAL_MPC52xx
|
||||
+ struct device_node *stdout_node;
|
||||
+ const char *property;
|
||||
+
|
||||
+ if (strstr(cmd_line, "console="))
|
||||
+ return;
|
||||
+ /* find the boot console from /chosen/stdout */
|
||||
+ if (!of_chosen)
|
||||
+ return;
|
||||
+ property = of_get_property(of_chosen, "linux,stdout-path", NULL);
|
||||
+ if (!property)
|
||||
+ return;
|
||||
+ stdout_node = of_find_node_by_path(property);
|
||||
+ if (!stdout_node)
|
||||
+ return;
|
||||
+ property = of_get_property(stdout_node, "device_type", NULL);
|
||||
+ if (property && strcmp(property, "serial") == 0) {
|
||||
+ /*
|
||||
+ * The 9pin connector is either /failsafe or /builtin/serial.
|
||||
+ * The optional graphics card has also type 'serial' in VGA mode.
|
||||
+ */
|
||||
+ property = of_get_property(stdout_node, "name", NULL);
|
||||
+ if (property) {
|
||||
+ if (strcmp(property, "failsafe") == 0)
|
||||
+ add_preferred_console("ttyPSC", 0, NULL);
|
||||
+ else {
|
||||
+ if (strcmp(property, "serial") == 0) {
|
||||
+ property = of_get_property(stdout_node, "model", NULL);
|
||||
+ if (property && strcmp(property, "mpc5200-serial") == 0)
|
||||
+ add_preferred_console("ttyPSC", 0, NULL);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ of_node_put(stdout_node);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
define_machine(efika)
|
||||
{
|
||||
.name = EFIKA_PLATFORM_NAME,
|
||||
.probe = efika_probe,
|
||||
.setup_arch = efika_setup_arch,
|
||||
.init = mpc52xx_declare_of_platform_devices,
|
||||
+ .init_early = efika_init_early,
|
||||
.show_cpuinfo = efika_show_cpuinfo,
|
||||
.init_IRQ = mpc52xx_init_irq,
|
||||
.get_irq = mpc52xx_get_irq,
|
||||
@@ -0,0 +1,25 @@
|
||||
Subject: Don't emulate mr. instructions
|
||||
From: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
|
||||
References: 459387 - LTC49903
|
||||
|
||||
Currently emulate_step() emulates mr. instructions without updating cr0
|
||||
and this can be disastrous. Don't emulate mr.
|
||||
|
||||
Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/lib/sstep.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/arch/powerpc/lib/sstep.c
|
||||
+++ b/arch/powerpc/lib/sstep.c
|
||||
@@ -172,6 +172,8 @@ int __kprobes emulate_step(struct pt_reg
|
||||
}
|
||||
break;
|
||||
case 0x378: /* orx */
|
||||
+ if (instr & 1)
|
||||
+ break;
|
||||
rs = (instr >> 21) & 0x1f;
|
||||
rb = (instr >> 11) & 0x1f;
|
||||
if (rs == rb) { /* mr */
|
||||
@@ -0,0 +1,33 @@
|
||||
From: Takashi Iwai <tiwai@suse.de>
|
||||
Subject: [PATCH] Fix build_error without CONFIG_PPC_83xx
|
||||
Patch-mainline:
|
||||
References:
|
||||
|
||||
fsl_deep_sleep() is defined only with CONFIG_PPC_83xx although
|
||||
CONFIG_IPIC is set for CONFIG_PPC_MPC512x, too.
|
||||
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
|
||||
---
|
||||
---
|
||||
arch/powerpc/sysdev/ipic.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/arch/powerpc/sysdev/ipic.c
|
||||
+++ b/arch/powerpc/sysdev/ipic.c
|
||||
@@ -920,6 +920,7 @@ static int ipic_suspend(struct sys_devic
|
||||
ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR);
|
||||
ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR);
|
||||
|
||||
+#ifdef CONFIG_PPC_83xx
|
||||
if (fsl_deep_sleep()) {
|
||||
/* In deep sleep, make sure there can be no
|
||||
* pending interrupts, as this can cause
|
||||
@@ -930,6 +931,7 @@ static int ipic_suspend(struct sys_devic
|
||||
ipic_write(ipic->regs, IPIC_SEMSR, 0);
|
||||
ipic_write(ipic->regs, IPIC_SERMR, 0);
|
||||
}
|
||||
+#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
Subject: fix booting with memoryless nodes
|
||||
From: haveblue@us.ibm.com
|
||||
References: 443280 - LTC49675
|
||||
|
||||
I've reproduced this on 2.6.27.7. I'm pretty sure it is caused by this
|
||||
patch:
|
||||
|
||||
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=8f64e1f2d1e09267ac926e15090fd505c1c0cbcb
|
||||
|
||||
The problem is that Jon took a loop which was (in psuedocode):
|
||||
|
||||
for_each_node(nid)
|
||||
NODE_DATA(nid) = careful_alloc(nid);
|
||||
setup_bootmem(nid);
|
||||
reserve_node_bootmem(nid);
|
||||
|
||||
and broke it up into:
|
||||
|
||||
for_each_node(nid)
|
||||
NODE_DATA(nid) = careful_alloc(nid);
|
||||
setup_bootmem(nid);
|
||||
for_each_node(nid)
|
||||
reserve_node_bootmem(nid);
|
||||
|
||||
The issue comes in when the 'careful_alloc()' is called on a node with
|
||||
no memory. It falls back to using bootmem from a previously-initialized
|
||||
node. But, bootmem has not yet been reserved when Jon's patch is
|
||||
applied. It gives back bogus memory (0xc000000000000000) and pukes
|
||||
later in boot.
|
||||
|
||||
The following patch collapses the loop back together. It also breaks
|
||||
the mark_reserved_regions_for_nid() code out into a function and adds
|
||||
some comments. I think a huge part of introducing this bug is because
|
||||
for loop was too long and hard to read.
|
||||
|
||||
The actual bug fix here is the:
|
||||
|
||||
+ if (end_pfn <= node->node_start_pfn ||
|
||||
+ start_pfn >= node_end_pfn)
|
||||
+ continue;
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/mm/numa.c | 130 ++++++++++++++++++++++++++++++-------------------
|
||||
1 file changed, 82 insertions(+), 48 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/mm/numa.c
|
||||
+++ b/arch/powerpc/mm/numa.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/lmb.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/pfn.h>
|
||||
#include <asm/sparsemem.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/system.h>
|
||||
@@ -867,10 +868,75 @@ static struct notifier_block __cpuinitda
|
||||
.priority = 1 /* Must run before sched domains notifier. */
|
||||
};
|
||||
|
||||
+static void mark_reserved_regions_for_nid(int nid)
|
||||
+{
|
||||
+ struct pglist_data *node = NODE_DATA(nid);
|
||||
+ int i;
|
||||
+
|
||||
+ dbg("mark_reserved_regions_for_nid(%d) NODE_DATA: %p\n", nid, node);
|
||||
+ for (i = 0; i < lmb.reserved.cnt; i++) {
|
||||
+ unsigned long physbase = lmb.reserved.region[i].base;
|
||||
+ unsigned long size = lmb.reserved.region[i].size;
|
||||
+ unsigned long start_pfn = physbase >> PAGE_SHIFT;
|
||||
+ unsigned long end_pfn = PFN_UP(physbase + size);
|
||||
+ struct node_active_region node_ar;
|
||||
+ unsigned long node_end_pfn = node->node_start_pfn +
|
||||
+ node->node_spanned_pages;
|
||||
+
|
||||
+ /*
|
||||
+ * Check to make sure that this lmb.reserved area is
|
||||
+ * within the bounds of the node that we care about.
|
||||
+ * Checking the nid of the start and end points is not
|
||||
+ * sufficient because the reserved area could span the
|
||||
+ * entire node.
|
||||
+ */
|
||||
+ if (end_pfn <= node->node_start_pfn ||
|
||||
+ start_pfn >= node_end_pfn)
|
||||
+ continue;
|
||||
+
|
||||
+ get_node_active_region(start_pfn, &node_ar);
|
||||
+ while (start_pfn < end_pfn &&
|
||||
+ node_ar.start_pfn < node_ar.end_pfn) {
|
||||
+ unsigned long reserve_size = size;
|
||||
+ /*
|
||||
+ * if reserved region extends past active region
|
||||
+ * then trim size to active region
|
||||
+ */
|
||||
+ if (end_pfn > node_ar.end_pfn)
|
||||
+ reserve_size = (node_ar.end_pfn << PAGE_SHIFT)
|
||||
+ - physbase;
|
||||
+ /*
|
||||
+ * Only worry about *this* node, others may not
|
||||
+ * yet have valid NODE_DATA().
|
||||
+ */
|
||||
+ if (node_ar.nid == nid)
|
||||
+ reserve_bootmem_node(NODE_DATA(node_ar.nid),
|
||||
+ physbase, reserve_size,
|
||||
+ BOOTMEM_DEFAULT);
|
||||
+ /*
|
||||
+ * if reserved region is contained in the active region
|
||||
+ * then done.
|
||||
+ */
|
||||
+ if (end_pfn <= node_ar.end_pfn)
|
||||
+ break;
|
||||
+
|
||||
+ /*
|
||||
+ * reserved region extends past the active region
|
||||
+ * get next active region that contains this
|
||||
+ * reserved region
|
||||
+ */
|
||||
+ start_pfn = node_ar.end_pfn;
|
||||
+ physbase = start_pfn << PAGE_SHIFT;
|
||||
+ size = size - reserve_size;
|
||||
+ get_node_active_region(start_pfn, &node_ar);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
void __init do_init_bootmem(void)
|
||||
{
|
||||
int nid;
|
||||
- unsigned int i;
|
||||
|
||||
min_low_pfn = 0;
|
||||
max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
|
||||
@@ -890,9 +956,16 @@ void __init do_init_bootmem(void)
|
||||
unsigned long bootmem_paddr;
|
||||
unsigned long bootmap_pages;
|
||||
|
||||
+ dbg("node %d is online\n", nid);
|
||||
get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
|
||||
|
||||
- /* Allocate the node structure node local if possible */
|
||||
+ /*
|
||||
+ * Allocate the node structure node local if possible
|
||||
+ *
|
||||
+ * Be careful moving this around, as it relies on all
|
||||
+ * previous nodes' bootmem to be initialized and have
|
||||
+ * all reserved areas marked.
|
||||
+ */
|
||||
NODE_DATA(nid) = careful_allocation(nid,
|
||||
sizeof(struct pglist_data),
|
||||
SMP_CACHE_BYTES, end_pfn);
|
||||
@@ -924,53 +997,14 @@ void __init do_init_bootmem(void)
|
||||
start_pfn, end_pfn);
|
||||
|
||||
free_bootmem_with_active_regions(nid, end_pfn);
|
||||
- }
|
||||
-
|
||||
- /* Mark reserved regions */
|
||||
- for (i = 0; i < lmb.reserved.cnt; i++) {
|
||||
- unsigned long physbase = lmb.reserved.region[i].base;
|
||||
- unsigned long size = lmb.reserved.region[i].size;
|
||||
- unsigned long start_pfn = physbase >> PAGE_SHIFT;
|
||||
- unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT);
|
||||
- struct node_active_region node_ar;
|
||||
-
|
||||
- get_node_active_region(start_pfn, &node_ar);
|
||||
- while (start_pfn < end_pfn &&
|
||||
- node_ar.start_pfn < node_ar.end_pfn) {
|
||||
- unsigned long reserve_size = size;
|
||||
- /*
|
||||
- * if reserved region extends past active region
|
||||
- * then trim size to active region
|
||||
- */
|
||||
- if (end_pfn > node_ar.end_pfn)
|
||||
- reserve_size = (node_ar.end_pfn << PAGE_SHIFT)
|
||||
- - (start_pfn << PAGE_SHIFT);
|
||||
- dbg("reserve_bootmem %lx %lx nid=%d\n", physbase,
|
||||
- reserve_size, node_ar.nid);
|
||||
- reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase,
|
||||
- reserve_size, BOOTMEM_DEFAULT);
|
||||
- /*
|
||||
- * if reserved region is contained in the active region
|
||||
- * then done.
|
||||
- */
|
||||
- if (end_pfn <= node_ar.end_pfn)
|
||||
- break;
|
||||
-
|
||||
- /*
|
||||
- * reserved region extends past the active region
|
||||
- * get next active region that contains this
|
||||
- * reserved region
|
||||
- */
|
||||
- start_pfn = node_ar.end_pfn;
|
||||
- physbase = start_pfn << PAGE_SHIFT;
|
||||
- size = size - reserve_size;
|
||||
- get_node_active_region(start_pfn, &node_ar);
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- for_each_online_node(nid)
|
||||
+ /*
|
||||
+ * Be very careful about moving this around. Future
|
||||
+ * calls to careful_allocation() depend on this getting
|
||||
+ * done correctly.
|
||||
+ */
|
||||
+ mark_reserved_regions_for_nid(nid);
|
||||
sparse_memory_present_with_active_regions(nid);
|
||||
+ }
|
||||
}
|
||||
|
||||
void __init paging_init(void)
|
||||
30
src/patches/suse-2.6.27.25/patches.arch/ppc-of-irq-map.patch
Normal file
30
src/patches/suse-2.6.27.25/patches.arch/ppc-of-irq-map.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
Subject: fix IRQ assignment if interrupts property is missing
|
||||
From: Adhemerval Zanella Neto <azanella@br.ibm.com>
|
||||
References: 446610 - LTC50006
|
||||
|
||||
This patch fix the IRQ assign.
|
||||
If the code can not get "interrupts" property from PCI OF node,
|
||||
it falls back to standard OF parsing.
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/kernel/prom_parse.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/prom_parse.c
|
||||
+++ b/arch/powerpc/kernel/prom_parse.c
|
||||
@@ -250,8 +250,11 @@ int of_irq_map_pci(struct pci_dev *pdev,
|
||||
* parsing
|
||||
*/
|
||||
dn = pci_device_to_OF_node(pdev);
|
||||
- if (dn)
|
||||
- return of_irq_map_one(dn, 0, out_irq);
|
||||
+ if (dn) {
|
||||
+ rc = of_irq_map_one(dn, 0, out_irq);
|
||||
+ if (!rc)
|
||||
+ return rc;
|
||||
+ }
|
||||
|
||||
/* Ok, we don't, time to have fun. Let's start by building up an
|
||||
* interrupt spec. we assume #interrupt-cells is 1, which is standard
|
||||
@@ -0,0 +1,513 @@
|
||||
Subject: [PATCH] powerpc/oprofile: Fix mutex locking for cell spu-oprofile
|
||||
From: Carl Love <cel@us.ibm.com>
|
||||
References: 422501 - LTC47617
|
||||
|
||||
The issue is the SPU code is not holding the kernel mutex lock while
|
||||
adding samples to the kernel buffer.
|
||||
|
||||
This patch creates per SPU buffers to hold the data. Data
|
||||
is added to the buffers from in interrupt context. The data
|
||||
is periodically pushed to the kernel buffer via a new Oprofile
|
||||
function oprofile_put_buff(). The oprofile_put_buff() function
|
||||
is called via a work queue enabling the funtion to acquire the
|
||||
mutex lock.
|
||||
|
||||
The existing user controls for adjusting the per CPU buffer
|
||||
size is used to control the size of the per SPU buffers.
|
||||
Similarly, overflows of the SPU buffers are reported by
|
||||
incrementing the per CPU buffer stats. This eliminates the
|
||||
need to have architecture specific controls for the per SPU
|
||||
buffers which is not acceptable to the OProfile user tool
|
||||
maintainer.
|
||||
|
||||
The export of the oprofile add_event_entry() is removed as it
|
||||
is no longer needed given this patch.
|
||||
|
||||
Note, this patch has not addressed the issue of indexing arrays
|
||||
by the spu number. This still needs to be fixed as the spu
|
||||
numbering is not guarenteed to be 0 to max_num_spus-1.
|
||||
|
||||
Signed-off-by: Carl Love <carll@us.ibm.com>
|
||||
Signed-off-by: Maynard Johnson <maynardj@us.ibm.com>
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Acked-by: Acked-by: Robert Richter <robert.richter@amd.com>
|
||||
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/oprofile/cell/pr_util.h | 13 +
|
||||
arch/powerpc/oprofile/cell/spu_profiler.c | 4
|
||||
arch/powerpc/oprofile/cell/spu_task_sync.c | 236 +++++++++++++++++++++++++----
|
||||
drivers/oprofile/buffer_sync.c | 24 ++
|
||||
drivers/oprofile/cpu_buffer.c | 15 +
|
||||
drivers/oprofile/event_buffer.h | 7
|
||||
include/linux/oprofile.h | 16 +
|
||||
7 files changed, 279 insertions(+), 36 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/oprofile/cell/pr_util.h
|
||||
+++ b/arch/powerpc/oprofile/cell/pr_util.h
|
||||
@@ -24,6 +24,11 @@
|
||||
#define SKIP_GENERIC_SYNC 0
|
||||
#define SYNC_START_ERROR -1
|
||||
#define DO_GENERIC_SYNC 1
|
||||
+#define SPUS_PER_NODE 8
|
||||
+#define DEFAULT_TIMER_EXPIRE (HZ / 10)
|
||||
+
|
||||
+extern struct delayed_work spu_work;
|
||||
+extern int spu_prof_running;
|
||||
|
||||
struct spu_overlay_info { /* map of sections within an SPU overlay */
|
||||
unsigned int vma; /* SPU virtual memory address from elf */
|
||||
@@ -62,6 +67,14 @@ struct vma_to_fileoffset_map { /* map of
|
||||
|
||||
};
|
||||
|
||||
+struct spu_buffer {
|
||||
+ int last_guard_val;
|
||||
+ int ctx_sw_seen;
|
||||
+ unsigned long *buff;
|
||||
+ unsigned int head, tail;
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* The three functions below are for maintaining and accessing
|
||||
* the vma-to-fileoffset map.
|
||||
*/
|
||||
--- a/arch/powerpc/oprofile/cell/spu_profiler.c
|
||||
+++ b/arch/powerpc/oprofile/cell/spu_profiler.c
|
||||
@@ -24,12 +24,11 @@
|
||||
|
||||
static u32 *samples;
|
||||
|
||||
-static int spu_prof_running;
|
||||
+int spu_prof_running;
|
||||
static unsigned int profiling_interval;
|
||||
|
||||
#define NUM_SPU_BITS_TRBUF 16
|
||||
#define SPUS_PER_TB_ENTRY 4
|
||||
-#define SPUS_PER_NODE 8
|
||||
|
||||
#define SPU_PC_MASK 0xFFFF
|
||||
|
||||
@@ -209,6 +208,7 @@ int start_spu_profiling(unsigned int cyc
|
||||
|
||||
spu_prof_running = 1;
|
||||
hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
|
||||
+ schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/arch/powerpc/oprofile/cell/spu_task_sync.c
|
||||
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
|
||||
@@ -35,7 +35,102 @@ static DEFINE_SPINLOCK(buffer_lock);
|
||||
static DEFINE_SPINLOCK(cache_lock);
|
||||
static int num_spu_nodes;
|
||||
int spu_prof_num_nodes;
|
||||
-int last_guard_val[MAX_NUMNODES * 8];
|
||||
+
|
||||
+struct spu_buffer spu_buff[MAX_NUMNODES * SPUS_PER_NODE];
|
||||
+struct delayed_work spu_work;
|
||||
+static unsigned max_spu_buff;
|
||||
+
|
||||
+static void spu_buff_add(unsigned long int value, int spu)
|
||||
+{
|
||||
+ /* spu buff is a circular buffer. Add entries to the
|
||||
+ * head. Head is the index to store the next value.
|
||||
+ * The buffer is full when there is one available entry
|
||||
+ * in the queue, i.e. head and tail can't be equal.
|
||||
+ * That way we can tell the difference between the
|
||||
+ * buffer being full versus empty.
|
||||
+ *
|
||||
+ * ASSUPTION: the buffer_lock is held when this function
|
||||
+ * is called to lock the buffer, head and tail.
|
||||
+ */
|
||||
+ int full = 1;
|
||||
+
|
||||
+ if (spu_buff[spu].head >= spu_buff[spu].tail) {
|
||||
+ if ((spu_buff[spu].head - spu_buff[spu].tail)
|
||||
+ < (max_spu_buff - 1))
|
||||
+ full = 0;
|
||||
+
|
||||
+ } else if (spu_buff[spu].tail > spu_buff[spu].head) {
|
||||
+ if ((spu_buff[spu].tail - spu_buff[spu].head)
|
||||
+ > 1)
|
||||
+ full = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!full) {
|
||||
+ spu_buff[spu].buff[spu_buff[spu].head] = value;
|
||||
+ spu_buff[spu].head++;
|
||||
+
|
||||
+ if (spu_buff[spu].head >= max_spu_buff)
|
||||
+ spu_buff[spu].head = 0;
|
||||
+ } else {
|
||||
+ /* From the user's perspective make the SPU buffer
|
||||
+ * size management/overflow look like we are using
|
||||
+ * per cpu buffers. The user uses the same
|
||||
+ * per cpu parameter to adjust the SPU buffer size.
|
||||
+ * Increment the sample_lost_overflow to inform
|
||||
+ * the user the buffer size needs to be increased.
|
||||
+ */
|
||||
+ oprofile_cpu_buffer_inc_smpl_lost();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* This function copies the per SPU buffers to the
|
||||
+ * OProfile kernel buffer.
|
||||
+ */
|
||||
+void sync_spu_buff(void)
|
||||
+{
|
||||
+ int spu;
|
||||
+ unsigned long flags;
|
||||
+ int curr_head;
|
||||
+
|
||||
+ for (spu = 0; spu < num_spu_nodes; spu++) {
|
||||
+ /* In case there was an issue and the buffer didn't
|
||||
+ * get created skip it.
|
||||
+ */
|
||||
+ if (spu_buff[spu].buff == NULL)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Hold the lock to make sure the head/tail
|
||||
+ * doesn't change while spu_buff_add() is
|
||||
+ * deciding if the buffer is full or not.
|
||||
+ * Being a little paranoid.
|
||||
+ */
|
||||
+ spin_lock_irqsave(&buffer_lock, flags);
|
||||
+ curr_head = spu_buff[spu].head;
|
||||
+ spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
+
|
||||
+ /* Transfer the current contents to the kernel buffer.
|
||||
+ * data can still be added to the head of the buffer.
|
||||
+ */
|
||||
+ oprofile_put_buff(spu_buff[spu].buff,
|
||||
+ spu_buff[spu].tail,
|
||||
+ curr_head, max_spu_buff);
|
||||
+
|
||||
+ spin_lock_irqsave(&buffer_lock, flags);
|
||||
+ spu_buff[spu].tail = curr_head;
|
||||
+ spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static void wq_sync_spu_buff(struct work_struct *work)
|
||||
+{
|
||||
+ /* move data from spu buffers to kernel buffer */
|
||||
+ sync_spu_buff();
|
||||
+
|
||||
+ /* only reschedule if profiling is not done */
|
||||
+ if (spu_prof_running)
|
||||
+ schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE);
|
||||
+}
|
||||
|
||||
/* Container for caching information about an active SPU task. */
|
||||
struct cached_info {
|
||||
@@ -305,14 +400,21 @@ static int process_context_switch(struct
|
||||
|
||||
/* Record context info in event buffer */
|
||||
spin_lock_irqsave(&buffer_lock, flags);
|
||||
- add_event_entry(ESCAPE_CODE);
|
||||
- add_event_entry(SPU_CTX_SWITCH_CODE);
|
||||
- add_event_entry(spu->number);
|
||||
- add_event_entry(spu->pid);
|
||||
- add_event_entry(spu->tgid);
|
||||
- add_event_entry(app_dcookie);
|
||||
- add_event_entry(spu_cookie);
|
||||
- add_event_entry(offset);
|
||||
+ spu_buff_add(ESCAPE_CODE, spu->number);
|
||||
+ spu_buff_add(SPU_CTX_SWITCH_CODE, spu->number);
|
||||
+ spu_buff_add(spu->number, spu->number);
|
||||
+ spu_buff_add(spu->pid, spu->number);
|
||||
+ spu_buff_add(spu->tgid, spu->number);
|
||||
+ spu_buff_add(app_dcookie, spu->number);
|
||||
+ spu_buff_add(spu_cookie, spu->number);
|
||||
+ spu_buff_add(offset, spu->number);
|
||||
+
|
||||
+ /* Set flag to indicate SPU PC data can now be written out. If
|
||||
+ * the SPU program counter data is seen before an SPU context
|
||||
+ * record is seen, the postprocessing will fail.
|
||||
+ */
|
||||
+ spu_buff[spu->number].ctx_sw_seen = 1;
|
||||
+
|
||||
spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
smp_wmb(); /* insure spu event buffer updates are written */
|
||||
/* don't want entries intermingled... */
|
||||
@@ -360,6 +462,47 @@ static int number_of_online_nodes(void)
|
||||
return nodes;
|
||||
}
|
||||
|
||||
+static int oprofile_spu_buff_create(void)
|
||||
+{
|
||||
+ int spu;
|
||||
+
|
||||
+ max_spu_buff = oprofile_get_cpu_buffer_size();
|
||||
+
|
||||
+ for (spu = 0; spu < num_spu_nodes; spu++) {
|
||||
+ /* create circular buffers to store the data in.
|
||||
+ * use locks to manage accessing the buffers
|
||||
+ */
|
||||
+ spu_buff[spu].head = 0;
|
||||
+ spu_buff[spu].tail = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Create a buffer for each SPU. Can't reliably
|
||||
+ * create a single buffer for all spus due to not
|
||||
+ * enough contiguous kernel memory.
|
||||
+ */
|
||||
+
|
||||
+ spu_buff[spu].buff = kzalloc((max_spu_buff
|
||||
+ * sizeof(unsigned long)),
|
||||
+ GFP_KERNEL);
|
||||
+
|
||||
+ if (!spu_buff[spu].buff) {
|
||||
+ printk(KERN_ERR "SPU_PROF: "
|
||||
+ "%s, line %d: oprofile_spu_buff_create "
|
||||
+ "failed to allocate spu buffer %d.\n",
|
||||
+ __func__, __LINE__, spu);
|
||||
+
|
||||
+ /* release the spu buffers that have been allocated */
|
||||
+ while (spu >= 0) {
|
||||
+ kfree(spu_buff[spu].buff);
|
||||
+ spu_buff[spu].buff = 0;
|
||||
+ spu--;
|
||||
+ }
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* The main purpose of this function is to synchronize
|
||||
* OProfile with SPUFS by registering to be notified of
|
||||
* SPU task switches.
|
||||
@@ -372,20 +515,35 @@ static int number_of_online_nodes(void)
|
||||
*/
|
||||
int spu_sync_start(void)
|
||||
{
|
||||
- int k;
|
||||
+ int spu;
|
||||
int ret = SKIP_GENERIC_SYNC;
|
||||
int register_ret;
|
||||
unsigned long flags = 0;
|
||||
|
||||
spu_prof_num_nodes = number_of_online_nodes();
|
||||
num_spu_nodes = spu_prof_num_nodes * 8;
|
||||
+ INIT_DELAYED_WORK(&spu_work, wq_sync_spu_buff);
|
||||
+
|
||||
+ /* create buffer for storing the SPU data to put in
|
||||
+ * the kernel buffer.
|
||||
+ */
|
||||
+ ret = oprofile_spu_buff_create();
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
|
||||
spin_lock_irqsave(&buffer_lock, flags);
|
||||
- add_event_entry(ESCAPE_CODE);
|
||||
- add_event_entry(SPU_PROFILING_CODE);
|
||||
- add_event_entry(num_spu_nodes);
|
||||
+ for (spu = 0; spu < num_spu_nodes; spu++) {
|
||||
+ spu_buff_add(ESCAPE_CODE, spu);
|
||||
+ spu_buff_add(SPU_PROFILING_CODE, spu);
|
||||
+ spu_buff_add(num_spu_nodes, spu);
|
||||
+ }
|
||||
spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
|
||||
+ for (spu = 0; spu < num_spu_nodes; spu++) {
|
||||
+ spu_buff[spu].ctx_sw_seen = 0;
|
||||
+ spu_buff[spu].last_guard_val = 0;
|
||||
+ }
|
||||
+
|
||||
/* Register for SPU events */
|
||||
register_ret = spu_switch_event_register(&spu_active);
|
||||
if (register_ret) {
|
||||
@@ -393,8 +551,6 @@ int spu_sync_start(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- for (k = 0; k < (MAX_NUMNODES * 8); k++)
|
||||
- last_guard_val[k] = 0;
|
||||
pr_debug("spu_sync_start -- running.\n");
|
||||
out:
|
||||
return ret;
|
||||
@@ -446,13 +602,20 @@ void spu_sync_buffer(int spu_num, unsign
|
||||
* use. We need to discard samples taken during the time
|
||||
* period which an overlay occurs (i.e., guard value changes).
|
||||
*/
|
||||
- if (grd_val && grd_val != last_guard_val[spu_num]) {
|
||||
- last_guard_val[spu_num] = grd_val;
|
||||
+ if (grd_val && grd_val != spu_buff[spu_num].last_guard_val) {
|
||||
+ spu_buff[spu_num].last_guard_val = grd_val;
|
||||
/* Drop the rest of the samples. */
|
||||
break;
|
||||
}
|
||||
|
||||
- add_event_entry(file_offset | spu_num_shifted);
|
||||
+ /* We must ensure that the SPU context switch has been written
|
||||
+ * out before samples for the SPU. Otherwise, the SPU context
|
||||
+ * information is not available and the postprocessing of the
|
||||
+ * SPU PC will fail with no available anonymous map information.
|
||||
+ */
|
||||
+ if (spu_buff[spu_num].ctx_sw_seen)
|
||||
+ spu_buff_add((file_offset | spu_num_shifted),
|
||||
+ spu_num);
|
||||
}
|
||||
spin_unlock(&buffer_lock);
|
||||
out:
|
||||
@@ -463,20 +626,41 @@ out:
|
||||
int spu_sync_stop(void)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
- int ret = spu_switch_event_unregister(&spu_active);
|
||||
- if (ret) {
|
||||
+ int ret;
|
||||
+ int k;
|
||||
+
|
||||
+ ret = spu_switch_event_unregister(&spu_active);
|
||||
+
|
||||
+ if (ret)
|
||||
printk(KERN_ERR "SPU_PROF: "
|
||||
- "%s, line %d: spu_switch_event_unregister returned %d\n",
|
||||
- __func__, __LINE__, ret);
|
||||
- goto out;
|
||||
- }
|
||||
+ "%s, line %d: spu_switch_event_unregister " \
|
||||
+ "returned %d\n",
|
||||
+ __func__, __LINE__, ret);
|
||||
+
|
||||
+ /* flush any remaining data in the per SPU buffers */
|
||||
+ sync_spu_buff();
|
||||
|
||||
spin_lock_irqsave(&cache_lock, flags);
|
||||
ret = release_cached_info(RELEASE_ALL);
|
||||
spin_unlock_irqrestore(&cache_lock, flags);
|
||||
-out:
|
||||
+
|
||||
+ /* remove scheduled work queue item rather then waiting
|
||||
+ * for every queued entry to execute. Then flush pending
|
||||
+ * system wide buffer to event buffer.
|
||||
+ */
|
||||
+ cancel_delayed_work(&spu_work);
|
||||
+
|
||||
+ for (k = 0; k < num_spu_nodes; k++) {
|
||||
+ spu_buff[k].ctx_sw_seen = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * spu_sys_buff will be null if there was a problem
|
||||
+ * allocating the buffer. Only delete if it exists.
|
||||
+ */
|
||||
+ kfree(spu_buff[k].buff);
|
||||
+ spu_buff[k].buff = 0;
|
||||
+ }
|
||||
pr_debug("spu_sync_stop -- done.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
-
|
||||
--- a/drivers/oprofile/buffer_sync.c
|
||||
+++ b/drivers/oprofile/buffer_sync.c
|
||||
@@ -551,3 +551,27 @@ void sync_buffer(int cpu)
|
||||
|
||||
mutex_unlock(&buffer_mutex);
|
||||
}
|
||||
+
|
||||
+/* The function can be used to add a buffer worth of data directly to
|
||||
+ * the kernel buffer. The buffer is assumed to be a circular buffer.
|
||||
+ * Take the entries from index start and end at index end, wrapping
|
||||
+ * at max_entries.
|
||||
+ */
|
||||
+void oprofile_put_buff(unsigned long *buf, unsigned int start,
|
||||
+ unsigned int stop, unsigned int max)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ i = start;
|
||||
+
|
||||
+ mutex_lock(&buffer_mutex);
|
||||
+ while (i != stop) {
|
||||
+ add_event_entry(buf[i++]);
|
||||
+
|
||||
+ if (i >= max)
|
||||
+ i = 0;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&buffer_mutex);
|
||||
+}
|
||||
+
|
||||
--- a/drivers/oprofile/cpu_buffer.c
|
||||
+++ b/drivers/oprofile/cpu_buffer.c
|
||||
@@ -37,13 +37,26 @@ static int work_enabled;
|
||||
void free_cpu_buffers(void)
|
||||
{
|
||||
int i;
|
||||
-
|
||||
+
|
||||
for_each_online_cpu(i) {
|
||||
vfree(per_cpu(cpu_buffer, i).buffer);
|
||||
per_cpu(cpu_buffer, i).buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+unsigned long oprofile_get_cpu_buffer_size(void)
|
||||
+{
|
||||
+ return fs_cpu_buffer_size;
|
||||
+}
|
||||
+
|
||||
+void oprofile_cpu_buffer_inc_smpl_lost(void)
|
||||
+{
|
||||
+ struct oprofile_cpu_buffer *cpu_buf
|
||||
+ = &__get_cpu_var(cpu_buffer);
|
||||
+
|
||||
+ cpu_buf->sample_lost_overflow++;
|
||||
+}
|
||||
+
|
||||
int alloc_cpu_buffers(void)
|
||||
{
|
||||
int i;
|
||||
--- a/drivers/oprofile/event_buffer.h
|
||||
+++ b/drivers/oprofile/event_buffer.h
|
||||
@@ -17,6 +17,13 @@ int alloc_event_buffer(void);
|
||||
|
||||
void free_event_buffer(void);
|
||||
|
||||
+/**
|
||||
+ * Add data to the event buffer.
|
||||
+ * The data passed is free-form, but typically consists of
|
||||
+ * file offsets, dcookies, context information, and ESCAPE codes.
|
||||
+ */
|
||||
+void add_event_entry(unsigned long data);
|
||||
+
|
||||
/* wake up the process sleeping on the event file */
|
||||
void wake_up_buffer_waiter(void);
|
||||
|
||||
--- a/include/linux/oprofile.h
|
||||
+++ b/include/linux/oprofile.h
|
||||
@@ -84,13 +84,6 @@ int oprofile_arch_init(struct oprofile_o
|
||||
void oprofile_arch_exit(void);
|
||||
|
||||
/**
|
||||
- * Add data to the event buffer.
|
||||
- * The data passed is free-form, but typically consists of
|
||||
- * file offsets, dcookies, context information, and ESCAPE codes.
|
||||
- */
|
||||
-void add_event_entry(unsigned long data);
|
||||
-
|
||||
-/**
|
||||
* Add a sample. This may be called from any context. Pass
|
||||
* smp_processor_id() as cpu.
|
||||
*/
|
||||
@@ -160,5 +153,14 @@ int oprofilefs_ulong_from_user(unsigned
|
||||
|
||||
/** lock for read/write safety */
|
||||
extern spinlock_t oprofilefs_lock;
|
||||
+
|
||||
+/**
|
||||
+ * Add the contents of a circular buffer to the event buffer.
|
||||
+ */
|
||||
+void oprofile_put_buff(unsigned long *buf, unsigned int start,
|
||||
+ unsigned int stop, unsigned int max);
|
||||
+
|
||||
+unsigned long oprofile_get_cpu_buffer_size(void);
|
||||
+void oprofile_cpu_buffer_inc_smpl_lost(void);
|
||||
|
||||
#endif /* OPROFILE_H */
|
||||
@@ -0,0 +1,64 @@
|
||||
Subject: Incorrect local array size in activate spu profiling function
|
||||
From: Carl Love <carll@us.ibm.com>
|
||||
References: 439553 - LTC48925
|
||||
|
||||
Updated the patch to address comments by Michael Ellerman.
|
||||
Specifically, changed upper limit in for loop to
|
||||
ARRAY_SIZE() macro and added a check to make sure the
|
||||
number of events specified by the user, which is used as
|
||||
the max for indexing various arrays, is no bigger then the
|
||||
declared size of the arrays.
|
||||
|
||||
The size of the pm_signal_local array should be equal to the
|
||||
number of SPUs being configured in the array. Currently, the
|
||||
array is of size 4 (NR_PHYS_CTRS) but being indexed by a for
|
||||
loop from 0 to 7 (NUM_SPUS_PER_NODE).
|
||||
|
||||
Signed-off-by: Carl Love <carll@us.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/oprofile/op_model_cell.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/oprofile/op_model_cell.c
|
||||
+++ b/arch/powerpc/oprofile/op_model_cell.c
|
||||
@@ -582,6 +582,13 @@ static int cell_reg_setup(struct op_coun
|
||||
|
||||
num_counters = num_ctrs;
|
||||
|
||||
+ if (unlikely(num_ctrs > NR_PHYS_CTRS)) {
|
||||
+ printk(KERN_ERR
|
||||
+ "%s: Oprofile, number of specified events " \
|
||||
+ "exceeds number of physical counters\n",
|
||||
+ __func__);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
pm_regs.group_control = 0;
|
||||
pm_regs.debug_bus_control = 0;
|
||||
|
||||
@@ -830,13 +837,13 @@ static int calculate_lfsr(int n)
|
||||
static int pm_rtas_activate_spu_profiling(u32 node)
|
||||
{
|
||||
int ret, i;
|
||||
- struct pm_signal pm_signal_local[NR_PHYS_CTRS];
|
||||
+ struct pm_signal pm_signal_local[NUM_SPUS_PER_NODE];
|
||||
|
||||
/*
|
||||
* Set up the rtas call to configure the debug bus to
|
||||
* route the SPU PCs. Setup the pm_signal for each SPU
|
||||
*/
|
||||
- for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(pm_signal_local); i++) {
|
||||
pm_signal_local[i].cpu = node;
|
||||
pm_signal_local[i].signal_group = 41;
|
||||
/* spu i on word (i/2) */
|
||||
@@ -848,7 +855,7 @@ static int pm_rtas_activate_spu_profilin
|
||||
|
||||
ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
|
||||
PASSTHRU_ENABLE, pm_signal_local,
|
||||
- (NUM_SPUS_PER_NODE
|
||||
+ (ARRAY_SIZE(pm_signal_local)
|
||||
* sizeof(struct pm_signal)));
|
||||
|
||||
if (unlikely(ret)) {
|
||||
240
src/patches/suse-2.6.27.25/patches.arch/ppc-optimize-sync.patch
Normal file
240
src/patches/suse-2.6.27.25/patches.arch/ppc-optimize-sync.patch
Normal file
@@ -0,0 +1,240 @@
|
||||
Subject: Optimise smp_{r,w}mb and mutex
|
||||
From: Nick Piggin <npiggin@suse.de>
|
||||
References: 471222 - LTC51356
|
||||
|
||||
powerpc: Optimise smp_wmb
|
||||
|
||||
Change 2d1b2027626d5151fff8ef7c06ca8e7876a1a510 ("powerpc: Fixup
|
||||
lwsync at runtime") removed __SUBARCH_HAS_LWSYNC, causing smp_wmb to
|
||||
revert back to eieio for all CPUs. This restores the behaviour
|
||||
intorduced in 74f0609526afddd88bef40b651da24f3167b10b2 ("powerpc:
|
||||
Optimise smp_wmb on 64-bit processors").
|
||||
|
||||
powerpc: Optimise smp_rmb
|
||||
|
||||
After commit 598056d5af8fef1dbe8f96f5c2b641a528184e5a ("[POWERPC] Fix
|
||||
rmb to order cacheable vs. noncacheable"), rmb() becomes a sync
|
||||
instruction, which is needed to order cacheable vs noncacheable loads.
|
||||
However smp_rmb() is #defined to rmb(), and smp_rmb() can be an
|
||||
lwsync.
|
||||
|
||||
This restores smp_rmb() performance by using lwsync there and updates
|
||||
the comments.
|
||||
|
||||
powerpc: Optimise mutex
|
||||
|
||||
This implements an optimised mutex fastpath for powerpc, making use of
|
||||
acquire and release barrier semantics. This takes the mutex
|
||||
lock+unlock benchmark from 203 to 173 cycles on a G5.
|
||||
|
||||
Signed-off-by: Nick Piggin <npiggin@suse.de>
|
||||
Signed-off-by: Paul Mackerras <paulus@samba.org>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/include/asm/mutex.h | 135 ++++++++++++++++++++++++++++++++++++--
|
||||
arch/powerpc/include/asm/synch.h | 4 +
|
||||
arch/powerpc/include/asm/system.h | 24 +++---
|
||||
3 files changed, 147 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/mutex.h
|
||||
+++ b/arch/powerpc/include/asm/mutex.h
|
||||
@@ -1,9 +1,134 @@
|
||||
/*
|
||||
- * Pull in the generic implementation for the mutex fastpath.
|
||||
+ * Optimised mutex implementation of include/asm-generic/mutex-dec.h algorithm
|
||||
+ */
|
||||
+#ifndef _ASM_POWERPC_MUTEX_H
|
||||
+#define _ASM_POWERPC_MUTEX_H
|
||||
+
|
||||
+static inline int __mutex_cmpxchg_lock(atomic_t *v, int old, int new)
|
||||
+{
|
||||
+ int t;
|
||||
+
|
||||
+ __asm__ __volatile__ (
|
||||
+"1: lwarx %0,0,%1 # mutex trylock\n\
|
||||
+ cmpw 0,%0,%2\n\
|
||||
+ bne- 2f\n"
|
||||
+ PPC405_ERR77(0,%1)
|
||||
+" stwcx. %3,0,%1\n\
|
||||
+ bne- 1b"
|
||||
+ ISYNC_ON_SMP
|
||||
+ "\n\
|
||||
+2:"
|
||||
+ : "=&r" (t)
|
||||
+ : "r" (&v->counter), "r" (old), "r" (new)
|
||||
+ : "cc", "memory");
|
||||
+
|
||||
+ return t;
|
||||
+}
|
||||
+
|
||||
+static inline int __mutex_dec_return_lock(atomic_t *v)
|
||||
+{
|
||||
+ int t;
|
||||
+
|
||||
+ __asm__ __volatile__(
|
||||
+"1: lwarx %0,0,%1 # mutex lock\n\
|
||||
+ addic %0,%0,-1\n"
|
||||
+ PPC405_ERR77(0,%1)
|
||||
+" stwcx. %0,0,%1\n\
|
||||
+ bne- 1b"
|
||||
+ ISYNC_ON_SMP
|
||||
+ : "=&r" (t)
|
||||
+ : "r" (&v->counter)
|
||||
+ : "cc", "memory");
|
||||
+
|
||||
+ return t;
|
||||
+}
|
||||
+
|
||||
+static inline int __mutex_inc_return_unlock(atomic_t *v)
|
||||
+{
|
||||
+ int t;
|
||||
+
|
||||
+ __asm__ __volatile__(
|
||||
+ LWSYNC_ON_SMP
|
||||
+"1: lwarx %0,0,%1 # mutex unlock\n\
|
||||
+ addic %0,%0,1\n"
|
||||
+ PPC405_ERR77(0,%1)
|
||||
+" stwcx. %0,0,%1 \n\
|
||||
+ bne- 1b"
|
||||
+ : "=&r" (t)
|
||||
+ : "r" (&v->counter)
|
||||
+ : "cc", "memory");
|
||||
+
|
||||
+ return t;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * __mutex_fastpath_lock - try to take the lock by moving the count
|
||||
+ * from 1 to a 0 value
|
||||
+ * @count: pointer of type atomic_t
|
||||
+ * @fail_fn: function to call if the original value was not 1
|
||||
+ *
|
||||
+ * Change the count from 1 to a value lower than 1, and call <fail_fn> if
|
||||
+ * it wasn't 1 originally. This function MUST leave the value lower than
|
||||
+ * 1 even when the "1" assertion wasn't true.
|
||||
+ */
|
||||
+static inline void
|
||||
+__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
+{
|
||||
+ if (unlikely(__mutex_dec_return_lock(count) < 0))
|
||||
+ fail_fn(count);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * __mutex_fastpath_lock_retval - try to take the lock by moving the count
|
||||
+ * from 1 to a 0 value
|
||||
+ * @count: pointer of type atomic_t
|
||||
+ * @fail_fn: function to call if the original value was not 1
|
||||
+ *
|
||||
+ * Change the count from 1 to a value lower than 1, and call <fail_fn> if
|
||||
+ * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
|
||||
+ * or anything the slow path function returns.
|
||||
+ */
|
||||
+static inline int
|
||||
+__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
+{
|
||||
+ if (unlikely(__mutex_dec_return_lock(count) < 0))
|
||||
+ return fail_fn(count);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * __mutex_fastpath_unlock - try to promote the count from 0 to 1
|
||||
+ * @count: pointer of type atomic_t
|
||||
+ * @fail_fn: function to call if the original value was not 0
|
||||
+ *
|
||||
+ * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>.
|
||||
+ * In the failure case, this function is allowed to either set the value to
|
||||
+ * 1, or to set it to a value lower than 1.
|
||||
+ */
|
||||
+static inline void
|
||||
+__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||||
+{
|
||||
+ if (unlikely(__mutex_inc_return_unlock(count) <= 0))
|
||||
+ fail_fn(count);
|
||||
+}
|
||||
+
|
||||
+#define __mutex_slowpath_needs_to_unlock() 1
|
||||
+
|
||||
+/**
|
||||
+ * __mutex_fastpath_trylock - try to acquire the mutex, without waiting
|
||||
+ *
|
||||
+ * @count: pointer of type atomic_t
|
||||
+ * @fail_fn: fallback function
|
||||
*
|
||||
- * TODO: implement optimized primitives instead, or leave the generic
|
||||
- * implementation in place, or pick the atomic_xchg() based generic
|
||||
- * implementation. (see asm-generic/mutex-xchg.h for details)
|
||||
+ * Change the count from 1 to 0, and return 1 (success), or if the count
|
||||
+ * was not 1, then return 0 (failure).
|
||||
*/
|
||||
+static inline int
|
||||
+__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||||
+{
|
||||
+ if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1))
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
-#include <asm-generic/mutex-dec.h>
|
||||
+#endif
|
||||
--- a/arch/powerpc/include/asm/synch.h
|
||||
+++ b/arch/powerpc/include/asm/synch.h
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <linux/stringify.h>
|
||||
#include <asm/feature-fixups.h>
|
||||
|
||||
+#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
|
||||
+#define __SUBARCH_HAS_LWSYNC
|
||||
+#endif
|
||||
+
|
||||
#ifndef __ASSEMBLY__
|
||||
extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
|
||||
extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
|
||||
--- a/arch/powerpc/include/asm/system.h
|
||||
+++ b/arch/powerpc/include/asm/system.h
|
||||
@@ -23,15 +23,17 @@
|
||||
* read_barrier_depends() prevents data-dependent loads being reordered
|
||||
* across this point (nop on PPC).
|
||||
*
|
||||
- * We have to use the sync instructions for mb(), since lwsync doesn't
|
||||
- * order loads with respect to previous stores. Lwsync is fine for
|
||||
- * rmb(), though. Note that rmb() actually uses a sync on 32-bit
|
||||
- * architectures.
|
||||
+ * *mb() variants without smp_ prefix must order all types of memory
|
||||
+ * operations with one another. sync is the only instruction sufficient
|
||||
+ * to do this.
|
||||
*
|
||||
- * For wmb(), we use sync since wmb is used in drivers to order
|
||||
- * stores to system memory with respect to writes to the device.
|
||||
- * However, smp_wmb() can be a lighter-weight lwsync or eieio barrier
|
||||
- * on SMP since it is only used to order updates to system memory.
|
||||
+ * For the smp_ barriers, ordering is for cacheable memory operations
|
||||
+ * only. We have to use the sync instruction for smp_mb(), since lwsync
|
||||
+ * doesn't order loads with respect to previous stores. Lwsync can be
|
||||
+ * used for smp_rmb() and smp_wmb().
|
||||
+ *
|
||||
+ * However, on CPUs that don't support lwsync, lwsync actually maps to a
|
||||
+ * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
|
||||
*/
|
||||
#define mb() __asm__ __volatile__ ("sync" : : : "memory")
|
||||
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
|
||||
@@ -45,14 +47,14 @@
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#ifdef __SUBARCH_HAS_LWSYNC
|
||||
-# define SMPWMB lwsync
|
||||
+# define SMPWMB LWSYNC
|
||||
#else
|
||||
# define SMPWMB eieio
|
||||
#endif
|
||||
|
||||
#define smp_mb() mb()
|
||||
-#define smp_rmb() rmb()
|
||||
-#define smp_wmb() __asm__ __volatile__ (__stringify(SMPWMB) : : :"memory")
|
||||
+#define smp_rmb() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
|
||||
+#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
|
||||
#define smp_read_barrier_depends() read_barrier_depends()
|
||||
#else
|
||||
#define smp_mb() barrier()
|
||||
@@ -0,0 +1,178 @@
|
||||
Subject: Fix DLPAR
|
||||
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
References: 439491
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
---
|
||||
arch/powerpc/include/asm/pci.h | 2
|
||||
arch/powerpc/kernel/pci-common.c | 110 ++++++++++++++---------------
|
||||
arch/powerpc/platforms/pseries/pci_dlpar.c | 2
|
||||
3 files changed, 59 insertions(+), 55 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/pci.h
|
||||
+++ b/arch/powerpc/include/asm/pci.h
|
||||
@@ -196,6 +196,8 @@ extern void pcibios_setup_new_device(str
|
||||
|
||||
extern void pcibios_claim_one_bus(struct pci_bus *b);
|
||||
|
||||
+extern void pcibios_allocate_bus_resources(struct pci_bus *bus);
|
||||
+
|
||||
extern void pcibios_resource_survey(void);
|
||||
|
||||
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
|
||||
--- a/arch/powerpc/kernel/pci-common.c
|
||||
+++ b/arch/powerpc/kernel/pci-common.c
|
||||
@@ -986,69 +986,66 @@ static int __init reparent_resources(str
|
||||
* as well.
|
||||
*/
|
||||
|
||||
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
|
||||
+void pcibios_allocate_bus_resources(struct pci_bus *bus)
|
||||
{
|
||||
- struct pci_bus *bus;
|
||||
+ struct pci_bus *b;
|
||||
int i;
|
||||
struct resource *res, *pr;
|
||||
|
||||
- /* Depth-First Search on bus tree */
|
||||
- list_for_each_entry(bus, bus_list, node) {
|
||||
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||
- if ((res = bus->resource[i]) == NULL || !res->flags
|
||||
- || res->start > res->end)
|
||||
- continue;
|
||||
- if (bus->parent == NULL)
|
||||
- pr = (res->flags & IORESOURCE_IO) ?
|
||||
- &ioport_resource : &iomem_resource;
|
||||
- else {
|
||||
- /* Don't bother with non-root busses when
|
||||
- * re-assigning all resources. We clear the
|
||||
- * resource flags as if they were colliding
|
||||
- * and as such ensure proper re-allocation
|
||||
- * later.
|
||||
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||
+ if ((res = bus->resource[i]) == NULL || !res->flags
|
||||
+ || res->start > res->end)
|
||||
+ continue;
|
||||
+ if (bus->parent == NULL)
|
||||
+ pr = (res->flags & IORESOURCE_IO) ?
|
||||
+ &ioport_resource : &iomem_resource;
|
||||
+ else {
|
||||
+ /* Don't bother with non-root busses when
|
||||
+ * re-assigning all resources. We clear the
|
||||
+ * resource flags as if they were colliding
|
||||
+ * and as such ensure proper re-allocation
|
||||
+ * later.
|
||||
+ */
|
||||
+ if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
|
||||
+ goto clear_resource;
|
||||
+ pr = pci_find_parent_resource(bus->self, res);
|
||||
+ if (pr == res) {
|
||||
+ /* this happens when the generic PCI
|
||||
+ * code (wrongly) decides that this
|
||||
+ * bridge is transparent -- paulus
|
||||
*/
|
||||
- if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)
|
||||
- goto clear_resource;
|
||||
- pr = pci_find_parent_resource(bus->self, res);
|
||||
- if (pr == res) {
|
||||
- /* this happens when the generic PCI
|
||||
- * code (wrongly) decides that this
|
||||
- * bridge is transparent -- paulus
|
||||
- */
|
||||
- continue;
|
||||
- }
|
||||
+ continue;
|
||||
}
|
||||
+ }
|
||||
|
||||
- DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
|
||||
- "[0x%x], parent %p (%s)\n",
|
||||
- bus->self ? pci_name(bus->self) : "PHB",
|
||||
- bus->number, i,
|
||||
- (unsigned long long)res->start,
|
||||
- (unsigned long long)res->end,
|
||||
- (unsigned int)res->flags,
|
||||
- pr, (pr && pr->name) ? pr->name : "nil");
|
||||
-
|
||||
- if (pr && !(pr->flags & IORESOURCE_UNSET)) {
|
||||
- if (request_resource(pr, res) == 0)
|
||||
- continue;
|
||||
- /*
|
||||
- * Must be a conflict with an existing entry.
|
||||
- * Move that entry (or entries) under the
|
||||
- * bridge resource and try again.
|
||||
- */
|
||||
- if (reparent_resources(pr, res) == 0)
|
||||
- continue;
|
||||
- }
|
||||
- printk(KERN_WARNING
|
||||
- "PCI: Cannot allocate resource region "
|
||||
- "%d of PCI bridge %d, will remap\n",
|
||||
- i, bus->number);
|
||||
-clear_resource:
|
||||
- res->flags = 0;
|
||||
+ DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
|
||||
+ "[0x%x], parent %p (%s)\n",
|
||||
+ bus->self ? pci_name(bus->self) : "PHB",
|
||||
+ bus->number, i,
|
||||
+ (unsigned long long)res->start,
|
||||
+ (unsigned long long)res->end,
|
||||
+ (unsigned int)res->flags,
|
||||
+ pr, (pr && pr->name) ? pr->name : "nil");
|
||||
+
|
||||
+ if (pr && !(pr->flags & IORESOURCE_UNSET)) {
|
||||
+ if (request_resource(pr, res) == 0)
|
||||
+ continue;
|
||||
+ /*
|
||||
+ * Must be a conflict with an existing entry.
|
||||
+ * Move that entry (or entries) under the
|
||||
+ * bridge resource and try again.
|
||||
+ */
|
||||
+ if (reparent_resources(pr, res) == 0)
|
||||
+ continue;
|
||||
}
|
||||
- pcibios_allocate_bus_resources(&bus->children);
|
||||
+ printk(KERN_WARNING "PCI: Cannot allocate resource region "
|
||||
+ "%d of PCI bridge %d, will remap\n", i, bus->number);
|
||||
+clear_resource:
|
||||
+ res->flags = 0;
|
||||
}
|
||||
+
|
||||
+ list_for_each_entry(b, &bus->children, node)
|
||||
+ pcibios_allocate_bus_resources(b);
|
||||
}
|
||||
|
||||
static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
|
||||
@@ -1119,10 +1116,13 @@ static void __init pcibios_allocate_reso
|
||||
|
||||
void __init pcibios_resource_survey(void)
|
||||
{
|
||||
+ struct pci_bus *b;
|
||||
+
|
||||
/* Allocate and assign resources. If we re-assign everything, then
|
||||
* we skip the allocate phase
|
||||
*/
|
||||
- pcibios_allocate_bus_resources(&pci_root_buses);
|
||||
+ list_for_each_entry(b, &pci_root_buses, node)
|
||||
+ pcibios_allocate_bus_resources(b);
|
||||
|
||||
if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) {
|
||||
pcibios_allocate_resources(0);
|
||||
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
|
||||
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
|
||||
@@ -189,6 +189,7 @@ struct pci_controller * __devinit init_p
|
||||
{
|
||||
struct pci_controller *phb;
|
||||
int primary;
|
||||
+ struct pci_bus *b;
|
||||
|
||||
primary = list_empty(&hose_list);
|
||||
phb = pcibios_alloc_controller(dn);
|
||||
@@ -203,6 +204,7 @@ struct pci_controller * __devinit init_p
|
||||
eeh_add_device_tree_early(dn);
|
||||
|
||||
scan_phb(phb);
|
||||
+ pcibios_allocate_bus_resources(phb->bus);
|
||||
pcibios_fixup_new_pci_devices(phb->bus);
|
||||
pci_bus_add_devices(phb->bus);
|
||||
eeh_add_device_tree_late(phb->bus);
|
||||
@@ -0,0 +1,19 @@
|
||||
From: olh@suse.de
|
||||
Subject: force speed to fix autodetection on pegasos2
|
||||
Patch-mainline: never
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/chrp/setup.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/chrp/setup.c
|
||||
+++ b/arch/powerpc/platforms/chrp/setup.c
|
||||
@@ -295,7 +295,7 @@ static void chrp_init_early(void)
|
||||
if (!property)
|
||||
goto out_put;
|
||||
if (!strcmp(property, "failsafe") || !strcmp(property, "serial"))
|
||||
- add_preferred_console("ttyS", 0, NULL);
|
||||
+ add_preferred_console("ttyS", 0, "115200");
|
||||
out_put:
|
||||
of_node_put(node);
|
||||
}
|
||||
@@ -0,0 +1,834 @@
|
||||
Subject: Fix DLPAR
|
||||
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
References: 439491
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
---
|
||||
arch/powerpc/include/asm/pci-bridge.h | 4
|
||||
arch/powerpc/include/asm/pci.h | 10 +
|
||||
arch/powerpc/kernel/pci-common.c | 124 ++++++++++++----------
|
||||
arch/powerpc/kernel/pci_32.c | 6 -
|
||||
arch/powerpc/kernel/pci_64.c | 27 +++-
|
||||
arch/powerpc/kernel/rtas_pci.c | 48 --------
|
||||
arch/powerpc/platforms/pseries/eeh.c | 44 ++++---
|
||||
arch/powerpc/platforms/pseries/pci_dlpar.c | 163 +++++++++++++++--------------
|
||||
drivers/pci/hotplug/rpadlpar_core.c | 49 +++++---
|
||||
drivers/pci/hotplug/rpaphp_slot.c | 4
|
||||
10 files changed, 245 insertions(+), 234 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/pci-bridge.h
|
||||
+++ b/arch/powerpc/include/asm/pci-bridge.h
|
||||
@@ -234,9 +234,7 @@ extern void pcibios_remove_pci_devices(s
|
||||
|
||||
/** Discover new pci devices under this bus, and add them */
|
||||
extern void pcibios_add_pci_devices(struct pci_bus *bus);
|
||||
-extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus);
|
||||
-
|
||||
-extern int pcibios_remove_root_bus(struct pci_controller *phb);
|
||||
+extern void pcibios_finish_adding_new_bus(struct pci_bus *bus);
|
||||
|
||||
static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
|
||||
{
|
||||
--- a/arch/powerpc/include/asm/pci.h
|
||||
+++ b/arch/powerpc/include/asm/pci.h
|
||||
@@ -201,6 +201,7 @@ extern void pcibios_allocate_bus_resourc
|
||||
extern void pcibios_resource_survey(void);
|
||||
|
||||
extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
|
||||
+extern int remove_phb_dynamic(struct pci_controller *phb);
|
||||
|
||||
extern struct pci_dev *of_create_pci_dev(struct device_node *node,
|
||||
struct pci_bus *bus, int devfn);
|
||||
@@ -208,7 +209,8 @@ extern struct pci_dev *of_create_pci_dev
|
||||
extern void of_scan_pci_bridge(struct device_node *node,
|
||||
struct pci_dev *dev);
|
||||
|
||||
-extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
|
||||
+extern void of_scan_bus(struct device_node *node, struct pci_bus *bus,
|
||||
+ int rescan_existing);
|
||||
|
||||
extern int pci_read_irq_line(struct pci_dev *dev);
|
||||
|
||||
@@ -223,8 +225,10 @@ extern void pci_resource_to_user(const s
|
||||
const struct resource *rsrc,
|
||||
resource_size_t *start, resource_size_t *end);
|
||||
|
||||
-extern void pcibios_do_bus_setup(struct pci_bus *bus);
|
||||
-extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus);
|
||||
+extern void pcibios_do_bus_setup_self(struct pci_bus *bus);
|
||||
+extern void pcibios_do_bus_setup_devices(struct pci_bus *bus);
|
||||
+extern void pcibios_fixup_bus_self(struct pci_bus *bus);
|
||||
+extern void pcibios_fixup_bus_devices(struct pci_bus *bus);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __ASM_POWERPC_PCI_H */
|
||||
--- a/arch/powerpc/kernel/pci_32.c
|
||||
+++ b/arch/powerpc/kernel/pci_32.c
|
||||
@@ -418,7 +418,7 @@ static int __init pcibios_init(void)
|
||||
|
||||
subsys_initcall(pcibios_init);
|
||||
|
||||
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
|
||||
+void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
|
||||
unsigned long io_offset;
|
||||
@@ -459,6 +459,10 @@ void __devinit pcibios_do_bus_setup(stru
|
||||
}
|
||||
}
|
||||
|
||||
+void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
/* the next one is stolen from the alpha port... */
|
||||
void __init
|
||||
pcibios_update_irq(struct pci_dev *dev, int irq)
|
||||
--- a/arch/powerpc/kernel/pci_64.c
|
||||
+++ b/arch/powerpc/kernel/pci_64.c
|
||||
@@ -225,14 +225,16 @@ struct pci_dev *of_create_pci_dev(struct
|
||||
EXPORT_SYMBOL(of_create_pci_dev);
|
||||
|
||||
void __devinit of_scan_bus(struct device_node *node,
|
||||
- struct pci_bus *bus)
|
||||
+ struct pci_bus *bus,
|
||||
+ int rescan_existing)
|
||||
{
|
||||
struct device_node *child;
|
||||
const u32 *reg;
|
||||
int reglen, devfn;
|
||||
struct pci_dev *dev;
|
||||
|
||||
- DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
|
||||
+ DBG("of_scan_bus(%s) %s bus no %d... \n", node->full_name,
|
||||
+ rescan_existing ? "existing" : "new", bus->number);
|
||||
|
||||
/* Scan direct children */
|
||||
for_each_child_of_node(node, child) {
|
||||
@@ -249,8 +251,12 @@ void __devinit of_scan_bus(struct device
|
||||
DBG(" dev header type: %x\n", dev->hdr_type);
|
||||
}
|
||||
|
||||
- /* Ally all fixups */
|
||||
- pcibios_fixup_of_probed_bus(bus);
|
||||
+ /* Apply all fixups necessary. We don't fixup the bus "self"
|
||||
+ * for an existing bridge that is being rescanned
|
||||
+ */
|
||||
+ if (!rescan_existing)
|
||||
+ pcibios_fixup_bus_self(bus);
|
||||
+ pcibios_fixup_bus_devices(bus);
|
||||
|
||||
/* Now scan child busses */
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
@@ -346,7 +352,7 @@ void __devinit of_scan_pci_bridge(struct
|
||||
DBG(" probe mode: %d\n", mode);
|
||||
|
||||
if (mode == PCI_PROBE_DEVTREE)
|
||||
- of_scan_bus(node, bus);
|
||||
+ of_scan_bus(node, bus, 0);
|
||||
else if (mode == PCI_PROBE_NORMAL)
|
||||
pci_scan_child_bus(bus);
|
||||
}
|
||||
@@ -396,7 +402,7 @@ void __devinit scan_phb(struct pci_contr
|
||||
DBG(" probe mode: %d\n", mode);
|
||||
if (mode == PCI_PROBE_DEVTREE) {
|
||||
bus->subordinate = hose->last_busno;
|
||||
- of_scan_bus(node, bus);
|
||||
+ of_scan_bus(node, bus, 0);
|
||||
}
|
||||
|
||||
if (mode == PCI_PROBE_NORMAL)
|
||||
@@ -568,12 +574,15 @@ void __devinit pcibios_setup_new_device(
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_setup_new_device);
|
||||
|
||||
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
|
||||
+void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus)
|
||||
{
|
||||
- struct pci_dev *dev;
|
||||
-
|
||||
if (ppc_md.pci_dma_bus_setup)
|
||||
ppc_md.pci_dma_bus_setup(bus);
|
||||
+}
|
||||
+
|
||||
+void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus)
|
||||
+{
|
||||
+ struct pci_dev *dev;
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list)
|
||||
pcibios_setup_new_device(dev);
|
||||
--- a/arch/powerpc/kernel/pci-common.c
|
||||
+++ b/arch/powerpc/kernel/pci-common.c
|
||||
@@ -789,63 +789,78 @@ static void __devinit pcibios_fixup_reso
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
|
||||
|
||||
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
|
||||
+void __devinit pcibios_fixup_bus_self(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_controller *hose = pci_bus_to_host(bus);
|
||||
struct pci_dev *dev = bus->self;
|
||||
+ struct resource *res;
|
||||
+ int i;
|
||||
|
||||
- pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
|
||||
+ pr_debug("PCI: Fixup bus resources %d (%s)\n",
|
||||
+ bus->number, dev ? pci_name(dev) : "PHB");
|
||||
|
||||
/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
|
||||
* now differently between 32 and 64 bits.
|
||||
*/
|
||||
- if (dev != NULL) {
|
||||
- struct resource *res;
|
||||
- int i;
|
||||
-
|
||||
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||
- if ((res = bus->resource[i]) == NULL)
|
||||
- continue;
|
||||
- if (!res->flags)
|
||||
- continue;
|
||||
- if (i >= 3 && bus->self->transparent)
|
||||
- continue;
|
||||
- /* On PowerMac, Apple leaves bridge windows open over
|
||||
- * an inaccessible region of memory space (0...fffff)
|
||||
- * which is somewhat bogus, but that's what they think
|
||||
- * means disabled...
|
||||
- *
|
||||
- * We clear those to force them to be reallocated later
|
||||
- *
|
||||
- * We detect such regions by the fact that the base is
|
||||
- * equal to the pci_mem_offset of the host bridge and
|
||||
- * their size is smaller than 1M.
|
||||
- */
|
||||
- if (res->flags & IORESOURCE_MEM &&
|
||||
- res->start == hose->pci_mem_offset &&
|
||||
- res->end < 0x100000) {
|
||||
- printk(KERN_INFO
|
||||
- "PCI: Closing bogus Apple Firmware"
|
||||
- " region %d on bus 0x%02x\n",
|
||||
- i, bus->number);
|
||||
- res->flags = 0;
|
||||
- continue;
|
||||
- }
|
||||
+ if (dev == NULL)
|
||||
+ goto host_bridge;
|
||||
|
||||
- pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
|
||||
- pci_name(dev), i,
|
||||
- (unsigned long long)res->start,\
|
||||
- (unsigned long long)res->end,
|
||||
- (unsigned int)res->flags);
|
||||
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||
+ if ((res = bus->resource[i]) == NULL)
|
||||
+ continue;
|
||||
+ if (!res->flags)
|
||||
+ continue;
|
||||
+ if (i >= 3 && bus->self->transparent)
|
||||
+ continue;
|
||||
|
||||
- fixup_resource(res, dev);
|
||||
+ /* On PowerMac, Apple leaves bridge windows open over
|
||||
+ * an inaccessible region of memory space (0...fffff)
|
||||
+ * which is somewhat bogus, but that's what they think
|
||||
+ * means disabled...
|
||||
+ *
|
||||
+ * We clear those to force them to be reallocated later
|
||||
+ *
|
||||
+ * We detect such regions by the fact that the base is
|
||||
+ * equal to the pci_mem_offset of the host bridge and
|
||||
+ * their size is smaller than 1M.
|
||||
+ */
|
||||
+ if (res->flags & IORESOURCE_MEM &&
|
||||
+ res->start == hose->pci_mem_offset &&
|
||||
+ res->end < 0x100000) {
|
||||
+ printk(KERN_INFO
|
||||
+ "PCI: Closing bogus Apple Firmware"
|
||||
+ " region %d on bus 0x%02x\n",
|
||||
+ i, bus->number);
|
||||
+ res->flags = 0;
|
||||
+ continue;
|
||||
}
|
||||
+
|
||||
+ pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
|
||||
+ pci_name(dev), i,
|
||||
+ (unsigned long long)res->start,\
|
||||
+ (unsigned long long)res->end,
|
||||
+ (unsigned int)res->flags);
|
||||
+
|
||||
+ fixup_resource(res, dev);
|
||||
}
|
||||
|
||||
+host_bridge:
|
||||
+
|
||||
+ /* Additional setup that is different between 32 and 64 bits for now */
|
||||
+ pcibios_do_bus_setup_self(bus);
|
||||
+}
|
||||
+
|
||||
+void __devinit pcibios_fixup_bus_devices(struct pci_bus *bus)
|
||||
+{
|
||||
+ struct pci_dev *dev = bus->self;
|
||||
+
|
||||
+ pr_debug("PCI: Fixup bus devices %d (%s)\n",
|
||||
+ bus->number, dev ? pci_name(dev) : "PHB");
|
||||
+
|
||||
/* Additional setup that is different between 32 and 64 bits for now */
|
||||
- pcibios_do_bus_setup(bus);
|
||||
+ pcibios_do_bus_setup_devices(bus);
|
||||
|
||||
- /* Platform specific bus fixups */
|
||||
+ /* Platform specific bus fixups (XXX Get rid of these !) */
|
||||
if (ppc_md.pcibios_fixup_bus)
|
||||
ppc_md.pcibios_fixup_bus(bus);
|
||||
|
||||
@@ -864,19 +879,11 @@ void __devinit pcibios_fixup_bus(struct
|
||||
*/
|
||||
if (bus->self != NULL)
|
||||
pci_read_bridge_bases(bus);
|
||||
- __pcibios_fixup_bus(bus);
|
||||
+ pcibios_fixup_bus_self(bus);
|
||||
+ pcibios_fixup_bus_devices(bus);
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_fixup_bus);
|
||||
|
||||
-/* When building a bus from the OF tree rather than probing, we need a
|
||||
- * slightly different version of the fixup which doesn't read the
|
||||
- * bridge bases using config space accesses
|
||||
- */
|
||||
-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
|
||||
-{
|
||||
- __pcibios_fixup_bus(bus);
|
||||
-}
|
||||
-
|
||||
static int skip_isa_ioresource_align(struct pci_dev *dev)
|
||||
{
|
||||
if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
|
||||
@@ -992,9 +999,12 @@ void pcibios_allocate_bus_resources(stru
|
||||
int i;
|
||||
struct resource *res, *pr;
|
||||
|
||||
+ DBG("PCI: Allocating bus resources for %04x:%02x...\n",
|
||||
+ pci_domain_nr(bus), bus->number);
|
||||
+
|
||||
for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
|
||||
if ((res = bus->resource[i]) == NULL || !res->flags
|
||||
- || res->start > res->end)
|
||||
+ || res->start > res->end || res->parent)
|
||||
continue;
|
||||
if (bus->parent == NULL)
|
||||
pr = (res->flags & IORESOURCE_IO) ?
|
||||
@@ -1047,6 +1057,7 @@ clear_resource:
|
||||
list_for_each_entry(b, &bus->children, node)
|
||||
pcibios_allocate_bus_resources(b);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(pcibios_allocate_bus_resources);
|
||||
|
||||
static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
|
||||
{
|
||||
@@ -1157,6 +1168,13 @@ void __devinit pcibios_claim_one_bus(str
|
||||
|
||||
if (r->parent || !r->start || !r->flags)
|
||||
continue;
|
||||
+
|
||||
+ DBG("PCI: Claiming %s: Resource %d: %016llx..%016llx [%x]\n",
|
||||
+ pci_name(dev), i,
|
||||
+ (unsigned long long)r->start,
|
||||
+ (unsigned long long)r->end,
|
||||
+ (unsigned int)r->flags);
|
||||
+
|
||||
pci_claim_resource(dev, i);
|
||||
}
|
||||
}
|
||||
--- a/arch/powerpc/kernel/rtas_pci.c
|
||||
+++ b/arch/powerpc/kernel/rtas_pci.c
|
||||
@@ -301,51 +301,3 @@ void __init find_and_init_phbs(void)
|
||||
#endif /* CONFIG_PPC32 */
|
||||
}
|
||||
}
|
||||
-
|
||||
-/* RPA-specific bits for removing PHBs */
|
||||
-int pcibios_remove_root_bus(struct pci_controller *phb)
|
||||
-{
|
||||
- struct pci_bus *b = phb->bus;
|
||||
- struct resource *res;
|
||||
- int rc, i;
|
||||
-
|
||||
- res = b->resource[0];
|
||||
- if (!res->flags) {
|
||||
- printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__,
|
||||
- b->name);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- rc = pcibios_unmap_io_space(b);
|
||||
- if (rc) {
|
||||
- printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
|
||||
- __func__, b->name);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- if (release_resource(res)) {
|
||||
- printk(KERN_ERR "%s: failed to release IO on bus %s\n",
|
||||
- __func__, b->name);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- for (i = 1; i < 3; ++i) {
|
||||
- res = b->resource[i];
|
||||
- if (!res->flags && i == 0) {
|
||||
- printk(KERN_ERR "%s: no MEM resource for PHB %s\n",
|
||||
- __func__, b->name);
|
||||
- return 1;
|
||||
- }
|
||||
- if (res->flags && release_resource(res)) {
|
||||
- printk(KERN_ERR
|
||||
- "%s: failed to release IO %d on bus %s\n",
|
||||
- __func__, i, b->name);
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- pcibios_free_controller(phb);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-EXPORT_SYMBOL(pcibios_remove_root_bus);
|
||||
--- a/arch/powerpc/platforms/pseries/eeh.c
|
||||
+++ b/arch/powerpc/platforms/pseries/eeh.c
|
||||
@@ -21,6 +21,8 @@
|
||||
* Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
|
||||
*/
|
||||
|
||||
+#undef DEBUG
|
||||
+
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
@@ -488,10 +490,8 @@ int eeh_dn_check_failure(struct device_n
|
||||
if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
|
||||
pdn->eeh_mode & EEH_MODE_NOCHECK) {
|
||||
ignored_check++;
|
||||
-#ifdef DEBUG
|
||||
- printk ("EEH:ignored check (%x) for %s %s\n",
|
||||
- pdn->eeh_mode, pci_name (dev), dn->full_name);
|
||||
-#endif
|
||||
+ pr_debug("EEH: Ignored check (%x) for %s %s\n",
|
||||
+ pdn->eeh_mode, pci_name (dev), dn->full_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1014,10 +1014,9 @@ static void *early_enable_eeh(struct dev
|
||||
eeh_subsystem_enabled = 1;
|
||||
pdn->eeh_mode |= EEH_MODE_SUPPORTED;
|
||||
|
||||
-#ifdef DEBUG
|
||||
- printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",
|
||||
- dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);
|
||||
-#endif
|
||||
+ pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
|
||||
+ dn->full_name, pdn->eeh_config_addr,
|
||||
+ pdn->eeh_pe_config_addr);
|
||||
} else {
|
||||
|
||||
/* This device doesn't support EEH, but it may have an
|
||||
@@ -1161,13 +1160,17 @@ static void eeh_add_device_late(struct p
|
||||
if (!dev || !eeh_subsystem_enabled)
|
||||
return;
|
||||
|
||||
-#ifdef DEBUG
|
||||
- printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev));
|
||||
-#endif
|
||||
+ pr_debug("EEH: Adding device %s\n", pci_name(dev));
|
||||
|
||||
- pci_dev_get (dev);
|
||||
dn = pci_device_to_OF_node(dev);
|
||||
pdn = PCI_DN(dn);
|
||||
+ if (pdn->pcidev == dev) {
|
||||
+ pr_debug("EEH: Already referenced !\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ WARN_ON(pdn->pcidev);
|
||||
+
|
||||
+ pci_dev_get (dev);
|
||||
pdn->pcidev = dev;
|
||||
|
||||
pci_addr_cache_insert_device(dev);
|
||||
@@ -1206,17 +1209,18 @@ static void eeh_remove_device(struct pci
|
||||
return;
|
||||
|
||||
/* Unregister the device with the EEH/PCI address search system */
|
||||
-#ifdef DEBUG
|
||||
- printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));
|
||||
-#endif
|
||||
- pci_addr_cache_remove_device(dev);
|
||||
- eeh_sysfs_remove_device(dev);
|
||||
+ pr_debug("EEH: Removing device %s\n", pci_name(dev));
|
||||
|
||||
dn = pci_device_to_OF_node(dev);
|
||||
- if (PCI_DN(dn)->pcidev) {
|
||||
- PCI_DN(dn)->pcidev = NULL;
|
||||
- pci_dev_put (dev);
|
||||
+ if (PCI_DN(dn)->pcidev == NULL) {
|
||||
+ pr_debug("EEH: Not referenced !\n");
|
||||
+ return;
|
||||
}
|
||||
+ PCI_DN(dn)->pcidev = NULL;
|
||||
+ pci_dev_put (dev);
|
||||
+
|
||||
+ pci_addr_cache_remove_device(dev);
|
||||
+ eeh_sysfs_remove_device(dev);
|
||||
}
|
||||
|
||||
void eeh_remove_bus_device(struct pci_dev *dev)
|
||||
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
|
||||
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
|
||||
@@ -25,6 +25,8 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
+#undef DEBUG
|
||||
+
|
||||
#include <linux/pci.h>
|
||||
#include <asm/pci-bridge.h>
|
||||
#include <asm/ppc-pci.h>
|
||||
@@ -69,73 +71,41 @@ EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);
|
||||
* Remove all of the PCI devices under this bus both from the
|
||||
* linux pci device tree, and from the powerpc EEH address cache.
|
||||
*/
|
||||
-void
|
||||
-pcibios_remove_pci_devices(struct pci_bus *bus)
|
||||
+void pcibios_remove_pci_devices(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *dev, *tmp;
|
||||
+ struct pci_bus *child_bus;
|
||||
|
||||
+ /* First go down child busses */
|
||||
+ list_for_each_entry(child_bus, &bus->children, node)
|
||||
+ pcibios_remove_pci_devices(child_bus);
|
||||
+
|
||||
+ pr_debug("PCI: Removing devices on bus %04x:%02x\n",
|
||||
+ pci_domain_nr(bus), bus->number);
|
||||
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
|
||||
+ pr_debug(" * Removing %s...\n", pci_name(dev));
|
||||
eeh_remove_bus_device(dev);
|
||||
pci_remove_bus_device(dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
|
||||
|
||||
-/* Must be called before pci_bus_add_devices */
|
||||
-void
|
||||
-pcibios_fixup_new_pci_devices(struct pci_bus *bus)
|
||||
-{
|
||||
- struct pci_dev *dev;
|
||||
-
|
||||
- list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
- /* Skip already-added devices */
|
||||
- if (!dev->is_added) {
|
||||
- int i;
|
||||
-
|
||||
- /* Fill device archdata and setup iommu table */
|
||||
- pcibios_setup_new_device(dev);
|
||||
-
|
||||
- pci_read_irq_line(dev);
|
||||
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
|
||||
- struct resource *r = &dev->resource[i];
|
||||
-
|
||||
- if (r->parent || !r->start || !r->flags)
|
||||
- continue;
|
||||
- pci_claim_resource(dev, i);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices);
|
||||
-
|
||||
-static int
|
||||
-pcibios_pci_config_bridge(struct pci_dev *dev)
|
||||
+void pcibios_finish_adding_new_bus(struct pci_bus *bus)
|
||||
{
|
||||
- u8 sec_busno;
|
||||
- struct pci_bus *child_bus;
|
||||
-
|
||||
- /* Get busno of downstream bus */
|
||||
- pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
|
||||
+ pr_debug("PCI: Finishing adding hotplug bus %04x:%02x\n",
|
||||
+ pci_domain_nr(bus), bus->number);
|
||||
|
||||
- /* Add to children of PCI bridge dev->bus */
|
||||
- child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
|
||||
- if (!child_bus) {
|
||||
- printk (KERN_ERR "%s: could not add second bus\n", __func__);
|
||||
- return -EIO;
|
||||
- }
|
||||
- sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
|
||||
-
|
||||
- pci_scan_child_bus(child_bus);
|
||||
+ /* Allocate bus and devices resources */
|
||||
+ pcibios_allocate_bus_resources(bus);
|
||||
+ pcibios_claim_one_bus(bus);
|
||||
|
||||
- /* Fixup new pci devices */
|
||||
- pcibios_fixup_new_pci_devices(child_bus);
|
||||
+ /* Add new devices to global lists. Register in proc, sysfs. */
|
||||
+ pci_bus_add_devices(bus);
|
||||
|
||||
- /* Make the discovered devices available */
|
||||
- pci_bus_add_devices(child_bus);
|
||||
-
|
||||
- eeh_add_device_tree_late(child_bus);
|
||||
- return 0;
|
||||
+ /* Fixup EEH */
|
||||
+ eeh_add_device_tree_late(bus);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(pcibios_finish_adding_new_bus);
|
||||
|
||||
/**
|
||||
* pcibios_add_pci_devices - adds new pci devices to bus
|
||||
@@ -147,10 +117,9 @@ pcibios_pci_config_bridge(struct pci_dev
|
||||
* is how this routine differs from other, similar pcibios
|
||||
* routines.)
|
||||
*/
|
||||
-void
|
||||
-pcibios_add_pci_devices(struct pci_bus * bus)
|
||||
+void pcibios_add_pci_devices(struct pci_bus * bus)
|
||||
{
|
||||
- int slotno, num, mode;
|
||||
+ int slotno, num, mode, pass, max;
|
||||
struct pci_dev *dev;
|
||||
struct device_node *dn = pci_bus_to_OF_node(bus);
|
||||
|
||||
@@ -162,25 +131,24 @@ pcibios_add_pci_devices(struct pci_bus *
|
||||
|
||||
if (mode == PCI_PROBE_DEVTREE) {
|
||||
/* use ofdt-based probe */
|
||||
- of_scan_bus(dn, bus);
|
||||
- if (!list_empty(&bus->devices)) {
|
||||
- pcibios_fixup_new_pci_devices(bus);
|
||||
- pci_bus_add_devices(bus);
|
||||
- eeh_add_device_tree_late(bus);
|
||||
- }
|
||||
+ of_scan_bus(dn, bus, 1);
|
||||
+ if (!list_empty(&bus->devices))
|
||||
+ pcibios_finish_adding_new_bus(bus);
|
||||
} else if (mode == PCI_PROBE_NORMAL) {
|
||||
/* use legacy probe */
|
||||
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
|
||||
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
|
||||
- if (num) {
|
||||
- pcibios_fixup_new_pci_devices(bus);
|
||||
- pci_bus_add_devices(bus);
|
||||
- eeh_add_device_tree_late(bus);
|
||||
+ if (!num)
|
||||
+ return;
|
||||
+ pcibios_fixup_bus_devices(bus);
|
||||
+ max = bus->secondary;
|
||||
+ for (pass=0; pass < 2; pass++)
|
||||
+ list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
|
||||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
|
||||
+ max = pci_scan_bridge(bus, dev, max, pass);
|
||||
}
|
||||
-
|
||||
- list_for_each_entry(dev, &bus->devices, bus_list)
|
||||
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
|
||||
- pcibios_pci_config_bridge(dev);
|
||||
+ pcibios_finish_adding_new_bus(bus);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
|
||||
@@ -189,7 +157,8 @@ struct pci_controller * __devinit init_p
|
||||
{
|
||||
struct pci_controller *phb;
|
||||
int primary;
|
||||
- struct pci_bus *b;
|
||||
+
|
||||
+ pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
|
||||
|
||||
primary = list_empty(&hose_list);
|
||||
phb = pcibios_alloc_controller(dn);
|
||||
@@ -204,11 +173,57 @@ struct pci_controller * __devinit init_p
|
||||
eeh_add_device_tree_early(dn);
|
||||
|
||||
scan_phb(phb);
|
||||
- pcibios_allocate_bus_resources(phb->bus);
|
||||
- pcibios_fixup_new_pci_devices(phb->bus);
|
||||
- pci_bus_add_devices(phb->bus);
|
||||
- eeh_add_device_tree_late(phb->bus);
|
||||
+ pcibios_finish_adding_new_bus(phb->bus);
|
||||
|
||||
return phb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(init_phb_dynamic);
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/* RPA-specific bits for removing PHBs */
|
||||
+int remove_phb_dynamic(struct pci_controller *phb)
|
||||
+{
|
||||
+ struct pci_bus *b = phb->bus;
|
||||
+ struct resource *res;
|
||||
+ int rc, i;
|
||||
+
|
||||
+ pr_debug("PCI: Removing PHB %04x:%02x... \n", pci_domain_nr(b), b->number);
|
||||
+
|
||||
+ /* We -know- there aren't any child devices anymore at this stage
|
||||
+ * and thus, we can safely unmap the IO space as it's not in use
|
||||
+ */
|
||||
+ res = &phb->io_resource;
|
||||
+ if (res->flags & IORESOURCE_IO) {
|
||||
+ rc = pcibios_unmap_io_space(b);
|
||||
+ if (rc) {
|
||||
+ printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
|
||||
+ __func__, b->name);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Unregister the bridge device from sysfs and remove the PCI bus */
|
||||
+ device_unregister(b->bridge);
|
||||
+ phb->bus = NULL;
|
||||
+ pci_remove_bus(b);
|
||||
+
|
||||
+ /* Now release the IO resource */
|
||||
+ if (res->flags & IORESOURCE_IO)
|
||||
+ release_resource(res);
|
||||
+
|
||||
+ /* Release memory resources */
|
||||
+ for (i = 0; i < 3; ++i) {
|
||||
+ res = &phb->mem_resources[i];
|
||||
+ if (!(res->flags & IORESOURCE_MEM))
|
||||
+ continue;
|
||||
+ release_resource(res);
|
||||
+ }
|
||||
+
|
||||
+ /* Free pci_controller data structure */
|
||||
+ pcibios_free_controller(phb);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(remove_phb_dynamic);
|
||||
--- a/drivers/pci/hotplug/rpadlpar_core.c
|
||||
+++ b/drivers/pci/hotplug/rpadlpar_core.c
|
||||
@@ -14,6 +14,8 @@
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
+#undef DEBUG
|
||||
+
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/string.h>
|
||||
@@ -155,16 +157,15 @@ static void dlpar_pci_add_bus(struct dev
|
||||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
|
||||
of_scan_pci_bridge(dn, dev);
|
||||
|
||||
- pcibios_fixup_new_pci_devices(dev->subordinate);
|
||||
-
|
||||
- /* Claim new bus resources */
|
||||
- pcibios_claim_one_bus(dev->bus);
|
||||
-
|
||||
/* Map IO space for child bus, which may or may not succeed */
|
||||
pcibios_map_io_space(dev->subordinate);
|
||||
|
||||
- /* Add new devices to global lists. Register in proc, sysfs. */
|
||||
- pci_bus_add_devices(phb->bus);
|
||||
+ /* Finish adding it : resource allocation, adding devices, etc...
|
||||
+ * Note that we need to perform the finish pass on the -parent-
|
||||
+ * bus of the EADS bridge so the bridge device itself gets
|
||||
+ * properly added
|
||||
+ */
|
||||
+ pcibios_finish_adding_new_bus(phb->bus);
|
||||
}
|
||||
|
||||
static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
|
||||
@@ -206,22 +207,19 @@ static int dlpar_add_pci_slot(char *drc_
|
||||
static int dlpar_remove_root_bus(struct pci_controller *phb)
|
||||
{
|
||||
struct pci_bus *phb_bus;
|
||||
- int rc;
|
||||
|
||||
phb_bus = phb->bus;
|
||||
+ pr_debug("PCI: -> removing root bus %04x:%02x\n",
|
||||
+ pci_domain_nr(phb_bus), phb_bus->number);
|
||||
+
|
||||
+ /* We cannot to remove a root bus that has children */
|
||||
if (!(list_empty(&phb_bus->children) &&
|
||||
list_empty(&phb_bus->devices))) {
|
||||
+ pr_debug("PCI: PHB removal failed, bus not empty !\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
- rc = pcibios_remove_root_bus(phb);
|
||||
- if (rc)
|
||||
- return -EIO;
|
||||
-
|
||||
- device_unregister(phb_bus->bridge);
|
||||
- pci_remove_bus(phb_bus);
|
||||
-
|
||||
- return 0;
|
||||
+ return remove_phb_dynamic(phb);
|
||||
}
|
||||
|
||||
static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
|
||||
@@ -233,6 +231,8 @@ static int dlpar_remove_phb(char *drc_na
|
||||
if (!pcibios_find_pci_bus(dn))
|
||||
return -EINVAL;
|
||||
|
||||
+ pr_debug("PCI: Removing PHB %s...\n", dn->full_name);
|
||||
+
|
||||
/* If pci slot is hotplugable, use hotplug to remove it */
|
||||
slot = find_php_slot(dn);
|
||||
if (slot) {
|
||||
@@ -378,25 +378,36 @@ int dlpar_remove_pci_slot(char *drc_name
|
||||
if (!bus)
|
||||
return -EINVAL;
|
||||
|
||||
- /* If pci slot is hotplugable, use hotplug to remove it */
|
||||
+ pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
|
||||
+ bus->self ? pci_name(bus->self) : "<!PHB!>");
|
||||
+
|
||||
+ /* If pci slot is hotplugable, remove hotplug data structures */
|
||||
slot = find_php_slot(dn);
|
||||
if (slot) {
|
||||
+ pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
|
||||
+ pci_domain_nr(bus), bus->number);
|
||||
if (rpaphp_deregister_slot(slot)) {
|
||||
printk(KERN_ERR
|
||||
"%s: unable to remove hotplug slot %s\n",
|
||||
__func__, drc_name);
|
||||
return -EIO;
|
||||
}
|
||||
- } else
|
||||
- pcibios_remove_pci_devices(bus);
|
||||
+ }
|
||||
+
|
||||
+ /* Remove all devices below slot */
|
||||
+ pcibios_remove_pci_devices(bus);
|
||||
|
||||
+ /* Unmap PCI IO space */
|
||||
if (pcibios_unmap_io_space(bus)) {
|
||||
printk(KERN_ERR "%s: failed to unmap bus range\n",
|
||||
__func__);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
+ /* Remove the EADS bridge device itself */
|
||||
BUG_ON(!bus->self);
|
||||
+ pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
|
||||
+ eeh_remove_bus_device(bus->self);
|
||||
pci_remove_bus_device(bus->self);
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/pci/hotplug/rpaphp_slot.c
|
||||
+++ b/drivers/pci/hotplug/rpaphp_slot.c
|
||||
@@ -145,9 +145,5 @@ int rpaphp_register_slot(struct slot *sl
|
||||
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
|
||||
info("Slot [%s] registered\n", slot->name);
|
||||
return 0;
|
||||
-
|
||||
-sysfs_fail:
|
||||
- pci_hp_deregister(php_slot);
|
||||
- return retval;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
Subject: powerpc/pci: Fix unmapping of IO space on 64-bit
|
||||
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
References: 439491
|
||||
|
||||
A typo/thinko made us pass the wrong argument to __flush_hash_table_range
|
||||
when unplugging bridges, thus not flushing all the translations for
|
||||
the IO space on unplug.
|
||||
|
||||
This causes the hypervisor to refuse unplugging slots.
|
||||
|
||||
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/kernel/pci_64.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/pci_64.c
|
||||
+++ b/arch/powerpc/kernel/pci_64.c
|
||||
@@ -455,7 +455,7 @@ int pcibios_unmap_io_space(struct pci_bu
|
||||
pci_name(bus->self));
|
||||
|
||||
__flush_hash_table_range(&init_mm, res->start + _IO_BASE,
|
||||
- res->end - res->start + 1);
|
||||
+ res->end + _IO_BASE + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
From: unknown@suse.de
|
||||
Subject: some crazy ppc patch
|
||||
|
||||
add prom=nodisplay
|
||||
avoid crash in firmware on IBM B50 when OF stdout is on serial.
|
||||
|
||||
0 > boot scsi/sd@4:1,yaboot |
|
||||
yaboot starting: loaded at 00200000 00222530 (0/0/00c1a078; sp: 00efffd0)
|
||||
brokenfirmware did not claim executable memory, fixed it myself
|
||||
Config file 'yaboot.cnf' read, 213 bytes
|
||||
|
||||
Welcome to yaboot version 10.1.22-r945.SuSE
|
||||
booted from '/pci@80000000/scsi@10/sd@4:1,yaboot'
|
||||
Enter "help" to get some basic usage information
|
||||
boot:
|
||||
* linux
|
||||
boot: linux 3
|
||||
Please wait, loading kernel...
|
||||
Allocated 00600000 bytes for executable @ 02000000
|
||||
Elf32 kernel loaded...
|
||||
Loading ramdisk...
|
||||
ramdisk loaded 0030e057 @ 04100000
|
||||
OF stdout device is: /pci@80000000/isa@b/serial@i3f8
|
||||
command line: root=/dev/system/root xmon=on sysrq=1 quiet panic=12 3
|
||||
memory layout at init:
|
||||
memory_limit : 00000000 (16 MB aligned)
|
||||
alloc_bottom : 0440f000
|
||||
alloc_top : 30000000
|
||||
alloc_top_hi : 40000000
|
||||
rmo_top : 30000000
|
||||
ram_top : 40000000
|
||||
Looking for displays
|
||||
found display : /pci@80000000/display@16, opening ...
|
||||
Unexpected Firmware Error:
|
||||
DEFAULT CATCH!, code=fff00300 at %SRR0: 00c18ccc %SRR1: 00003030
|
||||
ok
|
||||
0 > reset-all
|
||||
|
||||
|
||||
---
|
||||
arch/powerpc/kernel/prom_init.c | 12 ++++++++++--
|
||||
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/prom_init.c
|
||||
+++ b/arch/powerpc/kernel/prom_init.c
|
||||
@@ -172,6 +172,7 @@ static unsigned long __initdata dt_strin
|
||||
|
||||
static unsigned long __initdata prom_initrd_start, prom_initrd_end;
|
||||
|
||||
+static int __initdata prom_no_display;
|
||||
#ifdef CONFIG_PPC64
|
||||
static int __initdata prom_iommu_force_on;
|
||||
static int __initdata prom_iommu_off;
|
||||
@@ -555,9 +556,7 @@ unsigned long prom_memparse(const char *
|
||||
static void __init early_cmdline_parse(void)
|
||||
{
|
||||
struct prom_t *_prom = &RELOC(prom);
|
||||
-#ifdef CONFIG_PPC64
|
||||
const char *opt;
|
||||
-#endif
|
||||
char *p;
|
||||
int l = 0;
|
||||
|
||||
@@ -572,6 +571,14 @@ static void __init early_cmdline_parse(v
|
||||
#endif /* CONFIG_CMDLINE */
|
||||
prom_printf("command line: %s\n", RELOC(prom_cmd_line));
|
||||
|
||||
+ opt = strstr(RELOC(prom_cmd_line), RELOC("prom="));
|
||||
+ if (opt) {
|
||||
+ opt += 5;
|
||||
+ while (*opt && *opt == ' ')
|
||||
+ opt++;
|
||||
+ if (!strncmp(opt, RELOC("nodisplay"), 9))
|
||||
+ RELOC(prom_no_display) = 1;
|
||||
+ }
|
||||
#ifdef CONFIG_PPC64
|
||||
opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));
|
||||
if (opt) {
|
||||
@@ -2400,6 +2407,7 @@ unsigned long __init prom_init(unsigned
|
||||
/*
|
||||
* Initialize display devices
|
||||
*/
|
||||
+ if (RELOC(prom_no_display) == 0)
|
||||
prom_check_displays();
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
@@ -0,0 +1,83 @@
|
||||
Subject: ps3: Add passthru support for non-audio streams
|
||||
From: Takashi Iwai tiwai@suse.de Mon Oct 20 08:05:10 2008 +0200
|
||||
Date: Mon Oct 20 08:05:15 2008 +0200:
|
||||
Git: 64931a4be03dbc49bd50d10d211592cf98b523bb
|
||||
|
||||
Add support for the channel status bit setting so that non-PCM
|
||||
data stream can be sent (i.e. pass-through) via SPDIF/HDMI.
|
||||
|
||||
Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
|
||||
Acked-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
Signed-off-by: Stefan Assmann <sassmann@suse.de>
|
||||
|
||||
diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h
|
||||
index d30bde2..5aa22cf 100644
|
||||
--- a/arch/powerpc/include/asm/ps3av.h
|
||||
+++ b/arch/powerpc/include/asm/ps3av.h
|
||||
@@ -678,6 +678,8 @@ struct ps3av_pkt_avb_param {
|
||||
u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE];
|
||||
};
|
||||
|
||||
+/* channel status */
|
||||
+extern u8 ps3av_mode_cs_info[];
|
||||
|
||||
/** command status **/
|
||||
#define PS3AV_STATUS_SUCCESS 0x0000 /* success */
|
||||
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
|
||||
index 7f880c2..11eb503 100644
|
||||
--- a/drivers/ps3/ps3av_cmd.c
|
||||
+++ b/drivers/ps3/ps3av_cmd.c
|
||||
@@ -660,9 +660,10 @@ u32 ps3av_cmd_set_av_audio_param(void *p, u32 port,
|
||||
}
|
||||
|
||||
/* default cs val */
|
||||
-static const u8 ps3av_mode_cs_info[] = {
|
||||
+u8 ps3av_mode_cs_info[] = {
|
||||
0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
+EXPORT_SYMBOL_GPL(ps3av_mode_cs_info);
|
||||
|
||||
#define CS_44 0x00
|
||||
#define CS_48 0x02
|
||||
@@ -677,7 +678,7 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
|
||||
u32 ch, u32 fs, u32 word_bits, u32 format,
|
||||
u32 source)
|
||||
{
|
||||
- int spdif_through, spdif_bitstream;
|
||||
+ int spdif_through;
|
||||
int i;
|
||||
|
||||
if (!(ch | fs | format | word_bits | source)) {
|
||||
@@ -687,7 +688,6 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
|
||||
format = PS3AV_CMD_AUDIO_FORMAT_PCM;
|
||||
source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
|
||||
}
|
||||
- spdif_through = spdif_bitstream = 0; /* XXX not supported */
|
||||
|
||||
/* audio mode */
|
||||
memset(audio, 0, sizeof(*audio));
|
||||
@@ -777,16 +777,17 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* non-audio bit */
|
||||
+ spdif_through = audio->audio_cs_info[0] & 0x02;
|
||||
+
|
||||
/* pass through setting */
|
||||
if (spdif_through &&
|
||||
(avport == PS3AV_CMD_AVPORT_SPDIF_0 ||
|
||||
- avport == PS3AV_CMD_AVPORT_SPDIF_1)) {
|
||||
+ avport == PS3AV_CMD_AVPORT_SPDIF_1 ||
|
||||
+ avport == PS3AV_CMD_AVPORT_HDMI_0 ||
|
||||
+ avport == PS3AV_CMD_AVPORT_HDMI_1)) {
|
||||
audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
|
||||
- audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF;
|
||||
- if (spdif_bitstream) {
|
||||
- audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
|
||||
- audio->audio_cs_info[0] |= CS_BIT;
|
||||
- }
|
||||
+ audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
Subject: ps3: Add ps3av_audio_mute_analog()
|
||||
From: Masakazu Mokuno mokuno@sm.sony.co.jp Mon Oct 20 08:03:33 2008 +0200
|
||||
Date: Mon Oct 20 08:04:59 2008 +0200:
|
||||
Git: 756ba83ee370fbf62643777e7ba4a4f05932f6fb
|
||||
|
||||
Add support for muting the analog output so that it does not
|
||||
play noises while non-PCM data is played.
|
||||
|
||||
Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
Signed-off-by: Stefan Assmann <sassmann@suse.de>
|
||||
|
||||
diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h
|
||||
index fda9871..d30bde2 100644
|
||||
--- a/arch/powerpc/include/asm/ps3av.h
|
||||
+++ b/arch/powerpc/include/asm/ps3av.h
|
||||
@@ -735,6 +735,7 @@ extern int ps3av_get_mode(void);
|
||||
extern int ps3av_video_mode2res(u32, u32 *, u32 *);
|
||||
extern int ps3av_video_mute(int);
|
||||
extern int ps3av_audio_mute(int);
|
||||
+extern int ps3av_audio_mute_analog(int);
|
||||
extern int ps3av_dev_open(void);
|
||||
extern int ps3av_dev_close(void);
|
||||
extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
|
||||
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
|
||||
index 6f2f90e..06848b2 100644
|
||||
--- a/drivers/ps3/ps3av.c
|
||||
+++ b/drivers/ps3/ps3av.c
|
||||
@@ -915,6 +915,22 @@ int ps3av_video_mute(int mute)
|
||||
|
||||
EXPORT_SYMBOL_GPL(ps3av_video_mute);
|
||||
|
||||
+/* mute analog output only */
|
||||
+int ps3av_audio_mute_analog(int mute)
|
||||
+{
|
||||
+ int i, res;
|
||||
+
|
||||
+ for (i = 0; i < ps3av->av_hw_conf.num_of_avmulti; i++) {
|
||||
+ res = ps3av_cmd_av_audio_mute(1,
|
||||
+ &ps3av->av_port[i + ps3av->av_hw_conf.num_of_hdmi],
|
||||
+ mute);
|
||||
+ if (res < 0)
|
||||
+ return -1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(ps3av_audio_mute_analog);
|
||||
+
|
||||
int ps3av_audio_mute(int mute)
|
||||
{
|
||||
return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
|
||||
@@ -0,0 +1,166 @@
|
||||
Subject: ALSA: ps3: Add support for SPDIF/HDMI passthru
|
||||
From: Takashi Iwai tiwai@suse.de Mon Oct 20 08:06:39 2008 +0200
|
||||
Date: Mon Oct 20 08:06:39 2008 +0200:
|
||||
Git: 1ee2a322b058f6399dc900603f9ebb392037ff77
|
||||
|
||||
Add support for SPDIF/HDMI pass-through support of PS3 audio driver.
|
||||
|
||||
Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
Signed-off-by: Stefan Assmann <sassmann@suse.de>
|
||||
|
||||
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
|
||||
index 20d0e32..8f9e385 100644
|
||||
--- a/sound/ppc/snd_ps3.c
|
||||
+++ b/sound/ppc/snd_ps3.c
|
||||
@@ -666,6 +666,7 @@ static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
|
||||
card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
|
||||
card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
|
||||
card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
|
||||
+ memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
|
||||
|
||||
ret = snd_ps3_change_avsetting(card);
|
||||
|
||||
@@ -685,6 +686,7 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
|
||||
struct snd_ps3_avsetting_info avs;
|
||||
+ int ret;
|
||||
|
||||
avs = card->avs;
|
||||
|
||||
@@ -729,19 +731,92 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
|
||||
return 1;
|
||||
}
|
||||
|
||||
- if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
|
||||
- (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
|
||||
- card->avs = avs;
|
||||
- snd_ps3_change_avsetting(card);
|
||||
+ memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
|
||||
|
||||
+ if (memcmp(&card->avs, &avs, sizeof(avs))) {
|
||||
pr_debug("%s: after freq=%d width=%d\n", __func__,
|
||||
card->avs.avs_audio_rate, card->avs.avs_audio_width);
|
||||
|
||||
- return 0;
|
||||
+ card->avs = avs;
|
||||
+ snd_ps3_change_avsetting(card);
|
||||
+ ret = 0;
|
||||
} else
|
||||
+ ret = 1;
|
||||
+
|
||||
+ /* check CS non-audio bit and mute accordingly */
|
||||
+ if (avs.avs_cs_info[0] & 0x02)
|
||||
+ ps3av_audio_mute_analog(1); /* mute if non-audio */
|
||||
+ else
|
||||
+ ps3av_audio_mute_analog(0);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * SPDIF status bits controls
|
||||
+ */
|
||||
+static int snd_ps3_spdif_mask_info(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_info *uinfo)
|
||||
+{
|
||||
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
|
||||
+ uinfo->count = 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* FIXME: ps3av_set_audio_mode() assumes only consumer mode */
|
||||
+static int snd_ps3_spdif_cmask_get(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ memset(ucontrol->value.iec958.status, 0xff, 8);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_ps3_spdif_pmask_get(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_ps3_spdif_default_get(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ memcpy(ucontrol->value.iec958.status, ps3av_mode_cs_info, 8);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_ps3_spdif_default_put(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ if (memcmp(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8)) {
|
||||
+ memcpy(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8);
|
||||
return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
+static struct snd_kcontrol_new spdif_ctls[] = {
|
||||
+ {
|
||||
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
|
||||
+ .info = snd_ps3_spdif_mask_info,
|
||||
+ .get = snd_ps3_spdif_cmask_get,
|
||||
+ },
|
||||
+ {
|
||||
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
|
||||
+ .info = snd_ps3_spdif_mask_info,
|
||||
+ .get = snd_ps3_spdif_pmask_get,
|
||||
+ },
|
||||
+ {
|
||||
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
|
||||
+ .info = snd_ps3_spdif_mask_info,
|
||||
+ .get = snd_ps3_spdif_default_get,
|
||||
+ .put = snd_ps3_spdif_default_put,
|
||||
+ },
|
||||
+};
|
||||
|
||||
|
||||
static int snd_ps3_map_mmio(void)
|
||||
@@ -842,7 +917,7 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
|
||||
|
||||
static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
- int ret;
|
||||
+ int i, ret;
|
||||
u64 lpar_addr, lpar_size;
|
||||
|
||||
BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
|
||||
@@ -903,6 +978,15 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
|
||||
strcpy(the_card.card->driver, "PS3");
|
||||
strcpy(the_card.card->shortname, "PS3");
|
||||
strcpy(the_card.card->longname, "PS3 sound");
|
||||
+
|
||||
+ /* create control elements */
|
||||
+ for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) {
|
||||
+ ret = snd_ctl_add(the_card.card,
|
||||
+ snd_ctl_new1(&spdif_ctls[i], &the_card));
|
||||
+ if (ret < 0)
|
||||
+ goto clean_card;
|
||||
+ }
|
||||
+
|
||||
/* create PCM devices instance */
|
||||
/* NOTE:this driver works assuming pcm:substream = 1:1 */
|
||||
ret = snd_pcm_new(the_card.card,
|
||||
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
|
||||
index 4b7e6fb..326fb29 100644
|
||||
--- a/sound/ppc/snd_ps3.h
|
||||
+++ b/sound/ppc/snd_ps3.h
|
||||
@@ -51,6 +51,7 @@ struct snd_ps3_avsetting_info {
|
||||
uint32_t avs_audio_width;
|
||||
uint32_t avs_audio_format; /* fixed */
|
||||
uint32_t avs_audio_source; /* fixed */
|
||||
+ unsigned char avs_cs_info[8];
|
||||
};
|
||||
/*
|
||||
* PS3 audio 'card' instance
|
||||
@@ -0,0 +1,164 @@
|
||||
From: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
|
||||
Subject: Introduce ps3_gpu_mutex
|
||||
|
||||
Introduce ps3_gpu_mutex to synchronizes GPU-related operations, like:
|
||||
- invoking the L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT command using the
|
||||
lv1_gpu_context_attribute() hypervisor call,
|
||||
- handling the PS3AV_CID_AVB_PARAM packet in the PS3 A/V Settings driver.
|
||||
|
||||
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
|
||||
Signed-off-by: Stefan Assmann <sassmann@suse.de>
|
||||
---
|
||||
arch/powerpc/include/asm/ps3.h | 3 +++
|
||||
arch/powerpc/include/asm/ps3av.h | 3 ---
|
||||
arch/powerpc/platforms/ps3/setup.c | 4 ++++
|
||||
drivers/ps3/ps3av.c | 20 --------------------
|
||||
drivers/ps3/ps3av_cmd.c | 4 ++--
|
||||
drivers/video/ps3fb.c | 17 +++++------------
|
||||
6 files changed, 14 insertions(+), 37 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/ps3.h
|
||||
+++ b/arch/powerpc/include/asm/ps3.h
|
||||
@@ -516,4 +516,7 @@ void ps3_sync_irq(int node);
|
||||
u32 ps3_get_hw_thread_id(int cpu);
|
||||
u64 ps3_get_spe_id(void *arg);
|
||||
|
||||
+/* mutex synchronizing GPU accesses and video mode changes */
|
||||
+extern struct mutex ps3_gpu_mutex;
|
||||
+
|
||||
#endif
|
||||
--- a/arch/powerpc/include/asm/ps3av.h
|
||||
+++ b/arch/powerpc/include/asm/ps3av.h
|
||||
@@ -740,8 +740,5 @@ extern int ps3av_audio_mute(int);
|
||||
extern int ps3av_audio_mute_analog(int);
|
||||
extern int ps3av_dev_open(void);
|
||||
extern int ps3av_dev_close(void);
|
||||
-extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
|
||||
- void *flip_data);
|
||||
-extern void ps3av_flip_ctl(int on);
|
||||
|
||||
#endif /* _ASM_POWERPC_PS3AV_H_ */
|
||||
--- a/arch/powerpc/platforms/ps3/setup.c
|
||||
+++ b/arch/powerpc/platforms/ps3/setup.c
|
||||
@@ -42,6 +42,10 @@
|
||||
#define DBG pr_debug
|
||||
#endif
|
||||
|
||||
+/* mutex synchronizing GPU accesses and video mode changes */
|
||||
+DEFINE_MUTEX(ps3_gpu_mutex);
|
||||
+EXPORT_SYMBOL_GPL(ps3_gpu_mutex);
|
||||
+
|
||||
#if !defined(CONFIG_SMP)
|
||||
static void smp_send_stop(void) {}
|
||||
#endif
|
||||
--- a/drivers/ps3/ps3av.c
|
||||
+++ b/drivers/ps3/ps3av.c
|
||||
@@ -59,8 +59,6 @@ static struct ps3av {
|
||||
struct ps3av_reply_hdr reply_hdr;
|
||||
u8 raw[PS3AV_BUF_SIZE];
|
||||
} recv_buf;
|
||||
- void (*flip_ctl)(int on, void *data);
|
||||
- void *flip_data;
|
||||
} *ps3av;
|
||||
|
||||
/* color space */
|
||||
@@ -939,24 +937,6 @@ int ps3av_audio_mute(int mute)
|
||||
|
||||
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
|
||||
|
||||
-void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
|
||||
- void *flip_data)
|
||||
-{
|
||||
- mutex_lock(&ps3av->mutex);
|
||||
- ps3av->flip_ctl = flip_ctl;
|
||||
- ps3av->flip_data = flip_data;
|
||||
- mutex_unlock(&ps3av->mutex);
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);
|
||||
-
|
||||
-void ps3av_flip_ctl(int on)
|
||||
-{
|
||||
- mutex_lock(&ps3av->mutex);
|
||||
- if (ps3av->flip_ctl)
|
||||
- ps3av->flip_ctl(on, ps3av->flip_data);
|
||||
- mutex_unlock(&ps3av->mutex);
|
||||
-}
|
||||
-
|
||||
static int ps3av_probe(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
int res;
|
||||
--- a/drivers/ps3/ps3av_cmd.c
|
||||
+++ b/drivers/ps3/ps3av_cmd.c
|
||||
@@ -864,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt
|
||||
{
|
||||
int res;
|
||||
|
||||
- ps3av_flip_ctl(0); /* flip off */
|
||||
+ mutex_lock(&ps3_gpu_mutex);
|
||||
|
||||
/* avb packet */
|
||||
res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
|
||||
@@ -878,7 +878,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt
|
||||
res);
|
||||
|
||||
out:
|
||||
- ps3av_flip_ctl(1); /* flip on */
|
||||
+ mutex_unlock(&ps3_gpu_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
--- a/drivers/video/ps3fb.c
|
||||
+++ b/drivers/video/ps3fb.c
|
||||
@@ -460,12 +460,16 @@ static void ps3fb_sync_image(struct devi
|
||||
line_length |= (u64)src_line_length << 32;
|
||||
|
||||
src_offset += GPU_FB_START;
|
||||
+
|
||||
+ mutex_lock(&ps3_gpu_mutex);
|
||||
status = lv1_gpu_context_attribute(ps3fb.context_handle,
|
||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
|
||||
dst_offset, GPU_IOIF + src_offset,
|
||||
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
|
||||
(width << 16) | height,
|
||||
line_length);
|
||||
+ mutex_unlock(&ps3_gpu_mutex);
|
||||
+
|
||||
if (status)
|
||||
dev_err(dev,
|
||||
"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
|
||||
@@ -784,15 +788,6 @@ static int ps3fb_wait_for_vsync(u32 crtc
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void ps3fb_flip_ctl(int on, void *data)
|
||||
-{
|
||||
- struct ps3fb_priv *priv = data;
|
||||
- if (on)
|
||||
- atomic_dec_if_positive(&priv->ext_flip);
|
||||
- else
|
||||
- atomic_inc(&priv->ext_flip);
|
||||
-}
|
||||
-
|
||||
|
||||
/*
|
||||
* ioctl
|
||||
@@ -1228,7 +1223,6 @@ static int __devinit ps3fb_probe(struct
|
||||
}
|
||||
|
||||
ps3fb.task = task;
|
||||
- ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1258,10 +1252,9 @@ static int ps3fb_shutdown(struct ps3_sys
|
||||
|
||||
dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
|
||||
|
||||
- ps3fb_flip_ctl(0, &ps3fb); /* flip off */
|
||||
+ atomic_inc(&ps3fb.ext_flip); /* flip off */
|
||||
ps3fb.dinfo->irq.mask = 0;
|
||||
|
||||
- ps3av_register_flip_ctl(NULL, NULL);
|
||||
if (ps3fb.task) {
|
||||
struct task_struct *task = ps3fb.task;
|
||||
ps3fb.task = NULL;
|
||||
@@ -0,0 +1,912 @@
|
||||
From: Jim Paris <jim@jtan.com>
|
||||
Subject: Add ps3vram driver, which exposes unused video RAM on the PS3 as a MTD
|
||||
|
||||
Add ps3vram driver, which exposes unused video RAM on the PS3 as a MTD
|
||||
device suitable for storage or swap. Fast data transfer is achieved
|
||||
using a local cache in system RAM and DMA transfers via the GPU.
|
||||
|
||||
Signed-off-by: Vivien Chappelier <vivien.chappelier@free.fr>
|
||||
CC: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
|
||||
CC: Geoff Levand <geoffrey.levand@am.sony.com>
|
||||
Signed-off-by: Jim Paris <jim@jtan.com>
|
||||
Signed-off-by: Stefan Assmann <sassmann@suse.de>
|
||||
---
|
||||
This version has been updated to work with PS3 firmware 2.50, and
|
||||
to use ps3_gpu_mutex.
|
||||
|
||||
Please consider for 2.6.29.
|
||||
|
||||
MAINTAINERS | 6
|
||||
arch/powerpc/include/asm/ps3.h | 1
|
||||
arch/powerpc/platforms/ps3/device-init.c | 37 +
|
||||
drivers/mtd/devices/Kconfig | 7
|
||||
drivers/mtd/devices/Makefile | 1
|
||||
MAINTAINERS | 6
|
||||
arch/powerpc/include/asm/ps3.h | 1
|
||||
arch/powerpc/platforms/ps3/device-init.c | 37 +
|
||||
drivers/mtd/devices/Kconfig | 7
|
||||
drivers/mtd/devices/Makefile | 1
|
||||
drivers/mtd/devices/ps3vram.c | 776 +++++++++++++++++++++++++++++++
|
||||
6 files changed, 828 insertions(+)
|
||||
create mode 100644 drivers/mtd/devices/ps3vram.c
|
||||
|
||||
--- a/arch/powerpc/include/asm/ps3.h
|
||||
+++ b/arch/powerpc/include/asm/ps3.h
|
||||
@@ -340,6 +340,7 @@ enum ps3_system_bus_device_type {
|
||||
enum ps3_match_sub_id {
|
||||
/* for PS3_MATCH_ID_GRAPHICS */
|
||||
PS3_MATCH_SUB_ID_FB = 1,
|
||||
+ PS3_MATCH_SUB_ID_RAMDISK = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
--- a/arch/powerpc/platforms/ps3/device-init.c
|
||||
+++ b/arch/powerpc/platforms/ps3/device-init.c
|
||||
@@ -499,6 +499,41 @@ static int __init ps3_register_graphics_
|
||||
return result;
|
||||
}
|
||||
|
||||
+static int __init ps3_register_ramdisk_device(void)
|
||||
+{
|
||||
+ int result;
|
||||
+ struct layout {
|
||||
+ struct ps3_system_bus_device dev;
|
||||
+ } *p;
|
||||
+
|
||||
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
|
||||
+
|
||||
+ p = kzalloc(sizeof(struct layout), GFP_KERNEL);
|
||||
+
|
||||
+ if (!p)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ p->dev.match_id = PS3_MATCH_ID_GRAPHICS;
|
||||
+ p->dev.match_sub_id = PS3_MATCH_SUB_ID_RAMDISK;
|
||||
+ p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
|
||||
+
|
||||
+ result = ps3_system_bus_device_register(&p->dev);
|
||||
+
|
||||
+ if (result) {
|
||||
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
|
||||
+ __func__, __LINE__);
|
||||
+ goto fail_device_register;
|
||||
+ }
|
||||
+
|
||||
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
|
||||
+ return 0;
|
||||
+
|
||||
+fail_device_register:
|
||||
+ kfree(p);
|
||||
+ pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* ps3_setup_dynamic_device - Setup a dynamic device from the repository
|
||||
*/
|
||||
@@ -927,6 +962,8 @@ static int __init ps3_register_devices(v
|
||||
|
||||
ps3_register_lpm_devices();
|
||||
|
||||
+ ps3_register_ramdisk_device();
|
||||
+
|
||||
pr_debug(" <- %s:%d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/mtd/devices/Kconfig
|
||||
+++ b/drivers/mtd/devices/Kconfig
|
||||
@@ -99,6 +99,13 @@ config MTD_PHRAM
|
||||
doesn't have access to, memory beyond the mem=xxx limit, nvram,
|
||||
memory on the video card, etc...
|
||||
|
||||
+config MTD_PS3VRAM
|
||||
+ tristate "PS3 video RAM"
|
||||
+ depends on FB_PS3
|
||||
+ help
|
||||
+ This driver allows you to use excess PS3 video RAM as volatile
|
||||
+ storage or system swap.
|
||||
+
|
||||
config MTD_LART
|
||||
tristate "28F160xx flash driver for LART"
|
||||
depends on SA1100_LART
|
||||
--- a/drivers/mtd/devices/Makefile
|
||||
+++ b/drivers/mtd/devices/Makefile
|
||||
@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_LART) += lart.o
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
+obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/devices/ps3vram.c
|
||||
@@ -0,0 +1,776 @@
|
||||
+/**
|
||||
+ * ps3vram - Use extra PS3 video ram as MTD block device.
|
||||
+ *
|
||||
+ * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
|
||||
+ * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <linux/gfp.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+
|
||||
+#include <asm/lv1call.h>
|
||||
+#include <asm/ps3.h>
|
||||
+
|
||||
+#define DEVICE_NAME "ps3vram"
|
||||
+
|
||||
+#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MB aligned) */
|
||||
+#define XDR_IOIF 0x0c000000
|
||||
+
|
||||
+#define FIFO_BASE XDR_IOIF
|
||||
+#define FIFO_SIZE (64 * 1024)
|
||||
+
|
||||
+#define DMA_PAGE_SIZE (4 * 1024)
|
||||
+
|
||||
+#define CACHE_PAGE_SIZE (256 * 1024)
|
||||
+#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
|
||||
+
|
||||
+#define CACHE_OFFSET CACHE_PAGE_SIZE
|
||||
+#define FIFO_OFFSET 0
|
||||
+
|
||||
+#define CTRL_PUT 0x10
|
||||
+#define CTRL_GET 0x11
|
||||
+#define CTRL_TOP 0x15
|
||||
+
|
||||
+#define UPLOAD_SUBCH 1
|
||||
+#define DOWNLOAD_SUBCH 2
|
||||
+
|
||||
+#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
|
||||
+#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
|
||||
+
|
||||
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
|
||||
+
|
||||
+struct mtd_info ps3vram_mtd;
|
||||
+
|
||||
+#define CACHE_PAGE_PRESENT 1
|
||||
+#define CACHE_PAGE_DIRTY 2
|
||||
+
|
||||
+#define dbg(fmt, args...) \
|
||||
+ pr_debug("%s:%d " fmt "\n", __func__, __LINE__, ## args)
|
||||
+
|
||||
+struct ps3vram_tag {
|
||||
+ unsigned int address;
|
||||
+ unsigned int flags;
|
||||
+};
|
||||
+
|
||||
+struct ps3vram_cache {
|
||||
+ unsigned int page_count;
|
||||
+ unsigned int page_size;
|
||||
+ struct ps3vram_tag *tags;
|
||||
+};
|
||||
+
|
||||
+struct ps3vram_priv {
|
||||
+ uint64_t memory_handle;
|
||||
+ uint64_t context_handle;
|
||||
+ uint8_t *base;
|
||||
+ uint32_t *ctrl;
|
||||
+ uint32_t *reports;
|
||||
+ uint8_t *xdr_buf;
|
||||
+
|
||||
+ uint32_t *fifo_base;
|
||||
+ uint32_t *fifo_ptr;
|
||||
+
|
||||
+ struct ps3vram_cache cache;
|
||||
+
|
||||
+ /* Used to serialize cache/DMA operations */
|
||||
+ struct mutex lock;
|
||||
+};
|
||||
+
|
||||
+#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
|
||||
+#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
|
||||
+#define DMA_NOTIFIER_SIZE 0x40
|
||||
+
|
||||
+#define NUM_NOTIFIERS 16
|
||||
+
|
||||
+#define NOTIFIER 7 /* notifier used for completion report */
|
||||
+
|
||||
+/* A trailing '-' means to subtract off ps3fb_videomemory.size */
|
||||
+char *size = "256M-";
|
||||
+module_param(size, charp, 0);
|
||||
+MODULE_PARM_DESC(size, "memory size");
|
||||
+
|
||||
+static inline uint32_t *ps3vram_get_notifier(uint32_t *reports, int notifier)
|
||||
+{
|
||||
+ return (void *) reports +
|
||||
+ DMA_NOTIFIER_OFFSET_BASE +
|
||||
+ DMA_NOTIFIER_SIZE * notifier;
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_notifier_reset(struct mtd_info *mtd)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ uint32_t *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ notify[i] = 0xffffffff;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_notifier_wait(struct mtd_info *mtd, int timeout_ms)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ uint32_t *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||
+
|
||||
+ timeout_ms *= 1000;
|
||||
+
|
||||
+ do {
|
||||
+ if (notify[3] == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (timeout_ms)
|
||||
+ udelay(1);
|
||||
+ } while (timeout_ms--);
|
||||
+
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_dump_ring(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ uint32_t *fifo;
|
||||
+
|
||||
+ pr_info("PUT = %08x GET = %08x\n", priv->ctrl[CTRL_PUT],
|
||||
+ priv->ctrl[CTRL_GET]);
|
||||
+ for (fifo = priv->fifo_base; fifo < priv->fifo_ptr; fifo++)
|
||||
+ pr_info("%p: %08x\n", fifo, *fifo);
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_dump_reports(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < NUM_NOTIFIERS; i++) {
|
||||
+ uint32_t *n = ps3vram_get_notifier(priv->reports, i);
|
||||
+ pr_info("%p: %08x\n", n, *n);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_init_ring(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||
+ priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_wait_ring(struct mtd_info *mtd, int timeout)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ /* wait until setup commands are processed */
|
||||
+ timeout *= 1000;
|
||||
+ while (--timeout) {
|
||||
+ if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
|
||||
+ break;
|
||||
+ udelay(1);
|
||||
+ }
|
||||
+ if (timeout == 0) {
|
||||
+ pr_err("FIFO timeout (%08x/%08x/%08x)\n", priv->ctrl[CTRL_PUT],
|
||||
+ priv->ctrl[CTRL_GET], priv->ctrl[CTRL_TOP]);
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline void ps3vram_out_ring(struct ps3vram_priv *priv, uint32_t data)
|
||||
+{
|
||||
+ *(priv->fifo_ptr)++ = data;
|
||||
+}
|
||||
+
|
||||
+static inline void ps3vram_begin_ring(struct ps3vram_priv *priv, uint32_t chan,
|
||||
+ uint32_t tag, uint32_t size)
|
||||
+{
|
||||
+ ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_rewind_ring(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ u64 status;
|
||||
+
|
||||
+ ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
|
||||
+
|
||||
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||
+
|
||||
+ /* asking the HV for a blit will kick the fifo */
|
||||
+ status = lv1_gpu_context_attribute(priv->context_handle,
|
||||
+ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
|
||||
+ 0, 0, 0, 0);
|
||||
+ if (status)
|
||||
+ pr_err("ps3vram: lv1_gpu_context_attribute FB_BLIT failed\n");
|
||||
+
|
||||
+ priv->fifo_ptr = priv->fifo_base;
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_fire_ring(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ u64 status;
|
||||
+
|
||||
+ mutex_lock(&ps3_gpu_mutex);
|
||||
+
|
||||
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
|
||||
+ (priv->fifo_ptr - priv->fifo_base) * sizeof(uint32_t);
|
||||
+
|
||||
+ /* asking the HV for a blit will kick the fifo */
|
||||
+ status = lv1_gpu_context_attribute(priv->context_handle,
|
||||
+ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
|
||||
+ 0, 0, 0, 0);
|
||||
+ if (status)
|
||||
+ pr_err("ps3vram: lv1_gpu_context_attribute FB_BLIT failed\n");
|
||||
+
|
||||
+ if ((priv->fifo_ptr - priv->fifo_base) * sizeof(uint32_t) >
|
||||
+ FIFO_SIZE - 1024) {
|
||||
+ dbg("fifo full, rewinding");
|
||||
+ ps3vram_wait_ring(mtd, 200);
|
||||
+ ps3vram_rewind_ring(mtd);
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&ps3_gpu_mutex);
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_bind(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
|
||||
+ ps3vram_out_ring(priv, 0x31337303);
|
||||
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
|
||||
+ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
|
||||
+ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
|
||||
+ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
|
||||
+
|
||||
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
|
||||
+ ps3vram_out_ring(priv, 0x3137c0de);
|
||||
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
|
||||
+ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
|
||||
+ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
|
||||
+ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
|
||||
+
|
||||
+ ps3vram_fire_ring(mtd);
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset,
|
||||
+ unsigned int dst_offset, int len, int count)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH,
|
||||
+ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
||||
+ ps3vram_out_ring(priv, XDR_IOIF + src_offset);
|
||||
+ ps3vram_out_ring(priv, dst_offset);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, count);
|
||||
+ ps3vram_out_ring(priv, (1 << 8) | 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+
|
||||
+ ps3vram_notifier_reset(mtd);
|
||||
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH,
|
||||
+ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+ ps3vram_fire_ring(mtd);
|
||||
+ if (ps3vram_notifier_wait(mtd, 200) < 0) {
|
||||
+ pr_err("notifier timeout\n");
|
||||
+ ps3vram_dump_ring(mtd);
|
||||
+ ps3vram_dump_reports(mtd);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset,
|
||||
+ unsigned int dst_offset, int len, int count)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
|
||||
+ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
||||
+ ps3vram_out_ring(priv, src_offset);
|
||||
+ ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, len);
|
||||
+ ps3vram_out_ring(priv, count);
|
||||
+ ps3vram_out_ring(priv, (1 << 8) | 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+
|
||||
+ ps3vram_notifier_reset(mtd);
|
||||
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
|
||||
+ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
|
||||
+ ps3vram_out_ring(priv, 0);
|
||||
+ ps3vram_fire_ring(mtd);
|
||||
+ if (ps3vram_notifier_wait(mtd, 200) < 0) {
|
||||
+ pr_err("notifier timeout\n");
|
||||
+ ps3vram_dump_ring(mtd);
|
||||
+ ps3vram_dump_reports(mtd);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_cache_evict(struct mtd_info *mtd, int entry)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ struct ps3vram_cache *cache = &priv->cache;
|
||||
+
|
||||
+ if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) {
|
||||
+ dbg("flushing %d : 0x%08x", entry, cache->tags[entry].address);
|
||||
+ if (ps3vram_upload(mtd,
|
||||
+ CACHE_OFFSET + entry * cache->page_size,
|
||||
+ cache->tags[entry].address,
|
||||
+ DMA_PAGE_SIZE,
|
||||
+ cache->page_size / DMA_PAGE_SIZE) < 0) {
|
||||
+ pr_err("failed to upload from 0x%x to 0x%x size 0x%x\n",
|
||||
+ entry * cache->page_size,
|
||||
+ cache->tags[entry].address,
|
||||
+ cache->page_size);
|
||||
+ }
|
||||
+ cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_cache_load(struct mtd_info *mtd, int entry,
|
||||
+ unsigned int address)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ struct ps3vram_cache *cache = &priv->cache;
|
||||
+
|
||||
+ dbg("fetching %d : 0x%08x", entry, address);
|
||||
+ if (ps3vram_download(mtd,
|
||||
+ address,
|
||||
+ CACHE_OFFSET + entry * cache->page_size,
|
||||
+ DMA_PAGE_SIZE,
|
||||
+ cache->page_size / DMA_PAGE_SIZE) < 0) {
|
||||
+ pr_err("failed to download from 0x%x to 0x%x size 0x%x\n",
|
||||
+ address,
|
||||
+ entry * cache->page_size,
|
||||
+ cache->page_size);
|
||||
+ }
|
||||
+
|
||||
+ cache->tags[entry].address = address;
|
||||
+ cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void ps3vram_cache_flush(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ struct ps3vram_cache *cache = &priv->cache;
|
||||
+ int i;
|
||||
+
|
||||
+ dbg("FLUSH");
|
||||
+ for (i = 0; i < cache->page_count; i++) {
|
||||
+ ps3vram_cache_evict(mtd, i);
|
||||
+ cache->tags[i].flags = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ struct ps3vram_cache *cache = &priv->cache;
|
||||
+ unsigned int base;
|
||||
+ unsigned int offset;
|
||||
+ int i;
|
||||
+ static int counter;
|
||||
+
|
||||
+ offset = (unsigned int) (address & (cache->page_size - 1));
|
||||
+ base = (unsigned int) (address - offset);
|
||||
+
|
||||
+ /* fully associative check */
|
||||
+ for (i = 0; i < cache->page_count; i++) {
|
||||
+ if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
|
||||
+ cache->tags[i].address == base) {
|
||||
+ dbg("found entry %d : 0x%08x",
|
||||
+ i, cache->tags[i].address);
|
||||
+ return i;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* choose a random entry */
|
||||
+ i = (jiffies + (counter++)) % cache->page_count;
|
||||
+ dbg("using cache entry %d", i);
|
||||
+
|
||||
+ ps3vram_cache_evict(mtd, i);
|
||||
+ ps3vram_cache_load(mtd, i, base);
|
||||
+
|
||||
+ return i;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_cache_init(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ pr_info("creating cache: %d entries, %d bytes pages\n",
|
||||
+ CACHE_PAGE_COUNT, CACHE_PAGE_SIZE);
|
||||
+
|
||||
+ priv->cache.page_count = CACHE_PAGE_COUNT;
|
||||
+ priv->cache.page_size = CACHE_PAGE_SIZE;
|
||||
+ priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
|
||||
+ CACHE_PAGE_COUNT, GFP_KERNEL);
|
||||
+ if (priv->cache.tags == NULL) {
|
||||
+ pr_err("could not allocate cache tags\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ps3vram_cache_cleanup(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ ps3vram_cache_flush(mtd);
|
||||
+ kfree(priv->cache.tags);
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+
|
||||
+ if (instr->addr + instr->len > mtd->size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&priv->lock);
|
||||
+
|
||||
+ ps3vram_cache_flush(mtd);
|
||||
+
|
||||
+ /* Set bytes to 0xFF */
|
||||
+ memset(priv->base + instr->addr, 0xFF, instr->len);
|
||||
+
|
||||
+ mutex_unlock(&priv->lock);
|
||||
+
|
||||
+ instr->state = MTD_ERASE_DONE;
|
||||
+ mtd_erase_callback(instr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
+ size_t *retlen, u_char *buf)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ unsigned int cached, count;
|
||||
+
|
||||
+ dbg("from = 0x%08x len = 0x%zx", (unsigned int) from, len);
|
||||
+
|
||||
+ if (from >= mtd->size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (len > mtd->size - from)
|
||||
+ len = mtd->size - from;
|
||||
+
|
||||
+ /* Copy from vram to buf */
|
||||
+ count = len;
|
||||
+ while (count) {
|
||||
+ unsigned int offset, avail;
|
||||
+ unsigned int entry;
|
||||
+
|
||||
+ offset = (unsigned int) (from & (priv->cache.page_size - 1));
|
||||
+ avail = priv->cache.page_size - offset;
|
||||
+
|
||||
+ mutex_lock(&priv->lock);
|
||||
+
|
||||
+ entry = ps3vram_cache_match(mtd, from);
|
||||
+ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
||||
+
|
||||
+ dbg("from=%08x cached=%08x offset=%08x avail=%08x count=%08x",
|
||||
+ (unsigned)from, cached, offset, avail, count);
|
||||
+
|
||||
+ if (avail > count)
|
||||
+ avail = count;
|
||||
+ memcpy(buf, priv->xdr_buf + cached, avail);
|
||||
+
|
||||
+ mutex_unlock(&priv->lock);
|
||||
+
|
||||
+ buf += avail;
|
||||
+ count -= avail;
|
||||
+ from += avail;
|
||||
+ }
|
||||
+
|
||||
+ *retlen = len;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
+ size_t *retlen, const u_char *buf)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv = mtd->priv;
|
||||
+ unsigned int cached, count;
|
||||
+
|
||||
+ if (to >= mtd->size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (len > mtd->size - to)
|
||||
+ len = mtd->size - to;
|
||||
+
|
||||
+ /* Copy from buf to vram */
|
||||
+ count = len;
|
||||
+ while (count) {
|
||||
+ unsigned int offset, avail;
|
||||
+ unsigned int entry;
|
||||
+
|
||||
+ offset = (unsigned int) (to & (priv->cache.page_size - 1));
|
||||
+ avail = priv->cache.page_size - offset;
|
||||
+
|
||||
+ mutex_lock(&priv->lock);
|
||||
+
|
||||
+ entry = ps3vram_cache_match(mtd, to);
|
||||
+ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
||||
+
|
||||
+ dbg("to=%08x cached=%08x offset=%08x avail=%08x count=%08x",
|
||||
+ (unsigned) to, cached, offset, avail, count);
|
||||
+
|
||||
+ if (avail > count)
|
||||
+ avail = count;
|
||||
+ memcpy(priv->xdr_buf + cached, buf, avail);
|
||||
+
|
||||
+ priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
|
||||
+
|
||||
+ mutex_unlock(&priv->lock);
|
||||
+
|
||||
+ buf += avail;
|
||||
+ count -= avail;
|
||||
+ to += avail;
|
||||
+ }
|
||||
+
|
||||
+ *retlen = len;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv;
|
||||
+ uint64_t status;
|
||||
+ uint64_t ddr_lpar, ctrl_lpar, info_lpar, reports_lpar;
|
||||
+ int64_t ddr_size;
|
||||
+ uint64_t reports_size;
|
||||
+ int ret = -ENOMEM;
|
||||
+ char *rest;
|
||||
+
|
||||
+ ret = -EIO;
|
||||
+ ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL);
|
||||
+ if (!ps3vram_mtd.priv)
|
||||
+ goto out;
|
||||
+ priv = ps3vram_mtd.priv;
|
||||
+
|
||||
+ mutex_init(&priv->lock);
|
||||
+
|
||||
+ /* Allocate XDR buffer (1MB aligned) */
|
||||
+ priv->xdr_buf = (uint8_t *) __get_free_pages(GFP_KERNEL,
|
||||
+ get_order(XDR_BUF_SIZE));
|
||||
+ if (priv->xdr_buf == NULL) {
|
||||
+ pr_err("ps3vram: could not allocate XDR buffer\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_priv;
|
||||
+ }
|
||||
+
|
||||
+ /* Put FIFO at begginning of XDR buffer */
|
||||
+ priv->fifo_base = (uint32_t *) (priv->xdr_buf + FIFO_OFFSET);
|
||||
+ priv->fifo_ptr = priv->fifo_base;
|
||||
+
|
||||
+ /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
|
||||
+ if (ps3_open_hv_device(dev)) {
|
||||
+ pr_err("ps3vram: ps3_open_hv_device failed\n");
|
||||
+ ret = -EAGAIN;
|
||||
+ goto out_close_gpu;
|
||||
+ }
|
||||
+
|
||||
+ /* Request memory */
|
||||
+ status = -1;
|
||||
+ ddr_size = memparse(size, &rest);
|
||||
+ if (*rest == '-')
|
||||
+ ddr_size -= ps3fb_videomemory.size;
|
||||
+ ddr_size = ALIGN(ddr_size, 1024*1024);
|
||||
+ if (ddr_size <= 0) {
|
||||
+ printk(KERN_ERR "ps3vram: specified size is too small\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto out_close_gpu;
|
||||
+ }
|
||||
+
|
||||
+ while (ddr_size > 0) {
|
||||
+ status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
|
||||
+ &priv->memory_handle,
|
||||
+ &ddr_lpar);
|
||||
+ if (status == 0)
|
||||
+ break;
|
||||
+ ddr_size -= 1024*1024;
|
||||
+ }
|
||||
+ if (status != 0 || ddr_size <= 0) {
|
||||
+ pr_err("ps3vram: lv1_gpu_memory_allocate failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_xdr_buf;
|
||||
+ }
|
||||
+ pr_info("ps3vram: allocated %u MiB of DDR memory\n",
|
||||
+ (unsigned int) (ddr_size / 1024 / 1024));
|
||||
+
|
||||
+ /* Request context */
|
||||
+ status = lv1_gpu_context_allocate(priv->memory_handle,
|
||||
+ 0,
|
||||
+ &priv->context_handle,
|
||||
+ &ctrl_lpar,
|
||||
+ &info_lpar,
|
||||
+ &reports_lpar,
|
||||
+ &reports_size);
|
||||
+ if (status) {
|
||||
+ pr_err("ps3vram: lv1_gpu_context_allocate failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_memory;
|
||||
+ }
|
||||
+
|
||||
+ /* Map XDR buffer to RSX */
|
||||
+ status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
|
||||
+ ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
|
||||
+ XDR_BUF_SIZE, 0);
|
||||
+ if (status) {
|
||||
+ pr_err("ps3vram: lv1_gpu_context_iomap failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_context;
|
||||
+ }
|
||||
+
|
||||
+ priv->base = ioremap(ddr_lpar, ddr_size);
|
||||
+ if (!priv->base) {
|
||||
+ pr_err("ps3vram: ioremap failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_context;
|
||||
+ }
|
||||
+
|
||||
+ priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
|
||||
+ if (!priv->ctrl) {
|
||||
+ pr_err("ps3vram: ioremap failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_unmap_vram;
|
||||
+ }
|
||||
+
|
||||
+ priv->reports = ioremap(reports_lpar, reports_size);
|
||||
+ if (!priv->reports) {
|
||||
+ pr_err("ps3vram: ioremap failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_unmap_ctrl;
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&ps3_gpu_mutex);
|
||||
+ ps3vram_init_ring(&ps3vram_mtd);
|
||||
+ mutex_unlock(&ps3_gpu_mutex);
|
||||
+
|
||||
+ ps3vram_mtd.name = "ps3vram";
|
||||
+ ps3vram_mtd.size = ddr_size;
|
||||
+ ps3vram_mtd.flags = MTD_CAP_RAM;
|
||||
+ ps3vram_mtd.erase = ps3vram_erase;
|
||||
+ ps3vram_mtd.point = NULL;
|
||||
+ ps3vram_mtd.unpoint = NULL;
|
||||
+ ps3vram_mtd.read = ps3vram_read;
|
||||
+ ps3vram_mtd.write = ps3vram_write;
|
||||
+ ps3vram_mtd.owner = THIS_MODULE;
|
||||
+ ps3vram_mtd.type = MTD_RAM;
|
||||
+ ps3vram_mtd.erasesize = CACHE_PAGE_SIZE;
|
||||
+ ps3vram_mtd.writesize = 1;
|
||||
+
|
||||
+ ps3vram_bind(&ps3vram_mtd);
|
||||
+
|
||||
+ mutex_lock(&ps3_gpu_mutex);
|
||||
+ ret = ps3vram_wait_ring(&ps3vram_mtd, 100);
|
||||
+ mutex_unlock(&ps3_gpu_mutex);
|
||||
+ if (ret < 0) {
|
||||
+ pr_err("failed to initialize channels\n");
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ goto out_unmap_reports;
|
||||
+ }
|
||||
+
|
||||
+ ps3vram_cache_init(&ps3vram_mtd);
|
||||
+
|
||||
+ if (add_mtd_device(&ps3vram_mtd)) {
|
||||
+ pr_err("ps3vram: failed to register device\n");
|
||||
+ ret = -EAGAIN;
|
||||
+ goto out_cache_cleanup;
|
||||
+ }
|
||||
+
|
||||
+ pr_info("ps3vram mtd device registered, %lu bytes\n", ddr_size);
|
||||
+ return 0;
|
||||
+
|
||||
+out_cache_cleanup:
|
||||
+ ps3vram_cache_cleanup(&ps3vram_mtd);
|
||||
+out_unmap_reports:
|
||||
+ iounmap(priv->reports);
|
||||
+out_unmap_ctrl:
|
||||
+ iounmap(priv->ctrl);
|
||||
+out_unmap_vram:
|
||||
+ iounmap(priv->base);
|
||||
+out_free_context:
|
||||
+ lv1_gpu_context_free(priv->context_handle);
|
||||
+out_free_memory:
|
||||
+ lv1_gpu_memory_free(priv->memory_handle);
|
||||
+out_close_gpu:
|
||||
+ ps3_close_hv_device(dev);
|
||||
+out_free_xdr_buf:
|
||||
+ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||
+out_free_priv:
|
||||
+ kfree(ps3vram_mtd.priv);
|
||||
+ ps3vram_mtd.priv = NULL;
|
||||
+out:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int ps3vram_shutdown(struct ps3_system_bus_device *dev)
|
||||
+{
|
||||
+ struct ps3vram_priv *priv;
|
||||
+
|
||||
+ priv = ps3vram_mtd.priv;
|
||||
+
|
||||
+ del_mtd_device(&ps3vram_mtd);
|
||||
+ ps3vram_cache_cleanup(&ps3vram_mtd);
|
||||
+ iounmap(priv->reports);
|
||||
+ iounmap(priv->ctrl);
|
||||
+ iounmap(priv->base);
|
||||
+ lv1_gpu_context_free(priv->context_handle);
|
||||
+ lv1_gpu_memory_free(priv->memory_handle);
|
||||
+ ps3_close_hv_device(dev);
|
||||
+ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||
+ kfree(priv);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct ps3_system_bus_driver ps3vram_driver = {
|
||||
+ .match_id = PS3_MATCH_ID_GRAPHICS,
|
||||
+ .match_sub_id = PS3_MATCH_SUB_ID_RAMDISK,
|
||||
+ .core.name = DEVICE_NAME,
|
||||
+ .core.owner = THIS_MODULE,
|
||||
+ .probe = ps3vram_probe,
|
||||
+ .remove = ps3vram_shutdown,
|
||||
+ .shutdown = ps3vram_shutdown,
|
||||
+};
|
||||
+
|
||||
+static int __init ps3vram_init(void)
|
||||
+{
|
||||
+ return ps3_system_bus_driver_register(&ps3vram_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit ps3vram_exit(void)
|
||||
+{
|
||||
+ ps3_system_bus_driver_unregister(&ps3vram_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(ps3vram_init);
|
||||
+module_exit(ps3vram_exit);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Jim Paris <jim@jtan.com>");
|
||||
+MODULE_DESCRIPTION("MTD driver for PS3 video RAM");
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -3353,6 +3353,12 @@ L: linuxppc-dev@ozlabs.org
|
||||
L: cbe-oss-dev@ozlabs.org
|
||||
S: Supported
|
||||
|
||||
+PS3VRAM DRIVER
|
||||
+P: Jim Paris
|
||||
+M: jim@jtan.com
|
||||
+L: cbe-oss-dev@ozlabs.org
|
||||
+S: Maintained
|
||||
+
|
||||
PVRUSB2 VIDEO4LINUX DRIVER
|
||||
P: Mike Isely
|
||||
M: isely@pobox.com
|
||||
@@ -0,0 +1,57 @@
|
||||
Subject: Unable to Use Small BSR register on Power LPAR
|
||||
From: Sonny Rao <sonnyrao@us.ibm.com>
|
||||
References: 443673 - LTC49749
|
||||
|
||||
Fix the BSR driver to allow small BSR devices on a 64k page kernel.
|
||||
Previously the driver would reject the mmap since the size was smaller
|
||||
than PAGESIZE. This patch adds a check for this case and uses remap_4k_pfn().
|
||||
|
||||
Also, take out code to set vm_flags, as the remap_pfn functions will
|
||||
do this for us.
|
||||
|
||||
Signed-off-by: Sonny Rao <sonnyrao@us.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
drivers/char/bsr.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/char/bsr.c
|
||||
+++ b/drivers/char/bsr.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
+#include <asm/pgtable.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
@@ -115,15 +116,22 @@ static int bsr_mmap(struct file *filp, s
|
||||
{
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
struct bsr_dev *dev = filp->private_data;
|
||||
+ int ret;
|
||||
|
||||
- if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
|
||||
- return -EINVAL;
|
||||
-
|
||||
- vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
- if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
|
||||
- size, vma->vm_page_prot))
|
||||
+ /* check for the case of a small BSR device and map one 4k page for it*/
|
||||
+ if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
|
||||
+ ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
|
||||
+ vma->vm_page_prot);
|
||||
+ else if (size <= dev->bsr_len)
|
||||
+ ret = io_remap_pfn_range(vma, vma->vm_start,
|
||||
+ dev->bsr_addr >> PAGE_SHIFT,
|
||||
+ size, vma->vm_page_prot);
|
||||
+ else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (ret)
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,206 @@
|
||||
Subject: Add support for multiple BSR nodes in the device tree.
|
||||
From: Sonny Rao <sonnyrao@us.ibm.com>
|
||||
References: 443665 - LTC49817
|
||||
|
||||
Previously, the BSR driver only supported a single OF node describing
|
||||
a BSR. Apparently when an LPAR is set to use "all system resources"
|
||||
the BSR appears as a single node, but when it is handed out in pieces,
|
||||
each 8 byte piece gets its own node. So, keep a list of bsr devices
|
||||
instead of the array and include all nodes.
|
||||
|
||||
Also, be more inclusive of what BSR devices we accept by only checking
|
||||
compatibility and not the device name property (which might change in
|
||||
the future versions of BSR).
|
||||
|
||||
Signed-off-by: Sonny Rao <sonnyrao@us.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
drivers/char/bsr.c | 84 ++++++++++++++++++++++++++++++++++-------------------
|
||||
1 file changed, 55 insertions(+), 29 deletions(-)
|
||||
|
||||
--- a/drivers/char/bsr.c
|
||||
+++ b/drivers/char/bsr.c
|
||||
@@ -61,6 +61,8 @@ struct bsr_dev {
|
||||
unsigned bsr_num; /* bsr id number for its type */
|
||||
int bsr_minor;
|
||||
|
||||
+ struct list_head bsr_list;
|
||||
+
|
||||
dev_t bsr_dev;
|
||||
struct cdev bsr_cdev;
|
||||
struct device *bsr_device;
|
||||
@@ -68,8 +70,8 @@ struct bsr_dev {
|
||||
|
||||
};
|
||||
|
||||
-static unsigned num_bsr_devs;
|
||||
-static struct bsr_dev *bsr_devs;
|
||||
+static unsigned total_bsr_devs;
|
||||
+static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
|
||||
static struct class *bsr_class;
|
||||
static int bsr_major;
|
||||
|
||||
@@ -154,24 +156,25 @@ const static struct file_operations bsr_
|
||||
|
||||
static void bsr_cleanup_devs(void)
|
||||
{
|
||||
- int i;
|
||||
- for (i=0 ; i < num_bsr_devs; i++) {
|
||||
- struct bsr_dev *cur = bsr_devs + i;
|
||||
+ struct bsr_dev *cur, *n;
|
||||
+
|
||||
+ list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
|
||||
if (cur->bsr_device) {
|
||||
cdev_del(&cur->bsr_cdev);
|
||||
device_del(cur->bsr_device);
|
||||
}
|
||||
+ list_del(&cur->bsr_list);
|
||||
+ kfree(cur);
|
||||
}
|
||||
-
|
||||
- kfree(bsr_devs);
|
||||
}
|
||||
|
||||
-static int bsr_create_devs(struct device_node *bn)
|
||||
+static int bsr_add_node(struct device_node *bn)
|
||||
{
|
||||
- int bsr_stride_len, bsr_bytes_len;
|
||||
+ int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
|
||||
const u32 *bsr_stride;
|
||||
const u32 *bsr_bytes;
|
||||
unsigned i;
|
||||
+ int ret = -ENODEV;
|
||||
|
||||
bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
|
||||
bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
|
||||
@@ -179,35 +182,36 @@ static int bsr_create_devs(struct device
|
||||
if (!bsr_stride || !bsr_bytes ||
|
||||
(bsr_stride_len != bsr_bytes_len)) {
|
||||
printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
num_bsr_devs = bsr_bytes_len / sizeof(u32);
|
||||
|
||||
- /* only a warning, its informational since we'll fail and exit */
|
||||
- WARN_ON(num_bsr_devs > BSR_MAX_DEVS);
|
||||
-
|
||||
- bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL);
|
||||
- if (!bsr_devs)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
for (i = 0 ; i < num_bsr_devs; i++) {
|
||||
- struct bsr_dev *cur = bsr_devs + i;
|
||||
+ struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
|
||||
+ GFP_KERNEL);
|
||||
struct resource res;
|
||||
int result;
|
||||
|
||||
+ if (!cur) {
|
||||
+ printk(KERN_ERR "Unable to alloc bsr dev\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+
|
||||
result = of_address_to_resource(bn, i, &res);
|
||||
if (result < 0) {
|
||||
- printk(KERN_ERR "bsr of-node has invalid reg property\n");
|
||||
- goto out_err;
|
||||
+ printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
|
||||
+ kfree(cur);
|
||||
+ continue;
|
||||
}
|
||||
|
||||
- cur->bsr_minor = i;
|
||||
+ cur->bsr_minor = i + total_bsr_devs;
|
||||
cur->bsr_addr = res.start;
|
||||
cur->bsr_len = res.end - res.start + 1;
|
||||
cur->bsr_bytes = bsr_bytes[i];
|
||||
cur->bsr_stride = bsr_stride[i];
|
||||
- cur->bsr_dev = MKDEV(bsr_major, i);
|
||||
+ cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
|
||||
|
||||
switch(cur->bsr_bytes) {
|
||||
case 8:
|
||||
@@ -228,14 +232,15 @@ static int bsr_create_devs(struct device
|
||||
}
|
||||
|
||||
cur->bsr_num = bsr_types[cur->bsr_type];
|
||||
- bsr_types[cur->bsr_type] = cur->bsr_num + 1;
|
||||
snprintf(cur->bsr_name, 32, "bsr%d_%d",
|
||||
cur->bsr_bytes, cur->bsr_num);
|
||||
|
||||
cdev_init(&cur->bsr_cdev, &bsr_fops);
|
||||
result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
|
||||
- if (result)
|
||||
+ if (result) {
|
||||
+ kfree(cur);
|
||||
goto out_err;
|
||||
+ }
|
||||
|
||||
cur->bsr_device = device_create_drvdata(bsr_class, NULL,
|
||||
cur->bsr_dev,
|
||||
@@ -244,16 +249,37 @@ static int bsr_create_devs(struct device
|
||||
printk(KERN_ERR "device_create failed for %s\n",
|
||||
cur->bsr_name);
|
||||
cdev_del(&cur->bsr_cdev);
|
||||
+ kfree(cur);
|
||||
goto out_err;
|
||||
}
|
||||
+
|
||||
+ bsr_types[cur->bsr_type] = cur->bsr_num + 1;
|
||||
+ list_add_tail(&cur->bsr_list, &bsr_devs);
|
||||
}
|
||||
|
||||
+ total_bsr_devs += num_bsr_devs;
|
||||
+
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
|
||||
bsr_cleanup_devs();
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bsr_create_devs(struct device_node *bn)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ while (bn) {
|
||||
+ ret = bsr_add_node(bn);
|
||||
+ if (ret) {
|
||||
+ of_node_put(bn);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
|
||||
+ }
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int __init bsr_init(void)
|
||||
@@ -263,7 +289,7 @@ static int __init bsr_init(void)
|
||||
int ret = -ENODEV;
|
||||
int result;
|
||||
|
||||
- np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr");
|
||||
+ np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
|
||||
if (!np)
|
||||
goto out_err;
|
||||
|
||||
@@ -281,10 +307,10 @@ static int __init bsr_init(void)
|
||||
goto out_err_2;
|
||||
}
|
||||
|
||||
- if ((ret = bsr_create_devs(np)) < 0)
|
||||
+ if ((ret = bsr_create_devs(np)) < 0) {
|
||||
+ np = NULL;
|
||||
goto out_err_3;
|
||||
-
|
||||
- of_node_put(np);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
Subject: powerpc: Update page in counter for CMM
|
||||
From: Brian King <brking@linux.vnet.ibm.com>
|
||||
References: 445540 - LTC49942
|
||||
|
||||
A new field has been added to the VPA as a method for
|
||||
the client OS to communicate to firmware the number of
|
||||
page ins it is performing when running collaborative
|
||||
memory overcommit. The hypervisor will use this information
|
||||
to better determine if a partition is experiencing memory
|
||||
pressure and needs more memory allocated to it.
|
||||
|
||||
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
|
||||
Signed-off-by: Robert Jennings <rcjenn@linux.vnet.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
|
||||
arch/powerpc/include/asm/lppaca.h | 3 ++-
|
||||
arch/powerpc/kernel/paca.c | 1 +
|
||||
arch/powerpc/mm/fault.c | 12 ++++++++++--
|
||||
3 files changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/include/asm/lppaca.h
|
||||
+++ b/arch/powerpc/include/asm/lppaca.h
|
||||
@@ -133,7 +133,8 @@ struct lppaca {
|
||||
//=============================================================================
|
||||
// CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
|
||||
//=============================================================================
|
||||
- u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF
|
||||
+ u32 page_ins; // CMO Hint - # page ins by OS x00-x04
|
||||
+ u8 pmc_save_area[252]; // PMC interrupt Area x04-xFF
|
||||
} __attribute__((__aligned__(0x400)));
|
||||
|
||||
extern struct lppaca lppaca[];
|
||||
--- a/arch/powerpc/kernel/paca.c
|
||||
+++ b/arch/powerpc/kernel/paca.c
|
||||
@@ -36,6 +36,7 @@ struct lppaca lppaca[] = {
|
||||
.end_of_quantum = 0xfffffffffffffffful,
|
||||
.slb_count = 64,
|
||||
.vmxregs_in_use = 0,
|
||||
+ .page_ins = 0,
|
||||
},
|
||||
};
|
||||
|
||||
--- a/arch/powerpc/mm/fault.c
|
||||
+++ b/arch/powerpc/mm/fault.c
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kdebug.h>
|
||||
|
||||
+#include <asm/firmware.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/mmu.h>
|
||||
@@ -318,9 +319,16 @@ good_area:
|
||||
goto do_sigbus;
|
||||
BUG();
|
||||
}
|
||||
- if (ret & VM_FAULT_MAJOR)
|
||||
+ if (ret & VM_FAULT_MAJOR) {
|
||||
current->maj_flt++;
|
||||
- else
|
||||
+#ifdef CONFIG_PPC_SMLPAR
|
||||
+ if (firmware_has_feature(FW_FEATURE_CMO)) {
|
||||
+ preempt_disable();
|
||||
+ get_lppaca()->page_ins += (1 << PAGE_FACTOR);
|
||||
+ preempt_enable();
|
||||
+ }
|
||||
+#endif
|
||||
+ } else
|
||||
current->min_flt++;
|
||||
up_read(&mm->mmap_sem);
|
||||
return 0;
|
||||
@@ -0,0 +1,60 @@
|
||||
Subject: Update default_server during migrate_irqs_away
|
||||
From: Milton Miller <miltonm@bga.com>
|
||||
References: 460566 - LTC50723
|
||||
|
||||
Currently, every time we determine which irq server to use, we check if
|
||||
default_server, which is the id of the bootcpu, is still online. But
|
||||
default_server is a hardware cpu, not the logical cpu id needed to index
|
||||
cpu_online_map.
|
||||
|
||||
Since the default server can only go offline during a cpu hotplug event,
|
||||
explicitly check the default server and choose the new one when we move
|
||||
irqs away from the cpu being offlined.
|
||||
|
||||
This has the added benefit of only needing the boot_cpuid to be updated
|
||||
and not relying on the cpu being marked offline during migrate_irqs_away.
|
||||
|
||||
Also, since xics_update_irq_servers only reads device tree information, we
|
||||
can call it before xics_init_host in xics_init_IRQ and then default_server
|
||||
will always be valid when we can reach get_irq_server via the host ops.
|
||||
|
||||
Signed-off-by: Milton Miller <miltonm@bga.com>
|
||||
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
---
|
||||
arch/powerpc/platforms/pseries/xics.c | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/pseries/xics.c
|
||||
+++ b/arch/powerpc/platforms/pseries/xics.c
|
||||
@@ -208,9 +208,6 @@ static int get_irq_server(unsigned int v
|
||||
cpumask_t cpumask = irq_desc[virq].affinity;
|
||||
cpumask_t tmp = CPU_MASK_NONE;
|
||||
|
||||
- if (! cpu_isset(default_server, cpu_online_map))
|
||||
- xics_update_irq_servers();
|
||||
-
|
||||
if (!distribute_irqs)
|
||||
return default_server;
|
||||
|
||||
@@ -659,8 +656,8 @@ void __init xics_init_IRQ(void)
|
||||
if (found == 0)
|
||||
return;
|
||||
|
||||
- xics_init_host();
|
||||
xics_update_irq_servers();
|
||||
+ xics_init_host();
|
||||
|
||||
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||
ppc_md.get_irq = xics_get_irq_lpar;
|
||||
@@ -753,6 +750,10 @@ void xics_migrate_irqs_away(void)
|
||||
int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
|
||||
unsigned int irq, virq;
|
||||
|
||||
+ /* If we used to be the default server, move to the new "boot_cpuid" */
|
||||
+ if (hw_cpu == default_server)
|
||||
+ xics_update_irq_servers();
|
||||
+
|
||||
/* Reject any interrupt that was queued to us... */
|
||||
xics_set_cpu_priority(0);
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
Subject: Fix partition migration hang under load
|
||||
From: Brian King <brking@linux.vnet.ibm.com>
|
||||
References: 470563 - LTC51153
|
||||
|
||||
While testing partition migration with heavy CPU load using
|
||||
shared processors, it was observed that sometimes the migration
|
||||
would never complete and would appear to hang. Currently, the
|
||||
migration code assumes that if H_SUCCESS is returned from the H_JOIN
|
||||
then the migration is complete and the processor is waking up on
|
||||
the target system. If there was an outstanding PROD to the processor
|
||||
when the H_JOIN is called, however, it will return H_SUCCESS on the source
|
||||
system, causing the migration to hang, or in some scenarios cause
|
||||
the kernel to crash on the complete call waking the caller
|
||||
of rtas_percpu_suspend_me.
|
||||
|
||||
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
---
|
||||
|
||||
arch/powerpc/kernel/rtas.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/rtas.c
|
||||
+++ b/arch/powerpc/kernel/rtas.c
|
||||
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(rtas);
|
||||
|
||||
struct rtas_suspend_me_data {
|
||||
atomic_t working; /* number of cpus accessing this struct */
|
||||
+ atomic_t done;
|
||||
int token; /* ibm,suspend-me */
|
||||
int error;
|
||||
struct completion *complete; /* wait on this until working == 0 */
|
||||
@@ -663,7 +664,7 @@ static int ibm_suspend_me_token = RTAS_U
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
static void rtas_percpu_suspend_me(void *info)
|
||||
{
|
||||
- long rc;
|
||||
+ long rc = H_SUCCESS;
|
||||
unsigned long msr_save;
|
||||
int cpu;
|
||||
struct rtas_suspend_me_data *data =
|
||||
@@ -675,7 +676,8 @@ static void rtas_percpu_suspend_me(void
|
||||
msr_save = mfmsr();
|
||||
mtmsr(msr_save & ~(MSR_EE));
|
||||
|
||||
- rc = plpar_hcall_norets(H_JOIN);
|
||||
+ while (rc == H_SUCCESS && !atomic_read(&data->done))
|
||||
+ rc = plpar_hcall_norets(H_JOIN);
|
||||
|
||||
mtmsr(msr_save);
|
||||
|
||||
@@ -698,6 +700,9 @@ static void rtas_percpu_suspend_me(void
|
||||
smp_processor_id(), rc);
|
||||
data->error = rc;
|
||||
}
|
||||
+
|
||||
+ atomic_set(&data->done, 1);
|
||||
+
|
||||
/* This cpu did the suspend or got an error; in either case,
|
||||
* we need to prod all other other cpus out of join state.
|
||||
* Extra prods are harmless.
|
||||
@@ -740,6 +745,7 @@ static int rtas_ibm_suspend_me(struct rt
|
||||
}
|
||||
|
||||
atomic_set(&data.working, 0);
|
||||
+ atomic_set(&data.done, 0);
|
||||
data.token = rtas_token("ibm,suspend-me");
|
||||
data.error = 0;
|
||||
data.complete = &done;
|
||||
@@ -0,0 +1,46 @@
|
||||
Subject: Bug 435181 - DMEM add caused kernel opps after ehca rejected request
|
||||
From: olh@suse.de
|
||||
References: 435181
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/pseries/hotplug-memory.c | 12 ++++++++++++
|
||||
mm/memory_hotplug.c | 4 ++--
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
|
||||
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
|
||||
@@ -22,6 +22,18 @@ static int pseries_remove_lmb(unsigned l
|
||||
int ret;
|
||||
|
||||
start_pfn = base >> PAGE_SHIFT;
|
||||
+
|
||||
+ if (!pfn_valid(start_pfn)) {
|
||||
+ /*
|
||||
+ * Failing hotplug memory add will end up calling
|
||||
+ * remove device node to clean up. Since its already
|
||||
+ * added to lmbs, we need to remove it and pretend
|
||||
+ * success.
|
||||
+ */
|
||||
+ lmb_remove(base, lmb_size);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
zone = page_zone(pfn_to_page(start_pfn));
|
||||
|
||||
/*
|
||||
--- a/mm/memory_hotplug.c
|
||||
+++ b/mm/memory_hotplug.c
|
||||
@@ -323,11 +323,11 @@ int __remove_pages(struct zone *zone, un
|
||||
BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
|
||||
BUG_ON(nr_pages % PAGES_PER_SECTION);
|
||||
|
||||
- release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE);
|
||||
-
|
||||
sections_to_remove = nr_pages / PAGES_PER_SECTION;
|
||||
for (i = 0; i < sections_to_remove; i++) {
|
||||
unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
|
||||
+ release_mem_region(pfn << PAGE_SHIFT,
|
||||
+ PAGES_PER_SECTION << PAGE_SHIFT);
|
||||
ret = __remove_section(zone, __pfn_to_section(pfn));
|
||||
if (ret)
|
||||
break;
|
||||
@@ -0,0 +1,32 @@
|
||||
Subject: Bug 431380 – UPT-LTE: mem dlpar remove generates oops(.pseries_remove_lmb+0x28/0xb8)
|
||||
From: Nathan Fontenot <nfont@austin.ibm.com>
|
||||
References: 431380 - LTC48430
|
||||
|
||||
|
||||
Testing hotplug memory remove has revealed that we can oops in
|
||||
pseries_lmb_remove(). The incorrect shift causes a NULL pointer
|
||||
dereference in the page_zone() inline routine.
|
||||
|
||||
I have only been able to reproduce the oops on kernels with large pages
|
||||
enabled.
|
||||
|
||||
Tested on Power5 and Power6 with and without large pages enabled.
|
||||
|
||||
|
||||
Signed-off-by: Olaf Hering <olh@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/pseries/hotplug-memory.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
|
||||
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
|
||||
@@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned l
|
||||
struct zone *zone;
|
||||
int ret;
|
||||
|
||||
- start_pfn = base >> PFN_SECTION_SHIFT;
|
||||
+ start_pfn = base >> PAGE_SHIFT;
|
||||
zone = page_zone(pfn_to_page(start_pfn));
|
||||
|
||||
/*
|
||||
17
src/patches/suse-2.6.27.25/patches.arch/ppc-select
Normal file
17
src/patches/suse-2.6.27.25/patches.arch/ppc-select
Normal file
@@ -0,0 +1,17 @@
|
||||
From: Paul Mackerras <paulus@samba.org>
|
||||
Subject: Fix wrong error code from ppc32 select syscall
|
||||
Acked-by: schwab@suse.de
|
||||
|
||||
See <http://ozlabs.org/pipermail/linuxppc-dev/2008-October/063678.html>.
|
||||
|
||||
--- linux-2.6.27/arch/powerpc/include/asm/systbl.h.~1~ 2008-11-10 23:10:37.000000000 +0100
|
||||
+++ linux-2.6.27/arch/powerpc/include/asm/systbl.h 2008-11-11 11:39:06.000000000 +0100
|
||||
@@ -145,7 +145,7 @@ SYSCALL_SPU(setfsuid)
|
||||
SYSCALL_SPU(setfsgid)
|
||||
SYSCALL_SPU(llseek)
|
||||
COMPAT_SYS_SPU(getdents)
|
||||
-SYSX_SPU(sys_select,ppc32_select,ppc_select)
|
||||
+SYSX_SPU(sys_select,ppc32_select,sys_select)
|
||||
SYSCALL_SPU(flock)
|
||||
SYSCALL_SPU(msync)
|
||||
COMPAT_SYS_SPU(readv)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user