Merge 4.14.153 into android-4.14-q
Changes in 4.14.153 arm64: dts: Fix gpio to pinmux mapping regulator: ti-abb: Fix timeout in ti_abb_wait_txdone/ti_abb_clear_all_txdone regulator: pfuze100-regulator: Variable "val" in pfuze100_regulator_probe() could be uninitialized ASoC: wm_adsp: Don't generate kcontrols without READ flags ASoc: rockchip: i2s: Fix RPM imbalance ARM: dts: logicpd-torpedo-som: Remove twl_keypad pinctrl: ns2: Fix off by one bugs in ns2_pinmux_enable() ARM: mm: fix alignment handler faults under memory pressure scsi: scsi_dh_alua: handle RTPG sense code correctly during state transitions scsi: sni_53c710: fix compilation error scsi: fix kconfig dependency warning related to 53C700_LE_ON_BE ARM: dts: imx7s: Correct GPT's ipg clock source perf c2c: Fix memory leak in build_cl_output() perf kmem: Fix memory leak in compact_gfp_flags() ARM: davinci: dm365: Fix McBSP dma_slave_map entry scsi: target: core: Do not overwrite CDB byte 1 ARM: 8926/1: v7m: remove register save to stack before svc of: unittest: fix memory leak in unittest_data_add MIPS: bmips: mark exception vectors as char arrays i2c: stm32f7: remove warning when compiling with W=1 cifs: Fix cifsInodeInfo lock_sem deadlock when reconnect occurs nbd: handle racing with error'ed out commands cxgb4: fix panic when attaching to ULD fail dccp: do not leak jiffies on the wire net: annotate accesses to sk->sk_incoming_cpu net: annotate lockless accesses to sk->sk_napi_id net: dsa: bcm_sf2: Fix IMP setup for port different than 8 net: ethernet: ftgmac100: Fix DMA coherency issue with SW checksum net: fix sk_page_frag() recursion from memory reclaim net: hisilicon: Fix ping latency when deal with high throughput net/mlx4_core: Dynamically set guaranteed amount of counters per VF net: Zeroing the structure ethtool_wolinfo in ethtool_get_wol() selftests: net: reuseport_dualstack: fix uninitalized parameter udp: fix data-race in udp_set_dev_scratch() net: add READ_ONCE() annotation in __skb_wait_for_more_packets() net/mlx5e: Fix handling of compressed CQEs in case of low NAPI budget net: dsa: b53: Do not clear existing mirrored port mask net: usb: lan78xx: Connect PHY before registering MAC r8152: add device id for Lenovo ThinkPad USB-C Dock Gen 2 net: dsa: fix switch tree list net: bcmgenet: reset 40nm EPHY on energy detect net: add skb_queue_empty_lockless() udp: use skb_queue_empty_lockless() net: use skb_queue_empty_lockless() in poll() handlers net: use skb_queue_empty_lockless() in busy poll contexts vxlan: check tun_info options_len properly erspan: fix the tun_info options_len check for erspan inet: stop leaking jiffies on the wire net/flow_dissector: switch to siphash dmaengine: qcom: bam_dma: Fix resource leak sched/wake_q: Fix wakeup ordering for wake_q kbuild: use -fmacro-prefix-map to make __FILE__ a relative path kbuild: add -fcf-protection=none when using retpoline flags platform/x86: pmc_atom: Add Siemens SIMATIC IPC227E to critclk_systems DMI table iio: adc: stm32-adc: move registers definitions iio: adc: stm32-adc: fix a race when using several adcs with dma and irq powerpc/mm: Fixup tlbie vs store ordering issue on POWER9 powerpc/book3s64/mm: Don't do tlbie fixup for some hardware revisions powerpc/book3s64/radix: Rename CPU_FTR_P9_TLBIE_BUG feature flag powerpc/mm: Fixup tlbie vs mtpidr/mtlpidr ordering issue on POWER9 selftests/powerpc: Add test case for tlbie vs mtpidr ordering issue selftests/powerpc: Fix compile error on tlbie_test due to newer gcc Linux 4.14.153 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
11
Makefile
11
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 14
|
||||
SUBLEVEL = 152
|
||||
SUBLEVEL = 153
|
||||
EXTRAVERSION =
|
||||
NAME = Petit Gorille
|
||||
|
||||
@@ -912,6 +912,15 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)
|
||||
# Require designated initializers for all marked structures
|
||||
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
|
||||
|
||||
# change __FILE__ to the relative path from the srctree
|
||||
KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
|
||||
|
||||
# ensure -fcf-protection is disabled when using retpoline as it is
|
||||
# incompatible with -mindirect-branch=thunk-extern
|
||||
ifdef CONFIG_RETPOLINE
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
||||
endif
|
||||
|
||||
# use the deterministic mode of AR if available
|
||||
KBUILD_ARFLAGS := $(call ar-option,D)
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@
|
||||
compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
|
||||
reg = <0x302d0000 0x10000>;
|
||||
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_CLK_DUMMY>,
|
||||
clocks = <&clks IMX7D_GPT1_ROOT_CLK>,
|
||||
<&clks IMX7D_GPT1_ROOT_CLK>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
@@ -459,7 +459,7 @@
|
||||
compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
|
||||
reg = <0x302e0000 0x10000>;
|
||||
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_CLK_DUMMY>,
|
||||
clocks = <&clks IMX7D_GPT2_ROOT_CLK>,
|
||||
<&clks IMX7D_GPT2_ROOT_CLK>;
|
||||
clock-names = "ipg", "per";
|
||||
status = "disabled";
|
||||
@@ -469,7 +469,7 @@
|
||||
compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
|
||||
reg = <0x302f0000 0x10000>;
|
||||
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_CLK_DUMMY>,
|
||||
clocks = <&clks IMX7D_GPT3_ROOT_CLK>,
|
||||
<&clks IMX7D_GPT3_ROOT_CLK>;
|
||||
clock-names = "ipg", "per";
|
||||
status = "disabled";
|
||||
@@ -479,7 +479,7 @@
|
||||
compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
|
||||
reg = <0x30300000 0x10000>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_CLK_DUMMY>,
|
||||
clocks = <&clks IMX7D_GPT4_ROOT_CLK>,
|
||||
<&clks IMX7D_GPT4_ROOT_CLK>;
|
||||
clock-names = "ipg", "per";
|
||||
status = "disabled";
|
||||
|
||||
@@ -270,3 +270,7 @@
|
||||
&twl_gpio {
|
||||
ti,use-leds;
|
||||
};
|
||||
|
||||
&twl_keypad {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -856,8 +856,8 @@ static s8 dm365_queue_priority_mapping[][2] = {
|
||||
};
|
||||
|
||||
static const struct dma_slave_map dm365_edma_map[] = {
|
||||
{ "davinci-mcbsp.0", "tx", EDMA_FILTER_PARAM(0, 2) },
|
||||
{ "davinci-mcbsp.0", "rx", EDMA_FILTER_PARAM(0, 3) },
|
||||
{ "davinci-mcbsp", "tx", EDMA_FILTER_PARAM(0, 2) },
|
||||
{ "davinci-mcbsp", "rx", EDMA_FILTER_PARAM(0, 3) },
|
||||
{ "davinci_voicecodec", "tx", EDMA_FILTER_PARAM(0, 2) },
|
||||
{ "davinci_voicecodec", "rx", EDMA_FILTER_PARAM(0, 3) },
|
||||
{ "spi_davinci.2", "tx", EDMA_FILTER_PARAM(0, 10) },
|
||||
|
||||
@@ -768,6 +768,36 @@ do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int alignment_get_arm(struct pt_regs *regs, u32 *ip, unsigned long *inst)
|
||||
{
|
||||
u32 instr = 0;
|
||||
int fault;
|
||||
|
||||
if (user_mode(regs))
|
||||
fault = get_user(instr, ip);
|
||||
else
|
||||
fault = probe_kernel_address(ip, instr);
|
||||
|
||||
*inst = __mem_to_opcode_arm(instr);
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
static int alignment_get_thumb(struct pt_regs *regs, u16 *ip, u16 *inst)
|
||||
{
|
||||
u16 instr = 0;
|
||||
int fault;
|
||||
|
||||
if (user_mode(regs))
|
||||
fault = get_user(instr, ip);
|
||||
else
|
||||
fault = probe_kernel_address(ip, instr);
|
||||
|
||||
*inst = __mem_to_opcode_thumb16(instr);
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
static int
|
||||
do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
{
|
||||
@@ -775,10 +805,10 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
unsigned long instr = 0, instrptr;
|
||||
int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
|
||||
unsigned int type;
|
||||
unsigned int fault;
|
||||
u16 tinstr = 0;
|
||||
int isize = 4;
|
||||
int thumb2_32b = 0;
|
||||
int fault;
|
||||
|
||||
if (interrupts_enabled(regs))
|
||||
local_irq_enable();
|
||||
@@ -787,15 +817,14 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
|
||||
if (thumb_mode(regs)) {
|
||||
u16 *ptr = (u16 *)(instrptr & ~1);
|
||||
fault = probe_kernel_address(ptr, tinstr);
|
||||
tinstr = __mem_to_opcode_thumb16(tinstr);
|
||||
|
||||
fault = alignment_get_thumb(regs, ptr, &tinstr);
|
||||
if (!fault) {
|
||||
if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
|
||||
IS_T32(tinstr)) {
|
||||
/* Thumb-2 32-bit */
|
||||
u16 tinst2 = 0;
|
||||
fault = probe_kernel_address(ptr + 1, tinst2);
|
||||
tinst2 = __mem_to_opcode_thumb16(tinst2);
|
||||
u16 tinst2;
|
||||
fault = alignment_get_thumb(regs, ptr + 1, &tinst2);
|
||||
instr = __opcode_thumb32_compose(tinstr, tinst2);
|
||||
thumb2_32b = 1;
|
||||
} else {
|
||||
@@ -804,8 +833,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fault = probe_kernel_address((void *)instrptr, instr);
|
||||
instr = __mem_to_opcode_arm(instr);
|
||||
fault = alignment_get_arm(regs, (void *)instrptr, &instr);
|
||||
}
|
||||
|
||||
if (fault) {
|
||||
|
||||
@@ -135,7 +135,6 @@ __v7m_setup_cont:
|
||||
dsb
|
||||
mov r6, lr @ save LR
|
||||
ldr sp, =init_thread_union + THREAD_START_SP
|
||||
stmia sp, {r0-r3, r12}
|
||||
cpsie i
|
||||
svc #0
|
||||
1: cpsid i
|
||||
|
||||
@@ -42,13 +42,14 @@
|
||||
|
||||
pinmux: pinmux@0014029c {
|
||||
compatible = "pinctrl-single";
|
||||
reg = <0x0014029c 0x250>;
|
||||
reg = <0x0014029c 0x26c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
pinctrl-single,register-width = <32>;
|
||||
pinctrl-single,function-mask = <0xf>;
|
||||
pinctrl-single,gpio-range = <
|
||||
&range 0 154 MODE_GPIO
|
||||
&range 0 91 MODE_GPIO
|
||||
&range 95 60 MODE_GPIO
|
||||
>;
|
||||
range: gpio-range {
|
||||
#pinctrl-single,gpio-range-cells = <3>;
|
||||
|
||||
@@ -444,8 +444,7 @@
|
||||
<&pinmux 108 16 27>,
|
||||
<&pinmux 135 77 6>,
|
||||
<&pinmux 141 67 4>,
|
||||
<&pinmux 145 149 6>,
|
||||
<&pinmux 151 91 4>;
|
||||
<&pinmux 145 149 6>;
|
||||
};
|
||||
|
||||
i2c1: i2c@000e0000 {
|
||||
|
||||
@@ -84,7 +84,7 @@ void __init prom_init(void)
|
||||
* Here we will start up CPU1 in the background and ask it to
|
||||
* reconfigure itself then go back to sleep.
|
||||
*/
|
||||
memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20);
|
||||
memcpy((void *)0xa0000200, bmips_smp_movevec, 0x20);
|
||||
__sync();
|
||||
set_c0_cause(C_SW0);
|
||||
cpumask_set_cpu(1, &bmips_booted_mask);
|
||||
|
||||
@@ -75,11 +75,11 @@ static inline int register_bmips_smp_ops(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
extern char bmips_reset_nmi_vec;
|
||||
extern char bmips_reset_nmi_vec_end;
|
||||
extern char bmips_smp_movevec;
|
||||
extern char bmips_smp_int_vec;
|
||||
extern char bmips_smp_int_vec_end;
|
||||
extern char bmips_reset_nmi_vec[];
|
||||
extern char bmips_reset_nmi_vec_end[];
|
||||
extern char bmips_smp_movevec[];
|
||||
extern char bmips_smp_int_vec[];
|
||||
extern char bmips_smp_int_vec_end[];
|
||||
|
||||
extern int bmips_smp_enabled;
|
||||
extern int bmips_cpu_offset;
|
||||
|
||||
@@ -457,10 +457,10 @@ static void bmips_wr_vec(unsigned long dst, char *start, char *end)
|
||||
|
||||
static inline void bmips_nmi_handler_setup(void)
|
||||
{
|
||||
bmips_wr_vec(BMIPS_NMI_RESET_VEC, &bmips_reset_nmi_vec,
|
||||
&bmips_reset_nmi_vec_end);
|
||||
bmips_wr_vec(BMIPS_WARM_RESTART_VEC, &bmips_smp_int_vec,
|
||||
&bmips_smp_int_vec_end);
|
||||
bmips_wr_vec(BMIPS_NMI_RESET_VEC, bmips_reset_nmi_vec,
|
||||
bmips_reset_nmi_vec_end);
|
||||
bmips_wr_vec(BMIPS_WARM_RESTART_VEC, bmips_smp_int_vec,
|
||||
bmips_smp_int_vec_end);
|
||||
}
|
||||
|
||||
struct reset_vec_info {
|
||||
|
||||
@@ -215,7 +215,9 @@ enum {
|
||||
#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000)
|
||||
#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000)
|
||||
#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000)
|
||||
#define CPU_FTR_P9_TLBIE_STQ_BUG LONG_ASM_CONST(0x0000400000000000)
|
||||
#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x4000000000000000)
|
||||
#define CPU_FTR_P9_TLBIE_ERAT_BUG LONG_ASM_CONST(0x0001000000000000)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -475,7 +477,8 @@ enum {
|
||||
CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
|
||||
CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
|
||||
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
|
||||
CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300)
|
||||
CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | \
|
||||
CPU_FTR_P9_TLBIE_STQ_BUG | CPU_FTR_P9_TLBIE_ERAT_BUG)
|
||||
#define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \
|
||||
(~CPU_FTR_SAO))
|
||||
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
|
||||
@@ -733,15 +733,45 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle POWER9 broadcast tlbie invalidation issue using
|
||||
* cpu feature flag.
|
||||
*/
|
||||
static __init void update_tlbie_feature_flag(unsigned long pvr)
|
||||
{
|
||||
if (PVR_VER(pvr) == PVR_POWER9) {
|
||||
/*
|
||||
* Set the tlbie feature flag for anything below
|
||||
* Nimbus DD 2.3 and Cumulus DD 1.3
|
||||
*/
|
||||
if ((pvr & 0xe000) == 0) {
|
||||
/* Nimbus */
|
||||
if ((pvr & 0xfff) < 0x203)
|
||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||
} else if ((pvr & 0xc000) == 0) {
|
||||
/* Cumulus */
|
||||
if ((pvr & 0xfff) < 0x103)
|
||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||
} else {
|
||||
WARN_ONCE(1, "Unknown PVR");
|
||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||
}
|
||||
|
||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_ERAT_BUG;
|
||||
}
|
||||
}
|
||||
|
||||
static __init void cpufeatures_cpu_quirks(void)
|
||||
{
|
||||
int version = mfspr(SPRN_PVR);
|
||||
unsigned long version = mfspr(SPRN_PVR);
|
||||
|
||||
/*
|
||||
* Not all quirks can be derived from the cpufeatures device tree.
|
||||
*/
|
||||
if ((version & 0xffffff00) == 0x004e0100)
|
||||
cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1;
|
||||
|
||||
update_tlbie_feature_flag(version);
|
||||
}
|
||||
|
||||
static void __init cpufeatures_setup_finished(void)
|
||||
|
||||
@@ -160,6 +160,9 @@ static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
|
||||
: : "r" (addr), "r" (kvm->arch.lpid) : "memory");
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG))
|
||||
asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
|
||||
: : "r" (addr), "r" (kvm->arch.lpid) : "memory");
|
||||
asm volatile("ptesync": : :"memory");
|
||||
}
|
||||
|
||||
|
||||
@@ -429,6 +429,37 @@ static inline int try_lock_tlbie(unsigned int *lock)
|
||||
return old == 0;
|
||||
}
|
||||
|
||||
static inline void fixup_tlbie_lpid(unsigned long rb_value, unsigned long lpid)
|
||||
{
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||
/* Radix flush for a hash guest */
|
||||
|
||||
unsigned long rb,rs,prs,r,ric;
|
||||
|
||||
rb = PPC_BIT(52); /* IS = 2 */
|
||||
rs = 0; /* lpid = 0 */
|
||||
prs = 0; /* partition scoped */
|
||||
r = 1; /* radix format */
|
||||
ric = 0; /* RIC_FLSUH_TLB */
|
||||
|
||||
/*
|
||||
* Need the extra ptesync to make sure we don't
|
||||
* re-order the tlbie
|
||||
*/
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs),
|
||||
"i"(ric), "r"(rs) : "memory");
|
||||
}
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
|
||||
"r" (rb_value), "r" (lpid));
|
||||
}
|
||||
}
|
||||
|
||||
static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
|
||||
long npages, int global, bool need_sync)
|
||||
{
|
||||
@@ -448,6 +479,8 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
|
||||
asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
|
||||
"r" (rbvalues[i]), "r" (kvm->arch.lpid));
|
||||
}
|
||||
|
||||
fixup_tlbie_lpid(rbvalues[i - 1], kvm->arch.lpid);
|
||||
asm volatile("eieio; tlbsync; ptesync" : : : "memory");
|
||||
kvm->arch.tlbie_lock = 0;
|
||||
} else {
|
||||
|
||||
@@ -104,6 +104,37 @@ static inline unsigned long ___tlbie(unsigned long vpn, int psize,
|
||||
return va;
|
||||
}
|
||||
|
||||
static inline void fixup_tlbie_vpn(unsigned long vpn, int psize,
|
||||
int apsize, int ssize)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||
/* Radix flush for a hash guest */
|
||||
|
||||
unsigned long rb,rs,prs,r,ric;
|
||||
|
||||
rb = PPC_BIT(52); /* IS = 2 */
|
||||
rs = 0; /* lpid = 0 */
|
||||
prs = 0; /* partition scoped */
|
||||
r = 1; /* radix format */
|
||||
ric = 0; /* RIC_FLSUH_TLB */
|
||||
|
||||
/*
|
||||
* Need the extra ptesync to make sure we don't
|
||||
* re-order the tlbie
|
||||
*/
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs),
|
||||
"i"(ric), "r"(rs) : "memory");
|
||||
}
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||
/* Need the extra ptesync to ensure we don't reorder tlbie*/
|
||||
asm volatile("ptesync": : :"memory");
|
||||
___tlbie(vpn, psize, apsize, ssize);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
|
||||
{
|
||||
unsigned long rb;
|
||||
@@ -181,6 +212,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize,
|
||||
asm volatile("ptesync": : :"memory");
|
||||
} else {
|
||||
__tlbie(vpn, psize, apsize, ssize);
|
||||
fixup_tlbie_vpn(vpn, psize, apsize, ssize);
|
||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||
}
|
||||
if (lock_tlbie && !use_local)
|
||||
@@ -674,7 +706,7 @@ static void native_hpte_clear(void)
|
||||
*/
|
||||
static void native_flush_hash_range(unsigned long number, int local)
|
||||
{
|
||||
unsigned long vpn;
|
||||
unsigned long vpn = 0;
|
||||
unsigned long hash, index, hidx, shift, slot;
|
||||
struct hash_pte *hptep;
|
||||
unsigned long hpte_v;
|
||||
@@ -746,6 +778,10 @@ static void native_flush_hash_range(unsigned long number, int local)
|
||||
__tlbie(vpn, psize, psize, ssize);
|
||||
} pte_iterate_hashed_end();
|
||||
}
|
||||
/*
|
||||
* Just do one more with the last used values.
|
||||
*/
|
||||
fixup_tlbie_vpn(vpn, psize, psize, ssize);
|
||||
asm volatile("eieio; tlbsync; ptesync":::"memory");
|
||||
|
||||
if (lock_tlbie)
|
||||
|
||||
@@ -491,6 +491,7 @@ void mmu_partition_table_set_entry(unsigned int lpid, unsigned long dw0,
|
||||
"r" (TLBIEL_INVAL_SET_LPID), "r" (lpid));
|
||||
trace_tlbie(lpid, 0, TLBIEL_INVAL_SET_LPID, lpid, 2, 0, 0);
|
||||
}
|
||||
/* do we need fixup here ?*/
|
||||
asm volatile("eieio; tlbsync; ptesync" : : : "memory");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmu_partition_table_set_entry);
|
||||
|
||||
@@ -23,6 +23,37 @@
|
||||
#define RIC_FLUSH_PWC 1
|
||||
#define RIC_FLUSH_ALL 2
|
||||
|
||||
static inline void __tlbie_va(unsigned long va, unsigned long pid,
|
||||
unsigned long ap, unsigned long ric)
|
||||
{
|
||||
unsigned long rb,rs,prs,r;
|
||||
|
||||
rb = va & ~(PPC_BITMASK(52, 63));
|
||||
rb |= ap << PPC_BITLSHIFT(58);
|
||||
rs = pid << PPC_BITLSHIFT(31);
|
||||
prs = 1; /* process scoped */
|
||||
r = 1; /* raidx format */
|
||||
|
||||
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
|
||||
trace_tlbie(0, 0, rb, rs, ric, prs, r);
|
||||
}
|
||||
|
||||
|
||||
static inline void fixup_tlbie_va(unsigned long va, unsigned long pid,
|
||||
unsigned long ap)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||
asm volatile("ptesync": : :"memory");
|
||||
__tlbie_va(va, 0, ap, RIC_FLUSH_TLB);
|
||||
}
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||
asm volatile("ptesync": : :"memory");
|
||||
__tlbie_va(va, pid, ap, RIC_FLUSH_TLB);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __tlbiel_pid(unsigned long pid, int set,
|
||||
unsigned long ric)
|
||||
{
|
||||
@@ -68,22 +99,64 @@ static inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
|
||||
asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory");
|
||||
}
|
||||
|
||||
static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
|
||||
static inline void __tlbie_pid(unsigned long pid, unsigned long ric)
|
||||
{
|
||||
unsigned long rb,rs,prs,r;
|
||||
|
||||
rb = PPC_BIT(53); /* IS = 1 */
|
||||
rs = pid << PPC_BITLSHIFT(31);
|
||||
prs = 1; /* process scoped */
|
||||
r = 1; /* raidx format */
|
||||
r = 1; /* radix format */
|
||||
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
|
||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||
trace_tlbie(0, 0, rb, rs, ric, prs, r);
|
||||
}
|
||||
|
||||
static inline void fixup_tlbie_pid(unsigned long pid)
|
||||
{
|
||||
/*
|
||||
* We can use any address for the invalidation, pick one which is
|
||||
* probably unused as an optimisation.
|
||||
*/
|
||||
unsigned long va = ((1UL << 52) - 1);
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||
asm volatile("ptesync": : :"memory");
|
||||
__tlbie_pid(0, RIC_FLUSH_TLB);
|
||||
}
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||
asm volatile("ptesync": : :"memory");
|
||||
__tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
|
||||
{
|
||||
asm volatile("ptesync": : :"memory");
|
||||
|
||||
/*
|
||||
* Workaround the fact that the "ric" argument to __tlbie_pid
|
||||
* must be a compile-time contraint to match the "i" constraint
|
||||
* in the asm statement.
|
||||
*/
|
||||
switch (ric) {
|
||||
case RIC_FLUSH_TLB:
|
||||
__tlbie_pid(pid, RIC_FLUSH_TLB);
|
||||
fixup_tlbie_pid(pid);
|
||||
break;
|
||||
case RIC_FLUSH_PWC:
|
||||
__tlbie_pid(pid, RIC_FLUSH_PWC);
|
||||
break;
|
||||
case RIC_FLUSH_ALL:
|
||||
default:
|
||||
__tlbie_pid(pid, RIC_FLUSH_ALL);
|
||||
fixup_tlbie_pid(pid);
|
||||
}
|
||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||
}
|
||||
|
||||
static inline void _tlbiel_va(unsigned long va, unsigned long pid,
|
||||
unsigned long ap, unsigned long ric)
|
||||
{
|
||||
@@ -105,19 +178,10 @@ static inline void _tlbiel_va(unsigned long va, unsigned long pid,
|
||||
static inline void _tlbie_va(unsigned long va, unsigned long pid,
|
||||
unsigned long ap, unsigned long ric)
|
||||
{
|
||||
unsigned long rb,rs,prs,r;
|
||||
|
||||
rb = va & ~(PPC_BITMASK(52, 63));
|
||||
rb |= ap << PPC_BITLSHIFT(58);
|
||||
rs = pid << PPC_BITLSHIFT(31);
|
||||
prs = 1; /* process scoped */
|
||||
r = 1; /* raidx format */
|
||||
|
||||
asm volatile("ptesync": : :"memory");
|
||||
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
|
||||
__tlbie_va(va, pid, ap, ric);
|
||||
fixup_tlbie_va(va, pid, ap);
|
||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||
trace_tlbie(0, 0, rb, rs, ric, prs, r);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -648,6 +648,12 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (cmd->status != BLK_STS_OK) {
|
||||
dev_err(disk_to_dev(nbd->disk), "Command already handled %p\n",
|
||||
req);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (test_bit(NBD_CMD_REQUEUED, &cmd->flags)) {
|
||||
dev_err(disk_to_dev(nbd->disk), "Raced with timeout on req %p\n",
|
||||
req);
|
||||
|
||||
@@ -690,7 +690,21 @@ static int bam_dma_terminate_all(struct dma_chan *chan)
|
||||
|
||||
/* remove all transactions, including active transaction */
|
||||
spin_lock_irqsave(&bchan->vc.lock, flag);
|
||||
/*
|
||||
* If we have transactions queued, then some might be committed to the
|
||||
* hardware in the desc fifo. The only way to reset the desc fifo is
|
||||
* to do a hardware reset (either by pipe or the entire block).
|
||||
* bam_chan_init_hw() will trigger a pipe reset, and also reinit the
|
||||
* pipe. If the pipe is left disabled (default state after pipe reset)
|
||||
* and is accessed by a connected hardware engine, a fatal error in
|
||||
* the BAM will occur. There is a small window where this could happen
|
||||
* with bam_chan_init_hw(), but it is assumed that the caller has
|
||||
* stopped activity on any attached hardware engine. Make sure to do
|
||||
* this first so that the BAM hardware doesn't cause memory corruption
|
||||
* by accessing freed resources.
|
||||
*/
|
||||
if (bchan->curr_txd) {
|
||||
bam_chan_init_hw(bchan, bchan->curr_txd->dir);
|
||||
list_add(&bchan->curr_txd->vd.node, &bchan->vc.desc_issued);
|
||||
bchan->curr_txd = NULL;
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ struct stm32f7_i2c_dev {
|
||||
struct stm32f7_i2c_timings timing;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* All these values are coming from I2C Specification, Version 6.0, 4th of
|
||||
* April 2014.
|
||||
*
|
||||
|
||||
@@ -33,36 +33,9 @@
|
||||
|
||||
#include "stm32-adc-core.h"
|
||||
|
||||
/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
|
||||
#define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
|
||||
#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
|
||||
|
||||
/* STM32F4_ADC_CSR - bit fields */
|
||||
#define STM32F4_EOC3 BIT(17)
|
||||
#define STM32F4_EOC2 BIT(9)
|
||||
#define STM32F4_EOC1 BIT(1)
|
||||
|
||||
/* STM32F4_ADC_CCR - bit fields */
|
||||
#define STM32F4_ADC_ADCPRE_SHIFT 16
|
||||
#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
|
||||
|
||||
/* STM32 F4 maximum analog clock rate (from datasheet) */
|
||||
#define STM32F4_ADC_MAX_CLK_RATE 36000000
|
||||
|
||||
/* STM32H7 - common registers for all ADC instances */
|
||||
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
|
||||
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
|
||||
|
||||
/* STM32H7_ADC_CSR - bit fields */
|
||||
#define STM32H7_EOC_SLV BIT(18)
|
||||
#define STM32H7_EOC_MST BIT(2)
|
||||
|
||||
/* STM32H7_ADC_CCR - bit fields */
|
||||
#define STM32H7_PRESC_SHIFT 18
|
||||
#define STM32H7_PRESC_MASK GENMASK(21, 18)
|
||||
#define STM32H7_CKMODE_SHIFT 16
|
||||
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
|
||||
|
||||
/* STM32 H7 maximum analog clock rate (from datasheet) */
|
||||
#define STM32H7_ADC_MAX_CLK_RATE 36000000
|
||||
|
||||
@@ -72,12 +45,16 @@
|
||||
* @eoc1: adc1 end of conversion flag in @csr
|
||||
* @eoc2: adc2 end of conversion flag in @csr
|
||||
* @eoc3: adc3 end of conversion flag in @csr
|
||||
* @ier: interrupt enable register offset for each adc
|
||||
* @eocie_msk: end of conversion interrupt enable mask in @ier
|
||||
*/
|
||||
struct stm32_adc_common_regs {
|
||||
u32 csr;
|
||||
u32 eoc1_msk;
|
||||
u32 eoc2_msk;
|
||||
u32 eoc3_msk;
|
||||
u32 ier;
|
||||
u32 eocie_msk;
|
||||
};
|
||||
|
||||
struct stm32_adc_priv;
|
||||
@@ -271,6 +248,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
|
||||
.eoc1_msk = STM32F4_EOC1,
|
||||
.eoc2_msk = STM32F4_EOC2,
|
||||
.eoc3_msk = STM32F4_EOC3,
|
||||
.ier = STM32F4_ADC_CR1,
|
||||
.eocie_msk = STM32F4_EOCIE,
|
||||
};
|
||||
|
||||
/* STM32H7 common registers definitions */
|
||||
@@ -278,8 +257,24 @@ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
|
||||
.csr = STM32H7_ADC_CSR,
|
||||
.eoc1_msk = STM32H7_EOC_MST,
|
||||
.eoc2_msk = STM32H7_EOC_SLV,
|
||||
.ier = STM32H7_ADC_IER,
|
||||
.eocie_msk = STM32H7_EOCIE,
|
||||
};
|
||||
|
||||
static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
|
||||
0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2,
|
||||
};
|
||||
|
||||
static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv,
|
||||
unsigned int adc)
|
||||
{
|
||||
u32 ier, offset = stm32_adc_offset[adc];
|
||||
|
||||
ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier);
|
||||
|
||||
return ier & priv->cfg->regs->eocie_msk;
|
||||
}
|
||||
|
||||
/* ADC common interrupt for all instances */
|
||||
static void stm32_adc_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
@@ -290,13 +285,28 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_enter(chip, desc);
|
||||
status = readl_relaxed(priv->common.base + priv->cfg->regs->csr);
|
||||
|
||||
if (status & priv->cfg->regs->eoc1_msk)
|
||||
/*
|
||||
* End of conversion may be handled by using IRQ or DMA. There may be a
|
||||
* race here when two conversions complete at the same time on several
|
||||
* ADCs. EOC may be read 'set' for several ADCs, with:
|
||||
* - an ADC configured to use DMA (EOC triggers the DMA request, and
|
||||
* is then automatically cleared by DR read in hardware)
|
||||
* - an ADC configured to use IRQs (EOCIE bit is set. The handler must
|
||||
* be called in this case)
|
||||
* So both EOC status bit in CSR and EOCIE control bit must be checked
|
||||
* before invoking the interrupt handler (e.g. call ISR only for
|
||||
* IRQ-enabled ADCs).
|
||||
*/
|
||||
if (status & priv->cfg->regs->eoc1_msk &&
|
||||
stm32_adc_eoc_enabled(priv, 0))
|
||||
generic_handle_irq(irq_find_mapping(priv->domain, 0));
|
||||
|
||||
if (status & priv->cfg->regs->eoc2_msk)
|
||||
if (status & priv->cfg->regs->eoc2_msk &&
|
||||
stm32_adc_eoc_enabled(priv, 1))
|
||||
generic_handle_irq(irq_find_mapping(priv->domain, 1));
|
||||
|
||||
if (status & priv->cfg->regs->eoc3_msk)
|
||||
if (status & priv->cfg->regs->eoc3_msk &&
|
||||
stm32_adc_eoc_enabled(priv, 2))
|
||||
generic_handle_irq(irq_find_mapping(priv->domain, 2));
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
|
||||
@@ -37,8 +37,143 @@
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
#define STM32_ADC_MAX_ADCS 3
|
||||
#define STM32_ADC_OFFSET 0x100
|
||||
#define STM32_ADCX_COMN_OFFSET 0x300
|
||||
|
||||
/* STM32F4 - Registers for each ADC instance */
|
||||
#define STM32F4_ADC_SR 0x00
|
||||
#define STM32F4_ADC_CR1 0x04
|
||||
#define STM32F4_ADC_CR2 0x08
|
||||
#define STM32F4_ADC_SMPR1 0x0C
|
||||
#define STM32F4_ADC_SMPR2 0x10
|
||||
#define STM32F4_ADC_HTR 0x24
|
||||
#define STM32F4_ADC_LTR 0x28
|
||||
#define STM32F4_ADC_SQR1 0x2C
|
||||
#define STM32F4_ADC_SQR2 0x30
|
||||
#define STM32F4_ADC_SQR3 0x34
|
||||
#define STM32F4_ADC_JSQR 0x38
|
||||
#define STM32F4_ADC_JDR1 0x3C
|
||||
#define STM32F4_ADC_JDR2 0x40
|
||||
#define STM32F4_ADC_JDR3 0x44
|
||||
#define STM32F4_ADC_JDR4 0x48
|
||||
#define STM32F4_ADC_DR 0x4C
|
||||
|
||||
/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */
|
||||
#define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
|
||||
#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
|
||||
|
||||
/* STM32F4_ADC_SR - bit fields */
|
||||
#define STM32F4_STRT BIT(4)
|
||||
#define STM32F4_EOC BIT(1)
|
||||
|
||||
/* STM32F4_ADC_CR1 - bit fields */
|
||||
#define STM32F4_RES_SHIFT 24
|
||||
#define STM32F4_RES_MASK GENMASK(25, 24)
|
||||
#define STM32F4_SCAN BIT(8)
|
||||
#define STM32F4_EOCIE BIT(5)
|
||||
|
||||
/* STM32F4_ADC_CR2 - bit fields */
|
||||
#define STM32F4_SWSTART BIT(30)
|
||||
#define STM32F4_EXTEN_SHIFT 28
|
||||
#define STM32F4_EXTEN_MASK GENMASK(29, 28)
|
||||
#define STM32F4_EXTSEL_SHIFT 24
|
||||
#define STM32F4_EXTSEL_MASK GENMASK(27, 24)
|
||||
#define STM32F4_EOCS BIT(10)
|
||||
#define STM32F4_DDS BIT(9)
|
||||
#define STM32F4_DMA BIT(8)
|
||||
#define STM32F4_ADON BIT(0)
|
||||
|
||||
/* STM32F4_ADC_CSR - bit fields */
|
||||
#define STM32F4_EOC3 BIT(17)
|
||||
#define STM32F4_EOC2 BIT(9)
|
||||
#define STM32F4_EOC1 BIT(1)
|
||||
|
||||
/* STM32F4_ADC_CCR - bit fields */
|
||||
#define STM32F4_ADC_ADCPRE_SHIFT 16
|
||||
#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
|
||||
|
||||
/* STM32H7 - Registers for each ADC instance */
|
||||
#define STM32H7_ADC_ISR 0x00
|
||||
#define STM32H7_ADC_IER 0x04
|
||||
#define STM32H7_ADC_CR 0x08
|
||||
#define STM32H7_ADC_CFGR 0x0C
|
||||
#define STM32H7_ADC_SMPR1 0x14
|
||||
#define STM32H7_ADC_SMPR2 0x18
|
||||
#define STM32H7_ADC_PCSEL 0x1C
|
||||
#define STM32H7_ADC_SQR1 0x30
|
||||
#define STM32H7_ADC_SQR2 0x34
|
||||
#define STM32H7_ADC_SQR3 0x38
|
||||
#define STM32H7_ADC_SQR4 0x3C
|
||||
#define STM32H7_ADC_DR 0x40
|
||||
#define STM32H7_ADC_CALFACT 0xC4
|
||||
#define STM32H7_ADC_CALFACT2 0xC8
|
||||
|
||||
/* STM32H7 - common registers for all ADC instances */
|
||||
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
|
||||
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
|
||||
|
||||
/* STM32H7_ADC_ISR - bit fields */
|
||||
#define STM32H7_EOC BIT(2)
|
||||
#define STM32H7_ADRDY BIT(0)
|
||||
|
||||
/* STM32H7_ADC_IER - bit fields */
|
||||
#define STM32H7_EOCIE STM32H7_EOC
|
||||
|
||||
/* STM32H7_ADC_CR - bit fields */
|
||||
#define STM32H7_ADCAL BIT(31)
|
||||
#define STM32H7_ADCALDIF BIT(30)
|
||||
#define STM32H7_DEEPPWD BIT(29)
|
||||
#define STM32H7_ADVREGEN BIT(28)
|
||||
#define STM32H7_LINCALRDYW6 BIT(27)
|
||||
#define STM32H7_LINCALRDYW5 BIT(26)
|
||||
#define STM32H7_LINCALRDYW4 BIT(25)
|
||||
#define STM32H7_LINCALRDYW3 BIT(24)
|
||||
#define STM32H7_LINCALRDYW2 BIT(23)
|
||||
#define STM32H7_LINCALRDYW1 BIT(22)
|
||||
#define STM32H7_ADCALLIN BIT(16)
|
||||
#define STM32H7_BOOST BIT(8)
|
||||
#define STM32H7_ADSTP BIT(4)
|
||||
#define STM32H7_ADSTART BIT(2)
|
||||
#define STM32H7_ADDIS BIT(1)
|
||||
#define STM32H7_ADEN BIT(0)
|
||||
|
||||
/* STM32H7_ADC_CFGR bit fields */
|
||||
#define STM32H7_EXTEN_SHIFT 10
|
||||
#define STM32H7_EXTEN_MASK GENMASK(11, 10)
|
||||
#define STM32H7_EXTSEL_SHIFT 5
|
||||
#define STM32H7_EXTSEL_MASK GENMASK(9, 5)
|
||||
#define STM32H7_RES_SHIFT 2
|
||||
#define STM32H7_RES_MASK GENMASK(4, 2)
|
||||
#define STM32H7_DMNGT_SHIFT 0
|
||||
#define STM32H7_DMNGT_MASK GENMASK(1, 0)
|
||||
|
||||
enum stm32h7_adc_dmngt {
|
||||
STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */
|
||||
STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */
|
||||
STM32H7_DMNGT_DFSDM, /* DFSDM mode */
|
||||
STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
|
||||
};
|
||||
|
||||
/* STM32H7_ADC_CALFACT - bit fields */
|
||||
#define STM32H7_CALFACT_D_SHIFT 16
|
||||
#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
|
||||
#define STM32H7_CALFACT_S_SHIFT 0
|
||||
#define STM32H7_CALFACT_S_MASK GENMASK(10, 0)
|
||||
|
||||
/* STM32H7_ADC_CALFACT2 - bit fields */
|
||||
#define STM32H7_LINCALFACT_SHIFT 0
|
||||
#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
|
||||
|
||||
/* STM32H7_ADC_CSR - bit fields */
|
||||
#define STM32H7_EOC_SLV BIT(18)
|
||||
#define STM32H7_EOC_MST BIT(2)
|
||||
|
||||
/* STM32H7_ADC_CCR - bit fields */
|
||||
#define STM32H7_PRESC_SHIFT 18
|
||||
#define STM32H7_PRESC_MASK GENMASK(21, 18)
|
||||
#define STM32H7_CKMODE_SHIFT 16
|
||||
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
|
||||
|
||||
/**
|
||||
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
|
||||
* @base: control registers base cpu addr
|
||||
|
||||
@@ -40,113 +40,6 @@
|
||||
|
||||
#include "stm32-adc-core.h"
|
||||
|
||||
/* STM32F4 - Registers for each ADC instance */
|
||||
#define STM32F4_ADC_SR 0x00
|
||||
#define STM32F4_ADC_CR1 0x04
|
||||
#define STM32F4_ADC_CR2 0x08
|
||||
#define STM32F4_ADC_SMPR1 0x0C
|
||||
#define STM32F4_ADC_SMPR2 0x10
|
||||
#define STM32F4_ADC_HTR 0x24
|
||||
#define STM32F4_ADC_LTR 0x28
|
||||
#define STM32F4_ADC_SQR1 0x2C
|
||||
#define STM32F4_ADC_SQR2 0x30
|
||||
#define STM32F4_ADC_SQR3 0x34
|
||||
#define STM32F4_ADC_JSQR 0x38
|
||||
#define STM32F4_ADC_JDR1 0x3C
|
||||
#define STM32F4_ADC_JDR2 0x40
|
||||
#define STM32F4_ADC_JDR3 0x44
|
||||
#define STM32F4_ADC_JDR4 0x48
|
||||
#define STM32F4_ADC_DR 0x4C
|
||||
|
||||
/* STM32F4_ADC_SR - bit fields */
|
||||
#define STM32F4_STRT BIT(4)
|
||||
#define STM32F4_EOC BIT(1)
|
||||
|
||||
/* STM32F4_ADC_CR1 - bit fields */
|
||||
#define STM32F4_RES_SHIFT 24
|
||||
#define STM32F4_RES_MASK GENMASK(25, 24)
|
||||
#define STM32F4_SCAN BIT(8)
|
||||
#define STM32F4_EOCIE BIT(5)
|
||||
|
||||
/* STM32F4_ADC_CR2 - bit fields */
|
||||
#define STM32F4_SWSTART BIT(30)
|
||||
#define STM32F4_EXTEN_SHIFT 28
|
||||
#define STM32F4_EXTEN_MASK GENMASK(29, 28)
|
||||
#define STM32F4_EXTSEL_SHIFT 24
|
||||
#define STM32F4_EXTSEL_MASK GENMASK(27, 24)
|
||||
#define STM32F4_EOCS BIT(10)
|
||||
#define STM32F4_DDS BIT(9)
|
||||
#define STM32F4_DMA BIT(8)
|
||||
#define STM32F4_ADON BIT(0)
|
||||
|
||||
/* STM32H7 - Registers for each ADC instance */
|
||||
#define STM32H7_ADC_ISR 0x00
|
||||
#define STM32H7_ADC_IER 0x04
|
||||
#define STM32H7_ADC_CR 0x08
|
||||
#define STM32H7_ADC_CFGR 0x0C
|
||||
#define STM32H7_ADC_SMPR1 0x14
|
||||
#define STM32H7_ADC_SMPR2 0x18
|
||||
#define STM32H7_ADC_PCSEL 0x1C
|
||||
#define STM32H7_ADC_SQR1 0x30
|
||||
#define STM32H7_ADC_SQR2 0x34
|
||||
#define STM32H7_ADC_SQR3 0x38
|
||||
#define STM32H7_ADC_SQR4 0x3C
|
||||
#define STM32H7_ADC_DR 0x40
|
||||
#define STM32H7_ADC_CALFACT 0xC4
|
||||
#define STM32H7_ADC_CALFACT2 0xC8
|
||||
|
||||
/* STM32H7_ADC_ISR - bit fields */
|
||||
#define STM32H7_EOC BIT(2)
|
||||
#define STM32H7_ADRDY BIT(0)
|
||||
|
||||
/* STM32H7_ADC_IER - bit fields */
|
||||
#define STM32H7_EOCIE STM32H7_EOC
|
||||
|
||||
/* STM32H7_ADC_CR - bit fields */
|
||||
#define STM32H7_ADCAL BIT(31)
|
||||
#define STM32H7_ADCALDIF BIT(30)
|
||||
#define STM32H7_DEEPPWD BIT(29)
|
||||
#define STM32H7_ADVREGEN BIT(28)
|
||||
#define STM32H7_LINCALRDYW6 BIT(27)
|
||||
#define STM32H7_LINCALRDYW5 BIT(26)
|
||||
#define STM32H7_LINCALRDYW4 BIT(25)
|
||||
#define STM32H7_LINCALRDYW3 BIT(24)
|
||||
#define STM32H7_LINCALRDYW2 BIT(23)
|
||||
#define STM32H7_LINCALRDYW1 BIT(22)
|
||||
#define STM32H7_ADCALLIN BIT(16)
|
||||
#define STM32H7_BOOST BIT(8)
|
||||
#define STM32H7_ADSTP BIT(4)
|
||||
#define STM32H7_ADSTART BIT(2)
|
||||
#define STM32H7_ADDIS BIT(1)
|
||||
#define STM32H7_ADEN BIT(0)
|
||||
|
||||
/* STM32H7_ADC_CFGR bit fields */
|
||||
#define STM32H7_EXTEN_SHIFT 10
|
||||
#define STM32H7_EXTEN_MASK GENMASK(11, 10)
|
||||
#define STM32H7_EXTSEL_SHIFT 5
|
||||
#define STM32H7_EXTSEL_MASK GENMASK(9, 5)
|
||||
#define STM32H7_RES_SHIFT 2
|
||||
#define STM32H7_RES_MASK GENMASK(4, 2)
|
||||
#define STM32H7_DMNGT_SHIFT 0
|
||||
#define STM32H7_DMNGT_MASK GENMASK(1, 0)
|
||||
|
||||
enum stm32h7_adc_dmngt {
|
||||
STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */
|
||||
STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */
|
||||
STM32H7_DMNGT_DFSDM, /* DFSDM mode */
|
||||
STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
|
||||
};
|
||||
|
||||
/* STM32H7_ADC_CALFACT - bit fields */
|
||||
#define STM32H7_CALFACT_D_SHIFT 16
|
||||
#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
|
||||
#define STM32H7_CALFACT_S_SHIFT 0
|
||||
#define STM32H7_CALFACT_S_MASK GENMASK(10, 0)
|
||||
|
||||
/* STM32H7_ADC_CALFACT2 - bit fields */
|
||||
#define STM32H7_LINCALFACT_SHIFT 0
|
||||
#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
|
||||
|
||||
/* Number of linear calibration shadow registers / LINCALRDYW control bits */
|
||||
#define STM32H7_LINCALFACT_NUM 6
|
||||
|
||||
|
||||
@@ -743,7 +743,7 @@ capi_poll(struct file *file, poll_table *wait)
|
||||
|
||||
poll_wait(file, &(cdev->recvwait), wait);
|
||||
mask = POLLOUT | POLLWRNORM;
|
||||
if (!skb_queue_empty(&cdev->recvqueue))
|
||||
if (!skb_queue_empty_lockless(&cdev->recvqueue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -1431,7 +1431,6 @@ int b53_mirror_add(struct dsa_switch *ds, int port,
|
||||
loc = B53_EG_MIR_CTL;
|
||||
|
||||
b53_read16(dev, B53_MGMT_PAGE, loc, ®);
|
||||
reg &= ~MIRROR_MASK;
|
||||
reg |= BIT(port);
|
||||
b53_write16(dev, B53_MGMT_PAGE, loc, reg);
|
||||
|
||||
|
||||
@@ -106,22 +106,11 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
|
||||
unsigned int i;
|
||||
u32 reg, offset;
|
||||
|
||||
if (priv->type == BCM7445_DEVICE_ID)
|
||||
offset = CORE_STS_OVERRIDE_IMP;
|
||||
else
|
||||
offset = CORE_STS_OVERRIDE_IMP2;
|
||||
|
||||
/* Enable the port memories */
|
||||
reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
|
||||
reg &= ~P_TXQ_PSM_VDD(port);
|
||||
core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
|
||||
|
||||
/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
|
||||
reg = core_readl(priv, CORE_IMP_CTL);
|
||||
reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
|
||||
reg &= ~(RX_DIS | TX_DIS);
|
||||
core_writel(priv, reg, CORE_IMP_CTL);
|
||||
|
||||
/* Enable forwarding */
|
||||
core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
|
||||
|
||||
@@ -140,10 +129,27 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
|
||||
|
||||
bcm_sf2_brcm_hdr_setup(priv, port);
|
||||
|
||||
/* Force link status for IMP port */
|
||||
reg = core_readl(priv, offset);
|
||||
reg |= (MII_SW_OR | LINK_STS);
|
||||
core_writel(priv, reg, offset);
|
||||
if (port == 8) {
|
||||
if (priv->type == BCM7445_DEVICE_ID)
|
||||
offset = CORE_STS_OVERRIDE_IMP;
|
||||
else
|
||||
offset = CORE_STS_OVERRIDE_IMP2;
|
||||
|
||||
/* Force link status for IMP port */
|
||||
reg = core_readl(priv, offset);
|
||||
reg |= (MII_SW_OR | LINK_STS);
|
||||
core_writel(priv, reg, offset);
|
||||
|
||||
/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
|
||||
reg = core_readl(priv, CORE_IMP_CTL);
|
||||
reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
|
||||
reg &= ~(RX_DIS | TX_DIS);
|
||||
core_writel(priv, reg, CORE_IMP_CTL);
|
||||
} else {
|
||||
reg = core_readl(priv, CORE_G_PCTL_PORT(port));
|
||||
reg &= ~(RX_DIS | TX_DIS);
|
||||
core_writel(priv, reg, CORE_G_PCTL_PORT(port));
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
|
||||
|
||||
@@ -1985,6 +1985,8 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
|
||||
*/
|
||||
if (priv->internal_phy) {
|
||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
||||
if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
|
||||
int0_enable |= UMAC_IRQ_PHY_DET_R;
|
||||
} else if (priv->ext_phy) {
|
||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
||||
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
|
||||
@@ -2608,6 +2610,10 @@ static void bcmgenet_irq_task(struct work_struct *work)
|
||||
bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
|
||||
}
|
||||
|
||||
if (status & UMAC_IRQ_PHY_DET_R &&
|
||||
priv->dev->phydev->autoneg != AUTONEG_ENABLE)
|
||||
phy_init_hw(priv->dev->phydev);
|
||||
|
||||
/* Link UP/DOWN event */
|
||||
if (status & UMAC_IRQ_LINK_EVENT)
|
||||
phy_mac_interrupt(priv->phydev,
|
||||
@@ -2713,8 +2719,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/* all other interested interrupts handled in bottom half */
|
||||
status &= (UMAC_IRQ_LINK_EVENT |
|
||||
UMAC_IRQ_MPD_R);
|
||||
status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_MPD_R | UMAC_IRQ_PHY_DET_R);
|
||||
if (status) {
|
||||
/* Save irq status for bottom-half processing. */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
@@ -670,10 +670,10 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld)
|
||||
lld->fr_nsmr_tpte_wr_support = adap->params.fr_nsmr_tpte_wr_support;
|
||||
}
|
||||
|
||||
static void uld_attach(struct adapter *adap, unsigned int uld)
|
||||
static int uld_attach(struct adapter *adap, unsigned int uld)
|
||||
{
|
||||
void *handle;
|
||||
struct cxgb4_lld_info lli;
|
||||
void *handle;
|
||||
|
||||
uld_init(adap, &lli);
|
||||
uld_queue_init(adap, uld, &lli);
|
||||
@@ -683,7 +683,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
|
||||
dev_warn(adap->pdev_dev,
|
||||
"could not attach to the %s driver, error %ld\n",
|
||||
adap->uld[uld].name, PTR_ERR(handle));
|
||||
return;
|
||||
return PTR_ERR(handle);
|
||||
}
|
||||
|
||||
adap->uld[uld].handle = handle;
|
||||
@@ -691,23 +691,24 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
|
||||
|
||||
if (adap->flags & FULL_INIT_DONE)
|
||||
adap->uld[uld].state_change(handle, CXGB4_STATE_UP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgb4_register_uld - register an upper-layer driver
|
||||
* @type: the ULD type
|
||||
* @p: the ULD methods
|
||||
/* cxgb4_register_uld - register an upper-layer driver
|
||||
* @type: the ULD type
|
||||
* @p: the ULD methods
|
||||
*
|
||||
* Registers an upper-layer driver with this driver and notifies the ULD
|
||||
* about any presently available devices that support its type. Returns
|
||||
* %-EBUSY if a ULD of the same type is already registered.
|
||||
* Registers an upper-layer driver with this driver and notifies the ULD
|
||||
* about any presently available devices that support its type. Returns
|
||||
* %-EBUSY if a ULD of the same type is already registered.
|
||||
*/
|
||||
int cxgb4_register_uld(enum cxgb4_uld type,
|
||||
const struct cxgb4_uld_info *p)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int adap_idx = 0;
|
||||
struct adapter *adap;
|
||||
int ret = 0;
|
||||
|
||||
if (type >= CXGB4_ULD_MAX)
|
||||
return -EINVAL;
|
||||
@@ -741,12 +742,16 @@ int cxgb4_register_uld(enum cxgb4_uld type,
|
||||
if (ret)
|
||||
goto free_irq;
|
||||
adap->uld[type] = *p;
|
||||
uld_attach(adap, type);
|
||||
ret = uld_attach(adap, type);
|
||||
if (ret)
|
||||
goto free_txq;
|
||||
adap_idx++;
|
||||
}
|
||||
mutex_unlock(&uld_mutex);
|
||||
return 0;
|
||||
|
||||
free_txq:
|
||||
release_sge_txq_uld(adap, type);
|
||||
free_irq:
|
||||
if (adap->flags & FULL_INIT_DONE)
|
||||
quiesce_rx_uld(adap, type);
|
||||
|
||||
@@ -734,6 +734,18 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
||||
*/
|
||||
nfrags = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
/* Setup HW checksumming */
|
||||
csum_vlan = 0;
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||
!ftgmac100_prep_tx_csum(skb, &csum_vlan))
|
||||
goto drop;
|
||||
|
||||
/* Add VLAN tag */
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
csum_vlan |= FTGMAC100_TXDES1_INS_VLANTAG;
|
||||
csum_vlan |= skb_vlan_tag_get(skb) & 0xffff;
|
||||
}
|
||||
|
||||
/* Get header len */
|
||||
len = skb_headlen(skb);
|
||||
|
||||
@@ -760,19 +772,6 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
||||
if (nfrags == 0)
|
||||
f_ctl_stat |= FTGMAC100_TXDES0_LTS;
|
||||
txdes->txdes3 = cpu_to_le32(map);
|
||||
|
||||
/* Setup HW checksumming */
|
||||
csum_vlan = 0;
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||
!ftgmac100_prep_tx_csum(skb, &csum_vlan))
|
||||
goto drop;
|
||||
|
||||
/* Add VLAN tag */
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
csum_vlan |= FTGMAC100_TXDES1_INS_VLANTAG;
|
||||
csum_vlan |= skb_vlan_tag_get(skb) & 0xffff;
|
||||
}
|
||||
|
||||
txdes->txdes1 = cpu_to_le32(csum_vlan);
|
||||
|
||||
/* Next descriptor */
|
||||
|
||||
@@ -174,6 +174,7 @@ struct hip04_priv {
|
||||
dma_addr_t rx_phys[RX_DESC_NUM];
|
||||
unsigned int rx_head;
|
||||
unsigned int rx_buf_size;
|
||||
unsigned int rx_cnt_remaining;
|
||||
|
||||
struct device_node *phy_node;
|
||||
struct phy_device *phy;
|
||||
@@ -487,7 +488,6 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
|
||||
struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi);
|
||||
struct net_device *ndev = priv->ndev;
|
||||
struct net_device_stats *stats = &ndev->stats;
|
||||
unsigned int cnt = hip04_recv_cnt(priv);
|
||||
struct rx_desc *desc;
|
||||
struct sk_buff *skb;
|
||||
unsigned char *buf;
|
||||
@@ -500,8 +500,8 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
|
||||
|
||||
/* clean up tx descriptors */
|
||||
tx_remaining = hip04_tx_reclaim(ndev, false);
|
||||
|
||||
while (cnt && !last) {
|
||||
priv->rx_cnt_remaining += hip04_recv_cnt(priv);
|
||||
while (priv->rx_cnt_remaining && !last) {
|
||||
buf = priv->rx_buf[priv->rx_head];
|
||||
skb = build_skb(buf, priv->rx_buf_size);
|
||||
if (unlikely(!skb)) {
|
||||
@@ -547,11 +547,13 @@ refill:
|
||||
hip04_set_recv_desc(priv, phys);
|
||||
|
||||
priv->rx_head = RX_NEXT(priv->rx_head);
|
||||
if (rx >= budget)
|
||||
if (rx >= budget) {
|
||||
--priv->rx_cnt_remaining;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (--cnt == 0)
|
||||
cnt = hip04_recv_cnt(priv);
|
||||
if (--priv->rx_cnt_remaining == 0)
|
||||
priv->rx_cnt_remaining += hip04_recv_cnt(priv);
|
||||
}
|
||||
|
||||
if (!(priv->reg_inten & RCV_INT)) {
|
||||
@@ -636,6 +638,7 @@ static int hip04_mac_open(struct net_device *ndev)
|
||||
int i;
|
||||
|
||||
priv->rx_head = 0;
|
||||
priv->rx_cnt_remaining = 0;
|
||||
priv->tx_head = 0;
|
||||
priv->tx_tail = 0;
|
||||
hip04_reset_ppe(priv);
|
||||
|
||||
@@ -471,12 +471,31 @@ void mlx4_init_quotas(struct mlx4_dev *dev)
|
||||
priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
|
||||
}
|
||||
|
||||
static int get_max_gauranteed_vfs_counter(struct mlx4_dev *dev)
|
||||
static int
|
||||
mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,
|
||||
struct resource_allocator *res_alloc,
|
||||
int vf)
|
||||
{
|
||||
/* reduce the sink counter */
|
||||
return (dev->caps.max_counters - 1 -
|
||||
(MLX4_PF_COUNTERS_PER_PORT * MLX4_MAX_PORTS))
|
||||
/ MLX4_MAX_PORTS;
|
||||
struct mlx4_active_ports actv_ports;
|
||||
int ports, counters_guaranteed;
|
||||
|
||||
/* For master, only allocate according to the number of phys ports */
|
||||
if (vf == mlx4_master_func_num(dev))
|
||||
return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;
|
||||
|
||||
/* calculate real number of ports for the VF */
|
||||
actv_ports = mlx4_get_active_ports(dev, vf);
|
||||
ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
|
||||
counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;
|
||||
|
||||
/* If we do not have enough counters for this VF, do not
|
||||
* allocate any for it. '-1' to reduce the sink counter.
|
||||
*/
|
||||
if ((res_alloc->res_reserved + counters_guaranteed) >
|
||||
(dev->caps.max_counters - 1))
|
||||
return 0;
|
||||
|
||||
return counters_guaranteed;
|
||||
}
|
||||
|
||||
int mlx4_init_resource_tracker(struct mlx4_dev *dev)
|
||||
@@ -484,7 +503,6 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
|
||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||
int i, j;
|
||||
int t;
|
||||
int max_vfs_guarantee_counter = get_max_gauranteed_vfs_counter(dev);
|
||||
|
||||
priv->mfunc.master.res_tracker.slave_list =
|
||||
kzalloc(dev->num_slaves * sizeof(struct slave_list),
|
||||
@@ -601,16 +619,8 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
|
||||
break;
|
||||
case RES_COUNTER:
|
||||
res_alloc->quota[t] = dev->caps.max_counters;
|
||||
if (t == mlx4_master_func_num(dev))
|
||||
res_alloc->guaranteed[t] =
|
||||
MLX4_PF_COUNTERS_PER_PORT *
|
||||
MLX4_MAX_PORTS;
|
||||
else if (t <= max_vfs_guarantee_counter)
|
||||
res_alloc->guaranteed[t] =
|
||||
MLX4_VF_COUNTERS_PER_PORT *
|
||||
MLX4_MAX_PORTS;
|
||||
else
|
||||
res_alloc->guaranteed[t] = 0;
|
||||
res_alloc->guaranteed[t] =
|
||||
mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1093,8 +1093,11 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
|
||||
if (unlikely(!MLX5E_TEST_BIT(rq->state, MLX5E_RQ_STATE_ENABLED)))
|
||||
return 0;
|
||||
|
||||
if (cq->decmprs_left)
|
||||
if (cq->decmprs_left) {
|
||||
work_done += mlx5e_decompress_cqes_cont(rq, cq, 0, budget);
|
||||
if (cq->decmprs_left || work_done >= budget)
|
||||
goto out;
|
||||
}
|
||||
|
||||
cqe = mlx5_cqwq_get_cqe(&cq->wq);
|
||||
if (!cqe) {
|
||||
|
||||
@@ -800,6 +800,13 @@ static const struct usb_device_id products[] = {
|
||||
.driver_info = 0,
|
||||
},
|
||||
|
||||
/* ThinkPad USB-C Dock Gen 2 (based on Realtek RTL8153) */
|
||||
{
|
||||
USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0xa387, USB_CLASS_COMM,
|
||||
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
|
||||
.driver_info = 0,
|
||||
},
|
||||
|
||||
/* NVIDIA Tegra USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
|
||||
{
|
||||
USB_DEVICE_AND_INTERFACE_INFO(NVIDIA_VENDOR_ID, 0x09ff, USB_CLASS_COMM,
|
||||
|
||||
@@ -3642,10 +3642,14 @@ static int lan78xx_probe(struct usb_interface *intf,
|
||||
/* driver requires remote-wakeup capability during autosuspend. */
|
||||
intf->needs_remote_wakeup = 1;
|
||||
|
||||
ret = lan78xx_phy_init(dev);
|
||||
if (ret < 0)
|
||||
goto out4;
|
||||
|
||||
ret = register_netdev(netdev);
|
||||
if (ret != 0) {
|
||||
netif_err(dev, probe, netdev, "couldn't register the device\n");
|
||||
goto out4;
|
||||
goto out5;
|
||||
}
|
||||
|
||||
usb_set_intfdata(intf, dev);
|
||||
@@ -3658,14 +3662,10 @@ static int lan78xx_probe(struct usb_interface *intf,
|
||||
pm_runtime_set_autosuspend_delay(&udev->dev,
|
||||
DEFAULT_AUTOSUSPEND_DELAY);
|
||||
|
||||
ret = lan78xx_phy_init(dev);
|
||||
if (ret < 0)
|
||||
goto out5;
|
||||
|
||||
return 0;
|
||||
|
||||
out5:
|
||||
unregister_netdev(netdev);
|
||||
phy_disconnect(netdev->phydev);
|
||||
out4:
|
||||
usb_free_urb(dev->urb_intr);
|
||||
out3:
|
||||
|
||||
@@ -5324,6 +5324,7 @@ static const struct usb_device_id rtl8152_table[] = {
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0xa387)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)},
|
||||
{REALTEK_USB_DEVICE(VENDOR_ID_TPLINK, 0x0601)},
|
||||
|
||||
@@ -2169,8 +2169,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
|
||||
vni = tunnel_id_to_key32(info->key.tun_id);
|
||||
ifindex = 0;
|
||||
dst_cache = &info->dst_cache;
|
||||
if (info->options_len)
|
||||
if (info->options_len) {
|
||||
if (info->options_len < sizeof(*md))
|
||||
goto drop;
|
||||
md = ip_tunnel_info_opts(info);
|
||||
}
|
||||
ttl = info->key.ttl;
|
||||
tos = info->key.tos;
|
||||
label = info->key.label;
|
||||
|
||||
@@ -1002,6 +1002,7 @@ static int __init unittest_data_add(void)
|
||||
of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
|
||||
if (!unittest_data_node) {
|
||||
pr_warn("%s: No tree to attach; not running tests\n", __func__);
|
||||
kfree(unittest_data);
|
||||
return -ENODATA;
|
||||
}
|
||||
of_node_set_flag(unittest_data_node, OF_DETACHED);
|
||||
|
||||
@@ -640,8 +640,8 @@ static int ns2_pinmux_enable(struct pinctrl_dev *pctrl_dev,
|
||||
const struct ns2_pin_function *func;
|
||||
const struct ns2_pin_group *grp;
|
||||
|
||||
if (grp_select > pinctrl->num_groups ||
|
||||
func_select > pinctrl->num_functions)
|
||||
if (grp_select >= pinctrl->num_groups ||
|
||||
func_select >= pinctrl->num_functions)
|
||||
return -EINVAL;
|
||||
|
||||
func = &pinctrl->functions[func_select];
|
||||
|
||||
@@ -475,6 +475,13 @@ static const struct dmi_system_id critclk_systems[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "CB6363"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "SIMATIC IPC227E",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "6ES7647-8B"),
|
||||
},
|
||||
},
|
||||
{ /*sentinel*/ }
|
||||
};
|
||||
|
||||
|
||||
@@ -632,7 +632,13 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
|
||||
|
||||
/* SW2~SW4 high bit check and modify the voltage value table */
|
||||
if (i >= sw_check_start && i <= sw_check_end) {
|
||||
regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
|
||||
ret = regmap_read(pfuze_chip->regmap,
|
||||
desc->vsel_reg, &val);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Fails to read from the register.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val & sw_hi) {
|
||||
if (pfuze_chip->chip_id == PFUZE3000) {
|
||||
desc->volt_table = pfuze3000_sw2hi;
|
||||
|
||||
@@ -173,19 +173,14 @@ static int ti_abb_wait_txdone(struct device *dev, struct ti_abb *abb)
|
||||
while (timeout++ <= abb->settling_time) {
|
||||
status = ti_abb_check_txdone(abb);
|
||||
if (status)
|
||||
break;
|
||||
return 0;
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (timeout > abb->settling_time) {
|
||||
dev_warn_ratelimited(dev,
|
||||
"%s:TRANXDONE timeout(%duS) int=0x%08x\n",
|
||||
__func__, timeout, readl(abb->int_base));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
|
||||
__func__, timeout, readl(abb->int_base));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,19 +200,14 @@ static int ti_abb_clear_all_txdone(struct device *dev, const struct ti_abb *abb)
|
||||
|
||||
status = ti_abb_check_txdone(abb);
|
||||
if (!status)
|
||||
break;
|
||||
return 0;
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (timeout > abb->settling_time) {
|
||||
dev_warn_ratelimited(dev,
|
||||
"%s:TRANXDONE timeout(%duS) int=0x%08x\n",
|
||||
__func__, timeout, readl(abb->int_base));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
dev_warn_ratelimited(dev, "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
|
||||
__func__, timeout, readl(abb->int_base));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -966,7 +966,7 @@ config SCSI_SNI_53C710
|
||||
|
||||
config 53C700_LE_ON_BE
|
||||
bool
|
||||
depends on SCSI_LASI700
|
||||
depends on SCSI_LASI700 || SCSI_SNI_53C710
|
||||
default y
|
||||
|
||||
config SCSI_STEX
|
||||
|
||||
@@ -523,6 +523,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
unsigned int tpg_desc_tbl_off;
|
||||
unsigned char orig_transition_tmo;
|
||||
unsigned long flags;
|
||||
bool transitioning_sense = false;
|
||||
|
||||
if (!pg->expiry) {
|
||||
unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
|
||||
@@ -567,13 +568,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
goto retry;
|
||||
}
|
||||
/*
|
||||
* Retry on ALUA state transition or if any
|
||||
* UNIT ATTENTION occurred.
|
||||
* If the array returns with 'ALUA state transition'
|
||||
* sense code here it cannot return RTPG data during
|
||||
* transition. So set the state to 'transitioning' directly.
|
||||
*/
|
||||
if (sense_hdr.sense_key == NOT_READY &&
|
||||
sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
|
||||
err = SCSI_DH_RETRY;
|
||||
else if (sense_hdr.sense_key == UNIT_ATTENTION)
|
||||
sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
|
||||
transitioning_sense = true;
|
||||
goto skip_rtpg;
|
||||
}
|
||||
/*
|
||||
* Retry on any other UNIT ATTENTION occurred.
|
||||
*/
|
||||
if (sense_hdr.sense_key == UNIT_ATTENTION)
|
||||
err = SCSI_DH_RETRY;
|
||||
if (err == SCSI_DH_RETRY &&
|
||||
pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
|
||||
@@ -661,7 +668,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
off = 8 + (desc[7] * 4);
|
||||
}
|
||||
|
||||
skip_rtpg:
|
||||
spin_lock_irqsave(&pg->lock, flags);
|
||||
if (transitioning_sense)
|
||||
pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
|
||||
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
|
||||
ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
|
||||
|
||||
@@ -78,10 +78,8 @@ static int snirm710_probe(struct platform_device *dev)
|
||||
|
||||
base = res->start;
|
||||
hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
|
||||
if (!hostdata) {
|
||||
dev_printk(KERN_ERR, dev, "Failed to allocate host data\n");
|
||||
if (!hostdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hostdata->dev = &dev->dev;
|
||||
dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
|
||||
|
||||
@@ -1151,27 +1151,6 @@ passthrough_parse_cdb(struct se_cmd *cmd,
|
||||
struct se_device *dev = cmd->se_dev;
|
||||
unsigned int size;
|
||||
|
||||
/*
|
||||
* Clear a lun set in the cdb if the initiator talking to use spoke
|
||||
* and old standards version, as we can't assume the underlying device
|
||||
* won't choke up on it.
|
||||
*/
|
||||
switch (cdb[0]) {
|
||||
case READ_10: /* SBC - RDProtect */
|
||||
case READ_12: /* SBC - RDProtect */
|
||||
case READ_16: /* SBC - RDProtect */
|
||||
case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
|
||||
case VERIFY: /* SBC - VRProtect */
|
||||
case VERIFY_16: /* SBC - VRProtect */
|
||||
case WRITE_VERIFY: /* SBC - VRProtect */
|
||||
case WRITE_VERIFY_12: /* SBC - VRProtect */
|
||||
case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
|
||||
break;
|
||||
default:
|
||||
cdb[1] &= 0x1f; /* clear logical unit number */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* For REPORT LUNS we always need to emulate the response, for everything
|
||||
* else, pass it up.
|
||||
|
||||
@@ -1210,6 +1210,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
|
||||
struct cifsInodeInfo {
|
||||
bool can_cache_brlcks;
|
||||
struct list_head llist; /* locks helb by this inode */
|
||||
/*
|
||||
* NOTE: Some code paths call down_read(lock_sem) twice, so
|
||||
* we must always use use cifs_down_write() instead of down_write()
|
||||
* for this semaphore to avoid deadlocks.
|
||||
*/
|
||||
struct rw_semaphore lock_sem; /* protect the fields above */
|
||||
/* BB add in lists for dirty pages i.e. write caching info for oplock */
|
||||
struct list_head openFileList;
|
||||
|
||||
@@ -149,6 +149,7 @@ extern int cifs_unlock_range(struct cifsFileInfo *cfile,
|
||||
struct file_lock *flock, const unsigned int xid);
|
||||
extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
|
||||
|
||||
extern void cifs_down_write(struct rw_semaphore *sem);
|
||||
extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
|
||||
struct file *file,
|
||||
struct tcon_link *tlink,
|
||||
|
||||
@@ -280,6 +280,13 @@ cifs_has_mand_locks(struct cifsInodeInfo *cinode)
|
||||
return has_locks;
|
||||
}
|
||||
|
||||
void
|
||||
cifs_down_write(struct rw_semaphore *sem)
|
||||
{
|
||||
while (!down_write_trylock(sem))
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
struct cifsFileInfo *
|
||||
cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
|
||||
struct tcon_link *tlink, __u32 oplock)
|
||||
@@ -305,7 +312,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
|
||||
INIT_LIST_HEAD(&fdlocks->locks);
|
||||
fdlocks->cfile = cfile;
|
||||
cfile->llist = fdlocks;
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
list_add(&fdlocks->llist, &cinode->llist);
|
||||
up_write(&cinode->lock_sem);
|
||||
|
||||
@@ -457,7 +464,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
|
||||
* Delete any outstanding lock records. We'll lose them when the file
|
||||
* is closed anyway.
|
||||
*/
|
||||
down_write(&cifsi->lock_sem);
|
||||
cifs_down_write(&cifsi->lock_sem);
|
||||
list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
|
||||
list_del(&li->llist);
|
||||
cifs_del_lock_waiters(li);
|
||||
@@ -1011,7 +1018,7 @@ static void
|
||||
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
|
||||
{
|
||||
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
list_add_tail(&lock->llist, &cfile->llist->locks);
|
||||
up_write(&cinode->lock_sem);
|
||||
}
|
||||
@@ -1033,7 +1040,7 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
|
||||
|
||||
try_again:
|
||||
exist = false;
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
|
||||
exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
|
||||
lock->type, &conf_lock, CIFS_LOCK_OP);
|
||||
@@ -1055,7 +1062,7 @@ try_again:
|
||||
(lock->blist.next == &lock->blist));
|
||||
if (!rc)
|
||||
goto try_again;
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
list_del_init(&lock->blist);
|
||||
}
|
||||
|
||||
@@ -1108,7 +1115,7 @@ cifs_posix_lock_set(struct file *file, struct file_lock *flock)
|
||||
return rc;
|
||||
|
||||
try_again:
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
if (!cinode->can_cache_brlcks) {
|
||||
up_write(&cinode->lock_sem);
|
||||
return rc;
|
||||
@@ -1314,7 +1321,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
|
||||
int rc = 0;
|
||||
|
||||
/* we are going to update can_cache_brlcks here - need a write access */
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
if (!cinode->can_cache_brlcks) {
|
||||
up_write(&cinode->lock_sem);
|
||||
return rc;
|
||||
@@ -1505,7 +1512,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
for (i = 0; i < 2; i++) {
|
||||
cur = buf;
|
||||
num = 0;
|
||||
|
||||
@@ -139,7 +139,7 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
||||
|
||||
cur = buf;
|
||||
|
||||
down_write(&cinode->lock_sem);
|
||||
cifs_down_write(&cinode->lock_sem);
|
||||
list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
|
||||
if (flock->fl_start > li->offset ||
|
||||
(flock->fl_start + length) <
|
||||
|
||||
@@ -313,6 +313,29 @@ static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
|
||||
return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
|
||||
}
|
||||
|
||||
/**
|
||||
* gfpflags_normal_context - is gfp_flags a normal sleepable context?
|
||||
* @gfp_flags: gfp_flags to test
|
||||
*
|
||||
* Test whether @gfp_flags indicates that the allocation is from the
|
||||
* %current context and allowed to sleep.
|
||||
*
|
||||
* An allocation being allowed to block doesn't mean it owns the %current
|
||||
* context. When direct reclaim path tries to allocate memory, the
|
||||
* allocation context is nested inside whatever %current was doing at the
|
||||
* time of the original allocation. The nested allocation may be allowed
|
||||
* to block but modifying anything %current owns can corrupt the outer
|
||||
* context's expectations.
|
||||
*
|
||||
* %true result from this function indicates that the allocation context
|
||||
* can sleep and use anything that's associated with %current.
|
||||
*/
|
||||
static inline bool gfpflags_normal_context(const gfp_t gfp_flags)
|
||||
{
|
||||
return (gfp_flags & (__GFP_DIRECT_RECLAIM | __GFP_MEMALLOC)) ==
|
||||
__GFP_DIRECT_RECLAIM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
#define OPT_ZONE_HIGHMEM ZONE_HIGHMEM
|
||||
#else
|
||||
|
||||
@@ -1228,7 +1228,8 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6
|
||||
return skb->hash;
|
||||
}
|
||||
|
||||
__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb);
|
||||
__u32 skb_get_hash_perturb(const struct sk_buff *skb,
|
||||
const siphash_key_t *perturb);
|
||||
|
||||
static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
|
||||
{
|
||||
@@ -1345,6 +1346,19 @@ static inline int skb_queue_empty(const struct sk_buff_head *list)
|
||||
return list->next == (const struct sk_buff *) list;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_queue_empty_lockless - check if a queue is empty
|
||||
* @list: queue head
|
||||
*
|
||||
* Returns true if the queue is empty, false otherwise.
|
||||
* This variant can be used in lockless contexts.
|
||||
*/
|
||||
static inline bool skb_queue_empty_lockless(const struct sk_buff_head *list)
|
||||
{
|
||||
return READ_ONCE(list->next) == (const struct sk_buff *) list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* skb_queue_is_last - check if skb is the last entry in the queue
|
||||
* @list: queue head
|
||||
@@ -1709,9 +1723,11 @@ static inline void __skb_insert(struct sk_buff *newsk,
|
||||
struct sk_buff *prev, struct sk_buff *next,
|
||||
struct sk_buff_head *list)
|
||||
{
|
||||
newsk->next = next;
|
||||
newsk->prev = prev;
|
||||
next->prev = prev->next = newsk;
|
||||
/* see skb_queue_empty_lockless() for the opposite READ_ONCE() */
|
||||
WRITE_ONCE(newsk->next, next);
|
||||
WRITE_ONCE(newsk->prev, prev);
|
||||
WRITE_ONCE(next->prev, newsk);
|
||||
WRITE_ONCE(prev->next, newsk);
|
||||
list->qlen++;
|
||||
}
|
||||
|
||||
@@ -1722,11 +1738,11 @@ static inline void __skb_queue_splice(const struct sk_buff_head *list,
|
||||
struct sk_buff *first = list->next;
|
||||
struct sk_buff *last = list->prev;
|
||||
|
||||
first->prev = prev;
|
||||
prev->next = first;
|
||||
WRITE_ONCE(first->prev, prev);
|
||||
WRITE_ONCE(prev->next, first);
|
||||
|
||||
last->next = next;
|
||||
next->prev = last;
|
||||
WRITE_ONCE(last->next, next);
|
||||
WRITE_ONCE(next->prev, last);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1867,8 +1883,8 @@ static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
|
||||
next = skb->next;
|
||||
prev = skb->prev;
|
||||
skb->next = skb->prev = NULL;
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
WRITE_ONCE(next->prev, prev);
|
||||
WRITE_ONCE(prev->next, next);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -134,7 +134,7 @@ static inline void skb_mark_napi_id(struct sk_buff *skb,
|
||||
static inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
sk->sk_napi_id = skb->napi_id;
|
||||
WRITE_ONCE(sk->sk_napi_id, skb->napi_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -143,8 +143,8 @@ static inline void sk_mark_napi_id_once(struct sock *sk,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
if (!sk->sk_napi_id)
|
||||
sk->sk_napi_id = skb->napi_id;
|
||||
if (!READ_ONCE(sk->sk_napi_id))
|
||||
WRITE_ONCE(sk->sk_napi_id, skb->napi_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <uapi/linux/if_ether.h>
|
||||
|
||||
/**
|
||||
@@ -229,7 +230,7 @@ struct flow_dissector {
|
||||
struct flow_keys {
|
||||
struct flow_dissector_key_control control;
|
||||
#define FLOW_KEYS_HASH_START_FIELD basic
|
||||
struct flow_dissector_key_basic basic;
|
||||
struct flow_dissector_key_basic basic __aligned(SIPHASH_ALIGNMENT);
|
||||
struct flow_dissector_key_tags tags;
|
||||
struct flow_dissector_key_vlan vlan;
|
||||
struct flow_dissector_key_keyid keyid;
|
||||
|
||||
@@ -70,7 +70,7 @@ struct fq {
|
||||
struct list_head backlogs;
|
||||
spinlock_t lock;
|
||||
u32 flows_cnt;
|
||||
u32 perturbation;
|
||||
siphash_key_t perturbation;
|
||||
u32 limit;
|
||||
u32 memory_limit;
|
||||
u32 memory_usage;
|
||||
|
||||
@@ -105,7 +105,7 @@ static struct fq_flow *fq_flow_classify(struct fq *fq,
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
hash = skb_get_hash_perturb(skb, fq->perturbation);
|
||||
hash = skb_get_hash_perturb(skb, &fq->perturbation);
|
||||
idx = reciprocal_scale(hash, fq->flows_cnt);
|
||||
flow = &fq->flows[idx];
|
||||
|
||||
@@ -255,7 +255,7 @@ static int fq_init(struct fq *fq, int flows_cnt)
|
||||
INIT_LIST_HEAD(&fq->backlogs);
|
||||
spin_lock_init(&fq->lock);
|
||||
fq->flows_cnt = max_t(u32, flows_cnt, 1);
|
||||
fq->perturbation = prandom_u32();
|
||||
get_random_bytes(&fq->perturbation, sizeof(fq->perturbation));
|
||||
fq->quantum = 300;
|
||||
fq->limit = 8192;
|
||||
fq->memory_limit = 16 << 20; /* 16 MBytes */
|
||||
|
||||
@@ -916,8 +916,8 @@ static inline void sk_incoming_cpu_update(struct sock *sk)
|
||||
{
|
||||
int cpu = raw_smp_processor_id();
|
||||
|
||||
if (unlikely(sk->sk_incoming_cpu != cpu))
|
||||
sk->sk_incoming_cpu = cpu;
|
||||
if (unlikely(READ_ONCE(sk->sk_incoming_cpu) != cpu))
|
||||
WRITE_ONCE(sk->sk_incoming_cpu, cpu);
|
||||
}
|
||||
|
||||
static inline void sock_rps_record_flow_hash(__u32 hash)
|
||||
@@ -2131,12 +2131,17 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp,
|
||||
* sk_page_frag - return an appropriate page_frag
|
||||
* @sk: socket
|
||||
*
|
||||
* If socket allocation mode allows current thread to sleep, it means its
|
||||
* safe to use the per task page_frag instead of the per socket one.
|
||||
* Use the per task page_frag instead of the per socket one for
|
||||
* optimization when we know that we're in the normal context and owns
|
||||
* everything that's associated with %current.
|
||||
*
|
||||
* gfpflags_allow_blocking() isn't enough here as direct reclaim may nest
|
||||
* inside other socket operations and end up recursing into sk_page_frag()
|
||||
* while it's already in use.
|
||||
*/
|
||||
static inline struct page_frag *sk_page_frag(struct sock *sk)
|
||||
{
|
||||
if (gfpflags_allow_blocking(sk->sk_allocation))
|
||||
if (gfpflags_normal_context(sk->sk_allocation))
|
||||
return ¤t->task_frag;
|
||||
|
||||
return &sk->sk_frag;
|
||||
|
||||
@@ -433,10 +433,11 @@ void wake_q_add(struct wake_q_head *head, struct task_struct *task)
|
||||
* its already queued (either by us or someone else) and will get the
|
||||
* wakeup due to that.
|
||||
*
|
||||
* This cmpxchg() implies a full barrier, which pairs with the write
|
||||
* barrier implied by the wakeup in wake_up_q().
|
||||
* In order to ensure that a pending wakeup will observe our pending
|
||||
* state, even in the failed case, an explicit smp_mb() must be used.
|
||||
*/
|
||||
if (cmpxchg(&node->next, NULL, WAKE_Q_TAIL))
|
||||
smp_mb__before_atomic();
|
||||
if (cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL))
|
||||
return;
|
||||
|
||||
head->count++;
|
||||
|
||||
@@ -667,7 +667,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
mask |= POLLHUP;
|
||||
|
||||
/* readable? */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* writable? */
|
||||
|
||||
@@ -489,7 +489,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
|
||||
if (sk->sk_state == BT_LISTEN)
|
||||
return bt_accept_poll(sk);
|
||||
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR |
|
||||
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
||||
|
||||
@@ -499,7 +499,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
|
||||
if (sk->sk_shutdown == SHUTDOWN_MASK)
|
||||
mask |= POLLHUP;
|
||||
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
if (sk->sk_state == BT_CLOSED)
|
||||
|
||||
@@ -953,7 +953,7 @@ static unsigned int caif_poll(struct file *file,
|
||||
mask |= POLLRDHUP;
|
||||
|
||||
/* readable? */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue) ||
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue) ||
|
||||
(sk->sk_shutdown & RCV_SHUTDOWN))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ int __skb_wait_for_more_packets(struct sock *sk, int *err, long *timeo_p,
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
if (sk->sk_receive_queue.prev != skb)
|
||||
if (READ_ONCE(sk->sk_receive_queue.prev) != skb)
|
||||
goto out;
|
||||
|
||||
/* Socket shut down? */
|
||||
@@ -281,7 +281,7 @@ struct sk_buff *__skb_try_recv_datagram(struct sock *sk, unsigned int flags,
|
||||
break;
|
||||
|
||||
sk_busy_loop(sk, flags & MSG_DONTWAIT);
|
||||
} while (sk->sk_receive_queue.prev != *last);
|
||||
} while (READ_ONCE(sk->sk_receive_queue.prev) != *last);
|
||||
|
||||
error = -EAGAIN;
|
||||
|
||||
@@ -844,7 +844,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
|
||||
mask = 0;
|
||||
|
||||
/* exceptional events? */
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR |
|
||||
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
||||
|
||||
@@ -854,7 +854,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
|
||||
mask |= POLLHUP;
|
||||
|
||||
/* readable? */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* Connection-based need to check for termination and startup */
|
||||
|
||||
@@ -1450,11 +1450,13 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
|
||||
|
||||
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
|
||||
struct ethtool_wolinfo wol;
|
||||
|
||||
if (!dev->ethtool_ops->get_wol)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(&wol, 0, sizeof(struct ethtool_wolinfo));
|
||||
wol.cmd = ETHTOOL_GWOL;
|
||||
dev->ethtool_ops->get_wol(dev, &wol);
|
||||
|
||||
if (copy_to_user(useraddr, &wol, sizeof(wol)))
|
||||
|
||||
@@ -889,45 +889,34 @@ out_bad:
|
||||
}
|
||||
EXPORT_SYMBOL(__skb_flow_dissect);
|
||||
|
||||
static u32 hashrnd __read_mostly;
|
||||
static siphash_key_t hashrnd __read_mostly;
|
||||
static __always_inline void __flow_hash_secret_init(void)
|
||||
{
|
||||
net_get_random_once(&hashrnd, sizeof(hashrnd));
|
||||
}
|
||||
|
||||
static __always_inline u32 __flow_hash_words(const u32 *words, u32 length,
|
||||
u32 keyval)
|
||||
static const void *flow_keys_hash_start(const struct flow_keys *flow)
|
||||
{
|
||||
return jhash2(words, length, keyval);
|
||||
}
|
||||
|
||||
static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow)
|
||||
{
|
||||
const void *p = flow;
|
||||
|
||||
BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
|
||||
return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET);
|
||||
BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
|
||||
return &flow->FLOW_KEYS_HASH_START_FIELD;
|
||||
}
|
||||
|
||||
static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
|
||||
{
|
||||
size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
|
||||
BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
|
||||
BUILD_BUG_ON(offsetof(typeof(*flow), addrs) !=
|
||||
sizeof(*flow) - sizeof(flow->addrs));
|
||||
size_t len = offsetof(typeof(*flow), addrs) - FLOW_KEYS_HASH_OFFSET;
|
||||
|
||||
switch (flow->control.addr_type) {
|
||||
case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
diff -= sizeof(flow->addrs.v4addrs);
|
||||
len += sizeof(flow->addrs.v4addrs);
|
||||
break;
|
||||
case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
diff -= sizeof(flow->addrs.v6addrs);
|
||||
len += sizeof(flow->addrs.v6addrs);
|
||||
break;
|
||||
case FLOW_DISSECTOR_KEY_TIPC_ADDRS:
|
||||
diff -= sizeof(flow->addrs.tipcaddrs);
|
||||
len += sizeof(flow->addrs.tipcaddrs);
|
||||
break;
|
||||
}
|
||||
return (sizeof(*flow) - diff) / sizeof(u32);
|
||||
return len;
|
||||
}
|
||||
|
||||
__be32 flow_get_u32_src(const struct flow_keys *flow)
|
||||
@@ -993,14 +982,15 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
|
||||
static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
|
||||
const siphash_key_t *keyval)
|
||||
{
|
||||
u32 hash;
|
||||
|
||||
__flow_hash_consistentify(keys);
|
||||
|
||||
hash = __flow_hash_words(flow_keys_hash_start(keys),
|
||||
flow_keys_hash_length(keys), keyval);
|
||||
hash = siphash(flow_keys_hash_start(keys),
|
||||
flow_keys_hash_length(keys), keyval);
|
||||
if (!hash)
|
||||
hash = 1;
|
||||
|
||||
@@ -1010,12 +1000,13 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
|
||||
u32 flow_hash_from_keys(struct flow_keys *keys)
|
||||
{
|
||||
__flow_hash_secret_init();
|
||||
return __flow_hash_from_keys(keys, hashrnd);
|
||||
return __flow_hash_from_keys(keys, &hashrnd);
|
||||
}
|
||||
EXPORT_SYMBOL(flow_hash_from_keys);
|
||||
|
||||
static inline u32 ___skb_get_hash(const struct sk_buff *skb,
|
||||
struct flow_keys *keys, u32 keyval)
|
||||
struct flow_keys *keys,
|
||||
const siphash_key_t *keyval)
|
||||
{
|
||||
skb_flow_dissect_flow_keys(skb, keys,
|
||||
FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
|
||||
@@ -1063,7 +1054,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
|
||||
NULL, 0, 0, 0,
|
||||
FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
|
||||
|
||||
return __flow_hash_from_keys(&keys, hashrnd);
|
||||
return __flow_hash_from_keys(&keys, &hashrnd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
|
||||
|
||||
@@ -1083,13 +1074,14 @@ void __skb_get_hash(struct sk_buff *skb)
|
||||
|
||||
__flow_hash_secret_init();
|
||||
|
||||
hash = ___skb_get_hash(skb, &keys, hashrnd);
|
||||
hash = ___skb_get_hash(skb, &keys, &hashrnd);
|
||||
|
||||
__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
|
||||
}
|
||||
EXPORT_SYMBOL(__skb_get_hash);
|
||||
|
||||
__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb)
|
||||
__u32 skb_get_hash_perturb(const struct sk_buff *skb,
|
||||
const siphash_key_t *perturb)
|
||||
{
|
||||
struct flow_keys keys;
|
||||
|
||||
|
||||
@@ -1039,7 +1039,7 @@ set_rcvbuf:
|
||||
break;
|
||||
|
||||
case SO_INCOMING_CPU:
|
||||
sk->sk_incoming_cpu = val;
|
||||
WRITE_ONCE(sk->sk_incoming_cpu, val);
|
||||
break;
|
||||
|
||||
case SO_CNX_ADVICE:
|
||||
@@ -1351,7 +1351,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case SO_INCOMING_CPU:
|
||||
v.val = sk->sk_incoming_cpu;
|
||||
v.val = READ_ONCE(sk->sk_incoming_cpu);
|
||||
break;
|
||||
|
||||
case SO_MEMINFO:
|
||||
@@ -3381,7 +3381,7 @@ bool sk_busy_loop_end(void *p, unsigned long start_time)
|
||||
{
|
||||
struct sock *sk = p;
|
||||
|
||||
return !skb_queue_empty(&sk->sk_receive_queue) ||
|
||||
return !skb_queue_empty_lockless(&sk->sk_receive_queue) ||
|
||||
sk_busy_loop_timeout(sk, start_time);
|
||||
}
|
||||
EXPORT_SYMBOL(sk_busy_loop_end);
|
||||
|
||||
@@ -121,7 +121,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
inet->inet_daddr,
|
||||
inet->inet_sport,
|
||||
inet->inet_dport);
|
||||
inet->inet_id = dp->dccps_iss ^ jiffies;
|
||||
inet->inet_id = prandom_u32();
|
||||
|
||||
err = dccp_connect(sk);
|
||||
rt = NULL;
|
||||
@@ -417,7 +417,7 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk,
|
||||
RCU_INIT_POINTER(newinet->inet_opt, rcu_dereference(ireq->ireq_opt));
|
||||
newinet->mc_index = inet_iif(skb);
|
||||
newinet->mc_ttl = ip_hdr(skb)->ttl;
|
||||
newinet->inet_id = jiffies;
|
||||
newinet->inet_id = prandom_u32();
|
||||
|
||||
if (dst == NULL && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL)
|
||||
goto put_and_exit;
|
||||
|
||||
@@ -62,7 +62,7 @@ static struct dsa_switch_tree *dsa_add_dst(u32 tree)
|
||||
return NULL;
|
||||
dst->tree = tree;
|
||||
INIT_LIST_HEAD(&dst->list);
|
||||
list_add_tail(&dsa_switch_trees, &dst->list);
|
||||
list_add_tail(&dst->list, &dsa_switch_trees);
|
||||
kref_init(&dst->refcount);
|
||||
|
||||
return dst;
|
||||
|
||||
@@ -75,7 +75,7 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
|
||||
inet->inet_dport = usin->sin_port;
|
||||
sk->sk_state = TCP_ESTABLISHED;
|
||||
sk_set_txhash(sk);
|
||||
inet->inet_id = jiffies;
|
||||
inet->inet_id = prandom_u32();
|
||||
|
||||
sk_dst_set(sk, &rt->dst);
|
||||
err = 0;
|
||||
|
||||
@@ -193,7 +193,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
||||
if (sk->sk_bound_dev_if)
|
||||
score += 4;
|
||||
}
|
||||
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
||||
if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
|
||||
score++;
|
||||
}
|
||||
return score;
|
||||
|
||||
@@ -592,6 +592,9 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
truncate = true;
|
||||
}
|
||||
|
||||
if (tun_info->options_len < sizeof(*md))
|
||||
goto err_free_rt;
|
||||
|
||||
md = ip_tunnel_info_opts(tun_info);
|
||||
if (!md)
|
||||
goto err_free_rt;
|
||||
|
||||
@@ -574,7 +574,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
}
|
||||
/* This barrier is coupled with smp_wmb() in tcp_reset() */
|
||||
smp_rmb();
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR;
|
||||
|
||||
return mask;
|
||||
@@ -1787,7 +1787,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
|
||||
if (unlikely(flags & MSG_ERRQUEUE))
|
||||
return inet_recv_error(sk, msg, len, addr_len);
|
||||
|
||||
if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) &&
|
||||
if (sk_can_busy_loop(sk) && skb_queue_empty_lockless(&sk->sk_receive_queue) &&
|
||||
(sk->sk_state == TCP_ESTABLISHED))
|
||||
sk_busy_loop(sk, nonblock);
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
inet->inet_daddr);
|
||||
}
|
||||
|
||||
inet->inet_id = tp->write_seq ^ jiffies;
|
||||
inet->inet_id = prandom_u32();
|
||||
|
||||
if (tcp_fastopen_defer_connect(sk, &err))
|
||||
return err;
|
||||
@@ -1368,7 +1368,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
|
||||
inet_csk(newsk)->icsk_ext_hdr_len = 0;
|
||||
if (inet_opt)
|
||||
inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
|
||||
newinet->inet_id = newtp->write_seq ^ jiffies;
|
||||
newinet->inet_id = prandom_u32();
|
||||
|
||||
if (!dst) {
|
||||
dst = inet_csk_route_child_sock(sk, newsk, req);
|
||||
|
||||
@@ -419,7 +419,7 @@ static int compute_score(struct sock *sk, struct net *net,
|
||||
score += 4;
|
||||
}
|
||||
|
||||
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
||||
if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
|
||||
score++;
|
||||
return score;
|
||||
}
|
||||
@@ -1195,6 +1195,20 @@ static void udp_set_dev_scratch(struct sk_buff *skb)
|
||||
scratch->_tsize_state |= UDP_SKB_IS_STATELESS;
|
||||
}
|
||||
|
||||
static void udp_skb_csum_unnecessary_set(struct sk_buff *skb)
|
||||
{
|
||||
/* We come here after udp_lib_checksum_complete() returned 0.
|
||||
* This means that __skb_checksum_complete() might have
|
||||
* set skb->csum_valid to 1.
|
||||
* On 64bit platforms, we can set csum_unnecessary
|
||||
* to true, but only if the skb is not shared.
|
||||
*/
|
||||
#if BITS_PER_LONG == 64
|
||||
if (!skb_shared(skb))
|
||||
udp_skb_scratch(skb)->csum_unnecessary = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int udp_skb_truesize(struct sk_buff *skb)
|
||||
{
|
||||
return udp_skb_scratch(skb)->_tsize_state & ~UDP_SKB_IS_STATELESS;
|
||||
@@ -1430,10 +1444,7 @@ static struct sk_buff *__first_packet_length(struct sock *sk,
|
||||
*total += skb->truesize;
|
||||
kfree_skb(skb);
|
||||
} else {
|
||||
/* the csum related bits could be changed, refresh
|
||||
* the scratch area
|
||||
*/
|
||||
udp_set_dev_scratch(skb);
|
||||
udp_skb_csum_unnecessary_set(skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1457,7 +1468,7 @@ static int first_packet_length(struct sock *sk)
|
||||
|
||||
spin_lock_bh(&rcvq->lock);
|
||||
skb = __first_packet_length(sk, rcvq, &total);
|
||||
if (!skb && !skb_queue_empty(sk_queue)) {
|
||||
if (!skb && !skb_queue_empty_lockless(sk_queue)) {
|
||||
spin_lock(&sk_queue->lock);
|
||||
skb_queue_splice_tail_init(sk_queue, rcvq);
|
||||
spin_unlock(&sk_queue->lock);
|
||||
@@ -1532,7 +1543,7 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags,
|
||||
return skb;
|
||||
}
|
||||
|
||||
if (skb_queue_empty(sk_queue)) {
|
||||
if (skb_queue_empty_lockless(sk_queue)) {
|
||||
spin_unlock_bh(&queue->lock);
|
||||
goto busy_check;
|
||||
}
|
||||
@@ -1559,7 +1570,7 @@ busy_check:
|
||||
break;
|
||||
|
||||
sk_busy_loop(sk, flags & MSG_DONTWAIT);
|
||||
} while (!skb_queue_empty(sk_queue));
|
||||
} while (!skb_queue_empty_lockless(sk_queue));
|
||||
|
||||
/* sk_queue is empty, reader_queue may contain peeked packets */
|
||||
} while (timeo &&
|
||||
@@ -2539,7 +2550,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
unsigned int mask = datagram_poll(file, sock, wait);
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
if (!skb_queue_empty(&udp_sk(sk)->reader_queue))
|
||||
if (!skb_queue_empty_lockless(&udp_sk(sk)->reader_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
sock_rps_record_flow(sk);
|
||||
|
||||
@@ -118,7 +118,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
||||
if (sk->sk_bound_dev_if)
|
||||
score++;
|
||||
}
|
||||
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
||||
if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
|
||||
score++;
|
||||
}
|
||||
return score;
|
||||
|
||||
@@ -170,7 +170,7 @@ static int compute_score(struct sock *sk, struct net *net,
|
||||
score++;
|
||||
}
|
||||
|
||||
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
||||
if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
|
||||
score++;
|
||||
|
||||
return score;
|
||||
|
||||
@@ -567,11 +567,11 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
|
||||
if (sk->sk_state == LLCP_LISTEN)
|
||||
return llcp_accept_poll(sk);
|
||||
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR |
|
||||
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
||||
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
if (sk->sk_state == LLCP_CLOSED)
|
||||
|
||||
@@ -352,9 +352,9 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
|
||||
|
||||
if (sk->sk_state == TCP_CLOSE)
|
||||
return POLLERR;
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (!skb_queue_empty(&pn->ctrlreq_queue))
|
||||
if (!skb_queue_empty_lockless(&pn->ctrlreq_queue))
|
||||
mask |= POLLPRI;
|
||||
if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
|
||||
return POLLHUP;
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 2013 Nandita Dukkipati <nanditad@google.com>
|
||||
*/
|
||||
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
@@ -125,7 +125,7 @@ struct wdrr_bucket {
|
||||
|
||||
struct hhf_sched_data {
|
||||
struct wdrr_bucket buckets[WDRR_BUCKET_CNT];
|
||||
u32 perturbation; /* hash perturbation */
|
||||
siphash_key_t perturbation; /* hash perturbation */
|
||||
u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
|
||||
u32 drop_overlimit; /* number of times max qdisc packet
|
||||
* limit was hit
|
||||
@@ -263,7 +263,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)
|
||||
}
|
||||
|
||||
/* Get hashed flow-id of the skb. */
|
||||
hash = skb_get_hash_perturb(skb, q->perturbation);
|
||||
hash = skb_get_hash_perturb(skb, &q->perturbation);
|
||||
|
||||
/* Check if this packet belongs to an already established HH flow. */
|
||||
flow_pos = hash & HHF_BIT_MASK;
|
||||
@@ -578,7 +578,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt)
|
||||
|
||||
sch->limit = 1000;
|
||||
q->quantum = psched_mtu(qdisc_dev(sch));
|
||||
q->perturbation = prandom_u32();
|
||||
get_random_bytes(&q->perturbation, sizeof(q->perturbation));
|
||||
INIT_LIST_HEAD(&q->new_buckets);
|
||||
INIT_LIST_HEAD(&q->old_buckets);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/pkt_cls.h>
|
||||
@@ -49,7 +49,7 @@ struct sfb_bucket {
|
||||
* (Section 4.4 of SFB reference : moving hash functions)
|
||||
*/
|
||||
struct sfb_bins {
|
||||
u32 perturbation; /* jhash perturbation */
|
||||
siphash_key_t perturbation; /* siphash key */
|
||||
struct sfb_bucket bins[SFB_LEVELS][SFB_NUMBUCKETS];
|
||||
};
|
||||
|
||||
@@ -221,7 +221,8 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
|
||||
|
||||
static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
|
||||
{
|
||||
q->bins[slot].perturbation = prandom_u32();
|
||||
get_random_bytes(&q->bins[slot].perturbation,
|
||||
sizeof(q->bins[slot].perturbation));
|
||||
}
|
||||
|
||||
static void sfb_swap_slot(struct sfb_sched_data *q)
|
||||
@@ -317,9 +318,9 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||
/* If using external classifiers, get result and record it. */
|
||||
if (!sfb_classify(skb, fl, &ret, &salt))
|
||||
goto other_drop;
|
||||
sfbhash = jhash_1word(salt, q->bins[slot].perturbation);
|
||||
sfbhash = siphash_1u32(salt, &q->bins[slot].perturbation);
|
||||
} else {
|
||||
sfbhash = skb_get_hash_perturb(skb, q->bins[slot].perturbation);
|
||||
sfbhash = skb_get_hash_perturb(skb, &q->bins[slot].perturbation);
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +356,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||
/* Inelastic flow */
|
||||
if (q->double_buffering) {
|
||||
sfbhash = skb_get_hash_perturb(skb,
|
||||
q->bins[slot].perturbation);
|
||||
&q->bins[slot].perturbation);
|
||||
if (!sfbhash)
|
||||
sfbhash = 1;
|
||||
sfb_skb_cb(skb)->hashes[slot] = sfbhash;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/netlink.h>
|
||||
@@ -121,7 +121,7 @@ struct sfq_sched_data {
|
||||
u8 headdrop;
|
||||
u8 maxdepth; /* limit of packets per flow */
|
||||
|
||||
u32 perturbation;
|
||||
siphash_key_t perturbation;
|
||||
u8 cur_depth; /* depth of longest slot */
|
||||
u8 flags;
|
||||
unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
|
||||
@@ -160,7 +160,7 @@ static inline struct sfq_head *sfq_dep_head(struct sfq_sched_data *q, sfq_index
|
||||
static unsigned int sfq_hash(const struct sfq_sched_data *q,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
return skb_get_hash_perturb(skb, q->perturbation) & (q->divisor - 1);
|
||||
return skb_get_hash_perturb(skb, &q->perturbation) & (q->divisor - 1);
|
||||
}
|
||||
|
||||
static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
|
||||
@@ -609,9 +609,11 @@ static void sfq_perturbation(unsigned long arg)
|
||||
struct Qdisc *sch = (struct Qdisc *)arg;
|
||||
struct sfq_sched_data *q = qdisc_priv(sch);
|
||||
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
||||
siphash_key_t nkey;
|
||||
|
||||
get_random_bytes(&nkey, sizeof(nkey));
|
||||
spin_lock(root_lock);
|
||||
q->perturbation = prandom_u32();
|
||||
q->perturbation = nkey;
|
||||
if (!q->filter_list && q->tail)
|
||||
sfq_rehash(sch);
|
||||
spin_unlock(root_lock);
|
||||
@@ -690,7 +692,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
|
||||
del_timer(&q->perturb_timer);
|
||||
if (q->perturb_period) {
|
||||
mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
|
||||
q->perturbation = prandom_u32();
|
||||
get_random_bytes(&q->perturbation, sizeof(q->perturbation));
|
||||
}
|
||||
sch_tree_unlock(sch);
|
||||
kfree(p);
|
||||
@@ -746,7 +748,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
|
||||
q->quantum = psched_mtu(qdisc_dev(sch));
|
||||
q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
|
||||
q->perturb_period = 0;
|
||||
q->perturbation = prandom_u32();
|
||||
get_random_bytes(&q->perturbation, sizeof(q->perturbation));
|
||||
|
||||
if (opt) {
|
||||
int err = sfq_change(sch, opt);
|
||||
|
||||
@@ -7371,7 +7371,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
mask = 0;
|
||||
|
||||
/* Is there any exceptional events? */
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR |
|
||||
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
@@ -7380,7 +7380,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
mask |= POLLHUP;
|
||||
|
||||
/* Is it readable? Reconsider this code with TCP-style support. */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* The association is either gone or not ready. */
|
||||
@@ -7716,7 +7716,7 @@ struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
|
||||
if (sk_can_busy_loop(sk)) {
|
||||
sk_busy_loop(sk, noblock);
|
||||
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -8136,7 +8136,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
|
||||
newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
|
||||
newinet->inet_dport = htons(asoc->peer.port);
|
||||
newinet->pmtudisc = inet->pmtudisc;
|
||||
newinet->inet_id = asoc->next_tsn ^ jiffies;
|
||||
newinet->inet_id = prandom_u32();
|
||||
|
||||
newinet->uc_ttl = inet->uc_ttl;
|
||||
newinet->mc_loop = 1;
|
||||
|
||||
@@ -714,14 +714,14 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
|
||||
/* fall thru' */
|
||||
case TIPC_LISTEN:
|
||||
case TIPC_CONNECTING:
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= (POLLIN | POLLRDNORM);
|
||||
break;
|
||||
case TIPC_OPEN:
|
||||
if (!tsk->cong_link_cnt)
|
||||
mask |= POLLOUT;
|
||||
if (tipc_sk_type_connectionless(sk) &&
|
||||
(!skb_queue_empty(&sk->sk_receive_queue)))
|
||||
(!skb_queue_empty_lockless(&sk->sk_receive_queue)))
|
||||
mask |= (POLLIN | POLLRDNORM);
|
||||
break;
|
||||
case TIPC_DISCONNECTING:
|
||||
|
||||
@@ -2665,7 +2665,7 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
|
||||
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
|
||||
|
||||
/* readable? */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* Connection-based need to check for termination and startup */
|
||||
@@ -2693,7 +2693,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
|
||||
mask = 0;
|
||||
|
||||
/* exceptional events? */
|
||||
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
||||
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
||||
mask |= POLLERR |
|
||||
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
||||
|
||||
@@ -2703,7 +2703,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
|
||||
mask |= POLLHUP;
|
||||
|
||||
/* readable? */
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue))
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
/* Connection-based need to check for termination and startup */
|
||||
|
||||
@@ -880,7 +880,7 @@ static unsigned int vsock_poll(struct file *file, struct socket *sock,
|
||||
* the queue and write as long as the socket isn't shutdown for
|
||||
* sending.
|
||||
*/
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue) ||
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue) ||
|
||||
(sk->sk_shutdown & RCV_SHUTDOWN)) {
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
}
|
||||
|
||||
@@ -1169,8 +1169,7 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
|
||||
}
|
||||
|
||||
if (in) {
|
||||
if (in & WMFW_CTL_FLAG_READABLE)
|
||||
out |= rd;
|
||||
out |= rd;
|
||||
if (in & WMFW_CTL_FLAG_WRITEABLE)
|
||||
out |= wr;
|
||||
if (in & WMFW_CTL_FLAG_VOLATILE)
|
||||
|
||||
@@ -676,7 +676,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
|
||||
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not register PCM\n");
|
||||
return ret;
|
||||
goto err_suspend;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2454,6 +2454,7 @@ static int build_cl_output(char *cl_sort, bool no_source)
|
||||
bool add_sym = false;
|
||||
bool add_dso = false;
|
||||
bool add_src = false;
|
||||
int ret = 0;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
@@ -2472,7 +2473,8 @@ static int build_cl_output(char *cl_sort, bool no_source)
|
||||
add_dso = true;
|
||||
} else if (strcmp(tok, "offset")) {
|
||||
pr_err("unrecognized sort token: %s\n", tok);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2495,13 +2497,15 @@ static int build_cl_output(char *cl_sort, bool no_source)
|
||||
add_sym ? "symbol," : "",
|
||||
add_dso ? "dso," : "",
|
||||
add_src ? "cl_srcline," : "",
|
||||
"node") < 0)
|
||||
return -ENOMEM;
|
||||
"node") < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
c2c.show_src = add_src;
|
||||
|
||||
err:
|
||||
free(buf);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setup_coalesce(const char *coalesce, bool no_source)
|
||||
|
||||
@@ -687,6 +687,7 @@ static char *compact_gfp_flags(char *gfp_flags)
|
||||
new = realloc(new_flags, len + strlen(cpt) + 2);
|
||||
if (new == NULL) {
|
||||
free(new_flags);
|
||||
free(orig_flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ static void test(int *rcv_fds, int count, int proto)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int epfd, i, test_fd;
|
||||
uint16_t test_family;
|
||||
int test_family;
|
||||
socklen_t len;
|
||||
|
||||
epfd = epoll_create(1);
|
||||
@@ -146,6 +146,7 @@ static void test(int *rcv_fds, int count, int proto)
|
||||
send_from_v4(proto);
|
||||
|
||||
test_fd = receive_once(epfd, proto);
|
||||
len = sizeof(test_family);
|
||||
if (getsockopt(test_fd, SOL_SOCKET, SO_DOMAIN, &test_family, &len))
|
||||
error(1, errno, "failed to read socket domain");
|
||||
if (test_family != AF_INET)
|
||||
|
||||
@@ -3,6 +3,7 @@ noarg:
|
||||
$(MAKE) -C ../
|
||||
|
||||
TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao
|
||||
TEST_GEN_PROGS_EXTENDED := tlbie_test
|
||||
TEST_GEN_FILES := tempfile
|
||||
|
||||
include ../../lib.mk
|
||||
@@ -14,3 +15,4 @@ $(OUTPUT)/prot_sao: ../utils.c
|
||||
$(OUTPUT)/tempfile:
|
||||
dd if=/dev/zero of=$@ bs=64k count=1
|
||||
|
||||
$(OUTPUT)/tlbie_test: LDLIBS += -lpthread
|
||||
|
||||
734
tools/testing/selftests/powerpc/mm/tlbie_test.c
Normal file
734
tools/testing/selftests/powerpc/mm/tlbie_test.c
Normal file
@@ -0,0 +1,734 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Copyright 2019, Nick Piggin, Gautham R. Shenoy, Aneesh Kumar K.V, IBM Corp.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Test tlbie/mtpidr race. We have 4 threads doing flush/load/compare/store
|
||||
* sequence in a loop. The same threads also rung a context switch task
|
||||
* that does sched_yield() in loop.
|
||||
*
|
||||
* The snapshot thread mark the mmap area PROT_READ in between, make a copy
|
||||
* and copy it back to the original area. This helps us to detect if any
|
||||
* store continued to happen after we marked the memory PROT_READ.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/futex.h>
|
||||
#include <unistd.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
static inline void dcbf(volatile unsigned int *addr)
|
||||
{
|
||||
__asm__ __volatile__ ("dcbf %y0; sync" : : "Z"(*(unsigned char *)addr) : "memory");
|
||||
}
|
||||
|
||||
static void err_msg(char *msg)
|
||||
{
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
printf("=================================\n");
|
||||
printf(" Error: %s\n", msg);
|
||||
printf(" %s", ctime(&now));
|
||||
printf("=================================\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char *map1;
|
||||
static char *map2;
|
||||
static pid_t rim_process_pid;
|
||||
|
||||
/*
|
||||
* A "rim-sequence" is defined to be the sequence of the following
|
||||
* operations performed on a memory word:
|
||||
* 1) FLUSH the contents of that word.
|
||||
* 2) LOAD the contents of that word.
|
||||
* 3) COMPARE the contents of that word with the content that was
|
||||
* previously stored at that word
|
||||
* 4) STORE new content into that word.
|
||||
*
|
||||
* The threads in this test that perform the rim-sequence are termed
|
||||
* as rim_threads.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A "corruption" is defined to be the failed COMPARE operation in a
|
||||
* rim-sequence.
|
||||
*
|
||||
* A rim_thread that detects a corruption informs about it to all the
|
||||
* other rim_threads, and the mem_snapshot thread.
|
||||
*/
|
||||
static volatile unsigned int corruption_found;
|
||||
|
||||
/*
|
||||
* This defines the maximum number of rim_threads in this test.
|
||||
*
|
||||
* The THREAD_ID_BITS denote the number of bits required
|
||||
* to represent the thread_ids [0..MAX_THREADS - 1].
|
||||
* We are being a bit paranoid here and set it to 8 bits,
|
||||
* though 6 bits suffice.
|
||||
*
|
||||
*/
|
||||
#define MAX_THREADS 64
|
||||
#define THREAD_ID_BITS 8
|
||||
#define THREAD_ID_MASK ((1 << THREAD_ID_BITS) - 1)
|
||||
static unsigned int rim_thread_ids[MAX_THREADS];
|
||||
static pthread_t rim_threads[MAX_THREADS];
|
||||
|
||||
|
||||
/*
|
||||
* Each rim_thread works on an exclusive "chunk" of size
|
||||
* RIM_CHUNK_SIZE.
|
||||
*
|
||||
* The ith rim_thread works on the ith chunk.
|
||||
*
|
||||
* The ith chunk begins at
|
||||
* map1 + (i * RIM_CHUNK_SIZE)
|
||||
*/
|
||||
#define RIM_CHUNK_SIZE 1024
|
||||
#define BITS_PER_BYTE 8
|
||||
#define WORD_SIZE (sizeof(unsigned int))
|
||||
#define WORD_BITS (WORD_SIZE * BITS_PER_BYTE)
|
||||
#define WORDS_PER_CHUNK (RIM_CHUNK_SIZE/WORD_SIZE)
|
||||
|
||||
static inline char *compute_chunk_start_addr(unsigned int thread_id)
|
||||
{
|
||||
char *chunk_start;
|
||||
|
||||
chunk_start = (char *)((unsigned long)map1 +
|
||||
(thread_id * RIM_CHUNK_SIZE));
|
||||
|
||||
return chunk_start;
|
||||
}
|
||||
|
||||
/*
|
||||
* The "word-offset" of a word-aligned address inside a chunk, is
|
||||
* defined to be the number of words that precede the address in that
|
||||
* chunk.
|
||||
*
|
||||
* WORD_OFFSET_BITS denote the number of bits required to represent
|
||||
* the word-offsets of all the word-aligned addresses of a chunk.
|
||||
*/
|
||||
#define WORD_OFFSET_BITS (__builtin_ctz(WORDS_PER_CHUNK))
|
||||
#define WORD_OFFSET_MASK ((1 << WORD_OFFSET_BITS) - 1)
|
||||
|
||||
static inline unsigned int compute_word_offset(char *start, unsigned int *addr)
|
||||
{
|
||||
unsigned int delta_bytes, ret;
|
||||
delta_bytes = (unsigned long)addr - (unsigned long)start;
|
||||
|
||||
ret = delta_bytes/WORD_SIZE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* A "sweep" is defined to be the sequential execution of the
|
||||
* rim-sequence by a rim_thread on its chunk one word at a time,
|
||||
* starting from the first word of its chunk and ending with the last
|
||||
* word of its chunk.
|
||||
*
|
||||
* Each sweep of a rim_thread is uniquely identified by a sweep_id.
|
||||
* SWEEP_ID_BITS denote the number of bits required to represent
|
||||
* the sweep_ids of rim_threads.
|
||||
*
|
||||
* As to why SWEEP_ID_BITS are computed as a function of THREAD_ID_BITS,
|
||||
* WORD_OFFSET_BITS, and WORD_BITS, see the "store-pattern" below.
|
||||
*/
|
||||
#define SWEEP_ID_BITS (WORD_BITS - (THREAD_ID_BITS + WORD_OFFSET_BITS))
|
||||
#define SWEEP_ID_MASK ((1 << SWEEP_ID_BITS) - 1)
|
||||
|
||||
/*
|
||||
* A "store-pattern" is the word-pattern that is stored into a word
|
||||
* location in the 4)STORE step of the rim-sequence.
|
||||
*
|
||||
* In the store-pattern, we shall encode:
|
||||
*
|
||||
* - The thread-id of the rim_thread performing the store
|
||||
* (The most significant THREAD_ID_BITS)
|
||||
*
|
||||
* - The word-offset of the address into which the store is being
|
||||
* performed (The next WORD_OFFSET_BITS)
|
||||
*
|
||||
* - The sweep_id of the current sweep in which the store is
|
||||
* being performed. (The lower SWEEP_ID_BITS)
|
||||
*
|
||||
* Store Pattern: 32 bits
|
||||
* |------------------|--------------------|---------------------------------|
|
||||
* | Thread id | Word offset | sweep_id |
|
||||
* |------------------|--------------------|---------------------------------|
|
||||
* THREAD_ID_BITS WORD_OFFSET_BITS SWEEP_ID_BITS
|
||||
*
|
||||
* In the store pattern, the (Thread-id + Word-offset) uniquely identify the
|
||||
* address to which the store is being performed i.e,
|
||||
* address == map1 +
|
||||
* (Thread-id * RIM_CHUNK_SIZE) + (Word-offset * WORD_SIZE)
|
||||
*
|
||||
* And the sweep_id in the store pattern identifies the time when the
|
||||
* store was performed by the rim_thread.
|
||||
*
|
||||
* We shall use this property in the 3)COMPARE step of the
|
||||
* rim-sequence.
|
||||
*/
|
||||
#define SWEEP_ID_SHIFT 0
|
||||
#define WORD_OFFSET_SHIFT (SWEEP_ID_BITS)
|
||||
#define THREAD_ID_SHIFT (WORD_OFFSET_BITS + SWEEP_ID_BITS)
|
||||
|
||||
/*
|
||||
* Compute the store pattern for a given thread with id @tid, at
|
||||
* location @addr in the sweep identified by @sweep_id
|
||||
*/
|
||||
static inline unsigned int compute_store_pattern(unsigned int tid,
|
||||
unsigned int *addr,
|
||||
unsigned int sweep_id)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
char *start = compute_chunk_start_addr(tid);
|
||||
unsigned int word_offset = compute_word_offset(start, addr);
|
||||
|
||||
ret += (tid & THREAD_ID_MASK) << THREAD_ID_SHIFT;
|
||||
ret += (word_offset & WORD_OFFSET_MASK) << WORD_OFFSET_SHIFT;
|
||||
ret += (sweep_id & SWEEP_ID_MASK) << SWEEP_ID_SHIFT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Extract the thread-id from the given store-pattern */
|
||||
static inline unsigned int extract_tid(unsigned int pattern)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
ret = (pattern >> THREAD_ID_SHIFT) & THREAD_ID_MASK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Extract the word-offset from the given store-pattern */
|
||||
static inline unsigned int extract_word_offset(unsigned int pattern)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
ret = (pattern >> WORD_OFFSET_SHIFT) & WORD_OFFSET_MASK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Extract the sweep-id from the given store-pattern */
|
||||
static inline unsigned int extract_sweep_id(unsigned int pattern)
|
||||
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
ret = (pattern >> SWEEP_ID_SHIFT) & SWEEP_ID_MASK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* *
|
||||
* Logging the output of the verification *
|
||||
* *
|
||||
************************************************************/
|
||||
#define LOGDIR_NAME_SIZE 100
|
||||
static char logdir[LOGDIR_NAME_SIZE];
|
||||
|
||||
static FILE *fp[MAX_THREADS];
|
||||
static const char logfilename[] ="Thread-%02d-Chunk";
|
||||
|
||||
static inline void start_verification_log(unsigned int tid,
|
||||
unsigned int *addr,
|
||||
unsigned int cur_sweep_id,
|
||||
unsigned int prev_sweep_id)
|
||||
{
|
||||
FILE *f;
|
||||
char logfile[30];
|
||||
char path[LOGDIR_NAME_SIZE + 30];
|
||||
char separator[2] = "/";
|
||||
char *chunk_start = compute_chunk_start_addr(tid);
|
||||
unsigned int size = RIM_CHUNK_SIZE;
|
||||
|
||||
sprintf(logfile, logfilename, tid);
|
||||
strcpy(path, logdir);
|
||||
strcat(path, separator);
|
||||
strcat(path, logfile);
|
||||
f = fopen(path, "w");
|
||||
|
||||
if (!f) {
|
||||
err_msg("Unable to create logfile\n");
|
||||
}
|
||||
|
||||
fp[tid] = f;
|
||||
|
||||
fprintf(f, "----------------------------------------------------------\n");
|
||||
fprintf(f, "PID = %d\n", rim_process_pid);
|
||||
fprintf(f, "Thread id = %02d\n", tid);
|
||||
fprintf(f, "Chunk Start Addr = 0x%016lx\n", (unsigned long)chunk_start);
|
||||
fprintf(f, "Chunk Size = %d\n", size);
|
||||
fprintf(f, "Next Store Addr = 0x%016lx\n", (unsigned long)addr);
|
||||
fprintf(f, "Current sweep-id = 0x%08x\n", cur_sweep_id);
|
||||
fprintf(f, "Previous sweep-id = 0x%08x\n", prev_sweep_id);
|
||||
fprintf(f, "----------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
static inline void log_anamoly(unsigned int tid, unsigned int *addr,
|
||||
unsigned int expected, unsigned int observed)
|
||||
{
|
||||
FILE *f = fp[tid];
|
||||
|
||||
fprintf(f, "Thread %02d: Addr 0x%lx: Expected 0x%x, Observed 0x%x\n",
|
||||
tid, (unsigned long)addr, expected, observed);
|
||||
fprintf(f, "Thread %02d: Expected Thread id = %02d\n", tid, extract_tid(expected));
|
||||
fprintf(f, "Thread %02d: Observed Thread id = %02d\n", tid, extract_tid(observed));
|
||||
fprintf(f, "Thread %02d: Expected Word offset = %03d\n", tid, extract_word_offset(expected));
|
||||
fprintf(f, "Thread %02d: Observed Word offset = %03d\n", tid, extract_word_offset(observed));
|
||||
fprintf(f, "Thread %02d: Expected sweep-id = 0x%x\n", tid, extract_sweep_id(expected));
|
||||
fprintf(f, "Thread %02d: Observed sweep-id = 0x%x\n", tid, extract_sweep_id(observed));
|
||||
fprintf(f, "----------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
static inline void end_verification_log(unsigned int tid, unsigned nr_anamolies)
|
||||
{
|
||||
FILE *f = fp[tid];
|
||||
char logfile[30];
|
||||
char path[LOGDIR_NAME_SIZE + 30];
|
||||
char separator[] = "/";
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (nr_anamolies == 0) {
|
||||
remove(path);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(logfile, logfilename, tid);
|
||||
strcpy(path, logdir);
|
||||
strcat(path, separator);
|
||||
strcat(path, logfile);
|
||||
|
||||
printf("Thread %02d chunk has %d corrupted words. For details check %s\n",
|
||||
tid, nr_anamolies, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* When a COMPARE step of a rim-sequence fails, the rim_thread informs
|
||||
* everyone else via the shared_memory pointed to by
|
||||
* corruption_found variable. On seeing this, every thread verifies the
|
||||
* content of its chunk as follows.
|
||||
*
|
||||
* Suppose a thread identified with @tid was about to store (but not
|
||||
* yet stored) to @next_store_addr in its current sweep identified
|
||||
* @cur_sweep_id. Let @prev_sweep_id indicate the previous sweep_id.
|
||||
*
|
||||
* This implies that for all the addresses @addr < @next_store_addr,
|
||||
* Thread @tid has already performed a store as part of its current
|
||||
* sweep. Hence we expect the content of such @addr to be:
|
||||
* |-------------------------------------------------|
|
||||
* | tid | word_offset(addr) | cur_sweep_id |
|
||||
* |-------------------------------------------------|
|
||||
*
|
||||
* Since Thread @tid is yet to perform stores on address
|
||||
* @next_store_addr and above, we expect the content of such an
|
||||
* address @addr to be:
|
||||
* |-------------------------------------------------|
|
||||
* | tid | word_offset(addr) | prev_sweep_id |
|
||||
* |-------------------------------------------------|
|
||||
*
|
||||
* The verifier function @verify_chunk does this verification and logs
|
||||
* any anamolies that it finds.
|
||||
*/
|
||||
static void verify_chunk(unsigned int tid, unsigned int *next_store_addr,
|
||||
unsigned int cur_sweep_id,
|
||||
unsigned int prev_sweep_id)
|
||||
{
|
||||
unsigned int *iter_ptr;
|
||||
unsigned int size = RIM_CHUNK_SIZE;
|
||||
unsigned int expected;
|
||||
unsigned int observed;
|
||||
char *chunk_start = compute_chunk_start_addr(tid);
|
||||
|
||||
int nr_anamolies = 0;
|
||||
|
||||
start_verification_log(tid, next_store_addr,
|
||||
cur_sweep_id, prev_sweep_id);
|
||||
|
||||
for (iter_ptr = (unsigned int *)chunk_start;
|
||||
(unsigned long)iter_ptr < (unsigned long)chunk_start + size;
|
||||
iter_ptr++) {
|
||||
unsigned int expected_sweep_id;
|
||||
|
||||
if (iter_ptr < next_store_addr) {
|
||||
expected_sweep_id = cur_sweep_id;
|
||||
} else {
|
||||
expected_sweep_id = prev_sweep_id;
|
||||
}
|
||||
|
||||
expected = compute_store_pattern(tid, iter_ptr, expected_sweep_id);
|
||||
|
||||
dcbf((volatile unsigned int*)iter_ptr); //Flush before reading
|
||||
observed = *iter_ptr;
|
||||
|
||||
if (observed != expected) {
|
||||
nr_anamolies++;
|
||||
log_anamoly(tid, iter_ptr, expected, observed);
|
||||
}
|
||||
}
|
||||
|
||||
end_verification_log(tid, nr_anamolies);
|
||||
}
|
||||
|
||||
static void set_pthread_cpu(pthread_t th, int cpu)
|
||||
{
|
||||
cpu_set_t run_cpu_mask;
|
||||
struct sched_param param;
|
||||
|
||||
CPU_ZERO(&run_cpu_mask);
|
||||
CPU_SET(cpu, &run_cpu_mask);
|
||||
pthread_setaffinity_np(th, sizeof(cpu_set_t), &run_cpu_mask);
|
||||
|
||||
param.sched_priority = 1;
|
||||
if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
|
||||
/* haven't reproduced with this setting, it kills random preemption which may be a factor */
|
||||
fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void set_mycpu(int cpu)
|
||||
{
|
||||
cpu_set_t run_cpu_mask;
|
||||
struct sched_param param;
|
||||
|
||||
CPU_ZERO(&run_cpu_mask);
|
||||
CPU_SET(cpu, &run_cpu_mask);
|
||||
sched_setaffinity(0, sizeof(cpu_set_t), &run_cpu_mask);
|
||||
|
||||
param.sched_priority = 1;
|
||||
if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
|
||||
fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
|
||||
}
|
||||
}
|
||||
|
||||
static volatile int segv_wait;
|
||||
|
||||
static void segv_handler(int signo, siginfo_t *info, void *extra)
|
||||
{
|
||||
while (segv_wait) {
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void set_segv_handler(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = segv_handler;
|
||||
|
||||
if (sigaction(SIGSEGV, &sa, NULL) == -1) {
|
||||
perror("sigaction");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int timeout = 0;
|
||||
/*
|
||||
* This function is executed by every rim_thread.
|
||||
*
|
||||
* This function performs sweeps over the exclusive chunks of the
|
||||
* rim_threads executing the rim-sequence one word at a time.
|
||||
*/
|
||||
static void *rim_fn(void *arg)
|
||||
{
|
||||
unsigned int tid = *((unsigned int *)arg);
|
||||
|
||||
int size = RIM_CHUNK_SIZE;
|
||||
char *chunk_start = compute_chunk_start_addr(tid);
|
||||
|
||||
unsigned int prev_sweep_id;
|
||||
unsigned int cur_sweep_id = 0;
|
||||
|
||||
/* word access */
|
||||
unsigned int pattern = cur_sweep_id;
|
||||
unsigned int *pattern_ptr = &pattern;
|
||||
unsigned int *w_ptr, read_data;
|
||||
|
||||
set_segv_handler();
|
||||
|
||||
/*
|
||||
* Let us initialize the chunk:
|
||||
*
|
||||
* Each word-aligned address addr in the chunk,
|
||||
* is initialized to :
|
||||
* |-------------------------------------------------|
|
||||
* | tid | word_offset(addr) | 0 |
|
||||
* |-------------------------------------------------|
|
||||
*/
|
||||
for (w_ptr = (unsigned int *)chunk_start;
|
||||
(unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
|
||||
w_ptr++) {
|
||||
|
||||
*pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
|
||||
*w_ptr = *pattern_ptr;
|
||||
}
|
||||
|
||||
while (!corruption_found && !timeout) {
|
||||
prev_sweep_id = cur_sweep_id;
|
||||
cur_sweep_id = cur_sweep_id + 1;
|
||||
|
||||
for (w_ptr = (unsigned int *)chunk_start;
|
||||
(unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
|
||||
w_ptr++) {
|
||||
unsigned int old_pattern;
|
||||
|
||||
/*
|
||||
* Compute the pattern that we would have
|
||||
* stored at this location in the previous
|
||||
* sweep.
|
||||
*/
|
||||
old_pattern = compute_store_pattern(tid, w_ptr, prev_sweep_id);
|
||||
|
||||
/*
|
||||
* FLUSH:Ensure that we flush the contents of
|
||||
* the cache before loading
|
||||
*/
|
||||
dcbf((volatile unsigned int*)w_ptr); //Flush
|
||||
|
||||
/* LOAD: Read the value */
|
||||
read_data = *w_ptr; //Load
|
||||
|
||||
/*
|
||||
* COMPARE: Is it the same as what we had stored
|
||||
* in the previous sweep ? It better be!
|
||||
*/
|
||||
if (read_data != old_pattern) {
|
||||
/* No it isn't! Tell everyone */
|
||||
corruption_found = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before performing a store, let us check if
|
||||
* any rim_thread has found a corruption.
|
||||
*/
|
||||
if (corruption_found || timeout) {
|
||||
/*
|
||||
* Yes. Someone (including us!) has found
|
||||
* a corruption :(
|
||||
*
|
||||
* Let us verify that our chunk is
|
||||
* correct.
|
||||
*/
|
||||
/* But first, let us allow the dust to settle down! */
|
||||
verify_chunk(tid, w_ptr, cur_sweep_id, prev_sweep_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the new pattern that we are going
|
||||
* to write to this location
|
||||
*/
|
||||
*pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
|
||||
|
||||
/*
|
||||
* STORE: Now let us write this pattern into
|
||||
* the location
|
||||
*/
|
||||
*w_ptr = *pattern_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long start_cpu = 0;
|
||||
static unsigned long nrthreads = 4;
|
||||
|
||||
static pthread_t mem_snapshot_thread;
|
||||
|
||||
static void *mem_snapshot_fn(void *arg)
|
||||
{
|
||||
int page_size = getpagesize();
|
||||
size_t size = page_size;
|
||||
void *tmp = malloc(size);
|
||||
|
||||
while (!corruption_found && !timeout) {
|
||||
/* Stop memory migration once corruption is found */
|
||||
segv_wait = 1;
|
||||
|
||||
mprotect(map1, size, PROT_READ);
|
||||
|
||||
/*
|
||||
* Load from the working alias (map1). Loading from map2
|
||||
* also fails.
|
||||
*/
|
||||
memcpy(tmp, map1, size);
|
||||
|
||||
/*
|
||||
* Stores must go via map2 which has write permissions, but
|
||||
* the corrupted data tends to be seen in the snapshot buffer,
|
||||
* so corruption does not appear to be introduced at the
|
||||
* copy-back via map2 alias here.
|
||||
*/
|
||||
memcpy(map2, tmp, size);
|
||||
/*
|
||||
* Before releasing other threads, must ensure the copy
|
||||
* back to
|
||||
*/
|
||||
asm volatile("sync" ::: "memory");
|
||||
mprotect(map1, size, PROT_READ|PROT_WRITE);
|
||||
asm volatile("sync" ::: "memory");
|
||||
segv_wait = 0;
|
||||
|
||||
usleep(1); /* This value makes a big difference */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void alrm_sighandler(int sig)
|
||||
{
|
||||
timeout = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int page_size = getpagesize();
|
||||
time_t now;
|
||||
int i, dir_error;
|
||||
pthread_attr_t attr;
|
||||
key_t shm_key = (key_t) getpid();
|
||||
int shmid, run_time = 20 * 60;
|
||||
struct sigaction sa_alrm;
|
||||
|
||||
snprintf(logdir, LOGDIR_NAME_SIZE,
|
||||
"/tmp/logdir-%u", (unsigned int)getpid());
|
||||
while ((c = getopt(argc, argv, "r:hn:l:t:")) != -1) {
|
||||
switch(c) {
|
||||
case 'r':
|
||||
start_cpu = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'h':
|
||||
printf("%s [-r <start_cpu>] [-n <nrthreads>] [-l <logdir>] [-t <timeout>]\n", argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'n':
|
||||
nrthreads = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'l':
|
||||
strncpy(logdir, optarg, LOGDIR_NAME_SIZE - 1);
|
||||
break;
|
||||
case 't':
|
||||
run_time = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
default:
|
||||
printf("invalid option\n");
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nrthreads > MAX_THREADS)
|
||||
nrthreads = MAX_THREADS;
|
||||
|
||||
shmid = shmget(shm_key, page_size, IPC_CREAT|0666);
|
||||
if (shmid < 0) {
|
||||
err_msg("Failed shmget\n");
|
||||
}
|
||||
|
||||
map1 = shmat(shmid, NULL, 0);
|
||||
if (map1 == (void *) -1) {
|
||||
err_msg("Failed shmat");
|
||||
}
|
||||
|
||||
map2 = shmat(shmid, NULL, 0);
|
||||
if (map2 == (void *) -1) {
|
||||
err_msg("Failed shmat");
|
||||
}
|
||||
|
||||
dir_error = mkdir(logdir, 0755);
|
||||
|
||||
if (dir_error) {
|
||||
err_msg("Failed mkdir");
|
||||
}
|
||||
|
||||
printf("start_cpu list:%lu\n", start_cpu);
|
||||
printf("number of worker threads:%lu + 1 snapshot thread\n", nrthreads);
|
||||
printf("Allocated address:0x%016lx + secondary map:0x%016lx\n", (unsigned long)map1, (unsigned long)map2);
|
||||
printf("logdir at : %s\n", logdir);
|
||||
printf("Timeout: %d seconds\n", run_time);
|
||||
|
||||
time(&now);
|
||||
printf("=================================\n");
|
||||
printf(" Starting Test\n");
|
||||
printf(" %s", ctime(&now));
|
||||
printf("=================================\n");
|
||||
|
||||
for (i = 0; i < nrthreads; i++) {
|
||||
if (1 && !fork()) {
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
set_mycpu(start_cpu + i);
|
||||
for (;;)
|
||||
sched_yield();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sa_alrm.sa_handler = &alrm_sighandler;
|
||||
sigemptyset(&sa_alrm.sa_mask);
|
||||
sa_alrm.sa_flags = 0;
|
||||
|
||||
if (sigaction(SIGALRM, &sa_alrm, 0) == -1) {
|
||||
err_msg("Failed signal handler registration\n");
|
||||
}
|
||||
|
||||
alarm(run_time);
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
for (i = 0; i < nrthreads; i++) {
|
||||
rim_thread_ids[i] = i;
|
||||
pthread_create(&rim_threads[i], &attr, rim_fn, &rim_thread_ids[i]);
|
||||
set_pthread_cpu(rim_threads[i], start_cpu + i);
|
||||
}
|
||||
|
||||
pthread_create(&mem_snapshot_thread, &attr, mem_snapshot_fn, map1);
|
||||
set_pthread_cpu(mem_snapshot_thread, start_cpu + i);
|
||||
|
||||
|
||||
pthread_join(mem_snapshot_thread, NULL);
|
||||
for (i = 0; i < nrthreads; i++) {
|
||||
pthread_join(rim_threads[i], NULL);
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
time(&now);
|
||||
printf("=================================\n");
|
||||
printf(" Data Corruption Detected\n");
|
||||
printf(" %s", ctime(&now));
|
||||
printf(" See logfiles in %s\n", logdir);
|
||||
printf("=================================\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user