Merge 806381e1a2 ("Merge tag 'powerpc-6.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux") into android-mainline
Steps on the way to v6.17-rc1 Change-Id: I0a9a23ee0a486d4e1ddcf56257954e323a834375 Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
commit
42d3f1efd8
137 files changed
+5120
-1031
No files matched your search
@@ -673,6 +673,7 @@ Muchun Song <muchun.song@linux.dev> <smuchun@gmail.com>
|
||||
Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com>
|
||||
Rudolf Marek <R.Marek@sh.cvut.cz>
|
||||
Rui Saraiva <rmps@joel.ist.utl.pt>
|
||||
Sachin Mokashi <sachin.mokashi@intel.com> <sachinx.mokashi@intel.com>
|
||||
Sachin P Sant <ssant@in.ibm.com>
|
||||
Sai Prakash Ranjan <quic_saipraka@quicinc.com> <saiprakash.ranjan@codeaurora.org>
|
||||
Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
|
||||
|
||||
@@ -131,3 +131,59 @@ Get IO accounting for pid 1, it works only with -p::
|
||||
linuxrc: read=65536, write=0, cancelled_write=0
|
||||
|
||||
The above command can be used with -v to get more debug information.
|
||||
|
||||
After the system starts, use `delaytop` to get the system-wide delay information,
|
||||
which includes system-wide PSI information and Top-N high-latency tasks.
|
||||
|
||||
`delaytop` supports sorting by CPU latency in descending order by default,
|
||||
displays the top 20 high-latency tasks by default, and refreshes the latency
|
||||
data every 2 seconds by default.
|
||||
|
||||
Get PSI information and Top-N tasks delay, since system boot::
|
||||
|
||||
bash# ./delaytop
|
||||
System Pressure Information: (avg10/avg60/avg300/total)
|
||||
CPU some: 0.0%/ 0.0%/ 0.0%/ 345(ms)
|
||||
CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
|
||||
Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
|
||||
Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms)
|
||||
IO full: 0.0%/ 0.0%/ 0.0%/ 65(ms)
|
||||
IO some: 0.0%/ 0.0%/ 0.0%/ 79(ms)
|
||||
IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
|
||||
Top 20 processes (sorted by CPU delay):
|
||||
PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms)
|
||||
----------------------------------------------------------------------------------------------
|
||||
161 161 zombie_memcg_re 1.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
130 130 blkcg_punt_bio 1.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
444 444 scsi_tmf_0 0.73 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1280 1280 rsyslogd 0.53 0.04 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
12 12 ksoftirqd/0 0.47 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1277 1277 nbd-server 0.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
308 308 kworker/2:2-sys 0.41 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
55 55 netns 0.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1187 1187 acpid 0.31 0.03 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
6184 6184 kworker/1:2-sys 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
186 186 kaluad 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
18 18 ksoftirqd/1 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
185 185 kmpath_rdacd 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
190 190 kstrp 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
2759 2759 agetty 0.20 0.03 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1190 1190 kworker/0:3-sys 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1272 1272 sshd 0.15 0.04 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
1156 1156 license 0.15 0.11 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
134 134 md 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
6142 6142 kworker/3:2-xfs 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
|
||||
Dynamic interactive interface of delaytop::
|
||||
|
||||
# ./delaytop -p pid
|
||||
Print delayacct stats
|
||||
|
||||
# ./delaytop -P num
|
||||
Display the top N tasks
|
||||
|
||||
# ./delaytop -n num
|
||||
Set delaytop refresh frequency (num times)
|
||||
|
||||
# ./delaytop -d secs
|
||||
Specify refresh interval as secs
|
||||
@@ -311,6 +311,27 @@ crashkernel syntax
|
||||
|
||||
crashkernel=0,low
|
||||
|
||||
4) crashkernel=size,cma
|
||||
|
||||
Reserve additional crash kernel memory from CMA. This reservation is
|
||||
usable by the first system's userspace memory and kernel movable
|
||||
allocations (memory balloon, zswap). Pages allocated from this memory
|
||||
range will not be included in the vmcore so this should not be used if
|
||||
dumping of userspace memory is intended and it has to be expected that
|
||||
some movable kernel pages may be missing from the dump.
|
||||
|
||||
A standard crashkernel reservation, as described above, is still needed
|
||||
to hold the crash kernel and initrd.
|
||||
|
||||
This option increases the risk of a kdump failure: DMA transfers
|
||||
configured by the first kernel may end up corrupting the second
|
||||
kernel's memory.
|
||||
|
||||
This reservation method is intended for systems that can't afford to
|
||||
sacrifice enough memory for standard crashkernel reservation and where
|
||||
less reliable and possibly incomplete kdump is preferable to no kdump at
|
||||
all.
|
||||
|
||||
Boot into System Kernel
|
||||
-----------------------
|
||||
1) Update the boot loader (such as grub, yaboot, or lilo) configuration
|
||||
|
||||
@@ -994,6 +994,28 @@
|
||||
0: to disable low allocation.
|
||||
It will be ignored when crashkernel=X,high is not used
|
||||
or memory reserved is below 4G.
|
||||
crashkernel=size[KMG],cma
|
||||
[KNL, X86] Reserve additional crash kernel memory from
|
||||
CMA. This reservation is usable by the first system's
|
||||
userspace memory and kernel movable allocations (memory
|
||||
balloon, zswap). Pages allocated from this memory range
|
||||
will not be included in the vmcore so this should not
|
||||
be used if dumping of userspace memory is intended and
|
||||
it has to be expected that some movable kernel pages
|
||||
may be missing from the dump.
|
||||
|
||||
A standard crashkernel reservation, as described above,
|
||||
is still needed to hold the crash kernel and initrd.
|
||||
|
||||
This option increases the risk of a kdump failure: DMA
|
||||
transfers configured by the first kernel may end up
|
||||
corrupting the second kernel's memory.
|
||||
|
||||
This reservation method is intended for systems that
|
||||
can't afford to sacrifice enough memory for standard
|
||||
crashkernel reservation and where less reliable and
|
||||
possibly incomplete kdump is preferable to no kdump at
|
||||
all.
|
||||
|
||||
cryptomgr.notests
|
||||
[KNL] Disable crypto self-tests
|
||||
@@ -4565,7 +4587,7 @@
|
||||
bit 2: print timer info
|
||||
bit 3: print locks info if CONFIG_LOCKDEP is on
|
||||
bit 4: print ftrace buffer
|
||||
bit 5: print all printk messages in buffer
|
||||
bit 5: replay all messages on consoles at the end of panic
|
||||
bit 6: print all CPUs backtrace (if available in the arch)
|
||||
bit 7: print only tasks in uninterruptible (blocked) state
|
||||
*Be aware* that this option may print a _lot_ of lines,
|
||||
@@ -4573,6 +4595,25 @@
|
||||
Use this option carefully, maybe worth to setup a
|
||||
bigger log buffer with "log_buf_len" along with this.
|
||||
|
||||
panic_sys_info= A comma separated list of extra information to be dumped
|
||||
on panic.
|
||||
Format: val[,val...]
|
||||
Where @val can be any of the following:
|
||||
|
||||
tasks: print all tasks info
|
||||
mem: print system memory info
|
||||
timers: print timers info
|
||||
locks: print locks info if CONFIG_LOCKDEP is on
|
||||
ftrace: print ftrace buffer
|
||||
all_bt: print all CPUs backtrace (if available in the arch)
|
||||
blocked_tasks: print only tasks in uninterruptible (blocked) state
|
||||
|
||||
This is a human readable alternative to the 'panic_print' option.
|
||||
|
||||
panic_console_replay
|
||||
When panic happens, replay all kernel messages on
|
||||
consoles at the end of panic.
|
||||
|
||||
parkbd.port= [HW] Parallel port number the keyboard adapter is
|
||||
connected to, default is 0.
|
||||
Format: <parport#>
|
||||
@@ -7055,6 +7096,11 @@
|
||||
consumed by the stack hash table. By default this is set
|
||||
to false.
|
||||
|
||||
stack_depot_max_pools= [KNL,EARLY]
|
||||
Specify the maximum number of pools to use for storing
|
||||
stack traces. Pools are allocated on-demand up to this
|
||||
limit. Default value is 8191 pools.
|
||||
|
||||
stacktrace [FTRACE]
|
||||
Enabled the stack tracer on boot up.
|
||||
|
||||
|
||||
@@ -890,7 +890,7 @@ bit 1 print system memory info
|
||||
bit 2 print timer info
|
||||
bit 3 print locks info if ``CONFIG_LOCKDEP`` is on
|
||||
bit 4 print ftrace buffer
|
||||
bit 5 print all printk messages in buffer
|
||||
bit 5 replay all messages on consoles at the end of panic
|
||||
bit 6 print all CPUs backtrace (if available in the arch)
|
||||
bit 7 print only tasks in uninterruptible (blocked) state
|
||||
===== ============================================
|
||||
@@ -900,6 +900,24 @@ So for example to print tasks and memory info on panic, user can::
|
||||
echo 3 > /proc/sys/kernel/panic_print
|
||||
|
||||
|
||||
panic_sys_info
|
||||
==============
|
||||
|
||||
A comma separated list of extra information to be dumped on panic,
|
||||
for example, "tasks,mem,timers,...". It is a human readable alternative
|
||||
to 'panic_print'. Possible values are:
|
||||
|
||||
============= ===================================================
|
||||
tasks print all tasks info
|
||||
mem print system memory info
|
||||
timer print timers info
|
||||
lock print locks info if CONFIG_LOCKDEP is on
|
||||
ftrace print ftrace buffer
|
||||
all_bt print all CPUs backtrace (if available in the arch)
|
||||
blocked_tasks print only tasks in uninterruptible (blocked) state
|
||||
============= ===================================================
|
||||
|
||||
|
||||
panic_on_rcu_stall
|
||||
==================
|
||||
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i3c/renesas,i3c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/G3S and RZ/G3E I3C Bus Interface
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
- Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a08g045-i3c # RZ/G3S
|
||||
- renesas,r9a09g047-i3c # RZ/G3E
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Non-recoverable internal error interrupt
|
||||
- description: Normal transfer error interrupt
|
||||
- description: Normal transfer abort interrupt
|
||||
- description: Normal response status buffer full interrupt
|
||||
- description: Normal command buffer empty interrupt
|
||||
- description: Normal IBI status buffer full interrupt
|
||||
- description: Normal Rx data buffer full interrupt
|
||||
- description: Normal Tx data buffer empty interrupt
|
||||
- description: Normal receive status buffer full interrupt
|
||||
- description: START condition detection interrupt
|
||||
- description: STOP condition detection interrupt
|
||||
- description: Transmit end interrupt
|
||||
- description: NACK detection interrupt
|
||||
- description: Arbitration lost interrupt
|
||||
- description: Timeout detection interrupt
|
||||
- description: Wake-up condition detection interrupt
|
||||
- description: HDR Exit Pattern detection interrupt
|
||||
minItems: 16
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: ierr
|
||||
- const: terr
|
||||
- const: abort
|
||||
- const: resp
|
||||
- const: cmd
|
||||
- const: ibi
|
||||
- const: rx
|
||||
- const: tx
|
||||
- const: rcv
|
||||
- const: st
|
||||
- const: sp
|
||||
- const: tend
|
||||
- const: nack
|
||||
- const: al
|
||||
- const: tmo
|
||||
- const: wu
|
||||
- const: exit
|
||||
minItems: 16
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: APB bus clock
|
||||
- description: transfer clock
|
||||
- description: SFRs clock
|
||||
minItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: tclk
|
||||
- const: pclkrw
|
||||
minItems: 2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: Reset signal
|
||||
- description: APB interface reset signal/SCAN reset signal
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: presetn
|
||||
- const: tresetn
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clock-names
|
||||
- clocks
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
allOf:
|
||||
- $ref: i3c.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a08g045-i3c
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
interrupts:
|
||||
minItems: 17
|
||||
interrupt-names:
|
||||
minItems: 17
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g047-i3c
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
clock-names:
|
||||
minItems: 3
|
||||
interrupts:
|
||||
maxItems: 16
|
||||
interrupt-names:
|
||||
maxItems: 16
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r9a08g045-cpg.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
i3c@1005b000 {
|
||||
compatible = "renesas,r9a08g045-i3c";
|
||||
reg = <0x1005b000 0x1000>;
|
||||
clocks = <&cpg CPG_MOD R9A08G045_I3C_PCLK>,
|
||||
<&cpg CPG_MOD R9A08G045_I3C_TCLK>;
|
||||
clock-names = "pclk", "tclk";
|
||||
interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "ierr", "terr", "abort", "resp",
|
||||
"cmd", "ibi", "rx", "tx", "rcv",
|
||||
"st", "sp", "tend", "nack",
|
||||
"al", "tmo", "wu", "exit";
|
||||
resets = <&cpg R9A08G045_I3C_PRESETN>,
|
||||
<&cpg R9A08G045_I3C_TRESETN>;
|
||||
reset-names = "presetn", "tresetn";
|
||||
power-domains = <&cpg>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
...
|
||||
+20
@@ -11612,6 +11612,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml
|
||||
F: drivers/i3c/master/i3c-master-cdns.c
|
||||
|
||||
I3C DRIVER FOR RENESAS
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
M: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
|
||||
F: drivers/i3c/master/renesas-i3c.c
|
||||
|
||||
I3C DRIVER FOR SYNOPSYS DESIGNWARE
|
||||
S: Orphan
|
||||
F: Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml
|
||||
@@ -11622,6 +11629,7 @@ M: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
R: Frank Li <Frank.Li@nxp.com>
|
||||
L: linux-i3c@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
Q: https://patchwork.kernel.org/project/linux-i3c/list/
|
||||
C: irc://chat.freenode.net/linux-i3c
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
|
||||
F: Documentation/ABI/testing/sysfs-bus-i3c
|
||||
@@ -13543,6 +13551,7 @@ F: Documentation/admin-guide/mm/kho.rst
|
||||
F: Documentation/core-api/kho/*
|
||||
F: include/linux/kexec_handover.h
|
||||
F: kernel/kexec_handover.c
|
||||
F: tools/testing/selftests/kho/
|
||||
|
||||
KEYS-ENCRYPTED
|
||||
M: Mimi Zohar <zohar@linux.ibm.com>
|
||||
@@ -19740,6 +19749,16 @@ S: Maintained
|
||||
F: include/linux/delayacct.h
|
||||
F: kernel/delayacct.c
|
||||
|
||||
TASK DELAY MONITORING TOOLS
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: Wang Yaxin <wang.yaxin@zte.com.cn>
|
||||
M: Fan Yu <fan.yu9@zte.com.cn>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/accounting/delay-accounting.rst
|
||||
F: tools/accounting/delaytop.c
|
||||
F: tools/accounting/getdelays.c
|
||||
|
||||
PERFORMANCE EVENTS SUBSYSTEM
|
||||
M: Peter Zijlstra <peterz@infradead.org>
|
||||
M: Ingo Molnar <mingo@redhat.com>
|
||||
@@ -23381,6 +23400,7 @@ F: drivers/md/md*
|
||||
F: drivers/md/raid*
|
||||
F: include/linux/raid/
|
||||
F: include/uapi/linux/raid/
|
||||
F: lib/raid6/
|
||||
|
||||
SOLIDRUN CLEARFOG SUPPORT
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/memblock.h>
|
||||
|
||||
@@ -79,10 +80,12 @@ mk_resource_name(int pe, int port, char *str)
|
||||
{
|
||||
char tmp[80];
|
||||
char *name;
|
||||
|
||||
sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
|
||||
name = memblock_alloc_or_panic(strlen(tmp) + 1, SMP_CACHE_BYTES);
|
||||
strcpy(name, tmp);
|
||||
size_t sz;
|
||||
|
||||
sz = scnprintf(tmp, sizeof(tmp), "PCI %s PE %d PORT %d", str, pe, port);
|
||||
sz += 1; /* NUL terminator */
|
||||
name = memblock_alloc_or_panic(sz, SMP_CACHE_BYTES);
|
||||
strscpy(name, tmp, sz);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -1004,7 +1004,7 @@ static void __init reserve_crashkernel(void)
|
||||
total_mem = get_total_mem();
|
||||
ret = parse_crashkernel(boot_command_line, total_mem,
|
||||
&crash_size, &crash_base,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
/* invalid value specified or crashkernel=0 */
|
||||
if (ret || !crash_size)
|
||||
return;
|
||||
|
||||
@@ -112,7 +112,7 @@ static void __init arch_reserve_crashkernel(void)
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&crash_size, &crash_base,
|
||||
&low_size, &high);
|
||||
&low_size, NULL, &high);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ static void __init arch_reserve_crashkernel(void)
|
||||
return;
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&crash_size, &crash_base, &low_size, &high);
|
||||
&crash_size, &crash_base, &low_size, NULL, &high);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
|
||||
@@ -458,7 +458,7 @@ static void __init mips_parse_crashkernel(void)
|
||||
total_mem = memblock_phys_mem_size();
|
||||
ret = parse_crashkernel(boot_command_line, total_mem,
|
||||
&crash_size, &crash_base,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
if (ret != 0 || crash_size <= 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -425,6 +425,7 @@
|
||||
#define PPC_RAW_SC() (0x44000002)
|
||||
#define PPC_RAW_SYNC() (0x7c0004ac)
|
||||
#define PPC_RAW_ISYNC() (0x4c00012c)
|
||||
#define PPC_RAW_LWSYNC() (0x7c2004ac)
|
||||
|
||||
/*
|
||||
* Define what the VSX XX1 form instructions will look like, then add
|
||||
|
||||
@@ -1139,6 +1139,7 @@ int eeh_unfreeze_pe(struct eeh_pe *pe)
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eeh_unfreeze_pe);
|
||||
|
||||
|
||||
static struct pci_device_id eeh_reset_ids[] = {
|
||||
|
||||
@@ -257,13 +257,12 @@ static void eeh_pe_report_edev(struct eeh_dev *edev, eeh_report_fn fn,
|
||||
struct pci_driver *driver;
|
||||
enum pci_ers_result new_result;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pdev = edev->pdev;
|
||||
if (pdev)
|
||||
get_device(&pdev->dev);
|
||||
pci_unlock_rescan_remove();
|
||||
if (!pdev) {
|
||||
eeh_edev_info(edev, "no device");
|
||||
*result = PCI_ERS_RESULT_DISCONNECT;
|
||||
return;
|
||||
}
|
||||
device_lock(&pdev->dev);
|
||||
@@ -304,8 +303,9 @@ static void eeh_pe_report(const char *name, struct eeh_pe *root,
|
||||
struct eeh_dev *edev, *tmp;
|
||||
|
||||
pr_info("EEH: Beginning: '%s'\n", name);
|
||||
eeh_for_each_pe(root, pe) eeh_pe_for_each_dev(pe, edev, tmp)
|
||||
eeh_pe_report_edev(edev, fn, result);
|
||||
eeh_for_each_pe(root, pe)
|
||||
eeh_pe_for_each_dev(pe, edev, tmp)
|
||||
eeh_pe_report_edev(edev, fn, result);
|
||||
if (result)
|
||||
pr_info("EEH: Finished:'%s' with aggregate recovery state:'%s'\n",
|
||||
name, pci_ers_result_name(*result));
|
||||
@@ -383,6 +383,8 @@ static void eeh_dev_restore_state(struct eeh_dev *edev, void *userdata)
|
||||
if (!edev)
|
||||
return;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
/*
|
||||
* The content in the config space isn't saved because
|
||||
* the blocked config space on some adapters. We have
|
||||
@@ -393,14 +395,19 @@ static void eeh_dev_restore_state(struct eeh_dev *edev, void *userdata)
|
||||
if (list_is_last(&edev->entry, &edev->pe->edevs))
|
||||
eeh_pe_restore_bars(edev->pe);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
}
|
||||
|
||||
pdev = eeh_dev_to_pci_dev(edev);
|
||||
if (!pdev)
|
||||
if (!pdev) {
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
}
|
||||
|
||||
pci_restore_state(pdev);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,9 +654,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
|
||||
if (any_passed || driver_eeh_aware || (pe->type & EEH_PE_VF)) {
|
||||
eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
|
||||
} else {
|
||||
pci_lock_rescan_remove();
|
||||
pci_hp_remove_devices(bus);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -665,8 +670,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
/* Restore PE */
|
||||
eeh_ops->configure_bridge(pe);
|
||||
eeh_pe_restore_bars(pe);
|
||||
@@ -674,7 +677,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
|
||||
/* Clear frozen state */
|
||||
rc = eeh_clear_pe_frozen_state(pe, false);
|
||||
if (rc) {
|
||||
pci_unlock_rescan_remove();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -709,7 +711,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
|
||||
pe->tstamp = tstamp;
|
||||
pe->freeze_count = cnt;
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -843,10 +844,13 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
|
||||
{LIST_HEAD_INIT(rmv_data.removed_vf_list), 0};
|
||||
int devices = 0;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
bus = eeh_pe_bus_get(pe);
|
||||
if (!bus) {
|
||||
pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n",
|
||||
__func__, pe->phb->global_number, pe->addr);
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1094,10 +1098,15 @@ recover_failed:
|
||||
eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
|
||||
eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
pci_hp_remove_devices(bus);
|
||||
pci_unlock_rescan_remove();
|
||||
bus = eeh_pe_bus_get(pe);
|
||||
if (bus)
|
||||
pci_hp_remove_devices(bus);
|
||||
else
|
||||
pr_err("%s: PCI bus for PHB#%x-PE#%x disappeared\n",
|
||||
__func__, pe->phb->global_number, pe->addr);
|
||||
|
||||
/* The passed PE should no longer be used */
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1114,6 +1123,8 @@ out:
|
||||
eeh_clear_slot_attention(edev->pdev);
|
||||
|
||||
eeh_pe_state_clear(pe, EEH_PE_RECOVERING, true);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1132,6 +1143,7 @@ void eeh_handle_special_event(void)
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
do {
|
||||
rc = eeh_ops->next_error(&pe);
|
||||
@@ -1171,10 +1183,12 @@ void eeh_handle_special_event(void)
|
||||
|
||||
break;
|
||||
case EEH_NEXT_ERR_NONE:
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
default:
|
||||
pr_warn("%s: Invalid value %d from next_error()\n",
|
||||
__func__, rc);
|
||||
pci_unlock_rescan_remove();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1186,7 +1200,9 @@ void eeh_handle_special_event(void)
|
||||
if (rc == EEH_NEXT_ERR_FROZEN_PE ||
|
||||
rc == EEH_NEXT_ERR_FENCED_PHB) {
|
||||
eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
|
||||
pci_unlock_rescan_remove();
|
||||
eeh_handle_normal_event(pe);
|
||||
pci_lock_rescan_remove();
|
||||
} else {
|
||||
eeh_for_each_pe(pe, tmp_pe)
|
||||
eeh_pe_for_each_dev(tmp_pe, edev, tmp_edev)
|
||||
@@ -1199,7 +1215,6 @@ void eeh_handle_special_event(void)
|
||||
eeh_report_failure, NULL);
|
||||
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
list_for_each_entry(hose, &hose_list, list_node) {
|
||||
phb_pe = eeh_phb_pe_get(hose);
|
||||
if (!phb_pe ||
|
||||
@@ -1218,7 +1233,6 @@ void eeh_handle_special_event(void)
|
||||
}
|
||||
pci_hp_remove_devices(bus);
|
||||
}
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1228,4 +1242,6 @@ void eeh_handle_special_event(void)
|
||||
if (rc == EEH_NEXT_ERR_DEAD_IOC)
|
||||
break;
|
||||
} while (rc != EEH_NEXT_ERR_NONE);
|
||||
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
@@ -671,10 +671,12 @@ static void eeh_bridge_check_link(struct eeh_dev *edev)
|
||||
eeh_ops->write_config(edev, cap + PCI_EXP_LNKCTL, 2, val);
|
||||
|
||||
/* Check link */
|
||||
if (!edev->pdev->link_active_reporting) {
|
||||
eeh_edev_dbg(edev, "No link reporting capability\n");
|
||||
msleep(1000);
|
||||
return;
|
||||
if (edev->pdev) {
|
||||
if (!edev->pdev->link_active_reporting) {
|
||||
eeh_edev_dbg(edev, "No link reporting capability\n");
|
||||
msleep(1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait the link is up until timeout (5s) */
|
||||
|
||||
@@ -333,7 +333,7 @@ static __init u64 fadump_calculate_reserve_size(void)
|
||||
* memory at a predefined offset.
|
||||
*/
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&size, &base, NULL, NULL);
|
||||
&size, &base, NULL, NULL, NULL);
|
||||
if (ret == 0 && size > 0) {
|
||||
unsigned long max_size;
|
||||
|
||||
|
||||
@@ -141,6 +141,9 @@ void pci_hp_add_devices(struct pci_bus *bus)
|
||||
struct pci_controller *phb;
|
||||
struct device_node *dn = pci_bus_to_OF_node(bus);
|
||||
|
||||
if (!dn)
|
||||
return;
|
||||
|
||||
phb = pci_bus_to_host(bus);
|
||||
|
||||
mode = PCI_PROBE_NORMAL;
|
||||
|
||||
@@ -110,7 +110,7 @@ void __init arch_reserve_crashkernel(void)
|
||||
|
||||
/* use common parsing */
|
||||
ret = parse_crashkernel(boot_command_line, total_mem_sz, &crash_size,
|
||||
&crash_base, NULL, NULL);
|
||||
&crash_base, NULL, NULL, NULL);
|
||||
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -178,7 +178,7 @@ static void __init get_crash_kernel(void *fdt, unsigned long size)
|
||||
int ret;
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, size, &crash_size,
|
||||
&crash_base, NULL, NULL);
|
||||
&crash_base, NULL, NULL, NULL);
|
||||
if (ret != 0 || crash_size == 0)
|
||||
return;
|
||||
if (crash_base == 0)
|
||||
|
||||
@@ -409,6 +409,71 @@ asm (
|
||||
" blr ;"
|
||||
);
|
||||
|
||||
static int emit_atomic_ld_st(const struct bpf_insn insn, struct codegen_context *ctx, u32 *image)
|
||||
{
|
||||
u32 code = insn.code;
|
||||
u32 dst_reg = bpf_to_ppc(insn.dst_reg);
|
||||
u32 src_reg = bpf_to_ppc(insn.src_reg);
|
||||
u32 size = BPF_SIZE(code);
|
||||
u32 tmp1_reg = bpf_to_ppc(TMP_REG_1);
|
||||
u32 tmp2_reg = bpf_to_ppc(TMP_REG_2);
|
||||
s16 off = insn.off;
|
||||
s32 imm = insn.imm;
|
||||
|
||||
switch (imm) {
|
||||
case BPF_LOAD_ACQ:
|
||||
switch (size) {
|
||||
case BPF_B:
|
||||
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
|
||||
break;
|
||||
case BPF_H:
|
||||
EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
|
||||
break;
|
||||
case BPF_W:
|
||||
EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
|
||||
break;
|
||||
case BPF_DW:
|
||||
if (off % 4) {
|
||||
EMIT(PPC_RAW_LI(tmp1_reg, off));
|
||||
EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg));
|
||||
} else {
|
||||
EMIT(PPC_RAW_LD(dst_reg, src_reg, off));
|
||||
}
|
||||
break;
|
||||
}
|
||||
EMIT(PPC_RAW_LWSYNC());
|
||||
break;
|
||||
case BPF_STORE_REL:
|
||||
EMIT(PPC_RAW_LWSYNC());
|
||||
switch (size) {
|
||||
case BPF_B:
|
||||
EMIT(PPC_RAW_STB(src_reg, dst_reg, off));
|
||||
break;
|
||||
case BPF_H:
|
||||
EMIT(PPC_RAW_STH(src_reg, dst_reg, off));
|
||||
break;
|
||||
case BPF_W:
|
||||
EMIT(PPC_RAW_STW(src_reg, dst_reg, off));
|
||||
break;
|
||||
case BPF_DW:
|
||||
if (off % 4) {
|
||||
EMIT(PPC_RAW_LI(tmp2_reg, off));
|
||||
EMIT(PPC_RAW_STDX(src_reg, dst_reg, tmp2_reg));
|
||||
} else {
|
||||
EMIT(PPC_RAW_STD(src_reg, dst_reg, off));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_err_ratelimited("unexpected atomic load/store op code %02x\n",
|
||||
imm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assemble the body code between the prologue & epilogue */
|
||||
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
|
||||
u32 *addrs, int pass, bool extra_pass)
|
||||
@@ -898,8 +963,25 @@ emit_clear:
|
||||
/*
|
||||
* BPF_STX ATOMIC (atomic ops)
|
||||
*/
|
||||
case BPF_STX | BPF_ATOMIC | BPF_B:
|
||||
case BPF_STX | BPF_ATOMIC | BPF_H:
|
||||
case BPF_STX | BPF_ATOMIC | BPF_W:
|
||||
case BPF_STX | BPF_ATOMIC | BPF_DW:
|
||||
if (bpf_atomic_is_load_store(&insn[i])) {
|
||||
ret = emit_atomic_ld_st(insn[i], ctx, image);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
|
||||
addrs[++i] = ctx->idx * 4;
|
||||
break;
|
||||
} else if (size == BPF_B || size == BPF_H) {
|
||||
pr_err_ratelimited(
|
||||
"eBPF filter atomic op code %02x (@%d) unsupported\n",
|
||||
code, i);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
save_reg = tmp2_reg;
|
||||
ret_reg = src_reg;
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ config RISCV
|
||||
select CLINT_TIMER if RISCV_M_MODE
|
||||
select CLONE_BACKWARDS
|
||||
select COMMON_CLK
|
||||
select CPU_NO_EFFICIENT_FFS if !RISCV_ISA_ZBB
|
||||
select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND
|
||||
select DYNAMIC_FTRACE if FUNCTION_TRACER
|
||||
select EDAC_SUPPORT
|
||||
|
||||
@@ -95,6 +95,7 @@ static int elf_find_pbase(struct kimage *image, unsigned long kernel_len,
|
||||
kbuf.buf_align = PMD_SIZE;
|
||||
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE);
|
||||
kbuf.cma = NULL;
|
||||
kbuf.top_down = false;
|
||||
ret = arch_kexec_locate_mem_hole(&kbuf);
|
||||
if (!ret) {
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <linux/efi.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/panic_notifier.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/gcd.h>
|
||||
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/alternative.h>
|
||||
@@ -362,6 +364,9 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
riscv_user_isa_enable();
|
||||
riscv_spinlock_init();
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))
|
||||
static_branch_disable(&efficient_ffs_key);
|
||||
}
|
||||
|
||||
bool arch_cpu_is_hotpluggable(int cpu)
|
||||
|
||||
@@ -1408,7 +1408,7 @@ static void __init arch_reserve_crashkernel(void)
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&crash_size, &crash_base,
|
||||
&low_size, &high);
|
||||
&low_size, NULL, &high);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ static void __init reserve_crashkernel(void)
|
||||
int rc;
|
||||
|
||||
rc = parse_crashkernel(boot_command_line, ident_map_size,
|
||||
&crash_size, &crash_base, NULL, NULL);
|
||||
&crash_size, &crash_base, NULL, NULL, NULL);
|
||||
|
||||
crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN);
|
||||
crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN);
|
||||
|
||||
@@ -146,7 +146,7 @@ void __init reserve_crashkernel(void)
|
||||
return;
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&crash_size, &crash_base, NULL, NULL);
|
||||
&crash_size, &crash_base, NULL, NULL, NULL);
|
||||
if (ret == 0 && crash_size > 0) {
|
||||
crashk_res.start = crash_base;
|
||||
crashk_res.end = crash_base + crash_size - 1;
|
||||
|
||||
+22
-4
@@ -163,10 +163,10 @@ static struct crash_mem *fill_up_crash_elf_data(void)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Exclusion of crash region and/or crashk_low_res may cause
|
||||
* another range split. So add extra two slots here.
|
||||
* Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
|
||||
* may cause range splits. So add extra slots here.
|
||||
*/
|
||||
nr_ranges += 2;
|
||||
nr_ranges += 2 + crashk_cma_cnt;
|
||||
cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
|
||||
if (!cmem)
|
||||
return NULL;
|
||||
@@ -184,6 +184,7 @@ static struct crash_mem *fill_up_crash_elf_data(void)
|
||||
static int elf_header_exclude_ranges(struct crash_mem *cmem)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
/* Exclude the low 1M because it is always reserved */
|
||||
ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
|
||||
@@ -198,8 +199,17 @@ static int elf_header_exclude_ranges(struct crash_mem *cmem)
|
||||
if (crashk_low_res.end)
|
||||
ret = crash_exclude_mem_range(cmem, crashk_low_res.start,
|
||||
crashk_low_res.end);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
for (i = 0; i < crashk_cma_cnt; ++i) {
|
||||
ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
|
||||
crashk_cma_ranges[i].end);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
|
||||
@@ -374,6 +384,14 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params)
|
||||
add_e820_entry(params, &ei);
|
||||
}
|
||||
|
||||
for (i = 0; i < crashk_cma_cnt; ++i) {
|
||||
ei.addr = crashk_cma_ranges[i].start;
|
||||
ei.size = crashk_cma_ranges[i].end -
|
||||
crashk_cma_ranges[i].start + 1;
|
||||
ei.type = E820_TYPE_RAM;
|
||||
add_e820_entry(params, &ei);
|
||||
}
|
||||
|
||||
out:
|
||||
vfree(cmem);
|
||||
return ret;
|
||||
|
||||
@@ -603,7 +603,7 @@ static void __init memblock_x86_reserve_range_setup_data(void)
|
||||
|
||||
static void __init arch_reserve_crashkernel(void)
|
||||
{
|
||||
unsigned long long crash_base, crash_size, low_size = 0;
|
||||
unsigned long long crash_base, crash_size, low_size = 0, cma_size = 0;
|
||||
bool high = false;
|
||||
int ret;
|
||||
|
||||
@@ -612,7 +612,7 @@ static void __init arch_reserve_crashkernel(void)
|
||||
|
||||
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
|
||||
&crash_size, &crash_base,
|
||||
&low_size, &high);
|
||||
&low_size, &cma_size, &high);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -622,6 +622,7 @@ static void __init arch_reserve_crashkernel(void)
|
||||
}
|
||||
|
||||
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
|
||||
reserve_crashkernel_cma(cma_size);
|
||||
}
|
||||
|
||||
static struct resource standard_io_resources[] = {
|
||||
|
||||
@@ -641,7 +641,7 @@ static void kvm_pit_reset(struct kvm_pit *pit)
|
||||
kvm_pit_reset_reinject(pit);
|
||||
}
|
||||
|
||||
static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
|
||||
static void pit_mask_notifier(struct kvm_irq_mask_notifier *kimn, bool mask)
|
||||
{
|
||||
struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier);
|
||||
|
||||
@@ -763,7 +763,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
|
||||
|
||||
pit_state->irq_ack_notifier.gsi = 0;
|
||||
pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
|
||||
pit->mask_notifier.func = pit_mask_notifer;
|
||||
pit->mask_notifier.func = pit_mask_notifier;
|
||||
|
||||
kvm_pit_reset(pit);
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
|
||||
for (i = 0; i < disks; i++) {
|
||||
if (blocks[i] == NULL) {
|
||||
BUG_ON(i > disks - 3); /* P or Q can't be zero */
|
||||
srcs[i] = (void*)raid6_empty_zero_page;
|
||||
srcs[i] = raid6_get_zero_page();
|
||||
} else {
|
||||
srcs[i] = page_address(blocks[i]) + offsets[i];
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
|
||||
async_tx_quiesce(&submit->depend_tx);
|
||||
for (i = 0; i < disks; i++)
|
||||
if (blocks[i] == NULL)
|
||||
ptrs[i] = (void *) raid6_empty_zero_page;
|
||||
ptrs[i] = raid6_get_zero_page();
|
||||
else
|
||||
ptrs[i] = page_address(blocks[i]) + offs[i];
|
||||
|
||||
@@ -497,7 +497,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
|
||||
async_tx_quiesce(&submit->depend_tx);
|
||||
for (i = 0; i < disks; i++)
|
||||
if (blocks[i] == NULL)
|
||||
ptrs[i] = (void*)raid6_empty_zero_page;
|
||||
ptrs[i] = raid6_get_zero_page();
|
||||
else
|
||||
ptrs[i] = page_address(blocks[i]) + offs[i];
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifdef CONFIG_CXL_MCE
|
||||
int devm_cxl_register_mce_notifier(struct device *dev,
|
||||
struct notifier_block *mce_notifer);
|
||||
struct notifier_block *mce_notifier);
|
||||
#else
|
||||
static inline int
|
||||
devm_cxl_register_mce_notifier(struct device *dev,
|
||||
|
||||
@@ -220,8 +220,7 @@ static int guc_action_control_log(struct intel_guc *guc, bool enable,
|
||||
*/
|
||||
static int subbuf_start_callback(struct rchan_buf *buf,
|
||||
void *subbuf,
|
||||
void *prev_subbuf,
|
||||
size_t prev_padding)
|
||||
void *prev_subbuf)
|
||||
{
|
||||
/*
|
||||
* Use no-overwrite mode by default, where relay will stop accepting
|
||||
|
||||
@@ -266,7 +266,7 @@ struct xe_vm {
|
||||
* up for revalidation. Protected from access with the
|
||||
* @invalidated_lock. Removing items from the list
|
||||
* additionally requires @lock in write mode, and adding
|
||||
* items to the list requires either the @userptr.notifer_lock in
|
||||
* items to the list requires either the @userptr.notifier_lock in
|
||||
* write mode, OR @lock in write mode.
|
||||
*/
|
||||
struct list_head invalidated;
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
*
|
||||
* This function can sleep and thus cannot be called in atomic context.
|
||||
*
|
||||
* Return: 0 in case of success, a negative error core otherwise.
|
||||
* -EAGAIN: controller lost address arbitration. Target
|
||||
* (IBI, HJ or controller role request) win the bus. Client
|
||||
* driver needs to resend the 'xfers' some time later.
|
||||
* See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3.
|
||||
* Return:
|
||||
* * 0 in case of success, a negative error core otherwise.
|
||||
* * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or
|
||||
* controller role request) win the bus. Client driver needs to resend the
|
||||
* 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
|
||||
* 5.1.2.2.3.
|
||||
*/
|
||||
int i3c_device_do_priv_xfers(struct i3c_device *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define I3C_INTERNALS_H
|
||||
|
||||
#include <linux/i3c/master.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
void i3c_bus_normaluse_lock(struct i3c_bus *bus);
|
||||
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
|
||||
@@ -22,4 +23,41 @@ int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
|
||||
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
|
||||
const struct i3c_ibi_setup *req);
|
||||
void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
|
||||
|
||||
/**
|
||||
* i3c_writel_fifo - Write data buffer to 32bit FIFO
|
||||
* @addr: FIFO Address to write to
|
||||
* @buf: Pointer to the data bytes to write
|
||||
* @nbytes: Number of bytes to write
|
||||
*/
|
||||
static inline void i3c_writel_fifo(void __iomem *addr, const void *buf,
|
||||
int nbytes)
|
||||
{
|
||||
writesl(addr, buf, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp = 0;
|
||||
|
||||
memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3);
|
||||
writel(tmp, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* i3c_readl_fifo - Read data buffer from 32bit FIFO
|
||||
* @addr: FIFO Address to read from
|
||||
* @buf: Pointer to the buffer to store read bytes
|
||||
* @nbytes: Number of bytes to read
|
||||
*/
|
||||
static inline void i3c_readl_fifo(const void __iomem *addr, void *buf,
|
||||
int nbytes)
|
||||
{
|
||||
readsl(addr, buf, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(addr);
|
||||
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* I3C_INTERNAL_H */
|
||||
+20
-18
@@ -141,7 +141,7 @@ static ssize_t bcr_show(struct device *dev,
|
||||
|
||||
i3c_bus_normaluse_lock(bus);
|
||||
desc = dev_to_i3cdesc(dev);
|
||||
ret = sprintf(buf, "%x\n", desc->info.bcr);
|
||||
ret = sprintf(buf, "0x%02x\n", desc->info.bcr);
|
||||
i3c_bus_normaluse_unlock(bus);
|
||||
|
||||
return ret;
|
||||
@@ -158,7 +158,7 @@ static ssize_t dcr_show(struct device *dev,
|
||||
|
||||
i3c_bus_normaluse_lock(bus);
|
||||
desc = dev_to_i3cdesc(dev);
|
||||
ret = sprintf(buf, "%x\n", desc->info.dcr);
|
||||
ret = sprintf(buf, "0x%02x\n", desc->info.dcr);
|
||||
i3c_bus_normaluse_unlock(bus);
|
||||
|
||||
return ret;
|
||||
@@ -727,12 +727,12 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
|
||||
switch (i3cbus->mode) {
|
||||
case I3C_BUS_MODE_PURE:
|
||||
if (!i3cbus->scl_rate.i3c)
|
||||
i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
|
||||
i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
|
||||
break;
|
||||
case I3C_BUS_MODE_MIXED_FAST:
|
||||
case I3C_BUS_MODE_MIXED_LIMITED:
|
||||
if (!i3cbus->scl_rate.i3c)
|
||||
i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
|
||||
i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
|
||||
if (!i3cbus->scl_rate.i2c)
|
||||
i3cbus->scl_rate.i2c = max_i2c_scl_rate;
|
||||
break;
|
||||
@@ -754,8 +754,8 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
|
||||
* I3C/I2C frequency may have been overridden, check that user-provided
|
||||
* values are not exceeding max possible frequency.
|
||||
*/
|
||||
if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE ||
|
||||
i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE)
|
||||
if (i3cbus->scl_rate.i3c > I3C_BUS_I3C_SCL_MAX_RATE ||
|
||||
i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -837,14 +837,14 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->ops->send_ccc_cmd)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests))
|
||||
return -EINVAL;
|
||||
|
||||
if (master->ops->supports_ccc_cmd &&
|
||||
!master->ops->supports_ccc_cmd(master, cmd))
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = master->ops->send_ccc_cmd(master, cmd);
|
||||
if (ret) {
|
||||
@@ -1439,7 +1439,7 @@ static int i3c_master_retrieve_dev_info(struct i3c_dev_desc *dev)
|
||||
|
||||
if (dev->info.bcr & I3C_BCR_HDR_CAP) {
|
||||
ret = i3c_master_gethdrcap_locked(master, &dev->info);
|
||||
if (ret)
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2210,7 +2210,7 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
|
||||
*/
|
||||
if (boardinfo->base.flags & I2C_CLIENT_TEN) {
|
||||
dev_err(dev, "I2C device with 10 bit address not supported.");
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* LVR is encoded in reg[2]. */
|
||||
@@ -2340,13 +2340,13 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->ops->i2c_xfers)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Doing transfers to different devices is not supported. */
|
||||
addr = xfers[0].addr;
|
||||
for (i = 1; i < nxfers; i++) {
|
||||
if (addr != xfers[i].addr)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
i3c_bus_normaluse_lock(&master->bus);
|
||||
@@ -2467,6 +2467,8 @@ static int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action
|
||||
case BUS_NOTIFY_DEL_DEVICE:
|
||||
ret = i3c_master_i2c_detach(adap, client);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
i3c_bus_maintenance_unlock(&master->bus);
|
||||
|
||||
@@ -2766,7 +2768,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
|
||||
* controller)
|
||||
* @ops: the master controller operations
|
||||
* @secondary: true if you are registering a secondary master. Will return
|
||||
* -ENOTSUPP if set to true since secondary masters are not yet
|
||||
* -EOPNOTSUPP if set to true since secondary masters are not yet
|
||||
* supported
|
||||
*
|
||||
* This function takes care of everything for you:
|
||||
@@ -2785,7 +2787,7 @@ int i3c_master_register(struct i3c_master_controller *master,
|
||||
const struct i3c_master_controller_ops *ops,
|
||||
bool secondary)
|
||||
{
|
||||
unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
|
||||
unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE;
|
||||
struct i3c_bus *i3cbus = i3c_master_get_bus(master);
|
||||
enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
|
||||
struct i2c_dev_boardinfo *i2cbi;
|
||||
@@ -2793,7 +2795,7 @@ int i3c_master_register(struct i3c_master_controller *master,
|
||||
|
||||
/* We do not support secondary masters yet. */
|
||||
if (secondary)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = i3c_master_check_ops(ops);
|
||||
if (ret)
|
||||
@@ -2844,7 +2846,7 @@ int i3c_master_register(struct i3c_master_controller *master,
|
||||
}
|
||||
|
||||
if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE)
|
||||
i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE;
|
||||
i2c_scl_rate = I3C_BUS_I2C_FM_SCL_MAX_RATE;
|
||||
}
|
||||
|
||||
ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate);
|
||||
@@ -2954,7 +2956,7 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->ops->priv_xfers)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return master->ops->priv_xfers(dev, xfers, nxfers);
|
||||
}
|
||||
@@ -3004,7 +3006,7 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
|
||||
int ret;
|
||||
|
||||
if (!master->ops->request_ibi)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ibi)
|
||||
return -EBUSY;
|
||||
|
||||
@@ -64,3 +64,13 @@ config MIPI_I3C_HCI_PCI
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called mipi-i3c-hci-pci.
|
||||
|
||||
config RENESAS_I3C
|
||||
tristate "Renesas I3C controller driver"
|
||||
depends on HAS_IOMEM
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
help
|
||||
Support the Renesas I3C controller as found in some RZ variants.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called renesas-i3c.
|
||||
@@ -4,3 +4,4 @@ obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o
|
||||
obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o
|
||||
obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o
|
||||
obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/
|
||||
obj-$(CONFIG_RENESAS_I3C) += renesas-i3c.o
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../internals.h"
|
||||
#include "dw-i3c-master.h"
|
||||
|
||||
#define DEVICE_CTRL 0x0
|
||||
@@ -336,37 +337,19 @@ static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
|
||||
static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
|
||||
const u8 *bytes, int nbytes)
|
||||
{
|
||||
writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp = 0;
|
||||
|
||||
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
|
||||
writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_i3c_master_read_fifo(struct dw_i3c_master *master,
|
||||
int reg, u8 *bytes, int nbytes)
|
||||
{
|
||||
readsl(master->regs + reg, bytes, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp;
|
||||
|
||||
readsl(master->regs + reg, &tmp, 1);
|
||||
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
|
||||
}
|
||||
i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
|
||||
}
|
||||
|
||||
static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master,
|
||||
u8 *bytes, int nbytes)
|
||||
{
|
||||
return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes);
|
||||
i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
|
||||
}
|
||||
|
||||
static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master,
|
||||
u8 *bytes, int nbytes)
|
||||
{
|
||||
return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes);
|
||||
i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes);
|
||||
}
|
||||
|
||||
static struct dw_i3c_xfer *
|
||||
@@ -622,14 +605,14 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
|
||||
core_period = DIV_ROUND_UP(1000000000, core_rate);
|
||||
|
||||
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period);
|
||||
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
|
||||
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) - lcnt;
|
||||
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) |
|
||||
SCL_I2C_FMP_TIMING_LCNT(lcnt);
|
||||
writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING);
|
||||
master->i2c_fmp_timing = scl_timing;
|
||||
|
||||
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period);
|
||||
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
|
||||
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_MAX_RATE) - lcnt;
|
||||
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) |
|
||||
SCL_I2C_FM_TIMING_LCNT(lcnt);
|
||||
writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
|
||||
@@ -699,7 +682,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
|
||||
dw_i3c_master_enable(master);
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
}
|
||||
@@ -829,7 +811,6 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
|
||||
else
|
||||
ret = dw_i3c_ccc_set(master, ccc);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
}
|
||||
@@ -912,7 +893,6 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
}
|
||||
@@ -932,7 +912,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
return 0;
|
||||
|
||||
if (i3c_nxfers > master->caps.cmdfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < i3c_nxfers; i++) {
|
||||
if (i3c_xfers[i].rnw)
|
||||
@@ -943,7 +923,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
|
||||
if (ntxwords > master->caps.datafifodepth ||
|
||||
nrxwords > master->caps.datafifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
|
||||
if (!xfer)
|
||||
@@ -998,7 +978,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
ret = xfer->ret;
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
}
|
||||
@@ -1093,7 +1072,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
return 0;
|
||||
|
||||
if (i2c_nxfers > master->caps.cmdfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < i2c_nxfers; i++) {
|
||||
if (i2c_xfers[i].flags & I2C_M_RD)
|
||||
@@ -1104,7 +1083,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
|
||||
if (ntxwords > master->caps.datafifodepth ||
|
||||
nrxwords > master->caps.datafifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
|
||||
if (!xfer)
|
||||
@@ -1142,13 +1121,12 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
}
|
||||
|
||||
dw_i3c_master_enqueue_xfer(master, xfer);
|
||||
if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
|
||||
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
|
||||
dw_i3c_master_dequeue_xfer(master, xfer);
|
||||
|
||||
ret = xfer->ret;
|
||||
dw_i3c_master_free_xfer(xfer);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return ret;
|
||||
}
|
||||
@@ -1316,7 +1294,6 @@ static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
|
||||
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
|
||||
master->regs + DEVICE_CTRL);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -1342,7 +1319,6 @@ static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
|
||||
|
||||
if (rc) {
|
||||
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
}
|
||||
|
||||
@@ -1362,7 +1338,6 @@ static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
|
||||
|
||||
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "../internals.h"
|
||||
|
||||
#define DEV_ID 0x0
|
||||
#define DEV_ID_I3C_MASTER 0x5034
|
||||
|
||||
@@ -412,7 +414,6 @@ struct cdns_i3c_master {
|
||||
} xferqueue;
|
||||
void __iomem *regs;
|
||||
struct clk *sysclk;
|
||||
struct clk *pclk;
|
||||
struct cdns_i3c_master_caps caps;
|
||||
unsigned long i3c_scl_lim;
|
||||
const struct cdns_i3c_data *devdata;
|
||||
@@ -427,25 +428,13 @@ to_cdns_i3c_master(struct i3c_master_controller *master)
|
||||
static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
|
||||
const u8 *bytes, int nbytes)
|
||||
{
|
||||
writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp = 0;
|
||||
|
||||
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
|
||||
writesl(master->regs + TX_FIFO, &tmp, 1);
|
||||
}
|
||||
i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes);
|
||||
}
|
||||
|
||||
static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
|
||||
u8 *bytes, int nbytes)
|
||||
{
|
||||
readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
|
||||
if (nbytes & 3) {
|
||||
u32 tmp;
|
||||
|
||||
readsl(master->regs + RX_FIFO, &tmp, 1);
|
||||
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
|
||||
}
|
||||
i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes);
|
||||
}
|
||||
|
||||
static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
|
||||
@@ -742,7 +731,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
|
||||
for (i = 0; i < nxfers; i++) {
|
||||
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!nxfers)
|
||||
@@ -750,7 +739,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
|
||||
if (nxfers > master->caps.cmdfifodepth ||
|
||||
nxfers > master->caps.cmdrfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* First make sure that all transactions (block of transfers separated
|
||||
@@ -765,7 +754,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
|
||||
|
||||
if (rxslots > master->caps.rxfifodepth ||
|
||||
txslots > master->caps.txfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
|
||||
if (!cdns_xfer)
|
||||
@@ -822,11 +811,11 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
int i, ret = 0;
|
||||
|
||||
if (nxfers > master->caps.cmdfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < nxfers; i++) {
|
||||
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (xfers[i].flags & I2C_M_RD)
|
||||
nrxwords += DIV_ROUND_UP(xfers[i].len, 4);
|
||||
@@ -836,7 +825,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
|
||||
if (ntxwords > master->caps.txfifodepth ||
|
||||
nrxwords > master->caps.rxfifodepth)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
|
||||
if (!xfer)
|
||||
@@ -863,7 +852,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
}
|
||||
|
||||
cdns_i3c_master_queue_xfer(master, xfer);
|
||||
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
|
||||
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
|
||||
cdns_i3c_master_unqueue_xfer(master, xfer);
|
||||
|
||||
ret = xfer->ret;
|
||||
@@ -1330,12 +1319,7 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
|
||||
buf = slot->data;
|
||||
|
||||
nbytes = IBIR_XFER_BYTES(ibir);
|
||||
readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
|
||||
if (nbytes % 3) {
|
||||
u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
|
||||
|
||||
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
|
||||
}
|
||||
i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
|
||||
|
||||
slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
|
||||
dev->ibi->max_payload_len);
|
||||
@@ -1566,6 +1550,7 @@ MODULE_DEVICE_TABLE(of, cdns_i3c_master_of_ids);
|
||||
static int cdns_i3c_master_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_i3c_master *master;
|
||||
struct clk *pclk;
|
||||
int ret, irq;
|
||||
u32 val;
|
||||
|
||||
@@ -1581,11 +1566,11 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(master->regs))
|
||||
return PTR_ERR(master->regs);
|
||||
|
||||
master->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(master->pclk))
|
||||
return PTR_ERR(master->pclk);
|
||||
pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
|
||||
if (IS_ERR(pclk))
|
||||
return PTR_ERR(pclk);
|
||||
|
||||
master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
|
||||
master->sysclk = devm_clk_get_enabled(&pdev->dev, "sysclk");
|
||||
if (IS_ERR(master->sysclk))
|
||||
return PTR_ERR(master->sysclk);
|
||||
|
||||
@@ -1593,18 +1578,8 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = clk_prepare_enable(master->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(master->sysclk);
|
||||
if (ret)
|
||||
goto err_disable_pclk;
|
||||
|
||||
if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
|
||||
ret = -EINVAL;
|
||||
goto err_disable_sysclk;
|
||||
}
|
||||
if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_init(&master->xferqueue.lock);
|
||||
INIT_LIST_HEAD(&master->xferqueue.list);
|
||||
@@ -1615,7 +1590,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
|
||||
dev_name(&pdev->dev), master);
|
||||
if (ret)
|
||||
goto err_disable_sysclk;
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
@@ -1637,29 +1612,15 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
|
||||
master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
|
||||
sizeof(*master->ibi.slots),
|
||||
GFP_KERNEL);
|
||||
if (!master->ibi.slots) {
|
||||
ret = -ENOMEM;
|
||||
goto err_disable_sysclk;
|
||||
}
|
||||
if (!master->ibi.slots)
|
||||
return -ENOMEM;
|
||||
|
||||
writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
|
||||
writel(MST_INT_IBIR_THR, master->regs + MST_IER);
|
||||
writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
|
||||
|
||||
ret = i3c_master_register(&master->base, &pdev->dev,
|
||||
&cdns_i3c_master_ops, false);
|
||||
if (ret)
|
||||
goto err_disable_sysclk;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_sysclk:
|
||||
clk_disable_unprepare(master->sysclk);
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable_unprepare(master->pclk);
|
||||
|
||||
return ret;
|
||||
return i3c_master_register(&master->base, &pdev->dev,
|
||||
&cdns_i3c_master_ops, false);
|
||||
}
|
||||
|
||||
static void cdns_i3c_master_remove(struct platform_device *pdev)
|
||||
@@ -1668,9 +1629,6 @@ static void cdns_i3c_master_remove(struct platform_device *pdev)
|
||||
|
||||
cancel_work_sync(&master->hj_work);
|
||||
i3c_master_unregister(&master->base);
|
||||
|
||||
clk_disable_unprepare(master->sysclk);
|
||||
clk_disable_unprepare(master->pclk);
|
||||
}
|
||||
|
||||
static struct platform_driver cdns_i3c_master = {
|
||||
|
||||
@@ -395,7 +395,7 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
ret = hci->io->queue_xfer(hci, xfer, nxfers);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (!wait_for_completion_timeout(&done, HZ) &&
|
||||
if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
|
||||
hci->io->dequeue_xfer(hci, xfer, nxfers)) {
|
||||
ret = -ETIME;
|
||||
goto out;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -104,6 +104,7 @@
|
||||
#define SVC_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4)
|
||||
#define SVC_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0
|
||||
#define SVC_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x))
|
||||
#define SVC_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x))
|
||||
#define SVC_I3C_MDATACTRL_TXFULL BIT(30)
|
||||
#define SVC_I3C_MDATACTRL_RXEMPTY BIT(31)
|
||||
|
||||
@@ -664,7 +665,6 @@ static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
|
||||
}
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return ret;
|
||||
@@ -779,7 +779,6 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
|
||||
goto rpm_out;
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return ret;
|
||||
@@ -801,7 +800,6 @@ static void svc_i3c_master_bus_cleanup(struct i3c_master_controller *m)
|
||||
/* Disable master */
|
||||
writel(0, master->regs + SVC_I3C_MCONFIG);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
}
|
||||
|
||||
@@ -1207,7 +1205,6 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
|
||||
dev_err(master->dev, "Cannot handle such a list of devices");
|
||||
|
||||
rpm_out:
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return ret;
|
||||
@@ -1304,14 +1301,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
|
||||
* FIFO start filling as soon as possible after EmitStartAddr.
|
||||
*/
|
||||
if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
|
||||
u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END;
|
||||
u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE);
|
||||
u32 space, end, len;
|
||||
|
||||
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
|
||||
/* Mark END bit if this is the last byte */
|
||||
writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
|
||||
xfer_len -= len;
|
||||
out += len;
|
||||
reg = readl(master->regs + SVC_I3C_MDATACTRL);
|
||||
space = SVC_I3C_FIFO_SIZE - SVC_I3C_MDATACTRL_TXCOUNT(reg);
|
||||
if (space) {
|
||||
end = xfer_len > space ? 0 : SVC_I3C_MWDATAB_END;
|
||||
len = min_t(u32, xfer_len, space);
|
||||
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
|
||||
/* Mark END bit if this is the last byte */
|
||||
writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
|
||||
xfer_len -= len;
|
||||
out += len;
|
||||
}
|
||||
}
|
||||
|
||||
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
|
||||
@@ -1511,7 +1513,6 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
|
||||
}
|
||||
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
}
|
||||
|
||||
@@ -1708,7 +1709,7 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
|
||||
|
||||
mutex_lock(&master->lock);
|
||||
svc_i3c_master_enqueue_xfer(master, xfer);
|
||||
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
|
||||
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
|
||||
svc_i3c_master_dequeue_xfer(master, xfer);
|
||||
mutex_unlock(&master->lock);
|
||||
|
||||
@@ -1801,7 +1802,6 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
|
||||
|
||||
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return ret;
|
||||
@@ -1834,7 +1834,6 @@ static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
|
||||
if (!master->enabled_events)
|
||||
svc_i3c_master_disable_interrupts(master);
|
||||
|
||||
pm_runtime_mark_last_busy(master->dev);
|
||||
pm_runtime_put_autosuspend(master->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1954,7 +1953,6 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto rpm_disable;
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4610,7 +4610,7 @@ static int mvneta_stop(struct net_device *dev)
|
||||
/* Inform that we are stopping so we don't want to setup the
|
||||
* driver for new CPUs in the notifiers. The code of the
|
||||
* notifier for CPU online is protected by the same spinlock,
|
||||
* so when we get the lock, the notifer work is done.
|
||||
* so when we get the lock, the notifier work is done.
|
||||
*/
|
||||
spin_lock(&pp->lock);
|
||||
pp->is_stopped = true;
|
||||
|
||||
@@ -51,8 +51,7 @@ static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
|
||||
}
|
||||
|
||||
static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
|
||||
void *prev_subbuf,
|
||||
size_t prev_padding)
|
||||
void *prev_subbuf)
|
||||
{
|
||||
if (relay_buf_full(buf)) {
|
||||
pr_err_ratelimited("Relay_buf full dropping traces");
|
||||
|
||||
@@ -33,7 +33,7 @@ static int t7xx_trace_remove_buf_file_handler(struct dentry *dentry)
|
||||
}
|
||||
|
||||
static int t7xx_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
|
||||
void *prev_subbuf, size_t prev_padding)
|
||||
void *prev_subbuf)
|
||||
{
|
||||
if (relay_buf_full(buf)) {
|
||||
pr_err_ratelimited("Relay_buf full dropping traces");
|
||||
|
||||
+226
-24
@@ -3,12 +3,15 @@
|
||||
* PCI Hotplug Driver for PowerPC PowerNV platform.
|
||||
*
|
||||
* Copyright Gavin Shan, IBM Corporation 2016.
|
||||
* Copyright (C) 2025 Raptor Engineering, LLC
|
||||
* Copyright (C) 2025 Raptor Computing Systems, LLC
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
@@ -36,8 +39,10 @@ static void pnv_php_register(struct device_node *dn);
|
||||
static void pnv_php_unregister_one(struct device_node *dn);
|
||||
static void pnv_php_unregister(struct device_node *dn);
|
||||
|
||||
static void pnv_php_enable_irq(struct pnv_php_slot *php_slot);
|
||||
|
||||
static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
|
||||
bool disable_device)
|
||||
bool disable_device, bool disable_msi)
|
||||
{
|
||||
struct pci_dev *pdev = php_slot->pdev;
|
||||
u16 ctrl;
|
||||
@@ -53,19 +58,15 @@ static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
|
||||
php_slot->irq = 0;
|
||||
}
|
||||
|
||||
if (php_slot->wq) {
|
||||
destroy_workqueue(php_slot->wq);
|
||||
php_slot->wq = NULL;
|
||||
}
|
||||
|
||||
if (disable_device) {
|
||||
if (disable_device || disable_msi) {
|
||||
if (pdev->msix_enabled)
|
||||
pci_disable_msix(pdev);
|
||||
else if (pdev->msi_enabled)
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
if (disable_device)
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static void pnv_php_free_slot(struct kref *kref)
|
||||
@@ -74,7 +75,8 @@ static void pnv_php_free_slot(struct kref *kref)
|
||||
struct pnv_php_slot, kref);
|
||||
|
||||
WARN_ON(!list_empty(&php_slot->children));
|
||||
pnv_php_disable_irq(php_slot, false);
|
||||
pnv_php_disable_irq(php_slot, false, false);
|
||||
destroy_workqueue(php_slot->wq);
|
||||
kfree(php_slot->name);
|
||||
kfree(php_slot);
|
||||
}
|
||||
@@ -391,6 +393,20 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcie_check_link_active(struct pci_dev *pdev)
|
||||
{
|
||||
u16 lnk_status;
|
||||
int ret;
|
||||
|
||||
ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
|
||||
if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
|
||||
return -ENODEV;
|
||||
|
||||
ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
|
||||
{
|
||||
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
|
||||
@@ -403,6 +419,19 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
|
||||
*/
|
||||
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
|
||||
if (ret >= 0) {
|
||||
if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
|
||||
presence == OPAL_PCI_SLOT_EMPTY) {
|
||||
/*
|
||||
* Similar to pciehp_hpc, check whether the Link Active
|
||||
* bit is set to account for broken downstream bridges
|
||||
* that don't properly assert Presence Detect State, as
|
||||
* was observed on the Microsemi Switchtec PM8533 PFX
|
||||
* [11f8:8533].
|
||||
*/
|
||||
if (pcie_check_link_active(php_slot->pdev) > 0)
|
||||
presence = OPAL_PCI_SLOT_PRESENT;
|
||||
}
|
||||
|
||||
*state = presence;
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -412,10 +441,23 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pnv_php_get_raw_indicator_status(struct hotplug_slot *slot, u8 *state)
|
||||
{
|
||||
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
|
||||
struct pci_dev *bridge = php_slot->pdev;
|
||||
u16 status;
|
||||
|
||||
pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
|
||||
*state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
|
||||
{
|
||||
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
|
||||
|
||||
pnv_php_get_raw_indicator_status(slot, &php_slot->attention_state);
|
||||
*state = php_slot->attention_state;
|
||||
return 0;
|
||||
}
|
||||
@@ -433,7 +475,7 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
|
||||
mask = PCI_EXP_SLTCTL_AIC;
|
||||
|
||||
if (state)
|
||||
new = PCI_EXP_SLTCTL_ATTN_IND_ON;
|
||||
new = FIELD_PREP(PCI_EXP_SLTCTL_AIC, state);
|
||||
else
|
||||
new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
|
||||
|
||||
@@ -442,6 +484,61 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
|
||||
struct hotplug_slot *slot)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* Issue initial slot activation command to firmware
|
||||
*
|
||||
* Firmware will power slot on, attempt to train the link, and
|
||||
* discover any downstream devices. If this process fails, firmware
|
||||
* will return an error code and an invalid device tree. Failure
|
||||
* can be caused for multiple reasons, including a faulty
|
||||
* downstream device, poor connection to the downstream device, or
|
||||
* a previously latched PHB fence. On failure, issue fundamental
|
||||
* reset up to three times before aborting.
|
||||
*/
|
||||
ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
|
||||
if (ret) {
|
||||
SLOT_WARN(
|
||||
php_slot,
|
||||
"PCI slot activation failed with error code %d, possible frozen PHB",
|
||||
ret);
|
||||
SLOT_WARN(
|
||||
php_slot,
|
||||
"Attempting complete PHB reset before retrying slot activation\n");
|
||||
for (i = 0; i < 3; i++) {
|
||||
/*
|
||||
* Slot activation failed, PHB may be fenced from a
|
||||
* prior device failure.
|
||||
*
|
||||
* Use the OPAL fundamental reset call to both try a
|
||||
* device reset and clear any potentially active PHB
|
||||
* fence / freeze.
|
||||
*/
|
||||
SLOT_WARN(php_slot, "Try %d...\n", i + 1);
|
||||
pci_set_pcie_reset_state(php_slot->pdev,
|
||||
pcie_warm_reset);
|
||||
msleep(250);
|
||||
pci_set_pcie_reset_state(php_slot->pdev,
|
||||
pcie_deassert_reset);
|
||||
|
||||
ret = pnv_php_set_slot_power_state(
|
||||
slot, OPAL_PCI_SLOT_POWER_ON);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= 3)
|
||||
SLOT_WARN(php_slot,
|
||||
"Failed to bring slot online, aborting!\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
|
||||
{
|
||||
struct hotplug_slot *slot = &php_slot->slot;
|
||||
@@ -504,7 +601,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
|
||||
goto scan;
|
||||
|
||||
/* Power is off, turn it on and then scan the slot */
|
||||
ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
|
||||
ret = pnv_php_activate_slot(php_slot, slot);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -561,8 +658,58 @@ static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
|
||||
static int pnv_php_enable_slot(struct hotplug_slot *slot)
|
||||
{
|
||||
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
|
||||
u32 prop32;
|
||||
int ret;
|
||||
|
||||
return pnv_php_enable(php_slot, true);
|
||||
ret = pnv_php_enable(php_slot, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* (Re-)enable interrupt if the slot supports surprise hotplug */
|
||||
ret = of_property_read_u32(php_slot->dn, "ibm,slot-surprise-pluggable",
|
||||
&prop32);
|
||||
if (!ret && prop32)
|
||||
pnv_php_enable_irq(php_slot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable any hotplug interrupts for all slots on the provided bus, as well as
|
||||
* all downstream slots in preparation for a hot unplug.
|
||||
*/
|
||||
static int pnv_php_disable_all_irqs(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_bus *child_bus;
|
||||
struct pci_slot *slot;
|
||||
|
||||
/* First go down child buses */
|
||||
list_for_each_entry(child_bus, &bus->children, node)
|
||||
pnv_php_disable_all_irqs(child_bus);
|
||||
|
||||
/* Disable IRQs for all pnv_php slots on this bus */
|
||||
list_for_each_entry(slot, &bus->slots, list) {
|
||||
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot->hotplug);
|
||||
|
||||
pnv_php_disable_irq(php_slot, false, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable any hotplug interrupts for all downstream slots on the provided
|
||||
* bus in preparation for a hot unplug.
|
||||
*/
|
||||
static int pnv_php_disable_all_downstream_irqs(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_bus *child_bus;
|
||||
|
||||
/* Go down child buses, recursively deactivating their IRQs */
|
||||
list_for_each_entry(child_bus, &bus->children, node)
|
||||
pnv_php_disable_all_irqs(child_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_php_disable_slot(struct hotplug_slot *slot)
|
||||
@@ -579,6 +726,13 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot)
|
||||
php_slot->state != PNV_PHP_STATE_REGISTERED)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Free all IRQ resources from all child slots before remove.
|
||||
* Note that we do not disable the root slot IRQ here as that
|
||||
* would also deactivate the slot hot (re)plug interrupt!
|
||||
*/
|
||||
pnv_php_disable_all_downstream_irqs(php_slot->bus);
|
||||
|
||||
/* Remove all devices behind the slot */
|
||||
pci_lock_rescan_remove();
|
||||
pci_hp_remove_devices(php_slot->bus);
|
||||
@@ -647,6 +801,15 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate workqueue for this slot's interrupt handling */
|
||||
php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
|
||||
if (!php_slot->wq) {
|
||||
SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
|
||||
kfree(php_slot->name);
|
||||
kfree(php_slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dn->child && PCI_DN(dn->child))
|
||||
php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
|
||||
else
|
||||
@@ -745,16 +908,63 @@ static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
|
||||
return entry.vector;
|
||||
}
|
||||
|
||||
static void
|
||||
pnv_php_detect_clear_suprise_removal_freeze(struct pnv_php_slot *php_slot)
|
||||
{
|
||||
struct pci_dev *pdev = php_slot->pdev;
|
||||
struct eeh_dev *edev;
|
||||
struct eeh_pe *pe;
|
||||
int i, rc;
|
||||
|
||||
/*
|
||||
* When a device is surprise removed from a downstream bridge slot,
|
||||
* the upstream bridge port can still end up frozen due to related EEH
|
||||
* events, which will in turn block the MSI interrupts for slot hotplug
|
||||
* detection.
|
||||
*
|
||||
* Detect and thaw any frozen upstream PE after slot deactivation.
|
||||
*/
|
||||
edev = pci_dev_to_eeh_dev(pdev);
|
||||
pe = edev ? edev->pe : NULL;
|
||||
rc = eeh_pe_get_state(pe);
|
||||
if ((rc == -ENODEV) || (rc == -ENOENT)) {
|
||||
SLOT_WARN(
|
||||
php_slot,
|
||||
"Upstream bridge PE state unknown, hotplug detect may fail\n");
|
||||
} else {
|
||||
if (pe->state & EEH_PE_ISOLATED) {
|
||||
SLOT_WARN(
|
||||
php_slot,
|
||||
"Upstream bridge PE %02x frozen, thawing...\n",
|
||||
pe->addr);
|
||||
for (i = 0; i < 3; i++)
|
||||
if (!eeh_unfreeze_pe(pe))
|
||||
break;
|
||||
if (i >= 3)
|
||||
SLOT_WARN(
|
||||
php_slot,
|
||||
"Unable to thaw PE %02x, hotplug detect will fail!\n",
|
||||
pe->addr);
|
||||
else
|
||||
SLOT_WARN(php_slot,
|
||||
"PE %02x thawed successfully\n",
|
||||
pe->addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_php_event_handler(struct work_struct *work)
|
||||
{
|
||||
struct pnv_php_event *event =
|
||||
container_of(work, struct pnv_php_event, work);
|
||||
struct pnv_php_slot *php_slot = event->php_slot;
|
||||
|
||||
if (event->added)
|
||||
if (event->added) {
|
||||
pnv_php_enable_slot(&php_slot->slot);
|
||||
else
|
||||
} else {
|
||||
pnv_php_disable_slot(&php_slot->slot);
|
||||
pnv_php_detect_clear_suprise_removal_freeze(php_slot);
|
||||
}
|
||||
|
||||
kfree(event);
|
||||
}
|
||||
@@ -843,14 +1053,6 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
|
||||
u16 sts, ctrl;
|
||||
int ret;
|
||||
|
||||
/* Allocate workqueue */
|
||||
php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
|
||||
if (!php_slot->wq) {
|
||||
SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
|
||||
pnv_php_disable_irq(php_slot, true);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check PDC (Presence Detection Change) is broken or not */
|
||||
ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
|
||||
&broken_pdc);
|
||||
@@ -869,7 +1071,7 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
|
||||
ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
|
||||
php_slot->name, php_slot);
|
||||
if (ret) {
|
||||
pnv_php_disable_irq(php_slot, true);
|
||||
pnv_php_disable_irq(php_slot, true, true);
|
||||
SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -356,7 +356,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
|
||||
|
||||
if (!fat_valid_entry(sbi, entry)) {
|
||||
fatent_brelse(fatent);
|
||||
fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
|
||||
fat_fs_error_ratelimit(sb, "invalid access to FAT (entry 0x%08x)", entry);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -158,9 +158,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
|
||||
fat_fs_error(sb, "clusters badly computed (%d != %llu)",
|
||||
new_fclus,
|
||||
(llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
|
||||
fat_fs_error_ratelimit(
|
||||
sb, "clusters badly computed (%d != %llu)", new_fclus,
|
||||
(llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
|
||||
fat_cache_inval_inode(inode);
|
||||
}
|
||||
inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
|
||||
|
||||
@@ -1071,6 +1071,7 @@ static int ocfs2_grab_folios_for_write(struct address_space *mapping,
|
||||
if (IS_ERR(wc->w_folios[i])) {
|
||||
ret = PTR_ERR(wc->w_folios[i]);
|
||||
mlog_errno(ret);
|
||||
wc->w_folios[i] = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,6 +798,14 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
|
||||
}
|
||||
}
|
||||
|
||||
if (le16_to_cpu(el->l_next_free_rec) == 0) {
|
||||
ret = ocfs2_error(inode->i_sb,
|
||||
"Inode %lu has empty extent list at depth %u\n",
|
||||
inode->i_ino,
|
||||
le16_to_cpu(el->l_tree_depth));
|
||||
goto out;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
|
||||
rec = &el->l_recs[i];
|
||||
|
||||
@@ -2632,7 +2632,7 @@ again:
|
||||
dlm_reco_master_ready(dlm),
|
||||
msecs_to_jiffies(1000));
|
||||
if (!dlm_reco_master_ready(dlm)) {
|
||||
mlog(0, "%s: reco master taking awhile\n",
|
||||
mlog(0, "%s: reco master taking a while\n",
|
||||
dlm->name);
|
||||
goto again;
|
||||
}
|
||||
|
||||
+66
-4
@@ -50,8 +50,6 @@ struct ocfs2_find_inode_args
|
||||
unsigned int fi_sysfile_type;
|
||||
};
|
||||
|
||||
static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
|
||||
|
||||
static int ocfs2_read_locked_inode(struct inode *inode,
|
||||
struct ocfs2_find_inode_args *args);
|
||||
static int ocfs2_init_locked_inode(struct inode *inode, void *opaque);
|
||||
@@ -250,14 +248,77 @@ bail:
|
||||
static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
|
||||
{
|
||||
struct ocfs2_find_inode_args *args = opaque;
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
|
||||
static struct lock_class_key ocfs2_quota_ip_alloc_sem_key,
|
||||
ocfs2_file_ip_alloc_sem_key;
|
||||
#endif
|
||||
|
||||
inode->i_ino = args->fi_ino;
|
||||
OCFS2_I(inode)->ip_blkno = args->fi_blkno;
|
||||
if (args->fi_sysfile_type != 0)
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
switch (args->fi_sysfile_type) {
|
||||
case BAD_BLOCK_SYSTEM_INODE:
|
||||
break;
|
||||
case GLOBAL_INODE_ALLOC_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
|
||||
&ocfs2_sysfile_lock_key[GLOBAL_INODE_ALLOC_SYSTEM_INODE]);
|
||||
break;
|
||||
case SLOT_MAP_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[SLOT_MAP_SYSTEM_INODE]);
|
||||
break;
|
||||
case HEARTBEAT_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[HEARTBEAT_SYSTEM_INODE]);
|
||||
break;
|
||||
case GLOBAL_BITMAP_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[GLOBAL_BITMAP_SYSTEM_INODE]);
|
||||
break;
|
||||
case USER_QUOTA_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[USER_QUOTA_SYSTEM_INODE]);
|
||||
break;
|
||||
case GROUP_QUOTA_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[GROUP_QUOTA_SYSTEM_INODE]);
|
||||
break;
|
||||
case ORPHAN_DIR_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);
|
||||
break;
|
||||
case EXTENT_ALLOC_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]);
|
||||
break;
|
||||
case INODE_ALLOC_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]);
|
||||
break;
|
||||
case JOURNAL_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[JOURNAL_SYSTEM_INODE]);
|
||||
break;
|
||||
case LOCAL_ALLOC_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[LOCAL_ALLOC_SYSTEM_INODE]);
|
||||
break;
|
||||
case TRUNCATE_LOG_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[TRUNCATE_LOG_SYSTEM_INODE]);
|
||||
break;
|
||||
case LOCAL_USER_QUOTA_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[LOCAL_USER_QUOTA_SYSTEM_INODE]);
|
||||
break;
|
||||
case LOCAL_GROUP_QUOTA_SYSTEM_INODE:
|
||||
lockdep_set_class(&inode->i_rwsem,
|
||||
&ocfs2_sysfile_lock_key[LOCAL_GROUP_QUOTA_SYSTEM_INODE]);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Unknown sysfile type %d\n", args->fi_sysfile_type);
|
||||
}
|
||||
if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE ||
|
||||
args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE ||
|
||||
args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE ||
|
||||
@@ -267,6 +328,7 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
|
||||
else
|
||||
lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem,
|
||||
&ocfs2_file_ip_alloc_sem_key);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+9
-10
@@ -617,6 +617,8 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
|
||||
*/
|
||||
credits += OCFS2_INODE_UPDATE_CREDITS + 1;
|
||||
|
||||
inode_lock(tl_inode);
|
||||
|
||||
/*
|
||||
* ocfs2_move_extent() didn't reserve any clusters in lock_allocators()
|
||||
* logic, while we still need to lock the global_bitmap.
|
||||
@@ -626,7 +628,7 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
|
||||
if (!gb_inode) {
|
||||
mlog(ML_ERROR, "unable to get global_bitmap inode\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
goto out_unlock_tl_inode;
|
||||
}
|
||||
|
||||
inode_lock(gb_inode);
|
||||
@@ -634,16 +636,14 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
|
||||
ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto out_unlock_gb_mutex;
|
||||
goto out_unlock_gb_inode;
|
||||
}
|
||||
|
||||
inode_lock(tl_inode);
|
||||
|
||||
handle = ocfs2_start_trans(osb, credits);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
mlog_errno(ret);
|
||||
goto out_unlock_tl_inode;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos);
|
||||
@@ -703,15 +703,14 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
|
||||
out_commit:
|
||||
ocfs2_commit_trans(osb, handle);
|
||||
brelse(gd_bh);
|
||||
|
||||
out_unlock_tl_inode:
|
||||
inode_unlock(tl_inode);
|
||||
|
||||
out_unlock:
|
||||
ocfs2_inode_unlock(gb_inode, 1);
|
||||
out_unlock_gb_mutex:
|
||||
out_unlock_gb_inode:
|
||||
inode_unlock(gb_inode);
|
||||
brelse(gb_bh);
|
||||
iput(gb_inode);
|
||||
out_unlock_tl_inode:
|
||||
inode_unlock(tl_inode);
|
||||
|
||||
out:
|
||||
if (context->meta_ac) {
|
||||
|
||||
+7
-4
@@ -142,6 +142,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
bail_add:
|
||||
ret = d_splice_alias(inode, dentry);
|
||||
if (IS_ERR(ret))
|
||||
goto bail_unlock;
|
||||
|
||||
if (inode) {
|
||||
/*
|
||||
@@ -154,15 +156,16 @@ bail_add:
|
||||
* NOTE: This dentry already has ->d_op set from
|
||||
* ocfs2_get_parent() and ocfs2_get_dentry()
|
||||
*/
|
||||
if (!IS_ERR_OR_NULL(ret))
|
||||
if (ret)
|
||||
dentry = ret;
|
||||
|
||||
status = ocfs2_dentry_attach_lock(dentry, inode,
|
||||
OCFS2_I(dir)->ip_blkno);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
if (ret)
|
||||
dput(ret);
|
||||
ret = ERR_PTR(status);
|
||||
goto bail_unlock;
|
||||
}
|
||||
} else
|
||||
ocfs2_dentry_attach_gen(dentry);
|
||||
@@ -1452,8 +1455,8 @@ static int ocfs2_rename(struct mnt_idmap *idmap,
|
||||
newfe = (struct ocfs2_dinode *) newfe_bh->b_data;
|
||||
|
||||
trace_ocfs2_rename_over_existing(
|
||||
(unsigned long long)newfe_blkno, newfe_bh, newfe_bh ?
|
||||
(unsigned long long)newfe_bh->b_blocknr : 0ULL);
|
||||
(unsigned long long)newfe_blkno, newfe_bh,
|
||||
(unsigned long long)newfe_bh->b_blocknr);
|
||||
|
||||
if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
|
||||
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
|
||||
|
||||
+4
-11
@@ -360,7 +360,6 @@ static int ocfs2_control_do_setnode_msg(struct file *file,
|
||||
struct ocfs2_control_message_setn *msg)
|
||||
{
|
||||
long nodenum;
|
||||
char *ptr = NULL;
|
||||
struct ocfs2_control_private *p = file->private_data;
|
||||
|
||||
if (ocfs2_control_get_handshake_state(file) !=
|
||||
@@ -375,8 +374,7 @@ static int ocfs2_control_do_setnode_msg(struct file *file,
|
||||
return -EINVAL;
|
||||
msg->space = msg->newline = '\0';
|
||||
|
||||
nodenum = simple_strtol(msg->nodestr, &ptr, 16);
|
||||
if (!ptr || *ptr)
|
||||
if (kstrtol(msg->nodestr, 16, &nodenum))
|
||||
return -EINVAL;
|
||||
|
||||
if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
|
||||
@@ -391,7 +389,6 @@ static int ocfs2_control_do_setversion_msg(struct file *file,
|
||||
struct ocfs2_control_message_setv *msg)
|
||||
{
|
||||
long major, minor;
|
||||
char *ptr = NULL;
|
||||
struct ocfs2_control_private *p = file->private_data;
|
||||
struct ocfs2_protocol_version *max =
|
||||
&ocfs2_user_plugin.sp_max_proto;
|
||||
@@ -409,11 +406,9 @@ static int ocfs2_control_do_setversion_msg(struct file *file,
|
||||
return -EINVAL;
|
||||
msg->space1 = msg->space2 = msg->newline = '\0';
|
||||
|
||||
major = simple_strtol(msg->major, &ptr, 16);
|
||||
if (!ptr || *ptr)
|
||||
if (kstrtol(msg->major, 16, &major))
|
||||
return -EINVAL;
|
||||
minor = simple_strtol(msg->minor, &ptr, 16);
|
||||
if (!ptr || *ptr)
|
||||
if (kstrtol(msg->minor, 16, &minor))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
@@ -441,7 +436,6 @@ static int ocfs2_control_do_down_msg(struct file *file,
|
||||
struct ocfs2_control_message_down *msg)
|
||||
{
|
||||
long nodenum;
|
||||
char *p = NULL;
|
||||
|
||||
if (ocfs2_control_get_handshake_state(file) !=
|
||||
OCFS2_CONTROL_HANDSHAKE_VALID)
|
||||
@@ -456,8 +450,7 @@ static int ocfs2_control_do_down_msg(struct file *file,
|
||||
return -EINVAL;
|
||||
msg->space1 = msg->space2 = msg->newline = '\0';
|
||||
|
||||
nodenum = simple_strtol(msg->nodestr, &p, 16);
|
||||
if (!p || *p)
|
||||
if (kstrtol(msg->nodestr, 16, &nodenum))
|
||||
return -EINVAL;
|
||||
|
||||
if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
|
||||
|
||||
+12
-17
@@ -1490,10 +1490,8 @@ int vmcore_add_device_dump(struct vmcoredd_data *data)
|
||||
return -EINVAL;
|
||||
|
||||
dump = vzalloc(sizeof(*dump));
|
||||
if (!dump) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
if (!dump)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Keep size of the buffer page aligned so that it can be mmaped */
|
||||
data_size = roundup(sizeof(struct vmcoredd_header) + data->size,
|
||||
@@ -1519,22 +1517,19 @@ int vmcore_add_device_dump(struct vmcoredd_data *data)
|
||||
dump->size = data_size;
|
||||
|
||||
/* Add the dump to driver sysfs list and update the elfcore hdr */
|
||||
mutex_lock(&vmcore_mutex);
|
||||
if (vmcore_opened)
|
||||
pr_warn_once("Unexpected adding of device dump\n");
|
||||
if (vmcore_open) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
scoped_guard(mutex, &vmcore_mutex) {
|
||||
if (vmcore_opened)
|
||||
pr_warn_once("Unexpected adding of device dump\n");
|
||||
if (vmcore_open) {
|
||||
ret = -EBUSY;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
list_add_tail(&dump->list, &vmcoredd_list);
|
||||
vmcoredd_update_size(data_size);
|
||||
}
|
||||
|
||||
list_add_tail(&dump->list, &vmcoredd_list);
|
||||
vmcoredd_update_size(data_size);
|
||||
mutex_unlock(&vmcore_mutex);
|
||||
return 0;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&vmcore_mutex);
|
||||
|
||||
out_err:
|
||||
vfree(buf);
|
||||
vfree(dump);
|
||||
|
||||
+23
-24
@@ -80,23 +80,22 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
|
||||
struct address_space *cache_mapping, u64 index, int length,
|
||||
u64 read_start, u64 read_end, int page_count)
|
||||
{
|
||||
struct page *head_to_cache = NULL, *tail_to_cache = NULL;
|
||||
struct folio *head_to_cache = NULL, *tail_to_cache = NULL;
|
||||
struct block_device *bdev = fullbio->bi_bdev;
|
||||
int start_idx = 0, end_idx = 0;
|
||||
struct bvec_iter_all iter_all;
|
||||
struct folio_iter fi;
|
||||
struct bio *bio = NULL;
|
||||
struct bio_vec *bv;
|
||||
int idx = 0;
|
||||
int err = 0;
|
||||
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
|
||||
struct page **cache_pages = kmalloc_array(page_count,
|
||||
sizeof(void *), GFP_KERNEL | __GFP_ZERO);
|
||||
struct folio **cache_folios = kmalloc_array(page_count,
|
||||
sizeof(*cache_folios), GFP_KERNEL | __GFP_ZERO);
|
||||
#endif
|
||||
|
||||
bio_for_each_segment_all(bv, fullbio, iter_all) {
|
||||
struct page *page = bv->bv_page;
|
||||
bio_for_each_folio_all(fi, fullbio) {
|
||||
struct folio *folio = fi.folio;
|
||||
|
||||
if (page->mapping == cache_mapping) {
|
||||
if (folio->mapping == cache_mapping) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
@@ -111,13 +110,13 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
|
||||
* adjacent blocks.
|
||||
*/
|
||||
if (idx == 0 && index != read_start)
|
||||
head_to_cache = page;
|
||||
head_to_cache = folio;
|
||||
else if (idx == page_count - 1 && index + length != read_end)
|
||||
tail_to_cache = page;
|
||||
tail_to_cache = folio;
|
||||
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
|
||||
/* Cache all pages in the BIO for repeated reads */
|
||||
else if (cache_pages)
|
||||
cache_pages[idx] = page;
|
||||
else if (cache_folios)
|
||||
cache_folios[idx] = folio;
|
||||
#endif
|
||||
|
||||
if (!bio || idx != end_idx) {
|
||||
@@ -150,45 +149,45 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
|
||||
return err;
|
||||
|
||||
if (head_to_cache) {
|
||||
int ret = add_to_page_cache_lru(head_to_cache, cache_mapping,
|
||||
int ret = filemap_add_folio(cache_mapping, head_to_cache,
|
||||
read_start >> PAGE_SHIFT,
|
||||
GFP_NOIO);
|
||||
|
||||
if (!ret) {
|
||||
SetPageUptodate(head_to_cache);
|
||||
unlock_page(head_to_cache);
|
||||
folio_mark_uptodate(head_to_cache);
|
||||
folio_unlock(head_to_cache);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tail_to_cache) {
|
||||
int ret = add_to_page_cache_lru(tail_to_cache, cache_mapping,
|
||||
int ret = filemap_add_folio(cache_mapping, tail_to_cache,
|
||||
(read_end >> PAGE_SHIFT) - 1,
|
||||
GFP_NOIO);
|
||||
|
||||
if (!ret) {
|
||||
SetPageUptodate(tail_to_cache);
|
||||
unlock_page(tail_to_cache);
|
||||
folio_mark_uptodate(tail_to_cache);
|
||||
folio_unlock(tail_to_cache);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
|
||||
if (!cache_pages)
|
||||
if (!cache_folios)
|
||||
goto out;
|
||||
|
||||
for (idx = 0; idx < page_count; idx++) {
|
||||
if (!cache_pages[idx])
|
||||
if (!cache_folios[idx])
|
||||
continue;
|
||||
int ret = add_to_page_cache_lru(cache_pages[idx], cache_mapping,
|
||||
int ret = filemap_add_folio(cache_mapping, cache_folios[idx],
|
||||
(read_start >> PAGE_SHIFT) + idx,
|
||||
GFP_NOIO);
|
||||
|
||||
if (!ret) {
|
||||
SetPageUptodate(cache_pages[idx]);
|
||||
unlock_page(cache_pages[idx]);
|
||||
folio_mark_uptodate(cache_folios[idx]);
|
||||
folio_unlock(cache_folios[idx]);
|
||||
}
|
||||
}
|
||||
kfree(cache_pages);
|
||||
kfree(cache_folios);
|
||||
out:
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
+3
-4
@@ -493,10 +493,9 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int squashfs_readahead_fragment(struct page **page,
|
||||
static int squashfs_readahead_fragment(struct inode *inode, struct page **page,
|
||||
unsigned int pages, unsigned int expected, loff_t start)
|
||||
{
|
||||
struct inode *inode = page[0]->mapping->host;
|
||||
struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
@@ -605,8 +604,8 @@ static void squashfs_readahead(struct readahead_control *ractl)
|
||||
|
||||
if (start >> msblk->block_log == file_end &&
|
||||
squashfs_i(inode)->fragment_block != SQUASHFS_INVALID_BLK) {
|
||||
res = squashfs_readahead_fragment(pages, nr_pages,
|
||||
expected, start);
|
||||
res = squashfs_readahead_fragment(inode, pages,
|
||||
nr_pages, expected, start);
|
||||
if (res)
|
||||
goto skip_pages;
|
||||
continue;
|
||||
|
||||
@@ -13,10 +13,23 @@
|
||||
*/
|
||||
extern struct resource crashk_res;
|
||||
extern struct resource crashk_low_res;
|
||||
extern struct range crashk_cma_ranges[];
|
||||
#if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION)
|
||||
#define CRASHKERNEL_CMA
|
||||
#define CRASHKERNEL_CMA_RANGES_MAX 4
|
||||
extern int crashk_cma_cnt;
|
||||
#else
|
||||
#define crashk_cma_cnt 0
|
||||
#define CRASHKERNEL_CMA_RANGES_MAX 0
|
||||
#endif
|
||||
|
||||
|
||||
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
|
||||
unsigned long long *crash_size, unsigned long long *crash_base,
|
||||
unsigned long long *low_size, bool *high);
|
||||
unsigned long long *low_size, unsigned long long *cma_size,
|
||||
bool *high);
|
||||
|
||||
void __init reserve_crashkernel_cma(unsigned long long cma_size);
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
|
||||
#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#define _GCD_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
DECLARE_STATIC_KEY_TRUE(efficient_ffs_key);
|
||||
|
||||
unsigned long gcd(unsigned long a, unsigned long b) __attribute_const__;
|
||||
|
||||
|
||||
@@ -21,17 +21,17 @@
|
||||
* type.
|
||||
*
|
||||
* Type encoding:
|
||||
* 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX)
|
||||
* 01 - Blocked on semaphore (BLOCKER_TYPE_SEM)
|
||||
* 10 - Blocked on rt-mutex (BLOCKER_TYPE_RTMUTEX)
|
||||
* 11 - Blocked on rw-semaphore (BLOCKER_TYPE_RWSEM)
|
||||
* 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX)
|
||||
* 01 - Blocked on semaphore (BLOCKER_TYPE_SEM)
|
||||
* 10 - Blocked on rw-semaphore as READER (BLOCKER_TYPE_RWSEM_READER)
|
||||
* 11 - Blocked on rw-semaphore as WRITER (BLOCKER_TYPE_RWSEM_WRITER)
|
||||
*/
|
||||
#define BLOCKER_TYPE_MUTEX 0x00UL
|
||||
#define BLOCKER_TYPE_SEM 0x01UL
|
||||
#define BLOCKER_TYPE_RTMUTEX 0x02UL
|
||||
#define BLOCKER_TYPE_RWSEM 0x03UL
|
||||
#define BLOCKER_TYPE_MUTEX 0x00UL
|
||||
#define BLOCKER_TYPE_SEM 0x01UL
|
||||
#define BLOCKER_TYPE_RWSEM_READER 0x02UL
|
||||
#define BLOCKER_TYPE_RWSEM_WRITER 0x03UL
|
||||
|
||||
#define BLOCKER_TYPE_MASK 0x03UL
|
||||
#define BLOCKER_TYPE_MASK 0x03UL
|
||||
|
||||
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
||||
static inline void hung_task_set_blocker(void *lock, unsigned long type)
|
||||
|
||||
@@ -245,7 +245,7 @@ void i3c_driver_unregister(struct i3c_driver *drv);
|
||||
*
|
||||
* Return: 0 if both registrations succeeds, a negative error code otherwise.
|
||||
*/
|
||||
static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
|
||||
static __always_inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
|
||||
struct i2c_driver *i2cdrv)
|
||||
{
|
||||
int ret;
|
||||
@@ -270,7 +270,7 @@ static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
|
||||
* Note that when CONFIG_I3C is not enabled, this function only unregisters the
|
||||
* @i2cdrv.
|
||||
*/
|
||||
static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
|
||||
static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
|
||||
struct i2c_driver *i2cdrv)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_I3C))
|
||||
|
||||
@@ -249,10 +249,15 @@ struct i3c_device {
|
||||
*/
|
||||
#define I3C_BUS_MAX_DEVS 11
|
||||
|
||||
#define I3C_BUS_MAX_I3C_SCL_RATE 12900000
|
||||
#define I3C_BUS_TYP_I3C_SCL_RATE 12500000
|
||||
#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000
|
||||
#define I3C_BUS_I2C_FM_SCL_RATE 400000
|
||||
/* Taken from the I3C Spec V1.1.1, chapter 6.2. "Timing specification" */
|
||||
#define I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE 1000000
|
||||
#define I3C_BUS_I2C_FM_SCL_MAX_RATE 400000
|
||||
#define I3C_BUS_I3C_SCL_MAX_RATE 12900000
|
||||
#define I3C_BUS_I3C_SCL_TYP_RATE 12500000
|
||||
#define I3C_BUS_TAVAL_MIN_NS 1000
|
||||
#define I3C_BUS_TBUF_MIXED_FM_MIN_NS 1300
|
||||
#define I3C_BUS_THIGH_MIXED_MAX_NS 41
|
||||
#define I3C_BUS_TIDLE_MIN_NS 200000
|
||||
#define I3C_BUS_TLOW_OD_MIN_NS 200
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* Jozsef
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/unaligned/packed_struct.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
/* Best hash sizes are of power of two */
|
||||
#define jhash_size(n) ((u32)1<<(n))
|
||||
@@ -77,9 +77,9 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
|
||||
|
||||
/* All but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12) {
|
||||
a += __get_unaligned_cpu32(k);
|
||||
b += __get_unaligned_cpu32(k + 4);
|
||||
c += __get_unaligned_cpu32(k + 8);
|
||||
a += get_unaligned((u32 *)k);
|
||||
b += get_unaligned((u32 *)(k + 4));
|
||||
c += get_unaligned((u32 *)(k + 8));
|
||||
__jhash_mix(a, b, c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
|
||||
@@ -79,6 +79,12 @@ extern note_buf_t __percpu *crash_notes;
|
||||
|
||||
typedef unsigned long kimage_entry_t;
|
||||
|
||||
/*
|
||||
* This is a copy of the UAPI struct kexec_segment and must be identical
|
||||
* to it because it gets copied straight from user space into kernel
|
||||
* memory. Do not modify this structure unless you change the way segments
|
||||
* get ingested from user space.
|
||||
*/
|
||||
struct kexec_segment {
|
||||
/*
|
||||
* This pointer can point to user memory if kexec_load() system
|
||||
@@ -172,6 +178,7 @@ int kexec_image_post_load_cleanup_default(struct kimage *image);
|
||||
* @buf_align: Minimum alignment needed.
|
||||
* @buf_min: The buffer can't be placed below this address.
|
||||
* @buf_max: The buffer can't be placed above this address.
|
||||
* @cma: CMA page if the buffer is backed by CMA.
|
||||
* @top_down: Allocate from top of memory.
|
||||
* @random: Place the buffer at a random position.
|
||||
*/
|
||||
@@ -184,6 +191,7 @@ struct kexec_buf {
|
||||
unsigned long buf_align;
|
||||
unsigned long buf_min;
|
||||
unsigned long buf_max;
|
||||
struct page *cma;
|
||||
bool top_down;
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
bool random;
|
||||
@@ -340,6 +348,7 @@ struct kimage {
|
||||
|
||||
unsigned long nr_segments;
|
||||
struct kexec_segment segment[KEXEC_SEGMENT_MAX];
|
||||
struct page *segment_cma[KEXEC_SEGMENT_MAX];
|
||||
|
||||
struct list_head control_pages;
|
||||
struct list_head dest_pages;
|
||||
@@ -361,6 +370,7 @@ struct kimage {
|
||||
*/
|
||||
unsigned int hotplug_support:1;
|
||||
#endif
|
||||
unsigned int no_cma:1;
|
||||
|
||||
#ifdef ARCH_HAS_KIMAGE_ARCH
|
||||
struct kimage_arch arch;
|
||||
|
||||
+11
-18
@@ -33,7 +33,7 @@
|
||||
#include <linux/percpu.h>
|
||||
#include <asm/module.h>
|
||||
|
||||
#define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
|
||||
#define MODULE_NAME_LEN __MODULE_NAME_LEN
|
||||
|
||||
struct modversion_info {
|
||||
unsigned long crc;
|
||||
@@ -303,23 +303,6 @@ static typeof(name) __mod_device_table__##type##__##name \
|
||||
|
||||
struct notifier_block;
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
/* Get/put a kernel symbol (calls must be symmetric) */
|
||||
void *__symbol_get(const char *symbol);
|
||||
void *__symbol_get_gpl(const char *symbol);
|
||||
#define symbol_get(x) ({ \
|
||||
static const char __notrim[] \
|
||||
__used __section(".no_trim_symbol") = __stringify(x); \
|
||||
(typeof(&x))(__symbol_get(__stringify(x))); })
|
||||
|
||||
/* modules using other modules: kdb wants to see this. */
|
||||
struct module_use {
|
||||
struct list_head source_list;
|
||||
struct list_head target_list;
|
||||
struct module *source, *target;
|
||||
};
|
||||
|
||||
enum module_state {
|
||||
MODULE_STATE_LIVE, /* Normal state. */
|
||||
MODULE_STATE_COMING, /* Full formed, running module_init. */
|
||||
@@ -607,6 +590,16 @@ struct module {
|
||||
#define MODULE_ARCH_INIT {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
/* Get/put a kernel symbol (calls must be symmetric) */
|
||||
void *__symbol_get(const char *symbol);
|
||||
void *__symbol_get_gpl(const char *symbol);
|
||||
#define symbol_get(x) ({ \
|
||||
static const char __notrim[] \
|
||||
__used __section(".no_trim_symbol") = __stringify(x); \
|
||||
(typeof(&x))(__symbol_get(__stringify(x))); })
|
||||
|
||||
#ifndef HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
|
||||
static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/*
|
||||
* The maximum module name length, including the NUL byte.
|
||||
* Chosen so that structs with an unsigned long line up, specifically
|
||||
* modversion_info.
|
||||
*/
|
||||
#define __MODULE_NAME_LEN (64 - sizeof(unsigned long))
|
||||
|
||||
/* You can override this manually, but generally this should match the
|
||||
module name. */
|
||||
#ifdef MODULE
|
||||
@@ -17,9 +24,6 @@
|
||||
#define __MODULE_INFO_PREFIX KBUILD_MODNAME "."
|
||||
#endif
|
||||
|
||||
/* Chosen so that structs with an unsigned long line up. */
|
||||
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
|
||||
|
||||
#define __MODULE_INFO(tag, name, info) \
|
||||
static const char __UNIQUE_ID(name)[] \
|
||||
__used __section(".modinfo") __aligned(1) \
|
||||
@@ -282,10 +286,9 @@ struct kparam_array
|
||||
#define __moduleparam_const const
|
||||
#endif
|
||||
|
||||
/* This is the fundamental function for registering boot/module
|
||||
parameters. */
|
||||
/* This is the fundamental function for registering boot/module parameters. */
|
||||
#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
|
||||
/* Default value instead of permissions? */ \
|
||||
static_assert(sizeof(""prefix) - 1 <= __MODULE_NAME_LEN); \
|
||||
static const char __param_str_##name[] = prefix #name; \
|
||||
static struct kernel_param __moduleparam_const __param_##name \
|
||||
__used __section("__param") \
|
||||
|
||||
+11
-1
@@ -11,8 +11,13 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
extern const char raid6_empty_zero_page[PAGE_SIZE];
|
||||
/* This should be const but the raid6 code is too convoluted for that. */
|
||||
static inline void *raid6_get_zero_page(void)
|
||||
{
|
||||
return page_address(ZERO_PAGE(0));
|
||||
}
|
||||
|
||||
#else /* ! __KERNEL__ */
|
||||
/* Used for testing in user space */
|
||||
@@ -191,6 +196,11 @@ static inline uint32_t raid6_jiffies(void)
|
||||
return tv.tv_sec*1000 + tv.tv_usec/1000;
|
||||
}
|
||||
|
||||
static inline void *raid6_get_zero_page(void)
|
||||
{
|
||||
return raid6_empty_zero_page;
|
||||
}
|
||||
|
||||
#endif /* ! __KERNEL__ */
|
||||
|
||||
#endif /* LINUX_RAID_RAID6_H */
|
||||
+19
-5
@@ -28,6 +28,22 @@
|
||||
*/
|
||||
#define RELAYFS_CHANNEL_VERSION 7
|
||||
|
||||
/*
|
||||
* Relay buffer statistics
|
||||
*/
|
||||
enum {
|
||||
RELAY_STATS_BUF_FULL = (1 << 0),
|
||||
RELAY_STATS_WRT_BIG = (1 << 1),
|
||||
|
||||
RELAY_STATS_LAST = RELAY_STATS_WRT_BIG,
|
||||
};
|
||||
|
||||
struct rchan_buf_stats
|
||||
{
|
||||
unsigned int full_count; /* counter for buffer full */
|
||||
unsigned int big_count; /* counter for too big to write */
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-cpu relay channel buffer
|
||||
*/
|
||||
@@ -43,11 +59,11 @@ struct rchan_buf
|
||||
struct irq_work wakeup_work; /* reader wakeup */
|
||||
struct dentry *dentry; /* channel file dentry */
|
||||
struct kref kref; /* channel buffer refcount */
|
||||
struct rchan_buf_stats stats; /* buffer stats */
|
||||
struct page **page_array; /* array of current buffer pages */
|
||||
unsigned int page_count; /* number of current buffer pages */
|
||||
unsigned int finalized; /* buffer has been finalized */
|
||||
size_t *padding; /* padding counts per sub-buffer */
|
||||
size_t prev_padding; /* temporary variable */
|
||||
size_t bytes_consumed; /* bytes consumed in cur read subbuf */
|
||||
size_t early_bytes; /* bytes consumed before VFS inited */
|
||||
unsigned int cpu; /* this buf's cpu */
|
||||
@@ -65,7 +81,6 @@ struct rchan
|
||||
const struct rchan_callbacks *cb; /* client callbacks */
|
||||
struct kref kref; /* channel refcount */
|
||||
void *private_data; /* for user-defined data */
|
||||
size_t last_toobig; /* tried to log event > subbuf size */
|
||||
struct rchan_buf * __percpu *buf; /* per-cpu channel buffers */
|
||||
int is_global; /* One global buffer ? */
|
||||
struct list_head list; /* for channel list */
|
||||
@@ -84,7 +99,6 @@ struct rchan_callbacks
|
||||
* @buf: the channel buffer containing the new sub-buffer
|
||||
* @subbuf: the start of the new sub-buffer
|
||||
* @prev_subbuf: the start of the previous sub-buffer
|
||||
* @prev_padding: unused space at the end of previous sub-buffer
|
||||
*
|
||||
* The client should return 1 to continue logging, 0 to stop
|
||||
* logging.
|
||||
@@ -100,8 +114,7 @@ struct rchan_callbacks
|
||||
*/
|
||||
int (*subbuf_start) (struct rchan_buf *buf,
|
||||
void *subbuf,
|
||||
void *prev_subbuf,
|
||||
size_t prev_padding);
|
||||
void *prev_subbuf);
|
||||
|
||||
/*
|
||||
* create_buf_file - create file to represent a relay channel buffer
|
||||
@@ -161,6 +174,7 @@ struct rchan *relay_open(const char *base_filename,
|
||||
void *private_data);
|
||||
extern void relay_close(struct rchan *chan);
|
||||
extern void relay_flush(struct rchan *chan);
|
||||
size_t relay_stats(struct rchan *chan, int flags);
|
||||
extern void relay_subbufs_consumed(struct rchan *chan,
|
||||
unsigned int cpu,
|
||||
size_t consumed);
|
||||
|
||||
@@ -144,6 +144,9 @@ int ring_buffer_write(struct trace_buffer *buffer,
|
||||
void ring_buffer_nest_start(struct trace_buffer *buffer);
|
||||
void ring_buffer_nest_end(struct trace_buffer *buffer);
|
||||
|
||||
DEFINE_GUARD(ring_buffer_nest, struct trace_buffer *,
|
||||
ring_buffer_nest_start(_T), ring_buffer_nest_end(_T))
|
||||
|
||||
struct ring_buffer_event *
|
||||
ring_buffer_peek(struct trace_buffer *buffer, int cpu, u64 *ts,
|
||||
unsigned long *lost_events);
|
||||
|
||||
@@ -132,6 +132,18 @@ static inline int rwsem_is_contended(struct rw_semaphore *sem)
|
||||
return !list_empty(&sem->wait_list);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER)
|
||||
/*
|
||||
* Return just the real task structure pointer of the owner
|
||||
*/
|
||||
extern struct task_struct *rwsem_owner(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* Return true if the rwsem is owned by a reader.
|
||||
*/
|
||||
extern bool is_rwsem_reader_owned(struct rw_semaphore *sem);
|
||||
#endif
|
||||
|
||||
#else /* !CONFIG_PREEMPT_RT */
|
||||
|
||||
#include <linux/rwbase_rt.h>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_SYS_INFO_H
|
||||
#define _LINUX_SYS_INFO_H
|
||||
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
/*
|
||||
* SYS_INFO_PANIC_CONSOLE_REPLAY is for panic case only, as it needs special
|
||||
* handling which only fits panic case.
|
||||
*/
|
||||
#define SYS_INFO_TASKS 0x00000001
|
||||
#define SYS_INFO_MEM 0x00000002
|
||||
#define SYS_INFO_TIMERS 0x00000004
|
||||
#define SYS_INFO_LOCKS 0x00000008
|
||||
#define SYS_INFO_FTRACE 0x00000010
|
||||
#define SYS_INFO_PANIC_CONSOLE_REPLAY 0x00000020
|
||||
#define SYS_INFO_ALL_CPU_BT 0x00000040
|
||||
#define SYS_INFO_BLOCKED_TASKS 0x00000080
|
||||
|
||||
void sys_info(unsigned long si_mask);
|
||||
unsigned long sys_info_parse_param(char *str);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
|
||||
void *buffer, size_t *lenp,
|
||||
loff_t *ppos);
|
||||
#endif
|
||||
#endif /* _LINUX_SYS_INFO_H */
|
||||
@@ -177,32 +177,6 @@ struct xxh64_state {
|
||||
*/
|
||||
void xxh32_reset(struct xxh32_state *state, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh32_update() - hash the data given and update the xxh32 state
|
||||
*
|
||||
* @state: The xxh32 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh32_reset() call xxh32_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh32_digest() - produce the current xxh32 hash
|
||||
*
|
||||
* @state: Produce the current xxh32 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh32_digest(), and
|
||||
* generate new hashes later on, by calling xxh32_digest() again.
|
||||
*
|
||||
* Return: The xxh32 hash stored in the state.
|
||||
*/
|
||||
uint32_t xxh32_digest(const struct xxh32_state *state);
|
||||
|
||||
/**
|
||||
* xxh64_reset() - reset the xxh64 state to start a new hashing operation
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define KEXEC_FILE_ON_CRASH 0x00000002
|
||||
#define KEXEC_FILE_NO_INITRAMFS 0x00000004
|
||||
#define KEXEC_FILE_DEBUG 0x00000008
|
||||
#define KEXEC_FILE_NO_CMA 0x00000010
|
||||
|
||||
/* These values match the ELF architecture values.
|
||||
* Unless there is a good reason that should continue to be the case.
|
||||
|
||||
@@ -178,7 +178,7 @@ int xenbus_printf(struct xenbus_transaction t,
|
||||
* sprintf-style type string, and pointer. Returns 0 or errno.*/
|
||||
int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
|
||||
|
||||
/* notifer routines for when the xenstore comes up */
|
||||
/* notifier routines for when the xenstore comes up */
|
||||
extern int xenstored_ready;
|
||||
int register_xenstore_notifier(struct notifier_block *nb);
|
||||
void unregister_xenstore_notifier(struct notifier_block *nb);
|
||||
|
||||
@@ -172,6 +172,10 @@ menu "General setup"
|
||||
|
||||
config BROKEN
|
||||
bool
|
||||
help
|
||||
This option allows you to choose whether you want to try to
|
||||
compile (and fix) old drivers that haven't been updated to
|
||||
new infrastructure.
|
||||
|
||||
config BROKEN_ON_SMP
|
||||
bool
|
||||
|
||||
+5
-1
@@ -1615,7 +1615,11 @@ static noinline void __init kernel_init_freeable(void)
|
||||
* check if there is an early userspace init. If yes, let it do all
|
||||
* the work
|
||||
*/
|
||||
if (init_eaccess(ramdisk_execute_command) != 0) {
|
||||
int ramdisk_command_access;
|
||||
ramdisk_command_access = init_eaccess(ramdisk_execute_command);
|
||||
if (ramdisk_command_access != 0) {
|
||||
pr_warn("check access for rdinit=%s failed: %i, ignoring\n",
|
||||
ramdisk_execute_command, ramdisk_command_access);
|
||||
ramdisk_execute_command = NULL;
|
||||
prepare_namespace();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
@@ -33,6 +34,11 @@
|
||||
/* Per cpu memory for storing cpu states in case of system crash. */
|
||||
note_buf_t __percpu *crash_notes;
|
||||
|
||||
/* time to wait for possible DMA to finish before starting the kdump kernel
|
||||
* when a CMA reservation is used
|
||||
*/
|
||||
#define CMA_DMA_TIMEOUT_SEC 10
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
|
||||
int kimage_crash_copy_vmcoreinfo(struct kimage *image)
|
||||
@@ -97,6 +103,14 @@ int kexec_crash_loaded(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kexec_crash_loaded);
|
||||
|
||||
static void crash_cma_clear_pending_dma(void)
|
||||
{
|
||||
if (!crashk_cma_cnt)
|
||||
return;
|
||||
|
||||
mdelay(CMA_DMA_TIMEOUT_SEC * 1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* No panic_cpu check version of crash_kexec(). This function is called
|
||||
* only when panic_cpu holds the current CPU number; this is the only CPU
|
||||
@@ -119,6 +133,7 @@ void __noclone __crash_kexec(struct pt_regs *regs)
|
||||
crash_setup_regs(&fixed_regs, regs);
|
||||
crash_save_vmcoreinfo();
|
||||
machine_crash_shutdown(&fixed_regs);
|
||||
crash_cma_clear_pending_dma();
|
||||
machine_kexec(kexec_crash_image);
|
||||
}
|
||||
kexec_unlock();
|
||||
|
||||
+66
-2
@@ -14,6 +14,8 @@
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/kmemleak.h>
|
||||
#include <linux/cma.h>
|
||||
#include <linux/crash_reserve.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
@@ -172,17 +174,19 @@ static int __init parse_crashkernel_simple(char *cmdline,
|
||||
|
||||
#define SUFFIX_HIGH 0
|
||||
#define SUFFIX_LOW 1
|
||||
#define SUFFIX_NULL 2
|
||||
#define SUFFIX_CMA 2
|
||||
#define SUFFIX_NULL 3
|
||||
static __initdata char *suffix_tbl[] = {
|
||||
[SUFFIX_HIGH] = ",high",
|
||||
[SUFFIX_LOW] = ",low",
|
||||
[SUFFIX_CMA] = ",cma",
|
||||
[SUFFIX_NULL] = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* That function parses "suffix" crashkernel command lines like
|
||||
*
|
||||
* crashkernel=size,[high|low]
|
||||
* crashkernel=size,[high|low|cma]
|
||||
*
|
||||
* It returns 0 on success and -EINVAL on failure.
|
||||
*/
|
||||
@@ -298,9 +302,11 @@ int __init parse_crashkernel(char *cmdline,
|
||||
unsigned long long *crash_size,
|
||||
unsigned long long *crash_base,
|
||||
unsigned long long *low_size,
|
||||
unsigned long long *cma_size,
|
||||
bool *high)
|
||||
{
|
||||
int ret;
|
||||
unsigned long long __always_unused cma_base;
|
||||
|
||||
/* crashkernel=X[@offset] */
|
||||
ret = __parse_crashkernel(cmdline, system_ram, crash_size,
|
||||
@@ -331,6 +337,14 @@ int __init parse_crashkernel(char *cmdline,
|
||||
|
||||
*high = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* optional CMA reservation
|
||||
* cma_base is ignored
|
||||
*/
|
||||
if (cma_size)
|
||||
__parse_crashkernel(cmdline, 0, cma_size,
|
||||
&cma_base, suffix_tbl[SUFFIX_CMA]);
|
||||
#endif
|
||||
if (!*crash_size)
|
||||
ret = -EINVAL;
|
||||
@@ -457,6 +471,56 @@ retry:
|
||||
#endif
|
||||
}
|
||||
|
||||
struct range crashk_cma_ranges[CRASHKERNEL_CMA_RANGES_MAX];
|
||||
#ifdef CRASHKERNEL_CMA
|
||||
int crashk_cma_cnt;
|
||||
void __init reserve_crashkernel_cma(unsigned long long cma_size)
|
||||
{
|
||||
unsigned long long request_size = roundup(cma_size, PAGE_SIZE);
|
||||
unsigned long long reserved_size = 0;
|
||||
|
||||
if (!cma_size)
|
||||
return;
|
||||
|
||||
while (cma_size > reserved_size &&
|
||||
crashk_cma_cnt < CRASHKERNEL_CMA_RANGES_MAX) {
|
||||
|
||||
struct cma *res;
|
||||
|
||||
if (cma_declare_contiguous(0, request_size, 0, 0, 0, false,
|
||||
"crashkernel", &res)) {
|
||||
/* reservation failed, try half-sized blocks */
|
||||
if (request_size <= PAGE_SIZE)
|
||||
break;
|
||||
|
||||
request_size = roundup(request_size / 2, PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
crashk_cma_ranges[crashk_cma_cnt].start = cma_get_base(res);
|
||||
crashk_cma_ranges[crashk_cma_cnt].end =
|
||||
crashk_cma_ranges[crashk_cma_cnt].start +
|
||||
cma_get_size(res) - 1;
|
||||
++crashk_cma_cnt;
|
||||
reserved_size += request_size;
|
||||
}
|
||||
|
||||
if (cma_size > reserved_size)
|
||||
pr_warn("crashkernel CMA reservation failed: %lld MB requested, %lld MB reserved in %d ranges\n",
|
||||
cma_size >> 20, reserved_size >> 20, crashk_cma_cnt);
|
||||
else
|
||||
pr_info("crashkernel CMA reserved: %lld MB in %d ranges\n",
|
||||
reserved_size >> 20, crashk_cma_cnt);
|
||||
}
|
||||
|
||||
#else /* CRASHKERNEL_CMA */
|
||||
void __init reserve_crashkernel_cma(unsigned long long cma_size)
|
||||
{
|
||||
if (cma_size)
|
||||
pr_warn("crashkernel CMA reservation not supported\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
|
||||
static __init int insert_crashkernel_resources(void)
|
||||
{
|
||||
|
||||
@@ -580,8 +580,8 @@ retry:
|
||||
|
||||
out:
|
||||
/* Revert back reference counter if instruction update failed. */
|
||||
if (ret < 0 && is_register && ref_ctr_updated)
|
||||
update_ref_ctr(uprobe, mm, -1);
|
||||
if (ret < 0 && ref_ctr_updated)
|
||||
update_ref_ctr(uprobe, mm, is_register ? -1 : 1);
|
||||
|
||||
/* try collapse pmd for compound page */
|
||||
if (ret > 0)
|
||||
|
||||
+1
-6
@@ -693,12 +693,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
|
||||
}
|
||||
|
||||
/*
|
||||
* This does two things:
|
||||
*
|
||||
* A. Make init inherit all the child processes
|
||||
* B. Check to see if any process groups have become orphaned
|
||||
* as a result of our exiting, and if they have any stopped
|
||||
* jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
|
||||
* Make init inherit all the child processes
|
||||
*/
|
||||
static void forget_original_parent(struct task_struct *father,
|
||||
struct list_head *dead)
|
||||
|
||||
+47
-48
@@ -195,33 +195,33 @@ static inline void free_task_struct(struct task_struct *tsk)
|
||||
kmem_cache_free(task_struct_cachep, tsk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
|
||||
* kmemcache based allocator.
|
||||
*/
|
||||
# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
|
||||
|
||||
# ifdef CONFIG_VMAP_STACK
|
||||
#ifdef CONFIG_VMAP_STACK
|
||||
/*
|
||||
* vmalloc() is a bit slow, and calling vfree() enough times will force a TLB
|
||||
* flush. Try to minimize the number of calls by caching stacks.
|
||||
*/
|
||||
#define NR_CACHED_STACKS 2
|
||||
static DEFINE_PER_CPU(struct vm_struct *, cached_stacks[NR_CACHED_STACKS]);
|
||||
/*
|
||||
* Allocated stacks are cached and later reused by new threads, so memcg
|
||||
* accounting is performed by the code assigning/releasing stacks to tasks.
|
||||
* We need a zeroed memory without __GFP_ACCOUNT.
|
||||
*/
|
||||
#define GFP_VMAP_STACK (GFP_KERNEL | __GFP_ZERO)
|
||||
|
||||
struct vm_stack {
|
||||
struct rcu_head rcu;
|
||||
struct vm_struct *stack_vm_area;
|
||||
};
|
||||
|
||||
static bool try_release_thread_stack_to_cache(struct vm_struct *vm)
|
||||
static bool try_release_thread_stack_to_cache(struct vm_struct *vm_area)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NR_CACHED_STACKS; i++) {
|
||||
struct vm_struct *tmp = NULL;
|
||||
|
||||
if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm))
|
||||
if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm_area))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -230,11 +230,12 @@ static bool try_release_thread_stack_to_cache(struct vm_struct *vm)
|
||||
static void thread_stack_free_rcu(struct rcu_head *rh)
|
||||
{
|
||||
struct vm_stack *vm_stack = container_of(rh, struct vm_stack, rcu);
|
||||
struct vm_struct *vm_area = vm_stack->stack_vm_area;
|
||||
|
||||
if (try_release_thread_stack_to_cache(vm_stack->stack_vm_area))
|
||||
return;
|
||||
|
||||
vfree(vm_stack);
|
||||
vfree(vm_area->addr);
|
||||
}
|
||||
|
||||
static void thread_stack_delayed_free(struct task_struct *tsk)
|
||||
@@ -247,32 +248,32 @@ static void thread_stack_delayed_free(struct task_struct *tsk)
|
||||
|
||||
static int free_vm_stack_cache(unsigned int cpu)
|
||||
{
|
||||
struct vm_struct **cached_vm_stacks = per_cpu_ptr(cached_stacks, cpu);
|
||||
struct vm_struct **cached_vm_stack_areas = per_cpu_ptr(cached_stacks, cpu);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_CACHED_STACKS; i++) {
|
||||
struct vm_struct *vm_stack = cached_vm_stacks[i];
|
||||
struct vm_struct *vm_area = cached_vm_stack_areas[i];
|
||||
|
||||
if (!vm_stack)
|
||||
if (!vm_area)
|
||||
continue;
|
||||
|
||||
vfree(vm_stack->addr);
|
||||
cached_vm_stacks[i] = NULL;
|
||||
vfree(vm_area->addr);
|
||||
cached_vm_stack_areas[i] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memcg_charge_kernel_stack(struct vm_struct *vm)
|
||||
static int memcg_charge_kernel_stack(struct vm_struct *vm_area)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
int nr_charged = 0;
|
||||
|
||||
BUG_ON(vm->nr_pages != THREAD_SIZE / PAGE_SIZE);
|
||||
BUG_ON(vm_area->nr_pages != THREAD_SIZE / PAGE_SIZE);
|
||||
|
||||
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) {
|
||||
ret = memcg_kmem_charge_page(vm->pages[i], GFP_KERNEL, 0);
|
||||
ret = memcg_kmem_charge_page(vm_area->pages[i], GFP_KERNEL, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
nr_charged++;
|
||||
@@ -280,55 +281,47 @@ static int memcg_charge_kernel_stack(struct vm_struct *vm)
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < nr_charged; i++)
|
||||
memcg_kmem_uncharge_page(vm->pages[i], 0);
|
||||
memcg_kmem_uncharge_page(vm_area->pages[i], 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int alloc_thread_stack_node(struct task_struct *tsk, int node)
|
||||
{
|
||||
struct vm_struct *vm;
|
||||
struct vm_struct *vm_area;
|
||||
void *stack;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_CACHED_STACKS; i++) {
|
||||
struct vm_struct *s;
|
||||
|
||||
s = this_cpu_xchg(cached_stacks[i], NULL);
|
||||
|
||||
if (!s)
|
||||
vm_area = this_cpu_xchg(cached_stacks[i], NULL);
|
||||
if (!vm_area)
|
||||
continue;
|
||||
|
||||
/* Reset stack metadata. */
|
||||
kasan_unpoison_range(s->addr, THREAD_SIZE);
|
||||
kasan_unpoison_range(vm_area->addr, THREAD_SIZE);
|
||||
|
||||
stack = kasan_reset_tag(s->addr);
|
||||
stack = kasan_reset_tag(vm_area->addr);
|
||||
|
||||
/* Clear stale pointers from reused stack. */
|
||||
memset(stack, 0, THREAD_SIZE);
|
||||
|
||||
if (memcg_charge_kernel_stack(s)) {
|
||||
vfree(s->addr);
|
||||
if (memcg_charge_kernel_stack(vm_area)) {
|
||||
vfree(vm_area->addr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tsk->stack_vm_area = s;
|
||||
tsk->stack_vm_area = vm_area;
|
||||
tsk->stack = stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocated stacks are cached and later reused by new threads,
|
||||
* so memcg accounting is performed manually on assigning/releasing
|
||||
* stacks to tasks. Drop __GFP_ACCOUNT.
|
||||
*/
|
||||
stack = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN,
|
||||
THREADINFO_GFP & ~__GFP_ACCOUNT,
|
||||
GFP_VMAP_STACK,
|
||||
node, __builtin_return_address(0));
|
||||
if (!stack)
|
||||
return -ENOMEM;
|
||||
|
||||
vm = find_vm_area(stack);
|
||||
if (memcg_charge_kernel_stack(vm)) {
|
||||
vm_area = find_vm_area(stack);
|
||||
if (memcg_charge_kernel_stack(vm_area)) {
|
||||
vfree(stack);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -337,7 +330,7 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
|
||||
* free_thread_stack() can be called in interrupt context,
|
||||
* so cache the vm_struct.
|
||||
*/
|
||||
tsk->stack_vm_area = vm;
|
||||
tsk->stack_vm_area = vm_area;
|
||||
stack = kasan_reset_tag(stack);
|
||||
tsk->stack = stack;
|
||||
return 0;
|
||||
@@ -352,7 +345,13 @@ static void free_thread_stack(struct task_struct *tsk)
|
||||
tsk->stack_vm_area = NULL;
|
||||
}
|
||||
|
||||
# else /* !CONFIG_VMAP_STACK */
|
||||
#else /* !CONFIG_VMAP_STACK */
|
||||
|
||||
/*
|
||||
* Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
|
||||
* kmemcache based allocator.
|
||||
*/
|
||||
#if THREAD_SIZE >= PAGE_SIZE
|
||||
|
||||
static void thread_stack_free_rcu(struct rcu_head *rh)
|
||||
{
|
||||
@@ -384,8 +383,7 @@ static void free_thread_stack(struct task_struct *tsk)
|
||||
tsk->stack = NULL;
|
||||
}
|
||||
|
||||
# endif /* CONFIG_VMAP_STACK */
|
||||
# else /* !(THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)) */
|
||||
#else /* !(THREAD_SIZE >= PAGE_SIZE) */
|
||||
|
||||
static struct kmem_cache *thread_stack_cache;
|
||||
|
||||
@@ -424,7 +422,8 @@ void thread_stack_cache_init(void)
|
||||
BUG_ON(thread_stack_cache == NULL);
|
||||
}
|
||||
|
||||
# endif /* THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) */
|
||||
#endif /* THREAD_SIZE >= PAGE_SIZE */
|
||||
#endif /* CONFIG_VMAP_STACK */
|
||||
|
||||
/* SLAB cache for signal_struct structures (tsk->signal) */
|
||||
static struct kmem_cache *signal_cachep;
|
||||
@@ -444,11 +443,11 @@ static struct kmem_cache *mm_cachep;
|
||||
static void account_kernel_stack(struct task_struct *tsk, int account)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_VMAP_STACK)) {
|
||||
struct vm_struct *vm = task_stack_vm_area(tsk);
|
||||
struct vm_struct *vm_area = task_stack_vm_area(tsk);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
|
||||
mod_lruvec_page_state(vm->pages[i], NR_KERNEL_STACK_KB,
|
||||
mod_lruvec_page_state(vm_area->pages[i], NR_KERNEL_STACK_KB,
|
||||
account * (PAGE_SIZE / 1024));
|
||||
} else {
|
||||
void *stack = task_stack_page(tsk);
|
||||
@@ -464,12 +463,12 @@ void exit_task_stack_account(struct task_struct *tsk)
|
||||
account_kernel_stack(tsk, -1);
|
||||
|
||||
if (IS_ENABLED(CONFIG_VMAP_STACK)) {
|
||||
struct vm_struct *vm;
|
||||
struct vm_struct *vm_area;
|
||||
int i;
|
||||
|
||||
vm = task_stack_vm_area(tsk);
|
||||
vm_area = task_stack_vm_area(tsk);
|
||||
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
|
||||
memcg_kmem_uncharge_page(vm->pages[i], 0);
|
||||
memcg_kmem_uncharge_page(vm_area->pages[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-4
@@ -23,6 +23,7 @@
|
||||
#include <linux/sched/debug.h>
|
||||
#include <linux/sched/sysctl.h>
|
||||
#include <linux/hung_task.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
#include <trace/events/sched.h>
|
||||
|
||||
@@ -100,6 +101,7 @@ static void debug_show_blocker(struct task_struct *task)
|
||||
{
|
||||
struct task_struct *g, *t;
|
||||
unsigned long owner, blocker, blocker_type;
|
||||
const char *rwsem_blocked_by, *rwsem_blocked_as;
|
||||
|
||||
RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "No rcu lock held");
|
||||
|
||||
@@ -111,12 +113,20 @@ static void debug_show_blocker(struct task_struct *task)
|
||||
|
||||
switch (blocker_type) {
|
||||
case BLOCKER_TYPE_MUTEX:
|
||||
owner = mutex_get_owner(
|
||||
(struct mutex *)hung_task_blocker_to_lock(blocker));
|
||||
owner = mutex_get_owner(hung_task_blocker_to_lock(blocker));
|
||||
break;
|
||||
case BLOCKER_TYPE_SEM:
|
||||
owner = sem_last_holder(
|
||||
(struct semaphore *)hung_task_blocker_to_lock(blocker));
|
||||
owner = sem_last_holder(hung_task_blocker_to_lock(blocker));
|
||||
break;
|
||||
case BLOCKER_TYPE_RWSEM_READER:
|
||||
case BLOCKER_TYPE_RWSEM_WRITER:
|
||||
owner = (unsigned long)rwsem_owner(
|
||||
hung_task_blocker_to_lock(blocker));
|
||||
rwsem_blocked_as = (blocker_type == BLOCKER_TYPE_RWSEM_READER) ?
|
||||
"reader" : "writer";
|
||||
rwsem_blocked_by = is_rwsem_reader_owned(
|
||||
hung_task_blocker_to_lock(blocker)) ?
|
||||
"reader" : "writer";
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
@@ -134,6 +144,11 @@ static void debug_show_blocker(struct task_struct *task)
|
||||
pr_err("INFO: task %s:%d is blocked on a semaphore, but the last holder is not found.\n",
|
||||
task->comm, task->pid);
|
||||
break;
|
||||
case BLOCKER_TYPE_RWSEM_READER:
|
||||
case BLOCKER_TYPE_RWSEM_WRITER:
|
||||
pr_err("INFO: task %s:%d is blocked on an rw-semaphore, but the owner is not found.\n",
|
||||
task->comm, task->pid);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -152,6 +167,12 @@ static void debug_show_blocker(struct task_struct *task)
|
||||
pr_err("INFO: task %s:%d blocked on a semaphore likely last held by task %s:%d\n",
|
||||
task->comm, task->pid, t->comm, t->pid);
|
||||
break;
|
||||
case BLOCKER_TYPE_RWSEM_READER:
|
||||
case BLOCKER_TYPE_RWSEM_WRITER:
|
||||
pr_err("INFO: task %s:%d <%s> blocked on an rw-semaphore likely owned by task %s:%d <%s>\n",
|
||||
task->comm, task->pid, rwsem_blocked_as, t->comm,
|
||||
t->pid, rwsem_blocked_by);
|
||||
break;
|
||||
}
|
||||
sched_show_task(t);
|
||||
return;
|
||||
|
||||
+1
-1
@@ -552,7 +552,7 @@ static int kcov_get_mode(unsigned long arg)
|
||||
|
||||
/*
|
||||
* Fault in a lazily-faulted vmalloc area before it can be used by
|
||||
* __santizer_cov_trace_pc(), to avoid recursion issues if any code on the
|
||||
* __sanitizer_cov_trace_pc(), to avoid recursion issues if any code on the
|
||||
* vmalloc fault handling path is instrumented.
|
||||
*/
|
||||
static void kcov_fault_in_area(struct kcov *kcov)
|
||||
|
||||
+1
-1
@@ -152,7 +152,7 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < nr_segments; i++) {
|
||||
ret = kimage_load_segment(image, &image->segment[i]);
|
||||
ret = kimage_load_segment(image, i);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+92
-8
@@ -40,6 +40,7 @@
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
@@ -553,6 +554,24 @@ static void kimage_free_entry(kimage_entry_t entry)
|
||||
kimage_free_pages(page);
|
||||
}
|
||||
|
||||
static void kimage_free_cma(struct kimage *image)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < image->nr_segments; i++) {
|
||||
struct page *cma = image->segment_cma[i];
|
||||
u32 nr_pages = image->segment[i].memsz >> PAGE_SHIFT;
|
||||
|
||||
if (!cma)
|
||||
continue;
|
||||
|
||||
arch_kexec_pre_free_pages(page_address(cma), nr_pages);
|
||||
dma_release_from_contiguous(NULL, cma, nr_pages);
|
||||
image->segment_cma[i] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void kimage_free(struct kimage *image)
|
||||
{
|
||||
kimage_entry_t *ptr, entry;
|
||||
@@ -591,6 +610,9 @@ void kimage_free(struct kimage *image)
|
||||
/* Free the kexec control pages... */
|
||||
kimage_free_page_list(&image->control_pages);
|
||||
|
||||
/* Free CMA allocations */
|
||||
kimage_free_cma(image);
|
||||
|
||||
/*
|
||||
* Free up any temporary buffers allocated. This might hit if
|
||||
* error occurred much later after buffer allocation.
|
||||
@@ -716,9 +738,69 @@ static struct page *kimage_alloc_page(struct kimage *image,
|
||||
return page;
|
||||
}
|
||||
|
||||
static int kimage_load_normal_segment(struct kimage *image,
|
||||
struct kexec_segment *segment)
|
||||
static int kimage_load_cma_segment(struct kimage *image, int idx)
|
||||
{
|
||||
struct kexec_segment *segment = &image->segment[idx];
|
||||
struct page *cma = image->segment_cma[idx];
|
||||
char *ptr = page_address(cma);
|
||||
unsigned long maddr;
|
||||
size_t ubytes, mbytes;
|
||||
int result = 0;
|
||||
unsigned char __user *buf = NULL;
|
||||
unsigned char *kbuf = NULL;
|
||||
|
||||
if (image->file_mode)
|
||||
kbuf = segment->kbuf;
|
||||
else
|
||||
buf = segment->buf;
|
||||
ubytes = segment->bufsz;
|
||||
mbytes = segment->memsz;
|
||||
maddr = segment->mem;
|
||||
|
||||
/* Then copy from source buffer to the CMA one */
|
||||
while (mbytes) {
|
||||
size_t uchunk, mchunk;
|
||||
|
||||
ptr += maddr & ~PAGE_MASK;
|
||||
mchunk = min_t(size_t, mbytes,
|
||||
PAGE_SIZE - (maddr & ~PAGE_MASK));
|
||||
uchunk = min(ubytes, mchunk);
|
||||
|
||||
if (uchunk) {
|
||||
/* For file based kexec, source pages are in kernel memory */
|
||||
if (image->file_mode)
|
||||
memcpy(ptr, kbuf, uchunk);
|
||||
else
|
||||
result = copy_from_user(ptr, buf, uchunk);
|
||||
ubytes -= uchunk;
|
||||
if (image->file_mode)
|
||||
kbuf += uchunk;
|
||||
else
|
||||
buf += uchunk;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ptr += mchunk;
|
||||
maddr += mchunk;
|
||||
mbytes -= mchunk;
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
/* Clear any remainder */
|
||||
memset(ptr, 0, mbytes);
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int kimage_load_normal_segment(struct kimage *image, int idx)
|
||||
{
|
||||
struct kexec_segment *segment = &image->segment[idx];
|
||||
unsigned long maddr;
|
||||
size_t ubytes, mbytes;
|
||||
int result;
|
||||
@@ -733,6 +815,9 @@ static int kimage_load_normal_segment(struct kimage *image,
|
||||
mbytes = segment->memsz;
|
||||
maddr = segment->mem;
|
||||
|
||||
if (image->segment_cma[idx])
|
||||
return kimage_load_cma_segment(image, idx);
|
||||
|
||||
result = kimage_set_destination(image, maddr);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
@@ -787,13 +872,13 @@ out:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
static int kimage_load_crash_segment(struct kimage *image,
|
||||
struct kexec_segment *segment)
|
||||
static int kimage_load_crash_segment(struct kimage *image, int idx)
|
||||
{
|
||||
/* For crash dumps kernels we simply copy the data from
|
||||
* user space to it's destination.
|
||||
* We do things a page at a time for the sake of kmap.
|
||||
*/
|
||||
struct kexec_segment *segment = &image->segment[idx];
|
||||
unsigned long maddr;
|
||||
size_t ubytes, mbytes;
|
||||
int result;
|
||||
@@ -858,18 +943,17 @@ out:
|
||||
}
|
||||
#endif
|
||||
|
||||
int kimage_load_segment(struct kimage *image,
|
||||
struct kexec_segment *segment)
|
||||
int kimage_load_segment(struct kimage *image, int idx)
|
||||
{
|
||||
int result = -ENOMEM;
|
||||
|
||||
switch (image->type) {
|
||||
case KEXEC_TYPE_DEFAULT:
|
||||
result = kimage_load_normal_segment(image, segment);
|
||||
result = kimage_load_normal_segment(image, idx);
|
||||
break;
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
case KEXEC_TYPE_CRASH:
|
||||
result = kimage_load_crash_segment(image, segment);
|
||||
result = kimage_load_crash_segment(image, idx);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
+50
-1
@@ -26,6 +26,7 @@
|
||||
#include <linux/kernel_read_file.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include "kexec_internal.h"
|
||||
|
||||
#ifdef CONFIG_KEXEC_SIG
|
||||
@@ -253,6 +254,8 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
|
||||
|
||||
if (cmdline_len) {
|
||||
image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);
|
||||
if (IS_ERR(image->cmdline_buf)) {
|
||||
@@ -434,7 +437,7 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
|
||||
i, ksegment->buf, ksegment->bufsz, ksegment->mem,
|
||||
ksegment->memsz);
|
||||
|
||||
ret = kimage_load_segment(image, &image->segment[i]);
|
||||
ret = kimage_load_segment(image, i);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -663,6 +666,43 @@ static int kexec_walk_resources(struct kexec_buf *kbuf,
|
||||
return walk_system_ram_res(0, ULONG_MAX, kbuf, func);
|
||||
}
|
||||
|
||||
static int kexec_alloc_contig(struct kexec_buf *kbuf)
|
||||
{
|
||||
size_t nr_pages = kbuf->memsz >> PAGE_SHIFT;
|
||||
unsigned long mem;
|
||||
struct page *p;
|
||||
|
||||
/* User space disabled CMA allocations, bail out. */
|
||||
if (kbuf->image->no_cma)
|
||||
return -EPERM;
|
||||
|
||||
/* Skip CMA logic for crash kernel */
|
||||
if (kbuf->image->type == KEXEC_TYPE_CRASH)
|
||||
return -EPERM;
|
||||
|
||||
p = dma_alloc_from_contiguous(NULL, nr_pages, get_order(kbuf->buf_align), true);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_debug("allocated %zu DMA pages at 0x%lx", nr_pages, page_to_boot_pfn(p));
|
||||
|
||||
mem = page_to_boot_pfn(p) << PAGE_SHIFT;
|
||||
|
||||
if (kimage_is_destination_range(kbuf->image, mem, mem + kbuf->memsz)) {
|
||||
/* Our region is already in use by a statically defined one. Bail out. */
|
||||
pr_debug("CMA overlaps existing mem: 0x%lx+0x%lx\n", mem, kbuf->memsz);
|
||||
dma_release_from_contiguous(NULL, p, nr_pages);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
kbuf->mem = page_to_boot_pfn(p) << PAGE_SHIFT;
|
||||
kbuf->cma = p;
|
||||
|
||||
arch_kexec_post_alloc_pages(page_address(p), (int)nr_pages, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kexec_locate_mem_hole - find free memory for the purgatory or the next kernel
|
||||
* @kbuf: Parameters for the memory search.
|
||||
@@ -687,6 +727,13 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Try to find a free physically contiguous block of memory first. With that, we
|
||||
* can avoid any copying at kexec time.
|
||||
*/
|
||||
if (!kexec_alloc_contig(kbuf))
|
||||
return 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
|
||||
ret = kexec_walk_resources(kbuf, locate_mem_hole_callback);
|
||||
else
|
||||
@@ -732,6 +779,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
|
||||
/* Ensure minimum alignment needed for segments. */
|
||||
kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE);
|
||||
kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE);
|
||||
kbuf->cma = NULL;
|
||||
|
||||
/* Walk the RAM ranges and allocate a suitable range for the buffer */
|
||||
ret = arch_kexec_locate_mem_hole(kbuf);
|
||||
@@ -744,6 +792,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
|
||||
ksegment->bufsz = kbuf->bufsz;
|
||||
ksegment->mem = kbuf->mem;
|
||||
ksegment->memsz = kbuf->memsz;
|
||||
kbuf->image->segment_cma[kbuf->image->nr_segments] = kbuf->cma;
|
||||
kbuf->image->nr_segments++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ struct kimage *do_kimage_alloc_init(void);
|
||||
int sanity_check_segment_list(struct kimage *image);
|
||||
void kimage_free_page_list(struct list_head *list);
|
||||
void kimage_free(struct kimage *image);
|
||||
int kimage_load_segment(struct kimage *image, struct kexec_segment *segment);
|
||||
int kimage_load_segment(struct kimage *image, int idx);
|
||||
void kimage_terminate(struct kimage *image);
|
||||
int kimage_is_destination_range(struct kimage *image,
|
||||
unsigned long start, unsigned long end);
|
||||
|
||||
+5
-6
@@ -88,13 +88,12 @@ static inline struct kthread *to_kthread(struct task_struct *k)
|
||||
/*
|
||||
* Variant of to_kthread() that doesn't assume @p is a kthread.
|
||||
*
|
||||
* Per construction; when:
|
||||
* When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will
|
||||
* always remain a kthread. For kthreads p->worker_private always
|
||||
* points to a struct kthread. For tasks that are not kthreads
|
||||
* p->worker_private is used to point to other things.
|
||||
*
|
||||
* (p->flags & PF_KTHREAD) && p->worker_private
|
||||
*
|
||||
* the task is both a kthread and struct kthread is persistent. However
|
||||
* PF_KTHREAD on it's own is not, kernel_thread() can exec() (See umh.c and
|
||||
* begin_new_exec()).
|
||||
* Return NULL for any task that is not a kthread.
|
||||
*/
|
||||
static inline struct kthread *__to_kthread(struct task_struct *p)
|
||||
{
|
||||
|
||||
+23
-8
@@ -27,6 +27,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/hung_task.h>
|
||||
#include <trace/events/lock.h>
|
||||
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
@@ -181,11 +182,11 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
|
||||
__rwsem_set_reader_owned(sem, current);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_RWSEMS
|
||||
#if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER)
|
||||
/*
|
||||
* Return just the real task structure pointer of the owner
|
||||
*/
|
||||
static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem)
|
||||
struct task_struct *rwsem_owner(struct rw_semaphore *sem)
|
||||
{
|
||||
return (struct task_struct *)
|
||||
(atomic_long_read(&sem->owner) & ~RWSEM_OWNER_FLAGS_MASK);
|
||||
@@ -194,7 +195,7 @@ static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem)
|
||||
/*
|
||||
* Return true if the rwsem is owned by a reader.
|
||||
*/
|
||||
static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
|
||||
bool is_rwsem_reader_owned(struct rw_semaphore *sem)
|
||||
{
|
||||
/*
|
||||
* Check the count to see if it is write-locked.
|
||||
@@ -207,10 +208,10 @@ static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
|
||||
}
|
||||
|
||||
/*
|
||||
* With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there
|
||||
* is a task pointer in owner of a reader-owned rwsem, it will be the
|
||||
* real owner or one of the real owners. The only exception is when the
|
||||
* unlock is done by up_read_non_owner().
|
||||
* With CONFIG_DEBUG_RWSEMS or CONFIG_DETECT_HUNG_TASK_BLOCKER configured,
|
||||
* it will make sure that the owner field of a reader-owned rwsem either
|
||||
* points to a real reader-owner(s) or gets cleared. The only exception is
|
||||
* when the unlock is done by up_read_non_owner().
|
||||
*/
|
||||
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
|
||||
{
|
||||
@@ -1063,10 +1064,13 @@ queue:
|
||||
wake_up_q(&wake_q);
|
||||
|
||||
trace_contention_begin(sem, LCB_F_READ);
|
||||
set_current_state(state);
|
||||
|
||||
if (state == TASK_UNINTERRUPTIBLE)
|
||||
hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_READER);
|
||||
|
||||
/* wait to be given the lock */
|
||||
for (;;) {
|
||||
set_current_state(state);
|
||||
if (!smp_load_acquire(&waiter.task)) {
|
||||
/* Matches rwsem_mark_wake()'s smp_store_release(). */
|
||||
break;
|
||||
@@ -1081,8 +1085,12 @@ queue:
|
||||
}
|
||||
schedule_preempt_disabled();
|
||||
lockevent_inc(rwsem_sleep_reader);
|
||||
set_current_state(state);
|
||||
}
|
||||
|
||||
if (state == TASK_UNINTERRUPTIBLE)
|
||||
hung_task_clear_blocker();
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
lockevent_inc(rwsem_rlock);
|
||||
trace_contention_end(sem, 0);
|
||||
@@ -1144,6 +1152,9 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
|
||||
set_current_state(state);
|
||||
trace_contention_begin(sem, LCB_F_WRITE);
|
||||
|
||||
if (state == TASK_UNINTERRUPTIBLE)
|
||||
hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_WRITER);
|
||||
|
||||
for (;;) {
|
||||
if (rwsem_try_write_lock(sem, &waiter)) {
|
||||
/* rwsem_try_write_lock() implies ACQUIRE on success */
|
||||
@@ -1177,6 +1188,10 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
|
||||
trylock_again:
|
||||
raw_spin_lock_irq(&sem->wait_lock);
|
||||
}
|
||||
|
||||
if (state == TASK_UNINTERRUPTIBLE)
|
||||
hung_task_clear_blocker();
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
raw_spin_unlock_irq(&sem->wait_lock);
|
||||
lockevent_inc(rwsem_wlock);
|
||||
|
||||
@@ -112,6 +112,13 @@ struct find_symbol_arg {
|
||||
enum mod_license license;
|
||||
};
|
||||
|
||||
/* modules using other modules */
|
||||
struct module_use {
|
||||
struct list_head source_list;
|
||||
struct list_head target_list;
|
||||
struct module *source, *target;
|
||||
};
|
||||
|
||||
int mod_verify_sig(const void *mod, struct load_info *info);
|
||||
int try_to_force_load(struct module *mod, const char *reason);
|
||||
bool find_symbol(struct find_symbol_arg *fsa);
|
||||
|
||||
@@ -609,7 +609,7 @@ MODINFO_ATTR(srcversion);
|
||||
MODINFO_ATTR(scmversion);
|
||||
|
||||
static struct {
|
||||
char name[MODULE_NAME_LEN + 1];
|
||||
char name[MODULE_NAME_LEN];
|
||||
char taints[MODULE_FLAGS_BUF_SIZE];
|
||||
} last_unloaded_module;
|
||||
|
||||
@@ -780,14 +780,16 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
|
||||
struct module *mod;
|
||||
char name[MODULE_NAME_LEN];
|
||||
char buf[MODULE_FLAGS_BUF_SIZE];
|
||||
int ret, forced = 0;
|
||||
int ret, len, forced = 0;
|
||||
|
||||
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
||||
return -EPERM;
|
||||
|
||||
if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
|
||||
return -EFAULT;
|
||||
name[MODULE_NAME_LEN-1] = '\0';
|
||||
len = strncpy_from_user(name, name_user, MODULE_NAME_LEN);
|
||||
if (len == 0 || len == MODULE_NAME_LEN)
|
||||
return -ENOENT;
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
audit_log_kern_module(name);
|
||||
|
||||
|
||||
+32
-39
@@ -36,6 +36,7 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <linux/seq_buf.h>
|
||||
#include <linux/sys_info.h>
|
||||
#include <trace/events/error_report.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
@@ -63,20 +64,13 @@ int panic_on_warn __read_mostly;
|
||||
unsigned long panic_on_taint;
|
||||
bool panic_on_taint_nousertaint = false;
|
||||
static unsigned int warn_limit __read_mostly;
|
||||
static bool panic_console_replay;
|
||||
|
||||
bool panic_triggering_all_cpu_backtrace;
|
||||
|
||||
int panic_timeout = CONFIG_PANIC_TIMEOUT;
|
||||
EXPORT_SYMBOL_GPL(panic_timeout);
|
||||
|
||||
#define PANIC_PRINT_TASK_INFO 0x00000001
|
||||
#define PANIC_PRINT_MEM_INFO 0x00000002
|
||||
#define PANIC_PRINT_TIMER_INFO 0x00000004
|
||||
#define PANIC_PRINT_LOCK_INFO 0x00000008
|
||||
#define PANIC_PRINT_FTRACE_INFO 0x00000010
|
||||
#define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020
|
||||
#define PANIC_PRINT_ALL_CPU_BT 0x00000040
|
||||
#define PANIC_PRINT_BLOCKED_TASKS 0x00000080
|
||||
unsigned long panic_print;
|
||||
|
||||
ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
|
||||
@@ -128,6 +122,13 @@ static int proc_taint(const struct ctl_table *table, int write,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sysctl_panic_print_handler(const struct ctl_table *table, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
pr_info_once("Kernel: 'panic_print' sysctl interface will be obsoleted by both 'panic_sys_info' and 'panic_console_replay'\n");
|
||||
return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
|
||||
}
|
||||
|
||||
static const struct ctl_table kern_panic_table[] = {
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
@@ -165,7 +166,7 @@ static const struct ctl_table kern_panic_table[] = {
|
||||
.data = &panic_print,
|
||||
.maxlen = sizeof(unsigned long),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_doulongvec_minmax,
|
||||
.proc_handler = sysctl_panic_print_handler,
|
||||
},
|
||||
{
|
||||
.procname = "panic_on_warn",
|
||||
@@ -193,6 +194,13 @@ static const struct ctl_table kern_panic_table[] = {
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.procname = "panic_sys_info",
|
||||
.data = &panic_print,
|
||||
.maxlen = sizeof(panic_print),
|
||||
.mode = 0644,
|
||||
.proc_handler = sysctl_sys_info_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static __init int kernel_panic_sysctls_init(void)
|
||||
@@ -203,6 +211,15 @@ static __init int kernel_panic_sysctls_init(void)
|
||||
late_initcall(kernel_panic_sysctls_init);
|
||||
#endif
|
||||
|
||||
/* The format is "panic_sys_info=tasks,mem,locks,ftrace,..." */
|
||||
static int __init setup_panic_sys_info(char *buf)
|
||||
{
|
||||
/* There is no risk of race in kernel boot phase */
|
||||
panic_print = sys_info_parse_param(buf);
|
||||
return 1;
|
||||
}
|
||||
__setup("panic_sys_info=", setup_panic_sys_info);
|
||||
|
||||
static atomic_t warn_count = ATOMIC_INIT(0);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
@@ -298,33 +315,6 @@ void nmi_panic(struct pt_regs *regs, const char *msg)
|
||||
}
|
||||
EXPORT_SYMBOL(nmi_panic);
|
||||
|
||||
static void panic_print_sys_info(bool console_flush)
|
||||
{
|
||||
if (console_flush) {
|
||||
if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG)
|
||||
console_flush_on_panic(CONSOLE_REPLAY_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (panic_print & PANIC_PRINT_TASK_INFO)
|
||||
show_state();
|
||||
|
||||
if (panic_print & PANIC_PRINT_MEM_INFO)
|
||||
show_mem();
|
||||
|
||||
if (panic_print & PANIC_PRINT_TIMER_INFO)
|
||||
sysrq_timer_list_show();
|
||||
|
||||
if (panic_print & PANIC_PRINT_LOCK_INFO)
|
||||
debug_show_all_locks();
|
||||
|
||||
if (panic_print & PANIC_PRINT_FTRACE_INFO)
|
||||
ftrace_dump(DUMP_ALL);
|
||||
|
||||
if (panic_print & PANIC_PRINT_BLOCKED_TASKS)
|
||||
show_state_filter(TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
void check_panic_on_warn(const char *origin)
|
||||
{
|
||||
unsigned int limit;
|
||||
@@ -345,7 +335,7 @@ void check_panic_on_warn(const char *origin)
|
||||
*/
|
||||
static void panic_other_cpus_shutdown(bool crash_kexec)
|
||||
{
|
||||
if (panic_print & PANIC_PRINT_ALL_CPU_BT) {
|
||||
if (panic_print & SYS_INFO_ALL_CPU_BT) {
|
||||
/* Temporary allow non-panic CPUs to write their backtraces. */
|
||||
panic_triggering_all_cpu_backtrace = true;
|
||||
trigger_all_cpu_backtrace();
|
||||
@@ -468,7 +458,7 @@ void vpanic(const char *fmt, va_list args)
|
||||
*/
|
||||
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
|
||||
|
||||
panic_print_sys_info(false);
|
||||
sys_info(panic_print);
|
||||
|
||||
kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
|
||||
|
||||
@@ -497,7 +487,9 @@ void vpanic(const char *fmt, va_list args)
|
||||
debug_locks_off();
|
||||
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
|
||||
|
||||
panic_print_sys_info(true);
|
||||
if ((panic_print & SYS_INFO_PANIC_CONSOLE_REPLAY) ||
|
||||
panic_console_replay)
|
||||
console_flush_on_panic(CONSOLE_REPLAY_ALL);
|
||||
|
||||
if (!panic_blink)
|
||||
panic_blink = no_blink;
|
||||
@@ -949,6 +941,7 @@ core_param(panic_print, panic_print, ulong, 0644);
|
||||
core_param(pause_on_oops, pause_on_oops, int, 0644);
|
||||
core_param(panic_on_warn, panic_on_warn, int, 0644);
|
||||
core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
|
||||
core_param(panic_console_replay, panic_console_replay, bool, 0644);
|
||||
|
||||
static int __init oops_setup(char *s)
|
||||
{
|
||||
|
||||
+54
-15
@@ -118,7 +118,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
buf->page_array[i] = alloc_page(GFP_KERNEL);
|
||||
buf->page_array[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (unlikely(!buf->page_array[i]))
|
||||
goto depopulate;
|
||||
set_page_private(buf->page_array[i], (unsigned long)buf);
|
||||
@@ -127,7 +127,6 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
|
||||
if (!mem)
|
||||
goto depopulate;
|
||||
|
||||
memset(mem, 0, *size);
|
||||
buf->page_count = n_pages;
|
||||
return mem;
|
||||
|
||||
@@ -250,13 +249,18 @@ EXPORT_SYMBOL_GPL(relay_buf_full);
|
||||
*/
|
||||
|
||||
static int relay_subbuf_start(struct rchan_buf *buf, void *subbuf,
|
||||
void *prev_subbuf, size_t prev_padding)
|
||||
void *prev_subbuf)
|
||||
{
|
||||
int full = relay_buf_full(buf);
|
||||
|
||||
if (full)
|
||||
buf->stats.full_count++;
|
||||
|
||||
if (!buf->chan->cb->subbuf_start)
|
||||
return !relay_buf_full(buf);
|
||||
return !full;
|
||||
|
||||
return buf->chan->cb->subbuf_start(buf, subbuf,
|
||||
prev_subbuf, prev_padding);
|
||||
prev_subbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,11 +302,13 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
|
||||
buf->finalized = 0;
|
||||
buf->data = buf->start;
|
||||
buf->offset = 0;
|
||||
buf->stats.full_count = 0;
|
||||
buf->stats.big_count = 0;
|
||||
|
||||
for (i = 0; i < buf->chan->n_subbufs; i++)
|
||||
buf->padding[i] = 0;
|
||||
|
||||
relay_subbuf_start(buf, buf->data, NULL, 0);
|
||||
relay_subbuf_start(buf, buf->data, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,9 +561,11 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
|
||||
goto toobig;
|
||||
|
||||
if (buf->offset != buf->chan->subbuf_size + 1) {
|
||||
buf->prev_padding = buf->chan->subbuf_size - buf->offset;
|
||||
size_t prev_padding;
|
||||
|
||||
prev_padding = buf->chan->subbuf_size - buf->offset;
|
||||
old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
|
||||
buf->padding[old_subbuf] = buf->prev_padding;
|
||||
buf->padding[old_subbuf] = prev_padding;
|
||||
buf->subbufs_produced++;
|
||||
if (buf->dentry)
|
||||
d_inode(buf->dentry)->i_size +=
|
||||
@@ -582,7 +590,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
|
||||
new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
|
||||
new = buf->start + new_subbuf * buf->chan->subbuf_size;
|
||||
buf->offset = 0;
|
||||
if (!relay_subbuf_start(buf, new, old, buf->prev_padding)) {
|
||||
if (!relay_subbuf_start(buf, new, old)) {
|
||||
buf->offset = buf->chan->subbuf_size + 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -595,7 +603,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
|
||||
return length;
|
||||
|
||||
toobig:
|
||||
buf->chan->last_toobig = length;
|
||||
buf->stats.big_count++;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(relay_switch_subbuf);
|
||||
@@ -655,11 +663,6 @@ void relay_close(struct rchan *chan)
|
||||
if ((buf = *per_cpu_ptr(chan->buf, i)))
|
||||
relay_close_buf(buf);
|
||||
|
||||
if (chan->last_toobig)
|
||||
printk(KERN_WARNING "relay: one or more items not logged "
|
||||
"[item size (%zd) > sub-buffer size (%zd)]\n",
|
||||
chan->last_toobig, chan->subbuf_size);
|
||||
|
||||
list_del(&chan->list);
|
||||
kref_put(&chan->kref, relay_destroy_channel);
|
||||
mutex_unlock(&relay_channels_mutex);
|
||||
@@ -693,6 +696,42 @@ void relay_flush(struct rchan *chan)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(relay_flush);
|
||||
|
||||
/**
|
||||
* relay_stats - get channel buffer statistics
|
||||
* @chan: the channel
|
||||
* @flags: select particular information to get
|
||||
*
|
||||
* Returns the count of certain field that caller specifies.
|
||||
*/
|
||||
size_t relay_stats(struct rchan *chan, int flags)
|
||||
{
|
||||
unsigned int i, count = 0;
|
||||
struct rchan_buf *rbuf;
|
||||
|
||||
if (!chan || flags > RELAY_STATS_LAST)
|
||||
return 0;
|
||||
|
||||
if (chan->is_global) {
|
||||
rbuf = *per_cpu_ptr(chan->buf, 0);
|
||||
if (flags & RELAY_STATS_BUF_FULL)
|
||||
count = rbuf->stats.full_count;
|
||||
else if (flags & RELAY_STATS_WRT_BIG)
|
||||
count = rbuf->stats.big_count;
|
||||
} else {
|
||||
for_each_online_cpu(i) {
|
||||
rbuf = *per_cpu_ptr(chan->buf, i);
|
||||
if (rbuf) {
|
||||
if (flags & RELAY_STATS_BUF_FULL)
|
||||
count += rbuf->stats.full_count;
|
||||
else if (flags & RELAY_STATS_WRT_BIG)
|
||||
count += rbuf->stats.big_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* relay_file_open - open file op for relay files
|
||||
* @inode: the inode
|
||||
|
||||
+2
-20
@@ -415,9 +415,10 @@ static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct blk_trace *bt = filp->private_data;
|
||||
size_t dropped = relay_stats(bt->rchan, RELAY_STATS_BUF_FULL);
|
||||
char buf[16];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped));
|
||||
snprintf(buf, sizeof(buf), "%zu\n", dropped);
|
||||
|
||||
return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
|
||||
}
|
||||
@@ -456,23 +457,6 @@ static const struct file_operations blk_msg_fops = {
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
/*
|
||||
* Keep track of how many times we encountered a full subbuffer, to aid
|
||||
* the user space app in telling how many lost events there were.
|
||||
*/
|
||||
static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
|
||||
void *prev_subbuf, size_t prev_padding)
|
||||
{
|
||||
struct blk_trace *bt;
|
||||
|
||||
if (!relay_buf_full(buf))
|
||||
return 1;
|
||||
|
||||
bt = buf->chan->private_data;
|
||||
atomic_inc(&bt->dropped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_remove_buf_file_callback(struct dentry *dentry)
|
||||
{
|
||||
debugfs_remove(dentry);
|
||||
@@ -491,7 +475,6 @@ static struct dentry *blk_create_buf_file_callback(const char *filename,
|
||||
}
|
||||
|
||||
static const struct rchan_callbacks blk_relay_callbacks = {
|
||||
.subbuf_start = blk_subbuf_start_callback,
|
||||
.create_buf_file = blk_create_buf_file_callback,
|
||||
.remove_buf_file = blk_remove_buf_file_callback,
|
||||
};
|
||||
@@ -580,7 +563,6 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
|
||||
}
|
||||
|
||||
bt->dev = dev;
|
||||
atomic_set(&bt->dropped, 0);
|
||||
INIT_LIST_HEAD(&bt->running_list);
|
||||
|
||||
ret = -EIO;
|
||||
|
||||
@@ -4812,26 +4812,26 @@ int ring_buffer_write(struct trace_buffer *buffer,
|
||||
int ret = -EBUSY;
|
||||
int cpu;
|
||||
|
||||
preempt_disable_notrace();
|
||||
guard(preempt_notrace)();
|
||||
|
||||
if (atomic_read(&buffer->record_disabled))
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
cpu = raw_smp_processor_id();
|
||||
|
||||
if (!cpumask_test_cpu(cpu, buffer->cpumask))
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
cpu_buffer = buffer->buffers[cpu];
|
||||
|
||||
if (atomic_read(&cpu_buffer->record_disabled))
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
if (length > buffer->max_data_size)
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
if (unlikely(trace_recursive_lock(cpu_buffer)))
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
event = rb_reserve_next_event(buffer, cpu_buffer, length);
|
||||
if (!event)
|
||||
@@ -4849,10 +4849,6 @@ int ring_buffer_write(struct trace_buffer *buffer,
|
||||
|
||||
out_unlock:
|
||||
trace_recursive_unlock(cpu_buffer);
|
||||
|
||||
out:
|
||||
preempt_enable_notrace();
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ring_buffer_write);
|
||||
|
||||
+103
-186
@@ -432,15 +432,13 @@ static void ftrace_exports(struct ring_buffer_event *event, int flag)
|
||||
{
|
||||
struct trace_export *export;
|
||||
|
||||
preempt_disable_notrace();
|
||||
guard(preempt_notrace)();
|
||||
|
||||
export = rcu_dereference_raw_check(ftrace_exports_list);
|
||||
while (export) {
|
||||
trace_process_export(export, event, flag);
|
||||
export = rcu_dereference_raw_check(export->next);
|
||||
}
|
||||
|
||||
preempt_enable_notrace();
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -497,27 +495,18 @@ int register_ftrace_export(struct trace_export *export)
|
||||
if (WARN_ON_ONCE(!export->write))
|
||||
return -1;
|
||||
|
||||
mutex_lock(&ftrace_export_lock);
|
||||
guard(mutex)(&ftrace_export_lock);
|
||||
|
||||
add_ftrace_export(&ftrace_exports_list, export);
|
||||
|
||||
mutex_unlock(&ftrace_export_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_ftrace_export);
|
||||
|
||||
int unregister_ftrace_export(struct trace_export *export)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ftrace_export_lock);
|
||||
|
||||
ret = rm_ftrace_export(&ftrace_exports_list, export);
|
||||
|
||||
mutex_unlock(&ftrace_export_lock);
|
||||
|
||||
return ret;
|
||||
guard(mutex)(&ftrace_export_lock);
|
||||
return rm_ftrace_export(&ftrace_exports_list, export);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_ftrace_export);
|
||||
|
||||
@@ -640,9 +629,8 @@ void trace_array_put(struct trace_array *this_tr)
|
||||
if (!this_tr)
|
||||
return;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
__trace_array_put(this_tr);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(trace_array_put);
|
||||
|
||||
@@ -1159,13 +1147,11 @@ int __trace_array_puts(struct trace_array *tr, unsigned long ip,
|
||||
|
||||
trace_ctx = tracing_gen_ctx();
|
||||
buffer = tr->array_buffer.buffer;
|
||||
ring_buffer_nest_start(buffer);
|
||||
guard(ring_buffer_nest)(buffer);
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,
|
||||
trace_ctx);
|
||||
if (!event) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
if (!event)
|
||||
return 0;
|
||||
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
@@ -1181,8 +1167,6 @@ int __trace_array_puts(struct trace_array *tr, unsigned long ip,
|
||||
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
|
||||
out:
|
||||
ring_buffer_nest_end(buffer);
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__trace_array_puts);
|
||||
@@ -1212,7 +1196,6 @@ int __trace_bputs(unsigned long ip, const char *str)
|
||||
struct bputs_entry *entry;
|
||||
unsigned int trace_ctx;
|
||||
int size = sizeof(struct bputs_entry);
|
||||
int ret = 0;
|
||||
|
||||
if (!printk_binsafe(tr))
|
||||
return __trace_puts(ip, str, strlen(str));
|
||||
@@ -1226,11 +1209,11 @@ int __trace_bputs(unsigned long ip, const char *str)
|
||||
trace_ctx = tracing_gen_ctx();
|
||||
buffer = tr->array_buffer.buffer;
|
||||
|
||||
ring_buffer_nest_start(buffer);
|
||||
guard(ring_buffer_nest)(buffer);
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
|
||||
trace_ctx);
|
||||
if (!event)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
@@ -1239,10 +1222,7 @@ int __trace_bputs(unsigned long ip, const char *str)
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
|
||||
|
||||
ret = 1;
|
||||
out:
|
||||
ring_buffer_nest_end(buffer);
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__trace_bputs);
|
||||
|
||||
@@ -1431,13 +1411,8 @@ static int tracing_arm_snapshot_locked(struct trace_array *tr)
|
||||
|
||||
int tracing_arm_snapshot(struct trace_array *tr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
ret = tracing_arm_snapshot_locked(tr);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return ret;
|
||||
guard(mutex)(&trace_types_lock);
|
||||
return tracing_arm_snapshot_locked(tr);
|
||||
}
|
||||
|
||||
void tracing_disarm_snapshot(struct trace_array *tr)
|
||||
@@ -1839,7 +1814,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||||
|
||||
ret = get_user(ch, ubuf++);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
read++;
|
||||
cnt--;
|
||||
@@ -1853,7 +1828,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||||
while (cnt && isspace(ch)) {
|
||||
ret = get_user(ch, ubuf++);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
read++;
|
||||
cnt--;
|
||||
}
|
||||
@@ -1863,8 +1838,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||||
/* only spaces were written */
|
||||
if (isspace(ch) || !ch) {
|
||||
*ppos += read;
|
||||
ret = read;
|
||||
goto out;
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1872,13 +1846,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||||
while (cnt && !isspace(ch) && ch) {
|
||||
if (parser->idx < parser->size - 1)
|
||||
parser->buffer[parser->idx++] = ch;
|
||||
else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = get_user(ch, ubuf++);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
read++;
|
||||
cnt--;
|
||||
}
|
||||
@@ -1893,15 +1866,11 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
|
||||
/* Make sure the parsed string always terminates with '\0'. */
|
||||
parser->buffer[parser->idx] = 0;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ppos += read;
|
||||
ret = read;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return read;
|
||||
}
|
||||
|
||||
/* TODO add a seq_buf_to_buffer() */
|
||||
@@ -2403,10 +2372,10 @@ int __init register_tracer(struct tracer *type)
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
if (ret || !default_bootup_tracer)
|
||||
goto out_unlock;
|
||||
return ret;
|
||||
|
||||
if (strncmp(default_bootup_tracer, type->name, MAX_TRACER_SIZE))
|
||||
goto out_unlock;
|
||||
return 0;
|
||||
|
||||
printk(KERN_INFO "Starting tracer '%s'\n", type->name);
|
||||
/* Do we want this tracer to start on bootup? */
|
||||
@@ -2418,8 +2387,7 @@ int __init register_tracer(struct tracer *type)
|
||||
/* disable other selftests, since this will break it. */
|
||||
disable_tracing_selftest("running a tracer");
|
||||
|
||||
out_unlock:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tracing_reset_cpu(struct array_buffer *buf, int cpu)
|
||||
@@ -2496,9 +2464,8 @@ void tracing_reset_all_online_cpus_unlocked(void)
|
||||
|
||||
void tracing_reset_all_online_cpus(void)
|
||||
{
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
tracing_reset_all_online_cpus_unlocked();
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
|
||||
int is_tracing_stopped(void)
|
||||
@@ -2509,18 +2476,17 @@ int is_tracing_stopped(void)
|
||||
static void tracing_start_tr(struct trace_array *tr)
|
||||
{
|
||||
struct trace_buffer *buffer;
|
||||
unsigned long flags;
|
||||
|
||||
if (tracing_disabled)
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&tr->start_lock, flags);
|
||||
guard(raw_spinlock_irqsave)(&tr->start_lock);
|
||||
if (--tr->stop_count) {
|
||||
if (WARN_ON_ONCE(tr->stop_count < 0)) {
|
||||
/* Someone screwed up their debugging */
|
||||
tr->stop_count = 0;
|
||||
}
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prevent the buffers from switching */
|
||||
@@ -2537,9 +2503,6 @@ static void tracing_start_tr(struct trace_array *tr)
|
||||
#endif
|
||||
|
||||
arch_spin_unlock(&tr->max_lock);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&tr->start_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2557,11 +2520,10 @@ void tracing_start(void)
|
||||
static void tracing_stop_tr(struct trace_array *tr)
|
||||
{
|
||||
struct trace_buffer *buffer;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&tr->start_lock, flags);
|
||||
guard(raw_spinlock_irqsave)(&tr->start_lock);
|
||||
if (tr->stop_count++)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/* Prevent the buffers from switching */
|
||||
arch_spin_lock(&tr->max_lock);
|
||||
@@ -2577,9 +2539,6 @@ static void tracing_stop_tr(struct trace_array *tr)
|
||||
#endif
|
||||
|
||||
arch_spin_unlock(&tr->max_lock);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&tr->start_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2692,12 +2651,12 @@ void trace_buffered_event_enable(void)
|
||||
|
||||
per_cpu(trace_buffered_event, cpu) = event;
|
||||
|
||||
preempt_disable();
|
||||
if (cpu == smp_processor_id() &&
|
||||
__this_cpu_read(trace_buffered_event) !=
|
||||
per_cpu(trace_buffered_event, cpu))
|
||||
WARN_ON_ONCE(1);
|
||||
preempt_enable();
|
||||
scoped_guard(preempt,) {
|
||||
if (cpu == smp_processor_id() &&
|
||||
__this_cpu_read(trace_buffered_event) !=
|
||||
per_cpu(trace_buffered_event, cpu))
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3042,7 +3001,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
|
||||
skip++;
|
||||
#endif
|
||||
|
||||
preempt_disable_notrace();
|
||||
guard(preempt_notrace)();
|
||||
|
||||
stackidx = __this_cpu_inc_return(ftrace_stack_reserve) - 1;
|
||||
|
||||
@@ -3100,8 +3059,6 @@ static void __ftrace_trace_stack(struct trace_array *tr,
|
||||
/* Again, don't let gcc optimize things here */
|
||||
barrier();
|
||||
__this_cpu_dec(ftrace_stack_reserve);
|
||||
preempt_enable_notrace();
|
||||
|
||||
}
|
||||
|
||||
static inline void ftrace_trace_stack(struct trace_array *tr,
|
||||
@@ -3184,9 +3141,9 @@ ftrace_trace_userstack(struct trace_array *tr,
|
||||
* prevent recursion, since the user stack tracing may
|
||||
* trigger other kernel events.
|
||||
*/
|
||||
preempt_disable();
|
||||
guard(preempt)();
|
||||
if (__this_cpu_read(user_stack_count))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
__this_cpu_inc(user_stack_count);
|
||||
|
||||
@@ -3204,8 +3161,6 @@ ftrace_trace_userstack(struct trace_array *tr,
|
||||
|
||||
out_drop_count:
|
||||
__this_cpu_dec(user_stack_count);
|
||||
out:
|
||||
preempt_enable();
|
||||
}
|
||||
#else /* CONFIG_USER_STACKTRACE_SUPPORT */
|
||||
static void ftrace_trace_userstack(struct trace_array *tr,
|
||||
@@ -3387,7 +3342,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
|
||||
pause_graph_tracing();
|
||||
|
||||
trace_ctx = tracing_gen_ctx();
|
||||
preempt_disable_notrace();
|
||||
guard(preempt_notrace)();
|
||||
|
||||
tbuffer = get_trace_buf();
|
||||
if (!tbuffer) {
|
||||
@@ -3402,26 +3357,23 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
|
||||
|
||||
size = sizeof(*entry) + sizeof(u32) * len;
|
||||
buffer = tr->array_buffer.buffer;
|
||||
ring_buffer_nest_start(buffer);
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
|
||||
trace_ctx);
|
||||
if (!event)
|
||||
goto out;
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
entry->fmt = fmt;
|
||||
scoped_guard(ring_buffer_nest, buffer) {
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
|
||||
trace_ctx);
|
||||
if (!event)
|
||||
goto out_put;
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
entry->fmt = fmt;
|
||||
|
||||
memcpy(entry->buf, tbuffer, sizeof(u32) * len);
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL);
|
||||
|
||||
out:
|
||||
ring_buffer_nest_end(buffer);
|
||||
memcpy(entry->buf, tbuffer, sizeof(u32) * len);
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL);
|
||||
}
|
||||
out_put:
|
||||
put_trace_buf();
|
||||
|
||||
out_nobuffer:
|
||||
preempt_enable_notrace();
|
||||
unpause_graph_tracing();
|
||||
|
||||
return len;
|
||||
@@ -3445,7 +3397,7 @@ int __trace_array_vprintk(struct trace_buffer *buffer,
|
||||
pause_graph_tracing();
|
||||
|
||||
trace_ctx = tracing_gen_ctx();
|
||||
preempt_disable_notrace();
|
||||
guard(preempt_notrace)();
|
||||
|
||||
|
||||
tbuffer = get_trace_buf();
|
||||
@@ -3457,24 +3409,22 @@ int __trace_array_vprintk(struct trace_buffer *buffer,
|
||||
len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
|
||||
|
||||
size = sizeof(*entry) + len + 1;
|
||||
ring_buffer_nest_start(buffer);
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
|
||||
trace_ctx);
|
||||
if (!event)
|
||||
goto out;
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
|
||||
memcpy(&entry->buf, tbuffer, len + 1);
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL);
|
||||
scoped_guard(ring_buffer_nest, buffer) {
|
||||
event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
|
||||
trace_ctx);
|
||||
if (!event)
|
||||
goto out;
|
||||
entry = ring_buffer_event_data(event);
|
||||
entry->ip = ip;
|
||||
|
||||
memcpy(&entry->buf, tbuffer, len + 1);
|
||||
__buffer_unlock_commit(buffer, event);
|
||||
ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL);
|
||||
}
|
||||
out:
|
||||
ring_buffer_nest_end(buffer);
|
||||
put_trace_buf();
|
||||
|
||||
out_nobuffer:
|
||||
preempt_enable_notrace();
|
||||
unpause_graph_tracing();
|
||||
|
||||
return len;
|
||||
@@ -4798,20 +4748,16 @@ int tracing_open_file_tr(struct inode *inode, struct file *filp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
guard(mutex)(&event_mutex);
|
||||
|
||||
/* Fail if the file is marked for removal */
|
||||
if (file->flags & EVENT_FILE_FL_FREED) {
|
||||
trace_array_put(file->tr);
|
||||
ret = -ENODEV;
|
||||
return -ENODEV;
|
||||
} else {
|
||||
event_file_get(file);
|
||||
}
|
||||
|
||||
mutex_unlock(&event_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
filp->private_data = inode->i_private;
|
||||
|
||||
return 0;
|
||||
@@ -5088,7 +5034,7 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct trace_array *tr = file_inode(filp)->i_private;
|
||||
char *mask_str;
|
||||
char *mask_str __free(kfree) = NULL;
|
||||
int len;
|
||||
|
||||
len = snprintf(NULL, 0, "%*pb\n",
|
||||
@@ -5099,16 +5045,10 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,
|
||||
|
||||
len = snprintf(mask_str, len, "%*pb\n",
|
||||
cpumask_pr_args(tr->tracing_cpumask));
|
||||
if (len >= count) {
|
||||
count = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
count = simple_read_from_buffer(ubuf, count, ppos, mask_str, len);
|
||||
if (len >= count)
|
||||
return -EINVAL;
|
||||
|
||||
out_err:
|
||||
kfree(mask_str);
|
||||
|
||||
return count;
|
||||
return simple_read_from_buffer(ubuf, count, ppos, mask_str, len);
|
||||
}
|
||||
|
||||
int tracing_set_cpumask(struct trace_array *tr,
|
||||
@@ -5955,9 +5895,9 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
|
||||
char buf[MAX_TRACER_SIZE+2];
|
||||
int r;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
r = sprintf(buf, "%s\n", tr->current_trace->name);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
scoped_guard(mutex, &trace_types_lock) {
|
||||
r = sprintf(buf, "%s\n", tr->current_trace->name);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
|
||||
}
|
||||
@@ -6259,15 +6199,13 @@ int tracing_update_buffers(struct trace_array *tr)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
|
||||
update_last_data(tr);
|
||||
|
||||
if (!tr->ring_buffer_expanded)
|
||||
ret = __tracing_resize_ring_buffer(tr, trace_buf_size,
|
||||
RING_BUFFER_ALL_CPUS);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6564,7 +6502,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
cpu = tracing_get_cpu(inode);
|
||||
ret = open_pipe_on_cpu(tr, cpu);
|
||||
if (ret)
|
||||
@@ -6608,7 +6546,6 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
||||
|
||||
tr->trace_ref++;
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
@@ -6617,7 +6554,6 @@ fail_alloc_iter:
|
||||
close_pipe_on_cpu(tr, cpu);
|
||||
fail_pipe_on_cpu:
|
||||
__trace_array_put(tr);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6626,14 +6562,13 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
|
||||
struct trace_iterator *iter = file->private_data;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
scoped_guard(mutex, &trace_types_lock) {
|
||||
tr->trace_ref--;
|
||||
|
||||
tr->trace_ref--;
|
||||
|
||||
if (iter->trace->pipe_close)
|
||||
iter->trace->pipe_close(iter);
|
||||
close_pipe_on_cpu(tr, iter->cpu_file);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
if (iter->trace->pipe_close)
|
||||
iter->trace->pipe_close(iter);
|
||||
close_pipe_on_cpu(tr, iter->cpu_file);
|
||||
}
|
||||
|
||||
free_trace_iter_content(iter);
|
||||
kfree(iter);
|
||||
@@ -7436,7 +7371,7 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
|
||||
if (i == ARRAY_SIZE(trace_clocks))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
|
||||
tr->clock_id = i;
|
||||
|
||||
@@ -7460,8 +7395,6 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
|
||||
tscratch->clock_id = i;
|
||||
}
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7513,15 +7446,13 @@ static int tracing_time_stamp_mode_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct trace_array *tr = m->private;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
|
||||
if (ring_buffer_time_stamp_abs(tr->array_buffer.buffer))
|
||||
seq_puts(m, "delta [absolute]\n");
|
||||
else
|
||||
seq_puts(m, "[delta] absolute\n");
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8109,14 +8040,14 @@ static void clear_tracing_err_log(struct trace_array *tr)
|
||||
{
|
||||
struct tracing_log_err *err, *next;
|
||||
|
||||
mutex_lock(&tracing_err_log_lock);
|
||||
guard(mutex)(&tracing_err_log_lock);
|
||||
|
||||
list_for_each_entry_safe(err, next, &tr->err_log, list) {
|
||||
list_del(&err->list);
|
||||
free_tracing_log_err(err);
|
||||
}
|
||||
|
||||
tr->n_err_log_entries = 0;
|
||||
mutex_unlock(&tracing_err_log_lock);
|
||||
}
|
||||
|
||||
static void *tracing_err_log_seq_start(struct seq_file *m, loff_t *pos)
|
||||
@@ -8387,7 +8318,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
|
||||
struct ftrace_buffer_info *info = file->private_data;
|
||||
struct trace_iterator *iter = &info->iter;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
|
||||
iter->tr->trace_ref--;
|
||||
|
||||
@@ -8398,8 +8329,6 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
|
||||
info->spare_cpu, info->spare);
|
||||
kvfree(info);
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8607,14 +8536,13 @@ static long tracing_buffers_ioctl(struct file *file, unsigned int cmd, unsigned
|
||||
* An ioctl call with cmd 0 to the ring buffer file will wake up all
|
||||
* waiters
|
||||
*/
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
|
||||
/* Make sure the waiters see the new wait_index */
|
||||
(void)atomic_fetch_inc_release(&iter->wait_index);
|
||||
|
||||
ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8955,12 +8883,12 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
|
||||
out_reg:
|
||||
ret = tracing_arm_snapshot(tr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
ret = register_ftrace_function_probe(glob, tr, ops, count);
|
||||
if (ret < 0)
|
||||
tracing_disarm_snapshot(tr);
|
||||
out:
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
@@ -9104,10 +9032,9 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
return -EINVAL;
|
||||
|
||||
if (!!(topt->flags->val & topt->opt->bit) != val) {
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
ret = __set_tracer_option(topt->tr, topt->flags,
|
||||
topt->opt, !val);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -9416,7 +9343,7 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
|
||||
return ret;
|
||||
|
||||
if (buffer) {
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
if (!!val == tracer_tracing_is_on(tr)) {
|
||||
val = 0; /* do nothing */
|
||||
} else if (val) {
|
||||
@@ -9430,7 +9357,6 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
|
||||
/* Wake up any waiters */
|
||||
ring_buffer_wake_waiters(buffer, RING_BUFFER_ALL_CPUS);
|
||||
}
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
|
||||
(*ppos)++;
|
||||
@@ -9814,10 +9740,9 @@ static void __update_tracer_options(struct trace_array *tr)
|
||||
|
||||
static void update_tracer_options(struct trace_array *tr)
|
||||
{
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
tracer_options_updated = true;
|
||||
__update_tracer_options(tr);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
|
||||
/* Must have trace_types_lock held */
|
||||
@@ -9839,11 +9764,10 @@ struct trace_array *trace_array_find_get(const char *instance)
|
||||
{
|
||||
struct trace_array *tr;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
guard(mutex)(&trace_types_lock);
|
||||
tr = trace_array_find(instance);
|
||||
if (tr)
|
||||
tr->ref++;
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return tr;
|
||||
}
|
||||
@@ -10374,7 +10298,7 @@ bool module_exists(const char *module)
|
||||
{
|
||||
/* All modules have the symbol __this_module */
|
||||
static const char this_mod[] = "__this_module";
|
||||
char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2];
|
||||
char modname[MODULE_NAME_LEN + sizeof(this_mod) + 2];
|
||||
unsigned long val;
|
||||
int n;
|
||||
|
||||
@@ -10801,7 +10725,8 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos,
|
||||
int (*createfn)(const char *))
|
||||
{
|
||||
char *kbuf, *buf, *tmp;
|
||||
char *kbuf __free(kfree) = NULL;
|
||||
char *buf, *tmp;
|
||||
int ret = 0;
|
||||
size_t done = 0;
|
||||
size_t size;
|
||||
@@ -10816,10 +10741,9 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
|
||||
if (size >= WRITE_BUFSIZE)
|
||||
size = WRITE_BUFSIZE - 1;
|
||||
|
||||
if (copy_from_user(kbuf, buffer + done, size)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(kbuf, buffer + done, size))
|
||||
return -EFAULT;
|
||||
|
||||
kbuf[size] = '\0';
|
||||
buf = kbuf;
|
||||
do {
|
||||
@@ -10835,8 +10759,7 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
|
||||
/* This can accept WRITE_BUFSIZE - 2 ('\n' + '\0') */
|
||||
pr_warn("Line length is too long: Should be less than %d\n",
|
||||
WRITE_BUFSIZE - 2);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
done += size;
|
||||
@@ -10849,17 +10772,12 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
|
||||
|
||||
ret = createfn(buf);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
buf += size;
|
||||
|
||||
} while (done < count);
|
||||
}
|
||||
ret = done;
|
||||
|
||||
out:
|
||||
kfree(kbuf);
|
||||
|
||||
return ret;
|
||||
return done;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRACER_MAX_TRACE
|
||||
@@ -11062,7 +10980,7 @@ __init static int tracer_alloc_buffers(void)
|
||||
BUILD_BUG_ON(TRACE_ITER_LAST_BIT > TRACE_FLAGS_MAX_SIZE);
|
||||
|
||||
if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
if (!alloc_cpumask_var(&global_trace.tracing_cpumask, GFP_KERNEL))
|
||||
goto out_free_buffer_mask;
|
||||
@@ -11180,7 +11098,6 @@ out_free_cpumask:
|
||||
free_cpumask_var(global_trace.tracing_cpumask);
|
||||
out_free_buffer_mask:
|
||||
free_cpumask_var(tracing_buffer_mask);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user