25065 lines
829 KiB
Diff
25065 lines
829 KiB
Diff
diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst
|
|
index 70d3bc90893f33..949c0d35694c2c 100644
|
|
--- a/Documentation/PCI/endpoint/pci-vntb-howto.rst
|
|
+++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst
|
|
@@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used::
|
|
# cd /sys/kernel/config/pci_ep/
|
|
# mkdir functions/pci_epf_vntb/func1
|
|
|
|
-The "mkdir func1" above creates the pci-epf-ntb function device that will
|
|
+The "mkdir func1" above creates the pci-epf-vntb function device that will
|
|
be probed by pci_epf_vntb driver.
|
|
|
|
The PCI endpoint framework populates the directory with the following
|
|
configurable fields::
|
|
|
|
- # ls functions/pci_epf_ntb/func1
|
|
- baseclass_code deviceid msi_interrupts pci-epf-ntb.0
|
|
+ # ls functions/pci_epf_vntb/func1
|
|
+ baseclass_code deviceid msi_interrupts pci-epf-vntb.0
|
|
progif_code secondary subsys_id vendorid
|
|
cache_line_size interrupt_pin msix_interrupts primary
|
|
revid subclass_code subsys_vendor_id
|
|
@@ -106,13 +106,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus::
|
|
# echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid
|
|
# echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number
|
|
|
|
-Binding pci-epf-ntb Device to EP Controller
|
|
+Binding pci-epf-vntb Device to EP Controller
|
|
--------------------------------------------
|
|
|
|
NTB function device should be attached to PCI endpoint controllers
|
|
connected to the host.
|
|
|
|
- # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary
|
|
+ # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary
|
|
|
|
Once the above step is completed, the PCI endpoint controllers are ready to
|
|
establish a link with the host.
|
|
@@ -134,7 +134,7 @@ lspci Output at Host side
|
|
-------------------------
|
|
|
|
Note that the devices listed here correspond to the values populated in
|
|
-"Creating pci-epf-ntb Device" section above::
|
|
+"Creating pci-epf-vntb Device" section above::
|
|
|
|
# lspci
|
|
00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01)
|
|
@@ -147,7 +147,7 @@ lspci Output at EP Side / Virtual PCI bus
|
|
-----------------------------------------
|
|
|
|
Note that the devices listed here correspond to the values populated in
|
|
-"Creating pci-epf-ntb Device" section above::
|
|
+"Creating pci-epf-vntb Device" section above::
|
|
|
|
# lspci
|
|
10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff)
|
|
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4458.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4458.yaml
|
|
index 4477f84b7acc0e..e44801ddbd2a92 100644
|
|
--- a/Documentation/devicetree/bindings/sound/asahi-kasei,ak4458.yaml
|
|
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4458.yaml
|
|
@@ -18,10 +18,10 @@ properties:
|
|
reg:
|
|
maxItems: 1
|
|
|
|
- avdd-supply:
|
|
+ AVDD-supply:
|
|
description: Analog power supply
|
|
|
|
- dvdd-supply:
|
|
+ DVDD-supply:
|
|
description: Digital power supply
|
|
|
|
reset-gpios:
|
|
@@ -56,7 +56,7 @@ allOf:
|
|
properties:
|
|
dsd-path: false
|
|
|
|
-additionalProperties: false
|
|
+unevaluatedProperties: false
|
|
|
|
examples:
|
|
- |
|
|
diff --git a/Documentation/devicetree/bindings/sound/asahi-kasei,ak5558.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak5558.yaml
|
|
index d3d494ae8abfeb..dc8f85f266bf30 100644
|
|
--- a/Documentation/devicetree/bindings/sound/asahi-kasei,ak5558.yaml
|
|
+++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak5558.yaml
|
|
@@ -19,10 +19,10 @@ properties:
|
|
reg:
|
|
maxItems: 1
|
|
|
|
- avdd-supply:
|
|
+ AVDD-supply:
|
|
description: A 1.8V supply that powers up the AVDD pin.
|
|
|
|
- dvdd-supply:
|
|
+ DVDD-supply:
|
|
description: A 1.2V supply that powers up the DVDD pin.
|
|
|
|
reset-gpios:
|
|
diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst
|
|
index cad96c8d1f97dd..613a818d5db6ec 100644
|
|
--- a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst
|
|
+++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst
|
|
@@ -24,6 +24,10 @@ Supported Devices
|
|
Currently, this driver support following devices:
|
|
* Network controller: Cavium, Inc. Device b200
|
|
* Network controller: Cavium, Inc. Device b400
|
|
+ * Network controller: Cavium, Inc. Device b900
|
|
+ * Network controller: Cavium, Inc. Device ba00
|
|
+ * Network controller: Cavium, Inc. Device bc00
|
|
+ * Network controller: Cavium, Inc. Device bd00
|
|
|
|
Interface Control
|
|
=================
|
|
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
|
|
index a66054d0763a69..531a070df2a6bb 100644
|
|
--- a/Documentation/networking/ip-sysctl.rst
|
|
+++ b/Documentation/networking/ip-sysctl.rst
|
|
@@ -745,6 +745,13 @@ tcp_comp_sack_nr - INTEGER
|
|
|
|
Default : 44
|
|
|
|
+tcp_backlog_ack_defer - BOOLEAN
|
|
+ If set, user thread processing socket backlog tries sending
|
|
+ one ACK for the whole queue. This helps to avoid potential
|
|
+ long latencies at end of a TCP socket syscall.
|
|
+
|
|
+ Default : true
|
|
+
|
|
tcp_slow_start_after_idle - BOOLEAN
|
|
If set, provide RFC2861 behavior and time out the congestion
|
|
window after an idle period. An idle period is defined at
|
|
@@ -1176,6 +1183,19 @@ tcp_plb_cong_thresh - INTEGER
|
|
|
|
Default: 128
|
|
|
|
+tcp_pingpong_thresh - INTEGER
|
|
+ The number of estimated data replies sent for estimated incoming data
|
|
+ requests that must happen before TCP considers that a connection is a
|
|
+ "ping-pong" (request-response) connection for which delayed
|
|
+ acknowledgments can provide benefits.
|
|
+
|
|
+ This threshold is 1 by default, but some applications may need a higher
|
|
+ threshold for optimal performance.
|
|
+
|
|
+ Possible Values: 1 - 255
|
|
+
|
|
+ Default: 1
|
|
+
|
|
UDP variables
|
|
=============
|
|
|
|
diff --git a/Documentation/trace/events-pci.rst b/Documentation/trace/events-pci.rst
|
|
new file mode 100644
|
|
index 00000000000000..03ff4ad30ddfa1
|
|
--- /dev/null
|
|
+++ b/Documentation/trace/events-pci.rst
|
|
@@ -0,0 +1,74 @@
|
|
+.. SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+===========================
|
|
+Subsystem Trace Points: PCI
|
|
+===========================
|
|
+
|
|
+Overview
|
|
+========
|
|
+The PCI tracing system provides tracepoints to monitor critical hardware events
|
|
+that can impact system performance and reliability. These events normally show
|
|
+up here:
|
|
+
|
|
+ /sys/kernel/tracing/events/pci
|
|
+
|
|
+Cf. include/trace/events/pci.h for the events definitions.
|
|
+
|
|
+Available Tracepoints
|
|
+=====================
|
|
+
|
|
+pci_hp_event
|
|
+------------
|
|
+
|
|
+Monitors PCI hotplug events including card insertion/removal and link
|
|
+state changes.
|
|
+::
|
|
+
|
|
+ pci_hp_event "%s slot:%s, event:%s\n"
|
|
+
|
|
+**Event Types**:
|
|
+
|
|
+* ``LINK_UP`` - PCIe link established
|
|
+* ``LINK_DOWN`` - PCIe link lost
|
|
+* ``CARD_PRESENT`` - Card detected in slot
|
|
+* ``CARD_NOT_PRESENT`` - Card removed from slot
|
|
+
|
|
+**Example Usage**::
|
|
+
|
|
+ # Enable the tracepoint
|
|
+ echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable
|
|
+
|
|
+ # Monitor events (the following output is generated when a device is hotplugged)
|
|
+ cat /sys/kernel/debug/tracing/trace_pipe
|
|
+ irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT
|
|
+
|
|
+ irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP
|
|
+
|
|
+pcie_link_event
|
|
+---------------
|
|
+
|
|
+Monitors PCIe link speed changes and provides detailed link status information.
|
|
+::
|
|
+
|
|
+ pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n"
|
|
+
|
|
+**Parameters**:
|
|
+
|
|
+* ``type`` - PCIe device type (4=Root Port, etc.)
|
|
+* ``reason`` - Reason for link change:
|
|
+
|
|
+ - ``0`` - Link retrain
|
|
+ - ``1`` - Bus enumeration
|
|
+ - ``2`` - Bandwidth notification enable
|
|
+ - ``3`` - Bandwidth notification IRQ
|
|
+ - ``4`` - Hotplug event
|
|
+
|
|
+
|
|
+**Example Usage**::
|
|
+
|
|
+ # Enable the tracepoint
|
|
+ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable
|
|
+
|
|
+ # Monitor events (the following output is generated when a device is hotplugged)
|
|
+ cat /sys/kernel/debug/tracing/trace_pipe
|
|
+ irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA
|
|
diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst
|
|
index 5092d6c13af5e3..e9bcb9d9f7f3b3 100644
|
|
--- a/Documentation/trace/index.rst
|
|
+++ b/Documentation/trace/index.rst
|
|
@@ -1,37 +1,104 @@
|
|
-==========================
|
|
-Linux Tracing Technologies
|
|
-==========================
|
|
+================================
|
|
+Linux Tracing Technologies Guide
|
|
+================================
|
|
+
|
|
+Tracing in the Linux kernel is a powerful mechanism that allows
|
|
+developers and system administrators to analyze and debug system
|
|
+behavior. This guide provides documentation on various tracing
|
|
+frameworks and tools available in the Linux kernel.
|
|
+
|
|
+Introduction to Tracing
|
|
+-----------------------
|
|
+
|
|
+This section provides an overview of Linux tracing mechanisms
|
|
+and debugging approaches.
|
|
|
|
.. toctree::
|
|
:maxdepth: 2
|
|
|
|
- ftrace-design
|
|
+ debugging
|
|
+ tracepoints
|
|
tracepoint-analysis
|
|
+ ring-buffer-map
|
|
+
|
|
+Core Tracing Frameworks
|
|
+-----------------------
|
|
+
|
|
+The following are the primary tracing frameworks integrated into
|
|
+the Linux kernel.
|
|
+
|
|
+.. toctree::
|
|
+ :maxdepth: 1
|
|
+
|
|
ftrace
|
|
+ ftrace-design
|
|
ftrace-uses
|
|
- fprobe
|
|
kprobes
|
|
kprobetrace
|
|
- uprobetracer
|
|
fprobetrace
|
|
- tracepoints
|
|
+ fprobe
|
|
+ ring-buffer-design
|
|
+
|
|
+Event Tracing and Analysis
|
|
+--------------------------
|
|
+
|
|
+A detailed explanation of event tracing mechanisms and their
|
|
+applications.
|
|
+
|
|
+.. toctree::
|
|
+ :maxdepth: 1
|
|
+
|
|
events
|
|
events-kmem
|
|
events-power
|
|
events-nmi
|
|
events-msr
|
|
- mmiotrace
|
|
+ events-pci
|
|
+ boottime-trace
|
|
histogram
|
|
histogram-design
|
|
- boottime-trace
|
|
- hwlat_detector
|
|
- osnoise-tracer
|
|
- timerlat-tracer
|
|
+
|
|
+Hardware and Performance Tracing
|
|
+--------------------------------
|
|
+
|
|
+This section covers tracing features that monitor hardware
|
|
+interactions and system performance.
|
|
+
|
|
+.. toctree::
|
|
+ :maxdepth: 1
|
|
+
|
|
intel_th
|
|
- ring-buffer-design
|
|
stm
|
|
sys-t
|
|
coresight/index
|
|
- user_events
|
|
rv/index
|
|
hisi-ptt
|
|
+ mmiotrace
|
|
+ hwlat_detector
|
|
+ osnoise-tracer
|
|
+ timerlat-tracer
|
|
+
|
|
+User-Space Tracing
|
|
+------------------
|
|
+
|
|
+These tools allow tracing user-space applications and
|
|
+interactions.
|
|
+
|
|
+.. toctree::
|
|
+ :maxdepth: 1
|
|
+
|
|
+ user_events
|
|
+ uprobetracer
|
|
+
|
|
+Additional Resources
|
|
+--------------------
|
|
+
|
|
+For more details, refer to the respective documentation of each
|
|
+tracing tool and framework.
|
|
+
|
|
+.. only:: subproject and html
|
|
+
|
|
+ Indices
|
|
+ =======
|
|
+
|
|
+ * :ref:`genindex`
|
|
diff --git a/Documentation/trace/ring-buffer-map.rst b/Documentation/trace/ring-buffer-map.rst
|
|
new file mode 100644
|
|
index 00000000000000..8e296bcc0d7f32
|
|
--- /dev/null
|
|
+++ b/Documentation/trace/ring-buffer-map.rst
|
|
@@ -0,0 +1,106 @@
|
|
+.. SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+==================================
|
|
+Tracefs ring-buffer memory mapping
|
|
+==================================
|
|
+
|
|
+:Author: Vincent Donnefort <vdonnefort@google.com>
|
|
+
|
|
+Overview
|
|
+========
|
|
+Tracefs ring-buffer memory map provides an efficient method to stream data
|
|
+as no memory copy is necessary. The application mapping the ring-buffer becomes
|
|
+then a consumer for that ring-buffer, in a similar fashion to trace_pipe.
|
|
+
|
|
+Memory mapping setup
|
|
+====================
|
|
+The mapping works with a mmap() of the trace_pipe_raw interface.
|
|
+
|
|
+The first system page of the mapping contains ring-buffer statistics and
|
|
+description. It is referred to as the meta-page. One of the most important
|
|
+fields of the meta-page is the reader. It contains the sub-buffer ID which can
|
|
+be safely read by the mapper (see ring-buffer-design.rst).
|
|
+
|
|
+The meta-page is followed by all the sub-buffers, ordered by ascending ID. It is
|
|
+therefore effortless to know where the reader starts in the mapping:
|
|
+
|
|
+.. code-block:: c
|
|
+
|
|
+ reader_id = meta->reader->id;
|
|
+ reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size;
|
|
+
|
|
+When the application is done with the current reader, it can get a new one using
|
|
+the trace_pipe_raw ioctl() TRACE_MMAP_IOCTL_GET_READER. This ioctl also updates
|
|
+the meta-page fields.
|
|
+
|
|
+Limitations
|
|
+===========
|
|
+When a mapping is in place on a Tracefs ring-buffer, it is not possible to
|
|
+either resize it (either by increasing the entire size of the ring-buffer or
|
|
+each subbuf). It is also not possible to use snapshot and causes splice to copy
|
|
+the ring buffer data instead of using the copyless swap from the ring buffer.
|
|
+
|
|
+Concurrent readers (either another application mapping that ring-buffer or the
|
|
+kernel with trace_pipe) are allowed but not recommended. They will compete for
|
|
+the ring-buffer and the output is unpredictable, just like concurrent readers on
|
|
+trace_pipe would be.
|
|
+
|
|
+Example
|
|
+=======
|
|
+
|
|
+.. code-block:: c
|
|
+
|
|
+ #include <fcntl.h>
|
|
+ #include <stdio.h>
|
|
+ #include <stdlib.h>
|
|
+ #include <unistd.h>
|
|
+
|
|
+ #include <linux/trace_mmap.h>
|
|
+
|
|
+ #include <sys/mman.h>
|
|
+ #include <sys/ioctl.h>
|
|
+
|
|
+ #define TRACE_PIPE_RAW "/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw"
|
|
+
|
|
+ int main(void)
|
|
+ {
|
|
+ int page_size = getpagesize(), fd, reader_id;
|
|
+ unsigned long meta_len, data_len;
|
|
+ struct trace_buffer_meta *meta;
|
|
+ void *map, *reader, *data;
|
|
+
|
|
+ fd = open(TRACE_PIPE_RAW, O_RDONLY | O_NONBLOCK);
|
|
+ if (fd < 0)
|
|
+ exit(EXIT_FAILURE);
|
|
+
|
|
+ map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
+ if (map == MAP_FAILED)
|
|
+ exit(EXIT_FAILURE);
|
|
+
|
|
+ meta = (struct trace_buffer_meta *)map;
|
|
+ meta_len = meta->meta_page_size;
|
|
+
|
|
+ printf("entries: %llu\n", meta->entries);
|
|
+ printf("overrun: %llu\n", meta->overrun);
|
|
+ printf("read: %llu\n", meta->read);
|
|
+ printf("nr_subbufs: %u\n", meta->nr_subbufs);
|
|
+
|
|
+ data_len = meta->subbuf_size * meta->nr_subbufs;
|
|
+ data = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, meta_len);
|
|
+ if (data == MAP_FAILED)
|
|
+ exit(EXIT_FAILURE);
|
|
+
|
|
+ if (ioctl(fd, TRACE_MMAP_IOCTL_GET_READER) < 0)
|
|
+ exit(EXIT_FAILURE);
|
|
+
|
|
+ reader_id = meta->reader.id;
|
|
+ reader = data + meta->subbuf_size * reader_id;
|
|
+
|
|
+ printf("Current reader address: %p\n", reader);
|
|
+
|
|
+ munmap(data, data_len);
|
|
+ munmap(meta, meta_len);
|
|
+ close (fd);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
diff --git a/Makefile b/Makefile
|
|
index b9c04d8271b94a..f7157576539da7 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 127
|
|
+SUBLEVEL = 128
|
|
EXTRAVERSION =
|
|
NAME = Pinguïn Aangedreven
|
|
|
|
@@ -1356,6 +1356,15 @@ ifneq ($(wildcard $(resolve_btfids_O)),)
|
|
$(Q)$(MAKE) -sC $(srctree)/tools/bpf/resolve_btfids O=$(resolve_btfids_O) clean
|
|
endif
|
|
|
|
+PHONY += objtool_clean
|
|
+
|
|
+objtool_O = $(abspath $(objtree))/tools/objtool
|
|
+
|
|
+objtool_clean:
|
|
+ifneq ($(wildcard $(objtool_O)),)
|
|
+ $(Q)$(MAKE) -sC $(abs_srctree)/tools/objtool O=$(objtool_O) srctree=$(abs_srctree) clean
|
|
+endif
|
|
+
|
|
tools/: FORCE
|
|
$(Q)mkdir -p $(objtree)/tools
|
|
$(Q)$(MAKE) O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/
|
|
@@ -1509,7 +1518,7 @@ vmlinuxclean:
|
|
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean
|
|
$(Q)$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) clean)
|
|
|
|
-clean: archclean vmlinuxclean resolve_btfids_clean
|
|
+clean: archclean vmlinuxclean resolve_btfids_clean objtool_clean
|
|
|
|
# mrproper - Delete all generated files, including .config
|
|
#
|
|
diff --git a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
|
|
index be486d28d04fae..428cab5a0e906e 100644
|
|
--- a/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
|
|
+++ b/arch/arm/boot/dts/allwinner/sun5i-a13-utoo-p66.dts
|
|
@@ -102,6 +102,7 @@
|
|
/* The P66 uses a different EINT then the reference design */
|
|
interrupts = <6 9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */
|
|
/* The icn8318 binding expects wake-gpios instead of power-gpios */
|
|
+ /delete-property/ power-gpios;
|
|
wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
|
|
touchscreen-size-x = <800>;
|
|
touchscreen-size-y = <480>;
|
|
diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
|
|
index 974410918f35b6..7503074d2877c2 100644
|
|
--- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
|
|
+++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi
|
|
@@ -301,8 +301,9 @@
|
|
mpwm: mpwm@400e8000 {
|
|
compatible = "nxp,lpc3220-motor-pwm";
|
|
reg = <0x400e8000 0x78>;
|
|
+ clocks = <&clk LPC32XX_CLK_MCPWM>;
|
|
+ #pwm-cells = <3>;
|
|
status = "disabled";
|
|
- #pwm-cells = <2>;
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
|
|
index f297d66a8a7624..32b6683b459568 100644
|
|
--- a/arch/arm/kernel/vdso.c
|
|
+++ b/arch/arm/kernel/vdso.c
|
|
@@ -176,6 +176,7 @@ static void __init patch_vdso(void *ehdr)
|
|
vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
|
|
vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
|
|
vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64");
|
|
+ vdso_nullpatch_one(&einfo, "__vdso_clock_getres");
|
|
}
|
|
}
|
|
|
|
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
|
|
index 79860b23030de3..eb6fc7c61b6e08 100644
|
|
--- a/arch/arm/mach-omap2/control.c
|
|
+++ b/arch/arm/mach-omap2/control.c
|
|
@@ -732,7 +732,7 @@ int __init omap2_control_base_init(void)
|
|
*/
|
|
int __init omap_control_init(void)
|
|
{
|
|
- struct device_node *np, *scm_conf;
|
|
+ struct device_node *np, *scm_conf, *clocks_node;
|
|
const struct of_device_id *match;
|
|
const struct omap_prcm_init_data *data;
|
|
int ret;
|
|
@@ -753,16 +753,19 @@ int __init omap_control_init(void)
|
|
|
|
if (IS_ERR(syscon)) {
|
|
ret = PTR_ERR(syscon);
|
|
- goto of_node_put;
|
|
+ goto err_put_scm_conf;
|
|
}
|
|
|
|
- if (of_get_child_by_name(scm_conf, "clocks")) {
|
|
+ clocks_node = of_get_child_by_name(scm_conf, "clocks");
|
|
+ if (clocks_node) {
|
|
+ of_node_put(clocks_node);
|
|
ret = omap2_clk_provider_init(scm_conf,
|
|
data->index,
|
|
syscon, NULL);
|
|
if (ret)
|
|
- goto of_node_put;
|
|
+ goto err_put_scm_conf;
|
|
}
|
|
+ of_node_put(scm_conf);
|
|
} else {
|
|
/* No scm_conf found, direct access */
|
|
ret = omap2_clk_provider_init(np, data->index, NULL,
|
|
@@ -780,6 +783,9 @@ int __init omap_control_init(void)
|
|
|
|
return 0;
|
|
|
|
+err_put_scm_conf:
|
|
+ if (scm_conf)
|
|
+ of_node_put(scm_conf);
|
|
of_node_put:
|
|
of_node_put(np);
|
|
return ret;
|
|
diff --git a/arch/arm/mm/physaddr.c b/arch/arm/mm/physaddr.c
|
|
index 3f263c840ebc46..1a37ebfacbba96 100644
|
|
--- a/arch/arm/mm/physaddr.c
|
|
+++ b/arch/arm/mm/physaddr.c
|
|
@@ -38,7 +38,7 @@ static inline bool __virt_addr_valid(unsigned long x)
|
|
phys_addr_t __virt_to_phys(unsigned long x)
|
|
{
|
|
WARN(!__virt_addr_valid(x),
|
|
- "virt_to_phys used for non-linear address: %pK (%pS)\n",
|
|
+ "virt_to_phys used for non-linear address: %px (%pS)\n",
|
|
(void *)x, (void *)x);
|
|
|
|
return __virt_to_phys_nodebug(x);
|
|
diff --git a/arch/arm64/Kbuild b/arch/arm64/Kbuild
|
|
index 5bfbf7d79c99be..d876bc0e542110 100644
|
|
--- a/arch/arm64/Kbuild
|
|
+++ b/arch/arm64/Kbuild
|
|
@@ -1,4 +1,8 @@
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+# Branch profiling isn't noinstr-safe
|
|
+subdir-ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING
|
|
+
|
|
obj-y += kernel/ mm/ net/
|
|
obj-$(CONFIG_KVM) += kvm/
|
|
obj-$(CONFIG_XEN) += xen/
|
|
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
|
|
index 768d0ed78dbe63..16af71d84a1324 100644
|
|
--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
|
|
+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
|
|
@@ -1894,6 +1894,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_B>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
sd_emmc_c: mmc@7000 {
|
|
@@ -1906,6 +1909,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_C>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
usb2_phy1: phy@9020 {
|
|
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
index 0ff0d090548d0e..c5848363df37ae 100644
|
|
--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
+++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
|
@@ -2341,6 +2341,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_A>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
sd_emmc_b: mmc@ffe05000 {
|
|
@@ -2353,6 +2356,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_B>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
sd_emmc_c: mmc@ffe07000 {
|
|
@@ -2365,6 +2371,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_C>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
usb: usb@ffe09000 {
|
|
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
|
index ed00e67e6923a0..851ae89dd17faa 100644
|
|
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
|
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
|
@@ -799,6 +799,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_A>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&sd_emmc_b {
|
|
@@ -807,6 +810,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_B>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&sd_emmc_c {
|
|
@@ -815,6 +821,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_C>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&simplefb_hdmi {
|
|
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
|
index f58d1790de1cb4..f7fafebafd809e 100644
|
|
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
|
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
|
@@ -869,6 +869,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_A>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_A_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&sd_emmc_b {
|
|
@@ -877,6 +880,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_B>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_B_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&sd_emmc_c {
|
|
@@ -885,6 +891,9 @@
|
|
<&clkc CLKID_FCLK_DIV2>;
|
|
clock-names = "core", "clkin0", "clkin1";
|
|
resets = <&reset RESET_SD_EMMC_C>;
|
|
+
|
|
+ assigned-clocks = <&clkc CLKID_SD_EMMC_C_CLK0>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
};
|
|
|
|
&simplefb_hdmi {
|
|
diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts
|
|
index 06fe257f08be49..4ae1ce919dafc4 100644
|
|
--- a/arch/arm64/boot/dts/apple/t8112-j473.dts
|
|
+++ b/arch/arm64/boot/dts/apple/t8112-j473.dts
|
|
@@ -21,6 +21,25 @@
|
|
};
|
|
};
|
|
|
|
+/*
|
|
+ * Keep the power-domains used for the HDMI port on.
|
|
+ */
|
|
+&framebuffer0 {
|
|
+ power-domains = <&ps_dispext_cpu0>, <&ps_dptx_ext_phy>;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * The M2 Mac mini uses dispext for the HDMI output so it's not necessary to
|
|
+ * keep disp0 power-domains always-on.
|
|
+ */
|
|
+&ps_disp0_sys {
|
|
+ /delete-property/ apple,always-on;
|
|
+};
|
|
+
|
|
+&ps_disp0_fe {
|
|
+ /delete-property/ apple,always-on;
|
|
+};
|
|
+
|
|
/*
|
|
* Force the bus number assignments so that we can declare some of the
|
|
* on-board devices and properties that are populated by the bootloader
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
|
|
index 258e90cc16ff3a..5430b62a3b2827 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
|
|
@@ -810,7 +810,7 @@
|
|
fsl,pins = <MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x400001c2>,
|
|
<MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x400001c2>,
|
|
<MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x40000010>,
|
|
- <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x40000010>;
|
|
+ <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x40000030>;
|
|
};
|
|
|
|
pinctrl_hoggpio2: hoggpio2grp {
|
|
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
|
|
index 53805555dd2d24..a75c6c1928a4a5 100644
|
|
--- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
|
|
+++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
|
|
@@ -1724,6 +1724,8 @@
|
|
status = "okay";
|
|
vbus-supply = <&usbc_vbus>;
|
|
mode = "otg";
|
|
+ usb-role-switch;
|
|
+ role-switch-default-mode = "host";
|
|
};
|
|
|
|
usb3-0 {
|
|
diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi
|
|
index 0f3f57fb860ec8..74b36cb8bffa8b 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi
|
|
+++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi
|
|
@@ -589,8 +589,8 @@
|
|
};
|
|
|
|
gpu_speed_bin: gpu-speed-bin@41a0 {
|
|
- reg = <0x41a2 0x1>;
|
|
- bits = <5 7>;
|
|
+ reg = <0x41a2 0x2>;
|
|
+ bits = <5 8>;
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
|
|
index 0a891a0122446c..1164f2cf5bc961 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
|
|
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
|
|
@@ -372,6 +372,12 @@
|
|
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
|
|
};
|
|
|
|
+ vreg_l23a_3p3: ldo23 {
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3312000>;
|
|
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
|
|
+ };
|
|
+
|
|
vreg_l24a_3p075: ldo24 {
|
|
regulator-min-microvolt = <3088000>;
|
|
regulator-max-microvolt = <3088000>;
|
|
@@ -852,7 +858,6 @@
|
|
status = "okay";
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&qup_spi0_default>;
|
|
- cs-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>;
|
|
|
|
can@0 {
|
|
compatible = "microchip,mcp2517fd";
|
|
@@ -1158,6 +1163,7 @@
|
|
vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
|
|
vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
|
|
vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
|
|
+ vdd-3.3-ch1-supply = <&vreg_l23a_3p3>;
|
|
|
|
qcom,snoc-host-cap-8bit-quirk;
|
|
qcom,ath10k-calibration-variant = "Thundercomm_DB845C";
|
|
diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
|
|
index bccc52e01da382..e028b58a30f314 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
|
|
+++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
|
|
@@ -155,7 +155,6 @@
|
|
|
|
gpio = <&tlmm 88 0>;
|
|
enable-active-high;
|
|
- regulator-boot-on;
|
|
};
|
|
};
|
|
|
|
@@ -246,6 +245,7 @@
|
|
regulator-min-microvolt = <1800000>;
|
|
regulator-max-microvolt = <1800000>;
|
|
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
|
|
+ regulator-boot-on;
|
|
};
|
|
|
|
vreg_l14a_1p88: ldo14 {
|
|
diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi
|
|
index 5c6fcf725473c1..4c6d30404ff132 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi
|
|
+++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi
|
|
@@ -1336,8 +1336,12 @@
|
|
|
|
gpu: gpu@5900000 {
|
|
compatible = "qcom,adreno-610.0", "qcom,adreno";
|
|
- reg = <0x0 0x05900000 0x0 0x40000>;
|
|
- reg-names = "kgsl_3d0_reg_memory";
|
|
+ reg = <0x0 0x05900000 0x0 0x40000>,
|
|
+ <0x0 0x0599e000 0x0 0x1000>,
|
|
+ <0x0 0x05961000 0x0 0x800>;
|
|
+ reg-names = "kgsl_3d0_reg_memory",
|
|
+ "cx_mem",
|
|
+ "cx_dbgc";
|
|
|
|
/* There's no (real) GMU, so we have to handle quite a bunch of clocks! */
|
|
clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>,
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
|
|
index fb3012a6c9fc30..a1594a436eca63 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
|
|
@@ -429,10 +429,6 @@
|
|
status = "okay";
|
|
};
|
|
|
|
-&hdmi_sound {
|
|
- status = "okay";
|
|
-};
|
|
-
|
|
&i2c0 {
|
|
clock-frequency = <400000>;
|
|
i2c-scl-falling-time-ns = <4>;
|
|
diff --git a/arch/arm64/include/asm/rwonce.h b/arch/arm64/include/asm/rwonce.h
|
|
index 56f7b1d4d54b9a..bd5fc880b90908 100644
|
|
--- a/arch/arm64/include/asm/rwonce.h
|
|
+++ b/arch/arm64/include/asm/rwonce.h
|
|
@@ -62,7 +62,7 @@
|
|
default: \
|
|
atomic = 0; \
|
|
} \
|
|
- atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(__x))__x);\
|
|
+ atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(*__x) *)__x);\
|
|
})
|
|
|
|
#endif /* !BUILD_VDSO */
|
|
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
|
|
index 2c81e0efaf378e..19518a9da53f8a 100644
|
|
--- a/arch/arm64/kernel/proton-pack.c
|
|
+++ b/arch/arm64/kernel/proton-pack.c
|
|
@@ -896,6 +896,7 @@ static u8 spectre_bhb_loop_affected(void)
|
|
MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
|
|
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
|
|
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
|
|
+ MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
|
|
{},
|
|
};
|
|
static const struct midr_range spectre_bhb_k24_list[] = {
|
|
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c
|
|
index 5b7890139bc2f8..15a953ac6f0fbf 100644
|
|
--- a/arch/arm64/lib/delay.c
|
|
+++ b/arch/arm64/lib/delay.c
|
|
@@ -23,9 +23,24 @@ static inline unsigned long xloops_to_cycles(unsigned long xloops)
|
|
return (xloops * loops_per_jiffy * HZ) >> 32;
|
|
}
|
|
|
|
+/*
|
|
+ * Force the use of CNTVCT_EL0 in order to have the same base as WFxT.
|
|
+ * This avoids some annoying issues when CNTVOFF_EL2 is not reset 0 on a
|
|
+ * KVM host running at EL1 until we do a vcpu_put() on the vcpu. When
|
|
+ * running at EL2, the effective offset is always 0.
|
|
+ *
|
|
+ * Note that userspace cannot change the offset behind our back either,
|
|
+ * as the vcpu mutex is held as long as KVM_RUN is in progress.
|
|
+ */
|
|
+static cycles_t notrace __delay_cycles(void)
|
|
+{
|
|
+ guard(preempt_notrace)();
|
|
+ return __arch_counter_get_cntvct_stable();
|
|
+}
|
|
+
|
|
void __delay(unsigned long cycles)
|
|
{
|
|
- cycles_t start = get_cycles();
|
|
+ cycles_t start = __delay_cycles();
|
|
|
|
if (cpus_have_const_cap(ARM64_HAS_WFXT)) {
|
|
u64 end = start + cycles;
|
|
@@ -35,17 +50,17 @@ void __delay(unsigned long cycles)
|
|
* early, use a WFET loop to complete the delay.
|
|
*/
|
|
wfit(end);
|
|
- while ((get_cycles() - start) < cycles)
|
|
+ while ((__delay_cycles() - start) < cycles)
|
|
wfet(end);
|
|
} else if (arch_timer_evtstrm_available()) {
|
|
const cycles_t timer_evt_period =
|
|
USECS_TO_CYCLES(ARCH_TIMER_EVT_STREAM_PERIOD_US);
|
|
|
|
- while ((get_cycles() - start + timer_evt_period) < cycles)
|
|
+ while ((__delay_cycles() - start + timer_evt_period) < cycles)
|
|
wfe();
|
|
}
|
|
|
|
- while ((get_cycles() - start) < cycles)
|
|
+ while ((__delay_cycles() - start) < cycles)
|
|
cpu_relax();
|
|
}
|
|
EXPORT_SYMBOL(__delay);
|
|
diff --git a/arch/loongarch/include/asm/topology.h b/arch/loongarch/include/asm/topology.h
|
|
index 66128dec0bf6e0..6ff4cdc3d186db 100644
|
|
--- a/arch/loongarch/include/asm/topology.h
|
|
+++ b/arch/loongarch/include/asm/topology.h
|
|
@@ -11,7 +11,7 @@
|
|
|
|
extern cpumask_t cpus_on_node[];
|
|
|
|
-#define cpumask_of_node(node) (&cpus_on_node[node])
|
|
+#define cpumask_of_node(node) ((node) == NUMA_NO_NODE ? cpu_all_mask : &cpus_on_node[node])
|
|
|
|
struct pci_bus;
|
|
extern int pcibus_to_node(struct pci_bus *);
|
|
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
|
|
index 5dfd5d8dfca25f..2e34ece474eece 100644
|
|
--- a/arch/loongarch/kernel/setup.c
|
|
+++ b/arch/loongarch/kernel/setup.c
|
|
@@ -432,6 +432,7 @@ static void __init arch_mem_init(char **cmdline_p)
|
|
PFN_UP(__pa_symbol(&__nosave_end)));
|
|
|
|
memblock_dump_all();
|
|
+ memblock_set_bottom_up(false);
|
|
|
|
early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
|
|
}
|
|
diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c
|
|
index 929ae240280a5f..c9ee6892d81c7f 100644
|
|
--- a/arch/loongarch/kernel/unwind_prologue.c
|
|
+++ b/arch/loongarch/kernel/unwind_prologue.c
|
|
@@ -64,7 +64,7 @@ static inline bool scan_handlers(unsigned long entry_offset)
|
|
|
|
static inline bool fix_exception(unsigned long pc)
|
|
{
|
|
-#ifdef CONFIG_NUMA
|
|
+#if defined(CONFIG_NUMA) && !defined(CONFIG_PREEMPT_RT)
|
|
int cpu;
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c
|
|
index 526310ec73c7e6..885c9fa447caf6 100644
|
|
--- a/arch/loongarch/mm/tlb.c
|
|
+++ b/arch/loongarch/mm/tlb.c
|
|
@@ -201,7 +201,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
-static void setup_ptwalker(void)
|
|
+static void __no_sanitize_address setup_ptwalker(void)
|
|
{
|
|
unsigned long pwctl0, pwctl1;
|
|
unsigned long pgd_i = 0, pgd_w = 0;
|
|
diff --git a/arch/m68k/lib/memmove.c b/arch/m68k/lib/memmove.c
|
|
index 6519f7f349f665..e33f00b02e4c0f 100644
|
|
--- a/arch/m68k/lib/memmove.c
|
|
+++ b/arch/m68k/lib/memmove.c
|
|
@@ -24,6 +24,15 @@ void *memmove(void *dest, const void *src, size_t n)
|
|
src = csrc;
|
|
n--;
|
|
}
|
|
+#if defined(CONFIG_M68000)
|
|
+ if ((long)src & 1) {
|
|
+ char *cdest = dest;
|
|
+ const char *csrc = src;
|
|
+ for (; n; n--)
|
|
+ *cdest++ = *csrc++;
|
|
+ return xdest;
|
|
+ }
|
|
+#endif
|
|
if (n > 2 && (long)dest & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
@@ -66,6 +75,15 @@ void *memmove(void *dest, const void *src, size_t n)
|
|
src = csrc;
|
|
n--;
|
|
}
|
|
+#if defined(CONFIG_M68000)
|
|
+ if ((long)src & 1) {
|
|
+ char *cdest = dest;
|
|
+ const char *csrc = src;
|
|
+ for (; n; n--)
|
|
+ *--cdest = *--csrc;
|
|
+ return xdest;
|
|
+ }
|
|
+#endif
|
|
if (n > 2 && (long)dest & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
diff --git a/arch/mips/include/asm/mach-loongson64/topology.h b/arch/mips/include/asm/mach-loongson64/topology.h
|
|
index 3414a1fd17835e..89bb4deab98a67 100644
|
|
--- a/arch/mips/include/asm/mach-loongson64/topology.h
|
|
+++ b/arch/mips/include/asm/mach-loongson64/topology.h
|
|
@@ -7,7 +7,7 @@
|
|
#define cpu_to_node(cpu) (cpu_logical_map(cpu) >> 2)
|
|
|
|
extern cpumask_t __node_cpumask[];
|
|
-#define cpumask_of_node(node) (&__node_cpumask[node])
|
|
+#define cpumask_of_node(node) ((node) == NUMA_NO_NODE ? cpu_all_mask : &__node_cpumask[node])
|
|
|
|
struct pci_bus;
|
|
extern int pcibus_to_node(struct pci_bus *);
|
|
diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
|
|
index 6d35d4f7ebe196..55fe0e8295494c 100644
|
|
--- a/arch/mips/kernel/relocate.c
|
|
+++ b/arch/mips/kernel/relocate.c
|
|
@@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
|
|
goto out;
|
|
|
|
/* The current thread is now within the relocated image */
|
|
+#ifndef CONFIG_CC_IS_CLANG
|
|
__current_thread_info = RELOCATED(&init_thread_union);
|
|
+#else
|
|
+ /*
|
|
+ * LLVM may wrongly restore $gp ($28) in epilog even if it's
|
|
+ * intentionally modified. Work around this by using inline
|
|
+ * assembly to assign $gp. $gp couldn't be listed as output or
|
|
+ * clobber, or LLVM will still restore its original value.
|
|
+ * See also LLVM upstream issue
|
|
+ * https://github.com/llvm/llvm-project/issues/176546
|
|
+ */
|
|
+ asm volatile("move $28, %0" : :
|
|
+ "r" (RELOCATED(&init_thread_union)));
|
|
+#endif
|
|
|
|
/* Return the new kernel's entry point */
|
|
kernel_entry = RELOCATED(start_kernel);
|
|
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
|
|
index b7f6f782d9a130..ffa4d38ca95df7 100644
|
|
--- a/arch/mips/rb532/devices.c
|
|
+++ b/arch/mips/rb532/devices.c
|
|
@@ -212,11 +212,12 @@ static struct platform_device rb532_wdt = {
|
|
static struct plat_serial8250_port rb532_uart_res[] = {
|
|
{
|
|
.type = PORT_16550A,
|
|
- .membase = (char *)KSEG1ADDR(REGBASE + UART0BASE),
|
|
+ .mapbase = REGBASE + UART0BASE,
|
|
+ .mapsize = 0x1000,
|
|
.irq = UART0_IRQ,
|
|
.regshift = 2,
|
|
.iotype = UPIO_MEM,
|
|
- .flags = UPF_BOOT_AUTOCONF,
|
|
+ .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
|
|
},
|
|
{
|
|
.flags = 0,
|
|
diff --git a/arch/openrisc/include/asm/barrier.h b/arch/openrisc/include/asm/barrier.h
|
|
index 7538294721bed7..8e592c99090235 100644
|
|
--- a/arch/openrisc/include/asm/barrier.h
|
|
+++ b/arch/openrisc/include/asm/barrier.h
|
|
@@ -4,6 +4,8 @@
|
|
|
|
#define mb() asm volatile ("l.msync" ::: "memory")
|
|
|
|
+#define nop() asm volatile ("l.nop")
|
|
+
|
|
#include <asm-generic/barrier.h>
|
|
|
|
#endif /* __ASM_BARRIER_H */
|
|
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
|
|
index 8be4558ef33c0e..3cfd81c7e112ec 100644
|
|
--- a/arch/parisc/kernel/drivers.c
|
|
+++ b/arch/parisc/kernel/drivers.c
|
|
@@ -435,7 +435,7 @@ static struct parisc_device * __init create_tree_node(char id,
|
|
dev->dev.dma_mask = &dev->dma_mask;
|
|
dev->dev.coherent_dma_mask = dev->dma_mask;
|
|
if (device_register(&dev->dev)) {
|
|
- kfree(dev);
|
|
+ put_device(&dev->dev);
|
|
return NULL;
|
|
}
|
|
|
|
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
|
|
index ed93bd8c154533..d7b0f233f2cc9e 100644
|
|
--- a/arch/parisc/kernel/process.c
|
|
+++ b/arch/parisc/kernel/process.c
|
|
@@ -85,6 +85,9 @@ void machine_restart(char *cmd)
|
|
#endif
|
|
/* set up a new led state on systems shipped with a LED State panel */
|
|
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
|
|
+
|
|
+ /* prevent interrupts during reboot */
|
|
+ set_eiem(0);
|
|
|
|
/* "Normal" system reset */
|
|
pdc_do_reset();
|
|
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
|
|
index 514dd056c2c84b..b5709b9aed238f 100644
|
|
--- a/arch/powerpc/include/asm/eeh.h
|
|
+++ b/arch/powerpc/include/asm/eeh.h
|
|
@@ -289,6 +289,8 @@ void eeh_pe_dev_traverse(struct eeh_pe *root,
|
|
void eeh_pe_restore_bars(struct eeh_pe *pe);
|
|
const char *eeh_pe_loc_get(struct eeh_pe *pe);
|
|
struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
|
|
+const char *eeh_pe_loc_get_bus(struct pci_bus *bus);
|
|
+struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe);
|
|
|
|
void eeh_show_enabled(void);
|
|
int __init eeh_init(struct eeh_ops *ops);
|
|
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
|
|
index ad7e8c5aec3f82..63223b7e520f01 100644
|
|
--- a/arch/powerpc/include/asm/kup.h
|
|
+++ b/arch/powerpc/include/asm/kup.h
|
|
@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void)
|
|
|
|
static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
|
|
{
|
|
- barrier_nospec();
|
|
allow_user_access(NULL, from, size, KUAP_READ);
|
|
}
|
|
|
|
@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s
|
|
static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
|
|
unsigned long size)
|
|
{
|
|
- barrier_nospec();
|
|
allow_user_access(to, from, size, KUAP_READ_WRITE);
|
|
}
|
|
|
|
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
|
|
index a81bd825087cda..ec7f001d03d017 100644
|
|
--- a/arch/powerpc/include/asm/uaccess.h
|
|
+++ b/arch/powerpc/include/asm/uaccess.h
|
|
@@ -290,6 +290,7 @@ do { \
|
|
__typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \
|
|
\
|
|
might_fault(); \
|
|
+ barrier_nospec(); \
|
|
allow_read_from_user(__gu_addr, __gu_size); \
|
|
__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
|
|
prevent_read_from_user(__gu_addr, __gu_size); \
|
|
@@ -318,6 +319,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
|
|
{
|
|
unsigned long ret;
|
|
|
|
+ barrier_nospec();
|
|
allow_read_write_user(to, from, n);
|
|
ret = __copy_tofrom_user(to, from, n);
|
|
prevent_read_write_user(to, from, n);
|
|
@@ -404,6 +406,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt
|
|
|
|
might_fault();
|
|
|
|
+ barrier_nospec();
|
|
allow_read_write_user((void __user *)ptr, ptr, len);
|
|
return true;
|
|
}
|
|
@@ -420,6 +423,7 @@ user_read_access_begin(const void __user *ptr, size_t len)
|
|
|
|
might_fault();
|
|
|
|
+ barrier_nospec();
|
|
allow_read_from_user(ptr, len);
|
|
return true;
|
|
}
|
|
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
|
|
index cc8bedf410ea70..632bf157636ec4 100644
|
|
--- a/arch/powerpc/kernel/eeh_driver.c
|
|
+++ b/arch/powerpc/kernel/eeh_driver.c
|
|
@@ -846,7 +846,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
|
|
|
|
pci_lock_rescan_remove();
|
|
|
|
- bus = eeh_pe_bus_get(pe);
|
|
+ bus = eeh_pe_bus_get_nolock(pe);
|
|
if (!bus) {
|
|
pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n",
|
|
__func__, pe->phb->global_number, pe->addr);
|
|
@@ -877,14 +877,15 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
|
|
/* Log the event */
|
|
if (pe->type & EEH_PE_PHB) {
|
|
pr_err("EEH: Recovering PHB#%x, location: %s\n",
|
|
- pe->phb->global_number, eeh_pe_loc_get(pe));
|
|
+ pe->phb->global_number, eeh_pe_loc_get_bus(bus));
|
|
} else {
|
|
struct eeh_pe *phb_pe = eeh_phb_pe_get(pe->phb);
|
|
|
|
pr_err("EEH: Recovering PHB#%x-PE#%x\n",
|
|
pe->phb->global_number, pe->addr);
|
|
pr_err("EEH: PE location: %s, PHB location: %s\n",
|
|
- eeh_pe_loc_get(pe), eeh_pe_loc_get(phb_pe));
|
|
+ eeh_pe_loc_get_bus(bus),
|
|
+ eeh_pe_loc_get_bus(eeh_pe_bus_get_nolock(phb_pe)));
|
|
}
|
|
|
|
#ifdef CONFIG_STACKTRACE
|
|
@@ -1089,7 +1090,7 @@ recover_failed:
|
|
eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
|
|
eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
|
|
|
|
- bus = eeh_pe_bus_get(pe);
|
|
+ bus = eeh_pe_bus_get_nolock(pe);
|
|
if (bus)
|
|
pci_hp_remove_devices(bus);
|
|
else
|
|
@@ -1213,7 +1214,7 @@ void eeh_handle_special_event(void)
|
|
(phb_pe->state & EEH_PE_RECOVERING))
|
|
continue;
|
|
|
|
- bus = eeh_pe_bus_get(phb_pe);
|
|
+ bus = eeh_pe_bus_get_nolock(phb_pe);
|
|
if (!bus) {
|
|
pr_err("%s: Cannot find PCI bus for "
|
|
"PHB#%x-PE#%x\n",
|
|
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
|
|
index 08095aeba5c983..b10fcca5204003 100644
|
|
--- a/arch/powerpc/kernel/eeh_pe.c
|
|
+++ b/arch/powerpc/kernel/eeh_pe.c
|
|
@@ -812,6 +812,24 @@ void eeh_pe_restore_bars(struct eeh_pe *pe)
|
|
const char *eeh_pe_loc_get(struct eeh_pe *pe)
|
|
{
|
|
struct pci_bus *bus = eeh_pe_bus_get(pe);
|
|
+ return eeh_pe_loc_get_bus(bus);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * eeh_pe_loc_get_bus - Retrieve location code binding to the given PCI bus
|
|
+ * @bus: PCI bus
|
|
+ *
|
|
+ * Retrieve the location code associated with the given PCI bus. If the bus
|
|
+ * is a root bus, the location code is fetched from the PHB device tree node
|
|
+ * or root port. Otherwise, the location code is obtained from the device
|
|
+ * tree node of the upstream bridge of the bus. The function walks up the
|
|
+ * bus hierarchy if necessary, checking each node for the appropriate
|
|
+ * location code property ("ibm,io-base-loc-code" for root buses,
|
|
+ * "ibm,slot-location-code" for others). If no location code is found,
|
|
+ * returns "N/A".
|
|
+ */
|
|
+const char *eeh_pe_loc_get_bus(struct pci_bus *bus)
|
|
+{
|
|
struct device_node *dn;
|
|
const char *loc = NULL;
|
|
|
|
@@ -838,8 +856,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe)
|
|
}
|
|
|
|
/**
|
|
- * eeh_pe_bus_get - Retrieve PCI bus according to the given PE
|
|
+ * _eeh_pe_bus_get - Retrieve PCI bus according to the given PE
|
|
* @pe: EEH PE
|
|
+ * @do_lock: Is the caller already held the pci_lock_rescan_remove?
|
|
*
|
|
* Retrieve the PCI bus according to the given PE. Basically,
|
|
* there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the
|
|
@@ -847,7 +866,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe)
|
|
* returned for BUS PE. However, we don't have associated PCI
|
|
* bus for DEVICE PE.
|
|
*/
|
|
-struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
|
|
+static struct pci_bus *_eeh_pe_bus_get(struct eeh_pe *pe, bool do_lock)
|
|
{
|
|
struct eeh_dev *edev;
|
|
struct pci_dev *pdev;
|
|
@@ -862,11 +881,58 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
|
|
|
|
/* Retrieve the parent PCI bus of first (top) PCI device */
|
|
edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry);
|
|
- pci_lock_rescan_remove();
|
|
+ if (do_lock)
|
|
+ pci_lock_rescan_remove();
|
|
pdev = eeh_dev_to_pci_dev(edev);
|
|
if (pdev)
|
|
bus = pdev->bus;
|
|
- pci_unlock_rescan_remove();
|
|
+ if (do_lock)
|
|
+ pci_unlock_rescan_remove();
|
|
|
|
return bus;
|
|
}
|
|
+
|
|
+/**
|
|
+ * eeh_pe_bus_get - Retrieve PCI bus associated with the given EEH PE, locking
|
|
+ * if needed
|
|
+ * @pe: Pointer to the EEH PE
|
|
+ *
|
|
+ * This function is a wrapper around _eeh_pe_bus_get(), which retrieves the PCI
|
|
+ * bus associated with the provided EEH PE structure. It acquires the PCI
|
|
+ * rescans lock to ensure safe access to shared data during the retrieval
|
|
+ * process. This function should be used when the caller requires the PCI bus
|
|
+ * while holding the rescan/remove lock, typically during operations that modify
|
|
+ * or inspect PCIe device state in a safe manner.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * A pointer to the PCI bus associated with the EEH PE, or NULL if none found.
|
|
+ */
|
|
+
|
|
+struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
|
|
+{
|
|
+ return _eeh_pe_bus_get(pe, true);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * eeh_pe_bus_get_nolock - Retrieve PCI bus associated with the given EEH PE
|
|
+ * without locking
|
|
+ * @pe: Pointer to the EEH PE
|
|
+ *
|
|
+ * This function is a variant of _eeh_pe_bus_get() that retrieves the PCI bus
|
|
+ * associated with the specified EEH PE without acquiring the
|
|
+ * pci_lock_rescan_remove lock. It should only be used when the caller can
|
|
+ * guarantee safe access to PE structures without the need for that lock,
|
|
+ * typically in contexts where the lock is already held locking is otherwise
|
|
+ * managed.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * pointer to the PCI bus associated with the EEH PE, or NULL if none is found.
|
|
+ *
|
|
+ * NOTE:
|
|
+ * Use this function carefully to avoid race conditions and data corruption.
|
|
+ */
|
|
+
|
|
+struct pci_bus *eeh_pe_bus_get_nolock(struct eeh_pe *pe)
|
|
+{
|
|
+ return _eeh_pe_bus_get(pe, false);
|
|
+}
|
|
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
|
|
index 4e4870031265c7..ab99a3e7f99728 100644
|
|
--- a/arch/powerpc/kernel/smp.c
|
|
+++ b/arch/powerpc/kernel/smp.c
|
|
@@ -830,6 +830,8 @@ static int parse_thread_groups(struct device_node *dn,
|
|
|
|
count = of_property_count_u32_elems(dn, "ibm,thread-groups");
|
|
thread_group_array = kcalloc(count, sizeof(u32), GFP_KERNEL);
|
|
+ if (!thread_group_array)
|
|
+ return -ENOMEM;
|
|
ret = of_property_read_u32_array(dn, "ibm,thread-groups",
|
|
thread_group_array, count);
|
|
if (ret)
|
|
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
|
|
index e99dae26500d26..3b2625eb34c5a1 100644
|
|
--- a/arch/s390/Kconfig
|
|
+++ b/arch/s390/Kconfig
|
|
@@ -231,6 +231,7 @@ config S390
|
|
select SPARSE_IRQ
|
|
select SWIOTLB
|
|
select SYSCTL_EXCEPTION_TRACE
|
|
+ select SYSTEM_DATA_VERIFICATION if KEXEC_SIG
|
|
select THREAD_INFO_IN_TASK
|
|
select TRACE_IRQFLAGS_SUPPORT
|
|
select TTY
|
|
@@ -254,7 +255,7 @@ config ARCH_SUPPORTS_KEXEC_FILE
|
|
def_bool y
|
|
|
|
config ARCH_SUPPORTS_KEXEC_SIG
|
|
- def_bool MODULE_SIG_FORMAT
|
|
+ def_bool y
|
|
|
|
config ARCH_SUPPORTS_KEXEC_PURGATORY
|
|
def_bool y
|
|
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
|
|
index e52c89739bc9a1..c6cac49f3ae726 100644
|
|
--- a/arch/s390/kernel/perf_cpum_sf.c
|
|
+++ b/arch/s390/kernel/perf_cpum_sf.c
|
|
@@ -925,7 +925,7 @@ static bool is_callchain_event(struct perf_event *event)
|
|
u64 sample_type = event->attr.sample_type;
|
|
|
|
return sample_type & (PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER |
|
|
- PERF_SAMPLE_STACK_USER);
|
|
+ PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_STACK_USER);
|
|
}
|
|
|
|
static int cpumsf_pmu_event_init(struct perf_event *event)
|
|
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
|
|
index 777362cb4ea80b..d4c7c4ef102d8c 100644
|
|
--- a/arch/s390/pci/pci.c
|
|
+++ b/arch/s390/pci/pci.c
|
|
@@ -206,24 +206,33 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
|
|
static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
|
|
{
|
|
u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
|
|
+ int rc = -ENODEV;
|
|
u64 data;
|
|
- int rc;
|
|
+
|
|
+ if (!zdev_enabled(zdev))
|
|
+ goto out_err;
|
|
|
|
rc = __zpci_load(&data, req, offset);
|
|
- if (!rc) {
|
|
- data = le64_to_cpu((__force __le64) data);
|
|
- data >>= (8 - len) * 8;
|
|
- *val = (u32) data;
|
|
- } else
|
|
- *val = 0xffffffff;
|
|
+ if (rc)
|
|
+ goto out_err;
|
|
+ data = le64_to_cpu((__force __le64)data);
|
|
+ data >>= (8 - len) * 8;
|
|
+ *val = (u32)data;
|
|
+ return 0;
|
|
+
|
|
+out_err:
|
|
+ PCI_SET_ERROR_RESPONSE(val);
|
|
return rc;
|
|
}
|
|
|
|
static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
|
|
{
|
|
u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
|
|
+ int rc = -ENODEV;
|
|
u64 data = val;
|
|
- int rc;
|
|
+
|
|
+ if (!zdev_enabled(zdev))
|
|
+ return rc;
|
|
|
|
data <<= (8 - len) * 8;
|
|
data = (__force u64) cpu_to_le64(data);
|
|
diff --git a/arch/s390/purgatory/Makefile b/arch/s390/purgatory/Makefile
|
|
index fe7e71f91711b2..0cbfa716a64a70 100644
|
|
--- a/arch/s390/purgatory/Makefile
|
|
+++ b/arch/s390/purgatory/Makefile
|
|
@@ -29,6 +29,7 @@ KBUILD_CFLAGS += -fno-stack-protector
|
|
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
|
KBUILD_CFLAGS += $(CLANG_FLAGS)
|
|
KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
|
|
+KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
|
|
KBUILD_AFLAGS := $(filter-out -DCC_USING_EXPOLINE,$(KBUILD_AFLAGS))
|
|
|
|
# Since we link purgatory with -r unresolved symbols are not checked, so we
|
|
diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h
|
|
index 7fd2f5873c9e7a..a8bbdf9877a41a 100644
|
|
--- a/arch/sparc/include/uapi/asm/ioctls.h
|
|
+++ b/arch/sparc/include/uapi/asm/ioctls.h
|
|
@@ -5,10 +5,10 @@
|
|
#include <asm/ioctl.h>
|
|
|
|
/* Big T */
|
|
-#define TCGETA _IOR('T', 1, struct termio)
|
|
-#define TCSETA _IOW('T', 2, struct termio)
|
|
-#define TCSETAW _IOW('T', 3, struct termio)
|
|
-#define TCSETAF _IOW('T', 4, struct termio)
|
|
+#define TCGETA 0x40125401 /* _IOR('T', 1, struct termio) */
|
|
+#define TCSETA 0x80125402 /* _IOW('T', 2, struct termio) */
|
|
+#define TCSETAW 0x80125403 /* _IOW('T', 3, struct termio) */
|
|
+#define TCSETAF 0x80125404 /* _IOW('T', 4, struct termio) */
|
|
#define TCSBRK _IO('T', 5)
|
|
#define TCXONC _IO('T', 6)
|
|
#define TCFLSH _IO('T', 7)
|
|
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
|
|
index 0442ab00518d3c..7d69877511fac9 100644
|
|
--- a/arch/sparc/kernel/process.c
|
|
+++ b/arch/sparc/kernel/process.c
|
|
@@ -17,14 +17,18 @@
|
|
|
|
asmlinkage long sparc_fork(struct pt_regs *regs)
|
|
{
|
|
- unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
|
+ unsigned long orig_i1;
|
|
long ret;
|
|
struct kernel_clone_args args = {
|
|
.exit_signal = SIGCHLD,
|
|
- /* Reuse the parent's stack for the child. */
|
|
- .stack = regs->u_regs[UREG_FP],
|
|
};
|
|
|
|
+ synchronize_user_stack();
|
|
+
|
|
+ orig_i1 = regs->u_regs[UREG_I1];
|
|
+ /* Reuse the parent's stack for the child. */
|
|
+ args.stack = regs->u_regs[UREG_FP];
|
|
+
|
|
ret = kernel_clone(&args);
|
|
|
|
/* If we get an error and potentially restart the system
|
|
@@ -40,16 +44,19 @@ asmlinkage long sparc_fork(struct pt_regs *regs)
|
|
|
|
asmlinkage long sparc_vfork(struct pt_regs *regs)
|
|
{
|
|
- unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
|
+ unsigned long orig_i1;
|
|
long ret;
|
|
-
|
|
struct kernel_clone_args args = {
|
|
.flags = CLONE_VFORK | CLONE_VM,
|
|
.exit_signal = SIGCHLD,
|
|
- /* Reuse the parent's stack for the child. */
|
|
- .stack = regs->u_regs[UREG_FP],
|
|
};
|
|
|
|
+ synchronize_user_stack();
|
|
+
|
|
+ orig_i1 = regs->u_regs[UREG_I1];
|
|
+ /* Reuse the parent's stack for the child. */
|
|
+ args.stack = regs->u_regs[UREG_FP];
|
|
+
|
|
ret = kernel_clone(&args);
|
|
|
|
/* If we get an error and potentially restart the system
|
|
@@ -65,15 +72,18 @@ asmlinkage long sparc_vfork(struct pt_regs *regs)
|
|
|
|
asmlinkage long sparc_clone(struct pt_regs *regs)
|
|
{
|
|
- unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
|
- unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
|
|
+ unsigned long orig_i1;
|
|
+ unsigned int flags;
|
|
long ret;
|
|
+ struct kernel_clone_args args = {0};
|
|
|
|
- struct kernel_clone_args args = {
|
|
- .flags = (flags & ~CSIGNAL),
|
|
- .exit_signal = (flags & CSIGNAL),
|
|
- .tls = regs->u_regs[UREG_I3],
|
|
- };
|
|
+ synchronize_user_stack();
|
|
+
|
|
+ orig_i1 = regs->u_regs[UREG_I1];
|
|
+ flags = lower_32_bits(regs->u_regs[UREG_I0]);
|
|
+ args.flags = (flags & ~CSIGNAL);
|
|
+ args.exit_signal = (flags & CSIGNAL);
|
|
+ args.tls = regs->u_regs[UREG_I3];
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
if (test_thread_flag(TIF_32BIT)) {
|
|
diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
|
|
index b12bef0ff7bb6f..4b91b41df52070 100644
|
|
--- a/arch/x86/hyperv/hv_vtl.c
|
|
+++ b/arch/x86/hyperv/hv_vtl.c
|
|
@@ -68,7 +68,7 @@ static void hv_vtl_ap_entry(void)
|
|
|
|
static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
|
|
{
|
|
- u64 status;
|
|
+ u64 status, rsp, rip;
|
|
int ret = 0;
|
|
struct hv_enable_vp_vtl *input;
|
|
unsigned long irq_flags;
|
|
@@ -81,9 +81,11 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
|
|
struct desc_struct *gdt;
|
|
|
|
struct task_struct *idle = idle_thread_get(cpu);
|
|
- u64 rsp = (unsigned long)idle->thread.sp;
|
|
+ if (IS_ERR(idle))
|
|
+ return PTR_ERR(idle);
|
|
|
|
- u64 rip = (u64)&hv_vtl_ap_entry;
|
|
+ rsp = (unsigned long)idle->thread.sp;
|
|
+ rip = (u64)&hv_vtl_ap_entry;
|
|
|
|
native_store_gdt(&gdt_ptr);
|
|
store_idt(&idt_ptr);
|
|
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
|
|
index a61c12c0127097..b1f10084474ad5 100644
|
|
--- a/arch/x86/kernel/kexec-bzimage64.c
|
|
+++ b/arch/x86/kernel/kexec-bzimage64.c
|
|
@@ -184,6 +184,13 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,
|
|
struct efi_info *current_ei = &boot_params.efi_info;
|
|
struct efi_info *ei = ¶ms->efi_info;
|
|
|
|
+ if (!params->acpi_rsdp_addr) {
|
|
+ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
|
|
+ params->acpi_rsdp_addr = efi.acpi20;
|
|
+ else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
|
|
+ params->acpi_rsdp_addr = efi.acpi;
|
|
+ }
|
|
+
|
|
if (!efi_enabled(EFI_RUNTIME_SERVICES))
|
|
return 0;
|
|
|
|
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
|
|
index eb129277dcdd64..df74f865c9f121 100644
|
|
--- a/arch/x86/kernel/setup.c
|
|
+++ b/arch/x86/kernel/setup.c
|
|
@@ -372,9 +372,15 @@ int __init ima_free_kexec_buffer(void)
|
|
|
|
int __init ima_get_kexec_buffer(void **addr, size_t *size)
|
|
{
|
|
+ int ret;
|
|
+
|
|
if (!ima_kexec_buffer_size)
|
|
return -ENOENT;
|
|
|
|
+ ret = ima_validate_range(ima_kexec_buffer_phys, ima_kexec_buffer_size);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
*addr = __va(ima_kexec_buffer_phys);
|
|
*size = ima_kexec_buffer_size;
|
|
|
|
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
|
|
index 97ec7781eb671f..eebfea13228555 100644
|
|
--- a/arch/x86/kvm/svm/nested.c
|
|
+++ b/arch/x86/kvm/svm/nested.c
|
|
@@ -1758,10 +1758,9 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
|
* thus MMU might not be initialized correctly.
|
|
* Set it again to fix this.
|
|
*/
|
|
-
|
|
ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
|
|
nested_npt_enabled(svm), false);
|
|
- if (WARN_ON_ONCE(ret))
|
|
+ if (ret)
|
|
goto out_free;
|
|
|
|
svm->nested.force_msr_bitmap_recalc = true;
|
|
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
|
|
index dd4236a6bd94d2..9ddd1ee5f31234 100644
|
|
--- a/arch/x86/kvm/svm/svm.c
|
|
+++ b/arch/x86/kvm/svm/svm.c
|
|
@@ -2299,12 +2299,13 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload)
|
|
|
|
ret = kvm_skip_emulated_instruction(vcpu);
|
|
|
|
+ /* KVM always performs VMLOAD/VMSAVE on VMCB01 (see __svm_vcpu_run()) */
|
|
if (vmload) {
|
|
- svm_copy_vmloadsave_state(svm->vmcb, vmcb12);
|
|
+ svm_copy_vmloadsave_state(svm->vmcb01.ptr, vmcb12);
|
|
svm->sysenter_eip_hi = 0;
|
|
svm->sysenter_esp_hi = 0;
|
|
} else {
|
|
- svm_copy_vmloadsave_state(vmcb12, svm->vmcb);
|
|
+ svm_copy_vmloadsave_state(vmcb12, svm->vmcb01.ptr);
|
|
}
|
|
|
|
kvm_vcpu_unmap(vcpu, &map, true);
|
|
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
|
index 89df215ebf2842..00bbee40dbec2a 100644
|
|
--- a/arch/x86/kvm/x86.c
|
|
+++ b/arch/x86/kvm/x86.c
|
|
@@ -11437,9 +11437,11 @@ static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2)
|
|
return;
|
|
|
|
if (is_pae_paging(vcpu)) {
|
|
+ kvm_vcpu_srcu_read_lock(vcpu);
|
|
for (i = 0 ; i < 4 ; i++)
|
|
sregs2->pdptrs[i] = kvm_pdptr_read(vcpu, i);
|
|
sregs2->flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID;
|
|
+ kvm_vcpu_srcu_read_unlock(vcpu);
|
|
}
|
|
}
|
|
|
|
diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
|
|
index fc46b4dfbd7475..10deae1a30c652 100644
|
|
--- a/arch/x86/platform/pvh/head.S
|
|
+++ b/arch/x86/platform/pvh/head.S
|
|
@@ -70,10 +70,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
|
|
|
|
mov $_pa(early_stack_end), %esp
|
|
|
|
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
|
|
/* Enable PAE mode. */
|
|
mov %cr4, %eax
|
|
orl $X86_CR4_PAE, %eax
|
|
mov %eax, %cr4
|
|
+#endif
|
|
|
|
#ifdef CONFIG_X86_64
|
|
/* Enable Long mode. */
|
|
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
|
|
index 638de313fc4ed5..03fb16dc0b926e 100644
|
|
--- a/arch/x86/xen/enlighten.c
|
|
+++ b/arch/x86/xen/enlighten.c
|
|
@@ -480,7 +480,7 @@ int __init arch_xen_unpopulated_init(struct resource **res)
|
|
* driver to know how much of the physmap is unpopulated and
|
|
* set an accurate initial memory target.
|
|
*/
|
|
- xen_released_pages += xen_extra_mem[i].n_pfns;
|
|
+ xen_unpopulated_pages += xen_extra_mem[i].n_pfns;
|
|
/* Zero so region is not also added to the balloon driver. */
|
|
xen_extra_mem[i].n_pfns = 0;
|
|
}
|
|
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
|
|
index 6e4c6bd622033b..11fa577af6b488 100644
|
|
--- a/arch/x86/xen/mmu.h
|
|
+++ b/arch/x86/xen/mmu.h
|
|
@@ -17,10 +17,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
|
|
|
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
|
|
|
|
-pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep);
|
|
-void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
|
|
- pte_t *ptep, pte_t pte);
|
|
-
|
|
unsigned long xen_read_cr2_direct(void);
|
|
|
|
extern void xen_init_mmu_ops(void);
|
|
diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c
|
|
index 88a722954f3f78..23f30ca52816c8 100644
|
|
--- a/arch/x86/xen/mmu_pv.c
|
|
+++ b/arch/x86/xen/mmu_pv.c
|
|
@@ -173,7 +173,7 @@ static int alloc_discontig_frames(unsigned int order)
|
|
* looking at another vcpu's cr3 value, it should use this variable.
|
|
*/
|
|
DEFINE_PER_CPU(unsigned long, xen_cr3); /* cr3 stored as physaddr */
|
|
-DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
|
|
+static DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
|
|
|
|
static phys_addr_t xen_pt_base, xen_pt_size __initdata;
|
|
|
|
@@ -350,16 +350,17 @@ static void xen_set_pte(pte_t *ptep, pte_t pteval)
|
|
__xen_set_pte(ptep, pteval);
|
|
}
|
|
|
|
-pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
|
|
- unsigned long addr, pte_t *ptep)
|
|
+static pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
|
|
+ unsigned long addr, pte_t *ptep)
|
|
{
|
|
/* Just return the pte as-is. We preserve the bits on commit */
|
|
trace_xen_mmu_ptep_modify_prot_start(vma->vm_mm, addr, ptep, *ptep);
|
|
return *ptep;
|
|
}
|
|
|
|
-void xen_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr,
|
|
- pte_t *ptep, pte_t pte)
|
|
+static void xen_ptep_modify_prot_commit(struct vm_area_struct *vma,
|
|
+ unsigned long addr,
|
|
+ pte_t *ptep, pte_t pte)
|
|
{
|
|
struct mmu_update u;
|
|
|
|
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
|
|
index 607f3a42fe3b1b..af418489335cd7 100644
|
|
--- a/arch/x86/xen/xen-ops.h
|
|
+++ b/arch/x86/xen/xen-ops.h
|
|
@@ -23,7 +23,6 @@ void xen_copy_trap_info(struct trap_info *traps);
|
|
|
|
DECLARE_PER_CPU_ALIGNED(struct vcpu_info, xen_vcpu_info);
|
|
DECLARE_PER_CPU(unsigned long, xen_cr3);
|
|
-DECLARE_PER_CPU(unsigned long, xen_current_cr3);
|
|
|
|
extern struct start_info *xen_start_info;
|
|
extern struct shared_info xen_dummy_shared_info;
|
|
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
|
|
index c3b5930106b288..e0677043f00de3 100644
|
|
--- a/block/blk-mq-debugfs.c
|
|
+++ b/block/blk-mq-debugfs.c
|
|
@@ -730,8 +730,10 @@ void blk_mq_debugfs_register_hctxs(struct request_queue *q)
|
|
struct blk_mq_hw_ctx *hctx;
|
|
unsigned long i;
|
|
|
|
+ mutex_lock(&q->debugfs_mutex);
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
blk_mq_debugfs_register_hctx(q, hctx);
|
|
+ mutex_unlock(&q->debugfs_mutex);
|
|
}
|
|
|
|
void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
|
|
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
|
|
index c0f9cf9768ea9a..5e409f86f07098 100644
|
|
--- a/drivers/acpi/acpi_processor.c
|
|
+++ b/drivers/acpi/acpi_processor.c
|
|
@@ -39,6 +39,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
|
{
|
|
u8 value1 = 0;
|
|
u8 value2 = 0;
|
|
+ struct pci_dev *ide_dev = NULL, *isa_dev = NULL;
|
|
|
|
|
|
if (!dev)
|
|
@@ -96,12 +97,12 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
|
* each IDE controller's DMA status to make sure we catch all
|
|
* DMA activity.
|
|
*/
|
|
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
|
+ ide_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
|
PCI_DEVICE_ID_INTEL_82371AB,
|
|
PCI_ANY_ID, PCI_ANY_ID, NULL);
|
|
- if (dev) {
|
|
- errata.piix4.bmisx = pci_resource_start(dev, 4);
|
|
- pci_dev_put(dev);
|
|
+ if (ide_dev) {
|
|
+ errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
|
|
+ pci_dev_put(ide_dev);
|
|
}
|
|
|
|
/*
|
|
@@ -113,24 +114,25 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
|
* disable C3 support if this is enabled, as some legacy
|
|
* devices won't operate well if fast DMA is disabled.
|
|
*/
|
|
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
|
+ isa_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
|
PCI_DEVICE_ID_INTEL_82371AB_0,
|
|
PCI_ANY_ID, PCI_ANY_ID, NULL);
|
|
- if (dev) {
|
|
- pci_read_config_byte(dev, 0x76, &value1);
|
|
- pci_read_config_byte(dev, 0x77, &value2);
|
|
+ if (isa_dev) {
|
|
+ pci_read_config_byte(isa_dev, 0x76, &value1);
|
|
+ pci_read_config_byte(isa_dev, 0x77, &value2);
|
|
if ((value1 & 0x80) || (value2 & 0x80))
|
|
errata.piix4.fdma = 1;
|
|
- pci_dev_put(dev);
|
|
+ pci_dev_put(isa_dev);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
- if (errata.piix4.bmisx)
|
|
- dev_dbg(&dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
|
|
- if (errata.piix4.fdma)
|
|
- dev_dbg(&dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
|
|
+ if (ide_dev)
|
|
+ dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
|
|
+
|
|
+ if (isa_dev)
|
|
+ dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
|
|
index cf53b9535f18e0..7788c27ccf4610 100644
|
|
--- a/drivers/acpi/acpica/evregion.c
|
|
+++ b/drivers/acpi/acpica/evregion.c
|
|
@@ -163,7 +163,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
|
|
return_ACPI_STATUS(AE_NOT_EXIST);
|
|
}
|
|
|
|
- if (region_obj->region.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
|
|
+ if (field_obj
|
|
+ && region_obj->region.space_id ==
|
|
+ ACPI_ADR_SPACE_PLATFORM_COMM) {
|
|
struct acpi_pcc_info *ctx =
|
|
handler_desc->address_space.context;
|
|
|
|
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
|
|
index d3091f619909e8..41758343657ddb 100644
|
|
--- a/drivers/acpi/acpica/exoparg3.c
|
|
+++ b/drivers/acpi/acpica/exoparg3.c
|
|
@@ -10,6 +10,7 @@
|
|
#include <acpi/acpi.h>
|
|
#include "accommon.h"
|
|
#include "acinterp.h"
|
|
+#include <acpi/acoutput.h>
|
|
#include "acparser.h"
|
|
#include "amlcode.h"
|
|
|
|
@@ -51,8 +52,7 @@ ACPI_MODULE_NAME("exoparg3")
|
|
acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
|
|
{
|
|
union acpi_operand_object **operand = &walk_state->operands[0];
|
|
- struct acpi_signal_fatal_info *fatal;
|
|
- acpi_status status = AE_OK;
|
|
+ struct acpi_signal_fatal_info fatal;
|
|
|
|
ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R,
|
|
acpi_ps_get_opcode_name(walk_state->opcode));
|
|
@@ -60,28 +60,23 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
|
|
switch (walk_state->opcode) {
|
|
case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
|
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
- "FatalOp: Type %X Code %X Arg %X "
|
|
- "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
|
|
- (u32)operand[0]->integer.value,
|
|
- (u32)operand[1]->integer.value,
|
|
- (u32)operand[2]->integer.value));
|
|
-
|
|
- fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
|
|
- if (fatal) {
|
|
- fatal->type = (u32) operand[0]->integer.value;
|
|
- fatal->code = (u32) operand[1]->integer.value;
|
|
- fatal->argument = (u32) operand[2]->integer.value;
|
|
- }
|
|
+ fatal.type = (u32)operand[0]->integer.value;
|
|
+ fatal.code = (u32)operand[1]->integer.value;
|
|
+ fatal.argument = (u32)operand[2]->integer.value;
|
|
|
|
- /* Always signal the OS! */
|
|
+ ACPI_BIOS_ERROR((AE_INFO,
|
|
+ "Fatal ACPI BIOS error (Type 0x%X Code 0x%X Arg 0x%X)\n",
|
|
+ fatal.type, fatal.code, fatal.argument));
|
|
|
|
- status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal);
|
|
+ /* Always signal the OS! */
|
|
|
|
- /* Might return while OS is shutting down, just continue */
|
|
+ acpi_os_signal(ACPI_SIGNAL_FATAL, &fatal);
|
|
|
|
- ACPI_FREE(fatal);
|
|
- goto cleanup;
|
|
+ /*
|
|
+ * Might return while OS is shutting down, so abort the AML execution
|
|
+ * by returning an error.
|
|
+ */
|
|
+ return_ACPI_STATUS(AE_ERROR);
|
|
|
|
case AML_EXTERNAL_OP:
|
|
/*
|
|
@@ -93,21 +88,16 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
|
|
* wrong if an external opcode ever gets here.
|
|
*/
|
|
ACPI_ERROR((AE_INFO, "Executed External Op"));
|
|
- status = AE_OK;
|
|
- goto cleanup;
|
|
+
|
|
+ return_ACPI_STATUS(AE_OK);
|
|
|
|
default:
|
|
|
|
ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
|
|
walk_state->opcode));
|
|
|
|
- status = AE_AML_BAD_OPCODE;
|
|
- goto cleanup;
|
|
+ return_ACPI_STATUS(AE_AML_BAD_OPCODE);
|
|
}
|
|
-
|
|
-cleanup:
|
|
-
|
|
- return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
|
|
index e768dfd345fb28..9c0d256fc72b11 100644
|
|
--- a/drivers/acpi/apei/ghes.c
|
|
+++ b/drivers/acpi/apei/ghes.c
|
|
@@ -28,6 +28,7 @@
|
|
#include <linux/timer.h>
|
|
#include <linux/cper.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/minmax.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/ratelimit.h>
|
|
#include <linux/vmalloc.h>
|
|
@@ -290,6 +291,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
|
|
error_block_length = GHES_ESTATUS_MAX_SIZE;
|
|
}
|
|
ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
|
|
+ ghes->estatus_length = error_block_length;
|
|
if (!ghes->estatus) {
|
|
rc = -ENOMEM;
|
|
goto err_unmap_status_addr;
|
|
@@ -361,13 +363,15 @@ static int __ghes_check_estatus(struct ghes *ghes,
|
|
struct acpi_hest_generic_status *estatus)
|
|
{
|
|
u32 len = cper_estatus_len(estatus);
|
|
+ u32 max_len = min(ghes->generic->error_block_length,
|
|
+ ghes->estatus_length);
|
|
|
|
if (len < sizeof(*estatus)) {
|
|
pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n");
|
|
return -EIO;
|
|
}
|
|
|
|
- if (len > ghes->generic->error_block_length) {
|
|
+ if (!len || len > max_len) {
|
|
pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n");
|
|
return -EIO;
|
|
}
|
|
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
|
|
index 16ac219ae6fe51..0bf3861cf79b13 100644
|
|
--- a/drivers/acpi/cppc_acpi.c
|
|
+++ b/drivers/acpi/cppc_acpi.c
|
|
@@ -347,7 +347,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
|
|
end:
|
|
if (cmd == CMD_WRITE) {
|
|
if (unlikely(ret)) {
|
|
- for_each_possible_cpu(i) {
|
|
+ for_each_online_cpu(i) {
|
|
struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i);
|
|
|
|
if (!desc)
|
|
@@ -509,7 +509,7 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data)
|
|
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
|
|
cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY;
|
|
|
|
- for_each_possible_cpu(i) {
|
|
+ for_each_online_cpu(i) {
|
|
if (i == cpu)
|
|
continue;
|
|
|
|
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
|
|
index c2c70139c4f1d9..ff5fcd541e50fb 100644
|
|
--- a/drivers/acpi/power.c
|
|
+++ b/drivers/acpi/power.c
|
|
@@ -1035,6 +1035,19 @@ static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),
|
|
},
|
|
},
|
|
+ {
|
|
+ /*
|
|
+ * THUNDEROBOT ZERO laptop: Due to its SSDT table bug, power
|
|
+ * resource 'PXP' will be shut down on initialization, making
|
|
+ * the NVMe #2 and the NVIDIA dGPU both unavailable (they're
|
|
+ * both controlled by 'PXP').
|
|
+ */
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "THUNDEROBOT"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZERO"),
|
|
+ }
|
|
+
|
|
+ },
|
|
{}
|
|
};
|
|
|
|
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
|
|
index 43f11f66970b25..73408a5b45b3b0 100644
|
|
--- a/drivers/android/binder.c
|
|
+++ b/drivers/android/binder.c
|
|
@@ -4211,7 +4211,7 @@ static int binder_thread_write(struct binder_proc *proc,
|
|
}
|
|
}
|
|
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
|
- "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
|
|
+ "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
|
|
proc->pid, thread->pid, (u64)cookie,
|
|
death);
|
|
if (death == NULL) {
|
|
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
|
|
index 34c27223cb7dd2..6a4be6087ae6b1 100644
|
|
--- a/drivers/android/binder_alloc.c
|
|
+++ b/drivers/android/binder_alloc.c
|
|
@@ -79,7 +79,7 @@ static void binder_insert_free_buffer(struct binder_alloc *alloc,
|
|
new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer);
|
|
|
|
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
|
- "%d: add free buffer, size %zd, at %pK\n",
|
|
+ "%d: add free buffer, size %zd, at %p\n",
|
|
alloc->pid, new_buffer_size, new_buffer);
|
|
|
|
while (*p) {
|
|
@@ -474,7 +474,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
|
|
}
|
|
|
|
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
|
- "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
|
|
+ "%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
|
|
alloc->pid, size, buffer, buffer_size);
|
|
|
|
has_page_addr = (void __user *)
|
|
@@ -646,7 +646,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
|
|
ALIGN(buffer->extra_buffers_size, sizeof(void *));
|
|
|
|
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
|
|
- "%d: binder_free_buf %pK size %zd buffer_size %zd\n",
|
|
+ "%d: binder_free_buf %p size %zd buffer_size %zd\n",
|
|
alloc->pid, buffer, size, buffer_size);
|
|
|
|
BUG_ON(buffer->free);
|
|
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
|
|
index d5e713f284b71d..91c6291b01f4e0 100644
|
|
--- a/drivers/ata/libata-core.c
|
|
+++ b/drivers/ata/libata-core.c
|
|
@@ -2318,6 +2318,24 @@ static bool ata_dev_check_adapter(struct ata_device *dev,
|
|
return false;
|
|
}
|
|
|
|
+bool ata_adapter_is_online(struct ata_port *ap)
|
|
+{
|
|
+ struct device *dev;
|
|
+
|
|
+ if (!ap || !ap->host)
|
|
+ return false;
|
|
+
|
|
+ dev = ap->host->dev;
|
|
+ if (!dev)
|
|
+ return false;
|
|
+
|
|
+ if (dev_is_pci(dev) &&
|
|
+ pci_channel_offline(to_pci_dev(dev)))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
static int ata_dev_config_ncq(struct ata_device *dev,
|
|
char *desc, size_t desc_sz)
|
|
{
|
|
@@ -5023,6 +5041,12 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
|
|
qc->flags |= ATA_QCFLAG_ACTIVE;
|
|
ap->qc_active |= 1ULL << qc->tag;
|
|
|
|
+ /* Make sure the device is still accessible. */
|
|
+ if (!ata_adapter_is_online(ap)) {
|
|
+ qc->err_mask |= AC_ERR_HOST_BUS;
|
|
+ goto sys_err;
|
|
+ }
|
|
+
|
|
/*
|
|
* We guarantee to LLDs that they will have at least one
|
|
* non-zero sg if the command is a data command.
|
|
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
|
|
index 3263fc13491e1d..fc2c508c41bd42 100644
|
|
--- a/drivers/ata/libata-eh.c
|
|
+++ b/drivers/ata/libata-eh.c
|
|
@@ -723,7 +723,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
|
|
spin_unlock_irqrestore(ap->lock, flags);
|
|
|
|
/* invoke EH, skip if unloading or suspended */
|
|
- if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
|
|
+ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)) &&
|
|
+ ata_adapter_is_online(ap))
|
|
ap->ops->error_handler(ap);
|
|
else {
|
|
/* if unloading, commence suicide */
|
|
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
|
|
index 8f6a7acf770e4a..300818cb1478a2 100644
|
|
--- a/drivers/ata/libata-scsi.c
|
|
+++ b/drivers/ata/libata-scsi.c
|
|
@@ -1736,6 +1736,42 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|
ata_qc_done(qc);
|
|
}
|
|
|
|
+static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (!ap->ops->qc_defer)
|
|
+ goto issue;
|
|
+
|
|
+ /* Check if the command needs to be deferred. */
|
|
+ ret = ap->ops->qc_defer(qc);
|
|
+ switch (ret) {
|
|
+ case 0:
|
|
+ break;
|
|
+ case ATA_DEFER_LINK:
|
|
+ ret = SCSI_MLQUEUE_DEVICE_BUSY;
|
|
+ break;
|
|
+ case ATA_DEFER_PORT:
|
|
+ ret = SCSI_MLQUEUE_HOST_BUSY;
|
|
+ break;
|
|
+ default:
|
|
+ WARN_ON_ONCE(1);
|
|
+ ret = SCSI_MLQUEUE_HOST_BUSY;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (ret) {
|
|
+ /* Force a requeue of the command to defer its execution. */
|
|
+ ata_qc_free(qc);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+issue:
|
|
+ ata_qc_issue(qc);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* ata_scsi_translate - Translate then issue SCSI command to ATA device
|
|
* @dev: ATA device to which the command is addressed
|
|
@@ -1759,66 +1795,49 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|
* spin_lock_irqsave(host lock)
|
|
*
|
|
* RETURNS:
|
|
- * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
|
|
- * needs to be deferred.
|
|
+ * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY or SCSI_MLQUEUE_HOST_BUSY if the
|
|
+ * command needs to be deferred.
|
|
*/
|
|
static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
|
|
ata_xlat_func_t xlat_func)
|
|
{
|
|
struct ata_port *ap = dev->link->ap;
|
|
struct ata_queued_cmd *qc;
|
|
- int rc;
|
|
|
|
+ lockdep_assert_held(ap->lock);
|
|
+
|
|
+ /*
|
|
+ * ata_scsi_qc_new() calls scsi_done(cmd) in case of failure. So we
|
|
+ * have nothing further to do when allocating a qc fails.
|
|
+ */
|
|
qc = ata_scsi_qc_new(dev, cmd);
|
|
if (!qc)
|
|
- goto err_mem;
|
|
+ return 0;
|
|
|
|
/* data is present; dma-map it */
|
|
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
|
|
cmd->sc_data_direction == DMA_TO_DEVICE) {
|
|
if (unlikely(scsi_bufflen(cmd) < 1)) {
|
|
ata_dev_warn(dev, "WARNING: zero len r/w req\n");
|
|
- goto err_did;
|
|
+ cmd->result = (DID_ERROR << 16);
|
|
+ goto done;
|
|
}
|
|
|
|
ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
|
|
-
|
|
qc->dma_dir = cmd->sc_data_direction;
|
|
}
|
|
|
|
qc->complete_fn = ata_scsi_qc_complete;
|
|
|
|
if (xlat_func(qc))
|
|
- goto early_finish;
|
|
-
|
|
- if (ap->ops->qc_defer) {
|
|
- if ((rc = ap->ops->qc_defer(qc)))
|
|
- goto defer;
|
|
- }
|
|
+ goto done;
|
|
|
|
- /* select device, send command to hardware */
|
|
- ata_qc_issue(qc);
|
|
+ return ata_scsi_qc_issue(ap, qc);
|
|
|
|
- return 0;
|
|
-
|
|
-early_finish:
|
|
+done:
|
|
ata_qc_free(qc);
|
|
scsi_done(cmd);
|
|
return 0;
|
|
-
|
|
-err_did:
|
|
- ata_qc_free(qc);
|
|
- cmd->result = (DID_ERROR << 16);
|
|
- scsi_done(cmd);
|
|
-err_mem:
|
|
- return 0;
|
|
-
|
|
-defer:
|
|
- ata_qc_free(qc);
|
|
- if (rc == ATA_DEFER_LINK)
|
|
- return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
- else
|
|
- return SCSI_MLQUEUE_HOST_BUSY;
|
|
}
|
|
|
|
struct ata_scsi_args {
|
|
@@ -2867,6 +2886,9 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
|
|
{
|
|
struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
|
|
|
|
+ if (!ata_adapter_is_online(ap))
|
|
+ return NULL;
|
|
+
|
|
if (unlikely(!dev || !ata_dev_enabled(dev)))
|
|
return NULL;
|
|
|
|
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
|
|
index 05ac80da8ebc7d..9927d79e55878b 100644
|
|
--- a/drivers/ata/libata.h
|
|
+++ b/drivers/ata/libata.h
|
|
@@ -75,6 +75,7 @@ extern int atapi_check_dma(struct ata_queued_cmd *qc);
|
|
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
|
|
extern bool ata_phys_link_online(struct ata_link *link);
|
|
extern bool ata_phys_link_offline(struct ata_link *link);
|
|
+bool ata_adapter_is_online(struct ata_port *ap);
|
|
extern void ata_dev_init(struct ata_device *dev);
|
|
extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
|
|
extern int sata_link_init_spd(struct ata_link *link);
|
|
diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c
|
|
index 4d6ef90ccc774b..3e6c82f68ab9dc 100644
|
|
--- a/drivers/ata/pata_ftide010.c
|
|
+++ b/drivers/ata/pata_ftide010.c
|
|
@@ -122,10 +122,10 @@ static const u8 mwdma_50_active_time[3] = {6, 2, 2};
|
|
static const u8 mwdma_50_recovery_time[3] = {6, 2, 1};
|
|
static const u8 mwdma_66_active_time[3] = {8, 3, 3};
|
|
static const u8 mwdma_66_recovery_time[3] = {8, 2, 1};
|
|
-static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 1};
|
|
+static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 9};
|
|
static const u8 udma_50_hold_time[6] = {3, 1, 1, 1, 1, 1};
|
|
-static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, };
|
|
-static const u8 udma_66_hold_time[7] = {};
|
|
+static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, 1, 9, 9};
|
|
+static const u8 udma_66_hold_time[7] = {4, 2, 1, 1, 1, 1, 1};
|
|
|
|
/*
|
|
* We set 66 MHz for all MWDMA modes
|
|
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
|
|
index b57faf6dc327ec..ca3051e0023e8f 100644
|
|
--- a/drivers/atm/fore200e.c
|
|
+++ b/drivers/atm/fore200e.c
|
|
@@ -376,6 +376,10 @@ fore200e_shutdown(struct fore200e* fore200e)
|
|
fallthrough;
|
|
case FORE200E_STATE_IRQ:
|
|
free_irq(fore200e->irq, fore200e->atm_dev);
|
|
+#ifdef FORE200E_USE_TASKLET
|
|
+ tasklet_kill(&fore200e->tx_tasklet);
|
|
+ tasklet_kill(&fore200e->rx_tasklet);
|
|
+#endif
|
|
|
|
fallthrough;
|
|
case FORE200E_STATE_ALLOC_BUF:
|
|
diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c
|
|
index 0b1c99cca7334f..f418b133ee7525 100644
|
|
--- a/drivers/auxdisplay/arm-charlcd.c
|
|
+++ b/drivers/auxdisplay/arm-charlcd.c
|
|
@@ -323,7 +323,7 @@ static int __init charlcd_probe(struct platform_device *pdev)
|
|
out_no_irq:
|
|
iounmap(lcd->virtbase);
|
|
out_no_memregion:
|
|
- release_mem_region(lcd->phybase, SZ_4K);
|
|
+ release_mem_region(lcd->phybase, lcd->physize);
|
|
out_no_resource:
|
|
kfree(lcd);
|
|
return ret;
|
|
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
|
|
index 5a5a9e978e85f3..ddbe9cc91d23da 100644
|
|
--- a/drivers/base/power/wakeirq.c
|
|
+++ b/drivers/base/power/wakeirq.c
|
|
@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
|
|
*/
|
|
void dev_pm_clear_wake_irq(struct device *dev)
|
|
{
|
|
- struct wake_irq *wirq = dev->power.wakeirq;
|
|
+ struct wake_irq *wirq;
|
|
unsigned long flags;
|
|
|
|
- if (!wirq)
|
|
+ spin_lock_irqsave(&dev->power.lock, flags);
|
|
+ wirq = dev->power.wakeirq;
|
|
+ if (!wirq) {
|
|
+ spin_unlock_irqrestore(&dev->power.lock, flags);
|
|
return;
|
|
+ }
|
|
|
|
- spin_lock_irqsave(&dev->power.lock, flags);
|
|
device_wakeup_detach_irq(dev);
|
|
dev->power.wakeirq = NULL;
|
|
spin_unlock_irqrestore(&dev->power.lock, flags);
|
|
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
|
|
index a917219feea62d..eae81def0902a0 100644
|
|
--- a/drivers/base/power/wakeup.c
|
|
+++ b/drivers/base/power/wakeup.c
|
|
@@ -280,9 +280,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock);
|
|
*/
|
|
struct wakeup_source *wakeup_sources_walk_start(void)
|
|
{
|
|
- struct list_head *ws_head = &wakeup_sources;
|
|
-
|
|
- return list_entry_rcu(ws_head->next, struct wakeup_source, entry);
|
|
+ return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entry);
|
|
}
|
|
EXPORT_SYMBOL_GPL(wakeup_sources_walk_start);
|
|
|
|
diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c
|
|
index b67e39a34010b1..ebc0f4c091051f 100644
|
|
--- a/drivers/block/rnbd/rnbd-srv.c
|
|
+++ b/drivers/block/rnbd/rnbd-srv.c
|
|
@@ -536,6 +536,8 @@ static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp,
|
|
{
|
|
struct block_device *bdev = sess_dev->bdev;
|
|
|
|
+ memset(rsp, 0, sizeof(*rsp));
|
|
+
|
|
rsp->hdr.type = cpu_to_le16(RNBD_MSG_OPEN_RSP);
|
|
rsp->device_id = cpu_to_le32(sess_dev->device_id);
|
|
rsp->nsectors = cpu_to_le64(bdev_nr_sectors(bdev));
|
|
@@ -641,6 +643,7 @@ static void process_msg_sess_info(struct rnbd_srv_session *srv_sess,
|
|
|
|
trace_process_msg_sess_info(srv_sess, sess_info_msg);
|
|
|
|
+ memset(rsp, 0, sizeof(*rsp));
|
|
rsp->hdr.type = cpu_to_le16(RNBD_MSG_SESS_INFO_RSP);
|
|
rsp->ver = srv_sess->ver;
|
|
}
|
|
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
|
|
index 44f630a3f610bd..89c1d6ec7adaa8 100644
|
|
--- a/drivers/block/ublk_drv.c
|
|
+++ b/drivers/block/ublk_drv.c
|
|
@@ -2908,10 +2908,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
|
|
if (issue_flags & IO_URING_F_NONBLOCK)
|
|
return -EAGAIN;
|
|
|
|
- ublk_ctrl_cmd_dump(cmd);
|
|
-
|
|
if (!(issue_flags & IO_URING_F_SQE128))
|
|
- goto out;
|
|
+ return -EINVAL;
|
|
+
|
|
+ ublk_ctrl_cmd_dump(cmd);
|
|
|
|
ret = ublk_check_cmd_op(cmd_op);
|
|
if (ret)
|
|
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
|
index eaeacdadb20232..168e46ce59976a 100644
|
|
--- a/drivers/bluetooth/btusb.c
|
|
+++ b/drivers/bluetooth/btusb.c
|
|
@@ -548,6 +548,8 @@ static const struct usb_device_id quirks_table[] = {
|
|
BTUSB_WIDEBAND_SPEECH },
|
|
{ USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
|
|
BTUSB_WIDEBAND_SPEECH },
|
|
+ { USB_DEVICE(0x13d3, 0x3612), .driver_info = BTUSB_REALTEK |
|
|
+ BTUSB_WIDEBAND_SPEECH },
|
|
{ USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK |
|
|
BTUSB_WIDEBAND_SPEECH },
|
|
|
|
@@ -719,6 +721,7 @@ static const struct usb_device_id quirks_table[] = {
|
|
|
|
/* Additional Realtek 8723BU Bluetooth devices */
|
|
{ USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK },
|
|
+ { USB_DEVICE(0x2c0a, 0x8761), .driver_info = BTUSB_REALTEK },
|
|
|
|
/* Additional Realtek 8723DE Bluetooth devices */
|
|
{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
|
|
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
|
|
index 9c6f79d8605329..cdad817e632c61 100644
|
|
--- a/drivers/bluetooth/hci_qca.c
|
|
+++ b/drivers/bluetooth/hci_qca.c
|
|
@@ -1959,19 +1959,23 @@ retry:
|
|
}
|
|
|
|
out:
|
|
- if (ret && retries < MAX_INIT_RETRIES) {
|
|
- bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
|
|
+ if (ret) {
|
|
qca_power_shutdown(hu);
|
|
- if (hu->serdev) {
|
|
- serdev_device_close(hu->serdev);
|
|
- ret = serdev_device_open(hu->serdev);
|
|
- if (ret) {
|
|
- bt_dev_err(hdev, "failed to open port");
|
|
- return ret;
|
|
+
|
|
+ if (retries < MAX_INIT_RETRIES) {
|
|
+ bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
|
|
+ if (hu->serdev) {
|
|
+ serdev_device_close(hu->serdev);
|
|
+ ret = serdev_device_open(hu->serdev);
|
|
+ if (ret) {
|
|
+ bt_dev_err(hdev, "failed to open port");
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
+ retries++;
|
|
+ goto retry;
|
|
}
|
|
- retries++;
|
|
- goto retry;
|
|
+ return ret;
|
|
}
|
|
|
|
/* Setup bdaddr */
|
|
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
|
|
index 8b421ef0580a78..56f5c24c367c09 100644
|
|
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
|
|
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
|
|
@@ -908,11 +908,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
|
|
return 0;
|
|
|
|
error_cleanup_dev:
|
|
- kfree(mc_dev->regions);
|
|
- if (mc_bus)
|
|
- kfree(mc_bus);
|
|
- else
|
|
- kfree(mc_dev);
|
|
+ put_device(&mc_dev->dev);
|
|
|
|
return error;
|
|
}
|
|
diff --git a/drivers/char/ipmi/ipmi_ipmb.c b/drivers/char/ipmi/ipmi_ipmb.c
|
|
index 4e335832fc264e..2b7f6d9aa73996 100644
|
|
--- a/drivers/char/ipmi/ipmi_ipmb.c
|
|
+++ b/drivers/char/ipmi/ipmi_ipmb.c
|
|
@@ -202,11 +202,16 @@ static int ipmi_ipmb_slave_cb(struct i2c_client *client,
|
|
break;
|
|
|
|
case I2C_SLAVE_READ_REQUESTED:
|
|
+ *val = 0xff;
|
|
+ ipmi_ipmb_check_msg_done(iidev);
|
|
+ break;
|
|
+
|
|
case I2C_SLAVE_STOP:
|
|
ipmi_ipmb_check_msg_done(iidev);
|
|
break;
|
|
|
|
case I2C_SLAVE_READ_PROCESSED:
|
|
+ *val = 0xff;
|
|
break;
|
|
}
|
|
|
|
diff --git a/drivers/char/random.c b/drivers/char/random.c
|
|
index 7b5d4822fa3ae1..c66aecb5616405 100644
|
|
--- a/drivers/char/random.c
|
|
+++ b/drivers/char/random.c
|
|
@@ -91,8 +91,7 @@ static ATOMIC_NOTIFIER_HEAD(random_ready_notifier);
|
|
/* Control how we warn userspace. */
|
|
static struct ratelimit_state urandom_warning =
|
|
RATELIMIT_STATE_INIT_FLAGS("urandom_warning", HZ, 3, RATELIMIT_MSG_ON_RELEASE);
|
|
-static int ratelimit_disable __read_mostly =
|
|
- IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM);
|
|
+static int ratelimit_disable __read_mostly = 0;
|
|
module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
|
|
MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
|
|
|
|
@@ -163,12 +162,6 @@ int __cold execute_with_initialized_rng(struct notifier_block *nb)
|
|
return ret;
|
|
}
|
|
|
|
-#define warn_unseeded_randomness() \
|
|
- if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
|
|
- printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
|
|
- __func__, (void *)_RET_IP_, crng_init)
|
|
-
|
|
-
|
|
/*********************************************************************
|
|
*
|
|
* Fast key erasure RNG, the "crng".
|
|
@@ -413,7 +406,6 @@ static void _get_random_bytes(void *buf, size_t len)
|
|
*/
|
|
void get_random_bytes(void *buf, size_t len)
|
|
{
|
|
- warn_unseeded_randomness();
|
|
_get_random_bytes(buf, len);
|
|
}
|
|
EXPORT_SYMBOL(get_random_bytes);
|
|
@@ -501,8 +493,6 @@ type get_random_ ##type(void) \
|
|
struct batch_ ##type *batch; \
|
|
unsigned long next_gen; \
|
|
\
|
|
- warn_unseeded_randomness(); \
|
|
- \
|
|
if (!crng_ready()) { \
|
|
_get_random_bytes(&ret, sizeof(ret)); \
|
|
return ret; \
|
|
diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c
|
|
index a5b554cd477861..f78c61f4163d57 100644
|
|
--- a/drivers/char/tpm/st33zp24/st33zp24.c
|
|
+++ b/drivers/char/tpm/st33zp24/st33zp24.c
|
|
@@ -328,8 +328,10 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
|
|
|
|
for (i = 0; i < len - 1;) {
|
|
burstcnt = get_burstcount(chip);
|
|
- if (burstcnt < 0)
|
|
- return burstcnt;
|
|
+ if (burstcnt < 0) {
|
|
+ ret = burstcnt;
|
|
+ goto out_err;
|
|
+ }
|
|
size = min_t(int, len - i - 1, burstcnt);
|
|
ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO,
|
|
buf + i, size);
|
|
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
|
|
index 81d8a78dc65528..3675faa4a00c75 100644
|
|
--- a/drivers/char/tpm/tpm_i2c_infineon.c
|
|
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
|
|
@@ -543,8 +543,10 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|
burstcnt = get_burstcount(chip);
|
|
|
|
/* burstcnt < 0 = TPM is busy */
|
|
- if (burstcnt < 0)
|
|
- return burstcnt;
|
|
+ if (burstcnt < 0) {
|
|
+ rc = burstcnt;
|
|
+ goto out_err;
|
|
+ }
|
|
|
|
if (burstcnt > (len - 1 - count))
|
|
burstcnt = len - 1 - count;
|
|
diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c
|
|
index e70abd69e1ae30..0f589f301e5bbd 100644
|
|
--- a/drivers/char/tpm/tpm_tis_i2c_cr50.c
|
|
+++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c
|
|
@@ -713,8 +713,7 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client)
|
|
|
|
if (client->irq > 0) {
|
|
rc = devm_request_irq(dev, client->irq, tpm_cr50_i2c_int_handler,
|
|
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
|
|
- IRQF_NO_AUTOEN,
|
|
+ IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
|
|
dev->driver->name, chip);
|
|
if (rc < 0) {
|
|
dev_err(dev, "Failed to probe IRQ %d\n", client->irq);
|
|
diff --git a/drivers/char/tpm/tpm_tis_spi_cr50.c b/drivers/char/tpm/tpm_tis_spi_cr50.c
|
|
index f4937280e94061..32920b4cecfb44 100644
|
|
--- a/drivers/char/tpm/tpm_tis_spi_cr50.c
|
|
+++ b/drivers/char/tpm/tpm_tis_spi_cr50.c
|
|
@@ -287,7 +287,7 @@ int cr50_spi_probe(struct spi_device *spi)
|
|
if (spi->irq > 0) {
|
|
ret = devm_request_irq(&spi->dev, spi->irq,
|
|
cr50_spi_irq_handler,
|
|
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
|
+ IRQF_TRIGGER_RISING,
|
|
"cr50_spi", cr50_phy);
|
|
if (ret < 0) {
|
|
if (ret == -EPROBE_DEFER)
|
|
diff --git a/drivers/clk/clk-apple-nco.c b/drivers/clk/clk-apple-nco.c
|
|
index 457a48d4894128..c205b7f1dadeb8 100644
|
|
--- a/drivers/clk/clk-apple-nco.c
|
|
+++ b/drivers/clk/clk-apple-nco.c
|
|
@@ -318,6 +318,7 @@ static int applnco_probe(struct platform_device *pdev)
|
|
}
|
|
|
|
static const struct of_device_id applnco_ids[] = {
|
|
+ { .compatible = "apple,t8103-nco" },
|
|
{ .compatible = "apple,nco" },
|
|
{ }
|
|
};
|
|
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
|
|
index ba1d1c495bc2bf..644e5a854f2b65 100644
|
|
--- a/drivers/clk/mediatek/clk-mtk.c
|
|
+++ b/drivers/clk/mediatek/clk-mtk.c
|
|
@@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev,
|
|
|
|
|
|
if (mcd->need_runtime_pm) {
|
|
- devm_pm_runtime_enable(&pdev->dev);
|
|
+ r = devm_pm_runtime_enable(&pdev->dev);
|
|
+ if (r)
|
|
+ goto unmap_io;
|
|
/*
|
|
* Do a pm_runtime_resume_and_get() to workaround a possible
|
|
* deadlock between clk_register() and the genpd framework.
|
|
*/
|
|
r = pm_runtime_resume_and_get(&pdev->dev);
|
|
if (r)
|
|
- return r;
|
|
+ goto unmap_io;
|
|
}
|
|
|
|
/* Calculate how many clk_hw_onecell_data entries to allocate */
|
|
@@ -618,11 +620,11 @@ unregister_fixed_clks:
|
|
free_data:
|
|
mtk_free_clk_data(clk_data);
|
|
free_base:
|
|
- if (mcd->shared_io && base)
|
|
- iounmap(base);
|
|
-
|
|
if (mcd->need_runtime_pm)
|
|
pm_runtime_put(&pdev->dev);
|
|
+unmap_io:
|
|
+ if (mcd->shared_io && base)
|
|
+ iounmap(base);
|
|
return r;
|
|
}
|
|
|
|
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
|
index a133013356b645..00eaca92b388a9 100644
|
|
--- a/drivers/clk/meson/gxbb.c
|
|
+++ b/drivers/clk/meson/gxbb.c
|
|
@@ -318,12 +318,23 @@ static struct clk_regmap gxbb_hdmi_pll = {
|
|
},
|
|
};
|
|
|
|
+/*
|
|
+ * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4.
|
|
+ * A divider value of 3 should map to /8 but instead map /4 so ignore it.
|
|
+ */
|
|
+static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = {
|
|
+ { .val = 0, .div = 1 },
|
|
+ { .val = 1, .div = 2 },
|
|
+ { .val = 2, .div = 4 },
|
|
+ { /* sentinel */ }
|
|
+};
|
|
+
|
|
static struct clk_regmap gxl_hdmi_pll_od = {
|
|
.data = &(struct clk_regmap_div_data){
|
|
.offset = HHI_HDMI_PLL_CNTL + 8,
|
|
.shift = 21,
|
|
.width = 2,
|
|
- .flags = CLK_DIVIDER_POWER_OF_TWO,
|
|
+ .table = gxl_hdmi_pll_od_div_table,
|
|
},
|
|
.hw.init = &(struct clk_init_data){
|
|
.name = "hdmi_pll_od",
|
|
@@ -341,7 +352,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = {
|
|
.offset = HHI_HDMI_PLL_CNTL + 8,
|
|
.shift = 23,
|
|
.width = 2,
|
|
- .flags = CLK_DIVIDER_POWER_OF_TWO,
|
|
+ .table = gxl_hdmi_pll_od_div_table,
|
|
},
|
|
.hw.init = &(struct clk_init_data){
|
|
.name = "hdmi_pll_od2",
|
|
@@ -359,7 +370,7 @@ static struct clk_regmap gxl_hdmi_pll = {
|
|
.offset = HHI_HDMI_PLL_CNTL + 8,
|
|
.shift = 19,
|
|
.width = 2,
|
|
- .flags = CLK_DIVIDER_POWER_OF_TWO,
|
|
+ .table = gxl_hdmi_pll_od_div_table,
|
|
},
|
|
.hw.init = &(struct clk_init_data){
|
|
.name = "hdmi_pll",
|
|
diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c
|
|
index 1b4f023cdc8be4..71fbaf8318f22e 100644
|
|
--- a/drivers/clk/microchip/clk-core.c
|
|
+++ b/drivers/clk/microchip/clk-core.c
|
|
@@ -281,14 +281,13 @@ static u8 roclk_get_parent(struct clk_hw *hw)
|
|
|
|
v = (readl(refo->ctrl_reg) >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
|
|
|
|
- if (!refo->parent_map)
|
|
- return v;
|
|
-
|
|
- for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
|
- if (refo->parent_map[i] == v)
|
|
- return i;
|
|
+ if (refo->parent_map) {
|
|
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
|
+ if (refo->parent_map[i] == v)
|
|
+ return i;
|
|
+ }
|
|
|
|
- return -EINVAL;
|
|
+ return v;
|
|
}
|
|
|
|
static unsigned long roclk_calc_rate(unsigned long parent_rate,
|
|
@@ -823,13 +822,13 @@ static u8 sclk_get_parent(struct clk_hw *hw)
|
|
|
|
v = (readl(sclk->mux_reg) >> OSC_CUR_SHIFT) & OSC_CUR_MASK;
|
|
|
|
- if (!sclk->parent_map)
|
|
- return v;
|
|
+ if (sclk->parent_map) {
|
|
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
|
+ if (sclk->parent_map[i] == v)
|
|
+ return i;
|
|
+ }
|
|
|
|
- for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
|
- if (sclk->parent_map[i] == v)
|
|
- return i;
|
|
- return -EINVAL;
|
|
+ return v;
|
|
}
|
|
|
|
static int sclk_set_parent(struct clk_hw *hw, u8 index)
|
|
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
|
|
index fae1c07982aba7..20bb72565f0edb 100644
|
|
--- a/drivers/clk/qcom/clk-rcg2.c
|
|
+++ b/drivers/clk/qcom/clk-rcg2.c
|
|
@@ -434,7 +434,7 @@ static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
|
static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
|
{
|
|
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
|
- u32 notn_m, n, m, d, not2d, mask, duty_per, cfg;
|
|
+ u32 notn_m, n, m, d, not2d, mask, cfg;
|
|
int ret;
|
|
|
|
/* Duty-cycle cannot be modified for non-MND RCGs */
|
|
@@ -453,10 +453,8 @@ static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
|
|
|
|
n = (~(notn_m) + m) & mask;
|
|
|
|
- duty_per = (duty->num * 100) / duty->den;
|
|
-
|
|
/* Calculate 2d value */
|
|
- d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100);
|
|
+ d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den);
|
|
|
|
/*
|
|
* Check bit widths of 2d. If D is too big reduce duty cycle.
|
|
@@ -920,6 +918,7 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw,
|
|
if (req->max_rate < parent_req.max_rate)
|
|
parent_req.max_rate = req->max_rate;
|
|
|
|
+ parent_req.best_parent_hw = req->best_parent_hw;
|
|
ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
|
|
if (ret)
|
|
return ret;
|
|
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
|
|
index 35bd987f2e52ab..3d6e87872ddc35 100644
|
|
--- a/drivers/clk/qcom/common.c
|
|
+++ b/drivers/clk/qcom/common.c
|
|
@@ -325,7 +325,7 @@ int qcom_cc_probe_by_index(struct platform_device *pdev, int index,
|
|
|
|
base = devm_platform_ioremap_resource(pdev, index);
|
|
if (IS_ERR(base))
|
|
- return -ENOMEM;
|
|
+ return PTR_ERR(base);
|
|
|
|
regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config);
|
|
if (IS_ERR(regmap))
|
|
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
|
|
index e792e0b130d333..eae6dcff18da54 100644
|
|
--- a/drivers/clk/qcom/dispcc-sdm845.c
|
|
+++ b/drivers/clk/qcom/dispcc-sdm845.c
|
|
@@ -280,7 +280,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
|
|
.name = "disp_cc_mdss_pclk0_clk_src",
|
|
.parent_data = disp_cc_parent_data_4,
|
|
.num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
|
|
- .flags = CLK_SET_RATE_PARENT,
|
|
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
|
.ops = &clk_pixel_ops,
|
|
},
|
|
};
|
|
@@ -295,7 +295,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
|
|
.name = "disp_cc_mdss_pclk1_clk_src",
|
|
.parent_data = disp_cc_parent_data_4,
|
|
.num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
|
|
- .flags = CLK_SET_RATE_PARENT,
|
|
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
|
.ops = &clk_pixel_ops,
|
|
},
|
|
};
|
|
diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c
|
|
index 915e84db3c97da..292eaa154737f4 100644
|
|
--- a/drivers/clk/qcom/gcc-ipq5018.c
|
|
+++ b/drivers/clk/qcom/gcc-ipq5018.c
|
|
@@ -1339,6 +1339,7 @@ static struct clk_branch gcc_sleep_clk_src = {
|
|
.name = "gcc_sleep_clk_src",
|
|
.parent_data = gcc_sleep_clk_data,
|
|
.num_parents = ARRAY_SIZE(gcc_sleep_clk_data),
|
|
+ .flags = CLK_IS_CRITICAL,
|
|
.ops = &clk_branch2_ops,
|
|
},
|
|
},
|
|
diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c
|
|
index f2dd132e2fb1c1..0be62cb7a62288 100644
|
|
--- a/drivers/clk/qcom/gcc-msm8917.c
|
|
+++ b/drivers/clk/qcom/gcc-msm8917.c
|
|
@@ -3034,7 +3034,6 @@ static struct gdsc cpp_gdsc = {
|
|
.pd = {
|
|
.name = "cpp_gdsc",
|
|
},
|
|
- .flags = ALWAYS_ON,
|
|
.pwrsts = PWRSTS_OFF_ON,
|
|
};
|
|
|
|
diff --git a/drivers/clk/qcom/gcc-msm8953.c b/drivers/clk/qcom/gcc-msm8953.c
|
|
index e6e2ab1380f20b..1689f088140634 100644
|
|
--- a/drivers/clk/qcom/gcc-msm8953.c
|
|
+++ b/drivers/clk/qcom/gcc-msm8953.c
|
|
@@ -3946,7 +3946,6 @@ static struct gdsc cpp_gdsc = {
|
|
.pd = {
|
|
.name = "cpp_gdsc",
|
|
},
|
|
- .flags = ALWAYS_ON,
|
|
.pwrsts = PWRSTS_OFF_ON,
|
|
};
|
|
|
|
diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c
|
|
index 9f42d2601464e7..84643f9ffb02d0 100644
|
|
--- a/drivers/clk/qcom/gcc-qdu1000.c
|
|
+++ b/drivers/clk/qcom/gcc-qdu1000.c
|
|
@@ -904,7 +904,7 @@ static struct clk_rcg2 gcc_sdcc5_apps_clk_src = {
|
|
.name = "gcc_sdcc5_apps_clk_src",
|
|
.parent_data = gcc_parent_data_8,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_8),
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
@@ -923,7 +923,7 @@ static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = {
|
|
.name = "gcc_sdcc5_ice_core_clk_src",
|
|
.parent_data = gcc_parent_data_2,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_2),
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c
|
|
index 573af17bd24caa..314bacd03374b5 100644
|
|
--- a/drivers/clk/qcom/gcc-sdx75.c
|
|
+++ b/drivers/clk/qcom/gcc-sdx75.c
|
|
@@ -1033,7 +1033,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
|
|
.name = "gcc_sdcc1_apps_clk_src",
|
|
.parent_data = gcc_parent_data_17,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_17),
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
@@ -1057,7 +1057,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
|
|
.name = "gcc_sdcc2_apps_clk_src",
|
|
.parent_data = gcc_parent_data_18,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_18),
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c
|
|
index 4c55df89ddca7d..ef02d1003cb4a4 100644
|
|
--- a/drivers/clk/qcom/gcc-sm8450.c
|
|
+++ b/drivers/clk/qcom/gcc-sm8450.c
|
|
@@ -936,7 +936,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
|
|
.parent_data = gcc_parent_data_7,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_7),
|
|
.flags = CLK_SET_RATE_PARENT,
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
@@ -959,7 +959,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
|
|
.parent_data = gcc_parent_data_0,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
|
|
.flags = CLK_SET_RATE_PARENT,
|
|
- .ops = &clk_rcg2_floor_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c
|
|
index b30ece62216f7e..3e5ce6fa680588 100644
|
|
--- a/drivers/clk/qcom/gcc-sm8550.c
|
|
+++ b/drivers/clk/qcom/gcc-sm8550.c
|
|
@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
|
|
.parent_data = gcc_parent_data_9,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_9),
|
|
.flags = CLK_SET_RATE_PARENT,
|
|
- .ops = &clk_rcg2_shared_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
|
|
.parent_data = gcc_parent_data_0,
|
|
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
|
|
.flags = CLK_SET_RATE_PARENT,
|
|
- .ops = &clk_rcg2_shared_ops,
|
|
+ .ops = &clk_rcg2_shared_floor_ops,
|
|
},
|
|
};
|
|
|
|
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
|
|
index 4bba49215c710c..2dea5fb8b858b6 100644
|
|
--- a/drivers/clk/renesas/rzg2l-cpg.c
|
|
+++ b/drivers/clk/renesas/rzg2l-cpg.c
|
|
@@ -91,8 +91,8 @@ struct sd_mux_hw_data {
|
|
|
|
struct rzg2l_pll5_param {
|
|
u32 pl5_fracin;
|
|
+ u16 pl5_intin;
|
|
u8 pl5_refdiv;
|
|
- u8 pl5_intin;
|
|
u8 pl5_postdiv1;
|
|
u8 pl5_postdiv2;
|
|
u8 pl5_spread;
|
|
@@ -380,8 +380,8 @@ rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params,
|
|
foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA,
|
|
(params->pl5_intin << 24) + params->pl5_fracin),
|
|
params->pl5_refdiv) >> 24;
|
|
- foutpostdiv_rate = DIV_ROUND_CLOSEST_ULL(foutvco_rate,
|
|
- params->pl5_postdiv1 * params->pl5_postdiv2);
|
|
+ foutpostdiv_rate = DIV_ROUND_CLOSEST(foutvco_rate,
|
|
+ params->pl5_postdiv1 * params->pl5_postdiv2);
|
|
|
|
return foutpostdiv_rate;
|
|
}
|
|
diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c
|
|
index 2a6db043428159..0f6fb776b2298d 100644
|
|
--- a/drivers/clk/tegra/clk-tegra124-emc.c
|
|
+++ b/drivers/clk/tegra/clk-tegra124-emc.c
|
|
@@ -538,8 +538,10 @@ struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np
|
|
tegra->hw.init = &init;
|
|
|
|
clk = clk_register(NULL, &tegra->hw);
|
|
- if (IS_ERR(clk))
|
|
+ if (IS_ERR(clk)) {
|
|
+ kfree(tegra);
|
|
return clk;
|
|
+ }
|
|
|
|
tegra->prev_parent = clk_hw_get_parent_by_index(
|
|
&tegra->hw, emc_get_parent(&tegra->hw))->clk;
|
|
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
|
|
index 8208a3d895634b..5b526b74e5deef 100644
|
|
--- a/drivers/clocksource/Kconfig
|
|
+++ b/drivers/clocksource/Kconfig
|
|
@@ -236,6 +236,7 @@ config KEYSTONE_TIMER
|
|
|
|
config INTEGRATOR_AP_TIMER
|
|
bool "Integrator-AP timer driver" if COMPILE_TEST
|
|
+ depends on OF
|
|
select CLKSRC_MMIO
|
|
help
|
|
Enables support for the Integrator-AP timer.
|
|
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
|
|
index beffff81c00f3d..3fc6ed9b56300d 100644
|
|
--- a/drivers/clocksource/sh_tmu.c
|
|
+++ b/drivers/clocksource/sh_tmu.c
|
|
@@ -143,16 +143,6 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
|
|
|
|
static int __sh_tmu_enable(struct sh_tmu_channel *ch)
|
|
{
|
|
- int ret;
|
|
-
|
|
- /* enable clock */
|
|
- ret = clk_enable(ch->tmu->clk);
|
|
- if (ret) {
|
|
- dev_err(&ch->tmu->pdev->dev, "ch%u: cannot enable clock\n",
|
|
- ch->index);
|
|
- return ret;
|
|
- }
|
|
-
|
|
/* make sure channel is disabled */
|
|
sh_tmu_start_stop_ch(ch, 0);
|
|
|
|
@@ -174,7 +164,6 @@ static int sh_tmu_enable(struct sh_tmu_channel *ch)
|
|
if (ch->enable_count++ > 0)
|
|
return 0;
|
|
|
|
- pm_runtime_get_sync(&ch->tmu->pdev->dev);
|
|
dev_pm_syscore_device(&ch->tmu->pdev->dev, true);
|
|
|
|
return __sh_tmu_enable(ch);
|
|
@@ -187,9 +176,6 @@ static void __sh_tmu_disable(struct sh_tmu_channel *ch)
|
|
|
|
/* disable interrupts in TMU block */
|
|
sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
|
|
-
|
|
- /* stop clock */
|
|
- clk_disable(ch->tmu->clk);
|
|
}
|
|
|
|
static void sh_tmu_disable(struct sh_tmu_channel *ch)
|
|
@@ -203,7 +189,6 @@ static void sh_tmu_disable(struct sh_tmu_channel *ch)
|
|
__sh_tmu_disable(ch);
|
|
|
|
dev_pm_syscore_device(&ch->tmu->pdev->dev, false);
|
|
- pm_runtime_put(&ch->tmu->pdev->dev);
|
|
}
|
|
|
|
static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta,
|
|
@@ -552,7 +537,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
|
|
goto err_clk_unprepare;
|
|
|
|
tmu->rate = clk_get_rate(tmu->clk) / 4;
|
|
- clk_disable(tmu->clk);
|
|
|
|
/* Map the memory resource. */
|
|
ret = sh_tmu_map_memory(tmu);
|
|
@@ -626,8 +610,6 @@ static int sh_tmu_probe(struct platform_device *pdev)
|
|
out:
|
|
if (tmu->has_clockevent || tmu->has_clocksource)
|
|
pm_runtime_irq_safe(&pdev->dev);
|
|
- else
|
|
- pm_runtime_idle(&pdev->dev);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
index 8b53388280d730..ad4f23e2158be2 100644
|
|
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
@@ -158,8 +158,11 @@ static const struct of_device_id blocklist[] __initconst = {
|
|
{ .compatible = "qcom,sdm845", },
|
|
{ .compatible = "qcom,sdx75", },
|
|
{ .compatible = "qcom,sm6115", },
|
|
+ { .compatible = "qcom,sm6125", },
|
|
+ { .compatible = "qcom,sm6150", },
|
|
{ .compatible = "qcom,sm6350", },
|
|
{ .compatible = "qcom,sm6375", },
|
|
+ { .compatible = "qcom,sm7125", },
|
|
{ .compatible = "qcom,sm7225", },
|
|
{ .compatible = "qcom,sm8150", },
|
|
{ .compatible = "qcom,sm8250", },
|
|
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
|
|
index 6704d610573ad6..aa117f2967fdfc 100644
|
|
--- a/drivers/cpuidle/cpuidle.c
|
|
+++ b/drivers/cpuidle/cpuidle.c
|
|
@@ -356,6 +356,16 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
|
|
int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|
bool *stop_tick)
|
|
{
|
|
+ /*
|
|
+ * If there is only a single idle state (or none), there is nothing
|
|
+ * meaningful for the governor to choose. Skip the governor and
|
|
+ * always use state 0 with the tick running.
|
|
+ */
|
|
+ if (drv->state_count <= 1) {
|
|
+ *stop_tick = false;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
return cpuidle_curr_governor->select(drv, dev, stop_tick);
|
|
}
|
|
|
|
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
|
|
index 27010eee6d1bcd..bedf6c4b8d1b57 100644
|
|
--- a/drivers/cpuidle/governors/menu.c
|
|
+++ b/drivers/cpuidle/governors/menu.c
|
|
@@ -14,8 +14,6 @@
|
|
#include <linux/ktime.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/tick.h>
|
|
-#include <linux/sched.h>
|
|
-#include <linux/sched/loadavg.h>
|
|
#include <linux/sched/stat.h>
|
|
#include <linux/math64.h>
|
|
|
|
@@ -94,16 +92,11 @@
|
|
* state, and thus the less likely a busy CPU will hit such a deep
|
|
* C state.
|
|
*
|
|
- * Two factors are used in determing this multiplier:
|
|
- * a value of 10 is added for each point of "per cpu load average" we have.
|
|
- * a value of 5 points is added for each process that is waiting for
|
|
- * IO on this CPU.
|
|
- * (these values are experimentally determined)
|
|
- *
|
|
- * The load average factor gives a longer term (few seconds) input to the
|
|
- * decision, while the iowait value gives a cpu local instantanious input.
|
|
- * The iowait factor may look low, but realize that this is also already
|
|
- * represented in the system load average.
|
|
+ * Currently there is only one value determining the factor:
|
|
+ * 10 points are added for each process that is waiting for IO on this CPU.
|
|
+ * (This value was experimentally determined.)
|
|
+ * Utilization is no longer a factor as it was shown that it never contributed
|
|
+ * significantly to the performance multiplier in the first place.
|
|
*
|
|
*/
|
|
|
|
@@ -276,7 +269,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|
|
|
/* Find the shortest expected idle interval. */
|
|
predicted_ns = get_typical_interval(data) * NSEC_PER_USEC;
|
|
- if (predicted_ns > RESIDENCY_THRESHOLD_NS) {
|
|
+ if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) {
|
|
unsigned int timer_us;
|
|
|
|
/* Determine the time till the closest timer. */
|
|
@@ -296,6 +289,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|
RESOLUTION * DECAY * NSEC_PER_USEC);
|
|
/* Use the lowest expected idle interval to pick the idle state. */
|
|
predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns);
|
|
+ /*
|
|
+ * If the tick is already stopped, the cost of possible short
|
|
+ * idle duration misprediction is much higher, because the CPU
|
|
+ * may be stuck in a shallow idle state for a long time as a
|
|
+ * result of it. In that case, say we might mispredict and use
|
|
+ * the known time till the closest timer event for the idle
|
|
+ * state selection.
|
|
+ */
|
|
+ if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC)
|
|
+ predicted_ns = data->next_timer_ns;
|
|
} else {
|
|
/*
|
|
* Because the next timer event is not going to be determined
|
|
@@ -321,16 +324,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|
return 0;
|
|
}
|
|
|
|
- /*
|
|
- * If the tick is already stopped, the cost of possible short idle
|
|
- * duration misprediction is much higher, because the CPU may be stuck
|
|
- * in a shallow idle state for a long time as a result of it. In that
|
|
- * case, say we might mispredict and use the known time till the closest
|
|
- * timer event for the idle state selection.
|
|
- */
|
|
- if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC)
|
|
- predicted_ns = data->next_timer_ns;
|
|
-
|
|
/*
|
|
* Find the idle state with the lowest power while satisfying
|
|
* our constraints.
|
|
diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c
|
|
index c246920e6f540c..bccd680c7f7ee4 100644
|
|
--- a/drivers/crypto/cavium/cpt/cptvf_main.c
|
|
+++ b/drivers/crypto/cavium/cpt/cptvf_main.c
|
|
@@ -180,7 +180,8 @@ static void free_command_queues(struct cpt_vf *cptvf,
|
|
|
|
hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead,
|
|
nextchunk) {
|
|
- dma_free_coherent(&pdev->dev, chunk->size,
|
|
+ dma_free_coherent(&pdev->dev,
|
|
+ chunk->size + CPT_NEXT_CHUNK_PTR_SIZE,
|
|
chunk->head,
|
|
chunk->dma_addr);
|
|
chunk->head = NULL;
|
|
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
|
|
index d42d7bc623523d..5f591bce095211 100644
|
|
--- a/drivers/crypto/ccp/psp-dev.c
|
|
+++ b/drivers/crypto/ccp/psp-dev.c
|
|
@@ -9,6 +9,9 @@
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/irqreturn.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/delay.h>
|
|
|
|
#include "sp-dev.h"
|
|
#include "psp-dev.h"
|
|
@@ -19,6 +22,62 @@
|
|
|
|
struct psp_device *psp_master;
|
|
|
|
+#define PSP_C2PMSG_17_CMDRESP_CMD GENMASK(19, 16)
|
|
+
|
|
+static int psp_mailbox_poll(const void __iomem *cmdresp_reg, unsigned int *cmdresp,
|
|
+ unsigned int timeout_msecs)
|
|
+{
|
|
+ while (true) {
|
|
+ *cmdresp = ioread32(cmdresp_reg);
|
|
+ if (FIELD_GET(PSP_CMDRESP_RESP, *cmdresp))
|
|
+ return 0;
|
|
+
|
|
+ if (!timeout_msecs--)
|
|
+ break;
|
|
+
|
|
+ usleep_range(1000, 1100);
|
|
+ }
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+int psp_mailbox_command(struct psp_device *psp, enum psp_cmd cmd, void *cmdbuff,
|
|
+ unsigned int timeout_msecs, unsigned int *cmdresp)
|
|
+{
|
|
+ void __iomem *cmdresp_reg, *cmdbuff_lo_reg, *cmdbuff_hi_reg;
|
|
+ int ret;
|
|
+
|
|
+ if (!psp || !psp->vdata || !psp->vdata->cmdresp_reg ||
|
|
+ !psp->vdata->cmdbuff_addr_lo_reg || !psp->vdata->cmdbuff_addr_hi_reg)
|
|
+ return -ENODEV;
|
|
+
|
|
+ cmdresp_reg = psp->io_regs + psp->vdata->cmdresp_reg;
|
|
+ cmdbuff_lo_reg = psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg;
|
|
+ cmdbuff_hi_reg = psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg;
|
|
+
|
|
+ mutex_lock(&psp->mailbox_mutex);
|
|
+
|
|
+ /* Ensure mailbox is ready for a command */
|
|
+ ret = -EBUSY;
|
|
+ if (psp_mailbox_poll(cmdresp_reg, cmdresp, 0))
|
|
+ goto unlock;
|
|
+
|
|
+ if (cmdbuff) {
|
|
+ iowrite32(lower_32_bits(__psp_pa(cmdbuff)), cmdbuff_lo_reg);
|
|
+ iowrite32(upper_32_bits(__psp_pa(cmdbuff)), cmdbuff_hi_reg);
|
|
+ }
|
|
+
|
|
+ *cmdresp = FIELD_PREP(PSP_C2PMSG_17_CMDRESP_CMD, cmd);
|
|
+ iowrite32(*cmdresp, cmdresp_reg);
|
|
+
|
|
+ ret = psp_mailbox_poll(cmdresp_reg, cmdresp, timeout_msecs);
|
|
+
|
|
+unlock:
|
|
+ mutex_unlock(&psp->mailbox_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static struct psp_device *psp_alloc_struct(struct sp_device *sp)
|
|
{
|
|
struct device *dev = sp->dev;
|
|
@@ -164,6 +223,7 @@ int psp_dev_init(struct sp_device *sp)
|
|
}
|
|
|
|
psp->io_regs = sp->io_map;
|
|
+ mutex_init(&psp->mailbox_mutex);
|
|
|
|
ret = psp_get_capability(psp);
|
|
if (ret)
|
|
@@ -253,6 +313,17 @@ struct psp_device *psp_get_master_device(void)
|
|
return sp ? sp->psp_data : NULL;
|
|
}
|
|
|
|
+int psp_restore(struct sp_device *sp)
|
|
+{
|
|
+ struct psp_device *psp = sp->psp_data;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (psp->tee_data)
|
|
+ ret = tee_restore(psp);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
void psp_pci_init(void)
|
|
{
|
|
psp_master = psp_get_master_device();
|
|
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
|
|
index 8a4de69399c59a..d917657c6085ad 100644
|
|
--- a/drivers/crypto/ccp/psp-dev.h
|
|
+++ b/drivers/crypto/ccp/psp-dev.h
|
|
@@ -14,6 +14,8 @@
|
|
#include <linux/list.h>
|
|
#include <linux/bits.h>
|
|
#include <linux/interrupt.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/psp.h>
|
|
|
|
#include "sp-dev.h"
|
|
|
|
@@ -33,6 +35,7 @@ struct psp_device {
|
|
struct sp_device *sp;
|
|
|
|
void __iomem *io_regs;
|
|
+ struct mutex mailbox_mutex;
|
|
|
|
psp_irq_handler_t sev_irq_handler;
|
|
void *sev_irq_data;
|
|
@@ -71,4 +74,19 @@ struct psp_device *psp_get_master_device(void);
|
|
#define PSP_SECURITY_HSP_TPM_AVAILABLE BIT(10)
|
|
#define PSP_SECURITY_ROM_ARMOR_ENFORCED BIT(11)
|
|
|
|
+/**
|
|
+ * enum psp_cmd - PSP mailbox commands
|
|
+ * @PSP_CMD_TEE_RING_INIT: Initialize TEE ring buffer
|
|
+ * @PSP_CMD_TEE_RING_DESTROY: Destroy TEE ring buffer
|
|
+ * @PSP_CMD_MAX: Maximum command id
|
|
+ */
|
|
+enum psp_cmd {
|
|
+ PSP_CMD_TEE_RING_INIT = 1,
|
|
+ PSP_CMD_TEE_RING_DESTROY = 2,
|
|
+ PSP_CMD_MAX = 15,
|
|
+};
|
|
+
|
|
+int psp_mailbox_command(struct psp_device *psp, enum psp_cmd cmd, void *cmdbuff,
|
|
+ unsigned int timeout_msecs, unsigned int *cmdresp);
|
|
+
|
|
#endif /* __PSP_DEV_H */
|
|
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
|
|
index 7eb3e46682860c..ccbe009ad6e580 100644
|
|
--- a/drivers/crypto/ccp/sp-dev.c
|
|
+++ b/drivers/crypto/ccp/sp-dev.c
|
|
@@ -229,6 +229,18 @@ int sp_resume(struct sp_device *sp)
|
|
return 0;
|
|
}
|
|
|
|
+int sp_restore(struct sp_device *sp)
|
|
+{
|
|
+ if (sp->psp_data) {
|
|
+ int ret = psp_restore(sp);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return sp_resume(sp);
|
|
+}
|
|
+
|
|
struct sp_device *sp_get_psp_master_device(void)
|
|
{
|
|
struct sp_device *i, *ret = NULL;
|
|
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
|
|
index 2329ad524b4945..2efe4a6ef544f1 100644
|
|
--- a/drivers/crypto/ccp/sp-dev.h
|
|
+++ b/drivers/crypto/ccp/sp-dev.h
|
|
@@ -71,6 +71,9 @@ struct psp_vdata {
|
|
const struct sev_vdata *sev;
|
|
const struct tee_vdata *tee;
|
|
const struct platform_access_vdata *platform_access;
|
|
+ const unsigned int cmdresp_reg;
|
|
+ const unsigned int cmdbuff_addr_lo_reg;
|
|
+ const unsigned int cmdbuff_addr_hi_reg;
|
|
const unsigned int feature_reg;
|
|
const unsigned int inten_reg;
|
|
const unsigned int intsts_reg;
|
|
@@ -138,6 +141,7 @@ struct sp_device *sp_get_master(void);
|
|
|
|
int sp_suspend(struct sp_device *sp);
|
|
int sp_resume(struct sp_device *sp);
|
|
+int sp_restore(struct sp_device *sp);
|
|
int sp_request_ccp_irq(struct sp_device *sp, irq_handler_t handler,
|
|
const char *name, void *data);
|
|
void sp_free_ccp_irq(struct sp_device *sp, void *data);
|
|
@@ -171,6 +175,7 @@ int psp_dev_init(struct sp_device *sp);
|
|
void psp_pci_init(void);
|
|
void psp_dev_destroy(struct sp_device *sp);
|
|
void psp_pci_exit(void);
|
|
+int psp_restore(struct sp_device *sp);
|
|
|
|
#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
|
|
|
|
@@ -178,6 +183,7 @@ static inline int psp_dev_init(struct sp_device *sp) { return 0; }
|
|
static inline void psp_pci_init(void) { }
|
|
static inline void psp_dev_destroy(struct sp_device *sp) { }
|
|
static inline void psp_pci_exit(void) { }
|
|
+static inline int psp_restore(struct sp_device *sp) { return 0; }
|
|
|
|
#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
|
|
|
|
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
|
|
index b1e60542351a66..86517bb4c19527 100644
|
|
--- a/drivers/crypto/ccp/sp-pci.c
|
|
+++ b/drivers/crypto/ccp/sp-pci.c
|
|
@@ -407,6 +407,13 @@ static int __maybe_unused sp_pci_resume(struct device *dev)
|
|
return sp_resume(sp);
|
|
}
|
|
|
|
+static int __maybe_unused sp_pci_restore(struct device *dev)
|
|
+{
|
|
+ struct sp_device *sp = dev_get_drvdata(dev);
|
|
+
|
|
+ return sp_restore(sp);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_CRYPTO_DEV_SP_PSP
|
|
static const struct sev_vdata sevv1 = {
|
|
.cmdresp_reg = 0x10580, /* C2PMSG_32 */
|
|
@@ -421,18 +428,12 @@ static const struct sev_vdata sevv2 = {
|
|
};
|
|
|
|
static const struct tee_vdata teev1 = {
|
|
- .cmdresp_reg = 0x10544, /* C2PMSG_17 */
|
|
- .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */
|
|
- .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */
|
|
.ring_wptr_reg = 0x10550, /* C2PMSG_20 */
|
|
.ring_rptr_reg = 0x10554, /* C2PMSG_21 */
|
|
.info_reg = 0x109e8, /* C2PMSG_58 */
|
|
};
|
|
|
|
static const struct tee_vdata teev2 = {
|
|
- .cmdresp_reg = 0x10944, /* C2PMSG_17 */
|
|
- .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */
|
|
- .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */
|
|
.ring_wptr_reg = 0x10950, /* C2PMSG_20 */
|
|
.ring_rptr_reg = 0x10954, /* C2PMSG_21 */
|
|
};
|
|
@@ -469,6 +470,9 @@ static const struct psp_vdata pspv2 = {
|
|
static const struct psp_vdata pspv3 = {
|
|
.tee = &teev1,
|
|
.platform_access = &pa_v1,
|
|
+ .cmdresp_reg = 0x10544, /* C2PMSG_17 */
|
|
+ .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */
|
|
+ .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */
|
|
.bootloader_info_reg = 0x109ec, /* C2PMSG_59 */
|
|
.feature_reg = 0x109fc, /* C2PMSG_63 */
|
|
.inten_reg = 0x10690, /* P2CMSG_INTEN */
|
|
@@ -479,6 +483,9 @@ static const struct psp_vdata pspv3 = {
|
|
static const struct psp_vdata pspv4 = {
|
|
.sev = &sevv2,
|
|
.tee = &teev1,
|
|
+ .cmdresp_reg = 0x10544, /* C2PMSG_17 */
|
|
+ .cmdbuff_addr_lo_reg = 0x10548, /* C2PMSG_18 */
|
|
+ .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */
|
|
.bootloader_info_reg = 0x109ec, /* C2PMSG_59 */
|
|
.feature_reg = 0x109fc, /* C2PMSG_63 */
|
|
.inten_reg = 0x10690, /* P2CMSG_INTEN */
|
|
@@ -488,6 +495,9 @@ static const struct psp_vdata pspv4 = {
|
|
static const struct psp_vdata pspv5 = {
|
|
.tee = &teev2,
|
|
.platform_access = &pa_v2,
|
|
+ .cmdresp_reg = 0x10944, /* C2PMSG_17 */
|
|
+ .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */
|
|
+ .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */
|
|
.feature_reg = 0x109fc, /* C2PMSG_63 */
|
|
.inten_reg = 0x10510, /* P2CMSG_INTEN */
|
|
.intsts_reg = 0x10514, /* P2CMSG_INTSTS */
|
|
@@ -496,6 +506,9 @@ static const struct psp_vdata pspv5 = {
|
|
static const struct psp_vdata pspv6 = {
|
|
.sev = &sevv2,
|
|
.tee = &teev2,
|
|
+ .cmdresp_reg = 0x10944, /* C2PMSG_17 */
|
|
+ .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */
|
|
+ .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */
|
|
.feature_reg = 0x109fc, /* C2PMSG_63 */
|
|
.inten_reg = 0x10510, /* P2CMSG_INTEN */
|
|
.intsts_reg = 0x10514, /* P2CMSG_INTSTS */
|
|
@@ -585,7 +598,14 @@ static const struct pci_device_id sp_pci_table[] = {
|
|
};
|
|
MODULE_DEVICE_TABLE(pci, sp_pci_table);
|
|
|
|
-static SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume);
|
|
+static const struct dev_pm_ops sp_pci_pm_ops = {
|
|
+ .suspend = pm_sleep_ptr(sp_pci_suspend),
|
|
+ .resume = pm_sleep_ptr(sp_pci_resume),
|
|
+ .freeze = pm_sleep_ptr(sp_pci_suspend),
|
|
+ .thaw = pm_sleep_ptr(sp_pci_resume),
|
|
+ .poweroff = pm_sleep_ptr(sp_pci_suspend),
|
|
+ .restore_early = pm_sleep_ptr(sp_pci_restore),
|
|
+};
|
|
|
|
static struct pci_driver sp_pci_driver = {
|
|
.name = "ccp",
|
|
diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
|
|
index 5560bf8329a127..01d7dcb9cfee19 100644
|
|
--- a/drivers/crypto/ccp/tee-dev.c
|
|
+++ b/drivers/crypto/ccp/tee-dev.c
|
|
@@ -62,26 +62,6 @@ static void tee_free_ring(struct psp_tee_device *tee)
|
|
mutex_destroy(&rb_mgr->mutex);
|
|
}
|
|
|
|
-static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
|
|
- unsigned int *reg)
|
|
-{
|
|
- /* ~10ms sleep per loop => nloop = timeout * 100 */
|
|
- int nloop = timeout * 100;
|
|
-
|
|
- while (--nloop) {
|
|
- *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
|
|
- if (FIELD_GET(PSP_CMDRESP_RESP, *reg))
|
|
- return 0;
|
|
-
|
|
- usleep_range(10000, 10100);
|
|
- }
|
|
-
|
|
- dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
|
|
- psp_dead = true;
|
|
-
|
|
- return -ETIMEDOUT;
|
|
-}
|
|
-
|
|
static
|
|
struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
|
|
{
|
|
@@ -106,11 +86,34 @@ static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
|
|
kfree(cmd);
|
|
}
|
|
|
|
+static bool tee_send_destroy_cmd(struct psp_tee_device *tee)
|
|
+{
|
|
+ unsigned int reg;
|
|
+ int ret;
|
|
+
|
|
+ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_DESTROY, NULL,
|
|
+ TEE_DEFAULT_CMD_TIMEOUT, ®);
|
|
+ if (ret) {
|
|
+ dev_err(tee->dev, "tee: ring destroy command timed out, disabling TEE support\n");
|
|
+ psp_dead = true;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
|
|
+ dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n",
|
|
+ FIELD_GET(PSP_CMDRESP_STS, reg));
|
|
+ psp_dead = true;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
static int tee_init_ring(struct psp_tee_device *tee)
|
|
{
|
|
int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
|
|
struct tee_init_ring_cmd *cmd;
|
|
- phys_addr_t cmd_buffer;
|
|
+ bool retry = false;
|
|
unsigned int reg;
|
|
int ret;
|
|
|
|
@@ -130,27 +133,32 @@ static int tee_init_ring(struct psp_tee_device *tee)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- cmd_buffer = __psp_pa((void *)cmd);
|
|
-
|
|
/* Send command buffer details to Trusted OS by writing to
|
|
* CPU-PSP message registers
|
|
*/
|
|
-
|
|
- iowrite32(lower_32_bits(cmd_buffer),
|
|
- tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
|
|
- iowrite32(upper_32_bits(cmd_buffer),
|
|
- tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
|
|
- iowrite32(TEE_RING_INIT_CMD,
|
|
- tee->io_regs + tee->vdata->cmdresp_reg);
|
|
-
|
|
- ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®);
|
|
+retry_init:
|
|
+ ret = psp_mailbox_command(tee->psp, PSP_CMD_TEE_RING_INIT, cmd,
|
|
+ TEE_DEFAULT_CMD_TIMEOUT, ®);
|
|
if (ret) {
|
|
- dev_err(tee->dev, "tee: ring init command timed out\n");
|
|
+ dev_err(tee->dev, "tee: ring init command timed out, disabling TEE support\n");
|
|
tee_free_ring(tee);
|
|
+ psp_dead = true;
|
|
goto free_buf;
|
|
}
|
|
|
|
if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
|
|
+ /*
|
|
+ * During the hibernate resume sequence driver may have gotten loaded
|
|
+ * but the ring not properly destroyed. If the ring doesn't work, try
|
|
+ * to destroy and re-init once.
|
|
+ */
|
|
+ if (!retry && FIELD_GET(PSP_CMDRESP_STS, reg) == PSP_TEE_STS_RING_BUSY) {
|
|
+ dev_info(tee->dev, "tee: ring init command failed with busy status, retrying\n");
|
|
+ if (tee_send_destroy_cmd(tee)) {
|
|
+ retry = true;
|
|
+ goto retry_init;
|
|
+ }
|
|
+ }
|
|
dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n",
|
|
FIELD_GET(PSP_CMDRESP_STS, reg));
|
|
tee_free_ring(tee);
|
|
@@ -165,25 +173,13 @@ free_buf:
|
|
|
|
static void tee_destroy_ring(struct psp_tee_device *tee)
|
|
{
|
|
- unsigned int reg;
|
|
- int ret;
|
|
-
|
|
if (!tee->rb_mgr.ring_start)
|
|
return;
|
|
|
|
if (psp_dead)
|
|
goto free_ring;
|
|
|
|
- iowrite32(TEE_RING_DESTROY_CMD,
|
|
- tee->io_regs + tee->vdata->cmdresp_reg);
|
|
-
|
|
- ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®);
|
|
- if (ret) {
|
|
- dev_err(tee->dev, "tee: ring destroy command timed out\n");
|
|
- } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
|
|
- dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n",
|
|
- FIELD_GET(PSP_CMDRESP_STS, reg));
|
|
- }
|
|
+ tee_send_destroy_cmd(tee);
|
|
|
|
free_ring:
|
|
tee_free_ring(tee);
|
|
@@ -370,7 +366,7 @@ int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
|
|
+ ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_RING_TIMEOUT);
|
|
if (ret) {
|
|
resp->flag = CMD_RESPONSE_TIMEDOUT;
|
|
return ret;
|
|
@@ -395,3 +391,8 @@ int psp_check_tee_status(void)
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(psp_check_tee_status);
|
|
+
|
|
+int tee_restore(struct psp_device *psp)
|
|
+{
|
|
+ return tee_init_ring(psp->tee_data);
|
|
+}
|
|
diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h
|
|
index 49d26158b71e31..c23416cb7bb37f 100644
|
|
--- a/drivers/crypto/ccp/tee-dev.h
|
|
+++ b/drivers/crypto/ccp/tee-dev.h
|
|
@@ -17,21 +17,10 @@
|
|
#include <linux/device.h>
|
|
#include <linux/mutex.h>
|
|
|
|
-#define TEE_DEFAULT_TIMEOUT 10
|
|
+#define TEE_DEFAULT_CMD_TIMEOUT (10 * MSEC_PER_SEC)
|
|
+#define TEE_DEFAULT_RING_TIMEOUT 10
|
|
#define MAX_BUFFER_SIZE 988
|
|
|
|
-/**
|
|
- * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration
|
|
- * @TEE_RING_INIT_CMD: Initialize ring buffer
|
|
- * @TEE_RING_DESTROY_CMD: Destroy ring buffer
|
|
- * @TEE_RING_MAX_CMD: Maximum command id
|
|
- */
|
|
-enum tee_ring_cmd_id {
|
|
- TEE_RING_INIT_CMD = 0x00010000,
|
|
- TEE_RING_DESTROY_CMD = 0x00020000,
|
|
- TEE_RING_MAX_CMD = 0x000F0000,
|
|
-};
|
|
-
|
|
/**
|
|
* struct tee_init_ring_cmd - Command to init TEE ring buffer
|
|
* @low_addr: bits [31:0] of the physical address of ring buffer
|
|
@@ -122,5 +111,6 @@ struct tee_ring_cmd {
|
|
|
|
int tee_dev_init(struct psp_device *psp);
|
|
void tee_dev_destroy(struct psp_device *psp);
|
|
+int tee_restore(struct psp_device *psp);
|
|
|
|
#endif /* __TEE_DEV_H__ */
|
|
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
|
|
index 2c0ca68914e2f2..e09357fea057ca 100644
|
|
--- a/drivers/crypto/hisilicon/qm.c
|
|
+++ b/drivers/crypto/hisilicon/qm.c
|
|
@@ -633,9 +633,13 @@ static void qm_mb_write(struct hisi_qm *qm, const void *src)
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_ARM64)
|
|
+ /*
|
|
+ * The dmb oshst instruction ensures that the data in the
|
|
+ * mailbox is written before it is sent to the hardware.
|
|
+ */
|
|
asm volatile("ldp %0, %1, %3\n"
|
|
- "stp %0, %1, %2\n"
|
|
"dmb oshst\n"
|
|
+ "stp %0, %1, %2\n"
|
|
: "=&r" (tmp0),
|
|
"=&r" (tmp1),
|
|
"+Q" (*((char __iomem *)fun_base))
|
|
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
|
|
index d6727b8ff582b6..8db3d2990816ea 100644
|
|
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
|
|
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
|
|
@@ -590,10 +590,8 @@ static int sec_ctx_base_init(struct sec_ctx *ctx)
|
|
int i, ret;
|
|
|
|
ctx->qps = sec_create_qps();
|
|
- if (!ctx->qps) {
|
|
- pr_err("Can not create sec qps!\n");
|
|
+ if (!ctx->qps)
|
|
return -ENODEV;
|
|
- }
|
|
|
|
sec = container_of(ctx->qps[0]->qm, struct sec_dev, qm);
|
|
ctx->sec = sec;
|
|
@@ -632,6 +630,9 @@ static void sec_ctx_base_uninit(struct sec_ctx *ctx)
|
|
{
|
|
int i;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return;
|
|
+
|
|
for (i = 0; i < ctx->sec->ctx_q_num; i++)
|
|
sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]);
|
|
|
|
@@ -643,6 +644,9 @@ static int sec_cipher_init(struct sec_ctx *ctx)
|
|
{
|
|
struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return 0;
|
|
+
|
|
c_ctx->c_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
|
|
&c_ctx->c_key_dma, GFP_KERNEL);
|
|
if (!c_ctx->c_key)
|
|
@@ -655,6 +659,9 @@ static void sec_cipher_uninit(struct sec_ctx *ctx)
|
|
{
|
|
struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return;
|
|
+
|
|
memzero_explicit(c_ctx->c_key, SEC_MAX_KEY_SIZE);
|
|
dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
|
|
c_ctx->c_key, c_ctx->c_key_dma);
|
|
@@ -676,6 +683,9 @@ static void sec_auth_uninit(struct sec_ctx *ctx)
|
|
{
|
|
struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return;
|
|
+
|
|
memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE);
|
|
dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE,
|
|
a_ctx->a_key, a_ctx->a_key_dma);
|
|
@@ -713,7 +723,7 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm)
|
|
}
|
|
|
|
ret = sec_ctx_base_init(ctx);
|
|
- if (ret)
|
|
+ if (ret && ret != -ENODEV)
|
|
return ret;
|
|
|
|
ret = sec_cipher_init(ctx);
|
|
@@ -824,6 +834,9 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
|
struct device *dev = ctx->dev;
|
|
int ret;
|
|
|
|
+ if (!ctx->qps)
|
|
+ goto set_soft_key;
|
|
+
|
|
if (c_mode == SEC_CMODE_XTS) {
|
|
ret = xts_verify_key(tfm, key, keylen);
|
|
if (ret) {
|
|
@@ -854,13 +867,14 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
|
}
|
|
|
|
memcpy(c_ctx->c_key, key, keylen);
|
|
- if (c_ctx->fbtfm) {
|
|
- ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen);
|
|
- if (ret) {
|
|
- dev_err(dev, "failed to set fallback skcipher key!\n");
|
|
- return ret;
|
|
- }
|
|
+
|
|
+set_soft_key:
|
|
+ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to set fallback skcipher key!\n");
|
|
+ return ret;
|
|
}
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1139,6 +1153,9 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
|
|
struct crypto_authenc_keys keys;
|
|
int ret;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
|
|
+
|
|
ctx->a_ctx.a_alg = a_alg;
|
|
ctx->c_ctx.c_alg = c_alg;
|
|
c_ctx->c_mode = c_mode;
|
|
@@ -1833,6 +1850,9 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ if (!ctx->qps)
|
|
+ return 0;
|
|
+
|
|
if (ctx->sec->qm.ver < QM_HW_V3) {
|
|
ctx->type_supported = SEC_BD_TYPE2;
|
|
ctx->req_op = &sec_skcipher_req_ops;
|
|
@@ -1841,7 +1861,7 @@ static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
|
|
ctx->req_op = &sec_skcipher_req_ops_v3;
|
|
}
|
|
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm)
|
|
@@ -1909,7 +1929,7 @@ static int sec_aead_ctx_init(struct crypto_aead *tfm, const char *hash_name)
|
|
int ret;
|
|
|
|
ret = sec_aead_init(tfm);
|
|
- if (ret) {
|
|
+ if (ret && ret != -ENODEV) {
|
|
pr_err("hisi_sec2: aead init error!\n");
|
|
return ret;
|
|
}
|
|
@@ -1951,7 +1971,7 @@ static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm)
|
|
int ret;
|
|
|
|
ret = sec_aead_init(tfm);
|
|
- if (ret) {
|
|
+ if (ret && ret != -ENODEV) {
|
|
dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n");
|
|
return ret;
|
|
}
|
|
@@ -2098,6 +2118,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
|
|
bool need_fallback = false;
|
|
int ret;
|
|
|
|
+ if (!ctx->qps)
|
|
+ goto soft_crypto;
|
|
+
|
|
if (!sk_req->cryptlen) {
|
|
if (ctx->c_ctx.c_mode == SEC_CMODE_XTS)
|
|
return -EINVAL;
|
|
@@ -2114,9 +2137,12 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
|
|
return -EINVAL;
|
|
|
|
if (unlikely(ctx->c_ctx.fallback || need_fallback))
|
|
- return sec_skcipher_soft_crypto(ctx, sk_req, encrypt);
|
|
+ goto soft_crypto;
|
|
|
|
return ctx->req_op->process(ctx, req);
|
|
+
|
|
+soft_crypto:
|
|
+ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt);
|
|
}
|
|
|
|
static int sec_skcipher_encrypt(struct skcipher_request *sk_req)
|
|
@@ -2346,6 +2372,9 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
|
|
bool need_fallback = false;
|
|
int ret;
|
|
|
|
+ if (!ctx->qps)
|
|
+ goto soft_crypto;
|
|
+
|
|
req->flag = a_req->base.flags;
|
|
req->aead_req.aead_req = a_req;
|
|
req->c_req.encrypt = encrypt;
|
|
@@ -2355,11 +2384,14 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
|
|
ret = sec_aead_param_check(ctx, req, &need_fallback);
|
|
if (unlikely(ret)) {
|
|
if (need_fallback)
|
|
- return sec_aead_soft_crypto(ctx, a_req, encrypt);
|
|
+ goto soft_crypto;
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ctx->req_op->process(ctx, req);
|
|
+
|
|
+soft_crypto:
|
|
+ return sec_aead_soft_crypto(ctx, a_req, encrypt);
|
|
}
|
|
|
|
static int sec_aead_encrypt(struct aead_request *a_req)
|
|
diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
|
|
index 97e500db0a8259..b2d9b5310b784c 100644
|
|
--- a/drivers/crypto/hisilicon/trng/trng.c
|
|
+++ b/drivers/crypto/hisilicon/trng/trng.c
|
|
@@ -1,6 +1,7 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2019 HiSilicon Limited. */
|
|
|
|
+#include <crypto/internal/rng.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/crypto.h>
|
|
#include <linux/err.h>
|
|
@@ -13,7 +14,6 @@
|
|
#include <linux/mutex.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/random.h>
|
|
-#include <crypto/internal/rng.h>
|
|
|
|
#define HISI_TRNG_REG 0x00F0
|
|
#define HISI_TRNG_BYTES 4
|
|
@@ -40,6 +40,7 @@
|
|
#define SEED_SHIFT_24 24
|
|
#define SEED_SHIFT_16 16
|
|
#define SEED_SHIFT_8 8
|
|
+#define SW_MAX_RANDOM_BYTES 65520
|
|
|
|
struct hisi_trng_list {
|
|
struct mutex lock;
|
|
@@ -53,8 +54,10 @@ struct hisi_trng {
|
|
struct list_head list;
|
|
struct hwrng rng;
|
|
u32 ver;
|
|
- bool is_used;
|
|
- struct mutex mutex;
|
|
+ u32 ctx_num;
|
|
+ /* The bytes of the random number generated since the last seeding. */
|
|
+ u32 random_bytes;
|
|
+ struct mutex lock;
|
|
};
|
|
|
|
struct hisi_trng_ctx {
|
|
@@ -63,10 +66,14 @@ struct hisi_trng_ctx {
|
|
|
|
static atomic_t trng_active_devs;
|
|
static struct hisi_trng_list trng_devices;
|
|
+static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
|
|
|
|
-static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
|
|
+static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
|
|
{
|
|
u32 val, seed_reg, i;
|
|
+ int ret;
|
|
+
|
|
+ writel(0x0, trng->base + SW_DRBG_BLOCKS);
|
|
|
|
for (i = 0; i < SW_DRBG_SEED_SIZE;
|
|
i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
|
|
@@ -78,6 +85,20 @@ static void hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
|
|
seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
|
|
writel(val, trng->base + SW_DRBG_SEED(seed_reg));
|
|
}
|
|
+
|
|
+ writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
|
|
+ trng->base + SW_DRBG_BLOCKS);
|
|
+ writel(0x1, trng->base + SW_DRBG_INIT);
|
|
+ ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
|
|
+ val, val & BIT(0), SLEEP_US, TIMEOUT_US);
|
|
+ if (ret) {
|
|
+ pr_err("failed to init trng(%d)\n", ret);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ trng->random_bytes = 0;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
|
|
@@ -85,8 +106,7 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
|
|
{
|
|
struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
|
|
struct hisi_trng *trng = ctx->trng;
|
|
- u32 val = 0;
|
|
- int ret = 0;
|
|
+ int ret;
|
|
|
|
if (slen < SW_DRBG_SEED_SIZE) {
|
|
pr_err("slen(%u) is not matched with trng(%d)\n", slen,
|
|
@@ -94,43 +114,45 @@ static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- writel(0x0, trng->base + SW_DRBG_BLOCKS);
|
|
- hisi_trng_set_seed(trng, seed);
|
|
+ mutex_lock(&trng->lock);
|
|
+ ret = hisi_trng_set_seed(trng, seed);
|
|
+ mutex_unlock(&trng->lock);
|
|
|
|
- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
|
|
- trng->base + SW_DRBG_BLOCKS);
|
|
- writel(0x1, trng->base + SW_DRBG_INIT);
|
|
+ return ret;
|
|
+}
|
|
|
|
- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
|
|
- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
|
|
- if (ret)
|
|
- pr_err("fail to init trng(%d)\n", ret);
|
|
+static int hisi_trng_reseed(struct hisi_trng *trng)
|
|
+{
|
|
+ u8 seed[SW_DRBG_SEED_SIZE];
|
|
+ int size;
|
|
|
|
- return ret;
|
|
+ if (!trng->random_bytes)
|
|
+ return 0;
|
|
+
|
|
+ size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
|
|
+ if (size != SW_DRBG_SEED_SIZE)
|
|
+ return -EIO;
|
|
+
|
|
+ return hisi_trng_set_seed(trng, seed);
|
|
}
|
|
|
|
-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
|
|
- unsigned int slen, u8 *dstn, unsigned int dlen)
|
|
+static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
|
|
{
|
|
- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
|
|
- struct hisi_trng *trng = ctx->trng;
|
|
u32 data[SW_DRBG_DATA_NUM];
|
|
u32 currsize = 0;
|
|
u32 val = 0;
|
|
int ret;
|
|
u32 i;
|
|
|
|
- if (dlen > SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES || dlen == 0) {
|
|
- pr_err("dlen(%d) exceeds limit(%d)!\n", dlen,
|
|
- SW_DRBG_BLOCKS_NUM * SW_DRBG_BYTES);
|
|
- return -EINVAL;
|
|
- }
|
|
+ ret = hisi_trng_reseed(trng);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
do {
|
|
ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
|
|
- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
|
|
+ val, val & BIT(1), SLEEP_US, TIMEOUT_US);
|
|
if (ret) {
|
|
- pr_err("fail to generate random number(%d)!\n", ret);
|
|
+ pr_err("failed to generate random number(%d)!\n", ret);
|
|
break;
|
|
}
|
|
|
|
@@ -145,30 +167,57 @@ static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
|
|
currsize = dlen;
|
|
}
|
|
|
|
+ trng->random_bytes += SW_DRBG_BYTES;
|
|
writel(0x1, trng->base + SW_DRBG_GEN);
|
|
} while (currsize < dlen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
+static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
|
|
+ unsigned int slen, u8 *dstn, unsigned int dlen)
|
|
+{
|
|
+ struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
|
|
+ struct hisi_trng *trng = ctx->trng;
|
|
+ unsigned int currsize = 0;
|
|
+ unsigned int block_size;
|
|
+ int ret;
|
|
+
|
|
+ if (!dstn || !dlen) {
|
|
+ pr_err("output is error, dlen %u!\n", dlen);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
|
|
+ mutex_lock(&trng->lock);
|
|
+ ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
|
|
+ mutex_unlock(&trng->lock);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ currsize += block_size;
|
|
+ } while (currsize < dlen);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int hisi_trng_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
struct hisi_trng *trng;
|
|
- int ret = -EBUSY;
|
|
+ u32 ctx_num = ~0;
|
|
|
|
mutex_lock(&trng_devices.lock);
|
|
list_for_each_entry(trng, &trng_devices.list, list) {
|
|
- if (!trng->is_used) {
|
|
- trng->is_used = true;
|
|
+ if (trng->ctx_num < ctx_num) {
|
|
+ ctx_num = trng->ctx_num;
|
|
ctx->trng = trng;
|
|
- ret = 0;
|
|
- break;
|
|
}
|
|
}
|
|
+ ctx->trng->ctx_num++;
|
|
mutex_unlock(&trng_devices.lock);
|
|
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
static void hisi_trng_exit(struct crypto_tfm *tfm)
|
|
@@ -176,7 +225,7 @@ static void hisi_trng_exit(struct crypto_tfm *tfm)
|
|
struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
|
mutex_lock(&trng_devices.lock);
|
|
- ctx->trng->is_used = false;
|
|
+ ctx->trng->ctx_num--;
|
|
mutex_unlock(&trng_devices.lock);
|
|
}
|
|
|
|
@@ -238,7 +287,7 @@ static int hisi_trng_del_from_list(struct hisi_trng *trng)
|
|
int ret = -EBUSY;
|
|
|
|
mutex_lock(&trng_devices.lock);
|
|
- if (!trng->is_used) {
|
|
+ if (!trng->ctx_num) {
|
|
list_del(&trng->list);
|
|
ret = 0;
|
|
}
|
|
@@ -262,7 +311,9 @@ static int hisi_trng_probe(struct platform_device *pdev)
|
|
if (IS_ERR(trng->base))
|
|
return PTR_ERR(trng->base);
|
|
|
|
- trng->is_used = false;
|
|
+ trng->ctx_num = 0;
|
|
+ trng->random_bytes = SW_MAX_RANDOM_BYTES;
|
|
+ mutex_init(&trng->lock);
|
|
trng->ver = readl(trng->base + HISI_TRNG_VERSION);
|
|
if (!trng_devices.is_init) {
|
|
INIT_LIST_HEAD(&trng_devices.list);
|
|
diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c
|
|
index 6608971d10cdc1..d21ce4094d7dbf 100644
|
|
--- a/drivers/crypto/hisilicon/zip/zip_crypto.c
|
|
+++ b/drivers/crypto/hisilicon/zip/zip_crypto.c
|
|
@@ -16,36 +16,14 @@
|
|
#define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0)
|
|
/* hisi_zip_sqe dw9 */
|
|
#define HZIP_REQ_TYPE_M GENMASK(7, 0)
|
|
-#define HZIP_ALG_TYPE_ZLIB 0x02
|
|
-#define HZIP_ALG_TYPE_GZIP 0x03
|
|
+#define HZIP_ALG_TYPE_DEFLATE 0x01
|
|
#define HZIP_BUF_TYPE_M GENMASK(11, 8)
|
|
-#define HZIP_PBUFFER 0x0
|
|
#define HZIP_SGL 0x1
|
|
|
|
-#define HZIP_ZLIB_HEAD_SIZE 2
|
|
-#define HZIP_GZIP_HEAD_SIZE 10
|
|
-
|
|
-#define GZIP_HEAD_FHCRC_BIT BIT(1)
|
|
-#define GZIP_HEAD_FEXTRA_BIT BIT(2)
|
|
-#define GZIP_HEAD_FNAME_BIT BIT(3)
|
|
-#define GZIP_HEAD_FCOMMENT_BIT BIT(4)
|
|
-
|
|
-#define GZIP_HEAD_FLG_SHIFT 3
|
|
-#define GZIP_HEAD_FEXTRA_SHIFT 10
|
|
-#define GZIP_HEAD_FEXTRA_XLEN 2UL
|
|
-#define GZIP_HEAD_FHCRC_SIZE 2
|
|
-
|
|
-#define HZIP_GZIP_HEAD_BUF 256
|
|
#define HZIP_ALG_PRIORITY 300
|
|
#define HZIP_SGL_SGE_NR 10
|
|
|
|
-#define HZIP_ALG_ZLIB GENMASK(1, 0)
|
|
-#define HZIP_ALG_GZIP GENMASK(3, 2)
|
|
-
|
|
-static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c};
|
|
-static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {
|
|
- 0x1f, 0x8b, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03
|
|
-};
|
|
+#define HZIP_ALG_DEFLATE GENMASK(5, 4)
|
|
|
|
enum hisi_zip_alg_type {
|
|
HZIP_ALG_TYPE_COMP = 0,
|
|
@@ -58,26 +36,17 @@ enum {
|
|
HZIP_CTX_Q_NUM
|
|
};
|
|
|
|
+#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32)
|
|
#define COMP_NAME_TO_TYPE(alg_name) \
|
|
- (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \
|
|
- !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0) \
|
|
-
|
|
-#define TO_HEAD_SIZE(req_type) \
|
|
- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? sizeof(zlib_head) : \
|
|
- ((req_type) == HZIP_ALG_TYPE_GZIP) ? sizeof(gzip_head) : 0) \
|
|
-
|
|
-#define TO_HEAD(req_type) \
|
|
- (((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head : \
|
|
- ((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : NULL) \
|
|
+ (!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : 0)
|
|
|
|
struct hisi_zip_req {
|
|
struct acomp_req *req;
|
|
- u32 sskip;
|
|
- u32 dskip;
|
|
struct hisi_acc_hw_sgl *hw_src;
|
|
struct hisi_acc_hw_sgl *hw_dst;
|
|
dma_addr_t dma_src;
|
|
dma_addr_t dma_dst;
|
|
+ struct hisi_zip_qp_ctx *qp_ctx;
|
|
u16 req_id;
|
|
};
|
|
|
|
@@ -104,7 +73,6 @@ struct hisi_zip_sqe_ops {
|
|
void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type);
|
|
void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req);
|
|
void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type);
|
|
- u32 (*get_tag)(struct hisi_zip_sqe *sqe);
|
|
u32 (*get_status)(struct hisi_zip_sqe *sqe);
|
|
u32 (*get_dstlen)(struct hisi_zip_sqe *sqe);
|
|
};
|
|
@@ -138,85 +106,8 @@ static u16 sgl_sge_nr = HZIP_SGL_SGE_NR;
|
|
module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444);
|
|
MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)");
|
|
|
|
-static u32 get_extra_field_size(const u8 *start)
|
|
-{
|
|
- return *((u16 *)start) + GZIP_HEAD_FEXTRA_XLEN;
|
|
-}
|
|
-
|
|
-static u32 get_name_field_size(const u8 *start)
|
|
-{
|
|
- return strlen(start) + 1;
|
|
-}
|
|
-
|
|
-static u32 get_comment_field_size(const u8 *start)
|
|
-{
|
|
- return strlen(start) + 1;
|
|
-}
|
|
-
|
|
-static u32 __get_gzip_head_size(const u8 *src)
|
|
-{
|
|
- u8 head_flg = *(src + GZIP_HEAD_FLG_SHIFT);
|
|
- u32 size = GZIP_HEAD_FEXTRA_SHIFT;
|
|
-
|
|
- if (head_flg & GZIP_HEAD_FEXTRA_BIT)
|
|
- size += get_extra_field_size(src + size);
|
|
- if (head_flg & GZIP_HEAD_FNAME_BIT)
|
|
- size += get_name_field_size(src + size);
|
|
- if (head_flg & GZIP_HEAD_FCOMMENT_BIT)
|
|
- size += get_comment_field_size(src + size);
|
|
- if (head_flg & GZIP_HEAD_FHCRC_BIT)
|
|
- size += GZIP_HEAD_FHCRC_SIZE;
|
|
-
|
|
- return size;
|
|
-}
|
|
-
|
|
-static u32 __maybe_unused get_gzip_head_size(struct scatterlist *sgl)
|
|
-{
|
|
- char buf[HZIP_GZIP_HEAD_BUF];
|
|
-
|
|
- sg_copy_to_buffer(sgl, sg_nents(sgl), buf, sizeof(buf));
|
|
-
|
|
- return __get_gzip_head_size(buf);
|
|
-}
|
|
-
|
|
-static int add_comp_head(struct scatterlist *dst, u8 req_type)
|
|
-{
|
|
- int head_size = TO_HEAD_SIZE(req_type);
|
|
- const u8 *head = TO_HEAD(req_type);
|
|
- int ret;
|
|
-
|
|
- ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size);
|
|
- if (unlikely(ret != head_size)) {
|
|
- pr_err("the head size of buffer is wrong (%d)!\n", ret);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- return head_size;
|
|
-}
|
|
-
|
|
-static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type)
|
|
-{
|
|
- if (unlikely(!acomp_req->src || !acomp_req->slen))
|
|
- return -EINVAL;
|
|
-
|
|
- if (unlikely(req_type == HZIP_ALG_TYPE_GZIP &&
|
|
- acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT))
|
|
- return -EINVAL;
|
|
-
|
|
- switch (req_type) {
|
|
- case HZIP_ALG_TYPE_ZLIB:
|
|
- return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB);
|
|
- case HZIP_ALG_TYPE_GZIP:
|
|
- return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP);
|
|
- default:
|
|
- pr_err("request type does not support!\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-}
|
|
-
|
|
-static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req,
|
|
- struct hisi_zip_qp_ctx *qp_ctx,
|
|
- size_t head_size, bool is_comp)
|
|
+static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx,
|
|
+ struct acomp_req *req)
|
|
{
|
|
struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
|
|
struct hisi_zip_req *q = req_q->q;
|
|
@@ -238,14 +129,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req,
|
|
req_cache = q + req_id;
|
|
req_cache->req_id = req_id;
|
|
req_cache->req = req;
|
|
-
|
|
- if (is_comp) {
|
|
- req_cache->sskip = 0;
|
|
- req_cache->dskip = head_size;
|
|
- } else {
|
|
- req_cache->sskip = head_size;
|
|
- req_cache->dskip = 0;
|
|
- }
|
|
+ req_cache->qp_ctx = qp_ctx;
|
|
|
|
return req_cache;
|
|
}
|
|
@@ -272,10 +156,8 @@ static void hisi_zip_fill_buf_size(struct hisi_zip_sqe *sqe, struct hisi_zip_req
|
|
{
|
|
struct acomp_req *a_req = req->req;
|
|
|
|
- sqe->input_data_length = a_req->slen - req->sskip;
|
|
- sqe->dest_avail_out = a_req->dlen - req->dskip;
|
|
- sqe->dw7 = FIELD_PREP(HZIP_IN_SGE_DATA_OFFSET_M, req->sskip);
|
|
- sqe->dw8 = FIELD_PREP(HZIP_OUT_SGE_DATA_OFFSET_M, req->dskip);
|
|
+ sqe->input_data_length = a_req->slen;
|
|
+ sqe->dest_avail_out = a_req->dlen;
|
|
}
|
|
|
|
static void hisi_zip_fill_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type)
|
|
@@ -296,14 +178,10 @@ static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type)
|
|
sqe->dw9 = val;
|
|
}
|
|
|
|
-static void hisi_zip_fill_tag_v1(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
|
|
-{
|
|
- sqe->dw13 = req->req_id;
|
|
-}
|
|
-
|
|
-static void hisi_zip_fill_tag_v2(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
|
|
+static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
|
|
{
|
|
- sqe->dw26 = req->req_id;
|
|
+ sqe->dw26 = lower_32_bits((u64)req);
|
|
+ sqe->dw27 = upper_32_bits((u64)req);
|
|
}
|
|
|
|
static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type)
|
|
@@ -330,8 +208,8 @@ static void hisi_zip_fill_sqe(struct hisi_zip_ctx *ctx, struct hisi_zip_sqe *sqe
|
|
ops->fill_sqe_type(sqe, ops->sqe_type);
|
|
}
|
|
|
|
-static int hisi_zip_do_work(struct hisi_zip_req *req,
|
|
- struct hisi_zip_qp_ctx *qp_ctx)
|
|
+static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx,
|
|
+ struct hisi_zip_req *req)
|
|
{
|
|
struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool;
|
|
struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
|
|
@@ -357,7 +235,7 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
|
|
&req->dma_dst);
|
|
if (IS_ERR(req->hw_dst)) {
|
|
ret = PTR_ERR(req->hw_dst);
|
|
- dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n",
|
|
+ dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n",
|
|
ret);
|
|
goto err_unmap_input;
|
|
}
|
|
@@ -383,16 +261,6 @@ err_unmap_input:
|
|
return ret;
|
|
}
|
|
|
|
-static u32 hisi_zip_get_tag_v1(struct hisi_zip_sqe *sqe)
|
|
-{
|
|
- return sqe->dw13;
|
|
-}
|
|
-
|
|
-static u32 hisi_zip_get_tag_v2(struct hisi_zip_sqe *sqe)
|
|
-{
|
|
- return sqe->dw26;
|
|
-}
|
|
-
|
|
static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe)
|
|
{
|
|
return sqe->dw3 & HZIP_BD_STATUS_M;
|
|
@@ -405,17 +273,15 @@ static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe)
|
|
|
|
static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
|
|
{
|
|
- struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx;
|
|
+ struct hisi_zip_sqe *sqe = data;
|
|
+ struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe);
|
|
+ struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx;
|
|
const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops;
|
|
struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
|
|
- struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
|
|
struct device *dev = &qp->qm->pdev->dev;
|
|
- struct hisi_zip_sqe *sqe = data;
|
|
- u32 tag = ops->get_tag(sqe);
|
|
- struct hisi_zip_req *req = req_q->q + tag;
|
|
struct acomp_req *acomp_req = req->req;
|
|
- u32 status, dlen, head_size;
|
|
int err = 0;
|
|
+ u32 status;
|
|
|
|
atomic64_inc(&dfx->recv_cnt);
|
|
status = ops->get_status(sqe);
|
|
@@ -427,13 +293,10 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
|
|
err = -EIO;
|
|
}
|
|
|
|
- dlen = ops->get_dstlen(sqe);
|
|
-
|
|
hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src);
|
|
hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst);
|
|
|
|
- head_size = (qp->alg_type == 0) ? TO_HEAD_SIZE(qp->req_type) : 0;
|
|
- acomp_req->dlen = dlen + head_size;
|
|
+ acomp_req->dlen = ops->get_dstlen(sqe);
|
|
|
|
if (acomp_req->base.complete)
|
|
acomp_request_complete(acomp_req, err);
|
|
@@ -447,22 +310,13 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req)
|
|
struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP];
|
|
struct device *dev = &qp_ctx->qp->qm->pdev->dev;
|
|
struct hisi_zip_req *req;
|
|
- int head_size;
|
|
int ret;
|
|
|
|
- /* let's output compression head now */
|
|
- head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type);
|
|
- if (unlikely(head_size < 0)) {
|
|
- dev_err_ratelimited(dev, "failed to add comp head (%d)!\n",
|
|
- head_size);
|
|
- return head_size;
|
|
- }
|
|
-
|
|
- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true);
|
|
+ req = hisi_zip_create_req(qp_ctx, acomp_req);
|
|
if (IS_ERR(req))
|
|
return PTR_ERR(req);
|
|
|
|
- ret = hisi_zip_do_work(req, qp_ctx);
|
|
+ ret = hisi_zip_do_work(qp_ctx, req);
|
|
if (unlikely(ret != -EINPROGRESS)) {
|
|
dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret);
|
|
hisi_zip_remove_req(qp_ctx, req);
|
|
@@ -477,20 +331,13 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req)
|
|
struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP];
|
|
struct device *dev = &qp_ctx->qp->qm->pdev->dev;
|
|
struct hisi_zip_req *req;
|
|
- int head_size, ret;
|
|
-
|
|
- head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type);
|
|
- if (unlikely(head_size < 0)) {
|
|
- dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n",
|
|
- head_size);
|
|
- return head_size;
|
|
- }
|
|
+ int ret;
|
|
|
|
- req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false);
|
|
+ req = hisi_zip_create_req(qp_ctx, acomp_req);
|
|
if (IS_ERR(req))
|
|
return PTR_ERR(req);
|
|
|
|
- ret = hisi_zip_do_work(req, qp_ctx);
|
|
+ ret = hisi_zip_do_work(qp_ctx, req);
|
|
if (unlikely(ret != -EINPROGRESS)) {
|
|
dev_info_ratelimited(dev, "failed to do decompress (%d)!\n",
|
|
ret);
|
|
@@ -527,28 +374,14 @@ static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *qp_ctx)
|
|
hisi_qm_free_qps(&qp_ctx->qp, 1);
|
|
}
|
|
|
|
-static const struct hisi_zip_sqe_ops hisi_zip_ops_v1 = {
|
|
- .sqe_type = 0,
|
|
- .fill_addr = hisi_zip_fill_addr,
|
|
- .fill_buf_size = hisi_zip_fill_buf_size,
|
|
- .fill_buf_type = hisi_zip_fill_buf_type,
|
|
- .fill_req_type = hisi_zip_fill_req_type,
|
|
- .fill_tag = hisi_zip_fill_tag_v1,
|
|
- .fill_sqe_type = hisi_zip_fill_sqe_type,
|
|
- .get_tag = hisi_zip_get_tag_v1,
|
|
- .get_status = hisi_zip_get_status,
|
|
- .get_dstlen = hisi_zip_get_dstlen,
|
|
-};
|
|
-
|
|
-static const struct hisi_zip_sqe_ops hisi_zip_ops_v2 = {
|
|
+static const struct hisi_zip_sqe_ops hisi_zip_ops = {
|
|
.sqe_type = 0x3,
|
|
.fill_addr = hisi_zip_fill_addr,
|
|
.fill_buf_size = hisi_zip_fill_buf_size,
|
|
.fill_buf_type = hisi_zip_fill_buf_type,
|
|
.fill_req_type = hisi_zip_fill_req_type,
|
|
- .fill_tag = hisi_zip_fill_tag_v2,
|
|
+ .fill_tag = hisi_zip_fill_tag,
|
|
.fill_sqe_type = hisi_zip_fill_sqe_type,
|
|
- .get_tag = hisi_zip_get_tag_v2,
|
|
.get_status = hisi_zip_get_status,
|
|
.get_dstlen = hisi_zip_get_dstlen,
|
|
};
|
|
@@ -584,10 +417,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int
|
|
qp_ctx->zip_dev = hisi_zip;
|
|
}
|
|
|
|
- if (hisi_zip->qm.ver < QM_HW_V3)
|
|
- hisi_zip_ctx->ops = &hisi_zip_ops_v1;
|
|
- else
|
|
- hisi_zip_ctx->ops = &hisi_zip_ops_v2;
|
|
+ hisi_zip_ctx->ops = &hisi_zip_ops;
|
|
|
|
return 0;
|
|
}
|
|
@@ -739,101 +569,53 @@ static void hisi_zip_acomp_exit(struct crypto_acomp *tfm)
|
|
{
|
|
struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base);
|
|
|
|
- hisi_zip_set_acomp_cb(ctx, NULL);
|
|
hisi_zip_release_sgl_pool(ctx);
|
|
hisi_zip_release_req_q(ctx);
|
|
hisi_zip_ctx_exit(ctx);
|
|
}
|
|
|
|
-static struct acomp_alg hisi_zip_acomp_zlib = {
|
|
+static struct acomp_alg hisi_zip_acomp_deflate = {
|
|
.init = hisi_zip_acomp_init,
|
|
.exit = hisi_zip_acomp_exit,
|
|
.compress = hisi_zip_acompress,
|
|
.decompress = hisi_zip_adecompress,
|
|
.base = {
|
|
- .cra_name = "zlib-deflate",
|
|
- .cra_driver_name = "hisi-zlib-acomp",
|
|
+ .cra_name = "deflate",
|
|
+ .cra_driver_name = "hisi-deflate-acomp",
|
|
.cra_module = THIS_MODULE,
|
|
- .cra_priority = HZIP_ALG_PRIORITY,
|
|
+ .cra_priority = HZIP_ALG_PRIORITY,
|
|
.cra_ctxsize = sizeof(struct hisi_zip_ctx),
|
|
}
|
|
};
|
|
|
|
-static int hisi_zip_register_zlib(struct hisi_qm *qm)
|
|
+static int hisi_zip_register_deflate(struct hisi_qm *qm)
|
|
{
|
|
int ret;
|
|
|
|
- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB))
|
|
+ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE))
|
|
return 0;
|
|
|
|
- ret = crypto_register_acomp(&hisi_zip_acomp_zlib);
|
|
+ ret = crypto_register_acomp(&hisi_zip_acomp_deflate);
|
|
if (ret)
|
|
- dev_err(&qm->pdev->dev, "failed to register to zlib (%d)!\n", ret);
|
|
+ dev_err(&qm->pdev->dev, "failed to register to deflate (%d)!\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
-static void hisi_zip_unregister_zlib(struct hisi_qm *qm)
|
|
+static void hisi_zip_unregister_deflate(struct hisi_qm *qm)
|
|
{
|
|
- if (!hisi_zip_alg_support(qm, HZIP_ALG_ZLIB))
|
|
+ if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE))
|
|
return;
|
|
|
|
- crypto_unregister_acomp(&hisi_zip_acomp_zlib);
|
|
-}
|
|
-
|
|
-static struct acomp_alg hisi_zip_acomp_gzip = {
|
|
- .init = hisi_zip_acomp_init,
|
|
- .exit = hisi_zip_acomp_exit,
|
|
- .compress = hisi_zip_acompress,
|
|
- .decompress = hisi_zip_adecompress,
|
|
- .base = {
|
|
- .cra_name = "gzip",
|
|
- .cra_driver_name = "hisi-gzip-acomp",
|
|
- .cra_module = THIS_MODULE,
|
|
- .cra_priority = HZIP_ALG_PRIORITY,
|
|
- .cra_ctxsize = sizeof(struct hisi_zip_ctx),
|
|
- }
|
|
-};
|
|
-
|
|
-static int hisi_zip_register_gzip(struct hisi_qm *qm)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP))
|
|
- return 0;
|
|
-
|
|
- ret = crypto_register_acomp(&hisi_zip_acomp_gzip);
|
|
- if (ret)
|
|
- dev_err(&qm->pdev->dev, "failed to register to gzip (%d)!\n", ret);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static void hisi_zip_unregister_gzip(struct hisi_qm *qm)
|
|
-{
|
|
- if (!hisi_zip_alg_support(qm, HZIP_ALG_GZIP))
|
|
- return;
|
|
-
|
|
- crypto_unregister_acomp(&hisi_zip_acomp_gzip);
|
|
+ crypto_unregister_acomp(&hisi_zip_acomp_deflate);
|
|
}
|
|
|
|
int hisi_zip_register_to_crypto(struct hisi_qm *qm)
|
|
{
|
|
- int ret = 0;
|
|
-
|
|
- ret = hisi_zip_register_zlib(qm);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = hisi_zip_register_gzip(qm);
|
|
- if (ret)
|
|
- hisi_zip_unregister_zlib(qm);
|
|
-
|
|
- return ret;
|
|
+ return hisi_zip_register_deflate(qm);
|
|
}
|
|
|
|
void hisi_zip_unregister_from_crypto(struct hisi_qm *qm)
|
|
{
|
|
- hisi_zip_unregister_zlib(qm);
|
|
- hisi_zip_unregister_gzip(qm);
|
|
+ hisi_zip_unregister_deflate(qm);
|
|
}
|
|
diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c
|
|
index b70aa6032874e1..91212d9584bf54 100644
|
|
--- a/drivers/crypto/hisilicon/zip/zip_main.c
|
|
+++ b/drivers/crypto/hisilicon/zip/zip_main.c
|
|
@@ -238,8 +238,8 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = {
|
|
{ZIP_CLUSTER_DECOMP_NUM_CAP, 0x313C, 0, GENMASK(7, 0), 0x6, 0x6, 0x3},
|
|
{ZIP_DECOMP_ENABLE_BITMAP, 0x3140, 16, GENMASK(15, 0), 0xFC, 0xFC, 0x1C},
|
|
{ZIP_COMP_ENABLE_BITMAP, 0x3140, 0, GENMASK(15, 0), 0x3, 0x3, 0x3},
|
|
- {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0xF, 0xF, 0xF},
|
|
- {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0xFF},
|
|
+ {ZIP_DRV_ALG_BITMAP, 0x3144, 0, GENMASK(31, 0), 0x0, 0x0, 0x30},
|
|
+ {ZIP_DEV_ALG_BITMAP, 0x3148, 0, GENMASK(31, 0), 0xF, 0xF, 0x3F},
|
|
{ZIP_CORE1_ALG_BITMAP, 0x314C, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5},
|
|
{ZIP_CORE2_ALG_BITMAP, 0x3150, 0, GENMASK(31, 0), 0x5, 0x5, 0xD5},
|
|
{ZIP_CORE3_ALG_BITMAP, 0x3154, 0, GENMASK(31, 0), 0xA, 0xA, 0x2A},
|
|
diff --git a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c
|
|
index 388e58bcbcaf26..4a1ea3e720329c 100644
|
|
--- a/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c
|
|
+++ b/drivers/crypto/intel/qat/qat_common/adf_pfvf_pf_proto.c
|
|
@@ -148,6 +148,16 @@ static struct pfvf_message handle_blkmsg_req(struct adf_accel_vf_info *vf_info,
|
|
blk_byte = FIELD_GET(ADF_VF2PF_SMALL_BLOCK_BYTE_MASK, req.data);
|
|
byte_max = ADF_VF2PF_SMALL_BLOCK_BYTE_MAX;
|
|
break;
|
|
+ default:
|
|
+ dev_err(&GET_DEV(vf_info->accel_dev),
|
|
+ "Invalid BlockMsg type 0x%.4x received from VF%u\n",
|
|
+ req.type, vf_info->vf_nr);
|
|
+ resp.type = ADF_PF2VF_MSGTYPE_BLKMSG_RESP;
|
|
+ resp.data = FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_TYPE_MASK,
|
|
+ ADF_PF2VF_BLKMSG_RESP_TYPE_ERROR) |
|
|
+ FIELD_PREP(ADF_PF2VF_BLKMSG_RESP_DATA_MASK,
|
|
+ ADF_PF2VF_UNSPECIFIED_ERROR);
|
|
+ return resp;
|
|
}
|
|
|
|
/* Is this a request for CRC or data? */
|
|
diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c
|
|
index 88a41d1ca5f644..6c0bfb3ea1c9f2 100644
|
|
--- a/drivers/crypto/marvell/octeontx/otx_cptvf_main.c
|
|
+++ b/drivers/crypto/marvell/octeontx/otx_cptvf_main.c
|
|
@@ -168,7 +168,8 @@ static void free_command_queues(struct otx_cptvf *cptvf,
|
|
chunk = list_first_entry(&cqinfo->queue[i].chead,
|
|
struct otx_cpt_cmd_chunk, nextchunk);
|
|
|
|
- dma_free_coherent(&pdev->dev, chunk->size,
|
|
+ dma_free_coherent(&pdev->dev,
|
|
+ chunk->size + OTX_CPT_NEXT_CHUNK_PTR_SIZE,
|
|
chunk->head,
|
|
chunk->dma_addr);
|
|
chunk->head = NULL;
|
|
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
|
|
index 36b20b844b109a..f9738c863df0e1 100644
|
|
--- a/drivers/cxl/core/hdm.c
|
|
+++ b/drivers/cxl/core/hdm.c
|
|
@@ -710,14 +710,13 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld)
|
|
writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
|
|
up_read(&cxl_dpa_rwsem);
|
|
|
|
- port->commit_end++;
|
|
rc = cxld_await_commit(hdm, cxld->id);
|
|
if (rc) {
|
|
dev_dbg(&port->dev, "%s: error %d committing decoder\n",
|
|
dev_name(&cxld->dev), rc);
|
|
- cxld->reset(cxld);
|
|
return rc;
|
|
}
|
|
+ port->commit_end++;
|
|
cxld->flags |= CXL_DECODER_F_ENABLE;
|
|
|
|
return 0;
|
|
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
|
|
index 4f426be2868843..93e00130400df2 100644
|
|
--- a/drivers/dma/dma-axi-dmac.c
|
|
+++ b/drivers/dma/dma-axi-dmac.c
|
|
@@ -225,6 +225,7 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
|
|
return;
|
|
list_move_tail(&vdesc->node, &chan->active_descs);
|
|
desc = to_axi_dmac_desc(vdesc);
|
|
+ chan->next_desc = desc;
|
|
}
|
|
sg = &desc->sg[desc->num_submitted];
|
|
|
|
@@ -242,8 +243,6 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
|
|
else
|
|
chan->next_desc = NULL;
|
|
flags |= AXI_DMAC_FLAG_LAST;
|
|
- } else {
|
|
- chan->next_desc = desc;
|
|
}
|
|
|
|
sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID);
|
|
diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
|
|
index eccbcf67951fbe..34b194759d218e 100644
|
|
--- a/drivers/dma/fsl-edma-main.c
|
|
+++ b/drivers/dma/fsl-edma-main.c
|
|
@@ -669,7 +669,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
|
|
return 0;
|
|
}
|
|
|
|
-static int fsl_edma_remove(struct platform_device *pdev)
|
|
+static void fsl_edma_remove(struct platform_device *pdev)
|
|
{
|
|
struct device_node *np = pdev->dev.of_node;
|
|
struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
|
|
@@ -678,9 +678,6 @@ static int fsl_edma_remove(struct platform_device *pdev)
|
|
of_dma_controller_free(np);
|
|
dma_async_device_unregister(&fsl_edma->dma_dev);
|
|
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
|
|
- fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
|
|
-
|
|
- return 0;
|
|
}
|
|
|
|
static int fsl_edma_suspend_late(struct device *dev)
|
|
@@ -749,7 +746,7 @@ static struct platform_driver fsl_edma_driver = {
|
|
.pm = &fsl_edma_pm_ops,
|
|
},
|
|
.probe = fsl_edma_probe,
|
|
- .remove = fsl_edma_remove,
|
|
+ .remove_new = fsl_edma_remove,
|
|
};
|
|
|
|
static int __init fsl_edma_init(void)
|
|
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
|
|
index 06d12ac39144f4..aa42a09fde1a68 100644
|
|
--- a/drivers/dma/mediatek/mtk-uart-apdma.c
|
|
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
|
|
@@ -41,7 +41,7 @@
|
|
#define VFF_STOP_CLR_B 0
|
|
#define VFF_EN_CLR_B 0
|
|
#define VFF_INT_EN_CLR_B 0
|
|
-#define VFF_4G_SUPPORT_CLR_B 0
|
|
+#define VFF_ADDR2_CLR_B 0
|
|
|
|
/*
|
|
* interrupt trigger level for tx
|
|
@@ -72,7 +72,7 @@
|
|
/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
|
|
#define VFF_LEFT_SIZE 0x40
|
|
#define VFF_DEBUG_STATUS 0x50
|
|
-#define VFF_4G_SUPPORT 0x54
|
|
+#define VFF_ADDR2 0x54
|
|
|
|
struct mtk_uart_apdmadev {
|
|
struct dma_device ddev;
|
|
@@ -149,7 +149,7 @@ static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
|
|
mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
|
|
|
|
if (mtkd->support_33bits)
|
|
- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
|
|
+ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr));
|
|
}
|
|
|
|
mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
|
|
@@ -192,7 +192,7 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
|
|
mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
|
|
|
|
if (mtkd->support_33bits)
|
|
- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
|
|
+ mtk_uart_apdma_write(c, VFF_ADDR2, upper_32_bits(d->addr));
|
|
}
|
|
|
|
mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B);
|
|
@@ -298,7 +298,7 @@ static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
|
|
}
|
|
|
|
if (mtkd->support_33bits)
|
|
- mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
|
|
+ mtk_uart_apdma_write(c, VFF_ADDR2, VFF_ADDR2_CLR_B);
|
|
|
|
err_pm:
|
|
pm_runtime_put_noidle(mtkd->ddev.dev);
|
|
diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
|
|
index f414efdbd809e1..87956563cb1d35 100644
|
|
--- a/drivers/dma/stm32-mdma.c
|
|
+++ b/drivers/dma/stm32-mdma.c
|
|
@@ -732,7 +732,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
|
|
struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
|
|
struct scatterlist *sg;
|
|
dma_addr_t src_addr, dst_addr;
|
|
- u32 m2m_hw_period, ccr, ctcr, ctbr;
|
|
+ u32 m2m_hw_period = 0, ccr = 0, ctcr, ctbr;
|
|
int i, ret = 0;
|
|
|
|
if (chan_config->m2m_hw)
|
|
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
|
|
index 2469efddf54015..6a384bd469528e 100644
|
|
--- a/drivers/dma/sun6i-dma.c
|
|
+++ b/drivers/dma/sun6i-dma.c
|
|
@@ -582,6 +582,22 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
|
|
return ret;
|
|
}
|
|
|
|
+static u32 find_burst_size(const u32 burst_lengths, u32 maxburst)
|
|
+{
|
|
+ if (!maxburst)
|
|
+ return 1;
|
|
+
|
|
+ if (BIT(maxburst) & burst_lengths)
|
|
+ return maxburst;
|
|
+
|
|
+ /* Hardware only does power-of-two bursts. */
|
|
+ for (u32 burst = rounddown_pow_of_two(maxburst); burst > 0; burst /= 2)
|
|
+ if (BIT(burst) & burst_lengths)
|
|
+ return burst;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
static int set_config(struct sun6i_dma_dev *sdev,
|
|
struct dma_slave_config *sconfig,
|
|
enum dma_transfer_direction direction,
|
|
@@ -615,15 +631,13 @@ static int set_config(struct sun6i_dma_dev *sdev,
|
|
return -EINVAL;
|
|
if (!(BIT(dst_addr_width) & sdev->slave.dst_addr_widths))
|
|
return -EINVAL;
|
|
- if (!(BIT(src_maxburst) & sdev->cfg->src_burst_lengths))
|
|
- return -EINVAL;
|
|
- if (!(BIT(dst_maxburst) & sdev->cfg->dst_burst_lengths))
|
|
- return -EINVAL;
|
|
|
|
src_width = convert_buswidth(src_addr_width);
|
|
dst_width = convert_buswidth(dst_addr_width);
|
|
- dst_burst = convert_burst(dst_maxburst);
|
|
- src_burst = convert_burst(src_maxburst);
|
|
+ src_burst = find_burst_size(sdev->cfg->src_burst_lengths, src_maxburst);
|
|
+ dst_burst = find_burst_size(sdev->cfg->dst_burst_lengths, dst_maxburst);
|
|
+ dst_burst = convert_burst(dst_burst);
|
|
+ src_burst = convert_burst(src_burst);
|
|
|
|
*p_cfg = DMA_CHAN_CFG_SRC_WIDTH(src_width) |
|
|
DMA_CHAN_CFG_DST_WIDTH(dst_width);
|
|
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
|
|
index 4f8f87207b67b8..dc1915ffc3cbe2 100644
|
|
--- a/drivers/edac/altera_edac.c
|
|
+++ b/drivers/edac/altera_edac.c
|
|
@@ -1573,8 +1573,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|
goto err_release_group_1;
|
|
}
|
|
rc = devm_request_irq(&altdev->ddev, altdev->sb_irq,
|
|
- prv->ecc_irq_handler,
|
|
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
|
+ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH,
|
|
ecc_name, altdev);
|
|
if (rc) {
|
|
edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n");
|
|
@@ -1597,8 +1596,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|
goto err_release_group_1;
|
|
}
|
|
rc = devm_request_irq(&altdev->ddev, altdev->db_irq,
|
|
- prv->ecc_irq_handler,
|
|
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
|
+ prv->ecc_irq_handler, IRQF_TRIGGER_HIGH,
|
|
ecc_name, altdev);
|
|
if (rc) {
|
|
edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
|
|
@@ -1981,8 +1979,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
|
|
goto err_release_group1;
|
|
}
|
|
rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler,
|
|
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
|
- ecc_name, altdev);
|
|
+ IRQF_TRIGGER_HIGH, ecc_name, altdev);
|
|
if (rc) {
|
|
edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
|
|
goto err_release_group1;
|
|
@@ -2004,7 +2001,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
|
|
goto err_release_group1;
|
|
}
|
|
rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler,
|
|
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
|
+ IRQF_TRIGGER_HIGH,
|
|
ecc_name, altdev);
|
|
if (rc) {
|
|
edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
|
|
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
|
|
index 4b5a71f8739d90..8c6a291e01f6a4 100644
|
|
--- a/drivers/edac/i5000_edac.c
|
|
+++ b/drivers/edac/i5000_edac.c
|
|
@@ -1111,6 +1111,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
|
|
|
|
n = snprintf(p, space, " ");
|
|
p += n;
|
|
+ space -= n;
|
|
for (branch = 0; branch < MAX_BRANCHES; branch++) {
|
|
n = snprintf(p, space, " branch %d | ", branch);
|
|
p += n;
|
|
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
|
|
index 49b4499269fb75..68afb3bb8e290e 100644
|
|
--- a/drivers/edac/i5400_edac.c
|
|
+++ b/drivers/edac/i5400_edac.c
|
|
@@ -1025,13 +1025,13 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
|
|
space -= n;
|
|
}
|
|
|
|
- space -= n;
|
|
edac_dbg(2, "%s\n", mem_buffer);
|
|
p = mem_buffer;
|
|
space = PAGE_SIZE;
|
|
|
|
n = snprintf(p, space, " ");
|
|
p += n;
|
|
+ space -= n;
|
|
for (branch = 0; branch < MAX_BRANCHES; branch++) {
|
|
n = snprintf(p, space, " branch %d | ", branch);
|
|
p += n;
|
|
diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c
|
|
index 52d18490b59e33..70e1735dfcdd41 100644
|
|
--- a/drivers/firmware/efi/cper-arm.c
|
|
+++ b/drivers/firmware/efi/cper-arm.c
|
|
@@ -226,7 +226,8 @@ static void cper_print_arm_err_info(const char *pfx, u32 type,
|
|
}
|
|
|
|
void cper_print_proc_arm(const char *pfx,
|
|
- const struct cper_sec_proc_arm *proc)
|
|
+ const struct cper_sec_proc_arm *proc,
|
|
+ u32 length)
|
|
{
|
|
int i, len, max_ctx_type;
|
|
struct cper_arm_err_info *err_info;
|
|
@@ -238,9 +239,12 @@ void cper_print_proc_arm(const char *pfx,
|
|
|
|
len = proc->section_length - (sizeof(*proc) +
|
|
proc->err_info_num * (sizeof(*err_info)));
|
|
- if (len < 0) {
|
|
- printk("%ssection length: %d\n", pfx, proc->section_length);
|
|
- printk("%ssection length is too small\n", pfx);
|
|
+
|
|
+ if (len < 0 || proc->section_length > length) {
|
|
+ printk("%ssection length: %d, CPER size: %d\n",
|
|
+ pfx, proc->section_length, length);
|
|
+ printk("%ssection length is too %s\n", pfx,
|
|
+ (len < 0) ? "small" : "big");
|
|
printk("%sfirmware-generated error record is incorrect\n", pfx);
|
|
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
|
|
return;
|
|
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
|
|
index 74ffaf44d74ce1..9d0f0bf3067ccb 100644
|
|
--- a/drivers/firmware/efi/cper.c
|
|
+++ b/drivers/firmware/efi/cper.c
|
|
@@ -555,6 +555,11 @@ static void cper_print_fw_err(const char *pfx,
|
|
} else {
|
|
offset = sizeof(*fw_err);
|
|
}
|
|
+ if (offset > length) {
|
|
+ printk("%s""error section length is too small: offset=%d, length=%d\n",
|
|
+ pfx, offset, length);
|
|
+ return;
|
|
+ }
|
|
|
|
buf += offset;
|
|
length -= offset;
|
|
@@ -635,7 +640,8 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
|
|
|
|
printk("%ssection_type: ARM processor error\n", newpfx);
|
|
if (gdata->error_data_length >= sizeof(*arm_err))
|
|
- cper_print_proc_arm(newpfx, arm_err);
|
|
+ cper_print_proc_arm(newpfx, arm_err,
|
|
+ gdata->error_data_length);
|
|
else
|
|
goto err_section_too_small;
|
|
#endif
|
|
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
|
|
index 1ab161e00c8679..ef55e3851b3623 100644
|
|
--- a/drivers/firmware/efi/efi.c
|
|
+++ b/drivers/firmware/efi/efi.c
|
|
@@ -648,13 +648,13 @@ static __init int match_config_table(const efi_guid_t *guid,
|
|
|
|
static __init void reserve_unaccepted(struct efi_unaccepted_memory *unaccepted)
|
|
{
|
|
- phys_addr_t start, size;
|
|
+ phys_addr_t start, end;
|
|
|
|
start = PAGE_ALIGN_DOWN(efi.unaccepted);
|
|
- size = PAGE_ALIGN(sizeof(*unaccepted) + unaccepted->size);
|
|
+ end = PAGE_ALIGN(efi.unaccepted + sizeof(*unaccepted) + unaccepted->size);
|
|
|
|
- memblock_add(start, size);
|
|
- memblock_reserve(start, size);
|
|
+ memblock_add(start, end - start);
|
|
+ memblock_reserve(start, end - start);
|
|
}
|
|
|
|
int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
|
|
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
|
|
index dd7a783d53b5f4..f1ced28793d2ad 100644
|
|
--- a/drivers/fpga/dfl.c
|
|
+++ b/drivers/fpga/dfl.c
|
|
@@ -2029,7 +2029,7 @@ static void __exit dfl_fpga_exit(void)
|
|
bus_unregister(&dfl_bus_type);
|
|
}
|
|
|
|
-module_init(dfl_fpga_init);
|
|
+subsys_initcall(dfl_fpga_init);
|
|
module_exit(dfl_fpga_exit);
|
|
|
|
MODULE_DESCRIPTION("FPGA Device Feature List (DFL) Support");
|
|
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
|
|
index a6affd83f27578..ed6eae98511794 100644
|
|
--- a/drivers/fpga/of-fpga-region.c
|
|
+++ b/drivers/fpga/of-fpga-region.c
|
|
@@ -83,7 +83,7 @@ static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np)
|
|
* done with the bridges.
|
|
*
|
|
* Return: 0 for success (even if there are no bridges specified)
|
|
- * or -EBUSY if any of the bridges are in use.
|
|
+ * or an error code if any of the bridges are not available.
|
|
*/
|
|
static int of_fpga_region_get_bridges(struct fpga_region *region)
|
|
{
|
|
@@ -130,10 +130,10 @@ static int of_fpga_region_get_bridges(struct fpga_region *region)
|
|
®ion->bridge_list);
|
|
of_node_put(br);
|
|
|
|
- /* If any of the bridges are in use, give up */
|
|
- if (ret == -EBUSY) {
|
|
+ /* If any of the bridges are not available, give up */
|
|
+ if (ret) {
|
|
fpga_bridges_put(®ion->bridge_list);
|
|
- return -EBUSY;
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c
|
|
index 72755fee647847..e69a6ce7be3fbb 100644
|
|
--- a/drivers/gpio/gpio-aspeed-sgpio.c
|
|
+++ b/drivers/gpio/gpio-aspeed-sgpio.c
|
|
@@ -534,7 +534,7 @@ static const struct of_device_id aspeed_sgpio_of_table[] = {
|
|
|
|
MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
|
|
|
|
-static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|
+static int aspeed_sgpio_probe(struct platform_device *pdev)
|
|
{
|
|
u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
|
|
const struct aspeed_sgpio_pdata *pdata;
|
|
@@ -629,11 +629,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|
}
|
|
|
|
static struct platform_driver aspeed_sgpio_driver = {
|
|
+ .probe = aspeed_sgpio_probe,
|
|
.driver = {
|
|
.name = KBUILD_MODNAME,
|
|
.of_match_table = aspeed_sgpio_of_table,
|
|
},
|
|
};
|
|
|
|
-module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
|
|
+module_platform_driver(aspeed_sgpio_driver);
|
|
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
|
|
index 8b2f2b921d9de3..7730e56444934f 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
|
|
@@ -1128,8 +1128,10 @@ static int amdgpu_acpi_enumerate_xcc(void)
|
|
if (!dev_info)
|
|
ret = amdgpu_acpi_dev_init(&dev_info, xcc_info, bdf);
|
|
|
|
- if (ret == -ENOMEM)
|
|
+ if (ret == -ENOMEM) {
|
|
+ kfree(xcc_info);
|
|
return ret;
|
|
+ }
|
|
|
|
if (!dev_info) {
|
|
kfree(xcc_info);
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
|
|
index 2e492f779b54ce..5c4aa5ff873b6c 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
|
|
@@ -2491,6 +2491,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|
case IP_VERSION(6, 0, 0):
|
|
case IP_VERSION(6, 0, 1):
|
|
case IP_VERSION(6, 1, 0):
|
|
+ case IP_VERSION(6, 1, 1):
|
|
adev->hdp.funcs = &hdp_v6_0_funcs;
|
|
break;
|
|
default:
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
index e9adfc88a54ab1..8175d831abd4d4 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
@@ -65,7 +65,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
|
|
DRM_ERROR("Process information: process %s pid %d thread %s pid %d\n",
|
|
ti.process_name, ti.tgid, ti.task_name, ti.pid);
|
|
|
|
- dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
|
|
+ if (dma_fence_get_status(&s_job->s_fence->finished) == 0)
|
|
+ dma_fence_set_error(&s_job->s_fence->finished, -ETIME);
|
|
|
|
if (amdgpu_device_should_recover_gpu(ring->adev)) {
|
|
struct amdgpu_reset_context reset_context;
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
|
|
index 08886e0ee6428b..2ef87646e6bb14 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
|
|
@@ -656,7 +656,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
|
|
ras_intr = amdgpu_ras_intr_triggered();
|
|
if (ras_intr)
|
|
break;
|
|
- usleep_range(10, 100);
|
|
+ usleep_range(60, 100);
|
|
amdgpu_device_invalidate_hdp(psp->adev, NULL);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
|
|
index 7cba98f8bbdca8..4214bbd7a1a236 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
|
|
@@ -2673,7 +2673,7 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
|
|
* to handle fatal error */
|
|
r = amdgpu_nbio_ras_sw_init(adev);
|
|
if (r)
|
|
- return r;
|
|
+ goto release_con;
|
|
|
|
if (adev->nbio.ras &&
|
|
adev->nbio.ras->init_ras_controller_interrupt) {
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
|
|
index 18794394c5a052..2505951ad06a09 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
|
|
@@ -1862,7 +1862,8 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev)
|
|
struct mmsch_v2_0_cmd_end end = { {0} };
|
|
struct mmsch_v2_0_init_header *header;
|
|
uint32_t *init_table = adev->virt.mm_table.cpu_addr;
|
|
- uint8_t i = 0;
|
|
+
|
|
+ /* This path only programs VCN instance 0. */
|
|
|
|
header = (struct mmsch_v2_0_init_header *)init_table;
|
|
direct_wt.cmd_header.command_type = MMSCH_COMMAND__DIRECT_REG_WRITE;
|
|
@@ -1881,93 +1882,93 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev)
|
|
size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
|
|
|
|
MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_STATUS),
|
|
0xFFFFFFFF, 0x00000004);
|
|
|
|
/* mc resume*/
|
|
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
|
|
adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo);
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
|
|
adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi);
|
|
offset = 0;
|
|
} else {
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW),
|
|
lower_32_bits(adev->vcn.inst->gpu_addr));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH),
|
|
upper_32_bits(adev->vcn.inst->gpu_addr));
|
|
offset = size;
|
|
}
|
|
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET0),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0),
|
|
0);
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE0),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE0),
|
|
size);
|
|
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW),
|
|
lower_32_bits(adev->vcn.inst->gpu_addr + offset));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH),
|
|
upper_32_bits(adev->vcn.inst->gpu_addr + offset));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET1),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1),
|
|
0);
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE1),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE1),
|
|
AMDGPU_VCN_STACK_SIZE);
|
|
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW),
|
|
lower_32_bits(adev->vcn.inst->gpu_addr + offset +
|
|
AMDGPU_VCN_STACK_SIZE));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH),
|
|
upper_32_bits(adev->vcn.inst->gpu_addr + offset +
|
|
AMDGPU_VCN_STACK_SIZE));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_OFFSET2),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2),
|
|
0);
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_VCPU_CACHE_SIZE2),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_VCPU_CACHE_SIZE2),
|
|
AMDGPU_VCN_CONTEXT_SIZE);
|
|
|
|
for (r = 0; r < adev->vcn.num_enc_rings; ++r) {
|
|
ring = &adev->vcn.inst->ring_enc[r];
|
|
ring->wptr = 0;
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_LO),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_LO),
|
|
lower_32_bits(ring->gpu_addr));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_BASE_HI),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_BASE_HI),
|
|
upper_32_bits(ring->gpu_addr));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_RB_SIZE),
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_RB_SIZE),
|
|
ring->ring_size / 4);
|
|
}
|
|
|
|
ring = &adev->vcn.inst->ring_dec;
|
|
ring->wptr = 0;
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_RBC_RB_64BIT_BAR_LOW),
|
|
lower_32_bits(ring->gpu_addr));
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i,
|
|
+ SOC15_REG_OFFSET(UVD, 0,
|
|
mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH),
|
|
upper_32_bits(ring->gpu_addr));
|
|
/* force RBC into idle state */
|
|
@@ -1978,7 +1979,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev)
|
|
tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
|
|
tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
|
|
MMSCH_V2_0_INSERT_DIRECT_WT(
|
|
- SOC15_REG_OFFSET(UVD, i, mmUVD_RBC_RB_CNTL), tmp);
|
|
+ SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), tmp);
|
|
|
|
/* add end packet */
|
|
tmp = sizeof(struct mmsch_v2_0_cmd_end);
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
|
|
index 9c32c64c407fa9..267650dcced9d1 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c
|
|
@@ -381,47 +381,45 @@ static int kfd_dbg_get_dev_watch_id(struct kfd_process_device *pdd, int *watch_i
|
|
|
|
*watch_id = KFD_DEBUGGER_INVALID_WATCH_POINT_ID;
|
|
|
|
- spin_lock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_lock(&pdd->dev->watch_points_lock);
|
|
|
|
for (i = 0; i < MAX_WATCH_ADDRESSES; i++) {
|
|
/* device watchpoint in use so skip */
|
|
- if ((pdd->dev->kfd->alloc_watch_ids >> i) & 0x1)
|
|
+ if ((pdd->dev->alloc_watch_ids >> i) & 0x1)
|
|
continue;
|
|
|
|
pdd->alloc_watch_ids |= 0x1 << i;
|
|
- pdd->dev->kfd->alloc_watch_ids |= 0x1 << i;
|
|
+ pdd->dev->alloc_watch_ids |= 0x1 << i;
|
|
*watch_id = i;
|
|
- spin_unlock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_unlock(&pdd->dev->watch_points_lock);
|
|
return 0;
|
|
}
|
|
|
|
- spin_unlock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_unlock(&pdd->dev->watch_points_lock);
|
|
|
|
return -ENOMEM;
|
|
}
|
|
|
|
-static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
|
|
+static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
|
|
{
|
|
- spin_lock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_lock(&pdd->dev->watch_points_lock);
|
|
|
|
/* process owns device watch point so safe to clear */
|
|
- if ((pdd->alloc_watch_ids >> watch_id) & 0x1) {
|
|
- pdd->alloc_watch_ids &= ~(0x1 << watch_id);
|
|
- pdd->dev->kfd->alloc_watch_ids &= ~(0x1 << watch_id);
|
|
+ if (pdd->alloc_watch_ids & BIT(watch_id)) {
|
|
+ pdd->alloc_watch_ids &= ~BIT(watch_id);
|
|
+ pdd->dev->alloc_watch_ids &= ~BIT(watch_id);
|
|
}
|
|
|
|
- spin_unlock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_unlock(&pdd->dev->watch_points_lock);
|
|
}
|
|
|
|
-static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
|
|
+static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
|
|
{
|
|
bool owns_watch_id = false;
|
|
|
|
- spin_lock(&pdd->dev->kfd->watch_points_lock);
|
|
- owns_watch_id = watch_id < MAX_WATCH_ADDRESSES &&
|
|
- ((pdd->alloc_watch_ids >> watch_id) & 0x1);
|
|
-
|
|
- spin_unlock(&pdd->dev->kfd->watch_points_lock);
|
|
+ spin_lock(&pdd->dev->watch_points_lock);
|
|
+ owns_watch_id = pdd->alloc_watch_ids & BIT(watch_id);
|
|
+ spin_unlock(&pdd->dev->watch_points_lock);
|
|
|
|
return owns_watch_id;
|
|
}
|
|
@@ -431,6 +429,9 @@ int kfd_dbg_trap_clear_dev_address_watch(struct kfd_process_device *pdd,
|
|
{
|
|
int r;
|
|
|
|
+ if (watch_id >= MAX_WATCH_ADDRESSES)
|
|
+ return -EINVAL;
|
|
+
|
|
if (!kfd_dbg_owns_dev_watch_id(pdd, watch_id))
|
|
return -EINVAL;
|
|
|
|
@@ -468,6 +469,9 @@ int kfd_dbg_trap_set_dev_address_watch(struct kfd_process_device *pdd,
|
|
if (r)
|
|
return r;
|
|
|
|
+ if (*watch_id >= MAX_WATCH_ADDRESSES)
|
|
+ return -EINVAL;
|
|
+
|
|
if (!pdd->dev->kfd->shared_resources.enable_mes) {
|
|
r = debug_lock_and_unmap(pdd->dev->dqm);
|
|
if (r) {
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
|
|
index 6af65db4de9479..af50aa9638cab8 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
|
|
@@ -815,13 +815,14 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
|
|
dev_err(kfd_device, "Error initializing KFD node\n");
|
|
goto node_init_error;
|
|
}
|
|
+
|
|
+ spin_lock_init(&node->watch_points_lock);
|
|
+
|
|
kfd->nodes[i] = node;
|
|
}
|
|
|
|
svm_range_set_max_pages(kfd->adev);
|
|
|
|
- spin_lock_init(&kfd->watch_points_lock);
|
|
-
|
|
kfd->init_complete = true;
|
|
dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor,
|
|
kfd->adev->pdev->device);
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
index 2b07c0000df6eb..c98a08c269ae74 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
@@ -330,6 +330,12 @@ static int kfd_event_page_set(struct kfd_process *p, void *kernel_address,
|
|
if (p->signal_page)
|
|
return -EBUSY;
|
|
|
|
+ if (size < KFD_SIGNAL_EVENT_LIMIT * 8) {
|
|
+ pr_err("Event page size %llu is too small, need at least %lu bytes\n",
|
|
+ size, (unsigned long)(KFD_SIGNAL_EVENT_LIMIT * 8));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
page = kzalloc(sizeof(*page), GFP_KERNEL);
|
|
if (!page)
|
|
return -ENOMEM;
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
|
|
index f99e3b812ee44b..59575e2424d07d 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
|
|
@@ -62,7 +62,7 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
|
|
*gart_addr = adev->gmc.gart_start;
|
|
|
|
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
|
|
- num_bytes = npages * 8;
|
|
+ num_bytes = npages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
|
|
|
|
r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
|
|
AMDGPU_FENCE_OWNER_UNDEFINED,
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
index b475c2ab9768af..0b69ff5375c528 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
|
|
@@ -316,6 +316,10 @@ struct kfd_node {
|
|
struct kfd_local_mem_info local_mem_info;
|
|
|
|
struct kfd_dev *kfd;
|
|
+
|
|
+ /* Track per device allocated watch points */
|
|
+ uint32_t alloc_watch_ids;
|
|
+ spinlock_t watch_points_lock;
|
|
};
|
|
|
|
struct kfd_dev {
|
|
@@ -368,10 +372,6 @@ struct kfd_dev {
|
|
struct kfd_node *nodes[MAX_KFD_NODES];
|
|
unsigned int num_nodes;
|
|
|
|
- /* Track per device allocated watch points */
|
|
- uint32_t alloc_watch_ids;
|
|
- spinlock_t watch_points_lock;
|
|
-
|
|
/* Kernel doorbells for KFD device */
|
|
struct amdgpu_bo *doorbells;
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
index faef07fdfd3027..26047109726eb4 100644
|
|
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
|
|
@@ -8934,7 +8934,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
|
*/
|
|
dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_ATOMIC);
|
|
for (j = 0; j < status->plane_count; j++)
|
|
- dummy_updates[j].surface = status->plane_states[0];
|
|
+ dummy_updates[j].surface = status->plane_states[j];
|
|
|
|
|
|
mutex_lock(&dm->dc_lock);
|
|
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
|
|
index d1329f20b7bd4b..746df72405eb43 100644
|
|
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
|
|
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
|
|
@@ -970,10 +970,15 @@ static void get_min_max_dc_plane_scaling(struct drm_device *dev,
|
|
*min_downscale = plane_cap->max_downscale_factor.nv12;
|
|
break;
|
|
|
|
+ /* All 64 bpp formats have the same fp16 scaling limits */
|
|
case DRM_FORMAT_XRGB16161616F:
|
|
case DRM_FORMAT_ARGB16161616F:
|
|
case DRM_FORMAT_XBGR16161616F:
|
|
case DRM_FORMAT_ABGR16161616F:
|
|
+ case DRM_FORMAT_XRGB16161616:
|
|
+ case DRM_FORMAT_ARGB16161616:
|
|
+ case DRM_FORMAT_XBGR16161616:
|
|
+ case DRM_FORMAT_ABGR16161616:
|
|
*max_upscale = plane_cap->max_upscale_factor.fp16;
|
|
*min_downscale = plane_cap->max_downscale_factor.fp16;
|
|
break;
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
|
|
index 1d052f08aff5e1..f20f0b2be4c7d5 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c
|
|
@@ -716,8 +716,7 @@ bool mpc32_program_shaper(
|
|
return false;
|
|
}
|
|
|
|
- if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
|
|
- mpc32_power_on_shaper_3dlut(mpc, mpcc_id, true);
|
|
+ mpc32_power_on_shaper_3dlut(mpc, mpcc_id, true);
|
|
|
|
current_mode = mpc32_get_shaper_current(mpc, mpcc_id);
|
|
|
|
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
|
|
index caf590caaf2c7b..e759004046938c 100644
|
|
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
|
|
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
|
|
@@ -3449,6 +3449,11 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
|
|
max_sclk = 60000;
|
|
max_mclk = 80000;
|
|
}
|
|
+ if ((adev->pdev->device == 0x666f) &&
|
|
+ (adev->pdev->revision == 0x00)) {
|
|
+ max_sclk = 80000;
|
|
+ max_mclk = 95000;
|
|
+ }
|
|
} else if (adev->asic_type == CHIP_OLAND) {
|
|
if ((adev->pdev->revision == 0xC7) ||
|
|
(adev->pdev->revision == 0x80) ||
|
|
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
|
|
index daa508504f47d6..b35d367b861418 100644
|
|
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
|
|
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
|
|
@@ -78,8 +78,6 @@ drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
|
|
return container_of(s, struct atmel_hlcdc_plane_state, base);
|
|
}
|
|
|
|
-#define SUBPIXEL_MASK 0xffff
|
|
-
|
|
static uint32_t rgb_formats[] = {
|
|
DRM_FORMAT_C8,
|
|
DRM_FORMAT_XRGB4444,
|
|
@@ -619,24 +617,15 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
|
|
if (ret || !s->visible)
|
|
return ret;
|
|
|
|
- hstate->src_x = s->src.x1;
|
|
- hstate->src_y = s->src.y1;
|
|
- hstate->src_w = drm_rect_width(&s->src);
|
|
- hstate->src_h = drm_rect_height(&s->src);
|
|
+ hstate->src_x = s->src.x1 >> 16;
|
|
+ hstate->src_y = s->src.y1 >> 16;
|
|
+ hstate->src_w = drm_rect_width(&s->src) >> 16;
|
|
+ hstate->src_h = drm_rect_height(&s->src) >> 16;
|
|
hstate->crtc_x = s->dst.x1;
|
|
hstate->crtc_y = s->dst.y1;
|
|
hstate->crtc_w = drm_rect_width(&s->dst);
|
|
hstate->crtc_h = drm_rect_height(&s->dst);
|
|
|
|
- if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
|
|
- SUBPIXEL_MASK)
|
|
- return -EINVAL;
|
|
-
|
|
- hstate->src_x >>= 16;
|
|
- hstate->src_y >>= 16;
|
|
- hstate->src_w >>= 16;
|
|
- hstate->src_h >>= 16;
|
|
-
|
|
hstate->nplanes = fb->format->num_planes;
|
|
if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
|
|
return -EINVAL;
|
|
@@ -915,8 +904,7 @@ atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
|
|
return NULL;
|
|
}
|
|
|
|
- if (copy->base.fb)
|
|
- drm_framebuffer_get(copy->base.fb);
|
|
+ __drm_atomic_helper_plane_duplicate_state(p, ©->base);
|
|
|
|
return ©->base;
|
|
}
|
|
@@ -934,8 +922,7 @@ static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
|
|
state->dscrs[i]->self);
|
|
}
|
|
|
|
- if (s->fb)
|
|
- drm_framebuffer_put(s->fb);
|
|
+ __drm_atomic_helper_plane_destroy_state(s);
|
|
|
|
kfree(state);
|
|
}
|
|
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
|
|
index 21ff7ef7ce920f..d4a5489d010c4d 100644
|
|
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
|
|
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
|
|
@@ -4527,7 +4527,8 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state,
|
|
if (!payload->delete) {
|
|
payload->pbn = 0;
|
|
payload->delete = true;
|
|
- topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
|
|
+ if (payload->vcpi > 0)
|
|
+ topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
|
|
index dfec479830e496..b4ee7d4110f842 100644
|
|
--- a/drivers/gpu/drm/drm_property.c
|
|
+++ b/drivers/gpu/drm/drm_property.c
|
|
@@ -561,7 +561,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
|
|
if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
- blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
|
|
+ blob = kvzalloc(sizeof(struct drm_property_blob) + length, GFP_KERNEL_ACCOUNT);
|
|
if (!blob)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
|
|
index 9df78e7caa2bd7..231b341d968ad0 100644
|
|
--- a/drivers/gpu/drm/i915/display/intel_acpi.c
|
|
+++ b/drivers/gpu/drm/i915/display/intel_acpi.c
|
|
@@ -93,6 +93,7 @@ static void intel_dsm_platform_mux_info(acpi_handle dhandle)
|
|
|
|
if (!pkg->package.count) {
|
|
DRM_DEBUG_DRIVER("no connection in _DSM\n");
|
|
+ ACPI_FREE(pkg);
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c
|
|
index 718f2f1b6174d1..a2bffa4a4dd158 100644
|
|
--- a/drivers/gpu/drm/i915/intel_wakeref.c
|
|
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
|
|
@@ -76,7 +76,7 @@ void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags)
|
|
/* Assume we are not in process context and so cannot sleep. */
|
|
if (flags & INTEL_WAKEREF_PUT_ASYNC || !mutex_trylock(&wf->mutex)) {
|
|
mod_delayed_work(wf->i915->unordered_wq, &wf->work,
|
|
- FIELD_GET(INTEL_WAKEREF_PUT_DELAY, flags));
|
|
+ FIELD_GET(INTEL_WAKEREF_PUT_DELAY_MASK, flags));
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h
|
|
index ec881b09736896..9923628d706ccd 100644
|
|
--- a/drivers/gpu/drm/i915/intel_wakeref.h
|
|
+++ b/drivers/gpu/drm/i915/intel_wakeref.h
|
|
@@ -119,17 +119,16 @@ intel_wakeref_get_if_active(struct intel_wakeref *wf)
|
|
return atomic_inc_not_zero(&wf->count);
|
|
}
|
|
|
|
-enum {
|
|
- INTEL_WAKEREF_PUT_ASYNC_BIT = 0,
|
|
- __INTEL_WAKEREF_PUT_LAST_BIT__
|
|
-};
|
|
-
|
|
static inline void
|
|
intel_wakeref_might_get(struct intel_wakeref *wf)
|
|
{
|
|
might_lock(&wf->mutex);
|
|
}
|
|
|
|
+/* flags for __intel_wakeref_put() and __intel_wakeref_put_last */
|
|
+#define INTEL_WAKEREF_PUT_ASYNC BIT(0)
|
|
+#define INTEL_WAKEREF_PUT_DELAY_MASK GENMASK(BITS_PER_LONG - 1, 1)
|
|
+
|
|
/**
|
|
* __intel_wakeref_put: Release the wakeref
|
|
* @wf: the wakeref
|
|
@@ -145,9 +144,6 @@ intel_wakeref_might_get(struct intel_wakeref *wf)
|
|
*/
|
|
static inline void
|
|
__intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags)
|
|
-#define INTEL_WAKEREF_PUT_ASYNC BIT(INTEL_WAKEREF_PUT_ASYNC_BIT)
|
|
-#define INTEL_WAKEREF_PUT_DELAY \
|
|
- GENMASK(BITS_PER_LONG - 1, __INTEL_WAKEREF_PUT_LAST_BIT__)
|
|
{
|
|
INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
|
|
if (unlikely(!atomic_add_unless(&wf->count, -1, 1)))
|
|
@@ -172,7 +168,7 @@ intel_wakeref_put_delay(struct intel_wakeref *wf, unsigned long delay)
|
|
{
|
|
__intel_wakeref_put(wf,
|
|
INTEL_WAKEREF_PUT_ASYNC |
|
|
- FIELD_PREP(INTEL_WAKEREF_PUT_DELAY, delay));
|
|
+ FIELD_PREP(INTEL_WAKEREF_PUT_DELAY_MASK, delay));
|
|
}
|
|
|
|
static inline void
|
|
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
|
|
index 535c89ce5d62eb..0410a1657b15e6 100644
|
|
--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
|
|
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
|
|
@@ -77,7 +77,10 @@ static bool a2xx_me_init(struct msm_gpu *gpu)
|
|
|
|
/* Vertex and Pixel Shader Start Addresses in instructions
|
|
* (3 DWORDS per instruction) */
|
|
- OUT_RING(ring, 0x80000180);
|
|
+ if (adreno_is_a225(adreno_gpu))
|
|
+ OUT_RING(ring, 0x80000300);
|
|
+ else
|
|
+ OUT_RING(ring, 0x80000180);
|
|
/* Maximum Contexts */
|
|
OUT_RING(ring, 0x00000001);
|
|
/* Write Confirm Interval and The CP will wait the
|
|
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h
|
|
index 9195cb996f444b..cbaca4bf2864ac 100644
|
|
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h
|
|
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h
|
|
@@ -14,6 +14,7 @@ static const struct dpu_caps sc7280_dpu_caps = {
|
|
.has_dim_layer = true,
|
|
.has_idle_pc = true,
|
|
.max_linewidth = 2400,
|
|
+ .has_3d_merge = true,
|
|
.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
|
|
};
|
|
|
|
@@ -145,7 +146,7 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = {
|
|
.base = 0x6b000, .len = 0,
|
|
.features = BIT(DPU_PINGPONG_DITHER),
|
|
.sblk = &sc7280_pp_sblk,
|
|
- .merge_3d = 0,
|
|
+ .merge_3d = MERGE_3D_1,
|
|
.intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
|
|
.intr_rdptr = -1,
|
|
}, {
|
|
@@ -153,12 +154,19 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = {
|
|
.base = 0x6c000, .len = 0,
|
|
.features = BIT(DPU_PINGPONG_DITHER),
|
|
.sblk = &sc7280_pp_sblk,
|
|
- .merge_3d = 0,
|
|
+ .merge_3d = MERGE_3D_1,
|
|
.intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
|
|
.intr_rdptr = -1,
|
|
},
|
|
};
|
|
|
|
+static const struct dpu_merge_3d_cfg sc7280_merge_3d[] = {
|
|
+ {
|
|
+ .name = "merge_3d_1", .id = MERGE_3D_1,
|
|
+ .base = 0x4f000, .len = 0x8,
|
|
+ },
|
|
+};
|
|
+
|
|
/* NOTE: sc7280 only has one DSC hard slice encoder */
|
|
static const struct dpu_dsc_cfg sc7280_dsc[] = {
|
|
{
|
|
@@ -265,6 +273,8 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = {
|
|
.mixer = sc7280_lm,
|
|
.pingpong_count = ARRAY_SIZE(sc7280_pp),
|
|
.pingpong = sc7280_pp,
|
|
+ .merge_3d_count = ARRAY_SIZE(sc7280_merge_3d),
|
|
+ .merge_3d = sc7280_merge_3d,
|
|
.dsc_count = ARRAY_SIZE(sc7280_dsc),
|
|
.dsc = sc7280_dsc,
|
|
.wb_count = ARRAY_SIZE(sc7280_wb),
|
|
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
|
|
index 83a804ebf8d7ef..fd2400c4665d27 100644
|
|
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
|
|
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
|
|
@@ -675,10 +675,11 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done(
|
|
if (!dpu_encoder_phys_cmd_is_master(phys_enc))
|
|
return 0;
|
|
|
|
- if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl))
|
|
- return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc);
|
|
+ if (phys_enc->irq[INTR_IDX_CTL_START] &&
|
|
+ !phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl))
|
|
+ return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
|
|
|
|
- return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
|
|
+ return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc);
|
|
}
|
|
|
|
static void dpu_encoder_phys_cmd_handle_post_kickoff(
|
|
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
|
|
index fbf968e3f6d789..c688b4d914819c 100644
|
|
--- a/drivers/gpu/drm/radeon/si_dpm.c
|
|
+++ b/drivers/gpu/drm/radeon/si_dpm.c
|
|
@@ -2969,6 +2969,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
|
|
max_sclk = 60000;
|
|
max_mclk = 80000;
|
|
}
|
|
+ if ((rdev->pdev->device == 0x666f) &&
|
|
+ (rdev->pdev->revision == 0x00)) {
|
|
+ max_sclk = 80000;
|
|
+ max_mclk = 95000;
|
|
+ }
|
|
} else if (rdev->family == CHIP_OLAND) {
|
|
if ((rdev->pdev->revision == 0xC7) ||
|
|
(rdev->pdev->revision == 0x80) ||
|
|
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
|
index 0e8ea990118844..691a8c8848e405 100644
|
|
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
|
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
|
@@ -242,6 +242,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
goto clk_disable;
|
|
|
|
+ dma_set_max_seg_size(&pdev->dev, UINT_MAX);
|
|
+
|
|
v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
|
|
|
|
ident1 = V3D_READ(V3D_HUB_IDENT1);
|
|
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
|
|
index ffbeb39341e1a4..851ddbc25bedd1 100644
|
|
--- a/drivers/hid/Kconfig
|
|
+++ b/drivers/hid/Kconfig
|
|
@@ -328,6 +328,7 @@ config HID_ELECOM
|
|
- EX-G Trackballs (M-XT3DRBK, M-XT3URBK)
|
|
- DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK)
|
|
- HUGE Trackballs (M-HT1DRBK, M-HT1URBK)
|
|
+ - HUGE Plus Trackball (M-HT1MRBK)
|
|
|
|
config HID_ELO
|
|
tristate "ELO USB 4000/4500 touchscreen"
|
|
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
|
|
index 2b8021628d3c6a..9dd5c698fefe05 100644
|
|
--- a/drivers/hid/hid-apple.c
|
|
+++ b/drivers/hid/hid-apple.c
|
|
@@ -340,6 +340,7 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
|
|
};
|
|
|
|
static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
|
|
+ { "SONiX KN85 Keyboard" },
|
|
{ "SONiX USB DEVICE" },
|
|
{ "SONiX AK870 PRO" },
|
|
{ "Keychron" },
|
|
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
|
|
index f76fec79e89034..9aeb2d2b43a439 100644
|
|
--- a/drivers/hid/hid-elecom.c
|
|
+++ b/drivers/hid/hid-elecom.c
|
|
@@ -5,6 +5,7 @@
|
|
* - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK)
|
|
* - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK)
|
|
* - HUGE Trackballs (M-HT1DRBK, M-HT1URBK)
|
|
+ * - HUGE Plus Trackball (M-HT1MRBK)
|
|
*
|
|
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
|
|
* Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
|
|
@@ -111,12 +112,25 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|
*/
|
|
mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8);
|
|
break;
|
|
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK:
|
|
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB:
|
|
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC:
|
|
+ /*
|
|
+ * Report descriptor format:
|
|
+ * 24: button bit count
|
|
+ * 28: padding bit count
|
|
+ * 22: button report size
|
|
+ * 16: button usage maximum
|
|
+ */
|
|
+ mouse_button_fixup(hdev, rdesc, *rsize, 24, 28, 22, 16, 8);
|
|
+ break;
|
|
}
|
|
return rdesc;
|
|
}
|
|
|
|
static const struct hid_device_id elecom_devices[] = {
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
|
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) },
|
|
@@ -127,6 +141,8 @@ static const struct hid_device_id elecom_devices[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(hid, elecom_devices);
|
|
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
index 931746cf363027..a1910e12f7e05f 100644
|
|
--- a/drivers/hid/hid-ids.h
|
|
+++ b/drivers/hid/hid-ids.h
|
|
@@ -427,6 +427,7 @@
|
|
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349
|
|
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
|
|
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
|
|
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000 0xc000
|
|
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002 0xc002
|
|
|
|
#define USB_VENDOR_ID_EDIFIER 0x2d99
|
|
@@ -452,6 +453,9 @@
|
|
#define USB_DEVICE_ID_ELECOM_M_HT1URBK 0x010c
|
|
#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D 0x010d
|
|
#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C 0x011c
|
|
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK 0x01aa
|
|
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB 0x01ab
|
|
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC 0x01ac
|
|
|
|
#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
|
|
#define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004
|
|
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
|
|
index 5a2fe703cf57b0..339a227c457e7a 100644
|
|
--- a/drivers/hid/hid-logitech-hidpp.c
|
|
+++ b/drivers/hid/hid-logitech-hidpp.c
|
|
@@ -4339,7 +4339,7 @@ static int hidpp_get_report_length(struct hid_device *hdev, int id)
|
|
|
|
re = &(hdev->report_enum[HID_OUTPUT_REPORT]);
|
|
report = re->report_id_hash[id];
|
|
- if (!report)
|
|
+ if (!report || !report->maxfield)
|
|
return 0;
|
|
|
|
return report->field[0]->report_count + 1;
|
|
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
|
|
index 4fe1e0bc244934..99d0dbf62af378 100644
|
|
--- a/drivers/hid/hid-magicmouse.c
|
|
+++ b/drivers/hid/hid-magicmouse.c
|
|
@@ -712,6 +712,11 @@ static int magicmouse_input_configured(struct hid_device *hdev,
|
|
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
|
|
int ret;
|
|
|
|
+ if (!msc->input) {
|
|
+ hid_err(hdev, "magicmouse setup input failed (no input)");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
ret = magicmouse_setup_input(msc->input, hdev);
|
|
if (ret) {
|
|
hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
|
|
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
|
index 6d9a85c5fc4097..b6c2cb7153fde3 100644
|
|
--- a/drivers/hid/hid-multitouch.c
|
|
+++ b/drivers/hid/hid-multitouch.c
|
|
@@ -2020,6 +2020,9 @@ static const struct hid_device_id mt_devices[] = {
|
|
{ .driver_data = MT_CLS_EGALAX_SERIAL,
|
|
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
|
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
|
|
+ { .driver_data = MT_CLS_EGALAX_SERIAL,
|
|
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
|
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) },
|
|
{ .driver_data = MT_CLS_EGALAX,
|
|
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
|
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
|
|
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
|
|
index 93fb07ec31802f..d1a1ddd933abd2 100644
|
|
--- a/drivers/hid/hid-pl.c
|
|
+++ b/drivers/hid/hid-pl.c
|
|
@@ -194,9 +194,14 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
goto err;
|
|
}
|
|
|
|
- plff_init(hdev);
|
|
+ ret = plff_init(hdev);
|
|
+ if (ret)
|
|
+ goto stop;
|
|
|
|
return 0;
|
|
+
|
|
+stop:
|
|
+ hid_hw_stop(hdev);
|
|
err:
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
|
|
index 32f65c45fdc8af..199f76988bae89 100644
|
|
--- a/drivers/hid/hid-playstation.c
|
|
+++ b/drivers/hid/hid-playstation.c
|
|
@@ -732,7 +732,9 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev,
|
|
#if IS_ENABLED(CONFIG_PLAYSTATION_FF)
|
|
if (play_effect) {
|
|
input_set_capability(gamepad, EV_FF, FF_RUMBLE);
|
|
- input_ff_create_memless(gamepad, NULL, play_effect);
|
|
+ ret = input_ff_create_memless(gamepad, NULL, play_effect);
|
|
+ if (ret)
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
#endif
|
|
|
|
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
|
|
index e4e9471d0f1e92..f20d29566b4da7 100644
|
|
--- a/drivers/hid/hid-prodikeys.c
|
|
+++ b/drivers/hid/hid-prodikeys.c
|
|
@@ -388,6 +388,10 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data)
|
|
bit_mask = (bit_mask << 8) | data[2];
|
|
bit_mask = (bit_mask << 8) | data[3];
|
|
|
|
+ /* robustness in case input_mapping hook does not get called */
|
|
+ if (!pm->input_ep82)
|
|
+ return 0;
|
|
+
|
|
/* break keys */
|
|
for (bit_index = 0; bit_index < 24; bit_index++) {
|
|
if (!((0x01 << bit_index) & bit_mask)) {
|
|
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
|
|
index 1f531626192cdb..7a3e0675d9ba2b 100644
|
|
--- a/drivers/hid/hid-quirks.c
|
|
+++ b/drivers/hid/hid-quirks.c
|
|
@@ -415,6 +415,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|
#if IS_ENABLED(CONFIG_HID_ELECOM)
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
|
|
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) },
|
|
@@ -424,6 +425,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) },
|
|
#endif
|
|
#if IS_ENABLED(CONFIG_HID_ELO)
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
|
|
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
|
|
index 27207ec6f7febd..5e3c8be255e873 100644
|
|
--- a/drivers/hwmon/f71882fg.c
|
|
+++ b/drivers/hwmon/f71882fg.c
|
|
@@ -51,6 +51,7 @@
|
|
#define SIO_F81866_ID 0x1010 /* Chipset ID */
|
|
#define SIO_F71858AD_ID 0x0903 /* Chipset ID */
|
|
#define SIO_F81966_ID 0x1502 /* Chipset ID */
|
|
+#define SIO_F81968_ID 0x1806 /* Chipset ID */
|
|
|
|
#define REGION_LENGTH 8
|
|
#define ADDR_REG_OFFSET 5
|
|
@@ -2571,6 +2572,7 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
|
|
break;
|
|
case SIO_F81866_ID:
|
|
case SIO_F81966_ID:
|
|
+ case SIO_F81968_ID:
|
|
sio_data->type = f81866a;
|
|
break;
|
|
default:
|
|
@@ -2600,9 +2602,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
|
|
address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
|
|
|
|
err = address;
|
|
- pr_info("Found %s chip at %#x, revision %d\n",
|
|
+ pr_info("Found %s chip at %#x, revision %d, devid: %04x\n",
|
|
f71882fg_names[sio_data->type], (unsigned int)address,
|
|
- (int)superio_inb(sioaddr, SIO_REG_DEVREV));
|
|
+ (int)superio_inb(sioaddr, SIO_REG_DEVREV), devid);
|
|
exit:
|
|
superio_exit(sioaddr);
|
|
return err;
|
|
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
|
|
index 40fff7e95ea1c0..db066b3689187d 100644
|
|
--- a/drivers/hwmon/ibmpex.c
|
|
+++ b/drivers/hwmon/ibmpex.c
|
|
@@ -282,9 +282,6 @@ static ssize_t ibmpex_high_low_store(struct device *dev,
|
|
{
|
|
struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
|
|
|
|
- if (!data)
|
|
- return -ENODEV;
|
|
-
|
|
ibmpex_reset_high_low_data(data);
|
|
|
|
return count;
|
|
@@ -517,9 +514,6 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
|
|
{
|
|
int i, j;
|
|
|
|
- hwmon_device_unregister(data->hwmon_dev);
|
|
- dev_set_drvdata(data->bmc_device, NULL);
|
|
-
|
|
device_remove_file(data->bmc_device,
|
|
&sensor_dev_attr_reset_high_low.dev_attr);
|
|
device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
|
|
@@ -533,7 +527,8 @@ static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
|
|
}
|
|
|
|
list_del(&data->list);
|
|
-
|
|
+ dev_set_drvdata(data->bmc_device, NULL);
|
|
+ hwmon_device_unregister(data->hwmon_dev);
|
|
ipmi_destroy_user(data->user);
|
|
kfree(data->sensors);
|
|
kfree(data);
|
|
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
|
|
index 7e0ac3fcbc0501..b09fd5791db8ef 100644
|
|
--- a/drivers/hwmon/nct6775-platform.c
|
|
+++ b/drivers/hwmon/nct6775-platform.c
|
|
@@ -1356,6 +1356,7 @@ static const char * const asus_msi_boards[] = {
|
|
"Pro WS W680-ACE IPMI",
|
|
"Pro WS W790-ACE",
|
|
"Pro WS W790E-SAGE SE",
|
|
+ "Pro WS WRX90E-SAGE SE",
|
|
"ProArt B650-CREATOR",
|
|
"ProArt B660-CREATOR D4",
|
|
"ProArt B760-CREATOR D4",
|
|
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
|
|
index 116a91d90ac20a..4cef1023f02903 100644
|
|
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
|
|
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
|
|
@@ -814,16 +814,16 @@ static int __init etm_hp_setup(void)
|
|
{
|
|
int ret;
|
|
|
|
- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ARM_CORESIGHT_STARTING,
|
|
- "arm/coresight:starting",
|
|
- etm_starting_cpu, etm_dying_cpu);
|
|
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
|
|
+ "arm/coresight:starting",
|
|
+ etm_starting_cpu, etm_dying_cpu);
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN,
|
|
- "arm/coresight:online",
|
|
- etm_online_cpu, NULL);
|
|
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
|
+ "arm/coresight:online",
|
|
+ etm_online_cpu, NULL);
|
|
|
|
/* HP dyn state ID returned in ret on success */
|
|
if (ret > 0) {
|
|
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
|
|
index 060f70e4d52d77..f74ef65d257d7b 100644
|
|
--- a/drivers/i3c/master.c
|
|
+++ b/drivers/i3c/master.c
|
|
@@ -586,7 +586,8 @@ static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
|
|
else
|
|
ret = master->ops->disable_hotjoin(master);
|
|
|
|
- master->hotjoin = enable;
|
|
+ if (!ret)
|
|
+ master->hotjoin = enable;
|
|
|
|
i3c_bus_normaluse_unlock(&master->bus);
|
|
|
|
@@ -2769,7 +2770,6 @@ int i3c_master_register(struct i3c_master_controller *master,
|
|
INIT_LIST_HEAD(&master->boardinfo.i3c);
|
|
|
|
device_initialize(&master->dev);
|
|
- dev_set_name(&master->dev, "i3c-%d", i3cbus->id);
|
|
|
|
master->dev.dma_mask = parent->dma_mask;
|
|
master->dev.coherent_dma_mask = parent->coherent_dma_mask;
|
|
@@ -2779,6 +2779,8 @@ int i3c_master_register(struct i3c_master_controller *master,
|
|
if (ret)
|
|
goto err_put_dev;
|
|
|
|
+ dev_set_name(&master->dev, "i3c-%d", i3cbus->id);
|
|
+
|
|
ret = of_populate_i3c_bus(master);
|
|
if (ret)
|
|
goto err_put_dev;
|
|
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
|
|
index 030127525672e7..cee2805fccd0f8 100644
|
|
--- a/drivers/i3c/master/dw-i3c-master.c
|
|
+++ b/drivers/i3c/master/dw-i3c-master.c
|
|
@@ -1483,6 +1483,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
|
|
spin_lock_init(&master->xferqueue.lock);
|
|
INIT_LIST_HEAD(&master->xferqueue.list);
|
|
|
|
+ spin_lock_init(&master->devs_lock);
|
|
+
|
|
writel(INTR_ALL, master->regs + INTR_STATUS);
|
|
irq = platform_get_irq(pdev, 0);
|
|
ret = devm_request_irq(&pdev->dev, irq,
|
|
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
|
|
index 3222b8f56a926f..94792f3559a0f5 100644
|
|
--- a/drivers/i3c/master/svc-i3c-master.c
|
|
+++ b/drivers/i3c/master/svc-i3c-master.c
|
|
@@ -418,8 +418,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
|
{
|
|
struct svc_i3c_master *master = container_of(work, struct svc_i3c_master, ibi_work);
|
|
struct svc_i3c_i2c_dev_data *data;
|
|
+ struct i3c_dev_desc *dev = NULL;
|
|
unsigned int ibitype, ibiaddr;
|
|
- struct i3c_dev_desc *dev;
|
|
u32 status, val;
|
|
int ret;
|
|
|
|
@@ -503,7 +503,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
|
* for the slave to interrupt again.
|
|
*/
|
|
if (svc_i3c_master_error(master)) {
|
|
- if (master->ibi.tbq_slot) {
|
|
+ if (master->ibi.tbq_slot && dev) {
|
|
data = i3c_dev_get_master_data(dev);
|
|
i3c_generic_ibi_recycle_slot(data->ibi_pool,
|
|
master->ibi.tbq_slot);
|
|
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
|
|
index 13439f52d26dba..0eabcd6957979d 100644
|
|
--- a/drivers/iio/accel/bma180.c
|
|
+++ b/drivers/iio/accel/bma180.c
|
|
@@ -996,8 +996,9 @@ static int bma180_probe(struct i2c_client *client)
|
|
}
|
|
|
|
ret = devm_request_irq(dev, client->irq,
|
|
- iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING,
|
|
- "bma180_event", data->trig);
|
|
+ iio_trigger_generic_data_rdy_poll,
|
|
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
|
+ "bma180_event", data->trig);
|
|
if (ret) {
|
|
dev_err(dev, "unable to request IRQ\n");
|
|
goto err_trigger_free;
|
|
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
|
|
index 87c54e41f6ccd2..2b87f7f5508bbd 100644
|
|
--- a/drivers/iio/accel/sca3000.c
|
|
+++ b/drivers/iio/accel/sca3000.c
|
|
@@ -1496,7 +1496,11 @@ static int sca3000_probe(struct spi_device *spi)
|
|
if (ret)
|
|
goto error_free_irq;
|
|
|
|
- return iio_device_register(indio_dev);
|
|
+ ret = iio_device_register(indio_dev);
|
|
+ if (ret)
|
|
+ goto error_free_irq;
|
|
+
|
|
+ return 0;
|
|
|
|
error_free_irq:
|
|
if (spi->irq)
|
|
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
|
|
index 3079a0872947e0..d1d010c1dbf6c8 100644
|
|
--- a/drivers/iio/adc/ad7766.c
|
|
+++ b/drivers/iio/adc/ad7766.c
|
|
@@ -261,7 +261,7 @@ static int ad7766_probe(struct spi_device *spi)
|
|
* don't enable the interrupt to avoid extra load on the system
|
|
*/
|
|
ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq,
|
|
- IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
|
|
+ IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN | IRQF_NO_THREAD,
|
|
dev_name(&spi->dev),
|
|
ad7766->trig);
|
|
if (ret < 0)
|
|
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
|
|
index 4cfa0d43956053..d1c125a77308ad 100644
|
|
--- a/drivers/iio/gyro/itg3200_buffer.c
|
|
+++ b/drivers/iio/gyro/itg3200_buffer.c
|
|
@@ -118,11 +118,9 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
|
|
if (!st->trig)
|
|
return -ENOMEM;
|
|
|
|
- ret = request_irq(st->i2c->irq,
|
|
- &iio_trigger_generic_data_rdy_poll,
|
|
- IRQF_TRIGGER_RISING,
|
|
- "itg3200_data_rdy",
|
|
- st->trig);
|
|
+ ret = request_irq(st->i2c->irq, &iio_trigger_generic_data_rdy_poll,
|
|
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
|
+ "itg3200_data_rdy", st->trig);
|
|
if (ret)
|
|
goto error_free_trig;
|
|
|
|
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
|
|
index 53fb92f0ac7ef9..1127dd9f0df257 100644
|
|
--- a/drivers/iio/gyro/itg3200_core.c
|
|
+++ b/drivers/iio/gyro/itg3200_core.c
|
|
@@ -93,6 +93,8 @@ static int itg3200_read_raw(struct iio_dev *indio_dev,
|
|
case IIO_CHAN_INFO_RAW:
|
|
reg = (u8)chan->address;
|
|
ret = itg3200_read_reg_s16(indio_dev, reg, val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
return IIO_VAL_INT;
|
|
case IIO_CHAN_INFO_SCALE:
|
|
*val = 0;
|
|
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
|
|
index a791ba3a693a47..de126561f197d8 100644
|
|
--- a/drivers/iio/gyro/mpu3050-core.c
|
|
+++ b/drivers/iio/gyro/mpu3050-core.c
|
|
@@ -1172,10 +1172,8 @@ int mpu3050_common_probe(struct device *dev,
|
|
mpu3050->regs[1].supply = mpu3050_reg_vlogic;
|
|
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(mpu3050->regs),
|
|
mpu3050->regs);
|
|
- if (ret) {
|
|
- dev_err(dev, "Cannot get regulators\n");
|
|
- return ret;
|
|
- }
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret, "Cannot get regulators\n");
|
|
|
|
ret = mpu3050_power_up(mpu3050);
|
|
if (ret)
|
|
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
|
|
index 77666b780a5c5a..9655214a382762 100644
|
|
--- a/drivers/iio/light/si1145.c
|
|
+++ b/drivers/iio/light/si1145.c
|
|
@@ -1251,7 +1251,7 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
|
|
|
|
ret = devm_request_irq(&client->dev, client->irq,
|
|
iio_trigger_generic_data_rdy_poll,
|
|
- IRQF_TRIGGER_FALLING,
|
|
+ IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
|
|
"si1145_irq",
|
|
trig);
|
|
if (ret < 0) {
|
|
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
|
|
index 3a98d6bae1b203..c1894a26ffd670 100644
|
|
--- a/drivers/iio/magnetometer/ak8975.c
|
|
+++ b/drivers/iio/magnetometer/ak8975.c
|
|
@@ -542,7 +542,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
|
|
irq = gpiod_to_irq(data->eoc_gpiod);
|
|
|
|
rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
|
|
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
|
+ IRQF_TRIGGER_RISING,
|
|
dev_name(&client->dev), data);
|
|
if (rc < 0) {
|
|
dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc);
|
|
diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c
|
|
index 829c472812e49b..566c21bf3ea0df 100644
|
|
--- a/drivers/iio/pressure/mprls0025pa.c
|
|
+++ b/drivers/iio/pressure/mprls0025pa.c
|
|
@@ -132,8 +132,8 @@ static const struct iio_chan_spec mpr_channels[] = {
|
|
BIT(IIO_CHAN_INFO_OFFSET),
|
|
.scan_index = 0,
|
|
.scan_type = {
|
|
- .sign = 's',
|
|
- .realbits = 32,
|
|
+ .sign = 'u',
|
|
+ .realbits = 24,
|
|
.storagebits = 32,
|
|
.endianness = IIO_CPU,
|
|
},
|
|
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
|
|
index 77c0b89259911f..cda4fb81174fbd 100644
|
|
--- a/drivers/infiniband/core/cache.c
|
|
+++ b/drivers/infiniband/core/cache.c
|
|
@@ -927,6 +927,13 @@ static int gid_table_setup_one(struct ib_device *ib_dev)
|
|
if (err)
|
|
return err;
|
|
|
|
+ /*
|
|
+ * Mark the device as ready for GID cache updates. This allows netdev
|
|
+ * event handlers to update the GID cache even before the device is
|
|
+ * fully registered.
|
|
+ */
|
|
+ ib_device_enable_gid_updates(ib_dev);
|
|
+
|
|
rdma_roce_rescan_device(ib_dev);
|
|
|
|
return err;
|
|
@@ -1566,7 +1573,8 @@ static void ib_cache_event_task(struct work_struct *_work)
|
|
* the cache.
|
|
*/
|
|
ret = ib_cache_update(work->event.device, work->event.element.port_num,
|
|
- work->event.event == IB_EVENT_GID_CHANGE,
|
|
+ work->event.event == IB_EVENT_GID_CHANGE ||
|
|
+ work->event.event == IB_EVENT_CLIENT_REREGISTER,
|
|
work->event.event == IB_EVENT_PKEY_CHANGE,
|
|
work->enforce_security);
|
|
|
|
@@ -1667,6 +1675,12 @@ void ib_cache_release_one(struct ib_device *device)
|
|
|
|
void ib_cache_cleanup_one(struct ib_device *device)
|
|
{
|
|
+ /*
|
|
+ * Clear the GID updates mark first to prevent event handlers from
|
|
+ * accessing the device while it's being torn down.
|
|
+ */
|
|
+ ib_device_disable_gid_updates(device);
|
|
+
|
|
/* The cleanup function waits for all in-progress workqueue
|
|
* elements and cleans up the GID cache. This function should be
|
|
* called after the device was removed from the devices list and
|
|
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
|
|
index f66f48d860ec38..149dacf5b64d83 100644
|
|
--- a/drivers/infiniband/core/core_priv.h
|
|
+++ b/drivers/infiniband/core/core_priv.h
|
|
@@ -100,6 +100,9 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
|
|
roce_netdev_callback cb,
|
|
void *cookie);
|
|
|
|
+void ib_device_enable_gid_updates(struct ib_device *device);
|
|
+void ib_device_disable_gid_updates(struct ib_device *device);
|
|
+
|
|
typedef int (*nldev_callback)(struct ib_device *device,
|
|
struct sk_buff *skb,
|
|
struct netlink_callback *cb,
|
|
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
|
|
index d5931bb1de41a7..1a241864b7b547 100644
|
|
--- a/drivers/infiniband/core/device.c
|
|
+++ b/drivers/infiniband/core/device.c
|
|
@@ -93,6 +93,7 @@ static struct workqueue_struct *ib_unreg_wq;
|
|
static DEFINE_XARRAY_FLAGS(devices, XA_FLAGS_ALLOC);
|
|
static DECLARE_RWSEM(devices_rwsem);
|
|
#define DEVICE_REGISTERED XA_MARK_1
|
|
+#define DEVICE_GID_UPDATES XA_MARK_2
|
|
|
|
static u32 highest_client_id;
|
|
#define CLIENT_REGISTERED XA_MARK_1
|
|
@@ -2344,11 +2345,42 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
|
|
unsigned long index;
|
|
|
|
down_read(&devices_rwsem);
|
|
- xa_for_each_marked (&devices, index, dev, DEVICE_REGISTERED)
|
|
+ xa_for_each_marked(&devices, index, dev, DEVICE_GID_UPDATES)
|
|
ib_enum_roce_netdev(dev, filter, filter_cookie, cb, cookie);
|
|
up_read(&devices_rwsem);
|
|
}
|
|
|
|
+/**
|
|
+ * ib_device_enable_gid_updates - Mark device as ready for GID cache updates
|
|
+ * @device: Device to mark
|
|
+ *
|
|
+ * Called after GID table is allocated and initialized. After this mark is set,
|
|
+ * netdevice event handlers can update the device's GID cache. This allows
|
|
+ * events that arrive during device registration to be processed, avoiding
|
|
+ * stale GID entries when netdev properties change during the device
|
|
+ * registration process.
|
|
+ */
|
|
+void ib_device_enable_gid_updates(struct ib_device *device)
|
|
+{
|
|
+ down_write(&devices_rwsem);
|
|
+ xa_set_mark(&devices, device->index, DEVICE_GID_UPDATES);
|
|
+ up_write(&devices_rwsem);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * ib_device_disable_gid_updates - Clear the GID updates mark
|
|
+ * @device: Device to unmark
|
|
+ *
|
|
+ * Called before GID table cleanup to prevent event handlers from accessing
|
|
+ * the device while it's being torn down.
|
|
+ */
|
|
+void ib_device_disable_gid_updates(struct ib_device *device)
|
|
+{
|
|
+ down_write(&devices_rwsem);
|
|
+ xa_clear_mark(&devices, device->index, DEVICE_GID_UPDATES);
|
|
+ up_write(&devices_rwsem);
|
|
+}
|
|
+
|
|
/*
|
|
* ib_enum_all_devs - enumerate all ib_devices
|
|
* @cb: Callback to call for each found ib_device
|
|
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
|
|
index 8367974b7998b0..2522ff1cc462c7 100644
|
|
--- a/drivers/infiniband/core/rw.c
|
|
+++ b/drivers/infiniband/core/rw.c
|
|
@@ -651,34 +651,57 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num,
|
|
}
|
|
EXPORT_SYMBOL(rdma_rw_mr_factor);
|
|
|
|
+/**
|
|
+ * rdma_rw_max_send_wr - compute max Send WRs needed for RDMA R/W contexts
|
|
+ * @dev: RDMA device
|
|
+ * @port_num: port number
|
|
+ * @max_rdma_ctxs: number of rdma_rw_ctx structures
|
|
+ * @create_flags: QP create flags (pass IB_QP_CREATE_INTEGRITY_EN if
|
|
+ * data integrity will be enabled on the QP)
|
|
+ *
|
|
+ * Returns the total number of Send Queue entries needed for
|
|
+ * @max_rdma_ctxs. The result accounts for memory registration and
|
|
+ * invalidation work requests when the device requires them.
|
|
+ *
|
|
+ * ULPs use this to size Send Queues and Send CQs before creating a
|
|
+ * Queue Pair.
|
|
+ */
|
|
+unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num,
|
|
+ unsigned int max_rdma_ctxs, u32 create_flags)
|
|
+{
|
|
+ unsigned int factor = 1;
|
|
+ unsigned int result;
|
|
+
|
|
+ if (create_flags & IB_QP_CREATE_INTEGRITY_EN ||
|
|
+ rdma_rw_can_use_mr(dev, port_num))
|
|
+ factor += 2; /* reg + inv */
|
|
+
|
|
+ if (check_mul_overflow(factor, max_rdma_ctxs, &result))
|
|
+ return UINT_MAX;
|
|
+ return result;
|
|
+}
|
|
+EXPORT_SYMBOL(rdma_rw_max_send_wr);
|
|
+
|
|
void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr)
|
|
{
|
|
- u32 factor;
|
|
+ unsigned int factor = 1;
|
|
|
|
WARN_ON_ONCE(attr->port_num == 0);
|
|
|
|
/*
|
|
- * Each context needs at least one RDMA READ or WRITE WR.
|
|
- *
|
|
- * For some hardware we might need more, eventually we should ask the
|
|
- * HCA driver for a multiplier here.
|
|
- */
|
|
- factor = 1;
|
|
-
|
|
- /*
|
|
- * If the devices needs MRs to perform RDMA READ or WRITE operations,
|
|
- * we'll need two additional MRs for the registrations and the
|
|
- * invalidation.
|
|
+ * If the device uses MRs to perform RDMA READ or WRITE operations,
|
|
+ * or if data integrity is enabled, account for registration and
|
|
+ * invalidation work requests.
|
|
*/
|
|
if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN ||
|
|
rdma_rw_can_use_mr(dev, attr->port_num))
|
|
- factor += 2; /* inv + reg */
|
|
+ factor += 2; /* reg + inv */
|
|
|
|
attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs;
|
|
|
|
/*
|
|
- * But maybe we were just too high in the sky and the device doesn't
|
|
- * even support all we need, and we'll have to live with what we get..
|
|
+ * The device might not support all we need, and we'll have to
|
|
+ * live with what we get.
|
|
*/
|
|
attr->cap.max_send_wr =
|
|
min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr);
|
|
diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
|
|
index 39357dc2d229f0..66f5760197479d 100644
|
|
--- a/drivers/infiniband/core/umem_dmabuf.c
|
|
+++ b/drivers/infiniband/core/umem_dmabuf.c
|
|
@@ -205,13 +205,11 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device,
|
|
|
|
err = ib_umem_dmabuf_map_pages(umem_dmabuf);
|
|
if (err)
|
|
- goto err_unpin;
|
|
+ goto err_release;
|
|
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
|
|
|
|
return umem_dmabuf;
|
|
|
|
-err_unpin:
|
|
- dma_buf_unpin(umem_dmabuf->attach);
|
|
err_release:
|
|
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
|
|
ib_umem_release(&umem_dmabuf->umem);
|
|
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
|
|
index 2ed749f50a29ff..285f251fc014be 100644
|
|
--- a/drivers/infiniband/core/user_mad.c
|
|
+++ b/drivers/infiniband/core/user_mad.c
|
|
@@ -514,7 +514,8 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
|
|
struct rdma_ah_attr ah_attr;
|
|
struct ib_ah *ah;
|
|
__be64 *tid;
|
|
- int ret, data_len, hdr_len, copy_offset, rmpp_active;
|
|
+ int ret, hdr_len, copy_offset, rmpp_active;
|
|
+ size_t data_len;
|
|
u8 base_version;
|
|
|
|
if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
|
|
@@ -588,7 +589,10 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
|
|
}
|
|
|
|
base_version = ((struct ib_mad_hdr *)&packet->mad.data)->base_version;
|
|
- data_len = count - hdr_size(file) - hdr_len;
|
|
+ if (check_sub_overflow(count, hdr_size(file) + hdr_len, &data_len)) {
|
|
+ ret = -EINVAL;
|
|
+ goto err_ah;
|
|
+ }
|
|
packet->msg = ib_create_send_mad(agent,
|
|
be32_to_cpu(packet->mad.hdr.qpn),
|
|
packet->mad.hdr.pkey_index, rmpp_active,
|
|
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
|
|
index 33e2fe0facd529..2e4265ba35b7f3 100644
|
|
--- a/drivers/infiniband/core/uverbs_cmd.c
|
|
+++ b/drivers/infiniband/core/uverbs_cmd.c
|
|
@@ -2030,7 +2030,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL);
|
|
+ if (cmd.wqe_size < sizeof(struct ib_uverbs_send_wr))
|
|
+ return -EINVAL;
|
|
+
|
|
+ user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL | __GFP_NOWARN);
|
|
if (!user_wr)
|
|
return -ENOMEM;
|
|
|
|
@@ -2220,7 +2223,7 @@ ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count,
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
- user_wr = kmalloc(wqe_size, GFP_KERNEL);
|
|
+ user_wr = kmalloc(wqe_size, GFP_KERNEL | __GFP_NOWARN);
|
|
if (!user_wr)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
|
|
index 2a5b93ef4b3353..121384fee6696e 100644
|
|
--- a/drivers/infiniband/hw/efa/efa_verbs.c
|
|
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
|
|
@@ -1567,7 +1567,7 @@ static struct efa_mr *efa_alloc_mr(struct ib_pd *ibpd, int access_flags,
|
|
struct efa_mr *mr;
|
|
|
|
if (udata && udata->inlen &&
|
|
- !ib_is_udata_cleared(udata, 0, sizeof(udata->inlen))) {
|
|
+ !ib_is_udata_cleared(udata, 0, udata->inlen)) {
|
|
ibdev_dbg(&dev->ibdev,
|
|
"Incompatible ABI params, udata not cleared\n");
|
|
return ERR_PTR(-EINVAL);
|
|
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
|
|
index f1d4494c7d0082..b50529a652741a 100644
|
|
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
|
|
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
|
|
@@ -3588,6 +3588,23 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev,
|
|
HNS_ROCE_V2_CQ_DEFAULT_INTERVAL);
|
|
}
|
|
|
|
+static bool left_sw_wc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
|
|
+{
|
|
+ struct hns_roce_qp *hr_qp;
|
|
+
|
|
+ list_for_each_entry(hr_qp, &hr_cq->sq_list, sq_node) {
|
|
+ if (hr_qp->sq.head != hr_qp->sq.tail)
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ list_for_each_entry(hr_qp, &hr_cq->rq_list, rq_node) {
|
|
+ if (hr_qp->rq.head != hr_qp->rq.tail)
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq,
|
|
enum ib_cq_notify_flags flags)
|
|
{
|
|
@@ -3596,6 +3613,12 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq,
|
|
struct hns_roce_v2_db cq_db = {};
|
|
u32 notify_flag;
|
|
|
|
+ if (hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN) {
|
|
+ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) &&
|
|
+ left_sw_wc(hr_dev, hr_cq))
|
|
+ return 1;
|
|
+ return 0;
|
|
+ }
|
|
/*
|
|
* flags = 0, then notify_flag : next
|
|
* flags = 1, then notify flag : solocited
|
|
@@ -6604,7 +6627,8 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev)
|
|
|
|
INIT_WORK(&hr_dev->ecc_work, fmea_ram_ecc_work);
|
|
|
|
- hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq", 0);
|
|
+ hr_dev->irq_workq = alloc_ordered_workqueue("hns_roce_irq_workq",
|
|
+ WQ_MEM_RECLAIM);
|
|
if (!hr_dev->irq_workq) {
|
|
dev_err(dev, "failed to create irq workqueue.\n");
|
|
ret = -ENOMEM;
|
|
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
|
|
index c997b7cbf2a9e8..81b645c727a17c 100644
|
|
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
|
|
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
|
|
@@ -119,12 +119,15 @@ void retransmit_timer(struct timer_list *t)
|
|
|
|
rxe_dbg_qp(qp, "retransmit timer fired\n");
|
|
|
|
+ if (!rxe_get(qp))
|
|
+ return;
|
|
spin_lock_irqsave(&qp->state_lock, flags);
|
|
if (qp->valid) {
|
|
qp->comp.timeout = 1;
|
|
rxe_sched_task(&qp->comp.task);
|
|
}
|
|
spin_unlock_irqrestore(&qp->state_lock, flags);
|
|
+ rxe_put(qp);
|
|
}
|
|
|
|
void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb)
|
|
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
|
|
index 7ff152ffe15b9f..4d550ac0dac5ad 100644
|
|
--- a/drivers/infiniband/sw/rxe/rxe_req.c
|
|
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
|
|
@@ -103,6 +103,8 @@ void rnr_nak_timer(struct timer_list *t)
|
|
|
|
rxe_dbg_qp(qp, "nak timer fired\n");
|
|
|
|
+ if (!rxe_get(qp))
|
|
+ return;
|
|
spin_lock_irqsave(&qp->state_lock, flags);
|
|
if (qp->valid) {
|
|
/* request a send queue retry */
|
|
@@ -111,6 +113,7 @@ void rnr_nak_timer(struct timer_list *t)
|
|
rxe_sched_task(&qp->req.task);
|
|
}
|
|
spin_unlock_irqrestore(&qp->state_lock, flags);
|
|
+ rxe_put(qp);
|
|
}
|
|
|
|
static void req_check_sq_drain_done(struct rxe_qp *qp)
|
|
diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c
|
|
index 2a234f26ac1044..c9a7cd38953d31 100644
|
|
--- a/drivers/infiniband/sw/rxe/rxe_srq.c
|
|
+++ b/drivers/infiniband/sw/rxe/rxe_srq.c
|
|
@@ -77,9 +77,6 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
|
|
goto err_free;
|
|
}
|
|
|
|
- srq->rq.queue = q;
|
|
- init->attr.max_wr = srq->rq.max_wr;
|
|
-
|
|
if (uresp) {
|
|
if (copy_to_user(&uresp->srq_num, &srq->srq_num,
|
|
sizeof(uresp->srq_num))) {
|
|
@@ -88,6 +85,9 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
|
|
}
|
|
}
|
|
|
|
+ srq->rq.queue = q;
|
|
+ init->attr.max_wr = srq->rq.max_wr;
|
|
+
|
|
return 0;
|
|
|
|
err_free:
|
|
diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c
|
|
index 58bbf738e4e599..e2ad2425d57dac 100644
|
|
--- a/drivers/infiniband/sw/siw/siw_qp_rx.c
|
|
+++ b/drivers/infiniband/sw/siw/siw_qp_rx.c
|
|
@@ -1456,7 +1456,8 @@ int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb,
|
|
}
|
|
if (unlikely(rv != 0 && rv != -EAGAIN)) {
|
|
if ((srx->state > SIW_GET_HDR ||
|
|
- qp->rx_fpdu->more_ddp_segs) && run_completion)
|
|
+ (qp->rx_fpdu && qp->rx_fpdu->more_ddp_segs)) &&
|
|
+ run_completion)
|
|
siw_rdmap_complete(qp, rv);
|
|
|
|
siw_dbg_qp(qp, "rx error %d, rx state %d\n", rv,
|
|
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
|
|
index eaf911e2ffa9fb..1af2ee8c8ed5ef 100644
|
|
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
|
|
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
|
|
@@ -1922,7 +1922,7 @@ static int rtrs_rdma_conn_rejected(struct rtrs_clt_con *con,
|
|
struct rtrs_path *s = con->c.path;
|
|
const struct rtrs_msg_conn_rsp *msg;
|
|
const char *rej_msg;
|
|
- int status, errno;
|
|
+ int status, errno = -ECONNRESET;
|
|
u8 data_len;
|
|
|
|
status = ev->status;
|
|
@@ -1944,7 +1944,7 @@ static int rtrs_rdma_conn_rejected(struct rtrs_clt_con *con,
|
|
status, rej_msg);
|
|
}
|
|
|
|
- return -ECONNRESET;
|
|
+ return errno;
|
|
}
|
|
|
|
void rtrs_clt_close_conns(struct rtrs_clt_path *clt_path, bool wait)
|
|
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
|
|
index 5dbf315630c1a2..2c3c8b32190f8a 100644
|
|
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c
|
|
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
|
|
@@ -205,7 +205,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id)
|
|
size_t sg_cnt;
|
|
int err, offset;
|
|
bool need_inval;
|
|
- u32 rkey = 0;
|
|
struct ib_reg_wr rwr;
|
|
struct ib_sge *plist;
|
|
struct ib_sge list;
|
|
@@ -237,11 +236,6 @@ static int rdma_write_sg(struct rtrs_srv_op *id)
|
|
wr->wr.num_sge = 1;
|
|
wr->remote_addr = le64_to_cpu(id->rd_msg->desc[0].addr);
|
|
wr->rkey = le32_to_cpu(id->rd_msg->desc[0].key);
|
|
- if (rkey == 0)
|
|
- rkey = wr->rkey;
|
|
- else
|
|
- /* Only one key is actually used */
|
|
- WARN_ON_ONCE(rkey != wr->rkey);
|
|
|
|
wr->wr.opcode = IB_WR_RDMA_WRITE;
|
|
wr->wr.wr_cqe = &io_comp_cqe;
|
|
@@ -274,7 +268,7 @@ static int rdma_write_sg(struct rtrs_srv_op *id)
|
|
inv_wr.opcode = IB_WR_SEND_WITH_INV;
|
|
inv_wr.wr_cqe = &io_comp_cqe;
|
|
inv_wr.send_flags = 0;
|
|
- inv_wr.ex.invalidate_rkey = rkey;
|
|
+ inv_wr.ex.invalidate_rkey = wr->rkey;
|
|
}
|
|
|
|
imm_wr.wr.next = NULL;
|
|
@@ -598,7 +592,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
|
|
srv_path->mrs_num++) {
|
|
struct rtrs_srv_mr *srv_mr = &srv_path->mrs[srv_path->mrs_num];
|
|
struct scatterlist *s;
|
|
- int nr, nr_sgt, chunks;
|
|
+ int nr, nr_sgt, chunks, ind;
|
|
|
|
sgt = &srv_mr->sgt;
|
|
chunks = chunks_per_mr * srv_path->mrs_num;
|
|
@@ -628,7 +622,7 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
|
|
}
|
|
nr = ib_map_mr_sg(mr, sgt->sgl, nr_sgt,
|
|
NULL, max_chunk_size);
|
|
- if (nr != nr_sgt) {
|
|
+ if (nr < nr_sgt) {
|
|
err = nr < 0 ? nr : -EINVAL;
|
|
goto dereg_mr;
|
|
}
|
|
@@ -644,9 +638,24 @@ static int map_cont_bufs(struct rtrs_srv_path *srv_path)
|
|
goto dereg_mr;
|
|
}
|
|
}
|
|
- /* Eventually dma addr for each chunk can be cached */
|
|
- for_each_sg(sgt->sgl, s, nr_sgt, i)
|
|
- srv_path->dma_addr[chunks + i] = sg_dma_address(s);
|
|
+
|
|
+ /*
|
|
+ * Cache DMA addresses by traversing sg entries. If
|
|
+ * regions were merged, an inner loop is required to
|
|
+ * populate the DMA address array by traversing larger
|
|
+ * regions.
|
|
+ */
|
|
+ ind = chunks;
|
|
+ for_each_sg(sgt->sgl, s, nr_sgt, i) {
|
|
+ unsigned int dma_len = sg_dma_len(s);
|
|
+ u64 dma_addr = sg_dma_address(s);
|
|
+ u64 dma_addr_end = dma_addr + dma_len;
|
|
+
|
|
+ do {
|
|
+ srv_path->dma_addr[ind++] = dma_addr;
|
|
+ dma_addr += max_chunk_size;
|
|
+ } while (dma_addr < dma_addr_end);
|
|
+ }
|
|
|
|
ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
|
|
srv_mr->mr = mr;
|
|
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
|
|
index 23cfb98fe90a7b..d119a104a34361 100644
|
|
--- a/drivers/iommu/amd/iommu.c
|
|
+++ b/drivers/iommu/amd/iommu.c
|
|
@@ -941,7 +941,12 @@ static int wait_on_sem(struct amd_iommu *iommu, u64 data)
|
|
{
|
|
int i = 0;
|
|
|
|
- while (*iommu->cmd_sem != data && i < LOOP_TIMEOUT) {
|
|
+ /*
|
|
+ * cmd_sem holds a monotonically non-decreasing completion sequence
|
|
+ * number.
|
|
+ */
|
|
+ while ((__s64)(READ_ONCE(*iommu->cmd_sem) - data) < 0 &&
|
|
+ i < LOOP_TIMEOUT) {
|
|
udelay(1);
|
|
i += 1;
|
|
}
|
|
@@ -1210,14 +1215,13 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
|
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
|
|
|
ret = __iommu_queue_command_sync(iommu, &cmd, false);
|
|
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
|
+
|
|
if (ret)
|
|
- goto out_unlock;
|
|
+ return ret;
|
|
|
|
ret = wait_on_sem(iommu, data);
|
|
|
|
-out_unlock:
|
|
- raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
|
-
|
|
return ret;
|
|
}
|
|
|
|
@@ -2879,13 +2883,18 @@ static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
|
|
raw_spin_lock_irqsave(&iommu->lock, flags);
|
|
ret = __iommu_queue_command_sync(iommu, &cmd, true);
|
|
if (ret)
|
|
- goto out;
|
|
+ goto out_err;
|
|
ret = __iommu_queue_command_sync(iommu, &cmd2, false);
|
|
if (ret)
|
|
- goto out;
|
|
+ goto out_err;
|
|
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
|
+
|
|
wait_on_sem(iommu, data);
|
|
-out:
|
|
+ return;
|
|
+
|
|
+out_err:
|
|
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
|
+ return;
|
|
}
|
|
|
|
static void set_dte_irq_entry(struct amd_iommu *iommu, u16 devid,
|
|
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
index f2260f45728e79..bb7365b4321989 100644
|
|
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
|
|
@@ -443,20 +443,26 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
|
|
*/
|
|
static void arm_smmu_cmdq_shared_lock(struct arm_smmu_cmdq *cmdq)
|
|
{
|
|
- int val;
|
|
-
|
|
/*
|
|
- * We can try to avoid the cmpxchg() loop by simply incrementing the
|
|
- * lock counter. When held in exclusive state, the lock counter is set
|
|
- * to INT_MIN so these increments won't hurt as the value will remain
|
|
- * negative.
|
|
+ * When held in exclusive state, the lock counter is set to INT_MIN
|
|
+ * so these increments won't hurt as the value will remain negative.
|
|
+ * The increment will also signal the exclusive locker that there are
|
|
+ * shared waiters.
|
|
*/
|
|
if (atomic_fetch_inc_relaxed(&cmdq->lock) >= 0)
|
|
return;
|
|
|
|
- do {
|
|
- val = atomic_cond_read_relaxed(&cmdq->lock, VAL >= 0);
|
|
- } while (atomic_cmpxchg_relaxed(&cmdq->lock, val, val + 1) != val);
|
|
+ /*
|
|
+ * Someone else is holding the lock in exclusive state, so wait
|
|
+ * for them to finish. Since we already incremented the lock counter,
|
|
+ * no exclusive lock can be acquired until we finish. We don't need
|
|
+ * the return value since we only care that the exclusive lock is
|
|
+ * released (i.e. the lock counter is non-negative).
|
|
+ * Once the exclusive locker releases the lock, the sign bit will
|
|
+ * be cleared and our increment will make the lock counter positive,
|
|
+ * allowing us to proceed.
|
|
+ */
|
|
+ atomic_cond_read_relaxed(&cmdq->lock, VAL > 0);
|
|
}
|
|
|
|
static void arm_smmu_cmdq_shared_unlock(struct arm_smmu_cmdq *cmdq)
|
|
@@ -483,9 +489,14 @@ static bool arm_smmu_cmdq_shared_tryunlock(struct arm_smmu_cmdq *cmdq)
|
|
__ret; \
|
|
})
|
|
|
|
+/*
|
|
+ * Only clear the sign bit when releasing the exclusive lock this will
|
|
+ * allow any shared_lock() waiters to proceed without the possibility
|
|
+ * of entering the exclusive lock in a tight loop.
|
|
+ */
|
|
#define arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags) \
|
|
({ \
|
|
- atomic_set_release(&cmdq->lock, 0); \
|
|
+ atomic_fetch_andnot_release(INT_MIN, &cmdq->lock); \
|
|
local_irq_restore(flags); \
|
|
})
|
|
|
|
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
|
|
index 8faa93cffac45d..99589ac3b96bc6 100644
|
|
--- a/drivers/iommu/intel/pasid.c
|
|
+++ b/drivers/iommu/intel/pasid.c
|
|
@@ -207,6 +207,9 @@ retry:
|
|
if (!entries)
|
|
return NULL;
|
|
|
|
+ if (!ecap_coherent(info->iommu->ecap))
|
|
+ clflush_cache_range(entries, VTD_PAGE_SIZE);
|
|
+
|
|
/*
|
|
* The pasid directory table entry won't be freed after
|
|
* allocation. No worry about the race with free and
|
|
@@ -218,10 +221,8 @@ retry:
|
|
free_pgtable_page(entries);
|
|
goto retry;
|
|
}
|
|
- if (!ecap_coherent(info->iommu->ecap)) {
|
|
- clflush_cache_range(entries, VTD_PAGE_SIZE);
|
|
+ if (!ecap_coherent(info->iommu->ecap))
|
|
clflush_cache_range(&dir[dir_index].val, sizeof(*dir));
|
|
- }
|
|
}
|
|
|
|
return &entries[index];
|
|
@@ -428,7 +429,7 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu,
|
|
if (!info || !info->ats_enabled)
|
|
return;
|
|
|
|
- if (pci_dev_is_disconnected(to_pci_dev(dev)))
|
|
+ if (!pci_device_is_present(to_pci_dev(dev)))
|
|
return;
|
|
|
|
sid = info->bus << 8 | info->devfn;
|
|
diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c
|
|
index a41c2b13766dc1..9843fe2e5f9eb3 100644
|
|
--- a/drivers/leds/rgb/leds-qcom-lpg.c
|
|
+++ b/drivers/leds/rgb/leds-qcom-lpg.c
|
|
@@ -221,7 +221,7 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern,
|
|
{
|
|
unsigned int idx;
|
|
u16 val;
|
|
- int i;
|
|
+ int i, ret;
|
|
|
|
idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size,
|
|
0, len, 0);
|
|
@@ -231,8 +231,10 @@ static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern,
|
|
for (i = 0; i < len; i++) {
|
|
val = pattern[i].brightness;
|
|
|
|
- regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i),
|
|
- &val, sizeof(val));
|
|
+ ret = regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i),
|
|
+ &val, sizeof(val));
|
|
+ if (ret)
|
|
+ return ret;
|
|
}
|
|
|
|
bitmap_set(lpg->lut_bitmap, idx, len);
|
|
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
|
|
index a2b8839d4e7c5e..a1e02efe93ad29 100644
|
|
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
|
|
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
|
|
@@ -1173,14 +1173,6 @@ static int flexrm_debugfs_stats_show(struct seq_file *file, void *offset)
|
|
|
|
/* ====== FlexRM interrupt handler ===== */
|
|
|
|
-static irqreturn_t flexrm_irq_event(int irq, void *dev_id)
|
|
-{
|
|
- /* We only have MSI for completions so just wakeup IRQ thread */
|
|
- /* Ring related errors will be informed via completion descriptors */
|
|
-
|
|
- return IRQ_WAKE_THREAD;
|
|
-}
|
|
-
|
|
static irqreturn_t flexrm_irq_thread(int irq, void *dev_id)
|
|
{
|
|
flexrm_process_completions(dev_id);
|
|
@@ -1271,10 +1263,8 @@ static int flexrm_startup(struct mbox_chan *chan)
|
|
ret = -ENODEV;
|
|
goto fail_free_cmpl_memory;
|
|
}
|
|
- ret = request_threaded_irq(ring->irq,
|
|
- flexrm_irq_event,
|
|
- flexrm_irq_thread,
|
|
- 0, dev_name(ring->mbox->dev), ring);
|
|
+ ret = request_threaded_irq(ring->irq, NULL, flexrm_irq_thread,
|
|
+ IRQF_ONESHOT, dev_name(ring->mbox->dev), ring);
|
|
if (ret) {
|
|
dev_err(ring->mbox->dev,
|
|
"failed to request ring%d IRQ\n", ring->num);
|
|
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
|
|
index 3ef4dd8adf5db1..5eef59f00abd51 100644
|
|
--- a/drivers/mailbox/imx-mailbox.c
|
|
+++ b/drivers/mailbox/imx-mailbox.c
|
|
@@ -113,6 +113,7 @@ struct imx_mu_dcfg {
|
|
u32 xRR; /* Receive Register0 */
|
|
u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */
|
|
u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */
|
|
+ bool skip_suspend_flag;
|
|
};
|
|
|
|
#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
|
|
@@ -906,6 +907,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
|
|
.xRR = 0x40,
|
|
.xSR = {0x60, 0x60, 0x60, 0x60},
|
|
.xCR = {0x64, 0x64, 0x64, 0x64, 0x64},
|
|
+ .skip_suspend_flag = true,
|
|
};
|
|
|
|
static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
|
|
@@ -986,7 +988,8 @@ static int __maybe_unused imx_mu_suspend_noirq(struct device *dev)
|
|
priv->xcr[i] = imx_mu_read(priv, priv->dcfg->xCR[i]);
|
|
}
|
|
|
|
- priv->suspend = true;
|
|
+ if (!priv->dcfg->skip_suspend_flag)
|
|
+ priv->suspend = true;
|
|
|
|
return 0;
|
|
}
|
|
@@ -1009,7 +1012,8 @@ static int __maybe_unused imx_mu_resume_noirq(struct device *dev)
|
|
imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]);
|
|
}
|
|
|
|
- priv->suspend = false;
|
|
+ if (!priv->dcfg->skip_suspend_flag)
|
|
+ priv->suspend = false;
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
|
|
index 2b7d0bc9207263..1d4191cb913804 100644
|
|
--- a/drivers/mailbox/pcc.c
|
|
+++ b/drivers/mailbox/pcc.c
|
|
@@ -481,7 +481,7 @@ static int pcc_startup(struct mbox_chan *chan)
|
|
|
|
if (pchan->plat_irq > 0) {
|
|
irqflags = pcc_chan_plat_irq_can_be_shared(pchan) ?
|
|
- IRQF_SHARED | IRQF_ONESHOT : 0;
|
|
+ IRQF_SHARED : 0;
|
|
rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq,
|
|
irqflags, MBOX_IRQ_NAME, chan);
|
|
if (unlikely(rc)) {
|
|
diff --git a/drivers/mailbox/sprd-mailbox.c b/drivers/mailbox/sprd-mailbox.c
|
|
index 9ae57de77d4d76..109ff60c4ac749 100644
|
|
--- a/drivers/mailbox/sprd-mailbox.c
|
|
+++ b/drivers/mailbox/sprd-mailbox.c
|
|
@@ -167,6 +167,11 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
+ /* Clear FIFO delivery and overflow status first */
|
|
+ writel(fifo_sts &
|
|
+ (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
|
|
+ priv->inbox_base + SPRD_MBOX_FIFO_RST);
|
|
+
|
|
while (send_sts) {
|
|
id = __ffs(send_sts);
|
|
send_sts &= (send_sts - 1);
|
|
@@ -182,11 +187,6 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
|
|
mbox_chan_txdone(chan, 0);
|
|
}
|
|
|
|
- /* Clear FIFO delivery and overflow status */
|
|
- writel(fifo_sts &
|
|
- (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
|
|
- priv->inbox_base + SPRD_MBOX_FIFO_RST);
|
|
-
|
|
/* Clear irq status */
|
|
writel(SPRD_MBOX_IRQ_CLR, priv->inbox_base + SPRD_MBOX_IRQ_STS);
|
|
|
|
@@ -244,21 +244,19 @@ static int sprd_mbox_startup(struct mbox_chan *chan)
|
|
/* Select outbox FIFO mode and reset the outbox FIFO status */
|
|
writel(0x0, priv->outbox_base + SPRD_MBOX_FIFO_RST);
|
|
|
|
- /* Enable inbox FIFO overflow and delivery interrupt */
|
|
- val = readl(priv->inbox_base + SPRD_MBOX_IRQ_MSK);
|
|
- val &= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ | SPRD_INBOX_FIFO_DELIVER_IRQ);
|
|
+ /* Enable inbox FIFO delivery interrupt */
|
|
+ val = SPRD_INBOX_FIFO_IRQ_MASK;
|
|
+ val &= ~SPRD_INBOX_FIFO_DELIVER_IRQ;
|
|
writel(val, priv->inbox_base + SPRD_MBOX_IRQ_MSK);
|
|
|
|
/* Enable outbox FIFO not empty interrupt */
|
|
- val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK);
|
|
+ val = SPRD_OUTBOX_FIFO_IRQ_MASK;
|
|
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
|
|
writel(val, priv->outbox_base + SPRD_MBOX_IRQ_MSK);
|
|
|
|
/* Enable supplementary outbox as the fundamental one */
|
|
if (priv->supp_base) {
|
|
writel(0x0, priv->supp_base + SPRD_MBOX_FIFO_RST);
|
|
- val = readl(priv->supp_base + SPRD_MBOX_IRQ_MSK);
|
|
- val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
|
|
writel(val, priv->supp_base + SPRD_MBOX_IRQ_MSK);
|
|
}
|
|
}
|
|
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
|
|
index c3799757bf4a0c..88f119a0a2ae0d 100644
|
|
--- a/drivers/md/dm-exception-store.c
|
|
+++ b/drivers/md/dm-exception-store.c
|
|
@@ -116,7 +116,7 @@ int dm_exception_store_type_register(struct dm_exception_store_type *type)
|
|
if (!__find_exception_store_type(type->name))
|
|
list_add(&type->list, &_exception_store_types);
|
|
else
|
|
- r = -EEXIST;
|
|
+ r = -EBUSY;
|
|
spin_unlock(&_lock);
|
|
|
|
return r;
|
|
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
|
|
index 6442d41622eff9..be1bf38654156d 100644
|
|
--- a/drivers/md/dm-integrity.c
|
|
+++ b/drivers/md/dm-integrity.c
|
|
@@ -2313,7 +2313,7 @@ offload_to_thread:
|
|
|
|
new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
|
|
if (unlikely(new_pos != NOT_FOUND) ||
|
|
- unlikely(next_sector < dio->range.logical_sector - dio->range.n_sectors)) {
|
|
+ unlikely(next_sector < dio->range.logical_sector + dio->range.n_sectors)) {
|
|
remove_range_unlocked(ic, &dio->range);
|
|
spin_unlock_irq(&ic->endio_wait.lock);
|
|
queue_work(ic->commit_wq, &ic->commit_work);
|
|
@@ -3258,14 +3258,27 @@ static void dm_integrity_resume(struct dm_target *ti)
|
|
struct dm_integrity_c *ic = ti->private;
|
|
__u64 old_provided_data_sectors = le64_to_cpu(ic->sb->provided_data_sectors);
|
|
int r;
|
|
+ __le32 flags;
|
|
|
|
DEBUG_print("resume\n");
|
|
|
|
ic->wrote_to_journal = false;
|
|
|
|
+ flags = ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING);
|
|
+ r = sync_rw_sb(ic, REQ_OP_READ);
|
|
+ if (r)
|
|
+ dm_integrity_io_error(ic, "reading superblock", r);
|
|
+ if ((ic->sb->flags & flags) != flags) {
|
|
+ ic->sb->flags |= flags;
|
|
+ r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
|
|
+ if (unlikely(r))
|
|
+ dm_integrity_io_error(ic, "writing superblock", r);
|
|
+ }
|
|
+
|
|
if (ic->provided_data_sectors != old_provided_data_sectors) {
|
|
if (ic->provided_data_sectors > old_provided_data_sectors &&
|
|
ic->mode == 'B' &&
|
|
+ ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP) &&
|
|
ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) {
|
|
rw_journal_sectors(ic, REQ_OP_READ, 0,
|
|
ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
|
|
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
|
|
index f7f9c2100937ba..e215478bcee048 100644
|
|
--- a/drivers/md/dm-log.c
|
|
+++ b/drivers/md/dm-log.c
|
|
@@ -121,7 +121,7 @@ int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
|
|
if (!__find_dirty_log_type(type->name))
|
|
list_add(&type->list, &_log_types);
|
|
else
|
|
- r = -EEXIST;
|
|
+ r = -EBUSY;
|
|
spin_unlock(&_lock);
|
|
|
|
return r;
|
|
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
|
|
index bea3cda9938e97..9a03658aec202c 100644
|
|
--- a/drivers/md/dm-mpath.c
|
|
+++ b/drivers/md/dm-mpath.c
|
|
@@ -220,6 +220,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
|
|
mutex_init(&m->work_mutex);
|
|
|
|
m->queue_mode = DM_TYPE_NONE;
|
|
+ m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
|
|
|
|
m->ti = ti;
|
|
ti->private = m;
|
|
@@ -252,7 +253,6 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m)
|
|
set_bit(MPATHF_QUEUE_IO, &m->flags);
|
|
atomic_set(&m->pg_init_in_progress, 0);
|
|
atomic_set(&m->pg_init_count, 0);
|
|
- m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
|
|
init_waitqueue_head(&m->pg_init_wait);
|
|
|
|
return 0;
|
|
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
|
|
index 3e4cb81ce512c7..78f98545ca72d0 100644
|
|
--- a/drivers/md/dm-path-selector.c
|
|
+++ b/drivers/md/dm-path-selector.c
|
|
@@ -107,7 +107,7 @@ int dm_register_path_selector(struct path_selector_type *pst)
|
|
|
|
if (__find_path_selector_type(pst->name)) {
|
|
kfree(psi);
|
|
- r = -EEXIST;
|
|
+ r = -EBUSY;
|
|
} else
|
|
list_add(&psi->list, &_path_selectors);
|
|
|
|
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
|
|
index 499f8cc8a39fbf..29d6ee68d4dfbc 100644
|
|
--- a/drivers/md/dm-rq.c
|
|
+++ b/drivers/md/dm-rq.c
|
|
@@ -109,14 +109,21 @@ static void end_clone_bio(struct bio *clone)
|
|
*/
|
|
tio->completed += nr_bytes;
|
|
|
|
+ if (!is_last)
|
|
+ return;
|
|
+ /*
|
|
+ * At this moment we know this is the last bio of the cloned request,
|
|
+ * and all cloned bios have been released, so reset the clone request's
|
|
+ * bio pointer to avoid double free.
|
|
+ */
|
|
+ tio->clone->bio = NULL;
|
|
+ exit:
|
|
/*
|
|
* Update the original request.
|
|
* Do not use blk_mq_end_request() here, because it may complete
|
|
* the original request before the clone, and break the ordering.
|
|
*/
|
|
- if (is_last)
|
|
- exit:
|
|
- blk_update_request(tio->orig, BLK_STS_OK, tio->completed);
|
|
+ blk_update_request(tio->orig, BLK_STS_OK, tio->completed);
|
|
}
|
|
|
|
static struct dm_rq_target_io *tio_from_request(struct request *rq)
|
|
@@ -278,8 +285,7 @@ static void dm_complete_request(struct request *rq, blk_status_t error)
|
|
struct dm_rq_target_io *tio = tio_from_request(rq);
|
|
|
|
tio->error = error;
|
|
- if (likely(!blk_should_fake_timeout(rq->q)))
|
|
- blk_mq_complete_request(rq);
|
|
+ blk_mq_complete_request(rq);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
|
|
index 27e2992ff24927..4d1f04b40653f9 100644
|
|
--- a/drivers/md/dm-target.c
|
|
+++ b/drivers/md/dm-target.c
|
|
@@ -88,7 +88,7 @@ int dm_register_target(struct target_type *tt)
|
|
if (__find_target_type(tt->name)) {
|
|
DMERR("%s: '%s' target already registered",
|
|
__func__, tt->name);
|
|
- rv = -EEXIST;
|
|
+ rv = -EBUSY;
|
|
} else {
|
|
list_add(&tt->list, &_targets);
|
|
}
|
|
diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c
|
|
index e8a9432057dce1..17be483595642c 100644
|
|
--- a/drivers/md/dm-unstripe.c
|
|
+++ b/drivers/md/dm-unstripe.c
|
|
@@ -117,7 +117,7 @@ static void unstripe_dtr(struct dm_target *ti)
|
|
static sector_t map_to_core(struct dm_target *ti, struct bio *bio)
|
|
{
|
|
struct unstripe_c *uc = ti->private;
|
|
- sector_t sector = bio->bi_iter.bi_sector;
|
|
+ sector_t sector = dm_target_offset(ti, bio->bi_iter.bi_sector);
|
|
sector_t tmp_sector = sector;
|
|
|
|
/* Shift us up to the right "row" on the stripe */
|
|
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
|
|
index 4474352ad3d138..9275053b387b0d 100644
|
|
--- a/drivers/md/dm-verity-fec.c
|
|
+++ b/drivers/md/dm-verity-fec.c
|
|
@@ -566,9 +566,9 @@ void verity_fec_dtr(struct dm_verity *v)
|
|
mempool_exit(&f->output_pool);
|
|
kmem_cache_destroy(f->cache);
|
|
|
|
- if (f->data_bufio)
|
|
+ if (!IS_ERR_OR_NULL(f->data_bufio))
|
|
dm_bufio_client_destroy(f->data_bufio);
|
|
- if (f->bufio)
|
|
+ if (!IS_ERR_OR_NULL(f->bufio))
|
|
dm_bufio_client_destroy(f->bufio);
|
|
|
|
if (f->dev)
|
|
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
|
|
index f0c4c3553c0166..1d03536fded005 100644
|
|
--- a/drivers/md/dm.c
|
|
+++ b/drivers/md/dm.c
|
|
@@ -1363,6 +1363,8 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone)
|
|
if (!tgt_clone)
|
|
tgt_clone = clone;
|
|
|
|
+ bio_clone_blkg_association(tgt_clone, io->orig_bio);
|
|
+
|
|
/*
|
|
* Account io->origin_bio to DM dev on behalf of target
|
|
* that took ownership of IO with DM_MAPIO_SUBMITTED.
|
|
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
|
|
index 1f1991634d0a21..ace28eb81111cf 100644
|
|
--- a/drivers/md/md-bitmap.c
|
|
+++ b/drivers/md/md-bitmap.c
|
|
@@ -2224,6 +2224,7 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
|
|
memcpy(page_address(store.sb_page),
|
|
page_address(bitmap->storage.sb_page),
|
|
sizeof(bitmap_super_t));
|
|
+ mutex_lock(&bitmap->mddev->bitmap_info.mutex);
|
|
spin_lock_irq(&bitmap->counts.lock);
|
|
md_bitmap_file_unmap(&bitmap->storage);
|
|
bitmap->storage = store;
|
|
@@ -2331,7 +2332,7 @@ int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
|
|
set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
|
|
}
|
|
spin_unlock_irq(&bitmap->counts.lock);
|
|
-
|
|
+ mutex_unlock(&bitmap->mddev->bitmap_info.mutex);
|
|
if (!init) {
|
|
md_bitmap_unplug(bitmap);
|
|
bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
|
|
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
|
|
index 6a89f6b5d64f98..54f90afbafe967 100644
|
|
--- a/drivers/md/md-cluster.c
|
|
+++ b/drivers/md/md-cluster.c
|
|
@@ -532,8 +532,13 @@ static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg
|
|
|
|
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
|
|
|
|
- /* daemaon thread must exist */
|
|
thread = rcu_dereference_protected(mddev->thread, true);
|
|
+ if (!thread) {
|
|
+ pr_warn("md-cluster: Received metadata update but MD thread is not ready\n");
|
|
+ dlm_unlock_sync(cinfo->no_new_dev_lockres);
|
|
+ return;
|
|
+ }
|
|
+
|
|
wait_event(thread->wqueue,
|
|
(got_lock = mddev_trylock(mddev)) ||
|
|
test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state));
|
|
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
|
|
index a75d090a7fa15a..8546ef98bfa7ed 100644
|
|
--- a/drivers/md/raid10.c
|
|
+++ b/drivers/md/raid10.c
|
|
@@ -3533,7 +3533,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|
!test_bit(In_sync, &rdev->flags))
|
|
continue;
|
|
/* This is where we read from */
|
|
- any_working = 1;
|
|
sector = r10_bio->devs[j].addr;
|
|
|
|
if (is_badblock(rdev, sector, max_sync,
|
|
@@ -3548,6 +3547,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|
continue;
|
|
}
|
|
}
|
|
+ any_working = 1;
|
|
bio = r10_bio->devs[0].bio;
|
|
bio->bi_next = biolist;
|
|
biolist = bio;
|
|
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
|
|
index 9ce5f010de3f84..804fb339f73551 100644
|
|
--- a/drivers/media/dvb-core/dmxdev.c
|
|
+++ b/drivers/media/dvb-core/dmxdev.c
|
|
@@ -396,11 +396,11 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
|
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
|
|
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
|
|
buffer1, buffer1_len,
|
|
- buffer_flags);
|
|
+ buffer_flags, true);
|
|
if (ret == buffer1_len)
|
|
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
|
|
buffer2, buffer2_len,
|
|
- buffer_flags);
|
|
+ buffer_flags, true);
|
|
} else {
|
|
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
|
|
buffer1, buffer1_len);
|
|
@@ -451,10 +451,10 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
|
|
|
if (dvb_vb2_is_streaming(ctx)) {
|
|
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
|
|
- buffer_flags);
|
|
+ buffer_flags, false);
|
|
if (ret == buffer1_len)
|
|
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
|
|
- buffer_flags);
|
|
+ buffer_flags, false);
|
|
} else {
|
|
if (buffer->error) {
|
|
spin_unlock(&dmxdevfilter->dev->lock);
|
|
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
|
|
index 909df82fed3329..8950e608a87a41 100644
|
|
--- a/drivers/media/dvb-core/dvb_vb2.c
|
|
+++ b/drivers/media/dvb-core/dvb_vb2.c
|
|
@@ -252,7 +252,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx)
|
|
|
|
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
|
|
const unsigned char *src, int len,
|
|
- enum dmx_buffer_flags *buffer_flags)
|
|
+ enum dmx_buffer_flags *buffer_flags,
|
|
+ bool flush)
|
|
{
|
|
unsigned long flags = 0;
|
|
void *vbuf = NULL;
|
|
@@ -309,7 +310,7 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
|
|
}
|
|
}
|
|
|
|
- if (ctx->nonblocking && ctx->buf) {
|
|
+ if (flush && ctx->buf) {
|
|
vb2_set_plane_payload(&ctx->buf->vb, 0, ll);
|
|
vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
|
|
list_del(&ctx->buf->list);
|
|
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
|
|
index ecb0e7b1f2a5fc..4778ae653ca9dd 100644
|
|
--- a/drivers/media/i2c/adv7180.c
|
|
+++ b/drivers/media/i2c/adv7180.c
|
|
@@ -471,6 +471,13 @@ static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
|
|
fi->interval.denominator = 25;
|
|
}
|
|
|
|
+ /*
|
|
+ * If the de-interlacer is active, the chip produces full video frames
|
|
+ * at the field rate.
|
|
+ */
|
|
+ if (state->field == V4L2_FIELD_NONE)
|
|
+ fi->interval.denominator *= 2;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
|
|
index 4d31b2bb8f09f6..ae8309bd5e4d52 100644
|
|
--- a/drivers/media/i2c/ccs/ccs-core.c
|
|
+++ b/drivers/media/i2c/ccs/ccs-core.c
|
|
@@ -2386,7 +2386,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
|
|
* CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height;
|
|
max_m = crops[CCS_PAD_SINK]->width
|
|
* CCS_LIM(sensor, SCALER_N_MIN)
|
|
- / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE);
|
|
+ / (CCS_LIM(sensor, MIN_X_OUTPUT_SIZE) ?: 1);
|
|
|
|
a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN),
|
|
CCS_LIM(sensor, SCALER_M_MAX));
|
|
@@ -3530,7 +3530,21 @@ static int ccs_probe(struct i2c_client *client)
|
|
sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN);
|
|
|
|
/* prepare PLL configuration input values */
|
|
- sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY;
|
|
+ switch (sensor->hwcfg.csi_signalling_mode) {
|
|
+ case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY:
|
|
+ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_CPHY;
|
|
+ break;
|
|
+ case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY:
|
|
+ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK:
|
|
+ case SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE:
|
|
+ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(&client->dev, "unsupported signalling mode %u\n",
|
|
+ sensor->hwcfg.csi_signalling_mode);
|
|
+ rval = -EINVAL;
|
|
+ goto out_cleanup;
|
|
+ }
|
|
sensor->pll.csi2.lanes = sensor->hwcfg.lanes;
|
|
if (CCS_LIM(sensor, CLOCK_CALCULATION) &
|
|
CCS_CLOCK_CALCULATION_LANE_SPEED) {
|
|
diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c
|
|
index 9afe9bf50334a9..a0e8b1ed0fc93f 100644
|
|
--- a/drivers/media/i2c/ov01a10.c
|
|
+++ b/drivers/media/i2c/ov01a10.c
|
|
@@ -17,7 +17,7 @@
|
|
#include <media/v4l2-fwnode.h>
|
|
|
|
#define OV01A10_LINK_FREQ_400MHZ 400000000ULL
|
|
-#define OV01A10_SCLK 40000000LL
|
|
+#define OV01A10_SCLK 80000000LL
|
|
#define OV01A10_DATA_LANES 1
|
|
|
|
#define OV01A10_REG_CHIP_ID 0x300a
|
|
@@ -49,7 +49,7 @@
|
|
/* analog gain controls */
|
|
#define OV01A10_REG_ANALOG_GAIN 0x3508
|
|
#define OV01A10_ANAL_GAIN_MIN 0x100
|
|
-#define OV01A10_ANAL_GAIN_MAX 0xffff
|
|
+#define OV01A10_ANAL_GAIN_MAX 0x3fff
|
|
#define OV01A10_ANAL_GAIN_STEP 1
|
|
|
|
/* digital gain controls */
|
|
@@ -58,7 +58,7 @@
|
|
#define OV01A10_REG_DIGITAL_GAIN_GR 0x3513
|
|
#define OV01A10_REG_DIGITAL_GAIN_R 0x3516
|
|
#define OV01A10_DGTL_GAIN_MIN 0
|
|
-#define OV01A10_DGTL_GAIN_MAX 0x3ffff
|
|
+#define OV01A10_DGTL_GAIN_MAX 0x3fff
|
|
#define OV01A10_DGTL_GAIN_STEP 1
|
|
#define OV01A10_DGTL_GAIN_DEFAULT 1024
|
|
|
|
@@ -76,6 +76,15 @@
|
|
#define OV01A10_REG_X_WIN 0x3811
|
|
#define OV01A10_REG_Y_WIN 0x3813
|
|
|
|
+/*
|
|
+ * The native ov01a10 bayer-pattern is GBRG, but there was a driver bug enabling
|
|
+ * hflip/mirroring by default resulting in BGGR. Because of this bug Intel's
|
|
+ * proprietary IPU6 userspace stack expects BGGR. So we report BGGR to not break
|
|
+ * userspace and fix things up by shifting the crop window-x coordinate by 1
|
|
+ * when hflip is *disabled*.
|
|
+ */
|
|
+#define OV01A10_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR10_1X10
|
|
+
|
|
struct ov01a10_reg {
|
|
u16 address;
|
|
u8 val;
|
|
@@ -186,14 +195,14 @@ static const struct ov01a10_reg sensor_1280x800_setting[] = {
|
|
{0x380e, 0x03},
|
|
{0x380f, 0x80},
|
|
{0x3810, 0x00},
|
|
- {0x3811, 0x08},
|
|
+ {0x3811, 0x09},
|
|
{0x3812, 0x00},
|
|
{0x3813, 0x08},
|
|
{0x3814, 0x01},
|
|
{0x3815, 0x01},
|
|
{0x3816, 0x01},
|
|
{0x3817, 0x01},
|
|
- {0x3820, 0xa0},
|
|
+ {0x3820, 0xa8},
|
|
{0x3822, 0x13},
|
|
{0x3832, 0x28},
|
|
{0x3833, 0x10},
|
|
@@ -241,9 +250,8 @@ static const struct ov01a10_reg sensor_1280x800_setting[] = {
|
|
static const char * const ov01a10_test_pattern_menu[] = {
|
|
"Disabled",
|
|
"Color Bar",
|
|
- "Top-Bottom Darker Color Bar",
|
|
- "Right-Left Darker Color Bar",
|
|
- "Color Bar type 4",
|
|
+ "Left-Right Darker Color Bar",
|
|
+ "Bottom-Top Darker Color Bar",
|
|
};
|
|
|
|
static const s64 link_freq_menu_items[] = {
|
|
@@ -401,10 +409,8 @@ static int ov01a10_update_digital_gain(struct ov01a10 *ov01a10, u32 d_gain)
|
|
|
|
static int ov01a10_test_pattern(struct ov01a10 *ov01a10, u32 pattern)
|
|
{
|
|
- if (!pattern)
|
|
- return 0;
|
|
-
|
|
- pattern = (pattern - 1) | OV01A10_TEST_PATTERN_ENABLE;
|
|
+ if (pattern)
|
|
+ pattern |= OV01A10_TEST_PATTERN_ENABLE;
|
|
|
|
return ov01a10_write_reg(ov01a10, OV01A10_REG_TEST_PATTERN, 1, pattern);
|
|
}
|
|
@@ -415,7 +421,7 @@ static int ov01a10_set_hflip(struct ov01a10 *ov01a10, u32 hflip)
|
|
int ret;
|
|
u32 val, offset;
|
|
|
|
- offset = hflip ? 0x9 : 0x8;
|
|
+ offset = hflip ? 0x8 : 0x9;
|
|
ret = ov01a10_write_reg(ov01a10, OV01A10_REG_X_WIN, 1, offset);
|
|
if (ret)
|
|
return ret;
|
|
@@ -424,8 +430,8 @@ static int ov01a10_set_hflip(struct ov01a10 *ov01a10, u32 hflip)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- val = hflip ? val | FIELD_PREP(OV01A10_HFLIP_MASK, 0x1) :
|
|
- val & ~OV01A10_HFLIP_MASK;
|
|
+ val = hflip ? val & ~OV01A10_HFLIP_MASK :
|
|
+ val | FIELD_PREP(OV01A10_HFLIP_MASK, 0x1);
|
|
|
|
return ov01a10_write_reg(ov01a10, OV01A10_REG_FORMAT1, 1, val);
|
|
}
|
|
@@ -614,7 +620,7 @@ static void ov01a10_update_pad_format(const struct ov01a10_mode *mode,
|
|
{
|
|
fmt->width = mode->width;
|
|
fmt->height = mode->height;
|
|
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
|
+ fmt->code = OV01A10_MEDIA_BUS_FMT;
|
|
fmt->field = V4L2_FIELD_NONE;
|
|
fmt->colorspace = V4L2_COLORSPACE_RAW;
|
|
}
|
|
@@ -800,7 +806,7 @@ static int ov01a10_enum_mbus_code(struct v4l2_subdev *sd,
|
|
if (code->index > 0)
|
|
return -EINVAL;
|
|
|
|
- code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
|
+ code->code = OV01A10_MEDIA_BUS_FMT;
|
|
|
|
return 0;
|
|
}
|
|
@@ -810,7 +816,7 @@ static int ov01a10_enum_frame_size(struct v4l2_subdev *sd,
|
|
struct v4l2_subdev_frame_size_enum *fse)
|
|
{
|
|
if (fse->index >= ARRAY_SIZE(supported_modes) ||
|
|
- fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
|
|
+ fse->code != OV01A10_MEDIA_BUS_FMT)
|
|
return -EINVAL;
|
|
|
|
fse->min_width = supported_modes[fse->index].width;
|
|
@@ -903,6 +909,7 @@ static void ov01a10_remove(struct i2c_client *client)
|
|
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
|
|
|
v4l2_async_unregister_subdev(sd);
|
|
+ v4l2_subdev_cleanup(sd);
|
|
media_entity_cleanup(&sd->entity);
|
|
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
|
|
|
@@ -973,6 +980,7 @@ static int ov01a10_probe(struct i2c_client *client)
|
|
err_pm_disable:
|
|
pm_runtime_disable(dev);
|
|
pm_runtime_set_suspended(&client->dev);
|
|
+ v4l2_subdev_cleanup(&ov01a10->sd);
|
|
|
|
err_media_entity_cleanup:
|
|
media_entity_cleanup(&ov01a10->sd.entity);
|
|
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
|
|
index 8de398423b7cb9..b8033fb7aa30e8 100644
|
|
--- a/drivers/media/i2c/ov5647.c
|
|
+++ b/drivers/media/i2c/ov5647.c
|
|
@@ -69,11 +69,11 @@
|
|
#define OV5647_NATIVE_HEIGHT 1956U
|
|
|
|
#define OV5647_PIXEL_ARRAY_LEFT 16U
|
|
-#define OV5647_PIXEL_ARRAY_TOP 16U
|
|
+#define OV5647_PIXEL_ARRAY_TOP 6U
|
|
#define OV5647_PIXEL_ARRAY_WIDTH 2592U
|
|
#define OV5647_PIXEL_ARRAY_HEIGHT 1944U
|
|
|
|
-#define OV5647_VBLANK_MIN 4
|
|
+#define OV5647_VBLANK_MIN 24
|
|
#define OV5647_VTS_MAX 32767
|
|
|
|
#define OV5647_EXPOSURE_MIN 4
|
|
@@ -509,7 +509,7 @@ static const struct ov5647_mode ov5647_modes[] = {
|
|
{
|
|
.format = {
|
|
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
|
|
- .colorspace = V4L2_COLORSPACE_SRGB,
|
|
+ .colorspace = V4L2_COLORSPACE_RAW,
|
|
.field = V4L2_FIELD_NONE,
|
|
.width = 2592,
|
|
.height = 1944
|
|
@@ -530,7 +530,7 @@ static const struct ov5647_mode ov5647_modes[] = {
|
|
{
|
|
.format = {
|
|
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
|
|
- .colorspace = V4L2_COLORSPACE_SRGB,
|
|
+ .colorspace = V4L2_COLORSPACE_RAW,
|
|
.field = V4L2_FIELD_NONE,
|
|
.width = 1920,
|
|
.height = 1080
|
|
@@ -551,7 +551,7 @@ static const struct ov5647_mode ov5647_modes[] = {
|
|
{
|
|
.format = {
|
|
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
|
|
- .colorspace = V4L2_COLORSPACE_SRGB,
|
|
+ .colorspace = V4L2_COLORSPACE_RAW,
|
|
.field = V4L2_FIELD_NONE,
|
|
.width = 1296,
|
|
.height = 972
|
|
@@ -572,7 +572,7 @@ static const struct ov5647_mode ov5647_modes[] = {
|
|
{
|
|
.format = {
|
|
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
|
|
- .colorspace = V4L2_COLORSPACE_SRGB,
|
|
+ .colorspace = V4L2_COLORSPACE_RAW,
|
|
.field = V4L2_FIELD_NONE,
|
|
.width = 640,
|
|
.height = 480
|
|
@@ -583,7 +583,7 @@ static const struct ov5647_mode ov5647_modes[] = {
|
|
.width = 2560,
|
|
.height = 1920,
|
|
},
|
|
- .pixel_rate = 55000000,
|
|
+ .pixel_rate = 58333000,
|
|
.hts = 1852,
|
|
.vts = 0x1f8,
|
|
.reg_list = ov5647_640x480_10bpp,
|
|
@@ -1297,6 +1297,8 @@ static int ov5647_init_controls(struct ov5647 *sensor)
|
|
|
|
v4l2_ctrl_handler_init(&sensor->ctrls, 9);
|
|
|
|
+ sensor->ctrls.lock = &sensor->lock;
|
|
+
|
|
v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
|
|
V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
|
|
|
|
@@ -1430,15 +1432,15 @@ static int ov5647_probe(struct i2c_client *client)
|
|
|
|
sensor->mode = OV5647_DEFAULT_MODE;
|
|
|
|
- ret = ov5647_init_controls(sensor);
|
|
- if (ret)
|
|
- goto mutex_destroy;
|
|
-
|
|
sd = &sensor->sd;
|
|
v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
|
|
sd->internal_ops = &ov5647_subdev_internal_ops;
|
|
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
|
|
|
+ ret = ov5647_init_controls(sensor);
|
|
+ if (ret)
|
|
+ goto mutex_destroy;
|
|
+
|
|
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
|
|
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
|
ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
|
|
diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c
|
|
index 996be3960af3f8..d17f3b9270ef1e 100644
|
|
--- a/drivers/media/i2c/tw9903.c
|
|
+++ b/drivers/media/i2c/tw9903.c
|
|
@@ -228,6 +228,7 @@ static int tw9903_probe(struct i2c_client *client)
|
|
|
|
if (write_regs(sd, initial_registers) < 0) {
|
|
v4l2_err(client, "error initializing TW9903\n");
|
|
+ v4l2_ctrl_handler_free(hdl);
|
|
return -EINVAL;
|
|
}
|
|
|
|
diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c
|
|
index 25c625f6d6e488..13cd1b25ef601a 100644
|
|
--- a/drivers/media/i2c/tw9906.c
|
|
+++ b/drivers/media/i2c/tw9906.c
|
|
@@ -196,6 +196,7 @@ static int tw9906_probe(struct i2c_client *client)
|
|
|
|
if (write_regs(sd, initial_registers) < 0) {
|
|
v4l2_err(client, "error initializing TW9906\n");
|
|
+ v4l2_ctrl_handler_free(hdl);
|
|
return -EINVAL;
|
|
}
|
|
|
|
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
|
|
index 25dc8d4dc5b73a..717fc6c9ef21f8 100644
|
|
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
|
|
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
|
|
@@ -392,8 +392,10 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
|
|
chip->period_size, chip->num_periods, 1);
|
|
- if (ret < 0)
|
|
+ if (ret < 0) {
|
|
+ cx23885_alsa_dma_unmap(chip);
|
|
goto error;
|
|
+ }
|
|
|
|
/* Loop back to start of program */
|
|
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
|
|
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
|
|
index a42f0c03a7ca86..f463365163b7ec 100644
|
|
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
|
|
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
|
|
@@ -535,6 +535,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
|
|
chip->period_size, chip->num_periods, 1);
|
|
if (ret < 0) {
|
|
pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
|
|
+ cx25821_alsa_dma_unmap(chip);
|
|
goto error;
|
|
}
|
|
|
|
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
|
|
index 6627fa9166d301..a7336be444748a 100644
|
|
--- a/drivers/media/pci/cx25821/cx25821-core.c
|
|
+++ b/drivers/media/pci/cx25821/cx25821-core.c
|
|
@@ -908,6 +908,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
|
|
|
|
if (!dev->lmmio) {
|
|
CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
|
|
+ release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
|
|
cx25821_iounmap(dev);
|
|
return -ENOMEM;
|
|
}
|
|
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
|
|
index 29fb1311e44349..4e574d8390b4d7 100644
|
|
--- a/drivers/media/pci/cx88/cx88-alsa.c
|
|
+++ b/drivers/media/pci/cx88/cx88-alsa.c
|
|
@@ -483,8 +483,10 @@ static int snd_cx88_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
|
|
chip->period_size, chip->num_periods, 1);
|
|
- if (ret < 0)
|
|
+ if (ret < 0) {
|
|
+ cx88_alsa_dma_unmap(chip);
|
|
goto error;
|
|
+ }
|
|
|
|
/* Loop back to start of program */
|
|
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
|
diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c
|
|
index 1b7c22a9bc94f1..8f53946c67928f 100644
|
|
--- a/drivers/media/pci/solo6x10/solo6x10-tw28.c
|
|
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c
|
|
@@ -166,7 +166,7 @@ static const u8 tbl_tw2865_pal_template[] = {
|
|
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
|
|
};
|
|
|
|
-#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
|
|
+#define is_tw286x(__solo, __id) (!((__solo)->tw2815 & (1U << (__id))))
|
|
|
|
static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
|
|
u8 tw_off)
|
|
@@ -686,6 +686,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
|
|
chip_num = ch / 4;
|
|
ch %= 4;
|
|
|
|
+ if (chip_num >= TW_NUM_CHIP)
|
|
+ return -EINVAL;
|
|
+
|
|
if (val > 255 || val < 0)
|
|
return -ERANGE;
|
|
|
|
@@ -758,6 +761,9 @@ int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
|
|
chip_num = ch / 4;
|
|
ch %= 4;
|
|
|
|
+ if (chip_num >= TW_NUM_CHIP)
|
|
+ return -EINVAL;
|
|
+
|
|
switch (ctrl) {
|
|
case V4L2_CID_SHARPNESS:
|
|
/* Only 286x has sharpness */
|
|
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
|
|
index 4f438eaa7d385a..d7e477f0eb4300 100644
|
|
--- a/drivers/media/platform/amphion/vdec.c
|
|
+++ b/drivers/media/platform/amphion/vdec.c
|
|
@@ -630,6 +630,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd
|
|
switch (cmd->cmd) {
|
|
case V4L2_DEC_CMD_START:
|
|
vdec_cmd_start(inst);
|
|
+ vb2_clear_last_buffer_dequeued(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
|
|
break;
|
|
case V4L2_DEC_CMD_STOP:
|
|
vdec_cmd_stop(inst);
|
|
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
|
|
index 917cdf38f230e7..98540015b1cca6 100644
|
|
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
|
|
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
|
|
@@ -194,11 +194,17 @@ static int mtk_mdp_probe(struct platform_device *pdev)
|
|
}
|
|
|
|
mdp->vpu_dev = vpu_get_plat_device(pdev);
|
|
+ if (!mdp->vpu_dev) {
|
|
+ dev_err(&pdev->dev, "Failed to get vpu device\n");
|
|
+ ret = -ENODEV;
|
|
+ goto err_vpu_get_dev;
|
|
+ }
|
|
+
|
|
ret = vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp,
|
|
VPU_RST_MDP);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "Failed to register reset handler\n");
|
|
- goto err_m2m_register;
|
|
+ goto err_reg_handler;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, mdp);
|
|
@@ -206,7 +212,7 @@ static int mtk_mdp_probe(struct platform_device *pdev)
|
|
ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "Failed to set vb2 dma mag seg size\n");
|
|
- goto err_m2m_register;
|
|
+ goto err_reg_handler;
|
|
}
|
|
|
|
pm_runtime_enable(dev);
|
|
@@ -214,6 +220,12 @@ static int mtk_mdp_probe(struct platform_device *pdev)
|
|
|
|
return 0;
|
|
|
|
+err_reg_handler:
|
|
+ platform_device_put(mdp->vpu_dev);
|
|
+
|
|
+err_vpu_get_dev:
|
|
+ mtk_mdp_unregister_m2m_device(mdp);
|
|
+
|
|
err_m2m_register:
|
|
v4l2_device_unregister(&mdp->v4l2_dev);
|
|
|
|
@@ -242,6 +254,7 @@ static void mtk_mdp_remove(struct platform_device *pdev)
|
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
|
|
+ platform_device_put(mdp->vpu_dev);
|
|
mtk_mdp_unregister_m2m_device(mdp);
|
|
v4l2_device_unregister(&mdp->v4l2_dev);
|
|
|
|
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
|
|
index e29c9c58f3dac9..fb629a7cd81271 100644
|
|
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
|
|
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
|
|
@@ -475,6 +475,12 @@ static int mtk_vdec_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
mtk_v4l2_vdec_err(ctx, "VP9: bit_depth:%d", frame->bit_depth);
|
|
return -EINVAL;
|
|
}
|
|
+
|
|
+ if (!(frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) ||
|
|
+ !(frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)) {
|
|
+ mtk_v4l2_vdec_err(ctx, "VP9: only 420 subsampling is supported");
|
|
+ return -EINVAL;
|
|
+ }
|
|
break;
|
|
case V4L2_CID_STATELESS_AV1_SEQUENCE:
|
|
seq = (struct v4l2_ctrl_av1_sequence *)hdr_ctrl->p_new.p;
|
|
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
|
|
index eb381fa6e7d14e..ca9d859376d3ea 100644
|
|
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
|
|
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
|
|
@@ -865,7 +865,7 @@ static void vb2ops_venc_buf_queue(struct vb2_buffer *vb)
|
|
static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
|
|
{
|
|
struct mtk_vcodec_enc_ctx *ctx = vb2_get_drv_priv(q);
|
|
- struct venc_enc_param param;
|
|
+ struct venc_enc_param param = { };
|
|
int ret;
|
|
int i;
|
|
|
|
@@ -1021,7 +1021,7 @@ static int mtk_venc_encode_header(void *priv)
|
|
int ret;
|
|
struct vb2_v4l2_buffer *src_buf, *dst_buf;
|
|
struct mtk_vcodec_mem bs_buf;
|
|
- struct venc_done_result enc_result;
|
|
+ struct venc_done_result enc_result = { };
|
|
|
|
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
|
|
if (!dst_buf) {
|
|
@@ -1142,7 +1142,7 @@ static void mtk_venc_worker(struct work_struct *work)
|
|
struct vb2_v4l2_buffer *src_buf, *dst_buf;
|
|
struct venc_frm_buf frm_buf;
|
|
struct mtk_vcodec_mem bs_buf;
|
|
- struct venc_done_result enc_result;
|
|
+ struct venc_done_result enc_result = { };
|
|
int ret, i;
|
|
|
|
/* check dst_buf, dst_buf may be removed in device_run
|
|
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
|
|
index 8ddb8016434ae9..98d7398db95687 100644
|
|
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
|
|
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
|
|
@@ -223,11 +223,13 @@ static irqreturn_t vfe_isr(int irq, void *dev)
|
|
writel_relaxed(status, vfe->base + VFE_BUS_IRQ_CLEAR(0));
|
|
writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
|
|
|
|
- /* Loop through all WMs IRQs */
|
|
- for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) {
|
|
+ for (i = 0; i < MAX_VFE_OUTPUT_LINES; i++) {
|
|
if (status & BUS_IRQ_MASK_0_RDI_RUP(vfe, i))
|
|
vfe_isr_reg_update(vfe, i);
|
|
+ }
|
|
|
|
+ /* Loop through all WMs IRQs */
|
|
+ for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) {
|
|
if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i)))
|
|
vfe_isr_wm_done(vfe, i);
|
|
}
|
|
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
|
|
index 8be056210f1d34..f15c3b322fe4aa 100644
|
|
--- a/drivers/media/platform/qcom/venus/vdec.c
|
|
+++ b/drivers/media/platform/qcom/venus/vdec.c
|
|
@@ -568,7 +568,13 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
|
|
|
|
fdata.buffer_type = HFI_BUFFER_INPUT;
|
|
fdata.flags |= HFI_BUFFERFLAG_EOS;
|
|
- if (IS_V6(inst->core) && is_fw_rev_or_older(inst->core, 1, 0, 87))
|
|
+
|
|
+ /* Send NULL EOS addr for only IRIS2 (SM8250),for firmware <= 1.0.87.
|
|
+ * SC7280 also reports "1.0.<hash>" parsed as 1.0.0; restricting to IRIS2
|
|
+ * avoids misapplying this quirk and breaking VP9 decode on SC7280.
|
|
+ */
|
|
+
|
|
+ if (IS_IRIS2(inst->core) && is_fw_rev_or_older(inst->core, 1, 0, 87))
|
|
fdata.device_addr = 0;
|
|
else
|
|
fdata.device_addr = 0xdeadb000;
|
|
@@ -1433,10 +1439,10 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
|
|
inst->drain_active = false;
|
|
inst->codec_state = VENUS_DEC_STATE_STOPPED;
|
|
}
|
|
+ } else {
|
|
+ if (!bytesused)
|
|
+ state = VB2_BUF_STATE_ERROR;
|
|
}
|
|
-
|
|
- if (!bytesused)
|
|
- state = VB2_BUF_STATE_ERROR;
|
|
} else {
|
|
vbuf->sequence = inst->sequence_out++;
|
|
}
|
|
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
|
|
index 3482f7d707b75d..09c20fb2d92eed 100644
|
|
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
|
|
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
|
|
@@ -385,12 +385,6 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
|
|
rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT,
|
|
arg->lum_weight);
|
|
|
|
- rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE,
|
|
- (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) |
|
|
- RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
|
|
- RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
|
|
- RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1));
|
|
-
|
|
/* avoid to override the old enable value */
|
|
filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE);
|
|
filt_mode &= RKISP1_CIF_ISP_FLT_ENA;
|
|
diff --git a/drivers/media/platform/ti/omap3isp/isppreview.c b/drivers/media/platform/ti/omap3isp/isppreview.c
|
|
index 53aedec7990da1..32e4348e6837a3 100644
|
|
--- a/drivers/media/platform/ti/omap3isp/isppreview.c
|
|
+++ b/drivers/media/platform/ti/omap3isp/isppreview.c
|
|
@@ -1744,22 +1744,17 @@ static void preview_try_format(struct isp_prev_device *prev,
|
|
|
|
switch (pad) {
|
|
case PREV_PAD_SINK:
|
|
- /* When reading data from the CCDC, the input size has already
|
|
- * been mangled by the CCDC output pad so it can be accepted
|
|
- * as-is.
|
|
- *
|
|
- * When reading data from memory, clamp the requested width and
|
|
- * height. The TRM doesn't specify a minimum input height, make
|
|
+ /*
|
|
+ * Clamp the requested width and height.
|
|
+ * The TRM doesn't specify a minimum input height, make
|
|
* sure we got enough lines to enable the noise filter and color
|
|
* filter array interpolation.
|
|
*/
|
|
- if (prev->input == PREVIEW_INPUT_MEMORY) {
|
|
- fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
|
|
- preview_max_out_width(prev));
|
|
- fmt->height = clamp_t(u32, fmt->height,
|
|
- PREV_MIN_IN_HEIGHT,
|
|
- PREV_MAX_IN_HEIGHT);
|
|
- }
|
|
+ fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
|
|
+ preview_max_out_width(prev));
|
|
+ fmt->height = clamp_t(u32, fmt->height,
|
|
+ PREV_MIN_IN_HEIGHT,
|
|
+ PREV_MAX_IN_HEIGHT);
|
|
|
|
fmt->colorspace = V4L2_COLORSPACE_SRGB;
|
|
|
|
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
|
|
index daca689dc08254..b9e0b6215fa048 100644
|
|
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
|
|
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
|
|
@@ -148,12 +148,12 @@ static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
|
|
pix->width = mbus->width;
|
|
pix->height = mbus->height;
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
|
|
+ for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
|
|
if (formats[i].code == mbus->code)
|
|
break;
|
|
}
|
|
|
|
- if (WARN_ON(i == ARRAY_SIZE(formats)))
|
|
+ if (WARN_ON(i == ARRAY_SIZE(formats) - 1))
|
|
return 0;
|
|
|
|
min_bpl = pix->width * formats[i].bpp;
|
|
@@ -191,7 +191,7 @@ static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
|
|
/* Skip the last format in the loop so that it will be selected if no
|
|
* match is found.
|
|
*/
|
|
- for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
|
|
+ for (i = 0; i < ARRAY_SIZE(formats) - 2; ++i) {
|
|
if (formats[i].pixelformat == pix->pixelformat)
|
|
break;
|
|
}
|
|
@@ -1288,6 +1288,7 @@ static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
|
|
static int isp_video_open(struct file *file)
|
|
{
|
|
struct isp_video *video = video_drvdata(file);
|
|
+ struct v4l2_mbus_framefmt fmt;
|
|
struct isp_video_fh *handle;
|
|
struct vb2_queue *queue;
|
|
int ret = 0;
|
|
@@ -1329,6 +1330,13 @@ static int isp_video_open(struct file *file)
|
|
|
|
memset(&handle->format, 0, sizeof(handle->format));
|
|
handle->format.type = video->type;
|
|
+ handle->format.fmt.pix.width = 720;
|
|
+ handle->format.fmt.pix.height = 480;
|
|
+ handle->format.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
|
+ handle->format.fmt.pix.field = V4L2_FIELD_NONE;
|
|
+ handle->format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
|
+ isp_video_pix_to_mbus(&handle->format.fmt.pix, &fmt);
|
|
+ isp_video_mbus_to_pix(video, &fmt, &handle->format.fmt.pix);
|
|
handle->timeperframe.denominator = 1;
|
|
|
|
handle->video = video;
|
|
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
|
|
index ff78b31728290d..03b9b78d95e88f 100644
|
|
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
|
|
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
|
|
@@ -72,6 +72,14 @@
|
|
: AV1_DIV_ROUND_UP_POW2((_value_), (_n_))); \
|
|
})
|
|
|
|
+enum rockchip_av1_tx_mode {
|
|
+ ROCKCHIP_AV1_TX_MODE_ONLY_4X4 = 0,
|
|
+ ROCKCHIP_AV1_TX_MODE_8X8 = 1,
|
|
+ ROCKCHIP_AV1_TX_MODE_16x16 = 2,
|
|
+ ROCKCHIP_AV1_TX_MODE_32x32 = 3,
|
|
+ ROCKCHIP_AV1_TX_MODE_SELECT = 4,
|
|
+};
|
|
+
|
|
struct rockchip_av1_film_grain {
|
|
u8 scaling_lut_y[256];
|
|
u8 scaling_lut_cb[256];
|
|
@@ -372,12 +380,12 @@ int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx)
|
|
return -ENOMEM;
|
|
av1_dec->global_model.size = GLOBAL_MODEL_SIZE;
|
|
|
|
- av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_MAX_TILES,
|
|
+ av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_TILE_INFO_SIZE,
|
|
&av1_dec->tile_info.dma,
|
|
GFP_KERNEL);
|
|
if (!av1_dec->tile_info.cpu)
|
|
return -ENOMEM;
|
|
- av1_dec->tile_info.size = AV1_MAX_TILES;
|
|
+ av1_dec->tile_info.size = AV1_TILE_INFO_SIZE;
|
|
|
|
av1_dec->film_grain.cpu = dma_alloc_coherent(vpu->dev,
|
|
ALIGN(sizeof(struct rockchip_av1_film_grain), 2048),
|
|
@@ -1397,8 +1405,16 @@ static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
|
|
u16 luma_sec_strength = 0;
|
|
u32 chroma_pri_strength = 0;
|
|
u16 chroma_sec_strength = 0;
|
|
+ bool enable_cdef;
|
|
int i;
|
|
|
|
+ enable_cdef = !(cdef->bits == 0 &&
|
|
+ cdef->damping_minus_3 == 0 &&
|
|
+ cdef->y_pri_strength[0] == 0 &&
|
|
+ cdef->y_sec_strength[0] == 0 &&
|
|
+ cdef->uv_pri_strength[0] == 0 &&
|
|
+ cdef->uv_sec_strength[0] == 0);
|
|
+ hantro_reg_write(vpu, &av1_enable_cdef, enable_cdef);
|
|
hantro_reg_write(vpu, &av1_cdef_bits, cdef->bits);
|
|
hantro_reg_write(vpu, &av1_cdef_damping, cdef->damping_minus_3);
|
|
|
|
@@ -1928,11 +1944,26 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
|
|
rockchip_vpu981_av1_dec_set_other_frames(ctx);
|
|
}
|
|
|
|
+static int rockchip_vpu981_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode)
|
|
+{
|
|
+ switch (tx_mode) {
|
|
+ case V4L2_AV1_TX_MODE_ONLY_4X4:
|
|
+ return ROCKCHIP_AV1_TX_MODE_ONLY_4X4;
|
|
+ case V4L2_AV1_TX_MODE_LARGEST:
|
|
+ return ROCKCHIP_AV1_TX_MODE_32x32;
|
|
+ case V4L2_AV1_TX_MODE_SELECT:
|
|
+ return ROCKCHIP_AV1_TX_MODE_SELECT;
|
|
+ }
|
|
+
|
|
+ return ROCKCHIP_AV1_TX_MODE_32x32;
|
|
+}
|
|
+
|
|
static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
|
|
{
|
|
struct hantro_dev *vpu = ctx->dev;
|
|
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
|
|
struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
|
|
+ int tx_mode;
|
|
|
|
hantro_reg_write(vpu, &av1_skip_mode,
|
|
!!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT));
|
|
@@ -1954,8 +1985,6 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
|
|
!!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_SHOW_FRAME));
|
|
hantro_reg_write(vpu, &av1_switchable_motion_mode,
|
|
!!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE));
|
|
- hantro_reg_write(vpu, &av1_enable_cdef,
|
|
- !!(ctrls->sequence->flags & V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF));
|
|
hantro_reg_write(vpu, &av1_allow_masked_compound,
|
|
!!(ctrls->sequence->flags
|
|
& V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND));
|
|
@@ -1990,7 +2019,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
|
|
!!(ctrls->frame->quantization.flags
|
|
& V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT));
|
|
|
|
- hantro_reg_write(vpu, &av1_idr_pic_e, !ctrls->frame->frame_type);
|
|
+ hantro_reg_write(vpu, &av1_idr_pic_e, IS_INTRA(ctrls->frame->frame_type));
|
|
hantro_reg_write(vpu, &av1_quant_base_qindex, ctrls->frame->quantization.base_q_idx);
|
|
hantro_reg_write(vpu, &av1_bit_depth_y_minus8, ctx->bit_depth - 8);
|
|
hantro_reg_write(vpu, &av1_bit_depth_c_minus8, ctx->bit_depth - 8);
|
|
@@ -2000,7 +2029,9 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
|
|
!!(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV));
|
|
hantro_reg_write(vpu, &av1_comp_pred_mode,
|
|
(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
|
|
- hantro_reg_write(vpu, &av1_transform_mode, (ctrls->frame->tx_mode == 1) ? 3 : 4);
|
|
+
|
|
+ tx_mode = rockchip_vpu981_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
|
|
+ hantro_reg_write(vpu, &av1_transform_mode, tx_mode);
|
|
hantro_reg_write(vpu, &av1_max_cb_size,
|
|
(ctrls->sequence->flags
|
|
& V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK) ? 7 : 6);
|
|
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
|
|
index a35648316aa8d2..05d3c4b5672113 100644
|
|
--- a/drivers/media/radio/radio-keene.c
|
|
+++ b/drivers/media/radio/radio-keene.c
|
|
@@ -338,7 +338,6 @@ static int usb_keene_probe(struct usb_interface *intf,
|
|
if (hdl->error) {
|
|
retval = hdl->error;
|
|
|
|
- v4l2_ctrl_handler_free(hdl);
|
|
goto err_v4l2;
|
|
}
|
|
retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
|
|
@@ -384,6 +383,7 @@ static int usb_keene_probe(struct usb_interface *intf,
|
|
err_vdev:
|
|
v4l2_device_unregister(&radio->v4l2_dev);
|
|
err_v4l2:
|
|
+ v4l2_ctrl_handler_free(&radio->hdl);
|
|
kfree(radio->buffer);
|
|
kfree(radio);
|
|
err:
|
|
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
index 2de104736f8741..943d56b10251b0 100644
|
|
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
|
|
@@ -3709,6 +3709,11 @@ status);
|
|
"Failed to submit read-control URB status=%d",
|
|
status);
|
|
hdw->ctl_read_pend_flag = 0;
|
|
+ if (hdw->ctl_write_pend_flag) {
|
|
+ usb_unlink_urb(hdw->ctl_write_urb);
|
|
+ while (hdw->ctl_write_pend_flag)
|
|
+ wait_for_completion(&hdw->ctl_done);
|
|
+ }
|
|
goto done;
|
|
}
|
|
}
|
|
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
|
|
index a9f880eb518ad8..ea7d91b19079e0 100644
|
|
--- a/drivers/media/usb/uvc/uvc_video.c
|
|
+++ b/drivers/media/usb/uvc/uvc_video.c
|
|
@@ -1819,7 +1819,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
|
|
npackets = UVC_MAX_PACKETS;
|
|
|
|
/* Retry allocations until one succeed. */
|
|
- for (; npackets > 1; npackets /= 2) {
|
|
+ for (; npackets > 0; npackets /= 2) {
|
|
stream->urb_size = psize * npackets;
|
|
|
|
for (i = 0; i < UVC_URBS; ++i) {
|
|
@@ -1844,6 +1844,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
|
|
uvc_dbg(stream->dev, VIDEO,
|
|
"Failed to allocate URB buffers (%u bytes per packet)\n",
|
|
psize);
|
|
+ stream->urb_size = 0;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
|
|
index ac4d987bba2556..cf2923dea84b3d 100644
|
|
--- a/drivers/media/v4l2-core/v4l2-async.c
|
|
+++ b/drivers/media/v4l2-core/v4l2-async.c
|
|
@@ -339,7 +339,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
|
|
struct v4l2_subdev *sd,
|
|
struct v4l2_async_connection *asc)
|
|
{
|
|
- struct v4l2_async_notifier *subdev_notifier;
|
|
bool registered = false;
|
|
int ret;
|
|
|
|
@@ -385,6 +384,25 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
|
|
dev_dbg(notifier_dev(notifier), "v4l2-async: %s bound (ret %d)\n",
|
|
dev_name(sd->dev), ret);
|
|
|
|
+ return 0;
|
|
+
|
|
+err_call_unbind:
|
|
+ v4l2_async_nf_call_unbind(notifier, sd, asc);
|
|
+ list_del(&asc->asc_subdev_entry);
|
|
+
|
|
+err_unregister_subdev:
|
|
+ if (registered)
|
|
+ v4l2_device_unregister_subdev(sd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+v4l2_async_nf_try_subdev_notifier(struct v4l2_async_notifier *notifier,
|
|
+ struct v4l2_subdev *sd)
|
|
+{
|
|
+ struct v4l2_async_notifier *subdev_notifier;
|
|
+
|
|
/*
|
|
* See if the sub-device has a notifier. If not, return here.
|
|
*/
|
|
@@ -400,16 +418,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
|
|
subdev_notifier->parent = notifier;
|
|
|
|
return v4l2_async_nf_try_all_subdevs(subdev_notifier);
|
|
-
|
|
-err_call_unbind:
|
|
- v4l2_async_nf_call_unbind(notifier, sd, asc);
|
|
- list_del(&asc->asc_subdev_entry);
|
|
-
|
|
-err_unregister_subdev:
|
|
- if (registered)
|
|
- v4l2_device_unregister_subdev(sd);
|
|
-
|
|
- return ret;
|
|
}
|
|
|
|
/* Test all async sub-devices in a notifier for a match. */
|
|
@@ -441,6 +449,10 @@ again:
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
+ ret = v4l2_async_nf_try_subdev_notifier(notifier, sd);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
/*
|
|
* v4l2_async_match_notify() may lead to registering a
|
|
* new notifier and thus changing the async subdevs
|
|
@@ -823,7 +835,11 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
|
|
ret = v4l2_async_match_notify(notifier, v4l2_dev, sd,
|
|
asc);
|
|
if (ret)
|
|
- goto err_unbind;
|
|
+ goto err_unlock;
|
|
+
|
|
+ ret = v4l2_async_nf_try_subdev_notifier(notifier, sd);
|
|
+ if (ret)
|
|
+ goto err_unbind_one;
|
|
|
|
ret = v4l2_async_nf_try_complete(notifier);
|
|
if (ret)
|
|
@@ -847,9 +863,10 @@ err_unbind:
|
|
if (subdev_notifier)
|
|
v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
|
|
|
|
- if (asc)
|
|
- v4l2_async_unbind_subdev_one(notifier, asc);
|
|
+err_unbind_one:
|
|
+ v4l2_async_unbind_subdev_one(notifier, asc);
|
|
|
|
+err_unlock:
|
|
mutex_unlock(&list_lock);
|
|
|
|
return ret;
|
|
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
|
|
index 68d71b4b55bd35..cfb22fb7b238bc 100644
|
|
--- a/drivers/mfd/Kconfig
|
|
+++ b/drivers/mfd/Kconfig
|
|
@@ -335,6 +335,17 @@ config MFD_CS47L92
|
|
help
|
|
Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs
|
|
|
|
+config MFD_TN48M_CPLD
|
|
+ tristate "Delta Networks TN48M switch CPLD driver"
|
|
+ depends on I2C
|
|
+ depends on ARCH_MVEBU || COMPILE_TEST
|
|
+ select MFD_SIMPLE_MFD_I2C
|
|
+ help
|
|
+ Select this option to enable support for Delta Networks TN48M switch
|
|
+ CPLD. It consists of reset and GPIO drivers. CPLD provides GPIOS-s
|
|
+ for the SFP slots as well as power supply related information.
|
|
+ SFP support depends on the GPIO driver being selected.
|
|
+
|
|
config PMIC_DA903X
|
|
bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
|
|
depends on I2C=y
|
|
@@ -1137,6 +1148,19 @@ config MFD_QCOM_RPM
|
|
Say M here if you want to include support for the Qualcomm RPM as a
|
|
module. This will build a module called "qcom_rpm".
|
|
|
|
+config MFD_SPACEMIT_P1
|
|
+ tristate "SpacemiT P1 PMIC"
|
|
+ depends on ARCH_SPACEMIT || COMPILE_TEST
|
|
+ depends on I2C
|
|
+ select I2C_K1
|
|
+ select MFD_SIMPLE_MFD_I2C
|
|
+ help
|
|
+ This option supports the I2C-based SpacemiT P1 PMIC, which
|
|
+ contains regulators, a power switch, GPIOs, an RTC, and more.
|
|
+ This option is selected when any of the supported sub-devices
|
|
+ is configured. The basic functionality is implemented by the
|
|
+ simple MFD I2C driver.
|
|
+
|
|
config MFD_SPMI_PMIC
|
|
tristate "Qualcomm SPMI PMICs"
|
|
depends on ARCH_QCOM || COMPILE_TEST
|
|
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
|
|
index 19a0adf8ce3dbc..35f516d934c8b5 100644
|
|
--- a/drivers/mfd/arizona-core.c
|
|
+++ b/drivers/mfd/arizona-core.c
|
|
@@ -1100,7 +1100,7 @@ int arizona_dev_init(struct arizona *arizona)
|
|
} else if (val & 0x01) {
|
|
ret = wm5102_clear_write_sequencer(arizona);
|
|
if (ret)
|
|
- return ret;
|
|
+ goto err_reset;
|
|
}
|
|
break;
|
|
default:
|
|
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
|
|
index 80fc5c0cac2fb0..be5f2b34e18aeb 100644
|
|
--- a/drivers/mfd/da9052-spi.c
|
|
+++ b/drivers/mfd/da9052-spi.c
|
|
@@ -37,7 +37,7 @@ static int da9052_spi_probe(struct spi_device *spi)
|
|
spi_set_drvdata(spi, da9052);
|
|
|
|
config = da9052_regmap_config;
|
|
- config.write_flag_mask = 1;
|
|
+ config.read_flag_mask = 1;
|
|
config.reg_bits = 7;
|
|
config.pad_bits = 1;
|
|
config.val_bits = 8;
|
|
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
|
|
index 2b85509a90fc29..2b323d1430f522 100644
|
|
--- a/drivers/mfd/mfd-core.c
|
|
+++ b/drivers/mfd/mfd-core.c
|
|
@@ -22,6 +22,7 @@
|
|
#include <linux/regulator/consumer.h>
|
|
|
|
static LIST_HEAD(mfd_of_node_list);
|
|
+static DEFINE_MUTEX(mfd_of_node_mutex);
|
|
|
|
struct mfd_of_node_entry {
|
|
struct list_head list;
|
|
@@ -105,9 +106,11 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
|
|
u64 of_node_addr;
|
|
|
|
/* Skip if OF node has previously been allocated to a device */
|
|
- list_for_each_entry(of_entry, &mfd_of_node_list, list)
|
|
- if (of_entry->np == np)
|
|
- return -EAGAIN;
|
|
+ scoped_guard(mutex, &mfd_of_node_mutex) {
|
|
+ list_for_each_entry(of_entry, &mfd_of_node_list, list)
|
|
+ if (of_entry->np == np)
|
|
+ return -EAGAIN;
|
|
+ }
|
|
|
|
if (!cell->use_of_reg)
|
|
/* No of_reg defined - allocate first free compatible match */
|
|
@@ -129,7 +132,8 @@ allocate_of_node:
|
|
|
|
of_entry->dev = &pdev->dev;
|
|
of_entry->np = np;
|
|
- list_add_tail(&of_entry->list, &mfd_of_node_list);
|
|
+ scoped_guard(mutex, &mfd_of_node_mutex)
|
|
+ list_add_tail(&of_entry->list, &mfd_of_node_list);
|
|
|
|
pdev->dev.of_node = np;
|
|
pdev->dev.fwnode = &np->fwnode;
|
|
@@ -286,11 +290,13 @@ fail_res_conflict:
|
|
if (cell->swnode)
|
|
device_remove_software_node(&pdev->dev);
|
|
fail_of_entry:
|
|
- list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
|
|
- if (of_entry->dev == &pdev->dev) {
|
|
- list_del(&of_entry->list);
|
|
- kfree(of_entry);
|
|
- }
|
|
+ scoped_guard(mutex, &mfd_of_node_mutex) {
|
|
+ list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
|
|
+ if (of_entry->dev == &pdev->dev) {
|
|
+ list_del(&of_entry->list);
|
|
+ kfree(of_entry);
|
|
+ }
|
|
+ }
|
|
fail_alias:
|
|
regulator_bulk_unregister_supply_alias(&pdev->dev,
|
|
cell->parent_supplies,
|
|
@@ -360,11 +366,13 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
|
|
if (cell->swnode)
|
|
device_remove_software_node(&pdev->dev);
|
|
|
|
- list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
|
|
- if (of_entry->dev == &pdev->dev) {
|
|
- list_del(&of_entry->list);
|
|
- kfree(of_entry);
|
|
- }
|
|
+ scoped_guard(mutex, &mfd_of_node_mutex) {
|
|
+ list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
|
|
+ if (of_entry->dev == &pdev->dev) {
|
|
+ list_del(&of_entry->list);
|
|
+ kfree(of_entry);
|
|
+ }
|
|
+ }
|
|
|
|
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
|
|
cell->num_parent_supplies);
|
|
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
|
|
index 6eda79533208a3..908eae338fee00 100644
|
|
--- a/drivers/mfd/simple-mfd-i2c.c
|
|
+++ b/drivers/mfd/simple-mfd-i2c.c
|
|
@@ -83,11 +83,42 @@ static const struct simple_mfd_data maxim_max5970 = {
|
|
.mfd_cell_size = ARRAY_SIZE(max5970_cells),
|
|
};
|
|
|
|
+static const struct mfd_cell max77705_sensor_cells[] = {
|
|
+ { .name = "max77705-battery" },
|
|
+ { .name = "max77705-hwmon", },
|
|
+};
|
|
+
|
|
+static const struct simple_mfd_data maxim_mon_max77705 = {
|
|
+ .mfd_cell = max77705_sensor_cells,
|
|
+ .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells),
|
|
+};
|
|
+
|
|
+static const struct regmap_config spacemit_p1_regmap_config = {
|
|
+ .reg_bits = 8,
|
|
+ .val_bits = 8,
|
|
+};
|
|
+
|
|
+static const struct mfd_cell spacemit_p1_cells[] = {
|
|
+ { .name = "spacemit-p1-regulator", },
|
|
+ { .name = "spacemit-p1-rtc", },
|
|
+};
|
|
+
|
|
+static const struct simple_mfd_data spacemit_p1 = {
|
|
+ .regmap_config = &spacemit_p1_regmap_config,
|
|
+ .mfd_cell = spacemit_p1_cells,
|
|
+ .mfd_cell_size = ARRAY_SIZE(spacemit_p1_cells),
|
|
+};
|
|
+
|
|
static const struct of_device_id simple_mfd_i2c_of_match[] = {
|
|
+ { .compatible = "delta,tn48m-cpld" },
|
|
+ { .compatible = "fsl,ls1028aqds-fpga" },
|
|
+ { .compatible = "fsl,lx2160aqds-fpga" },
|
|
{ .compatible = "kontron,sl28cpld" },
|
|
- { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
|
|
{ .compatible = "maxim,max5970", .data = &maxim_max5970},
|
|
{ .compatible = "maxim,max5978", .data = &maxim_max5970},
|
|
+ { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705},
|
|
+ { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
|
|
+ { .compatible = "spacemit,p1", .data = &spacemit_p1, },
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);
|
|
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c
|
|
index e17d81231ea6da..54e25e9bc51b13 100644
|
|
--- a/drivers/misc/bcm-vk/bcm_vk_msg.c
|
|
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.c
|
|
@@ -1010,6 +1010,9 @@ ssize_t bcm_vk_read(struct file *p_file,
|
|
struct device *dev = &vk->pdev->dev;
|
|
struct bcm_vk_msg_chan *chan = &vk->to_h_msg_chan;
|
|
struct bcm_vk_wkent *entry = NULL, *iter;
|
|
+ struct vk_msg_blk tmp_msg;
|
|
+ u32 tmp_usr_msg_id;
|
|
+ u32 tmp_blks;
|
|
u32 q_num;
|
|
u32 rsp_length;
|
|
|
|
@@ -1034,6 +1037,9 @@ ssize_t bcm_vk_read(struct file *p_file,
|
|
entry = iter;
|
|
} else {
|
|
/* buffer not big enough */
|
|
+ tmp_msg = iter->to_h_msg[0];
|
|
+ tmp_usr_msg_id = iter->usr_msg_id;
|
|
+ tmp_blks = iter->to_h_blks;
|
|
rc = -EMSGSIZE;
|
|
}
|
|
goto read_loop_exit;
|
|
@@ -1052,14 +1058,12 @@ read_loop_exit:
|
|
|
|
bcm_vk_free_wkent(dev, entry);
|
|
} else if (rc == -EMSGSIZE) {
|
|
- struct vk_msg_blk tmp_msg = entry->to_h_msg[0];
|
|
-
|
|
/*
|
|
* in this case, return just the first block, so
|
|
* that app knows what size it is looking for.
|
|
*/
|
|
- set_msg_id(&tmp_msg, entry->usr_msg_id);
|
|
- tmp_msg.size = entry->to_h_blks - 1;
|
|
+ set_msg_id(&tmp_msg, tmp_usr_msg_id);
|
|
+ tmp_msg.size = tmp_blks - 1;
|
|
if (copy_to_user(buf, &tmp_msg, VK_MSGQ_BLK_SIZE) != 0) {
|
|
dev_err(dev, "Error return 1st block in -EMSGSIZE\n");
|
|
rc = -EFAULT;
|
|
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
|
|
index b630625b3024ba..b510d0b5ddfa7b 100644
|
|
--- a/drivers/misc/eeprom/eeprom_93xx46.c
|
|
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
|
|
@@ -23,6 +23,7 @@
|
|
#define OP_START 0x4
|
|
#define OP_WRITE (OP_START | 0x1)
|
|
#define OP_READ (OP_START | 0x2)
|
|
+/* The following addresses are offset for the 1K EEPROM variant in 16-bit mode */
|
|
#define ADDR_EWDS 0x00
|
|
#define ADDR_ERAL 0x20
|
|
#define ADDR_EWEN 0x30
|
|
@@ -173,10 +174,7 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
|
|
bits = edev->addrlen + 3;
|
|
|
|
cmd_addr = OP_START << edev->addrlen;
|
|
- if (edev->pdata->flags & EE_ADDR8)
|
|
- cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1;
|
|
- else
|
|
- cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS);
|
|
+ cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << (edev->addrlen - 6);
|
|
|
|
if (has_quirk_instruction_length(edev)) {
|
|
cmd_addr <<= 2;
|
|
@@ -320,10 +318,7 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
|
|
bits = edev->addrlen + 3;
|
|
|
|
cmd_addr = OP_START << edev->addrlen;
|
|
- if (edev->pdata->flags & EE_ADDR8)
|
|
- cmd_addr |= ADDR_ERAL << 1;
|
|
- else
|
|
- cmd_addr |= ADDR_ERAL;
|
|
+ cmd_addr |= ADDR_ERAL << (edev->addrlen - 6);
|
|
|
|
if (has_quirk_instruction_length(edev)) {
|
|
cmd_addr <<= 2;
|
|
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
index 202b4fc064fa39..0831feb58e13db 100644
|
|
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
@@ -1018,7 +1018,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl,
|
|
}
|
|
|
|
/* Send SDMA command and wait for finish. */
|
|
-static u32
|
|
+static int
|
|
cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl,
|
|
u8 thread)
|
|
{
|
|
diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c
|
|
index c506e92a3e457d..eaaaf3319bf863 100644
|
|
--- a/drivers/mtd/nand/raw/pl35x-nand-controller.c
|
|
+++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c
|
|
@@ -976,6 +976,7 @@ static int pl35x_nand_attach_chip(struct nand_chip *chip)
|
|
fallthrough;
|
|
case NAND_ECC_ENGINE_TYPE_NONE:
|
|
case NAND_ECC_ENGINE_TYPE_SOFT:
|
|
+ chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
|
|
break;
|
|
case NAND_ECC_ENGINE_TYPE_ON_HOST:
|
|
ret = pl35x_nand_init_hw_ecc_controller(nfc, chip);
|
|
diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c
|
|
index e7b8e9d0a91033..3cf75b56d5a2e7 100644
|
|
--- a/drivers/mtd/parsers/ofpart_core.c
|
|
+++ b/drivers/mtd/parsers/ofpart_core.c
|
|
@@ -77,6 +77,7 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|
of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
|
|
if (dedicated && !of_id) {
|
|
/* The 'partitions' subnode might be used by another parser */
|
|
+ of_node_put(ofpart_node);
|
|
return 0;
|
|
}
|
|
|
|
@@ -91,12 +92,18 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|
nr_parts++;
|
|
}
|
|
|
|
- if (nr_parts == 0)
|
|
+ if (nr_parts == 0) {
|
|
+ if (dedicated)
|
|
+ of_node_put(ofpart_node);
|
|
return 0;
|
|
+ }
|
|
|
|
parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
|
|
- if (!parts)
|
|
+ if (!parts) {
|
|
+ if (dedicated)
|
|
+ of_node_put(ofpart_node);
|
|
return -ENOMEM;
|
|
+ }
|
|
|
|
i = 0;
|
|
for_each_child_of_node(ofpart_node, pp) {
|
|
@@ -175,6 +182,9 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|
if (quirks && quirks->post_parse)
|
|
quirks->post_parse(master, parts, nr_parts);
|
|
|
|
+ if (dedicated)
|
|
+ of_node_put(ofpart_node);
|
|
+
|
|
*pparts = parts;
|
|
return nr_parts;
|
|
|
|
@@ -183,6 +193,8 @@ ofpart_fail:
|
|
master->name, pp, mtd_node);
|
|
ret = -EINVAL;
|
|
ofpart_none:
|
|
+ if (dedicated)
|
|
+ of_node_put(ofpart_node);
|
|
of_node_put(pp);
|
|
kfree(parts);
|
|
return ret;
|
|
diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c
|
|
index 1c689dafca2ae9..3580c79e3277ea 100644
|
|
--- a/drivers/mtd/parsers/tplink_safeloader.c
|
|
+++ b/drivers/mtd/parsers/tplink_safeloader.c
|
|
@@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
|
|
return idx;
|
|
|
|
err_free:
|
|
+ kfree(buf);
|
|
for (idx -= 1; idx >= 0; idx--)
|
|
kfree(parts[idx].name);
|
|
err_free_parts:
|
|
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
|
index 4373e300879d92..836d7fcac71a1d 100644
|
|
--- a/drivers/net/bonding/bond_main.c
|
|
+++ b/drivers/net/bonding/bond_main.c
|
|
@@ -727,26 +727,29 @@ static int bond_update_speed_duplex(struct slave *slave)
|
|
struct ethtool_link_ksettings ecmd;
|
|
int res;
|
|
|
|
- slave->speed = SPEED_UNKNOWN;
|
|
- slave->duplex = DUPLEX_UNKNOWN;
|
|
-
|
|
res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
|
|
if (res < 0)
|
|
- return 1;
|
|
+ goto speed_duplex_unknown;
|
|
if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1))
|
|
- return 1;
|
|
+ goto speed_duplex_unknown;
|
|
switch (ecmd.base.duplex) {
|
|
case DUPLEX_FULL:
|
|
case DUPLEX_HALF:
|
|
break;
|
|
default:
|
|
- return 1;
|
|
+ goto speed_duplex_unknown;
|
|
}
|
|
|
|
slave->speed = ecmd.base.speed;
|
|
slave->duplex = ecmd.base.duplex;
|
|
|
|
return 0;
|
|
+
|
|
+speed_duplex_unknown:
|
|
+ slave->speed = SPEED_UNKNOWN;
|
|
+ slave->duplex = DUPLEX_UNKNOWN;
|
|
+
|
|
+ return 1;
|
|
}
|
|
|
|
const char *bond_slave_link_status(s8 link)
|
|
@@ -4398,9 +4401,13 @@ static int bond_close(struct net_device *bond_dev)
|
|
|
|
bond_work_cancel_all(bond);
|
|
bond->send_peer_notif = 0;
|
|
+ WRITE_ONCE(bond->recv_probe, NULL);
|
|
+
|
|
+ /* Wait for any in-flight RX handlers */
|
|
+ synchronize_net();
|
|
+
|
|
if (bond_is_lb(bond))
|
|
bond_alb_deinitialize(bond);
|
|
- bond->recv_probe = NULL;
|
|
|
|
if (bond_uses_primary(bond)) {
|
|
rcu_read_lock();
|
|
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
|
|
index ed3a589def6b1c..699ed0ff461e89 100644
|
|
--- a/drivers/net/caif/caif_serial.c
|
|
+++ b/drivers/net/caif/caif_serial.c
|
|
@@ -298,6 +298,7 @@ static void ser_release(struct work_struct *work)
|
|
{
|
|
struct list_head list;
|
|
struct ser_device *ser, *tmp;
|
|
+ struct tty_struct *tty;
|
|
|
|
spin_lock(&ser_lock);
|
|
list_replace_init(&ser_release_list, &list);
|
|
@@ -306,9 +307,11 @@ static void ser_release(struct work_struct *work)
|
|
if (!list_empty(&list)) {
|
|
rtnl_lock();
|
|
list_for_each_entry_safe(ser, tmp, &list, node) {
|
|
+ tty = ser->tty;
|
|
dev_close(ser->dev);
|
|
unregister_netdevice(ser->dev);
|
|
debugfs_deinit(ser);
|
|
+ tty_kref_put(tty);
|
|
}
|
|
rtnl_unlock();
|
|
}
|
|
@@ -369,8 +372,6 @@ static void ldisc_close(struct tty_struct *tty)
|
|
{
|
|
struct ser_device *ser = tty->disc_data;
|
|
|
|
- tty_kref_put(ser->tty);
|
|
-
|
|
spin_lock(&ser_lock);
|
|
list_move(&ser->node, &ser_release_list);
|
|
spin_unlock(&ser_lock);
|
|
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
|
|
index 5cbda8ccdbf096..e1df1546a2d6e2 100644
|
|
--- a/drivers/net/ethernet/cadence/macb_main.c
|
|
+++ b/drivers/net/ethernet/cadence/macb_main.c
|
|
@@ -756,14 +756,12 @@ static void macb_mac_link_up(struct phylink_config *config,
|
|
if (rx_pause)
|
|
ctrl |= MACB_BIT(PAE);
|
|
|
|
- /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down
|
|
- * cleared the pipeline and control registers.
|
|
- */
|
|
- macb_init_buffers(bp);
|
|
-
|
|
- for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
|
|
+ for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
|
+ queue->tx_head = 0;
|
|
+ queue->tx_tail = 0;
|
|
queue_writel(queue, IER,
|
|
bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
|
|
+ }
|
|
}
|
|
|
|
macb_or_gem_writel(bp, NCFGR, ctrl);
|
|
@@ -2953,6 +2951,7 @@ static int macb_open(struct net_device *dev)
|
|
}
|
|
|
|
bp->macbgem_ops.mog_init_rings(bp);
|
|
+ macb_init_buffers(bp);
|
|
|
|
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
|
napi_enable(&queue->napi_rx);
|
|
diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c
|
|
index c2c5c589a5e329..6233602d7c5aad 100644
|
|
--- a/drivers/net/ethernet/ec_bhf.c
|
|
+++ b/drivers/net/ethernet/ec_bhf.c
|
|
@@ -424,7 +424,7 @@ static int ec_bhf_open(struct net_device *net_dev)
|
|
|
|
error_rx_free:
|
|
dma_free_coherent(dev, priv->rx_buf.alloc_len, priv->rx_buf.alloc,
|
|
- priv->rx_buf.alloc_len);
|
|
+ priv->rx_buf.alloc_phys);
|
|
out:
|
|
return err;
|
|
}
|
|
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
|
|
index 37e3224262ed43..2631732ab2164a 100644
|
|
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
|
|
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
|
|
@@ -2998,6 +2998,13 @@ static int dpaa2_switch_init(struct fsl_mc_device *sw_dev)
|
|
goto err_close;
|
|
}
|
|
|
|
+ if (ethsw->sw_attr.num_ifs >= DPSW_MAX_IF) {
|
|
+ dev_err(dev, "DPSW num_ifs %u exceeds max %u\n",
|
|
+ ethsw->sw_attr.num_ifs, DPSW_MAX_IF);
|
|
+ err = -EINVAL;
|
|
+ goto err_close;
|
|
+ }
|
|
+
|
|
err = dpsw_get_api_version(ethsw->mc_io, 0,
|
|
ðsw->major,
|
|
ðsw->minor);
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
index 34627de2e311ee..107e692e8c87ae 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
@@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring)
|
|
int order;
|
|
|
|
if (!alloc_size)
|
|
- return;
|
|
+ goto not_init;
|
|
|
|
order = get_order(alloc_size);
|
|
if (order > MAX_ORDER) {
|
|
if (net_ratelimit())
|
|
dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n");
|
|
- return;
|
|
+ goto not_init;
|
|
}
|
|
|
|
tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare),
|
|
@@ -1092,6 +1092,13 @@ alloc_pages_error:
|
|
devm_kfree(ring_to_dev(ring), tx_spare);
|
|
devm_kzalloc_error:
|
|
ring->tqp->handle->kinfo.tx_spare_buf_size = 0;
|
|
+not_init:
|
|
+ /* When driver init or reset_init, the ring->tx_spare is always NULL;
|
|
+ * but when called from hns3_set_ringparam, it's usually not NULL, and
|
|
+ * will be restored if hns3_init_all_ring() failed. So it's safe to set
|
|
+ * ring->tx_spare to NULL here.
|
|
+ */
|
|
+ ring->tx_spare = NULL;
|
|
}
|
|
|
|
/* Use hns3_tx_spare_space() to make sure there is enough buffer
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
|
|
index 659d6351f26c83..f404a4c10e8f50 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
|
|
@@ -727,8 +727,8 @@ struct hclge_fd_tcam_config_3_cmd {
|
|
|
|
#define HCLGE_FD_AD_DROP_B 0
|
|
#define HCLGE_FD_AD_DIRECT_QID_B 1
|
|
-#define HCLGE_FD_AD_QID_S 2
|
|
-#define HCLGE_FD_AD_QID_M GENMASK(11, 2)
|
|
+#define HCLGE_FD_AD_QID_L_S 2
|
|
+#define HCLGE_FD_AD_QID_L_M GENMASK(11, 2)
|
|
#define HCLGE_FD_AD_USE_COUNTER_B 12
|
|
#define HCLGE_FD_AD_COUNTER_NUM_S 13
|
|
#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(19, 13)
|
|
@@ -741,6 +741,7 @@ struct hclge_fd_tcam_config_3_cmd {
|
|
#define HCLGE_FD_AD_TC_OVRD_B 16
|
|
#define HCLGE_FD_AD_TC_SIZE_S 17
|
|
#define HCLGE_FD_AD_TC_SIZE_M GENMASK(20, 17)
|
|
+#define HCLGE_FD_AD_QID_H_B 21
|
|
|
|
struct hclge_fd_ad_config_cmd {
|
|
u8 stage;
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
index 72a5df4e3a3292..04c58928585ca4 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
@@ -5606,11 +5606,13 @@ static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc,
|
|
hnae3_set_field(ad_data, HCLGE_FD_AD_TC_SIZE_M,
|
|
HCLGE_FD_AD_TC_SIZE_S, (u32)action->tc_size);
|
|
}
|
|
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_QID_H_B,
|
|
+ action->queue_id >= HCLGE_TQP_MAX_SIZE_DEV_V2 ? 1 : 0);
|
|
ad_data <<= 32;
|
|
hnae3_set_bit(ad_data, HCLGE_FD_AD_DROP_B, action->drop_packet);
|
|
hnae3_set_bit(ad_data, HCLGE_FD_AD_DIRECT_QID_B,
|
|
action->forward_to_direct_queue);
|
|
- hnae3_set_field(ad_data, HCLGE_FD_AD_QID_M, HCLGE_FD_AD_QID_S,
|
|
+ hnae3_set_field(ad_data, HCLGE_FD_AD_QID_L_M, HCLGE_FD_AD_QID_L_S,
|
|
action->queue_id);
|
|
hnae3_set_bit(ad_data, HCLGE_FD_AD_USE_COUNTER_B, action->use_counter);
|
|
hnae3_set_field(ad_data, HCLGE_FD_AD_COUNTER_NUM_M,
|
|
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
index 8a0eb51fe9744f..1f233fac9d4e3f 100644
|
|
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
|
|
@@ -74,7 +74,13 @@ static const struct pci_device_id i40e_pci_tbl[] = {
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0},
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_BC), 0},
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_SFP), 0},
|
|
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_B), 0},
|
|
+ /*
|
|
+ * This ID conflicts with ipw2200, but the devices can be differentiated
|
|
+ * because i40e devices use PCI_CLASS_NETWORK_ETHERNET and ipw2200
|
|
+ * devices use PCI_CLASS_NETWORK_OTHER.
|
|
+ */
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, I40E_DEV_ID_10G_B),
|
|
+ PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0},
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722), 0},
|
|
{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0},
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/Makefile b/drivers/net/ethernet/marvell/octeon_ep/Makefile
|
|
index 2026c8118158c6..02a4a21bc29867 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/Makefile
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/Makefile
|
|
@@ -6,4 +6,5 @@
|
|
obj-$(CONFIG_OCTEON_EP) += octeon_ep.o
|
|
|
|
octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \
|
|
- octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o
|
|
+ octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \
|
|
+ octep_cnxk_pf.o
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
|
|
index 90c3a419932d1e..0ed07aad066f4b 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
|
|
@@ -16,9 +16,6 @@
|
|
#define CTRL_MBOX_MAX_PF 128
|
|
#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF))
|
|
|
|
-#define FW_HB_INTERVAL_IN_SECS 1
|
|
-#define FW_HB_MISS_COUNT 10
|
|
-
|
|
/* Names of Hardware non-queue generic interrupts */
|
|
static char *cn93_non_ioq_msix_names[] = {
|
|
"epf_ire_rint",
|
|
@@ -250,12 +247,11 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
|
|
link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link);
|
|
}
|
|
conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr +
|
|
- (0x400000ull * 7) +
|
|
+ CN93_PEM_BAR4_INDEX_OFFSET +
|
|
(link * CTRL_MBOX_SZ);
|
|
|
|
- conf->hb_interval = FW_HB_INTERVAL_IN_SECS;
|
|
- conf->max_hb_miss_cnt = FW_HB_MISS_COUNT;
|
|
-
|
|
+ conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL;
|
|
+ conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT;
|
|
}
|
|
|
|
/* Setup registers for a hardware Tx Queue */
|
|
@@ -306,7 +302,7 @@ static void octep_setup_iq_regs_cn93_pf(struct octep_device *oct, int iq_no)
|
|
}
|
|
|
|
/* Setup registers for a hardware Rx Queue */
|
|
-static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no)
|
|
+static int octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no)
|
|
{
|
|
u64 reg_val;
|
|
u64 oq_ctl = 0ULL;
|
|
@@ -354,6 +350,7 @@ static void octep_setup_oq_regs_cn93_pf(struct octep_device *oct, int oq_no)
|
|
reg_val = ((u64)time_threshold << 32) |
|
|
CFG_GET_OQ_INTR_PKT(oct->conf);
|
|
octep_write_csr64(oct, CN93_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
|
+ return 0;
|
|
}
|
|
|
|
/* Setup registers for a PF mailbox */
|
|
@@ -373,34 +370,40 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
|
|
mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
|
|
}
|
|
|
|
-/* Process non-ioq interrupts required to keep pf interface running.
|
|
- * OEI_RINT is needed for control mailbox
|
|
- */
|
|
-static bool octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
|
|
-{
|
|
- bool handled = false;
|
|
- u64 reg0;
|
|
-
|
|
- /* Check for OEI INTR */
|
|
- reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
|
|
- if (reg0) {
|
|
- dev_info(&oct->pdev->dev,
|
|
- "Received OEI_RINT intr: 0x%llx\n",
|
|
- reg0);
|
|
- octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg0);
|
|
- if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
|
|
+/* Poll OEI events like heartbeat */
|
|
+static void octep_poll_oei_cn93_pf(struct octep_device *oct)
|
|
+{
|
|
+ u64 reg;
|
|
+
|
|
+ reg = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
|
|
+ if (reg) {
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg);
|
|
+ if (reg & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
|
|
queue_work(octep_wq, &oct->ctrl_mbox_task);
|
|
- else if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
|
|
+ else if (reg & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
|
|
atomic_set(&oct->hb_miss_cnt, 0);
|
|
-
|
|
- handled = true;
|
|
}
|
|
+}
|
|
+
|
|
+/* OEI interrupt handler */
|
|
+static irqreturn_t octep_oei_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
|
|
- return handled;
|
|
+ octep_poll_oei_cn93_pf(oct);
|
|
+ return IRQ_HANDLED;
|
|
}
|
|
|
|
-/* Interrupts handler for all non-queue generic interrupts. */
|
|
-static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
+/* Process non-ioq interrupts required to keep pf interface running.
|
|
+ * OEI_RINT is needed for control mailbox
|
|
+ */
|
|
+static void octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
|
|
+{
|
|
+ octep_poll_oei_cn93_pf(oct);
|
|
+}
|
|
+
|
|
+/* Interrupt handler for input ring error interrupts. */
|
|
+static irqreturn_t octep_ire_intr_handler_cn93_pf(void *dev)
|
|
{
|
|
struct octep_device *oct = (struct octep_device *)dev;
|
|
struct pci_dev *pdev = oct->pdev;
|
|
@@ -425,8 +428,17 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
reg_val);
|
|
}
|
|
}
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for output ring error interrupts. */
|
|
+static irqreturn_t octep_ore_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+ int i = 0;
|
|
|
|
/* Check for ORERR INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_ORERR_RINT);
|
|
@@ -444,9 +456,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
reg_val);
|
|
}
|
|
}
|
|
-
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for vf input ring error interrupts. */
|
|
+static irqreturn_t octep_vfire_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for VFIRE INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_VFIRE_RINT(0));
|
|
@@ -454,8 +473,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
dev_info(&pdev->dev,
|
|
"Received VFIRE_RINT intr: 0x%llx\n", reg_val);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT(0), reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for vf output ring error interrupts. */
|
|
+static irqreturn_t octep_vfore_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for VFORE INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_VFORE_RINT(0));
|
|
@@ -463,19 +490,30 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
dev_info(&pdev->dev,
|
|
"Received VFORE_RINT intr: 0x%llx\n", reg_val);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT(0), reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
|
|
- /* Check for MBOX INTR and OEI INTR */
|
|
- if (octep_poll_non_ioq_interrupts_cn93_pf(oct))
|
|
- goto irq_handled;
|
|
+/* Interrupt handler for dpi dma related interrupts. */
|
|
+static irqreturn_t octep_dma_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for DMA INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_RINT);
|
|
if (reg_val) {
|
|
octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT, reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for dpi dma transaction error interrupts for VFs */
|
|
+static irqreturn_t octep_dma_vf_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for DMA VF INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT(0));
|
|
@@ -483,8 +521,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
dev_info(&pdev->dev,
|
|
"Received DMA_VF_RINT intr: 0x%llx\n", reg_val);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT(0), reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for pp transaction error interrupts for VFs */
|
|
+static irqreturn_t octep_pp_vf_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for PPVF INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_PP_VF_RINT(0));
|
|
@@ -492,8 +538,16 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
dev_info(&pdev->dev,
|
|
"Received PP_VF_RINT intr: 0x%llx\n", reg_val);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT(0), reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for mac related interrupts. */
|
|
+static irqreturn_t octep_misc_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
|
|
/* Check for MISC INTR */
|
|
reg_val = octep_read_csr64(oct, CN93_SDP_EPF_MISC_RINT);
|
|
@@ -501,11 +555,17 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
|
|
dev_info(&pdev->dev,
|
|
"Received MISC_RINT intr: 0x%llx\n", reg_val);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT, reg_val);
|
|
- goto irq_handled;
|
|
}
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupts handler for all reserved interrupts. */
|
|
+static irqreturn_t octep_rsvd_intr_handler_cn93_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
|
|
dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n");
|
|
-irq_handled:
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -569,27 +629,53 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct)
|
|
octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL);
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL);
|
|
+
|
|
octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
|
|
+
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
|
|
}
|
|
|
|
/* Disable all interrupts */
|
|
static void octep_disable_interrupts_cn93_pf(struct octep_device *oct)
|
|
{
|
|
- u64 intr_mask = 0ULL;
|
|
+ u64 reg_val, intr_mask = 0ULL;
|
|
int srn, num_rings, i;
|
|
|
|
srn = CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
|
|
|
- for (i = 0; i < num_rings; i++)
|
|
- intr_mask |= (0x1ULL << (srn + i));
|
|
+ for (i = 0; i < num_rings; i++) {
|
|
+ intr_mask |= BIT_ULL(srn + i);
|
|
+ reg_val = octep_read_csr64(oct,
|
|
+ CN93_SDP_R_IN_INT_LEVELS(srn + i));
|
|
+ reg_val &= ~CN93_INT_ENA_BIT;
|
|
+ octep_write_csr64(oct,
|
|
+ CN93_SDP_R_IN_INT_LEVELS(srn + i), reg_val);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct,
|
|
+ CN93_SDP_R_OUT_INT_LEVELS(srn + i));
|
|
+ reg_val &= ~CN93_INT_ENA_BIT;
|
|
+ octep_write_csr64(oct,
|
|
+ CN93_SDP_R_OUT_INT_LEVELS(srn + i), reg_val);
|
|
+ }
|
|
|
|
octep_write_csr64(oct, CN93_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL);
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL);
|
|
+
|
|
octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
|
|
octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
|
|
+
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
|
|
+ octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
|
|
}
|
|
|
|
/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */
|
|
@@ -722,7 +808,16 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)
|
|
oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cn93_pf;
|
|
oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cn93_pf;
|
|
|
|
- oct->hw_ops.non_ioq_intr_handler = octep_non_ioq_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cn93_pf;
|
|
+ oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cn93_pf;
|
|
oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cn93_pf;
|
|
oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf;
|
|
oct->hw_ops.reinit_regs = octep_reinit_regs_cn93_pf;
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c
|
|
new file mode 100644
|
|
index 00000000000000..b1f7bf6e0f5d01
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c
|
|
@@ -0,0 +1,935 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
|
|
+ *
|
|
+ * Copyright (C) 2020 Marvell.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/pci.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/jiffies.h>
|
|
+
|
|
+#include "octep_config.h"
|
|
+#include "octep_main.h"
|
|
+#include "octep_regs_cnxk_pf.h"
|
|
+
|
|
+/* We will support 128 pf's in control mbox */
|
|
+#define CTRL_MBOX_MAX_PF 128
|
|
+#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF))
|
|
+
|
|
+/* Names of Hardware non-queue generic interrupts */
|
|
+static char *cnxk_non_ioq_msix_names[] = {
|
|
+ "epf_ire_rint",
|
|
+ "epf_ore_rint",
|
|
+ "epf_vfire_rint",
|
|
+ "epf_rsvd0",
|
|
+ "epf_vfore_rint",
|
|
+ "epf_rsvd1",
|
|
+ "epf_mbox_rint",
|
|
+ "epf_rsvd2_0",
|
|
+ "epf_rsvd2_1",
|
|
+ "epf_dma_rint",
|
|
+ "epf_dma_vf_rint",
|
|
+ "epf_rsvd3",
|
|
+ "epf_pp_vf_rint",
|
|
+ "epf_rsvd3",
|
|
+ "epf_misc_rint",
|
|
+ "epf_rsvd5",
|
|
+ /* Next 16 are for OEI_RINT */
|
|
+ "epf_oei_rint0",
|
|
+ "epf_oei_rint1",
|
|
+ "epf_oei_rint2",
|
|
+ "epf_oei_rint3",
|
|
+ "epf_oei_rint4",
|
|
+ "epf_oei_rint5",
|
|
+ "epf_oei_rint6",
|
|
+ "epf_oei_rint7",
|
|
+ "epf_oei_rint8",
|
|
+ "epf_oei_rint9",
|
|
+ "epf_oei_rint10",
|
|
+ "epf_oei_rint11",
|
|
+ "epf_oei_rint12",
|
|
+ "epf_oei_rint13",
|
|
+ "epf_oei_rint14",
|
|
+ "epf_oei_rint15",
|
|
+ /* IOQ interrupt */
|
|
+ "octeon_ep"
|
|
+};
|
|
+
|
|
+/* Dump useful hardware CSRs for debug purpose */
|
|
+static void cnxk_dump_regs(struct octep_device *oct, int qno)
|
|
+{
|
|
+ struct device *dev = &oct->pdev->dev;
|
|
+
|
|
+ dev_info(dev, "IQ-%d register dump\n", qno);
|
|
+ dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_INSTR_DBELL(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_CONTROL(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_ENABLE(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_INSTR_BADDR(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_INSTR_RSIZE(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_CNTS(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_CNTS(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_INT_LEVELS(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_PKT_CNT(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(qno)));
|
|
+ dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_IN_BYTE_CNT(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(qno)));
|
|
+
|
|
+ dev_info(dev, "OQ-%d register dump\n", qno);
|
|
+ dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_SLIST_DBELL(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_CONTROL(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_ENABLE(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_SLIST_BADDR(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_SLIST_RSIZE(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_CNTS(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_CNTS(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_INT_LEVELS(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_PKT_CNT(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(qno)));
|
|
+ dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_OUT_BYTE_CNT(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_BYTE_CNT(qno)));
|
|
+ dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n",
|
|
+ qno, CNXK_SDP_R_ERR_TYPE(qno),
|
|
+ octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(qno)));
|
|
+}
|
|
+
|
|
+/* Reset Hardware Tx queue */
|
|
+static int cnxk_reset_iq(struct octep_device *oct, int q_no)
|
|
+{
|
|
+ struct octep_config *conf = oct->conf;
|
|
+ u64 val = 0ULL;
|
|
+
|
|
+ dev_dbg(&oct->pdev->dev, "Reset PF IQ-%d\n", q_no);
|
|
+
|
|
+ /* Get absolute queue number */
|
|
+ q_no += conf->pf_ring_cfg.srn;
|
|
+
|
|
+ /* Disable the Tx/Instruction Ring */
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(q_no), val);
|
|
+
|
|
+ /* clear the Instruction Ring packet/byte counts and doorbell CSRs */
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_CNTS(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(q_no), val);
|
|
+
|
|
+ val = 0xFFFFFFFF;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(q_no), val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Reset Hardware Rx queue */
|
|
+static void cnxk_reset_oq(struct octep_device *oct, int q_no)
|
|
+{
|
|
+ u64 val = 0ULL;
|
|
+
|
|
+ q_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+
|
|
+ /* Disable Output (Rx) Ring */
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(q_no), val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(q_no), val);
|
|
+
|
|
+ /* Clear count CSRs */
|
|
+ val = octep_read_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no));
|
|
+ octep_write_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no), val);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF);
|
|
+}
|
|
+
|
|
+/* Reset all hardware Tx/Rx queues */
|
|
+static void octep_reset_io_queues_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ int q;
|
|
+
|
|
+ dev_dbg(&pdev->dev, "Reset OCTEP_CNXK PF IO Queues\n");
|
|
+
|
|
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
|
+ cnxk_reset_iq(oct, q);
|
|
+ cnxk_reset_oq(oct, q);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Initialize windowed addresses to access some hardware registers */
|
|
+static void octep_setup_pci_window_regs_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr;
|
|
+
|
|
+ oct->pci_win_regs.pci_win_wr_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_ADDR64);
|
|
+ oct->pci_win_regs.pci_win_rd_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_ADDR64);
|
|
+ oct->pci_win_regs.pci_win_wr_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_DATA64);
|
|
+ oct->pci_win_regs.pci_win_rd_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_DATA64);
|
|
+}
|
|
+
|
|
+/* Configure Hardware mapping: inform hardware which rings belong to PF. */
|
|
+static void octep_configure_ring_mapping_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ struct octep_config *conf = oct->conf;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 pf_srn = CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ int q;
|
|
+
|
|
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(conf); q++) {
|
|
+ u64 regval = 0;
|
|
+
|
|
+ if (oct->pcie_port)
|
|
+ regval = 8 << CNXK_SDP_FUNC_SEL_EPF_BIT_POS;
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q), regval);
|
|
+
|
|
+ regval = octep_read_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q));
|
|
+ dev_dbg(&pdev->dev, "Write SDP_EPVF_RING[0x%llx] = 0x%llx\n",
|
|
+ CNXK_SDP_EPVF_RING(pf_srn + q), regval);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Initialize configuration limits and initial active config */
|
|
+static void octep_init_config_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ struct octep_config *conf = oct->conf;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u8 link = 0;
|
|
+ u64 val;
|
|
+ int pos;
|
|
+
|
|
+ /* Read ring configuration:
|
|
+ * PF ring count, number of VFs and rings per VF supported
|
|
+ */
|
|
+ val = octep_read_csr64(oct, CNXK_SDP_EPF_RINFO);
|
|
+ dev_info(&pdev->dev, "SDP_EPF_RINFO[0x%x]:0x%llx\n", CNXK_SDP_EPF_RINFO, val);
|
|
+ conf->sriov_cfg.max_rings_per_vf = CNXK_SDP_EPF_RINFO_RPVF(val);
|
|
+ conf->sriov_cfg.active_rings_per_vf = conf->sriov_cfg.max_rings_per_vf;
|
|
+ conf->sriov_cfg.max_vfs = CNXK_SDP_EPF_RINFO_NVFS(val);
|
|
+ conf->sriov_cfg.active_vfs = conf->sriov_cfg.max_vfs;
|
|
+ conf->sriov_cfg.vf_srn = CNXK_SDP_EPF_RINFO_SRN(val);
|
|
+
|
|
+ val = octep_read_csr64(oct, CNXK_SDP_MAC_PF_RING_CTL(oct->pcie_port));
|
|
+ dev_info(&pdev->dev, "SDP_MAC_PF_RING_CTL[%d]:0x%llx\n", oct->pcie_port, val);
|
|
+ conf->pf_ring_cfg.srn = CNXK_SDP_MAC_PF_RING_CTL_SRN(val);
|
|
+ conf->pf_ring_cfg.max_io_rings = CNXK_SDP_MAC_PF_RING_CTL_RPPF(val);
|
|
+ conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings;
|
|
+ dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n",
|
|
+ conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf,
|
|
+ conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings);
|
|
+
|
|
+ conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS;
|
|
+ conf->iq.instr_type = OCTEP_64BYTE_INSTR;
|
|
+ conf->iq.db_min = OCTEP_DB_MIN;
|
|
+ conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD;
|
|
+
|
|
+ conf->oq.num_descs = OCTEP_OQ_MAX_DESCRIPTORS;
|
|
+ conf->oq.buf_size = OCTEP_OQ_BUF_SIZE;
|
|
+ conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD;
|
|
+ conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD;
|
|
+ conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD;
|
|
+ conf->oq.wmark = OCTEP_OQ_WMARK_MIN;
|
|
+
|
|
+ conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR;
|
|
+ conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings;
|
|
+ conf->msix_cfg.non_ioq_msix_names = cnxk_non_ioq_msix_names;
|
|
+
|
|
+ pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV);
|
|
+ if (pos) {
|
|
+ pci_read_config_byte(oct->pdev,
|
|
+ pos + PCI_SRIOV_FUNC_LINK,
|
|
+ &link);
|
|
+ link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link);
|
|
+ }
|
|
+ conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr +
|
|
+ CNXK_PEM_BAR4_INDEX_OFFSET +
|
|
+ (link * CTRL_MBOX_SZ);
|
|
+
|
|
+ conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL;
|
|
+ conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT;
|
|
+}
|
|
+
|
|
+/* Setup registers for a hardware Tx Queue */
|
|
+static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no)
|
|
+{
|
|
+ struct octep_iq *iq = oct->iq[iq_no];
|
|
+ u32 reset_instr_cnt;
|
|
+ u64 reg_val;
|
|
+
|
|
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no));
|
|
+
|
|
+ /* wait for IDLE to set to 1 */
|
|
+ if (!(reg_val & CNXK_R_IN_CTL_IDLE)) {
|
|
+ do {
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no));
|
|
+ } while (!(reg_val & CNXK_R_IN_CTL_IDLE));
|
|
+ }
|
|
+
|
|
+ reg_val |= CNXK_R_IN_CTL_RDSIZE;
|
|
+ reg_val |= CNXK_R_IN_CTL_IS_64B;
|
|
+ reg_val |= CNXK_R_IN_CTL_ESR;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no), reg_val);
|
|
+
|
|
+ /* Write the start of the input queue's ring and its size */
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(iq_no),
|
|
+ iq->desc_ring_dma);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(iq_no),
|
|
+ iq->max_count);
|
|
+
|
|
+ /* Remember the doorbell & instruction count register addr
|
|
+ * for this queue
|
|
+ */
|
|
+ iq->doorbell_reg = oct->mmio[0].hw_addr +
|
|
+ CNXK_SDP_R_IN_INSTR_DBELL(iq_no);
|
|
+ iq->inst_cnt_reg = oct->mmio[0].hw_addr +
|
|
+ CNXK_SDP_R_IN_CNTS(iq_no);
|
|
+ iq->intr_lvl_reg = oct->mmio[0].hw_addr +
|
|
+ CNXK_SDP_R_IN_INT_LEVELS(iq_no);
|
|
+
|
|
+ /* Store the current instruction counter (used in flush_iq calculation) */
|
|
+ reset_instr_cnt = readl(iq->inst_cnt_reg);
|
|
+ writel(reset_instr_cnt, iq->inst_cnt_reg);
|
|
+
|
|
+ /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */
|
|
+ reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
|
+}
|
|
+
|
|
+/* Setup registers for a hardware Rx Queue */
|
|
+static int octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no)
|
|
+{
|
|
+ struct octep_oq *oq = oct->oq[oq_no];
|
|
+ unsigned long t_out_jiffies;
|
|
+ u32 time_threshold = 0;
|
|
+ u64 oq_ctl = 0ULL;
|
|
+ u64 reg_ba_val;
|
|
+ u64 reg_val;
|
|
+
|
|
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
|
|
+
|
|
+ /* wait for IDLE to set to 1 */
|
|
+ if (!(reg_val & CNXK_R_OUT_CTL_IDLE)) {
|
|
+ do {
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
|
|
+ } while (!(reg_val & CNXK_R_OUT_CTL_IDLE));
|
|
+ }
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), oq->max_count);
|
|
+ /* Wait for WMARK to get applied */
|
|
+ usleep_range(10, 15);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no),
|
|
+ oq->desc_ring_dma);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no),
|
|
+ oq->max_count);
|
|
+ reg_ba_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no));
|
|
+
|
|
+ if (reg_ba_val != oq->desc_ring_dma) {
|
|
+ t_out_jiffies = jiffies + 10 * HZ;
|
|
+ do {
|
|
+ if (reg_ba_val == ULLONG_MAX)
|
|
+ return -EFAULT;
|
|
+ octep_write_csr64(oct,
|
|
+ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no),
|
|
+ oq->desc_ring_dma);
|
|
+ octep_write_csr64(oct,
|
|
+ CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no),
|
|
+ oq->max_count);
|
|
+ reg_ba_val =
|
|
+ octep_read_csr64(oct,
|
|
+ CNXK_SDP_R_OUT_SLIST_BADDR(oq_no));
|
|
+ } while ((reg_ba_val != oq->desc_ring_dma) &&
|
|
+ time_before(jiffies, t_out_jiffies));
|
|
+
|
|
+ if (reg_ba_val != oq->desc_ring_dma)
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_IMODE);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_P);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_P);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_I);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_I);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_ES_I);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_D);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_D);
|
|
+ reg_val &= ~(CNXK_R_OUT_CTL_ES_D);
|
|
+ reg_val |= (CNXK_R_OUT_CTL_ES_P);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val);
|
|
+
|
|
+ oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
|
|
+
|
|
+ /* Clear the ISIZE and BSIZE (22-0) */
|
|
+ oq_ctl &= ~0x7fffffULL;
|
|
+
|
|
+ /* Populate the BSIZE (15-0) */
|
|
+ oq_ctl |= (oq->buffer_size & 0xffff);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), oq_ctl);
|
|
+
|
|
+ /* Get the mapped address of the pkt_sent and pkts_credit regs */
|
|
+ oq->pkts_sent_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_OUT_CNTS(oq_no);
|
|
+ oq->pkts_credit_reg = oct->mmio[0].hw_addr +
|
|
+ CNXK_SDP_R_OUT_SLIST_DBELL(oq_no);
|
|
+
|
|
+ time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf);
|
|
+ reg_val = ((u64)time_threshold << 32) |
|
|
+ CFG_GET_OQ_INTR_PKT(oct->conf);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
|
+
|
|
+ /* set watermark for backpressure */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no));
|
|
+ reg_val &= ~0xFFFFFFFFULL;
|
|
+ reg_val |= CFG_GET_OQ_WMARK(oct->conf);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Setup registers for a PF mailbox */
|
|
+static void octep_setup_mbox_regs_cnxk_pf(struct octep_device *oct, int q_no)
|
|
+{
|
|
+ struct octep_mbox *mbox = oct->mbox[q_no];
|
|
+
|
|
+ mbox->q_no = q_no;
|
|
+
|
|
+ /* PF mbox interrupt reg */
|
|
+ mbox->mbox_int_reg = oct->mmio[0].hw_addr + CNXK_SDP_EPF_MBOX_RINT(0);
|
|
+
|
|
+ /* PF to VF DATA reg. PF writes into this reg */
|
|
+ mbox->mbox_write_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_PF_VF_DATA(q_no);
|
|
+
|
|
+ /* VF to PF DATA reg. PF reads from this reg */
|
|
+ mbox->mbox_read_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_VF_PF_DATA(q_no);
|
|
+}
|
|
+
|
|
+/* Poll OEI events like heartbeat */
|
|
+static void octep_poll_oei_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u64 reg0;
|
|
+
|
|
+ /* Check for OEI INTR */
|
|
+ reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_OEI_RINT);
|
|
+ if (reg0) {
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT, reg0);
|
|
+ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
|
|
+ queue_work(octep_wq, &oct->ctrl_mbox_task);
|
|
+ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
|
|
+ atomic_set(&oct->hb_miss_cnt, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* OEI interrupt handler */
|
|
+static irqreturn_t octep_oei_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+
|
|
+ octep_poll_oei_cnxk_pf(oct);
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Process non-ioq interrupts required to keep pf interface running.
|
|
+ * OEI_RINT is needed for control mailbox
|
|
+ * MBOX_RINT is needed for pfvf mailbox
|
|
+ */
|
|
+static void octep_poll_non_ioq_interrupts_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ octep_poll_oei_cnxk_pf(oct);
|
|
+}
|
|
+
|
|
+/* Interrupt handler for input ring error interrupts. */
|
|
+static irqreturn_t octep_ire_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+ int i = 0;
|
|
+
|
|
+ /* Check for IRERR INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_IRERR_RINT);
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "received IRERR_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT, reg_val);
|
|
+
|
|
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
|
+ reg_val = octep_read_csr64(oct,
|
|
+ CNXK_SDP_R_ERR_TYPE(i));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received err type on IQ-%d: 0x%llx\n",
|
|
+ i, reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i),
|
|
+ reg_val);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for output ring error interrupts. */
|
|
+static irqreturn_t octep_ore_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+ int i = 0;
|
|
+
|
|
+ /* Check for ORERR INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_ORERR_RINT);
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received ORERR_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT, reg_val);
|
|
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(i));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received err type on OQ-%d: 0x%llx\n",
|
|
+ i, reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i),
|
|
+ reg_val);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for vf input ring error interrupts. */
|
|
+static irqreturn_t octep_vfire_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for VFIRE INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received VFIRE_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0), reg_val);
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for vf output ring error interrupts. */
|
|
+static irqreturn_t octep_vfore_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for VFORE INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received VFORE_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0), reg_val);
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for dpi dma related interrupts. */
|
|
+static irqreturn_t octep_dma_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for DMA INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_RINT);
|
|
+ if (reg_val)
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT, reg_val);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for dpi dma transaction error interrupts for VFs */
|
|
+static irqreturn_t octep_dma_vf_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for DMA VF INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received DMA_VF_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0), reg_val);
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for pp transaction error interrupts for VFs */
|
|
+static irqreturn_t octep_pp_vf_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for PPVF INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0));
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received PP_VF_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0), reg_val);
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupt handler for mac related interrupts. */
|
|
+static irqreturn_t octep_misc_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+ u64 reg_val = 0;
|
|
+
|
|
+ /* Check for MISC INTR */
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_MISC_RINT);
|
|
+ if (reg_val) {
|
|
+ dev_info(&pdev->dev,
|
|
+ "Received MISC_RINT intr: 0x%llx\n", reg_val);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT, reg_val);
|
|
+ }
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Interrupts handler for all reserved interrupts. */
|
|
+static irqreturn_t octep_rsvd_intr_handler_cnxk_pf(void *dev)
|
|
+{
|
|
+ struct octep_device *oct = (struct octep_device *)dev;
|
|
+ struct pci_dev *pdev = oct->pdev;
|
|
+
|
|
+ dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n");
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* Tx/Rx queue interrupt handler */
|
|
+static irqreturn_t octep_ioq_intr_handler_cnxk_pf(void *data)
|
|
+{
|
|
+ struct octep_ioq_vector *vector = (struct octep_ioq_vector *)data;
|
|
+ struct octep_oq *oq = vector->oq;
|
|
+
|
|
+ napi_schedule_irqoff(oq->napi);
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+/* soft reset */
|
|
+static int octep_soft_reset_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ dev_info(&oct->pdev->dev, "CNXKXX: Doing soft reset\n");
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF);
|
|
+
|
|
+ /* Firmware status CSR is supposed to be cleared by
|
|
+ * core domain reset, but due to a hw bug, it is not.
|
|
+ * Set it to RUNNING right before reset so that it is not
|
|
+ * left in READY (1) state after a reset. This is required
|
|
+ * in addition to the early setting to handle the case where
|
|
+ * the OcteonTX is unexpectedly reset, reboots, and then
|
|
+ * the module is removed.
|
|
+ */
|
|
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL),
|
|
+ FW_STATUS_RUNNING);
|
|
+
|
|
+ /* Set chip domain reset bit */
|
|
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_RST_CHIP_DOMAIN_W1S, 1);
|
|
+ /* Wait till Octeon resets. */
|
|
+ mdelay(10);
|
|
+ /* restore the reset value */
|
|
+ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Re-initialize Octeon hardware registers */
|
|
+static void octep_reinit_regs_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u32 i;
|
|
+
|
|
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
|
+ oct->hw_ops.setup_iq_regs(oct, i);
|
|
+
|
|
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
|
+ oct->hw_ops.setup_oq_regs(oct, i);
|
|
+
|
|
+ oct->hw_ops.enable_interrupts(oct);
|
|
+ oct->hw_ops.enable_io_queues(oct);
|
|
+
|
|
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
|
|
+ writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
|
|
+}
|
|
+
|
|
+/* Enable all interrupts */
|
|
+static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u64 intr_mask = 0ULL;
|
|
+ int srn, num_rings, i;
|
|
+
|
|
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
|
+
|
|
+ for (i = 0; i < num_rings; i++)
|
|
+ intr_mask |= (0x1ULL << (srn + i));
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
|
|
+}
|
|
+
|
|
+/* Disable all interrupts */
|
|
+static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u64 reg_val, intr_mask = 0ULL;
|
|
+ int srn, num_rings, i;
|
|
+
|
|
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
|
+
|
|
+ for (i = 0; i < num_rings; i++) {
|
|
+ intr_mask |= BIT_ULL(srn + i);
|
|
+ reg_val = octep_read_csr64(oct,
|
|
+ CNXK_SDP_R_IN_INT_LEVELS(srn + i));
|
|
+ reg_val &= ~CNXK_INT_ENA_BIT;
|
|
+ octep_write_csr64(oct,
|
|
+ CNXK_SDP_R_IN_INT_LEVELS(srn + i), reg_val);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct,
|
|
+ CNXK_SDP_R_OUT_INT_LEVELS(srn + i));
|
|
+ reg_val &= ~CNXK_INT_ENA_BIT;
|
|
+ octep_write_csr64(oct,
|
|
+ CNXK_SDP_R_OUT_INT_LEVELS(srn + i), reg_val);
|
|
+ }
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
|
|
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
|
|
+}
|
|
+
|
|
+/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */
|
|
+static u32 octep_update_iq_read_index_cnxk_pf(struct octep_iq *iq)
|
|
+{
|
|
+ u32 pkt_in_done = readl(iq->inst_cnt_reg);
|
|
+ u32 last_done, new_idx;
|
|
+
|
|
+ last_done = pkt_in_done - iq->pkt_in_done;
|
|
+ iq->pkt_in_done = pkt_in_done;
|
|
+
|
|
+ new_idx = (iq->octep_read_index + last_done) % iq->max_count;
|
|
+
|
|
+ return new_idx;
|
|
+}
|
|
+
|
|
+/* Enable a hardware Tx Queue */
|
|
+static void octep_enable_iq_cnxk_pf(struct octep_device *oct, int iq_no)
|
|
+{
|
|
+ u64 loop = HZ;
|
|
+ u64 reg_val;
|
|
+
|
|
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF);
|
|
+
|
|
+ while (octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no)) &&
|
|
+ loop--) {
|
|
+ schedule_timeout_interruptible(1);
|
|
+ }
|
|
+
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no));
|
|
+ reg_val |= (0x1ULL << 62);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no));
|
|
+ reg_val |= 0x1ULL;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val);
|
|
+}
|
|
+
|
|
+/* Enable a hardware Rx Queue */
|
|
+static void octep_enable_oq_cnxk_pf(struct octep_device *oct, int oq_no)
|
|
+{
|
|
+ u64 reg_val = 0ULL;
|
|
+
|
|
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no));
|
|
+ reg_val |= (0x1ULL << 62);
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
|
|
+
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no));
|
|
+ reg_val |= 0x1ULL;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
|
+}
|
|
+
|
|
+/* Enable all hardware Tx/Rx Queues assined to PF */
|
|
+static void octep_enable_io_queues_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u8 q;
|
|
+
|
|
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
|
+ octep_enable_iq_cnxk_pf(oct, q);
|
|
+ octep_enable_oq_cnxk_pf(oct, q);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Disable a hardware Tx Queue assined to PF */
|
|
+static void octep_disable_iq_cnxk_pf(struct octep_device *oct, int iq_no)
|
|
+{
|
|
+ u64 reg_val = 0ULL;
|
|
+
|
|
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no));
|
|
+ reg_val &= ~0x1ULL;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val);
|
|
+}
|
|
+
|
|
+/* Disable a hardware Rx Queue assined to PF */
|
|
+static void octep_disable_oq_cnxk_pf(struct octep_device *oct, int oq_no)
|
|
+{
|
|
+ u64 reg_val = 0ULL;
|
|
+
|
|
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no));
|
|
+ reg_val &= ~0x1ULL;
|
|
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val);
|
|
+}
|
|
+
|
|
+/* Disable all hardware Tx/Rx Queues assined to PF */
|
|
+static void octep_disable_io_queues_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ int q = 0;
|
|
+
|
|
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
|
|
+ octep_disable_iq_cnxk_pf(oct, q);
|
|
+ octep_disable_oq_cnxk_pf(oct, q);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Dump hardware registers (including Tx/Rx queues) for debugging. */
|
|
+static void octep_dump_registers_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ u8 srn, num_rings, q;
|
|
+
|
|
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
|
|
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
|
|
+
|
|
+ for (q = srn; q < srn + num_rings; q++)
|
|
+ cnxk_dump_regs(oct, q);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_device_setup_cnxk_pf() - Setup Octeon device.
|
|
+ *
|
|
+ * @oct: Octeon device private data structure.
|
|
+ *
|
|
+ * - initialize hardware operations.
|
|
+ * - get target side pcie port number for the device.
|
|
+ * - setup window access to hardware registers.
|
|
+ * - set initial configuration and max limits.
|
|
+ * - setup hardware mapping of rings to the PF device.
|
|
+ */
|
|
+void octep_device_setup_cnxk_pf(struct octep_device *oct)
|
|
+{
|
|
+ oct->hw_ops.setup_iq_regs = octep_setup_iq_regs_cnxk_pf;
|
|
+ oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cnxk_pf;
|
|
+ oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cnxk_pf;
|
|
+ oct->hw_ops.soft_reset = octep_soft_reset_cnxk_pf;
|
|
+ oct->hw_ops.reinit_regs = octep_reinit_regs_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.enable_interrupts = octep_enable_interrupts_cnxk_pf;
|
|
+ oct->hw_ops.disable_interrupts = octep_disable_interrupts_cnxk_pf;
|
|
+ oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.enable_iq = octep_enable_iq_cnxk_pf;
|
|
+ oct->hw_ops.enable_oq = octep_enable_oq_cnxk_pf;
|
|
+ oct->hw_ops.enable_io_queues = octep_enable_io_queues_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.disable_iq = octep_disable_iq_cnxk_pf;
|
|
+ oct->hw_ops.disable_oq = octep_disable_oq_cnxk_pf;
|
|
+ oct->hw_ops.disable_io_queues = octep_disable_io_queues_cnxk_pf;
|
|
+ oct->hw_ops.reset_io_queues = octep_reset_io_queues_cnxk_pf;
|
|
+
|
|
+ oct->hw_ops.dump_registers = octep_dump_registers_cnxk_pf;
|
|
+
|
|
+ octep_setup_pci_window_regs_cnxk_pf(oct);
|
|
+
|
|
+ oct->pcie_port = octep_read_csr64(oct, CNXK_SDP_MAC_NUMBER) & 0xff;
|
|
+ dev_info(&oct->pdev->dev,
|
|
+ "Octeon device using PCIE Port %d\n", oct->pcie_port);
|
|
+
|
|
+ octep_init_config_cnxk_pf(oct);
|
|
+ octep_configure_ring_mapping_cnxk_pf(oct);
|
|
+
|
|
+ /* Firmware status CSR is supposed to be cleared by
|
|
+ * core domain reset, but due to IPBUPEM-38842, it is not.
|
|
+ * Set it to RUNNING early in boot, so that unexpected resets
|
|
+ * leave it in a state that is not READY (1).
|
|
+ */
|
|
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL),
|
|
+ FW_STATUS_RUNNING);
|
|
+}
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
|
|
index df7cd39d9fce13..ecc29479314109 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
|
|
@@ -19,6 +19,9 @@
|
|
/* Packet threshold for Tx queue interrupt */
|
|
#define OCTEP_IQ_INTR_THRESHOLD 0x0
|
|
|
|
+/* Minimum watermark for backpressure */
|
|
+#define OCTEP_OQ_WMARK_MIN 256
|
|
+
|
|
/* Rx Queue: maximum descriptors per ring */
|
|
#define OCTEP_OQ_MAX_DESCRIPTORS 1024
|
|
|
|
@@ -49,6 +52,11 @@
|
|
/* Default MTU */
|
|
#define OCTEP_DEFAULT_MTU 1500
|
|
|
|
+/* pf heartbeat interval in milliseconds */
|
|
+#define OCTEP_DEFAULT_FW_HB_INTERVAL 1000
|
|
+/* pf heartbeat miss count */
|
|
+#define OCTEP_DEFAULT_FW_HB_MISS_COUNT 20
|
|
+
|
|
/* Macros to get octeon config params */
|
|
#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq)
|
|
#define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs)
|
|
@@ -63,6 +71,7 @@
|
|
#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold)
|
|
#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt)
|
|
#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time)
|
|
+#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark)
|
|
|
|
#define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.max_io_rings)
|
|
#define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings)
|
|
@@ -132,6 +141,12 @@ struct octep_oq_config {
|
|
* default. The time is specified in microseconds.
|
|
*/
|
|
u32 oq_intr_time;
|
|
+
|
|
+ /* Water mark for backpressure.
|
|
+ * Output queue sends backpressure signal to source when
|
|
+ * free buffer count falls below wmark.
|
|
+ */
|
|
+ u32 wmark;
|
|
};
|
|
|
|
/* Tx/Rx configuration */
|
|
@@ -181,6 +196,16 @@ struct octep_ctrl_mbox_config {
|
|
void __iomem *barmem_addr;
|
|
};
|
|
|
|
+/* Info from firmware */
|
|
+struct octep_fw_info {
|
|
+ /* interface pkind */
|
|
+ u16 pkind;
|
|
+ /* heartbeat interval in milliseconds */
|
|
+ u16 hb_interval;
|
|
+ /* heartbeat miss count */
|
|
+ u16 hb_miss_count;
|
|
+};
|
|
+
|
|
/* Data Structure to hold configuration limits and active config */
|
|
struct octep_config {
|
|
/* Input Queue attributes. */
|
|
@@ -201,10 +226,7 @@ struct octep_config {
|
|
/* ctrl mbox config */
|
|
struct octep_ctrl_mbox_config ctrl_mbox_cfg;
|
|
|
|
- /* Configured maximum heartbeat miss count */
|
|
- u32 max_hb_miss_cnt;
|
|
-
|
|
- /* Configured firmware heartbeat interval in secs */
|
|
- u32 hb_interval;
|
|
+ /* fw info */
|
|
+ struct octep_fw_info fw_info;
|
|
};
|
|
#endif /* _OCTEP_CONFIG_H_ */
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
|
|
index 17bfd5cdf46201..0594607a258545 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
|
|
@@ -26,7 +26,7 @@ static atomic_t ctrl_net_msg_id;
|
|
|
|
/* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */
|
|
static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = {
|
|
- [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_LINK_INFO] =
|
|
+ [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_GET_INFO] =
|
|
OCTEP_CP_VERSION(1, 0, 0)
|
|
};
|
|
|
|
@@ -353,6 +353,28 @@ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct)
|
|
}
|
|
}
|
|
|
|
+int octep_ctrl_net_get_info(struct octep_device *oct, int vfid,
|
|
+ struct octep_fw_info *info)
|
|
+{
|
|
+ struct octep_ctrl_net_wait_data d = {0};
|
|
+ struct octep_ctrl_net_h2f_resp *resp;
|
|
+ struct octep_ctrl_net_h2f_req *req;
|
|
+ int err;
|
|
+
|
|
+ req = &d.data.req;
|
|
+ init_send_req(&d.msg, req, 0, vfid);
|
|
+ req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_GET_INFO;
|
|
+ req->link_info.cmd = OCTEP_CTRL_NET_CMD_GET;
|
|
+ err = octep_send_mbox_req(oct, &d, true);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ resp = &d.data.resp;
|
|
+ memcpy(info, &resp->info.fw_info, sizeof(struct octep_fw_info));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int octep_ctrl_net_uninit(struct octep_device *oct)
|
|
{
|
|
struct octep_ctrl_net_wait_data *pos, *n;
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
|
|
index 1c2ef4ee31d91e..b330f370131be7 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
|
|
@@ -41,6 +41,7 @@ enum octep_ctrl_net_h2f_cmd {
|
|
OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS,
|
|
OCTEP_CTRL_NET_H2F_CMD_RX_STATE,
|
|
OCTEP_CTRL_NET_H2F_CMD_LINK_INFO,
|
|
+ OCTEP_CTRL_NET_H2F_CMD_GET_INFO,
|
|
OCTEP_CTRL_NET_H2F_CMD_MAX
|
|
};
|
|
|
|
@@ -161,6 +162,11 @@ struct octep_ctrl_net_h2f_resp_cmd_state {
|
|
u16 state;
|
|
};
|
|
|
|
+/* get info request */
|
|
+struct octep_ctrl_net_h2f_resp_cmd_get_info {
|
|
+ struct octep_fw_info fw_info;
|
|
+};
|
|
+
|
|
/* Host to fw response data */
|
|
struct octep_ctrl_net_h2f_resp {
|
|
union octep_ctrl_net_resp_hdr hdr;
|
|
@@ -171,6 +177,7 @@ struct octep_ctrl_net_h2f_resp {
|
|
struct octep_ctrl_net_h2f_resp_cmd_state link;
|
|
struct octep_ctrl_net_h2f_resp_cmd_state rx;
|
|
struct octep_ctrl_net_link_info link_info;
|
|
+ struct octep_ctrl_net_h2f_resp_cmd_get_info info;
|
|
};
|
|
} __packed;
|
|
|
|
@@ -330,6 +337,17 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct,
|
|
*/
|
|
void octep_ctrl_net_recv_fw_messages(struct octep_device *oct);
|
|
|
|
+/** Get info from firmware.
|
|
+ *
|
|
+ * @param oct: non-null pointer to struct octep_device.
|
|
+ * @param vfid: Index of virtual function.
|
|
+ * @param info: non-null pointer to struct octep_fw_info.
|
|
+ *
|
|
+ * return value: 0 on success, -errno on failure.
|
|
+ */
|
|
+int octep_ctrl_net_get_info(struct octep_device *oct, int vfid,
|
|
+ struct octep_fw_info *info);
|
|
+
|
|
/** Uninitialize data for ctrl net.
|
|
*
|
|
* @param oct: non-null pointer to struct octep_device.
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
index c385084546639d..db24c290a90796 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
|
|
@@ -24,6 +24,10 @@ struct workqueue_struct *octep_wq;
|
|
static const struct pci_device_id octep_pci_id_tbl[] = {
|
|
{PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_PF)},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_PF)},
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_PF)},
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_PF)},
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_PF)},
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_PF)},
|
|
{0, },
|
|
};
|
|
MODULE_DEVICE_TABLE(pci, octep_pci_id_tbl);
|
|
@@ -155,18 +159,153 @@ static void octep_disable_msix(struct octep_device *oct)
|
|
}
|
|
|
|
/**
|
|
- * octep_non_ioq_intr_handler() - common handler for all generic interrupts.
|
|
+ * octep_oei_intr_handler() - common handler for output endpoint interrupts.
|
|
*
|
|
* @irq: Interrupt number.
|
|
* @data: interrupt data.
|
|
*
|
|
- * this is common handler for all non-queue (generic) interrupts.
|
|
+ * this is common handler for all output endpoint interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_oei_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.oei_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_ire_intr_handler() - common handler for input ring error interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for input ring error interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_ire_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.ire_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_ore_intr_handler() - common handler for output ring error interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for output ring error interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_ore_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.ore_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_vfire_intr_handler() - common handler for vf input ring error interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for vf input ring error interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_vfire_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.vfire_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_vfore_intr_handler() - common handler for vf output ring error interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for vf output ring error interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_vfore_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.vfore_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_dma_intr_handler() - common handler for dpi dma related interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for dpi dma related interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_dma_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.dma_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_dma_vf_intr_handler() - common handler for dpi dma transaction error interrupts for VFs.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for dpi dma transaction error interrupts for VFs.
|
|
+ */
|
|
+static irqreturn_t octep_dma_vf_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.dma_vf_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_pp_vf_intr_handler() - common handler for pp transaction error interrupts for VFs.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for pp transaction error interrupts for VFs.
|
|
+ */
|
|
+static irqreturn_t octep_pp_vf_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.pp_vf_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_misc_intr_handler() - common handler for mac related interrupts.
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for mac related interrupts.
|
|
*/
|
|
-static irqreturn_t octep_non_ioq_intr_handler(int irq, void *data)
|
|
+static irqreturn_t octep_misc_intr_handler(int irq, void *data)
|
|
{
|
|
struct octep_device *oct = data;
|
|
|
|
- return oct->hw_ops.non_ioq_intr_handler(oct);
|
|
+ return oct->hw_ops.misc_intr_handler(oct);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * octep_rsvd_intr_handler() - common handler for reserved interrupts (future use).
|
|
+ *
|
|
+ * @irq: Interrupt number.
|
|
+ * @data: interrupt data.
|
|
+ *
|
|
+ * this is common handler for all reserved interrupts.
|
|
+ */
|
|
+static irqreturn_t octep_rsvd_intr_handler(int irq, void *data)
|
|
+{
|
|
+ struct octep_device *oct = data;
|
|
+
|
|
+ return oct->hw_ops.rsvd_intr_handler(oct);
|
|
}
|
|
|
|
/**
|
|
@@ -222,9 +361,57 @@ static int octep_request_irqs(struct octep_device *oct)
|
|
|
|
snprintf(irq_name, OCTEP_MSIX_NAME_SIZE,
|
|
"%s-%s", netdev->name, non_ioq_msix_names[i]);
|
|
- ret = request_irq(msix_entry->vector,
|
|
- octep_non_ioq_intr_handler, 0,
|
|
- irq_name, oct);
|
|
+ if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint",
|
|
+ strlen("epf_oei_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_oei_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_ire_rint",
|
|
+ strlen("epf_ire_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_ire_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_ore_rint",
|
|
+ strlen("epf_ore_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_ore_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_vfire_rint",
|
|
+ strlen("epf_vfire_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_vfire_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_vfore_rint",
|
|
+ strlen("epf_vfore_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_vfore_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_dma_rint",
|
|
+ strlen("epf_dma_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_dma_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_dma_vf_rint",
|
|
+ strlen("epf_dma_vf_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_dma_vf_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_pp_vf_rint",
|
|
+ strlen("epf_pp_vf_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_pp_vf_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_misc_rint",
|
|
+ strlen("epf_misc_rint"))) {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_misc_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ } else {
|
|
+ ret = request_irq(msix_entry->vector,
|
|
+ octep_rsvd_intr_handler, 0,
|
|
+ irq_name, oct);
|
|
+ }
|
|
+
|
|
if (ret) {
|
|
netdev_err(netdev,
|
|
"request_irq failed for %s; err=%d",
|
|
@@ -907,9 +1094,9 @@ static void octep_hb_timeout_task(struct work_struct *work)
|
|
int miss_cnt;
|
|
|
|
miss_cnt = atomic_inc_return(&oct->hb_miss_cnt);
|
|
- if (miss_cnt < oct->conf->max_hb_miss_cnt) {
|
|
+ if (miss_cnt < oct->conf->fw_info.hb_miss_count) {
|
|
queue_delayed_work(octep_wq, &oct->hb_task,
|
|
- msecs_to_jiffies(oct->conf->hb_interval * 1000));
|
|
+ msecs_to_jiffies(oct->conf->fw_info.hb_interval));
|
|
return;
|
|
}
|
|
|
|
@@ -943,6 +1130,14 @@ static const char *octep_devid_to_str(struct octep_device *oct)
|
|
return "CN93XX";
|
|
case OCTEP_PCI_DEVICE_ID_CNF95N_PF:
|
|
return "CNF95N";
|
|
+ case OCTEP_PCI_DEVICE_ID_CN10KA_PF:
|
|
+ return "CN10KA";
|
|
+ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF:
|
|
+ return "CNF10KA";
|
|
+ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF:
|
|
+ return "CNF10KB";
|
|
+ case OCTEP_PCI_DEVICE_ID_CN10KB_PF:
|
|
+ return "CN10KB";
|
|
default:
|
|
return "Unsupported";
|
|
}
|
|
@@ -988,6 +1183,14 @@ int octep_device_setup(struct octep_device *oct)
|
|
OCTEP_MINOR_REV(oct));
|
|
octep_device_setup_cn93_pf(oct);
|
|
break;
|
|
+ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF:
|
|
+ case OCTEP_PCI_DEVICE_ID_CN10KA_PF:
|
|
+ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF:
|
|
+ case OCTEP_PCI_DEVICE_ID_CN10KB_PF:
|
|
+ dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n",
|
|
+ octep_devid_to_str(oct), OCTEP_MAJOR_REV(oct), OCTEP_MINOR_REV(oct));
|
|
+ octep_device_setup_cnxk_pf(oct);
|
|
+ break;
|
|
default:
|
|
dev_err(&pdev->dev,
|
|
"%s: unsupported device\n", __func__);
|
|
@@ -1002,8 +1205,7 @@ int octep_device_setup(struct octep_device *oct)
|
|
|
|
atomic_set(&oct->hb_miss_cnt, 0);
|
|
INIT_DELAYED_WORK(&oct->hb_task, octep_hb_timeout_task);
|
|
- queue_delayed_work(octep_wq, &oct->hb_task,
|
|
- msecs_to_jiffies(oct->conf->hb_interval * 1000));
|
|
+
|
|
return 0;
|
|
|
|
unsupported_dev:
|
|
@@ -1133,6 +1335,15 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
dev_err(&pdev->dev, "Device setup failed\n");
|
|
goto err_octep_config;
|
|
}
|
|
+
|
|
+ octep_ctrl_net_get_info(octep_dev, OCTEP_CTRL_NET_INVALID_VFID,
|
|
+ &octep_dev->conf->fw_info);
|
|
+ dev_info(&octep_dev->pdev->dev, "Heartbeat interval %u msecs Heartbeat miss count %u\n",
|
|
+ octep_dev->conf->fw_info.hb_interval,
|
|
+ octep_dev->conf->fw_info.hb_miss_count);
|
|
+ queue_delayed_work(octep_wq, &octep_dev->hb_task,
|
|
+ msecs_to_jiffies(octep_dev->conf->fw_info.hb_interval));
|
|
+
|
|
INIT_WORK(&octep_dev->tx_timeout_task, octep_tx_timeout_task);
|
|
INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_task);
|
|
INIT_DELAYED_WORK(&octep_dev->intr_poll_task, octep_intr_poll_task);
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
|
|
index e0907a7191330e..ce92a201278948 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
|
|
@@ -23,6 +23,11 @@
|
|
|
|
#define OCTEP_PCI_DEVICE_ID_CNF95N_PF 0xB400 //95N PF
|
|
|
|
+#define OCTEP_PCI_DEVICE_ID_CN10KA_PF 0xB900 //CN10KA PF
|
|
+#define OCTEP_PCI_DEVICE_ID_CNF10KA_PF 0xBA00 //CNF10KA PF
|
|
+#define OCTEP_PCI_DEVICE_ID_CNF10KB_PF 0xBC00 //CNF10KB PF
|
|
+#define OCTEP_PCI_DEVICE_ID_CN10KB_PF 0xBD00 //CN10KB PF
|
|
+
|
|
#define OCTEP_MAX_QUEUES 63
|
|
#define OCTEP_MAX_IQ OCTEP_MAX_QUEUES
|
|
#define OCTEP_MAX_OQ OCTEP_MAX_QUEUES
|
|
@@ -62,10 +67,19 @@ struct octep_pci_win_regs {
|
|
|
|
struct octep_hw_ops {
|
|
void (*setup_iq_regs)(struct octep_device *oct, int q);
|
|
- void (*setup_oq_regs)(struct octep_device *oct, int q);
|
|
+ int (*setup_oq_regs)(struct octep_device *oct, int q);
|
|
void (*setup_mbox_regs)(struct octep_device *oct, int mbox);
|
|
|
|
- irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*oei_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*ire_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*ore_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*vfire_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*vfore_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*dma_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*dma_vf_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*pp_vf_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*misc_intr_handler)(void *ioq_vector);
|
|
+ irqreturn_t (*rsvd_intr_handler)(void *ioq_vector);
|
|
irqreturn_t (*ioq_intr_handler)(void *ioq_vector);
|
|
int (*soft_reset)(struct octep_device *oct);
|
|
void (*reinit_regs)(struct octep_device *oct);
|
|
@@ -73,7 +87,7 @@ struct octep_hw_ops {
|
|
|
|
void (*enable_interrupts)(struct octep_device *oct);
|
|
void (*disable_interrupts)(struct octep_device *oct);
|
|
- bool (*poll_non_ioq_interrupts)(struct octep_device *oct);
|
|
+ void (*poll_non_ioq_interrupts)(struct octep_device *oct);
|
|
|
|
void (*enable_io_queues)(struct octep_device *oct);
|
|
void (*disable_io_queues)(struct octep_device *oct);
|
|
@@ -368,6 +382,7 @@ int octep_setup_oqs(struct octep_device *oct);
|
|
void octep_free_oqs(struct octep_device *oct);
|
|
void octep_oq_dbell_init(struct octep_device *oct);
|
|
void octep_device_setup_cn93_pf(struct octep_device *oct);
|
|
+void octep_device_setup_cnxk_pf(struct octep_device *oct);
|
|
int octep_iq_process_completions(struct octep_iq *iq, u16 budget);
|
|
int octep_oq_process_rx(struct octep_oq *oq, int budget);
|
|
void octep_set_ethtool_ops(struct net_device *netdev);
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
|
|
index b25c3093dc7b4e..9ecfbabe3b9c5b 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
|
|
@@ -370,4 +370,9 @@
|
|
/* bit 1 for firmware heartbeat interrupt */
|
|
#define CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1)
|
|
|
|
+#define CN93_PEM_BAR4_INDEX 7
|
|
+#define CN93_PEM_BAR4_INDEX_SIZE 0x400000ULL
|
|
+#define CN93_PEM_BAR4_INDEX_OFFSET (CN93_PEM_BAR4_INDEX * CN93_PEM_BAR4_INDEX_SIZE)
|
|
+#define CN93_INT_ENA_BIT BIT_ULL(62)
|
|
+
|
|
#endif /* _OCTEP_REGS_CN9K_PF_H_ */
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h
|
|
new file mode 100644
|
|
index 00000000000000..f0b3937002b624
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h
|
|
@@ -0,0 +1,404 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
|
|
+ *
|
|
+ * Copyright (C) 2020 Marvell.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _OCTEP_REGS_CNXK_PF_H_
|
|
+#define _OCTEP_REGS_CNXK_PF_H_
|
|
+
|
|
+/* ############################ RST ######################### */
|
|
+#define CNXK_RST_BOOT 0x000087E006001600ULL
|
|
+#define CNXK_RST_CHIP_DOMAIN_W1S 0x000087E006001810ULL
|
|
+#define CNXK_RST_CORE_DOMAIN_W1S 0x000087E006001820ULL
|
|
+#define CNXK_RST_CORE_DOMAIN_W1C 0x000087E006001828ULL
|
|
+
|
|
+#define CNXK_CONFIG_XPANSION_BAR 0x38
|
|
+#define CNXK_CONFIG_PCIE_CAP 0x70
|
|
+#define CNXK_CONFIG_PCIE_DEVCAP 0x74
|
|
+#define CNXK_CONFIG_PCIE_DEVCTL 0x78
|
|
+#define CNXK_CONFIG_PCIE_LINKCAP 0x7C
|
|
+#define CNXK_CONFIG_PCIE_LINKCTL 0x80
|
|
+#define CNXK_CONFIG_PCIE_SLOTCAP 0x84
|
|
+#define CNXK_CONFIG_PCIE_SLOTCTL 0x88
|
|
+
|
|
+#define CNXK_PCIE_SRIOV_FDL 0x188 /* 0x98 */
|
|
+#define CNXK_PCIE_SRIOV_FDL_BIT_POS 0x10
|
|
+#define CNXK_PCIE_SRIOV_FDL_MASK 0xFF
|
|
+
|
|
+#define CNXK_CONFIG_PCIE_FLTMSK 0x720
|
|
+
|
|
+/* ################# Offsets of RING, EPF, MAC ######################### */
|
|
+#define CNXK_RING_OFFSET (0x1ULL << 17)
|
|
+#define CNXK_EPF_OFFSET (0x1ULL << 25)
|
|
+#define CNXK_MAC_OFFSET (0x1ULL << 4)
|
|
+#define CNXK_BIT_ARRAY_OFFSET (0x1ULL << 4)
|
|
+#define CNXK_EPVF_RING_OFFSET (0x1ULL << 4)
|
|
+
|
|
+/* ################# Scratch Registers ######################### */
|
|
+#define CNXK_SDP_EPF_SCRATCH 0x209E0
|
|
+
|
|
+/* ################# Window Registers ######################### */
|
|
+#define CNXK_SDP_WIN_WR_ADDR64 0x20000
|
|
+#define CNXK_SDP_WIN_RD_ADDR64 0x20010
|
|
+#define CNXK_SDP_WIN_WR_DATA64 0x20020
|
|
+#define CNXK_SDP_WIN_WR_MASK_REG 0x20030
|
|
+#define CNXK_SDP_WIN_RD_DATA64 0x20040
|
|
+
|
|
+#define CNXK_SDP_MAC_NUMBER 0x2C100
|
|
+
|
|
+/* ################# Global Previliged registers ######################### */
|
|
+#define CNXK_SDP_EPF_RINFO 0x209F0
|
|
+
|
|
+#define CNXK_SDP_EPF_RINFO_SRN(val) ((val) & 0x7F)
|
|
+#define CNXK_SDP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF)
|
|
+#define CNXK_SDP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F)
|
|
+
|
|
+/* SDP Function select */
|
|
+#define CNXK_SDP_FUNC_SEL_EPF_BIT_POS 7
|
|
+#define CNXK_SDP_FUNC_SEL_FUNC_BIT_POS 0
|
|
+
|
|
+/* ##### RING IN (Into device from PCI: Tx Ring) REGISTERS #### */
|
|
+#define CNXK_SDP_R_IN_CONTROL_START 0x10000
|
|
+#define CNXK_SDP_R_IN_ENABLE_START 0x10010
|
|
+#define CNXK_SDP_R_IN_INSTR_BADDR_START 0x10020
|
|
+#define CNXK_SDP_R_IN_INSTR_RSIZE_START 0x10030
|
|
+#define CNXK_SDP_R_IN_INSTR_DBELL_START 0x10040
|
|
+#define CNXK_SDP_R_IN_CNTS_START 0x10050
|
|
+#define CNXK_SDP_R_IN_INT_LEVELS_START 0x10060
|
|
+#define CNXK_SDP_R_IN_PKT_CNT_START 0x10080
|
|
+#define CNXK_SDP_R_IN_BYTE_CNT_START 0x10090
|
|
+
|
|
+#define CNXK_SDP_R_IN_CONTROL(ring) \
|
|
+ (CNXK_SDP_R_IN_CONTROL_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_ENABLE(ring) \
|
|
+ (CNXK_SDP_R_IN_ENABLE_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INSTR_BADDR(ring) \
|
|
+ (CNXK_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INSTR_RSIZE(ring) \
|
|
+ (CNXK_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INSTR_DBELL(ring) \
|
|
+ (CNXK_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_CNTS(ring) \
|
|
+ (CNXK_SDP_R_IN_CNTS_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INT_LEVELS(ring) \
|
|
+ (CNXK_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_PKT_CNT(ring) \
|
|
+ (CNXK_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_BYTE_CNT(ring) \
|
|
+ (CNXK_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+/* Rings per Virtual Function */
|
|
+#define CNXK_R_IN_CTL_RPVF_MASK (0xF)
|
|
+#define CNXK_R_IN_CTL_RPVF_POS (48)
|
|
+
|
|
+/* Number of instructions to be read in one MAC read request.
|
|
+ * setting to Max value(4)
|
|
+ */
|
|
+#define CNXK_R_IN_CTL_IDLE (0x1ULL << 28)
|
|
+#define CNXK_R_IN_CTL_RDSIZE (0x3ULL << 25)
|
|
+#define CNXK_R_IN_CTL_IS_64B (0x1ULL << 24)
|
|
+#define CNXK_R_IN_CTL_D_NSR (0x1ULL << 8)
|
|
+#define CNXK_R_IN_CTL_D_ESR (0x1ULL << 6)
|
|
+#define CNXK_R_IN_CTL_D_ROR (0x1ULL << 5)
|
|
+#define CNXK_R_IN_CTL_NSR (0x1ULL << 3)
|
|
+#define CNXK_R_IN_CTL_ESR (0x1ULL << 1)
|
|
+#define CNXK_R_IN_CTL_ROR (0x1ULL << 0)
|
|
+
|
|
+#define CNXK_R_IN_CTL_MASK (CNXK_R_IN_CTL_RDSIZE | CNXK_R_IN_CTL_IS_64B)
|
|
+
|
|
+/* ##### RING OUT (out from device to PCI host: Rx Ring) REGISTERS #### */
|
|
+#define CNXK_SDP_R_OUT_CNTS_START 0x10100
|
|
+#define CNXK_SDP_R_OUT_INT_LEVELS_START 0x10110
|
|
+#define CNXK_SDP_R_OUT_SLIST_BADDR_START 0x10120
|
|
+#define CNXK_SDP_R_OUT_SLIST_RSIZE_START 0x10130
|
|
+#define CNXK_SDP_R_OUT_SLIST_DBELL_START 0x10140
|
|
+#define CNXK_SDP_R_OUT_CONTROL_START 0x10150
|
|
+#define CNXK_SDP_R_OUT_WMARK_START 0x10160
|
|
+#define CNXK_SDP_R_OUT_ENABLE_START 0x10170
|
|
+#define CNXK_SDP_R_OUT_PKT_CNT_START 0x10180
|
|
+#define CNXK_SDP_R_OUT_BYTE_CNT_START 0x10190
|
|
+
|
|
+#define CNXK_SDP_R_OUT_CONTROL(ring) \
|
|
+ (CNXK_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_ENABLE(ring) \
|
|
+ (CNXK_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_SLIST_BADDR(ring) \
|
|
+ (CNXK_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_SLIST_RSIZE(ring) \
|
|
+ (CNXK_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \
|
|
+ (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_WMARK(ring) \
|
|
+ (CNXK_SDP_R_OUT_WMARK_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_CNTS(ring) \
|
|
+ (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_INT_LEVELS(ring) \
|
|
+ (CNXK_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_PKT_CNT(ring) \
|
|
+ (CNXK_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_BYTE_CNT(ring) \
|
|
+ (CNXK_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+/*------------------ R_OUT Masks ----------------*/
|
|
+#define CNXK_R_OUT_INT_LEVELS_BMODE BIT_ULL(63)
|
|
+#define CNXK_R_OUT_INT_LEVELS_TIMET (32)
|
|
+
|
|
+#define CNXK_R_OUT_CTL_IDLE BIT_ULL(40)
|
|
+#define CNXK_R_OUT_CTL_ES_I BIT_ULL(34)
|
|
+#define CNXK_R_OUT_CTL_NSR_I BIT_ULL(33)
|
|
+#define CNXK_R_OUT_CTL_ROR_I BIT_ULL(32)
|
|
+#define CNXK_R_OUT_CTL_ES_D BIT_ULL(30)
|
|
+#define CNXK_R_OUT_CTL_NSR_D BIT_ULL(29)
|
|
+#define CNXK_R_OUT_CTL_ROR_D BIT_ULL(28)
|
|
+#define CNXK_R_OUT_CTL_ES_P BIT_ULL(26)
|
|
+#define CNXK_R_OUT_CTL_NSR_P BIT_ULL(25)
|
|
+#define CNXK_R_OUT_CTL_ROR_P BIT_ULL(24)
|
|
+#define CNXK_R_OUT_CTL_IMODE BIT_ULL(23)
|
|
+
|
|
+/* ############### Interrupt Moderation Registers ############### */
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_CTL0_START 0x10280
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_CTL1_START 0x102A0
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_DBG_START 0x102C0
|
|
+
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL0_START 0x10380
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL1_START 0x103A0
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_DBG_START 0x103C0
|
|
+
|
|
+#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510
|
|
+#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520
|
|
+
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_CTL0(ring) \
|
|
+ (CNXK_SDP_R_IN_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_CTL1(ring) \
|
|
+ (CNXK_SDP_R_IN_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_INT_MDRT_DBG(ring) \
|
|
+ (CNXK_SDP_R_IN_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL0(ring) \
|
|
+ (CNXK_SDP_R_OUT_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL1(ring) \
|
|
+ (CNXK_SDP_R_OUT_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_INT_MDRT_DBG(ring) \
|
|
+ (CNXK_SDP_R_OUT_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \
|
|
+ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_CNTS_ISM(ring) \
|
|
+ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+/* ##################### Mail Box Registers ########################## */
|
|
+/* INT register for VF. when a MBOX write from PF happed to a VF,
|
|
+ * corresponding bit will be set in this register as well as in
|
|
+ * PF_VF_INT register.
|
|
+ *
|
|
+ * This is a RO register, the int can be cleared by writing 1 to PF_VF_INT
|
|
+ */
|
|
+/* Basically first 3 are from PF to VF. The last one is data from VF to PF */
|
|
+#define CNXK_SDP_R_MBOX_PF_VF_DATA_START 0x10210
|
|
+#define CNXK_SDP_R_MBOX_PF_VF_INT_START 0x10220
|
|
+#define CNXK_SDP_R_MBOX_VF_PF_DATA_START 0x10230
|
|
+
|
|
+#define CNXK_SDP_R_MBOX_PF_VF_DATA(ring) \
|
|
+ (CNXK_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_MBOX_PF_VF_INT(ring) \
|
|
+ (CNXK_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_MBOX_VF_PF_DATA(ring) \
|
|
+ (CNXK_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+/* ##################### Interrupt Registers ########################## */
|
|
+#define CNXK_SDP_R_ERR_TYPE_START 0x10400
|
|
+
|
|
+#define CNXK_SDP_R_ERR_TYPE(ring) \
|
|
+ (CNXK_SDP_R_ERR_TYPE_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_MBOX_ISM_START 0x10500
|
|
+#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510
|
|
+#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520
|
|
+
|
|
+#define CNXK_SDP_R_MBOX_ISM(ring) \
|
|
+ (CNXK_SDP_R_MBOX_ISM_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \
|
|
+ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_R_IN_CNTS_ISM(ring) \
|
|
+ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_START 0x20100
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_W1S_START 0x20120
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START 0x20140
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START 0x20160
|
|
+
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_START 0x20180
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_W1S_START 0x201A0
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START 0x201C0
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START 0x201E0
|
|
+
|
|
+#define CNXK_SDP_EPF_IRERR_RINT 0x20200
|
|
+#define CNXK_SDP_EPF_IRERR_RINT_W1S 0x20210
|
|
+#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1C 0x20220
|
|
+#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1S 0x20230
|
|
+
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_START 0x20240
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_W1S_START 0x20260
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START 0x20280
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START 0x202A0
|
|
+
|
|
+#define CNXK_SDP_EPF_ORERR_RINT 0x20320
|
|
+#define CNXK_SDP_EPF_ORERR_RINT_W1S 0x20330
|
|
+#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1C 0x20340
|
|
+#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1S 0x20350
|
|
+
|
|
+#define CNXK_SDP_EPF_OEI_RINT 0x20400
|
|
+#define CNXK_SDP_EPF_OEI_RINT_W1S 0x20500
|
|
+#define CNXK_SDP_EPF_OEI_RINT_ENA_W1C 0x20600
|
|
+#define CNXK_SDP_EPF_OEI_RINT_ENA_W1S 0x20700
|
|
+
|
|
+#define CNXK_SDP_EPF_DMA_RINT 0x20800
|
|
+#define CNXK_SDP_EPF_DMA_RINT_W1S 0x20810
|
|
+#define CNXK_SDP_EPF_DMA_RINT_ENA_W1C 0x20820
|
|
+#define CNXK_SDP_EPF_DMA_RINT_ENA_W1S 0x20830
|
|
+
|
|
+#define CNXK_SDP_EPF_DMA_INT_LEVEL_START 0x20840
|
|
+#define CNXK_SDP_EPF_DMA_CNT_START 0x20860
|
|
+#define CNXK_SDP_EPF_DMA_TIM_START 0x20880
|
|
+
|
|
+#define CNXK_SDP_EPF_MISC_RINT 0x208A0
|
|
+#define CNXK_SDP_EPF_MISC_RINT_W1S 0x208B0
|
|
+#define CNXK_SDP_EPF_MISC_RINT_ENA_W1C 0x208C0
|
|
+#define CNXK_SDP_EPF_MISC_RINT_ENA_W1S 0x208D0
|
|
+
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_START 0x208E0
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_W1S_START 0x20900
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START 0x20920
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START 0x20940
|
|
+
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_START 0x20960
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_W1S_START 0x20980
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START 0x209A0
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START 0x209C0
|
|
+
|
|
+#define CNXK_SDP_EPF_MBOX_RINT(index) \
|
|
+ (CNXK_SDP_EPF_MBOX_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_W1S(index) \
|
|
+ (CNXK_SDP_EPF_MBOX_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(index) \
|
|
+ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(index) \
|
|
+ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT(index) \
|
|
+ (CNXK_SDP_EPF_VFIRE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_W1S(index) \
|
|
+ (CNXK_SDP_EPF_VFIRE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(index) \
|
|
+ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(index) \
|
|
+ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_EPF_VFORE_RINT(index) \
|
|
+ (CNXK_SDP_EPF_VFORE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_W1S(index) \
|
|
+ (CNXK_SDP_EPF_VFORE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(index) \
|
|
+ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(index) \
|
|
+ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT(index) \
|
|
+ (CNXK_SDP_EPF_DMA_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_W1S(index) \
|
|
+ (CNXK_SDP_EPF_DMA_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(index) \
|
|
+ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(index) \
|
|
+ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT(index) \
|
|
+ (CNXK_SDP_EPF_PP_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_W1S(index) \
|
|
+ (CNXK_SDP_EPF_PP_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(index) \
|
|
+ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(index) \
|
|
+ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
|
|
+
|
|
+/*------------------ Interrupt Masks ----------------*/
|
|
+#define CNXK_INTR_R_SEND_ISM BIT_ULL(63)
|
|
+#define CNXK_INTR_R_OUT_INT BIT_ULL(62)
|
|
+#define CNXK_INTR_R_IN_INT BIT_ULL(61)
|
|
+#define CNXK_INTR_R_MBOX_INT BIT_ULL(60)
|
|
+#define CNXK_INTR_R_RESEND BIT_ULL(59)
|
|
+#define CNXK_INTR_R_CLR_TIM BIT_ULL(58)
|
|
+
|
|
+/* ####################### Ring Mapping Registers ################################## */
|
|
+#define CNXK_SDP_EPVF_RING_START 0x26000
|
|
+#define CNXK_SDP_IN_RING_TB_MAP_START 0x28000
|
|
+#define CNXK_SDP_IN_RATE_LIMIT_START 0x2A000
|
|
+#define CNXK_SDP_MAC_PF_RING_CTL_START 0x2C000
|
|
+
|
|
+#define CNXK_SDP_EPVF_RING(ring) \
|
|
+ (CNXK_SDP_EPVF_RING_START + ((ring) * CNXK_EPVF_RING_OFFSET))
|
|
+#define CNXK_SDP_IN_RING_TB_MAP(ring) \
|
|
+ (CNXK_SDP_N_RING_TB_MAP_START + ((ring) * CNXK_EPVF_RING_OFFSET))
|
|
+#define CNXK_SDP_IN_RATE_LIMIT(ring) \
|
|
+ (CNXK_SDP_IN_RATE_LIMIT_START + ((ring) * CNXK_EPVF_RING_OFFSET))
|
|
+#define CNXK_SDP_MAC_PF_RING_CTL(mac) \
|
|
+ (CNXK_SDP_MAC_PF_RING_CTL_START + ((mac) * CNXK_MAC_OFFSET))
|
|
+
|
|
+#define CNXK_SDP_MAC_PF_RING_CTL_NPFS(val) ((val) & 0x3)
|
|
+#define CNXK_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0x7F)
|
|
+#define CNXK_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F)
|
|
+
|
|
+/* Number of non-queue interrupts in CNXKxx */
|
|
+#define CNXK_NUM_NON_IOQ_INTR 32
|
|
+
|
|
+/* bit 0 for control mbox interrupt */
|
|
+#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX BIT_ULL(0)
|
|
+/* bit 1 for firmware heartbeat interrupt */
|
|
+#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1)
|
|
+#define FW_STATUS_RUNNING 2ULL
|
|
+#define CNXK_PEMX_PFX_CSX_PFCFGX(pem, pf, offset) ({ typeof(offset) _off = (offset); \
|
|
+ ((0x8e0000008000 | \
|
|
+ (uint64_t)(pem) << 36 \
|
|
+ | (pf) << 18 \
|
|
+ | ((_off >> 16) & 1) << 16 \
|
|
+ | (_off >> 3) << 3) \
|
|
+ + (((_off >> 2) & 1) << 2)); \
|
|
+ })
|
|
+
|
|
+/* Register defines for use with CNXK_PEMX_PFX_CSX_PFCFGX */
|
|
+#define CNXK_PCIEEP_VSECST_CTL 0x418
|
|
+
|
|
+#define CNXK_PEM_BAR4_INDEX 7
|
|
+#define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL
|
|
+#define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE)
|
|
+#define CNXK_INT_ENA_BIT BIT_ULL(62)
|
|
+
|
|
+#endif /* _OCTEP_REGS_CNXK_PF_H_ */
|
|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
|
|
index c7f4e3c058b7fa..60afb6bf2f6792 100644
|
|
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
|
|
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
|
|
@@ -12,6 +12,8 @@
|
|
#include "octep_config.h"
|
|
#include "octep_main.h"
|
|
|
|
+static void octep_oq_free_ring_buffers(struct octep_oq *oq);
|
|
+
|
|
static void octep_oq_reset_indices(struct octep_oq *oq)
|
|
{
|
|
oq->host_read_idx = 0;
|
|
@@ -169,11 +171,15 @@ static int octep_setup_oq(struct octep_device *oct, int q_no)
|
|
goto oq_fill_buff_err;
|
|
|
|
octep_oq_reset_indices(oq);
|
|
- oct->hw_ops.setup_oq_regs(oct, q_no);
|
|
+ if (oct->hw_ops.setup_oq_regs(oct, q_no))
|
|
+ goto oq_setup_err;
|
|
+
|
|
oct->num_oqs++;
|
|
|
|
return 0;
|
|
|
|
+oq_setup_err:
|
|
+ octep_oq_free_ring_buffers(oq);
|
|
oq_fill_buff_err:
|
|
vfree(oq->buff_info);
|
|
oq->buff_info = NULL;
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
|
|
index 729d1833a829a5..278dc1aabd4b41 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
|
|
@@ -1793,6 +1793,8 @@ static int cgx_lmac_exit(struct cgx *cgx)
|
|
cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false);
|
|
cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true);
|
|
kfree(lmac->mac_to_index_bmap.bmap);
|
|
+ rvu_free_bitmap(&lmac->rx_fc_pfvf_bmap);
|
|
+ rvu_free_bitmap(&lmac->tx_fc_pfvf_bmap);
|
|
kfree(lmac->name);
|
|
kfree(lmac);
|
|
}
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
|
|
index 846049b6c4d60c..a7fcea9b1ee7e0 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
|
|
@@ -3444,11 +3444,22 @@ static void rvu_remove(struct pci_dev *pdev)
|
|
devm_kfree(&pdev->dev, rvu);
|
|
}
|
|
|
|
+static void rvu_shutdown(struct pci_dev *pdev)
|
|
+{
|
|
+ struct rvu *rvu = pci_get_drvdata(pdev);
|
|
+
|
|
+ if (!rvu)
|
|
+ return;
|
|
+
|
|
+ rvu_clear_rvum_blk_revid(rvu);
|
|
+}
|
|
+
|
|
static struct pci_driver rvu_driver = {
|
|
.name = DRV_NAME,
|
|
.id_table = rvu_id_table,
|
|
.probe = rvu_probe,
|
|
.remove = rvu_remove,
|
|
+ .shutdown = rvu_shutdown,
|
|
};
|
|
|
|
static int __init rvu_init_module(void)
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
|
|
index 29487518ca6724..0703b0d8df783e 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
|
|
@@ -4509,12 +4509,18 @@ static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw)
|
|
/* Set chan/link to backpressure TL3 instead of TL2 */
|
|
rvu_write64(rvu, blkaddr, NIX_AF_PSE_CHANNEL_LEVEL, 0x01);
|
|
|
|
- /* Disable SQ manager's sticky mode operation (set TM6 = 0)
|
|
+ /* Disable SQ manager's sticky mode operation (set TM6 = 0, TM11 = 0)
|
|
* This sticky mode is known to cause SQ stalls when multiple
|
|
- * SQs are mapped to same SMQ and transmitting pkts at a time.
|
|
+ * SQs are mapped to same SMQ and transmitting pkts simultaneously.
|
|
+ * NIX PSE may deadlock when there are any sticky to non-sticky
|
|
+ * transmission. Hence disable it (TM5 = 0).
|
|
*/
|
|
cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQM_DBG_CTL_STATUS);
|
|
- cfg &= ~BIT_ULL(15);
|
|
+ cfg &= ~(BIT_ULL(15) | BIT_ULL(14) | BIT_ULL(23));
|
|
+ /* NIX may drop credits when condition clocks are turned off.
|
|
+ * Hence enable control flow clk (set TM9 = 1).
|
|
+ */
|
|
+ cfg |= BIT_ULL(21);
|
|
rvu_write64(rvu, blkaddr, NIX_AF_SQM_DBG_CTL_STATUS, cfg);
|
|
|
|
ltdefs = rvu->kpu.lt_def;
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
|
|
index 00ef6d201b973a..9b8a6046e6dff0 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
|
|
@@ -1070,32 +1070,35 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
|
|
rvu_write64(rvu, blkaddr,
|
|
NPC_AF_MCAMEX_BANKX_ACTION(index, bank), *(u64 *)&action);
|
|
|
|
- /* update the VF flow rule action with the VF default entry action */
|
|
- if (mcam_index < 0)
|
|
- npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc,
|
|
- *(u64 *)&action);
|
|
-
|
|
/* update the action change in default rule */
|
|
pfvf = rvu_get_pfvf(rvu, pcifunc);
|
|
if (pfvf->def_ucast_rule)
|
|
pfvf->def_ucast_rule->rx_action = action;
|
|
|
|
- index = npc_get_nixlf_mcam_index(mcam, pcifunc,
|
|
- nixlf, NIXLF_PROMISC_ENTRY);
|
|
+ if (mcam_index < 0) {
|
|
+ /* update the VF flow rule action with the VF default
|
|
+ * entry action
|
|
+ */
|
|
+ npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc,
|
|
+ *(u64 *)&action);
|
|
|
|
- /* If PF's promiscuous entry is enabled,
|
|
- * Set RSS action for that entry as well
|
|
- */
|
|
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index, blkaddr,
|
|
- alg_idx);
|
|
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
|
|
+ nixlf, NIXLF_PROMISC_ENTRY);
|
|
|
|
- index = npc_get_nixlf_mcam_index(mcam, pcifunc,
|
|
- nixlf, NIXLF_ALLMULTI_ENTRY);
|
|
- /* If PF's allmulti entry is enabled,
|
|
- * Set RSS action for that entry as well
|
|
- */
|
|
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index, blkaddr,
|
|
- alg_idx);
|
|
+ /* If PF's promiscuous entry is enabled,
|
|
+ * Set RSS action for that entry as well
|
|
+ */
|
|
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
|
|
+ blkaddr, alg_idx);
|
|
+
|
|
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
|
|
+ nixlf, NIXLF_ALLMULTI_ENTRY);
|
|
+ /* If PF's allmulti entry is enabled,
|
|
+ * Set RSS action for that entry as well
|
|
+ */
|
|
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
|
|
+ blkaddr, alg_idx);
|
|
+ }
|
|
}
|
|
|
|
void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,
|
|
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
|
|
index b4194ec2a1f2d0..784130b4b08655 100644
|
|
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
|
|
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
|
|
@@ -3097,6 +3097,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
return 0;
|
|
|
|
err_pf_sriov_init:
|
|
+ otx2_unregister_dl(pf);
|
|
otx2_shutdown_tc(pf);
|
|
err_mcam_flow_del:
|
|
otx2_mcam_flow_del(pf);
|
|
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
|
|
index 1b43704baceb52..2bb77e2389701e 100644
|
|
--- a/drivers/net/ethernet/marvell/skge.c
|
|
+++ b/drivers/net/ethernet/marvell/skge.c
|
|
@@ -78,7 +78,6 @@ static const struct pci_device_id skge_id_table[] = {
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x4320) }, /* SK-98xx V2.0 */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* D-Link DGE-530T (rev.B) */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4c00) }, /* D-Link DGE-530T */
|
|
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302) }, /* D-Link DGE-530T Rev C1 */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, /* Marvell Yukon 88E8001/8003/8010 */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, 0x434E) }, /* CNet PowerG-2000 */
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
index a2fc937d54617c..172862a70c70d2 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
|
|
@@ -193,7 +193,9 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs)
|
|
err = pci_enable_sriov(pdev, num_vfs);
|
|
if (err) {
|
|
mlx5_core_warn(dev, "pci_enable_sriov failed : %d\n", err);
|
|
+ devl_lock(devlink);
|
|
mlx5_device_disable_sriov(dev, num_vfs, true, true);
|
|
+ devl_unlock(devlink);
|
|
}
|
|
return err;
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c
|
|
index 7e36e1062139ea..ebe81c5aa61155 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c
|
|
@@ -664,8 +664,8 @@ static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
|
|
struct mlx5dr_table *tbl;
|
|
int ret;
|
|
|
|
- mutex_lock(&dmn->dump_info.dbg_mutex);
|
|
mlx5dr_domain_lock(dmn);
|
|
+ mutex_lock(&dmn->dump_info.dbg_mutex);
|
|
|
|
ret = dr_dump_domain(file, dmn);
|
|
if (ret < 0)
|
|
@@ -678,8 +678,8 @@ static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
|
|
}
|
|
|
|
unlock_mutex:
|
|
- mlx5dr_domain_unlock(dmn);
|
|
mutex_unlock(&dmn->dump_info.dbg_mutex);
|
|
+ mlx5dr_domain_unlock(dmn);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
|
|
index 5a932460db5819..6b2dbfbeef377b 100644
|
|
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
|
|
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
|
|
@@ -562,7 +562,7 @@ static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
static struct ptp_clock_info sparx5_ptp_clock_info = {
|
|
.owner = THIS_MODULE,
|
|
.name = "sparx5 ptp",
|
|
- .max_adj = 200000,
|
|
+ .max_adj = 10000000,
|
|
.gettime64 = sparx5_ptp_gettime64,
|
|
.settime64 = sparx5_ptp_settime64,
|
|
.adjtime = sparx5_ptp_adjtime,
|
|
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
|
|
index ced35033a6c5dd..b1c6c5c6f16caf 100644
|
|
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
|
|
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h
|
|
@@ -35,7 +35,7 @@
|
|
#define SPX5_SE_BURST_UNIT 4096
|
|
|
|
/* Dwrr */
|
|
-#define SPX5_DWRR_COST_MAX 63
|
|
+#define SPX5_DWRR_COST_MAX 31
|
|
|
|
struct sparx5_shaper {
|
|
u32 mode;
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
|
|
index 21a87a3fc5562d..b516b4e1ed974b 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot_net.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
|
|
@@ -551,44 +551,81 @@ static int ocelot_port_stop(struct net_device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
+static bool ocelot_xmit_timestamp(struct ocelot *ocelot, int port,
|
|
+ struct sk_buff *skb, u32 *rew_op)
|
|
{
|
|
- struct ocelot_port_private *priv = netdev_priv(dev);
|
|
- struct ocelot_port *ocelot_port = &priv->port;
|
|
- struct ocelot *ocelot = ocelot_port->ocelot;
|
|
- int port = priv->port.index;
|
|
- u32 rew_op = 0;
|
|
-
|
|
- if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
|
|
- !ocelot_can_inject(ocelot, 0))
|
|
- return NETDEV_TX_BUSY;
|
|
-
|
|
- /* Check if timestamping is needed */
|
|
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
|
|
struct sk_buff *clone = NULL;
|
|
|
|
if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
|
|
kfree_skb(skb);
|
|
- return NETDEV_TX_OK;
|
|
+ return false;
|
|
}
|
|
|
|
if (clone)
|
|
OCELOT_SKB_CB(skb)->clone = clone;
|
|
|
|
- rew_op = ocelot_ptp_rew_op(skb);
|
|
+ *rew_op = ocelot_ptp_rew_op(skb);
|
|
}
|
|
|
|
- if (static_branch_unlikely(&ocelot_fdma_enabled)) {
|
|
- ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
|
|
- } else {
|
|
- ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static netdev_tx_t ocelot_port_xmit_fdma(struct sk_buff *skb,
|
|
+ struct net_device *dev)
|
|
+{
|
|
+ struct ocelot_port_private *priv = netdev_priv(dev);
|
|
+ struct ocelot_port *ocelot_port = &priv->port;
|
|
+ struct ocelot *ocelot = ocelot_port->ocelot;
|
|
+ int port = priv->port.index;
|
|
+ u32 rew_op = 0;
|
|
+
|
|
+ if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
|
|
+ return NETDEV_TX_OK;
|
|
+
|
|
+ ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
|
|
+
|
|
+ return NETDEV_TX_OK;
|
|
+}
|
|
|
|
- consume_skb(skb);
|
|
+static netdev_tx_t ocelot_port_xmit_inj(struct sk_buff *skb,
|
|
+ struct net_device *dev)
|
|
+{
|
|
+ struct ocelot_port_private *priv = netdev_priv(dev);
|
|
+ struct ocelot_port *ocelot_port = &priv->port;
|
|
+ struct ocelot *ocelot = ocelot_port->ocelot;
|
|
+ int port = priv->port.index;
|
|
+ u32 rew_op = 0;
|
|
+
|
|
+ ocelot_lock_inj_grp(ocelot, 0);
|
|
+
|
|
+ if (!ocelot_can_inject(ocelot, 0)) {
|
|
+ ocelot_unlock_inj_grp(ocelot, 0);
|
|
+ return NETDEV_TX_BUSY;
|
|
}
|
|
|
|
+ if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op)) {
|
|
+ ocelot_unlock_inj_grp(ocelot, 0);
|
|
+ return NETDEV_TX_OK;
|
|
+ }
|
|
+
|
|
+ ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
|
|
+
|
|
+ ocelot_unlock_inj_grp(ocelot, 0);
|
|
+
|
|
+ consume_skb(skb);
|
|
+
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
+static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
+{
|
|
+ if (static_branch_unlikely(&ocelot_fdma_enabled))
|
|
+ return ocelot_port_xmit_fdma(skb, dev);
|
|
+
|
|
+ return ocelot_port_xmit_inj(skb, dev);
|
|
+}
|
|
+
|
|
enum ocelot_action_type {
|
|
OCELOT_MACT_LEARN,
|
|
OCELOT_MACT_FORGET,
|
|
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
|
|
index 7b7e1c5b00f472..f3b1605f6adc9a 100644
|
|
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
|
|
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
|
|
@@ -688,6 +688,9 @@ static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
|
|
|
|
/* probe for IPv6 TSO support */
|
|
mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
|
|
+ cmd.data0 = 0,
|
|
+ cmd.data1 = 0,
|
|
+ cmd.data2 = 0,
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
|
|
&cmd, 0);
|
|
if (status == 0) {
|
|
@@ -806,6 +809,7 @@ static int myri10ge_update_mac_address(struct myri10ge_priv *mgp,
|
|
| (addr[2] << 8) | addr[3]);
|
|
|
|
cmd.data1 = ((addr[4] << 8) | (addr[5]));
|
|
+ cmd.data2 = 0;
|
|
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_SET_MAC_ADDRESS, &cmd, 0);
|
|
return status;
|
|
@@ -817,6 +821,9 @@ static int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause)
|
|
int status, ctl;
|
|
|
|
ctl = pause ? MXGEFW_ENABLE_FLOW_CONTROL : MXGEFW_DISABLE_FLOW_CONTROL;
|
|
+ cmd.data0 = 0,
|
|
+ cmd.data1 = 0,
|
|
+ cmd.data2 = 0,
|
|
status = myri10ge_send_cmd(mgp, ctl, &cmd, 0);
|
|
|
|
if (status) {
|
|
@@ -834,6 +841,9 @@ myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic)
|
|
int status, ctl;
|
|
|
|
ctl = promisc ? MXGEFW_ENABLE_PROMISC : MXGEFW_DISABLE_PROMISC;
|
|
+ cmd.data0 = 0;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status = myri10ge_send_cmd(mgp, ctl, &cmd, atomic);
|
|
if (status)
|
|
netdev_err(mgp->dev, "Failed to set promisc mode\n");
|
|
@@ -1946,6 +1956,8 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
|
|
/* get ring sizes */
|
|
slice = ss - mgp->ss;
|
|
cmd.data0 = slice;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
|
|
tx_ring_size = cmd.data0;
|
|
cmd.data0 = slice;
|
|
@@ -2238,12 +2250,16 @@ static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
|
|
status = 0;
|
|
if (slice == 0 || (mgp->dev->real_num_tx_queues > 1)) {
|
|
cmd.data0 = slice;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET,
|
|
&cmd, 0);
|
|
ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
|
|
(mgp->sram + cmd.data0);
|
|
}
|
|
cmd.data0 = slice;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
|
|
&cmd, 0);
|
|
ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *)
|
|
@@ -2312,6 +2328,7 @@ static int myri10ge_open(struct net_device *dev)
|
|
if (mgp->num_slices > 1) {
|
|
cmd.data0 = mgp->num_slices;
|
|
cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
|
|
+ cmd.data2 = 0;
|
|
if (mgp->dev->real_num_tx_queues > 1)
|
|
cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
|
|
@@ -2414,6 +2431,8 @@ static int myri10ge_open(struct net_device *dev)
|
|
|
|
/* now give firmware buffers sizes, and MTU */
|
|
cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_MTU, &cmd, 0);
|
|
cmd.data0 = mgp->small_bytes;
|
|
status |=
|
|
@@ -2472,7 +2491,6 @@ abort_with_nothing:
|
|
static int myri10ge_close(struct net_device *dev)
|
|
{
|
|
struct myri10ge_priv *mgp = netdev_priv(dev);
|
|
- struct myri10ge_cmd cmd;
|
|
int status, old_down_cnt;
|
|
int i;
|
|
|
|
@@ -2491,8 +2509,13 @@ static int myri10ge_close(struct net_device *dev)
|
|
|
|
netif_tx_stop_all_queues(dev);
|
|
if (mgp->rebooted == 0) {
|
|
+ struct myri10ge_cmd cmd;
|
|
+
|
|
old_down_cnt = mgp->down_cnt;
|
|
mb();
|
|
+ cmd.data0 = 0;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
status =
|
|
myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0);
|
|
if (status)
|
|
@@ -2956,6 +2979,9 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
|
|
|
|
/* Disable multicast filtering */
|
|
|
|
+ cmd.data0 = 0;
|
|
+ cmd.data1 = 0;
|
|
+ cmd.data2 = 0;
|
|
err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
|
|
if (err != 0) {
|
|
netdev_err(dev, "Failed MXGEFW_ENABLE_ALLMULTI, error status: %d\n",
|
|
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
|
|
index d76e63f57ff1ec..b07dd56b0c76d2 100644
|
|
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
|
|
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
|
|
@@ -222,9 +222,10 @@ static int ionic_get_link_ksettings(struct net_device *netdev,
|
|
/* This means there's no module plugged in */
|
|
break;
|
|
default:
|
|
- dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n",
|
|
- idev->port_info->status.xcvr.pid,
|
|
- idev->port_info->status.xcvr.pid);
|
|
+ dev_dbg_ratelimited(lif->ionic->dev,
|
|
+ "unknown xcvr type pid=%d / 0x%x\n",
|
|
+ idev->port_info->status.xcvr.pid,
|
|
+ idev->port_info->status.xcvr.pid);
|
|
break;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
|
|
index b983b9c23be68a..61ca7377b612c1 100644
|
|
--- a/drivers/net/ethernet/sun/sunhme.c
|
|
+++ b/drivers/net/ethernet/sun/sunhme.c
|
|
@@ -2551,6 +2551,9 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe)
|
|
goto err_out_clear_quattro;
|
|
}
|
|
|
|
+ /* BIGMAC may have bogus sizes */
|
|
+ if ((op->resource[3].end - op->resource[3].start) >= BMAC_REG_SIZE)
|
|
+ op->resource[3].end = op->resource[3].start + BMAC_REG_SIZE - 1;
|
|
hp->bigmacregs = devm_platform_ioremap_resource(op, 3);
|
|
if (IS_ERR(hp->bigmacregs)) {
|
|
dev_err(&op->dev, "Cannot map BIGMAC registers.\n");
|
|
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
|
|
index 1c1d4806c119b8..1f98044b3666ff 100644
|
|
--- a/drivers/net/ethernet/ti/cpsw_new.c
|
|
+++ b/drivers/net/ethernet/ti/cpsw_new.c
|
|
@@ -1967,7 +1967,7 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
/* setup netdevs */
|
|
ret = cpsw_create_ports(cpsw);
|
|
if (ret)
|
|
- goto clean_unregister_netdev;
|
|
+ goto clean_cpts;
|
|
|
|
/* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and
|
|
* MISC IRQs which are always kept disabled with this driver so
|
|
@@ -1981,14 +1981,14 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
0, dev_name(dev), cpsw);
|
|
if (ret < 0) {
|
|
dev_err(dev, "error attaching irq (%d)\n", ret);
|
|
- goto clean_unregister_netdev;
|
|
+ goto clean_cpts;
|
|
}
|
|
|
|
ret = devm_request_irq(dev, cpsw->irqs_table[1], cpsw_tx_interrupt,
|
|
0, dev_name(dev), cpsw);
|
|
if (ret < 0) {
|
|
dev_err(dev, "error attaching irq (%d)\n", ret);
|
|
- goto clean_unregister_netdev;
|
|
+ goto clean_cpts;
|
|
}
|
|
|
|
if (!cpsw->cpts)
|
|
@@ -1998,7 +1998,7 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
0, dev_name(&pdev->dev), cpsw);
|
|
if (ret < 0) {
|
|
dev_err(dev, "error attaching misc irq (%d)\n", ret);
|
|
- goto clean_unregister_netdev;
|
|
+ goto clean_cpts;
|
|
}
|
|
|
|
/* Enable misc CPTS evnt_pend IRQ */
|
|
@@ -2007,7 +2007,7 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
skip_cpts:
|
|
ret = cpsw_register_notifiers(cpsw);
|
|
if (ret)
|
|
- goto clean_unregister_netdev;
|
|
+ goto clean_cpts;
|
|
|
|
ret = cpsw_register_devlink(cpsw);
|
|
if (ret)
|
|
@@ -2029,8 +2029,6 @@ skip_cpts:
|
|
|
|
clean_unregister_notifiers:
|
|
cpsw_unregister_notifiers(cpsw);
|
|
-clean_unregister_netdev:
|
|
- cpsw_unregister_ports(cpsw);
|
|
clean_cpts:
|
|
cpts_release(cpsw->cpts);
|
|
cpdma_ctlr_destroy(cpsw->dma);
|
|
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
|
|
index 3b0c5f177447bf..aa6d30dd35c383 100644
|
|
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
|
|
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
|
|
@@ -386,28 +386,29 @@ static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
|
|
__raw_writel(TX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event);
|
|
}
|
|
|
|
-static int hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
|
|
+static int ixp4xx_hwtstamp_set(struct net_device *netdev,
|
|
+ struct kernel_hwtstamp_config *cfg,
|
|
+ struct netlink_ext_ack *extack)
|
|
{
|
|
- struct hwtstamp_config cfg;
|
|
struct ixp46x_ts_regs *regs;
|
|
struct port *port = netdev_priv(netdev);
|
|
int ret;
|
|
int ch;
|
|
|
|
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
|
- return -EFAULT;
|
|
+ if (!netif_running(netdev))
|
|
+ return -EINVAL;
|
|
|
|
ret = ixp46x_ptp_find(&port->timesync_regs, &port->phc_index);
|
|
if (ret)
|
|
- return ret;
|
|
+ return -EOPNOTSUPP;
|
|
|
|
ch = PORT2CHANNEL(port);
|
|
regs = port->timesync_regs;
|
|
|
|
- if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)
|
|
+ if (cfg->tx_type != HWTSTAMP_TX_OFF && cfg->tx_type != HWTSTAMP_TX_ON)
|
|
return -ERANGE;
|
|
|
|
- switch (cfg.rx_filter) {
|
|
+ switch (cfg->rx_filter) {
|
|
case HWTSTAMP_FILTER_NONE:
|
|
port->hwts_rx_en = 0;
|
|
break;
|
|
@@ -423,39 +424,45 @@ static int hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
|
|
return -ERANGE;
|
|
}
|
|
|
|
- port->hwts_tx_en = cfg.tx_type == HWTSTAMP_TX_ON;
|
|
+ port->hwts_tx_en = cfg->tx_type == HWTSTAMP_TX_ON;
|
|
|
|
/* Clear out any old time stamps. */
|
|
__raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
|
|
®s->channel[ch].ch_event);
|
|
|
|
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
|
+ return 0;
|
|
}
|
|
|
|
-static int hwtstamp_get(struct net_device *netdev, struct ifreq *ifr)
|
|
+static int ixp4xx_hwtstamp_get(struct net_device *netdev,
|
|
+ struct kernel_hwtstamp_config *cfg)
|
|
{
|
|
- struct hwtstamp_config cfg;
|
|
struct port *port = netdev_priv(netdev);
|
|
|
|
- cfg.flags = 0;
|
|
- cfg.tx_type = port->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
|
+ if (!cpu_is_ixp46x())
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (!netif_running(netdev))
|
|
+ return -EINVAL;
|
|
+
|
|
+ cfg->flags = 0;
|
|
+ cfg->tx_type = port->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
|
|
|
switch (port->hwts_rx_en) {
|
|
case 0:
|
|
- cfg.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
+ cfg->rx_filter = HWTSTAMP_FILTER_NONE;
|
|
break;
|
|
case PTP_SLAVE_MODE:
|
|
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
|
|
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
|
|
break;
|
|
case PTP_MASTER_MODE:
|
|
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
|
|
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
|
|
break;
|
|
default:
|
|
WARN_ON_ONCE(1);
|
|
return -ERANGE;
|
|
}
|
|
|
|
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
|
+ return 0;
|
|
}
|
|
|
|
static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
|
|
@@ -977,21 +984,6 @@ static void eth_set_mcast_list(struct net_device *dev)
|
|
}
|
|
|
|
|
|
-static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
|
|
-{
|
|
- if (!netif_running(dev))
|
|
- return -EINVAL;
|
|
-
|
|
- if (cpu_is_ixp46x()) {
|
|
- if (cmd == SIOCSHWTSTAMP)
|
|
- return hwtstamp_set(dev, req);
|
|
- if (cmd == SIOCGHWTSTAMP)
|
|
- return hwtstamp_get(dev, req);
|
|
- }
|
|
-
|
|
- return phy_mii_ioctl(dev->phydev, req, cmd);
|
|
-}
|
|
-
|
|
/* ethtool support */
|
|
|
|
static void ixp4xx_get_drvinfo(struct net_device *dev,
|
|
@@ -1376,9 +1368,11 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
|
|
.ndo_stop = eth_close,
|
|
.ndo_start_xmit = eth_xmit,
|
|
.ndo_set_rx_mode = eth_set_mcast_list,
|
|
- .ndo_eth_ioctl = eth_ioctl,
|
|
+ .ndo_eth_ioctl = phy_do_ioctl_running,
|
|
.ndo_set_mac_address = eth_mac_addr,
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
+ .ndo_hwtstamp_get = ixp4xx_hwtstamp_get,
|
|
+ .ndo_hwtstamp_set = ixp4xx_hwtstamp_set,
|
|
};
|
|
|
|
static struct eth_plat_info *ixp4xx_of_get_platdata(struct device *dev)
|
|
diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c
|
|
index 94203eb46e6b02..93c64db22a696c 100644
|
|
--- a/drivers/net/ethernet/xscale/ptp_ixp46x.c
|
|
+++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c
|
|
@@ -232,6 +232,9 @@ static struct ixp_clock ixp_clock;
|
|
|
|
int ixp46x_ptp_find(struct ixp46x_ts_regs *__iomem *regs, int *phc_index)
|
|
{
|
|
+ if (!cpu_is_ixp46x())
|
|
+ return -ENODEV;
|
|
+
|
|
*regs = ixp_clock.regs;
|
|
*phc_index = ptp_clock_index(ixp_clock.ptp_clock);
|
|
|
|
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
|
|
index fea7352e2a470c..4e28fcbf13c74d 100644
|
|
--- a/drivers/net/macvlan.c
|
|
+++ b/drivers/net/macvlan.c
|
|
@@ -1577,6 +1577,11 @@ destroy_macvlan_port:
|
|
if (create)
|
|
macvlan_port_destroy(port->dev);
|
|
}
|
|
+ /* @dev might have been made visible before an error was detected.
|
|
+ * Make sure to observe an RCU grace period before our caller
|
|
+ * (rtnl_newlink()) frees it.
|
|
+ */
|
|
+ synchronize_net();
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(macvlan_common_newlink);
|
|
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
|
|
index fbe8483a07b589..c8c2c5dc46eb79 100644
|
|
--- a/drivers/net/mctp/mctp-i2c.c
|
|
+++ b/drivers/net/mctp/mctp-i2c.c
|
|
@@ -243,6 +243,12 @@ static int mctp_i2c_slave_cb(struct i2c_client *client,
|
|
return 0;
|
|
|
|
switch (event) {
|
|
+ case I2C_SLAVE_READ_REQUESTED:
|
|
+ case I2C_SLAVE_READ_PROCESSED:
|
|
+ /* MCTP I2C transport only uses writes */
|
|
+ midev->rx_pos = 0;
|
|
+ *val = 0xff;
|
|
+ break;
|
|
case I2C_SLAVE_WRITE_RECEIVED:
|
|
if (midev->rx_pos < MCTP_I2C_BUFSZ) {
|
|
midev->rx_buffer[midev->rx_pos] = *val;
|
|
@@ -280,6 +286,9 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev)
|
|
size_t recvlen;
|
|
int status;
|
|
|
|
+ if (midev->rx_pos == 0)
|
|
+ return 0;
|
|
+
|
|
/* + 1 for the PEC */
|
|
if (midev->rx_pos < MCTP_I2C_MINLEN + 1) {
|
|
ndev->stats.rx_length_errors++;
|
|
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
|
|
index 3fd7dccf0f9c98..fe9e8483e8c59c 100644
|
|
--- a/drivers/net/usb/Kconfig
|
|
+++ b/drivers/net/usb/Kconfig
|
|
@@ -320,7 +320,6 @@ config USB_NET_DM9601
|
|
config USB_NET_SR9700
|
|
tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
|
|
depends on USB_USBNET
|
|
- select CRC32
|
|
help
|
|
This option adds support for CoreChip-sz SR9700 based USB 1.1
|
|
10/100 Ethernet adapters.
|
|
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
|
|
index ff439ef535ac9b..98346cb4ece01e 100644
|
|
--- a/drivers/net/usb/catc.c
|
|
+++ b/drivers/net/usb/catc.c
|
|
@@ -64,6 +64,16 @@ static const char driver_name[] = "catc";
|
|
#define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */
|
|
#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */
|
|
|
|
+/*
|
|
+ * USB endpoints.
|
|
+ */
|
|
+
|
|
+enum catc_usb_ep {
|
|
+ CATC_USB_EP_CONTROL = 0,
|
|
+ CATC_USB_EP_BULK = 1,
|
|
+ CATC_USB_EP_INT_IN = 2,
|
|
+};
|
|
+
|
|
/*
|
|
* Control requests.
|
|
*/
|
|
@@ -772,6 +782,13 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
u8 broadcast[ETH_ALEN];
|
|
u8 *macbuf;
|
|
int pktsz, ret = -ENOMEM;
|
|
+ static const u8 bulk_ep_addr[] = {
|
|
+ CATC_USB_EP_BULK | USB_DIR_OUT,
|
|
+ CATC_USB_EP_BULK | USB_DIR_IN,
|
|
+ 0};
|
|
+ static const u8 int_ep_addr[] = {
|
|
+ CATC_USB_EP_INT_IN | USB_DIR_IN,
|
|
+ 0};
|
|
|
|
macbuf = kmalloc(ETH_ALEN, GFP_KERNEL);
|
|
if (!macbuf)
|
|
@@ -784,6 +801,14 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
goto fail_mem;
|
|
}
|
|
|
|
+ /* Verify that all required endpoints are present */
|
|
+ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
|
|
+ !usb_check_int_endpoints(intf, int_ep_addr)) {
|
|
+ dev_err(dev, "Missing or invalid endpoints\n");
|
|
+ ret = -ENODEV;
|
|
+ goto fail_mem;
|
|
+ }
|
|
+
|
|
netdev = alloc_etherdev(sizeof(struct catc));
|
|
if (!netdev)
|
|
goto fail_mem;
|
|
@@ -828,14 +853,14 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|
usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
|
|
NULL, NULL, 0, catc_ctrl_done, catc);
|
|
|
|
- usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
|
|
- NULL, 0, catc_tx_done, catc);
|
|
+ usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, CATC_USB_EP_BULK),
|
|
+ NULL, 0, catc_tx_done, catc);
|
|
|
|
- usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
|
|
- catc->rx_buf, pktsz, catc_rx_done, catc);
|
|
+ usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, CATC_USB_EP_BULK),
|
|
+ catc->rx_buf, pktsz, catc_rx_done, catc);
|
|
|
|
- usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
|
|
- catc->irq_buf, 2, catc_irq_done, catc, 1);
|
|
+ usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, CATC_USB_EP_INT_IN),
|
|
+ catc->irq_buf, 2, catc_irq_done, catc, 1);
|
|
|
|
if (!catc->is_f5u011) {
|
|
u32 *buf;
|
|
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
|
|
index c9efb7df892ec5..e01d14f6c36677 100644
|
|
--- a/drivers/net/usb/kaweth.c
|
|
+++ b/drivers/net/usb/kaweth.c
|
|
@@ -765,7 +765,6 @@ static void kaweth_set_rx_mode(struct net_device *net)
|
|
|
|
netdev_dbg(net, "Setting Rx mode to %d\n", packet_filter_bitmap);
|
|
|
|
- netif_stop_queue(net);
|
|
|
|
if (net->flags & IFF_PROMISC) {
|
|
packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
|
|
@@ -775,7 +774,6 @@ static void kaweth_set_rx_mode(struct net_device *net)
|
|
}
|
|
|
|
kaweth->packet_filter_bitmap = packet_filter_bitmap;
|
|
- netif_wake_queue(net);
|
|
}
|
|
|
|
/****************************************************************
|
|
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
|
|
index 121f1c15c67936..4a6377ac316090 100644
|
|
--- a/drivers/net/usb/lan78xx.c
|
|
+++ b/drivers/net/usb/lan78xx.c
|
|
@@ -2106,8 +2106,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
|
|
dev->mdiobus->phy_mask = ~(1 << 1);
|
|
break;
|
|
case ID_REV_CHIP_ID_7801_:
|
|
- /* scan thru PHYAD[2..0] */
|
|
- dev->mdiobus->phy_mask = ~(0xFF);
|
|
break;
|
|
}
|
|
|
|
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
|
|
index c514483134f05f..0f16a133c75d13 100644
|
|
--- a/drivers/net/usb/pegasus.c
|
|
+++ b/drivers/net/usb/pegasus.c
|
|
@@ -31,6 +31,17 @@ static const char driver_name[] = "pegasus";
|
|
BMSR_100FULL | BMSR_ANEGCAPABLE)
|
|
#define CARRIER_CHECK_DELAY (2 * HZ)
|
|
|
|
+/*
|
|
+ * USB endpoints.
|
|
+ */
|
|
+
|
|
+enum pegasus_usb_ep {
|
|
+ PEGASUS_USB_EP_CONTROL = 0,
|
|
+ PEGASUS_USB_EP_BULK_IN = 1,
|
|
+ PEGASUS_USB_EP_BULK_OUT = 2,
|
|
+ PEGASUS_USB_EP_INT_IN = 3,
|
|
+};
|
|
+
|
|
static bool loopback;
|
|
static bool mii_mode;
|
|
static char *devid;
|
|
@@ -545,7 +556,7 @@ static void read_bulk_callback(struct urb *urb)
|
|
goto tl_sched;
|
|
goon:
|
|
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
|
|
- usb_rcvbulkpipe(pegasus->usb, 1),
|
|
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
|
|
pegasus->rx_skb->data, PEGASUS_MTU,
|
|
read_bulk_callback, pegasus);
|
|
rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
|
|
@@ -585,7 +596,7 @@ static void rx_fixup(struct tasklet_struct *t)
|
|
return;
|
|
}
|
|
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
|
|
- usb_rcvbulkpipe(pegasus->usb, 1),
|
|
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
|
|
pegasus->rx_skb->data, PEGASUS_MTU,
|
|
read_bulk_callback, pegasus);
|
|
try_again:
|
|
@@ -713,7 +724,7 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
|
|
((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
|
|
skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len);
|
|
usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,
|
|
- usb_sndbulkpipe(pegasus->usb, 2),
|
|
+ usb_sndbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_OUT),
|
|
pegasus->tx_buff, count,
|
|
write_bulk_callback, pegasus);
|
|
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
|
|
@@ -840,7 +851,7 @@ static int pegasus_open(struct net_device *net)
|
|
set_registers(pegasus, EthID, 6, net->dev_addr);
|
|
|
|
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
|
|
- usb_rcvbulkpipe(pegasus->usb, 1),
|
|
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
|
|
pegasus->rx_skb->data, PEGASUS_MTU,
|
|
read_bulk_callback, pegasus);
|
|
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
|
|
@@ -851,7 +862,7 @@ static int pegasus_open(struct net_device *net)
|
|
}
|
|
|
|
usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
|
|
- usb_rcvintpipe(pegasus->usb, 3),
|
|
+ usb_rcvintpipe(pegasus->usb, PEGASUS_USB_EP_INT_IN),
|
|
pegasus->intr_buff, sizeof(pegasus->intr_buff),
|
|
intr_callback, pegasus, pegasus->intr_interval);
|
|
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
|
|
@@ -1136,10 +1147,24 @@ static int pegasus_probe(struct usb_interface *intf,
|
|
pegasus_t *pegasus;
|
|
int dev_index = id - pegasus_ids;
|
|
int res = -ENOMEM;
|
|
+ static const u8 bulk_ep_addr[] = {
|
|
+ PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
|
|
+ PEGASUS_USB_EP_BULK_OUT | USB_DIR_OUT,
|
|
+ 0};
|
|
+ static const u8 int_ep_addr[] = {
|
|
+ PEGASUS_USB_EP_INT_IN | USB_DIR_IN,
|
|
+ 0};
|
|
|
|
if (pegasus_blacklisted(dev))
|
|
return -ENODEV;
|
|
|
|
+ /* Verify that all required endpoints are present */
|
|
+ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
|
|
+ !usb_check_int_endpoints(intf, int_ep_addr)) {
|
|
+ dev_err(&intf->dev, "Missing or invalid endpoints\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
net = alloc_etherdev(sizeof(struct pegasus));
|
|
if (!net)
|
|
goto out;
|
|
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
|
|
index 386376ceeda25d..a2e3f9583def78 100644
|
|
--- a/drivers/net/usb/r8152.c
|
|
+++ b/drivers/net/usb/r8152.c
|
|
@@ -2445,6 +2445,8 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
|
|
ret = usb_submit_urb(agg->urb, GFP_ATOMIC);
|
|
if (ret < 0)
|
|
usb_autopm_put_interface_async(tp->intf);
|
|
+ else
|
|
+ netif_trans_update(tp->netdev);
|
|
|
|
out_tx_fill:
|
|
return ret;
|
|
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
|
|
index 213b4817cfdf6d..e4d7bcd0d99c23 100644
|
|
--- a/drivers/net/usb/sr9700.c
|
|
+++ b/drivers/net/usb/sr9700.c
|
|
@@ -18,7 +18,6 @@
|
|
#include <linux/ethtool.h>
|
|
#include <linux/mii.h>
|
|
#include <linux/usb.h>
|
|
-#include <linux/crc32.h>
|
|
#include <linux/usb/usbnet.h>
|
|
|
|
#include "sr9700.h"
|
|
@@ -265,31 +264,15 @@ static const struct ethtool_ops sr9700_ethtool_ops = {
|
|
static void sr9700_set_multicast(struct net_device *netdev)
|
|
{
|
|
struct usbnet *dev = netdev_priv(netdev);
|
|
- /* We use the 20 byte dev->data for our 8 byte filter buffer
|
|
- * to avoid allocating memory that is tricky to free later
|
|
- */
|
|
- u8 *hashes = (u8 *)&dev->data;
|
|
/* rx_ctl setting : enable, disable_long, disable_crc */
|
|
u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
|
|
|
|
- memset(hashes, 0x00, SR_MCAST_SIZE);
|
|
- /* broadcast address */
|
|
- hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
|
|
- if (netdev->flags & IFF_PROMISC) {
|
|
+ if (netdev->flags & IFF_PROMISC)
|
|
rx_ctl |= RCR_PRMSC;
|
|
- } else if (netdev->flags & IFF_ALLMULTI ||
|
|
- netdev_mc_count(netdev) > SR_MCAST_MAX) {
|
|
- rx_ctl |= RCR_RUNT;
|
|
- } else if (!netdev_mc_empty(netdev)) {
|
|
- struct netdev_hw_addr *ha;
|
|
-
|
|
- netdev_for_each_mc_addr(ha, netdev) {
|
|
- u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
|
- hashes[crc >> 3] |= 1 << (crc & 0x7);
|
|
- }
|
|
- }
|
|
+ else if (netdev->flags & IFF_ALLMULTI || !netdev_mc_empty(netdev))
|
|
+ /* The chip has no multicast filter */
|
|
+ rx_ctl |= RCR_ALL;
|
|
|
|
- sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
|
|
sr_write_reg_async(dev, SR_RCR, rx_ctl);
|
|
}
|
|
|
|
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
|
|
index ea2b4de621c867..c479908f7d823d 100644
|
|
--- a/drivers/net/usb/sr9700.h
|
|
+++ b/drivers/net/usb/sr9700.h
|
|
@@ -104,9 +104,7 @@
|
|
#define WCR_LINKEN (1 << 5)
|
|
/* Physical Address Reg */
|
|
#define SR_PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */
|
|
-/* Multicast Address Reg */
|
|
-#define SR_MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */
|
|
-/* 0x1e unused */
|
|
+/* 0x16 --> 0x1E unused */
|
|
/* Phy Reset Reg */
|
|
#define SR_PRR 0x1F
|
|
#define PRR_PHY_RST (1 << 0)
|
|
@@ -161,9 +159,6 @@
|
|
/* parameters */
|
|
#define SR_SHARE_TIMEOUT 1000
|
|
#define SR_EEPROM_LEN 256
|
|
-#define SR_MCAST_SIZE 8
|
|
-#define SR_MCAST_ADDR_FLAG 0x80
|
|
-#define SR_MCAST_MAX 64
|
|
#define SR_TX_OVERHEAD 2 /* 2bytes header */
|
|
#define SR_RX_OVERHEAD 7 /* 3bytes header + 4crc tail */
|
|
|
|
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
|
|
index 5b01642ca44e05..6b2d1e63855e8b 100644
|
|
--- a/drivers/net/wan/farsync.c
|
|
+++ b/drivers/net/wan/farsync.c
|
|
@@ -2550,6 +2550,8 @@ fst_remove_one(struct pci_dev *pdev)
|
|
|
|
fst_disable_intr(card);
|
|
free_irq(card->irq, card);
|
|
+ tasklet_kill(&fst_tx_task);
|
|
+ tasklet_kill(&fst_int_task);
|
|
|
|
iounmap(card->ctlmem);
|
|
iounmap(card->mem);
|
|
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
|
|
index fd50bb313b9244..7176055cb38a5d 100644
|
|
--- a/drivers/net/wan/fsl_ucc_hdlc.c
|
|
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
|
|
@@ -790,18 +790,14 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv)
|
|
|
|
if (priv->rx_buffer) {
|
|
dma_free_coherent(priv->dev,
|
|
- RX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
|
|
+ (RX_BD_RING_LEN + TX_BD_RING_LEN) * MAX_RX_BUF_LENGTH,
|
|
priv->rx_buffer, priv->dma_rx_addr);
|
|
priv->rx_buffer = NULL;
|
|
priv->dma_rx_addr = 0;
|
|
- }
|
|
|
|
- if (priv->tx_buffer) {
|
|
- dma_free_coherent(priv->dev,
|
|
- TX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
|
|
- priv->tx_buffer, priv->dma_tx_addr);
|
|
priv->tx_buffer = NULL;
|
|
priv->dma_tx_addr = 0;
|
|
+
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
|
|
index 850d999615a2c3..7d0a522e5402ef 100644
|
|
--- a/drivers/net/wireless/ath/ath10k/sdio.c
|
|
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
|
|
@@ -2486,7 +2486,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
|
|
if (fast_dump)
|
|
ath10k_bmi_start(ar);
|
|
|
|
+ mutex_lock(&ar->dump_mutex);
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
ar->stats.fw_crash_counter++;
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
|
ath10k_sdio_disable_intrs(ar);
|
|
|
|
@@ -2504,6 +2508,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
|
|
|
|
ath10k_sdio_enable_intrs(ar);
|
|
|
|
+ mutex_unlock(&ar->dump_mutex);
|
|
+
|
|
ath10k_core_start_recovery(ar);
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
|
|
index c7c96d210061d1..ee41f45b3426c0 100644
|
|
--- a/drivers/net/wireless/ath/ath10k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
|
|
@@ -5283,8 +5283,6 @@ ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
|
|
struct ath10k_sta *arsta;
|
|
u8 peer_addr[ETH_ALEN];
|
|
|
|
- lockdep_assert_held(&ar->data_lock);
|
|
-
|
|
ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data;
|
|
ether_addr_copy(peer_addr, ev->peer_macaddr.addr);
|
|
|
|
@@ -5299,7 +5297,9 @@ ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
|
|
}
|
|
|
|
arsta = (struct ath10k_sta *)sta->drv_priv;
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
arsta->peer_ps_state = __le32_to_cpu(ev->peer_ps_state);
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
|
exit:
|
|
rcu_read_unlock();
|
|
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
|
|
index 355424baeedde2..9eb8887f84e7e4 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -789,6 +789,34 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),
|
|
},
|
|
},
|
|
+ {
|
|
+ .driver_data = (void *)ATH11K_PM_WOW,
|
|
+ .matches = { /* Z13 G1 */
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "21D2"),
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .driver_data = (void *)ATH11K_PM_WOW,
|
|
+ .matches = { /* Z13 G1 */
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "21D3"),
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .driver_data = (void *)ATH11K_PM_WOW,
|
|
+ .matches = { /* Z16 G1 */
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "21D4"),
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .driver_data = (void *)ATH11K_PM_WOW,
|
|
+ .matches = { /* Z16 G1 */
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "21D5"),
|
|
+ },
|
|
+ },
|
|
{}
|
|
};
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
|
|
index 7e400a0e0eb111..fe920ecd25baf2 100644
|
|
--- a/drivers/net/wireless/ath/ath12k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
|
|
@@ -3804,7 +3804,7 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
|
|
|
|
pref = soc->wmi_ab.preferred_hw_mode;
|
|
|
|
- if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {
|
|
+ if (ath12k_hw_mode_pri_map[mode] <= ath12k_hw_mode_pri_map[pref]) {
|
|
svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps;
|
|
soc->wmi_ab.preferred_hw_mode = mode;
|
|
}
|
|
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
|
|
index 820100cac49150..76e67870f38519 100644
|
|
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
|
|
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
|
|
@@ -11384,7 +11384,13 @@ static const struct pci_device_id card_ids[] = {
|
|
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
|
|
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
|
|
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
|
|
- {PCI_VDEVICE(INTEL, 0x104f), 0},
|
|
+ /*
|
|
+ * This ID conflicts with i40e, but the devices can be differentiated
|
|
+ * because i40e devices use PCI_CLASS_NETWORK_ETHERNET and ipw2200
|
|
+ * devices use PCI_CLASS_NETWORK_OTHER.
|
|
+ */
|
|
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x104f),
|
|
+ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0},
|
|
{PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
|
|
{PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
|
|
{PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
|
|
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
|
|
index 9eaf5ec133f9ef..5d61cebbdc400b 100644
|
|
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
|
|
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
|
|
@@ -3262,7 +3262,9 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr,
|
|
|
|
D_INFO("Invoking measurement of type %d on " "channel %d (for '%s')\n",
|
|
type, params.channel, buf);
|
|
+ mutex_lock(&il->mutex);
|
|
il3945_get_measurement(il, ¶ms, type);
|
|
+ mutex_unlock(&il->mutex);
|
|
|
|
return count;
|
|
}
|
|
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
|
|
index 75118e24061911..b345fa22563415 100644
|
|
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
|
|
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
|
|
@@ -4612,7 +4612,9 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
|
|
if (ret)
|
|
IL_INFO("%s is not in decimal form.\n", buf);
|
|
else {
|
|
+ mutex_lock(&il->mutex);
|
|
ret = il_set_tx_power(il, val, false);
|
|
+ mutex_unlock(&il->mutex);
|
|
if (ret)
|
|
IL_ERR("failed setting tx power (0x%08x).\n", ret);
|
|
else
|
|
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
|
|
index 9c97691e603844..60472c89fca380 100644
|
|
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
|
|
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
|
|
@@ -1722,6 +1722,20 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
|
|
|
|
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
|
+ /*
|
|
+ * len_low should be 2 + n*13 (where n is the number of descriptors.
|
|
+ * 13 is the size of a NoA descriptor). We can have either one or two
|
|
+ * descriptors.
|
|
+ */
|
|
+ if (IWL_FW_CHECK(mvm, notif->noa_active &&
|
|
+ notif->noa_attr.len_low != 2 +
|
|
+ sizeof(struct ieee80211_p2p_noa_desc) &&
|
|
+ notif->noa_attr.len_low != 2 +
|
|
+ sizeof(struct ieee80211_p2p_noa_desc) * 2,
|
|
+ "Invalid noa_attr.len_low (%d)\n",
|
|
+ notif->noa_attr.len_low))
|
|
+ return;
|
|
+
|
|
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
|
|
if (!new_data)
|
|
return;
|
|
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
|
|
index 2240b4db8c0366..d98c81539ba53b 100644
|
|
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
|
|
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
|
|
@@ -426,6 +426,8 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb
|
|
goto tx_ret;
|
|
}
|
|
|
|
+ usb_kill_urb(cardp->tx_urb);
|
|
+
|
|
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
|
|
usb_sndbulkpipe(cardp->udev,
|
|
cardp->ep_out),
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
|
|
index c7396ae9256b9b..9a4c23163fba4c 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/main.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/main.c
|
|
@@ -710,10 +710,10 @@ void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel)
|
|
}
|
|
EXPORT_SYMBOL(rtw_set_rx_freq_band);
|
|
|
|
-void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period)
|
|
+void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period)
|
|
{
|
|
rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_TIMIE);
|
|
- rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period - 1);
|
|
+ rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period ? dtim_period - 1 : 0);
|
|
}
|
|
|
|
void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel,
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
|
|
index c42ef8294d59e4..6e0e1c9c28f707 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/main.h
|
|
+++ b/drivers/net/wireless/realtek/rtw88/main.h
|
|
@@ -2154,7 +2154,7 @@ enum nl80211_band rtw_hw_to_nl80211_band(enum rtw_supported_band hw_band)
|
|
}
|
|
|
|
void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel);
|
|
-void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period);
|
|
+void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period);
|
|
void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
|
|
struct rtw_channel_params *ch_param);
|
|
bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target);
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c
|
|
index a019f4085e7389..1f5af09aed99fa 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c
|
|
@@ -37,6 +37,8 @@ static const struct usb_device_id rtw_8821cu_id_table[] = {
|
|
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd811, 0xff, 0xff, 0xff),
|
|
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */
|
|
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0105, 0xff, 0xff, 0xff),
|
|
+ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Mercusys */
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table);
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
|
|
index 99318a82b43f4b..e792d7c8669910 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
|
|
@@ -1044,7 +1044,8 @@ static int rtw8822b_set_antenna(struct rtw_dev *rtwdev,
|
|
hal->antenna_tx = antenna_tx;
|
|
hal->antenna_rx = antenna_rx;
|
|
|
|
- rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false);
|
|
+ if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
|
|
+ rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
|
|
index 33b2543ee4d230..1ac5d021893d38 100644
|
|
--- a/drivers/net/wireless/realtek/rtw89/pci.c
|
|
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
|
|
@@ -3856,6 +3856,7 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev)
|
|
rtw89_write32_clr(rtwdev, R_AX_PCIE_PS_CTRL_V1,
|
|
B_AX_SEL_REQ_ENTR_L1);
|
|
}
|
|
+ rtw89_pci_hci_ldo(rtwdev);
|
|
rtw89_pci_l2_hci_ldo(rtwdev);
|
|
rtw89_pci_filter_out(rtwdev);
|
|
rtw89_pci_link_cfg(rtwdev);
|
|
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
|
|
index aa9efca0402539..f558df21a2fd00 100644
|
|
--- a/drivers/net/wireless/realtek/rtw89/wow.c
|
|
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
|
|
@@ -100,6 +100,10 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev)
|
|
reason = rtw89_read8(rtwdev, wow_reason_reg);
|
|
|
|
switch (reason) {
|
|
+ case RTW89_WOW_RSN_RX_DISASSOC:
|
|
+ wakeup.disconnect = true;
|
|
+ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx disassoc\n");
|
|
+ break;
|
|
case RTW89_WOW_RSN_RX_DEAUTH:
|
|
wakeup.disconnect = true;
|
|
rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n");
|
|
diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h
|
|
index a2f7b2e3cdb4dd..fd85772ccb04ed 100644
|
|
--- a/drivers/net/wireless/realtek/rtw89/wow.h
|
|
+++ b/drivers/net/wireless/realtek/rtw89/wow.h
|
|
@@ -8,6 +8,7 @@
|
|
enum rtw89_wake_reason {
|
|
RTW89_WOW_RSN_RX_PTK_REKEY = 0x1,
|
|
RTW89_WOW_RSN_RX_GTK_REKEY = 0x2,
|
|
+ RTW89_WOW_RSN_RX_DISASSOC = 0x4,
|
|
RTW89_WOW_RSN_RX_DEAUTH = 0x8,
|
|
RTW89_WOW_RSN_DISCONNECT = 0x10,
|
|
RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21,
|
|
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
|
|
index a78a25b872409a..61b547aab286a2 100644
|
|
--- a/drivers/net/xen-netback/xenbus.c
|
|
+++ b/drivers/net/xen-netback/xenbus.c
|
|
@@ -735,10 +735,11 @@ static void connect(struct backend_info *be)
|
|
*/
|
|
requested_num_queues = xenbus_read_unsigned(dev->otherend,
|
|
"multi-queue-num-queues", 1);
|
|
- if (requested_num_queues > xenvif_max_queues) {
|
|
+ if (requested_num_queues > xenvif_max_queues ||
|
|
+ requested_num_queues == 0) {
|
|
/* buggy or malicious guest */
|
|
xenbus_dev_fatal(dev, -EINVAL,
|
|
- "guest requested %u queues, exceeding the maximum of %u.",
|
|
+ "guest requested %u queues, but valid range is 1 - %u.",
|
|
requested_num_queues, xenvif_max_queues);
|
|
return;
|
|
}
|
|
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
|
|
index 3ae4b41c59ac3d..edf5514795fd08 100644
|
|
--- a/drivers/nfc/nxp-nci/i2c.c
|
|
+++ b/drivers/nfc/nxp-nci/i2c.c
|
|
@@ -305,7 +305,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client)
|
|
|
|
r = request_threaded_irq(client->irq, NULL,
|
|
nxp_nci_i2c_irq_thread_fn,
|
|
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
|
+ IRQF_ONESHOT,
|
|
NXP_NCI_I2C_DRIVER_NAME, phy);
|
|
if (r < 0)
|
|
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
|
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
|
|
index b5f93f07e22a4d..7f23f10ef64e47 100644
|
|
--- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
|
|
+++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
|
|
@@ -1202,7 +1202,8 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
|
|
sndev->mmio_self_ctrl);
|
|
|
|
sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries);
|
|
- sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
|
|
+ if (sndev->nr_lut_mw)
|
|
+ sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
|
|
|
|
dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n",
|
|
sndev->nr_direct_mw, sndev->nr_lut_mw);
|
|
@@ -1212,7 +1213,8 @@ static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
|
|
|
|
sndev->peer_nr_lut_mw =
|
|
ioread16(&sndev->mmio_peer_ctrl->lut_table_entries);
|
|
- sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
|
|
+ if (sndev->peer_nr_lut_mw)
|
|
+ sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
|
|
|
|
dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n",
|
|
sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw);
|
|
@@ -1314,6 +1316,12 @@ static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev)
|
|
for (i = 0; i < sndev->nr_lut_mw; i++) {
|
|
int idx = sndev->nr_direct_mw + i;
|
|
|
|
+ if (idx >= MAX_MWS) {
|
|
+ dev_err(&sndev->stdev->dev,
|
|
+ "Total number of MW cannot be bigger than %d", MAX_MWS);
|
|
+ break;
|
|
+ }
|
|
+
|
|
sndev->self_shared->mw_sizes[idx] = LUT_SIZE;
|
|
}
|
|
}
|
|
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
|
|
index 76cc5b49a5f1ee..0087c23655c7a4 100644
|
|
--- a/drivers/ntb/ntb_transport.c
|
|
+++ b/drivers/ntb/ntb_transport.c
|
|
@@ -1227,9 +1227,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
|
|
qp->tx_max_entry = tx_size / qp->tx_max_frame;
|
|
|
|
if (nt->debugfs_node_dir) {
|
|
- char debugfs_name[4];
|
|
+ char debugfs_name[8];
|
|
|
|
- snprintf(debugfs_name, 4, "qp%d", qp_num);
|
|
+ snprintf(debugfs_name, sizeof(debugfs_name), "qp%d", qp_num);
|
|
qp->debugfs_dir = debugfs_create_dir(debugfs_name,
|
|
nt->debugfs_node_dir);
|
|
|
|
diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c
|
|
index 839f10ca56eac9..e5a7b031da2d6f 100644
|
|
--- a/drivers/nvdimm/nd_virtio.c
|
|
+++ b/drivers/nvdimm/nd_virtio.c
|
|
@@ -44,6 +44,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region)
|
|
unsigned long flags;
|
|
int err, err1;
|
|
|
|
+ guard(mutex)(&vpmem->flush_lock);
|
|
+
|
|
/*
|
|
* Don't bother to submit the request to the device if the device is
|
|
* not activated.
|
|
@@ -53,7 +55,6 @@ static int virtio_pmem_flush(struct nd_region *nd_region)
|
|
return -EIO;
|
|
}
|
|
|
|
- might_sleep();
|
|
req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
|
|
if (!req_data)
|
|
return -ENOMEM;
|
|
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
|
|
index a92eb172f0e7eb..4eebb2ec3cf978 100644
|
|
--- a/drivers/nvdimm/virtio_pmem.c
|
|
+++ b/drivers/nvdimm/virtio_pmem.c
|
|
@@ -49,6 +49,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
|
|
goto out_err;
|
|
}
|
|
|
|
+ mutex_init(&vpmem->flush_lock);
|
|
vpmem->vdev = vdev;
|
|
vdev->priv = vpmem;
|
|
err = init_vq(vpmem);
|
|
diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h
|
|
index 0dddefe594c46a..f72cf17f9518fb 100644
|
|
--- a/drivers/nvdimm/virtio_pmem.h
|
|
+++ b/drivers/nvdimm/virtio_pmem.h
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/module.h>
|
|
#include <uapi/linux/virtio_pmem.h>
|
|
#include <linux/libnvdimm.h>
|
|
+#include <linux/mutex.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
struct virtio_pmem_request {
|
|
@@ -35,6 +36,9 @@ struct virtio_pmem {
|
|
/* Virtio pmem request queue */
|
|
struct virtqueue *req_vq;
|
|
|
|
+ /* Serialize flush requests to the device. */
|
|
+ struct mutex flush_lock;
|
|
+
|
|
/* nvdimm bus registers virtio pmem device */
|
|
struct nvdimm_bus *nvdimm_bus;
|
|
struct nvdimm_bus_descriptor nd_desc;
|
|
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
|
|
index dd00cc09ae5ec5..5b819bbd451afc 100644
|
|
--- a/drivers/nvmem/core.c
|
|
+++ b/drivers/nvmem/core.c
|
|
@@ -724,6 +724,7 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
|
|
kfree(info.name);
|
|
if (ret) {
|
|
of_node_put(child);
|
|
+ of_node_put(info.np);
|
|
return ret;
|
|
}
|
|
}
|
|
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
|
|
index aae4e8ef9e3654..4b7e663feee3d6 100644
|
|
--- a/drivers/of/unittest.c
|
|
+++ b/drivers/of/unittest.c
|
|
@@ -800,11 +800,13 @@ static void __init of_unittest_property_copy(void)
|
|
|
|
new = __of_prop_dup(&p1, GFP_KERNEL);
|
|
unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
|
|
- __of_prop_free(new);
|
|
+ if (new)
|
|
+ __of_prop_free(new);
|
|
|
|
new = __of_prop_dup(&p2, GFP_KERNEL);
|
|
unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
|
|
- __of_prop_free(new);
|
|
+ if (new)
|
|
+ __of_prop_free(new);
|
|
#endif
|
|
}
|
|
|
|
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
|
|
index 8af7a837a0612c..615bb9b42c5137 100644
|
|
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
|
|
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
|
|
@@ -48,6 +48,8 @@
|
|
#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4)
|
|
#define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0)
|
|
|
|
+#define PCIE_TYPE0_HDR_DBI2_OFFSET 0x100000
|
|
+
|
|
struct rockchip_pcie {
|
|
struct dw_pcie pci;
|
|
void __iomem *apb_base;
|
|
@@ -198,6 +200,8 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
|
|
if (irq < 0)
|
|
return irq;
|
|
|
|
+ pci->dbi_base2 = pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
|
|
+
|
|
ret = rockchip_pcie_init_irq_domain(rockchip);
|
|
if (ret < 0)
|
|
dev_err(dev, "failed to init irq domain\n");
|
|
@@ -211,6 +215,10 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
|
|
rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE,
|
|
PCIE_CLIENT_GENERAL_CONTROL);
|
|
|
|
+ /* Disable Root Ports BAR0 and BAR1 as they report bogus size */
|
|
+ dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0);
|
|
+ dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0x0);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
|
|
index 48372013f26d23..82e575e4d3877a 100644
|
|
--- a/drivers/pci/controller/pcie-mediatek.c
|
|
+++ b/drivers/pci/controller/pcie-mediatek.c
|
|
@@ -587,8 +587,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
|
|
|
|
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
|
ret = mtk_pcie_allocate_msi_domains(port);
|
|
- if (ret)
|
|
+ if (ret) {
|
|
+ irq_domain_remove(port->irq_domain);
|
|
return ret;
|
|
+ }
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
|
|
index c28c3f094496a8..5b64203f100fc7 100644
|
|
--- a/drivers/pci/endpoint/pci-ep-cfs.c
|
|
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
|
|
@@ -65,8 +65,8 @@ static int pci_secondary_epc_epf_link(struct config_item *epf_item,
|
|
return 0;
|
|
}
|
|
|
|
-static void pci_secondary_epc_epf_unlink(struct config_item *epc_item,
|
|
- struct config_item *epf_item)
|
|
+static void pci_secondary_epc_epf_unlink(struct config_item *epf_item,
|
|
+ struct config_item *epc_item)
|
|
{
|
|
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
|
|
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
|
|
@@ -126,8 +126,8 @@ static int pci_primary_epc_epf_link(struct config_item *epf_item,
|
|
return 0;
|
|
}
|
|
|
|
-static void pci_primary_epc_epf_unlink(struct config_item *epc_item,
|
|
- struct config_item *epf_item)
|
|
+static void pci_primary_epc_epf_unlink(struct config_item *epf_item,
|
|
+ struct config_item *epc_item)
|
|
{
|
|
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
|
|
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
|
|
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
|
|
index f97c4f0e1c7a3d..b8bce45a599866 100644
|
|
--- a/drivers/pci/iov.c
|
|
+++ b/drivers/pci/iov.c
|
|
@@ -447,7 +447,9 @@ static ssize_t sriov_numvfs_store(struct device *dev,
|
|
|
|
if (num_vfs == 0) {
|
|
/* disable VFs */
|
|
+ pci_lock_rescan_remove();
|
|
ret = pdev->driver->sriov_configure(pdev, 0);
|
|
+ pci_unlock_rescan_remove();
|
|
goto exit;
|
|
}
|
|
|
|
@@ -459,7 +461,9 @@ static ssize_t sriov_numvfs_store(struct device *dev,
|
|
goto exit;
|
|
}
|
|
|
|
+ pci_lock_rescan_remove();
|
|
ret = pdev->driver->sriov_configure(pdev, num_vfs);
|
|
+ pci_unlock_rescan_remove();
|
|
if (ret < 0)
|
|
goto exit;
|
|
|
|
@@ -581,18 +585,15 @@ static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs)
|
|
if (dev->no_vf_scan)
|
|
return 0;
|
|
|
|
- pci_lock_rescan_remove();
|
|
for (i = 0; i < num_vfs; i++) {
|
|
rc = pci_iov_add_virtfn(dev, i);
|
|
if (rc)
|
|
goto failed;
|
|
}
|
|
- pci_unlock_rescan_remove();
|
|
return 0;
|
|
failed:
|
|
while (i--)
|
|
pci_iov_remove_virtfn(dev, i);
|
|
- pci_unlock_rescan_remove();
|
|
|
|
return rc;
|
|
}
|
|
@@ -712,10 +713,8 @@ static void sriov_del_vfs(struct pci_dev *dev)
|
|
struct pci_sriov *iov = dev->sriov;
|
|
int i;
|
|
|
|
- pci_lock_rescan_remove();
|
|
for (i = 0; i < iov->num_VFs; i++)
|
|
pci_iov_remove_virtfn(dev, i);
|
|
- pci_unlock_rescan_remove();
|
|
}
|
|
|
|
static void sriov_disable(struct pci_dev *dev)
|
|
diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
|
|
index b638731aa5ff2f..f6f4a778a98678 100644
|
|
--- a/drivers/pci/msi/msi.c
|
|
+++ b/drivers/pci/msi/msi.c
|
|
@@ -737,7 +737,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
|
|
|
|
ret = msix_setup_interrupts(dev, entries, nvec, affd);
|
|
if (ret)
|
|
- goto out_disable;
|
|
+ goto out_unmap;
|
|
|
|
/* Disable INTX */
|
|
pci_intx_for_msi(dev, 0);
|
|
@@ -756,6 +756,8 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
|
|
pcibios_free_irq(dev);
|
|
return 0;
|
|
|
|
+out_unmap:
|
|
+ iounmap(dev->msix_base);
|
|
out_disable:
|
|
dev->msix_enabled = 0;
|
|
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE, 0);
|
|
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
|
|
index 0f1e431bbfc20a..f97ac18a8dc8fc 100644
|
|
--- a/drivers/pci/p2pdma.c
|
|
+++ b/drivers/pci/p2pdma.c
|
|
@@ -143,6 +143,7 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj,
|
|
ret = vm_insert_page(vma, vaddr, virt_to_page(kaddr));
|
|
if (ret) {
|
|
gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len);
|
|
+ percpu_ref_put(ref);
|
|
return ret;
|
|
}
|
|
percpu_ref_get(ref);
|
|
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
|
|
index 61bded8623d218..508873c526e718 100644
|
|
--- a/drivers/pci/pci-acpi.c
|
|
+++ b/drivers/pci/pci-acpi.c
|
|
@@ -246,21 +246,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
|
|
return AE_OK;
|
|
}
|
|
|
|
-static bool pcie_root_rcb_set(struct pci_dev *dev)
|
|
-{
|
|
- struct pci_dev *rp = pcie_find_root_port(dev);
|
|
- u16 lnkctl;
|
|
-
|
|
- if (!rp)
|
|
- return false;
|
|
-
|
|
- pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
|
|
- if (lnkctl & PCI_EXP_LNKCTL_RCB)
|
|
- return true;
|
|
-
|
|
- return false;
|
|
-}
|
|
-
|
|
/* _HPX PCI Express Setting Record (Type 2) */
|
|
struct hpx_type2 {
|
|
u32 revision;
|
|
@@ -286,6 +271,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
|
|
{
|
|
int pos;
|
|
u32 reg32;
|
|
+ const struct pci_host_bridge *host;
|
|
|
|
if (!hpx)
|
|
return;
|
|
@@ -293,6 +279,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
|
|
if (!pci_is_pcie(dev))
|
|
return;
|
|
|
|
+ host = pci_find_host_bridge(dev->bus);
|
|
+
|
|
+ /*
|
|
+ * Only do the _HPX Type 2 programming if OS owns PCIe native
|
|
+ * hotplug but not AER.
|
|
+ */
|
|
+ if (!host->native_pcie_hotplug || host->native_aer)
|
|
+ return;
|
|
+
|
|
if (hpx->revision > 1) {
|
|
pci_warn(dev, "PCIe settings rev %d not supported\n",
|
|
hpx->revision);
|
|
@@ -300,33 +295,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
|
|
}
|
|
|
|
/*
|
|
- * Don't allow _HPX to change MPS or MRRS settings. We manage
|
|
- * those to make sure they're consistent with the rest of the
|
|
- * platform.
|
|
+ * We only allow _HPX to program DEVCTL bits related to AER, namely
|
|
+ * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE,
|
|
+ * and PCI_EXP_DEVCTL_URRE.
|
|
+ *
|
|
+ * The rest of DEVCTL is managed by the OS to make sure it's
|
|
+ * consistent with the rest of the platform.
|
|
*/
|
|
- hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
|
|
- PCI_EXP_DEVCTL_READRQ;
|
|
- hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
|
|
- PCI_EXP_DEVCTL_READRQ);
|
|
+ hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS;
|
|
+ hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS;
|
|
|
|
/* Initialize Device Control Register */
|
|
pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
|
~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or);
|
|
|
|
- /* Initialize Link Control Register */
|
|
+ /* Log if _HPX attempts to modify Link Control Register */
|
|
if (pcie_cap_has_lnkctl(dev)) {
|
|
-
|
|
- /*
|
|
- * If the Root Port supports Read Completion Boundary of
|
|
- * 128, set RCB to 128. Otherwise, clear it.
|
|
- */
|
|
- hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
|
|
- hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
|
|
- if (pcie_root_rcb_set(dev))
|
|
- hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
|
|
-
|
|
- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
|
|
- ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or);
|
|
+ if (hpx->pci_exp_lnkctl_and != 0xffff ||
|
|
+ hpx->pci_exp_lnkctl_or != 0)
|
|
+ pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n",
|
|
+ hpx->pci_exp_lnkctl_and,
|
|
+ hpx->pci_exp_lnkctl_or);
|
|
}
|
|
|
|
/* Find Advanced Error Reporting Enhanced Capability */
|
|
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
|
|
index 8c941d6267a5c5..b7a6d8a28fe930 100644
|
|
--- a/drivers/pci/pci-driver.c
|
|
+++ b/drivers/pci/pci-driver.c
|
|
@@ -1668,6 +1668,14 @@ static int pci_dma_configure(struct device *dev)
|
|
ret = acpi_dma_configure(dev, acpi_get_dma_attr(adev));
|
|
}
|
|
|
|
+ /*
|
|
+ * Attempt to enable ACS regardless of capability because some Root
|
|
+ * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
|
|
+ * the standard ACS capability but still support ACS via those
|
|
+ * quirks.
|
|
+ */
|
|
+ pci_enable_acs(to_pci_dev(dev));
|
|
+
|
|
pci_put_host_bridge_device(bridge);
|
|
|
|
if (!ret && !driver->driver_managed_dma) {
|
|
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
|
|
index 9a3f6bb60eb4d8..d7d7913eb0ee93 100644
|
|
--- a/drivers/pci/pci.c
|
|
+++ b/drivers/pci/pci.c
|
|
@@ -986,7 +986,7 @@ static void pci_std_enable_acs(struct pci_dev *dev)
|
|
* pci_enable_acs - enable ACS if hardware support it
|
|
* @dev: the PCI device
|
|
*/
|
|
-static void pci_enable_acs(struct pci_dev *dev)
|
|
+void pci_enable_acs(struct pci_dev *dev)
|
|
{
|
|
if (!pci_acs_enable)
|
|
goto disable_acs_redir;
|
|
@@ -1427,6 +1427,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool
|
|
|| (state == PCI_D2 && !dev->d2_support))
|
|
return -EIO;
|
|
|
|
+ if (dev->current_state == state)
|
|
+ return 0;
|
|
+
|
|
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
|
|
if (PCI_POSSIBLE_ERROR(pmcsr)) {
|
|
pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n",
|
|
@@ -3758,14 +3761,6 @@ bool pci_acs_path_enabled(struct pci_dev *start,
|
|
void pci_acs_init(struct pci_dev *dev)
|
|
{
|
|
dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
|
|
-
|
|
- /*
|
|
- * Attempt to enable ACS regardless of capability because some Root
|
|
- * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
|
|
- * the standard ACS capability but still support ACS via those
|
|
- * quirks.
|
|
- */
|
|
- pci_enable_acs(dev);
|
|
}
|
|
|
|
/**
|
|
@@ -5790,10 +5785,9 @@ unlock:
|
|
/* Do any devices on or below this slot prevent a bus reset? */
|
|
static bool pci_slot_resettable(struct pci_slot *slot)
|
|
{
|
|
- struct pci_dev *dev;
|
|
+ struct pci_dev *dev, *bridge = slot->bus->self;
|
|
|
|
- if (slot->bus->self &&
|
|
- (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
|
|
+ if (bridge && (bridge->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
|
|
return false;
|
|
|
|
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
|
|
@@ -5810,7 +5804,10 @@ static bool pci_slot_resettable(struct pci_slot *slot)
|
|
/* Lock devices from the top of the tree down */
|
|
static void pci_slot_lock(struct pci_slot *slot)
|
|
{
|
|
- struct pci_dev *dev;
|
|
+ struct pci_dev *dev, *bridge = slot->bus->self;
|
|
+
|
|
+ if (bridge)
|
|
+ pci_dev_lock(bridge);
|
|
|
|
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
|
|
if (!dev->slot || dev->slot != slot)
|
|
@@ -5825,7 +5822,7 @@ static void pci_slot_lock(struct pci_slot *slot)
|
|
/* Unlock devices from the bottom of the tree up */
|
|
static void pci_slot_unlock(struct pci_slot *slot)
|
|
{
|
|
- struct pci_dev *dev;
|
|
+ struct pci_dev *dev, *bridge = slot->bus->self;
|
|
|
|
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
|
|
if (!dev->slot || dev->slot != slot)
|
|
@@ -5835,21 +5832,25 @@ static void pci_slot_unlock(struct pci_slot *slot)
|
|
else
|
|
pci_dev_unlock(dev);
|
|
}
|
|
+
|
|
+ if (bridge)
|
|
+ pci_dev_unlock(bridge);
|
|
}
|
|
|
|
/* Return 1 on successful lock, 0 on contention */
|
|
static int pci_slot_trylock(struct pci_slot *slot)
|
|
{
|
|
- struct pci_dev *dev;
|
|
+ struct pci_dev *dev, *bridge = slot->bus->self;
|
|
+
|
|
+ if (bridge && !pci_dev_trylock(bridge))
|
|
+ return 0;
|
|
|
|
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
|
|
if (!dev->slot || dev->slot != slot)
|
|
continue;
|
|
if (dev->subordinate) {
|
|
- if (!pci_bus_trylock(dev->subordinate)) {
|
|
- pci_dev_unlock(dev);
|
|
+ if (!pci_bus_trylock(dev->subordinate))
|
|
goto unlock;
|
|
- }
|
|
} else if (!pci_dev_trylock(dev))
|
|
goto unlock;
|
|
}
|
|
@@ -5865,6 +5866,9 @@ unlock:
|
|
else
|
|
pci_dev_unlock(dev);
|
|
}
|
|
+
|
|
+ if (bridge)
|
|
+ pci_dev_unlock(bridge);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
|
|
index d69a17947ffcef..485f917641e11c 100644
|
|
--- a/drivers/pci/pci.h
|
|
+++ b/drivers/pci/pci.h
|
|
@@ -22,6 +22,31 @@
|
|
*/
|
|
#define PCIE_PME_TO_L2_TIMEOUT_US 10000
|
|
|
|
+/* Message Routing (r[2:0]); PCIe r6.0, sec 2.2.8 */
|
|
+#define PCIE_MSG_TYPE_R_RC 0
|
|
+#define PCIE_MSG_TYPE_R_ADDR 1
|
|
+#define PCIE_MSG_TYPE_R_ID 2
|
|
+#define PCIE_MSG_TYPE_R_BC 3
|
|
+#define PCIE_MSG_TYPE_R_LOCAL 4
|
|
+#define PCIE_MSG_TYPE_R_GATHER 5
|
|
+
|
|
+/* INTx Mechanism Messages; PCIe r6.0, sec 2.2.8.1 */
|
|
+#define PCIE_MSG_CODE_ASSERT_INTA 0x20
|
|
+#define PCIE_MSG_CODE_ASSERT_INTB 0x21
|
|
+#define PCIE_MSG_CODE_ASSERT_INTC 0x22
|
|
+#define PCIE_MSG_CODE_ASSERT_INTD 0x23
|
|
+#define PCIE_MSG_CODE_DEASSERT_INTA 0x24
|
|
+#define PCIE_MSG_CODE_DEASSERT_INTB 0x25
|
|
+#define PCIE_MSG_CODE_DEASSERT_INTC 0x26
|
|
+#define PCIE_MSG_CODE_DEASSERT_INTD 0x27
|
|
+
|
|
+#define PCI_BUS_BRIDGE_IO_WINDOW 0
|
|
+#define PCI_BUS_BRIDGE_MEM_WINDOW 1
|
|
+#define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2
|
|
+
|
|
+#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
|
|
+ PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
|
|
+
|
|
extern const unsigned char pcie_link_speed[];
|
|
extern bool pci_early_dump;
|
|
|
|
@@ -530,6 +555,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
|
|
}
|
|
|
|
void pci_acs_init(struct pci_dev *dev);
|
|
+void pci_enable_acs(struct pci_dev *dev);
|
|
#ifdef CONFIG_PCI_QUIRKS
|
|
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
|
|
int pci_dev_specific_enable_acs(struct pci_dev *dev);
|
|
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
|
|
index 8e700020ee0bc3..42a0f86b72fa5a 100644
|
|
--- a/drivers/pci/pcie/aer.c
|
|
+++ b/drivers/pci/pcie/aer.c
|
|
@@ -218,9 +218,6 @@ void pcie_ecrc_get_policy(char *str)
|
|
}
|
|
#endif /* CONFIG_PCIE_ECRC */
|
|
|
|
-#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \
|
|
- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE)
|
|
-
|
|
int pcie_aer_is_native(struct pci_dev *dev)
|
|
{
|
|
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
|
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
|
|
index d6e5fef54c3b8d..dac3ba1b2552f1 100644
|
|
--- a/drivers/pci/pcie/portdrv.c
|
|
+++ b/drivers/pci/pcie/portdrv.c
|
|
@@ -554,10 +554,10 @@ static int pcie_port_remove_service(struct device *dev)
|
|
|
|
pciedev = to_pcie_device(dev);
|
|
driver = to_service_driver(dev->driver);
|
|
- if (driver && driver->remove) {
|
|
+ if (driver && driver->remove)
|
|
driver->remove(pciedev);
|
|
- put_device(dev);
|
|
- }
|
|
+
|
|
+ put_device(dev);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
|
|
index 5557290b63dc15..cc56bf47c4a3f3 100644
|
|
--- a/drivers/pci/probe.c
|
|
+++ b/drivers/pci/probe.c
|
|
@@ -344,64 +344,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
|
|
}
|
|
}
|
|
|
|
-static void pci_read_bridge_windows(struct pci_dev *bridge)
|
|
+static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
|
|
+ bool log)
|
|
{
|
|
- u16 io;
|
|
- u32 pmem, tmp;
|
|
-
|
|
- pci_read_config_word(bridge, PCI_IO_BASE, &io);
|
|
- if (!io) {
|
|
- pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
|
|
- pci_read_config_word(bridge, PCI_IO_BASE, &io);
|
|
- pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
|
|
- }
|
|
- if (io)
|
|
- bridge->io_window = 1;
|
|
-
|
|
- /*
|
|
- * DECchip 21050 pass 2 errata: the bridge may miss an address
|
|
- * disconnect boundary by one PCI data phase. Workaround: do not
|
|
- * use prefetching on this device.
|
|
- */
|
|
- if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
|
|
- return;
|
|
-
|
|
- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
|
- if (!pmem) {
|
|
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
|
|
- 0xffe0fff0);
|
|
- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
|
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
|
|
- }
|
|
- if (!pmem)
|
|
- return;
|
|
-
|
|
- bridge->pref_window = 1;
|
|
-
|
|
- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
|
|
-
|
|
- /*
|
|
- * Bridge claims to have a 64-bit prefetchable memory
|
|
- * window; verify that the upper bits are actually
|
|
- * writable.
|
|
- */
|
|
- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem);
|
|
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
|
|
- 0xffffffff);
|
|
- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
|
|
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem);
|
|
- if (tmp)
|
|
- bridge->pref_64_window = 1;
|
|
- }
|
|
-}
|
|
-
|
|
-static void pci_read_bridge_io(struct pci_bus *child)
|
|
-{
|
|
- struct pci_dev *dev = child->self;
|
|
u8 io_base_lo, io_limit_lo;
|
|
unsigned long io_mask, io_granularity, base, limit;
|
|
struct pci_bus_region region;
|
|
- struct resource *res;
|
|
|
|
io_mask = PCI_IO_RANGE_MASK;
|
|
io_granularity = 0x1000;
|
|
@@ -411,7 +359,6 @@ static void pci_read_bridge_io(struct pci_bus *child)
|
|
io_granularity = 0x400;
|
|
}
|
|
|
|
- res = child->resource[0];
|
|
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
|
|
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
|
|
base = (io_base_lo & io_mask) << 8;
|
|
@@ -431,19 +378,18 @@ static void pci_read_bridge_io(struct pci_bus *child)
|
|
region.start = base;
|
|
region.end = limit + io_granularity - 1;
|
|
pcibios_bus_to_resource(dev->bus, res, ®ion);
|
|
- pci_info(dev, " bridge window %pR\n", res);
|
|
+ if (log)
|
|
+ pci_info(dev, " bridge window %pR\n", res);
|
|
}
|
|
}
|
|
|
|
-static void pci_read_bridge_mmio(struct pci_bus *child)
|
|
+static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res,
|
|
+ bool log)
|
|
{
|
|
- struct pci_dev *dev = child->self;
|
|
u16 mem_base_lo, mem_limit_lo;
|
|
unsigned long base, limit;
|
|
struct pci_bus_region region;
|
|
- struct resource *res;
|
|
|
|
- res = child->resource[1];
|
|
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
|
|
pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
|
|
base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
|
|
@@ -453,20 +399,19 @@ static void pci_read_bridge_mmio(struct pci_bus *child)
|
|
region.start = base;
|
|
region.end = limit + 0xfffff;
|
|
pcibios_bus_to_resource(dev->bus, res, ®ion);
|
|
- pci_info(dev, " bridge window %pR\n", res);
|
|
+ if (log)
|
|
+ pci_info(dev, " bridge window %pR\n", res);
|
|
}
|
|
}
|
|
|
|
-static void pci_read_bridge_mmio_pref(struct pci_bus *child)
|
|
+static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res,
|
|
+ bool log)
|
|
{
|
|
- struct pci_dev *dev = child->self;
|
|
u16 mem_base_lo, mem_limit_lo;
|
|
u64 base64, limit64;
|
|
pci_bus_addr_t base, limit;
|
|
struct pci_bus_region region;
|
|
- struct resource *res;
|
|
|
|
- res = child->resource[2];
|
|
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
|
|
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
|
|
base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
|
|
@@ -506,8 +451,75 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
|
|
region.start = base;
|
|
region.end = limit + 0xfffff;
|
|
pcibios_bus_to_resource(dev->bus, res, ®ion);
|
|
- pci_info(dev, " bridge window %pR\n", res);
|
|
+ if (log)
|
|
+ pci_info(dev, " bridge window %pR\n", res);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void pci_read_bridge_windows(struct pci_dev *bridge)
|
|
+{
|
|
+ u32 buses;
|
|
+ u16 io;
|
|
+ u32 pmem, tmp;
|
|
+ struct resource res;
|
|
+
|
|
+ pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses);
|
|
+ res.flags = IORESOURCE_BUS;
|
|
+ res.start = (buses >> 8) & 0xff;
|
|
+ res.end = (buses >> 16) & 0xff;
|
|
+ pci_info(bridge, "PCI bridge to %pR%s\n", &res,
|
|
+ bridge->transparent ? " (subtractive decode)" : "");
|
|
+
|
|
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
|
|
+ if (!io) {
|
|
+ pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
|
|
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
|
|
+ pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
|
|
+ }
|
|
+ if (io) {
|
|
+ bridge->io_window = 1;
|
|
+ pci_read_bridge_io(bridge, &res, true);
|
|
}
|
|
+
|
|
+ pci_read_bridge_mmio(bridge, &res, true);
|
|
+
|
|
+ /*
|
|
+ * DECchip 21050 pass 2 errata: the bridge may miss an address
|
|
+ * disconnect boundary by one PCI data phase. Workaround: do not
|
|
+ * use prefetching on this device.
|
|
+ */
|
|
+ if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
|
|
+ return;
|
|
+
|
|
+ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
|
+ if (!pmem) {
|
|
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
|
|
+ 0xffe0fff0);
|
|
+ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
|
|
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
|
|
+ }
|
|
+ if (!pmem)
|
|
+ return;
|
|
+
|
|
+ bridge->pref_window = 1;
|
|
+
|
|
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
|
|
+
|
|
+ /*
|
|
+ * Bridge claims to have a 64-bit prefetchable memory
|
|
+ * window; verify that the upper bits are actually
|
|
+ * writable.
|
|
+ */
|
|
+ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem);
|
|
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
|
|
+ 0xffffffff);
|
|
+ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
|
|
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem);
|
|
+ if (tmp)
|
|
+ bridge->pref_64_window = 1;
|
|
+ }
|
|
+
|
|
+ pci_read_bridge_mmio_pref(bridge, &res, true);
|
|
}
|
|
|
|
void pci_read_bridge_bases(struct pci_bus *child)
|
|
@@ -527,9 +539,13 @@ void pci_read_bridge_bases(struct pci_bus *child)
|
|
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
|
|
child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
|
|
|
|
- pci_read_bridge_io(child);
|
|
- pci_read_bridge_mmio(child);
|
|
- pci_read_bridge_mmio_pref(child);
|
|
+ pci_read_bridge_io(child->self,
|
|
+ child->resource[PCI_BUS_BRIDGE_IO_WINDOW], false);
|
|
+ pci_read_bridge_mmio(child->self,
|
|
+ child->resource[PCI_BUS_BRIDGE_MEM_WINDOW], false);
|
|
+ pci_read_bridge_mmio_pref(child->self,
|
|
+ child->resource[PCI_BUS_BRIDGE_PREF_MEM_WINDOW],
|
|
+ false);
|
|
|
|
if (dev->transparent) {
|
|
pci_bus_for_each_resource(child->parent, res) {
|
|
@@ -2101,7 +2117,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
|
|
u16 ctl;
|
|
int ret;
|
|
|
|
- if (!pci_is_pcie(dev))
|
|
+ /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */
|
|
+ if (!pci_is_pcie(dev) || dev->is_virtfn)
|
|
return 0;
|
|
|
|
ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
|
|
@@ -2287,6 +2304,37 @@ static void pci_configure_serr(struct pci_dev *dev)
|
|
}
|
|
}
|
|
|
|
+static void pci_configure_rcb(struct pci_dev *dev)
|
|
+{
|
|
+ struct pci_dev *rp;
|
|
+ u16 rp_lnkctl;
|
|
+
|
|
+ /*
|
|
+ * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports
|
|
+ * (where it is read-only), Endpoints, and Bridges. It may only be
|
|
+ * set for Endpoints and Bridges if it is set in the Root Port. For
|
|
+ * Endpoints, it is 'RsvdP' for Virtual Functions.
|
|
+ */
|
|
+ if (!pci_is_pcie(dev) ||
|
|
+ pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
|
+ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM ||
|
|
+ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
|
|
+ pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC ||
|
|
+ dev->is_virtfn)
|
|
+ return;
|
|
+
|
|
+ /* Root Port often not visible to virtualized guests */
|
|
+ rp = pcie_find_root_port(dev);
|
|
+ if (!rp)
|
|
+ return;
|
|
+
|
|
+ pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl);
|
|
+ pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
|
|
+ PCI_EXP_LNKCTL_RCB,
|
|
+ (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ?
|
|
+ PCI_EXP_LNKCTL_RCB : 0);
|
|
+}
|
|
+
|
|
static void pci_configure_device(struct pci_dev *dev)
|
|
{
|
|
pci_configure_mps(dev);
|
|
@@ -2295,6 +2343,7 @@ static void pci_configure_device(struct pci_dev *dev)
|
|
pci_configure_ltr(dev);
|
|
pci_configure_eetlp_prefix(dev);
|
|
pci_configure_serr(dev);
|
|
+ pci_configure_rcb(dev);
|
|
|
|
pci_acpi_program_hp_params(dev);
|
|
}
|
|
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
|
|
index 30a5f809ee798d..cab4cdbb31387e 100644
|
|
--- a/drivers/pci/quirks.c
|
|
+++ b/drivers/pci/quirks.c
|
|
@@ -3741,6 +3741,14 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
|
|
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
|
|
}
|
|
|
|
+/*
|
|
+ * After asserting Secondary Bus Reset to downstream devices via a GB10
|
|
+ * Root Port, the link may not retrain correctly.
|
|
+ * https://lore.kernel.org/r/20251113084441.2124737-1-Johnny-CC.Chang@mediatek.com
|
|
+ */
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x22CE, quirk_no_bus_reset);
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x22D0, quirk_no_bus_reset);
|
|
+
|
|
/*
|
|
* Some NVIDIA GPU devices do not work with bus reset, SBR needs to be
|
|
* prevented for those affected devices.
|
|
@@ -3784,6 +3792,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
|
|
*/
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0xb005, quirk_no_bus_reset);
|
|
|
|
+/*
|
|
+ * Reports from users making use of PCI device assignment with ASM1164
|
|
+ * controllers indicate an issue with bus reset where the device fails to
|
|
+ * retrain. The issue appears more common in configurations with multiple
|
|
+ * controllers. The device does indicate PM reset support (NoSoftRst-),
|
|
+ * therefore this still leaves a viable reset method.
|
|
+ * https://forum.proxmox.com/threads/problems-with-pcie-passthrough-with-two-identical-devices.149003/
|
|
+ */
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1164, quirk_no_bus_reset);
|
|
+
|
|
static void quirk_no_pm_reset(struct pci_dev *dev)
|
|
{
|
|
/*
|
|
@@ -5100,6 +5118,10 @@ static const struct pci_dev_acs_enabled {
|
|
{ PCI_VENDOR_ID_QCOM, 0x0401, pci_quirk_qcom_rp_acs },
|
|
/* QCOM SA8775P root port */
|
|
{ PCI_VENDOR_ID_QCOM, 0x0115, pci_quirk_qcom_rp_acs },
|
|
+ /* QCOM Hamoa root port */
|
|
+ { PCI_VENDOR_ID_QCOM, 0x0111, pci_quirk_qcom_rp_acs },
|
|
+ /* QCOM Glymur root port */
|
|
+ { PCI_VENDOR_ID_QCOM, 0x0120, pci_quirk_qcom_rp_acs },
|
|
/* HXT SD4800 root ports. The ACS design is same as QCOM QDF2xxx */
|
|
{ PCI_VENDOR_ID_HXT, 0x0401, pci_quirk_qcom_rp_acs },
|
|
/* Intel PCH root ports */
|
|
@@ -5573,6 +5595,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev)
|
|
pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL);
|
|
}
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags);
|
|
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags);
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags);
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags);
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags);
|
|
@@ -6180,6 +6203,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303,
|
|
pci_fixup_pericom_acs_store_forward);
|
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303,
|
|
pci_fixup_pericom_acs_store_forward);
|
|
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404,
|
|
+ pci_fixup_pericom_acs_store_forward);
|
|
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404,
|
|
+ pci_fixup_pericom_acs_store_forward);
|
|
|
|
static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
|
|
{
|
|
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
|
|
index 77aa37de59880f..9ca6fd74021005 100644
|
|
--- a/drivers/perf/arm-cmn.c
|
|
+++ b/drivers/perf/arm-cmn.c
|
|
@@ -205,6 +205,7 @@ enum cmn_model {
|
|
enum cmn_part {
|
|
PART_CMN600 = 0x434,
|
|
PART_CMN650 = 0x436,
|
|
+ PART_CMN600AE = 0x438,
|
|
PART_CMN700 = 0x43c,
|
|
PART_CI700 = 0x43a,
|
|
};
|
|
@@ -2167,6 +2168,9 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
|
|
reg = readq_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_01);
|
|
part = FIELD_GET(CMN_CFGM_PID0_PART_0, reg);
|
|
part |= FIELD_GET(CMN_CFGM_PID1_PART_1, reg) << 8;
|
|
+ /* 600AE is close enough that it's not really worth more complexity */
|
|
+ if (part == PART_CMN600AE)
|
|
+ part = PART_CMN600;
|
|
if (cmn->part && cmn->part != part)
|
|
dev_warn(cmn->dev,
|
|
"Firmware binding mismatch: expected part number 0x%x, found 0x%x\n",
|
|
@@ -2307,6 +2311,15 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
|
|
arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn);
|
|
dn->portid_bits = xp->portid_bits;
|
|
dn->deviceid_bits = xp->deviceid_bits;
|
|
+ /*
|
|
+ * Logical IDs are assigned from 0 per node type, so as
|
|
+ * soon as we see one bigger than expected, we can assume
|
|
+ * there are more than we can cope with.
|
|
+ */
|
|
+ if (dn->logid > CMN_MAX_NODES_PER_EVENT) {
|
|
+ dev_err(cmn->dev, "Node ID invalid for supported CMN versions: %d\n", dn->logid);
|
|
+ return -ENODEV;
|
|
+ }
|
|
|
|
switch (dn->type) {
|
|
case CMN_TYPE_DTC:
|
|
@@ -2355,7 +2368,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
|
|
break;
|
|
/* Something has gone horribly wrong */
|
|
default:
|
|
- dev_err(cmn->dev, "invalid device node type: 0x%x\n", dn->type);
|
|
+ dev_err(cmn->dev, "Device node type invalid for supported CMN versions: 0x%x\n", dn->type);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
@@ -2383,6 +2396,10 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
|
|
cmn->mesh_x = cmn->num_xps;
|
|
cmn->mesh_y = cmn->num_xps / cmn->mesh_x;
|
|
|
|
+ if (max(cmn->mesh_x, cmn->mesh_y) > CMN_MAX_DIMENSION) {
|
|
+ dev_err(cmn->dev, "Mesh size invalid for supported CMN versions: %dx%d\n", cmn->mesh_x, cmn->mesh_y);
|
|
+ return -ENODEV;
|
|
+ }
|
|
/* 1x1 config plays havoc with XP event encodings */
|
|
if (cmn->num_xps == 1)
|
|
dev_warn(cmn->dev, "1x1 config not fully supported, translate XP events manually\n");
|
|
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
|
|
index affa78376b6a80..5164078c06d258 100644
|
|
--- a/drivers/perf/arm_spe_pmu.c
|
|
+++ b/drivers/perf/arm_spe_pmu.c
|
|
@@ -102,6 +102,8 @@ struct arm_spe_pmu {
|
|
/* Keep track of our dynamic hotplug state */
|
|
static enum cpuhp_state arm_spe_pmu_online;
|
|
|
|
+static void arm_spe_pmu_stop(struct perf_event *event, int flags);
|
|
+
|
|
enum arm_spe_pmu_buf_fault_action {
|
|
SPE_PMU_BUF_FAULT_ACT_SPURIOUS,
|
|
SPE_PMU_BUF_FAULT_ACT_FATAL,
|
|
@@ -519,8 +521,8 @@ static u64 arm_spe_pmu_next_off(struct perf_output_handle *handle)
|
|
return limit;
|
|
}
|
|
|
|
-static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle,
|
|
- struct perf_event *event)
|
|
+static int arm_spe_perf_aux_output_begin(struct perf_output_handle *handle,
|
|
+ struct perf_event *event)
|
|
{
|
|
u64 base, limit;
|
|
struct arm_spe_pmu_buf *buf;
|
|
@@ -528,7 +530,6 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle,
|
|
/* Start a new aux session */
|
|
buf = perf_aux_output_begin(handle, event);
|
|
if (!buf) {
|
|
- event->hw.state |= PERF_HES_STOPPED;
|
|
/*
|
|
* We still need to clear the limit pointer, since the
|
|
* profiler might only be disabled by virtue of a fault.
|
|
@@ -548,6 +549,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle,
|
|
|
|
out_write_limit:
|
|
write_sysreg_s(limit, SYS_PMBLIMITR_EL1);
|
|
+ return (limit & PMBLIMITR_EL1_E) ? 0 : -EIO;
|
|
}
|
|
|
|
static void arm_spe_perf_aux_output_end(struct perf_output_handle *handle)
|
|
@@ -687,7 +689,10 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev)
|
|
* when we get to it.
|
|
*/
|
|
if (!(handle->aux_flags & PERF_AUX_FLAG_TRUNCATED)) {
|
|
- arm_spe_perf_aux_output_begin(handle, event);
|
|
+ if (arm_spe_perf_aux_output_begin(handle, event)) {
|
|
+ arm_spe_pmu_stop(event, PERF_EF_UPDATE);
|
|
+ break;
|
|
+ }
|
|
isb();
|
|
}
|
|
break;
|
|
@@ -782,9 +787,10 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags)
|
|
struct perf_output_handle *handle = this_cpu_ptr(spe_pmu->handle);
|
|
|
|
hwc->state = 0;
|
|
- arm_spe_perf_aux_output_begin(handle, event);
|
|
- if (hwc->state)
|
|
+ if (arm_spe_perf_aux_output_begin(handle, event)) {
|
|
+ arm_spe_pmu_stop(event, 0);
|
|
return;
|
|
+ }
|
|
|
|
reg = arm_spe_event_to_pmsfcr(event);
|
|
write_sysreg_s(reg, SYS_PMSFCR_EL1);
|
|
diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c
|
|
index c03df0f5288984..3e1a4f90061190 100644
|
|
--- a/drivers/perf/cxl_pmu.c
|
|
+++ b/drivers/perf/cxl_pmu.c
|
|
@@ -885,7 +885,7 @@ static int cxl_pmu_probe(struct device *dev)
|
|
if (!irq_name)
|
|
return -ENOMEM;
|
|
|
|
- rc = devm_request_irq(dev, irq, cxl_pmu_irq, IRQF_SHARED | IRQF_ONESHOT,
|
|
+ rc = devm_request_irq(dev, irq, cxl_pmu_irq, IRQF_SHARED | IRQF_NO_THREAD,
|
|
irq_name, info);
|
|
if (rc)
|
|
return rc;
|
|
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
|
|
index 043063699e0644..41194083e358ca 100644
|
|
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
|
|
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
|
|
@@ -411,6 +411,7 @@ static struct platform_driver imx8mq_usb_phy_driver = {
|
|
.driver = {
|
|
.name = "imx8mq-usb-phy",
|
|
.of_match_table = imx8mq_usb_phy_of_match,
|
|
+ .suppress_bind_attrs = true,
|
|
}
|
|
};
|
|
module_platform_driver(imx8mq_usb_phy_driver);
|
|
diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
|
|
index 4922a5f3327d51..30391d0d7d4b43 100644
|
|
--- a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
|
|
+++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c
|
|
@@ -326,7 +326,7 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1);
|
|
+ port->dr_mode = of_usb_get_dr_mode_by_phy(child, 0);
|
|
if ((port->dr_mode != USB_DR_MODE_HOST) &&
|
|
(port->dr_mode != USB_DR_MODE_PERIPHERAL)) {
|
|
dev_err(&pdev->dev,
|
|
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
|
|
index 5b5ddf7e5d0eb1..d7c89c310b3737 100644
|
|
--- a/drivers/pinctrl/pinctrl-equilibrium.c
|
|
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
|
|
@@ -850,6 +850,7 @@ static int pinbank_init(struct device_node *np,
|
|
|
|
bank->pin_base = spec.args[1];
|
|
bank->nr_pins = spec.args[2];
|
|
+ of_node_put(spec.np);
|
|
|
|
bank->aval_pinmap = readl(bank->membase + REG_AVAIL);
|
|
bank->id = id;
|
|
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
|
|
index 2ee0ee3b6ed14d..4aadafe2c50a52 100644
|
|
--- a/drivers/pinctrl/pinctrl-single.c
|
|
+++ b/drivers/pinctrl/pinctrl-single.c
|
|
@@ -1363,6 +1363,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
|
|
}
|
|
range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL);
|
|
if (!range) {
|
|
+ of_node_put(gpiospec.np);
|
|
ret = -ENOMEM;
|
|
break;
|
|
}
|
|
@@ -1372,6 +1373,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
|
|
mutex_lock(&pcs->mutex);
|
|
list_add_tail(&range->node, &pcs->gpiofuncs);
|
|
mutex_unlock(&pcs->mutex);
|
|
+ of_node_put(gpiospec.np);
|
|
}
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
|
|
index ddbc6317f2a745..422ef44b864233 100644
|
|
--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
|
|
+++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
|
|
@@ -88,7 +88,7 @@ static const char * const i2s1_ws_groups[] = { "gpio7" };
|
|
static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" };
|
|
static const char * const wsa_swr_clk_groups[] = { "gpio10" };
|
|
static const char * const wsa_swr_data_groups[] = { "gpio11" };
|
|
-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" };
|
|
+static const char * const i2s2_data_groups[] = { "gpio12", "gpio13" };
|
|
|
|
static const struct lpi_pingroup sm8250_groups[] = {
|
|
LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _),
|
|
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
|
|
index 376425bbd8ffb6..0f185b4b6f655c 100644
|
|
--- a/drivers/platform/chrome/cros_ec_lightbar.c
|
|
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
|
|
@@ -118,7 +118,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec,
|
|
param = (struct ec_params_lightbar *)msg->data;
|
|
param->cmd = LIGHTBAR_CMD_VERSION;
|
|
msg->outsize = sizeof(param->cmd);
|
|
- msg->result = sizeof(resp->version);
|
|
+ msg->insize = sizeof(resp->version);
|
|
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
|
if (ret < 0 && ret != -EINVAL) {
|
|
ret = 0;
|
|
diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
|
|
index 0eefdcf14d63f6..28080f48315dcf 100644
|
|
--- a/drivers/platform/chrome/cros_typec_switch.c
|
|
+++ b/drivers/platform/chrome/cros_typec_switch.c
|
|
@@ -230,20 +230,20 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata)
|
|
|
|
adev = to_acpi_device_node(fwnode);
|
|
if (!adev) {
|
|
- dev_err(fwnode->dev, "Couldn't get ACPI device handle\n");
|
|
+ dev_err(dev, "Couldn't get ACPI device handle for %pfwP\n", fwnode);
|
|
ret = -ENODEV;
|
|
goto err_switch;
|
|
}
|
|
|
|
ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index);
|
|
if (ACPI_FAILURE(ret)) {
|
|
- dev_err(fwnode->dev, "_ADR wasn't evaluated\n");
|
|
+ dev_err(dev, "_ADR wasn't evaluated for %pfwP\n", fwnode);
|
|
ret = -ENODATA;
|
|
goto err_switch;
|
|
}
|
|
|
|
if (index >= EC_USB_PD_MAX_PORTS) {
|
|
- dev_err(fwnode->dev, "Invalid port index number: %llu\n", index);
|
|
+ dev_err(dev, "%pfwP: Invalid port index number: %llu\n", fwnode, index);
|
|
ret = -EINVAL;
|
|
goto err_switch;
|
|
}
|
|
diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
|
|
index e229308d43e25c..819f11bae788b3 100644
|
|
--- a/drivers/power/reset/nvmem-reboot-mode.c
|
|
+++ b/drivers/power/reset/nvmem-reboot-mode.c
|
|
@@ -10,6 +10,7 @@
|
|
#include <linux/nvmem-consumer.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/reboot-mode.h>
|
|
+#include <linux/slab.h>
|
|
|
|
struct nvmem_reboot_mode {
|
|
struct reboot_mode_driver reboot;
|
|
@@ -19,12 +20,22 @@ struct nvmem_reboot_mode {
|
|
static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot,
|
|
unsigned int magic)
|
|
{
|
|
- int ret;
|
|
struct nvmem_reboot_mode *nvmem_rbm;
|
|
+ size_t buf_len;
|
|
+ void *buf;
|
|
+ int ret;
|
|
|
|
nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot);
|
|
|
|
- ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic));
|
|
+ buf = nvmem_cell_read(nvmem_rbm->cell, &buf_len);
|
|
+ if (IS_ERR(buf))
|
|
+ return PTR_ERR(buf);
|
|
+ kfree(buf);
|
|
+
|
|
+ if (buf_len > sizeof(magic))
|
|
+ return -EINVAL;
|
|
+
|
|
+ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, buf_len);
|
|
if (ret < 0)
|
|
dev_err(reboot->dev, "update reboot mode bits failed\n");
|
|
|
|
diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
|
|
index 308e68545d44d4..c6d513953b042b 100644
|
|
--- a/drivers/power/supply/ab8500_charger.c
|
|
+++ b/drivers/power/supply/ab8500_charger.c
|
|
@@ -3456,26 +3456,6 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
- /* Request interrupts */
|
|
- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
|
|
- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
|
|
- if (irq < 0)
|
|
- return irq;
|
|
-
|
|
- ret = devm_request_threaded_irq(dev,
|
|
- irq, NULL, ab8500_charger_irq[i].isr,
|
|
- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
|
- ab8500_charger_irq[i].name, di);
|
|
-
|
|
- if (ret != 0) {
|
|
- dev_err(dev, "failed to request %s IRQ %d: %d\n"
|
|
- , ab8500_charger_irq[i].name, irq, ret);
|
|
- return ret;
|
|
- }
|
|
- dev_dbg(dev, "Requested %s IRQ %d: %d\n",
|
|
- ab8500_charger_irq[i].name, irq, ret);
|
|
- }
|
|
-
|
|
/* initialize lock */
|
|
spin_lock_init(&di->usb_state.usb_lock);
|
|
mutex_init(&di->usb_ipt_crnt_lock);
|
|
@@ -3604,6 +3584,26 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|
return PTR_ERR(di->usb_chg.psy);
|
|
}
|
|
|
|
+ /* Request interrupts */
|
|
+ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
|
|
+ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
|
|
+ if (irq < 0)
|
|
+ return irq;
|
|
+
|
|
+ ret = devm_request_threaded_irq(dev,
|
|
+ irq, NULL, ab8500_charger_irq[i].isr,
|
|
+ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
|
+ ab8500_charger_irq[i].name, di);
|
|
+
|
|
+ if (ret != 0) {
|
|
+ dev_err(dev, "failed to request %s IRQ %d: %d\n"
|
|
+ , ab8500_charger_irq[i].name, irq, ret);
|
|
+ return ret;
|
|
+ }
|
|
+ dev_dbg(dev, "Requested %s IRQ %d: %d\n",
|
|
+ ab8500_charger_irq[i].name, irq, ret);
|
|
+ }
|
|
+
|
|
/*
|
|
* Check what battery we have, since we always have the USB
|
|
* psy, use that as a handle.
|
|
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
|
|
index e9b5f42837729f..e9cb06daecea90 100644
|
|
--- a/drivers/power/supply/act8945a_charger.c
|
|
+++ b/drivers/power/supply/act8945a_charger.c
|
|
@@ -597,14 +597,6 @@ static int act8945a_charger_probe(struct platform_device *pdev)
|
|
return irq ?: -ENXIO;
|
|
}
|
|
|
|
- ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
|
|
- IRQF_TRIGGER_FALLING, "act8945a_interrupt",
|
|
- charger);
|
|
- if (ret) {
|
|
- dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
charger->desc.name = "act8945a-charger";
|
|
charger->desc.get_property = act8945a_charger_get_property;
|
|
charger->desc.properties = act8945a_charger_props;
|
|
@@ -625,6 +617,14 @@ static int act8945a_charger_probe(struct platform_device *pdev)
|
|
return PTR_ERR(charger->psy);
|
|
}
|
|
|
|
+ ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
|
|
+ IRQF_TRIGGER_FALLING, "act8945a_interrupt",
|
|
+ charger);
|
|
+ if (ret) {
|
|
+ dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
platform_set_drvdata(pdev, charger);
|
|
|
|
INIT_WORK(&charger->work, act8945a_work);
|
|
diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c
|
|
index c8368dae69c712..2b0216d32d5f77 100644
|
|
--- a/drivers/power/supply/bq256xx_charger.c
|
|
+++ b/drivers/power/supply/bq256xx_charger.c
|
|
@@ -1746,6 +1746,12 @@ static int bq256xx_probe(struct i2c_client *client)
|
|
usb_register_notifier(bq->usb3_phy, &bq->usb_nb);
|
|
}
|
|
|
|
+ ret = bq256xx_power_supply_init(bq, &psy_cfg, dev);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "Failed to register power supply\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
if (client->irq) {
|
|
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
|
bq256xx_irq_handler_thread,
|
|
@@ -1758,12 +1764,6 @@ static int bq256xx_probe(struct i2c_client *client)
|
|
}
|
|
}
|
|
|
|
- ret = bq256xx_power_supply_init(bq, &psy_cfg, dev);
|
|
- if (ret) {
|
|
- dev_err(dev, "Failed to register power supply\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
ret = bq256xx_hw_init(bq);
|
|
if (ret) {
|
|
dev_err(dev, "Cannot initialize the chip.\n");
|
|
diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c
|
|
index d8411722266f51..fd00f9e5335487 100644
|
|
--- a/drivers/power/supply/bq25980_charger.c
|
|
+++ b/drivers/power/supply/bq25980_charger.c
|
|
@@ -1241,6 +1241,12 @@ static int bq25980_probe(struct i2c_client *client)
|
|
return ret;
|
|
}
|
|
|
|
+ ret = bq25980_power_supply_init(bq, dev);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "Failed to register power supply\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
if (client->irq) {
|
|
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
|
bq25980_irq_handler_thread,
|
|
@@ -1251,12 +1257,6 @@ static int bq25980_probe(struct i2c_client *client)
|
|
return ret;
|
|
}
|
|
|
|
- ret = bq25980_power_supply_init(bq, dev);
|
|
- if (ret) {
|
|
- dev_err(dev, "Failed to register power supply\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
ret = bq25980_hw_init(bq);
|
|
if (ret) {
|
|
dev_err(dev, "Cannot initialize the chip.\n");
|
|
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
|
|
index 1f06dee4b8b4e3..ff01d5d850f9a4 100644
|
|
--- a/drivers/power/supply/bq27xxx_battery.c
|
|
+++ b/drivers/power/supply/bq27xxx_battery.c
|
|
@@ -1162,7 +1162,7 @@ static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index,
|
|
return -EINVAL;
|
|
|
|
if (!di->bus.write)
|
|
- return -EPERM;
|
|
+ return -EOPNOTSUPP;
|
|
|
|
ret = di->bus.write(di, di->regs[reg_index], value, single);
|
|
if (ret < 0)
|
|
@@ -1181,7 +1181,7 @@ static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_ind
|
|
return -EINVAL;
|
|
|
|
if (!di->bus.read_bulk)
|
|
- return -EPERM;
|
|
+ return -EOPNOTSUPP;
|
|
|
|
ret = di->bus.read_bulk(di, di->regs[reg_index], data, len);
|
|
if (ret < 0)
|
|
@@ -1200,7 +1200,7 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
|
|
return -EINVAL;
|
|
|
|
if (!di->bus.write_bulk)
|
|
- return -EPERM;
|
|
+ return -EOPNOTSUPP;
|
|
|
|
ret = di->bus.write_bulk(di, di->regs[reg_index], data, len);
|
|
if (ret < 0)
|
|
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
|
|
index 5dd76c0ac98dae..d84b81e7736287 100644
|
|
--- a/drivers/power/supply/cpcap-battery.c
|
|
+++ b/drivers/power/supply/cpcap-battery.c
|
|
@@ -1122,10 +1122,6 @@ static int cpcap_battery_probe(struct platform_device *pdev)
|
|
|
|
platform_set_drvdata(pdev, ddata);
|
|
|
|
- error = cpcap_battery_init_interrupts(pdev, ddata);
|
|
- if (error)
|
|
- return error;
|
|
-
|
|
error = cpcap_battery_init_iio(ddata);
|
|
if (error)
|
|
return error;
|
|
@@ -1142,6 +1138,10 @@ static int cpcap_battery_probe(struct platform_device *pdev)
|
|
return error;
|
|
}
|
|
|
|
+ error = cpcap_battery_init_interrupts(pdev, ddata);
|
|
+ if (error)
|
|
+ return error;
|
|
+
|
|
atomic_set(&ddata->active, 1);
|
|
|
|
error = cpcap_battery_calibrate(ddata);
|
|
diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c
|
|
index a58d713d75ce81..4d204f0e18532f 100644
|
|
--- a/drivers/power/supply/goldfish_battery.c
|
|
+++ b/drivers/power/supply/goldfish_battery.c
|
|
@@ -224,12 +224,6 @@ static int goldfish_battery_probe(struct platform_device *pdev)
|
|
if (data->irq < 0)
|
|
return -ENODEV;
|
|
|
|
- ret = devm_request_irq(&pdev->dev, data->irq,
|
|
- goldfish_battery_interrupt,
|
|
- IRQF_SHARED, pdev->name, data);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
psy_cfg.drv_data = data;
|
|
|
|
data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);
|
|
@@ -245,6 +239,12 @@ static int goldfish_battery_probe(struct platform_device *pdev)
|
|
|
|
platform_set_drvdata(pdev, data);
|
|
|
|
+ ret = devm_request_irq(&pdev->dev, data->irq,
|
|
+ goldfish_battery_interrupt,
|
|
+ IRQF_SHARED, pdev->name, data);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
|
|
index 0c993780d3ef29..e5eade13281636 100644
|
|
--- a/drivers/power/supply/qcom_battmgr.c
|
|
+++ b/drivers/power/supply/qcom_battmgr.c
|
|
@@ -981,7 +981,8 @@ static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry
|
|
if ((!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN)) ||
|
|
(!strncmp(chemistry, "OOI", BATTMGR_CHEMISTRY_LEN)))
|
|
return POWER_SUPPLY_TECHNOLOGY_LION;
|
|
- if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN))
|
|
+ if (!strncmp(chemistry, "LIP", BATTMGR_CHEMISTRY_LEN) ||
|
|
+ !strncmp(chemistry, "LiP", BATTMGR_CHEMISTRY_LEN))
|
|
return POWER_SUPPLY_TECHNOLOGY_LIPO;
|
|
|
|
pr_err("Unknown battery technology '%s'\n", chemistry);
|
|
diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c
|
|
index e4dbacd50a437d..248dc2b5e1f7c7 100644
|
|
--- a/drivers/power/supply/rt9455_charger.c
|
|
+++ b/drivers/power/supply/rt9455_charger.c
|
|
@@ -1663,6 +1663,15 @@ static int rt9455_probe(struct i2c_client *client)
|
|
rt9455_charger_config.supplied_to = rt9455_charger_supplied_to;
|
|
rt9455_charger_config.num_supplicants =
|
|
ARRAY_SIZE(rt9455_charger_supplied_to);
|
|
+
|
|
+ info->charger = devm_power_supply_register(dev, &rt9455_charger_desc,
|
|
+ &rt9455_charger_config);
|
|
+ if (IS_ERR(info->charger)) {
|
|
+ dev_err(dev, "Failed to register charger\n");
|
|
+ ret = PTR_ERR(info->charger);
|
|
+ goto put_usb_notifier;
|
|
+ }
|
|
+
|
|
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
|
rt9455_irq_handler_thread,
|
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
@@ -1678,14 +1687,6 @@ static int rt9455_probe(struct i2c_client *client)
|
|
goto put_usb_notifier;
|
|
}
|
|
|
|
- info->charger = devm_power_supply_register(dev, &rt9455_charger_desc,
|
|
- &rt9455_charger_config);
|
|
- if (IS_ERR(info->charger)) {
|
|
- dev_err(dev, "Failed to register charger\n");
|
|
- ret = PTR_ERR(info->charger);
|
|
- goto put_usb_notifier;
|
|
- }
|
|
-
|
|
return 0;
|
|
|
|
put_usb_notifier:
|
|
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
|
|
index cdfc8466d129b7..f30a542d4716ce 100644
|
|
--- a/drivers/power/supply/sbs-battery.c
|
|
+++ b/drivers/power/supply/sbs-battery.c
|
|
@@ -1173,24 +1173,6 @@ static int sbs_probe(struct i2c_client *client)
|
|
|
|
i2c_set_clientdata(client, chip);
|
|
|
|
- if (!chip->gpio_detect)
|
|
- goto skip_gpio;
|
|
-
|
|
- irq = gpiod_to_irq(chip->gpio_detect);
|
|
- if (irq <= 0) {
|
|
- dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
|
|
- goto skip_gpio;
|
|
- }
|
|
-
|
|
- rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
|
|
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
- dev_name(&client->dev), chip);
|
|
- if (rc) {
|
|
- dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
|
|
- goto skip_gpio;
|
|
- }
|
|
-
|
|
-skip_gpio:
|
|
/*
|
|
* Before we register, we might need to make sure we can actually talk
|
|
* to the battery.
|
|
@@ -1216,6 +1198,24 @@ skip_gpio:
|
|
return dev_err_probe(&client->dev, PTR_ERR(chip->power_supply),
|
|
"Failed to register power supply\n");
|
|
|
|
+ if (!chip->gpio_detect)
|
|
+ goto out;
|
|
+
|
|
+ irq = gpiod_to_irq(chip->gpio_detect);
|
|
+ if (irq <= 0) {
|
|
+ dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
|
|
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
+ dev_name(&client->dev), chip);
|
|
+ if (rc) {
|
|
+ dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
dev_info(&client->dev,
|
|
"%s: battery gas gauge device registered\n", client->name);
|
|
|
|
diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
|
|
index f4b190adb33594..d3e5c2f7762a6f 100644
|
|
--- a/drivers/power/supply/wm97xx_battery.c
|
|
+++ b/drivers/power/supply/wm97xx_battery.c
|
|
@@ -178,12 +178,6 @@ static int wm97xx_bat_probe(struct platform_device *dev)
|
|
"failed to get charge GPIO\n");
|
|
if (charge_gpiod) {
|
|
gpiod_set_consumer_name(charge_gpiod, "BATT CHRG");
|
|
- ret = request_irq(gpiod_to_irq(charge_gpiod),
|
|
- wm97xx_chrg_irq, 0,
|
|
- "AC Detect", dev);
|
|
- if (ret)
|
|
- return dev_err_probe(&dev->dev, ret,
|
|
- "failed to request GPIO irq\n");
|
|
props++; /* POWER_SUPPLY_PROP_STATUS */
|
|
}
|
|
|
|
@@ -199,10 +193,8 @@ static int wm97xx_bat_probe(struct platform_device *dev)
|
|
props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
|
|
|
|
prop = kcalloc(props, sizeof(*prop), GFP_KERNEL);
|
|
- if (!prop) {
|
|
- ret = -ENOMEM;
|
|
- goto err3;
|
|
- }
|
|
+ if (!prop)
|
|
+ return -ENOMEM;
|
|
|
|
prop[i++] = POWER_SUPPLY_PROP_PRESENT;
|
|
if (charge_gpiod)
|
|
@@ -236,15 +228,27 @@ static int wm97xx_bat_probe(struct platform_device *dev)
|
|
schedule_work(&bat_work);
|
|
} else {
|
|
ret = PTR_ERR(bat_psy);
|
|
- goto err4;
|
|
+ goto free;
|
|
+ }
|
|
+
|
|
+ if (charge_gpiod) {
|
|
+ ret = request_irq(gpiod_to_irq(charge_gpiod), wm97xx_chrg_irq,
|
|
+ 0, "AC Detect", dev);
|
|
+ if (ret) {
|
|
+ dev_err_probe(&dev->dev, ret,
|
|
+ "failed to request GPIO irq\n");
|
|
+ goto unregister;
|
|
+ }
|
|
}
|
|
|
|
return 0;
|
|
-err4:
|
|
+
|
|
+unregister:
|
|
+ power_supply_unregister(bat_psy);
|
|
+
|
|
+free:
|
|
kfree(prop);
|
|
-err3:
|
|
- if (charge_gpiod)
|
|
- free_irq(gpiod_to_irq(charge_gpiod), dev);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/powercap/intel_rapl_tpmi.c b/drivers/powercap/intel_rapl_tpmi.c
|
|
index 1c48dba0ba96af..6958c2f0b76606 100644
|
|
--- a/drivers/powercap/intel_rapl_tpmi.c
|
|
+++ b/drivers/powercap/intel_rapl_tpmi.c
|
|
@@ -156,7 +156,7 @@ static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset)
|
|
tpmi_domain_flags = tpmi_domain_header >> 32 & 0xffff;
|
|
|
|
if (tpmi_domain_version == TPMI_VERSION_INVALID) {
|
|
- pr_warn(FW_BUG "Invalid version\n");
|
|
+ pr_debug("Invalid version, other instances may be valid\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
|
|
index c12941f71e2cba..dcd6619a4b0277 100644
|
|
--- a/drivers/rapidio/rio-scan.c
|
|
+++ b/drivers/rapidio/rio-scan.c
|
|
@@ -854,7 +854,8 @@ static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport,
|
|
|
|
if (idtab == NULL) {
|
|
pr_err("RIO: failed to allocate destID table\n");
|
|
- rio_free_net(net);
|
|
+ kfree(net);
|
|
+ mport->net = NULL;
|
|
net = NULL;
|
|
} else {
|
|
net->enum_data = idtab;
|
|
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
|
|
index 23cdf220ca7db5..a1a26743430c0c 100644
|
|
--- a/drivers/regulator/core.c
|
|
+++ b/drivers/regulator/core.c
|
|
@@ -1466,6 +1466,33 @@ static int set_machine_constraints(struct regulator_dev *rdev)
|
|
int ret = 0;
|
|
const struct regulator_ops *ops = rdev->desc->ops;
|
|
|
|
+ /*
|
|
+ * If there is no mechanism for controlling the regulator then
|
|
+ * flag it as always_on so we don't end up duplicating checks
|
|
+ * for this so much. Note that we could control the state of
|
|
+ * a supply to control the output on a regulator that has no
|
|
+ * direct control.
|
|
+ */
|
|
+ if (!rdev->ena_pin && !ops->enable) {
|
|
+ if (rdev->supply_name && !rdev->supply)
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ if (rdev->supply)
|
|
+ rdev->constraints->always_on =
|
|
+ rdev->supply->rdev->constraints->always_on;
|
|
+ else
|
|
+ rdev->constraints->always_on = true;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * If we want to enable this regulator, make sure that we know the
|
|
+ * supplying regulator.
|
|
+ */
|
|
+ if (rdev->constraints->always_on || rdev->constraints->boot_on) {
|
|
+ if (rdev->supply_name && !rdev->supply)
|
|
+ return -EPROBE_DEFER;
|
|
+ }
|
|
+
|
|
ret = machine_constraints_voltage(rdev, rdev->constraints);
|
|
if (ret != 0)
|
|
return ret;
|
|
@@ -1631,37 +1658,15 @@ static int set_machine_constraints(struct regulator_dev *rdev)
|
|
}
|
|
}
|
|
|
|
- /*
|
|
- * If there is no mechanism for controlling the regulator then
|
|
- * flag it as always_on so we don't end up duplicating checks
|
|
- * for this so much. Note that we could control the state of
|
|
- * a supply to control the output on a regulator that has no
|
|
- * direct control.
|
|
- */
|
|
- if (!rdev->ena_pin && !ops->enable) {
|
|
- if (rdev->supply_name && !rdev->supply)
|
|
- return -EPROBE_DEFER;
|
|
-
|
|
- if (rdev->supply)
|
|
- rdev->constraints->always_on =
|
|
- rdev->supply->rdev->constraints->always_on;
|
|
- else
|
|
- rdev->constraints->always_on = true;
|
|
- }
|
|
-
|
|
/* If the constraints say the regulator should be on at this point
|
|
* and we have control then make sure it is enabled.
|
|
*/
|
|
if (rdev->constraints->always_on || rdev->constraints->boot_on) {
|
|
bool supply_enabled = false;
|
|
|
|
- /* If we want to enable this regulator, make sure that we know
|
|
- * the supplying regulator.
|
|
- */
|
|
- if (rdev->supply_name && !rdev->supply)
|
|
- return -EPROBE_DEFER;
|
|
-
|
|
- /* If supplying regulator has already been enabled,
|
|
+ /* We have ensured a potential supply has been resolved above.
|
|
+ *
|
|
+ * If supplying regulator has already been enabled,
|
|
* it's not intended to have use_count increment
|
|
* when rdev is only boot-on.
|
|
*/
|
|
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
|
|
index 8fcda9b7454597..960fbd4b1d9b97 100644
|
|
--- a/drivers/remoteproc/imx_dsp_rproc.c
|
|
+++ b/drivers/remoteproc/imx_dsp_rproc.c
|
|
@@ -1250,6 +1250,15 @@ static int imx_dsp_suspend(struct device *dev)
|
|
if (rproc->state != RPROC_RUNNING)
|
|
goto out;
|
|
|
|
+ /*
|
|
+ * No channel available for sending messages;
|
|
+ * indicates no mailboxes present, so trigger PM runtime suspend
|
|
+ */
|
|
+ if (!priv->tx_ch) {
|
|
+ dev_dbg(dev, "No initialized mbox tx channel, suspend directly.\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
reinit_completion(&priv->pm_comp);
|
|
|
|
/* Tell DSP that suspend is happening */
|
|
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
|
|
index 251f9840d85bd8..fda0e644f3106a 100644
|
|
--- a/drivers/remoteproc/imx_rproc.c
|
|
+++ b/drivers/remoteproc/imx_rproc.c
|
|
@@ -674,6 +674,10 @@ imx_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *
|
|
{
|
|
struct imx_rproc *priv = rproc->priv;
|
|
|
|
+ /* No resource table in the firmware */
|
|
+ if (!rproc->table_ptr)
|
|
+ return NULL;
|
|
+
|
|
if (priv->rsc_table)
|
|
return (struct resource_table *)priv->rsc_table;
|
|
|
|
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
|
|
index c4c535b011812d..ecbece2b5ce7ca 100644
|
|
--- a/drivers/remoteproc/mtk_scp.c
|
|
+++ b/drivers/remoteproc/mtk_scp.c
|
|
@@ -225,7 +225,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv)
|
|
struct mtk_scp *scp = priv;
|
|
int ret;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(scp->dev, "failed to enable clocks\n");
|
|
return IRQ_NONE;
|
|
@@ -233,7 +233,7 @@ static irqreturn_t scp_irq_handler(int irq, void *priv)
|
|
|
|
scp->data->scp_irq_handler(scp);
|
|
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -467,7 +467,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw)
|
|
struct device *dev = scp->dev;
|
|
int ret;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(dev, "failed to enable clocks\n");
|
|
return ret;
|
|
@@ -482,7 +482,7 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw)
|
|
|
|
ret = scp_elf_load_segments(rproc, fw);
|
|
leave:
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
|
|
return ret;
|
|
}
|
|
@@ -493,14 +493,14 @@ static int scp_parse_fw(struct rproc *rproc, const struct firmware *fw)
|
|
struct device *dev = scp->dev;
|
|
int ret;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(dev, "failed to enable clocks\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = scp_ipi_init(scp, fw);
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
return ret;
|
|
}
|
|
|
|
@@ -511,7 +511,7 @@ static int scp_start(struct rproc *rproc)
|
|
struct scp_run *run = &scp->run;
|
|
int ret;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(dev, "failed to enable clocks\n");
|
|
return ret;
|
|
@@ -536,14 +536,14 @@ static int scp_start(struct rproc *rproc)
|
|
goto stop;
|
|
}
|
|
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver);
|
|
|
|
return 0;
|
|
|
|
stop:
|
|
scp->data->scp_reset_assert(scp);
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
return ret;
|
|
}
|
|
|
|
@@ -638,7 +638,7 @@ static int scp_stop(struct rproc *rproc)
|
|
struct mtk_scp *scp = rproc->priv;
|
|
int ret;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(scp->dev, "failed to enable clocks\n");
|
|
return ret;
|
|
@@ -646,12 +646,29 @@ static int scp_stop(struct rproc *rproc)
|
|
|
|
scp->data->scp_reset_assert(scp);
|
|
scp->data->scp_stop(scp);
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
+static int scp_prepare(struct rproc *rproc)
|
|
+{
|
|
+ struct mtk_scp *scp = rproc->priv;
|
|
+
|
|
+ return clk_prepare(scp->clk);
|
|
+}
|
|
+
|
|
+static int scp_unprepare(struct rproc *rproc)
|
|
+{
|
|
+ struct mtk_scp *scp = rproc->priv;
|
|
+
|
|
+ clk_unprepare(scp->clk);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct rproc_ops scp_ops = {
|
|
+ .prepare = scp_prepare,
|
|
+ .unprepare = scp_unprepare,
|
|
.start = scp_start,
|
|
.stop = scp_stop,
|
|
.load = scp_load,
|
|
diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c
|
|
index 9c7c17b9d181f1..0c3ed37bd08210 100644
|
|
--- a/drivers/remoteproc/mtk_scp_ipi.c
|
|
+++ b/drivers/remoteproc/mtk_scp_ipi.c
|
|
@@ -168,7 +168,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
|
|
WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
|
|
return -EINVAL;
|
|
|
|
- ret = clk_prepare_enable(scp->clk);
|
|
+ ret = clk_enable(scp->clk);
|
|
if (ret) {
|
|
dev_err(scp->dev, "failed to enable clock\n");
|
|
return ret;
|
|
@@ -208,7 +208,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
|
|
|
|
unlock_mutex:
|
|
mutex_unlock(&scp->send_lock);
|
|
- clk_disable_unprepare(scp->clk);
|
|
+ clk_disable(scp->clk);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
|
|
index 32b550c91d9f1c..662a674314045c 100644
|
|
--- a/drivers/rpmsg/rpmsg_core.c
|
|
+++ b/drivers/rpmsg/rpmsg_core.c
|
|
@@ -413,50 +413,38 @@ field##_show(struct device *dev, \
|
|
} \
|
|
static DEVICE_ATTR_RO(field);
|
|
|
|
-#define rpmsg_string_attr(field, member) \
|
|
-static ssize_t \
|
|
-field##_store(struct device *dev, struct device_attribute *attr, \
|
|
- const char *buf, size_t sz) \
|
|
-{ \
|
|
- struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
|
|
- const char *old; \
|
|
- char *new; \
|
|
- \
|
|
- new = kstrndup(buf, sz, GFP_KERNEL); \
|
|
- if (!new) \
|
|
- return -ENOMEM; \
|
|
- new[strcspn(new, "\n")] = '\0'; \
|
|
- \
|
|
- device_lock(dev); \
|
|
- old = rpdev->member; \
|
|
- if (strlen(new)) { \
|
|
- rpdev->member = new; \
|
|
- } else { \
|
|
- kfree(new); \
|
|
- rpdev->member = NULL; \
|
|
- } \
|
|
- device_unlock(dev); \
|
|
- \
|
|
- kfree(old); \
|
|
- \
|
|
- return sz; \
|
|
-} \
|
|
-static ssize_t \
|
|
-field##_show(struct device *dev, \
|
|
- struct device_attribute *attr, char *buf) \
|
|
-{ \
|
|
- struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
|
|
- \
|
|
- return sprintf(buf, "%s\n", rpdev->member); \
|
|
-} \
|
|
-static DEVICE_ATTR_RW(field)
|
|
-
|
|
/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
|
|
rpmsg_show_attr(name, id.name, "%s\n");
|
|
rpmsg_show_attr(src, src, "0x%x\n");
|
|
rpmsg_show_attr(dst, dst, "0x%x\n");
|
|
rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
|
|
-rpmsg_string_attr(driver_override, driver_override);
|
|
+
|
|
+static ssize_t driver_override_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
|
|
+ int ret;
|
|
+
|
|
+ ret = driver_set_override(dev, &rpdev->driver_override, buf, count);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static ssize_t driver_override_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
|
|
+ ssize_t len;
|
|
+
|
|
+ device_lock(dev);
|
|
+ len = sysfs_emit(buf, "%s\n", rpdev->driver_override);
|
|
+ device_unlock(dev);
|
|
+ return len;
|
|
+}
|
|
+static DEVICE_ATTR_RW(driver_override);
|
|
|
|
static ssize_t modalias_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
|
|
index 93baffe110c00a..13de2cb07f75d3 100644
|
|
--- a/drivers/rtc/interface.c
|
|
+++ b/drivers/rtc/interface.c
|
|
@@ -457,7 +457,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
* are in, we can return -ETIME to signal that the timer has already
|
|
* expired, which is true in both cases.
|
|
*/
|
|
- if ((scheduled - now) <= 1) {
|
|
+ if (!err && (scheduled - now) <= 1) {
|
|
err = __rtc_read_time(rtc, &tm);
|
|
if (err)
|
|
return err;
|
|
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
|
|
index b6f96c10196ae3..f49af7d963fbd7 100644
|
|
--- a/drivers/rtc/rtc-zynqmp.c
|
|
+++ b/drivers/rtc/rtc-zynqmp.c
|
|
@@ -330,7 +330,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
|
&xrtcdev->freq);
|
|
if (ret)
|
|
xrtcdev->freq = RTC_CALIB_DEF;
|
|
+ } else {
|
|
+ xrtcdev->freq--;
|
|
}
|
|
+
|
|
ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
|
|
if (!ret)
|
|
writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));
|
|
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
|
|
index 3ff46fc694f85e..e50592c3d30ca0 100644
|
|
--- a/drivers/s390/cio/css.c
|
|
+++ b/drivers/s390/cio/css.c
|
|
@@ -247,7 +247,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid,
|
|
err_lock:
|
|
kfree(sch->lock);
|
|
err:
|
|
- kfree(sch);
|
|
+ put_device(&sch->dev);
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
|
|
index 72ceaf650b0d56..dfe97e25635edf 100644
|
|
--- a/drivers/scsi/BusLogic.c
|
|
+++ b/drivers/scsi/BusLogic.c
|
|
@@ -919,7 +919,8 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter)
|
|
a particular probe order.
|
|
*/
|
|
|
|
-static void __init blogic_init_probeinfo_list(struct blogic_adapter *adapter)
|
|
+static noinline_for_stack void __init
|
|
+blogic_init_probeinfo_list(struct blogic_adapter *adapter)
|
|
{
|
|
/*
|
|
If a PCI BIOS is present, interrogate it for MultiMaster and
|
|
@@ -1689,7 +1690,8 @@ common:
|
|
blogic_reportconfig reports the configuration of Host Adapter.
|
|
*/
|
|
|
|
-static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
|
+static noinline_for_stack bool __init
|
|
+blogic_reportconfig(struct blogic_adapter *adapter)
|
|
{
|
|
unsigned short alltgt_mask = (1 << adapter->maxdev) - 1;
|
|
unsigned short sync_ok, fast_ok;
|
|
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
|
|
index 05e1a63e00c3a1..ed40ae6b9800c0 100644
|
|
--- a/drivers/scsi/csiostor/csio_scsi.c
|
|
+++ b/drivers/scsi/csiostor/csio_scsi.c
|
|
@@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd)
|
|
struct csio_scsi_level_data sld;
|
|
|
|
if (!rn)
|
|
- goto fail;
|
|
+ goto fail_ret;
|
|
|
|
csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n",
|
|
cmnd->device->lun, rn->flowid, rn->scsi_id);
|
|
@@ -2220,6 +2220,7 @@ fail_ret_ioreq:
|
|
csio_put_scsi_ioreq_lock(hw, scsim, ioreq);
|
|
fail:
|
|
CSIO_INC_STATS(rn, n_lun_rst_fail);
|
|
+fail_ret:
|
|
return FAILED;
|
|
}
|
|
|
|
diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c
|
|
index 49fd2cfed70c70..37aba56e072177 100644
|
|
--- a/drivers/scsi/elx/efct/efct_driver.c
|
|
+++ b/drivers/scsi/elx/efct/efct_driver.c
|
|
@@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
-static irqreturn_t
|
|
-efct_intr_msix(int irq, void *handle)
|
|
-{
|
|
- return IRQ_WAKE_THREAD;
|
|
-}
|
|
-
|
|
static int
|
|
efct_setup_msix(struct efct *efct, u32 num_intrs)
|
|
{
|
|
@@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs)
|
|
intr_ctx->index = i;
|
|
|
|
rc = request_threaded_irq(pci_irq_vector(efct->pci, i),
|
|
- efct_intr_msix, efct_intr_thread, 0,
|
|
+ NULL, efct_intr_thread, IRQF_ONESHOT,
|
|
EFCT_DRIVER_NAME, intr_ctx);
|
|
if (rc) {
|
|
dev_err(&efct->pci->dev,
|
|
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
|
|
index 0cdeb7aa550203..dc194c76f38b7c 100644
|
|
--- a/drivers/scsi/smartpqi/smartpqi_init.c
|
|
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
|
|
@@ -1240,7 +1240,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b
|
|
dev_err(&ctrl_info->pci_dev->dev,
|
|
"RPL returned unsupported data format %u\n",
|
|
rpl_response_format);
|
|
- return -EINVAL;
|
|
+ rc = -EINVAL;
|
|
+ goto out_free_rpl_list;
|
|
} else {
|
|
dev_warn(&ctrl_info->pci_dev->dev,
|
|
"RPL returned extended format 2 instead of 4\n");
|
|
@@ -1252,8 +1253,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b
|
|
|
|
rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries,
|
|
num_physicals), GFP_KERNEL);
|
|
- if (!rpl_16byte_wwid_list)
|
|
- return -ENOMEM;
|
|
+ if (!rpl_16byte_wwid_list) {
|
|
+ rc = -ENOMEM;
|
|
+ goto out_free_rpl_list;
|
|
+ }
|
|
|
|
put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid),
|
|
&rpl_16byte_wwid_list->header.list_length);
|
|
@@ -1274,6 +1277,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b
|
|
*buffer = rpl_16byte_wwid_list;
|
|
|
|
return 0;
|
|
+
|
|
+out_free_rpl_list:
|
|
+ kfree(rpl_list);
|
|
+ return rc;
|
|
}
|
|
|
|
static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer)
|
|
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
|
|
index 3a2f97cd527200..37d21e3de69423 100644
|
|
--- a/drivers/soc/mediatek/mtk-svs.c
|
|
+++ b/drivers/soc/mediatek/mtk-svs.c
|
|
@@ -7,6 +7,7 @@
|
|
#include <linux/bits.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/completion.h>
|
|
+#include <linux/cleanup.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpuidle.h>
|
|
#include <linux/debugfs.h>
|
|
@@ -717,7 +718,7 @@ static ssize_t svs_enable_debug_write(struct file *filp,
|
|
struct svs_bank *svsb = file_inode(filp)->i_private;
|
|
struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
|
|
int enabled, ret;
|
|
- char *buf = NULL;
|
|
+ char *buf __free(kfree) = NULL;
|
|
|
|
if (count >= PAGE_SIZE)
|
|
return -EINVAL;
|
|
@@ -735,8 +736,6 @@ static ssize_t svs_enable_debug_write(struct file *filp,
|
|
svsb->mode_support = SVSB_MODE_ALL_DISABLE;
|
|
}
|
|
|
|
- kfree(buf);
|
|
-
|
|
return count;
|
|
}
|
|
|
|
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
|
|
index ab2418d2fe43a9..0c54a9525baf19 100644
|
|
--- a/drivers/soc/qcom/cmd-db.c
|
|
+++ b/drivers/soc/qcom/cmd-db.c
|
|
@@ -354,15 +354,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
|
|
return -EINVAL;
|
|
}
|
|
|
|
- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC);
|
|
- if (!cmd_db_header) {
|
|
- ret = -ENOMEM;
|
|
+ cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC);
|
|
+ if (IS_ERR(cmd_db_header)) {
|
|
+ ret = PTR_ERR(cmd_db_header);
|
|
cmd_db_header = NULL;
|
|
return ret;
|
|
}
|
|
|
|
if (!cmd_db_magic_matches(cmd_db_header)) {
|
|
dev_err(&pdev->dev, "Invalid Command DB Magic\n");
|
|
+ cmd_db_header = NULL;
|
|
return -EINVAL;
|
|
}
|
|
|
|
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
|
|
index 5217ff0a434f55..d039c660d04fbe 100644
|
|
--- a/drivers/soc/qcom/smem.c
|
|
+++ b/drivers/soc/qcom/smem.c
|
|
@@ -1189,7 +1189,9 @@ static int qcom_smem_probe(struct platform_device *pdev)
|
|
smem->item_count = qcom_smem_get_item_count(smem);
|
|
break;
|
|
case SMEM_GLOBAL_HEAP_VERSION:
|
|
- qcom_smem_map_global(smem, size);
|
|
+ ret = qcom_smem_map_global(smem, size);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
smem->item_count = SMEM_ITEM_COUNT;
|
|
break;
|
|
default:
|
|
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
|
|
index 7a3bdef5a7c0da..4724d4759dd07e 100644
|
|
--- a/drivers/soc/ti/k3-socinfo.c
|
|
+++ b/drivers/soc/ti/k3-socinfo.c
|
|
@@ -87,7 +87,7 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
|
|
if (IS_ERR(base))
|
|
return PTR_ERR(base);
|
|
|
|
- regmap = regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg);
|
|
+ regmap = devm_regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg);
|
|
if (IS_ERR(regmap))
|
|
return PTR_ERR(regmap);
|
|
|
|
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
|
|
index f49f8492dde512..e01aec084e39b7 100644
|
|
--- a/drivers/soc/ti/pruss.c
|
|
+++ b/drivers/soc/ti/pruss.c
|
|
@@ -366,12 +366,10 @@ static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
|
|
|
|
ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
|
|
clk_mux_np);
|
|
- if (ret) {
|
|
+ if (ret)
|
|
dev_err(dev, "failed to add clkmux free action %d", ret);
|
|
- goto put_clk_mux_np;
|
|
- }
|
|
|
|
- return 0;
|
|
+ return ret;
|
|
|
|
put_clk_mux_np:
|
|
of_node_put(clk_mux_np);
|
|
diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c
|
|
index 91ab97a456fa9f..5854218e1a274e 100644
|
|
--- a/drivers/soundwire/dmi-quirks.c
|
|
+++ b/drivers/soundwire/dmi-quirks.c
|
|
@@ -122,6 +122,17 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
|
|
},
|
|
.driver_data = (void *)intel_tgl_bios,
|
|
},
|
|
+ {
|
|
+ /*
|
|
+ * quirk used for Avell B.ON (OEM rebrand of NUC15 'Bishop County'
|
|
+ * LAPBC510 and LAPBC710)
|
|
+ */
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Avell High Performance"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "B.ON"),
|
|
+ },
|
|
+ .driver_data = (void *)intel_tgl_bios,
|
|
+ },
|
|
{
|
|
/* quirk used for NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
|
|
.matches = {
|
|
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
|
|
index 6a3b41dbfa701f..37a20652fd2e75 100644
|
|
--- a/drivers/spi/spi-geni-qcom.c
|
|
+++ b/drivers/spi/spi-geni-qcom.c
|
|
@@ -548,10 +548,10 @@ static u32 get_xfer_len_in_words(struct spi_transfer *xfer,
|
|
{
|
|
u32 len;
|
|
|
|
- if (!(mas->cur_bits_per_word % MIN_WORD_LEN))
|
|
- len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word;
|
|
+ if (!(xfer->bits_per_word % MIN_WORD_LEN))
|
|
+ len = xfer->len * BITS_PER_BYTE / xfer->bits_per_word;
|
|
else
|
|
- len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1);
|
|
+ len = xfer->len / (xfer->bits_per_word / BITS_PER_BYTE + 1);
|
|
len &= TRANS_LEN_MSK;
|
|
|
|
return len;
|
|
@@ -571,7 +571,7 @@ static bool geni_can_dma(struct spi_controller *ctlr,
|
|
return true;
|
|
|
|
len = get_xfer_len_in_words(xfer, mas);
|
|
- fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
|
|
+ fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / xfer->bits_per_word;
|
|
|
|
if (len > fifo_size)
|
|
return true;
|
|
@@ -710,6 +710,12 @@ static int spi_geni_init(struct spi_geni_master *mas)
|
|
case 0:
|
|
mas->cur_xfer_mode = GENI_SE_FIFO;
|
|
geni_se_select_mode(se, GENI_SE_FIFO);
|
|
+ /* setup_fifo_params assumes that these registers start with a zero value */
|
|
+ writel(0, se->base + SE_SPI_LOOPBACK);
|
|
+ writel(0, se->base + SE_SPI_DEMUX_SEL);
|
|
+ writel(0, se->base + SE_SPI_CPHA);
|
|
+ writel(0, se->base + SE_SPI_CPOL);
|
|
+ writel(0, se->base + SE_SPI_DEMUX_OUTPUT_INV);
|
|
ret = 0;
|
|
break;
|
|
}
|
|
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
|
|
index c581aa5fbf7cf7..932992b06022b0 100644
|
|
--- a/drivers/spi/spi-mem.c
|
|
+++ b/drivers/spi/spi-mem.c
|
|
@@ -175,8 +175,19 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
|
|
if (op->data.swap16 && !spi_mem_controller_is_capable(ctlr, swap16))
|
|
return false;
|
|
|
|
- if (op->cmd.nbytes != 2)
|
|
- return false;
|
|
+ /* Extra 8D-8D-8D limitations */
|
|
+ if (op->cmd.dtr && op->cmd.buswidth == 8) {
|
|
+ if (op->cmd.nbytes != 2)
|
|
+ return false;
|
|
+
|
|
+ if ((op->addr.nbytes % 2) ||
|
|
+ (op->dummy.nbytes % 2) ||
|
|
+ (op->data.nbytes % 2)) {
|
|
+ dev_err(&ctlr->dev,
|
|
+ "Even byte numbers not allowed in octal DTR operations\n");
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
} else {
|
|
if (op->cmd.nbytes != 1)
|
|
return false;
|
|
@@ -590,9 +601,18 @@ spi_mem_dirmap_create(struct spi_mem *mem,
|
|
|
|
desc->mem = mem;
|
|
desc->info = *info;
|
|
- if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create)
|
|
+ if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) {
|
|
+ ret = spi_mem_access_start(mem);
|
|
+ if (ret) {
|
|
+ kfree(desc);
|
|
+ return ERR_PTR(ret);
|
|
+ }
|
|
+
|
|
ret = ctlr->mem_ops->dirmap_create(desc);
|
|
|
|
+ spi_mem_access_end(mem);
|
|
+ }
|
|
+
|
|
if (ret) {
|
|
desc->nodirmap = true;
|
|
if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
|
|
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
|
|
index 211d9c76665bc4..96ee0e8456f4c5 100644
|
|
--- a/drivers/spi/spi-stm32.c
|
|
+++ b/drivers/spi/spi-stm32.c
|
|
@@ -1507,11 +1507,12 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
|
|
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
|
|
if ((len > 1) && (spi->cur_midi > 0)) {
|
|
u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed);
|
|
- u32 midi = min_t(u32,
|
|
- DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
|
|
- FIELD_GET(STM32H7_SPI_CFG2_MIDI,
|
|
- STM32H7_SPI_CFG2_MIDI));
|
|
+ u32 midi = DIV_ROUND_UP(spi->cur_midi, sck_period_ns);
|
|
|
|
+ if ((spi->cur_bpw + midi) < 8)
|
|
+ midi = 8 - spi->cur_bpw;
|
|
+
|
|
+ midi = min_t(u32, midi, FIELD_MAX(STM32H7_SPI_CFG2_MIDI));
|
|
|
|
dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n",
|
|
sck_period_ns, midi, midi * sck_period_ns);
|
|
diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c
|
|
index 852ffe013d326e..c006889b37ebb3 100644
|
|
--- a/drivers/spi/spi-wpcm-fiu.c
|
|
+++ b/drivers/spi/spi-wpcm-fiu.c
|
|
@@ -448,12 +448,10 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
|
|
fiu = spi_controller_get_devdata(ctrl);
|
|
fiu->dev = dev;
|
|
|
|
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
|
|
- fiu->regs = devm_ioremap_resource(dev, res);
|
|
- if (IS_ERR(fiu->regs)) {
|
|
- dev_err(dev, "Failed to map registers\n");
|
|
- return PTR_ERR(fiu->regs);
|
|
- }
|
|
+ fiu->regs = devm_platform_ioremap_resource_byname(pdev, "control");
|
|
+ if (IS_ERR(fiu->regs))
|
|
+ return dev_err_probe(dev, PTR_ERR(fiu->regs),
|
|
+ "Failed to map registers\n");
|
|
|
|
fiu->clk = devm_clk_get_enabled(dev, NULL);
|
|
if (IS_ERR(fiu->clk))
|
|
@@ -461,12 +459,11 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
|
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
|
|
fiu->memory = devm_ioremap_resource(dev, res);
|
|
- fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
|
|
- if (IS_ERR(fiu->memory)) {
|
|
- dev_err(dev, "Failed to map flash memory window\n");
|
|
- return PTR_ERR(fiu->memory);
|
|
- }
|
|
+ if (IS_ERR(fiu->memory))
|
|
+ return dev_err_probe(dev, PTR_ERR(fiu->memory),
|
|
+ "Failed to map flash memory window\n");
|
|
|
|
+ fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
|
|
fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm");
|
|
|
|
wpcm_fiu_hw_init(fiu);
|
|
diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c
|
|
index 9999f84016992a..eb69500e080e05 100644
|
|
--- a/drivers/staging/greybus/light.c
|
|
+++ b/drivers/staging/greybus/light.c
|
|
@@ -1029,14 +1029,18 @@ static int gb_lights_light_config(struct gb_lights *glights, u8 id)
|
|
if (!strlen(conf.name))
|
|
return -EINVAL;
|
|
|
|
- light->channels_count = conf.channel_count;
|
|
light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL);
|
|
if (!light->name)
|
|
return -ENOMEM;
|
|
- light->channels = kcalloc(light->channels_count,
|
|
+ light->channels = kcalloc(conf.channel_count,
|
|
sizeof(struct gb_channel), GFP_KERNEL);
|
|
if (!light->channels)
|
|
return -ENOMEM;
|
|
+ /*
|
|
+ * Publish channels_count only after channels allocation so cleanup
|
|
+ * doesn't walk a NULL channels pointer on allocation failure.
|
|
+ */
|
|
+ light->channels_count = conf.channel_count;
|
|
|
|
/* First we collect all the configurations for all channels */
|
|
for (i = 0; i < light->channels_count; i++) {
|
|
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
|
|
index b221913733fb61..19b877f50fb627 100644
|
|
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
|
|
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
|
|
@@ -876,8 +876,10 @@ static void find_network(struct adapter *adapter)
|
|
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
|
|
|
|
pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.mac_address);
|
|
- if (pwlan)
|
|
- pwlan->fixed = false;
|
|
+ if (!pwlan)
|
|
+ return;
|
|
+
|
|
+ pwlan->fixed = false;
|
|
|
|
if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) &&
|
|
(adapter->stapriv.asoc_sta_count == 1))
|
|
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
|
|
index af155fca39b8ca..f23aeb58d041d0 100644
|
|
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
|
|
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
|
|
@@ -316,9 +316,10 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
|
|
len, notify_signal, GFP_ATOMIC);
|
|
|
|
if (unlikely(!bss))
|
|
- goto exit;
|
|
+ goto free_buf;
|
|
|
|
cfg80211_put_bss(wiphy, bss);
|
|
+free_buf:
|
|
kfree(buf);
|
|
|
|
exit:
|
|
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
|
|
index 49043148452429..335e6002df70f6 100644
|
|
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
|
|
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
|
|
@@ -380,7 +380,8 @@ static int rtw_drv_init(
|
|
if (status != _SUCCESS)
|
|
goto free_if1;
|
|
|
|
- if (sdio_alloc_irq(dvobj) != _SUCCESS)
|
|
+ status = sdio_alloc_irq(dvobj);
|
|
+ if (status != _SUCCESS)
|
|
goto free_if1;
|
|
|
|
rtw_ndev_notifier_register();
|
|
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
|
|
index 546b70434004cb..8bcac4adb9ecec 100644
|
|
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
|
|
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
|
|
@@ -348,8 +348,11 @@ int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc
|
|
|
|
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {
|
|
ret = sysfs_create_group(&pdev->dev.kobj, &dlvr_attribute_group);
|
|
- if (ret)
|
|
+ if (ret) {
|
|
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
|
|
+ sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
|
|
return ret;
|
|
+ }
|
|
}
|
|
|
|
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
|
|
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
|
|
index 57b27f9ea1f034..60a05bfecde39c 100644
|
|
--- a/drivers/tty/serial/8250/8250_dw.c
|
|
+++ b/drivers/tty/serial/8250/8250_dw.c
|
|
@@ -753,11 +753,18 @@ static int dw8250_runtime_suspend(struct device *dev)
|
|
|
|
static int dw8250_runtime_resume(struct device *dev)
|
|
{
|
|
+ int ret;
|
|
struct dw8250_data *data = dev_get_drvdata(dev);
|
|
|
|
- clk_prepare_enable(data->pclk);
|
|
+ ret = clk_prepare_enable(data->pclk);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- clk_prepare_enable(data->clk);
|
|
+ ret = clk_prepare_enable(data->clk);
|
|
+ if (ret) {
|
|
+ clk_disable_unprepare(data->pclk);
|
|
+ return ret;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
|
|
index 9ed62bc7cdd83a..776373423b2a01 100644
|
|
--- a/drivers/tty/serial/8250/8250_omap.c
|
|
+++ b/drivers/tty/serial/8250/8250_omap.c
|
|
@@ -924,7 +924,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
|
|
goto out;
|
|
|
|
cookie = dma->rx_cookie;
|
|
- dma->rx_running = 0;
|
|
|
|
/* Re-enable RX FIFO interrupt now that transfer is complete */
|
|
if (priv->habit & UART_HAS_RHR_IT_DIS) {
|
|
@@ -958,6 +957,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
|
|
goto out;
|
|
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
|
|
|
+ dma->rx_running = 0;
|
|
p->port.icount.rx += ret;
|
|
p->port.icount.buf_overrun += count - ret;
|
|
out:
|
|
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
|
|
index 4f57833e3ec742..2b9b2235e29d6f 100644
|
|
--- a/drivers/tty/serial/Kconfig
|
|
+++ b/drivers/tty/serial/Kconfig
|
|
@@ -479,14 +479,14 @@ config SERIAL_IMX
|
|
can enable its onboard serial port by enabling this option.
|
|
|
|
config SERIAL_IMX_CONSOLE
|
|
- tristate "Console on IMX serial port"
|
|
+ bool "Console on IMX serial port"
|
|
depends on SERIAL_IMX
|
|
select SERIAL_CORE_CONSOLE
|
|
help
|
|
If you have enabled the serial port on the Freescale IMX
|
|
- CPU you can make it the console by answering Y/M to this option.
|
|
+ CPU you can make it the console by answering Y to this option.
|
|
|
|
- Even if you say Y/M here, the currently visible virtual console
|
|
+ Even if you say Y here, the currently visible virtual console
|
|
(/dev/tty0) will still be used as the system console by default, but
|
|
you can alter that using a kernel command line option such as
|
|
"console=ttymxc0". (Try "man bootparam" or see the documentation of
|
|
@@ -661,7 +661,7 @@ config SERIAL_SH_SCI_EARLYCON
|
|
default ARCH_RENESAS
|
|
|
|
config SERIAL_SH_SCI_DMA
|
|
- bool "DMA support" if EXPERT
|
|
+ bool "Support for DMA on SuperH SCI(F)" if EXPERT
|
|
depends on SERIAL_SH_SCI && DMA_ENGINE
|
|
default ARCH_RENESAS
|
|
|
|
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
|
|
index 9f53ee92486dc3..808b648e1f3885 100644
|
|
--- a/drivers/ufs/core/ufshcd.c
|
|
+++ b/drivers/ufs/core/ufshcd.c
|
|
@@ -9836,6 +9836,8 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
|
|
|
|
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
|
|
req_link_state == UIC_LINK_ACTIVE_STATE) {
|
|
+ ufshcd_disable_auto_bkops(hba);
|
|
+ flush_work(&hba->eeh_work);
|
|
goto vops_suspend;
|
|
}
|
|
|
|
diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
|
|
index 580c8d0bd8bbd8..626bb9002f4a12 100644
|
|
--- a/drivers/ufs/host/Kconfig
|
|
+++ b/drivers/ufs/host/Kconfig
|
|
@@ -72,6 +72,7 @@ config SCSI_UFS_QCOM
|
|
config SCSI_UFS_MEDIATEK
|
|
tristate "Mediatek specific hooks to UFS controller platform driver"
|
|
depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK
|
|
+ depends on PM
|
|
depends on RESET_CONTROLLER
|
|
select PHY_MTK_UFS
|
|
select RESET_TI_SYSCON
|
|
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
|
|
index 8b4a3cc8125310..606e90ce8ca70d 100644
|
|
--- a/drivers/ufs/host/ufs-mediatek.c
|
|
+++ b/drivers/ufs/host/ufs-mediatek.c
|
|
@@ -1852,7 +1852,6 @@ static int ufs_mtk_remove(struct platform_device *pdev)
|
|
return 0;
|
|
}
|
|
|
|
-#ifdef CONFIG_PM_SLEEP
|
|
static int ufs_mtk_system_suspend(struct device *dev)
|
|
{
|
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
|
@@ -1875,9 +1874,7 @@ static int ufs_mtk_system_resume(struct device *dev)
|
|
|
|
return ufshcd_system_resume(dev);
|
|
}
|
|
-#endif
|
|
|
|
-#ifdef CONFIG_PM
|
|
static int ufs_mtk_runtime_suspend(struct device *dev)
|
|
{
|
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
|
@@ -1900,13 +1897,10 @@ static int ufs_mtk_runtime_resume(struct device *dev)
|
|
|
|
return ufshcd_runtime_resume(dev);
|
|
}
|
|
-#endif
|
|
|
|
static const struct dev_pm_ops ufs_mtk_pm_ops = {
|
|
- SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend,
|
|
- ufs_mtk_system_resume)
|
|
- SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend,
|
|
- ufs_mtk_runtime_resume, NULL)
|
|
+ SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume)
|
|
+ RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL)
|
|
.prepare = ufshcd_suspend_prepare,
|
|
.complete = ufshcd_resume_complete,
|
|
};
|
|
@@ -1916,7 +1910,7 @@ static struct platform_driver ufs_mtk_pltform = {
|
|
.remove = ufs_mtk_remove,
|
|
.driver = {
|
|
.name = "ufshcd-mtk",
|
|
- .pm = &ufs_mtk_pm_ops,
|
|
+ .pm = pm_ptr(&ufs_mtk_pm_ops),
|
|
.of_match_table = ufs_mtk_of_match,
|
|
},
|
|
};
|
|
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
|
|
index 5635e4d7ec880e..66080ab8c8e017 100644
|
|
--- a/drivers/usb/dwc2/core.c
|
|
+++ b/drivers/usb/dwc2/core.c
|
|
@@ -572,6 +572,7 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
|
|
{
|
|
switch (hsotg->dr_mode) {
|
|
case USB_DR_MODE_HOST:
|
|
+ dwc2_force_mode(hsotg, true);
|
|
/*
|
|
* NOTE: This is required for some rockchip soc based
|
|
* platforms on their host-only dwc2.
|
|
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
|
|
index 45c9a399f8a554..11b938fd9de04f 100644
|
|
--- a/drivers/usb/dwc3/core.c
|
|
+++ b/drivers/usb/dwc3/core.c
|
|
@@ -1892,6 +1892,20 @@ static int dwc3_get_clocks(struct dwc3 *dwc)
|
|
return 0;
|
|
}
|
|
|
|
+static void dwc3_vbus_draw_work(struct work_struct *work)
|
|
+{
|
|
+ struct dwc3 *dwc = container_of(work, struct dwc3, vbus_draw_work);
|
|
+ union power_supply_propval val = {0};
|
|
+ int ret;
|
|
+
|
|
+ val.intval = 1000 * (dwc->current_limit);
|
|
+ ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
|
|
+
|
|
+ if (ret < 0)
|
|
+ dev_dbg(dwc->dev, "Error (%d) setting vbus draw (%d mA)\n",
|
|
+ ret, dwc->current_limit);
|
|
+}
|
|
+
|
|
static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
|
|
{
|
|
struct power_supply *usb_psy;
|
|
@@ -1906,6 +1920,7 @@ static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
|
|
if (!usb_psy)
|
|
return ERR_PTR(-EPROBE_DEFER);
|
|
|
|
+ INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work);
|
|
return usb_psy;
|
|
}
|
|
|
|
@@ -2097,8 +2112,10 @@ static void dwc3_remove(struct platform_device *pdev)
|
|
|
|
dwc3_free_event_buffers(dwc);
|
|
|
|
- if (dwc->usb_psy)
|
|
+ if (dwc->usb_psy) {
|
|
+ cancel_work_sync(&dwc->vbus_draw_work);
|
|
power_supply_put(dwc->usb_psy);
|
|
+ }
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
|
|
index 9fc91f5c0bdbf2..45084ca66806ef 100644
|
|
--- a/drivers/usb/dwc3/core.h
|
|
+++ b/drivers/usb/dwc3/core.h
|
|
@@ -1034,6 +1034,8 @@ struct dwc3_scratchpad_array {
|
|
* @role_switch_default_mode: default operation mode of controller while
|
|
* usb role is USB_ROLE_NONE.
|
|
* @usb_psy: pointer to power supply interface.
|
|
+ * @vbus_draw_work: Work to set the vbus drawing limit
|
|
+ * @current_limit: How much current to draw from vbus, in milliAmperes.
|
|
* @usb2_phy: pointer to USB2 PHY
|
|
* @usb3_phy: pointer to USB3 PHY
|
|
* @usb2_generic_phy: pointer to USB2 PHY
|
|
@@ -1202,6 +1204,8 @@ struct dwc3 {
|
|
enum usb_dr_mode role_switch_default_mode;
|
|
|
|
struct power_supply *usb_psy;
|
|
+ struct work_struct vbus_draw_work;
|
|
+ unsigned int current_limit;
|
|
|
|
u32 fladj;
|
|
u32 ref_clk_per;
|
|
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
|
|
index 8781ebeaab9041..7e6661781afffe 100644
|
|
--- a/drivers/usb/dwc3/gadget.c
|
|
+++ b/drivers/usb/dwc3/gadget.c
|
|
@@ -3139,8 +3139,6 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
|
|
static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
|
|
{
|
|
struct dwc3 *dwc = gadget_to_dwc(g);
|
|
- union power_supply_propval val = {0};
|
|
- int ret;
|
|
|
|
if (dwc->usb2_phy)
|
|
return usb_phy_set_power(dwc->usb2_phy, mA);
|
|
@@ -3148,10 +3146,10 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
|
|
if (!dwc->usb_psy)
|
|
return -EOPNOTSUPP;
|
|
|
|
- val.intval = 1000 * mA;
|
|
- ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
|
|
+ dwc->current_limit = mA;
|
|
+ schedule_work(&dwc->vbus_draw_work);
|
|
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
|
|
index 35a652807fca87..c2e3fa997842ad 100644
|
|
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
|
|
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
|
|
@@ -35,8 +35,8 @@ static int poll_oip(struct bdc *bdc, u32 usec)
|
|
u32 status;
|
|
int ret;
|
|
|
|
- ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status,
|
|
- (BDC_CSTS(status) != BDC_OIP), 10, usec);
|
|
+ ret = readl_poll_timeout_atomic(bdc->regs + BDC_BDCSC, status,
|
|
+ (BDC_CSTS(status) != BDC_OIP), 10, usec);
|
|
if (ret)
|
|
dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status);
|
|
else
|
|
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
|
|
index 3a14b6b72d8c6f..114a80dd06fbb4 100644
|
|
--- a/drivers/usb/gadget/udc/tegra-xudc.c
|
|
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
|
|
@@ -3388,17 +3388,18 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc)
|
|
{
|
|
u32 val, imod;
|
|
|
|
+ val = xudc_readl(xudc, BLCG);
|
|
if (xudc->soc->has_ipfs) {
|
|
- val = xudc_readl(xudc, BLCG);
|
|
val |= BLCG_ALL;
|
|
val &= ~(BLCG_DFPCI | BLCG_UFPCI | BLCG_FE |
|
|
BLCG_COREPLL_PWRDN);
|
|
val |= BLCG_IOPLL_0_PWRDN;
|
|
val |= BLCG_IOPLL_1_PWRDN;
|
|
val |= BLCG_IOPLL_2_PWRDN;
|
|
-
|
|
- xudc_writel(xudc, val, BLCG);
|
|
+ } else {
|
|
+ val &= ~BLCG_COREPLL_PWRDN;
|
|
}
|
|
+ xudc_writel(xudc, val, BLCG);
|
|
|
|
if (xudc->soc->port_speed_quirk)
|
|
tegra_xudc_limit_port_speed(xudc);
|
|
@@ -3949,6 +3950,7 @@ static void tegra_xudc_remove(struct platform_device *pdev)
|
|
static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc)
|
|
{
|
|
unsigned long flags;
|
|
+ u32 val;
|
|
|
|
dev_dbg(xudc->dev, "entering ELPG\n");
|
|
|
|
@@ -3961,6 +3963,10 @@ static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc)
|
|
|
|
spin_unlock_irqrestore(&xudc->lock, flags);
|
|
|
|
+ val = xudc_readl(xudc, BLCG);
|
|
+ val |= BLCG_COREPLL_PWRDN;
|
|
+ xudc_writel(xudc, val, BLCG);
|
|
+
|
|
clk_bulk_disable_unprepare(xudc->soc->num_clks, xudc->clks);
|
|
|
|
regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
|
|
diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c
|
|
index c80c23d3384e89..3fc524190baf67 100644
|
|
--- a/drivers/usb/typec/ucsi/psy.c
|
|
+++ b/drivers/usb/typec/ucsi/psy.c
|
|
@@ -87,15 +87,20 @@ static int ucsi_psy_get_voltage_max(struct ucsi_connector *con,
|
|
union power_supply_propval *val)
|
|
{
|
|
u32 pdo;
|
|
+ int max_voltage = 0;
|
|
|
|
switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
|
|
case UCSI_CONSTAT_PWR_OPMODE_PD:
|
|
- if (con->num_pdos > 0) {
|
|
- pdo = con->src_pdos[con->num_pdos - 1];
|
|
- val->intval = pdo_fixed_voltage(pdo) * 1000;
|
|
- } else {
|
|
- val->intval = 0;
|
|
+ for (int i = 0; i < con->num_pdos; i++) {
|
|
+ int pdo_voltage = 0;
|
|
+
|
|
+ pdo = con->src_pdos[i];
|
|
+ if (pdo_type(pdo) == PDO_TYPE_FIXED)
|
|
+ pdo_voltage = pdo_fixed_voltage(pdo) * 1000;
|
|
+ max_voltage = (pdo_voltage > max_voltage) ? pdo_voltage
|
|
+ : max_voltage;
|
|
}
|
|
+ val->intval = max_voltage;
|
|
break;
|
|
case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
|
|
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
|
|
@@ -143,6 +148,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
|
|
union power_supply_propval *val)
|
|
{
|
|
u32 pdo;
|
|
+ int max_current = 0;
|
|
|
|
if (!(con->status.flags & UCSI_CONSTAT_CONNECTED)) {
|
|
val->intval = 0;
|
|
@@ -151,12 +157,16 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
|
|
|
|
switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
|
|
case UCSI_CONSTAT_PWR_OPMODE_PD:
|
|
- if (con->num_pdos > 0) {
|
|
- pdo = con->src_pdos[con->num_pdos - 1];
|
|
- val->intval = pdo_max_current(pdo) * 1000;
|
|
- } else {
|
|
- val->intval = 0;
|
|
+ for (int i = 0; i < con->num_pdos; i++) {
|
|
+ int pdo_current = 0;
|
|
+
|
|
+ pdo = con->src_pdos[i];
|
|
+ if (pdo_type(pdo) == PDO_TYPE_FIXED)
|
|
+ pdo_current = pdo_max_current(pdo) * 1000;
|
|
+ max_current = (pdo_current > max_current) ? pdo_current
|
|
+ : max_current;
|
|
}
|
|
+ val->intval = max_current;
|
|
break;
|
|
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
|
|
val->intval = UCSI_TYPEC_1_5_CURRENT * 1000;
|
|
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
|
|
index 712b178c42aae5..e544fd0a710c0c 100644
|
|
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
|
|
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
|
|
@@ -1152,8 +1152,7 @@ static void hisi_acc_vf_pci_aer_reset_done(struct pci_dev *pdev)
|
|
{
|
|
struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
|
|
|
|
- if (hisi_acc_vdev->core_device.vdev.migration_flags !=
|
|
- VFIO_MIGRATION_STOP_COPY)
|
|
+ if (!hisi_acc_vdev->core_device.vdev.mig_ops)
|
|
return;
|
|
|
|
/*
|
|
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
|
|
index c29a195a0175c0..f4da76fa235eae 100644
|
|
--- a/drivers/vhost/vdpa.c
|
|
+++ b/drivers/vhost/vdpa.c
|
|
@@ -1424,6 +1424,7 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma)
|
|
if (vma->vm_end - vma->vm_start != notify.size)
|
|
return -ENOTSUPP;
|
|
|
|
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
|
|
vma->vm_ops = &vhost_vdpa_vm_ops;
|
|
return 0;
|
|
diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c
|
|
index b19e5f73de8bb4..0d55818f554ec6 100644
|
|
--- a/drivers/video/backlight/qcom-wled.c
|
|
+++ b/drivers/video/backlight/qcom-wled.c
|
|
@@ -1244,6 +1244,15 @@ static const struct wled_var_cfg wled4_ovp_cfg = {
|
|
.size = ARRAY_SIZE(wled4_ovp_values),
|
|
};
|
|
|
|
+static const u32 pmi8994_wled_ovp_values[] = {
|
|
+ 31000, 29500, 19400, 17800,
|
|
+};
|
|
+
|
|
+static const struct wled_var_cfg pmi8994_wled_ovp_cfg = {
|
|
+ .values = pmi8994_wled_ovp_values,
|
|
+ .size = ARRAY_SIZE(pmi8994_wled_ovp_values),
|
|
+};
|
|
+
|
|
static inline u32 wled5_ovp_values_fn(u32 idx)
|
|
{
|
|
/*
|
|
@@ -1357,6 +1366,29 @@ static int wled_configure(struct wled *wled)
|
|
},
|
|
};
|
|
|
|
+ const struct wled_u32_opts pmi8994_wled_opts[] = {
|
|
+ {
|
|
+ .name = "qcom,current-boost-limit",
|
|
+ .val_ptr = &cfg->boost_i_limit,
|
|
+ .cfg = &wled4_boost_i_limit_cfg,
|
|
+ },
|
|
+ {
|
|
+ .name = "qcom,current-limit-microamp",
|
|
+ .val_ptr = &cfg->string_i_limit,
|
|
+ .cfg = &wled4_string_i_limit_cfg,
|
|
+ },
|
|
+ {
|
|
+ .name = "qcom,ovp-millivolt",
|
|
+ .val_ptr = &cfg->ovp,
|
|
+ .cfg = &pmi8994_wled_ovp_cfg,
|
|
+ },
|
|
+ {
|
|
+ .name = "qcom,switching-freq",
|
|
+ .val_ptr = &cfg->switch_freq,
|
|
+ .cfg = &wled3_switch_freq_cfg,
|
|
+ },
|
|
+ };
|
|
+
|
|
const struct wled_u32_opts wled5_opts[] = {
|
|
{
|
|
.name = "qcom,current-boost-limit",
|
|
@@ -1423,8 +1455,14 @@ static int wled_configure(struct wled *wled)
|
|
break;
|
|
|
|
case 4:
|
|
- u32_opts = wled4_opts;
|
|
- size = ARRAY_SIZE(wled4_opts);
|
|
+ if (of_device_is_compatible(dev->of_node, "qcom,pmi8950-wled") ||
|
|
+ of_device_is_compatible(dev->of_node, "qcom,pmi8994-wled")) {
|
|
+ u32_opts = pmi8994_wled_opts;
|
|
+ size = ARRAY_SIZE(pmi8994_wled_opts);
|
|
+ } else {
|
|
+ u32_opts = wled4_opts;
|
|
+ size = ARRAY_SIZE(wled4_opts);
|
|
+ }
|
|
*cfg = wled4_config_defaults;
|
|
wled->wled_set_brightness = wled4_set_brightness;
|
|
wled->wled_sync_toggle = wled3_sync_toggle;
|
|
diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c
|
|
index c137d6afe4840c..1b05dfbd5195e6 100644
|
|
--- a/drivers/video/fbdev/au1200fb.c
|
|
+++ b/drivers/video/fbdev/au1200fb.c
|
|
@@ -1732,8 +1732,10 @@ static int au1200fb_drv_probe(struct platform_device *dev)
|
|
|
|
/* Now hook interrupt too */
|
|
irq = platform_get_irq(dev, 0);
|
|
- if (irq < 0)
|
|
- return irq;
|
|
+ if (irq < 0) {
|
|
+ ret = irq;
|
|
+ goto failed;
|
|
+ }
|
|
|
|
ret = request_irq(irq, au1200fb_handle_irq,
|
|
IRQF_SHARED, "lcd", (void *)dev);
|
|
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
|
index 78a5b22c8d1507..703c4e851612c8 100644
|
|
--- a/drivers/video/fbdev/core/fbcon.c
|
|
+++ b/drivers/video/fbdev/core/fbcon.c
|
|
@@ -1023,7 +1023,8 @@ static void fbcon_init(struct vc_data *vc, bool init)
|
|
return;
|
|
|
|
if (!info->fbcon_par)
|
|
- con2fb_acquire_newinfo(vc, info, vc->vc_num);
|
|
+ if (con2fb_acquire_newinfo(vc, info, vc->vc_num))
|
|
+ return;
|
|
|
|
/* If we are not the first console on this
|
|
fb, copy the font from that console */
|
|
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
|
|
index 25691d4b027bfc..7945b360862cb3 100644
|
|
--- a/drivers/video/fbdev/core/fbcon.h
|
|
+++ b/drivers/video/fbdev/core/fbcon.h
|
|
@@ -30,7 +30,6 @@ struct fbcon_display {
|
|
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
|
|
u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
|
|
#endif
|
|
- u_short inverse; /* != 0 text black on white as default */
|
|
short yscroll; /* Hardware scrolling */
|
|
int vrows; /* number of virtual rows */
|
|
int cursor_shape;
|
|
diff --git a/drivers/video/fbdev/ffb.c b/drivers/video/fbdev/ffb.c
|
|
index e3a9bb7e9dea44..e8992bdd3c9a59 100644
|
|
--- a/drivers/video/fbdev/ffb.c
|
|
+++ b/drivers/video/fbdev/ffb.c
|
|
@@ -336,6 +336,9 @@ struct ffb_dac {
|
|
};
|
|
|
|
#define FFB_DAC_UCTRL 0x1001 /* User Control */
|
|
+#define FFB_DAC_UCTRL_OVENAB 0x00000008 /* Overlay Enable */
|
|
+#define FFB_DAC_UCTRL_WMODE 0x00000030 /* Window Mode */
|
|
+#define FFB_DAC_UCTRL_WM_COMB 0x00000000 /* Window Mode = Combined */
|
|
#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
|
|
#define FFB_DAC_UCTRL_MANREV_SHIFT 8
|
|
#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
|
|
@@ -426,7 +429,7 @@ static void ffb_switch_from_graph(struct ffb_par *par)
|
|
{
|
|
struct ffb_fbc __iomem *fbc = par->fbc;
|
|
struct ffb_dac __iomem *dac = par->dac;
|
|
- unsigned long flags;
|
|
+ unsigned long flags, uctrl;
|
|
|
|
spin_lock_irqsave(&par->lock, flags);
|
|
FFBWait(par);
|
|
@@ -451,6 +454,15 @@ static void ffb_switch_from_graph(struct ffb_par *par)
|
|
upa_writel((FFB_DAC_CUR_CTRL_P0 |
|
|
FFB_DAC_CUR_CTRL_P1), &dac->value2);
|
|
|
|
+ /* Disable overlay and window modes. */
|
|
+ upa_writel(FFB_DAC_UCTRL, &dac->type);
|
|
+ uctrl = upa_readl(&dac->value);
|
|
+ uctrl &= ~FFB_DAC_UCTRL_WMODE;
|
|
+ uctrl |= FFB_DAC_UCTRL_WM_COMB;
|
|
+ uctrl &= ~FFB_DAC_UCTRL_OVENAB;
|
|
+ upa_writel(FFB_DAC_UCTRL, &dac->type);
|
|
+ upa_writel(uctrl, &dac->value);
|
|
+
|
|
spin_unlock_irqrestore(&par->lock, flags);
|
|
}
|
|
|
|
diff --git a/drivers/video/fbdev/vt8500lcdfb.c b/drivers/video/fbdev/vt8500lcdfb.c
|
|
index 42d39a9d5130f9..f62fe1a9dd6287 100644
|
|
--- a/drivers/video/fbdev/vt8500lcdfb.c
|
|
+++ b/drivers/video/fbdev/vt8500lcdfb.c
|
|
@@ -367,7 +367,7 @@ static int vt8500lcd_probe(struct platform_device *pdev)
|
|
if (fbi->palette_cpu == NULL) {
|
|
dev_err(&pdev->dev, "Failed to allocate palette buffer\n");
|
|
ret = -ENOMEM;
|
|
- goto failed_free_io;
|
|
+ goto failed_free_mem_virt;
|
|
}
|
|
|
|
irq = platform_get_irq(pdev, 0);
|
|
@@ -431,6 +431,9 @@ failed_free_irq:
|
|
failed_free_palette:
|
|
dma_free_coherent(&pdev->dev, fbi->palette_size,
|
|
fbi->palette_cpu, fbi->palette_phys);
|
|
+failed_free_mem_virt:
|
|
+ dma_free_coherent(&pdev->dev, fbi->fb.fix.smem_len,
|
|
+ fbi->fb.screen_buffer, fbi->fb.fix.smem_start);
|
|
failed_free_io:
|
|
iounmap(fbi->regbase);
|
|
failed_free_res:
|
|
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
|
|
index bebd371c6b93ea..a6ec392253c3ee 100644
|
|
--- a/drivers/video/of_display_timing.c
|
|
+++ b/drivers/video/of_display_timing.c
|
|
@@ -181,7 +181,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np)
|
|
if (disp->num_timings == 0) {
|
|
/* should never happen, as entry was already found above */
|
|
pr_err("%pOF: no timings specified\n", np);
|
|
- goto entryfail;
|
|
+ goto timingfail;
|
|
}
|
|
|
|
disp->timings = kcalloc(disp->num_timings,
|
|
@@ -189,13 +189,13 @@ struct display_timings *of_get_display_timings(const struct device_node *np)
|
|
GFP_KERNEL);
|
|
if (!disp->timings) {
|
|
pr_err("%pOF: could not allocate timings array\n", np);
|
|
- goto entryfail;
|
|
+ goto timingfail;
|
|
}
|
|
|
|
disp->num_timings = 0;
|
|
disp->native_mode = 0;
|
|
|
|
- for_each_child_of_node(timings_np, entry) {
|
|
+ for_each_child_of_node_scoped(timings_np, child) {
|
|
struct display_timing *dt;
|
|
int r;
|
|
|
|
@@ -206,7 +206,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np)
|
|
goto timingfail;
|
|
}
|
|
|
|
- r = of_parse_display_timing(entry, dt);
|
|
+ r = of_parse_display_timing(child, dt);
|
|
if (r) {
|
|
/*
|
|
* to not encourage wrong devicetrees, fail in case of
|
|
@@ -218,7 +218,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np)
|
|
goto timingfail;
|
|
}
|
|
|
|
- if (native_mode == entry)
|
|
+ if (native_mode == child)
|
|
disp->native_mode = disp->num_timings;
|
|
|
|
disp->timings[disp->num_timings] = dt;
|
|
diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
|
|
index c703586c6e5f08..b6797845a48fb6 100644
|
|
--- a/drivers/watchdog/imx7ulp_wdt.c
|
|
+++ b/drivers/watchdog/imx7ulp_wdt.c
|
|
@@ -342,6 +342,7 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
|
|
watchdog_stop_on_reboot(wdog);
|
|
watchdog_stop_on_unregister(wdog);
|
|
watchdog_set_drvdata(wdog, imx7ulp_wdt);
|
|
+ watchdog_set_nowayout(wdog, nowayout);
|
|
|
|
imx7ulp_wdt->hw = of_device_get_match_data(dev);
|
|
ret = imx7ulp_wdt_init(imx7ulp_wdt, wdog->timeout * imx7ulp_wdt->hw->wdog_clock_rate);
|
|
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
|
|
index 239947df613db1..1392e557fa371b 100644
|
|
--- a/drivers/watchdog/it87_wdt.c
|
|
+++ b/drivers/watchdog/it87_wdt.c
|
|
@@ -183,6 +183,12 @@ static void _wdt_update_timeout(unsigned int t)
|
|
superio_outb(t >> 8, WDTVALMSB);
|
|
}
|
|
|
|
+/* Internal function, should be called after superio_select(GPIO) */
|
|
+static bool _wdt_running(void)
|
|
+{
|
|
+ return superio_inb(WDTVALLSB) || (max_units > 255 && superio_inb(WDTVALMSB));
|
|
+}
|
|
+
|
|
static int wdt_update_timeout(unsigned int t)
|
|
{
|
|
int ret;
|
|
@@ -365,6 +371,12 @@ static int __init it87_wdt_init(void)
|
|
}
|
|
}
|
|
|
|
+ /* wdt already left running by firmware? */
|
|
+ if (_wdt_running()) {
|
|
+ pr_info("Left running by firmware.\n");
|
|
+ set_bit(WDOG_HW_RUNNING, &wdt_dev.status);
|
|
+ }
|
|
+
|
|
superio_exit();
|
|
|
|
if (timeout < 1 || timeout > max_units * 60) {
|
|
diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c
|
|
index 0606142ffc5e2d..3842a0b1b6cb8e 100644
|
|
--- a/drivers/watchdog/starfive-wdt.c
|
|
+++ b/drivers/watchdog/starfive-wdt.c
|
|
@@ -444,7 +444,7 @@ static int starfive_wdt_probe(struct platform_device *pdev)
|
|
platform_set_drvdata(pdev, wdt);
|
|
pm_runtime_enable(&pdev->dev);
|
|
if (pm_runtime_enabled(&pdev->dev)) {
|
|
- ret = pm_runtime_get_sync(&pdev->dev);
|
|
+ ret = pm_runtime_resume_and_get(&pdev->dev);
|
|
if (ret < 0)
|
|
return ret;
|
|
} else {
|
|
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
|
|
index 204ec1bcbd526a..a76d5530533ff5 100644
|
|
--- a/drivers/xen/balloon.c
|
|
+++ b/drivers/xen/balloon.c
|
|
@@ -716,6 +716,7 @@ static int __init balloon_add_regions(void)
|
|
static int __init balloon_init(void)
|
|
{
|
|
struct task_struct *task;
|
|
+ unsigned long current_pages;
|
|
int rc;
|
|
|
|
if (!xen_domain())
|
|
@@ -723,12 +724,18 @@ static int __init balloon_init(void)
|
|
|
|
pr_info("Initialising balloon driver\n");
|
|
|
|
- if (xen_released_pages >= get_num_physpages()) {
|
|
- WARN(1, "Released pages underflow current target");
|
|
- return -ERANGE;
|
|
+ if (xen_pv_domain()) {
|
|
+ if (xen_released_pages >= xen_start_info->nr_pages)
|
|
+ goto underflow;
|
|
+ current_pages = min(xen_start_info->nr_pages -
|
|
+ xen_released_pages, max_pfn);
|
|
+ } else {
|
|
+ if (xen_unpopulated_pages >= get_num_physpages())
|
|
+ goto underflow;
|
|
+ current_pages = get_num_physpages() - xen_unpopulated_pages;
|
|
}
|
|
|
|
- balloon_stats.current_pages = get_num_physpages() - xen_released_pages;
|
|
+ balloon_stats.current_pages = current_pages;
|
|
balloon_stats.target_pages = balloon_stats.current_pages;
|
|
balloon_stats.balloon_low = 0;
|
|
balloon_stats.balloon_high = 0;
|
|
@@ -759,6 +766,10 @@ static int __init balloon_init(void)
|
|
xen_balloon_init();
|
|
|
|
return 0;
|
|
+
|
|
+ underflow:
|
|
+ WARN(1, "Released pages underflow current target");
|
|
+ return -ERANGE;
|
|
}
|
|
subsys_initcall(balloon_init);
|
|
|
|
diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c
|
|
index 76f6f26265a3b8..12fbe89382593b 100644
|
|
--- a/drivers/xen/grant-dma-ops.c
|
|
+++ b/drivers/xen/grant-dma-ops.c
|
|
@@ -362,7 +362,8 @@ static int xen_grant_init_backend_domid(struct device *dev,
|
|
if (np) {
|
|
ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid);
|
|
of_node_put(np);
|
|
- } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) {
|
|
+ } else if (!xen_initial_domain() &&
|
|
+ (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) {
|
|
dev_info(dev, "Using dom0 as backend\n");
|
|
*backend_domid = 0;
|
|
ret = 0;
|
|
diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c
|
|
index a39f2d36dd9cfc..ae46291e99a9de 100644
|
|
--- a/drivers/xen/unpopulated-alloc.c
|
|
+++ b/drivers/xen/unpopulated-alloc.c
|
|
@@ -18,6 +18,9 @@ static unsigned int list_count;
|
|
|
|
static struct resource *target_resource;
|
|
|
|
+/* Pages to subtract from the memory count when setting balloon target. */
|
|
+unsigned long xen_unpopulated_pages __initdata;
|
|
+
|
|
/*
|
|
* If arch is not happy with system "iomem_resource" being used for
|
|
* the region allocation it can provide it's own view by creating specific
|
|
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
|
|
index fcb335bb7b1878..1fdf5be1934301 100644
|
|
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
|
|
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
|
|
@@ -148,11 +148,9 @@ static void xenbus_frontend_dev_shutdown(struct device *_dev)
|
|
}
|
|
|
|
static const struct dev_pm_ops xenbus_pm_ops = {
|
|
- .suspend = xenbus_dev_suspend,
|
|
- .resume = xenbus_frontend_dev_resume,
|
|
.freeze = xenbus_dev_suspend,
|
|
.thaw = xenbus_dev_cancel,
|
|
- .restore = xenbus_dev_resume,
|
|
+ .restore = xenbus_frontend_dev_resume,
|
|
};
|
|
|
|
static struct xen_bus_type xenbus_frontend = {
|
|
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
|
|
index 5e3d1a87b7e9da..774bdafc822c1d 100644
|
|
--- a/fs/btrfs/extent-tree.c
|
|
+++ b/fs/btrfs/extent-tree.c
|
|
@@ -6196,6 +6196,10 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
range->minlen);
|
|
|
|
trimmed += group_trimmed;
|
|
+ if (ret == -ERESTARTSYS || ret == -EINTR) {
|
|
+ btrfs_put_block_group(cache);
|
|
+ break;
|
|
+ }
|
|
if (ret) {
|
|
bg_failed++;
|
|
bg_ret = ret;
|
|
@@ -6209,6 +6213,9 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
"failed to trim %llu block group(s), last error %d",
|
|
bg_failed, bg_ret);
|
|
|
|
+ if (ret == -ERESTARTSYS || ret == -EINTR)
|
|
+ return ret;
|
|
+
|
|
mutex_lock(&fs_devices->device_list_mutex);
|
|
list_for_each_entry(device, &fs_devices->devices, dev_list) {
|
|
if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
|
|
@@ -6217,10 +6224,12 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
ret = btrfs_trim_free_extents(device, &group_trimmed);
|
|
|
|
trimmed += group_trimmed;
|
|
+ if (ret == -ERESTARTSYS || ret == -EINTR)
|
|
+ break;
|
|
if (ret) {
|
|
dev_failed++;
|
|
dev_ret = ret;
|
|
- break;
|
|
+ continue;
|
|
}
|
|
}
|
|
mutex_unlock(&fs_devices->device_list_mutex);
|
|
@@ -6230,6 +6239,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
"failed to trim %llu device(s), last error %d",
|
|
dev_failed, dev_ret);
|
|
range->len = trimmed;
|
|
+ if (ret == -ERESTARTSYS || ret == -EINTR)
|
|
+ return ret;
|
|
if (bg_ret)
|
|
return bg_ret;
|
|
return dev_ret;
|
|
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
|
|
index c46ea2ecf18817..622febdb61e23e 100644
|
|
--- a/fs/btrfs/qgroup.c
|
|
+++ b/fs/btrfs/qgroup.c
|
|
@@ -1129,11 +1129,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
|
|
}
|
|
if (ret > 0) {
|
|
/*
|
|
- * Shouldn't happen, but in case it does we
|
|
- * don't need to do the btrfs_next_item, just
|
|
- * continue.
|
|
+ * Shouldn't happen because the key should still
|
|
+ * be there (return 0), but in case it does it
|
|
+ * means we have reached the end of the tree -
|
|
+ * there are no more leaves with items that have
|
|
+ * a key greater than or equals to @found_key,
|
|
+ * so just stop the search loop.
|
|
*/
|
|
- continue;
|
|
+ break;
|
|
}
|
|
}
|
|
ret = btrfs_next_item(tree_root, path);
|
|
@@ -1601,8 +1604,10 @@ delete_item:
|
|
if (ret < 0 && ret != -ENOENT)
|
|
goto out;
|
|
ret2 = del_qgroup_relation_item(trans, dst, src);
|
|
- if (ret2 < 0 && ret2 != -ENOENT)
|
|
+ if (ret2 < 0 && ret2 != -ENOENT) {
|
|
+ ret = ret2;
|
|
goto out;
|
|
+ }
|
|
|
|
/* At least one deletion succeeded, return 0 */
|
|
if (!ret || !ret2)
|
|
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
|
|
index ce1e5b5dae3a0e..6dbbb03be562f5 100644
|
|
--- a/fs/btrfs/transaction.c
|
|
+++ b/fs/btrfs/transaction.c
|
|
@@ -2457,13 +2457,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
|
list_add_tail(&fs_info->chunk_root->dirty_list,
|
|
&cur_trans->switch_commits);
|
|
|
|
- if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
|
|
- btrfs_set_root_node(&fs_info->block_group_root->root_item,
|
|
- fs_info->block_group_root->node);
|
|
- list_add_tail(&fs_info->block_group_root->dirty_list,
|
|
- &cur_trans->switch_commits);
|
|
- }
|
|
-
|
|
switch_commit_roots(trans);
|
|
|
|
ASSERT(list_empty(&cur_trans->dirty_bgs));
|
|
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
|
|
index 8207b0b4c43a01..6ce083a6ed61ff 100644
|
|
--- a/fs/btrfs/volumes.c
|
|
+++ b/fs/btrfs/volumes.c
|
|
@@ -3980,8 +3980,14 @@ again:
|
|
* this shouldn't happen, it means the last relocate
|
|
* failed
|
|
*/
|
|
- if (ret == 0)
|
|
- BUG(); /* FIXME break ? */
|
|
+ if (unlikely(ret == 0)) {
|
|
+ btrfs_err(fs_info,
|
|
+ "unexpected exact match of CHUNK_ITEM in chunk tree, offset 0x%llx",
|
|
+ key.offset);
|
|
+ mutex_unlock(&fs_info->reclaim_bgs_lock);
|
|
+ ret = -EUCLEAN;
|
|
+ goto error;
|
|
+ }
|
|
|
|
ret = btrfs_previous_item(chunk_root, path, 0,
|
|
BTRFS_CHUNK_ITEM_KEY);
|
|
diff --git a/fs/buffer.c b/fs/buffer.c
|
|
index 32df6163ffed5f..c225eef13279ba 100644
|
|
--- a/fs/buffer.c
|
|
+++ b/fs/buffer.c
|
|
@@ -2950,6 +2950,10 @@ bool try_to_free_buffers(struct folio *folio)
|
|
if (folio_test_writeback(folio))
|
|
return false;
|
|
|
|
+ /* Misconfigured folio check */
|
|
+ if (WARN_ON_ONCE(!folio_buffers(folio)))
|
|
+ return true;
|
|
+
|
|
if (mapping == NULL) { /* can this still happen? */
|
|
ret = drop_buffers(folio, &buffers_to_free);
|
|
goto out;
|
|
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
|
|
index 2c92de964c5a2e..db4d11604e9d5c 100644
|
|
--- a/fs/ceph/addr.c
|
|
+++ b/fs/ceph/addr.c
|
|
@@ -1833,6 +1833,7 @@ int ceph_uninline_data(struct file *file)
|
|
struct ceph_osd_request *req = NULL;
|
|
struct ceph_cap_flush *prealloc_cf = NULL;
|
|
struct folio *folio = NULL;
|
|
+ struct ceph_snap_context *snapc = NULL;
|
|
u64 inline_version = CEPH_INLINE_NONE;
|
|
struct page *pages[1];
|
|
int err = 0;
|
|
@@ -1860,6 +1861,24 @@ int ceph_uninline_data(struct file *file)
|
|
if (inline_version == 1) /* initial version, no data */
|
|
goto out_uninline;
|
|
|
|
+ down_read(&fsc->mdsc->snap_rwsem);
|
|
+ spin_lock(&ci->i_ceph_lock);
|
|
+ if (__ceph_have_pending_cap_snap(ci)) {
|
|
+ struct ceph_cap_snap *capsnap =
|
|
+ list_last_entry(&ci->i_cap_snaps,
|
|
+ struct ceph_cap_snap,
|
|
+ ci_item);
|
|
+ snapc = ceph_get_snap_context(capsnap->context);
|
|
+ } else {
|
|
+ if (!ci->i_head_snapc) {
|
|
+ ci->i_head_snapc = ceph_get_snap_context(
|
|
+ ci->i_snap_realm->cached_context);
|
|
+ }
|
|
+ snapc = ceph_get_snap_context(ci->i_head_snapc);
|
|
+ }
|
|
+ spin_unlock(&ci->i_ceph_lock);
|
|
+ up_read(&fsc->mdsc->snap_rwsem);
|
|
+
|
|
folio = read_mapping_folio(inode->i_mapping, 0, file);
|
|
if (IS_ERR(folio)) {
|
|
err = PTR_ERR(folio);
|
|
@@ -1875,7 +1894,7 @@ int ceph_uninline_data(struct file *file)
|
|
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
|
|
ceph_vino(inode), 0, &len, 0, 1,
|
|
CEPH_OSD_OP_CREATE, CEPH_OSD_FLAG_WRITE,
|
|
- NULL, 0, 0, false);
|
|
+ snapc, 0, 0, false);
|
|
if (IS_ERR(req)) {
|
|
err = PTR_ERR(req);
|
|
goto out_unlock;
|
|
@@ -1891,7 +1910,7 @@ int ceph_uninline_data(struct file *file)
|
|
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
|
|
ceph_vino(inode), 0, &len, 1, 3,
|
|
CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
|
|
- NULL, ci->i_truncate_seq,
|
|
+ snapc, ci->i_truncate_seq,
|
|
ci->i_truncate_size, false);
|
|
if (IS_ERR(req)) {
|
|
err = PTR_ERR(req);
|
|
@@ -1954,6 +1973,7 @@ out_unlock:
|
|
folio_put(folio);
|
|
}
|
|
out:
|
|
+ ceph_put_snap_context(snapc);
|
|
ceph_free_cap_flush(prealloc_cf);
|
|
dout("uninline_data %p %llx.%llx inline_version %llu = %d\n",
|
|
inode, ceph_vinop(inode), inline_version, err);
|
|
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
|
|
index 0ec78d87519ba7..0757eb7611daa9 100644
|
|
--- a/fs/ceph/file.c
|
|
+++ b/fs/ceph/file.c
|
|
@@ -2468,6 +2468,7 @@ static int ceph_zero_partial_object(struct inode *inode,
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
|
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
|
struct ceph_osd_request *req;
|
|
+ struct ceph_snap_context *snapc;
|
|
int ret = 0;
|
|
loff_t zero = 0;
|
|
int op;
|
|
@@ -2482,12 +2483,25 @@ static int ceph_zero_partial_object(struct inode *inode,
|
|
op = CEPH_OSD_OP_ZERO;
|
|
}
|
|
|
|
+ spin_lock(&ci->i_ceph_lock);
|
|
+ if (__ceph_have_pending_cap_snap(ci)) {
|
|
+ struct ceph_cap_snap *capsnap =
|
|
+ list_last_entry(&ci->i_cap_snaps,
|
|
+ struct ceph_cap_snap,
|
|
+ ci_item);
|
|
+ snapc = ceph_get_snap_context(capsnap->context);
|
|
+ } else {
|
|
+ BUG_ON(!ci->i_head_snapc);
|
|
+ snapc = ceph_get_snap_context(ci->i_head_snapc);
|
|
+ }
|
|
+ spin_unlock(&ci->i_ceph_lock);
|
|
+
|
|
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
|
|
ceph_vino(inode),
|
|
offset, length,
|
|
0, 1, op,
|
|
CEPH_OSD_FLAG_WRITE,
|
|
- NULL, 0, 0, false);
|
|
+ snapc, 0, 0, false);
|
|
if (IS_ERR(req)) {
|
|
ret = PTR_ERR(req);
|
|
goto out;
|
|
@@ -2501,6 +2515,7 @@ static int ceph_zero_partial_object(struct inode *inode,
|
|
ceph_osdc_put_request(req);
|
|
|
|
out:
|
|
+ ceph_put_snap_context(snapc);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
|
|
index a3d3c9fc64262f..8d9cd6574d3265 100644
|
|
--- a/fs/ext4/extents.c
|
|
+++ b/fs/ext4/extents.c
|
|
@@ -3172,6 +3172,9 @@ static int ext4_split_extent_at(handle_t *handle,
|
|
BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) ==
|
|
(EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2));
|
|
|
|
+ /* Do not cache extents that are in the process of being modified. */
|
|
+ flags |= EXT4_EX_NOCACHE;
|
|
+
|
|
ext_debug(inode, "logical block %llu\n", (unsigned long long)split);
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
@@ -3342,6 +3345,9 @@ static int ext4_split_extent(handle_t *handle,
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
|
|
|
+ /* Do not cache extents that are in the process of being modified. */
|
|
+ flags |= EXT4_EX_NOCACHE;
|
|
+
|
|
if (map->m_lblk + map->m_len < ee_block + ee_len) {
|
|
split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
|
|
flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
|
|
@@ -5252,7 +5258,8 @@ again:
|
|
if (!extent) {
|
|
EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
|
|
(unsigned long) *iterator);
|
|
- return -EFSCORRUPTED;
|
|
+ ret = -EFSCORRUPTED;
|
|
+ goto out;
|
|
}
|
|
if (SHIFT == SHIFT_LEFT && *iterator >
|
|
le32_to_cpu(extent->ee_block)) {
|
|
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
|
|
index 4f931f80cb3489..d34affd2075eb4 100644
|
|
--- a/fs/ext4/ioctl.c
|
|
+++ b/fs/ext4/ioctl.c
|
|
@@ -963,6 +963,7 @@ static long ext4_ioctl_group_add(struct file *file,
|
|
|
|
err = ext4_group_add(sb, input);
|
|
if (EXT4_SB(sb)->s_journal) {
|
|
+ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE, NULL);
|
|
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
|
|
err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal, 0);
|
|
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
|
|
@@ -1315,6 +1316,8 @@ setversion_out:
|
|
|
|
err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
|
|
if (EXT4_SB(sb)->s_journal) {
|
|
+ ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE,
|
|
+ NULL);
|
|
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
|
|
err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal, 0);
|
|
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
|
|
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
|
|
index 5ba161bd66a3ef..d095c4a218a3ac 100644
|
|
--- a/fs/ext4/mballoc.c
|
|
+++ b/fs/ext4/mballoc.c
|
|
@@ -1090,8 +1090,6 @@ static inline int should_optimize_scan(struct ext4_allocation_context *ac)
|
|
return 0;
|
|
if (ac->ac_criteria >= CR_GOAL_LEN_SLOW)
|
|
return 0;
|
|
- if (!ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS))
|
|
- return 0;
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
|
index c5c6faa995e1c5..561f670768f966 100644
|
|
--- a/fs/ext4/super.c
|
|
+++ b/fs/ext4/super.c
|
|
@@ -5563,6 +5563,10 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
|
|
clear_opt2(sb, MB_OPTIMIZE_SCAN);
|
|
}
|
|
|
|
+ err = ext4_percpu_param_init(sbi);
|
|
+ if (err)
|
|
+ goto failed_mount5;
|
|
+
|
|
err = ext4_mb_init(sb);
|
|
if (err) {
|
|
ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
|
|
@@ -5578,10 +5582,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
|
|
sbi->s_journal->j_commit_callback =
|
|
ext4_journal_commit_callback;
|
|
|
|
- err = ext4_percpu_param_init(sbi);
|
|
- if (err)
|
|
- goto failed_mount6;
|
|
-
|
|
if (ext4_has_feature_flex_bg(sb))
|
|
if (!ext4_fill_flex_info(sb)) {
|
|
ext4_msg(sb, KERN_ERR,
|
|
@@ -5661,8 +5661,8 @@ failed_mount7:
|
|
failed_mount6:
|
|
ext4_mb_release(sb);
|
|
ext4_flex_groups_free(sbi);
|
|
- ext4_percpu_param_destroy(sbi);
|
|
failed_mount5:
|
|
+ ext4_percpu_param_destroy(sbi);
|
|
ext4_ext_release(sb);
|
|
ext4_release_system_zone(sb);
|
|
failed_mount4a:
|
|
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
|
|
index 2116c486843b7d..e189fbf95fcace 100644
|
|
--- a/fs/fat/namei_msdos.c
|
|
+++ b/fs/fat/namei_msdos.c
|
|
@@ -325,7 +325,12 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
|
|
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
|
|
if (err)
|
|
goto out;
|
|
- drop_nlink(dir);
|
|
+ if (dir->i_nlink >= 3)
|
|
+ drop_nlink(dir);
|
|
+ else {
|
|
+ fat_fs_error(sb, "parent dir link count too low (%u)",
|
|
+ dir->i_nlink);
|
|
+ }
|
|
|
|
clear_nlink(inode);
|
|
fat_truncate_time(inode, NULL, S_CTIME);
|
|
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
|
|
index 3cf22a6727f1b6..7d7ac30c6eff81 100644
|
|
--- a/fs/fat/namei_vfat.c
|
|
+++ b/fs/fat/namei_vfat.c
|
|
@@ -806,7 +806,12 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
|
|
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
|
|
if (err)
|
|
goto out;
|
|
- drop_nlink(dir);
|
|
+ if (dir->i_nlink >= 3)
|
|
+ drop_nlink(dir);
|
|
+ else {
|
|
+ fat_fs_error(sb, "parent dir link count too low (%u)",
|
|
+ dir->i_nlink);
|
|
+ }
|
|
|
|
clear_nlink(inode);
|
|
fat_truncate_time(inode, NULL, S_ATIME|S_MTIME);
|
|
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
|
|
index 64c2d0814ed688..100bd3474476b2 100644
|
|
--- a/fs/fs_struct.c
|
|
+++ b/fs/fs_struct.c
|
|
@@ -6,6 +6,7 @@
|
|
#include <linux/path.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/fs_struct.h>
|
|
+#include <linux/init_task.h>
|
|
#include "internal.h"
|
|
|
|
/*
|
|
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
|
|
index 7ed276a8f599d4..bc0f7023adcf33 100644
|
|
--- a/fs/gfs2/bmap.c
|
|
+++ b/fs/gfs2/bmap.c
|
|
@@ -317,6 +317,12 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
|
|
}
|
|
}
|
|
|
|
+static inline struct buffer_head *
|
|
+metapath_dibh(struct metapath *mp)
|
|
+{
|
|
+ return mp->mp_bh[0];
|
|
+}
|
|
+
|
|
static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp,
|
|
unsigned int x, unsigned int h)
|
|
{
|
|
@@ -660,7 +666,7 @@ static int __gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
|
|
{
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
- struct buffer_head *dibh = mp->mp_bh[0];
|
|
+ struct buffer_head *dibh = metapath_dibh(mp);
|
|
u64 bn;
|
|
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
|
|
size_t dblks = iomap->length >> inode->i_blkbits;
|
|
@@ -1120,10 +1126,18 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
|
|
goto out_unlock;
|
|
break;
|
|
default:
|
|
- goto out_unlock;
|
|
+ goto out;
|
|
}
|
|
|
|
ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);
|
|
+ if (ret)
|
|
+ goto out_unlock;
|
|
+
|
|
+out:
|
|
+ if (iomap->type == IOMAP_INLINE) {
|
|
+ iomap->private = metapath_dibh(&mp);
|
|
+ get_bh(iomap->private);
|
|
+ }
|
|
|
|
out_unlock:
|
|
release_metapath(&mp);
|
|
@@ -1137,6 +1151,9 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
|
|
+ if (iomap->private)
|
|
+ brelse(iomap->private);
|
|
+
|
|
switch (flags & (IOMAP_WRITE | IOMAP_ZERO)) {
|
|
case IOMAP_WRITE:
|
|
if (flags & IOMAP_DIRECT)
|
|
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
|
|
index c4bc86c3535ba6..9265262807f098 100644
|
|
--- a/fs/gfs2/glock.c
|
|
+++ b/fs/gfs2/glock.c
|
|
@@ -1396,31 +1396,45 @@ static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs)
|
|
* gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions
|
|
* @num_gh: the number of holders in the array
|
|
* @ghs: the glock holder array
|
|
+ * @retries: number of retries attempted so far
|
|
*
|
|
* Returns: 0 on success, meaning all glocks have been granted and are held.
|
|
* -ESTALE if the request timed out, meaning all glocks were released,
|
|
* and the caller should retry the operation.
|
|
*/
|
|
|
|
-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
|
|
+int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs,
|
|
+ unsigned int retries)
|
|
{
|
|
struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd;
|
|
- int i, ret = 0, timeout = 0;
|
|
unsigned long start_time = jiffies;
|
|
+ int i, ret = 0;
|
|
+ long timeout;
|
|
|
|
might_sleep();
|
|
- /*
|
|
- * Total up the (minimum hold time * 2) of all glocks and use that to
|
|
- * determine the max amount of time we should wait.
|
|
- */
|
|
- for (i = 0; i < num_gh; i++)
|
|
- timeout += ghs[i].gh_gl->gl_hold_time << 1;
|
|
|
|
- if (!wait_event_timeout(sdp->sd_async_glock_wait,
|
|
+ timeout = GL_GLOCK_MIN_HOLD;
|
|
+ if (retries) {
|
|
+ unsigned int max_shift;
|
|
+ long incr;
|
|
+
|
|
+ /* Add a random delay and increase the timeout exponentially. */
|
|
+ max_shift = BITS_PER_LONG - 2 - __fls(GL_GLOCK_HOLD_INCR);
|
|
+ incr = min(GL_GLOCK_HOLD_INCR << min(retries - 1, max_shift),
|
|
+ 10 * HZ - GL_GLOCK_MIN_HOLD);
|
|
+ schedule_timeout_interruptible(get_random_long() % (incr / 3));
|
|
+ if (signal_pending(current))
|
|
+ goto interrupted;
|
|
+ timeout += (incr / 3) + get_random_long() % (incr / 3);
|
|
+ }
|
|
+
|
|
+ if (!wait_event_interruptible_timeout(sdp->sd_async_glock_wait,
|
|
!glocks_pending(num_gh, ghs), timeout)) {
|
|
ret = -ESTALE; /* request timed out. */
|
|
goto out;
|
|
}
|
|
+ if (signal_pending(current))
|
|
+ goto interrupted;
|
|
|
|
for (i = 0; i < num_gh; i++) {
|
|
struct gfs2_holder *gh = &ghs[i];
|
|
@@ -1444,6 +1458,10 @@ out:
|
|
}
|
|
}
|
|
return ret;
|
|
+
|
|
+interrupted:
|
|
+ ret = -EINTR;
|
|
+ goto out;
|
|
}
|
|
|
|
/**
|
|
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
|
|
index aae9fabbb76cc0..e86dccdd613321 100644
|
|
--- a/fs/gfs2/glock.h
|
|
+++ b/fs/gfs2/glock.h
|
|
@@ -204,7 +204,8 @@ int gfs2_glock_poll(struct gfs2_holder *gh);
|
|
int gfs2_instantiate(struct gfs2_holder *gh);
|
|
int gfs2_glock_holder_ready(struct gfs2_holder *gh);
|
|
int gfs2_glock_wait(struct gfs2_holder *gh);
|
|
-int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs);
|
|
+int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs,
|
|
+ unsigned int retries);
|
|
void gfs2_glock_dq(struct gfs2_holder *gh);
|
|
void gfs2_glock_dq_wait(struct gfs2_holder *gh);
|
|
void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
|
|
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
|
|
index 1cb5ce63fbf697..45040622d316e0 100644
|
|
--- a/fs/gfs2/inode.c
|
|
+++ b/fs/gfs2/inode.c
|
|
@@ -1408,7 +1408,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|
unsigned int num_gh;
|
|
int dir_rename = 0;
|
|
struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, };
|
|
- unsigned int x;
|
|
+ unsigned int retries = 0, x;
|
|
int error;
|
|
|
|
gfs2_holder_mark_uninitialized(&r_gh);
|
|
@@ -1458,12 +1458,17 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|
num_gh++;
|
|
}
|
|
|
|
+again:
|
|
for (x = 0; x < num_gh; x++) {
|
|
error = gfs2_glock_nq(ghs + x);
|
|
if (error)
|
|
goto out_gunlock;
|
|
}
|
|
- error = gfs2_glock_async_wait(num_gh, ghs);
|
|
+ error = gfs2_glock_async_wait(num_gh, ghs, retries);
|
|
+ if (error == -ESTALE) {
|
|
+ retries++;
|
|
+ goto again;
|
|
+ }
|
|
if (error)
|
|
goto out_gunlock;
|
|
|
|
@@ -1652,7 +1657,7 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry,
|
|
struct gfs2_sbd *sdp = GFS2_SB(odir);
|
|
struct gfs2_holder ghs[4], r_gh;
|
|
unsigned int num_gh;
|
|
- unsigned int x;
|
|
+ unsigned int retries = 0, x;
|
|
umode_t old_mode = oip->i_inode.i_mode;
|
|
umode_t new_mode = nip->i_inode.i_mode;
|
|
int error;
|
|
@@ -1696,13 +1701,18 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry,
|
|
gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, GL_ASYNC, ghs + num_gh);
|
|
num_gh++;
|
|
|
|
+again:
|
|
for (x = 0; x < num_gh; x++) {
|
|
error = gfs2_glock_nq(ghs + x);
|
|
if (error)
|
|
goto out_gunlock;
|
|
}
|
|
|
|
- error = gfs2_glock_async_wait(num_gh, ghs);
|
|
+ error = gfs2_glock_async_wait(num_gh, ghs, retries);
|
|
+ if (error == -ESTALE) {
|
|
+ retries++;
|
|
+ goto again;
|
|
+ }
|
|
if (error)
|
|
goto out_gunlock;
|
|
|
|
@@ -2095,6 +2105,14 @@ static int gfs2_getattr(struct mnt_idmap *idmap,
|
|
return 0;
|
|
}
|
|
|
|
+static bool fault_in_fiemap(struct fiemap_extent_info *fi)
|
|
+{
|
|
+ struct fiemap_extent __user *dest = fi->fi_extents_start;
|
|
+ size_t size = sizeof(*dest) * fi->fi_extents_max;
|
|
+
|
|
+ return fault_in_safe_writeable((char __user *)dest, size) == 0;
|
|
+}
|
|
+
|
|
static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|
u64 start, u64 len)
|
|
{
|
|
@@ -2104,14 +2122,22 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|
|
|
inode_lock_shared(inode);
|
|
|
|
+retry:
|
|
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
|
if (ret)
|
|
goto out;
|
|
|
|
+ pagefault_disable();
|
|
ret = iomap_fiemap(inode, fieinfo, start, len, &gfs2_iomap_ops);
|
|
+ pagefault_enable();
|
|
|
|
gfs2_glock_dq_uninit(&gh);
|
|
|
|
+ if (ret == -EFAULT && fault_in_fiemap(fieinfo)) {
|
|
+ fieinfo->fi_extents_mapped = 0;
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
out:
|
|
inode_unlock_shared(inode);
|
|
return ret;
|
|
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
|
|
index c0089849be50ed..fb437598e26259 100644
|
|
--- a/fs/hfsplus/bnode.c
|
|
+++ b/fs/hfsplus/bnode.c
|
|
@@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
|
|
if (node) {
|
|
pr_crit("new node %u already hashed?\n", num);
|
|
WARN_ON(1);
|
|
- return node;
|
|
+ return ERR_PTR(-EEXIST);
|
|
}
|
|
node = __hfs_bnode_create(tree, num);
|
|
if (!node)
|
|
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
|
|
index 2619e5371ec9c7..2dd17192d11c37 100644
|
|
--- a/fs/hfsplus/inode.c
|
|
+++ b/fs/hfsplus/inode.c
|
|
@@ -604,6 +604,7 @@ out:
|
|
int hfsplus_cat_write_inode(struct inode *inode)
|
|
{
|
|
struct inode *main_inode = inode;
|
|
+ struct hfs_btree *tree = HFSPLUS_SB(inode->i_sb)->cat_tree;
|
|
struct hfs_find_data fd;
|
|
hfsplus_cat_entry entry;
|
|
int res = 0;
|
|
@@ -614,7 +615,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
|
|
if (!main_inode->i_nlink)
|
|
return 0;
|
|
|
|
- if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
|
|
+ if (hfs_find_init(tree, &fd))
|
|
/* panic? */
|
|
return -EIO;
|
|
|
|
@@ -679,6 +680,15 @@ int hfsplus_cat_write_inode(struct inode *inode)
|
|
set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
|
|
out:
|
|
hfs_find_exit(&fd);
|
|
+
|
|
+ if (!res) {
|
|
+ res = hfs_btree_write(tree);
|
|
+ if (res) {
|
|
+ pr_err("b-tree write err: %d, ino %lu\n",
|
|
+ res, inode->i_ino);
|
|
+ }
|
|
+ }
|
|
+
|
|
return res;
|
|
}
|
|
|
|
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
|
|
index 7e889820a63d0b..954ceaa748e624 100644
|
|
--- a/fs/hfsplus/super.c
|
|
+++ b/fs/hfsplus/super.c
|
|
@@ -52,6 +52,12 @@ static int hfsplus_system_read_inode(struct inode *inode)
|
|
return -EIO;
|
|
}
|
|
|
|
+ /*
|
|
+ * Assign a dummy file type, for may_open() requires that
|
|
+ * an inode has a valid file type.
|
|
+ */
|
|
+ inode->i_mode = S_IFREG;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
|
|
index 8158ab18e1ae8c..ec6b019f087fdc 100644
|
|
--- a/fs/iomap/direct-io.c
|
|
+++ b/fs/iomap/direct-io.c
|
|
@@ -381,9 +381,13 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
|
|
nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS);
|
|
do {
|
|
size_t n;
|
|
- if (dio->error) {
|
|
- iov_iter_revert(dio->submit.iter, copied);
|
|
- copied = ret = 0;
|
|
+
|
|
+ /*
|
|
+ * If completions already occurred and reported errors, give up now and
|
|
+ * don't bother submitting more bios.
|
|
+ */
|
|
+ if (unlikely(data_race(dio->error))) {
|
|
+ ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
|
|
index cb6d1fda66a702..32e589bb663ae8 100644
|
|
--- a/fs/jfs/jfs_logmgr.c
|
|
+++ b/fs/jfs/jfs_logmgr.c
|
|
@@ -2312,6 +2312,7 @@ int jfsIOWait(void *arg)
|
|
{
|
|
struct lbuf *bp;
|
|
|
|
+ set_freezable();
|
|
do {
|
|
spin_lock_irq(&log_redrive_lock);
|
|
while ((bp = log_redrive_list)) {
|
|
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
|
|
index 57d7a4300210d2..649184d712ad0e 100644
|
|
--- a/fs/jfs/namei.c
|
|
+++ b/fs/jfs/namei.c
|
|
@@ -1227,7 +1227,7 @@ static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
|
jfs_err("jfs_rename: dtInsert returned -EIO");
|
|
goto out_tx;
|
|
}
|
|
- if (S_ISDIR(old_ip->i_mode))
|
|
+ if (S_ISDIR(old_ip->i_mode) && old_dir != new_dir)
|
|
inc_nlink(new_dir);
|
|
}
|
|
/*
|
|
@@ -1243,7 +1243,9 @@ static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
|
goto out_tx;
|
|
}
|
|
if (S_ISDIR(old_ip->i_mode)) {
|
|
- drop_nlink(old_dir);
|
|
+ if (new_ip || old_dir != new_dir)
|
|
+ drop_nlink(old_dir);
|
|
+
|
|
if (old_dir != new_dir) {
|
|
/*
|
|
* Change inode number of parent for moved directory
|
|
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
|
|
index ee8a6fe360e728..820c7753bd1059 100644
|
|
--- a/fs/minix/inode.c
|
|
+++ b/fs/minix/inode.c
|
|
@@ -153,10 +153,38 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
|
|
static bool minix_check_superblock(struct super_block *sb)
|
|
{
|
|
struct minix_sb_info *sbi = minix_sb(sb);
|
|
+ unsigned long block;
|
|
|
|
- if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
|
|
+ if (sbi->s_log_zone_size != 0) {
|
|
+ printk("minix-fs error: zone size must equal block size. "
|
|
+ "s_log_zone_size > 0 is not supported.\n");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (sbi->s_ninodes < 1 || sbi->s_firstdatazone <= 4 ||
|
|
+ sbi->s_firstdatazone >= sbi->s_nzones)
|
|
return false;
|
|
|
|
+ /* Apparently minix can create filesystems that allocate more blocks for
|
|
+ * the bitmaps than needed. We simply ignore that, but verify it didn't
|
|
+ * create one with not enough blocks and bail out if so.
|
|
+ */
|
|
+ block = minix_blocks_needed(sbi->s_ninodes, sb->s_blocksize);
|
|
+ if (sbi->s_imap_blocks < block) {
|
|
+ printk("MINIX-fs: file system does not have enough "
|
|
+ "imap blocks allocated. Refusing to mount.\n");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ block = minix_blocks_needed(
|
|
+ (sbi->s_nzones - sbi->s_firstdatazone + 1),
|
|
+ sb->s_blocksize);
|
|
+ if (sbi->s_zmap_blocks < block) {
|
|
+ printk("MINIX-fs: file system does not have enough "
|
|
+ "zmap blocks allocated. Refusing to mount.\n");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
/*
|
|
* s_max_size must not exceed the block mapping limitation. This check
|
|
* is only needed for V1 filesystems, since V2/V3 support an extra level
|
|
@@ -275,26 +303,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
|
|
minix_set_bit(0,sbi->s_imap[0]->b_data);
|
|
minix_set_bit(0,sbi->s_zmap[0]->b_data);
|
|
|
|
- /* Apparently minix can create filesystems that allocate more blocks for
|
|
- * the bitmaps than needed. We simply ignore that, but verify it didn't
|
|
- * create one with not enough blocks and bail out if so.
|
|
- */
|
|
- block = minix_blocks_needed(sbi->s_ninodes, s->s_blocksize);
|
|
- if (sbi->s_imap_blocks < block) {
|
|
- printk("MINIX-fs: file system does not have enough "
|
|
- "imap blocks allocated. Refusing to mount.\n");
|
|
- goto out_no_bitmap;
|
|
- }
|
|
-
|
|
- block = minix_blocks_needed(
|
|
- (sbi->s_nzones - sbi->s_firstdatazone + 1),
|
|
- s->s_blocksize);
|
|
- if (sbi->s_zmap_blocks < block) {
|
|
- printk("MINIX-fs: file system does not have enough "
|
|
- "zmap blocks allocated. Refusing to mount.\n");
|
|
- goto out_no_bitmap;
|
|
- }
|
|
-
|
|
/* set up enough so that it can read an inode */
|
|
s->s_op = &minix_sops;
|
|
s->s_time_min = 0;
|
|
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
|
|
index 32e922a20d0d4f..46f53f40b741aa 100644
|
|
--- a/fs/nfs/dir.c
|
|
+++ b/fs/nfs/dir.c
|
|
@@ -70,7 +70,7 @@ const struct address_space_operations nfs_dir_aops = {
|
|
.free_folio = nfs_readdir_clear_array,
|
|
};
|
|
|
|
-#define NFS_INIT_DTSIZE PAGE_SIZE
|
|
+#define NFS_INIT_DTSIZE SZ_64K
|
|
|
|
static struct nfs_open_dir_context *
|
|
alloc_nfs_open_dir_context(struct inode *dir)
|
|
@@ -81,7 +81,7 @@ alloc_nfs_open_dir_context(struct inode *dir)
|
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
|
|
if (ctx != NULL) {
|
|
ctx->attr_gencount = nfsi->attr_gencount;
|
|
- ctx->dtsize = NFS_INIT_DTSIZE;
|
|
+ ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE);
|
|
spin_lock(&dir->i_lock);
|
|
if (list_empty(&nfsi->open_files) &&
|
|
(nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
|
|
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
|
|
index 0737d9a15d862c..7dae2004c65f90 100644
|
|
--- a/fs/nfs/pnfs.c
|
|
+++ b/fs/nfs/pnfs.c
|
|
@@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
|
|
};
|
|
struct pnfs_layout_segment *lseg, *next;
|
|
|
|
- set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
|
|
+ if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
|
|
+ return !list_empty(&lo->plh_segs);
|
|
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags);
|
|
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
|
|
pnfs_clear_lseg_state(lseg, lseg_list);
|
|
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
|
|
index 8cca1329f3485c..c319c31b0f6476 100644
|
|
--- a/fs/nfsd/nfs4idmap.c
|
|
+++ b/fs/nfsd/nfs4idmap.c
|
|
@@ -643,34 +643,74 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr,
|
|
return idmap_id_to_name(xdr, rqstp, type, id);
|
|
}
|
|
|
|
-__be32
|
|
-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
|
- kuid_t *uid)
|
|
+/**
|
|
+ * nfsd_map_name_to_uid - Map user@domain to local UID
|
|
+ * @rqstp: RPC execution context
|
|
+ * @name: user@domain name to be mapped
|
|
+ * @namelen: length of name, in bytes
|
|
+ * @uid: OUT: mapped local UID value
|
|
+ *
|
|
+ * Returns nfs_ok on success or an NFSv4 status code on failure.
|
|
+ */
|
|
+__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name,
|
|
+ size_t namelen, kuid_t *uid)
|
|
{
|
|
__be32 status;
|
|
u32 id = -1;
|
|
|
|
+ /*
|
|
+ * The idmap lookup below triggers an upcall that invokes
|
|
+ * cache_check(). RQ_USEDEFERRAL must be clear to prevent
|
|
+ * cache_check() from setting RQ_DROPME via svc_defer().
|
|
+ * NFSv4 servers are not permitted to drop requests. Also
|
|
+ * RQ_DROPME will force NFSv4.1 session slot processing to
|
|
+ * be skipped.
|
|
+ */
|
|
+ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
|
|
+
|
|
if (name == NULL || namelen == 0)
|
|
return nfserr_inval;
|
|
|
|
status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
|
|
+ if (status)
|
|
+ return status;
|
|
*uid = make_kuid(nfsd_user_namespace(rqstp), id);
|
|
if (!uid_valid(*uid))
|
|
status = nfserr_badowner;
|
|
return status;
|
|
}
|
|
|
|
-__be32
|
|
-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
|
- kgid_t *gid)
|
|
+/**
|
|
+ * nfsd_map_name_to_gid - Map user@domain to local GID
|
|
+ * @rqstp: RPC execution context
|
|
+ * @name: user@domain name to be mapped
|
|
+ * @namelen: length of name, in bytes
|
|
+ * @gid: OUT: mapped local GID value
|
|
+ *
|
|
+ * Returns nfs_ok on success or an NFSv4 status code on failure.
|
|
+ */
|
|
+__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name,
|
|
+ size_t namelen, kgid_t *gid)
|
|
{
|
|
__be32 status;
|
|
u32 id = -1;
|
|
|
|
+ /*
|
|
+ * The idmap lookup below triggers an upcall that invokes
|
|
+ * cache_check(). RQ_USEDEFERRAL must be clear to prevent
|
|
+ * cache_check() from setting RQ_DROPME via svc_defer().
|
|
+ * NFSv4 servers are not permitted to drop requests. Also
|
|
+ * RQ_DROPME will force NFSv4.1 session slot processing to
|
|
+ * be skipped.
|
|
+ */
|
|
+ WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
|
|
+
|
|
if (name == NULL || namelen == 0)
|
|
return nfserr_inval;
|
|
|
|
status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
|
|
+ if (status)
|
|
+ return status;
|
|
*gid = make_kgid(nfsd_user_namespace(rqstp), id);
|
|
if (!gid_valid(*gid))
|
|
status = nfserr_badowner;
|
|
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
|
|
index a126fae2df5664..5767080362e85a 100644
|
|
--- a/fs/nfsd/nfs4proc.c
|
|
+++ b/fs/nfsd/nfs4proc.c
|
|
@@ -2763,8 +2763,6 @@ encode_op:
|
|
BUG_ON(cstate->replay_owner);
|
|
out:
|
|
cstate->status = status;
|
|
- /* Reset deferral mechanism for RPC deferrals */
|
|
- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
|
return rpc_success;
|
|
}
|
|
|
|
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
|
|
index 15189e683e834d..d84eaae7cd0b62 100644
|
|
--- a/fs/nfsd/nfs4xdr.c
|
|
+++ b/fs/nfsd/nfs4xdr.c
|
|
@@ -5492,6 +5492,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
|
args->ops = args->iops;
|
|
args->rqstp = rqstp;
|
|
|
|
+ /*
|
|
+ * NFSv4 operation decoders can invoke svc cache lookups
|
|
+ * that trigger svc_defer() when RQ_USEDEFERRAL is set,
|
|
+ * setting RQ_DROPME. This creates two problems:
|
|
+ *
|
|
+ * 1. Non-idempotency: Compounds make it too hard to avoid
|
|
+ * problems if a request is deferred and replayed.
|
|
+ *
|
|
+ * 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set
|
|
+ * during decode but SEQUENCE executes successfully, the
|
|
+ * session slot will be marked INUSE. The request is then
|
|
+ * dropped before encoding, so the slot is never released,
|
|
+ * rendering it permanently unusable by the client.
|
|
+ */
|
|
+ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
|
+
|
|
return nfsd4_decode_compound(args);
|
|
}
|
|
|
|
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
|
|
index e25989dd2c6bba..8f033e30e0d799 100644
|
|
--- a/fs/ntfs3/attrib.c
|
|
+++ b/fs/ntfs3/attrib.c
|
|
@@ -449,8 +449,10 @@ again:
|
|
|
|
is_ext = is_attr_ext(attr_b);
|
|
align = sbi->cluster_size;
|
|
- if (is_ext)
|
|
+ if (is_ext) {
|
|
align <<= attr_b->nres.c_unit;
|
|
+ keep_prealloc = false;
|
|
+ }
|
|
|
|
old_valid = le64_to_cpu(attr_b->nres.valid_size);
|
|
old_size = le64_to_cpu(attr_b->nres.data_size);
|
|
@@ -1367,19 +1369,28 @@ int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
|
CLST vcn;
|
|
CLST vcn_last = (to - 1) >> cluster_bits;
|
|
CLST lcn, clen;
|
|
- int err;
|
|
+ int err = 0;
|
|
+ int retry = 0;
|
|
|
|
for (vcn = from >> cluster_bits; vcn <= vcn_last; vcn += clen) {
|
|
if (!run_lookup_entry(run, vcn, &lcn, &clen, NULL)) {
|
|
+ if (retry != 0) { /* Next run_lookup_entry(vcn) also failed. */
|
|
+ err = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
err = attr_load_runs_vcn(ni, type, name, name_len, run,
|
|
vcn);
|
|
if (err)
|
|
- return err;
|
|
+ break;
|
|
+
|
|
clen = 0; /* Next run_lookup_entry(vcn) must be success. */
|
|
+ retry++;
|
|
}
|
|
+ else
|
|
+ retry = 0;
|
|
}
|
|
|
|
- return 0;
|
|
+ return err;
|
|
}
|
|
|
|
#ifdef CONFIG_NTFS3_LZX_XPRESS
|
|
diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c
|
|
index 9f4bd8d260901c..9355b4416719d0 100644
|
|
--- a/fs/ntfs3/attrlist.c
|
|
+++ b/fs/ntfs3/attrlist.c
|
|
@@ -52,6 +52,11 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
|
|
|
|
if (!attr->non_res) {
|
|
lsize = le32_to_cpu(attr->res.data_size);
|
|
+ if (!lsize) {
|
|
+ err = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
/* attr is resident: lsize < record_size (1K or 4K) */
|
|
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
|
|
if (!le) {
|
|
@@ -66,6 +71,10 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
|
|
u16 run_off = le16_to_cpu(attr->nres.run_off);
|
|
|
|
lsize = le64_to_cpu(attr->nres.data_size);
|
|
+ if (!lsize) {
|
|
+ err = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
|
|
run_init(&ni->attr_list.run);
|
|
|
|
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
|
|
index a7fe2e02c32ee6..212737a816d7af 100644
|
|
--- a/fs/ntfs3/file.c
|
|
+++ b/fs/ntfs3/file.c
|
|
@@ -901,8 +901,12 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
|
goto out;
|
|
|
|
if (lcn == SPARSE_LCN) {
|
|
- ni->i_valid = valid =
|
|
- frame_vbo + ((u64)clen << sbi->cluster_bits);
|
|
+ valid = frame_vbo + ((u64)clen << sbi->cluster_bits);
|
|
+ if (ni->i_valid == valid) {
|
|
+ err = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+ ni->i_valid = valid;
|
|
continue;
|
|
}
|
|
|
|
diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
|
|
index 2a1aeab53ea4b5..598b7f42b5e7ec 100644
|
|
--- a/fs/ntfs3/fslog.c
|
|
+++ b/fs/ntfs3/fslog.c
|
|
@@ -3431,6 +3431,9 @@ move_data:
|
|
|
|
e1 = Add2Ptr(attr, le16_to_cpu(lrh->attr_off));
|
|
esize = le16_to_cpu(e1->size);
|
|
+ if (PtrOffset(e1, Add2Ptr(hdr, used)) < esize)
|
|
+ goto dirty_vol;
|
|
+
|
|
e2 = Add2Ptr(e1, esize);
|
|
|
|
memmove(e1, e2, PtrOffset(e2, Add2Ptr(hdr, used)));
|
|
diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
|
|
index 446079b0866d4c..e17d4c1ba06f0a 100644
|
|
--- a/fs/ntfs3/fsntfs.c
|
|
+++ b/fs/ntfs3/fsntfs.c
|
|
@@ -1272,6 +1272,12 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
|
|
|
} while (len32);
|
|
|
|
+ if (!run) {
|
|
+ err = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* Get next fragment to read. */
|
|
vcn_next = vcn + clen;
|
|
if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
|
|
vcn != vcn_next) {
|
|
diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
|
|
index f227db9f76c2b4..4330c2b39e505a 100644
|
|
--- a/fs/ntfs3/index.c
|
|
+++ b/fs/ntfs3/index.c
|
|
@@ -1192,7 +1192,12 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- fnd_push(fnd, node, e);
|
|
+ err = fnd_push(fnd, node, e);
|
|
+
|
|
+ if (err) {
|
|
+ put_indx_node(node);
|
|
+ return err;
|
|
+ }
|
|
}
|
|
|
|
*entry = e;
|
|
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
|
|
index c2268b9e20a6d3..d0cb529b612a7f 100644
|
|
--- a/fs/ocfs2/xattr.c
|
|
+++ b/fs/ocfs2/xattr.c
|
|
@@ -6373,6 +6373,10 @@ static int ocfs2_reflink_xattr_header(handle_t *handle,
|
|
(void *)last - (void *)xe);
|
|
memset(last, 0,
|
|
sizeof(struct ocfs2_xattr_entry));
|
|
+ last = &new_xh->xh_entries[le16_to_cpu(new_xh->xh_count)] - 1;
|
|
+ } else {
|
|
+ memset(xe, 0, sizeof(struct ocfs2_xattr_entry));
|
|
+ last = NULL;
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
|
|
index de39e067ae65a5..0d667e95345737 100644
|
|
--- a/fs/overlayfs/readdir.c
|
|
+++ b/fs/overlayfs/readdir.c
|
|
@@ -659,7 +659,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
|
|
container_of(ctx, struct ovl_readdir_translate, ctx);
|
|
struct dir_context *orig_ctx = rdt->orig_ctx;
|
|
|
|
- if (rdt->parent_ino && strcmp(name, "..") == 0) {
|
|
+ if (rdt->parent_ino && namelen == 2 && !strncmp(name, "..", 2)) {
|
|
ino = rdt->parent_ino;
|
|
} else if (rdt->cache) {
|
|
struct ovl_cache_entry *p;
|
|
diff --git a/fs/proc/array.c b/fs/proc/array.c
|
|
index 5e4f7b411fbdb9..363d9331216b91 100644
|
|
--- a/fs/proc/array.c
|
|
+++ b/fs/proc/array.c
|
|
@@ -531,7 +531,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
|
|
}
|
|
|
|
sid = task_session_nr_ns(task, ns);
|
|
- ppid = task_tgid_nr_ns(task->real_parent, ns);
|
|
+ ppid = task_ppid_nr_ns(task, ns);
|
|
pgid = task_pgrp_nr_ns(task, ns);
|
|
|
|
unlock_task_sighand(task, &flags);
|
|
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
|
|
index f1848cdd6d3485..7b6d6378a3b87d 100644
|
|
--- a/fs/pstore/ram_core.c
|
|
+++ b/fs/pstore/ram_core.c
|
|
@@ -298,6 +298,17 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz)
|
|
if (!size)
|
|
return;
|
|
|
|
+ /*
|
|
+ * If the existing buffer is differently sized, free it so a new
|
|
+ * one is allocated. This can happen when persistent_ram_save_old()
|
|
+ * is called early in boot and later for a timer-triggered
|
|
+ * survivable crash when the crash dumps don't match in size
|
|
+ * (which would be extremely unlikely given kmsg buffers usually
|
|
+ * exceed prz buffer sizes).
|
|
+ */
|
|
+ if (prz->old_log && prz->old_log_size != size)
|
|
+ persistent_ram_free_old(prz);
|
|
+
|
|
if (!prz->old_log) {
|
|
persistent_ram_ecc_old(prz);
|
|
prz->old_log = kvzalloc(size, GFP_KERNEL);
|
|
@@ -446,6 +457,13 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size,
|
|
vaddr = vmap(pages, page_count, VM_MAP | VM_IOREMAP, prot);
|
|
kfree(pages);
|
|
|
|
+ /*
|
|
+ * vmap() may fail and return NULL. Do not add the offset in this
|
|
+ * case, otherwise a NULL mapping would appear successful.
|
|
+ */
|
|
+ if (!vaddr)
|
|
+ return NULL;
|
|
+
|
|
/*
|
|
* Since vmap() uses page granularity, we must add the offset
|
|
* into the page here, to get the byte granularity address
|
|
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
|
|
index 0e41fb84060f52..5be53cae2c95d7 100644
|
|
--- a/fs/quota/quota.c
|
|
+++ b/fs/quota/quota.c
|
|
@@ -899,6 +899,7 @@ retry:
|
|
sb_start_write(sb);
|
|
sb_end_write(sb);
|
|
put_super(sb);
|
|
+ cond_resched();
|
|
goto retry;
|
|
}
|
|
return sb;
|
|
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
|
|
index e92a61e934e447..d83161285a1754 100644
|
|
--- a/fs/smb/client/cached_dir.c
|
|
+++ b/fs/smb/client/cached_dir.c
|
|
@@ -769,11 +769,11 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
|
|
|
dput(dentry);
|
|
if (cfid->is_open) {
|
|
- spin_lock(&cifs_tcp_ses_lock);
|
|
+ spin_lock(&cfid->tcon->tc_lock);
|
|
++cfid->tcon->tc_count;
|
|
trace_smb3_tcon_ref(cfid->tcon->debug_id, cfid->tcon->tc_count,
|
|
netfs_trace_tcon_ref_get_cached_laundromat);
|
|
- spin_unlock(&cifs_tcp_ses_lock);
|
|
+ spin_unlock(&cfid->tcon->tc_lock);
|
|
queue_work(serverclose_wq, &cfid->close_work);
|
|
} else
|
|
/*
|
|
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
|
|
index 86c89917f18e90..59220ebd6eccef 100644
|
|
--- a/fs/smb/client/connect.c
|
|
+++ b/fs/smb/client/connect.c
|
|
@@ -4065,7 +4065,9 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
|
ses->ses_status = SES_IN_SETUP;
|
|
|
|
/* force iface_list refresh */
|
|
+ spin_lock(&ses->iface_lock);
|
|
ses->iface_last_update = 0;
|
|
+ spin_unlock(&ses->iface_lock);
|
|
}
|
|
spin_unlock(&ses->ses_lock);
|
|
|
|
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
|
|
index d436057ed77e32..4e7d5c612256d6 100644
|
|
--- a/fs/smb/client/smb2file.c
|
|
+++ b/fs/smb/client/smb2file.c
|
|
@@ -123,6 +123,8 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
|
|
&err_buftype);
|
|
if (rc == -EACCES && retry_without_read_attributes) {
|
|
free_rsp_buf(err_buftype, err_iov.iov_base);
|
|
+ memset(&err_iov, 0, sizeof(err_iov));
|
|
+ err_buftype = CIFS_NO_BUFFER;
|
|
oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
|
|
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
|
|
&err_buftype);
|
|
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
|
|
index fadc5fc274eb28..70a9536b03c637 100644
|
|
--- a/fs/smb/client/smb2misc.c
|
|
+++ b/fs/smb/client/smb2misc.c
|
|
@@ -807,14 +807,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
|
|
int rc;
|
|
|
|
cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
|
|
- spin_lock(&cifs_tcp_ses_lock);
|
|
+ spin_lock(&tcon->tc_lock);
|
|
if (tcon->tc_count <= 0) {
|
|
struct TCP_Server_Info *server = NULL;
|
|
|
|
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
|
netfs_trace_tcon_ref_see_cancelled_close);
|
|
WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative");
|
|
- spin_unlock(&cifs_tcp_ses_lock);
|
|
+ spin_unlock(&tcon->tc_lock);
|
|
|
|
if (tcon->ses) {
|
|
server = tcon->ses->server;
|
|
@@ -828,7 +828,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
|
|
tcon->tc_count++;
|
|
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
|
netfs_trace_tcon_ref_get_cancelled_close);
|
|
- spin_unlock(&cifs_tcp_ses_lock);
|
|
+ spin_unlock(&tcon->tc_lock);
|
|
|
|
rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0,
|
|
persistent_fid, volatile_fid);
|
|
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
|
|
index 138b3ed08217c9..63752bd02aafe3 100644
|
|
--- a/fs/smb/client/smb2ops.c
|
|
+++ b/fs/smb/client/smb2ops.c
|
|
@@ -595,13 +595,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
|
p = buf;
|
|
|
|
spin_lock(&ses->iface_lock);
|
|
- /* do not query too frequently, this time with lock held */
|
|
- if (ses->iface_last_update &&
|
|
- time_before(jiffies, ses->iface_last_update +
|
|
- (SMB_INTERFACE_POLL_INTERVAL * HZ))) {
|
|
- spin_unlock(&ses->iface_lock);
|
|
- return 0;
|
|
- }
|
|
|
|
/*
|
|
* Go through iface_list and mark them as inactive
|
|
@@ -624,7 +617,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
|
"Empty network interface list returned by server %s\n",
|
|
ses->server->hostname);
|
|
rc = -EOPNOTSUPP;
|
|
- ses->iface_last_update = jiffies;
|
|
goto out;
|
|
}
|
|
|
|
@@ -753,8 +745,6 @@ next_iface:
|
|
+ sizeof(p->Next) && p->Next))
|
|
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
|
|
|
|
- ses->iface_last_update = jiffies;
|
|
-
|
|
out:
|
|
/*
|
|
* Go through the list again and put the inactive entries
|
|
@@ -783,10 +773,17 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
|
|
struct TCP_Server_Info *pserver;
|
|
|
|
/* do not query too frequently */
|
|
+ spin_lock(&ses->iface_lock);
|
|
if (ses->iface_last_update &&
|
|
time_before(jiffies, ses->iface_last_update +
|
|
- (SMB_INTERFACE_POLL_INTERVAL * HZ)))
|
|
+ (SMB_INTERFACE_POLL_INTERVAL * HZ))) {
|
|
+ spin_unlock(&ses->iface_lock);
|
|
return 0;
|
|
+ }
|
|
+
|
|
+ ses->iface_last_update = jiffies;
|
|
+
|
|
+ spin_unlock(&ses->iface_lock);
|
|
|
|
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
|
|
FSCTL_QUERY_NETWORK_INTERFACE_INFO,
|
|
@@ -1147,6 +1144,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
replay_again:
|
|
/* reinitialize for possible replay */
|
|
+ used_len = 0;
|
|
flags = CIFS_CP_CREATE_CLOSE_OP;
|
|
oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
server = cifs_pick_channel(ses);
|
|
@@ -1545,6 +1543,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|
|
|
replay_again:
|
|
/* reinitialize for possible replay */
|
|
+ buffer = NULL;
|
|
flags = CIFS_CP_CREATE_CLOSE_OP;
|
|
oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
server = cifs_pick_channel(ses);
|
|
@@ -2941,7 +2940,9 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|
struct cifs_tcon,
|
|
tcon_list);
|
|
if (tcon) {
|
|
+ spin_lock(&tcon->tc_lock);
|
|
tcon->tc_count++;
|
|
+ spin_unlock(&tcon->tc_lock);
|
|
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
|
netfs_trace_tcon_ref_get_dfs_refer);
|
|
}
|
|
@@ -3006,13 +3007,9 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|
out:
|
|
if (tcon && !tcon->ipc) {
|
|
/* ipc tcons are not refcounted */
|
|
- spin_lock(&cifs_tcp_ses_lock);
|
|
- tcon->tc_count--;
|
|
+ cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_dfs_refer);
|
|
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
|
netfs_trace_tcon_ref_dec_dfs_refer);
|
|
- /* tc_count can never go negative */
|
|
- WARN_ON(tcon->tc_count < 0);
|
|
- spin_unlock(&cifs_tcp_ses_lock);
|
|
}
|
|
kfree(utf16_path);
|
|
kfree(dfs_req);
|
|
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
|
|
index a8890ae2171445..ea73fc5da60309 100644
|
|
--- a/fs/smb/client/smb2pdu.c
|
|
+++ b/fs/smb/client/smb2pdu.c
|
|
@@ -2850,6 +2850,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|
|
|
replay_again:
|
|
/* reinitialize for possible replay */
|
|
+ pc_buf = NULL;
|
|
flags = 0;
|
|
n_iov = 2;
|
|
server = cifs_pick_channel(ses);
|
|
@@ -4174,7 +4175,9 @@ void smb2_reconnect_server(struct work_struct *work)
|
|
|
|
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
|
if (tcon->need_reconnect || tcon->need_reopen_files) {
|
|
+ spin_lock(&tcon->tc_lock);
|
|
tcon->tc_count++;
|
|
+ spin_unlock(&tcon->tc_lock);
|
|
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
|
netfs_trace_tcon_ref_get_reconnect_server);
|
|
list_add_tail(&tcon->rlist, &tmp_list);
|
|
diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
|
|
index be9be8f3633196..359ab64e17d990 100644
|
|
--- a/fs/smb/client/smbdirect.c
|
|
+++ b/fs/smb/client/smbdirect.c
|
|
@@ -91,8 +91,23 @@ int smbd_send_credit_target = 255;
|
|
/* The maximum single message size can be sent to remote peer */
|
|
int smbd_max_send_size = 1364;
|
|
|
|
-/* The maximum fragmented upper-layer payload receive size supported */
|
|
-int smbd_max_fragmented_recv_size = 1024 * 1024;
|
|
+/*
|
|
+ * The maximum fragmented upper-layer payload receive size supported
|
|
+ *
|
|
+ * Assume max_payload_per_credit is
|
|
+ * smbd_max_receive_size - 24 = 1340
|
|
+ *
|
|
+ * The maximum number would be
|
|
+ * smbd_receive_credit_max * max_payload_per_credit
|
|
+ *
|
|
+ * 1340 * 255 = 341700 (0x536C4)
|
|
+ *
|
|
+ * The minimum value from the spec is 131072 (0x20000)
|
|
+ *
|
|
+ * For now we use the logic we used in ksmbd before:
|
|
+ * (1364 * 255) / 2 = 173910 (0x2A756)
|
|
+ */
|
|
+int smbd_max_fragmented_recv_size = (1364 * 255) / 2;
|
|
|
|
/* The maximum single-message size which can be received */
|
|
int smbd_max_receive_size = 1364;
|
|
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
|
|
index 4dfdc521c5c985..17e7ce3b14af06 100644
|
|
--- a/fs/smb/client/trace.h
|
|
+++ b/fs/smb/client/trace.h
|
|
@@ -42,6 +42,7 @@
|
|
EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \
|
|
EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \
|
|
EM(netfs_trace_tcon_ref_put_mnt_ctx, "PUT MntCtx") \
|
|
+ EM(netfs_trace_tcon_ref_put_dfs_refer, "PUT DfsRfr") \
|
|
EM(netfs_trace_tcon_ref_put_reconnect_server, "PUT Reconn") \
|
|
EM(netfs_trace_tcon_ref_put_tlink, "PUT Tlink ") \
|
|
EM(netfs_trace_tcon_ref_see_cancelled_close, "SEE Cn-Cls") \
|
|
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
index 4e5ede2a296a58..dcb09702cde26d 100644
|
|
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
@@ -1498,6 +1498,7 @@ xfs_attr3_leaf_add_work(
|
|
struct xfs_attr_leaf_name_local *name_loc;
|
|
struct xfs_attr_leaf_name_remote *name_rmt;
|
|
struct xfs_mount *mp;
|
|
+ int old_end, new_end;
|
|
int tmp;
|
|
int i;
|
|
|
|
@@ -1590,17 +1591,49 @@ xfs_attr3_leaf_add_work(
|
|
if (be16_to_cpu(entry->nameidx) < ichdr->firstused)
|
|
ichdr->firstused = be16_to_cpu(entry->nameidx);
|
|
|
|
- ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t)
|
|
- + xfs_attr3_leaf_hdr_size(leaf));
|
|
- tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t)
|
|
- + xfs_attr3_leaf_hdr_size(leaf);
|
|
+ new_end = ichdr->count * sizeof(struct xfs_attr_leaf_entry) +
|
|
+ xfs_attr3_leaf_hdr_size(leaf);
|
|
+ old_end = new_end - sizeof(struct xfs_attr_leaf_entry);
|
|
+
|
|
+ ASSERT(ichdr->firstused >= new_end);
|
|
|
|
for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
|
|
- if (ichdr->freemap[i].base == tmp) {
|
|
- ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t);
|
|
+ int diff = 0;
|
|
+
|
|
+ if (ichdr->freemap[i].base == old_end) {
|
|
+ /*
|
|
+ * This freemap entry starts at the old end of the
|
|
+ * leaf entry array, so we need to adjust its base
|
|
+ * upward to accomodate the larger array.
|
|
+ */
|
|
+ diff = sizeof(struct xfs_attr_leaf_entry);
|
|
+ } else if (ichdr->freemap[i].size > 0 &&
|
|
+ ichdr->freemap[i].base < new_end) {
|
|
+ /*
|
|
+ * This freemap entry starts in the space claimed by
|
|
+ * the new leaf entry. Adjust its base upward to
|
|
+ * reflect that.
|
|
+ */
|
|
+ diff = new_end - ichdr->freemap[i].base;
|
|
+ }
|
|
+
|
|
+ if (diff) {
|
|
+ ichdr->freemap[i].base += diff;
|
|
ichdr->freemap[i].size -=
|
|
- min_t(uint16_t, ichdr->freemap[i].size,
|
|
- sizeof(xfs_attr_leaf_entry_t));
|
|
+ min_t(uint16_t, ichdr->freemap[i].size, diff);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Don't leave zero-length freemaps with nonzero base lying
|
|
+ * around, because we don't want the code in _remove that
|
|
+ * matches on base address to get confused and create
|
|
+ * overlapping freemaps. If we end up with no freemap entries
|
|
+ * then the next _add will compact the leaf block and
|
|
+ * regenerate the freemaps.
|
|
+ */
|
|
+ if (ichdr->freemap[i].size == 0 && ichdr->freemap[i].base > 0) {
|
|
+ ichdr->freemap[i].base = 0;
|
|
+ ichdr->holes = 1;
|
|
}
|
|
}
|
|
ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
|
|
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
|
|
index 147babe738d201..c785d80bbfe50d 100644
|
|
--- a/fs/xfs/scrub/attr.c
|
|
+++ b/fs/xfs/scrub/attr.c
|
|
@@ -343,7 +343,10 @@ xchk_xattr_entry(
|
|
rentry = xfs_attr3_leaf_name_remote(leaf, idx);
|
|
namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
|
|
name_end = (char *)rentry + namesize;
|
|
- if (rentry->namelen == 0 || rentry->valueblk == 0)
|
|
+ if (rentry->namelen == 0)
|
|
+ xchk_da_set_corrupt(ds, level);
|
|
+ if (rentry->valueblk == 0 &&
|
|
+ !(ent->flags & XFS_ATTR_INCOMPLETE))
|
|
xchk_da_set_corrupt(ds, level);
|
|
}
|
|
if (name_end > buf_end)
|
|
diff --git a/fs/xfs/scrub/btree.c b/fs/xfs/scrub/btree.c
|
|
index c3a9f33e5a8d12..2afc7e5cc08fcc 100644
|
|
--- a/fs/xfs/scrub/btree.c
|
|
+++ b/fs/xfs/scrub/btree.c
|
|
@@ -42,6 +42,8 @@ __xchk_btree_process_error(
|
|
break;
|
|
case -EFSBADCRC:
|
|
case -EFSCORRUPTED:
|
|
+ case -EIO:
|
|
+ case -ENODATA:
|
|
/* Note the badness but don't abort. */
|
|
sc->sm->sm_flags |= errflag;
|
|
*error = 0;
|
|
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
|
|
index f10cd4fb0abd0d..36814c09bf1034 100644
|
|
--- a/fs/xfs/scrub/common.c
|
|
+++ b/fs/xfs/scrub/common.c
|
|
@@ -83,6 +83,8 @@ __xchk_process_error(
|
|
break;
|
|
case -EFSBADCRC:
|
|
case -EFSCORRUPTED:
|
|
+ case -EIO:
|
|
+ case -ENODATA:
|
|
/* Note the badness but don't abort. */
|
|
sc->sm->sm_flags |= errflag;
|
|
*error = 0;
|
|
@@ -137,6 +139,8 @@ __xchk_fblock_process_error(
|
|
break;
|
|
case -EFSBADCRC:
|
|
case -EFSCORRUPTED:
|
|
+ case -EIO:
|
|
+ case -ENODATA:
|
|
/* Note the badness but don't abort. */
|
|
sc->sm->sm_flags |= errflag;
|
|
*error = 0;
|
|
diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
|
|
index 82b150d3b8b700..338199d7b84165 100644
|
|
--- a/fs/xfs/scrub/dabtree.c
|
|
+++ b/fs/xfs/scrub/dabtree.c
|
|
@@ -45,6 +45,8 @@ xchk_da_process_error(
|
|
break;
|
|
case -EFSBADCRC:
|
|
case -EFSCORRUPTED:
|
|
+ case -EIO:
|
|
+ case -ENODATA:
|
|
/* Note the badness but don't abort. */
|
|
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
|
|
*error = 0;
|
|
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
|
|
index be1dd4c1a91744..16646fdd1f8415 100644
|
|
--- a/include/acpi/ghes.h
|
|
+++ b/include/acpi/ghes.h
|
|
@@ -21,6 +21,7 @@ struct ghes {
|
|
struct acpi_hest_generic_v2 *generic_v2;
|
|
};
|
|
struct acpi_hest_generic_status *estatus;
|
|
+ unsigned int estatus_length;
|
|
unsigned long flags;
|
|
union {
|
|
struct list_head list;
|
|
diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h
|
|
index 331670807cf011..6c311d4d37f4e6 100644
|
|
--- a/include/asm-generic/audit_change_attr.h
|
|
+++ b/include/asm-generic/audit_change_attr.h
|
|
@@ -20,6 +20,9 @@ __NR_fremovexattr,
|
|
__NR_fchownat,
|
|
__NR_fchmodat,
|
|
#endif
|
|
+#ifdef __NR_fchmodat2
|
|
+__NR_fchmodat2,
|
|
+#endif
|
|
#ifdef __NR_chown32
|
|
__NR_chown32,
|
|
__NR_fchown32,
|
|
diff --git a/include/asm-generic/audit_read.h b/include/asm-generic/audit_read.h
|
|
index 7bb7b5a83ae2e5..fb9991f53fb6f9 100644
|
|
--- a/include/asm-generic/audit_read.h
|
|
+++ b/include/asm-generic/audit_read.h
|
|
@@ -4,9 +4,15 @@ __NR_readlink,
|
|
#endif
|
|
__NR_quotactl,
|
|
__NR_listxattr,
|
|
+#ifdef __NR_listxattrat
|
|
+__NR_listxattrat,
|
|
+#endif
|
|
__NR_llistxattr,
|
|
__NR_flistxattr,
|
|
__NR_getxattr,
|
|
+#ifdef __NR_getxattrat
|
|
+__NR_getxattrat,
|
|
+#endif
|
|
__NR_lgetxattr,
|
|
__NR_fgetxattr,
|
|
#ifdef __NR_readlinkat
|
|
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
|
|
index 082a6e980d0178..3e38a470c5cbe4 100644
|
|
--- a/include/drm/drm_of.h
|
|
+++ b/include/drm/drm_of.h
|
|
@@ -4,6 +4,7 @@
|
|
|
|
#include <linux/of_graph.h>
|
|
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
|
|
+#include <linux/of.h>
|
|
#include <drm/drm_bridge.h>
|
|
#endif
|
|
|
|
@@ -163,6 +164,8 @@ static inline int drm_of_panel_bridge_remove(const struct device_node *np,
|
|
bridge = of_drm_find_bridge(remote);
|
|
drm_panel_bridge_remove(bridge);
|
|
|
|
+ of_node_put(remote);
|
|
+
|
|
return 0;
|
|
#else
|
|
return -EINVAL;
|
|
diff --git a/include/linux/audit.h b/include/linux/audit.h
|
|
index 7ca75f8873799d..517c665da25975 100644
|
|
--- a/include/linux/audit.h
|
|
+++ b/include/linux/audit.h
|
|
@@ -125,12 +125,6 @@ enum audit_nfcfgop {
|
|
extern int __init audit_register_class(int class, unsigned *list);
|
|
extern int audit_classify_syscall(int abi, unsigned syscall);
|
|
extern int audit_classify_arch(int arch);
|
|
-/* only for compat system calls */
|
|
-extern unsigned compat_write_class[];
|
|
-extern unsigned compat_read_class[];
|
|
-extern unsigned compat_dir_class[];
|
|
-extern unsigned compat_chattr_class[];
|
|
-extern unsigned compat_signal_class[];
|
|
|
|
/* audit_names->type values */
|
|
#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
|
|
diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h
|
|
index 0e34d673ef1712..2b8153791e6a5d 100644
|
|
--- a/include/linux/audit_arch.h
|
|
+++ b/include/linux/audit_arch.h
|
|
@@ -23,4 +23,11 @@ enum auditsc_class_t {
|
|
|
|
extern int audit_classify_compat_syscall(int abi, unsigned syscall);
|
|
|
|
+/* only for compat system calls */
|
|
+extern unsigned compat_write_class[];
|
|
+extern unsigned compat_read_class[];
|
|
+extern unsigned compat_dir_class[];
|
|
+extern unsigned compat_chattr_class[];
|
|
+extern unsigned compat_signal_class[];
|
|
+
|
|
#endif
|
|
diff --git a/include/linux/cache.h b/include/linux/cache.h
|
|
index 9900d20b76c282..ca2a05682a54b5 100644
|
|
--- a/include/linux/cache.h
|
|
+++ b/include/linux/cache.h
|
|
@@ -13,6 +13,32 @@
|
|
#define SMP_CACHE_BYTES L1_CACHE_BYTES
|
|
#endif
|
|
|
|
+/**
|
|
+ * SMP_CACHE_ALIGN - align a value to the L2 cacheline size
|
|
+ * @x: value to align
|
|
+ *
|
|
+ * On some architectures, L2 ("SMP") CL size is bigger than L1, and sometimes,
|
|
+ * this needs to be accounted.
|
|
+ *
|
|
+ * Return: aligned value.
|
|
+ */
|
|
+#ifndef SMP_CACHE_ALIGN
|
|
+#define SMP_CACHE_ALIGN(x) ALIGN(x, SMP_CACHE_BYTES)
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * ``__aligned_largest`` aligns a field to the value most optimal for the
|
|
+ * target architecture to perform memory operations. Get the actual value
|
|
+ * to be able to use it anywhere else.
|
|
+ */
|
|
+#ifndef __LARGEST_ALIGN
|
|
+#define __LARGEST_ALIGN sizeof(struct { long x; } __aligned_largest)
|
|
+#endif
|
|
+
|
|
+#ifndef LARGEST_ALIGN
|
|
+#define LARGEST_ALIGN(x) ALIGN(x, __LARGEST_ALIGN)
|
|
+#endif
|
|
+
|
|
/*
|
|
* __read_mostly is used to keep rarely changing variables out of frequently
|
|
* updated cachelines. Its use should be reserved for data that is used
|
|
@@ -85,6 +111,64 @@
|
|
#define cache_line_size() L1_CACHE_BYTES
|
|
#endif
|
|
|
|
+#ifndef __cacheline_group_begin
|
|
+#define __cacheline_group_begin(GROUP) \
|
|
+ __u8 __cacheline_group_begin__##GROUP[0]
|
|
+#endif
|
|
+
|
|
+#ifndef __cacheline_group_end
|
|
+#define __cacheline_group_end(GROUP) \
|
|
+ __u8 __cacheline_group_end__##GROUP[0]
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * __cacheline_group_begin_aligned - declare an aligned group start
|
|
+ * @GROUP: name of the group
|
|
+ * @...: optional group alignment
|
|
+ *
|
|
+ * The following block inside a struct:
|
|
+ *
|
|
+ * __cacheline_group_begin_aligned(grp);
|
|
+ * field a;
|
|
+ * field b;
|
|
+ * __cacheline_group_end_aligned(grp);
|
|
+ *
|
|
+ * will always be aligned to either the specified alignment or
|
|
+ * ``SMP_CACHE_BYTES``.
|
|
+ */
|
|
+#define __cacheline_group_begin_aligned(GROUP, ...) \
|
|
+ __cacheline_group_begin(GROUP) \
|
|
+ __aligned((__VA_ARGS__ + 0) ? : SMP_CACHE_BYTES)
|
|
+
|
|
+/**
|
|
+ * __cacheline_group_end_aligned - declare an aligned group end
|
|
+ * @GROUP: name of the group
|
|
+ * @...: optional alignment (same as was in __cacheline_group_begin_aligned())
|
|
+ *
|
|
+ * Note that the end marker is aligned to sizeof(long) to allow more precise
|
|
+ * size assertion. It also declares a padding at the end to avoid next field
|
|
+ * falling into this cacheline.
|
|
+ */
|
|
+#define __cacheline_group_end_aligned(GROUP, ...) \
|
|
+ __cacheline_group_end(GROUP) __aligned(sizeof(long)); \
|
|
+ struct { } __cacheline_group_pad__##GROUP \
|
|
+ __aligned((__VA_ARGS__ + 0) ? : SMP_CACHE_BYTES)
|
|
+
|
|
+#ifndef CACHELINE_ASSERT_GROUP_MEMBER
|
|
+#define CACHELINE_ASSERT_GROUP_MEMBER(TYPE, GROUP, MEMBER) \
|
|
+ BUILD_BUG_ON(!(offsetof(TYPE, MEMBER) >= \
|
|
+ offsetofend(TYPE, __cacheline_group_begin__##GROUP) && \
|
|
+ offsetofend(TYPE, MEMBER) <= \
|
|
+ offsetof(TYPE, __cacheline_group_end__##GROUP)))
|
|
+#endif
|
|
+
|
|
+#ifndef CACHELINE_ASSERT_GROUP_SIZE
|
|
+#define CACHELINE_ASSERT_GROUP_SIZE(TYPE, GROUP, SIZE) \
|
|
+ BUILD_BUG_ON(offsetof(TYPE, __cacheline_group_end__##GROUP) - \
|
|
+ offsetofend(TYPE, __cacheline_group_begin__##GROUP) > \
|
|
+ SIZE)
|
|
+#endif
|
|
+
|
|
/*
|
|
* Helper to add padding within a struct to ensure data fall into separate
|
|
* cachelines.
|
|
diff --git a/include/linux/capability.h b/include/linux/capability.h
|
|
index 0c356a5179917e..767c535dbd38ec 100644
|
|
--- a/include/linux/capability.h
|
|
+++ b/include/linux/capability.h
|
|
@@ -208,6 +208,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns)
|
|
ns_capable(ns, CAP_SYS_ADMIN);
|
|
}
|
|
|
|
+static inline bool checkpoint_restore_ns_capable_noaudit(struct user_namespace *ns)
|
|
+{
|
|
+ return ns_capable_noaudit(ns, CAP_CHECKPOINT_RESTORE) ||
|
|
+ ns_capable_noaudit(ns, CAP_SYS_ADMIN);
|
|
+}
|
|
+
|
|
/* audit system wants to get cap info from files as well */
|
|
int get_vfs_caps_from_disk(struct mnt_idmap *idmap,
|
|
const struct dentry *dentry,
|
|
diff --git a/include/linux/clk.h b/include/linux/clk.h
|
|
index 06f1b292f8a00a..862ef29ee5f0e3 100644
|
|
--- a/include/linux/clk.h
|
|
+++ b/include/linux/clk.h
|
|
@@ -216,6 +216,23 @@ int clk_rate_exclusive_get(struct clk *clk);
|
|
*/
|
|
void clk_rate_exclusive_put(struct clk *clk);
|
|
|
|
+/**
|
|
+ * clk_save_context - save clock context for poweroff
|
|
+ *
|
|
+ * Saves the context of the clock register for powerstates in which the
|
|
+ * contents of the registers will be lost. Occurs deep within the suspend
|
|
+ * code so locking is not necessary.
|
|
+ */
|
|
+int clk_save_context(void);
|
|
+
|
|
+/**
|
|
+ * clk_restore_context - restore clock context after poweroff
|
|
+ *
|
|
+ * This occurs with all clocks enabled. Occurs deep within the resume code
|
|
+ * so locking is not necessary.
|
|
+ */
|
|
+void clk_restore_context(void);
|
|
+
|
|
#else
|
|
|
|
static inline int clk_notifier_register(struct clk *clk,
|
|
@@ -276,6 +293,13 @@ static inline int clk_rate_exclusive_get(struct clk *clk)
|
|
|
|
static inline void clk_rate_exclusive_put(struct clk *clk) {}
|
|
|
|
+static inline int clk_save_context(void)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void clk_restore_context(void) {}
|
|
+
|
|
#endif
|
|
|
|
#ifdef CONFIG_HAVE_CLK_PREPARE
|
|
@@ -872,23 +896,6 @@ struct clk *clk_get_parent(struct clk *clk);
|
|
*/
|
|
struct clk *clk_get_sys(const char *dev_id, const char *con_id);
|
|
|
|
-/**
|
|
- * clk_save_context - save clock context for poweroff
|
|
- *
|
|
- * Saves the context of the clock register for powerstates in which the
|
|
- * contents of the registers will be lost. Occurs deep within the suspend
|
|
- * code so locking is not necessary.
|
|
- */
|
|
-int clk_save_context(void);
|
|
-
|
|
-/**
|
|
- * clk_restore_context - restore clock context after poweroff
|
|
- *
|
|
- * This occurs with all clocks enabled. Occurs deep within the resume code
|
|
- * so locking is not necessary.
|
|
- */
|
|
-void clk_restore_context(void);
|
|
-
|
|
#else /* !CONFIG_HAVE_CLK */
|
|
|
|
static inline struct clk *clk_get(struct device *dev, const char *id)
|
|
@@ -1055,13 +1062,6 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
|
return NULL;
|
|
}
|
|
|
|
-static inline int clk_save_context(void)
|
|
-{
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline void clk_restore_context(void) {}
|
|
-
|
|
#endif
|
|
|
|
/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
|
|
diff --git a/include/linux/cper.h b/include/linux/cper.h
|
|
index ad1ed24730917c..c588e5c2a96c6d 100644
|
|
--- a/include/linux/cper.h
|
|
+++ b/include/linux/cper.h
|
|
@@ -568,7 +568,8 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *,
|
|
const char *cper_mem_err_unpack(struct trace_seq *,
|
|
struct cper_mem_err_compact *);
|
|
void cper_print_proc_arm(const char *pfx,
|
|
- const struct cper_sec_proc_arm *proc);
|
|
+ const struct cper_sec_proc_arm *proc,
|
|
+ u32 length);
|
|
void cper_print_proc_ia(const char *pfx,
|
|
const struct cper_sec_proc_ia *proc);
|
|
int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);
|
|
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
|
|
index e8921871ef9aaa..5c3eaf9fc90c4e 100644
|
|
--- a/include/linux/ftrace.h
|
|
+++ b/include/linux/ftrace.h
|
|
@@ -89,11 +89,13 @@ struct ftrace_direct_func;
|
|
defined(CONFIG_DYNAMIC_FTRACE)
|
|
const char *
|
|
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
|
|
- unsigned long *off, char **modname, char *sym);
|
|
+ unsigned long *off, char **modname,
|
|
+ const unsigned char **modbuildid, char *sym);
|
|
#else
|
|
static inline const char *
|
|
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
|
|
- unsigned long *off, char **modname, char *sym)
|
|
+ unsigned long *off, char **modname,
|
|
+ const unsigned char **modbuildid, char *sym)
|
|
{
|
|
return NULL;
|
|
}
|
|
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
|
|
index ddb27fc0ee8c88..b157ff4f727fba 100644
|
|
--- a/include/linux/inetdevice.h
|
|
+++ b/include/linux/inetdevice.h
|
|
@@ -38,11 +38,11 @@ struct in_device {
|
|
struct ip_mc_list *mc_tomb;
|
|
unsigned long mr_v1_seen;
|
|
unsigned long mr_v2_seen;
|
|
- unsigned long mr_maxdelay;
|
|
unsigned long mr_qi; /* Query Interval */
|
|
unsigned long mr_qri; /* Query Response Interval */
|
|
unsigned char mr_qrv; /* Query Robustness Variable */
|
|
unsigned char mr_gq_running;
|
|
+ u32 mr_maxdelay;
|
|
u32 mr_ifc_count;
|
|
struct timer_list mr_gq_timer; /* general query timer */
|
|
struct timer_list mr_ifc_timer; /* interface change timer */
|
|
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
|
|
index a3241e4d754868..4816d4f4721011 100644
|
|
--- a/include/linux/mfd/wm8350/core.h
|
|
+++ b/include/linux/mfd/wm8350/core.h
|
|
@@ -663,7 +663,7 @@ static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq,
|
|
return -ENODEV;
|
|
|
|
return request_threaded_irq(irq + wm8350->irq_base, NULL,
|
|
- handler, flags, name, data);
|
|
+ handler, flags | IRQF_ONESHOT, name, data);
|
|
}
|
|
|
|
static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data)
|
|
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
|
|
index c0e0468b25a180..c29ecbfbf3da24 100644
|
|
--- a/include/linux/mlx5/driver.h
|
|
+++ b/include/linux/mlx5/driver.h
|
|
@@ -1288,12 +1288,12 @@ static inline bool mlx5_rl_is_supported(struct mlx5_core_dev *dev)
|
|
static inline int mlx5_core_is_mp_slave(struct mlx5_core_dev *dev)
|
|
{
|
|
return MLX5_CAP_GEN(dev, affiliate_nic_vport_criteria) &&
|
|
- MLX5_CAP_GEN(dev, num_vhca_ports) <= 1;
|
|
+ MLX5_CAP_GEN_MAX(dev, num_vhca_ports) <= 1;
|
|
}
|
|
|
|
static inline int mlx5_core_is_mp_master(struct mlx5_core_dev *dev)
|
|
{
|
|
- return MLX5_CAP_GEN(dev, num_vhca_ports) > 1;
|
|
+ return MLX5_CAP_GEN_MAX(dev, num_vhca_ports) > 1;
|
|
}
|
|
|
|
static inline int mlx5_core_mp_enabled(struct mlx5_core_dev *dev)
|
|
diff --git a/include/linux/module.h b/include/linux/module.h
|
|
index f58d1eb260fa9e..10603f725cae53 100644
|
|
--- a/include/linux/module.h
|
|
+++ b/include/linux/module.h
|
|
@@ -735,6 +735,15 @@ static inline void __module_get(struct module *module)
|
|
__mod ? __mod->name : "kernel"; \
|
|
})
|
|
|
|
+static inline const unsigned char *module_buildid(struct module *mod)
|
|
+{
|
|
+#ifdef CONFIG_STACKTRACE_BUILD_ID
|
|
+ return mod->build_id;
|
|
+#else
|
|
+ return NULL;
|
|
+#endif
|
|
+}
|
|
+
|
|
/* Dereference module function descriptor */
|
|
void *dereference_module_function_descriptor(struct module *mod, void *ptr);
|
|
|
|
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
|
|
index 5c2ccc6494529e..980e1fdf67eda0 100644
|
|
--- a/include/linux/mtd/spinand.h
|
|
+++ b/include/linux/mtd/spinand.h
|
|
@@ -195,7 +195,7 @@ struct spinand_device;
|
|
|
|
/**
|
|
* struct spinand_id - SPI NAND id structure
|
|
- * @data: buffer containing the id bytes. Currently 4 bytes large, but can
|
|
+ * @data: buffer containing the id bytes. Currently 5 bytes large, but can
|
|
* be extended if required
|
|
* @len: ID length
|
|
*/
|
|
diff --git a/include/linux/psp.h b/include/linux/psp.h
|
|
index 92e60aeef21e13..b337dcce1e9916 100644
|
|
--- a/include/linux/psp.h
|
|
+++ b/include/linux/psp.h
|
|
@@ -18,6 +18,7 @@
|
|
* and should include an appropriate local definition in their source file.
|
|
*/
|
|
#define PSP_CMDRESP_STS GENMASK(15, 0)
|
|
+#define PSP_TEE_STS_RING_BUSY 0x0000000d /* Ring already initialized */
|
|
#define PSP_CMDRESP_CMD GENMASK(23, 16)
|
|
#define PSP_CMDRESP_RESERVED GENMASK(29, 24)
|
|
#define PSP_CMDRESP_RECOVERY BIT(30)
|
|
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
|
index 69b392dc10aa37..1a91645fa24975 100644
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -1122,6 +1122,38 @@ static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
|
|
return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK);
|
|
}
|
|
|
|
+/**
|
|
+ * skb_dstref_steal() - return current dst_entry value and clear it
|
|
+ * @skb: buffer
|
|
+ *
|
|
+ * Resets skb dst_entry without adjusting its reference count. Useful in
|
|
+ * cases where dst_entry needs to be temporarily reset and restored.
|
|
+ * Note that the returned value cannot be used directly because it
|
|
+ * might contain SKB_DST_NOREF bit.
|
|
+ *
|
|
+ * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly
|
|
+ * handle dst_entry reference counting.
|
|
+ *
|
|
+ * Returns: original skb dst_entry.
|
|
+ */
|
|
+static inline unsigned long skb_dstref_steal(struct sk_buff *skb)
|
|
+{
|
|
+ unsigned long refdst = skb->_skb_refdst;
|
|
+
|
|
+ skb->_skb_refdst = 0;
|
|
+ return refdst;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal()
|
|
+ * @skb: buffer
|
|
+ * @refdst: dst entry from a call to skb_dstref_steal()
|
|
+ */
|
|
+static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst)
|
|
+{
|
|
+ skb->_skb_refdst = refdst;
|
|
+}
|
|
+
|
|
/**
|
|
* skb_dst_set - sets skb dst
|
|
* @skb: buffer
|
|
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
|
|
index 32bbebf5b71e3c..e923f1c24ce4b3 100644
|
|
--- a/include/linux/skmsg.h
|
|
+++ b/include/linux/skmsg.h
|
|
@@ -93,6 +93,8 @@ struct sk_psock {
|
|
struct sk_buff_head ingress_skb;
|
|
struct list_head ingress_msg;
|
|
spinlock_t ingress_lock;
|
|
+ /** @msg_tot_len: Total bytes queued in ingress_msg list. */
|
|
+ u32 msg_tot_len;
|
|
unsigned long state;
|
|
struct list_head link;
|
|
spinlock_t link_lock;
|
|
@@ -132,6 +134,8 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
|
|
struct sk_msg *msg, u32 bytes);
|
|
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
int len, int flags);
|
|
+int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
+ int len, int flags, int *copied_from_self);
|
|
bool sk_msg_is_readable(struct sock *sk);
|
|
|
|
static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes)
|
|
@@ -310,6 +314,27 @@ static inline void sock_drop(struct sock *sk, struct sk_buff *skb)
|
|
kfree_skb(skb);
|
|
}
|
|
|
|
+static inline u32 sk_psock_get_msg_len_nolock(struct sk_psock *psock)
|
|
+{
|
|
+ /* Used by ioctl to read msg_tot_len only; lock-free for performance */
|
|
+ return READ_ONCE(psock->msg_tot_len);
|
|
+}
|
|
+
|
|
+static inline void sk_psock_msg_len_add_locked(struct sk_psock *psock, int diff)
|
|
+{
|
|
+ /* Use WRITE_ONCE to ensure correct read in sk_psock_get_msg_len_nolock().
|
|
+ * ingress_lock should be held to prevent concurrent updates to msg_tot_len
|
|
+ */
|
|
+ WRITE_ONCE(psock->msg_tot_len, psock->msg_tot_len + diff);
|
|
+}
|
|
+
|
|
+static inline void sk_psock_msg_len_add(struct sk_psock *psock, int diff)
|
|
+{
|
|
+ spin_lock_bh(&psock->ingress_lock);
|
|
+ sk_psock_msg_len_add_locked(psock, diff);
|
|
+ spin_unlock_bh(&psock->ingress_lock);
|
|
+}
|
|
+
|
|
static inline bool sk_psock_queue_msg(struct sk_psock *psock,
|
|
struct sk_msg *msg)
|
|
{
|
|
@@ -318,6 +343,7 @@ static inline bool sk_psock_queue_msg(struct sk_psock *psock,
|
|
spin_lock_bh(&psock->ingress_lock);
|
|
if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
|
|
list_add_tail(&msg->list, &psock->ingress_msg);
|
|
+ sk_psock_msg_len_add_locked(psock, msg->sg.size);
|
|
ret = true;
|
|
} else {
|
|
sk_msg_free(psock->sk, msg);
|
|
@@ -334,18 +360,25 @@ static inline struct sk_msg *sk_psock_dequeue_msg(struct sk_psock *psock)
|
|
|
|
spin_lock_bh(&psock->ingress_lock);
|
|
msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list);
|
|
- if (msg)
|
|
+ if (msg) {
|
|
list_del(&msg->list);
|
|
+ sk_psock_msg_len_add_locked(psock, -msg->sg.size);
|
|
+ }
|
|
spin_unlock_bh(&psock->ingress_lock);
|
|
return msg;
|
|
}
|
|
|
|
+static inline struct sk_msg *sk_psock_peek_msg_locked(struct sk_psock *psock)
|
|
+{
|
|
+ return list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list);
|
|
+}
|
|
+
|
|
static inline struct sk_msg *sk_psock_peek_msg(struct sk_psock *psock)
|
|
{
|
|
struct sk_msg *msg;
|
|
|
|
spin_lock_bh(&psock->ingress_lock);
|
|
- msg = list_first_entry_or_null(&psock->ingress_msg, struct sk_msg, list);
|
|
+ msg = sk_psock_peek_msg_locked(psock);
|
|
spin_unlock_bh(&psock->ingress_lock);
|
|
return msg;
|
|
}
|
|
@@ -509,6 +542,39 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock)
|
|
return !!psock->saved_data_ready;
|
|
}
|
|
|
|
+/* for tcp only, sk is locked */
|
|
+static inline ssize_t sk_psock_msg_inq(struct sock *sk)
|
|
+{
|
|
+ struct sk_psock *psock;
|
|
+ ssize_t inq = 0;
|
|
+
|
|
+ psock = sk_psock_get(sk);
|
|
+ if (likely(psock)) {
|
|
+ inq = sk_psock_get_msg_len_nolock(psock);
|
|
+ sk_psock_put(sk, psock);
|
|
+ }
|
|
+ return inq;
|
|
+}
|
|
+
|
|
+/* for udp only, sk is not locked */
|
|
+static inline ssize_t sk_msg_first_len(struct sock *sk)
|
|
+{
|
|
+ struct sk_psock *psock;
|
|
+ struct sk_msg *msg;
|
|
+ ssize_t inq = 0;
|
|
+
|
|
+ psock = sk_psock_get(sk);
|
|
+ if (likely(psock)) {
|
|
+ spin_lock_bh(&psock->ingress_lock);
|
|
+ msg = sk_psock_peek_msg_locked(psock);
|
|
+ if (msg)
|
|
+ inq = msg->sg.size;
|
|
+ spin_unlock_bh(&psock->ingress_lock);
|
|
+ sk_psock_put(sk, psock);
|
|
+ }
|
|
+ return inq;
|
|
+}
|
|
+
|
|
#if IS_ENABLED(CONFIG_NET_SOCK_MSG)
|
|
|
|
#define BPF_F_STRPARSER (1UL << 1)
|
|
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
|
|
index 9b371aa7c79623..e15452df9804f6 100644
|
|
--- a/include/linux/tcp.h
|
|
+++ b/include/linux/tcp.h
|
|
@@ -471,15 +471,17 @@ enum tsq_enum {
|
|
TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call
|
|
* tcp_v{4|6}_mtu_reduced()
|
|
*/
|
|
+ TCP_ACK_DEFERRED, /* TX pure ack is deferred */
|
|
};
|
|
|
|
enum tsq_flags {
|
|
- TSQF_THROTTLED = (1UL << TSQ_THROTTLED),
|
|
- TSQF_QUEUED = (1UL << TSQ_QUEUED),
|
|
- TCPF_TSQ_DEFERRED = (1UL << TCP_TSQ_DEFERRED),
|
|
- TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED),
|
|
- TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED),
|
|
- TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED),
|
|
+ TSQF_THROTTLED = BIT(TSQ_THROTTLED),
|
|
+ TSQF_QUEUED = BIT(TSQ_QUEUED),
|
|
+ TCPF_TSQ_DEFERRED = BIT(TCP_TSQ_DEFERRED),
|
|
+ TCPF_WRITE_TIMER_DEFERRED = BIT(TCP_WRITE_TIMER_DEFERRED),
|
|
+ TCPF_DELACK_TIMER_DEFERRED = BIT(TCP_DELACK_TIMER_DEFERRED),
|
|
+ TCPF_MTU_REDUCED_DEFERRED = BIT(TCP_MTU_REDUCED_DEFERRED),
|
|
+ TCPF_ACK_DEFERRED = BIT(TCP_ACK_DEFERRED),
|
|
};
|
|
|
|
#define tcp_sk(ptr) container_of_const(ptr, struct tcp_sock, inet_conn.icsk_inet.sk)
|
|
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
|
|
index fe95d13c5e4d86..4035cb45035608 100644
|
|
--- a/include/linux/trace_events.h
|
|
+++ b/include/linux/trace_events.h
|
|
@@ -695,6 +695,11 @@ static inline void hist_poll_wakeup(void)
|
|
|
|
#define hist_poll_wait(file, wait) \
|
|
poll_wait(file, &hist_poll_wq, wait)
|
|
+
|
|
+#else
|
|
+static inline void hist_poll_wakeup(void)
|
|
+{
|
|
+}
|
|
#endif
|
|
|
|
#define __TRACE_EVENT_FLAGS(name, value) \
|
|
diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
|
|
index 457879938fc198..3366090a86bd2f 100644
|
|
--- a/include/linux/u64_stats_sync.h
|
|
+++ b/include/linux/u64_stats_sync.h
|
|
@@ -89,6 +89,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
|
|
local64_add(val, &p->v);
|
|
}
|
|
|
|
+static inline void u64_stats_sub(u64_stats_t *p, s64 val)
|
|
+{
|
|
+ local64_sub(val, &p->v);
|
|
+}
|
|
+
|
|
static inline void u64_stats_inc(u64_stats_t *p)
|
|
{
|
|
local64_inc(&p->v);
|
|
@@ -130,6 +135,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
|
|
p->v += val;
|
|
}
|
|
|
|
+static inline void u64_stats_sub(u64_stats_t *p, s64 val)
|
|
+{
|
|
+ p->v -= val;
|
|
+}
|
|
+
|
|
static inline void u64_stats_inc(u64_stats_t *p)
|
|
{
|
|
p->v++;
|
|
diff --git a/include/media/dvb_vb2.h b/include/media/dvb_vb2.h
|
|
index 8cb88452cd6c28..0fbbfc65157e64 100644
|
|
--- a/include/media/dvb_vb2.h
|
|
+++ b/include/media/dvb_vb2.h
|
|
@@ -124,7 +124,7 @@ static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
|
|
return 0;
|
|
};
|
|
#define dvb_vb2_is_streaming(ctx) (0)
|
|
-#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0)
|
|
+#define dvb_vb2_fill_buffer(ctx, file, wait, flags, flush) (0)
|
|
|
|
static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
|
|
struct file *file,
|
|
@@ -166,10 +166,12 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx);
|
|
* @buffer_flags:
|
|
* pointer to buffer flags as defined by &enum dmx_buffer_flags.
|
|
* can be NULL.
|
|
+ * @flush: flush the buffer, even if it isn't full.
|
|
*/
|
|
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
|
|
const unsigned char *src, int len,
|
|
- enum dmx_buffer_flags *buffer_flags);
|
|
+ enum dmx_buffer_flags *buffer_flags,
|
|
+ bool flush);
|
|
|
|
/**
|
|
* dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV
|
|
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
|
|
index 08574278645de1..a57fd4573783d4 100644
|
|
--- a/include/net/bluetooth/l2cap.h
|
|
+++ b/include/net/bluetooth/l2cap.h
|
|
@@ -487,6 +487,8 @@ struct l2cap_ecred_reconf_req {
|
|
#define L2CAP_RECONF_SUCCESS 0x0000
|
|
#define L2CAP_RECONF_INVALID_MTU 0x0001
|
|
#define L2CAP_RECONF_INVALID_MPS 0x0002
|
|
+#define L2CAP_RECONF_INVALID_CID 0x0003
|
|
+#define L2CAP_RECONF_INVALID_PARAMS 0x0004
|
|
|
|
struct l2cap_ecred_reconf_rsp {
|
|
__le16 result;
|
|
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
|
|
index e85834722b8f2b..3eb715f66cbf66 100644
|
|
--- a/include/net/inet_connection_sock.h
|
|
+++ b/include/net/inet_connection_sock.h
|
|
@@ -326,11 +326,10 @@ void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
|
|
|
|
struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu);
|
|
|
|
-#define TCP_PINGPONG_THRESH 1
|
|
-
|
|
static inline void inet_csk_enter_pingpong_mode(struct sock *sk)
|
|
{
|
|
- inet_csk(sk)->icsk_ack.pingpong = TCP_PINGPONG_THRESH;
|
|
+ inet_csk(sk)->icsk_ack.pingpong =
|
|
+ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pingpong_thresh);
|
|
}
|
|
|
|
static inline void inet_csk_exit_pingpong_mode(struct sock *sk)
|
|
@@ -340,7 +339,16 @@ static inline void inet_csk_exit_pingpong_mode(struct sock *sk)
|
|
|
|
static inline bool inet_csk_in_pingpong_mode(struct sock *sk)
|
|
{
|
|
- return inet_csk(sk)->icsk_ack.pingpong >= TCP_PINGPONG_THRESH;
|
|
+ return inet_csk(sk)->icsk_ack.pingpong >=
|
|
+ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pingpong_thresh);
|
|
+}
|
|
+
|
|
+static inline void inet_csk_inc_pingpong_cnt(struct sock *sk)
|
|
+{
|
|
+ struct inet_connection_sock *icsk = inet_csk(sk);
|
|
+
|
|
+ if (icsk->icsk_ack.pingpong < U8_MAX)
|
|
+ icsk->icsk_ack.pingpong++;
|
|
}
|
|
|
|
static inline bool inet_csk_has_ulp(const struct sock *sk)
|
|
diff --git a/include/net/ioam6.h b/include/net/ioam6.h
|
|
index 781d2d8b2f29d9..3f99eb445de61f 100644
|
|
--- a/include/net/ioam6.h
|
|
+++ b/include/net/ioam6.h
|
|
@@ -59,6 +59,8 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
|
|
struct ioam6_trace_hdr *trace,
|
|
bool is_input);
|
|
|
|
+u8 ioam6_trace_compute_nodelen(u32 trace_type);
|
|
+
|
|
int ioam6_init(void);
|
|
void ioam6_exit(void);
|
|
|
|
diff --git a/include/net/ip.h b/include/net/ip.h
|
|
index d8bf1f0a6919c4..bacdb4fecc89be 100644
|
|
--- a/include/net/ip.h
|
|
+++ b/include/net/ip.h
|
|
@@ -790,11 +790,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
|
ip_cmsg_recv_offset(msg, skb->sk, skb, 0, 0);
|
|
}
|
|
|
|
-bool icmp_global_allow(void);
|
|
-void icmp_global_consume(void);
|
|
-
|
|
-extern int sysctl_icmp_msgs_per_sec;
|
|
-extern int sysctl_icmp_msgs_burst;
|
|
+bool icmp_global_allow(struct net *net);
|
|
+void icmp_global_consume(struct net *net);
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
int ip_misc_proc_init(void);
|
|
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
|
|
index c6932d1a3fa806..d98f5390ffad38 100644
|
|
--- a/include/net/ipv6.h
|
|
+++ b/include/net/ipv6.h
|
|
@@ -1017,11 +1017,11 @@ static inline int ip6_default_np_autolabel(struct net *net)
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
static inline int ip6_multipath_hash_policy(const struct net *net)
|
|
{
|
|
- return net->ipv6.sysctl.multipath_hash_policy;
|
|
+ return READ_ONCE(net->ipv6.sysctl.multipath_hash_policy);
|
|
}
|
|
static inline u32 ip6_multipath_hash_fields(const struct net *net)
|
|
{
|
|
- return net->ipv6.sysctl.multipath_hash_fields;
|
|
+ return READ_ONCE(net->ipv6.sysctl.multipath_hash_fields);
|
|
}
|
|
#else
|
|
static inline int ip6_multipath_hash_policy(const struct net *net)
|
|
@@ -1293,12 +1293,15 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
|
|
|
|
static inline int ip6_sock_set_v6only(struct sock *sk)
|
|
{
|
|
- if (inet_sk(sk)->inet_num)
|
|
- return -EINVAL;
|
|
+ int ret = 0;
|
|
+
|
|
lock_sock(sk);
|
|
- sk->sk_ipv6only = true;
|
|
+ if (inet_sk(sk)->inet_num)
|
|
+ ret = -EINVAL;
|
|
+ else
|
|
+ sk->sk_ipv6only = true;
|
|
release_sock(sk);
|
|
- return 0;
|
|
+ return ret;
|
|
}
|
|
|
|
static inline void ip6_sock_set_recverr(struct sock *sk)
|
|
diff --git a/include/net/netfilter/nf_conntrack_count.h b/include/net/netfilter/nf_conntrack_count.h
|
|
index 115bb7e572f7d0..bf22661925b813 100644
|
|
--- a/include/net/netfilter/nf_conntrack_count.h
|
|
+++ b/include/net/netfilter/nf_conntrack_count.h
|
|
@@ -13,6 +13,7 @@ struct nf_conncount_list {
|
|
u32 last_gc; /* jiffies at most recent gc */
|
|
struct list_head head; /* connections with the same filtering key */
|
|
unsigned int count; /* length of list */
|
|
+ unsigned int last_gc_count; /* length of list at most recent gc */
|
|
};
|
|
|
|
struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int family,
|
|
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
|
|
index 7a41c479153673..521529e61ae1c9 100644
|
|
--- a/include/net/netns/ipv4.h
|
|
+++ b/include/net/netns/ipv4.h
|
|
@@ -42,6 +42,44 @@ struct inet_timewait_death_row {
|
|
struct tcp_fastopen_context;
|
|
|
|
struct netns_ipv4 {
|
|
+ /* Cacheline organization can be found documented in
|
|
+ * Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst.
|
|
+ * Please update the document when adding new fields.
|
|
+ */
|
|
+
|
|
+ /* TX readonly hotpath cache lines */
|
|
+ __cacheline_group_begin(netns_ipv4_read_tx);
|
|
+ u8 sysctl_tcp_early_retrans;
|
|
+ u8 sysctl_tcp_tso_win_divisor;
|
|
+ u8 sysctl_tcp_tso_rtt_log;
|
|
+ u8 sysctl_tcp_autocorking;
|
|
+ int sysctl_tcp_min_snd_mss;
|
|
+ unsigned int sysctl_tcp_notsent_lowat;
|
|
+ int sysctl_tcp_limit_output_bytes;
|
|
+ int sysctl_tcp_min_rtt_wlen;
|
|
+ int sysctl_tcp_wmem[3];
|
|
+ u8 sysctl_ip_fwd_use_pmtu;
|
|
+ __cacheline_group_end(netns_ipv4_read_tx);
|
|
+
|
|
+ /* TXRX readonly hotpath cache lines */
|
|
+ __cacheline_group_begin(netns_ipv4_read_txrx);
|
|
+ u8 sysctl_tcp_moderate_rcvbuf;
|
|
+ __cacheline_group_end(netns_ipv4_read_txrx);
|
|
+
|
|
+ /* RX readonly hotpath cache line */
|
|
+ __cacheline_group_begin(netns_ipv4_read_rx);
|
|
+ u8 sysctl_ip_early_demux;
|
|
+ u8 sysctl_tcp_early_demux;
|
|
+ int sysctl_tcp_reordering;
|
|
+ int sysctl_tcp_rmem[3];
|
|
+ __cacheline_group_end(netns_ipv4_read_rx);
|
|
+
|
|
+ /* ICMP rate limiter hot cache line. */
|
|
+ __cacheline_group_begin_aligned(icmp);
|
|
+ atomic_t icmp_global_credit;
|
|
+ u32 icmp_global_stamp;
|
|
+ __cacheline_group_end_aligned(icmp);
|
|
+
|
|
struct inet_timewait_death_row tcp_death_row;
|
|
struct udp_table *udp_table;
|
|
|
|
@@ -84,6 +122,8 @@ struct netns_ipv4 {
|
|
u8 sysctl_icmp_errors_use_inbound_ifaddr;
|
|
int sysctl_icmp_ratelimit;
|
|
int sysctl_icmp_ratemask;
|
|
+ int sysctl_icmp_msgs_per_sec;
|
|
+ int sysctl_icmp_msgs_burst;
|
|
|
|
u32 ip_rt_min_pmtu;
|
|
int ip_rt_mtu_expires;
|
|
@@ -96,17 +136,14 @@ struct netns_ipv4 {
|
|
|
|
u8 sysctl_ip_default_ttl;
|
|
u8 sysctl_ip_no_pmtu_disc;
|
|
- u8 sysctl_ip_fwd_use_pmtu;
|
|
u8 sysctl_ip_fwd_update_priority;
|
|
u8 sysctl_ip_nonlocal_bind;
|
|
u8 sysctl_ip_autobind_reuse;
|
|
/* Shall we try to damage output packets if routing dev changes? */
|
|
u8 sysctl_ip_dynaddr;
|
|
- u8 sysctl_ip_early_demux;
|
|
#ifdef CONFIG_NET_L3_MASTER_DEV
|
|
u8 sysctl_raw_l3mdev_accept;
|
|
#endif
|
|
- u8 sysctl_tcp_early_demux;
|
|
u8 sysctl_udp_early_demux;
|
|
|
|
u8 sysctl_nexthop_compat_mode;
|
|
@@ -119,7 +156,6 @@ struct netns_ipv4 {
|
|
u8 sysctl_tcp_mtu_probing;
|
|
int sysctl_tcp_mtu_probe_floor;
|
|
int sysctl_tcp_base_mss;
|
|
- int sysctl_tcp_min_snd_mss;
|
|
int sysctl_tcp_probe_threshold;
|
|
u32 sysctl_tcp_probe_interval;
|
|
|
|
@@ -132,17 +168,17 @@ struct netns_ipv4 {
|
|
u8 sysctl_tcp_syncookies;
|
|
u8 sysctl_tcp_migrate_req;
|
|
u8 sysctl_tcp_comp_sack_nr;
|
|
- int sysctl_tcp_reordering;
|
|
+ u8 sysctl_tcp_backlog_ack_defer;
|
|
+ u8 sysctl_tcp_pingpong_thresh;
|
|
+
|
|
u8 sysctl_tcp_retries1;
|
|
u8 sysctl_tcp_retries2;
|
|
u8 sysctl_tcp_orphan_retries;
|
|
u8 sysctl_tcp_tw_reuse;
|
|
int sysctl_tcp_fin_timeout;
|
|
- unsigned int sysctl_tcp_notsent_lowat;
|
|
u8 sysctl_tcp_sack;
|
|
u8 sysctl_tcp_window_scaling;
|
|
u8 sysctl_tcp_timestamps;
|
|
- u8 sysctl_tcp_early_retrans;
|
|
u8 sysctl_tcp_recovery;
|
|
u8 sysctl_tcp_thin_linear_timeouts;
|
|
u8 sysctl_tcp_slow_start_after_idle;
|
|
@@ -158,21 +194,13 @@ struct netns_ipv4 {
|
|
u8 sysctl_tcp_frto;
|
|
u8 sysctl_tcp_nometrics_save;
|
|
u8 sysctl_tcp_no_ssthresh_metrics_save;
|
|
- u8 sysctl_tcp_moderate_rcvbuf;
|
|
- u8 sysctl_tcp_tso_win_divisor;
|
|
u8 sysctl_tcp_workaround_signed_windows;
|
|
- int sysctl_tcp_limit_output_bytes;
|
|
int sysctl_tcp_challenge_ack_limit;
|
|
- int sysctl_tcp_min_rtt_wlen;
|
|
u8 sysctl_tcp_min_tso_segs;
|
|
- u8 sysctl_tcp_tso_rtt_log;
|
|
- u8 sysctl_tcp_autocorking;
|
|
u8 sysctl_tcp_reflect_tos;
|
|
int sysctl_tcp_invalid_ratelimit;
|
|
int sysctl_tcp_pacing_ss_ratio;
|
|
int sysctl_tcp_pacing_ca_ratio;
|
|
- int sysctl_tcp_wmem[3];
|
|
- int sysctl_tcp_rmem[3];
|
|
unsigned int sysctl_tcp_child_ehash_entries;
|
|
unsigned long sysctl_tcp_comp_sack_delay_ns;
|
|
unsigned long sysctl_tcp_comp_sack_slack_ns;
|
|
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
|
|
index de1d88d41270cf..038fa78835bed6 100644
|
|
--- a/include/rdma/ib_verbs.h
|
|
+++ b/include/rdma/ib_verbs.h
|
|
@@ -1096,7 +1096,7 @@ struct ib_qp_cap {
|
|
|
|
/*
|
|
* Maximum number of rdma_rw_ctx structures in flight at a time.
|
|
- * ib_create_qp() will calculate the right amount of neededed WRs
|
|
+ * ib_create_qp() will calculate the right amount of needed WRs
|
|
* and MRs based on this.
|
|
*/
|
|
u32 max_rdma_ctxs;
|
|
diff --git a/include/rdma/rw.h b/include/rdma/rw.h
|
|
index d606cac482338b..9a8f4b76ce588d 100644
|
|
--- a/include/rdma/rw.h
|
|
+++ b/include/rdma/rw.h
|
|
@@ -66,6 +66,8 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num,
|
|
|
|
unsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num,
|
|
unsigned int maxpages);
|
|
+unsigned int rdma_rw_max_send_wr(struct ib_device *dev, u32 port_num,
|
|
+ unsigned int max_rdma_ctxs, u32 create_flags);
|
|
void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr);
|
|
int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr);
|
|
void rdma_rw_cleanup_mrs(struct ib_qp *qp);
|
|
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
|
|
index aaa502a7bff46c..1749b35ab2c21d 100644
|
|
--- a/include/uapi/linux/hyperv.h
|
|
+++ b/include/uapi/linux/hyperv.h
|
|
@@ -362,7 +362,7 @@ struct hv_kvp_exchg_msg_value {
|
|
__u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
|
|
__u32 value_u32;
|
|
__u64 value_u64;
|
|
- };
|
|
+ } __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
struct hv_kvp_msg_enumerate {
|
|
diff --git a/include/uapi/linux/netfilter_bridge.h b/include/uapi/linux/netfilter_bridge.h
|
|
index 1610fdbab98dfc..ad520d3e9df8f7 100644
|
|
--- a/include/uapi/linux/netfilter_bridge.h
|
|
+++ b/include/uapi/linux/netfilter_bridge.h
|
|
@@ -5,6 +5,10 @@
|
|
/* bridge-specific defines for netfilter.
|
|
*/
|
|
|
|
+#ifndef __KERNEL__
|
|
+#include <netinet/if_ether.h> /* for __UAPI_DEF_ETHHDR if defined */
|
|
+#endif
|
|
+
|
|
#include <linux/in.h>
|
|
#include <linux/netfilter.h>
|
|
#include <linux/if_ether.h>
|
|
diff --git a/include/uapi/linux/vbox_vmmdev_types.h b/include/uapi/linux/vbox_vmmdev_types.h
|
|
index f8a8d6b3c5219d..436678d4fb24f3 100644
|
|
--- a/include/uapi/linux/vbox_vmmdev_types.h
|
|
+++ b/include/uapi/linux/vbox_vmmdev_types.h
|
|
@@ -236,7 +236,7 @@ struct vmmdev_hgcm_function_parameter32 {
|
|
/** Relative to the request header. */
|
|
__u32 offset;
|
|
} page_list;
|
|
- } u;
|
|
+ } __packed u;
|
|
} __packed;
|
|
VMMDEV_ASSERT_SIZE(vmmdev_hgcm_function_parameter32, 4 + 8);
|
|
|
|
@@ -251,7 +251,7 @@ struct vmmdev_hgcm_function_parameter64 {
|
|
union {
|
|
__u64 phys_addr;
|
|
__u64 linear_addr;
|
|
- } u;
|
|
+ } __packed u;
|
|
} __packed pointer;
|
|
struct {
|
|
/** Size of the buffer described by the page list. */
|
|
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
|
|
index 78380fc2374ea5..8d2efb9e5d664b 100644
|
|
--- a/include/ufs/ufshcd.h
|
|
+++ b/include/ufs/ufshcd.h
|
|
@@ -1329,17 +1329,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba)
|
|
return hba->priv;
|
|
}
|
|
|
|
-#ifdef CONFIG_PM
|
|
extern int ufshcd_runtime_suspend(struct device *dev);
|
|
extern int ufshcd_runtime_resume(struct device *dev);
|
|
-#endif
|
|
-#ifdef CONFIG_PM_SLEEP
|
|
extern int ufshcd_system_suspend(struct device *dev);
|
|
extern int ufshcd_system_resume(struct device *dev);
|
|
extern int ufshcd_system_freeze(struct device *dev);
|
|
extern int ufshcd_system_thaw(struct device *dev);
|
|
extern int ufshcd_system_restore(struct device *dev);
|
|
-#endif
|
|
|
|
extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
|
|
int agreed_gear,
|
|
diff --git a/include/xen/xen.h b/include/xen/xen.h
|
|
index a1e5b3f18d69f9..86fe96fe518345 100644
|
|
--- a/include/xen/xen.h
|
|
+++ b/include/xen/xen.h
|
|
@@ -62,11 +62,13 @@ extern u64 xen_saved_max_mem_size;
|
|
#endif
|
|
|
|
#ifdef CONFIG_XEN_UNPOPULATED_ALLOC
|
|
+extern unsigned long xen_unpopulated_pages;
|
|
int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages);
|
|
void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages);
|
|
#include <linux/ioport.h>
|
|
int arch_xen_unpopulated_init(struct resource **res);
|
|
#else
|
|
+#define xen_unpopulated_pages 0UL
|
|
#include <xen/balloon.h>
|
|
static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages,
|
|
struct page **pages)
|
|
diff --git a/io_uring/cancel.h b/io_uring/cancel.h
|
|
index fc98622e6166e1..7e6d0fca7db28a 100644
|
|
--- a/io_uring/cancel.h
|
|
+++ b/io_uring/cancel.h
|
|
@@ -4,10 +4,8 @@
|
|
|
|
struct io_cancel_data {
|
|
struct io_ring_ctx *ctx;
|
|
- union {
|
|
- u64 data;
|
|
- struct file *file;
|
|
- };
|
|
+ u64 data;
|
|
+ struct file *file;
|
|
u8 opcode;
|
|
u32 flags;
|
|
int seq;
|
|
diff --git a/io_uring/filetable.c b/io_uring/filetable.c
|
|
index ff74d41d9e53c5..aa9f0abcd8eeab 100644
|
|
--- a/io_uring/filetable.c
|
|
+++ b/io_uring/filetable.c
|
|
@@ -22,6 +22,10 @@ static int io_file_bitmap_get(struct io_ring_ctx *ctx)
|
|
if (!table->bitmap)
|
|
return -ENFILE;
|
|
|
|
+ if (table->alloc_hint < ctx->file_alloc_start ||
|
|
+ table->alloc_hint >= ctx->file_alloc_end)
|
|
+ table->alloc_hint = ctx->file_alloc_start;
|
|
+
|
|
do {
|
|
ret = find_next_zero_bit(table->bitmap, nr, table->alloc_hint);
|
|
if (ret != nr)
|
|
diff --git a/io_uring/sync.c b/io_uring/sync.c
|
|
index 255f68c37e55cc..27bd0a26500bcf 100644
|
|
--- a/io_uring/sync.c
|
|
+++ b/io_uring/sync.c
|
|
@@ -62,6 +62,8 @@ int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|
return -EINVAL;
|
|
|
|
sync->off = READ_ONCE(sqe->off);
|
|
+ if (sync->off < 0)
|
|
+ return -EINVAL;
|
|
sync->len = READ_ONCE(sqe->len);
|
|
req->flags |= REQ_F_FORCE_ASYNC;
|
|
return 0;
|
|
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
|
|
index b2f39a86f47341..22b12a482ba912 100644
|
|
--- a/ipc/ipc_sysctl.c
|
|
+++ b/ipc/ipc_sysctl.c
|
|
@@ -215,7 +215,7 @@ static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *tabl
|
|
if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) ||
|
|
(table->data == &ns->ids[IPC_MSG_IDS].next_id) ||
|
|
(table->data == &ns->ids[IPC_SHM_IDS].next_id)) &&
|
|
- checkpoint_restore_ns_capable(ns->user_ns))
|
|
+ checkpoint_restore_ns_capable_noaudit(ns->user_ns))
|
|
mode = 0666;
|
|
else
|
|
#endif
|
|
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
|
|
index 45b2f06de452ce..4af7c96f6985da 100644
|
|
--- a/kernel/bpf/verifier.c
|
|
+++ b/kernel/bpf/verifier.c
|
|
@@ -13136,21 +13136,17 @@ static void __scalar64_min_max_lsh(struct bpf_reg_state *dst_reg,
|
|
u64 umin_val, u64 umax_val)
|
|
{
|
|
/* Special case <<32 because it is a common compiler pattern to sign
|
|
- * extend subreg by doing <<32 s>>32. In this case if 32bit bounds are
|
|
- * positive we know this shift will also be positive so we can track
|
|
- * bounds correctly. Otherwise we lose all sign bit information except
|
|
- * what we can pick up from var_off. Perhaps we can generalize this
|
|
- * later to shifts of any length.
|
|
+ * extend subreg by doing <<32 s>>32. smin/smax assignments are correct
|
|
+ * because s32 bounds don't flip sign when shifting to the left by
|
|
+ * 32bits.
|
|
*/
|
|
- if (umin_val == 32 && umax_val == 32 && dst_reg->s32_max_value >= 0)
|
|
+ if (umin_val == 32 && umax_val == 32) {
|
|
dst_reg->smax_value = (s64)dst_reg->s32_max_value << 32;
|
|
- else
|
|
- dst_reg->smax_value = S64_MAX;
|
|
-
|
|
- if (umin_val == 32 && umax_val == 32 && dst_reg->s32_min_value >= 0)
|
|
dst_reg->smin_value = (s64)dst_reg->s32_min_value << 32;
|
|
- else
|
|
+ } else {
|
|
+ dst_reg->smax_value = S64_MAX;
|
|
dst_reg->smin_value = S64_MIN;
|
|
+ }
|
|
|
|
/* If we might shift our top bit out, then we know nothing */
|
|
if (dst_reg->umax_value > 1ULL << (63 - umax_val)) {
|
|
diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config
|
|
index 4722b998a32453..7471b4062b7a09 100644
|
|
--- a/kernel/configs/debug.config
|
|
+++ b/kernel/configs/debug.config
|
|
@@ -29,7 +29,6 @@ CONFIG_SECTION_MISMATCH_WARN_ONLY=y
|
|
# CONFIG_UBSAN_ALIGNMENT is not set
|
|
# CONFIG_UBSAN_DIV_ZERO is not set
|
|
# CONFIG_UBSAN_TRAP is not set
|
|
-# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
|
|
CONFIG_DEBUG_FS=y
|
|
CONFIG_DEBUG_FS_ALLOW_ALL=y
|
|
CONFIG_DEBUG_IRQFLAGS=y
|
|
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
|
|
index 07f33601cac281..cd44e9c4275330 100644
|
|
--- a/kernel/kallsyms.c
|
|
+++ b/kernel/kallsyms.c
|
|
@@ -431,8 +431,8 @@ static const char *kallsyms_lookup_buildid(unsigned long addr,
|
|
offset, modname, namebuf);
|
|
|
|
if (!ret)
|
|
- ret = ftrace_mod_address_lookup(addr, symbolsize,
|
|
- offset, modname, namebuf);
|
|
+ ret = ftrace_mod_address_lookup(addr, symbolsize, offset,
|
|
+ modname, modbuildid, namebuf);
|
|
|
|
found:
|
|
cleanup_symbol_name(namebuf);
|
|
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
|
|
index 830344627e9f20..92a169f0b2b575 100644
|
|
--- a/kernel/kexec_file.c
|
|
+++ b/kernel/kexec_file.c
|
|
@@ -797,6 +797,60 @@ out:
|
|
}
|
|
|
|
#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY
|
|
+/*
|
|
+ * kexec_purgatory_find_symbol - find a symbol in the purgatory
|
|
+ * @pi: Purgatory to search in.
|
|
+ * @name: Name of the symbol.
|
|
+ *
|
|
+ * Return: pointer to symbol in read-only symtab on success, NULL on error.
|
|
+ */
|
|
+static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi,
|
|
+ const char *name)
|
|
+{
|
|
+ const Elf_Shdr *sechdrs;
|
|
+ const Elf_Ehdr *ehdr;
|
|
+ const Elf_Sym *syms;
|
|
+ const char *strtab;
|
|
+ int i, k;
|
|
+
|
|
+ if (!pi->ehdr)
|
|
+ return NULL;
|
|
+
|
|
+ ehdr = pi->ehdr;
|
|
+ sechdrs = (void *)ehdr + ehdr->e_shoff;
|
|
+
|
|
+ for (i = 0; i < ehdr->e_shnum; i++) {
|
|
+ if (sechdrs[i].sh_type != SHT_SYMTAB)
|
|
+ continue;
|
|
+
|
|
+ if (sechdrs[i].sh_link >= ehdr->e_shnum)
|
|
+ /* Invalid strtab section number */
|
|
+ continue;
|
|
+ strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset;
|
|
+ syms = (void *)ehdr + sechdrs[i].sh_offset;
|
|
+
|
|
+ /* Go through symbols for a match */
|
|
+ for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) {
|
|
+ if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
|
|
+ continue;
|
|
+
|
|
+ if (strcmp(strtab + syms[k].st_name, name) != 0)
|
|
+ continue;
|
|
+
|
|
+ if (syms[k].st_shndx == SHN_UNDEF ||
|
|
+ syms[k].st_shndx >= ehdr->e_shnum) {
|
|
+ pr_debug("Symbol: %s has bad section index %d.\n",
|
|
+ name, syms[k].st_shndx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Found the symbol we are looking for */
|
|
+ return &syms[k];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
/*
|
|
* kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
|
|
* @pi: Purgatory to be loaded.
|
|
@@ -875,6 +929,10 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
|
unsigned long offset;
|
|
size_t sechdrs_size;
|
|
Elf_Shdr *sechdrs;
|
|
+ const Elf_Sym *entry_sym;
|
|
+ u16 entry_shndx = 0;
|
|
+ unsigned long entry_off = 0;
|
|
+ bool start_fixed = false;
|
|
int i;
|
|
|
|
/*
|
|
@@ -892,6 +950,12 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
|
bss_addr = kbuf->mem + kbuf->bufsz;
|
|
kbuf->image->start = pi->ehdr->e_entry;
|
|
|
|
+ entry_sym = kexec_purgatory_find_symbol(pi, "purgatory_start");
|
|
+ if (entry_sym) {
|
|
+ entry_shndx = entry_sym->st_shndx;
|
|
+ entry_off = entry_sym->st_value;
|
|
+ }
|
|
+
|
|
for (i = 0; i < pi->ehdr->e_shnum; i++) {
|
|
unsigned long align;
|
|
void *src, *dst;
|
|
@@ -909,6 +973,13 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
|
|
|
offset = ALIGN(offset, align);
|
|
|
|
+ if (!start_fixed && entry_sym && i == entry_shndx &&
|
|
+ (sechdrs[i].sh_flags & SHF_EXECINSTR) &&
|
|
+ entry_off < sechdrs[i].sh_size) {
|
|
+ kbuf->image->start = kbuf->mem + offset + entry_off;
|
|
+ start_fixed = true;
|
|
+ }
|
|
+
|
|
/*
|
|
* Check if the segment contains the entry point, if so,
|
|
* calculate the value of image->start based on it.
|
|
@@ -919,13 +990,14 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
|
* is not set to the initial value, and warn the user so they
|
|
* have a chance to fix their purgatory's linker script.
|
|
*/
|
|
- if (sechdrs[i].sh_flags & SHF_EXECINSTR &&
|
|
+ if (!start_fixed && sechdrs[i].sh_flags & SHF_EXECINSTR &&
|
|
pi->ehdr->e_entry >= sechdrs[i].sh_addr &&
|
|
pi->ehdr->e_entry < (sechdrs[i].sh_addr
|
|
+ sechdrs[i].sh_size) &&
|
|
- !WARN_ON(kbuf->image->start != pi->ehdr->e_entry)) {
|
|
+ kbuf->image->start == pi->ehdr->e_entry) {
|
|
kbuf->image->start -= sechdrs[i].sh_addr;
|
|
kbuf->image->start += kbuf->mem + offset;
|
|
+ start_fixed = true;
|
|
}
|
|
|
|
src = (void *)pi->ehdr + sechdrs[i].sh_offset;
|
|
@@ -1043,61 +1115,6 @@ out_free_kbuf:
|
|
return ret;
|
|
}
|
|
|
|
-/*
|
|
- * kexec_purgatory_find_symbol - find a symbol in the purgatory
|
|
- * @pi: Purgatory to search in.
|
|
- * @name: Name of the symbol.
|
|
- *
|
|
- * Return: pointer to symbol in read-only symtab on success, NULL on error.
|
|
- */
|
|
-static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi,
|
|
- const char *name)
|
|
-{
|
|
- const Elf_Shdr *sechdrs;
|
|
- const Elf_Ehdr *ehdr;
|
|
- const Elf_Sym *syms;
|
|
- const char *strtab;
|
|
- int i, k;
|
|
-
|
|
- if (!pi->ehdr)
|
|
- return NULL;
|
|
-
|
|
- ehdr = pi->ehdr;
|
|
- sechdrs = (void *)ehdr + ehdr->e_shoff;
|
|
-
|
|
- for (i = 0; i < ehdr->e_shnum; i++) {
|
|
- if (sechdrs[i].sh_type != SHT_SYMTAB)
|
|
- continue;
|
|
-
|
|
- if (sechdrs[i].sh_link >= ehdr->e_shnum)
|
|
- /* Invalid strtab section number */
|
|
- continue;
|
|
- strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset;
|
|
- syms = (void *)ehdr + sechdrs[i].sh_offset;
|
|
-
|
|
- /* Go through symbols for a match */
|
|
- for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) {
|
|
- if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
|
|
- continue;
|
|
-
|
|
- if (strcmp(strtab + syms[k].st_name, name) != 0)
|
|
- continue;
|
|
-
|
|
- if (syms[k].st_shndx == SHN_UNDEF ||
|
|
- syms[k].st_shndx >= ehdr->e_shnum) {
|
|
- pr_debug("Symbol: %s has bad section index %d.\n",
|
|
- name, syms[k].st_shndx);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- /* Found the symbol we are looking for */
|
|
- return &syms[k];
|
|
- }
|
|
- }
|
|
-
|
|
- return NULL;
|
|
-}
|
|
-
|
|
void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name)
|
|
{
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
|
diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
|
|
index ef73ae7c89094b..84280897911333 100644
|
|
--- a/kernel/module/kallsyms.c
|
|
+++ b/kernel/module/kallsyms.c
|
|
@@ -336,13 +336,8 @@ const char *module_address_lookup(unsigned long addr,
|
|
if (mod) {
|
|
if (modname)
|
|
*modname = mod->name;
|
|
- if (modbuildid) {
|
|
-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
|
|
- *modbuildid = mod->build_id;
|
|
-#else
|
|
- *modbuildid = NULL;
|
|
-#endif
|
|
- }
|
|
+ if (modbuildid)
|
|
+ *modbuildid = module_buildid(mod);
|
|
|
|
ret = find_kallsyms_symbol(mod, addr, size, offset);
|
|
}
|
|
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
|
|
index 607b2e68fa4c20..81f0a730c54b24 100644
|
|
--- a/kernel/rcu/tree.c
|
|
+++ b/kernel/rcu/tree.c
|
|
@@ -4379,6 +4379,54 @@ rcu_boot_init_percpu_data(int cpu)
|
|
rcu_boot_init_nocb_percpu_data(rdp);
|
|
}
|
|
|
|
+#ifdef CONFIG_RCU_EXP_KTHREAD
|
|
+struct kthread_worker *rcu_exp_gp_kworker;
|
|
+struct kthread_worker *rcu_exp_par_gp_kworker;
|
|
+
|
|
+static void __init rcu_start_exp_gp_kworkers(void)
|
|
+{
|
|
+ const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker";
|
|
+ const char *gp_kworker_name = "rcu_exp_gp_kthread_worker";
|
|
+ struct sched_param param = { .sched_priority = kthread_prio };
|
|
+
|
|
+ rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name);
|
|
+ if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
|
|
+ pr_err("Failed to create %s!\n", gp_kworker_name);
|
|
+ rcu_exp_gp_kworker = NULL;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name);
|
|
+ if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) {
|
|
+ pr_err("Failed to create %s!\n", par_gp_kworker_name);
|
|
+ rcu_exp_par_gp_kworker = NULL;
|
|
+ kthread_destroy_worker(rcu_exp_gp_kworker);
|
|
+ rcu_exp_gp_kworker = NULL;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m);
|
|
+ sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO,
|
|
+ ¶m);
|
|
+}
|
|
+
|
|
+static inline void rcu_alloc_par_gp_wq(void)
|
|
+{
|
|
+}
|
|
+#else /* !CONFIG_RCU_EXP_KTHREAD */
|
|
+struct workqueue_struct *rcu_par_gp_wq;
|
|
+
|
|
+static void __init rcu_start_exp_gp_kworkers(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void rcu_alloc_par_gp_wq(void)
|
|
+{
|
|
+ rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0);
|
|
+ WARN_ON(!rcu_par_gp_wq);
|
|
+}
|
|
+#endif /* CONFIG_RCU_EXP_KTHREAD */
|
|
+
|
|
/*
|
|
* Invoked early in the CPU-online process, when pretty much all services
|
|
* are available. The incoming CPU is not present.
|
|
@@ -4686,54 +4734,6 @@ static int rcu_pm_notify(struct notifier_block *self,
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
-#ifdef CONFIG_RCU_EXP_KTHREAD
|
|
-struct kthread_worker *rcu_exp_gp_kworker;
|
|
-struct kthread_worker *rcu_exp_par_gp_kworker;
|
|
-
|
|
-static void __init rcu_start_exp_gp_kworkers(void)
|
|
-{
|
|
- const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker";
|
|
- const char *gp_kworker_name = "rcu_exp_gp_kthread_worker";
|
|
- struct sched_param param = { .sched_priority = kthread_prio };
|
|
-
|
|
- rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name);
|
|
- if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
|
|
- pr_err("Failed to create %s!\n", gp_kworker_name);
|
|
- rcu_exp_gp_kworker = NULL;
|
|
- return;
|
|
- }
|
|
-
|
|
- rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name);
|
|
- if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) {
|
|
- pr_err("Failed to create %s!\n", par_gp_kworker_name);
|
|
- rcu_exp_par_gp_kworker = NULL;
|
|
- kthread_destroy_worker(rcu_exp_gp_kworker);
|
|
- rcu_exp_gp_kworker = NULL;
|
|
- return;
|
|
- }
|
|
-
|
|
- sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m);
|
|
- sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO,
|
|
- ¶m);
|
|
-}
|
|
-
|
|
-static inline void rcu_alloc_par_gp_wq(void)
|
|
-{
|
|
-}
|
|
-#else /* !CONFIG_RCU_EXP_KTHREAD */
|
|
-struct workqueue_struct *rcu_par_gp_wq;
|
|
-
|
|
-static void __init rcu_start_exp_gp_kworkers(void)
|
|
-{
|
|
-}
|
|
-
|
|
-static inline void rcu_alloc_par_gp_wq(void)
|
|
-{
|
|
- rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0);
|
|
- WARN_ON(!rcu_par_gp_wq);
|
|
-}
|
|
-#endif /* CONFIG_RCU_EXP_KTHREAD */
|
|
-
|
|
/*
|
|
* Spawn the kthreads that handle RCU's grace periods.
|
|
*/
|
|
@@ -4874,7 +4874,7 @@ static void __init rcu_init_one(void)
|
|
init_waitqueue_head(&rnp->exp_wq[2]);
|
|
init_waitqueue_head(&rnp->exp_wq[3]);
|
|
spin_lock_init(&rnp->exp_lock);
|
|
- mutex_init(&rnp->boost_kthread_mutex);
|
|
+ mutex_init(&rnp->kthread_mutex);
|
|
raw_spin_lock_init(&rnp->exp_poll_lock);
|
|
rnp->exp_seq_poll_rq = RCU_GET_STATE_COMPLETED;
|
|
INIT_WORK(&rnp->exp_poll_wq, sync_rcu_do_polled_gp);
|
|
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
|
|
index 71403d22a84655..b79599b2059cc8 100644
|
|
--- a/kernel/rcu/tree.h
|
|
+++ b/kernel/rcu/tree.h
|
|
@@ -113,7 +113,7 @@ struct rcu_node {
|
|
/* side effect, not as a lock. */
|
|
unsigned long boost_time;
|
|
/* When to start boosting (jiffies). */
|
|
- struct mutex boost_kthread_mutex;
|
|
+ struct mutex kthread_mutex;
|
|
/* Exclusion for thread spawning and affinity */
|
|
/* manipulation. */
|
|
struct task_struct *boost_kthread_task;
|
|
@@ -203,7 +203,7 @@ struct rcu_data {
|
|
/* during and after the last grace */
|
|
/* period it is aware of. */
|
|
struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */
|
|
- int defer_qs_iw_pending; /* Scheduler attention pending? */
|
|
+ int defer_qs_pending; /* irqwork or softirq pending? */
|
|
struct work_struct strict_work; /* Schedule readers for strict GPs. */
|
|
|
|
/* 2) batch handling */
|
|
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
|
|
index 8707f155afb6df..8cf1adcd259ba9 100644
|
|
--- a/kernel/rcu/tree_plugin.h
|
|
+++ b/kernel/rcu/tree_plugin.h
|
|
@@ -475,8 +475,8 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
|
|
union rcu_special special;
|
|
|
|
rdp = this_cpu_ptr(&rcu_data);
|
|
- if (rdp->defer_qs_iw_pending == DEFER_QS_PENDING)
|
|
- rdp->defer_qs_iw_pending = DEFER_QS_IDLE;
|
|
+ if (rdp->defer_qs_pending == DEFER_QS_PENDING)
|
|
+ rdp->defer_qs_pending = DEFER_QS_IDLE;
|
|
|
|
/*
|
|
* If RCU core is waiting for this CPU to exit its critical section,
|
|
@@ -615,11 +615,10 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t)
|
|
*/
|
|
static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
|
|
{
|
|
- unsigned long flags;
|
|
struct rcu_data *rdp;
|
|
|
|
+ lockdep_assert_irqs_disabled();
|
|
rdp = container_of(iwp, struct rcu_data, defer_qs_iw);
|
|
- local_irq_save(flags);
|
|
|
|
/*
|
|
* If the IRQ work handler happens to run in the middle of RCU read-side
|
|
@@ -635,9 +634,76 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
|
|
* 5. Deferred QS reporting does not happen.
|
|
*/
|
|
if (rcu_preempt_depth() > 0)
|
|
- WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE);
|
|
+ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE);
|
|
+}
|
|
|
|
- local_irq_restore(flags);
|
|
+/*
|
|
+ * Check if expedited grace period processing during unlock is needed.
|
|
+ *
|
|
+ * This function determines whether expedited handling is required based on:
|
|
+ * 1. Task blocking an expedited grace period (based on a heuristic, could be
|
|
+ * false-positive, see below.)
|
|
+ * 2. CPU participating in an expedited grace period
|
|
+ * 3. Strict grace period mode requiring expedited handling
|
|
+ * 4. RCU priority deboosting needs when interrupts were disabled
|
|
+ *
|
|
+ * @t: The task being checked
|
|
+ * @rdp: The per-CPU RCU data
|
|
+ * @rnp: The RCU node for this CPU
|
|
+ * @irqs_were_disabled: Whether interrupts were disabled before rcu_read_unlock()
|
|
+ *
|
|
+ * Returns true if expedited processing of the rcu_read_unlock() is needed.
|
|
+ */
|
|
+static bool rcu_unlock_needs_exp_handling(struct task_struct *t,
|
|
+ struct rcu_data *rdp,
|
|
+ struct rcu_node *rnp,
|
|
+ bool irqs_were_disabled)
|
|
+{
|
|
+ /*
|
|
+ * Check if this task is blocking an expedited grace period. If the
|
|
+ * task was preempted within an RCU read-side critical section and is
|
|
+ * on the expedited grace period blockers list (exp_tasks), we need
|
|
+ * expedited handling to unblock the expedited GP. This is not an exact
|
|
+ * check because 't' might not be on the exp_tasks list at all - its
|
|
+ * just a fast heuristic that can be false-positive sometimes.
|
|
+ */
|
|
+ if (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks))
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * Check if this CPU is participating in an expedited grace period.
|
|
+ * The expmask bitmap tracks which CPUs need to check in for the
|
|
+ * current expedited GP. If our CPU's bit is set, we need expedited
|
|
+ * handling to help complete the expedited GP.
|
|
+ */
|
|
+ if (rdp->grpmask & READ_ONCE(rnp->expmask))
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * In CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels, all grace periods
|
|
+ * are treated as short for testing purposes even if that means
|
|
+ * disturbing the system more. Check if either:
|
|
+ * - This CPU has not yet reported a quiescent state, or
|
|
+ * - This task was preempted within an RCU critical section
|
|
+ * In either case, require expedited handling for strict GP mode.
|
|
+ */
|
|
+ if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) &&
|
|
+ ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node))
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * RCU priority boosting case: If a task is subject to RCU priority
|
|
+ * boosting and exits an RCU read-side critical section with interrupts
|
|
+ * disabled, we need expedited handling to ensure timely deboosting.
|
|
+ * Without this, a low-priority task could incorrectly run at high
|
|
+ * real-time priority for an extended period degrading real-time
|
|
+ * responsiveness. This applies to all CONFIG_RCU_BOOST=y kernels,
|
|
+ * not just to PREEMPT_RT.
|
|
+ */
|
|
+ if (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled && t->rcu_blocked_node)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
}
|
|
|
|
/*
|
|
@@ -659,22 +725,21 @@ static void rcu_read_unlock_special(struct task_struct *t)
|
|
local_irq_save(flags);
|
|
irqs_were_disabled = irqs_disabled_flags(flags);
|
|
if (preempt_bh_were_disabled || irqs_were_disabled) {
|
|
- bool expboost; // Expedited GP in flight or possible boosting.
|
|
+ bool needs_exp; // Expedited handling needed.
|
|
struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
|
|
struct rcu_node *rnp = rdp->mynode;
|
|
|
|
- expboost = (t->rcu_blocked_node && READ_ONCE(t->rcu_blocked_node->exp_tasks)) ||
|
|
- (rdp->grpmask & READ_ONCE(rnp->expmask)) ||
|
|
- (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) &&
|
|
- ((rdp->grpmask & READ_ONCE(rnp->qsmask)) || t->rcu_blocked_node)) ||
|
|
- (IS_ENABLED(CONFIG_RCU_BOOST) && irqs_were_disabled &&
|
|
- t->rcu_blocked_node);
|
|
+ needs_exp = rcu_unlock_needs_exp_handling(t, rdp, rnp, irqs_were_disabled);
|
|
+
|
|
// Need to defer quiescent state until everything is enabled.
|
|
- if (use_softirq && (in_hardirq() || (expboost && !irqs_were_disabled))) {
|
|
+ if (use_softirq && (in_hardirq() || (needs_exp && !irqs_were_disabled))) {
|
|
// Using softirq, safe to awaken, and either the
|
|
// wakeup is free or there is either an expedited
|
|
// GP in flight or a potential need to deboost.
|
|
- raise_softirq_irqoff(RCU_SOFTIRQ);
|
|
+ if (rdp->defer_qs_pending != DEFER_QS_PENDING) {
|
|
+ rdp->defer_qs_pending = DEFER_QS_PENDING;
|
|
+ raise_softirq_irqoff(RCU_SOFTIRQ);
|
|
+ }
|
|
} else {
|
|
// Enabling BH or preempt does reschedule, so...
|
|
// Also if no expediting and no possible deboosting,
|
|
@@ -683,11 +748,11 @@ static void rcu_read_unlock_special(struct task_struct *t)
|
|
set_tsk_need_resched(current);
|
|
set_preempt_need_resched();
|
|
if (IS_ENABLED(CONFIG_IRQ_WORK) && irqs_were_disabled &&
|
|
- expboost && rdp->defer_qs_iw_pending != DEFER_QS_PENDING &&
|
|
+ needs_exp && rdp->defer_qs_pending != DEFER_QS_PENDING &&
|
|
cpu_online(rdp->cpu)) {
|
|
// Get scheduler to re-evaluate and call hooks.
|
|
// If !IRQ_WORK, FQS scan will eventually IPI.
|
|
- rdp->defer_qs_iw_pending = DEFER_QS_PENDING;
|
|
+ rdp->defer_qs_pending = DEFER_QS_PENDING;
|
|
irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu);
|
|
}
|
|
}
|
|
@@ -1229,7 +1294,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
|
|
struct sched_param sp;
|
|
struct task_struct *t;
|
|
|
|
- mutex_lock(&rnp->boost_kthread_mutex);
|
|
+ mutex_lock(&rnp->kthread_mutex);
|
|
if (rnp->boost_kthread_task || !rcu_scheduler_fully_active)
|
|
goto out;
|
|
|
|
@@ -1246,7 +1311,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
|
|
wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
|
|
|
|
out:
|
|
- mutex_unlock(&rnp->boost_kthread_mutex);
|
|
+ mutex_unlock(&rnp->kthread_mutex);
|
|
}
|
|
|
|
/*
|
|
@@ -1258,7 +1323,7 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
|
|
* no outgoing CPU. If there are no CPUs left in the affinity set,
|
|
* this function allows the kthread to execute on any CPU.
|
|
*
|
|
- * Any future concurrent calls are serialized via ->boost_kthread_mutex.
|
|
+ * Any future concurrent calls are serialized via ->kthread_mutex.
|
|
*/
|
|
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
|
|
{
|
|
@@ -1271,7 +1336,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
|
|
return;
|
|
if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
|
|
return;
|
|
- mutex_lock(&rnp->boost_kthread_mutex);
|
|
+ mutex_lock(&rnp->kthread_mutex);
|
|
mask = rcu_rnp_online_cpus(rnp);
|
|
for_each_leaf_node_possible_cpu(rnp, cpu)
|
|
if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
|
|
@@ -1284,7 +1349,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
|
|
cpumask_clear_cpu(outgoingcpu, cm);
|
|
}
|
|
set_cpus_allowed_ptr(t, cm);
|
|
- mutex_unlock(&rnp->boost_kthread_mutex);
|
|
+ mutex_unlock(&rnp->kthread_mutex);
|
|
free_cpumask_var(cm);
|
|
}
|
|
|
|
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
|
|
index 2d0acdd32108ab..0b420a65b31dc9 100644
|
|
--- a/kernel/sched/rt.c
|
|
+++ b/kernel/sched/rt.c
|
|
@@ -2219,6 +2219,7 @@ static void push_rt_tasks(struct rq *rq)
|
|
*/
|
|
static int rto_next_cpu(struct root_domain *rd)
|
|
{
|
|
+ int this_cpu = smp_processor_id();
|
|
int next;
|
|
int cpu;
|
|
|
|
@@ -2242,6 +2243,10 @@ static int rto_next_cpu(struct root_domain *rd)
|
|
|
|
rd->rto_cpu = cpu;
|
|
|
|
+ /* Do not send IPI to self */
|
|
+ if (cpu == this_cpu)
|
|
+ continue;
|
|
+
|
|
if (cpu < nr_cpu_ids)
|
|
return cpu;
|
|
|
|
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
|
|
index 0320f49bd1f4a0..03f488f93cddf6 100644
|
|
--- a/kernel/time/hrtimer.c
|
|
+++ b/kernel/time/hrtimer.c
|
|
@@ -1715,7 +1715,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
|
|
|
|
lockdep_assert_held(&cpu_base->lock);
|
|
|
|
- debug_deactivate(timer);
|
|
+ debug_hrtimer_deactivate(timer);
|
|
base->running = timer;
|
|
|
|
/*
|
|
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
|
index 8f2d44e741510f..94f7ed57d43e51 100644
|
|
--- a/kernel/trace/ftrace.c
|
|
+++ b/kernel/trace/ftrace.c
|
|
@@ -7046,7 +7046,8 @@ ftrace_func_address_lookup(struct ftrace_mod_map *mod_map,
|
|
|
|
const char *
|
|
ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
|
|
- unsigned long *off, char **modname, char *sym)
|
|
+ unsigned long *off, char **modname,
|
|
+ const unsigned char **modbuildid, char *sym)
|
|
{
|
|
struct ftrace_mod_map *mod_map;
|
|
const char *ret = NULL;
|
|
@@ -7058,6 +7059,8 @@ ftrace_mod_address_lookup(unsigned long addr, unsigned long *size,
|
|
if (ret) {
|
|
if (modname)
|
|
*modname = mod_map->mod->name;
|
|
+ if (modbuildid)
|
|
+ *modbuildid = module_buildid(mod_map->mod);
|
|
break;
|
|
}
|
|
}
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index a111be83c36939..29720531ac8188 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -8831,7 +8831,7 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
|
|
trace_create_cpu_file("stats", TRACE_MODE_READ, d_cpu,
|
|
tr, cpu, &tracing_stats_fops);
|
|
|
|
- trace_create_cpu_file("buffer_size_kb", TRACE_MODE_READ, d_cpu,
|
|
+ trace_create_cpu_file("buffer_size_kb", TRACE_MODE_WRITE, d_cpu,
|
|
tr, cpu, &tracing_entries_fops);
|
|
|
|
#ifdef CONFIG_TRACER_SNAPSHOT
|
|
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
|
|
index 382e07cd49f9f6..106ae22f0464d3 100644
|
|
--- a/kernel/trace/trace_events.c
|
|
+++ b/kernel/trace/trace_events.c
|
|
@@ -1169,6 +1169,9 @@ static void remove_event_file_dir(struct trace_event_file *file)
|
|
free_event_filter(file->filter);
|
|
file->flags |= EVENT_FILE_FL_FREED;
|
|
event_file_put(file);
|
|
+
|
|
+ /* Wake up hist poll waiters to notice the EVENT_FILE_FL_FREED flag. */
|
|
+ hist_poll_wakeup();
|
|
}
|
|
|
|
/*
|
|
@@ -3575,11 +3578,6 @@ void trace_put_event_file(struct trace_event_file *file)
|
|
EXPORT_SYMBOL_GPL(trace_put_event_file);
|
|
|
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
|
-
|
|
-/* Avoid typos */
|
|
-#define ENABLE_EVENT_STR "enable_event"
|
|
-#define DISABLE_EVENT_STR "disable_event"
|
|
-
|
|
struct event_probe_data {
|
|
struct trace_event_file *file;
|
|
unsigned long count;
|
|
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
|
|
index 99d1e8b57f85d3..19b3d388fbc69e 100644
|
|
--- a/kernel/trace/trace_events_hist.c
|
|
+++ b/kernel/trace/trace_events_hist.c
|
|
@@ -5760,7 +5760,7 @@ static __poll_t event_hist_poll(struct file *file, struct poll_table_struct *wai
|
|
|
|
guard(mutex)(&event_mutex);
|
|
|
|
- event_file = event_file_data(file);
|
|
+ event_file = event_file_file(file);
|
|
if (!event_file)
|
|
return EPOLLERR;
|
|
|
|
@@ -5798,7 +5798,7 @@ static int event_hist_open(struct inode *inode, struct file *file)
|
|
|
|
guard(mutex)(&event_mutex);
|
|
|
|
- event_file = event_file_data(file);
|
|
+ event_file = event_file_file(file);
|
|
if (!event_file) {
|
|
ret = -ENODEV;
|
|
goto err;
|
|
@@ -6889,7 +6889,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,
|
|
|
|
remove_hist_vars(hist_data);
|
|
|
|
- kfree(trigger_data);
|
|
+ trigger_data_free(trigger_data);
|
|
|
|
destroy_hist_data(hist_data);
|
|
goto out;
|
|
diff --git a/kernel/trace/trace_hwlat.c b/kernel/trace/trace_hwlat.c
|
|
index 3bd6071441ade9..bc437b6ce8969e 100644
|
|
--- a/kernel/trace/trace_hwlat.c
|
|
+++ b/kernel/trace/trace_hwlat.c
|
|
@@ -102,9 +102,9 @@ struct hwlat_sample {
|
|
/* keep the global state somewhere. */
|
|
static struct hwlat_data {
|
|
|
|
- struct mutex lock; /* protect changes */
|
|
+ struct mutex lock; /* protect changes */
|
|
|
|
- u64 count; /* total since reset */
|
|
+ atomic64_t count; /* total since reset */
|
|
|
|
u64 sample_window; /* total sampling window (on+off) */
|
|
u64 sample_width; /* active sampling portion of window */
|
|
@@ -195,8 +195,7 @@ void trace_hwlat_callback(bool enter)
|
|
* get_sample - sample the CPU TSC and look for likely hardware latencies
|
|
*
|
|
* Used to repeatedly capture the CPU TSC (or similar), looking for potential
|
|
- * hardware-induced latency. Called with interrupts disabled and with
|
|
- * hwlat_data.lock held.
|
|
+ * hardware-induced latency. Called with interrupts disabled.
|
|
*/
|
|
static int get_sample(void)
|
|
{
|
|
@@ -206,6 +205,7 @@ static int get_sample(void)
|
|
time_type start, t1, t2, last_t2;
|
|
s64 diff, outer_diff, total, last_total = 0;
|
|
u64 sample = 0;
|
|
+ u64 sample_width = READ_ONCE(hwlat_data.sample_width);
|
|
u64 thresh = tracing_thresh;
|
|
u64 outer_sample = 0;
|
|
int ret = -1;
|
|
@@ -269,7 +269,7 @@ static int get_sample(void)
|
|
if (diff > sample)
|
|
sample = diff; /* only want highest value */
|
|
|
|
- } while (total <= hwlat_data.sample_width);
|
|
+ } while (total <= sample_width);
|
|
|
|
barrier(); /* finish the above in the view for NMIs */
|
|
trace_hwlat_callback_enabled = false;
|
|
@@ -287,8 +287,7 @@ static int get_sample(void)
|
|
if (kdata->nmi_total_ts)
|
|
do_div(kdata->nmi_total_ts, NSEC_PER_USEC);
|
|
|
|
- hwlat_data.count++;
|
|
- s.seqnum = hwlat_data.count;
|
|
+ s.seqnum = atomic64_inc_return(&hwlat_data.count);
|
|
s.duration = sample;
|
|
s.outer_duration = outer_sample;
|
|
s.nmi_total_ts = kdata->nmi_total_ts;
|
|
@@ -837,7 +836,7 @@ static int hwlat_tracer_init(struct trace_array *tr)
|
|
|
|
hwlat_trace = tr;
|
|
|
|
- hwlat_data.count = 0;
|
|
+ atomic64_set(&hwlat_data.count, 0);
|
|
tr->max_latency = 0;
|
|
save_tracing_thresh = tracing_thresh;
|
|
|
|
diff --git a/kernel/ucount.c b/kernel/ucount.c
|
|
index a7fd89693bd2a1..44ede7a6b805a6 100644
|
|
--- a/kernel/ucount.c
|
|
+++ b/kernel/ucount.c
|
|
@@ -45,7 +45,7 @@ static int set_permissions(struct ctl_table_header *head,
|
|
int mode;
|
|
|
|
/* Allow users with CAP_SYS_RESOURCE unrestrained access */
|
|
- if (ns_capable(user_ns, CAP_SYS_RESOURCE))
|
|
+ if (ns_capable_noaudit(user_ns, CAP_SYS_RESOURCE))
|
|
mode = (table->mode & S_IRWXU) >> 6;
|
|
else
|
|
/* Allow all others at most read-only access */
|
|
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
|
|
index 59b6efb2a11c36..641914d86154d7 100644
|
|
--- a/kernel/workqueue.c
|
|
+++ b/kernel/workqueue.c
|
|
@@ -101,6 +101,8 @@ enum {
|
|
MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */
|
|
CREATE_COOLDOWN = HZ, /* time to breath after fail */
|
|
|
|
+ RESCUER_BATCH = 16, /* process items per turn */
|
|
+
|
|
/*
|
|
* Rescue workers are used only on emergencies and shared by
|
|
* all cpus. Give MIN_NICE.
|
|
@@ -254,6 +256,7 @@ struct pool_workqueue {
|
|
struct list_head inactive_works; /* L: inactive works */
|
|
struct list_head pwqs_node; /* WR: node on wq->pwqs */
|
|
struct list_head mayday_node; /* MD: node on wq->maydays */
|
|
+ struct work_struct mayday_cursor; /* L: cursor on pool->worklist */
|
|
|
|
u64 stats[PWQ_NR_STATS];
|
|
|
|
@@ -1015,6 +1018,12 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool,
|
|
return NULL;
|
|
}
|
|
|
|
+static void mayday_cursor_func(struct work_struct *work)
|
|
+{
|
|
+ /* should not be processed, only for marking position */
|
|
+ BUG();
|
|
+}
|
|
+
|
|
/**
|
|
* move_linked_works - move linked works to a list
|
|
* @work: start of series of works to be scheduled
|
|
@@ -1077,6 +1086,16 @@ static bool assign_work(struct work_struct *work, struct worker *worker,
|
|
|
|
lockdep_assert_held(&pool->lock);
|
|
|
|
+ /* The cursor work should not be processed */
|
|
+ if (unlikely(work->func == mayday_cursor_func)) {
|
|
+ /* only worker_thread() can possibly take this branch */
|
|
+ WARN_ON_ONCE(worker->rescue_wq);
|
|
+ if (nextp)
|
|
+ *nextp = list_next_entry(work, entry);
|
|
+ list_del_init(&work->entry);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
/*
|
|
* A single work shouldn't be executed concurrently by multiple workers.
|
|
* __queue_work() ensures that @work doesn't jump to a different pool
|
|
@@ -2808,6 +2827,35 @@ sleep:
|
|
goto woke_up;
|
|
}
|
|
|
|
+static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescuer)
|
|
+{
|
|
+ struct worker_pool *pool = pwq->pool;
|
|
+ struct work_struct *cursor = &pwq->mayday_cursor;
|
|
+ struct work_struct *work, *n;
|
|
+
|
|
+ /* need rescue? */
|
|
+ if (!pwq->nr_active || !need_to_create_worker(pool))
|
|
+ return false;
|
|
+
|
|
+ /* search from the start or cursor if available */
|
|
+ if (list_empty(&cursor->entry))
|
|
+ work = list_first_entry(&pool->worklist, struct work_struct, entry);
|
|
+ else
|
|
+ work = list_next_entry(cursor, entry);
|
|
+
|
|
+ /* find the next work item to rescue */
|
|
+ list_for_each_entry_safe_from(work, n, &pool->worklist, entry) {
|
|
+ if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) {
|
|
+ pwq->stats[PWQ_STAT_RESCUED]++;
|
|
+ /* put the cursor for next search */
|
|
+ list_move_tail(&cursor->entry, &n->entry);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
/**
|
|
* rescuer_thread - the rescuer thread function
|
|
* @__rescuer: self
|
|
@@ -2862,7 +2910,7 @@ repeat:
|
|
struct pool_workqueue *pwq = list_first_entry(&wq->maydays,
|
|
struct pool_workqueue, mayday_node);
|
|
struct worker_pool *pool = pwq->pool;
|
|
- struct work_struct *work, *n;
|
|
+ unsigned int count = 0;
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
list_del_init(&pwq->mayday_node);
|
|
@@ -2873,30 +2921,18 @@ repeat:
|
|
|
|
raw_spin_lock_irq(&pool->lock);
|
|
|
|
- /*
|
|
- * Slurp in all works issued via this workqueue and
|
|
- * process'em.
|
|
- */
|
|
WARN_ON_ONCE(!list_empty(&rescuer->scheduled));
|
|
- list_for_each_entry_safe(work, n, &pool->worklist, entry) {
|
|
- if (get_work_pwq(work) == pwq &&
|
|
- assign_work(work, rescuer, &n))
|
|
- pwq->stats[PWQ_STAT_RESCUED]++;
|
|
- }
|
|
|
|
- if (!list_empty(&rescuer->scheduled)) {
|
|
+ while (assign_rescuer_work(pwq, rescuer)) {
|
|
process_scheduled_works(rescuer);
|
|
|
|
/*
|
|
- * The above execution of rescued work items could
|
|
- * have created more to rescue through
|
|
- * pwq_activate_first_inactive() or chained
|
|
- * queueing. Let's put @pwq back on mayday list so
|
|
- * that such back-to-back work items, which may be
|
|
- * being used to relieve memory pressure, don't
|
|
- * incur MAYDAY_INTERVAL delay inbetween.
|
|
+ * If the per-turn work item limit is reached and other
|
|
+ * PWQs are in mayday, requeue mayday for this PWQ and
|
|
+ * let the rescuer handle the other PWQs first.
|
|
*/
|
|
- if (pwq->nr_active && need_to_create_worker(pool)) {
|
|
+ if (++count > RESCUER_BATCH && !list_empty(&pwq->wq->maydays) &&
|
|
+ pwq->nr_active && need_to_create_worker(pool)) {
|
|
raw_spin_lock(&wq_mayday_lock);
|
|
/*
|
|
* Queue iff we aren't racing destruction
|
|
@@ -2907,9 +2943,14 @@ repeat:
|
|
list_add_tail(&pwq->mayday_node, &wq->maydays);
|
|
}
|
|
raw_spin_unlock(&wq_mayday_lock);
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
+ /* The cursor can not be left behind without the rescuer watching it. */
|
|
+ if (!list_empty(&pwq->mayday_cursor.entry) && list_empty(&pwq->mayday_node))
|
|
+ list_del_init(&pwq->mayday_cursor.entry);
|
|
+
|
|
/*
|
|
* Put the reference grabbed by send_mayday(). @pool won't
|
|
* go away while we're still attached to it.
|
|
@@ -4222,6 +4263,19 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
|
|
INIT_LIST_HEAD(&pwq->pwqs_node);
|
|
INIT_LIST_HEAD(&pwq->mayday_node);
|
|
kthread_init_work(&pwq->release_work, pwq_release_workfn);
|
|
+
|
|
+ /*
|
|
+ * Set the dummy cursor work with valid function and get_work_pwq().
|
|
+ *
|
|
+ * The cursor work should only be in the pwq->pool->worklist, and
|
|
+ * should not be treated as a processable work item.
|
|
+ *
|
|
+ * WORK_STRUCT_PENDING and WORK_STRUCT_INACTIVE just make it less
|
|
+ * surprise for kernel debugging tools and reviewers.
|
|
+ */
|
|
+ INIT_WORK(&pwq->mayday_cursor, mayday_cursor_func);
|
|
+ atomic_long_set(&pwq->mayday_cursor.data, (unsigned long)pwq |
|
|
+ WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | WORK_STRUCT_INACTIVE);
|
|
}
|
|
|
|
/* sync @pwq with the current state of its associated wq and link it */
|
|
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
|
|
index 1aae81c57b2c9a..e56f9e1b18fdf0 100644
|
|
--- a/lib/Kconfig.debug
|
|
+++ b/lib/Kconfig.debug
|
|
@@ -1619,33 +1619,6 @@ config STACKTRACE
|
|
It is also used by various kernel debugging features that require
|
|
stack trace generation.
|
|
|
|
-config WARN_ALL_UNSEEDED_RANDOM
|
|
- bool "Warn for all uses of unseeded randomness"
|
|
- default n
|
|
- help
|
|
- Some parts of the kernel contain bugs relating to their use of
|
|
- cryptographically secure random numbers before it's actually possible
|
|
- to generate those numbers securely. This setting ensures that these
|
|
- flaws don't go unnoticed, by enabling a message, should this ever
|
|
- occur. This will allow people with obscure setups to know when things
|
|
- are going wrong, so that they might contact developers about fixing
|
|
- it.
|
|
-
|
|
- Unfortunately, on some models of some architectures getting
|
|
- a fully seeded CRNG is extremely difficult, and so this can
|
|
- result in dmesg getting spammed for a surprisingly long
|
|
- time. This is really bad from a security perspective, and
|
|
- so architecture maintainers really need to do what they can
|
|
- to get the CRNG seeded sooner after the system is booted.
|
|
- However, since users cannot do anything actionable to
|
|
- address this, by default this option is disabled.
|
|
-
|
|
- Say Y here if you want to receive warnings for all uses of
|
|
- unseeded randomness. This will be of use primarily for
|
|
- those developers interested in improving the security of
|
|
- Linux kernels running on their architecture (or
|
|
- subarchitecture).
|
|
-
|
|
config DEBUG_KOBJECT
|
|
bool "kobject debugging"
|
|
depends on DEBUG_KERNEL
|
|
diff --git a/mm/highmem.c b/mm/highmem.c
|
|
index e19269093a93cf..87c2fe3d2f3d11 100644
|
|
--- a/mm/highmem.c
|
|
+++ b/mm/highmem.c
|
|
@@ -169,12 +169,13 @@ struct page *__kmap_to_page(void *vaddr)
|
|
for (i = 0; i < kctrl->idx; i++) {
|
|
unsigned long base_addr;
|
|
int idx;
|
|
+ pte_t pteval = kctrl->pteval[i];
|
|
|
|
idx = arch_kmap_local_map_idx(i, pte_pfn(pteval));
|
|
base_addr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
|
|
|
|
if (base_addr == base)
|
|
- return pte_page(kctrl->pteval[i]);
|
|
+ return pte_page(pteval);
|
|
}
|
|
}
|
|
|
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
|
index 6c042f7796e48b..b617fb364b15d1 100644
|
|
--- a/mm/page_alloc.c
|
|
+++ b/mm/page_alloc.c
|
|
@@ -4057,6 +4057,20 @@ restart:
|
|
compact_result == COMPACT_DEFERRED)
|
|
goto nopage;
|
|
|
|
+ /*
|
|
+ * THP page faults may attempt local node only first,
|
|
+ * but are then allowed to only compact, not reclaim,
|
|
+ * see alloc_pages_mpol().
|
|
+ *
|
|
+ * Compaction can fail for other reasons than those
|
|
+ * checked above and we don't want such THP allocations
|
|
+ * to put reclaim pressure on a single node in a
|
|
+ * situation where other nodes might have plenty of
|
|
+ * available memory.
|
|
+ */
|
|
+ if (gfp_mask & __GFP_THISNODE)
|
|
+ goto nopage;
|
|
+
|
|
/*
|
|
* Looks like reclaim/compaction is worth trying, but
|
|
* sync compaction could be very expensive, so keep
|
|
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
|
|
index e70ae2c113f954..358fbe5e4d1d06 100644
|
|
--- a/net/atm/signaling.c
|
|
+++ b/net/atm/signaling.c
|
|
@@ -22,6 +22,36 @@
|
|
|
|
struct atm_vcc *sigd = NULL;
|
|
|
|
+/*
|
|
+ * find_get_vcc - validate and get a reference to a vcc pointer
|
|
+ * @vcc: the vcc pointer to validate
|
|
+ *
|
|
+ * This function validates that @vcc points to a registered VCC in vcc_hash.
|
|
+ * If found, it increments the socket reference count and returns the vcc.
|
|
+ * The caller must call sock_put(sk_atm(vcc)) when done.
|
|
+ *
|
|
+ * Returns the vcc pointer if valid, NULL otherwise.
|
|
+ */
|
|
+static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ read_lock(&vcc_sklist_lock);
|
|
+ for (i = 0; i < VCC_HTABLE_SIZE; i++) {
|
|
+ struct sock *s;
|
|
+
|
|
+ sk_for_each(s, &vcc_hash[i]) {
|
|
+ if (atm_sk(s) == vcc) {
|
|
+ sock_hold(s);
|
|
+ read_unlock(&vcc_sklist_lock);
|
|
+ return vcc;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ read_unlock(&vcc_sklist_lock);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static void sigd_put_skb(struct sk_buff *skb)
|
|
{
|
|
if (!sigd) {
|
|
@@ -69,7 +99,14 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
|
|
msg = (struct atmsvc_msg *) skb->data;
|
|
WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
|
|
- vcc = *(struct atm_vcc **) &msg->vcc;
|
|
+
|
|
+ vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc);
|
|
+ if (!vcc) {
|
|
+ pr_debug("invalid vcc pointer in msg\n");
|
|
+ dev_kfree_skb(skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc);
|
|
sk = sk_atm(vcc);
|
|
|
|
@@ -100,7 +137,16 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
|
break;
|
|
case as_indicate:
|
|
- vcc = *(struct atm_vcc **)&msg->listen_vcc;
|
|
+ /* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */
|
|
+ sock_put(sk);
|
|
+
|
|
+ vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc);
|
|
+ if (!vcc) {
|
|
+ pr_debug("invalid listen_vcc pointer in msg\n");
|
|
+ dev_kfree_skb(skb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
sk = sk_atm(vcc);
|
|
pr_debug("as_indicate!!!\n");
|
|
lock_sock(sk);
|
|
@@ -115,6 +161,8 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
sk->sk_state_change(sk);
|
|
as_indicate_complete:
|
|
release_sock(sk);
|
|
+ /* Paired with find_get_vcc(msg->listen_vcc) above */
|
|
+ sock_put(sk);
|
|
return 0;
|
|
case as_close:
|
|
set_bit(ATM_VF_RELEASED, &vcc->flags);
|
|
@@ -131,11 +179,15 @@ as_indicate_complete:
|
|
break;
|
|
default:
|
|
pr_alert("bad message type %d\n", (int)msg->type);
|
|
+ /* Paired with find_get_vcc(msg->vcc) above */
|
|
+ sock_put(sk);
|
|
return -EINVAL;
|
|
}
|
|
sk->sk_state_change(sk);
|
|
out:
|
|
dev_kfree_skb(skb);
|
|
+ /* Paired with find_get_vcc(msg->vcc) above */
|
|
+ sock_put(sk);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
|
|
index ff9d2520ba749c..30feeaf7e64248 100644
|
|
--- a/net/bluetooth/hci_conn.c
|
|
+++ b/net/bluetooth/hci_conn.c
|
|
@@ -951,6 +951,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
|
switch (type) {
|
|
case ACL_LINK:
|
|
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
|
|
+ conn->link_policy = hdev->link_policy;
|
|
conn->mtu = hdev->acl_mtu;
|
|
break;
|
|
case LE_LINK:
|
|
@@ -2517,8 +2518,8 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
|
|
|
|
timer:
|
|
if (hdev->idle_timeout > 0)
|
|
- queue_delayed_work(hdev->workqueue, &conn->idle_work,
|
|
- msecs_to_jiffies(hdev->idle_timeout));
|
|
+ mod_delayed_work(hdev->workqueue, &conn->idle_work,
|
|
+ msecs_to_jiffies(hdev->idle_timeout));
|
|
}
|
|
|
|
/* Drop all connection on the device */
|
|
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
|
|
index f0eb52d5c05811..6a14f760710774 100644
|
|
--- a/net/bluetooth/hci_sync.c
|
|
+++ b/net/bluetooth/hci_sync.c
|
|
@@ -6860,8 +6860,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
|
|
|
|
conn->attempt++;
|
|
|
|
- conn->link_policy = hdev->link_policy;
|
|
-
|
|
memset(&cp, 0, sizeof(cp));
|
|
bacpy(&cp.bdaddr, &conn->dst);
|
|
cp.pscan_rep_mode = 0x02;
|
|
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
|
|
index ad46112cb596bf..0cbd6c29212385 100644
|
|
--- a/net/bluetooth/l2cap_core.c
|
|
+++ b/net/bluetooth/l2cap_core.c
|
|
@@ -4863,6 +4863,13 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|
goto response_unlock;
|
|
}
|
|
|
|
+ /* Check if Key Size is sufficient for the security level */
|
|
+ if (!l2cap_check_enc_key_size(conn->hcon, pchan)) {
|
|
+ result = L2CAP_CR_LE_BAD_KEY_SIZE;
|
|
+ chan = NULL;
|
|
+ goto response_unlock;
|
|
+ }
|
|
+
|
|
/* Check for valid dynamic CID range */
|
|
if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
|
|
result = L2CAP_CR_LE_INVALID_SCID;
|
|
@@ -5059,7 +5066,16 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|
|
|
if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
|
|
SMP_ALLOW_STK)) {
|
|
- result = L2CAP_CR_LE_AUTHENTICATION;
|
|
+ result = pchan->sec_level == BT_SECURITY_MEDIUM ?
|
|
+ L2CAP_CR_LE_ENCRYPTION : L2CAP_CR_LE_AUTHENTICATION;
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ /* Check if the listening channel has set an output MTU then the
|
|
+ * requested MTU shall be less than or equal to that value.
|
|
+ */
|
|
+ if (pchan->omtu && mtu < pchan->omtu) {
|
|
+ result = L2CAP_CR_LE_UNACCEPT_PARAMS;
|
|
goto unlock;
|
|
}
|
|
|
|
@@ -5260,14 +5276,14 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
|
|
struct l2cap_ecred_reconf_req *req = (void *) data;
|
|
struct l2cap_ecred_reconf_rsp rsp;
|
|
u16 mtu, mps, result;
|
|
- struct l2cap_chan *chan;
|
|
+ struct l2cap_chan *chan[L2CAP_ECRED_MAX_CID] = {};
|
|
int i, num_scid;
|
|
|
|
if (!enable_ecred)
|
|
return -EINVAL;
|
|
|
|
- if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) {
|
|
- result = L2CAP_CR_LE_INVALID_PARAMS;
|
|
+ if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
|
|
+ result = L2CAP_RECONF_INVALID_CID;
|
|
goto respond;
|
|
}
|
|
|
|
@@ -5277,42 +5293,69 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
|
|
BT_DBG("mtu %u mps %u", mtu, mps);
|
|
|
|
if (mtu < L2CAP_ECRED_MIN_MTU) {
|
|
- result = L2CAP_RECONF_INVALID_MTU;
|
|
+ result = L2CAP_RECONF_INVALID_PARAMS;
|
|
goto respond;
|
|
}
|
|
|
|
if (mps < L2CAP_ECRED_MIN_MPS) {
|
|
- result = L2CAP_RECONF_INVALID_MPS;
|
|
+ result = L2CAP_RECONF_INVALID_PARAMS;
|
|
goto respond;
|
|
}
|
|
|
|
cmd_len -= sizeof(*req);
|
|
num_scid = cmd_len / sizeof(u16);
|
|
+
|
|
+ if (num_scid > L2CAP_ECRED_MAX_CID) {
|
|
+ result = L2CAP_RECONF_INVALID_PARAMS;
|
|
+ goto respond;
|
|
+ }
|
|
+
|
|
result = L2CAP_RECONF_SUCCESS;
|
|
|
|
+ /* Check if each SCID, MTU and MPS are valid */
|
|
for (i = 0; i < num_scid; i++) {
|
|
u16 scid;
|
|
|
|
scid = __le16_to_cpu(req->scid[i]);
|
|
- if (!scid)
|
|
- return -EPROTO;
|
|
+ if (!scid) {
|
|
+ result = L2CAP_RECONF_INVALID_CID;
|
|
+ goto respond;
|
|
+ }
|
|
|
|
- chan = __l2cap_get_chan_by_dcid(conn, scid);
|
|
- if (!chan)
|
|
- continue;
|
|
+ chan[i] = __l2cap_get_chan_by_dcid(conn, scid);
|
|
+ if (!chan[i]) {
|
|
+ result = L2CAP_RECONF_INVALID_CID;
|
|
+ goto respond;
|
|
+ }
|
|
|
|
- /* If the MTU value is decreased for any of the included
|
|
- * channels, then the receiver shall disconnect all
|
|
- * included channels.
|
|
+ /* The MTU field shall be greater than or equal to the greatest
|
|
+ * current MTU size of these channels.
|
|
*/
|
|
- if (chan->omtu > mtu) {
|
|
- BT_ERR("chan %p decreased MTU %u -> %u", chan,
|
|
- chan->omtu, mtu);
|
|
+ if (chan[i]->omtu > mtu) {
|
|
+ BT_ERR("chan %p decreased MTU %u -> %u", chan[i],
|
|
+ chan[i]->omtu, mtu);
|
|
result = L2CAP_RECONF_INVALID_MTU;
|
|
+ goto respond;
|
|
}
|
|
|
|
- chan->omtu = mtu;
|
|
- chan->remote_mps = mps;
|
|
+ /* If more than one channel is being configured, the MPS field
|
|
+ * shall be greater than or equal to the current MPS size of
|
|
+ * each of these channels. If only one channel is being
|
|
+ * configured, the MPS field may be less than the current MPS
|
|
+ * of that channel.
|
|
+ */
|
|
+ if (chan[i]->remote_mps >= mps && i) {
|
|
+ BT_ERR("chan %p decreased MPS %u -> %u", chan[i],
|
|
+ chan[i]->remote_mps, mps);
|
|
+ result = L2CAP_RECONF_INVALID_MPS;
|
|
+ goto respond;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Commit the new MTU and MPS values after checking they are valid */
|
|
+ for (i = 0; i < num_scid; i++) {
|
|
+ chan[i]->omtu = mtu;
|
|
+ chan[i]->remote_mps = mps;
|
|
}
|
|
|
|
respond:
|
|
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
|
|
index 59630dbeda20d6..250cc0bc552e01 100644
|
|
--- a/net/bluetooth/l2cap_sock.c
|
|
+++ b/net/bluetooth/l2cap_sock.c
|
|
@@ -1027,10 +1027,17 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
|
break;
|
|
}
|
|
|
|
- /* Setting is not supported as it's the remote side that
|
|
- * decides this.
|
|
- */
|
|
- err = -EPERM;
|
|
+ /* Only allow setting output MTU when not connected */
|
|
+ if (sk->sk_state == BT_CONNECTED) {
|
|
+ err = -EISCONN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
|
|
+ if (err)
|
|
+ break;
|
|
+
|
|
+ chan->omtu = mtu;
|
|
break;
|
|
|
|
case BT_RCVMTU:
|
|
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
|
|
index 4a2d94e8717e6f..4e75ec75c70210 100644
|
|
--- a/net/bridge/br_multicast.c
|
|
+++ b/net/bridge/br_multicast.c
|
|
@@ -243,14 +243,11 @@ br_multicast_port_vid_to_port_ctx(struct net_bridge_port *port, u16 vid)
|
|
|
|
lockdep_assert_held_once(&port->br->multicast_lock);
|
|
|
|
- if (!br_opt_get(port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
|
|
- return NULL;
|
|
-
|
|
/* Take RCU to access the vlan. */
|
|
rcu_read_lock();
|
|
|
|
vlan = br_vlan_find(nbp_vlan_group_rcu(port), vid);
|
|
- if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx))
|
|
+ if (vlan)
|
|
pmctx = &vlan->port_mcast_ctx;
|
|
|
|
rcu_read_unlock();
|
|
@@ -700,7 +697,10 @@ br_multicast_port_ngroups_inc_one(struct net_bridge_mcast_port *pmctx,
|
|
u32 max = READ_ONCE(pmctx->mdb_max_entries);
|
|
u32 n = READ_ONCE(pmctx->mdb_n_entries);
|
|
|
|
- if (max && n >= max) {
|
|
+ /* enforce the max limit when it's a port pmctx or a port-vlan pmctx
|
|
+ * with snooping enabled
|
|
+ */
|
|
+ if (!br_multicast_port_ctx_vlan_disabled(pmctx) && max && n >= max) {
|
|
NL_SET_ERR_MSG_FMT_MOD(extack, "%s is already in %u groups, and mcast_max_groups=%u",
|
|
what, n, max);
|
|
return -E2BIG;
|
|
@@ -735,9 +735,7 @@ static int br_multicast_port_ngroups_inc(struct net_bridge_port *port,
|
|
return err;
|
|
}
|
|
|
|
- /* Only count on the VLAN context if VID is given, and if snooping on
|
|
- * that VLAN is enabled.
|
|
- */
|
|
+ /* Only count on the VLAN context if VID is given */
|
|
if (!group->vid)
|
|
return 0;
|
|
|
|
@@ -2009,6 +2007,18 @@ void br_multicast_port_ctx_init(struct net_bridge_port *port,
|
|
timer_setup(&pmctx->ip6_own_query.timer,
|
|
br_ip6_multicast_port_query_expired, 0);
|
|
#endif
|
|
+ /* initialize mdb_n_entries if a new port vlan is being created */
|
|
+ if (vlan) {
|
|
+ struct net_bridge_port_group *pg;
|
|
+ u32 n = 0;
|
|
+
|
|
+ spin_lock_bh(&port->br->multicast_lock);
|
|
+ hlist_for_each_entry(pg, &port->mglist, mglist)
|
|
+ if (pg->key.addr.vid == vlan->vid)
|
|
+ n++;
|
|
+ WRITE_ONCE(pmctx->mdb_n_entries, n);
|
|
+ spin_unlock_bh(&port->br->multicast_lock);
|
|
+ }
|
|
}
|
|
|
|
void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pmctx)
|
|
@@ -2092,25 +2102,6 @@ static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
|
|
br_ip4_multicast_add_router(brmctx, pmctx);
|
|
br_ip6_multicast_add_router(brmctx, pmctx);
|
|
}
|
|
-
|
|
- if (br_multicast_port_ctx_is_vlan(pmctx)) {
|
|
- struct net_bridge_port_group *pg;
|
|
- u32 n = 0;
|
|
-
|
|
- /* The mcast_n_groups counter might be wrong. First,
|
|
- * BR_VLFLAG_MCAST_ENABLED is toggled before temporary entries
|
|
- * are flushed, thus mcast_n_groups after the toggle does not
|
|
- * reflect the true values. And second, permanent entries added
|
|
- * while BR_VLFLAG_MCAST_ENABLED was disabled, are not reflected
|
|
- * either. Thus we have to refresh the counter.
|
|
- */
|
|
-
|
|
- hlist_for_each_entry(pg, &pmctx->port->mglist, mglist) {
|
|
- if (pg->key.addr.vid == pmctx->vlan->vid)
|
|
- n++;
|
|
- }
|
|
- WRITE_ONCE(pmctx->mdb_n_entries, n);
|
|
- }
|
|
}
|
|
|
|
static void br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
|
|
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
|
|
index 051d22c0e4ad4b..3397d105f74f95 100644
|
|
--- a/net/ceph/crypto.c
|
|
+++ b/net/ceph/crypto.c
|
|
@@ -37,9 +37,6 @@ static int set_secret(struct ceph_crypto_key *key, void *buf)
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
- if (!key->len)
|
|
- return -EINVAL;
|
|
-
|
|
key->key = kmemdup(buf, key->len, GFP_NOIO);
|
|
if (!key->key) {
|
|
ret = -ENOMEM;
|
|
@@ -95,6 +92,11 @@ int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
|
|
ceph_decode_copy(p, &key->created, sizeof(key->created));
|
|
key->len = ceph_decode_16(p);
|
|
ceph_decode_need(p, end, key->len, bad);
|
|
+ if (key->len > CEPH_MAX_KEY_LEN) {
|
|
+ pr_err("secret too big %d\n", key->len);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
ret = set_secret(key, *p);
|
|
memzero_explicit(*p, key->len);
|
|
*p += key->len;
|
|
diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
|
|
index 13bd526349fa1b..0d32f1649f3d08 100644
|
|
--- a/net/ceph/crypto.h
|
|
+++ b/net/ceph/crypto.h
|
|
@@ -5,7 +5,7 @@
|
|
#include <linux/ceph/types.h>
|
|
#include <linux/ceph/buffer.h>
|
|
|
|
-#define CEPH_KEY_LEN 16
|
|
+#define CEPH_MAX_KEY_LEN 16
|
|
#define CEPH_MAX_CON_SECRET_LEN 64
|
|
|
|
/*
|
|
diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c
|
|
index 85819872443966..f82029bd33db8b 100644
|
|
--- a/net/ceph/messenger_v2.c
|
|
+++ b/net/ceph/messenger_v2.c
|
|
@@ -2393,7 +2393,7 @@ bad:
|
|
*/
|
|
static int process_auth_done(struct ceph_connection *con, void *p, void *end)
|
|
{
|
|
- u8 session_key_buf[CEPH_KEY_LEN + 16];
|
|
+ u8 session_key_buf[CEPH_MAX_KEY_LEN + 16];
|
|
u8 con_secret_buf[CEPH_MAX_CON_SECRET_LEN + 16];
|
|
u8 *session_key = PTR_ALIGN(&session_key_buf[0], 16);
|
|
u8 *con_secret = PTR_ALIGN(&con_secret_buf[0], 16);
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 206194bb8fcadd..56b6797589f561 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -701,7 +701,7 @@ static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
|
|
{
|
|
int k = stack->num_paths++;
|
|
|
|
- if (WARN_ON_ONCE(k >= NET_DEVICE_PATH_STACK_MAX))
|
|
+ if (k >= NET_DEVICE_PATH_STACK_MAX)
|
|
return NULL;
|
|
|
|
return &stack->path[k];
|
|
@@ -4424,6 +4424,8 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
|
|
* to -1 or to their cpu id, but not to our id.
|
|
*/
|
|
if (READ_ONCE(txq->xmit_lock_owner) != cpu) {
|
|
+ bool is_list = false;
|
|
+
|
|
if (dev_xmit_recursion())
|
|
goto recursion_alert;
|
|
|
|
@@ -4434,17 +4436,28 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
|
|
HARD_TX_LOCK(dev, txq, cpu);
|
|
|
|
if (!netif_xmit_stopped(txq)) {
|
|
+ is_list = !!skb->next;
|
|
+
|
|
dev_xmit_recursion_inc();
|
|
skb = dev_hard_start_xmit(skb, dev, txq, &rc);
|
|
dev_xmit_recursion_dec();
|
|
- if (dev_xmit_complete(rc)) {
|
|
- HARD_TX_UNLOCK(dev, txq);
|
|
- goto out;
|
|
- }
|
|
+
|
|
+ /* GSO segments a single SKB into
|
|
+ * a list of frames. TCP expects error
|
|
+ * to mean none of the data was sent.
|
|
+ */
|
|
+ if (is_list)
|
|
+ rc = NETDEV_TX_OK;
|
|
}
|
|
HARD_TX_UNLOCK(dev, txq);
|
|
+ if (!skb) /* xmit completed */
|
|
+ goto out;
|
|
+
|
|
net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
|
|
dev->name);
|
|
+ /* NETDEV_TX_BUSY or queue was stopped */
|
|
+ if (!is_list)
|
|
+ rc = -ENETDOWN;
|
|
} else {
|
|
/* Recursion is detected! It is possible,
|
|
* unfortunately
|
|
@@ -4452,10 +4465,10 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
|
|
recursion_alert:
|
|
net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
|
|
dev->name);
|
|
+ rc = -ENETDOWN;
|
|
}
|
|
}
|
|
|
|
- rc = -ENETDOWN;
|
|
rcu_read_unlock_bh();
|
|
|
|
dev_core_stats_tx_dropped_inc(dev);
|
|
diff --git a/net/core/filter.c b/net/core/filter.c
|
|
index ddb6d3dd34deb7..e5dc1f699297b0 100644
|
|
--- a/net/core/filter.c
|
|
+++ b/net/core/filter.c
|
|
@@ -4118,7 +4118,7 @@ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {
|
|
.ret_type = RET_INTEGER,
|
|
.arg1_type = ARG_PTR_TO_CTX,
|
|
.arg2_type = ARG_ANYTHING,
|
|
- .arg3_type = ARG_PTR_TO_UNINIT_MEM,
|
|
+ .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
|
.arg4_type = ARG_CONST_SIZE,
|
|
};
|
|
|
|
diff --git a/net/core/gro.c b/net/core/gro.c
|
|
index 87889cb75d2194..92cb86d4ce50ac 100644
|
|
--- a/net/core/gro.c
|
|
+++ b/net/core/gro.c
|
|
@@ -386,7 +386,7 @@ static void gro_pull_from_frag0(struct sk_buff *skb, int grow)
|
|
{
|
|
struct skb_shared_info *pinfo = skb_shinfo(skb);
|
|
|
|
- BUG_ON(skb->end - skb->tail < grow);
|
|
+ DEBUG_NET_WARN_ON_ONCE(skb->end - skb->tail < grow);
|
|
|
|
memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow);
|
|
|
|
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
|
|
index 20829e0c36cdbf..b99fdca441f318 100644
|
|
--- a/net/core/net_namespace.c
|
|
+++ b/net/core/net_namespace.c
|
|
@@ -1144,11 +1144,56 @@ out:
|
|
rtnl_set_sk_err(net, RTNLGRP_NSID, err);
|
|
}
|
|
|
|
+#ifdef CONFIG_NET_NS
|
|
+static void __init netns_ipv4_struct_check(void)
|
|
+{
|
|
+ /* TX readonly hotpath cache lines */
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_early_retrans);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_tso_win_divisor);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_tso_rtt_log);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_autocorking);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_min_snd_mss);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_notsent_lowat);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_limit_output_bytes);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_min_rtt_wlen);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_tcp_wmem);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx,
|
|
+ sysctl_ip_fwd_use_pmtu);
|
|
+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_tx, 33);
|
|
+
|
|
+ /* TXRX readonly hotpath cache lines */
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_txrx,
|
|
+ sysctl_tcp_moderate_rcvbuf);
|
|
+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_txrx, 1);
|
|
+
|
|
+ /* RX readonly hotpath cache line */
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx,
|
|
+ sysctl_ip_early_demux);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx,
|
|
+ sysctl_tcp_early_demux);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx,
|
|
+ sysctl_tcp_reordering);
|
|
+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx,
|
|
+ sysctl_tcp_rmem);
|
|
+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_rx, 18);
|
|
+}
|
|
+#endif
|
|
+
|
|
void __init net_ns_init(void)
|
|
{
|
|
struct net_generic *ng;
|
|
|
|
#ifdef CONFIG_NET_NS
|
|
+ netns_ipv4_struct_check();
|
|
net_cachep = kmem_cache_create("net_namespace", sizeof(struct net),
|
|
SMP_CACHE_BYTES,
|
|
SLAB_PANIC|SLAB_ACCOUNT, NULL);
|
|
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
|
|
index 6225547808a6ba..5d557ba9c0cb47 100644
|
|
--- a/net/core/skmsg.c
|
|
+++ b/net/core/skmsg.c
|
|
@@ -408,22 +408,26 @@ out:
|
|
}
|
|
EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter);
|
|
|
|
-/* Receive sk_msg from psock->ingress_msg to @msg. */
|
|
-int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
- int len, int flags)
|
|
+int __sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
+ int len, int flags, int *copied_from_self)
|
|
{
|
|
struct iov_iter *iter = &msg->msg_iter;
|
|
int peek = flags & MSG_PEEK;
|
|
struct sk_msg *msg_rx;
|
|
int i, copied = 0;
|
|
+ bool from_self;
|
|
|
|
msg_rx = sk_psock_peek_msg(psock);
|
|
+ if (copied_from_self)
|
|
+ *copied_from_self = 0;
|
|
+
|
|
while (copied != len) {
|
|
struct scatterlist *sge;
|
|
|
|
if (unlikely(!msg_rx))
|
|
break;
|
|
|
|
+ from_self = msg_rx->sk == sk;
|
|
i = msg_rx->sg.start;
|
|
do {
|
|
struct page *page;
|
|
@@ -442,6 +446,9 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
}
|
|
|
|
copied += copy;
|
|
+ if (from_self && copied_from_self)
|
|
+ *copied_from_self += copy;
|
|
+
|
|
if (likely(!peek)) {
|
|
sge->offset += copy;
|
|
sge->length -= copy;
|
|
@@ -450,6 +457,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
atomic_sub(copy, &sk->sk_rmem_alloc);
|
|
}
|
|
msg_rx->sg.size -= copy;
|
|
+ sk_psock_msg_len_add(psock, -copy);
|
|
|
|
if (!sge->length) {
|
|
sk_msg_iter_var_next(i);
|
|
@@ -486,6 +494,13 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
out:
|
|
return copied;
|
|
}
|
|
+
|
|
+/* Receive sk_msg from psock->ingress_msg to @msg. */
|
|
+int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
|
+ int len, int flags)
|
|
+{
|
|
+ return __sk_msg_recvmsg(sk, psock, msg, len, flags, NULL);
|
|
+}
|
|
EXPORT_SYMBOL_GPL(sk_msg_recvmsg);
|
|
|
|
bool sk_msg_is_readable(struct sock *sk)
|
|
@@ -615,6 +630,12 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb
|
|
if (unlikely(!msg))
|
|
return -EAGAIN;
|
|
skb_set_owner_r(skb, sk);
|
|
+
|
|
+ /* This is used in tcp_bpf_recvmsg_parser() to determine whether the
|
|
+ * data originates from the socket's own protocol stack. No need to
|
|
+ * refcount sk because msg's lifetime is bound to sk via the ingress_msg.
|
|
+ */
|
|
+ msg->sk = sk;
|
|
err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref);
|
|
if (err < 0)
|
|
kfree(msg);
|
|
@@ -800,9 +821,11 @@ static void __sk_psock_purge_ingress_msg(struct sk_psock *psock)
|
|
list_del(&msg->list);
|
|
if (!msg->skb)
|
|
atomic_sub(msg->sg.size, &psock->sk->sk_rmem_alloc);
|
|
+ sk_psock_msg_len_add(psock, -msg->sg.size);
|
|
sk_msg_free(psock->sk, msg);
|
|
kfree(msg);
|
|
}
|
|
+ WARN_ON_ONCE(psock->msg_tot_len);
|
|
}
|
|
|
|
static void __sk_psock_zap_ingress(struct sk_psock *psock)
|
|
@@ -908,6 +931,7 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock,
|
|
sk_msg_compute_data_pointers(msg);
|
|
msg->sk = sk;
|
|
ret = bpf_prog_run_pin_on_cpu(prog, msg);
|
|
+ msg->sk = NULL;
|
|
ret = sk_psock_map_verd(ret, msg->sk_redir);
|
|
psock->apply_bytes = msg->apply_bytes;
|
|
if (ret == __SK_REDIRECT) {
|
|
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
|
|
index f9b9e26c32c193..0b72796dd1ad38 100644
|
|
--- a/net/ipv4/fib_lookup.h
|
|
+++ b/net/ipv4/fib_lookup.h
|
|
@@ -28,8 +28,10 @@ struct fib_alias {
|
|
/* Don't write on fa_state unless needed, to keep it shared on all cpus */
|
|
static inline void fib_alias_accessed(struct fib_alias *fa)
|
|
{
|
|
- if (!(fa->fa_state & FA_S_ACCESSED))
|
|
- fa->fa_state |= FA_S_ACCESSED;
|
|
+ u8 fa_state = READ_ONCE(fa->fa_state);
|
|
+
|
|
+ if (!(fa_state & FA_S_ACCESSED))
|
|
+ WRITE_ONCE(fa->fa_state, fa_state | FA_S_ACCESSED);
|
|
}
|
|
|
|
/* Exported by fib_semantics.c */
|
|
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
|
|
index 4d148d0892327f..c9e1526e749b2b 100644
|
|
--- a/net/ipv4/fib_trie.c
|
|
+++ b/net/ipv4/fib_trie.c
|
|
@@ -1285,7 +1285,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
|
|
new_fa->fa_dscp = fa->fa_dscp;
|
|
new_fa->fa_info = fi;
|
|
new_fa->fa_type = cfg->fc_type;
|
|
- state = fa->fa_state;
|
|
+ state = READ_ONCE(fa->fa_state);
|
|
new_fa->fa_state = state & ~FA_S_ACCESSED;
|
|
new_fa->fa_slen = fa->fa_slen;
|
|
new_fa->tb_id = tb->tb_id;
|
|
@@ -1751,7 +1751,7 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
|
|
|
|
fib_remove_alias(t, tp, l, fa_to_delete);
|
|
|
|
- if (fa_to_delete->fa_state & FA_S_ACCESSED)
|
|
+ if (READ_ONCE(fa_to_delete->fa_state) & FA_S_ACCESSED)
|
|
rt_cache_flush(cfg->fc_nlinfo.nl_net);
|
|
|
|
fib_release_info(fa_to_delete->fa_info);
|
|
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
|
|
index b17549c4e5de8a..784591ed5bb7ce 100644
|
|
--- a/net/ipv4/icmp.c
|
|
+++ b/net/ipv4/icmp.c
|
|
@@ -221,22 +221,15 @@ static inline void icmp_xmit_unlock(struct sock *sk)
|
|
spin_unlock(&sk->sk_lock.slock);
|
|
}
|
|
|
|
-int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
|
|
-int sysctl_icmp_msgs_burst __read_mostly = 50;
|
|
-
|
|
-static struct {
|
|
- atomic_t credit;
|
|
- u32 stamp;
|
|
-} icmp_global;
|
|
-
|
|
/**
|
|
* icmp_global_allow - Are we allowed to send one more ICMP message ?
|
|
+ * @net: network namespace
|
|
*
|
|
* Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec.
|
|
* Returns false if we reached the limit and can not send another packet.
|
|
* Works in tandem with icmp_global_consume().
|
|
*/
|
|
-bool icmp_global_allow(void)
|
|
+bool icmp_global_allow(struct net *net)
|
|
{
|
|
u32 delta, now, oldstamp;
|
|
int incr, new, old;
|
|
@@ -245,36 +238,37 @@ bool icmp_global_allow(void)
|
|
* Then later icmp_global_consume() could consume more credits,
|
|
* this is an acceptable race.
|
|
*/
|
|
- if (atomic_read(&icmp_global.credit) > 0)
|
|
+ if (atomic_read(&net->ipv4.icmp_global_credit) > 0)
|
|
return true;
|
|
|
|
now = jiffies;
|
|
- oldstamp = READ_ONCE(icmp_global.stamp);
|
|
+ oldstamp = READ_ONCE(net->ipv4.icmp_global_stamp);
|
|
delta = min_t(u32, now - oldstamp, HZ);
|
|
if (delta < HZ / 50)
|
|
return false;
|
|
|
|
- incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
|
|
+ incr = READ_ONCE(net->ipv4.sysctl_icmp_msgs_per_sec);
|
|
+ incr = div_u64((u64)incr * delta, HZ);
|
|
if (!incr)
|
|
return false;
|
|
|
|
- if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) {
|
|
- old = atomic_read(&icmp_global.credit);
|
|
+ if (cmpxchg(&net->ipv4.icmp_global_stamp, oldstamp, now) == oldstamp) {
|
|
+ old = atomic_read(&net->ipv4.icmp_global_credit);
|
|
do {
|
|
- new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst));
|
|
- } while (!atomic_try_cmpxchg(&icmp_global.credit, &old, new));
|
|
+ new = min(old + incr, READ_ONCE(net->ipv4.sysctl_icmp_msgs_burst));
|
|
+ } while (!atomic_try_cmpxchg(&net->ipv4.icmp_global_credit, &old, new));
|
|
}
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL(icmp_global_allow);
|
|
|
|
-void icmp_global_consume(void)
|
|
+void icmp_global_consume(struct net *net)
|
|
{
|
|
int credits = get_random_u32_below(3);
|
|
|
|
/* Note: this might make icmp_global.credit negative. */
|
|
if (credits)
|
|
- atomic_sub(credits, &icmp_global.credit);
|
|
+ atomic_sub(credits, &net->ipv4.icmp_global_credit);
|
|
}
|
|
EXPORT_SYMBOL(icmp_global_consume);
|
|
|
|
@@ -300,7 +294,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code,
|
|
if (icmpv4_mask_allow(net, type, code))
|
|
return true;
|
|
|
|
- if (icmp_global_allow()) {
|
|
+ if (icmp_global_allow(net)) {
|
|
*apply_ratelimit = true;
|
|
return true;
|
|
}
|
|
@@ -337,7 +331,7 @@ out:
|
|
if (!rc)
|
|
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
|
|
else
|
|
- icmp_global_consume();
|
|
+ icmp_global_consume(net);
|
|
return rc;
|
|
}
|
|
|
|
@@ -546,14 +540,30 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
|
|
goto relookup_failed;
|
|
}
|
|
/* Ugh! */
|
|
- orefdst = skb_in->_skb_refdst; /* save old refdst */
|
|
- skb_dst_set(skb_in, NULL);
|
|
+ orefdst = skb_dstref_steal(skb_in);
|
|
err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr,
|
|
dscp, rt2->dst.dev);
|
|
|
|
dst_release(&rt2->dst);
|
|
rt2 = skb_rtable(skb_in);
|
|
- skb_in->_skb_refdst = orefdst; /* restore old refdst */
|
|
+ /* steal dst entry from skb_in, don't drop refcnt */
|
|
+ skb_dstref_steal(skb_in);
|
|
+ skb_dstref_restore(skb_in, orefdst);
|
|
+
|
|
+ /*
|
|
+ * At this point, fl4_dec.daddr should NOT be local (we
|
|
+ * checked fl4_dec.saddr above). However, a race condition
|
|
+ * may occur if the address is added to the interface
|
|
+ * concurrently. In that case, ip_route_input() returns a
|
|
+ * LOCAL route with dst.output=ip_rt_bug, which must not
|
|
+ * be used for output.
|
|
+ */
|
|
+ if (!err && rt2 && rt2->rt_type == RTN_LOCAL) {
|
|
+ net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n",
|
|
+ &fl4_dec.daddr, &fl4_dec.saddr);
|
|
+ dst_release(&rt2->dst);
|
|
+ err = -EINVAL;
|
|
+ }
|
|
}
|
|
|
|
if (err)
|
|
@@ -840,16 +850,22 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
|
|
/* Checkin full IP header plus 8 bytes of protocol to
|
|
* avoid additional coding at protocol handlers.
|
|
*/
|
|
- if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) {
|
|
- __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
|
|
- return;
|
|
- }
|
|
+ if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
|
|
+ goto out;
|
|
+
|
|
+ /* IPPROTO_RAW sockets are not supposed to receive anything. */
|
|
+ if (protocol == IPPROTO_RAW)
|
|
+ goto out;
|
|
|
|
raw_icmp_error(skb, protocol, info);
|
|
|
|
ipprot = rcu_dereference(inet_protos[protocol]);
|
|
if (ipprot && ipprot->err_handler)
|
|
ipprot->err_handler(skb, info);
|
|
+ return;
|
|
+
|
|
+out:
|
|
+ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
|
|
}
|
|
|
|
static bool icmp_tag_validation(int proto)
|
|
@@ -1498,6 +1514,8 @@ static int __net_init icmp_sk_init(struct net *net)
|
|
net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;
|
|
net->ipv4.sysctl_icmp_ratemask = 0x1818;
|
|
net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0;
|
|
+ net->ipv4.sysctl_icmp_msgs_per_sec = 1000;
|
|
+ net->ipv4.sysctl_icmp_msgs_burst = 50;
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
|
|
index d515881d02a6f7..2836020bf12d5e 100644
|
|
--- a/net/ipv4/igmp.c
|
|
+++ b/net/ipv4/igmp.c
|
|
@@ -224,7 +224,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
|
|
|
|
static void igmp_gq_start_timer(struct in_device *in_dev)
|
|
{
|
|
- int tv = get_random_u32_below(in_dev->mr_maxdelay);
|
|
+ int tv = get_random_u32_below(READ_ONCE(in_dev->mr_maxdelay));
|
|
unsigned long exp = jiffies + tv + 2;
|
|
|
|
if (in_dev->mr_gq_running &&
|
|
@@ -1006,7 +1006,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
|
|
max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
|
|
if (!max_delay)
|
|
max_delay = 1; /* can't mod w/ 0 */
|
|
- in_dev->mr_maxdelay = max_delay;
|
|
+ WRITE_ONCE(in_dev->mr_maxdelay, max_delay);
|
|
|
|
/* RFC3376, 4.1.6. QRV and 4.1.7. QQIC, when the most recently
|
|
* received value was zero, use the default or statically
|
|
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
|
|
index b4c59708fc0956..d898e1523a453e 100644
|
|
--- a/net/ipv4/ip_options.c
|
|
+++ b/net/ipv4/ip_options.c
|
|
@@ -615,14 +615,13 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
|
|
}
|
|
memcpy(&nexthop, &optptr[srrptr-1], 4);
|
|
|
|
- orefdst = skb->_skb_refdst;
|
|
- skb_dst_set(skb, NULL);
|
|
+ orefdst = skb_dstref_steal(skb);
|
|
err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph),
|
|
dev);
|
|
rt2 = skb_rtable(skb);
|
|
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
|
|
skb_dst_drop(skb);
|
|
- skb->_skb_refdst = orefdst;
|
|
+ skb_dstref_restore(skb, orefdst);
|
|
return -EINVAL;
|
|
}
|
|
refdst_drop(orefdst);
|
|
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
|
|
index 47f2e7dd554ad4..fa13cfa2fa00f9 100644
|
|
--- a/net/ipv4/ping.c
|
|
+++ b/net/ipv4/ping.c
|
|
@@ -159,7 +159,7 @@ void ping_unhash(struct sock *sk)
|
|
pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
|
|
spin_lock(&ping_table.lock);
|
|
if (sk_del_node_init_rcu(sk)) {
|
|
- isk->inet_num = 0;
|
|
+ WRITE_ONCE(isk->inet_num, 0);
|
|
isk->inet_sport = 0;
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
|
}
|
|
@@ -192,31 +192,35 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
|
|
}
|
|
|
|
sk_for_each_rcu(sk, hslot) {
|
|
+ int bound_dev_if;
|
|
+
|
|
if (!net_eq(sock_net(sk), net))
|
|
continue;
|
|
isk = inet_sk(sk);
|
|
|
|
pr_debug("iterate\n");
|
|
- if (isk->inet_num != ident)
|
|
+ if (READ_ONCE(isk->inet_num) != ident)
|
|
continue;
|
|
|
|
+ bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
|
|
if (skb->protocol == htons(ETH_P_IP) &&
|
|
sk->sk_family == AF_INET) {
|
|
+ __be32 rcv_saddr = READ_ONCE(isk->inet_rcv_saddr);
|
|
+
|
|
pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk,
|
|
- (int) isk->inet_num, &isk->inet_rcv_saddr,
|
|
- sk->sk_bound_dev_if);
|
|
+ ident, &rcv_saddr,
|
|
+ bound_dev_if);
|
|
|
|
- if (isk->inet_rcv_saddr &&
|
|
- isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
|
|
+ if (rcv_saddr && rcv_saddr != ip_hdr(skb)->daddr)
|
|
continue;
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
} else if (skb->protocol == htons(ETH_P_IPV6) &&
|
|
sk->sk_family == AF_INET6) {
|
|
|
|
pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
|
|
- (int) isk->inet_num,
|
|
+ ident,
|
|
&sk->sk_v6_rcv_saddr,
|
|
- sk->sk_bound_dev_if);
|
|
+ bound_dev_if);
|
|
|
|
if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
|
|
!ipv6_addr_equal(&sk->sk_v6_rcv_saddr,
|
|
@@ -227,8 +231,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
|
|
continue;
|
|
}
|
|
|
|
- if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
|
|
- sk->sk_bound_dev_if != sdif)
|
|
+ if (bound_dev_if && bound_dev_if != dif &&
|
|
+ bound_dev_if != sdif)
|
|
continue;
|
|
|
|
goto exit;
|
|
@@ -403,7 +407,9 @@ static void ping_set_saddr(struct sock *sk, struct sockaddr *saddr)
|
|
if (saddr->sa_family == AF_INET) {
|
|
struct inet_sock *isk = inet_sk(sk);
|
|
struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
|
|
- isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
|
|
+
|
|
+ isk->inet_saddr = addr->sin_addr.s_addr;
|
|
+ WRITE_ONCE(isk->inet_rcv_saddr, addr->sin_addr.s_addr);
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
} else if (saddr->sa_family == AF_INET6) {
|
|
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
|
|
@@ -860,7 +866,8 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
|
|
struct sk_buff *skb;
|
|
int copied, err;
|
|
|
|
- pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num);
|
|
+ pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk,
|
|
+ READ_ONCE(isk->inet_num));
|
|
|
|
err = -EOPNOTSUPP;
|
|
if (flags & MSG_OOB)
|
|
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
|
|
index 6ac890b4073f45..96f1b8d39fac11 100644
|
|
--- a/net/ipv4/sysctl_net_ipv4.c
|
|
+++ b/net/ipv4/sysctl_net_ipv4.c
|
|
@@ -547,22 +547,6 @@ static struct ctl_table ipv4_table[] = {
|
|
.mode = 0444,
|
|
.proc_handler = proc_tcp_available_ulp,
|
|
},
|
|
- {
|
|
- .procname = "icmp_msgs_per_sec",
|
|
- .data = &sysctl_icmp_msgs_per_sec,
|
|
- .maxlen = sizeof(int),
|
|
- .mode = 0644,
|
|
- .proc_handler = proc_dointvec_minmax,
|
|
- .extra1 = SYSCTL_ZERO,
|
|
- },
|
|
- {
|
|
- .procname = "icmp_msgs_burst",
|
|
- .data = &sysctl_icmp_msgs_burst,
|
|
- .maxlen = sizeof(int),
|
|
- .mode = 0644,
|
|
- .proc_handler = proc_dointvec_minmax,
|
|
- .extra1 = SYSCTL_ZERO,
|
|
- },
|
|
{
|
|
.procname = "udp_mem",
|
|
.data = &sysctl_udp_mem,
|
|
@@ -649,6 +633,22 @@ static struct ctl_table ipv4_net_table[] = {
|
|
.mode = 0644,
|
|
.proc_handler = proc_dointvec
|
|
},
|
|
+ {
|
|
+ .procname = "icmp_msgs_per_sec",
|
|
+ .data = &init_net.ipv4.sysctl_icmp_msgs_per_sec,
|
|
+ .maxlen = sizeof(int),
|
|
+ .mode = 0644,
|
|
+ .proc_handler = proc_dointvec_minmax,
|
|
+ .extra1 = SYSCTL_ZERO,
|
|
+ },
|
|
+ {
|
|
+ .procname = "icmp_msgs_burst",
|
|
+ .data = &init_net.ipv4.sysctl_icmp_msgs_burst,
|
|
+ .maxlen = sizeof(int),
|
|
+ .mode = 0644,
|
|
+ .proc_handler = proc_dointvec_minmax,
|
|
+ .extra1 = SYSCTL_ZERO,
|
|
+ },
|
|
{
|
|
.procname = "ping_group_range",
|
|
.data = &init_net.ipv4.ping_group_range.range,
|
|
@@ -1366,6 +1366,15 @@ static struct ctl_table ipv4_net_table[] = {
|
|
.proc_handler = proc_dou8vec_minmax,
|
|
.extra1 = SYSCTL_ZERO,
|
|
},
|
|
+ {
|
|
+ .procname = "tcp_backlog_ack_defer",
|
|
+ .data = &init_net.ipv4.sysctl_tcp_backlog_ack_defer,
|
|
+ .maxlen = sizeof(u8),
|
|
+ .mode = 0644,
|
|
+ .proc_handler = proc_dou8vec_minmax,
|
|
+ .extra1 = SYSCTL_ZERO,
|
|
+ .extra2 = SYSCTL_ONE,
|
|
+ },
|
|
{
|
|
.procname = "tcp_reflect_tos",
|
|
.data = &init_net.ipv4.sysctl_tcp_reflect_tos,
|
|
@@ -1489,6 +1498,14 @@ static struct ctl_table ipv4_net_table[] = {
|
|
.extra1 = SYSCTL_ZERO,
|
|
.extra2 = SYSCTL_ONE,
|
|
},
|
|
+ {
|
|
+ .procname = "tcp_pingpong_thresh",
|
|
+ .data = &init_net.ipv4.sysctl_tcp_pingpong_thresh,
|
|
+ .maxlen = sizeof(u8),
|
|
+ .mode = 0644,
|
|
+ .proc_handler = proc_dou8vec_minmax,
|
|
+ .extra1 = SYSCTL_ONE,
|
|
+ },
|
|
{ }
|
|
};
|
|
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 5dde0aed314405..2bae34d63c3db7 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -468,6 +468,9 @@ static void tcp_tx_timestamp(struct sock *sk, u16 tsflags)
|
|
{
|
|
struct sk_buff *skb = tcp_write_queue_tail(sk);
|
|
|
|
+ if (unlikely(!skb))
|
|
+ skb = skb_rb_last(&sk->tcp_rtx_queue);
|
|
+
|
|
if (tsflags && skb) {
|
|
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
|
struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
|
|
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
|
|
index 7518d2af630880..06a185bb1e35cf 100644
|
|
--- a/net/ipv4/tcp_bpf.c
|
|
+++ b/net/ipv4/tcp_bpf.c
|
|
@@ -10,6 +10,7 @@
|
|
|
|
#include <net/inet_common.h>
|
|
#include <net/tls.h>
|
|
+#include <asm/ioctls.h>
|
|
|
|
void tcp_eat_skb(struct sock *sk, struct sk_buff *skb)
|
|
{
|
|
@@ -226,6 +227,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
|
|
int peek = flags & MSG_PEEK;
|
|
struct sk_psock *psock;
|
|
struct tcp_sock *tcp;
|
|
+ int copied_from_self = 0;
|
|
int copied = 0;
|
|
u32 seq;
|
|
|
|
@@ -262,7 +264,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
|
|
}
|
|
|
|
msg_bytes_ready:
|
|
- copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
|
|
+ copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self);
|
|
/* The typical case for EFAULT is the socket was gracefully
|
|
* shutdown with a FIN pkt. So check here the other case is
|
|
* some error on copy_page_to_iter which would be unexpected.
|
|
@@ -277,7 +279,7 @@ msg_bytes_ready:
|
|
goto out;
|
|
}
|
|
}
|
|
- seq += copied;
|
|
+ seq += copied_from_self;
|
|
if (!copied) {
|
|
long timeo;
|
|
int data;
|
|
@@ -331,6 +333,24 @@ unlock:
|
|
return copied;
|
|
}
|
|
|
|
+static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
|
|
+{
|
|
+ bool slow;
|
|
+
|
|
+ if (cmd != SIOCINQ)
|
|
+ return tcp_ioctl(sk, cmd, karg);
|
|
+
|
|
+ /* works similar as tcp_ioctl */
|
|
+ if (sk->sk_state == TCP_LISTEN)
|
|
+ return -EINVAL;
|
|
+
|
|
+ slow = lock_sock_fast(sk);
|
|
+ *karg = sk_psock_msg_inq(sk);
|
|
+ unlock_sock_fast(sk, slow);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|
int flags, int *addr_len)
|
|
{
|
|
@@ -609,6 +629,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS],
|
|
prot[TCP_BPF_BASE].close = sock_map_close;
|
|
prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg;
|
|
prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable;
|
|
+ prot[TCP_BPF_BASE].ioctl = tcp_bpf_ioctl;
|
|
|
|
prot[TCP_BPF_TX] = prot[TCP_BPF_BASE];
|
|
prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg;
|
|
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
|
index 8834cd41b38408..f67967c7577146 100644
|
|
--- a/net/ipv4/tcp_input.c
|
|
+++ b/net/ipv4/tcp_input.c
|
|
@@ -5678,6 +5678,14 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
|
|
tcp_in_quickack_mode(sk) ||
|
|
/* Protocol state mandates a one-time immediate ACK */
|
|
inet_csk(sk)->icsk_ack.pending & ICSK_ACK_NOW) {
|
|
+ /* If we are running from __release_sock() in user context,
|
|
+ * Defer the ack until tcp_release_cb().
|
|
+ */
|
|
+ if (sock_owned_by_user_nocheck(sk) &&
|
|
+ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_backlog_ack_defer)) {
|
|
+ set_bit(TCP_ACK_DEFERRED, &sk->sk_tsq_flags);
|
|
+ return;
|
|
+ }
|
|
send_now:
|
|
tcp_send_ack(sk);
|
|
return;
|
|
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
|
|
index 2f49a504c9d3e3..ab4be34e58bb23 100644
|
|
--- a/net/ipv4/tcp_ipv4.c
|
|
+++ b/net/ipv4/tcp_ipv4.c
|
|
@@ -3279,6 +3279,7 @@ static int __net_init tcp_sk_init(struct net *net)
|
|
net->ipv4.sysctl_tcp_comp_sack_delay_ns = NSEC_PER_MSEC;
|
|
net->ipv4.sysctl_tcp_comp_sack_slack_ns = 100 * NSEC_PER_USEC;
|
|
net->ipv4.sysctl_tcp_comp_sack_nr = 44;
|
|
+ net->ipv4.sysctl_tcp_backlog_ack_defer = 1;
|
|
net->ipv4.sysctl_tcp_fastopen = TFO_CLIENT_ENABLE;
|
|
net->ipv4.sysctl_tcp_fastopen_blackhole_timeout = 0;
|
|
atomic_set(&net->ipv4.tfo_active_disable_times, 0);
|
|
@@ -3302,6 +3303,8 @@ static int __net_init tcp_sk_init(struct net *net)
|
|
net->ipv4.sysctl_tcp_syn_linear_timeouts = 4;
|
|
net->ipv4.sysctl_tcp_shrink_window = 0;
|
|
|
|
+ net->ipv4.sysctl_tcp_pingpong_thresh = 1;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
|
|
index 88551db62ca29d..db8f2830c67bf2 100644
|
|
--- a/net/ipv4/tcp_output.c
|
|
+++ b/net/ipv4/tcp_output.c
|
|
@@ -170,10 +170,10 @@ static void tcp_event_data_sent(struct tcp_sock *tp,
|
|
tp->lsndtime = now;
|
|
|
|
/* If it is a reply for ato after last received
|
|
- * packet, enter pingpong mode.
|
|
+ * packet, increase pingpong count.
|
|
*/
|
|
if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato)
|
|
- inet_csk_enter_pingpong_mode(sk);
|
|
+ inet_csk_inc_pingpong_cnt(sk);
|
|
}
|
|
|
|
/* Account for an ACK we sent. */
|
|
@@ -1083,7 +1083,8 @@ static void tcp_tasklet_func(struct tasklet_struct *t)
|
|
#define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \
|
|
TCPF_WRITE_TIMER_DEFERRED | \
|
|
TCPF_DELACK_TIMER_DEFERRED | \
|
|
- TCPF_MTU_REDUCED_DEFERRED)
|
|
+ TCPF_MTU_REDUCED_DEFERRED | \
|
|
+ TCPF_ACK_DEFERRED)
|
|
/**
|
|
* tcp_release_cb - tcp release_sock() callback
|
|
* @sk: socket
|
|
@@ -1130,6 +1131,8 @@ void tcp_release_cb(struct sock *sk)
|
|
inet_csk(sk)->icsk_af_ops->mtu_reduced(sk);
|
|
__sock_put(sk);
|
|
}
|
|
+ if ((flags & TCPF_ACK_DEFERRED) && inet_csk_ack_scheduled(sk))
|
|
+ tcp_send_ack(sk);
|
|
}
|
|
EXPORT_SYMBOL(tcp_release_cb);
|
|
|
|
diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c
|
|
index 0735d820e413f3..91233e37cd97a2 100644
|
|
--- a/net/ipv4/udp_bpf.c
|
|
+++ b/net/ipv4/udp_bpf.c
|
|
@@ -5,6 +5,7 @@
|
|
#include <net/sock.h>
|
|
#include <net/udp.h>
|
|
#include <net/inet_common.h>
|
|
+#include <asm/ioctls.h>
|
|
|
|
#include "udp_impl.h"
|
|
|
|
@@ -111,12 +112,26 @@ enum {
|
|
static DEFINE_SPINLOCK(udpv6_prot_lock);
|
|
static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS];
|
|
|
|
+static int udp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
|
|
+{
|
|
+ if (cmd != SIOCINQ)
|
|
+ return udp_ioctl(sk, cmd, karg);
|
|
+
|
|
+ /* Since we don't hold a lock, sk_receive_queue may contain data.
|
|
+ * BPF might only be processing this data at the moment. We only
|
|
+ * care about the data in the ingress_msg here.
|
|
+ */
|
|
+ *karg = sk_msg_first_len(sk);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base)
|
|
{
|
|
- *prot = *base;
|
|
- prot->close = sock_map_close;
|
|
- prot->recvmsg = udp_bpf_recvmsg;
|
|
- prot->sock_is_readable = sk_msg_is_readable;
|
|
+ *prot = *base;
|
|
+ prot->close = sock_map_close;
|
|
+ prot->recvmsg = udp_bpf_recvmsg;
|
|
+ prot->sock_is_readable = sk_msg_is_readable;
|
|
+ prot->ioctl = udp_bpf_ioctl;
|
|
}
|
|
|
|
static void udp_bpf_check_v6_needs_rebuild(struct proto *ops)
|
|
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
|
|
index 02e9ffb63af197..676284b6efe8b9 100644
|
|
--- a/net/ipv6/exthdrs.c
|
|
+++ b/net/ipv6/exthdrs.c
|
|
@@ -313,7 +313,7 @@ fail_and_free:
|
|
}
|
|
|
|
extlen = (skb_transport_header(skb)[1] + 1) << 3;
|
|
- if (extlen > net->ipv6.sysctl.max_dst_opts_len)
|
|
+ if (extlen > READ_ONCE(net->ipv6.sysctl.max_dst_opts_len))
|
|
goto fail_and_free;
|
|
|
|
opt->lastopt = opt->dst1 = skb_network_header_len(skb);
|
|
@@ -321,7 +321,8 @@ fail_and_free:
|
|
dstbuf = opt->dst1;
|
|
#endif
|
|
|
|
- if (ip6_parse_tlv(false, skb, net->ipv6.sysctl.max_dst_opts_cnt)) {
|
|
+ if (ip6_parse_tlv(false, skb,
|
|
+ READ_ONCE(net->ipv6.sysctl.max_dst_opts_cnt))) {
|
|
skb->transport_header += extlen;
|
|
opt = IP6CB(skb);
|
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
|
@@ -937,6 +938,11 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
|
|
if (hdr->opt_len < 2 + sizeof(*trace) + trace->remlen * 4)
|
|
goto drop;
|
|
|
|
+ /* Inconsistent Pre-allocated Trace header */
|
|
+ if (trace->nodelen !=
|
|
+ ioam6_trace_compute_nodelen(be32_to_cpu(trace->type_be32)))
|
|
+ goto drop;
|
|
+
|
|
/* Ignore if the IOAM namespace is unknown */
|
|
ns = ioam6_namespace(ipv6_skb_net(skb), trace->namespace_id);
|
|
if (!ns)
|
|
@@ -1053,11 +1059,12 @@ fail_and_free:
|
|
}
|
|
|
|
extlen = (skb_transport_header(skb)[1] + 1) << 3;
|
|
- if (extlen > net->ipv6.sysctl.max_hbh_opts_len)
|
|
+ if (extlen > READ_ONCE(net->ipv6.sysctl.max_hbh_opts_len))
|
|
goto fail_and_free;
|
|
|
|
opt->flags |= IP6SKB_HOPBYHOP;
|
|
- if (ip6_parse_tlv(true, skb, net->ipv6.sysctl.max_hbh_opts_cnt)) {
|
|
+ if (ip6_parse_tlv(true, skb,
|
|
+ READ_ONCE(net->ipv6.sysctl.max_hbh_opts_cnt))) {
|
|
skb->transport_header += extlen;
|
|
opt = IP6CB(skb);
|
|
opt->nhoff = sizeof(struct ipv6hdr);
|
|
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
|
|
index c7e815b7ca0870..1d1c56e0e24607 100644
|
|
--- a/net/ipv6/icmp.c
|
|
+++ b/net/ipv6/icmp.c
|
|
@@ -181,7 +181,7 @@ static bool icmpv6_global_allow(struct net *net, int type,
|
|
if (icmpv6_mask_allow(net, type))
|
|
return true;
|
|
|
|
- if (icmp_global_allow()) {
|
|
+ if (icmp_global_allow(net)) {
|
|
*apply_ratelimit = true;
|
|
return true;
|
|
}
|
|
@@ -231,7 +231,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
|
|
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
|
|
ICMP6_MIB_RATELIMITHOST);
|
|
else
|
|
- icmp_global_consume();
|
|
+ icmp_global_consume(net);
|
|
dst_release(dst);
|
|
return res;
|
|
}
|
|
@@ -869,6 +869,12 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
|
|
if (reason != SKB_NOT_DROPPED_YET)
|
|
goto out;
|
|
|
|
+ if (nexthdr == IPPROTO_RAW) {
|
|
+ /* Add a more specific reason later ? */
|
|
+ reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
/* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
|
|
Without this we will not able f.e. to make source routed
|
|
pmtu discovery.
|
|
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
|
|
index 571f0e4d9cf3d0..a35b6fdbc93e90 100644
|
|
--- a/net/ipv6/ioam6.c
|
|
+++ b/net/ipv6/ioam6.c
|
|
@@ -630,6 +630,20 @@ struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
|
|
return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
|
|
}
|
|
|
|
+#define IOAM6_MASK_SHORT_FIELDS 0xff1ffc00
|
|
+#define IOAM6_MASK_WIDE_FIELDS 0x00e00000
|
|
+
|
|
+u8 ioam6_trace_compute_nodelen(u32 trace_type)
|
|
+{
|
|
+ u8 nodelen = hweight32(trace_type & IOAM6_MASK_SHORT_FIELDS)
|
|
+ * (sizeof(__be32) / 4);
|
|
+
|
|
+ nodelen += hweight32(trace_type & IOAM6_MASK_WIDE_FIELDS)
|
|
+ * (sizeof(__be64) / 4);
|
|
+
|
|
+ return nodelen;
|
|
+}
|
|
+
|
|
static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|
struct ioam6_namespace *ns,
|
|
struct ioam6_trace_hdr *trace,
|
|
diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c
|
|
index a5cfc5b0b206bb..3a6065faaf9bfe 100644
|
|
--- a/net/ipv6/ioam6_iptunnel.c
|
|
+++ b/net/ipv6/ioam6_iptunnel.c
|
|
@@ -22,9 +22,6 @@
|
|
#include <net/ip6_route.h>
|
|
#include <net/addrconf.h>
|
|
|
|
-#define IOAM6_MASK_SHORT_FIELDS 0xff100000
|
|
-#define IOAM6_MASK_WIDE_FIELDS 0xe00000
|
|
-
|
|
struct ioam6_lwt_encap {
|
|
struct ipv6_hopopt_hdr eh;
|
|
u8 pad[2]; /* 2-octet padding for 4n-alignment */
|
|
@@ -88,13 +85,8 @@ static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
|
|
trace->type.bit21)
|
|
return false;
|
|
|
|
- trace->nodelen = 0;
|
|
fields = be32_to_cpu(trace->type_be32);
|
|
-
|
|
- trace->nodelen += hweight32(fields & IOAM6_MASK_SHORT_FIELDS)
|
|
- * (sizeof(__be32) / 4);
|
|
- trace->nodelen += hweight32(fields & IOAM6_MASK_WIDE_FIELDS)
|
|
- * (sizeof(__be64) / 4);
|
|
+ trace->nodelen = ioam6_trace_compute_nodelen(fields);
|
|
|
|
return true;
|
|
}
|
|
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
|
|
index fe57884ca7238a..6fe867579118ba 100644
|
|
--- a/net/ipv6/ip6_fib.c
|
|
+++ b/net/ipv6/ip6_fib.c
|
|
@@ -1137,7 +1137,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
|
|
fib6_add_gc_list(iter);
|
|
}
|
|
if (!(rt->fib6_flags & (RTF_ADDRCONF | RTF_PREFIX_RT)) &&
|
|
- !iter->fib6_nh->fib_nh_gw_family) {
|
|
+ (iter->nh || !iter->fib6_nh->fib_nh_gw_family)) {
|
|
iter->fib6_flags &= ~RTF_ADDRCONF;
|
|
iter->fib6_flags &= ~RTF_PREFIX_RT;
|
|
}
|
|
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
|
|
index f24faa78ee82d8..e5d76e782b9613 100644
|
|
--- a/net/ipv6/xfrm6_policy.c
|
|
+++ b/net/ipv6/xfrm6_policy.c
|
|
@@ -57,6 +57,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr,
|
|
struct dst_entry *dst;
|
|
struct net_device *dev;
|
|
struct inet6_dev *idev;
|
|
+ int err;
|
|
|
|
dst = xfrm6_dst_lookup(params);
|
|
if (IS_ERR(dst))
|
|
@@ -68,9 +69,11 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr,
|
|
return -EHOSTUNREACH;
|
|
}
|
|
dev = idev->dev;
|
|
- ipv6_dev_get_saddr(dev_net(dev), dev, ¶ms->daddr->in6, 0,
|
|
- &saddr->in6);
|
|
+ err = ipv6_dev_get_saddr(dev_net(dev), dev, ¶ms->daddr->in6, 0,
|
|
+ &saddr->in6);
|
|
dst_release(dst);
|
|
+ if (err)
|
|
+ return -EHOSTUNREACH;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
|
|
index f3856856aa446b..85ef9042873bef 100644
|
|
--- a/net/mptcp/protocol.c
|
|
+++ b/net/mptcp/protocol.c
|
|
@@ -2048,8 +2048,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
|
|
|
|
msk->rcvq_space.copied += copied;
|
|
|
|
- mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC);
|
|
- time = tcp_stamp_us_delta(mstamp, msk->rcvq_space.time);
|
|
+ mstamp = mptcp_stamp();
|
|
+ time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time));
|
|
|
|
rtt_us = msk->rcvq_space.rtt_us;
|
|
if (rtt_us && time < (rtt_us >> 3))
|
|
@@ -3451,6 +3451,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
|
|
__mptcp_propagate_sndbuf(nsk, ssk);
|
|
|
|
mptcp_rcv_space_init(msk, ssk);
|
|
+ msk->rcvq_space.time = mptcp_stamp();
|
|
|
|
if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
|
|
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
|
|
@@ -3468,8 +3469,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk)
|
|
msk->rcvq_space.copied = 0;
|
|
msk->rcvq_space.rtt_us = 0;
|
|
|
|
- msk->rcvq_space.time = tp->tcp_mstamp;
|
|
-
|
|
/* initial rcv_space offering made to peer */
|
|
msk->rcvq_space.space = min_t(u32, tp->rcv_wnd,
|
|
TCP_INIT_CWND * tp->advmss);
|
|
@@ -3688,6 +3687,7 @@ void mptcp_finish_connect(struct sock *ssk)
|
|
* accessing the field below
|
|
*/
|
|
WRITE_ONCE(msk->local_key, subflow->local_key);
|
|
+ WRITE_ONCE(msk->rcvq_space.time, mptcp_stamp());
|
|
|
|
mptcp_pm_new_connection(msk, ssk, 0);
|
|
}
|
|
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
|
|
index 0fbc1f13bd2d4c..58805fbf1f961c 100644
|
|
--- a/net/mptcp/protocol.h
|
|
+++ b/net/mptcp/protocol.h
|
|
@@ -786,6 +786,11 @@ static inline bool mptcp_is_fully_established(struct sock *sk)
|
|
READ_ONCE(mptcp_sk(sk)->fully_established);
|
|
}
|
|
|
|
+static inline u64 mptcp_stamp(void)
|
|
+{
|
|
+ return div_u64(tcp_clock_ns(), NSEC_PER_USEC);
|
|
+}
|
|
+
|
|
void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk);
|
|
void mptcp_data_ready(struct sock *sk, struct sock *ssk);
|
|
bool mptcp_finish_join(struct sock *sk);
|
|
diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c
|
|
index a2c5a7ba0c6fce..ae9ad439449fa5 100644
|
|
--- a/net/netfilter/nf_conncount.c
|
|
+++ b/net/netfilter/nf_conncount.c
|
|
@@ -34,8 +34,9 @@
|
|
|
|
#define CONNCOUNT_SLOTS 256U
|
|
|
|
-#define CONNCOUNT_GC_MAX_NODES 8
|
|
-#define MAX_KEYLEN 5
|
|
+#define CONNCOUNT_GC_MAX_NODES 8
|
|
+#define CONNCOUNT_GC_MAX_COLLECT 64
|
|
+#define MAX_KEYLEN 5
|
|
|
|
/* we will save the tuples of all connections we care about */
|
|
struct nf_conncount_tuple {
|
|
@@ -178,16 +179,28 @@ static int __nf_conncount_add(struct net *net,
|
|
return -ENOENT;
|
|
|
|
if (ct && nf_ct_is_confirmed(ct)) {
|
|
- err = -EEXIST;
|
|
- goto out_put;
|
|
+ /* local connections are confirmed in postrouting so confirmation
|
|
+ * might have happened before hitting connlimit
|
|
+ */
|
|
+ if (skb->skb_iif != LOOPBACK_IFINDEX) {
|
|
+ err = -EEXIST;
|
|
+ goto out_put;
|
|
+ }
|
|
+
|
|
+ /* this is likely a local connection, skip optimization to avoid
|
|
+ * adding duplicates from a 'packet train'
|
|
+ */
|
|
+ goto check_connections;
|
|
}
|
|
|
|
- if ((u32)jiffies == list->last_gc)
|
|
+ if ((u32)jiffies == list->last_gc &&
|
|
+ (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT)
|
|
goto add_new_node;
|
|
|
|
+check_connections:
|
|
/* check the saved connections */
|
|
list_for_each_entry_safe(conn, conn_n, &list->head, node) {
|
|
- if (collect > CONNCOUNT_GC_MAX_NODES)
|
|
+ if (collect > CONNCOUNT_GC_MAX_COLLECT)
|
|
break;
|
|
|
|
found = find_or_evict(net, list, conn);
|
|
@@ -230,6 +243,7 @@ static int __nf_conncount_add(struct net *net,
|
|
nf_ct_put(found_ct);
|
|
}
|
|
list->last_gc = (u32)jiffies;
|
|
+ list->last_gc_count = list->count;
|
|
|
|
add_new_node:
|
|
if (WARN_ON_ONCE(list->count > INT_MAX)) {
|
|
@@ -277,13 +291,14 @@ void nf_conncount_list_init(struct nf_conncount_list *list)
|
|
spin_lock_init(&list->list_lock);
|
|
INIT_LIST_HEAD(&list->head);
|
|
list->count = 0;
|
|
+ list->last_gc_count = 0;
|
|
list->last_gc = (u32)jiffies;
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_conncount_list_init);
|
|
|
|
/* Return true if the list is empty. Must be called with BH disabled. */
|
|
-bool nf_conncount_gc_list(struct net *net,
|
|
- struct nf_conncount_list *list)
|
|
+static bool __nf_conncount_gc_list(struct net *net,
|
|
+ struct nf_conncount_list *list)
|
|
{
|
|
const struct nf_conntrack_tuple_hash *found;
|
|
struct nf_conncount_tuple *conn, *conn_n;
|
|
@@ -295,10 +310,6 @@ bool nf_conncount_gc_list(struct net *net,
|
|
if ((u32)jiffies == READ_ONCE(list->last_gc))
|
|
return false;
|
|
|
|
- /* don't bother if other cpu is already doing GC */
|
|
- if (!spin_trylock(&list->list_lock))
|
|
- return false;
|
|
-
|
|
list_for_each_entry_safe(conn, conn_n, &list->head, node) {
|
|
found = find_or_evict(net, list, conn);
|
|
if (IS_ERR(found)) {
|
|
@@ -320,14 +331,29 @@ bool nf_conncount_gc_list(struct net *net,
|
|
}
|
|
|
|
nf_ct_put(found_ct);
|
|
- if (collected > CONNCOUNT_GC_MAX_NODES)
|
|
+ if (collected > CONNCOUNT_GC_MAX_COLLECT)
|
|
break;
|
|
}
|
|
|
|
if (!list->count)
|
|
ret = true;
|
|
list->last_gc = (u32)jiffies;
|
|
- spin_unlock(&list->list_lock);
|
|
+ list->last_gc_count = list->count;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+bool nf_conncount_gc_list(struct net *net,
|
|
+ struct nf_conncount_list *list)
|
|
+{
|
|
+ bool ret;
|
|
+
|
|
+ /* don't bother if other cpu is already doing GC */
|
|
+ if (!spin_trylock_bh(&list->list_lock))
|
|
+ return false;
|
|
+
|
|
+ ret = __nf_conncount_gc_list(net, list);
|
|
+ spin_unlock_bh(&list->list_lock);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c
|
|
index 540d97715bd23d..62aa22a0787695 100644
|
|
--- a/net/netfilter/nf_conntrack_h323_asn1.c
|
|
+++ b/net/netfilter/nf_conntrack_h323_asn1.c
|
|
@@ -796,7 +796,7 @@ static int decode_choice(struct bitstr *bs, const struct field_t *f,
|
|
|
|
if (ext || (son->attr & OPEN)) {
|
|
BYTE_ALIGN(bs);
|
|
- if (nf_h323_error_boundary(bs, len, 0))
|
|
+ if (nf_h323_error_boundary(bs, 2, 0))
|
|
return H323_ERROR_BOUND;
|
|
len = get_len(bs);
|
|
if (nf_h323_error_boundary(bs, len, 0))
|
|
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
|
|
index 5a9bce24f3c3d9..ed983421e2eb2f 100644
|
|
--- a/net/netfilter/nf_conntrack_h323_main.c
|
|
+++ b/net/netfilter/nf_conntrack_h323_main.c
|
|
@@ -1186,13 +1186,13 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
|
|
{
|
|
struct net *net = nf_ct_net(ct);
|
|
struct nf_conntrack_expect *exp;
|
|
- struct nf_conntrack_tuple tuple;
|
|
+ struct nf_conntrack_tuple tuple = {
|
|
+ .src.l3num = nf_ct_l3num(ct),
|
|
+ .dst.protonum = IPPROTO_TCP,
|
|
+ .dst.u.tcp.port = port,
|
|
+ };
|
|
|
|
- memset(&tuple.src.u3, 0, sizeof(tuple.src.u3));
|
|
- tuple.src.u.tcp.port = 0;
|
|
memcpy(&tuple.dst.u3, addr, sizeof(tuple.dst.u3));
|
|
- tuple.dst.u.tcp.port = port;
|
|
- tuple.dst.protonum = IPPROTO_TCP;
|
|
|
|
exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
|
|
if (exp && exp->master == ct)
|
|
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
|
|
index e831637bc8ca8f..cb260eb3d012c3 100644
|
|
--- a/net/netfilter/nf_conntrack_proto_generic.c
|
|
+++ b/net/netfilter/nf_conntrack_proto_generic.c
|
|
@@ -67,6 +67,7 @@ void nf_conntrack_generic_init_net(struct net *net)
|
|
const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic =
|
|
{
|
|
.l4proto = 255,
|
|
+ .allow_clash = true,
|
|
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
|
.ctnl_timeout = {
|
|
.nlattr_to_obj = generic_timeout_nlattr_to_obj,
|
|
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
|
|
index a0a5d19fa8506b..41614e897ec8fd 100644
|
|
--- a/net/netfilter/nf_tables_api.c
|
|
+++ b/net/netfilter/nf_tables_api.c
|
|
@@ -2581,6 +2581,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
|
|
|
|
err_register_hook:
|
|
nft_chain_del(chain);
|
|
+ synchronize_rcu();
|
|
err_chain_add:
|
|
nft_trans_destroy(trans);
|
|
err_trans:
|
|
@@ -10824,6 +10825,13 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
|
|
ret = __nf_tables_abort(net, action);
|
|
nft_gc_seq_end(nft_net, gc_seq);
|
|
|
|
+ if (action == NFNL_ABORT_NONE) {
|
|
+ struct nft_table *table;
|
|
+
|
|
+ list_for_each_entry(table, &nft_net->tables, list)
|
|
+ table->validate_state = NFT_VALIDATE_SKIP;
|
|
+ }
|
|
+
|
|
WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
|
|
|
|
/* module autoload needs to happen after GC sequence update because it
|
|
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
|
|
index 7ca4f0d21fe2a2..1e8142e64e8082 100644
|
|
--- a/net/netfilter/nft_compat.c
|
|
+++ b/net/netfilter/nft_compat.c
|
|
@@ -134,7 +134,8 @@ static void nft_target_eval_bridge(const struct nft_expr *expr,
|
|
}
|
|
|
|
static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
|
|
- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
|
|
+ [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING,
|
|
+ .len = XT_EXTENSION_MAXNAMELEN, },
|
|
[NFTA_TARGET_REV] = NLA_POLICY_MAX(NLA_BE32, 255),
|
|
[NFTA_TARGET_INFO] = { .type = NLA_BINARY },
|
|
};
|
|
@@ -434,7 +435,8 @@ static void nft_match_eval(const struct nft_expr *expr,
|
|
}
|
|
|
|
static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
|
|
- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
|
|
+ [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING,
|
|
+ .len = XT_EXTENSION_MAXNAMELEN },
|
|
[NFTA_MATCH_REV] = NLA_POLICY_MAX(NLA_BE32, 255),
|
|
[NFTA_MATCH_INFO] = { .type = NLA_BINARY },
|
|
};
|
|
@@ -693,7 +695,12 @@ static int nfnl_compat_get_rcu(struct sk_buff *skb,
|
|
|
|
name = nla_data(tb[NFTA_COMPAT_NAME]);
|
|
rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
|
|
- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
|
|
+ /* x_tables api checks for 'target == 1' to mean target,
|
|
+ * everything else means 'match'.
|
|
+ * In x_tables world, the number is set by kernel, not
|
|
+ * userspace.
|
|
+ */
|
|
+ target = nla_get_be32(tb[NFTA_COMPAT_TYPE]) == htonl(1);
|
|
|
|
switch(family) {
|
|
case AF_INET:
|
|
diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c
|
|
index 83a7d5769396cf..5dd50b3ab5a452 100644
|
|
--- a/net/netfilter/nft_connlimit.c
|
|
+++ b/net/netfilter/nft_connlimit.c
|
|
@@ -232,13 +232,8 @@ static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx,
|
|
static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr)
|
|
{
|
|
struct nft_connlimit *priv = nft_expr_priv(expr);
|
|
- bool ret;
|
|
|
|
- local_bh_disable();
|
|
- ret = nf_conncount_gc_list(net, priv->list);
|
|
- local_bh_enable();
|
|
-
|
|
- return ret;
|
|
+ return nf_conncount_gc_list(net, priv->list);
|
|
}
|
|
|
|
static struct nft_expr_type nft_connlimit_type;
|
|
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
|
|
index cc732532949630..0d70325280cc57 100644
|
|
--- a/net/netfilter/nft_counter.c
|
|
+++ b/net/netfilter/nft_counter.c
|
|
@@ -117,8 +117,8 @@ static void nft_counter_reset(struct nft_counter_percpu_priv *priv,
|
|
nft_sync = this_cpu_ptr(&nft_counter_sync);
|
|
|
|
u64_stats_update_begin(nft_sync);
|
|
- u64_stats_add(&this_cpu->packets, -total->packets);
|
|
- u64_stats_add(&this_cpu->bytes, -total->bytes);
|
|
+ u64_stats_sub(&this_cpu->packets, total->packets);
|
|
+ u64_stats_sub(&this_cpu->bytes, total->bytes);
|
|
u64_stats_update_end(nft_sync);
|
|
|
|
local_bh_enable();
|
|
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
|
|
index 2f1012bde1f34e..5a74ee4b7dfb35 100644
|
|
--- a/net/netfilter/nft_set_hash.c
|
|
+++ b/net/netfilter/nft_set_hash.c
|
|
@@ -525,15 +525,20 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
|
|
static void *nft_hash_get(const struct net *net, const struct nft_set *set,
|
|
const struct nft_set_elem *elem, unsigned int flags)
|
|
{
|
|
+ const u32 *key = (const u32 *)&elem->key.val;
|
|
struct nft_hash *priv = nft_set_priv(set);
|
|
u8 genmask = nft_genmask_cur(net);
|
|
struct nft_hash_elem *he;
|
|
u32 hash;
|
|
|
|
- hash = jhash(elem->key.val.data, set->klen, priv->seed);
|
|
+ if (set->klen == 4)
|
|
+ hash = jhash_1word(*key, priv->seed);
|
|
+ else
|
|
+ hash = jhash(key, set->klen, priv->seed);
|
|
+
|
|
hash = reciprocal_scale(hash, priv->buckets);
|
|
hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
|
|
- if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) &&
|
|
+ if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
|
|
nft_set_elem_active(&he->ext, genmask))
|
|
return he;
|
|
}
|
|
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
|
|
index 04672238e17dce..9c9b07f2def1b1 100644
|
|
--- a/net/netfilter/nft_set_rbtree.c
|
|
+++ b/net/netfilter/nft_set_rbtree.c
|
|
@@ -305,11 +305,23 @@ static bool nft_rbtree_update_first(const struct nft_set *set,
|
|
return false;
|
|
}
|
|
|
|
+/* Only for anonymous sets which do not allow updates, all element are active. */
|
|
+static struct nft_rbtree_elem *nft_rbtree_prev_active(struct nft_rbtree_elem *rbe)
|
|
+{
|
|
+ struct rb_node *node;
|
|
+
|
|
+ node = rb_prev(&rbe->node);
|
|
+ if (!node)
|
|
+ return NULL;
|
|
+
|
|
+ return rb_entry(node, struct nft_rbtree_elem, node);
|
|
+}
|
|
+
|
|
static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
struct nft_rbtree_elem *new,
|
|
struct nft_set_ext **ext)
|
|
{
|
|
- struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL;
|
|
+ struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
|
|
struct rb_node *node, *next, *parent, **p, *first = NULL;
|
|
struct nft_rbtree *priv = nft_set_priv(set);
|
|
u8 cur_genmask = nft_genmask_cur(net);
|
|
@@ -441,11 +453,19 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
/* - new start element with existing closest, less or equal key value
|
|
* being a start element: partial overlap, reported as -ENOTEMPTY.
|
|
* Anonymous sets allow for two consecutive start element since they
|
|
- * are constant, skip them to avoid bogus overlap reports.
|
|
+ * are constant, but validate that this new start element does not
|
|
+ * sit in between an existing start and end elements: partial overlap,
|
|
+ * reported as -ENOTEMPTY.
|
|
*/
|
|
- if (!nft_set_is_anonymous(set) && rbe_le &&
|
|
- nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new))
|
|
- return -ENOTEMPTY;
|
|
+ if (rbe_le &&
|
|
+ nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new)) {
|
|
+ if (!nft_set_is_anonymous(set))
|
|
+ return -ENOTEMPTY;
|
|
+
|
|
+ rbe_prev = nft_rbtree_prev_active(rbe_le);
|
|
+ if (rbe_prev && nft_rbtree_interval_end(rbe_prev))
|
|
+ return -ENOTEMPTY;
|
|
+ }
|
|
|
|
/* - new end element with existing closest, less or equal key value
|
|
* being a end element: partial overlap, reported as -ENOTEMPTY.
|
|
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
|
|
index 37704ab0179923..0d32d4841cb325 100644
|
|
--- a/net/netfilter/xt_tcpmss.c
|
|
+++ b/net/netfilter/xt_tcpmss.c
|
|
@@ -61,7 +61,7 @@ tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|
return (mssval >= info->mss_min &&
|
|
mssval <= info->mss_max) ^ info->invert;
|
|
}
|
|
- if (op[i] < 2)
|
|
+ if (op[i] < 2 || i == optlen - 1)
|
|
i++;
|
|
else
|
|
i += op[i+1] ? : 1;
|
|
diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c
|
|
index e90f70385813a8..a106f4352356df 100644
|
|
--- a/net/nfc/hci/llc_shdlc.c
|
|
+++ b/net/nfc/hci/llc_shdlc.c
|
|
@@ -762,6 +762,14 @@ static void llc_shdlc_deinit(struct nfc_llc *llc)
|
|
{
|
|
struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
|
|
|
|
+ timer_shutdown_sync(&shdlc->connect_timer);
|
|
+ timer_shutdown_sync(&shdlc->t1_timer);
|
|
+ timer_shutdown_sync(&shdlc->t2_timer);
|
|
+ shdlc->t1_active = false;
|
|
+ shdlc->t2_active = false;
|
|
+
|
|
+ cancel_work_sync(&shdlc->sm_work);
|
|
+
|
|
skb_queue_purge(&shdlc->rcv_q);
|
|
skb_queue_purge(&shdlc->send_q);
|
|
skb_queue_purge(&shdlc->ack_pending_q);
|
|
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
|
|
index cb2a672105dc1a..df0f1200082cfd 100644
|
|
--- a/net/nfc/nci/ntf.c
|
|
+++ b/net/nfc/nci/ntf.c
|
|
@@ -58,7 +58,7 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
|
|
struct nci_conn_info *conn_info;
|
|
int i;
|
|
|
|
- if (skb->len < sizeof(struct nci_core_conn_credit_ntf))
|
|
+ if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries))
|
|
return -EINVAL;
|
|
|
|
ntf = (struct nci_core_conn_credit_ntf *)skb->data;
|
|
@@ -68,6 +68,10 @@ static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
|
|
if (ntf->num_entries > NCI_MAX_NUM_CONN)
|
|
ntf->num_entries = NCI_MAX_NUM_CONN;
|
|
|
|
+ if (skb->len < offsetofend(struct nci_core_conn_credit_ntf, num_entries) +
|
|
+ ntf->num_entries * sizeof(struct conn_credit_entry))
|
|
+ return -EINVAL;
|
|
+
|
|
/* update the credits */
|
|
for (i = 0; i < ntf->num_entries; i++) {
|
|
ntf->conn_entries[i].conn_id =
|
|
@@ -138,23 +142,48 @@ static int nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
|
|
static const __u8 *
|
|
nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
|
|
struct rf_tech_specific_params_nfca_poll *nfca_poll,
|
|
- const __u8 *data)
|
|
+ const __u8 *data, ssize_t data_len)
|
|
{
|
|
+ /* Check if we have enough data for sens_res (2 bytes) */
|
|
+ if (data_len < 2)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfca_poll->sens_res = __le16_to_cpu(*((__le16 *)data));
|
|
data += 2;
|
|
+ data_len -= 2;
|
|
+
|
|
+ /* Check if we have enough data for nfcid1_len (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE);
|
|
+ data_len--;
|
|
|
|
pr_debug("sens_res 0x%x, nfcid1_len %d\n",
|
|
nfca_poll->sens_res, nfca_poll->nfcid1_len);
|
|
|
|
+ /* Check if we have enough data for nfcid1 */
|
|
+ if (data_len < nfca_poll->nfcid1_len)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
|
|
data += nfca_poll->nfcid1_len;
|
|
+ data_len -= nfca_poll->nfcid1_len;
|
|
+
|
|
+ /* Check if we have enough data for sel_res_len (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
nfca_poll->sel_res_len = *data++;
|
|
+ data_len--;
|
|
+
|
|
+ if (nfca_poll->sel_res_len != 0) {
|
|
+ /* Check if we have enough data for sel_res (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
- if (nfca_poll->sel_res_len != 0)
|
|
nfca_poll->sel_res = *data++;
|
|
+ }
|
|
|
|
pr_debug("sel_res_len %d, sel_res 0x%x\n",
|
|
nfca_poll->sel_res_len,
|
|
@@ -166,12 +195,21 @@ nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
|
|
static const __u8 *
|
|
nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
|
|
struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
|
|
- const __u8 *data)
|
|
+ const __u8 *data, ssize_t data_len)
|
|
{
|
|
+ /* Check if we have enough data for sensb_res_len (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE);
|
|
+ data_len--;
|
|
|
|
pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
|
|
|
|
+ /* Check if we have enough data for sensb_res */
|
|
+ if (data_len < nfcb_poll->sensb_res_len)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len);
|
|
data += nfcb_poll->sensb_res_len;
|
|
|
|
@@ -181,14 +219,29 @@ nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
|
|
static const __u8 *
|
|
nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
|
|
struct rf_tech_specific_params_nfcf_poll *nfcf_poll,
|
|
- const __u8 *data)
|
|
+ const __u8 *data, ssize_t data_len)
|
|
{
|
|
+ /* Check if we have enough data for bit_rate (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfcf_poll->bit_rate = *data++;
|
|
+ data_len--;
|
|
+
|
|
+ /* Check if we have enough data for sensf_res_len (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);
|
|
+ data_len--;
|
|
|
|
pr_debug("bit_rate %d, sensf_res_len %d\n",
|
|
nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
|
|
|
|
+ /* Check if we have enough data for sensf_res */
|
|
+ if (data_len < nfcf_poll->sensf_res_len)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len);
|
|
data += nfcf_poll->sensf_res_len;
|
|
|
|
@@ -198,22 +251,49 @@ nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
|
|
static const __u8 *
|
|
nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
|
|
struct rf_tech_specific_params_nfcv_poll *nfcv_poll,
|
|
- const __u8 *data)
|
|
+ const __u8 *data, ssize_t data_len)
|
|
{
|
|
+ /* Skip 1 byte (reserved) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
++data;
|
|
+ data_len--;
|
|
+
|
|
+ /* Check if we have enough data for dsfid (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfcv_poll->dsfid = *data++;
|
|
+ data_len--;
|
|
+
|
|
+ /* Check if we have enough data for uid (8 bytes) */
|
|
+ if (data_len < NFC_ISO15693_UID_MAXSIZE)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
memcpy(nfcv_poll->uid, data, NFC_ISO15693_UID_MAXSIZE);
|
|
data += NFC_ISO15693_UID_MAXSIZE;
|
|
+
|
|
return data;
|
|
}
|
|
|
|
static const __u8 *
|
|
nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev,
|
|
struct rf_tech_specific_params_nfcf_listen *nfcf_listen,
|
|
- const __u8 *data)
|
|
+ const __u8 *data, ssize_t data_len)
|
|
{
|
|
+ /* Check if we have enough data for local_nfcid2_len (1 byte) */
|
|
+ if (data_len < 1)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
nfcf_listen->local_nfcid2_len = min_t(__u8, *data++,
|
|
NFC_NFCID2_MAXSIZE);
|
|
+ data_len--;
|
|
+
|
|
+ /* Check if we have enough data for local_nfcid2 */
|
|
+ if (data_len < nfcf_listen->local_nfcid2_len)
|
|
+ return ERR_PTR(-EINVAL);
|
|
+
|
|
memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len);
|
|
data += nfcf_listen->local_nfcid2_len;
|
|
|
|
@@ -364,7 +444,7 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
|
|
const __u8 *data;
|
|
bool add_target = true;
|
|
|
|
- if (skb->len < sizeof(struct nci_rf_discover_ntf))
|
|
+ if (skb->len < offsetofend(struct nci_rf_discover_ntf, rf_tech_specific_params_len))
|
|
return -EINVAL;
|
|
|
|
data = skb->data;
|
|
@@ -380,26 +460,42 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
|
|
pr_debug("rf_tech_specific_params_len %d\n",
|
|
ntf.rf_tech_specific_params_len);
|
|
|
|
+ if (skb->len < (data - skb->data) +
|
|
+ ntf.rf_tech_specific_params_len + sizeof(ntf.ntf_type))
|
|
+ return -EINVAL;
|
|
+
|
|
if (ntf.rf_tech_specific_params_len > 0) {
|
|
switch (ntf.rf_tech_and_mode) {
|
|
case NCI_NFC_A_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfca_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfca_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfca_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return PTR_ERR(data);
|
|
break;
|
|
|
|
case NCI_NFC_B_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcb_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcb_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcb_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return PTR_ERR(data);
|
|
break;
|
|
|
|
case NCI_NFC_F_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcf_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcf_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcf_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return PTR_ERR(data);
|
|
break;
|
|
|
|
case NCI_NFC_V_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcv_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcv_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcv_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return PTR_ERR(data);
|
|
break;
|
|
|
|
default:
|
|
@@ -574,7 +670,7 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
const __u8 *data;
|
|
int err = NCI_STATUS_OK;
|
|
|
|
- if (skb->len < sizeof(struct nci_rf_intf_activated_ntf))
|
|
+ if (skb->len < offsetofend(struct nci_rf_intf_activated_ntf, rf_tech_specific_params_len))
|
|
return -EINVAL;
|
|
|
|
data = skb->data;
|
|
@@ -606,26 +702,41 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
if (ntf.rf_interface == NCI_RF_INTERFACE_NFCEE_DIRECT)
|
|
goto listen;
|
|
|
|
+ if (skb->len < (data - skb->data) + ntf.rf_tech_specific_params_len)
|
|
+ return -EINVAL;
|
|
+
|
|
if (ntf.rf_tech_specific_params_len > 0) {
|
|
switch (ntf.activation_rf_tech_and_mode) {
|
|
case NCI_NFC_A_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfca_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfca_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfca_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return -EINVAL;
|
|
break;
|
|
|
|
case NCI_NFC_B_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcb_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcb_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcb_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return -EINVAL;
|
|
break;
|
|
|
|
case NCI_NFC_F_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcf_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcf_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcf_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return -EINVAL;
|
|
break;
|
|
|
|
case NCI_NFC_V_PASSIVE_POLL_MODE:
|
|
data = nci_extract_rf_params_nfcv_passive_poll(ndev,
|
|
- &(ntf.rf_tech_specific_params.nfcv_poll), data);
|
|
+ &(ntf.rf_tech_specific_params.nfcv_poll), data,
|
|
+ ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return -EINVAL;
|
|
break;
|
|
|
|
case NCI_NFC_A_PASSIVE_LISTEN_MODE:
|
|
@@ -635,7 +746,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
case NCI_NFC_F_PASSIVE_LISTEN_MODE:
|
|
data = nci_extract_rf_params_nfcf_passive_listen(ndev,
|
|
&(ntf.rf_tech_specific_params.nfcf_listen),
|
|
- data);
|
|
+ data, ntf.rf_tech_specific_params_len);
|
|
+ if (IS_ERR(data))
|
|
+ return -EINVAL;
|
|
break;
|
|
|
|
default:
|
|
@@ -646,6 +759,13 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
}
|
|
}
|
|
|
|
+ if (skb->len < (data - skb->data) +
|
|
+ sizeof(ntf.data_exch_rf_tech_and_mode) +
|
|
+ sizeof(ntf.data_exch_tx_bit_rate) +
|
|
+ sizeof(ntf.data_exch_rx_bit_rate) +
|
|
+ sizeof(ntf.activation_params_len))
|
|
+ return -EINVAL;
|
|
+
|
|
ntf.data_exch_rf_tech_and_mode = *data++;
|
|
ntf.data_exch_tx_bit_rate = *data++;
|
|
ntf.data_exch_rx_bit_rate = *data++;
|
|
@@ -657,6 +777,9 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate);
|
|
pr_debug("activation_params_len %d\n", ntf.activation_params_len);
|
|
|
|
+ if (skb->len < (data - skb->data) + ntf.activation_params_len)
|
|
+ return -EINVAL;
|
|
+
|
|
if (ntf.activation_params_len > 0) {
|
|
switch (ntf.rf_interface) {
|
|
case NCI_RF_INTERFACE_ISO_DEP:
|
|
diff --git a/net/rds/connection.c b/net/rds/connection.c
|
|
index b4cc699c5fad37..98c0d5ff9de9c6 100644
|
|
--- a/net/rds/connection.c
|
|
+++ b/net/rds/connection.c
|
|
@@ -381,6 +381,8 @@ void rds_conn_shutdown(struct rds_conn_path *cp)
|
|
if (!rds_conn_path_transition(cp, RDS_CONN_UP,
|
|
RDS_CONN_DISCONNECTING) &&
|
|
!rds_conn_path_transition(cp, RDS_CONN_ERROR,
|
|
+ RDS_CONN_DISCONNECTING) &&
|
|
+ !rds_conn_path_transition(cp, RDS_CONN_RESETTING,
|
|
RDS_CONN_DISCONNECTING)) {
|
|
rds_conn_path_error(cp,
|
|
"shutdown called in state %d\n",
|
|
@@ -426,6 +428,8 @@ void rds_conn_shutdown(struct rds_conn_path *cp)
|
|
* to the conn hash, so we never trigger a reconnect on this
|
|
* conn - the reconnect is always triggered by the active peer. */
|
|
cancel_delayed_work_sync(&cp->cp_conn_w);
|
|
+
|
|
+ clear_bit(RDS_RECONNECT_PENDING, &cp->cp_flags);
|
|
rcu_read_lock();
|
|
if (!hlist_unhashed(&conn->c_hash_node)) {
|
|
rcu_read_unlock();
|
|
diff --git a/net/rds/send.c b/net/rds/send.c
|
|
index 09a28011065493..4a24ee9c22d7c9 100644
|
|
--- a/net/rds/send.c
|
|
+++ b/net/rds/send.c
|
|
@@ -1382,9 +1382,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
else
|
|
queue_delayed_work(rds_wq, &cpath->cp_send_w, 1);
|
|
rcu_read_unlock();
|
|
+
|
|
+ if (ret)
|
|
+ goto out;
|
|
}
|
|
- if (ret)
|
|
- goto out;
|
|
+
|
|
rds_message_put(rm);
|
|
|
|
for (ind = 0; ind < vct.indx; ind++)
|
|
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
|
|
index 53b3535a1e4a84..2e2f1a67504967 100644
|
|
--- a/net/rds/tcp_listen.c
|
|
+++ b/net/rds/tcp_listen.c
|
|
@@ -59,9 +59,6 @@ void rds_tcp_keepalive(struct socket *sock)
|
|
* socket and force a reconneect from smaller -> larger ip addr. The reason
|
|
* we special case cp_index 0 is to allow the rds probe ping itself to itself
|
|
* get through efficiently.
|
|
- * Since reconnects are only initiated from the node with the numerically
|
|
- * smaller ip address, we recycle conns in RDS_CONN_ERROR on the passive side
|
|
- * by moving them to CONNECTING in this function.
|
|
*/
|
|
static
|
|
struct rds_tcp_connection *rds_tcp_accept_one_path(struct rds_connection *conn)
|
|
@@ -86,8 +83,6 @@ struct rds_tcp_connection *rds_tcp_accept_one_path(struct rds_connection *conn)
|
|
struct rds_conn_path *cp = &conn->c_path[i];
|
|
|
|
if (rds_conn_path_transition(cp, RDS_CONN_DOWN,
|
|
- RDS_CONN_CONNECTING) ||
|
|
- rds_conn_path_transition(cp, RDS_CONN_ERROR,
|
|
RDS_CONN_CONNECTING)) {
|
|
return cp->cp_transport_data;
|
|
}
|
|
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
|
|
index ce7008cf291c3f..8675be6b1a2de6 100644
|
|
--- a/net/sched/act_skbedit.c
|
|
+++ b/net/sched/act_skbedit.c
|
|
@@ -128,7 +128,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
|
|
struct tcf_skbedit *d;
|
|
u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL;
|
|
u16 *queue_mapping = NULL, *ptype = NULL;
|
|
- u16 mapping_mod = 1;
|
|
+ u32 mapping_mod = 1;
|
|
bool exists = false;
|
|
int ret = 0, err;
|
|
u32 index;
|
|
@@ -196,6 +196,10 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
|
|
}
|
|
|
|
mapping_mod = *queue_mapping_max - *queue_mapping + 1;
|
|
+ if (mapping_mod > U16_MAX) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "The range of queue_mapping is invalid.");
|
|
+ return -EINVAL;
|
|
+ }
|
|
flags |= SKBEDIT_F_TXQ_SKBHASH;
|
|
}
|
|
if (*pure_flags & SKBEDIT_F_INHERITDSFIELD)
|
|
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
|
|
index 00753bc5f1b147..13a948e2f83d4f 100644
|
|
--- a/net/sunrpc/auth_gss/auth_gss.c
|
|
+++ b/net/sunrpc/auth_gss/auth_gss.c
|
|
@@ -39,6 +39,8 @@ static const struct rpc_authops authgss_ops;
|
|
static const struct rpc_credops gss_credops;
|
|
static const struct rpc_credops gss_nullops;
|
|
|
|
+static void gss_free_callback(struct kref *kref);
|
|
+
|
|
#define GSS_RETRY_EXPIRED 5
|
|
static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
|
|
|
|
@@ -551,6 +553,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
|
|
}
|
|
return gss_msg;
|
|
err_put_pipe_version:
|
|
+ kref_put(&gss_auth->kref, gss_free_callback);
|
|
put_pipe_version(gss_auth->net);
|
|
err_free_msg:
|
|
kfree(gss_msg);
|
|
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
|
index cb32ab9a839521..ee91f4d641e6fe 100644
|
|
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
|
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
|
@@ -320,29 +320,47 @@ static int gssx_dec_status(struct xdr_stream *xdr,
|
|
|
|
/* status->minor_status */
|
|
p = xdr_inline_decode(xdr, 8);
|
|
- if (unlikely(p == NULL))
|
|
- return -ENOSPC;
|
|
+ if (unlikely(p == NULL)) {
|
|
+ err = -ENOSPC;
|
|
+ goto out_free_mech;
|
|
+ }
|
|
p = xdr_decode_hyper(p, &status->minor_status);
|
|
|
|
/* status->major_status_string */
|
|
err = gssx_dec_buffer(xdr, &status->major_status_string);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_mech;
|
|
|
|
/* status->minor_status_string */
|
|
err = gssx_dec_buffer(xdr, &status->minor_status_string);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_major_status_string;
|
|
|
|
/* status->server_ctx */
|
|
err = gssx_dec_buffer(xdr, &status->server_ctx);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_minor_status_string;
|
|
|
|
/* we assume we have no options for now, so simply consume them */
|
|
/* status->options */
|
|
err = dummy_dec_opt_array(xdr, &status->options);
|
|
+ if (err)
|
|
+ goto out_free_server_ctx;
|
|
|
|
+ return 0;
|
|
+
|
|
+out_free_server_ctx:
|
|
+ kfree(status->server_ctx.data);
|
|
+ status->server_ctx.data = NULL;
|
|
+out_free_minor_status_string:
|
|
+ kfree(status->minor_status_string.data);
|
|
+ status->minor_status_string.data = NULL;
|
|
+out_free_major_status_string:
|
|
+ kfree(status->major_status_string.data);
|
|
+ status->major_status_string.data = NULL;
|
|
+out_free_mech:
|
|
+ kfree(status->mech.data);
|
|
+ status->mech.data = NULL;
|
|
return err;
|
|
}
|
|
|
|
@@ -505,28 +523,35 @@ static int gssx_dec_name(struct xdr_stream *xdr,
|
|
/* name->name_type */
|
|
err = gssx_dec_buffer(xdr, &dummy_netobj);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_display_name;
|
|
|
|
/* name->exported_name */
|
|
err = gssx_dec_buffer(xdr, &dummy_netobj);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_display_name;
|
|
|
|
/* name->exported_composite_name */
|
|
err = gssx_dec_buffer(xdr, &dummy_netobj);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_display_name;
|
|
|
|
/* we assume we have no attributes for now, so simply consume them */
|
|
/* name->name_attributes */
|
|
err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_display_name;
|
|
|
|
/* we assume we have no options for now, so simply consume them */
|
|
/* name->extensions */
|
|
err = dummy_dec_opt_array(xdr, &dummy_option_array);
|
|
+ if (err)
|
|
+ goto out_free_display_name;
|
|
|
|
+ return 0;
|
|
+
|
|
+out_free_display_name:
|
|
+ kfree(name->display_name.data);
|
|
+ name->display_name.data = NULL;
|
|
return err;
|
|
}
|
|
|
|
@@ -649,32 +674,34 @@ static int gssx_dec_ctx(struct xdr_stream *xdr,
|
|
/* ctx->state */
|
|
err = gssx_dec_buffer(xdr, &ctx->state);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_exported_context_token;
|
|
|
|
/* ctx->need_release */
|
|
err = gssx_dec_bool(xdr, &ctx->need_release);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_state;
|
|
|
|
/* ctx->mech */
|
|
err = gssx_dec_buffer(xdr, &ctx->mech);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_state;
|
|
|
|
/* ctx->src_name */
|
|
err = gssx_dec_name(xdr, &ctx->src_name);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_mech;
|
|
|
|
/* ctx->targ_name */
|
|
err = gssx_dec_name(xdr, &ctx->targ_name);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_src_name;
|
|
|
|
/* ctx->lifetime */
|
|
p = xdr_inline_decode(xdr, 8+8);
|
|
- if (unlikely(p == NULL))
|
|
- return -ENOSPC;
|
|
+ if (unlikely(p == NULL)) {
|
|
+ err = -ENOSPC;
|
|
+ goto out_free_targ_name;
|
|
+ }
|
|
p = xdr_decode_hyper(p, &ctx->lifetime);
|
|
|
|
/* ctx->ctx_flags */
|
|
@@ -683,17 +710,36 @@ static int gssx_dec_ctx(struct xdr_stream *xdr,
|
|
/* ctx->locally_initiated */
|
|
err = gssx_dec_bool(xdr, &ctx->locally_initiated);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_targ_name;
|
|
|
|
/* ctx->open */
|
|
err = gssx_dec_bool(xdr, &ctx->open);
|
|
if (err)
|
|
- return err;
|
|
+ goto out_free_targ_name;
|
|
|
|
/* we assume we have no options for now, so simply consume them */
|
|
/* ctx->options */
|
|
err = dummy_dec_opt_array(xdr, &ctx->options);
|
|
+ if (err)
|
|
+ goto out_free_targ_name;
|
|
+
|
|
+ return 0;
|
|
|
|
+out_free_targ_name:
|
|
+ kfree(ctx->targ_name.display_name.data);
|
|
+ ctx->targ_name.display_name.data = NULL;
|
|
+out_free_src_name:
|
|
+ kfree(ctx->src_name.display_name.data);
|
|
+ ctx->src_name.display_name.data = NULL;
|
|
+out_free_mech:
|
|
+ kfree(ctx->mech.data);
|
|
+ ctx->mech.data = NULL;
|
|
+out_free_state:
|
|
+ kfree(ctx->state.data);
|
|
+ ctx->state.data = NULL;
|
|
+out_free_exported_context_token:
|
|
+ kfree(ctx->exported_context_token.data);
|
|
+ ctx->exported_context_token.data = NULL;
|
|
return err;
|
|
}
|
|
|
|
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
|
|
index 2abd895046ee3d..b8d13b522298b8 100644
|
|
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
|
|
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
|
|
@@ -363,12 +363,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
|
*/
|
|
static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
|
{
|
|
+ unsigned int ctxts, rq_depth, maxpayload;
|
|
struct svcxprt_rdma *listen_rdma;
|
|
struct svcxprt_rdma *newxprt = NULL;
|
|
struct rdma_conn_param conn_param;
|
|
struct rpcrdma_connect_private pmsg;
|
|
struct ib_qp_init_attr qp_attr;
|
|
- unsigned int ctxts, rq_depth;
|
|
struct ib_device *dev;
|
|
int ret = 0;
|
|
RPC_IFDEBUG(struct sockaddr *sap);
|
|
@@ -391,37 +391,46 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
|
dev = newxprt->sc_cm_id->device;
|
|
newxprt->sc_port_num = newxprt->sc_cm_id->port_num;
|
|
|
|
- /* Qualify the transport resource defaults with the
|
|
- * capabilities of this particular device */
|
|
+ newxprt->sc_max_req_size = svcrdma_max_req_size;
|
|
+ newxprt->sc_max_requests = svcrdma_max_requests;
|
|
+ newxprt->sc_max_bc_requests = svcrdma_max_bc_requests;
|
|
+ newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH;
|
|
+ newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests);
|
|
+
|
|
+ /* Qualify the transport's resource defaults with the
|
|
+ * capabilities of this particular device.
|
|
+ */
|
|
+
|
|
/* Transport header, head iovec, tail iovec */
|
|
newxprt->sc_max_send_sges = 3;
|
|
/* Add one SGE per page list entry */
|
|
newxprt->sc_max_send_sges += (svcrdma_max_req_size / PAGE_SIZE) + 1;
|
|
if (newxprt->sc_max_send_sges > dev->attrs.max_send_sge)
|
|
newxprt->sc_max_send_sges = dev->attrs.max_send_sge;
|
|
- newxprt->sc_max_req_size = svcrdma_max_req_size;
|
|
- newxprt->sc_max_requests = svcrdma_max_requests;
|
|
- newxprt->sc_max_bc_requests = svcrdma_max_bc_requests;
|
|
- newxprt->sc_recv_batch = RPCRDMA_MAX_RECV_BATCH;
|
|
rq_depth = newxprt->sc_max_requests + newxprt->sc_max_bc_requests +
|
|
newxprt->sc_recv_batch;
|
|
if (rq_depth > dev->attrs.max_qp_wr) {
|
|
- pr_warn("svcrdma: reducing receive depth to %d\n",
|
|
- dev->attrs.max_qp_wr);
|
|
rq_depth = dev->attrs.max_qp_wr;
|
|
newxprt->sc_recv_batch = 1;
|
|
newxprt->sc_max_requests = rq_depth - 2;
|
|
newxprt->sc_max_bc_requests = 2;
|
|
}
|
|
- newxprt->sc_fc_credits = cpu_to_be32(newxprt->sc_max_requests);
|
|
- ctxts = rdma_rw_mr_factor(dev, newxprt->sc_port_num, RPCSVC_MAXPAGES);
|
|
- ctxts *= newxprt->sc_max_requests;
|
|
- newxprt->sc_sq_depth = rq_depth + ctxts;
|
|
- if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) {
|
|
- pr_warn("svcrdma: reducing send depth to %d\n",
|
|
- dev->attrs.max_qp_wr);
|
|
+
|
|
+ /* Estimate the needed number of rdma_rw contexts. The maximum
|
|
+ * Read and Write chunks have one segment each. Each request
|
|
+ * can involve one Read chunk and either a Write chunk or Reply
|
|
+ * chunk; thus a factor of three.
|
|
+ */
|
|
+ maxpayload = min(xprt->xpt_server->sv_max_payload,
|
|
+ RPCSVC_MAXPAYLOAD_RDMA);
|
|
+ ctxts = newxprt->sc_max_requests * 3 *
|
|
+ rdma_rw_mr_factor(dev, newxprt->sc_port_num,
|
|
+ maxpayload >> PAGE_SHIFT);
|
|
+
|
|
+ newxprt->sc_sq_depth = rq_depth +
|
|
+ rdma_rw_max_send_wr(dev, newxprt->sc_port_num, ctxts, 0);
|
|
+ if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr)
|
|
newxprt->sc_sq_depth = dev->attrs.max_qp_wr;
|
|
- }
|
|
atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth);
|
|
|
|
newxprt->sc_pd = ib_alloc_pd(dev, 0);
|
|
diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
|
|
index 2721baf9fd2b32..d7736d90027155 100644
|
|
--- a/net/tipc/crypto.c
|
|
+++ b/net/tipc/crypto.c
|
|
@@ -460,7 +460,7 @@ static void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim)
|
|
rcu_read_lock();
|
|
tmp = rcu_dereference(aead);
|
|
if (tmp)
|
|
- atomic_add_unless(&rcu_dereference(aead)->users, -1, lim);
|
|
+ atomic_add_unless(&tmp->users, -1, lim);
|
|
rcu_read_unlock();
|
|
}
|
|
|
|
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
|
|
index d1180370fdf41c..e6555254ddb85f 100644
|
|
--- a/net/tipc/name_table.c
|
|
+++ b/net/tipc/name_table.c
|
|
@@ -348,7 +348,8 @@ static bool tipc_service_insert_publ(struct net *net,
|
|
|
|
/* Return if the publication already exists */
|
|
list_for_each_entry(_p, &sr->all_publ, all_publ) {
|
|
- if (_p->key == key && (!_p->sk.node || _p->sk.node == node)) {
|
|
+ if (_p->key == key && _p->sk.ref == p->sk.ref &&
|
|
+ (!_p->sk.node || _p->sk.node == node)) {
|
|
pr_debug("Failed to bind duplicate %u,%u,%u/%u:%u/%u\n",
|
|
p->sr.type, p->sr.lower, p->sr.upper,
|
|
node, p->sk.ref, key);
|
|
@@ -388,7 +389,8 @@ static struct publication *tipc_service_remove_publ(struct service_range *r,
|
|
u32 node = sk->node;
|
|
|
|
list_for_each_entry(p, &r->all_publ, all_publ) {
|
|
- if (p->key != key || (node && node != p->sk.node))
|
|
+ if (p->key != key || p->sk.ref != sk->ref ||
|
|
+ (node && node != p->sk.node))
|
|
continue;
|
|
list_del(&p->all_publ);
|
|
list_del(&p->local_publ);
|
|
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
|
|
index 7eccd6708d6649..aca3132689cf18 100644
|
|
--- a/net/vmw_vsock/vmci_transport.c
|
|
+++ b/net/vmw_vsock/vmci_transport.c
|
|
@@ -161,7 +161,7 @@ vmci_transport_packet_init(struct vmci_transport_packet *pkt,
|
|
|
|
case VMCI_TRANSPORT_PACKET_TYPE_WAITING_READ:
|
|
case VMCI_TRANSPORT_PACKET_TYPE_WAITING_WRITE:
|
|
- memcpy(&pkt->u.wait, wait, sizeof(pkt->u.wait));
|
|
+ pkt->u.wait = *wait;
|
|
break;
|
|
|
|
case VMCI_TRANSPORT_PACKET_TYPE_REQUEST2:
|
|
diff --git a/net/wireless/core.c b/net/wireless/core.c
|
|
index f6693983b5e986..0baa4c6ab16940 100644
|
|
--- a/net/wireless/core.c
|
|
+++ b/net/wireless/core.c
|
|
@@ -1331,8 +1331,10 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
|
|
__cfg80211_leave_ocb(rdev, dev);
|
|
break;
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
+ cfg80211_stop_p2p_device(rdev, wdev);
|
|
+ break;
|
|
case NL80211_IFTYPE_NAN:
|
|
- /* cannot happen, has no netdev */
|
|
+ cfg80211_stop_nan(rdev, wdev);
|
|
break;
|
|
case NL80211_IFTYPE_AP_VLAN:
|
|
case NL80211_IFTYPE_MONITOR:
|
|
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
|
|
index e3acfac7430ae0..52abda40dfb3f2 100644
|
|
--- a/net/wireless/wext-compat.c
|
|
+++ b/net/wireless/wext-compat.c
|
|
@@ -735,7 +735,7 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev,
|
|
|
|
idx = erq->flags & IW_ENCODE_INDEX;
|
|
if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
|
|
- if (idx < 4 || idx > 5) {
|
|
+ if (idx < 5 || idx > 6) {
|
|
idx = wdev->wext.default_mgmt_key;
|
|
if (idx < 0)
|
|
return -EINVAL;
|
|
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
|
|
index 7188d3592dde4e..a73b3c9d7e4d42 100644
|
|
--- a/net/xfrm/xfrm_device.c
|
|
+++ b/net/xfrm/xfrm_device.c
|
|
@@ -515,6 +515,14 @@ static int xfrm_dev_down(struct net_device *dev)
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
+static int xfrm_dev_unregister(struct net_device *dev)
|
|
+{
|
|
+ xfrm_dev_state_flush(dev_net(dev), dev, true);
|
|
+ xfrm_dev_policy_flush(dev_net(dev), dev, true);
|
|
+
|
|
+ return NOTIFY_DONE;
|
|
+}
|
|
+
|
|
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
|
|
{
|
|
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
|
@@ -527,8 +535,10 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
|
|
return xfrm_api_check(dev);
|
|
|
|
case NETDEV_DOWN:
|
|
- case NETDEV_UNREGISTER:
|
|
return xfrm_dev_down(dev);
|
|
+
|
|
+ case NETDEV_UNREGISTER:
|
|
+ return xfrm_dev_unregister(dev);
|
|
}
|
|
return NOTIFY_DONE;
|
|
}
|
|
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
|
|
index 2edb0f868c5738..b516dd15113ed6 100644
|
|
--- a/net/xfrm/xfrm_policy.c
|
|
+++ b/net/xfrm/xfrm_policy.c
|
|
@@ -3734,8 +3734,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
|
struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
|
|
struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
|
|
struct xfrm_tmpl **tpp = tp;
|
|
+ int i, k = 0;
|
|
int ti = 0;
|
|
- int i, k;
|
|
|
|
sp = skb_sec_path(skb);
|
|
if (!sp)
|
|
@@ -3761,6 +3761,12 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
|
tpp = stp;
|
|
}
|
|
|
|
+ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET && sp == &dummy)
|
|
+ /* This policy template was already checked by HW
|
|
+ * and secpath was removed in __xfrm_policy_check2.
|
|
+ */
|
|
+ goto out;
|
|
+
|
|
/* For each tunnel xfrm, find the first matching tmpl.
|
|
* For each tmpl before that, find corresponding xfrm.
|
|
* Order is _important_. Later we will implement
|
|
@@ -3770,7 +3776,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
|
* verified to allow them to be skipped in future policy
|
|
* checks (e.g. nested tunnels).
|
|
*/
|
|
- for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
|
|
+ for (i = xfrm_nr - 1; i >= 0; i--) {
|
|
k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
|
|
if (k < 0) {
|
|
if (k < -1)
|
|
@@ -3786,6 +3792,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
|
goto reject;
|
|
}
|
|
|
|
+out:
|
|
xfrm_pols_put(pols, npols);
|
|
sp->verified_cnt = k;
|
|
|
|
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
|
|
index 6e199a745ccb25..d963fdf40e9006 100755
|
|
--- a/scripts/kernel-doc
|
|
+++ b/scripts/kernel-doc
|
|
@@ -1592,6 +1592,11 @@ sub push_parameter($$$$$) {
|
|
$parameterdescs{$param} = "anonymous\n";
|
|
$anon_struct_union = 1;
|
|
}
|
|
+ elsif ($param =~ "__cacheline_group" )
|
|
+ # handle cache group enforcing variables: they do not need be described in header files
|
|
+ {
|
|
+ return; # ignore __cacheline_group_begin and __cacheline_group_end
|
|
+ }
|
|
|
|
# warn if parameter has no description
|
|
# (but ignore ones starting with # as these are not parameters
|
|
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
|
|
index 3eb7fda8a98ff4..96a6e68730981b 100644
|
|
--- a/scripts/mod/modpost.c
|
|
+++ b/scripts/mod/modpost.c
|
|
@@ -608,6 +608,10 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
|
|
/* Special register function linked on all modules during final link of .ko */
|
|
if (strstarts(symname, "_restgpr0_") ||
|
|
strstarts(symname, "_savegpr0_") ||
|
|
+ strstarts(symname, "_restgpr1_") ||
|
|
+ strstarts(symname, "_savegpr1_") ||
|
|
+ strstarts(symname, "_restfpr_") ||
|
|
+ strstarts(symname, "_savefpr_") ||
|
|
strstarts(symname, "_restvr_") ||
|
|
strstarts(symname, "_savevr_") ||
|
|
strcmp(symname, ".TOC.") == 0)
|
|
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
|
index 23b2853ce3c428..6885ecd4afddca 100644
|
|
--- a/security/apparmor/apparmorfs.c
|
|
+++ b/security/apparmor/apparmorfs.c
|
|
@@ -619,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
|
|
|
|
if (profile_unconfined(profile))
|
|
return;
|
|
- if (rules->file.dfa && *match_str == AA_CLASS_FILE) {
|
|
- state = aa_dfa_match_len(rules->file.dfa,
|
|
- rules->file.start[AA_CLASS_FILE],
|
|
+ if (rules->file->dfa && *match_str == AA_CLASS_FILE) {
|
|
+ state = aa_dfa_match_len(rules->file->dfa,
|
|
+ rules->file->start[AA_CLASS_FILE],
|
|
match_str + 1, match_len - 1);
|
|
if (state) {
|
|
struct path_cond cond = { };
|
|
|
|
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
|
|
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
|
}
|
|
- } else if (rules->policy.dfa) {
|
|
+ } else if (rules->policy->dfa) {
|
|
if (!RULE_MEDIATES(rules, *match_str))
|
|
return; /* no change to current perms */
|
|
- state = aa_dfa_match_len(rules->policy.dfa,
|
|
- rules->policy.start[0],
|
|
+ state = aa_dfa_match_len(rules->policy->dfa,
|
|
+ rules->policy->start[0],
|
|
match_str, match_len);
|
|
if (state)
|
|
- tmp = *aa_lookup_perms(&rules->policy, state);
|
|
+ tmp = *aa_lookup_perms(rules->policy, state);
|
|
}
|
|
aa_apply_modes_to_perms(profile, &tmp);
|
|
aa_perms_accum_raw(perms, &tmp);
|
|
@@ -1096,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
|
|
struct aa_profile *profile = labels_profile(label);
|
|
if (profile->attach.xmatch_str)
|
|
seq_printf(seq, "%s\n", profile->attach.xmatch_str);
|
|
- else if (profile->attach.xmatch.dfa)
|
|
+ else if (profile->attach.xmatch->dfa)
|
|
seq_puts(seq, "<unknown>\n");
|
|
else
|
|
seq_printf(seq, "%s\n", profile->base.name);
|
|
@@ -1637,6 +1637,15 @@ static const char *rawdata_get_link_base(struct dentry *dentry,
|
|
|
|
label = aa_get_label_rcu(&proxy->label);
|
|
profile = labels_profile(label);
|
|
+
|
|
+ /* rawdata can be null when aa_g_export_binary is unset during
|
|
+ * runtime and a profile is replaced
|
|
+ */
|
|
+ if (!profile->rawdata) {
|
|
+ aa_put_label(label);
|
|
+ return ERR_PTR(-ENOENT);
|
|
+ }
|
|
+
|
|
depth = profile_depth(profile);
|
|
target = gen_symlink_name(depth, profile->rawdata->name, name);
|
|
aa_put_label(label);
|
|
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
|
index 543105cf7e334d..d6500ec4f6b636 100644
|
|
--- a/security/apparmor/domain.c
|
|
+++ b/security/apparmor/domain.c
|
|
@@ -77,7 +77,7 @@ out:
|
|
/**** TODO: dedup to aa_label_match - needs perm and dfa, merging
|
|
* specifically this is an exact copy of aa_label_match except
|
|
* aa_compute_perms is replaced with aa_compute_fperms
|
|
- * and policy.dfa with file.dfa
|
|
+ * and policy->dfa with file->dfa
|
|
****/
|
|
/* match a profile and its associated ns component if needed
|
|
* Assumes visibility test has already been done.
|
|
@@ -93,16 +93,16 @@ static inline aa_state_t match_component(struct aa_profile *profile,
|
|
const char *ns_name;
|
|
|
|
if (stack)
|
|
- state = aa_dfa_match(rules->file.dfa, state, "&");
|
|
+ state = aa_dfa_match(rules->file->dfa, state, "&");
|
|
if (profile->ns == tp->ns)
|
|
- return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
|
|
+ return aa_dfa_match(rules->file->dfa, state, tp->base.hname);
|
|
|
|
/* try matching with namespace name and then profile */
|
|
ns_name = aa_ns_name(profile->ns, tp->ns, true);
|
|
- state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
|
|
- state = aa_dfa_match(rules->file.dfa, state, ns_name);
|
|
- state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
|
|
- return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
|
|
+ state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
|
|
+ state = aa_dfa_match(rules->file->dfa, state, ns_name);
|
|
+ state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
|
|
+ return aa_dfa_match(rules->file->dfa, state, tp->base.hname);
|
|
}
|
|
|
|
/**
|
|
@@ -150,12 +150,12 @@ next:
|
|
label_for_each_cont(i, label, tp) {
|
|
if (!aa_ns_visible(profile->ns, tp->ns, subns))
|
|
continue;
|
|
- state = aa_dfa_match(rules->file.dfa, state, "//&");
|
|
+ state = aa_dfa_match(rules->file->dfa, state, "//&");
|
|
state = match_component(profile, tp, false, state);
|
|
if (!state)
|
|
goto fail;
|
|
}
|
|
- *perms = *(aa_lookup_fperms(&(rules->file), state, &cond));
|
|
+ *perms = *(aa_lookup_fperms(rules->file, state, &cond));
|
|
aa_apply_modes_to_perms(profile, perms);
|
|
if ((perms->allow & request) != request)
|
|
return -EACCES;
|
|
@@ -210,7 +210,7 @@ static int label_components_match(struct aa_profile *profile,
|
|
return 0;
|
|
|
|
next:
|
|
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
|
|
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
|
aa_apply_modes_to_perms(profile, &tmp);
|
|
aa_perms_accum(perms, &tmp);
|
|
label_for_each_cont(i, label, tp) {
|
|
@@ -219,7 +219,7 @@ next:
|
|
state = match_component(profile, tp, stack, start);
|
|
if (!state)
|
|
goto fail;
|
|
- tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
|
|
+ tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
|
aa_apply_modes_to_perms(profile, &tmp);
|
|
aa_perms_accum(perms, &tmp);
|
|
}
|
|
@@ -316,7 +316,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
|
|
might_sleep();
|
|
|
|
/* transition from exec match to xattr set */
|
|
- state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
|
|
+ state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
|
|
d = bprm->file->f_path.dentry;
|
|
|
|
for (i = 0; i < attach->xattr_count; i++) {
|
|
@@ -330,20 +330,20 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
|
|
* that not present xattr can be distinguished from a 0
|
|
* length value or rule that matches any value
|
|
*/
|
|
- state = aa_dfa_null_transition(attach->xmatch.dfa,
|
|
+ state = aa_dfa_null_transition(attach->xmatch->dfa,
|
|
state);
|
|
/* Check xattr value */
|
|
- state = aa_dfa_match_len(attach->xmatch.dfa, state,
|
|
+ state = aa_dfa_match_len(attach->xmatch->dfa, state,
|
|
value, size);
|
|
- index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
|
|
- perm = attach->xmatch.perms[index].allow;
|
|
+ index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
|
|
+ perm = attach->xmatch->perms[index].allow;
|
|
if (!(perm & MAY_EXEC)) {
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
}
|
|
/* transition to next element */
|
|
- state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
|
|
+ state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
|
|
if (size < 0) {
|
|
/*
|
|
* No xattr match, so verify if transition to
|
|
@@ -412,16 +412,16 @@ restart:
|
|
* as another profile, signal a conflict and refuse to
|
|
* match.
|
|
*/
|
|
- if (attach->xmatch.dfa) {
|
|
+ if (attach->xmatch->dfa) {
|
|
unsigned int count;
|
|
aa_state_t state;
|
|
u32 index, perm;
|
|
|
|
- state = aa_dfa_leftmatch(attach->xmatch.dfa,
|
|
- attach->xmatch.start[AA_CLASS_XMATCH],
|
|
+ state = aa_dfa_leftmatch(attach->xmatch->dfa,
|
|
+ attach->xmatch->start[AA_CLASS_XMATCH],
|
|
name, &count);
|
|
- index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
|
|
- perm = attach->xmatch.perms[index].allow;
|
|
+ index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
|
|
+ perm = attach->xmatch->perms[index].allow;
|
|
/* any accepting state means a valid match. */
|
|
if (perm & MAY_EXEC) {
|
|
int ret = 0;
|
|
@@ -524,7 +524,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
|
|
/* TODO: move lookup parsing to unpack time so this is a straight
|
|
* index into the resultant label
|
|
*/
|
|
- for (*name = rules->file.trans.table[index]; !label && *name;
|
|
+ for (*name = rules->file->trans.table[index]; !label && *name;
|
|
*name = next_name(xtype, *name)) {
|
|
if (xindex & AA_X_CHILD) {
|
|
struct aa_profile *new_profile;
|
|
@@ -577,7 +577,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
|
|
break;
|
|
case AA_X_TABLE:
|
|
/* TODO: fix when perm mapping done at unload */
|
|
- stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK];
|
|
+ stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK];
|
|
if (*stack != '&') {
|
|
/* released by caller */
|
|
new = x_table_lookup(profile, xindex, lookupname);
|
|
@@ -636,7 +636,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
|
|
typeof(*rules), list);
|
|
struct aa_label *new = NULL;
|
|
const char *info = NULL, *name = NULL, *target = NULL;
|
|
- aa_state_t state = rules->file.start[AA_CLASS_FILE];
|
|
+ aa_state_t state = rules->file->start[AA_CLASS_FILE];
|
|
struct aa_perms perms = {};
|
|
bool nonewprivs = false;
|
|
int error = 0;
|
|
@@ -670,7 +670,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
|
|
}
|
|
|
|
/* find exec permissions for name */
|
|
- state = aa_str_perms(&(rules->file), state, name, cond, &perms);
|
|
+ state = aa_str_perms(rules->file, state, name, cond, &perms);
|
|
if (perms.allow & MAY_EXEC) {
|
|
/* exec permission determine how to transition */
|
|
new = x_to_label(profile, bprm, name, perms.xindex, &target,
|
|
@@ -736,7 +736,7 @@ static int profile_onexec(const struct cred *subj_cred,
|
|
{
|
|
struct aa_ruleset *rules = list_first_entry(&profile->rules,
|
|
typeof(*rules), list);
|
|
- aa_state_t state = rules->file.start[AA_CLASS_FILE];
|
|
+ aa_state_t state = rules->file->start[AA_CLASS_FILE];
|
|
struct aa_perms perms = {};
|
|
const char *xname = NULL, *info = "change_profile onexec";
|
|
int error = -EACCES;
|
|
@@ -769,7 +769,7 @@ static int profile_onexec(const struct cred *subj_cred,
|
|
}
|
|
|
|
/* find exec permissions for name */
|
|
- state = aa_str_perms(&(rules->file), state, xname, cond, &perms);
|
|
+ state = aa_str_perms(rules->file, state, xname, cond, &perms);
|
|
if (!(perms.allow & AA_MAY_ONEXEC)) {
|
|
info = "no change_onexec valid for executable";
|
|
goto audit;
|
|
@@ -778,7 +778,7 @@ static int profile_onexec(const struct cred *subj_cred,
|
|
* onexec permission is linked to exec with a standard pairing
|
|
* exec\0change_profile
|
|
*/
|
|
- state = aa_dfa_null_transition(rules->file.dfa, state);
|
|
+ state = aa_dfa_null_transition(rules->file->dfa, state);
|
|
error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC,
|
|
state, &perms);
|
|
if (error) {
|
|
@@ -1298,7 +1298,7 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
|
|
|
|
if (!error)
|
|
error = change_profile_perms(profile, target, stack, request,
|
|
- rules->file.start[AA_CLASS_FILE],
|
|
+ rules->file->start[AA_CLASS_FILE],
|
|
perms);
|
|
if (error)
|
|
error = aa_audit_file(subj_cred, profile, perms, op, request,
|
|
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
|
|
index a51b83cf696899..e9e71d7bdcb6eb 100644
|
|
--- a/security/apparmor/file.c
|
|
+++ b/security/apparmor/file.c
|
|
@@ -236,7 +236,7 @@ static int __aa_path_perm(const char *op, const struct cred *subj_cred,
|
|
|
|
if (profile_unconfined(profile))
|
|
return 0;
|
|
- aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
|
|
+ aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
|
|
name, cond, perms);
|
|
if (request & ~perms->allow)
|
|
e = -EACCES;
|
|
@@ -353,16 +353,16 @@ static int profile_path_link(const struct cred *subj_cred,
|
|
|
|
error = -EACCES;
|
|
/* aa_str_perms - handles the case of the dfa being NULL */
|
|
- state = aa_str_perms(&(rules->file),
|
|
- rules->file.start[AA_CLASS_FILE], lname,
|
|
+ state = aa_str_perms(rules->file,
|
|
+ rules->file->start[AA_CLASS_FILE], lname,
|
|
cond, &lperms);
|
|
|
|
if (!(lperms.allow & AA_MAY_LINK))
|
|
goto audit;
|
|
|
|
/* test to see if target can be paired with link */
|
|
- state = aa_dfa_null_transition(rules->file.dfa, state);
|
|
- aa_str_perms(&(rules->file), state, tname, cond, &perms);
|
|
+ state = aa_dfa_null_transition(rules->file->dfa, state);
|
|
+ aa_str_perms(rules->file, state, tname, cond, &perms);
|
|
|
|
/* force audit/quiet masks for link are stored in the second entry
|
|
* in the link pair.
|
|
@@ -384,7 +384,7 @@ static int profile_path_link(const struct cred *subj_cred,
|
|
/* Do link perm subset test requiring allowed permission on link are
|
|
* a subset of the allowed permissions on target.
|
|
*/
|
|
- aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
|
|
+ aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
|
|
tname, cond, &perms);
|
|
|
|
/* AA_MAY_LINK is not considered in the subset test */
|
|
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
|
|
index 6e88e99da80f6b..1ec00113a056fc 100644
|
|
--- a/security/apparmor/include/lib.h
|
|
+++ b/security/apparmor/include/lib.h
|
|
@@ -16,6 +16,8 @@
|
|
|
|
#include "match.h"
|
|
|
|
+extern struct aa_dfa *stacksplitdfa;
|
|
+
|
|
/*
|
|
* DEBUG remains global (no per profile flag) since it is mostly used in sysctl
|
|
* which is not related to profile accesses.
|
|
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
|
|
index e59305abb85a33..ae31a8a631fc6a 100644
|
|
--- a/security/apparmor/include/match.h
|
|
+++ b/security/apparmor/include/match.h
|
|
@@ -102,9 +102,6 @@ struct aa_dfa {
|
|
struct table_header *tables[YYTD_ID_TSIZE];
|
|
};
|
|
|
|
-extern struct aa_dfa *nulldfa;
|
|
-extern struct aa_dfa *stacksplitdfa;
|
|
-
|
|
#define byte_to_byte(X) (X)
|
|
|
|
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \
|
|
@@ -122,9 +119,6 @@ static inline size_t table_size(size_t len, size_t el_size)
|
|
return ALIGN(sizeof(struct table_header) + len * el_size, 8);
|
|
}
|
|
|
|
-int aa_setup_dfa_engine(void);
|
|
-void aa_teardown_dfa_engine(void);
|
|
-
|
|
#define aa_state_t unsigned int
|
|
|
|
struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
|
|
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
|
index fa15a5c7febb89..bb682d51341299 100644
|
|
--- a/security/apparmor/include/policy.h
|
|
+++ b/security/apparmor/include/policy.h
|
|
@@ -74,12 +74,14 @@ enum profile_mode {
|
|
|
|
|
|
/* struct aa_policydb - match engine for a policy
|
|
+ * count: refcount for the pdb
|
|
* dfa: dfa pattern match
|
|
* perms: table of permissions
|
|
* strs: table of strings, index by x
|
|
* start: set of start states for the different classes of data
|
|
*/
|
|
struct aa_policydb {
|
|
+ struct kref count;
|
|
struct aa_dfa *dfa;
|
|
struct {
|
|
struct aa_perms *perms;
|
|
@@ -89,13 +91,36 @@ struct aa_policydb {
|
|
aa_state_t start[AA_CLASS_LAST + 1];
|
|
};
|
|
|
|
-static inline void aa_destroy_policydb(struct aa_policydb *policy)
|
|
+extern struct aa_policydb *nullpdb;
|
|
+
|
|
+struct aa_policydb *aa_alloc_pdb(gfp_t gfp);
|
|
+void aa_pdb_free_kref(struct kref *kref);
|
|
+
|
|
+/**
|
|
+ * aa_get_pdb - increment refcount on @pdb
|
|
+ * @pdb: policydb (MAYBE NULL)
|
|
+ *
|
|
+ * Returns: pointer to @pdb if @pdb is NULL will return NULL
|
|
+ * Requires: @pdb must be held with valid refcount when called
|
|
+ */
|
|
+static inline struct aa_policydb *aa_get_pdb(struct aa_policydb *pdb)
|
|
{
|
|
- aa_put_dfa(policy->dfa);
|
|
- if (policy->perms)
|
|
- kvfree(policy->perms);
|
|
- aa_free_str_table(&policy->trans);
|
|
+ if (pdb)
|
|
+ kref_get(&(pdb->count));
|
|
|
|
+ return pdb;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * aa_put_pdb - put a pdb refcount
|
|
+ * @pdb: pdb to put refcount (MAYBE NULL)
|
|
+ *
|
|
+ * Requires: if @pdb != NULL that a valid refcount be held
|
|
+ */
|
|
+static inline void aa_put_pdb(struct aa_policydb *pdb)
|
|
+{
|
|
+ if (pdb)
|
|
+ kref_put(&pdb->count, aa_pdb_free_kref);
|
|
}
|
|
|
|
static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
|
|
@@ -139,8 +164,8 @@ struct aa_ruleset {
|
|
int size;
|
|
|
|
/* TODO: merge policy and file */
|
|
- struct aa_policydb policy;
|
|
- struct aa_policydb file;
|
|
+ struct aa_policydb *policy;
|
|
+ struct aa_policydb *file;
|
|
struct aa_caps caps;
|
|
|
|
struct aa_rlimit rlimits;
|
|
@@ -159,7 +184,7 @@ struct aa_ruleset {
|
|
*/
|
|
struct aa_attachment {
|
|
const char *xmatch_str;
|
|
- struct aa_policydb xmatch;
|
|
+ struct aa_policydb *xmatch;
|
|
unsigned int xmatch_len;
|
|
int xattr_count;
|
|
char **xattrs;
|
|
@@ -276,10 +301,10 @@ static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
|
|
unsigned char class)
|
|
{
|
|
if (class <= AA_CLASS_LAST)
|
|
- return rules->policy.start[class];
|
|
+ return rules->policy->start[class];
|
|
else
|
|
- return aa_dfa_match_len(rules->policy.dfa,
|
|
- rules->policy.start[0], &class, 1);
|
|
+ return aa_dfa_match_len(rules->policy->dfa,
|
|
+ rules->policy->start[0], &class, 1);
|
|
}
|
|
|
|
static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
|
|
@@ -289,7 +314,7 @@ static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
|
|
|
|
if (!state)
|
|
return DFA_NOMATCH;
|
|
- return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2);
|
|
+ return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2);
|
|
}
|
|
|
|
static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
|
|
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
|
|
index c0d0dbd7b4c4b3..0cdf4340b02d5b 100644
|
|
--- a/security/apparmor/ipc.c
|
|
+++ b/security/apparmor/ipc.c
|
|
@@ -92,8 +92,8 @@ static int profile_signal_perm(const struct cred *cred,
|
|
ad->subj_cred = cred;
|
|
ad->peer = peer;
|
|
/* TODO: secondary cache check <profile, profile, perm> */
|
|
- state = aa_dfa_next(rules->policy.dfa,
|
|
- rules->policy.start[AA_CLASS_SIGNAL],
|
|
+ state = aa_dfa_next(rules->policy->dfa,
|
|
+ rules->policy->start[AA_CLASS_SIGNAL],
|
|
ad->signal);
|
|
aa_label_match(profile, rules, peer, state, false, request, &perms);
|
|
aa_apply_modes_to_perms(profile, &perms);
|
|
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
|
|
index 8a2af96f4da57b..d64c838f5d84e6 100644
|
|
--- a/security/apparmor/label.c
|
|
+++ b/security/apparmor/label.c
|
|
@@ -1269,14 +1269,14 @@ static inline aa_state_t match_component(struct aa_profile *profile,
|
|
const char *ns_name;
|
|
|
|
if (profile->ns == tp->ns)
|
|
- return aa_dfa_match(rules->policy.dfa, state, tp->base.hname);
|
|
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
|
|
|
|
/* try matching with namespace name and then profile */
|
|
ns_name = aa_ns_name(profile->ns, tp->ns, true);
|
|
- state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1);
|
|
- state = aa_dfa_match(rules->policy.dfa, state, ns_name);
|
|
- state = aa_dfa_match_len(rules->policy.dfa, state, ":", 1);
|
|
- return aa_dfa_match(rules->policy.dfa, state, tp->base.hname);
|
|
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
|
|
+ state = aa_dfa_match(rules->policy->dfa, state, ns_name);
|
|
+ state = aa_dfa_match_len(rules->policy->dfa, state, ":", 1);
|
|
+ return aa_dfa_match(rules->policy->dfa, state, tp->base.hname);
|
|
}
|
|
|
|
/**
|
|
@@ -1288,7 +1288,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
|
|
* @request: permissions to request
|
|
* @perms: perms struct to set
|
|
*
|
|
- * Returns: 0 on success else ERROR
|
|
+ * Returns: state match stopped at or DFA_NOMATCH if aborted early
|
|
*
|
|
* For the label A//&B//&C this does the perm match for A//&B//&C
|
|
* @perms should be preinitialized with allperms OR a previous permission
|
|
@@ -1315,27 +1315,23 @@ static int label_compound_match(struct aa_profile *profile,
|
|
|
|
/* no component visible */
|
|
*perms = allperms;
|
|
- return 0;
|
|
+ return state;
|
|
|
|
next:
|
|
label_for_each_cont(i, label, tp) {
|
|
if (!aa_ns_visible(profile->ns, tp->ns, subns))
|
|
continue;
|
|
- state = aa_dfa_match(rules->policy.dfa, state, "//&");
|
|
+ state = aa_dfa_match(rules->policy->dfa, state, "//&");
|
|
state = match_component(profile, rules, tp, state);
|
|
if (!state)
|
|
goto fail;
|
|
}
|
|
- *perms = *aa_lookup_perms(&rules->policy, state);
|
|
- aa_apply_modes_to_perms(profile, perms);
|
|
- if ((perms->allow & request) != request)
|
|
- return -EACCES;
|
|
-
|
|
- return 0;
|
|
+ *perms = *aa_lookup_perms(rules->policy, state);
|
|
+ return state;
|
|
|
|
fail:
|
|
*perms = nullperms;
|
|
- return state;
|
|
+ return DFA_NOMATCH;
|
|
}
|
|
|
|
/**
|
|
@@ -1348,7 +1344,7 @@ fail:
|
|
* @request: permissions to request
|
|
* @perms: an initialized perms struct to add accumulation to
|
|
*
|
|
- * Returns: 0 on success else ERROR
|
|
+ * Returns: the state the match finished in, may be the none matching state
|
|
*
|
|
* For the label A//&B//&C this does the perm match for each of A and B and C
|
|
* @perms should be preinitialized with allperms OR a previous permission
|
|
@@ -1376,11 +1372,10 @@ static int label_components_match(struct aa_profile *profile,
|
|
}
|
|
|
|
/* no subcomponents visible - no change in perms */
|
|
- return 0;
|
|
+ return state;
|
|
|
|
next:
|
|
- tmp = *aa_lookup_perms(&rules->policy, state);
|
|
- aa_apply_modes_to_perms(profile, &tmp);
|
|
+ tmp = *aa_lookup_perms(rules->policy, state);
|
|
aa_perms_accum(perms, &tmp);
|
|
label_for_each_cont(i, label, tp) {
|
|
if (!aa_ns_visible(profile->ns, tp->ns, subns))
|
|
@@ -1388,19 +1383,18 @@ next:
|
|
state = match_component(profile, rules, tp, start);
|
|
if (!state)
|
|
goto fail;
|
|
- tmp = *aa_lookup_perms(&rules->policy, state);
|
|
- aa_apply_modes_to_perms(profile, &tmp);
|
|
+ tmp = *aa_lookup_perms(rules->policy, state);
|
|
aa_perms_accum(perms, &tmp);
|
|
}
|
|
|
|
if ((perms->allow & request) != request)
|
|
- return -EACCES;
|
|
+ return DFA_NOMATCH;
|
|
|
|
- return 0;
|
|
+ return state;
|
|
|
|
fail:
|
|
*perms = nullperms;
|
|
- return -EACCES;
|
|
+ return DFA_NOMATCH;
|
|
}
|
|
|
|
/**
|
|
@@ -1419,11 +1413,12 @@ int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
|
|
struct aa_label *label, aa_state_t state, bool subns,
|
|
u32 request, struct aa_perms *perms)
|
|
{
|
|
- int error = label_compound_match(profile, rules, label, state, subns,
|
|
- request, perms);
|
|
- if (!error)
|
|
- return error;
|
|
+ aa_state_t tmp = label_compound_match(profile, rules, label, state, subns,
|
|
+ request, perms);
|
|
+ if ((perms->allow & request) == request)
|
|
+ return tmp;
|
|
|
|
+ /* failed compound_match try component matches */
|
|
*perms = allperms;
|
|
return label_components_match(profile, rules, label, state, subns,
|
|
request, perms);
|
|
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
|
|
index 7182a8b821fbdb..cd569fbbfe36d2 100644
|
|
--- a/security/apparmor/lib.c
|
|
+++ b/security/apparmor/lib.c
|
|
@@ -342,8 +342,8 @@ void aa_profile_match_label(struct aa_profile *profile,
|
|
/* TODO: doesn't yet handle extended types */
|
|
aa_state_t state;
|
|
|
|
- state = aa_dfa_next(rules->policy.dfa,
|
|
- rules->policy.start[AA_CLASS_LABEL],
|
|
+ state = aa_dfa_next(rules->policy->dfa,
|
|
+ rules->policy->start[AA_CLASS_LABEL],
|
|
type);
|
|
aa_label_match(profile, rules, label, state, false, request, perms);
|
|
}
|
|
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
|
index 5303a51eff9c10..641f6510d7cb0d 100644
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -1909,6 +1909,69 @@ static int __init apparmor_nf_ip_init(void)
|
|
__initcall(apparmor_nf_ip_init);
|
|
#endif
|
|
|
|
+static char nulldfa_src[] = {
|
|
+ #include "nulldfa.in"
|
|
+};
|
|
+struct aa_dfa *nulldfa;
|
|
+
|
|
+static char stacksplitdfa_src[] = {
|
|
+ #include "stacksplitdfa.in"
|
|
+};
|
|
+struct aa_dfa *stacksplitdfa;
|
|
+struct aa_policydb *nullpdb;
|
|
+
|
|
+static int __init aa_setup_dfa_engine(void)
|
|
+{
|
|
+ int error = -ENOMEM;
|
|
+
|
|
+ nullpdb = aa_alloc_pdb(GFP_KERNEL);
|
|
+ if (!nullpdb)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
|
|
+ TO_ACCEPT1_FLAG(YYTD_DATA32) |
|
|
+ TO_ACCEPT2_FLAG(YYTD_DATA32));
|
|
+ if (IS_ERR(nulldfa)) {
|
|
+ error = PTR_ERR(nulldfa);
|
|
+ goto fail;
|
|
+ }
|
|
+ nullpdb->dfa = aa_get_dfa(nulldfa);
|
|
+ nullpdb->perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
|
|
+ if (!nullpdb->perms)
|
|
+ goto fail;
|
|
+ nullpdb->size = 2;
|
|
+
|
|
+ stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
|
|
+ sizeof(stacksplitdfa_src),
|
|
+ TO_ACCEPT1_FLAG(YYTD_DATA32) |
|
|
+ TO_ACCEPT2_FLAG(YYTD_DATA32));
|
|
+ if (IS_ERR(stacksplitdfa)) {
|
|
+ error = PTR_ERR(stacksplitdfa);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ aa_put_pdb(nullpdb);
|
|
+ aa_put_dfa(nulldfa);
|
|
+ nullpdb = NULL;
|
|
+ nulldfa = NULL;
|
|
+ stacksplitdfa = NULL;
|
|
+
|
|
+ return error;
|
|
+}
|
|
+
|
|
+static void __init aa_teardown_dfa_engine(void)
|
|
+{
|
|
+ aa_put_dfa(stacksplitdfa);
|
|
+ aa_put_dfa(nulldfa);
|
|
+ aa_put_pdb(nullpdb);
|
|
+ nullpdb = NULL;
|
|
+ stacksplitdfa = NULL;
|
|
+ nulldfa = NULL;
|
|
+}
|
|
+
|
|
static int __init apparmor_init(void)
|
|
{
|
|
int error;
|
|
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
|
|
index 3667b79e9366b0..6f6cdb86f32b5d 100644
|
|
--- a/security/apparmor/match.c
|
|
+++ b/security/apparmor/match.c
|
|
@@ -21,50 +21,6 @@
|
|
|
|
#define base_idx(X) ((X) & 0xffffff)
|
|
|
|
-static char nulldfa_src[] = {
|
|
- #include "nulldfa.in"
|
|
-};
|
|
-struct aa_dfa *nulldfa;
|
|
-
|
|
-static char stacksplitdfa_src[] = {
|
|
- #include "stacksplitdfa.in"
|
|
-};
|
|
-struct aa_dfa *stacksplitdfa;
|
|
-
|
|
-int __init aa_setup_dfa_engine(void)
|
|
-{
|
|
- int error;
|
|
-
|
|
- nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
|
|
- TO_ACCEPT1_FLAG(YYTD_DATA32) |
|
|
- TO_ACCEPT2_FLAG(YYTD_DATA32));
|
|
- if (IS_ERR(nulldfa)) {
|
|
- error = PTR_ERR(nulldfa);
|
|
- nulldfa = NULL;
|
|
- return error;
|
|
- }
|
|
-
|
|
- stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
|
|
- sizeof(stacksplitdfa_src),
|
|
- TO_ACCEPT1_FLAG(YYTD_DATA32) |
|
|
- TO_ACCEPT2_FLAG(YYTD_DATA32));
|
|
- if (IS_ERR(stacksplitdfa)) {
|
|
- aa_put_dfa(nulldfa);
|
|
- nulldfa = NULL;
|
|
- error = PTR_ERR(stacksplitdfa);
|
|
- stacksplitdfa = NULL;
|
|
- return error;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-void __init aa_teardown_dfa_engine(void)
|
|
-{
|
|
- aa_put_dfa(stacksplitdfa);
|
|
- aa_put_dfa(nulldfa);
|
|
-}
|
|
-
|
|
/**
|
|
* unpack_table - unpack a dfa table (one of accept, default, base, next check)
|
|
* @blob: data to unpack (NOT NULL)
|
|
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
|
|
index cb0fdbdb82d944..49fe8da6fea459 100644
|
|
--- a/security/apparmor/mount.c
|
|
+++ b/security/apparmor/mount.c
|
|
@@ -332,8 +332,8 @@ static int match_mnt_path_str(const struct cred *subj_cred,
|
|
}
|
|
|
|
error = -EACCES;
|
|
- pos = do_match_mnt(&rules->policy,
|
|
- rules->policy.start[AA_CLASS_MOUNT],
|
|
+ pos = do_match_mnt(rules->policy,
|
|
+ rules->policy->start[AA_CLASS_MOUNT],
|
|
mntpnt, devname, type, flags, data, binary, &perms);
|
|
if (pos) {
|
|
info = mnt_info_table[pos];
|
|
@@ -620,10 +620,10 @@ static int profile_umount(const struct cred *subj_cred,
|
|
if (error)
|
|
goto audit;
|
|
|
|
- state = aa_dfa_match(rules->policy.dfa,
|
|
- rules->policy.start[AA_CLASS_MOUNT],
|
|
+ state = aa_dfa_match(rules->policy->dfa,
|
|
+ rules->policy->start[AA_CLASS_MOUNT],
|
|
name);
|
|
- perms = *aa_lookup_perms(&rules->policy, state);
|
|
+ perms = *aa_lookup_perms(rules->policy, state);
|
|
if (AA_MAY_UMOUNT & ~perms.allow)
|
|
error = -EACCES;
|
|
|
|
@@ -694,12 +694,12 @@ static struct aa_label *build_pivotroot(const struct cred *subj_cred,
|
|
goto audit;
|
|
|
|
error = -EACCES;
|
|
- state = aa_dfa_match(rules->policy.dfa,
|
|
- rules->policy.start[AA_CLASS_MOUNT],
|
|
+ state = aa_dfa_match(rules->policy->dfa,
|
|
+ rules->policy->start[AA_CLASS_MOUNT],
|
|
new_name);
|
|
- state = aa_dfa_null_transition(rules->policy.dfa, state);
|
|
- state = aa_dfa_match(rules->policy.dfa, state, old_name);
|
|
- perms = *aa_lookup_perms(&rules->policy, state);
|
|
+ state = aa_dfa_null_transition(rules->policy->dfa, state);
|
|
+ state = aa_dfa_match(rules->policy->dfa, state, old_name);
|
|
+ perms = *aa_lookup_perms(rules->policy, state);
|
|
|
|
if (AA_MAY_PIVOTROOT & perms.allow)
|
|
error = 0;
|
|
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
|
index 704c171232ab46..3e632700d06fb3 100644
|
|
--- a/security/apparmor/net.c
|
|
+++ b/security/apparmor/net.c
|
|
@@ -127,9 +127,9 @@ int aa_profile_af_perm(struct aa_profile *profile,
|
|
|
|
buffer[0] = cpu_to_be16(family);
|
|
buffer[1] = cpu_to_be16((u16) type);
|
|
- state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer,
|
|
+ state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer,
|
|
4);
|
|
- perms = *aa_lookup_perms(&rules->policy, state);
|
|
+ perms = *aa_lookup_perms(rules->policy, state);
|
|
aa_apply_modes_to_perms(profile, &perms);
|
|
|
|
return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
|
|
@@ -190,8 +190,10 @@ int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
|
|
const char *op, u32 request, struct socket *sock)
|
|
{
|
|
AA_BUG(!label);
|
|
- AA_BUG(!sock);
|
|
- AA_BUG(!sock->sk);
|
|
+
|
|
+ /* sock && sock->sk can be NULL for sockets being set up or torn down */
|
|
+ if (!sock || !sock->sk)
|
|
+ return 0;
|
|
|
|
return aa_label_sk_perm(subj_cred, label, op, request, sock->sk);
|
|
}
|
|
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
|
index d9d3b3d776e11b..009fa7cfb6688a 100644
|
|
--- a/security/apparmor/policy.c
|
|
+++ b/security/apparmor/policy.c
|
|
@@ -98,6 +98,41 @@ const char *const aa_profile_mode_names[] = {
|
|
};
|
|
|
|
|
|
+static void aa_free_pdb(struct aa_policydb *policy)
|
|
+{
|
|
+ if (policy) {
|
|
+ aa_put_dfa(policy->dfa);
|
|
+ if (policy->perms)
|
|
+ kvfree(policy->perms);
|
|
+ aa_free_str_table(&policy->trans);
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * aa_pdb_free_kref - free aa_policydb by kref (called by aa_put_pdb)
|
|
+ * @kr: kref callback for freeing of a dfa (NOT NULL)
|
|
+ */
|
|
+void aa_pdb_free_kref(struct kref *kref)
|
|
+{
|
|
+ struct aa_policydb *pdb = container_of(kref, struct aa_policydb, count);
|
|
+
|
|
+ aa_free_pdb(pdb);
|
|
+}
|
|
+
|
|
+
|
|
+struct aa_policydb *aa_alloc_pdb(gfp_t gfp)
|
|
+{
|
|
+ struct aa_policydb *pdb = kzalloc(sizeof(struct aa_policydb), gfp);
|
|
+
|
|
+ if (!pdb)
|
|
+ return NULL;
|
|
+
|
|
+ kref_init(&pdb->count);
|
|
+
|
|
+ return pdb;
|
|
+}
|
|
+
|
|
+
|
|
/**
|
|
* __add_profile - add a profiles to list and label tree
|
|
* @list: list to add it to (NOT NULL)
|
|
@@ -200,15 +235,15 @@ static void free_attachment(struct aa_attachment *attach)
|
|
for (i = 0; i < attach->xattr_count; i++)
|
|
kfree_sensitive(attach->xattrs[i]);
|
|
kfree_sensitive(attach->xattrs);
|
|
- aa_destroy_policydb(&attach->xmatch);
|
|
+ aa_put_pdb(attach->xmatch);
|
|
}
|
|
|
|
static void free_ruleset(struct aa_ruleset *rules)
|
|
{
|
|
int i;
|
|
|
|
- aa_destroy_policydb(&rules->file);
|
|
- aa_destroy_policydb(&rules->policy);
|
|
+ aa_put_pdb(rules->file);
|
|
+ aa_put_pdb(rules->policy);
|
|
aa_free_cap_rules(&rules->caps);
|
|
aa_free_rlimit_rules(&rules->rlimits);
|
|
|
|
@@ -590,16 +625,8 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
|
|
/* TODO: ideally we should inherit abi from parent */
|
|
profile->label.flags |= FLAG_NULL;
|
|
rules = list_first_entry(&profile->rules, typeof(*rules), list);
|
|
- rules->file.dfa = aa_get_dfa(nulldfa);
|
|
- rules->file.perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
|
|
- if (!rules->file.perms)
|
|
- goto fail;
|
|
- rules->file.size = 2;
|
|
- rules->policy.dfa = aa_get_dfa(nulldfa);
|
|
- rules->policy.perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
|
|
- if (!rules->policy.perms)
|
|
- goto fail;
|
|
- rules->policy.size = 2;
|
|
+ rules->file = aa_get_pdb(nullpdb);
|
|
+ rules->policy = aa_get_pdb(nullpdb);
|
|
|
|
if (parent) {
|
|
profile->path_flags = parent->path_flags;
|
|
@@ -610,11 +637,6 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
|
|
}
|
|
|
|
return profile;
|
|
-
|
|
-fail:
|
|
- aa_free_profile(profile);
|
|
-
|
|
- return NULL;
|
|
}
|
|
|
|
/**
|
|
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
|
index d752bfa9b3f37e..9b25624285e676 100644
|
|
--- a/security/apparmor/policy_unpack.c
|
|
+++ b/security/apparmor/policy_unpack.c
|
|
@@ -683,8 +683,10 @@ static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
|
|
if (!aa_unpack_array(e, NULL, &size))
|
|
goto fail_reset;
|
|
*perms = kcalloc(size, sizeof(struct aa_perms), GFP_KERNEL);
|
|
- if (!*perms)
|
|
- goto fail_reset;
|
|
+ if (!*perms) {
|
|
+ e->pos = pos;
|
|
+ return -ENOMEM;
|
|
+ }
|
|
for (i = 0; i < size; i++) {
|
|
if (!unpack_perm(e, version, &(*perms)[i]))
|
|
goto fail;
|
|
@@ -705,24 +707,29 @@ fail_reset:
|
|
return -EPROTO;
|
|
}
|
|
|
|
-static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
|
|
+static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
|
bool required_dfa, bool required_trans,
|
|
const char **info)
|
|
{
|
|
+ struct aa_policydb *pdb;
|
|
void *pos = e->pos;
|
|
int i, flags, error = -EPROTO;
|
|
ssize_t size;
|
|
|
|
- size = unpack_perms_table(e, &policy->perms);
|
|
+ pdb = aa_alloc_pdb(GFP_KERNEL);
|
|
+ if (!pdb)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ size = unpack_perms_table(e, &pdb->perms);
|
|
if (size < 0) {
|
|
error = size;
|
|
- policy->perms = NULL;
|
|
+ pdb->perms = NULL;
|
|
*info = "failed to unpack - perms";
|
|
goto fail;
|
|
}
|
|
- policy->size = size;
|
|
+ pdb->size = size;
|
|
|
|
- if (policy->perms) {
|
|
+ if (pdb->perms) {
|
|
/* perms table present accept is index */
|
|
flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
|
|
} else {
|
|
@@ -731,13 +738,13 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
|
|
TO_ACCEPT2_FLAG(YYTD_DATA32);
|
|
}
|
|
|
|
- policy->dfa = unpack_dfa(e, flags);
|
|
- if (IS_ERR(policy->dfa)) {
|
|
- error = PTR_ERR(policy->dfa);
|
|
- policy->dfa = NULL;
|
|
+ pdb->dfa = unpack_dfa(e, flags);
|
|
+ if (IS_ERR(pdb->dfa)) {
|
|
+ error = PTR_ERR(pdb->dfa);
|
|
+ pdb->dfa = NULL;
|
|
*info = "failed to unpack - dfa";
|
|
goto fail;
|
|
- } else if (!policy->dfa) {
|
|
+ } else if (!pdb->dfa) {
|
|
if (required_dfa) {
|
|
*info = "missing required dfa";
|
|
goto fail;
|
|
@@ -751,18 +758,18 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
|
|
* sadly start was given different names for file and policydb
|
|
* but since it is optional we can try both
|
|
*/
|
|
- if (!aa_unpack_u32(e, &policy->start[0], "start"))
|
|
+ if (!aa_unpack_u32(e, &pdb->start[0], "start"))
|
|
/* default start state */
|
|
- policy->start[0] = DFA_START;
|
|
- if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
|
|
+ pdb->start[0] = DFA_START;
|
|
+ if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) {
|
|
/* default start state for xmatch and file dfa */
|
|
- policy->start[AA_CLASS_FILE] = DFA_START;
|
|
+ pdb->start[AA_CLASS_FILE] = DFA_START;
|
|
} /* setup class index */
|
|
for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
|
|
- policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0],
|
|
+ pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0],
|
|
i);
|
|
}
|
|
- if (!unpack_trans_table(e, &policy->trans) && required_trans) {
|
|
+ if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
|
|
*info = "failed to unpack profile transition table";
|
|
goto fail;
|
|
}
|
|
@@ -770,9 +777,11 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
|
|
/* TODO: move compat mapping here, requires dfa merging first */
|
|
/* TODO: move verify here, it has to be done after compat mappings */
|
|
out:
|
|
+ *policy = pdb;
|
|
return 0;
|
|
|
|
fail:
|
|
+ aa_put_pdb(pdb);
|
|
e->pos = pos;
|
|
return error;
|
|
}
|
|
@@ -860,15 +869,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
|
}
|
|
|
|
/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
|
|
- if (profile->attach.xmatch.dfa) {
|
|
+ if (profile->attach.xmatch->dfa) {
|
|
if (!aa_unpack_u32(e, &tmp, NULL)) {
|
|
info = "missing xmatch len";
|
|
goto fail;
|
|
}
|
|
profile->attach.xmatch_len = tmp;
|
|
- profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START;
|
|
- if (!profile->attach.xmatch.perms) {
|
|
- error = aa_compat_map_xmatch(&profile->attach.xmatch);
|
|
+ profile->attach.xmatch->start[AA_CLASS_XMATCH] = DFA_START;
|
|
+ if (!profile->attach.xmatch->perms) {
|
|
+ error = aa_compat_map_xmatch(profile->attach.xmatch);
|
|
if (error) {
|
|
info = "failed to convert xmatch permission table";
|
|
goto fail;
|
|
@@ -985,16 +994,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
|
if (error)
|
|
goto fail;
|
|
/* Fixup: drop when we get rid of start array */
|
|
- if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0],
|
|
+ if (aa_dfa_next(rules->policy->dfa, rules->policy->start[0],
|
|
AA_CLASS_FILE))
|
|
- rules->policy.start[AA_CLASS_FILE] =
|
|
- aa_dfa_next(rules->policy.dfa,
|
|
- rules->policy.start[0],
|
|
+ rules->policy->start[AA_CLASS_FILE] =
|
|
+ aa_dfa_next(rules->policy->dfa,
|
|
+ rules->policy->start[0],
|
|
AA_CLASS_FILE);
|
|
if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
|
|
goto fail;
|
|
- if (!rules->policy.perms) {
|
|
- error = aa_compat_map_policy(&rules->policy,
|
|
+ if (!rules->policy->perms) {
|
|
+ error = aa_compat_map_policy(rules->policy,
|
|
e->version);
|
|
if (error) {
|
|
info = "failed to remap policydb permission table";
|
|
@@ -1002,44 +1011,25 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
|
}
|
|
}
|
|
} else {
|
|
- rules->policy.dfa = aa_get_dfa(nulldfa);
|
|
- rules->policy.perms = kcalloc(2, sizeof(struct aa_perms),
|
|
- GFP_KERNEL);
|
|
- if (!rules->policy.perms)
|
|
- goto fail;
|
|
- rules->policy.size = 2;
|
|
+ rules->policy = aa_get_pdb(nullpdb);
|
|
}
|
|
/* get file rules */
|
|
error = unpack_pdb(e, &rules->file, false, true, &info);
|
|
if (error) {
|
|
goto fail;
|
|
- } else if (rules->file.dfa) {
|
|
- if (!rules->file.perms) {
|
|
- error = aa_compat_map_file(&rules->file);
|
|
+ } else if (rules->file->dfa) {
|
|
+ if (!rules->file->perms) {
|
|
+ error = aa_compat_map_file(rules->file);
|
|
if (error) {
|
|
info = "failed to remap file permission table";
|
|
goto fail;
|
|
}
|
|
}
|
|
- } else if (rules->policy.dfa &&
|
|
- rules->policy.start[AA_CLASS_FILE]) {
|
|
- rules->file.dfa = aa_get_dfa(rules->policy.dfa);
|
|
- rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE];
|
|
- rules->file.perms = kcalloc(rules->policy.size,
|
|
- sizeof(struct aa_perms),
|
|
- GFP_KERNEL);
|
|
- if (!rules->file.perms)
|
|
- goto fail;
|
|
- memcpy(rules->file.perms, rules->policy.perms,
|
|
- rules->policy.size * sizeof(struct aa_perms));
|
|
- rules->file.size = rules->policy.size;
|
|
+ } else if (rules->policy->dfa &&
|
|
+ rules->policy->start[AA_CLASS_FILE]) {
|
|
+ rules->file = aa_get_pdb(rules->policy);
|
|
} else {
|
|
- rules->file.dfa = aa_get_dfa(nulldfa);
|
|
- rules->file.perms = kcalloc(2, sizeof(struct aa_perms),
|
|
- GFP_KERNEL);
|
|
- if (!rules->file.perms)
|
|
- goto fail;
|
|
- rules->file.size = 2;
|
|
+ rules->file = aa_get_pdb(nullpdb);
|
|
}
|
|
error = -EPROTO;
|
|
if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
|
|
@@ -1247,26 +1237,32 @@ static int verify_profile(struct aa_profile *profile)
|
|
if (!rules)
|
|
return 0;
|
|
|
|
- if ((rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa,
|
|
- rules->file.size)) ||
|
|
- (rules->policy.dfa &&
|
|
- !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size))) {
|
|
+ if (rules->file->dfa && !verify_dfa_accept_index(rules->file->dfa,
|
|
+ rules->file->size)) {
|
|
+ audit_iface(profile, NULL, NULL,
|
|
+ "Unpack: file Invalid named transition", NULL,
|
|
+ -EPROTO);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+ if (rules->policy->dfa &&
|
|
+ !verify_dfa_accept_index(rules->policy->dfa, rules->policy->size)) {
|
|
audit_iface(profile, NULL, NULL,
|
|
- "Unpack: Invalid named transition", NULL, -EPROTO);
|
|
+ "Unpack: policy Invalid named transition", NULL,
|
|
+ -EPROTO);
|
|
return -EPROTO;
|
|
}
|
|
|
|
- if (!verify_perms(&rules->file)) {
|
|
+ if (!verify_perms(rules->file)) {
|
|
audit_iface(profile, NULL, NULL,
|
|
"Unpack: Invalid perm index", NULL, -EPROTO);
|
|
return -EPROTO;
|
|
}
|
|
- if (!verify_perms(&rules->policy)) {
|
|
+ if (!verify_perms(rules->policy)) {
|
|
audit_iface(profile, NULL, NULL,
|
|
"Unpack: Invalid perm index", NULL, -EPROTO);
|
|
return -EPROTO;
|
|
}
|
|
- if (!verify_perms(&profile->attach.xmatch)) {
|
|
+ if (!verify_perms(profile->attach.xmatch)) {
|
|
audit_iface(profile, NULL, NULL,
|
|
"Unpack: Invalid perm index", NULL, -EPROTO);
|
|
return -EPROTO;
|
|
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
|
|
index dcc94c3153d511..a7eee815f12156 100644
|
|
--- a/security/apparmor/resource.c
|
|
+++ b/security/apparmor/resource.c
|
|
@@ -201,6 +201,11 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
|
|
rules->rlimits.limits[j].rlim_max);
|
|
/* soft limit should not exceed hard limit */
|
|
rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
|
|
+ if (j == RLIMIT_CPU &&
|
|
+ rlim->rlim_cur != RLIM_INFINITY &&
|
|
+ IS_ENABLED(CONFIG_POSIX_TIMERS))
|
|
+ (void) update_rlimit_cpu(current->group_leader,
|
|
+ rlim->rlim_cur);
|
|
}
|
|
}
|
|
}
|
|
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
|
|
index 1e35c9f807b2b6..109ad155ffc2a6 100644
|
|
--- a/security/smack/smackfs.c
|
|
+++ b/security/smack/smackfs.c
|
|
@@ -68,6 +68,7 @@ enum smk_inos {
|
|
static DEFINE_MUTEX(smack_cipso_lock);
|
|
static DEFINE_MUTEX(smack_ambient_lock);
|
|
static DEFINE_MUTEX(smk_net4addr_lock);
|
|
+static DEFINE_MUTEX(smk_cipso_doi_lock);
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
static DEFINE_MUTEX(smk_net6addr_lock);
|
|
#endif /* CONFIG_IPV6 */
|
|
@@ -139,7 +140,7 @@ struct smack_parsed_rule {
|
|
int smk_access2;
|
|
};
|
|
|
|
-static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
|
+static u32 smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN;
|
|
|
|
/*
|
|
* Values for parsing cipso rules
|
|
@@ -679,43 +680,60 @@ static const struct file_operations smk_load_ops = {
|
|
};
|
|
|
|
/**
|
|
- * smk_cipso_doi - initialize the CIPSO domain
|
|
+ * smk_cipso_doi - set netlabel maps
|
|
+ * @ndoi: new value for our CIPSO DOI
|
|
+ * @gfp_flags: kmalloc allocation context
|
|
*/
|
|
-static void smk_cipso_doi(void)
|
|
+static int
|
|
+smk_cipso_doi(u32 ndoi, gfp_t gfp_flags)
|
|
{
|
|
- int rc;
|
|
+ int rc = 0;
|
|
struct cipso_v4_doi *doip;
|
|
struct netlbl_audit nai;
|
|
|
|
- smk_netlabel_audit_set(&nai);
|
|
+ mutex_lock(&smk_cipso_doi_lock);
|
|
|
|
- rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
|
|
- if (rc != 0)
|
|
- printk(KERN_WARNING "%s:%d remove rc = %d\n",
|
|
- __func__, __LINE__, rc);
|
|
+ if (smk_cipso_doi_value == ndoi)
|
|
+ goto clr_doi_lock;
|
|
+
|
|
+ smk_netlabel_audit_set(&nai);
|
|
|
|
- doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL | __GFP_NOFAIL);
|
|
+ doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags);
|
|
+ if (!doip) {
|
|
+ rc = -ENOMEM;
|
|
+ goto clr_doi_lock;
|
|
+ }
|
|
doip->map.std = NULL;
|
|
- doip->doi = smk_cipso_doi_value;
|
|
+ doip->doi = ndoi;
|
|
doip->type = CIPSO_V4_MAP_PASS;
|
|
doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
|
|
for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
|
|
doip->tags[rc] = CIPSO_V4_TAG_INVALID;
|
|
|
|
rc = netlbl_cfg_cipsov4_add(doip, &nai);
|
|
- if (rc != 0) {
|
|
- printk(KERN_WARNING "%s:%d cipso add rc = %d\n",
|
|
- __func__, __LINE__, rc);
|
|
+ if (rc) {
|
|
kfree(doip);
|
|
- return;
|
|
+ goto clr_doi_lock;
|
|
}
|
|
- rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai);
|
|
- if (rc != 0) {
|
|
- printk(KERN_WARNING "%s:%d map add rc = %d\n",
|
|
- __func__, __LINE__, rc);
|
|
- netlbl_cfg_cipsov4_del(doip->doi, &nai);
|
|
- return;
|
|
+
|
|
+ if (smk_cipso_doi_value != CIPSO_V4_DOI_UNKNOWN) {
|
|
+ rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
|
|
+ if (rc && rc != -ENOENT)
|
|
+ goto clr_ndoi_def;
|
|
+
|
|
+ netlbl_cfg_cipsov4_del(smk_cipso_doi_value, &nai);
|
|
}
|
|
+
|
|
+ rc = netlbl_cfg_cipsov4_map_add(ndoi, NULL, NULL, NULL, &nai);
|
|
+ if (rc) {
|
|
+ smk_cipso_doi_value = CIPSO_V4_DOI_UNKNOWN; // no default map
|
|
+clr_ndoi_def: netlbl_cfg_cipsov4_del(ndoi, &nai);
|
|
+ } else
|
|
+ smk_cipso_doi_value = ndoi;
|
|
+
|
|
+clr_doi_lock:
|
|
+ mutex_unlock(&smk_cipso_doi_lock);
|
|
+ return rc;
|
|
}
|
|
|
|
/**
|
|
@@ -1580,7 +1598,7 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf,
|
|
if (*ppos != 0)
|
|
return 0;
|
|
|
|
- sprintf(temp, "%d", smk_cipso_doi_value);
|
|
+ sprintf(temp, "%lu", (unsigned long)smk_cipso_doi_value);
|
|
rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
|
|
|
|
return rc;
|
|
@@ -1599,7 +1617,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
char temp[80];
|
|
- int i;
|
|
+ unsigned long u;
|
|
|
|
if (!smack_privileged(CAP_MAC_ADMIN))
|
|
return -EPERM;
|
|
@@ -1612,14 +1630,13 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf,
|
|
|
|
temp[count] = '\0';
|
|
|
|
- if (sscanf(temp, "%d", &i) != 1)
|
|
+ if (kstrtoul(temp, 10, &u))
|
|
return -EINVAL;
|
|
|
|
- smk_cipso_doi_value = i;
|
|
-
|
|
- smk_cipso_doi();
|
|
+ if (u == CIPSO_V4_DOI_UNKNOWN || u > U32_MAX)
|
|
+ return -EINVAL;
|
|
|
|
- return count;
|
|
+ return smk_cipso_doi(u, GFP_KERNEL) ? : count;
|
|
}
|
|
|
|
static const struct file_operations smk_doi_ops = {
|
|
@@ -2996,6 +3013,7 @@ static int __init init_smk_fs(void)
|
|
{
|
|
int err;
|
|
int rc;
|
|
+ struct netlbl_audit nai;
|
|
|
|
if (smack_enabled == 0)
|
|
return 0;
|
|
@@ -3014,7 +3032,10 @@ static int __init init_smk_fs(void)
|
|
}
|
|
}
|
|
|
|
- smk_cipso_doi();
|
|
+ smk_netlabel_audit_set(&nai);
|
|
+ (void) netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
|
|
+ (void) smk_cipso_doi(SMACK_CIPSO_DOI_DEFAULT,
|
|
+ GFP_KERNEL | __GFP_NOFAIL);
|
|
smk_unlbl_ambient(NULL);
|
|
|
|
rc = smack_populate_secattr(&smack_known_floor);
|
|
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
|
|
index 157efd1530fbf3..fd141185ce2b99 100644
|
|
--- a/sound/pci/hda/patch_conexant.c
|
|
+++ b/sound/pci/hda/patch_conexant.c
|
|
@@ -1127,6 +1127,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
|
|
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
|
|
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
|
|
SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
|
|
+ SND_PCI_QUIRK(0x1d05, 0x3012, "MECHREVO Wujie 15X Pro", CXT_FIXUP_HEADSET_MIC),
|
|
HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER),
|
|
HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER),
|
|
{}
|
|
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
|
|
index b6068d289f5f9d..5aeacbcb1f6ad9 100644
|
|
--- a/sound/soc/amd/yc/acp6x-mach.c
|
|
+++ b/sound/soc/amd/yc/acp6x-mach.c
|
|
@@ -689,7 +689,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|
DMI_MATCH(DMI_BOARD_NAME, "XyloD5_RBU"),
|
|
}
|
|
},
|
|
-
|
|
+ {
|
|
+ .driver_data = &acp6x_card,
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
|
|
+ }
|
|
+ },
|
|
{}
|
|
};
|
|
|
|
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
|
|
index a697b5006b45b1..f2a9c33ff4a649 100644
|
|
--- a/sound/soc/codecs/aw88261.c
|
|
+++ b/sound/soc/codecs/aw88261.c
|
|
@@ -424,9 +424,10 @@ static int aw88261_dev_reg_update(struct aw88261 *aw88261,
|
|
if (ret)
|
|
break;
|
|
|
|
+ /* keep all three bits from current hw status */
|
|
read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) |
|
|
(~AW88261_HMUTE_MASK);
|
|
- reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK);
|
|
+ reg_val &= (AW88261_AMPPD_MASK & AW88261_PWDN_MASK & AW88261_HMUTE_MASK);
|
|
reg_val |= read_val;
|
|
|
|
/* enable uls hmute */
|
|
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
|
|
index 43792e175d75f1..864c6a858628d1 100644
|
|
--- a/sound/soc/codecs/es8328.c
|
|
+++ b/sound/soc/codecs/es8328.c
|
|
@@ -750,17 +750,23 @@ static int es8328_resume(struct snd_soc_component *component)
|
|
es8328->supplies);
|
|
if (ret) {
|
|
dev_err(component->dev, "unable to enable regulators\n");
|
|
- return ret;
|
|
+ goto err_clk;
|
|
}
|
|
|
|
regcache_mark_dirty(regmap);
|
|
ret = regcache_sync(regmap);
|
|
if (ret) {
|
|
dev_err(component->dev, "unable to sync regcache\n");
|
|
- return ret;
|
|
+ goto err_regulators;
|
|
}
|
|
|
|
return 0;
|
|
+
|
|
+err_regulators:
|
|
+ regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), es8328->supplies);
|
|
+err_clk:
|
|
+ clk_disable_unprepare(es8328->clk);
|
|
+ return ret;
|
|
}
|
|
|
|
static int es8328_component_probe(struct snd_soc_component *component)
|
|
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
|
|
index 5b8e78e516302e..f2a1306d042b7c 100644
|
|
--- a/sound/soc/codecs/max98390.c
|
|
+++ b/sound/soc/codecs/max98390.c
|
|
@@ -1076,6 +1076,9 @@ static int max98390_i2c_probe(struct i2c_client *i2c)
|
|
|
|
reset_gpio = devm_gpiod_get_optional(&i2c->dev,
|
|
"reset", GPIOD_OUT_HIGH);
|
|
+ if (IS_ERR(reset_gpio))
|
|
+ return dev_err_probe(&i2c->dev, PTR_ERR(reset_gpio),
|
|
+ "Failed to get reset gpio\n");
|
|
|
|
/* Power on device */
|
|
if (reset_gpio) {
|
|
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
|
|
index 48ed75c3a7db2b..3cf531258911bb 100644
|
|
--- a/sound/soc/codecs/nau8821.c
|
|
+++ b/sound/soc/codecs/nau8821.c
|
|
@@ -1067,20 +1067,24 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
|
|
snd_soc_component_disable_pin(component, "MICBIAS");
|
|
snd_soc_dapm_sync(dapm);
|
|
|
|
+ /* Disable & mask both insertion & ejection IRQs */
|
|
+ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
|
|
+ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS,
|
|
+ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS);
|
|
+ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
|
|
+ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN,
|
|
+ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN);
|
|
+
|
|
/* Clear all interruption status */
|
|
nau8821_irq_status_clear(regmap, 0);
|
|
|
|
- /* Enable the insertion interruption, disable the ejection inter-
|
|
- * ruption, and then bypass de-bounce circuit.
|
|
- */
|
|
+ /* Enable & unmask the insertion IRQ */
|
|
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
|
|
- NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS,
|
|
- NAU8821_IRQ_EJECT_DIS);
|
|
- /* Mask unneeded IRQs: 1 - disable, 0 - enable */
|
|
+ NAU8821_IRQ_INSERT_DIS, 0);
|
|
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
|
|
- NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN,
|
|
- NAU8821_IRQ_EJECT_EN);
|
|
+ NAU8821_IRQ_INSERT_EN, 0);
|
|
|
|
+ /* Bypass de-bounce circuit */
|
|
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
|
|
NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS);
|
|
|
|
@@ -1104,22 +1108,17 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
|
|
NAU8821_IRQ_KEY_RELEASE_DIS |
|
|
NAU8821_IRQ_KEY_PRESS_DIS);
|
|
}
|
|
-
|
|
}
|
|
|
|
static void nau8821_jdet_work(struct work_struct *work)
|
|
{
|
|
struct nau8821 *nau8821 =
|
|
- container_of(work, struct nau8821, jdet_work);
|
|
+ container_of(work, struct nau8821, jdet_work.work);
|
|
struct snd_soc_dapm_context *dapm = nau8821->dapm;
|
|
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
|
|
struct regmap *regmap = nau8821->regmap;
|
|
int jack_status_reg, mic_detected, event = 0, event_mask = 0;
|
|
|
|
- snd_soc_component_force_enable_pin(component, "MICBIAS");
|
|
- snd_soc_dapm_sync(dapm);
|
|
- msleep(20);
|
|
-
|
|
regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg);
|
|
mic_detected = !(jack_status_reg & NAU8821_KEYDET);
|
|
if (mic_detected) {
|
|
@@ -1149,6 +1148,7 @@ static void nau8821_jdet_work(struct work_struct *work)
|
|
snd_soc_component_disable_pin(component, "MICBIAS");
|
|
snd_soc_dapm_sync(dapm);
|
|
}
|
|
+
|
|
event_mask |= SND_JACK_HEADSET;
|
|
snd_soc_jack_report(nau8821->jack, event, event_mask);
|
|
}
|
|
@@ -1158,6 +1158,15 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
|
|
{
|
|
struct regmap *regmap = nau8821->regmap;
|
|
|
|
+ /* Disable & mask insertion IRQ */
|
|
+ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
|
|
+ NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS);
|
|
+ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
|
|
+ NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN);
|
|
+
|
|
+ /* Clear insert IRQ status */
|
|
+ nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED);
|
|
+
|
|
/* Enable internal VCO needed for interruptions */
|
|
if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE)
|
|
nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0);
|
|
@@ -1177,17 +1186,19 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
|
|
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
|
|
NAU8821_JACK_DET_DB_BYPASS, 0);
|
|
|
|
+ /* Unmask & enable the ejection IRQs */
|
|
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
|
|
- NAU8821_IRQ_EJECT_EN, 0);
|
|
+ NAU8821_IRQ_EJECT_EN, 0);
|
|
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
|
|
- NAU8821_IRQ_EJECT_DIS, 0);
|
|
+ NAU8821_IRQ_EJECT_DIS, 0);
|
|
}
|
|
|
|
static irqreturn_t nau8821_interrupt(int irq, void *data)
|
|
{
|
|
struct nau8821 *nau8821 = (struct nau8821 *)data;
|
|
struct regmap *regmap = nau8821->regmap;
|
|
- int active_irq, clear_irq = 0, event = 0, event_mask = 0;
|
|
+ struct snd_soc_component *component;
|
|
+ int active_irq, event = 0, event_mask = 0;
|
|
|
|
if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) {
|
|
dev_err(nau8821->dev, "failed to read irq status\n");
|
|
@@ -1198,49 +1209,41 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
|
|
|
|
if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) ==
|
|
NAU8821_JACK_EJECT_DETECTED) {
|
|
- cancel_work_sync(&nau8821->jdet_work);
|
|
+ cancel_delayed_work_sync(&nau8821->jdet_work);
|
|
regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
|
|
NAU8821_MICDET_MASK, NAU8821_MICDET_DIS);
|
|
nau8821_eject_jack(nau8821);
|
|
event_mask |= SND_JACK_HEADSET;
|
|
- clear_irq = NAU8821_JACK_EJECT_IRQ_MASK;
|
|
} else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) {
|
|
event |= NAU8821_BUTTON;
|
|
event_mask |= NAU8821_BUTTON;
|
|
- clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ;
|
|
+ nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ);
|
|
} else if (active_irq & NAU8821_KEY_RELEASE_IRQ) {
|
|
event_mask = NAU8821_BUTTON;
|
|
- clear_irq = NAU8821_KEY_RELEASE_IRQ;
|
|
+ nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ);
|
|
} else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
|
|
NAU8821_JACK_INSERT_DETECTED) {
|
|
- cancel_work_sync(&nau8821->jdet_work);
|
|
+ cancel_delayed_work_sync(&nau8821->jdet_work);
|
|
regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
|
|
NAU8821_MICDET_MASK, NAU8821_MICDET_EN);
|
|
if (nau8821_is_jack_inserted(regmap)) {
|
|
- /* detect microphone and jack type */
|
|
- schedule_work(&nau8821->jdet_work);
|
|
+ /* Detect microphone and jack type */
|
|
+ component = snd_soc_dapm_to_component(nau8821->dapm);
|
|
+ snd_soc_component_force_enable_pin(component, "MICBIAS");
|
|
+ snd_soc_dapm_sync(nau8821->dapm);
|
|
+ schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20));
|
|
/* Turn off insertion interruption at manual mode */
|
|
- regmap_update_bits(regmap,
|
|
- NAU8821_R12_INTERRUPT_DIS_CTRL,
|
|
- NAU8821_IRQ_INSERT_DIS,
|
|
- NAU8821_IRQ_INSERT_DIS);
|
|
- regmap_update_bits(regmap,
|
|
- NAU8821_R0F_INTERRUPT_MASK,
|
|
- NAU8821_IRQ_INSERT_EN,
|
|
- NAU8821_IRQ_INSERT_EN);
|
|
nau8821_setup_inserted_irq(nau8821);
|
|
} else {
|
|
dev_warn(nau8821->dev,
|
|
"Inserted IRQ fired but not connected\n");
|
|
nau8821_eject_jack(nau8821);
|
|
}
|
|
+ } else {
|
|
+ /* Clear the rightmost interrupt */
|
|
+ nau8821_irq_status_clear(regmap, active_irq);
|
|
}
|
|
|
|
- if (!clear_irq)
|
|
- clear_irq = active_irq;
|
|
- /* clears the rightmost interruption */
|
|
- regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq);
|
|
-
|
|
if (event_mask)
|
|
snd_soc_jack_report(nau8821->jack, event, event_mask);
|
|
|
|
@@ -1664,8 +1667,14 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component,
|
|
int ret;
|
|
|
|
nau8821->jack = jack;
|
|
+
|
|
+ if (nau8821->jdet_active)
|
|
+ return 0;
|
|
+
|
|
/* Initiate jack detection work queue */
|
|
- INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work);
|
|
+ INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work);
|
|
+ nau8821->jdet_active = true;
|
|
+
|
|
ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL,
|
|
nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
"nau8821", nau8821);
|
|
diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h
|
|
index 00a888ed07ceb9..ce0880cdd18994 100644
|
|
--- a/sound/soc/codecs/nau8821.h
|
|
+++ b/sound/soc/codecs/nau8821.h
|
|
@@ -559,7 +559,8 @@ struct nau8821 {
|
|
struct regmap *regmap;
|
|
struct snd_soc_dapm_context *dapm;
|
|
struct snd_soc_jack *jack;
|
|
- struct work_struct jdet_work;
|
|
+ struct delayed_work jdet_work;
|
|
+ bool jdet_active;
|
|
int irq;
|
|
int clk_id;
|
|
int micbias_voltage;
|
|
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
|
|
index 4f50b07848fd8f..68a5ca176d6f0b 100644
|
|
--- a/sound/soc/codecs/wm8962.c
|
|
+++ b/sound/soc/codecs/wm8962.c
|
|
@@ -67,6 +67,8 @@ struct wm8962_priv {
|
|
struct mutex dsp2_ena_lock;
|
|
u16 dsp2_ena;
|
|
|
|
+ int mic_status;
|
|
+
|
|
struct delayed_work mic_work;
|
|
struct snd_soc_jack *jack;
|
|
|
|
@@ -1759,7 +1761,7 @@ SND_SOC_BYTES("EQR Coefficients", WM8962_EQ24, 18),
|
|
|
|
|
|
SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
|
|
-SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
|
|
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA | WM8962_ADC_MONOMIX),
|
|
|
|
SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
|
|
SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
|
|
@@ -3073,8 +3075,16 @@ static void wm8962_mic_work(struct work_struct *work)
|
|
if (reg & WM8962_MICSHORT_STS) {
|
|
status |= SND_JACK_BTN_0;
|
|
irq_pol |= WM8962_MICSCD_IRQ_POL;
|
|
+
|
|
+ /* Don't report a microphone if it's shorted right after
|
|
+ * plugging in, as this may be a TRS plug in a TRRS socket.
|
|
+ */
|
|
+ if (!(wm8962->mic_status & WM8962_MICDET_STS))
|
|
+ status = 0;
|
|
}
|
|
|
|
+ wm8962->mic_status = status;
|
|
+
|
|
snd_soc_jack_report(wm8962->jack, status,
|
|
SND_JACK_MICROPHONE | SND_JACK_BTN_0);
|
|
|
|
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
|
|
index 3a5ab8b5367289..90a0a24c05d845 100644
|
|
--- a/sound/soc/fsl/fsl_xcvr.c
|
|
+++ b/sound/soc/fsl/fsl_xcvr.c
|
|
@@ -206,13 +206,10 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
|
|
|
|
xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
|
|
|
|
- down_read(&card->snd_card->controls_rwsem);
|
|
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
|
|
(xcvr->mode == FSL_XCVR_MODE_ARC));
|
|
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
|
|
(xcvr->mode == FSL_XCVR_MODE_EARC));
|
|
- up_read(&card->snd_card->controls_rwsem);
|
|
-
|
|
/* Allow playback for SPDIF only */
|
|
rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
|
|
rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
|
|
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
index 7ae93cbaea9a77..15ef6b6bec2bb7 100644
|
|
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#define DRV_NAME "rockchip-i2s-tdm"
|
|
|
|
+#define DEFAULT_MCLK_FS 256
|
|
#define CH_GRP_MAX 4 /* The max channel 8 / 2 */
|
|
#define MULTIPLEX_CH_MAX 10
|
|
|
|
@@ -695,6 +696,15 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
|
|
mclk_rate = i2s_tdm->mclk_rx_freq;
|
|
}
|
|
|
|
+ /*
|
|
+ * When the dai/component driver doesn't need to set mclk-fs for a specific
|
|
+ * clock, it can skip the call to set_sysclk() for that clock.
|
|
+ * In that case, simply use the clock rate from the params and multiply it by
|
|
+ * the default mclk-fs value.
|
|
+ */
|
|
+ if (!mclk_rate)
|
|
+ mclk_rate = DEFAULT_MCLK_FS * params_rate(params);
|
|
+
|
|
err = clk_set_rate(mclk, mclk_rate);
|
|
if (err)
|
|
return err;
|
|
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
|
|
index 84145209dec493..3835179b22b426 100644
|
|
--- a/sound/soc/sof/ipc4-control.c
|
|
+++ b/sound/soc/sof/ipc4-control.c
|
|
@@ -66,7 +66,7 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
|
|
* configuration
|
|
*/
|
|
memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
|
|
- scontrol->max_size);
|
|
+ scontrol->size);
|
|
kfree(scontrol->old_ipc_control_data);
|
|
scontrol->old_ipc_control_data = NULL;
|
|
/* Send the last known good configuration to firmware */
|
|
@@ -364,19 +364,35 @@ static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
|
|
int ret = 0;
|
|
|
|
/* Send the new data to the firmware only if it is powered up */
|
|
- if (set && !pm_runtime_active(sdev->dev))
|
|
- return 0;
|
|
+ if (set) {
|
|
+ if (!pm_runtime_active(sdev->dev))
|
|
+ return 0;
|
|
+
|
|
+ if (!data->size) {
|
|
+ dev_dbg(sdev->dev, "%s: No data to be sent.\n",
|
|
+ scontrol->name);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
|
|
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
|
|
|
|
msg->data_ptr = data->data;
|
|
- msg->data_size = data->size;
|
|
+ if (set)
|
|
+ msg->data_size = data->size;
|
|
+ else
|
|
+ msg->data_size = scontrol->max_size - sizeof(*data);
|
|
|
|
ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock);
|
|
- if (ret < 0)
|
|
+ if (ret < 0) {
|
|
dev_err(sdev->dev, "Failed to %s for %s\n",
|
|
set ? "set bytes update" : "get bytes",
|
|
scontrol->name);
|
|
+ } else if (!set) {
|
|
+ /* Update the sizes according to the received payload data */
|
|
+ data->size = msg->data_size;
|
|
+ scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size;
|
|
+ }
|
|
|
|
msg->data_ptr = NULL;
|
|
msg->data_size = 0;
|
|
@@ -392,6 +408,7 @@ static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
|
|
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
|
|
struct sof_abi_hdr *data = cdata->data;
|
|
size_t size;
|
|
+ int ret;
|
|
|
|
if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
|
|
dev_err_ratelimited(scomp->dev,
|
|
@@ -413,9 +430,12 @@ static int sof_ipc4_bytes_put(struct snd_sof_control *scontrol,
|
|
/* copy from kcontrol */
|
|
memcpy(data, ucontrol->value.bytes.data, size);
|
|
|
|
- sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
|
|
+ ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
|
|
+ if (!ret)
|
|
+ /* Update the cdata size */
|
|
+ scontrol->size = sizeof(*cdata) + size;
|
|
|
|
- return 0;
|
|
+ return ret;
|
|
}
|
|
|
|
static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
|
|
@@ -511,7 +531,7 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
|
|
if (!scontrol->old_ipc_control_data) {
|
|
/* Create a backup of the current, valid bytes control */
|
|
scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data,
|
|
- scontrol->max_size, GFP_KERNEL);
|
|
+ scontrol->size, GFP_KERNEL);
|
|
if (!scontrol->old_ipc_control_data)
|
|
return -ENOMEM;
|
|
}
|
|
@@ -519,12 +539,15 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
|
|
/* Copy the whole binary data which includes the ABI header and the payload */
|
|
if (copy_from_user(data, tlvd->tlv, header.length)) {
|
|
memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
|
|
- scontrol->max_size);
|
|
+ scontrol->size);
|
|
kfree(scontrol->old_ipc_control_data);
|
|
scontrol->old_ipc_control_data = NULL;
|
|
return -EFAULT;
|
|
}
|
|
|
|
+ /* Update the cdata size */
|
|
+ scontrol->size = sizeof(*cdata) + header.length;
|
|
+
|
|
return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true);
|
|
}
|
|
|
|
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
|
|
index c380ddf68a5898..cc17d4e74c82fe 100644
|
|
--- a/sound/soc/sof/ipc4-topology.c
|
|
+++ b/sound/soc/sof/ipc4-topology.c
|
|
@@ -2184,22 +2184,41 @@ static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
|
|
struct sof_ipc4_msg *msg;
|
|
int ret;
|
|
|
|
- if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) {
|
|
- dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n",
|
|
+ /*
|
|
+ * The max_size is coming from topology and indicates the maximum size
|
|
+ * of sof_abi_hdr plus the payload, which excludes the local only
|
|
+ * 'struct sof_ipc4_control_data'
|
|
+ */
|
|
+ if (scontrol->max_size < sizeof(struct sof_abi_hdr)) {
|
|
+ dev_err(sdev->dev,
|
|
+ "insufficient maximum size for a bytes control %s: %zu.\n",
|
|
scontrol->name, scontrol->max_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
- if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) {
|
|
- dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n",
|
|
- scontrol->name, scontrol->priv_size,
|
|
- scontrol->max_size - sizeof(*control_data));
|
|
+ if (scontrol->priv_size > scontrol->max_size) {
|
|
+ dev_err(sdev->dev,
|
|
+ "bytes control %s initial data size %zu exceeds max %zu.\n",
|
|
+ scontrol->name, scontrol->priv_size, scontrol->max_size);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (scontrol->priv_size < sizeof(struct sof_abi_hdr)) {
|
|
+ dev_err(sdev->dev,
|
|
+ "bytes control %s initial data size %zu is insufficient.\n",
|
|
+ scontrol->name, scontrol->priv_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
- scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size;
|
|
+ /*
|
|
+ * The used size behind the cdata pointer, which can be smaller than
|
|
+ * the maximum size
|
|
+ */
|
|
+ scontrol->size = sizeof(*control_data) + scontrol->priv_size;
|
|
|
|
- scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
|
|
+ /* Allocate the cdata: local struct size + maximum payload size */
|
|
+ scontrol->ipc_control_data = kzalloc(sizeof(*control_data) + scontrol->max_size,
|
|
+ GFP_KERNEL);
|
|
if (!scontrol->ipc_control_data)
|
|
return -ENOMEM;
|
|
|
|
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
|
|
index 2599683a582dcd..9071bc48357595 100644
|
|
--- a/sound/soc/sunxi/sun50i-dmic.c
|
|
+++ b/sound/soc/sunxi/sun50i-dmic.c
|
|
@@ -324,6 +324,9 @@ static int sun50i_dmic_probe(struct platform_device *pdev)
|
|
|
|
host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
|
&sun50i_dmic_regmap_config);
|
|
+ if (IS_ERR(host->regmap))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->regmap),
|
|
+ "failed to initialise regmap\n");
|
|
|
|
/* Clocks */
|
|
host->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
|
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
|
|
index 17ae74b067c5ef..1092b964167e97 100644
|
|
--- a/sound/usb/endpoint.c
|
|
+++ b/sound/usb/endpoint.c
|
|
@@ -278,8 +278,8 @@ static inline bool has_tx_length_quirk(struct snd_usb_audio *chip)
|
|
return chip->quirk_flags & QUIRK_FLAG_TX_LENGTH;
|
|
}
|
|
|
|
-static void prepare_silent_urb(struct snd_usb_endpoint *ep,
|
|
- struct snd_urb_ctx *ctx)
|
|
+static int prepare_silent_urb(struct snd_usb_endpoint *ep,
|
|
+ struct snd_urb_ctx *ctx)
|
|
{
|
|
struct urb *urb = ctx->urb;
|
|
unsigned int offs = 0;
|
|
@@ -292,28 +292,34 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
|
|
extra = sizeof(packet_length);
|
|
|
|
for (i = 0; i < ctx->packets; ++i) {
|
|
- unsigned int offset;
|
|
- unsigned int length;
|
|
- int counts;
|
|
-
|
|
- counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
|
|
- length = counts * ep->stride; /* number of silent bytes */
|
|
- offset = offs * ep->stride + extra * i;
|
|
- urb->iso_frame_desc[i].offset = offset;
|
|
+ int length;
|
|
+
|
|
+ length = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
|
|
+ if (length < 0)
|
|
+ return length;
|
|
+ length *= ep->stride; /* number of silent bytes */
|
|
+ if (offs + length + extra > ctx->buffer_size)
|
|
+ break;
|
|
+ urb->iso_frame_desc[i].offset = offs;
|
|
urb->iso_frame_desc[i].length = length + extra;
|
|
if (extra) {
|
|
packet_length = cpu_to_le32(length);
|
|
- memcpy(urb->transfer_buffer + offset,
|
|
+ memcpy(urb->transfer_buffer + offs,
|
|
&packet_length, sizeof(packet_length));
|
|
+ offs += extra;
|
|
}
|
|
- memset(urb->transfer_buffer + offset + extra,
|
|
+ memset(urb->transfer_buffer + offs,
|
|
ep->silence_value, length);
|
|
- offs += counts;
|
|
+ offs += length;
|
|
}
|
|
|
|
- urb->number_of_packets = ctx->packets;
|
|
- urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra;
|
|
+ if (!offs)
|
|
+ return -EPIPE;
|
|
+
|
|
+ urb->number_of_packets = i;
|
|
+ urb->transfer_buffer_length = offs;
|
|
ctx->queued = 0;
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -335,8 +341,7 @@ static int prepare_outbound_urb(struct snd_usb_endpoint *ep,
|
|
if (data_subs && ep->prepare_data_urb)
|
|
return ep->prepare_data_urb(data_subs, urb, in_stream_lock);
|
|
/* no data provider, so send silence */
|
|
- prepare_silent_urb(ep, ctx);
|
|
- break;
|
|
+ return prepare_silent_urb(ep, ctx);
|
|
|
|
case SND_USB_ENDPOINT_TYPE_SYNC:
|
|
if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
|
|
@@ -489,6 +494,7 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
|
|
|
|
/* copy over the length information */
|
|
if (implicit_fb) {
|
|
+ ctx->packets = packet->packets;
|
|
for (i = 0; i < packet->packets; i++)
|
|
ctx->packet_size[i] = packet->packet_size[i];
|
|
}
|
|
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
|
|
index cde5b5c165096a..ff2bbe761ee3a8 100644
|
|
--- a/sound/usb/quirks.c
|
|
+++ b/sound/usb/quirks.c
|
|
@@ -2047,6 +2047,8 @@ struct usb_audio_quirk_flags_table {
|
|
|
|
static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
/* Device matches */
|
|
+ DEVICE_FLG(0x001f, 0x0b21, /* AB13X USB Audio */
|
|
+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
|
|
DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */
|
|
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
|
|
DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */
|
|
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
|
|
index c2ca82fc21e21a..225d3678b4ed1d 100644
|
|
--- a/tools/bpf/bpftool/net.c
|
|
+++ b/tools/bpf/bpftool/net.c
|
|
@@ -150,7 +150,7 @@ static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
|
|
bool multipart = true;
|
|
struct nlmsgerr *err;
|
|
struct nlmsghdr *nh;
|
|
- char buf[4096];
|
|
+ char buf[8192];
|
|
int len, ret;
|
|
|
|
while (multipart) {
|
|
@@ -195,6 +195,9 @@ static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
|
|
return ret;
|
|
}
|
|
}
|
|
+
|
|
+ if (len)
|
|
+ p_err("Invalid message or trailing data in Netlink response: %d bytes left", len);
|
|
}
|
|
ret = 0;
|
|
done:
|
|
diff --git a/tools/include/linux/bitfield.h b/tools/include/linux/bitfield.h
|
|
index 6093fa6db2600b..ddf81f24956ba0 100644
|
|
--- a/tools/include/linux/bitfield.h
|
|
+++ b/tools/include/linux/bitfield.h
|
|
@@ -8,6 +8,7 @@
|
|
#define _LINUX_BITFIELD_H
|
|
|
|
#include <linux/build_bug.h>
|
|
+#include <linux/kernel.h>
|
|
#include <asm/byteorder.h>
|
|
|
|
/*
|
|
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
|
|
index cf4db51b99eb5d..beb91c78ca7a47 100644
|
|
--- a/tools/lib/bpf/btf_dump.c
|
|
+++ b/tools/lib/bpf/btf_dump.c
|
|
@@ -1758,9 +1758,18 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d,
|
|
__u16 left_shift_bits, right_shift_bits;
|
|
const __u8 *bytes = data;
|
|
__u8 nr_copy_bits;
|
|
+ __u8 start_bit, nr_bytes;
|
|
__u64 num = 0;
|
|
int i;
|
|
|
|
+ /* Calculate how many bytes cover the bitfield */
|
|
+ start_bit = bits_offset % 8;
|
|
+ nr_bytes = (start_bit + bit_sz + 7) / 8;
|
|
+
|
|
+ /* Bound check */
|
|
+ if (data + nr_bytes > d->typed_dump->data_end)
|
|
+ return -E2BIG;
|
|
+
|
|
/* Maximum supported bitfield size is 64 bits */
|
|
if (t->size > 8) {
|
|
pr_warn("unexpected bitfield size %d\n", t->size);
|
|
diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c
|
|
index 68a2def171751c..6f16c4f7b3a433 100644
|
|
--- a/tools/lib/bpf/netlink.c
|
|
+++ b/tools/lib/bpf/netlink.c
|
|
@@ -143,7 +143,7 @@ static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
|
struct nlmsghdr *nh;
|
|
int len, ret;
|
|
|
|
- ret = alloc_iov(&iov, 4096);
|
|
+ ret = alloc_iov(&iov, 8192);
|
|
if (ret)
|
|
goto done;
|
|
|
|
@@ -212,6 +212,8 @@ start:
|
|
}
|
|
}
|
|
}
|
|
+ if (len)
|
|
+ pr_warn("Invalid message or trailing data in Netlink response: %d bytes left\n", len);
|
|
}
|
|
ret = 0;
|
|
done:
|
|
diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile
|
|
index 3a9b2140aa048e..703a8ff0b34301 100644
|
|
--- a/tools/lib/perf/Makefile
|
|
+++ b/tools/lib/perf/Makefile
|
|
@@ -54,13 +54,6 @@ endif
|
|
|
|
TEST_ARGS := $(if $(V),-v)
|
|
|
|
-# Set compile option CFLAGS
|
|
-ifdef EXTRA_CFLAGS
|
|
- CFLAGS := $(EXTRA_CFLAGS)
|
|
-else
|
|
- CFLAGS := -g -Wall
|
|
-endif
|
|
-
|
|
INCLUDES = \
|
|
-I$(srctree)/tools/lib/perf/include \
|
|
-I$(srctree)/tools/lib/ \
|
|
@@ -70,11 +63,12 @@ INCLUDES = \
|
|
-I$(srctree)/tools/include/uapi
|
|
|
|
# Append required CFLAGS
|
|
-override CFLAGS += $(EXTRA_WARNINGS)
|
|
-override CFLAGS += -Werror -Wall
|
|
+override CFLAGS := $(INCLUDES) $(CFLAGS)
|
|
+override CFLAGS += -g -Werror -Wall
|
|
override CFLAGS += -fPIC
|
|
-override CFLAGS += $(INCLUDES)
|
|
override CFLAGS += -fvisibility=hidden
|
|
+override CFLAGS += $(EXTRA_WARNINGS)
|
|
+override CFLAGS += $(EXTRA_CFLAGS)
|
|
|
|
all:
|
|
|
|
diff --git a/tools/lib/subcmd/help.c b/tools/lib/subcmd/help.c
|
|
index ddaeb4eb3e2497..db94aa685b73b8 100644
|
|
--- a/tools/lib/subcmd/help.c
|
|
+++ b/tools/lib/subcmd/help.c
|
|
@@ -97,11 +97,13 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
|
ei++;
|
|
}
|
|
}
|
|
- if (ci != cj) {
|
|
- while (ci < cmds->cnt) {
|
|
- cmds->names[cj++] = cmds->names[ci];
|
|
- cmds->names[ci++] = NULL;
|
|
+ while (ci < cmds->cnt) {
|
|
+ if (ci != cj) {
|
|
+ cmds->names[cj] = cmds->names[ci];
|
|
+ cmds->names[ci] = NULL;
|
|
}
|
|
+ ci++;
|
|
+ cj++;
|
|
}
|
|
for (ci = cj; ci < cmds->cnt; ci++)
|
|
assert(cmds->names[ci] == NULL);
|
|
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
|
|
index 83b100c1e7f684..e9a0f89e9c39a9 100644
|
|
--- a/tools/objtool/Makefile
|
|
+++ b/tools/objtool/Makefile
|
|
@@ -7,6 +7,8 @@ srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
|
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
|
endif
|
|
|
|
+RM ?= rm -f
|
|
+
|
|
LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
|
|
ifneq ($(OUTPUT),)
|
|
LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
|
|
diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh
|
|
index 62f13dfeae8e4d..a76ccf2deb563c 100755
|
|
--- a/tools/perf/tests/shell/stat.sh
|
|
+++ b/tools/perf/tests/shell/stat.sh
|
|
@@ -18,7 +18,7 @@ test_default_stat() {
|
|
|
|
test_stat_record_report() {
|
|
echo "stat record and report test"
|
|
- if ! perf stat record -o - true | perf stat report -i - 2>&1 | \
|
|
+ if ! perf stat record -e task-clock -o - true | perf stat report -i - 2>&1 | \
|
|
grep -E -q "Performance counter stats for 'pipe':"
|
|
then
|
|
echo "stat record and report test [Failed]"
|
|
@@ -30,7 +30,7 @@ test_stat_record_report() {
|
|
|
|
test_stat_record_script() {
|
|
echo "stat record and script test"
|
|
- if ! perf stat record -o - true | perf script -i - 2>&1 | \
|
|
+ if ! perf stat record -e task-clock -o - true | perf script -i - 2>&1 | \
|
|
grep -E -q "CPU[[:space:]]+THREAD[[:space:]]+VAL[[:space:]]+ENA[[:space:]]+RUN[[:space:]]+TIME[[:space:]]+EVENT"
|
|
then
|
|
echo "stat record and script test [Failed]"
|
|
@@ -159,7 +159,7 @@ test_hybrid() {
|
|
fi
|
|
|
|
# Run default Perf stat
|
|
- cycles_events=$(perf stat -- true 2>&1 | grep -E "/cycles/[uH]*| cycles[:uH]* " -c)
|
|
+ cycles_events=$(perf stat -a -- sleep 0.1 2>&1 | grep -E "/cpu-cycles/[uH]*| cpu-cycles[:uH]* " | wc -l)
|
|
|
|
# The expectation is that default output will have a cycles events on each
|
|
# hybrid PMU. In situations with no cycles PMU events, like virtualized, this
|
|
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
|
|
index 8719b3cb564661..99310f8423967f 100644
|
|
--- a/tools/perf/util/evsel_fprintf.c
|
|
+++ b/tools/perf/util/evsel_fprintf.c
|
|
@@ -181,8 +181,12 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
|
if (print_dso && (!sym || !sym->inlined))
|
|
printed += map__fprintf_dsoname_dsoff(map, print_dsoff, addr, fp);
|
|
|
|
- if (print_srcline)
|
|
- printed += map__fprintf_srcline(map, addr, "\n ", fp);
|
|
+ if (print_srcline) {
|
|
+ if (node->srcline)
|
|
+ printed += fprintf(fp, "\n %s", node->srcline);
|
|
+ else
|
|
+ printed += map__fprintf_srcline(map, addr, "\n ", fp);
|
|
+ }
|
|
|
|
if (sym && sym->inlined)
|
|
printed += fprintf(fp, " (inlined)");
|
|
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
|
|
index 6013335a8daea5..bd027fdf6af179 100644
|
|
--- a/tools/perf/util/unwind-libdw.c
|
|
+++ b/tools/perf/util/unwind-libdw.c
|
|
@@ -133,8 +133,8 @@ static int entry(u64 ip, struct unwind_info *ui)
|
|
}
|
|
|
|
e->ip = ip;
|
|
- e->ms.maps = al.maps;
|
|
- e->ms.map = al.map;
|
|
+ e->ms.maps = maps__get(al.maps);
|
|
+ e->ms.map = map__get(al.map);
|
|
e->ms.sym = al.sym;
|
|
|
|
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
|
|
@@ -319,6 +319,9 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
|
if (err)
|
|
pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
|
|
|
|
+ for (i = 0; i < ui->idx; i++)
|
|
+ map_symbol__exit(&ui->entries[i].ms);
|
|
+
|
|
dwfl_end(ui->dwfl);
|
|
free(ui);
|
|
return 0;
|
|
diff --git a/tools/power/cpupower/lib/cpuidle.c b/tools/power/cpupower/lib/cpuidle.c
|
|
index c15d0de12357fb..e7b8c566383701 100644
|
|
--- a/tools/power/cpupower/lib/cpuidle.c
|
|
+++ b/tools/power/cpupower/lib/cpuidle.c
|
|
@@ -148,6 +148,7 @@ unsigned long long cpuidle_state_get_one_value(unsigned int cpu,
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
+ errno = 0;
|
|
value = strtoull(linebuf, &endp, 0);
|
|
|
|
if (endp == linebuf || errno == ERANGE)
|
|
diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c
|
|
index 5fcc2a92957e79..a5d512866a940d 100644
|
|
--- a/tools/power/x86/intel-speed-select/isst-config.c
|
|
+++ b/tools/power/x86/intel-speed-select/isst-config.c
|
|
@@ -936,9 +936,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
|
|
ret = write(fd, "member", strlen("member"));
|
|
if (ret == -1) {
|
|
printf("Can't update to member\n");
|
|
+ close(fd);
|
|
return ret;
|
|
}
|
|
|
|
+ close(fd);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/tools/spi/.gitignore b/tools/spi/.gitignore
|
|
index 14ddba3d21957b..038261b34ed83c 100644
|
|
--- a/tools/spi/.gitignore
|
|
+++ b/tools/spi/.gitignore
|
|
@@ -1,3 +1,4 @@
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
spidev_fdx
|
|
spidev_test
|
|
+include/
|
|
diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c
|
|
index 611b5a0a6f7e3e..fab89a84119f85 100644
|
|
--- a/tools/testing/selftests/bpf/veristat.c
|
|
+++ b/tools/testing/selftests/bpf/veristat.c
|
|
@@ -1372,7 +1372,7 @@ static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last
|
|
if (last && fmt == RESFMT_TABLE) {
|
|
output_header_underlines();
|
|
printf("Done. Processed %d files, %d programs. Skipped %d files, %d programs.\n",
|
|
- env.files_processed, env.files_skipped, env.progs_processed, env.progs_skipped);
|
|
+ env.files_processed, env.progs_processed, env.files_skipped, env.progs_skipped);
|
|
}
|
|
}
|
|
|
|
diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh
|
|
index 0441a18f098b10..aac8ef490feb80 100755
|
|
--- a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh
|
|
+++ b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh
|
|
@@ -317,7 +317,7 @@ police_limits_test()
|
|
|
|
tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
|
|
flower skip_sw \
|
|
- action police rate 0.5kbit burst 1m conform-exceed drop/ok
|
|
+ action police rate 0.5kbit burst 2k conform-exceed drop/ok
|
|
check_fail $? "Incorrect success to add police action with too low rate"
|
|
|
|
tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
|
|
@@ -327,7 +327,7 @@ police_limits_test()
|
|
|
|
tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
|
|
flower skip_sw \
|
|
- action police rate 1.5kbit burst 1m conform-exceed drop/ok
|
|
+ action police rate 1.5kbit burst 2k conform-exceed drop/ok
|
|
check_err $? "Failed to add police action with low rate"
|
|
|
|
tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower
|
|
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
|
|
index 9c9c82fd18a7ea..f2042de4bab8e2 100644
|
|
--- a/tools/testing/selftests/memfd/memfd_test.c
|
|
+++ b/tools/testing/selftests/memfd/memfd_test.c
|
|
@@ -18,6 +18,9 @@
|
|
#include <sys/stat.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/wait.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/ipc.h>
|
|
+#include <sys/sem.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
@@ -39,14 +42,26 @@
|
|
F_SEAL_EXEC)
|
|
|
|
#define MFD_NOEXEC_SEAL 0x0008U
|
|
+union semun {
|
|
+ int val;
|
|
+ struct semid_ds *buf;
|
|
+ unsigned short int *array;
|
|
+ struct seminfo *__buf;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * we use semaphores on nested wait tasks due the use of CLONE_NEWPID: the
|
|
+ * child will be PID 1 and can't send SIGSTOP to themselves due special
|
|
+ * treatment of the init task, so the SIGSTOP/SIGCONT synchronization
|
|
+ * approach can't be used here.
|
|
+ */
|
|
+#define SEM_KEY 0xdeadbeef
|
|
|
|
/*
|
|
* Default is not to test hugetlbfs
|
|
*/
|
|
static size_t mfd_def_size = MFD_DEF_SIZE;
|
|
static const char *memfd_str = MEMFD_STR;
|
|
-static int newpid_thread_fn2(void *arg);
|
|
-static void join_newpid_thread(pid_t pid);
|
|
|
|
static ssize_t fd2name(int fd, char *buf, size_t bufsize)
|
|
{
|
|
@@ -195,7 +210,6 @@ static unsigned int mfd_assert_get_seals(int fd)
|
|
static void mfd_assert_has_seals(int fd, unsigned int seals)
|
|
{
|
|
char buf[PATH_MAX];
|
|
- int nbytes;
|
|
unsigned int s;
|
|
fd2name(fd, buf, PATH_MAX);
|
|
|
|
@@ -715,7 +729,6 @@ static void mfd_assert_mode(int fd, int mode)
|
|
{
|
|
struct stat st;
|
|
char buf[PATH_MAX];
|
|
- int nbytes;
|
|
|
|
fd2name(fd, buf, PATH_MAX);
|
|
|
|
@@ -734,7 +747,6 @@ static void mfd_assert_mode(int fd, int mode)
|
|
static void mfd_assert_chmod(int fd, int mode)
|
|
{
|
|
char buf[PATH_MAX];
|
|
- int nbytes;
|
|
|
|
fd2name(fd, buf, PATH_MAX);
|
|
|
|
@@ -750,7 +762,6 @@ static void mfd_fail_chmod(int fd, int mode)
|
|
{
|
|
struct stat st;
|
|
char buf[PATH_MAX];
|
|
- int nbytes;
|
|
|
|
fd2name(fd, buf, PATH_MAX);
|
|
|
|
@@ -1297,9 +1308,6 @@ static void test_sysctl_set_sysctl2(void)
|
|
|
|
static int sysctl_simple_child(void *arg)
|
|
{
|
|
- int fd;
|
|
- int pid;
|
|
-
|
|
printf("%s sysctl 0\n", memfd_str);
|
|
test_sysctl_set_sysctl0();
|
|
|
|
@@ -1342,8 +1350,22 @@ static int sysctl_nested(void *arg)
|
|
|
|
static int sysctl_nested_wait(void *arg)
|
|
{
|
|
- /* Wait for a SIGCONT. */
|
|
- kill(getpid(), SIGSTOP);
|
|
+ int sem = semget(SEM_KEY, 1, 0600);
|
|
+ struct sembuf sembuf;
|
|
+
|
|
+ if (sem < 0) {
|
|
+ perror("semget:");
|
|
+ abort();
|
|
+ }
|
|
+ sembuf.sem_num = 0;
|
|
+ sembuf.sem_flg = 0;
|
|
+ sembuf.sem_op = 0;
|
|
+
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ abort();
|
|
+ }
|
|
+
|
|
return sysctl_nested(arg);
|
|
}
|
|
|
|
@@ -1364,8 +1386,9 @@ static void test_sysctl_sysctl2_failset(void)
|
|
|
|
static int sysctl_nested_child(void *arg)
|
|
{
|
|
- int fd;
|
|
- int pid;
|
|
+ int pid, sem;
|
|
+ union semun semun;
|
|
+ struct sembuf sembuf;
|
|
|
|
printf("%s nested sysctl 0\n", memfd_str);
|
|
sysctl_assert_write("0");
|
|
@@ -1399,23 +1422,53 @@ static int sysctl_nested_child(void *arg)
|
|
test_sysctl_sysctl2_failset);
|
|
join_thread(pid);
|
|
|
|
+ sem = semget(SEM_KEY, 1, IPC_CREAT | 0600);
|
|
+ if (sem < 0) {
|
|
+ perror("semget:");
|
|
+ return 1;
|
|
+ }
|
|
+ semun.val = 1;
|
|
+ sembuf.sem_op = -1;
|
|
+ sembuf.sem_flg = 0;
|
|
+ sembuf.sem_num = 0;
|
|
+
|
|
/* Verify that the rules are actually inherited after fork. */
|
|
printf("%s nested sysctl 0 -> 1 after fork\n", memfd_str);
|
|
sysctl_assert_write("0");
|
|
|
|
+ if (semctl(sem, 0, SETVAL, semun) < 0) {
|
|
+ perror("semctl:");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
|
|
test_sysctl_sysctl1_failset);
|
|
sysctl_assert_write("1");
|
|
- kill(pid, SIGCONT);
|
|
+
|
|
+ /* Allow child to continue */
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ return 1;
|
|
+ }
|
|
join_thread(pid);
|
|
|
|
printf("%s nested sysctl 0 -> 2 after fork\n", memfd_str);
|
|
sysctl_assert_write("0");
|
|
|
|
+ if (semctl(sem, 0, SETVAL, semun) < 0) {
|
|
+ perror("semctl:");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
|
|
test_sysctl_sysctl2_failset);
|
|
sysctl_assert_write("2");
|
|
- kill(pid, SIGCONT);
|
|
+
|
|
+ /* Allow child to continue */
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ return 1;
|
|
+ }
|
|
join_thread(pid);
|
|
|
|
/*
|
|
@@ -1425,28 +1478,62 @@ static int sysctl_nested_child(void *arg)
|
|
*/
|
|
printf("%s nested sysctl 2 -> 1 after fork\n", memfd_str);
|
|
sysctl_assert_write("2");
|
|
+
|
|
+ if (semctl(sem, 0, SETVAL, semun) < 0) {
|
|
+ perror("semctl:");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
|
|
test_sysctl_sysctl2);
|
|
sysctl_assert_write("1");
|
|
- kill(pid, SIGCONT);
|
|
+
|
|
+ /* Allow child to continue */
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ return 1;
|
|
+ }
|
|
join_thread(pid);
|
|
|
|
printf("%s nested sysctl 2 -> 0 after fork\n", memfd_str);
|
|
sysctl_assert_write("2");
|
|
+
|
|
+ if (semctl(sem, 0, SETVAL, semun) < 0) {
|
|
+ perror("semctl:");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
|
|
test_sysctl_sysctl2);
|
|
sysctl_assert_write("0");
|
|
- kill(pid, SIGCONT);
|
|
+
|
|
+ /* Allow child to continue */
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ return 1;
|
|
+ }
|
|
join_thread(pid);
|
|
|
|
printf("%s nested sysctl 1 -> 0 after fork\n", memfd_str);
|
|
sysctl_assert_write("1");
|
|
+
|
|
+ if (semctl(sem, 0, SETVAL, semun) < 0) {
|
|
+ perror("semctl:");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
|
|
test_sysctl_sysctl1);
|
|
sysctl_assert_write("0");
|
|
- kill(pid, SIGCONT);
|
|
+ /* Allow child to continue */
|
|
+ if (semop(sem, &sembuf, 1) < 0) {
|
|
+ perror("semop:");
|
|
+ return 1;
|
|
+ }
|
|
join_thread(pid);
|
|
|
|
+ semctl(sem, 0, IPC_RMID);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
|
|
index dc3fc438b3d9e1..7cf581f4f44fb5 100755
|
|
--- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
|
|
+++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
|
|
@@ -288,7 +288,7 @@ function run_test() {
|
|
setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
|
|
|
|
mkdir -p /mnt/huge
|
|
- mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
|
|
+ mount -t hugetlbfs -o pagesize=${MB}M none /mnt/huge
|
|
|
|
write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
|
|
"$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
|
|
@@ -342,7 +342,7 @@ function run_multiple_cgroup_test() {
|
|
setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
|
|
|
|
mkdir -p /mnt/huge
|
|
- mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
|
|
+ mount -t hugetlbfs -o pagesize=${MB}M none /mnt/huge
|
|
|
|
write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
|
|
"$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
|
|
diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh
|
|
index eb307ca37bfa69..002551451a7287 100755
|
|
--- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh
|
|
+++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh
|
|
@@ -559,6 +559,21 @@ vxlan_encapped_ping_do()
|
|
local inner_tos=$1; shift
|
|
local outer_tos=$1; shift
|
|
|
|
+ local ipv4hdr=$(:
|
|
+ )"45:"$( : IP version + IHL
|
|
+ )"$inner_tos:"$( : IP TOS
|
|
+ )"00:54:"$( : IP total length
|
|
+ )"99:83:"$( : IP identification
|
|
+ )"40:00:"$( : IP flags + frag off
|
|
+ )"40:"$( : IP TTL
|
|
+ )"01:"$( : IP proto
|
|
+ )"CHECKSUM:"$( : IP header csum
|
|
+ )"c0:00:02:03:"$( : IP saddr: 192.0.2.3
|
|
+ )"c0:00:02:01"$( : IP daddr: 192.0.2.1
|
|
+ )
|
|
+ local checksum=$(payload_template_calc_checksum "$ipv4hdr")
|
|
+ ipv4hdr=$(payload_template_expand_checksum "$ipv4hdr" $checksum)
|
|
+
|
|
$MZ $dev -c $count -d 100msec -q \
|
|
-b $next_hop_mac -B $dest_ip \
|
|
-t udp tos=$outer_tos,sp=23456,dp=$VXPORT,p=$(:
|
|
@@ -569,16 +584,7 @@ vxlan_encapped_ping_do()
|
|
)"$dest_mac:"$( : ETH daddr
|
|
)"$(mac_get w2):"$( : ETH saddr
|
|
)"08:00:"$( : ETH type
|
|
- )"45:"$( : IP version + IHL
|
|
- )"$inner_tos:"$( : IP TOS
|
|
- )"00:54:"$( : IP total length
|
|
- )"99:83:"$( : IP identification
|
|
- )"40:00:"$( : IP flags + frag off
|
|
- )"40:"$( : IP TTL
|
|
- )"01:"$( : IP proto
|
|
- )"00:00:"$( : IP header csum
|
|
- )"c0:00:02:03:"$( : IP saddr: 192.0.2.3
|
|
- )"c0:00:02:01:"$( : IP daddr: 192.0.2.1
|
|
+ )"$ipv4hdr:"$( : IPv4 header
|
|
)"08:"$( : ICMP type
|
|
)"00:"$( : ICMP code
|
|
)"8b:f2:"$( : ICMP csum
|
|
diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh
|
|
index bd3f7d492af2bb..28284a5aa07a97 100755
|
|
--- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh
|
|
+++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh
|
|
@@ -695,7 +695,7 @@ vxlan_encapped_ping_do()
|
|
)"6"$( : IP version
|
|
)"$inner_tos"$( : Traffic class
|
|
)"0:00:00:"$( : Flow label
|
|
- )"00:08:"$( : Payload length
|
|
+ )"00:03:"$( : Payload length
|
|
)"3a:"$( : Next header
|
|
)"04:"$( : Hop limit
|
|
)"$saddr:"$( : IP saddr
|