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:
Carlos Llamas committed 2025-09-02 18:08:01 +00:00
commit 42d3f1efd8
137 files changed
+5120 -1031

No files matched your search

+1
View File
@@ -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
+21
View File
@@ -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.
+19 -1
View File
@@ -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
View File
@@ -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>
+7 -4
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1
View File
@@ -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
+1
View File
@@ -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[] = {
+32 -16
View File
@@ -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();
}
+6 -4
View File
@@ -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) */
+1 -1
View File
@@ -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;
+3
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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)
+82
View File
@@ -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;
+1
View File
@@ -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
+1
View File
@@ -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) {
+5
View File
@@ -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)
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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;
+3 -2
View File
@@ -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[] = {
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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];
+2 -2
View File
@@ -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];
+1 -1
View File
@@ -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,
+1 -2
View File
@@ -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
+1 -1
View File
@@ -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;
+6 -5
View File
@@ -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,
+38
View File
@@ -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
View File
@@ -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;
+10
View File
@@ -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.
+1
View File
@@ -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
+11 -36
View File
@@ -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;
}
+24 -66
View File
@@ -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 = {
+1 -1
View File
@@ -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
+14 -16
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -2
View File
@@ -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");
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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;
}
}
+8
View File
@@ -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];
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+14 -1
View File
@@ -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
View File
@@ -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__;
+9 -9
View File
@@ -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)
+2 -2
View File
@@ -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))
+9 -4
View File
@@ -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
/**
+4 -4
View File
@@ -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;
+10
View File
@@ -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
View File
@@ -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)
{
+9 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+3
View File
@@ -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);
+12
View File
@@ -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>
+28
View File
@@ -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 */
-26
View File
@@ -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
*
+1
View File
@@ -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.
+1 -1
View File
@@ -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);
+4
View File
@@ -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
View File
@@ -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();
}
+15
View File
@@ -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
View File
@@ -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)
{
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+7
View File
@@ -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);
+7 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6 -10
View File
@@ -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
View File
@@ -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