mirror of
https://github.com/torvalds/linux.git
synced 2026-06-09 07:03:37 +02:00
Merge remote-tracking branch 'origin/upstream/linux-linaro-lsk-v3.10-android' into develop-3.10
This commit is contained in:
commit
48a48cd79b
2
Makefile
2
Makefile
|
|
@ -1,6 +1,6 @@
|
|||
VERSION = 3
|
||||
PATCHLEVEL = 10
|
||||
SUBLEVEL = 23
|
||||
SUBLEVEL = 24
|
||||
EXTRAVERSION =
|
||||
NAME = TOSSUG Baby Fish
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ mpic: interrupt-controller@20000 {
|
|||
|
||||
coherency-fabric@20200 {
|
||||
compatible = "marvell,coherency-fabric";
|
||||
reg = <0x20200 0xb0>, <0x21810 0x1c>;
|
||||
reg = <0x20200 0xb0>, <0x21010 0x1c>;
|
||||
};
|
||||
|
||||
serial@12000 {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ gpio1: gpio@18140 {
|
|||
/*
|
||||
* 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 @@ pcie-controller {
|
|||
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 @@ pcie@4,0 {
|
|||
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 @@ ethernet@34000 {
|
|||
/*
|
||||
* 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 @@ pcie-controller {
|
|||
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 @@ pcie@4,0 {
|
|||
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 @@ pcie@9,0 {
|
|||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -183,6 +183,12 @@ clcd@1f0000 {
|
|||
clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
|
||||
clock-names = "clcdclk", "apb_pclk";
|
||||
};
|
||||
|
||||
virtio_block@0130000 {
|
||||
compatible = "virtio,mmio";
|
||||
reg = <0x130000 0x200>;
|
||||
interrupts = <42>;
|
||||
};
|
||||
};
|
||||
|
||||
v2m_fixed_3v3: fixedregulator@0 {
|
||||
|
|
|
|||
|
|
@ -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 @@ int __init psci_init(void)
|
|||
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 @@ void __init smp_init_cpus(void)
|
|||
|
||||
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 = .;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -378,6 +378,9 @@ 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ source "drivers/cpufreq/Kconfig.x86"
|
|||
endmenu
|
||||
|
||||
menu "ARM CPU frequency scaling drivers"
|
||||
depends on ARM
|
||||
depends on ARM || ARM64
|
||||
source "drivers/cpufreq/Kconfig.arm"
|
||||
endmenu
|
||||
|
||||
|
|
|
|||
|
|
@ -1626,6 +1626,7 @@ static struct scsi_host_template scsi_driver_template = {
|
|||
.cmd_per_lun = 1,
|
||||
.can_queue = 1,
|
||||
.sdev_attrs = sbp2_scsi_sysfs_attrs,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
||||
|
|
|
|||
|
|
@ -69,10 +69,14 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
|||
u32 val;
|
||||
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
|
||||
u32 out_mask, out_shadow;
|
||||
|
||||
val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
|
||||
out_mask = in_be32(mm->regs + GPIO_DIR);
|
||||
|
||||
return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
|
||||
val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
|
||||
out_shadow = mpc8xxx_gc->data & out_mask;
|
||||
|
||||
return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
|
||||
}
|
||||
|
||||
static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
|
|
|
|||
|
|
@ -786,6 +786,8 @@
|
|||
#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009
|
||||
#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
|
||||
#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
|
||||
#define USB_DEVICE_ID_SYNAPTICS_LTS1 0x0af8
|
||||
#define USB_DEVICE_ID_SYNAPTICS_LTS2 0x1d10
|
||||
|
||||
#define USB_VENDOR_ID_THINGM 0x27b8
|
||||
#define USB_DEVICE_ID_BLINK1 0x01ed
|
||||
|
|
@ -913,4 +915,7 @@
|
|||
#define USB_VENDOR_ID_PRIMAX 0x0461
|
||||
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
||||
|
||||
#define USB_VENDOR_ID_SIS 0x0457
|
||||
#define USB_DEVICE_ID_SIS_TS 0x1013
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SIS, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ config INPUT_MATRIXKMAP
|
|||
comment "Userland interfaces"
|
||||
|
||||
config INPUT_MOUSEDEV
|
||||
tristate "Mouse interface" if EXPERT
|
||||
tristate "Mouse interface"
|
||||
default y
|
||||
help
|
||||
Say Y here if you want your mouse to be accessible as char devices
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Input core configuration
|
||||
#
|
||||
menuconfig INPUT_KEYBOARD
|
||||
bool "Keyboards" if EXPERT || !X86
|
||||
bool "Keyboards"
|
||||
default y
|
||||
help
|
||||
Say Y here, and a list of supported keyboards will be displayed.
|
||||
|
|
@ -67,7 +67,7 @@ config KEYBOARD_ATARI
|
|||
module will be called atakbd.
|
||||
|
||||
config KEYBOARD_ATKBD
|
||||
tristate "AT keyboard" if EXPERT || !X86
|
||||
tristate "AT keyboard"
|
||||
default y
|
||||
select SERIO
|
||||
select SERIO_LIBPS2
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Input core configuration
|
||||
#
|
||||
config SERIO
|
||||
tristate "Serial I/O support" if EXPERT || !X86
|
||||
tristate "Serial I/O support"
|
||||
default y
|
||||
help
|
||||
Say Yes here if you have any input device that uses serial I/O to
|
||||
|
|
@ -19,7 +19,7 @@ config SERIO
|
|||
if SERIO
|
||||
|
||||
config SERIO_I8042
|
||||
tristate "i8042 PC Keyboard controller" if EXPERT || !X86
|
||||
tristate "i8042 PC Keyboard controller"
|
||||
default y
|
||||
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
|
||||
(!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390
|
||||
|
|
@ -169,7 +169,7 @@ config SERIO_MACEPS2
|
|||
module will be called maceps2.
|
||||
|
||||
config SERIO_LIBPS2
|
||||
tristate "PS/2 driver library" if EXPERT
|
||||
tristate "PS/2 driver library"
|
||||
depends on SERIO_I8042 || SERIO_I8042=n
|
||||
help
|
||||
Say Y here if you are using a driver for device connected
|
||||
|
|
|
|||
|
|
@ -198,6 +198,13 @@ static void enclosure_remove_links(struct enclosure_component *cdev)
|
|||
{
|
||||
char name[ENCLOSURE_NAME_SIZE];
|
||||
|
||||
/*
|
||||
* In odd circumstances, like multipath devices, something else may
|
||||
* already have removed the links, so check for this condition first.
|
||||
*/
|
||||
if (!cdev->dev->kobj.sd)
|
||||
return;
|
||||
|
||||
enclosure_link_name(cdev, name);
|
||||
sysfs_remove_link(&cdev->dev->kobj, name);
|
||||
sysfs_remove_link(&cdev->cdev.kobj, "device");
|
||||
|
|
|
|||
|
|
@ -109,8 +109,12 @@
|
|||
#define MEI_DEV_ID_PPT_2 0x1CBA /* Panther Point */
|
||||
#define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */
|
||||
|
||||
#define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */
|
||||
#define MEI_DEV_ID_LPT_H 0x8C3A /* Lynx Point H */
|
||||
#define MEI_DEV_ID_LPT_W 0x8D3A /* Lynx Point - Wellsburg */
|
||||
#define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */
|
||||
#define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */
|
||||
|
||||
#define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */
|
||||
/*
|
||||
* MEI HW Section
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -79,8 +79,11 @@ static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
|
|||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_H)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_W)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_HR)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_WPT_LP)},
|
||||
|
||||
/* required last entry */
|
||||
{0, }
|
||||
|
|
|
|||
|
|
@ -712,22 +712,31 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int c_can_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
static int __c_can_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
unsigned int reg_err_counter;
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
|
||||
c_can_pm_runtime_get_sync(priv);
|
||||
|
||||
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
|
||||
bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
|
||||
ERR_CNT_REC_SHIFT;
|
||||
bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c_can_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
c_can_pm_runtime_get_sync(priv);
|
||||
err = __c_can_get_berr_counter(dev, bec);
|
||||
c_can_pm_runtime_put_sync(priv);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -872,7 +881,7 @@ static int c_can_handle_state_change(struct net_device *dev,
|
|||
if (unlikely(!skb))
|
||||
return 0;
|
||||
|
||||
c_can_get_berr_counter(dev, &bec);
|
||||
__c_can_get_berr_counter(dev, &bec);
|
||||
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
|
||||
rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
|
||||
ERR_CNT_RP_SHIFT;
|
||||
|
|
|
|||
|
|
@ -494,20 +494,20 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
|||
uint8_t isrc, status;
|
||||
int n = 0;
|
||||
|
||||
/* Shared interrupts and IRQ off? */
|
||||
if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (priv->pre_irq)
|
||||
priv->pre_irq(priv);
|
||||
|
||||
/* Shared interrupts and IRQ off? */
|
||||
if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
|
||||
goto out;
|
||||
|
||||
while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
|
||||
(n < SJA1000_MAX_IRQ)) {
|
||||
n++;
|
||||
|
||||
status = priv->read_reg(priv, SJA1000_SR);
|
||||
/* check for absent controller due to hw unplug */
|
||||
if (status == 0xFF && sja1000_is_absent(priv))
|
||||
return IRQ_NONE;
|
||||
goto out;
|
||||
|
||||
if (isrc & IRQ_WUI)
|
||||
netdev_warn(dev, "wakeup interrupt\n");
|
||||
|
|
@ -535,7 +535,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
|||
status = priv->read_reg(priv, SJA1000_SR);
|
||||
/* check for absent controller */
|
||||
if (status == 0xFF && sja1000_is_absent(priv))
|
||||
return IRQ_NONE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
|
||||
|
|
@ -543,8 +543,9 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
|||
if (sja1000_err(dev, isrc, status))
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (priv->post_irq)
|
||||
priv->post_irq(priv);
|
||||
|
||||
|
|
|
|||
|
|
@ -6722,12 +6722,6 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
|||
pci_unmap_single(tp->pdev, dma_addr, skb_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
|
||||
skb = build_skb(data, frag_size);
|
||||
if (!skb) {
|
||||
tg3_frag_free(frag_size != 0, data);
|
||||
goto drop_it_no_recycle;
|
||||
}
|
||||
skb_reserve(skb, TG3_RX_OFFSET(tp));
|
||||
/* Ensure that the update to the data happens
|
||||
* after the usage of the old DMA mapping.
|
||||
*/
|
||||
|
|
@ -6735,6 +6729,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
|||
|
||||
ri->data = NULL;
|
||||
|
||||
skb = build_skb(data, frag_size);
|
||||
if (!skb) {
|
||||
tg3_frag_free(frag_size != 0, data);
|
||||
goto drop_it_no_recycle;
|
||||
}
|
||||
skb_reserve(skb, TG3_RX_OFFSET(tp));
|
||||
} else {
|
||||
tg3_recycle_rx(tnapi, tpr, opaque_key,
|
||||
desc_idx, *post_ptr);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@
|
|||
defined(CONFIG_MACH_LITTLETON) ||\
|
||||
defined(CONFIG_MACH_ZYLONITE2) ||\
|
||||
defined(CONFIG_ARCH_VIPER) ||\
|
||||
defined(CONFIG_MACH_STARGATE2)
|
||||
defined(CONFIG_MACH_STARGATE2) ||\
|
||||
defined(CONFIG_ARCH_VERSATILE)
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
|
@ -154,6 +155,8 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
|
|||
#define SMC_outl(v, a, r) writel(v, (a) + (r))
|
||||
#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
|
||||
#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
|
||||
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
|
||||
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
|
||||
#define SMC_IRQ_FLAGS (-1) /* from resource */
|
||||
|
||||
/* We actually can't write halfwords properly if not word aligned */
|
||||
|
|
@ -206,23 +209,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
|
|||
#define RPC_LSA_DEFAULT RPC_LED_TX_RX
|
||||
#define RPC_LSB_DEFAULT RPC_LED_100_10
|
||||
|
||||
#elif defined(CONFIG_ARCH_VERSATILE)
|
||||
|
||||
#define SMC_CAN_USE_8BIT 1
|
||||
#define SMC_CAN_USE_16BIT 1
|
||||
#define SMC_CAN_USE_32BIT 1
|
||||
#define SMC_NOWAIT 1
|
||||
|
||||
#define SMC_inb(a, r) readb((a) + (r))
|
||||
#define SMC_inw(a, r) readw((a) + (r))
|
||||
#define SMC_inl(a, r) readl((a) + (r))
|
||||
#define SMC_outb(v, a, r) writeb(v, (a) + (r))
|
||||
#define SMC_outw(v, a, r) writew(v, (a) + (r))
|
||||
#define SMC_outl(v, a, r) writel(v, (a) + (r))
|
||||
#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
|
||||
#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
|
||||
#define SMC_IRQ_FLAGS (-1) /* from resource */
|
||||
|
||||
#elif defined(CONFIG_MN10300)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -445,27 +445,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
|
|||
/* Copy MAC header from skb into command buffer */
|
||||
memcpy(tx_cmd->hdr, hdr, hdr_len);
|
||||
|
||||
txq_id = info->hw_queue;
|
||||
|
||||
if (is_agg)
|
||||
txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
|
||||
else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
|
||||
/*
|
||||
* Send this frame after DTIM -- there's a special queue
|
||||
* reserved for this for contexts that support AP mode.
|
||||
*/
|
||||
txq_id = ctx->mcast_queue;
|
||||
|
||||
/*
|
||||
* The microcode will clear the more data
|
||||
* bit in the last frame it transmits.
|
||||
*/
|
||||
hdr->frame_control |=
|
||||
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||||
} else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
txq_id = IWL_AUX_QUEUE;
|
||||
else
|
||||
txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
|
||||
WARN_ON_ONCE(is_agg &&
|
||||
priv->queue_to_mac80211[txq_id] != info->hw_queue);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
|
@ -230,6 +231,100 @@ const void *of_get_property(const struct device_node *np, const char *name,
|
|||
}
|
||||
EXPORT_SYMBOL(of_get_property);
|
||||
|
||||
/*
|
||||
* arch_match_cpu_phys_id - Match the given logical CPU and physical id
|
||||
*
|
||||
* @cpu: logical cpu index of a core/thread
|
||||
* @phys_id: physical identifier of a core/thread
|
||||
*
|
||||
* CPU logical to physical index mapping is architecture specific.
|
||||
* However this __weak function provides a default match of physical
|
||||
* id to logical cpu index. phys_id provided here is usually values read
|
||||
* from the device tree which must match the hardware internal registers.
|
||||
*
|
||||
* Returns true if the physical identifier and the logical cpu index
|
||||
* correspond to the same core/thread, false otherwise.
|
||||
*/
|
||||
bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id)
|
||||
{
|
||||
return (u32)phys_id == cpu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given "prop_name" property holds the physical id of the
|
||||
* core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not
|
||||
* NULL, local thread number within the core is returned in it.
|
||||
*/
|
||||
static bool __of_find_n_match_cpu_property(struct device_node *cpun,
|
||||
const char *prop_name, int cpu, unsigned int *thread)
|
||||
{
|
||||
const __be32 *cell;
|
||||
int ac, prop_len, tid;
|
||||
u64 hwid;
|
||||
|
||||
ac = of_n_addr_cells(cpun);
|
||||
cell = of_get_property(cpun, prop_name, &prop_len);
|
||||
if (!cell)
|
||||
return false;
|
||||
prop_len /= sizeof(*cell);
|
||||
for (tid = 0; tid < prop_len; tid++) {
|
||||
hwid = of_read_number(cell, ac);
|
||||
if (arch_match_cpu_phys_id(cpu, hwid)) {
|
||||
if (thread)
|
||||
*thread = tid;
|
||||
return true;
|
||||
}
|
||||
cell += ac;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_cpu_node - Get device node associated with the given logical CPU
|
||||
*
|
||||
* @cpu: CPU number(logical index) for which device node is required
|
||||
* @thread: if not NULL, local thread number within the physical core is
|
||||
* returned
|
||||
*
|
||||
* The main purpose of this function is to retrieve the device node for the
|
||||
* given logical CPU index. It should be used to initialize the of_node in
|
||||
* cpu device. Once of_node in cpu device is populated, all the further
|
||||
* references can use that instead.
|
||||
*
|
||||
* CPU logical to physical index mapping is architecture specific and is built
|
||||
* before booting secondary cores. This function uses arch_match_cpu_phys_id
|
||||
* which can be overridden by architecture specific implementation.
|
||||
*
|
||||
* Returns a node pointer for the logical cpu if found, else NULL.
|
||||
*/
|
||||
struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
|
||||
{
|
||||
struct device_node *cpun, *cpus;
|
||||
|
||||
cpus = of_find_node_by_path("/cpus");
|
||||
if (!cpus) {
|
||||
pr_warn("Missing cpus node, bailing out\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(cpus, cpun) {
|
||||
if (of_node_cmp(cpun->type, "cpu"))
|
||||
continue;
|
||||
/* Check for non-standard "ibm,ppc-interrupt-server#s" property
|
||||
* for thread ids on PowerPC. If it doesn't exist fallback to
|
||||
* standard "reg" property.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_PPC) &&
|
||||
__of_find_n_match_cpu_property(cpun,
|
||||
"ibm,ppc-interrupt-server#s", cpu, thread))
|
||||
return cpun;
|
||||
if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
|
||||
return cpun;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_cpu_node);
|
||||
|
||||
/** Checks if the given "compat" string matches one of the strings in
|
||||
* the device's "compatible" property
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2025,7 +2025,8 @@ static struct scsi_host_template driver_template = {
|
|||
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = twa_host_attrs,
|
||||
.emulated = 1
|
||||
.emulated = 1,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/* This function will probe and initialize a card */
|
||||
|
|
|
|||
|
|
@ -1600,7 +1600,8 @@ static struct scsi_host_template driver_template = {
|
|||
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = twl_host_attrs,
|
||||
.emulated = 1
|
||||
.emulated = 1,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/* This function will probe and initialize a card */
|
||||
|
|
|
|||
|
|
@ -2277,7 +2277,8 @@ static struct scsi_host_template driver_template = {
|
|||
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = tw_host_attrs,
|
||||
.emulated = 1
|
||||
.emulated = 1,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/* This function will probe and initialize a card */
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,7 @@ static struct scsi_host_template aac_driver_template = {
|
|||
#endif
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.emulated = 1,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
static void __aac_shutdown(struct aac_dev * aac)
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
|
|||
.cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = arcmsr_host_attrs,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
static struct pci_device_id arcmsr_device_id_table[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ wwn_t bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn,
|
|||
struct bfa_fcs_lport_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs,
|
||||
u16 vf_id, wwn_t lpwwn);
|
||||
|
||||
void bfa_fcs_lport_set_symname(struct bfa_fcs_lport_s *port, char *symname);
|
||||
void bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port,
|
||||
struct bfa_lport_info_s *port_info);
|
||||
void bfa_fcs_lport_get_attr(struct bfa_fcs_lport_s *port,
|
||||
|
|
|
|||
|
|
@ -1097,6 +1097,17 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
|
|||
bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
|
||||
}
|
||||
|
||||
void
|
||||
bfa_fcs_lport_set_symname(struct bfa_fcs_lport_s *port,
|
||||
char *symname)
|
||||
{
|
||||
strcpy(port->port_cfg.sym_name.symname, symname);
|
||||
|
||||
if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
|
||||
bfa_fcs_lport_ns_util_send_rspn_id(
|
||||
BFA_FCS_GET_NS_FROM_PORT(port), NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* fcs_lport_api
|
||||
*/
|
||||
|
|
@ -4950,9 +4961,6 @@ bfa_fcs_lport_ns_util_send_rspn_id(void *cbarg, struct bfa_fcxp_s *fcxp_alloced)
|
|||
u8 *psymbl = &symbl[0];
|
||||
int len;
|
||||
|
||||
if (!bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
|
||||
return;
|
||||
|
||||
/* Avoid sending RSPN in the following states. */
|
||||
if (bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_offline) ||
|
||||
bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_plogi_sending) ||
|
||||
|
|
|
|||
|
|
@ -610,11 +610,8 @@ bfad_im_vport_set_symbolic_name(struct fc_vport *fc_vport)
|
|||
return;
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
if (strlen(sym_name) > 0) {
|
||||
strcpy(fcs_vport->lport.port_cfg.sym_name.symname, sym_name);
|
||||
bfa_fcs_lport_ns_util_send_rspn_id(
|
||||
BFA_FCS_GET_NS_FROM_PORT((&fcs_vport->lport)), NULL);
|
||||
}
|
||||
if (strlen(sym_name) > 0)
|
||||
bfa_fcs_lport_set_symname(&fcs_vport->lport, sym_name);
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4686,6 +4686,7 @@ static struct scsi_host_template gdth_template = {
|
|||
.cmd_per_lun = GDTH_MAXC_P_L,
|
||||
.unchecked_isa_dma = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ISA
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
|
|||
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
|
||||
shost->use_clustering = sht->use_clustering;
|
||||
shost->ordered_tag = sht->ordered_tag;
|
||||
shost->no_write_same = sht->no_write_same;
|
||||
|
||||
if (sht->supported_mode == MODE_UNKNOWN)
|
||||
/* means we didn't set it ... default to INITIATOR */
|
||||
|
|
|
|||
|
|
@ -538,6 +538,7 @@ static struct scsi_host_template hpsa_driver_template = {
|
|||
.sdev_attrs = hpsa_sdev_attrs,
|
||||
.shost_attrs = hpsa_shost_attrs,
|
||||
.max_sectors = 8192,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1265,7 +1266,7 @@ static void complete_scsi_command(struct CommandList *cp)
|
|||
"has check condition: aborted command: "
|
||||
"ASC: 0x%x, ASCQ: 0x%x\n",
|
||||
cp, asc, ascq);
|
||||
cmd->result = DID_SOFT_ERROR << 16;
|
||||
cmd->result |= DID_SOFT_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
/* Must be some other type of check condition */
|
||||
|
|
@ -4904,7 +4905,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
hpsa_hba_inquiry(h);
|
||||
hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
|
||||
start_controller_lockup_detector(h);
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
clean4:
|
||||
hpsa_free_sg_chain_blocks(h);
|
||||
|
|
|
|||
|
|
@ -6267,7 +6267,8 @@ static struct scsi_host_template driver_template = {
|
|||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = ipr_ioa_attrs,
|
||||
.sdev_attrs = ipr_dev_attrs,
|
||||
.proc_name = IPR_NAME
|
||||
.proc_name = IPR_NAME,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ static struct scsi_host_template ips_driver_template = {
|
|||
.sg_tablesize = IPS_MAX_SG,
|
||||
.cmd_per_lun = 3,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
|
|||
qc->tf.nsect = 0;
|
||||
}
|
||||
|
||||
ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
|
||||
ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *)&task->ata_task.fis);
|
||||
task->uldd_task = qc;
|
||||
if (ata_is_atapi(qc->tf.protocol)) {
|
||||
memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
|
||||
|
|
|
|||
|
|
@ -4244,6 +4244,7 @@ static struct scsi_host_template megaraid_template = {
|
|||
.eh_device_reset_handler = megaraid_reset,
|
||||
.eh_bus_reset_handler = megaraid_reset,
|
||||
.eh_host_reset_handler = megaraid_reset,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@ static struct scsi_host_template megaraid_template_g = {
|
|||
.eh_host_reset_handler = megaraid_reset_handler,
|
||||
.change_queue_depth = megaraid_change_queue_depth,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.no_write_same = 1,
|
||||
.sdev_attrs = megaraid_sdev_attrs,
|
||||
.shost_attrs = megaraid_shost_attrs,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2099,6 +2099,7 @@ static struct scsi_host_template megasas_template = {
|
|||
.bios_param = megasas_bios_param,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.change_queue_depth = megasas_change_queue_depth,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4314,6 +4314,7 @@ static struct scsi_host_template pmcraid_host_template = {
|
|||
.this_id = -1,
|
||||
.sg_tablesize = PMCRAID_MAX_IOADLS,
|
||||
.max_sectors = PMCRAID_IOA_MAX_SECTORS,
|
||||
.no_write_same = 1,
|
||||
.cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = pmcraid_host_attrs,
|
||||
|
|
|
|||
|
|
@ -2627,6 +2627,12 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
|
|||
{
|
||||
struct scsi_device *sdev = sdkp->device;
|
||||
|
||||
if (sdev->host->no_write_same) {
|
||||
sdev->no_write_same = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
|
||||
sdev->no_report_opcodes = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1454,6 +1454,7 @@ static struct scsi_host_template scsi_driver = {
|
|||
.use_clustering = DISABLE_CLUSTERING,
|
||||
/* Make sure we dont get a sg segment crosses a page boundary */
|
||||
.dma_boundary = PAGE_SIZE-1,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -1529,6 +1529,8 @@ static int acm_reset_resume(struct usb_interface *intf)
|
|||
|
||||
static const struct usb_device_id acm_ids[] = {
|
||||
/* quirky and broken devices */
|
||||
{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
|
||||
.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
|
||||
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
|
||||
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2131,6 +2131,20 @@ static void ftdi_set_termios(struct tty_struct *tty,
|
|||
termios->c_cflag |= CRTSCTS;
|
||||
}
|
||||
|
||||
/*
|
||||
* All FTDI UART chips are limited to CS7/8. We won't pretend to
|
||||
* support CS5/6 and revert the CSIZE setting instead.
|
||||
*/
|
||||
if ((C_CSIZE(tty) != CS8) && (C_CSIZE(tty) != CS7)) {
|
||||
dev_warn(ddev, "requested CSIZE setting not supported\n");
|
||||
|
||||
termios->c_cflag &= ~CSIZE;
|
||||
if (old_termios)
|
||||
termios->c_cflag |= old_termios->c_cflag & CSIZE;
|
||||
else
|
||||
termios->c_cflag |= CS8;
|
||||
}
|
||||
|
||||
cflag = termios->c_cflag;
|
||||
|
||||
if (!old_termios)
|
||||
|
|
@ -2167,19 +2181,16 @@ static void ftdi_set_termios(struct tty_struct *tty,
|
|||
} else {
|
||||
urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;
|
||||
}
|
||||
if (cflag & CSIZE) {
|
||||
switch (cflag & CSIZE) {
|
||||
case CS7:
|
||||
urb_value |= 7;
|
||||
dev_dbg(ddev, "Setting CS7\n");
|
||||
break;
|
||||
case CS8:
|
||||
urb_value |= 8;
|
||||
dev_dbg(ddev, "Setting CS8\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(ddev, "CSIZE was set but not CS7-CS8\n");
|
||||
}
|
||||
switch (cflag & CSIZE) {
|
||||
case CS7:
|
||||
urb_value |= 7;
|
||||
dev_dbg(ddev, "Setting CS7\n");
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
urb_value |= 8;
|
||||
dev_dbg(ddev, "Setting CS8\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* This is needed by the break command since it uses the same command
|
||||
|
|
|
|||
|
|
@ -1875,25 +1875,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
|
|||
iflag = tty->termios.c_iflag;
|
||||
|
||||
/* Change the number of bits */
|
||||
if (cflag & CSIZE) {
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
lData = LCR_BITS_5;
|
||||
break;
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
lData = LCR_BITS_5;
|
||||
break;
|
||||
|
||||
case CS6:
|
||||
lData = LCR_BITS_6;
|
||||
break;
|
||||
case CS6:
|
||||
lData = LCR_BITS_6;
|
||||
break;
|
||||
|
||||
case CS7:
|
||||
lData = LCR_BITS_7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
lData = LCR_BITS_8;
|
||||
break;
|
||||
}
|
||||
case CS7:
|
||||
lData = LCR_BITS_7;
|
||||
break;
|
||||
|
||||
default:
|
||||
case CS8:
|
||||
lData = LCR_BITS_8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Change the Parity bit */
|
||||
if (cflag & PARENB) {
|
||||
if (cflag & PARODD) {
|
||||
|
|
|
|||
|
|
@ -304,24 +304,22 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
|||
dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
|
||||
|
||||
if (cflag & CSIZE) {
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
buf[6] = 5;
|
||||
break;
|
||||
case CS6:
|
||||
buf[6] = 6;
|
||||
break;
|
||||
case CS7:
|
||||
buf[6] = 7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
buf[6] = 8;
|
||||
break;
|
||||
}
|
||||
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
buf[6] = 5;
|
||||
break;
|
||||
case CS6:
|
||||
buf[6] = 6;
|
||||
break;
|
||||
case CS7:
|
||||
buf[6] = 7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
buf[6] = 8;
|
||||
break;
|
||||
}
|
||||
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
|
||||
|
||||
/* For reference buf[0]:buf[3] baud rate value */
|
||||
/* NOTE: Only the values defined in baud_sup are supported !
|
||||
|
|
|
|||
|
|
@ -346,22 +346,20 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
|||
}
|
||||
|
||||
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
|
||||
if (cflag & CSIZE) {
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_5;
|
||||
break;
|
||||
case CS6:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_6;
|
||||
break;
|
||||
case CS7:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_8;
|
||||
break;
|
||||
}
|
||||
switch (cflag & CSIZE) {
|
||||
case CS5:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_5;
|
||||
break;
|
||||
case CS6:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_6;
|
||||
break;
|
||||
case CS7:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
buf[1] |= SET_UART_FORMAT_SIZE_8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set Stop bit2 : 0:1bit 1:2bit */
|
||||
|
|
|
|||
|
|
@ -317,7 +317,8 @@ config FB_PM2_FIFO_DISCONNECT
|
|||
|
||||
config FB_ARMCLCD
|
||||
tristate "ARM PrimeCell PL110 support"
|
||||
depends on FB && ARM && ARM_AMBA
|
||||
depends on ARM || ARM64 || COMPILE_TEST
|
||||
depends on FB && ARM_AMBA
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
|
|
|
|||
|
|
@ -920,9 +920,10 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
|
|||
ret = m2p_add_override(mfn, pages[i], kmap_ops ?
|
||||
&kmap_ops[i] : NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (lazy)
|
||||
arch_leave_lazy_mmu_mode();
|
||||
|
||||
|
|
@ -953,9 +954,10 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
|
|||
ret = m2p_remove_override(pages[i], kmap_ops ?
|
||||
&kmap_ops[i] : NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (lazy)
|
||||
arch_leave_lazy_mmu_mode();
|
||||
|
||||
|
|
|
|||
|
|
@ -4401,11 +4401,17 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
|||
return;
|
||||
|
||||
switch (task->tk_status) {
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
case 0:
|
||||
renew_lease(data->res.server, data->timestamp);
|
||||
break;
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
task->tk_status = 0;
|
||||
break;
|
||||
default:
|
||||
if (nfs4_async_handle_error(task, data->res.server, NULL) ==
|
||||
-EAGAIN) {
|
||||
|
|
|
|||
39
fs/pipe.c
39
fs/pipe.c
|
|
@ -726,11 +726,25 @@ pipe_poll(struct file *filp, poll_table *wait)
|
|||
return mask;
|
||||
}
|
||||
|
||||
static void put_pipe_info(struct inode *inode, struct pipe_inode_info *pipe)
|
||||
{
|
||||
int kill = 0;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!--pipe->files) {
|
||||
inode->i_pipe = NULL;
|
||||
kill = 1;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
if (kill)
|
||||
free_pipe_info(pipe);
|
||||
}
|
||||
|
||||
static int
|
||||
pipe_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pipe_inode_info *pipe = inode->i_pipe;
|
||||
int kill = 0;
|
||||
struct pipe_inode_info *pipe = file->private_data;
|
||||
|
||||
__pipe_lock(pipe);
|
||||
if (file->f_mode & FMODE_READ)
|
||||
|
|
@ -743,17 +757,9 @@ pipe_release(struct inode *inode, struct file *file)
|
|||
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
|
||||
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
|
||||
}
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!--pipe->files) {
|
||||
inode->i_pipe = NULL;
|
||||
kill = 1;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
__pipe_unlock(pipe);
|
||||
|
||||
if (kill)
|
||||
free_pipe_info(pipe);
|
||||
|
||||
put_pipe_info(inode, pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1014,7 +1020,6 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
{
|
||||
struct pipe_inode_info *pipe;
|
||||
bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC;
|
||||
int kill = 0;
|
||||
int ret;
|
||||
|
||||
filp->f_version = 0;
|
||||
|
|
@ -1130,15 +1135,9 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
goto err;
|
||||
|
||||
err:
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!--pipe->files) {
|
||||
inode->i_pipe = NULL;
|
||||
kill = 1;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
__pipe_unlock(pipe);
|
||||
if (kill)
|
||||
free_pipe_info(pipe);
|
||||
|
||||
put_pipe_info(inode, pipe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
|
|||
{
|
||||
sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
|
||||
sg1[num - 1].page_link &= ~0x02;
|
||||
sg1[num - 1].page_link |= 0x01;
|
||||
}
|
||||
|
||||
static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
|
||||
|
|
@ -43,7 +44,7 @@ static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
|
|||
if (sg_is_last(sg))
|
||||
return NULL;
|
||||
|
||||
return (++sg)->length ? sg : (void *)sg_page(sg);
|
||||
return (++sg)->length ? sg : sg_chain_ptr(sg);
|
||||
}
|
||||
|
||||
static inline void scatterwalk_crypto_chain(struct scatterlist *head,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ struct cpu {
|
|||
extern int register_cpu(struct cpu *cpu, int num);
|
||||
extern struct device *get_cpu_device(unsigned cpu);
|
||||
extern bool cpu_is_hotpluggable(unsigned cpu);
|
||||
extern bool arch_match_cpu_phys_id(int cpu, u64 phys_id);
|
||||
|
||||
extern int cpu_add_dev_attr(struct device_attribute *attr);
|
||||
extern void cpu_remove_dev_attr(struct device_attribute *attr);
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ struct gen_pool_chunk {
|
|||
struct list_head next_chunk; /* next chunk in pool */
|
||||
atomic_t avail;
|
||||
phys_addr_t phys_addr; /* physical starting address of memory chunk */
|
||||
unsigned long start_addr; /* starting address of memory chunk */
|
||||
unsigned long end_addr; /* ending address of memory chunk */
|
||||
unsigned long start_addr; /* start address of memory chunk */
|
||||
unsigned long end_addr; /* end address of memory chunk (inclusive) */
|
||||
unsigned long bits[0]; /* bitmap for allocating memory chunk */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ extern int of_device_is_available(const struct device_node *device);
|
|||
extern const void *of_get_property(const struct device_node *node,
|
||||
const char *name,
|
||||
int *lenp);
|
||||
extern struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
|
||||
#define for_each_property_of_node(dn, pp) \
|
||||
for (pp = dn->properties; pp != NULL; pp = pp->next)
|
||||
|
||||
|
|
@ -459,6 +460,12 @@ static inline const void *of_get_property(const struct device_node *node,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *of_get_cpu_node(int cpu,
|
||||
unsigned int *thread)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int of_property_read_u64(const struct device_node *np,
|
||||
const char *propname, u64 *out_value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -475,6 +475,9 @@ struct scsi_host_template {
|
|||
*/
|
||||
unsigned ordered_tag:1;
|
||||
|
||||
/* True if the controller does not support WRITE SAME */
|
||||
unsigned no_write_same:1;
|
||||
|
||||
/*
|
||||
* Countdown for host blocking with no commands outstanding.
|
||||
*/
|
||||
|
|
@ -674,6 +677,9 @@ struct Scsi_Host {
|
|||
/* Don't resume host in EH */
|
||||
unsigned eh_noresume:1;
|
||||
|
||||
/* The controller does not support WRITE SAME */
|
||||
unsigned no_write_same:1;
|
||||
|
||||
/*
|
||||
* Optional work queue to be utilized by the transport
|
||||
*/
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user