mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge remote-tracking branch 'origin/upstream/linux-linaro-lsk-v3.10-android' into linux-linaro-lsk-v3.10-android+android-common-3.10
Conflicts: kernel/printk.c
This commit is contained in:
@@ -571,9 +571,6 @@ tcp_limit_output_bytes - INTEGER
|
||||
typical pfifo_fast qdiscs.
|
||||
tcp_limit_output_bytes limits the number of bytes on qdisc
|
||||
or device to reduce artificial RTT/cwnd and reduce bufferbloat.
|
||||
Note: For GSO/TSO enabled flows, we try to have at least two
|
||||
packets in flight. Reducing tcp_limit_output_bytes might also
|
||||
reduce the size of individual GSO packet (64KB being the max)
|
||||
Default: 131072
|
||||
|
||||
tcp_challenge_ack_limit - INTEGER
|
||||
|
||||
@@ -289,13 +289,24 @@ Default value is "/sbin/hotplug".
|
||||
kptr_restrict:
|
||||
|
||||
This toggle indicates whether restrictions are placed on
|
||||
exposing kernel addresses via /proc and other interfaces. When
|
||||
kptr_restrict is set to (0), there are no restrictions. When
|
||||
kptr_restrict is set to (1), the default, kernel pointers
|
||||
printed using the %pK format specifier will be replaced with 0's
|
||||
unless the user has CAP_SYSLOG. When kptr_restrict is set to
|
||||
(2), kernel pointers printed using %pK will be replaced with 0's
|
||||
regardless of privileges.
|
||||
exposing kernel addresses via /proc and other interfaces.
|
||||
|
||||
When kptr_restrict is set to (0), the default, there are no restrictions.
|
||||
|
||||
When kptr_restrict is set to (1), kernel pointers printed using the %pK
|
||||
format specifier will be replaced with 0's unless the user has CAP_SYSLOG
|
||||
and effective user and group ids are equal to the real ids. This is
|
||||
because %pK checks are done at read() time rather than open() time, so
|
||||
if permissions are elevated between the open() and the read() (e.g via
|
||||
a setuid binary) then %pK will not leak kernel pointers to unprivileged
|
||||
users. Note, this is a temporary solution only. The correct long-term
|
||||
solution is to do the permission checks at open() time. Consider removing
|
||||
world read permissions from files that use %pK, and using dmesg_restrict
|
||||
to protect against uses of %pK in dmesg(8) if leaking kernel pointer
|
||||
values to unprivileged users is a concern.
|
||||
|
||||
When kptr_restrict is set to (2), kernel pointers printed using
|
||||
%pK will be replaced with 0's regardless of privileges.
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 3
|
||||
PATCHLEVEL = 10
|
||||
SUBLEVEL = 21
|
||||
SUBLEVEL = 24
|
||||
EXTRAVERSION =
|
||||
NAME = TOSSUG Baby Fish
|
||||
|
||||
|
||||
@@ -11,3 +11,5 @@ way to enable these options would be:
|
||||
This will generate a .config that can then be used to save a new defconfig or
|
||||
compile a new kernel with Android features enabled.
|
||||
|
||||
Because there is no tool to consistently generate these config fragments,
|
||||
lets keep them alphabetically sorted instead of random.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# KEEP ALPHABETICALLY SORTED
|
||||
# CONFIG_INET_LRO is not set
|
||||
# CONFIG_MODULES is not set
|
||||
# CONFIG_OABI_COMPAT is not set
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
CONFIG_COMPACTION=y
|
||||
# KEEP ALPHABETICALLY SORTED
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
@@ -14,6 +11,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_COMPACTION=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_EXT4_FS=y
|
||||
@@ -81,6 +79,7 @@ CONFIG_ION=y
|
||||
CONFIG_JOYSTICK_XPAD=y
|
||||
CONFIG_JOYSTICK_XPAD_FF=y
|
||||
CONFIG_JOYSTICK_XPAD_LEDS=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
@@ -88,7 +87,9 @@ CONFIG_LOGITECH_FF=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_PM_RUNTIME=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
|
||||
@@ -690,14 +690,6 @@ config EARLY_PRINTK
|
||||
kernel low-level debugging functions. Add earlyprintk to your
|
||||
kernel parameters to enable this console.
|
||||
|
||||
config EARLY_PRINTK_DIRECT
|
||||
bool "Early printk direct"
|
||||
depends on DEBUG_LL
|
||||
help
|
||||
Say Y here if you want to have an early console using the
|
||||
kernel low-level debugging functions and EARLY_PRINTK is
|
||||
not early enough.
|
||||
|
||||
config OC_ETM
|
||||
bool "On-chip ETM and ETB"
|
||||
depends on ARM_AMBA
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
coherency-fabric@20200 {
|
||||
compatible = "marvell,coherency-fabric";
|
||||
reg = <0x20200 0xb0>, <0x21810 0x1c>;
|
||||
reg = <0x20200 0xb0>, <0x21010 0x1c>;
|
||||
};
|
||||
|
||||
serial@12000 {
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
/*
|
||||
* MV78230 has 2 PCIe units Gen2.0: One unit can be
|
||||
* configured as x4 or quad x1 lanes. One unit is
|
||||
* x4/x1.
|
||||
* x1 only.
|
||||
*/
|
||||
pcie-controller {
|
||||
compatible = "marvell,armada-xp-pcie";
|
||||
@@ -94,10 +94,10 @@
|
||||
bus-range = <0x00 0xff>;
|
||||
|
||||
ranges = <0x82000000 0 0x40000 0x40000 0 0x00002000 /* Port 0.0 registers */
|
||||
0x82000000 0 0x42000 0x42000 0 0x00002000 /* Port 2.0 registers */
|
||||
0x82000000 0 0x44000 0x44000 0 0x00002000 /* Port 0.1 registers */
|
||||
0x82000000 0 0x48000 0x48000 0 0x00002000 /* Port 0.2 registers */
|
||||
0x82000000 0 0x4c000 0x4c000 0 0x00002000 /* Port 0.3 registers */
|
||||
0x82000000 0 0x80000 0x80000 0 0x00002000 /* Port 1.0 registers */
|
||||
0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
|
||||
0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
|
||||
|
||||
@@ -165,19 +165,19 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@9,0 {
|
||||
pcie@5,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
|
||||
reg = <0x4800 0 0 0 0>;
|
||||
assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
|
||||
reg = <0x2800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 99>;
|
||||
marvell,pcie-port = <2>;
|
||||
interrupt-map = <0 0 0 0 &mpic 62>;
|
||||
marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <0>;
|
||||
clocks = <&gateclk 26>;
|
||||
clocks = <&gateclk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
/*
|
||||
* MV78260 has 3 PCIe units Gen2.0: Two units can be
|
||||
* configured as x4 or quad x1 lanes. One unit is
|
||||
* x4/x1.
|
||||
* x4 only.
|
||||
*/
|
||||
pcie-controller {
|
||||
compatible = "marvell,armada-xp-pcie";
|
||||
@@ -119,7 +119,9 @@
|
||||
0x82000000 0 0x48000 0x48000 0 0x00002000 /* Port 0.2 registers */
|
||||
0x82000000 0 0x4c000 0x4c000 0 0x00002000 /* Port 0.3 registers */
|
||||
0x82000000 0 0x80000 0x80000 0 0x00002000 /* Port 1.0 registers */
|
||||
0x82000000 0 0x82000 0x82000 0 0x00002000 /* Port 3.0 registers */
|
||||
0x82000000 0 0x84000 0x84000 0 0x00002000 /* Port 1.1 registers */
|
||||
0x82000000 0 0x88000 0x88000 0 0x00002000 /* Port 1.2 registers */
|
||||
0x82000000 0 0x8c000 0x8c000 0 0x00002000 /* Port 1.3 registers */
|
||||
0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
|
||||
0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
|
||||
|
||||
@@ -187,6 +189,70 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@5,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x80000 0 0x2000>;
|
||||
reg = <0x2800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 62>;
|
||||
marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <0>;
|
||||
clocks = <&gateclk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@6,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x84000 0 0x2000>;
|
||||
reg = <0x3000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 63>;
|
||||
marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <1>;
|
||||
clocks = <&gateclk 10>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@7,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x88000 0 0x2000>;
|
||||
reg = <0x3800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 64>;
|
||||
marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <2>;
|
||||
clocks = <&gateclk 11>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@8,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x8c000 0 0x2000>;
|
||||
reg = <0x4000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 65>;
|
||||
marvell,pcie-port = <1>;
|
||||
marvell,pcie-lane = <3>;
|
||||
clocks = <&gateclk 12>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@9,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x42000 0 0x2000>;
|
||||
@@ -202,22 +268,6 @@
|
||||
clocks = <&gateclk 26>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pcie@10,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x82000 0 0x2000>;
|
||||
reg = <0x5000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &mpic 103>;
|
||||
marvell,pcie-port = <3>;
|
||||
marvell,pcie-lane = <0>;
|
||||
clocks = <&gateclk 27>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
reg = <0x7e205000 0x1000>;
|
||||
interrupts = <2 21>;
|
||||
clocks = <&clk_i2c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -93,6 +95,8 @@
|
||||
reg = <0x7e804000 0x1000>;
|
||||
interrupts = <2 21>;
|
||||
clocks = <&clk_i2c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
i2c2_bus: i2c2-bus {
|
||||
samsung,pin-pud = <0>;
|
||||
};
|
||||
|
||||
max77686_irq: max77686-irq {
|
||||
samsung,pins = "gpx3-2";
|
||||
samsung,pin-function = <0>;
|
||||
samsung,pin-pud = <0>;
|
||||
samsung,pin-drv = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@12C60000 {
|
||||
@@ -35,6 +42,11 @@
|
||||
|
||||
max77686@09 {
|
||||
compatible = "maxim,max77686";
|
||||
interrupt-parent = <&gpx3>;
|
||||
interrupts = <2 0>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&max77686_irq>;
|
||||
wakeup-source;
|
||||
reg = <0x09>;
|
||||
|
||||
voltage-regulators {
|
||||
|
||||
@@ -22,13 +22,14 @@
|
||||
/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
|
||||
|
||||
ENTRY(fiq_glue)
|
||||
/* store pc, cpsr from previous mode */
|
||||
/* store pc, cpsr from previous mode, reserve space for spsr */
|
||||
mrs r12, spsr
|
||||
sub r11, lr, #4
|
||||
sub lr, lr, #4
|
||||
subs r10, #1
|
||||
bne nested_fiq
|
||||
|
||||
stmfd sp!, {r11-r12, lr}
|
||||
str r12, [sp, #-8]!
|
||||
str lr, [sp, #-4]!
|
||||
|
||||
/* store r8-r14 from previous mode */
|
||||
sub sp, sp, #(7 * 4)
|
||||
@@ -85,12 +86,15 @@ fiq_from_usr_mode_exit:
|
||||
msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
|
||||
|
||||
ldmfd sp!, {r0-r7}
|
||||
add sp, sp, #(7 * 4)
|
||||
ldmfd sp!, {r11-r12, lr}
|
||||
ldr lr, [sp, #(4 * 7)]
|
||||
ldr r12, [sp, #(4 * 8)]
|
||||
add sp, sp, #(10 * 4)
|
||||
exit_fiq:
|
||||
msr spsr_cxsf, r12
|
||||
add r10, #1
|
||||
movs pc, r11
|
||||
cmp r11, #0
|
||||
moveqs pc, lr
|
||||
bx r11 /* jump to custom fiq return function */
|
||||
|
||||
nested_fiq:
|
||||
orr r12, r12, #(PSR_F_BIT)
|
||||
@@ -98,14 +102,17 @@ nested_fiq:
|
||||
|
||||
fiq_glue_end:
|
||||
|
||||
ENTRY(fiq_glue_setup) /* func, data, sp */
|
||||
mrs r3, cpsr
|
||||
ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */
|
||||
stmfd sp!, {r4}
|
||||
mrs r4, cpsr
|
||||
msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
|
||||
movs r8, r0
|
||||
mov r9, r1
|
||||
mov sp, r2
|
||||
mov r11, r3
|
||||
moveq r10, #0
|
||||
movne r10, #1
|
||||
msr cpsr_c, r3
|
||||
msr cpsr_c, r4
|
||||
ldmfd sp!, {r4}
|
||||
bx lr
|
||||
|
||||
|
||||
@@ -18,20 +18,23 @@
|
||||
#include <asm/fiq_glue.h>
|
||||
|
||||
extern unsigned char fiq_glue, fiq_glue_end;
|
||||
extern void fiq_glue_setup(void *func, void *data, void *sp);
|
||||
extern void fiq_glue_setup(void *func, void *data, void *sp,
|
||||
fiq_return_handler_t fiq_return_handler);
|
||||
|
||||
static struct fiq_handler fiq_debbuger_fiq_handler = {
|
||||
.name = "fiq_glue",
|
||||
};
|
||||
DEFINE_PER_CPU(void *, fiq_stack);
|
||||
static struct fiq_glue_handler *current_handler;
|
||||
static fiq_return_handler_t fiq_return_handler;
|
||||
static DEFINE_MUTEX(fiq_glue_lock);
|
||||
|
||||
static void fiq_glue_setup_helper(void *info)
|
||||
{
|
||||
struct fiq_glue_handler *handler = info;
|
||||
fiq_glue_setup(handler->fiq, handler,
|
||||
__get_cpu_var(fiq_stack) + THREAD_START_SP);
|
||||
__get_cpu_var(fiq_stack) + THREAD_START_SP,
|
||||
fiq_return_handler);
|
||||
}
|
||||
|
||||
int fiq_glue_register_handler(struct fiq_glue_handler *handler)
|
||||
@@ -80,6 +83,49 @@ err_busy:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fiq_glue_update_return_handler(void (*fiq_return)(void))
|
||||
{
|
||||
fiq_return_handler = fiq_return;
|
||||
if (current_handler)
|
||||
on_each_cpu(fiq_glue_setup_helper, current_handler, true);
|
||||
}
|
||||
|
||||
int fiq_glue_set_return_handler(void (*fiq_return)(void))
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&fiq_glue_lock);
|
||||
if (fiq_return_handler) {
|
||||
ret = -EBUSY;
|
||||
goto err_busy;
|
||||
}
|
||||
fiq_glue_update_return_handler(fiq_return);
|
||||
ret = 0;
|
||||
err_busy:
|
||||
mutex_unlock(&fiq_glue_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fiq_glue_set_return_handler);
|
||||
|
||||
int fiq_glue_clear_return_handler(void (*fiq_return)(void))
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&fiq_glue_lock);
|
||||
if (WARN_ON(fiq_return_handler != fiq_return)) {
|
||||
ret = -EINVAL;
|
||||
goto err_inval;
|
||||
}
|
||||
fiq_glue_update_return_handler(NULL);
|
||||
ret = 0;
|
||||
err_inval:
|
||||
mutex_unlock(&fiq_glue_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fiq_glue_clear_return_handler);
|
||||
|
||||
/**
|
||||
* fiq_glue_resume - Restore fiqs after suspend or low power idle states
|
||||
*
|
||||
@@ -93,7 +139,8 @@ void fiq_glue_resume(void)
|
||||
if (!current_handler)
|
||||
return;
|
||||
fiq_glue_setup(current_handler->fiq, current_handler,
|
||||
__get_cpu_var(fiq_stack) + THREAD_START_SP);
|
||||
__get_cpu_var(fiq_stack) + THREAD_START_SP,
|
||||
fiq_return_handler);
|
||||
if (current_handler->resume)
|
||||
current_handler->resume(current_handler);
|
||||
}
|
||||
|
||||
@@ -437,4 +437,50 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size)
|
||||
#define sync_cache_w(ptr) __sync_cache_range_w(ptr, sizeof *(ptr))
|
||||
#define sync_cache_r(ptr) __sync_cache_range_r(ptr, sizeof *(ptr))
|
||||
|
||||
/*
|
||||
* Disabling cache access for one CPU in an ARMv7 SMP system is tricky.
|
||||
* To do so we must:
|
||||
*
|
||||
* - Clear the SCTLR.C bit to prevent further cache allocations
|
||||
* - Flush the desired level of cache
|
||||
* - Clear the ACTLR "SMP" bit to disable local coherency
|
||||
*
|
||||
* ... and so without any intervening memory access in between those steps,
|
||||
* not even to the stack.
|
||||
*
|
||||
* WARNING -- After this has been called:
|
||||
*
|
||||
* - No ldrex/strex (and similar) instructions must be used.
|
||||
* - The CPU is obviously no longer coherent with the other CPUs.
|
||||
* - This is unlikely to work as expected if Linux is running non-secure.
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* - This is known to apply to several ARMv7 processor implementations,
|
||||
* however some exceptions may exist. Caveat emptor.
|
||||
*
|
||||
* - The clobber list is dictated by the call to v7_flush_dcache_*.
|
||||
* fp is preserved to the stack explicitly prior disabling the cache
|
||||
* since adding it to the clobber list is incompatible with having
|
||||
* CONFIG_FRAME_POINTER=y. ip is saved as well if ever r12-clobbering
|
||||
* trampoline are inserted by the linker and to keep sp 64-bit aligned.
|
||||
*/
|
||||
#define v7_exit_coherency_flush(level) \
|
||||
asm volatile( \
|
||||
"stmfd sp!, {fp, ip} \n\t" \
|
||||
"mrc p15, 0, r0, c1, c0, 0 @ get SCTLR \n\t" \
|
||||
"bic r0, r0, #"__stringify(CR_C)" \n\t" \
|
||||
"mcr p15, 0, r0, c1, c0, 0 @ set SCTLR \n\t" \
|
||||
"isb \n\t" \
|
||||
"bl v7_flush_dcache_"__stringify(level)" \n\t" \
|
||||
"clrex \n\t" \
|
||||
"mrc p15, 0, r0, c1, c0, 1 @ get ACTLR \n\t" \
|
||||
"bic r0, r0, #(1 << 6) @ disable local coherency \n\t" \
|
||||
"mcr p15, 0, r0, c1, c0, 1 @ set ACTLR \n\t" \
|
||||
"isb \n\t" \
|
||||
"dsb \n\t" \
|
||||
"ldmfd sp!, {fp, ip}" \
|
||||
: : : "r0","r1","r2","r3","r4","r5","r6","r7", \
|
||||
"r9","r10","lr","memory" )
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,8 +18,11 @@ struct fiq_glue_handler {
|
||||
void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp);
|
||||
void (*resume)(struct fiq_glue_handler *h);
|
||||
};
|
||||
typedef void (*fiq_return_handler_t)(void);
|
||||
|
||||
int fiq_glue_register_handler(struct fiq_glue_handler *handler);
|
||||
int fiq_glue_set_return_handler(fiq_return_handler_t fiq_return);
|
||||
int fiq_glue_clear_return_handler(fiq_return_handler_t fiq_return);
|
||||
|
||||
#ifdef CONFIG_FIQ_GLUE
|
||||
void fiq_glue_resume(void);
|
||||
|
||||
@@ -58,7 +58,7 @@ extern void __pgd_error(const char *file, int line, pgd_t);
|
||||
* mapping to be mapped at. This is particularly important for
|
||||
* non-high vector CPUs.
|
||||
*/
|
||||
#define FIRST_USER_ADDRESS PAGE_SIZE
|
||||
#define FIRST_USER_ADDRESS (PAGE_SIZE * 2)
|
||||
|
||||
/*
|
||||
* Use TASK_SIZE as the ceiling argument for free_pgtables() and
|
||||
|
||||
@@ -192,6 +192,7 @@ __dabt_svc:
|
||||
svc_entry
|
||||
mov r2, sp
|
||||
dabt_helper
|
||||
THUMB( ldr r5, [sp, #S_PSR] ) @ potentially updated CPSR
|
||||
svc_exit r5 @ return from exception
|
||||
UNWIND(.fnend )
|
||||
ENDPROC(__dabt_svc)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-y := irq.o gpio.o setup.o
|
||||
obj-y := irq.o gpio.o setup.o sysirq_mask.o
|
||||
obj-m :=
|
||||
obj-n :=
|
||||
obj- :=
|
||||
|
||||
@@ -351,6 +351,8 @@ static void __init at91sam9260_initialize(void)
|
||||
at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
|
||||
| (1 << AT91SAM9260_ID_IRQ2);
|
||||
|
||||
at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
|
||||
|
||||
/* Register GPIO subsystem */
|
||||
at91_gpio_init(at91sam9260_gpio, 3);
|
||||
}
|
||||
|
||||
@@ -293,6 +293,8 @@ static void __init at91sam9261_initialize(void)
|
||||
at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
|
||||
| (1 << AT91SAM9261_ID_IRQ2);
|
||||
|
||||
at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
|
||||
|
||||
/* Register GPIO subsystem */
|
||||
at91_gpio_init(at91sam9261_gpio, 3);
|
||||
}
|
||||
|
||||
@@ -329,6 +329,9 @@ static void __init at91sam9263_initialize(void)
|
||||
arm_pm_restart = at91sam9_alt_restart;
|
||||
at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
|
||||
|
||||
at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
|
||||
at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
|
||||
|
||||
/* Register GPIO subsystem */
|
||||
at91_gpio_init(at91sam9263_gpio, 5);
|
||||
}
|
||||
|
||||
@@ -376,6 +376,9 @@ static void __init at91sam9g45_initialize(void)
|
||||
arm_pm_restart = at91sam9g45_restart;
|
||||
at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
|
||||
|
||||
at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
|
||||
at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
|
||||
|
||||
/* Register GPIO subsystem */
|
||||
at91_gpio_init(at91sam9g45_gpio, 5);
|
||||
}
|
||||
|
||||
@@ -223,7 +223,13 @@ static void __init at91sam9n12_map_io(void)
|
||||
at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
|
||||
}
|
||||
|
||||
static void __init at91sam9n12_initialize(void)
|
||||
{
|
||||
at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9n12)
|
||||
.map_io = at91sam9n12_map_io,
|
||||
.register_clocks = at91sam9n12_register_clocks,
|
||||
.init = at91sam9n12_initialize,
|
||||
AT91_SOC_END
|
||||
|
||||
@@ -295,6 +295,9 @@ static void __init at91sam9rl_initialize(void)
|
||||
arm_pm_restart = at91sam9_alt_restart;
|
||||
at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
|
||||
|
||||
at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
|
||||
at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
|
||||
|
||||
/* Register GPIO subsystem */
|
||||
at91_gpio_init(at91sam9rl_gpio, 4);
|
||||
}
|
||||
|
||||
@@ -318,6 +318,11 @@ static void __init at91sam9x5_map_io(void)
|
||||
at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
|
||||
}
|
||||
|
||||
static void __init at91sam9x5_initialize(void)
|
||||
{
|
||||
at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Interrupt initialization
|
||||
* -------------------------------------------------------------------- */
|
||||
@@ -325,4 +330,5 @@ static void __init at91sam9x5_map_io(void)
|
||||
AT91_SOC_START(at91sam9x5)
|
||||
.map_io = at91sam9x5_map_io,
|
||||
.register_clocks = at91sam9x5_register_clocks,
|
||||
.init = at91sam9x5_initialize,
|
||||
AT91_SOC_END
|
||||
|
||||
@@ -33,6 +33,8 @@ extern int __init at91_aic_of_init(struct device_node *node,
|
||||
struct device_node *parent);
|
||||
extern int __init at91_aic5_of_init(struct device_node *node,
|
||||
struct device_node *parent);
|
||||
extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
|
||||
extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
|
||||
|
||||
|
||||
/* Timer */
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
#define AT91SAM9N12_BASE_USART2 0xf8024000
|
||||
#define AT91SAM9N12_BASE_USART3 0xf8028000
|
||||
|
||||
/*
|
||||
* System Peripherals
|
||||
*/
|
||||
#define AT91SAM9N12_BASE_RTC 0xfffffeb0
|
||||
|
||||
/*
|
||||
* Internal Memory.
|
||||
*/
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
#define AT91SAM9X5_BASE_USART1 0xf8020000
|
||||
#define AT91SAM9X5_BASE_USART2 0xf8024000
|
||||
|
||||
/*
|
||||
* System Peripherals
|
||||
*/
|
||||
#define AT91SAM9X5_BASE_RTC 0xfffffeb0
|
||||
|
||||
/*
|
||||
* Internal Memory.
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,11 @@
|
||||
#define SAMA5D3_ID_TRNG 45 /* True Random Generator Number */
|
||||
#define SAMA5D3_ID_IRQ0 47 /* Advanced Interrupt Controller (IRQ0) */
|
||||
|
||||
/*
|
||||
* System Peripherals
|
||||
*/
|
||||
#define SAMA5D3_BASE_RTC 0xfffffeb0
|
||||
|
||||
/*
|
||||
* Internal Memory
|
||||
*/
|
||||
|
||||
@@ -95,19 +95,19 @@ static struct clk twi0_clk = {
|
||||
.name = "twi0_clk",
|
||||
.pid = SAMA5D3_ID_TWI0,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
.div = AT91_PMC_PCR_DIV2,
|
||||
.div = AT91_PMC_PCR_DIV8,
|
||||
};
|
||||
static struct clk twi1_clk = {
|
||||
.name = "twi1_clk",
|
||||
.pid = SAMA5D3_ID_TWI1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
.div = AT91_PMC_PCR_DIV2,
|
||||
.div = AT91_PMC_PCR_DIV8,
|
||||
};
|
||||
static struct clk twi2_clk = {
|
||||
.name = "twi2_clk",
|
||||
.pid = SAMA5D3_ID_TWI2,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
.div = AT91_PMC_PCR_DIV2,
|
||||
.div = AT91_PMC_PCR_DIV8,
|
||||
};
|
||||
static struct clk mmc0_clk = {
|
||||
.name = "mci0_clk",
|
||||
@@ -371,7 +371,13 @@ static void __init sama5d3_map_io(void)
|
||||
at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE);
|
||||
}
|
||||
|
||||
static void __init sama5d3_initialize(void)
|
||||
{
|
||||
at91_sysirq_mask_rtc(SAMA5D3_BASE_RTC);
|
||||
}
|
||||
|
||||
AT91_SOC_START(sama5d3)
|
||||
.map_io = sama5d3_map_io,
|
||||
.register_clocks = sama5d3_register_clocks,
|
||||
.init = sama5d3_initialize,
|
||||
AT91_SOC_END
|
||||
|
||||
71
arch/arm/mach-at91/sysirq_mask.c
Normal file
71
arch/arm/mach-at91/sysirq_mask.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* sysirq_mask.c - System-interrupt masking
|
||||
*
|
||||
* Copyright (C) 2013 Johan Hovold <jhovold@gmail.com>
|
||||
*
|
||||
* Functions to disable system interrupts from backup-powered peripherals.
|
||||
*
|
||||
* The RTC and RTT-peripherals are generally powered by backup power (VDDBU)
|
||||
* and are not reset on wake-up, user, watchdog or software reset. This means
|
||||
* that their interrupts may be enabled during early boot (e.g. after a user
|
||||
* reset).
|
||||
*
|
||||
* As the RTC and RTT share the system-interrupt line with the PIT, an
|
||||
* interrupt occurring before a handler has been installed would lead to the
|
||||
* system interrupt being disabled and prevent the system from booting.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <mach/at91_rtt.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
|
||||
#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
|
||||
|
||||
void __init at91_sysirq_mask_rtc(u32 rtc_base)
|
||||
{
|
||||
void __iomem *base;
|
||||
u32 mask;
|
||||
|
||||
base = ioremap(rtc_base, 64);
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
mask = readl_relaxed(base + AT91_RTC_IMR);
|
||||
if (mask) {
|
||||
pr_info("AT91: Disabling rtc irq\n");
|
||||
writel_relaxed(mask, base + AT91_RTC_IDR);
|
||||
(void)readl_relaxed(base + AT91_RTC_IMR); /* flush */
|
||||
}
|
||||
|
||||
iounmap(base);
|
||||
}
|
||||
|
||||
void __init at91_sysirq_mask_rtt(u32 rtt_base)
|
||||
{
|
||||
void __iomem *base;
|
||||
void __iomem *reg;
|
||||
u32 mode;
|
||||
|
||||
base = ioremap(rtt_base, 16);
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
reg = base + AT91_RTT_MR;
|
||||
|
||||
mode = readl_relaxed(reg);
|
||||
if (mode & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
|
||||
pr_info("AT91: Disabling rtt irq\n");
|
||||
mode &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
|
||||
writel_relaxed(mode, reg);
|
||||
(void)readl_relaxed(reg); /* flush */
|
||||
}
|
||||
|
||||
iounmap(base);
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <video/vga.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
@@ -196,6 +197,8 @@ void __init footbridge_map_io(void)
|
||||
iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
|
||||
pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO));
|
||||
}
|
||||
|
||||
vga_base = PCIMEM_BASE;
|
||||
}
|
||||
|
||||
void footbridge_restart(char mode, const char *cmd)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <video/vga.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mach/pci.h>
|
||||
@@ -291,7 +290,6 @@ void __init dc21285_preinit(void)
|
||||
int cfn_mode;
|
||||
|
||||
pcibios_min_mem = 0x81000000;
|
||||
vga_base = PCIMEM_BASE;
|
||||
|
||||
mem_size = (unsigned int)high_memory - PAGE_OFFSET;
|
||||
for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
|
||||
|
||||
@@ -30,21 +30,24 @@ static const struct {
|
||||
const char *name;
|
||||
const char *trigger;
|
||||
} ebsa285_leds[] = {
|
||||
{ "ebsa285:amber", "heartbeat", },
|
||||
{ "ebsa285:green", "cpu0", },
|
||||
{ "ebsa285:amber", "cpu0", },
|
||||
{ "ebsa285:green", "heartbeat", },
|
||||
{ "ebsa285:red",},
|
||||
};
|
||||
|
||||
static unsigned char hw_led_state;
|
||||
|
||||
static void ebsa285_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness b)
|
||||
{
|
||||
struct ebsa285_led *led = container_of(cdev,
|
||||
struct ebsa285_led, cdev);
|
||||
|
||||
if (b != LED_OFF)
|
||||
*XBUS_LEDS |= led->mask;
|
||||
if (b == LED_OFF)
|
||||
hw_led_state |= led->mask;
|
||||
else
|
||||
*XBUS_LEDS &= ~led->mask;
|
||||
hw_led_state &= ~led->mask;
|
||||
*XBUS_LEDS = hw_led_state;
|
||||
}
|
||||
|
||||
static enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
|
||||
@@ -52,18 +55,19 @@ static enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
|
||||
struct ebsa285_led *led = container_of(cdev,
|
||||
struct ebsa285_led, cdev);
|
||||
|
||||
return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF;
|
||||
return hw_led_state & led->mask ? LED_OFF : LED_FULL;
|
||||
}
|
||||
|
||||
static int __init ebsa285_leds_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (machine_is_ebsa285())
|
||||
if (!machine_is_ebsa285())
|
||||
return -ENODEV;
|
||||
|
||||
/* 3 LEDS All ON */
|
||||
*XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED;
|
||||
/* 3 LEDS all off */
|
||||
hw_led_state = XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED;
|
||||
*XBUS_LEDS = hw_led_state;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) {
|
||||
struct ebsa285_led *led;
|
||||
|
||||
@@ -424,7 +424,7 @@ int __init mx6q_clocks_init(void)
|
||||
clk[asrc_podf] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3);
|
||||
clk[spdif_pred] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
|
||||
clk[spdif_podf] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
|
||||
clk[can_root] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6);
|
||||
clk[can_root] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
|
||||
clk[ecspi_root] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
|
||||
clk[gpu2d_core_podf] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3);
|
||||
clk[gpu3d_core_podf] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3);
|
||||
|
||||
@@ -199,7 +199,8 @@ static struct mmci_platform_data mmc_data = {
|
||||
static void cp_clcd_enable(struct clcd_fb *fb)
|
||||
{
|
||||
struct fb_var_screeninfo *var = &fb->fb.var;
|
||||
u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
|
||||
u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2
|
||||
| CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1;
|
||||
|
||||
if (var->bits_per_pixel <= 8 ||
|
||||
(var->bits_per_pixel == 16 && var->green.length == 5))
|
||||
|
||||
@@ -233,7 +233,7 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs
|
||||
goto out;
|
||||
|
||||
irqnr = readl_relaxed(base_addr + 0xd8);
|
||||
#ifdef CONFIG_SOC_TI81XX
|
||||
#if IS_ENABLED(CONFIG_SOC_TI81XX) || IS_ENABLED(CONFIG_SOC_AM33XX)
|
||||
if (irqnr)
|
||||
goto out;
|
||||
irqnr = readl_relaxed(base_addr + 0xf8);
|
||||
|
||||
@@ -512,6 +512,9 @@ static void __init assabet_map_io(void)
|
||||
* Its called GPCLKR0 in my SA1110 manual.
|
||||
*/
|
||||
Ser1SDCR0 |= SDCR0_SUS;
|
||||
MSC1 = (MSC1 & ~0xffff) |
|
||||
MSC_NonBrst | MSC_32BitStMem |
|
||||
MSC_RdAcc(2) | MSC_WrAcc(2) | MSC_Rec(0);
|
||||
|
||||
if (!machine_has_neponset())
|
||||
sa1100_register_uart_fns(&assabet_port_fns);
|
||||
|
||||
@@ -134,17 +134,8 @@ static void dcscb_power_down(void)
|
||||
if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
|
||||
arch_spin_unlock(&dcscb_lock);
|
||||
|
||||
/*
|
||||
* Flush all cache levels for this cluster.
|
||||
*
|
||||
* A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
|
||||
* a preliminary flush here for those CPUs. At least, that's
|
||||
* the theory -- without the extra flush, Linux explodes on
|
||||
* RTSM (to be investigated).
|
||||
*/
|
||||
flush_cache_all();
|
||||
set_cr(get_cr() & ~CR_C);
|
||||
flush_cache_all();
|
||||
/* Flush all cache levels for this cluster. */
|
||||
v7_exit_coherency_flush(all);
|
||||
|
||||
/*
|
||||
* This is a harmless no-op. On platforms with a real
|
||||
@@ -153,9 +144,6 @@ static void dcscb_power_down(void)
|
||||
*/
|
||||
outer_flush_all();
|
||||
|
||||
/* Disable local coherency by clearing the ACTLR "SMP" bit: */
|
||||
set_auxcr(get_auxcr() & ~(1 << 6));
|
||||
|
||||
/*
|
||||
* Disable cluster-level coherency by masking
|
||||
* incoming snoops and DVM messages:
|
||||
@@ -166,20 +154,8 @@ static void dcscb_power_down(void)
|
||||
} else {
|
||||
arch_spin_unlock(&dcscb_lock);
|
||||
|
||||
/*
|
||||
* Flush the local CPU cache.
|
||||
*
|
||||
* A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
|
||||
* a preliminary flush here for those CPUs. At least, that's
|
||||
* the theory -- without the extra flush, Linux explodes on
|
||||
* RTSM (to be investigated).
|
||||
*/
|
||||
flush_cache_louis();
|
||||
set_cr(get_cr() & ~CR_C);
|
||||
flush_cache_louis();
|
||||
|
||||
/* Disable local coherency by clearing the ACTLR "SMP" bit: */
|
||||
set_auxcr(get_auxcr() & ~(1 << 6));
|
||||
/* Disable and flush the local CPU cache. */
|
||||
v7_exit_coherency_flush(louis);
|
||||
}
|
||||
|
||||
__mcpm_cpu_down(cpu, cluster);
|
||||
|
||||
@@ -135,21 +135,22 @@ static void tc2_pm_down(u64 residency)
|
||||
if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
|
||||
arch_spin_unlock(&tc2_pm_lock);
|
||||
|
||||
set_cr(get_cr() & ~CR_C);
|
||||
flush_cache_all();
|
||||
asm volatile ("clrex");
|
||||
set_auxcr(get_auxcr() & ~(1 << 6));
|
||||
if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
|
||||
/*
|
||||
* On the Cortex-A15 we need to disable
|
||||
* L2 prefetching before flushing the cache.
|
||||
*/
|
||||
asm volatile(
|
||||
"mcr p15, 1, %0, c15, c0, 3 \n\t"
|
||||
"isb \n\t"
|
||||
"dsb "
|
||||
: : "r" (0x400) );
|
||||
}
|
||||
|
||||
v7_exit_coherency_flush(all);
|
||||
|
||||
cci_disable_port_by_cpu(mpidr);
|
||||
|
||||
/*
|
||||
* Ensure that both C & I bits are disabled in the SCTLR
|
||||
* before disabling ACE snoops. This ensures that no
|
||||
* coherency traffic will originate from this cpu after
|
||||
* ACE snoops are turned off.
|
||||
*/
|
||||
cpu_proc_fin();
|
||||
|
||||
__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
|
||||
} else {
|
||||
/*
|
||||
@@ -162,10 +163,7 @@ static void tc2_pm_down(u64 residency)
|
||||
|
||||
arch_spin_unlock(&tc2_pm_lock);
|
||||
|
||||
set_cr(get_cr() & ~CR_C);
|
||||
flush_cache_louis();
|
||||
asm volatile ("clrex");
|
||||
set_auxcr(get_auxcr() & ~(1 << 6));
|
||||
v7_exit_coherency_flush(louis);
|
||||
}
|
||||
|
||||
__mcpm_cpu_down(cpu, cluster);
|
||||
|
||||
@@ -9,8 +9,13 @@ int fixup_exception(struct pt_regs *regs)
|
||||
const struct exception_table_entry *fixup;
|
||||
|
||||
fixup = search_exception_tables(instruction_pointer(regs));
|
||||
if (fixup)
|
||||
if (fixup) {
|
||||
regs->ARM_pc = fixup->fixup;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/* Clear the IT state to avoid nasty surprises in the fixup */
|
||||
regs->ARM_cpsr &= ~PSR_IT_MASK;
|
||||
#endif
|
||||
}
|
||||
|
||||
return fixup != NULL;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
|
||||
|
||||
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
|
||||
info.length = len;
|
||||
info.low_limit = PAGE_SIZE;
|
||||
info.low_limit = FIRST_USER_ADDRESS;
|
||||
info.high_limit = mm->mmap_base;
|
||||
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||
info.align_offset = pgoff << PAGE_SHIFT;
|
||||
|
||||
@@ -87,7 +87,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
|
||||
init_pud = pud_offset(init_pgd, 0);
|
||||
init_pmd = pmd_offset(init_pud, 0);
|
||||
init_pte = pte_offset_map(init_pmd, 0);
|
||||
set_pte_ext(new_pte, *init_pte, 0);
|
||||
set_pte_ext(new_pte + 0, init_pte[0], 0);
|
||||
set_pte_ext(new_pte + 1, init_pte[1], 0);
|
||||
pte_unmap(init_pte);
|
||||
pte_unmap(new_pte);
|
||||
}
|
||||
|
||||
@@ -144,12 +144,139 @@ config SMP
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config ARM_CPU_TOPOLOGY
|
||||
bool "Support CPU topology definition"
|
||||
depends on SMP
|
||||
default y
|
||||
help
|
||||
Support CPU topology definition, based on configuration
|
||||
provided by the firmware.
|
||||
|
||||
config SCHED_MC
|
||||
bool "Multi-core scheduler support"
|
||||
depends on ARM_CPU_TOPOLOGY
|
||||
help
|
||||
Multi-core scheduler support improves the CPU scheduler's decision
|
||||
making when dealing with multi-core CPU chips at a cost of slightly
|
||||
increased overhead in some places. If unsure say N here.
|
||||
|
||||
config SCHED_SMT
|
||||
bool "SMT scheduler support"
|
||||
depends on ARM_CPU_TOPOLOGY
|
||||
help
|
||||
Improves the CPU scheduler's decision making when dealing with
|
||||
MultiThreading at a cost of slightly increased overhead in some
|
||||
places. If unsure say N here.
|
||||
|
||||
config DISABLE_CPU_SCHED_DOMAIN_BALANCE
|
||||
bool "(EXPERIMENTAL) Disable CPU level scheduler load-balancing"
|
||||
help
|
||||
Disables scheduler load-balancing at CPU sched domain level.
|
||||
|
||||
config SCHED_HMP
|
||||
bool "(EXPERIMENTAL) Heterogenous multiprocessor scheduling"
|
||||
depends on DISABLE_CPU_SCHED_DOMAIN_BALANCE && SCHED_MC && FAIR_GROUP_SCHED && !SCHED_AUTOGROUP
|
||||
help
|
||||
Experimental scheduler optimizations for heterogeneous platforms.
|
||||
Attempts to introspectively select task affinity to optimize power
|
||||
and performance. Basic support for multiple (>2) cpu types is in place,
|
||||
but it has only been tested with two types of cpus.
|
||||
There is currently no support for migration of task groups, hence
|
||||
!SCHED_AUTOGROUP. Furthermore, normal load-balancing must be disabled
|
||||
between cpus of different type (DISABLE_CPU_SCHED_DOMAIN_BALANCE).
|
||||
|
||||
config SCHED_HMP_PRIO_FILTER
|
||||
bool "(EXPERIMENTAL) Filter HMP migrations by task priority"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Enables task priority based HMP migration filter. Any task with
|
||||
a NICE value above the threshold will always be on low-power cpus
|
||||
with less compute capacity.
|
||||
|
||||
config SCHED_HMP_PRIO_FILTER_VAL
|
||||
int "NICE priority threshold"
|
||||
default 5
|
||||
depends on SCHED_HMP_PRIO_FILTER
|
||||
|
||||
config HMP_FAST_CPU_MASK
|
||||
string "HMP scheduler fast CPU mask"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Leave empty to use device tree information.
|
||||
Specify the cpuids of the fast CPUs in the system as a list string,
|
||||
e.g. cpuid 0+1 should be specified as 0-1.
|
||||
|
||||
config HMP_SLOW_CPU_MASK
|
||||
string "HMP scheduler slow CPU mask"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Leave empty to use device tree information.
|
||||
Specify the cpuids of the slow CPUs in the system as a list string,
|
||||
e.g. cpuid 0+1 should be specified as 0-1.
|
||||
|
||||
config HMP_VARIABLE_SCALE
|
||||
bool "Allows changing the load tracking scale through sysfs"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
When turned on, this option exports the thresholds and load average
|
||||
period value for the load tracking patches through sysfs.
|
||||
The values can be modified to change the rate of load accumulation
|
||||
and the thresholds used for HMP migration.
|
||||
The load_avg_period_ms is the time in ms to reach a load average of
|
||||
0.5 for an idle task of 0 load average ratio that start a busy loop.
|
||||
The up_threshold and down_threshold is the value to go to a faster
|
||||
CPU or to go back to a slower cpu.
|
||||
The {up,down}_threshold are devided by 1024 before being compared
|
||||
to the load average.
|
||||
For examples, with load_avg_period_ms = 128 and up_threshold = 512,
|
||||
a running task with a load of 0 will be migrated to a bigger CPU after
|
||||
128ms, because after 128ms its load_avg_ratio is 0.5 and the real
|
||||
up_threshold is 0.5.
|
||||
This patch has the same behavior as changing the Y of the load
|
||||
average computation to
|
||||
(1002/1024)^(LOAD_AVG_PERIOD/load_avg_period_ms)
|
||||
but it remove intermadiate overflows in computation.
|
||||
|
||||
config HMP_FREQUENCY_INVARIANT_SCALE
|
||||
bool "(EXPERIMENTAL) Frequency-Invariant Tracked Load for HMP"
|
||||
depends on HMP_VARIABLE_SCALE && CPU_FREQ
|
||||
help
|
||||
Scales the current load contribution in line with the frequency
|
||||
of the CPU that the task was executed on.
|
||||
In this version, we use a simple linear scale derived from the
|
||||
maximum frequency reported by CPUFreq.
|
||||
Restricting tracked load to be scaled by the CPU's frequency
|
||||
represents the consumption of possible compute capacity
|
||||
(rather than consumption of actual instantaneous capacity as
|
||||
normal) and allows the HMP migration's simple threshold
|
||||
migration strategy to interact more predictably with CPUFreq's
|
||||
asynchronous compute capacity changes.
|
||||
|
||||
config SCHED_HMP_LITTLE_PACKING
|
||||
bool "Small task packing for HMP"
|
||||
depends on SCHED_HMP
|
||||
default n
|
||||
help
|
||||
Allows the HMP Scheduler to pack small tasks into CPUs in the
|
||||
smallest HMP domain.
|
||||
Controlled by two sysfs files in sys/kernel/hmp.
|
||||
packing_enable: 1 to enable, 0 to disable packing. Default 1.
|
||||
packing_limit: runqueue load ratio where a RQ is considered
|
||||
to be full. Default is NICE_0_LOAD * 9/8.
|
||||
|
||||
config NR_CPUS
|
||||
int "Maximum number of CPUs (2-32)"
|
||||
range 2 32
|
||||
depends on SMP
|
||||
default "4"
|
||||
|
||||
config HOTPLUG_CPU
|
||||
bool "Support for hot-pluggable CPUs"
|
||||
depends on SMP
|
||||
help
|
||||
Say Y here to experiment with turning CPUs off and on. CPUs
|
||||
can be controlled through /sys/devices/system/cpu.
|
||||
|
||||
source kernel/Kconfig.preempt
|
||||
|
||||
config HZ
|
||||
@@ -229,6 +356,14 @@ config SYSVIPC_COMPAT
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Power management options"
|
||||
|
||||
source "kernel/power/Kconfig"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
|
||||
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb \
|
||||
fvp-base-gicv2-psci.dtb
|
||||
|
||||
targets += dtbs
|
||||
targets += $(dtb-y)
|
||||
|
||||
287
arch/arm64/boot/dts/fvp-base-gicv2-psci.dts
Normal file
287
arch/arm64/boot/dts/fvp-base-gicv2-psci.dts
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 2013, ARM Limited. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/memreserve/ 0x80000000 0x00010000;
|
||||
|
||||
/ {
|
||||
};
|
||||
|
||||
/ {
|
||||
model = "FVP Base";
|
||||
compatible = "arm,vfp-base", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
chosen { };
|
||||
|
||||
aliases {
|
||||
serial0 = &v2m_serial0;
|
||||
serial1 = &v2m_serial1;
|
||||
serial2 = &v2m_serial2;
|
||||
serial3 = &v2m_serial3;
|
||||
};
|
||||
|
||||
psci {
|
||||
compatible = "arm,psci";
|
||||
method = "smc";
|
||||
cpu_suspend = <0xc4000001>;
|
||||
cpu_off = <0x84000002>;
|
||||
cpu_on = <0xc4000003>;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
big0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a57", "arm,armv8";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
big1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a57", "arm,armv8";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
big2: cpu@2 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a57", "arm,armv8";
|
||||
reg = <0x0 0x2>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
big3: cpu@3 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a57", "arm,armv8";
|
||||
reg = <0x0 0x3>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
little0: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53", "arm,armv8";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
little1: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53", "arm,armv8";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
little2: cpu@102 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53", "arm,armv8";
|
||||
reg = <0x0 0x102>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
little3: cpu@103 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53", "arm,armv8";
|
||||
reg = <0x0 0x103>;
|
||||
enable-method = "psci";
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
cluster0 {
|
||||
core0 {
|
||||
cpu = <&big0>;
|
||||
};
|
||||
core1 {
|
||||
cpu = <&big1>;
|
||||
};
|
||||
core2 {
|
||||
cpu = <&big2>;
|
||||
};
|
||||
core3 {
|
||||
cpu = <&big3>;
|
||||
};
|
||||
};
|
||||
cluster1 {
|
||||
core0 {
|
||||
cpu = <&little0>;
|
||||
};
|
||||
core1 {
|
||||
cpu = <&little1>;
|
||||
};
|
||||
core2 {
|
||||
cpu = <&little2>;
|
||||
};
|
||||
core3 {
|
||||
cpu = <&little3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x80000000 0 0x80000000>,
|
||||
<0x00000008 0x80000000 0 0x80000000>;
|
||||
};
|
||||
|
||||
gic: interrupt-controller@2f000000 {
|
||||
compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
reg = <0x0 0x2f000000 0 0x10000>,
|
||||
<0x0 0x2c000000 0 0x2000>,
|
||||
<0x0 0x2c010000 0 0x2000>,
|
||||
<0x0 0x2c02F000 0 0x2000>;
|
||||
interrupts = <1 9 0xf04>;
|
||||
};
|
||||
|
||||
timer {
|
||||
compatible = "arm,armv8-timer";
|
||||
interrupts = <1 13 0xff01>,
|
||||
<1 14 0xff01>,
|
||||
<1 11 0xff01>,
|
||||
<1 10 0xff01>;
|
||||
clock-frequency = <100000000>;
|
||||
};
|
||||
|
||||
timer@2a810000 {
|
||||
compatible = "arm,armv7-timer-mem";
|
||||
reg = <0x0 0x2a810000 0x0 0x10000>;
|
||||
clock-frequency = <100000000>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
frame@2a820000 {
|
||||
frame-number = <0>;
|
||||
interrupts = <0 25 4>;
|
||||
reg = <0x0 0x2a820000 0x0 0x10000>;
|
||||
};
|
||||
};
|
||||
|
||||
pmu {
|
||||
compatible = "arm,armv8-pmuv3";
|
||||
interrupts = <0 60 4>,
|
||||
<0 61 4>,
|
||||
<0 62 4>,
|
||||
<0 63 4>;
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0 0x08000000 0x04000000>,
|
||||
<1 0 0 0x14000000 0x04000000>,
|
||||
<2 0 0 0x18000000 0x04000000>,
|
||||
<3 0 0 0x1c000000 0x04000000>,
|
||||
<4 0 0 0x0c000000 0x04000000>,
|
||||
<5 0 0 0x10000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
<0 0 2 &gic 0 2 4>,
|
||||
<0 0 3 &gic 0 3 4>,
|
||||
<0 0 4 &gic 0 4 4>,
|
||||
<0 0 5 &gic 0 5 4>,
|
||||
<0 0 6 &gic 0 6 4>,
|
||||
<0 0 7 &gic 0 7 4>,
|
||||
<0 0 8 &gic 0 8 4>,
|
||||
<0 0 9 &gic 0 9 4>,
|
||||
<0 0 10 &gic 0 10 4>,
|
||||
<0 0 11 &gic 0 11 4>,
|
||||
<0 0 12 &gic 0 12 4>,
|
||||
<0 0 13 &gic 0 13 4>,
|
||||
<0 0 14 &gic 0 14 4>,
|
||||
<0 0 15 &gic 0 15 4>,
|
||||
<0 0 16 &gic 0 16 4>,
|
||||
<0 0 17 &gic 0 17 4>,
|
||||
<0 0 18 &gic 0 18 4>,
|
||||
<0 0 19 &gic 0 19 4>,
|
||||
<0 0 20 &gic 0 20 4>,
|
||||
<0 0 21 &gic 0 21 4>,
|
||||
<0 0 22 &gic 0 22 4>,
|
||||
<0 0 23 &gic 0 23 4>,
|
||||
<0 0 24 &gic 0 24 4>,
|
||||
<0 0 25 &gic 0 25 4>,
|
||||
<0 0 26 &gic 0 26 4>,
|
||||
<0 0 27 &gic 0 27 4>,
|
||||
<0 0 28 &gic 0 28 4>,
|
||||
<0 0 29 &gic 0 29 4>,
|
||||
<0 0 30 &gic 0 30 4>,
|
||||
<0 0 31 &gic 0 31 4>,
|
||||
<0 0 32 &gic 0 32 4>,
|
||||
<0 0 33 &gic 0 33 4>,
|
||||
<0 0 34 &gic 0 34 4>,
|
||||
<0 0 35 &gic 0 35 4>,
|
||||
<0 0 36 &gic 0 36 4>,
|
||||
<0 0 37 &gic 0 37 4>,
|
||||
<0 0 38 &gic 0 38 4>,
|
||||
<0 0 39 &gic 0 39 4>,
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "rtsm_ve-motherboard.dtsi"
|
||||
};
|
||||
|
||||
panels {
|
||||
panel@0 {
|
||||
compatible = "panel";
|
||||
mode = "XVGA";
|
||||
refresh = <60>;
|
||||
xres = <1024>;
|
||||
yres = <768>;
|
||||
pixclock = <15748>;
|
||||
left_margin = <152>;
|
||||
right_margin = <48>;
|
||||
upper_margin = <23>;
|
||||
lower_margin = <3>;
|
||||
hsync_len = <104>;
|
||||
vsync_len = <4>;
|
||||
sync = <0>;
|
||||
vmode = "FB_VMODE_NONINTERLACED";
|
||||
tim2 = "TIM2_BCD", "TIM2_IPC";
|
||||
cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
|
||||
caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
|
||||
bpp = <16>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -182,6 +182,15 @@
|
||||
interrupts = <14>;
|
||||
clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
|
||||
clock-names = "clcdclk", "apb_pclk";
|
||||
mode = "XVGA";
|
||||
use_dma = <0>;
|
||||
framebuffer = <0x18000000 0x00180000>;
|
||||
};
|
||||
|
||||
virtio_block@0130000 {
|
||||
compatible = "virtio,mmio";
|
||||
reg = <0x130000 0x200>;
|
||||
interrupts = <42>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -158,17 +158,23 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define cmpxchg(ptr,o,n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))))
|
||||
#define cmpxchg(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \
|
||||
sizeof(*(ptr))); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define cmpxchg_local(ptr,o,n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))))
|
||||
#define cmpxchg_local(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__cmpxchg((ptr), (unsigned long)(o), \
|
||||
(unsigned long)(n), sizeof(*(ptr))); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
|
||||
#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
|
||||
|
||||
59
arch/arm64/include/asm/cpu_ops.h
Normal file
59
arch/arm64/include/asm/cpu_ops.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __ASM_CPU_OPS_H
|
||||
#define __ASM_CPU_OPS_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
|
||||
struct device_node;
|
||||
|
||||
/**
|
||||
* struct cpu_operations - Callback operations for hotplugging CPUs.
|
||||
*
|
||||
* @name: Name of the property as appears in a devicetree cpu node's
|
||||
* enable-method property.
|
||||
* @cpu_init: Reads any data necessary for a specific enable-method from the
|
||||
* devicetree, for a given cpu node and proposed logical id.
|
||||
* @cpu_prepare: Early one-time preparation step for a cpu. If there is a
|
||||
* mechanism for doing so, tests whether it is possible to boot
|
||||
* the given CPU.
|
||||
* @cpu_boot: Boots a cpu into the kernel.
|
||||
* @cpu_postboot: Optionally, perform any post-boot cleanup or necesary
|
||||
* synchronisation. Called from the cpu being booted.
|
||||
* @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific
|
||||
* reason, which will cause the hot unplug to be aborted. Called
|
||||
* from the cpu to be killed.
|
||||
* @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the
|
||||
* cpu being killed.
|
||||
*/
|
||||
struct cpu_operations {
|
||||
const char *name;
|
||||
int (*cpu_init)(struct device_node *, unsigned int);
|
||||
int (*cpu_prepare)(unsigned int);
|
||||
int (*cpu_boot)(unsigned int);
|
||||
void (*cpu_postboot)(void);
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int (*cpu_disable)(unsigned int cpu);
|
||||
void (*cpu_die)(unsigned int cpu);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern const struct cpu_operations *cpu_ops[NR_CPUS];
|
||||
extern int __init cpu_read_ops(struct device_node *dn, int cpu);
|
||||
extern void __init cpu_read_bootcpu_ops(void);
|
||||
|
||||
#endif /* ifndef __ASM_CPU_OPS_H */
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <asm-generic/irq.h>
|
||||
|
||||
extern void (*handle_arch_irq)(struct pt_regs *);
|
||||
extern void migrate_irqs(void);
|
||||
extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,25 +14,6 @@
|
||||
#ifndef __ASM_PSCI_H
|
||||
#define __ASM_PSCI_H
|
||||
|
||||
#define PSCI_POWER_STATE_TYPE_STANDBY 0
|
||||
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
|
||||
|
||||
struct psci_power_state {
|
||||
u16 id;
|
||||
u8 type;
|
||||
u8 affinity_level;
|
||||
};
|
||||
|
||||
struct psci_operations {
|
||||
int (*cpu_suspend)(struct psci_power_state state,
|
||||
unsigned long entry_point);
|
||||
int (*cpu_off)(struct psci_power_state state);
|
||||
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
|
||||
int (*migrate)(unsigned long cpuid);
|
||||
};
|
||||
|
||||
extern struct psci_operations psci_ops;
|
||||
|
||||
int psci_init(void);
|
||||
|
||||
#endif /* __ASM_PSCI_H */
|
||||
|
||||
@@ -60,21 +60,14 @@ struct secondary_data {
|
||||
void *stack;
|
||||
};
|
||||
extern struct secondary_data secondary_data;
|
||||
extern void secondary_holding_pen(void);
|
||||
extern volatile unsigned long secondary_holding_pen_release;
|
||||
extern void secondary_entry(void);
|
||||
|
||||
extern void arch_send_call_function_single_ipi(int cpu);
|
||||
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
|
||||
|
||||
struct device_node;
|
||||
extern int __cpu_disable(void);
|
||||
|
||||
struct smp_enable_ops {
|
||||
const char *name;
|
||||
int (*init_cpu)(struct device_node *, int);
|
||||
int (*prepare_cpu)(int);
|
||||
};
|
||||
|
||||
extern const struct smp_enable_ops smp_spin_table_ops;
|
||||
extern const struct smp_enable_ops smp_psci_ops;
|
||||
extern void __cpu_die(unsigned int cpu);
|
||||
extern void cpu_die(void);
|
||||
|
||||
#endif /* ifndef __ASM_SMP_H */
|
||||
|
||||
73
arch/arm64/include/asm/topology.h
Normal file
73
arch/arm64/include/asm/topology.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef _ASM_ARM_TOPOLOGY_H
|
||||
#define _ASM_ARM_TOPOLOGY_H
|
||||
|
||||
#ifdef CONFIG_ARM_CPU_TOPOLOGY
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
struct cputopo_arm {
|
||||
int thread_id;
|
||||
int core_id;
|
||||
int socket_id;
|
||||
cpumask_t thread_sibling;
|
||||
cpumask_t core_sibling;
|
||||
};
|
||||
|
||||
extern struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
|
||||
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
|
||||
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
|
||||
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
|
||||
#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
|
||||
|
||||
#define mc_capable() (cpu_topology[0].socket_id != -1)
|
||||
#define smt_capable() (cpu_topology[0].thread_id != -1)
|
||||
|
||||
void init_cpu_topology(void);
|
||||
void store_cpu_topology(unsigned int cpuid);
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||
int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask);
|
||||
|
||||
#ifdef CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE
|
||||
/* Common values for CPUs */
|
||||
#ifndef SD_CPU_INIT
|
||||
#define SD_CPU_INIT (struct sched_domain) { \
|
||||
.min_interval = 1, \
|
||||
.max_interval = 4, \
|
||||
.busy_factor = 64, \
|
||||
.imbalance_pct = 125, \
|
||||
.cache_nice_tries = 1, \
|
||||
.busy_idx = 2, \
|
||||
.idle_idx = 1, \
|
||||
.newidle_idx = 0, \
|
||||
.wake_idx = 0, \
|
||||
.forkexec_idx = 0, \
|
||||
\
|
||||
.flags = 0*SD_LOAD_BALANCE \
|
||||
| 1*SD_BALANCE_NEWIDLE \
|
||||
| 1*SD_BALANCE_EXEC \
|
||||
| 1*SD_BALANCE_FORK \
|
||||
| 0*SD_BALANCE_WAKE \
|
||||
| 1*SD_WAKE_AFFINE \
|
||||
| 0*SD_SHARE_CPUPOWER \
|
||||
| 0*SD_SHARE_PKG_RESOURCES \
|
||||
| 0*SD_SERIALIZE \
|
||||
, \
|
||||
.last_balance = jiffies, \
|
||||
.balance_interval = 1, \
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE */
|
||||
|
||||
#else
|
||||
|
||||
static inline void init_cpu_topology(void) { }
|
||||
static inline void store_cpu_topology(unsigned int cpuid) { }
|
||||
static inline int cluster_to_logical_mask(unsigned int socket_id,
|
||||
cpumask_t *cluster_mask) { return -EINVAL; }
|
||||
|
||||
#endif
|
||||
|
||||
#include <asm-generic/topology.h>
|
||||
|
||||
#endif /* _ASM_ARM_TOPOLOGY_H */
|
||||
@@ -9,15 +9,16 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
|
||||
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
|
||||
sys.o stacktrace.o time.o traps.o io.o vdso.o \
|
||||
hyp-stub.o psci.o
|
||||
hyp-stub.o psci.o cpu_ops.o
|
||||
|
||||
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
|
||||
sys_compat.o
|
||||
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
|
||||
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o
|
||||
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
|
||||
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
|
||||
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
|
||||
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
arm64-obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
|
||||
|
||||
obj-y += $(arm64-obj-y) vdso/
|
||||
obj-m += $(arm64-obj-m)
|
||||
|
||||
99
arch/arm64/kernel/cpu_ops.c
Normal file
99
arch/arm64/kernel/cpu_ops.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* CPU kernel entry/exit control
|
||||
*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
extern const struct cpu_operations smp_spin_table_ops;
|
||||
extern const struct cpu_operations cpu_psci_ops;
|
||||
|
||||
const struct cpu_operations *cpu_ops[NR_CPUS];
|
||||
|
||||
static const struct cpu_operations *supported_cpu_ops[] __initconst = {
|
||||
#ifdef CONFIG_SMP
|
||||
&smp_spin_table_ops,
|
||||
&cpu_psci_ops,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct cpu_operations * __init cpu_get_ops(const char *name)
|
||||
{
|
||||
const struct cpu_operations **ops = supported_cpu_ops;
|
||||
|
||||
while (*ops) {
|
||||
if (!strcmp(name, (*ops)->name))
|
||||
return *ops;
|
||||
|
||||
ops++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a cpu's enable method from the device tree and record it in cpu_ops.
|
||||
*/
|
||||
int __init cpu_read_ops(struct device_node *dn, int cpu)
|
||||
{
|
||||
const char *enable_method = of_get_property(dn, "enable-method", NULL);
|
||||
if (!enable_method) {
|
||||
/*
|
||||
* The boot CPU may not have an enable method (e.g. when
|
||||
* spin-table is used for secondaries). Don't warn spuriously.
|
||||
*/
|
||||
if (cpu != 0)
|
||||
pr_err("%s: missing enable-method property\n",
|
||||
dn->full_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
cpu_ops[cpu] = cpu_get_ops(enable_method);
|
||||
if (!cpu_ops[cpu]) {
|
||||
pr_warn("%s: unsupported enable-method property: %s\n",
|
||||
dn->full_name, enable_method);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init cpu_read_bootcpu_ops(void)
|
||||
{
|
||||
struct device_node *dn = NULL;
|
||||
u64 mpidr = cpu_logical_map(0);
|
||||
|
||||
while ((dn = of_find_node_by_type(dn, "cpu"))) {
|
||||
u64 hwid;
|
||||
const __be32 *prop;
|
||||
|
||||
prop = of_get_property(dn, "reg", NULL);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
hwid = of_read_number(prop, of_n_addr_cells(dn));
|
||||
if (hwid == mpidr) {
|
||||
cpu_read_ops(dn, 0);
|
||||
of_node_put(dn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
extern unsigned long __cpu_setup(void);
|
||||
|
||||
struct cpu_info __initdata cpu_table[] = {
|
||||
struct cpu_info cpu_table[] = {
|
||||
{
|
||||
.cpu_id_val = 0x000f0000,
|
||||
.cpu_id_mask = 0x000f0000,
|
||||
|
||||
@@ -217,7 +217,6 @@ ENTRY(__boot_cpu_mode)
|
||||
.quad PAGE_OFFSET
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
.pushsection .smp.pen.text, "ax"
|
||||
.align 3
|
||||
1: .quad .
|
||||
.quad secondary_holding_pen_release
|
||||
@@ -242,7 +241,16 @@ pen: ldr x4, [x3]
|
||||
wfe
|
||||
b pen
|
||||
ENDPROC(secondary_holding_pen)
|
||||
.popsection
|
||||
|
||||
/*
|
||||
* Secondary entry point that jumps straight into the kernel. Only to
|
||||
* be used where CPUs are brought online dynamically by the kernel.
|
||||
*/
|
||||
ENTRY(secondary_entry)
|
||||
bl __calc_phys_offset // x2=phys offset
|
||||
bl el2_setup // Drop to EL1
|
||||
b secondary_startup
|
||||
ENDPROC(secondary_entry)
|
||||
|
||||
ENTRY(secondary_startup)
|
||||
/*
|
||||
|
||||
@@ -81,3 +81,64 @@ void __init init_IRQ(void)
|
||||
if (!handle_arch_irq)
|
||||
panic("No interrupt controller found.");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static bool migrate_one_irq(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_data *d = irq_desc_get_irq_data(desc);
|
||||
const struct cpumask *affinity = d->affinity;
|
||||
struct irq_chip *c;
|
||||
bool ret = false;
|
||||
|
||||
/*
|
||||
* If this is a per-CPU interrupt, or the affinity does not
|
||||
* include this CPU, then we have nothing to do.
|
||||
*/
|
||||
if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
|
||||
return false;
|
||||
|
||||
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
|
||||
affinity = cpu_online_mask;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
c = irq_data_get_irq_chip(d);
|
||||
if (!c->irq_set_affinity)
|
||||
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
|
||||
else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
|
||||
cpumask_copy(d->affinity, affinity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current CPU has been marked offline. Migrate IRQs off this CPU.
|
||||
* If the affinity settings do not allow other CPUs, force them onto any
|
||||
* available CPU.
|
||||
*
|
||||
* Note: we must iterate over all IRQs, whether they have an attached
|
||||
* action structure or not, as we need to get chained interrupts too.
|
||||
*/
|
||||
void migrate_irqs(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct irq_desc *desc;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for_each_irq_desc(i, desc) {
|
||||
bool affinity_broken;
|
||||
|
||||
raw_spin_lock(&desc->lock);
|
||||
affinity_broken = migrate_one_irq(desc);
|
||||
raw_spin_unlock(&desc->lock);
|
||||
|
||||
if (affinity_broken)
|
||||
pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n",
|
||||
i, smp_processor_id());
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
@@ -102,6 +102,13 @@ void arch_cpu_idle(void)
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void arch_cpu_idle_dead(void)
|
||||
{
|
||||
cpu_die();
|
||||
}
|
||||
#endif
|
||||
|
||||
void machine_shutdown(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
@@ -17,12 +17,32 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/compiler.h>
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
struct psci_operations psci_ops;
|
||||
#define PSCI_POWER_STATE_TYPE_STANDBY 0
|
||||
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
|
||||
|
||||
struct psci_power_state {
|
||||
u16 id;
|
||||
u8 type;
|
||||
u8 affinity_level;
|
||||
};
|
||||
|
||||
struct psci_operations {
|
||||
int (*cpu_suspend)(struct psci_power_state state,
|
||||
unsigned long entry_point);
|
||||
int (*cpu_off)(struct psci_power_state state);
|
||||
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
|
||||
int (*migrate)(unsigned long cpuid);
|
||||
};
|
||||
|
||||
static struct psci_operations psci_ops;
|
||||
|
||||
static int (*invoke_psci_fn)(u64, u64, u64, u64);
|
||||
|
||||
@@ -209,3 +229,68 @@ out_put_node:
|
||||
of_node_put(np);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init cpu_psci_cpu_prepare(unsigned int cpu)
|
||||
{
|
||||
if (!psci_ops.cpu_on) {
|
||||
pr_err("no cpu_on method, not booting CPU%d\n", cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_psci_cpu_boot(unsigned int cpu)
|
||||
{
|
||||
int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
|
||||
if (err)
|
||||
pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int cpu_psci_cpu_disable(unsigned int cpu)
|
||||
{
|
||||
/* Fail early if we don't have CPU_OFF support */
|
||||
if (!psci_ops.cpu_off)
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpu_psci_cpu_die(unsigned int cpu)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* There are no known implementations of PSCI actually using the
|
||||
* power state field, pass a sensible default for now.
|
||||
*/
|
||||
struct psci_power_state state = {
|
||||
.type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
|
||||
};
|
||||
|
||||
ret = psci_ops.cpu_off(state);
|
||||
|
||||
pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct cpu_operations cpu_psci_ops = {
|
||||
.name = "psci",
|
||||
.cpu_init = cpu_psci_cpu_init,
|
||||
.cpu_prepare = cpu_psci_cpu_prepare,
|
||||
.cpu_boot = cpu_psci_cpu_boot,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_disable = cpu_psci_cpu_disable,
|
||||
.cpu_die = cpu_psci_cpu_die,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/elf.h>
|
||||
#include <asm/cputable.h>
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/smp_plat.h>
|
||||
@@ -97,6 +98,11 @@ void __init early_print(const char *str, ...)
|
||||
printk("%s", buf);
|
||||
}
|
||||
|
||||
bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
|
||||
{
|
||||
return phys_id == cpu_logical_map(cpu);
|
||||
}
|
||||
|
||||
static void __init setup_processor(void)
|
||||
{
|
||||
struct cpu_info *cpu_info;
|
||||
@@ -269,6 +275,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
psci_init();
|
||||
|
||||
cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
|
||||
cpu_read_bootcpu_ops();
|
||||
#ifdef CONFIG_SMP
|
||||
smp_init_cpus();
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
@@ -57,7 +58,6 @@
|
||||
* where to place its SVC stack
|
||||
*/
|
||||
struct secondary_data secondary_data;
|
||||
volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
|
||||
|
||||
enum ipi_msg_type {
|
||||
IPI_RESCHEDULE,
|
||||
@@ -66,61 +66,16 @@ enum ipi_msg_type {
|
||||
IPI_CPU_STOP,
|
||||
};
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(boot_lock);
|
||||
|
||||
/*
|
||||
* Write secondary_holding_pen_release in a way that is guaranteed to be
|
||||
* visible to all observers, irrespective of whether they're taking part
|
||||
* in coherency or not. This is necessary for the hotplug code to work
|
||||
* reliably.
|
||||
*/
|
||||
static void __cpuinit write_pen_release(u64 val)
|
||||
{
|
||||
void *start = (void *)&secondary_holding_pen_release;
|
||||
unsigned long size = sizeof(secondary_holding_pen_release);
|
||||
|
||||
secondary_holding_pen_release = val;
|
||||
__flush_dcache_area(start, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Boot a secondary CPU, and assign it the specified idle task.
|
||||
* This also gives us the initial stack to use for this CPU.
|
||||
*/
|
||||
static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
unsigned long timeout;
|
||||
if (cpu_ops[cpu]->cpu_boot)
|
||||
return cpu_ops[cpu]->cpu_boot(cpu);
|
||||
|
||||
/*
|
||||
* Set synchronisation state between this boot processor
|
||||
* and the secondary one
|
||||
*/
|
||||
raw_spin_lock(&boot_lock);
|
||||
|
||||
/*
|
||||
* Update the pen release flag.
|
||||
*/
|
||||
write_pen_release(cpu_logical_map(cpu));
|
||||
|
||||
/*
|
||||
* Send an event, causing the secondaries to read pen_release.
|
||||
*/
|
||||
sev();
|
||||
|
||||
timeout = jiffies + (1 * HZ);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (secondary_holding_pen_release == INVALID_HWID)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the secondary core is starting up let it run its
|
||||
* calibrations, then wait for it to finish
|
||||
*/
|
||||
raw_spin_unlock(&boot_lock);
|
||||
|
||||
return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static DECLARE_COMPLETION(cpu_running);
|
||||
@@ -161,6 +116,11 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
|
||||
{
|
||||
store_cpu_topology(cpuid);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the secondary CPU boot entry. We're using this CPUs
|
||||
* idle thread stack, but a set of temporary page tables.
|
||||
@@ -190,17 +150,8 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||
preempt_disable();
|
||||
trace_hardirqs_off();
|
||||
|
||||
/*
|
||||
* Let the primary processor know we're out of the
|
||||
* pen, then head off into the C entry point
|
||||
*/
|
||||
write_pen_release(INVALID_HWID);
|
||||
|
||||
/*
|
||||
* Synchronise with the boot thread.
|
||||
*/
|
||||
raw_spin_lock(&boot_lock);
|
||||
raw_spin_unlock(&boot_lock);
|
||||
if (cpu_ops[cpu]->cpu_postboot)
|
||||
cpu_ops[cpu]->cpu_postboot();
|
||||
|
||||
/*
|
||||
* Enable local interrupts.
|
||||
@@ -209,6 +160,8 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||
local_irq_enable();
|
||||
local_fiq_enable();
|
||||
|
||||
smp_store_cpu_info(cpu);
|
||||
|
||||
/*
|
||||
* OK, now it's safe to let the boot CPU continue. Wait for
|
||||
* the CPU migration code to notice that the CPU is online
|
||||
@@ -223,6 +176,102 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||
cpu_startup_entry(CPUHP_ONLINE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int op_cpu_disable(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* If we don't have a cpu_die method, abort before we reach the point
|
||||
* of no return. CPU0 may not have an cpu_ops, so test for it.
|
||||
*/
|
||||
if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* We may need to abort a hot unplug for some other mechanism-specific
|
||||
* reason.
|
||||
*/
|
||||
if (cpu_ops[cpu]->cpu_disable)
|
||||
return cpu_ops[cpu]->cpu_disable(cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* __cpu_disable runs on the processor to be shutdown.
|
||||
*/
|
||||
int __cpu_disable(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int ret;
|
||||
|
||||
ret = op_cpu_disable(cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Take this CPU offline. Once we clear this, we can't return,
|
||||
* and we must not schedule until we're ready to give up the cpu.
|
||||
*/
|
||||
set_cpu_online(cpu, false);
|
||||
|
||||
/*
|
||||
* OK - migrate IRQs away from this CPU
|
||||
*/
|
||||
migrate_irqs();
|
||||
|
||||
/*
|
||||
* Remove this CPU from the vm mask set of all processes.
|
||||
*/
|
||||
clear_tasks_mm_cpumask(cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DECLARE_COMPLETION(cpu_died);
|
||||
|
||||
/*
|
||||
* called on the thread which is asking for a CPU to be shutdown -
|
||||
* waits until shutdown has completed, or it is timed out.
|
||||
*/
|
||||
void __cpu_die(unsigned int cpu)
|
||||
{
|
||||
if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
|
||||
pr_crit("CPU%u: cpu didn't die\n", cpu);
|
||||
return;
|
||||
}
|
||||
pr_notice("CPU%u: shutdown\n", cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from the idle thread for the CPU which has been shutdown.
|
||||
*
|
||||
* Note that we disable IRQs here, but do not re-enable them
|
||||
* before returning to the caller. This is also the behaviour
|
||||
* of the other hotplug-cpu capable cores, so presumably coming
|
||||
* out of idle fixes this.
|
||||
*/
|
||||
void cpu_die(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
idle_task_exit();
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Tell __cpu_die() that this CPU is now safe to dispose of */
|
||||
complete(&cpu_died);
|
||||
|
||||
/*
|
||||
* Actually shutdown the CPU. This must never fail. The specific hotplug
|
||||
* mechanism must perform all required cache maintenance to ensure that
|
||||
* no dirty lines are lost in the process of shutting down the CPU.
|
||||
*/
|
||||
cpu_ops[cpu]->cpu_die(cpu);
|
||||
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
{
|
||||
unsigned long bogosum = loops_per_jiffy * num_online_cpus();
|
||||
@@ -238,28 +287,6 @@ void __init smp_prepare_boot_cpu(void)
|
||||
|
||||
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
|
||||
|
||||
static const struct smp_enable_ops *enable_ops[] __initconst = {
|
||||
&smp_spin_table_ops,
|
||||
&smp_psci_ops,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct smp_enable_ops *smp_enable_ops[NR_CPUS];
|
||||
|
||||
static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
|
||||
{
|
||||
const struct smp_enable_ops **ops = enable_ops;
|
||||
|
||||
while (*ops) {
|
||||
if (!strcmp(name, (*ops)->name))
|
||||
return *ops;
|
||||
|
||||
ops++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumerate the possible CPU set from the device tree and build the
|
||||
* cpu logical map array containing MPIDR values related to logical
|
||||
@@ -267,9 +294,8 @@ static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
|
||||
*/
|
||||
void __init smp_init_cpus(void)
|
||||
{
|
||||
const char *enable_method;
|
||||
struct device_node *dn = NULL;
|
||||
int i, cpu = 1;
|
||||
unsigned int i, cpu = 1;
|
||||
bool bootcpu_valid = false;
|
||||
|
||||
while ((dn = of_find_node_by_type(dn, "cpu"))) {
|
||||
@@ -338,25 +364,10 @@ void __init smp_init_cpus(void)
|
||||
if (cpu >= NR_CPUS)
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* We currently support only the "spin-table" enable-method.
|
||||
*/
|
||||
enable_method = of_get_property(dn, "enable-method", NULL);
|
||||
if (!enable_method) {
|
||||
pr_err("%s: missing enable-method property\n",
|
||||
dn->full_name);
|
||||
if (cpu_read_ops(dn, cpu) != 0)
|
||||
goto next;
|
||||
}
|
||||
|
||||
smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
|
||||
|
||||
if (!smp_enable_ops[cpu]) {
|
||||
pr_err("%s: invalid enable-method property: %s\n",
|
||||
dn->full_name, enable_method);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
|
||||
if (cpu_ops[cpu]->cpu_init(dn, cpu))
|
||||
goto next;
|
||||
|
||||
pr_debug("cpu logical map 0x%llx\n", hwid);
|
||||
@@ -386,8 +397,13 @@ next:
|
||||
|
||||
void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
int cpu, err;
|
||||
unsigned int ncores = num_possible_cpus();
|
||||
int err;
|
||||
unsigned int cpu, ncores = num_possible_cpus();
|
||||
|
||||
init_cpu_topology();
|
||||
|
||||
smp_store_cpu_info(smp_processor_id());
|
||||
|
||||
|
||||
/*
|
||||
* are we trying to boot more cores than exist?
|
||||
@@ -414,10 +430,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
if (cpu == smp_processor_id())
|
||||
continue;
|
||||
|
||||
if (!smp_enable_ops[cpu])
|
||||
if (!cpu_ops[cpu])
|
||||
continue;
|
||||
|
||||
err = smp_enable_ops[cpu]->prepare_cpu(cpu);
|
||||
err = cpu_ops[cpu]->cpu_prepare(cpu);
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* PSCI SMP initialisation
|
||||
*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/psci.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
static int __init smp_psci_init_cpu(struct device_node *dn, int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init smp_psci_prepare_cpu(int cpu)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!psci_ops.cpu_on) {
|
||||
pr_err("psci: no cpu_on method, not booting CPU%d\n", cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_holding_pen));
|
||||
if (err) {
|
||||
pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct smp_enable_ops smp_psci_ops __initconst = {
|
||||
.name = "psci",
|
||||
.init_cpu = smp_psci_init_cpu,
|
||||
.prepare_cpu = smp_psci_prepare_cpu,
|
||||
};
|
||||
@@ -16,15 +16,39 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
extern void secondary_holding_pen(void);
|
||||
volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
|
||||
|
||||
static phys_addr_t cpu_release_addr[NR_CPUS];
|
||||
static DEFINE_RAW_SPINLOCK(boot_lock);
|
||||
|
||||
static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu)
|
||||
/*
|
||||
* Write secondary_holding_pen_release in a way that is guaranteed to be
|
||||
* visible to all observers, irrespective of whether they're taking part
|
||||
* in coherency or not. This is necessary for the hotplug code to work
|
||||
* reliably.
|
||||
*/
|
||||
static void write_pen_release(u64 val)
|
||||
{
|
||||
void *start = (void *)&secondary_holding_pen_release;
|
||||
unsigned long size = sizeof(secondary_holding_pen_release);
|
||||
|
||||
secondary_holding_pen_release = val;
|
||||
__flush_dcache_area(start, size);
|
||||
}
|
||||
|
||||
|
||||
static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* Determine the address from which the CPU is polling.
|
||||
@@ -40,7 +64,7 @@ static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init smp_spin_table_prepare_cpu(int cpu)
|
||||
static int smp_spin_table_cpu_prepare(unsigned int cpu)
|
||||
{
|
||||
void **release_addr;
|
||||
|
||||
@@ -59,8 +83,60 @@ static int __init smp_spin_table_prepare_cpu(int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct smp_enable_ops smp_spin_table_ops __initconst = {
|
||||
static int smp_spin_table_cpu_boot(unsigned int cpu)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
/*
|
||||
* Set synchronisation state between this boot processor
|
||||
* and the secondary one
|
||||
*/
|
||||
raw_spin_lock(&boot_lock);
|
||||
|
||||
/*
|
||||
* Update the pen release flag.
|
||||
*/
|
||||
write_pen_release(cpu_logical_map(cpu));
|
||||
|
||||
/*
|
||||
* Send an event, causing the secondaries to read pen_release.
|
||||
*/
|
||||
sev();
|
||||
|
||||
timeout = jiffies + (1 * HZ);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (secondary_holding_pen_release == INVALID_HWID)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the secondary core is starting up let it run its
|
||||
* calibrations, then wait for it to finish
|
||||
*/
|
||||
raw_spin_unlock(&boot_lock);
|
||||
|
||||
return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
|
||||
}
|
||||
|
||||
void smp_spin_table_cpu_postboot(void)
|
||||
{
|
||||
/*
|
||||
* Let the primary processor know we're out of the pen.
|
||||
*/
|
||||
write_pen_release(INVALID_HWID);
|
||||
|
||||
/*
|
||||
* Synchronise with the boot thread.
|
||||
*/
|
||||
raw_spin_lock(&boot_lock);
|
||||
raw_spin_unlock(&boot_lock);
|
||||
}
|
||||
|
||||
const struct cpu_operations smp_spin_table_ops = {
|
||||
.name = "spin-table",
|
||||
.init_cpu = smp_spin_table_init_cpu,
|
||||
.prepare_cpu = smp_spin_table_prepare_cpu,
|
||||
.cpu_init = smp_spin_table_cpu_init,
|
||||
.cpu_prepare = smp_spin_table_cpu_prepare,
|
||||
.cpu_boot = smp_spin_table_cpu_boot,
|
||||
.cpu_postboot = smp_spin_table_cpu_postboot,
|
||||
};
|
||||
|
||||
537
arch/arm64/kernel/topology.c
Normal file
537
arch/arm64/kernel/topology.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* arch/arm64/kernel/topology.c
|
||||
*
|
||||
* Copyright (C) 2011,2013 Linaro Limited.
|
||||
* Written by: Vincent Guittot
|
||||
*
|
||||
* based on arch/sh/kernel/topology.c
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/node.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/topology.h>
|
||||
|
||||
/*
|
||||
* cpu power scale management
|
||||
*/
|
||||
|
||||
/*
|
||||
* cpu power table
|
||||
* This per cpu data structure describes the relative capacity of each core.
|
||||
* On a heteregenous system, cores don't have the same computation capacity
|
||||
* and we reflect that difference in the cpu_power field so the scheduler can
|
||||
* take this difference into account during load balance. A per cpu structure
|
||||
* is preferred because each CPU updates its own cpu_power field during the
|
||||
* load balance except for idle cores. One idle core is selected to run the
|
||||
* rebalance_domains for all idle cores and the cpu_power can be updated
|
||||
* during this sequence.
|
||||
*/
|
||||
static DEFINE_PER_CPU(unsigned long, cpu_scale);
|
||||
|
||||
unsigned long arch_scale_freq_power(struct sched_domain *sd, int cpu)
|
||||
{
|
||||
return per_cpu(cpu_scale, cpu);
|
||||
}
|
||||
|
||||
static void set_power_scale(unsigned int cpu, unsigned long power)
|
||||
{
|
||||
per_cpu(cpu_scale, cpu) = power;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct cpu_efficiency {
|
||||
const char *compatible;
|
||||
unsigned long efficiency;
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of relative efficiency of each processors
|
||||
* The efficiency value must fit in 20bit and the final
|
||||
* cpu_scale value must be in the range
|
||||
* 0 < cpu_scale < 3*SCHED_POWER_SCALE/2
|
||||
* in order to return at most 1 when DIV_ROUND_CLOSEST
|
||||
* is used to compute the capacity of a CPU.
|
||||
* Processors that are not defined in the table,
|
||||
* use the default SCHED_POWER_SCALE value for cpu_scale.
|
||||
*/
|
||||
static const struct cpu_efficiency table_efficiency[] = {
|
||||
{ "arm,cortex-a57", 3891 },
|
||||
{ "arm,cortex-a53", 2048 },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
static unsigned long *__cpu_capacity;
|
||||
#define cpu_capacity(cpu) __cpu_capacity[cpu]
|
||||
|
||||
static unsigned long middle_capacity = 1;
|
||||
static int cluster_id;
|
||||
|
||||
static int __init get_cpu_for_node(struct device_node *node)
|
||||
{
|
||||
struct device_node *cpu_node;
|
||||
int cpu;
|
||||
|
||||
cpu_node = of_parse_phandle(node, "cpu", 0);
|
||||
if (!cpu_node) {
|
||||
pr_crit("%s: Unable to parse CPU phandle\n", node->full_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (of_get_cpu_node(cpu, NULL) == cpu_node)
|
||||
return cpu;
|
||||
}
|
||||
|
||||
pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __init parse_core(struct device_node *core, int core_id)
|
||||
{
|
||||
char name[10];
|
||||
bool leaf = true;
|
||||
int i, cpu;
|
||||
struct device_node *t;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
snprintf(name, sizeof(name), "thread%d", i);
|
||||
t = of_get_child_by_name(core, name);
|
||||
if (t) {
|
||||
leaf = false;
|
||||
cpu = get_cpu_for_node(t);
|
||||
if (cpu) {
|
||||
pr_info("CPU%d: socket %d core %d thread %d\n",
|
||||
cpu, cluster_id, core_id, i);
|
||||
cpu_topology[cpu].socket_id = cluster_id;
|
||||
cpu_topology[cpu].core_id = core_id;
|
||||
cpu_topology[cpu].thread_id = i;
|
||||
} else {
|
||||
pr_err("%s: Can't get CPU for thread\n",
|
||||
t->full_name);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while (t);
|
||||
|
||||
cpu = get_cpu_for_node(core);
|
||||
if (cpu >= 0) {
|
||||
if (!leaf) {
|
||||
pr_err("%s: Core has both threads and CPU\n",
|
||||
core->full_name);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("CPU%d: socket %d core %d\n",
|
||||
cpu, cluster_id, core_id);
|
||||
cpu_topology[cpu].socket_id = cluster_id;
|
||||
cpu_topology[cpu].core_id = core_id;
|
||||
} else if (leaf) {
|
||||
pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init parse_cluster(struct device_node *cluster)
|
||||
{
|
||||
char name[10];
|
||||
bool leaf = true;
|
||||
bool has_cores = false;
|
||||
struct device_node *c;
|
||||
int core_id = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* First check for child clusters; we currently ignore any
|
||||
* information about the nesting of clusters and present the
|
||||
* scheduler with a flat list of them.
|
||||
*/
|
||||
i = 0;
|
||||
do {
|
||||
snprintf(name, sizeof(name), "cluster%d", i);
|
||||
c = of_get_child_by_name(cluster, name);
|
||||
if (c) {
|
||||
parse_cluster(c);
|
||||
leaf = false;
|
||||
}
|
||||
i++;
|
||||
} while (c);
|
||||
|
||||
/* Now check for cores */
|
||||
i = 0;
|
||||
do {
|
||||
snprintf(name, sizeof(name), "core%d", i);
|
||||
c = of_get_child_by_name(cluster, name);
|
||||
if (c) {
|
||||
has_cores = true;
|
||||
|
||||
if (leaf)
|
||||
parse_core(c, core_id++);
|
||||
else
|
||||
pr_err("%s: Non-leaf cluster with core %s\n",
|
||||
cluster->full_name, name);
|
||||
}
|
||||
i++;
|
||||
} while (c);
|
||||
|
||||
if (leaf && !has_cores)
|
||||
pr_warn("%s: empty cluster\n", cluster->full_name);
|
||||
|
||||
if (leaf)
|
||||
cluster_id++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate all CPUs' descriptor in DT and compute the efficiency
|
||||
* (as per table_efficiency). Also calculate a middle efficiency
|
||||
* as close as possible to (max{eff_i} - min{eff_i}) / 2
|
||||
* This is later used to scale the cpu_power field such that an
|
||||
* 'average' CPU is of middle power. Also see the comments near
|
||||
* table_efficiency[] and update_cpu_power().
|
||||
*/
|
||||
static void __init parse_dt_topology(void)
|
||||
{
|
||||
const struct cpu_efficiency *cpu_eff;
|
||||
struct device_node *cn = NULL;
|
||||
unsigned long min_capacity = (unsigned long)(-1);
|
||||
unsigned long max_capacity = 0;
|
||||
unsigned long capacity = 0;
|
||||
int alloc_size, cpu;
|
||||
|
||||
alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity);
|
||||
__cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
|
||||
|
||||
cn = of_find_node_by_path("/cpus");
|
||||
if (!cn) {
|
||||
pr_err("No CPU information found in DT\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If topology is provided as a cpu-map it is essentially a
|
||||
* root cluster.
|
||||
*/
|
||||
cn = of_find_node_by_name(cn, "cpu-map");
|
||||
if (!cn)
|
||||
return;
|
||||
parse_cluster(cn);
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
const u32 *rate;
|
||||
int len;
|
||||
|
||||
/* Too early to use cpu->of_node */
|
||||
cn = of_get_cpu_node(cpu, NULL);
|
||||
if (!cn) {
|
||||
pr_err("Missing device node for CPU %d\n", cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check if the cpu is marked as "disabled", if so ignore */
|
||||
if (!of_device_is_available(cn))
|
||||
continue;
|
||||
|
||||
for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
|
||||
if (of_device_is_compatible(cn, cpu_eff->compatible))
|
||||
break;
|
||||
|
||||
if (cpu_eff->compatible == NULL) {
|
||||
pr_warn("%s: Unknown CPU type\n", cn->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
rate = of_get_property(cn, "clock-frequency", &len);
|
||||
if (!rate || len != 4) {
|
||||
pr_err("%s: Missing clock-frequency property\n",
|
||||
cn->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
|
||||
|
||||
/* Save min capacity of the system */
|
||||
if (capacity < min_capacity)
|
||||
min_capacity = capacity;
|
||||
|
||||
/* Save max capacity of the system */
|
||||
if (capacity > max_capacity)
|
||||
max_capacity = capacity;
|
||||
|
||||
cpu_capacity(cpu) = capacity;
|
||||
}
|
||||
|
||||
/* If min and max capacities are equal we bypass the update of the
|
||||
* cpu_scale because all CPUs have the same capacity. Otherwise, we
|
||||
* compute a middle_capacity factor that will ensure that the capacity
|
||||
* of an 'average' CPU of the system will be as close as possible to
|
||||
* SCHED_POWER_SCALE, which is the default value, but with the
|
||||
* constraint explained near table_efficiency[].
|
||||
*/
|
||||
if (min_capacity == max_capacity)
|
||||
return;
|
||||
else if (4 * max_capacity < (3 * (max_capacity + min_capacity)))
|
||||
middle_capacity = (min_capacity + max_capacity)
|
||||
>> (SCHED_POWER_SHIFT+1);
|
||||
else
|
||||
middle_capacity = ((max_capacity / 3)
|
||||
>> (SCHED_POWER_SHIFT-1)) + 1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a customed capacity of a CPU in the cpu_topo_data table during the
|
||||
* boot. The update of all CPUs is in O(n^2) for heteregeneous system but the
|
||||
* function returns directly for SMP system.
|
||||
*/
|
||||
static void update_cpu_power(unsigned int cpu)
|
||||
{
|
||||
if (!cpu_capacity(cpu))
|
||||
return;
|
||||
|
||||
set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity);
|
||||
|
||||
pr_info("CPU%u: update cpu_power %lu\n",
|
||||
cpu, arch_scale_freq_power(NULL, cpu));
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void parse_dt_topology(void) {}
|
||||
static inline void update_cpu_power(unsigned int cpuid) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu topology table
|
||||
*/
|
||||
struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
EXPORT_SYMBOL_GPL(cpu_topology);
|
||||
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu)
|
||||
{
|
||||
return &cpu_topology[cpu].core_sibling;
|
||||
}
|
||||
|
||||
static void update_siblings_masks(unsigned int cpuid)
|
||||
{
|
||||
struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
|
||||
int cpu;
|
||||
|
||||
/* update core and thread sibling masks */
|
||||
for_each_possible_cpu(cpu) {
|
||||
cpu_topo = &cpu_topology[cpu];
|
||||
|
||||
if (cpuid_topo->socket_id != cpu_topo->socket_id)
|
||||
continue;
|
||||
|
||||
cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
|
||||
if (cpu != cpuid)
|
||||
cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
|
||||
|
||||
if (cpuid_topo->core_id != cpu_topo->core_id)
|
||||
continue;
|
||||
|
||||
cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
|
||||
if (cpu != cpuid)
|
||||
cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
|
||||
}
|
||||
smp_wmb();
|
||||
}
|
||||
|
||||
void store_cpu_topology(unsigned int cpuid)
|
||||
{
|
||||
struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
|
||||
|
||||
/* DT should have been parsed by the time we get here */
|
||||
if (cpuid_topo->core_id == -1)
|
||||
pr_info("CPU%u: No topology information configured\n", cpuid);
|
||||
else
|
||||
update_siblings_masks(cpuid);
|
||||
|
||||
update_cpu_power(cpuid);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
|
||||
/*
|
||||
* Retrieve logical cpu index corresponding to a given MPIDR[23:0]
|
||||
* - mpidr: MPIDR[23:0] to be used for the look-up
|
||||
*
|
||||
* Returns the cpu logical index or -EINVAL on look-up error
|
||||
*/
|
||||
static inline int get_logical_index(u32 mpidr)
|
||||
{
|
||||
int cpu;
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (cpu_logical_map(cpu) == mpidr)
|
||||
return cpu;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const char * const little_cores[] = {
|
||||
"arm,cortex-a53",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static bool is_little_cpu(struct device_node *cn)
|
||||
{
|
||||
const char * const *lc;
|
||||
for (lc = little_cores; *lc; lc++)
|
||||
if (of_device_is_compatible(cn, *lc))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void __init arch_get_fast_and_slow_cpus(struct cpumask *fast,
|
||||
struct cpumask *slow)
|
||||
{
|
||||
struct device_node *cn = NULL;
|
||||
int cpu;
|
||||
|
||||
cpumask_clear(fast);
|
||||
cpumask_clear(slow);
|
||||
|
||||
/*
|
||||
* Use the config options if they are given. This helps testing
|
||||
* HMP scheduling on systems without a big.LITTLE architecture.
|
||||
*/
|
||||
if (strlen(CONFIG_HMP_FAST_CPU_MASK) && strlen(CONFIG_HMP_SLOW_CPU_MASK)) {
|
||||
if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast))
|
||||
WARN(1, "Failed to parse HMP fast cpu mask!\n");
|
||||
if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow))
|
||||
WARN(1, "Failed to parse HMP slow cpu mask!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Else, parse device tree for little cores.
|
||||
*/
|
||||
while ((cn = of_find_node_by_type(cn, "cpu"))) {
|
||||
|
||||
const u32 *mpidr;
|
||||
int len;
|
||||
|
||||
mpidr = of_get_property(cn, "reg", &len);
|
||||
if (!mpidr || len != 8) {
|
||||
pr_err("%s missing reg property\n", cn->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu = get_logical_index(be32_to_cpup(mpidr+1));
|
||||
if (cpu == -EINVAL) {
|
||||
pr_err("couldn't get logical index for mpidr %x\n",
|
||||
be32_to_cpup(mpidr+1));
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_little_cpu(cn))
|
||||
cpumask_set_cpu(cpu, slow);
|
||||
else
|
||||
cpumask_set_cpu(cpu, fast);
|
||||
}
|
||||
|
||||
if (!cpumask_empty(fast) && !cpumask_empty(slow))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We didn't find both big and little cores so let's call all cores
|
||||
* fast as this will keep the system running, with all cores being
|
||||
* treated equal.
|
||||
*/
|
||||
cpumask_setall(fast);
|
||||
cpumask_clear(slow);
|
||||
}
|
||||
|
||||
struct cpumask hmp_slow_cpu_mask;
|
||||
|
||||
void __init arch_get_hmp_domains(struct list_head *hmp_domains_list)
|
||||
{
|
||||
struct cpumask hmp_fast_cpu_mask;
|
||||
struct hmp_domain *domain;
|
||||
|
||||
arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask);
|
||||
|
||||
/*
|
||||
* Initialize hmp_domains
|
||||
* Must be ordered with respect to compute capacity.
|
||||
* Fastest domain at head of list.
|
||||
*/
|
||||
if(!cpumask_empty(&hmp_slow_cpu_mask)) {
|
||||
domain = (struct hmp_domain *)
|
||||
kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
|
||||
cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask);
|
||||
cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
|
||||
list_add(&domain->hmp_domains, hmp_domains_list);
|
||||
}
|
||||
domain = (struct hmp_domain *)
|
||||
kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
|
||||
cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask);
|
||||
cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
|
||||
list_add(&domain->hmp_domains, hmp_domains_list);
|
||||
}
|
||||
#endif /* CONFIG_SCHED_HMP */
|
||||
|
||||
/*
|
||||
* cluster_to_logical_mask - return cpu logical mask of CPUs in a cluster
|
||||
* @socket_id: cluster HW identifier
|
||||
* @cluster_mask: the cpumask location to be initialized, modified by the
|
||||
* function only if return value == 0
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* 0 on success
|
||||
* -EINVAL if cluster_mask is NULL or there is no record matching socket_id
|
||||
*/
|
||||
int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (!cluster_mask)
|
||||
return -EINVAL;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
if (socket_id == topology_physical_package_id(cpu)) {
|
||||
cpumask_copy(cluster_mask, topology_core_cpumask(cpu));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* init_cpu_topology is called at boot when only one cpu is running
|
||||
* which prevent simultaneous write access to cpu_topology array
|
||||
*/
|
||||
void __init init_cpu_topology(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* init core mask and power*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
|
||||
|
||||
cpu_topo->thread_id = -1;
|
||||
cpu_topo->core_id = -1;
|
||||
cpu_topo->socket_id = -1;
|
||||
cpumask_clear(&cpu_topo->core_sibling);
|
||||
cpumask_clear(&cpu_topo->thread_sibling);
|
||||
|
||||
set_power_scale(cpu, SCHED_POWER_SCALE);
|
||||
}
|
||||
smp_wmb();
|
||||
|
||||
parse_dt_topology();
|
||||
}
|
||||
@@ -41,7 +41,6 @@ SECTIONS
|
||||
}
|
||||
.text : { /* Real text segment */
|
||||
_stext = .; /* Text and read-only data */
|
||||
*(.smp.pen.text)
|
||||
__exception_text_start = .;
|
||||
*(.exception.text)
|
||||
__exception_text_end = .;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <asm/setup.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
/*
|
||||
* The kernel is loaded where we want it to be and all caches
|
||||
@@ -20,11 +22,6 @@
|
||||
.section .init.text,"ax"
|
||||
.global _start
|
||||
_start:
|
||||
/* Check if the boot loader actually provided a tag table */
|
||||
lddpc r0, magic_number
|
||||
cp.w r12, r0
|
||||
brne no_tag_table
|
||||
|
||||
/* Initialize .bss */
|
||||
lddpc r2, bss_start_addr
|
||||
lddpc r3, end_addr
|
||||
@@ -34,6 +31,25 @@ _start:
|
||||
cp r2, r3
|
||||
brlo 1b
|
||||
|
||||
/* Initialize status register */
|
||||
lddpc r0, init_sr
|
||||
mtsr SYSREG_SR, r0
|
||||
|
||||
/* Set initial stack pointer */
|
||||
lddpc sp, stack_addr
|
||||
sub sp, -THREAD_SIZE
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
/* Mark last stack frame */
|
||||
mov lr, 0
|
||||
mov r7, 0
|
||||
#endif
|
||||
|
||||
/* Check if the boot loader actually provided a tag table */
|
||||
lddpc r0, magic_number
|
||||
cp.w r12, r0
|
||||
brne no_tag_table
|
||||
|
||||
/*
|
||||
* Save the tag table address for later use. This must be done
|
||||
* _after_ .bss has been initialized...
|
||||
@@ -53,8 +69,15 @@ bss_start_addr:
|
||||
.long __bss_start
|
||||
end_addr:
|
||||
.long _end
|
||||
init_sr:
|
||||
.long 0x007f0000 /* Supervisor mode, everything masked */
|
||||
stack_addr:
|
||||
.long init_thread_union
|
||||
panic_addr:
|
||||
.long panic
|
||||
|
||||
no_tag_table:
|
||||
sub r12, pc, (. - 2f)
|
||||
bral panic
|
||||
/* branch to panic() which can be far away with that construct */
|
||||
lddpc pc, panic_addr
|
||||
2: .asciz "Boot loader didn't provide correct magic number\n"
|
||||
|
||||
@@ -401,9 +401,10 @@ handle_critical:
|
||||
/* We should never get here... */
|
||||
bad_return:
|
||||
sub r12, pc, (. - 1f)
|
||||
bral panic
|
||||
lddpc pc, 2f
|
||||
.align 2
|
||||
1: .asciz "Return from critical exception!"
|
||||
2: .long panic
|
||||
|
||||
.align 1
|
||||
do_bus_error_write:
|
||||
|
||||
@@ -10,33 +10,13 @@
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
.section .init.text,"ax"
|
||||
.global kernel_entry
|
||||
kernel_entry:
|
||||
/* Initialize status register */
|
||||
lddpc r0, init_sr
|
||||
mtsr SYSREG_SR, r0
|
||||
|
||||
/* Set initial stack pointer */
|
||||
lddpc sp, stack_addr
|
||||
sub sp, -THREAD_SIZE
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
/* Mark last stack frame */
|
||||
mov lr, 0
|
||||
mov r7, 0
|
||||
#endif
|
||||
|
||||
/* Start the show */
|
||||
lddpc pc, kernel_start_addr
|
||||
|
||||
.align 2
|
||||
init_sr:
|
||||
.long 0x007f0000 /* Supervisor mode, everything masked */
|
||||
stack_addr:
|
||||
.long init_thread_union
|
||||
kernel_start_addr:
|
||||
.long start_kernel
|
||||
|
||||
11
arch/parisc/include/asm/socket.h
Normal file
11
arch/parisc/include/asm/socket.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _ASM_SOCKET_H
|
||||
#define _ASM_SOCKET_H
|
||||
|
||||
#include <uapi/asm/socket.h>
|
||||
|
||||
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
||||
* have to define SOCK_NONBLOCK to a different value here.
|
||||
*/
|
||||
#define SOCK_NONBLOCK 0x40000000
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _ASM_SOCKET_H
|
||||
#define _ASM_SOCKET_H
|
||||
#ifndef _UAPI_ASM_SOCKET_H
|
||||
#define _UAPI_ASM_SOCKET_H
|
||||
|
||||
#include <asm/sockios.h>
|
||||
|
||||
@@ -73,9 +73,4 @@
|
||||
|
||||
#define SO_SELECT_ERR_QUEUE 0x4026
|
||||
|
||||
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
||||
* have to define SOCK_NONBLOCK to a different value here.
|
||||
*/
|
||||
#define SOCK_NONBLOCK 0x40000000
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
||||
@@ -61,8 +61,15 @@ static int get_offset(struct address_space *mapping)
|
||||
return (unsigned long) mapping >> 8;
|
||||
}
|
||||
|
||||
static unsigned long get_shared_area(struct address_space *mapping,
|
||||
unsigned long addr, unsigned long len, unsigned long pgoff)
|
||||
static unsigned long shared_align_offset(struct file *filp, unsigned long pgoff)
|
||||
{
|
||||
struct address_space *mapping = filp ? filp->f_mapping : NULL;
|
||||
|
||||
return (get_offset(mapping) + pgoff) << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static unsigned long get_shared_area(struct file *filp, unsigned long addr,
|
||||
unsigned long len, unsigned long pgoff)
|
||||
{
|
||||
struct vm_unmapped_area_info info;
|
||||
|
||||
@@ -71,7 +78,7 @@ static unsigned long get_shared_area(struct address_space *mapping,
|
||||
info.low_limit = PAGE_ALIGN(addr);
|
||||
info.high_limit = TASK_SIZE;
|
||||
info.align_mask = PAGE_MASK & (SHMLBA - 1);
|
||||
info.align_offset = (get_offset(mapping) + pgoff) << PAGE_SHIFT;
|
||||
info.align_offset = shared_align_offset(filp, pgoff);
|
||||
return vm_unmapped_area(&info);
|
||||
}
|
||||
|
||||
@@ -82,20 +89,18 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
||||
return -ENOMEM;
|
||||
if (flags & MAP_FIXED) {
|
||||
if ((flags & MAP_SHARED) &&
|
||||
(addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
|
||||
(addr - shared_align_offset(filp, pgoff)) & (SHMLBA - 1))
|
||||
return -EINVAL;
|
||||
return addr;
|
||||
}
|
||||
if (!addr)
|
||||
addr = TASK_UNMAPPED_BASE;
|
||||
|
||||
if (filp) {
|
||||
addr = get_shared_area(filp->f_mapping, addr, len, pgoff);
|
||||
} else if(flags & MAP_SHARED) {
|
||||
addr = get_shared_area(NULL, addr, len, pgoff);
|
||||
} else {
|
||||
if (filp || (flags & MAP_SHARED))
|
||||
addr = get_shared_area(filp, addr, len, pgoff);
|
||||
else
|
||||
addr = get_unshared_area(addr, len);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
|
||||
|
||||
extern void kdump_move_device_tree(void);
|
||||
|
||||
/* CPU OF node matching */
|
||||
struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
|
||||
|
||||
/* cache lookup */
|
||||
struct device_node *of_find_next_cache_node(struct device_node *np);
|
||||
|
||||
|
||||
@@ -827,49 +827,10 @@ static int __init prom_reconfig_setup(void)
|
||||
__initcall(prom_reconfig_setup);
|
||||
#endif
|
||||
|
||||
/* Find the device node for a given logical cpu number, also returns the cpu
|
||||
* local thread number (index in ibm,interrupt-server#s) if relevant and
|
||||
* asked for (non NULL)
|
||||
*/
|
||||
struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
|
||||
bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
|
||||
{
|
||||
int hardid;
|
||||
struct device_node *np;
|
||||
|
||||
hardid = get_hard_smp_processor_id(cpu);
|
||||
|
||||
for_each_node_by_type(np, "cpu") {
|
||||
const u32 *intserv;
|
||||
unsigned int plen, t;
|
||||
|
||||
/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
|
||||
* fallback to "reg" property and assume no threads
|
||||
*/
|
||||
intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
|
||||
&plen);
|
||||
if (intserv == NULL) {
|
||||
const u32 *reg = of_get_property(np, "reg", NULL);
|
||||
if (reg == NULL)
|
||||
continue;
|
||||
if (*reg == hardid) {
|
||||
if (thread)
|
||||
*thread = 0;
|
||||
return np;
|
||||
}
|
||||
} else {
|
||||
plen /= sizeof(u32);
|
||||
for (t = 0; t < plen; t++) {
|
||||
if (hardid == intserv[t]) {
|
||||
if (thread)
|
||||
*thread = t;
|
||||
return np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return (int)phys_id == get_hard_smp_processor_id(cpu);
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_cpu_node);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
|
||||
static struct debugfs_blob_wrapper flat_dt_blob;
|
||||
|
||||
@@ -442,6 +442,12 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
|
||||
#endif /* CONFIG_ALTIVEC */
|
||||
if (copy_fpr_to_user(&frame->mc_fregs, current))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Clear the MSR VSX bit to indicate there is no valid state attached
|
||||
* to this context, except in the specific case below where we set it.
|
||||
*/
|
||||
msr &= ~MSR_VSX;
|
||||
#ifdef CONFIG_VSX
|
||||
/*
|
||||
* Copy VSR 0-31 upper half from thread_struct to local
|
||||
@@ -454,15 +460,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
|
||||
if (copy_vsx_to_user(&frame->mc_vsregs, current))
|
||||
return 1;
|
||||
msr |= MSR_VSX;
|
||||
} else if (!ctx_has_vsx_region)
|
||||
/*
|
||||
* With a small context structure we can't hold the VSX
|
||||
* registers, hence clear the MSR value to indicate the state
|
||||
* was not saved.
|
||||
*/
|
||||
msr &= ~MSR_VSX;
|
||||
|
||||
|
||||
}
|
||||
#endif /* CONFIG_VSX */
|
||||
#ifdef CONFIG_SPE
|
||||
/* save spe registers */
|
||||
|
||||
@@ -121,6 +121,12 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
||||
flush_fp_to_thread(current);
|
||||
/* copy fpr regs and fpscr */
|
||||
err |= copy_fpr_to_user(&sc->fp_regs, current);
|
||||
|
||||
/*
|
||||
* Clear the MSR VSX bit to indicate there is no valid state attached
|
||||
* to this context, except in the specific case below where we set it.
|
||||
*/
|
||||
msr &= ~MSR_VSX;
|
||||
#ifdef CONFIG_VSX
|
||||
/*
|
||||
* Copy VSX low doubleword to local buffer for formatting,
|
||||
|
||||
@@ -55,8 +55,7 @@ struct pcc_param {
|
||||
|
||||
struct s390_xts_ctx {
|
||||
u8 key[32];
|
||||
u8 xts_param[16];
|
||||
struct pcc_param pcc;
|
||||
u8 pcc_key[32];
|
||||
long enc;
|
||||
long dec;
|
||||
int key_len;
|
||||
@@ -591,7 +590,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||
xts_ctx->enc = KM_XTS_128_ENCRYPT;
|
||||
xts_ctx->dec = KM_XTS_128_DECRYPT;
|
||||
memcpy(xts_ctx->key + 16, in_key, 16);
|
||||
memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16);
|
||||
memcpy(xts_ctx->pcc_key + 16, in_key + 16, 16);
|
||||
break;
|
||||
case 48:
|
||||
xts_ctx->enc = 0;
|
||||
@@ -602,7 +601,7 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||
xts_ctx->enc = KM_XTS_256_ENCRYPT;
|
||||
xts_ctx->dec = KM_XTS_256_DECRYPT;
|
||||
memcpy(xts_ctx->key, in_key, 32);
|
||||
memcpy(xts_ctx->pcc.key, in_key + 32, 32);
|
||||
memcpy(xts_ctx->pcc_key, in_key + 32, 32);
|
||||
break;
|
||||
default:
|
||||
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||||
@@ -621,29 +620,33 @@ static int xts_aes_crypt(struct blkcipher_desc *desc, long func,
|
||||
unsigned int nbytes = walk->nbytes;
|
||||
unsigned int n;
|
||||
u8 *in, *out;
|
||||
void *param;
|
||||
struct pcc_param pcc_param;
|
||||
struct {
|
||||
u8 key[32];
|
||||
u8 init[16];
|
||||
} xts_param;
|
||||
|
||||
if (!nbytes)
|
||||
goto out;
|
||||
|
||||
memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block));
|
||||
memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit));
|
||||
memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts));
|
||||
memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak));
|
||||
param = xts_ctx->pcc.key + offset;
|
||||
ret = crypt_s390_pcc(func, param);
|
||||
memset(pcc_param.block, 0, sizeof(pcc_param.block));
|
||||
memset(pcc_param.bit, 0, sizeof(pcc_param.bit));
|
||||
memset(pcc_param.xts, 0, sizeof(pcc_param.xts));
|
||||
memcpy(pcc_param.tweak, walk->iv, sizeof(pcc_param.tweak));
|
||||
memcpy(pcc_param.key, xts_ctx->pcc_key, 32);
|
||||
ret = crypt_s390_pcc(func, &pcc_param.key[offset]);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16);
|
||||
param = xts_ctx->key + offset;
|
||||
memcpy(xts_param.key, xts_ctx->key, 32);
|
||||
memcpy(xts_param.init, pcc_param.xts, 16);
|
||||
do {
|
||||
/* only use complete blocks */
|
||||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
out = walk->dst.virt.addr;
|
||||
in = walk->src.virt.addr;
|
||||
|
||||
ret = crypt_s390_km(func, param, out, in, n);
|
||||
ret = crypt_s390_km(func, &xts_param.key[offset], out, in, n);
|
||||
if (ret < 0 || ret != n)
|
||||
return -EIO;
|
||||
|
||||
|
||||
@@ -78,11 +78,14 @@ static size_t copy_in_kernel(size_t count, void __user *to,
|
||||
* contains the (negative) exception code.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
|
||||
static unsigned long follow_table(struct mm_struct *mm,
|
||||
unsigned long address, int write)
|
||||
{
|
||||
unsigned long *table = (unsigned long *)__pa(mm->pgd);
|
||||
|
||||
if (unlikely(address > mm->context.asce_limit - 1))
|
||||
return -0x38UL;
|
||||
switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
|
||||
case _ASCE_TYPE_REGION1:
|
||||
table = table + ((address >> 53) & 0x7ff);
|
||||
|
||||
@@ -31,6 +31,9 @@ ifeq ($(CONFIG_X86_32),y)
|
||||
|
||||
KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return
|
||||
|
||||
# Don't autogenerate SSE instructions
|
||||
KBUILD_CFLAGS += -mno-sse
|
||||
|
||||
# Never want PIC in a 32-bit kernel, prevent breakage with GCC built
|
||||
# with nonstandard options
|
||||
KBUILD_CFLAGS += -fno-pic
|
||||
@@ -57,8 +60,11 @@ else
|
||||
KBUILD_AFLAGS += -m64
|
||||
KBUILD_CFLAGS += -m64
|
||||
|
||||
# Don't autogenerate SSE instructions
|
||||
KBUILD_CFLAGS += -mno-sse
|
||||
|
||||
# Use -mpreferred-stack-boundary=3 if supported.
|
||||
KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3)
|
||||
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
|
||||
|
||||
# FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
|
||||
cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
|
||||
|
||||
@@ -399,9 +399,9 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
|
||||
uint64_t v;
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin(&stat->syncp);
|
||||
start = u64_stats_fetch_begin_bh(&stat->syncp);
|
||||
v = stat->cnt;
|
||||
} while (u64_stats_fetch_retry(&stat->syncp, start));
|
||||
} while (u64_stats_fetch_retry_bh(&stat->syncp, start));
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -467,9 +467,9 @@ static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat)
|
||||
struct blkg_rwstat tmp;
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin(&rwstat->syncp);
|
||||
start = u64_stats_fetch_begin_bh(&rwstat->syncp);
|
||||
tmp = *rwstat;
|
||||
} while (u64_stats_fetch_retry(&rwstat->syncp, start));
|
||||
} while (u64_stats_fetch_retry_bh(&rwstat->syncp, start));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -645,10 +645,12 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
||||
__set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags);
|
||||
|
||||
if (blkcg_init_queue(q))
|
||||
goto fail_id;
|
||||
goto fail_bdi;
|
||||
|
||||
return q;
|
||||
|
||||
fail_bdi:
|
||||
bdi_destroy(&q->backing_dev_info);
|
||||
fail_id:
|
||||
ida_simple_remove(&blk_queue_ida, q->id);
|
||||
fail_q:
|
||||
@@ -739,9 +741,17 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
|
||||
|
||||
q->sg_reserved_size = INT_MAX;
|
||||
|
||||
/* Protect q->elevator from elevator_change */
|
||||
mutex_lock(&q->sysfs_lock);
|
||||
|
||||
/* init elevator */
|
||||
if (elevator_init(q, NULL))
|
||||
if (elevator_init(q, NULL)) {
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
|
||||
return q;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_init_allocated_queue);
|
||||
|
||||
@@ -186,6 +186,12 @@ int elevator_init(struct request_queue *q, char *name)
|
||||
struct elevator_type *e = NULL;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* q->sysfs_lock must be held to provide mutual exclusion between
|
||||
* elevator_switch() and here.
|
||||
*/
|
||||
lockdep_assert_held(&q->sysfs_lock);
|
||||
|
||||
if (unlikely(q->elevator))
|
||||
return 0;
|
||||
|
||||
@@ -959,7 +965,7 @@ fail_init:
|
||||
/*
|
||||
* Switch this queue to the given IO scheduler.
|
||||
*/
|
||||
int elevator_change(struct request_queue *q, const char *name)
|
||||
static int __elevator_change(struct request_queue *q, const char *name)
|
||||
{
|
||||
char elevator_name[ELV_NAME_MAX];
|
||||
struct elevator_type *e;
|
||||
@@ -981,6 +987,18 @@ int elevator_change(struct request_queue *q, const char *name)
|
||||
|
||||
return elevator_switch(q, e);
|
||||
}
|
||||
|
||||
int elevator_change(struct request_queue *q, const char *name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Protect q->elevator from elevator_init() */
|
||||
mutex_lock(&q->sysfs_lock);
|
||||
ret = __elevator_change(q, name);
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(elevator_change);
|
||||
|
||||
ssize_t elv_iosched_store(struct request_queue *q, const char *name,
|
||||
@@ -991,7 +1009,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
|
||||
if (!q->elevator)
|
||||
return count;
|
||||
|
||||
ret = elevator_change(q, name);
|
||||
ret = __elevator_change(q, name);
|
||||
if (!ret)
|
||||
return count;
|
||||
|
||||
|
||||
@@ -114,6 +114,12 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page,
|
||||
struct hash_ctx *ctx = ask->private;
|
||||
int err;
|
||||
|
||||
if (flags & MSG_SENDPAGE_NOTLAST)
|
||||
flags |= MSG_MORE;
|
||||
|
||||
if (flags & MSG_SENDPAGE_NOTLAST)
|
||||
flags |= MSG_MORE;
|
||||
|
||||
lock_sock(sk);
|
||||
sg_init_table(ctx->sgl.sg, 1);
|
||||
sg_set_page(ctx->sgl.sg, page, size, offset);
|
||||
@@ -161,8 +167,6 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
|
||||
else if (len < ds)
|
||||
msg->msg_flags |= MSG_TRUNC;
|
||||
|
||||
msg->msg_namelen = 0;
|
||||
|
||||
lock_sock(sk);
|
||||
if (ctx->more) {
|
||||
ctx->more = 0;
|
||||
|
||||
@@ -378,6 +378,12 @@ static ssize_t skcipher_sendpage(struct socket *sock, struct page *page,
|
||||
struct skcipher_sg_list *sgl;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (flags & MSG_SENDPAGE_NOTLAST)
|
||||
flags |= MSG_MORE;
|
||||
|
||||
if (flags & MSG_SENDPAGE_NOTLAST)
|
||||
flags |= MSG_MORE;
|
||||
|
||||
lock_sock(sk);
|
||||
if (!ctx->more && ctx->used)
|
||||
goto unlock;
|
||||
@@ -432,7 +438,6 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
|
||||
long copied = 0;
|
||||
|
||||
lock_sock(sk);
|
||||
msg->msg_namelen = 0;
|
||||
for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
|
||||
iovlen--, iov++) {
|
||||
unsigned long seglen = iov->iov_len;
|
||||
|
||||
@@ -106,7 +106,6 @@ error_no_sig:
|
||||
static int x509_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
struct tm now;
|
||||
size_t srlen, sulen;
|
||||
char *desc = NULL;
|
||||
int ret;
|
||||
@@ -137,43 +136,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
|
||||
pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
||||
now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
|
||||
now.tm_hour, now.tm_min, now.tm_sec);
|
||||
if (now.tm_year < cert->valid_from.tm_year ||
|
||||
(now.tm_year == cert->valid_from.tm_year &&
|
||||
(now.tm_mon < cert->valid_from.tm_mon ||
|
||||
(now.tm_mon == cert->valid_from.tm_mon &&
|
||||
(now.tm_mday < cert->valid_from.tm_mday ||
|
||||
(now.tm_mday == cert->valid_from.tm_mday &&
|
||||
(now.tm_hour < cert->valid_from.tm_hour ||
|
||||
(now.tm_hour == cert->valid_from.tm_hour &&
|
||||
(now.tm_min < cert->valid_from.tm_min ||
|
||||
(now.tm_min == cert->valid_from.tm_min &&
|
||||
(now.tm_sec < cert->valid_from.tm_sec
|
||||
))))))))))) {
|
||||
pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
|
||||
ret = -EKEYREJECTED;
|
||||
goto error_free_cert;
|
||||
}
|
||||
if (now.tm_year > cert->valid_to.tm_year ||
|
||||
(now.tm_year == cert->valid_to.tm_year &&
|
||||
(now.tm_mon > cert->valid_to.tm_mon ||
|
||||
(now.tm_mon == cert->valid_to.tm_mon &&
|
||||
(now.tm_mday > cert->valid_to.tm_mday ||
|
||||
(now.tm_mday == cert->valid_to.tm_mday &&
|
||||
(now.tm_hour > cert->valid_to.tm_hour ||
|
||||
(now.tm_hour == cert->valid_to.tm_hour &&
|
||||
(now.tm_min > cert->valid_to.tm_min ||
|
||||
(now.tm_min == cert->valid_to.tm_min &&
|
||||
(now.tm_sec > cert->valid_to.tm_sec
|
||||
))))))))))) {
|
||||
pr_warn("Cert %s has expired\n", cert->fingerprint);
|
||||
ret = -EKEYEXPIRED;
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
|
||||
cert->pub->id_type = PKEY_ID_X509;
|
||||
|
||||
|
||||
@@ -368,9 +368,10 @@ static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
|
||||
if (!err) {
|
||||
struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
|
||||
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
|
||||
struct ablkcipher_request *abreq = aead_request_ctx(areq);
|
||||
u8 *iv = (u8 *)(abreq + 1) +
|
||||
crypto_ablkcipher_reqsize(ctx->enc);
|
||||
struct authenc_request_ctx *areq_ctx = aead_request_ctx(areq);
|
||||
struct ablkcipher_request *abreq = (void *)(areq_ctx->tail
|
||||
+ ctx->reqoff);
|
||||
u8 *iv = (u8 *)abreq - crypto_ablkcipher_ivsize(ctx->enc);
|
||||
|
||||
err = crypto_authenc_genicv(areq, iv, 0);
|
||||
}
|
||||
|
||||
@@ -271,7 +271,8 @@ static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
|
||||
}
|
||||
|
||||
/* compute plaintext into mac */
|
||||
get_data_to_compute(cipher, pctx, plain, cryptlen);
|
||||
if (cryptlen)
|
||||
get_data_to_compute(cipher, pctx, plain, cryptlen);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
@@ -63,6 +63,9 @@ static struct acpi_scan_handler pci_root_handler = {
|
||||
.ids = root_device_ids,
|
||||
.attach = acpi_pci_root_add,
|
||||
.detach = acpi_pci_root_remove,
|
||||
.hotplug = {
|
||||
.ignore = true,
|
||||
},
|
||||
};
|
||||
|
||||
/* Lock to protect both acpi_pci_roots lists */
|
||||
|
||||
@@ -1790,7 +1790,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
|
||||
*/
|
||||
list_for_each_entry(hwid, &pnp.ids, list) {
|
||||
handler = acpi_scan_match_handler(hwid->id, NULL);
|
||||
if (handler) {
|
||||
if (handler && !handler->hotplug.ignore) {
|
||||
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
acpi_hotplug_notify_cb, handler);
|
||||
break;
|
||||
|
||||
@@ -292,6 +292,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
|
||||
|
||||
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
@@ -431,6 +435,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||||
.driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
|
||||
.driver_data = board_ahci_yes_fbs },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
|
||||
.driver_data = board_ahci_yes_fbs },
|
||||
|
||||
/* Promise */
|
||||
{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
|
||||
|
||||
@@ -1266,9 +1266,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||||
{
|
||||
struct ata_port *ap = link->ap;
|
||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
struct ahci_port_priv *pp = ap->private_data;
|
||||
const char *reason = NULL;
|
||||
unsigned long now, msecs;
|
||||
struct ata_taskfile tf;
|
||||
bool fbs_disabled = false;
|
||||
int rc;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
@@ -1278,6 +1280,16 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||||
if (rc && rc != -EOPNOTSUPP)
|
||||
ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
|
||||
|
||||
/*
|
||||
* According to AHCI-1.2 9.3.9: if FBS is enable, software shall
|
||||
* clear PxFBS.EN to '0' prior to issuing software reset to devices
|
||||
* that is attached to port multiplier.
|
||||
*/
|
||||
if (!ata_is_host_link(link) && pp->fbs_enabled) {
|
||||
ahci_disable_fbs(ap);
|
||||
fbs_disabled = true;
|
||||
}
|
||||
|
||||
ata_tf_init(link->device, &tf);
|
||||
|
||||
/* issue the first D2H Register FIS */
|
||||
@@ -1318,6 +1330,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
||||
} else
|
||||
*class = ahci_dev_classify(ap);
|
||||
|
||||
/* re-enable FBS if disabled before */
|
||||
if (fbs_disabled)
|
||||
ahci_enable_fbs(ap);
|
||||
|
||||
DPRINTK("EXIT, class=%u\n", *class);
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -4110,6 +4110,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
||||
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
|
||||
{ "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
|
||||
{ "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
|
||||
{ "Slimtype DVD A DS8A9SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
|
||||
|
||||
/* Devices we expect to fail diagnostics */
|
||||
|
||||
|
||||
@@ -3614,6 +3614,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
|
||||
shost->max_lun = 1;
|
||||
shost->max_channel = 1;
|
||||
shost->max_cmd_len = 16;
|
||||
shost->no_write_same = 1;
|
||||
|
||||
/* Schedule policy is determined by ->qc_defer()
|
||||
* callback and it needs to see every deferred qc.
|
||||
|
||||
@@ -319,25 +319,25 @@ int ata_tport_add(struct device *parent,
|
||||
/*
|
||||
* ATA link attributes
|
||||
*/
|
||||
static int noop(int x) { return x; }
|
||||
|
||||
|
||||
#define ata_link_show_linkspeed(field) \
|
||||
#define ata_link_show_linkspeed(field, format) \
|
||||
static ssize_t \
|
||||
show_ata_link_##field(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct ata_link *link = transport_class_to_link(dev); \
|
||||
\
|
||||
return sprintf(buf,"%s\n", sata_spd_string(fls(link->field))); \
|
||||
return sprintf(buf, "%s\n", sata_spd_string(format(link->field))); \
|
||||
}
|
||||
|
||||
#define ata_link_linkspeed_attr(field) \
|
||||
ata_link_show_linkspeed(field) \
|
||||
#define ata_link_linkspeed_attr(field, format) \
|
||||
ata_link_show_linkspeed(field, format) \
|
||||
static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
|
||||
|
||||
ata_link_linkspeed_attr(hw_sata_spd_limit);
|
||||
ata_link_linkspeed_attr(sata_spd_limit);
|
||||
ata_link_linkspeed_attr(sata_spd);
|
||||
ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd, noop);
|
||||
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
||||
|
||||
@@ -3511,7 +3511,7 @@ static int init_card(struct atm_dev *dev)
|
||||
tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */
|
||||
if (tmp) {
|
||||
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
|
||||
|
||||
dev_put(tmp);
|
||||
printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -499,7 +499,7 @@ static void __device_release_driver(struct device *dev)
|
||||
BUS_NOTIFY_UNBIND_DRIVER,
|
||||
dev);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
if (dev->bus && dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
|
||||
@@ -894,13 +894,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
|
||||
|
||||
bio_list_init(&lo->lo_bio_list);
|
||||
|
||||
/*
|
||||
* set queue make_request_fn, and add limits based on lower level
|
||||
* device
|
||||
*/
|
||||
blk_queue_make_request(lo->lo_queue, loop_make_request);
|
||||
lo->lo_queue->queuedata = lo;
|
||||
|
||||
if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
|
||||
blk_queue_flush(lo->lo_queue, REQ_FLUSH);
|
||||
|
||||
@@ -1618,6 +1611,8 @@ static int loop_add(struct loop_device **l, int i)
|
||||
if (!lo)
|
||||
goto out;
|
||||
|
||||
lo->lo_state = Lo_unbound;
|
||||
|
||||
/* allocate id, if @id >= 0, we're requesting that specific id */
|
||||
if (i >= 0) {
|
||||
err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
|
||||
@@ -1633,7 +1628,13 @@ static int loop_add(struct loop_device **l, int i)
|
||||
err = -ENOMEM;
|
||||
lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
|
||||
if (!lo->lo_queue)
|
||||
goto out_free_dev;
|
||||
goto out_free_idr;
|
||||
|
||||
/*
|
||||
* set queue make_request_fn
|
||||
*/
|
||||
blk_queue_make_request(lo->lo_queue, loop_make_request);
|
||||
lo->lo_queue->queuedata = lo;
|
||||
|
||||
disk = lo->lo_disk = alloc_disk(1 << part_shift);
|
||||
if (!disk)
|
||||
@@ -1678,6 +1679,8 @@ static int loop_add(struct loop_device **l, int i)
|
||||
|
||||
out_free_queue:
|
||||
blk_cleanup_queue(lo->lo_queue);
|
||||
out_free_idr:
|
||||
idr_remove(&loop_index_idr, i);
|
||||
out_free_dev:
|
||||
kfree(lo);
|
||||
out:
|
||||
|
||||
@@ -649,6 +649,8 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
|
||||
unsigned long secure;
|
||||
struct phys_req preq;
|
||||
|
||||
xen_blkif_get(blkif);
|
||||
|
||||
preq.sector_number = req->u.discard.sector_number;
|
||||
preq.nr_sects = req->u.discard.nr_sectors;
|
||||
|
||||
@@ -661,7 +663,6 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
|
||||
}
|
||||
blkif->st_ds_req++;
|
||||
|
||||
xen_blkif_get(blkif);
|
||||
secure = (blkif->vbd.discard_secure &&
|
||||
(req->u.discard.flag & BLKIF_DISCARD_SECURE)) ?
|
||||
BLKDEV_DISCARD_SECURE : 0;
|
||||
|
||||
@@ -664,6 +664,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell XPS421",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user