diff options
author | Jakub Kicinski <kuba@kernel.org> | 2020-11-28 03:25:27 +0100 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2020-11-28 03:25:27 +0100 |
commit | 5c39f26e67c984db0fa95f9faecf06eb0198dce7 (patch) | |
tree | 821aaa43d3f5806134438daa531be6d171292c5f | |
parent | Merge branch 'tipc-some-minor-improvements' (diff) | |
parent | Merge tag 'asm-generic-fixes-5.10-2' of git://git.kernel.org/pub/scm/linux/ke... (diff) | |
download | linux-5c39f26e67c984db0fa95f9faecf06eb0198dce7.tar.xz linux-5c39f26e67c984db0fa95f9faecf06eb0198dce7.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Trivial conflict in CAN, keep the net-next + the byteswap wrapper.
Conflicts:
drivers/net/can/usb/gs_usb.c
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
387 files changed, 6414 insertions, 2991 deletions
@@ -290,6 +290,7 @@ Santosh Shilimkar <ssantosh@kernel.org> Sarangdhar Joshi <spjoshi@codeaurora.org> Sascha Hauer <s.hauer@pengutronix.de> S.ÇaÄŸlar Onur <caglar@pardus.org.tr> +Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com> Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> Sebastian Reichel <sre@kernel.org> <sre@debian.org> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 index a10a4de3e5fe..c4a4497c249a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 @@ -109,30 +109,6 @@ Description: When counting down the counter start from preset value and fire event when reach 0. -What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available -KernelVersion: 4.12 -Contact: benjamin.gaignard@st.com -Description: - Reading returns the list possible quadrature modes. - -What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode -KernelVersion: 4.12 -Contact: benjamin.gaignard@st.com -Description: - Configure the device counter quadrature modes: - - channel_A: - Encoder A input servers as the count input and B as - the UP/DOWN direction control input. - - channel_B: - Encoder B input serves as the count input and A as - the UP/DOWN direction control input. - - quadrature: - Encoder A and B inputs are mixed to get direction - and count with a scale of 0.25. - What: /sys/bus/iio/devices/iio:deviceX/in_count_enable_mode_available KernelVersion: 4.12 Contact: benjamin.gaignard@st.com diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml index 03a76729d26c..7ce06f9f9f8e 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml @@ -76,6 +76,12 @@ properties: resets: maxItems: 1 + wifi-2.4ghz-coexistence: + type: boolean + description: > + Should the pixel frequencies in the WiFi frequencies range be + avoided? + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/rt1015.txt b/Documentation/devicetree/bindings/sound/rt1015.txt index fcfd02d8d32f..e498966d436f 100644 --- a/Documentation/devicetree/bindings/sound/rt1015.txt +++ b/Documentation/devicetree/bindings/sound/rt1015.txt @@ -8,10 +8,16 @@ Required properties: - reg : The I2C address of the device. +Optional properties: + +- realtek,power-up-delay-ms + Set a delay time for flush work to be completed, + this value is adjustable depending on platform. Example: rt1015: codec@28 { compatible = "realtek,rt1015"; reg = <0x28>; + realtek,power-up-delay-ms = <50>; }; diff --git a/Documentation/driver-api/media/drivers/vidtv.rst b/Documentation/driver-api/media/drivers/vidtv.rst index 65115448c52d..673bdff919ea 100644 --- a/Documentation/driver-api/media/drivers/vidtv.rst +++ b/Documentation/driver-api/media/drivers/vidtv.rst @@ -149,11 +149,11 @@ vidtv_psi.[ch] Because the generator is implemented in a separate file, it can be reused elsewhere in the media subsystem. - Currently vidtv supports working with 3 PSI tables: PAT, PMT and - SDT. + Currently vidtv supports working with 5 PSI tables: PAT, PMT, + SDT, NIT and EIT. The specification for PAT and PMT can be found in *ISO 13818-1: - Systems*, while the specification for the SDT can be found in *ETSI + Systems*, while the specification for the SDT, NIT, EIT can be found in *ETSI EN 300 468: Specification for Service Information (SI) in DVB systems*. @@ -197,6 +197,8 @@ vidtv_channel.[ch] #. Their programs will be concatenated to populate the PAT + #. Their events will be concatenated to populate the EIT + #. For each program in the PAT, a PMT section will be created #. The PMT section for a channel will be assigned its streams. @@ -256,6 +258,42 @@ Using dvb-fe-tool The first step to check whether the demod loaded successfully is to run:: $ dvb-fe-tool + Device Dummy demod for DVB-T/T2/C/S/S2 (/dev/dvb/adapter0/frontend0) capabilities: + CAN_FEC_1_2 + CAN_FEC_2_3 + CAN_FEC_3_4 + CAN_FEC_4_5 + CAN_FEC_5_6 + CAN_FEC_6_7 + CAN_FEC_7_8 + CAN_FEC_8_9 + CAN_FEC_AUTO + CAN_GUARD_INTERVAL_AUTO + CAN_HIERARCHY_AUTO + CAN_INVERSION_AUTO + CAN_QAM_16 + CAN_QAM_32 + CAN_QAM_64 + CAN_QAM_128 + CAN_QAM_256 + CAN_QAM_AUTO + CAN_QPSK + CAN_TRANSMISSION_MODE_AUTO + DVB API Version 5.11, Current v5 delivery system: DVBC/ANNEX_A + Supported delivery systems: + DVBT + DVBT2 + [DVBC/ANNEX_A] + DVBS + DVBS2 + Frequency range for the current standard: + From: 51.0 MHz + To: 2.15 GHz + Step: 62.5 kHz + Tolerance: 29.5 MHz + Symbol rate ranges for the current standard: + From: 1.00 MBauds + To: 45.0 MBauds This should return what is currently set up at the demod struct, i.e.:: @@ -314,7 +352,7 @@ For this, one should provide a configuration file known as a 'scan file', here's an example:: [Channel] - FREQUENCY = 330000000 + FREQUENCY = 474000000 MODULATION = QAM/AUTO SYMBOL_RATE = 6940000 INNER_FEC = AUTO @@ -335,6 +373,14 @@ You can browse scan tables online here: `dvb-scan-tables Assuming this channel is named 'channel.conf', you can then run:: $ dvbv5-scan channel.conf + dvbv5-scan ~/vidtv.conf + ERROR command BANDWIDTH_HZ (5) not found during retrieve + Cannot calc frequency shift. Either bandwidth/symbol-rate is unavailable (yet). + Scanning frequency #1 330000000 + (0x00) Signal= -68.00dBm + Scanning frequency #2 474000000 + Lock (0x1f) Signal= -34.45dBm C/N= 33.74dB UCB= 0 + Service Beethoven, provider LinuxTV.org: digital television For more information on dvb-scan, check its documentation online here: `dvb-scan Documentation <https://www.linuxtv.org/wiki/index.php/Dvbscan>`_. @@ -344,23 +390,38 @@ Using dvb-zap dvbv5-zap is a command line tool that can be used to record MPEG-TS to disk. The typical use is to tune into a channel and put it into record mode. The example -below - which is taken from the documentation - illustrates that:: +below - which is taken from the documentation - illustrates that\ [1]_:: - $ dvbv5-zap -c dvb_channel.conf "trilhas sonoras" -r - using demux '/dev/dvb/adapter0/demux0' + $ dvbv5-zap -c dvb_channel.conf "beethoven" -o music.ts -P -t 10 + using demux 'dvb0.demux0' reading channels from file 'dvb_channel.conf' - service has pid type 05: 204 - tuning to 573000000 Hz - audio pid 104 - dvb_set_pesfilter 104 - Lock (0x1f) Quality= Good Signal= 100.00% C/N= -13.80dB UCB= 70 postBER= 3.14x10^-3 PER= 0 - DVR interface '/dev/dvb/adapter0/dvr0' can now be opened + tuning to 474000000 Hz + pass all PID's to TS + dvb_set_pesfilter 8192 + dvb_dev_set_bufsize: buffer set to 6160384 + Lock (0x1f) Quality= Good Signal= -34.66dBm C/N= 33.41dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0 + Lock (0x1f) Quality= Good Signal= -34.57dBm C/N= 33.46dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0 + Record to file 'music.ts' started + received 24587768 bytes (2401 Kbytes/sec) + Lock (0x1f) Quality= Good Signal= -34.42dBm C/N= 33.89dB UCB= 0 postBER= 0 preBER= 2.44x10^-3 PER= 0 + +.. [1] In this example, it records 10 seconds with all program ID's stored + at the music.ts file. + -The channel can be watched by playing the contents of the DVR interface, with -some player that recognizes the MPEG-TS format, such as *mplayer* or *vlc*. +The channel can be watched by playing the contents of the stream with some +player that recognizes the MPEG-TS format, such as ``mplayer`` or ``vlc``. By playing the contents of the stream one can visually inspect the workings of -vidtv, e.g.:: +vidtv, e.g., to play a recorded TS file with:: + + $ mplayer music.ts + +or, alternatively, running this command on one terminal:: + + $ dvbv5-zap -c dvb_channel.conf "beethoven" -P -r & + +And, on a second terminal, playing the contents from DVR interface with:: $ mplayer /dev/dvb/adapter0/dvr0 @@ -423,3 +484,30 @@ A nice addition is to simulate some noise when the signal quality is bad by: - Updating the error statistics accordingly (e.g. BER, etc). - Simulating some noise in the encoded data. + +Functions and structs used within vidtv +--------------------------------------- + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_bridge.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_channel.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_demod.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_encoder.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_mux.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_pes.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_psi.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_s302m.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_ts.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.h + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_common.c + +.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.c diff --git a/Documentation/networking/netdev-FAQ.rst b/Documentation/networking/netdev-FAQ.rst index 21537766be4d..4b9ed5874d5a 100644 --- a/Documentation/networking/netdev-FAQ.rst +++ b/Documentation/networking/netdev-FAQ.rst @@ -254,6 +254,32 @@ you will have done run-time testing specific to your change, but at a minimum, your changes should survive an ``allyesconfig`` and an ``allmodconfig`` build without new warnings or failures. +Q: How do I post corresponding changes to user space components? +---------------------------------------------------------------- +A: User space code exercising kernel features should be posted +alongside kernel patches. This gives reviewers a chance to see +how any new interface is used and how well it works. + +When user space tools reside in the kernel repo itself all changes +should generally come as one series. If series becomes too large +or the user space project is not reviewed on netdev include a link +to a public repo where user space patches can be seen. + +In case user space tooling lives in a separate repository but is +reviewed on netdev (e.g. patches to `iproute2` tools) kernel and +user space patches should form separate series (threads) when posted +to the mailing list, e.g.:: + + [PATCH net-next 0/3] net: some feature cover letter + └─ [PATCH net-next 1/3] net: some feature prep + └─ [PATCH net-next 2/3] net: some feature do it + └─ [PATCH net-next 3/3] selftest: net: some feature + + [PATCH iproute2-next] ip: add support for some feature + +Posting as one thread is discouraged because it confuses patchwork +(as of patchwork 2.2.2). + Q: Any other tips to help ensure my net/net-next patch gets OK'd? ----------------------------------------------------------------- A: Attention to detail. Re-read your own work as if you were the diff --git a/MAINTAINERS b/MAINTAINERS index 8545e72c495c..a7bdebf955bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1995,7 +1995,6 @@ N: lpc18xx ARM/LPC32XX SOC SUPPORT M: Vladimir Zapolskiy <vz@mleia.com> -M: Sylvain Lemieux <slemieux.tyco@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://github.com/vzapolskiy/linux-lpc32xx.git @@ -3528,11 +3527,12 @@ BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER M: Arend van Spriel <arend.vanspriel@broadcom.com> M: Franky Lin <franky.lin@broadcom.com> M: Hante Meuleman <hante.meuleman@broadcom.com> -M: Chi-Hsien Lin <chi-hsien.lin@cypress.com> -M: Wright Feng <wright.feng@cypress.com> +M: Chi-hsien Lin <chi-hsien.lin@infineon.com> +M: Wright Feng <wright.feng@infineon.com> +M: Chung-hsien Hsu <chung-hsien.hsu@infineon.com> L: linux-wireless@vger.kernel.org L: brcm80211-dev-list.pdl@broadcom.com -L: brcm80211-dev-list@cypress.com +L: SHA-cyfmac-dev-list@infineon.com S: Supported F: drivers/net/wireless/broadcom/brcm80211/ @@ -9155,6 +9155,7 @@ F: include/linux/iomap.h IOMMU DRIVERS M: Joerg Roedel <joro@8bytes.org> +M: Will Deacon <will@kernel.org> L: iommu@lists.linux-foundation.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git @@ -9638,6 +9639,7 @@ F: Documentation/virt/kvm/s390* F: arch/s390/include/asm/gmap.h F: arch/s390/include/asm/kvm* F: arch/s390/include/uapi/asm/kvm* +F: arch/s390/kernel/uv.c F: arch/s390/kvm/ F: arch/s390/mm/gmap.c F: tools/testing/selftests/kvm/*/s390x/ @@ -13156,7 +13158,9 @@ M: Jesper Dangaard Brouer <hawk@kernel.org> M: Ilias Apalodimas <ilias.apalodimas@linaro.org> L: netdev@vger.kernel.org S: Supported +F: Documentation/networking/page_pool.rst F: include/net/page_pool.h +F: include/trace/events/page_pool.h F: net/core/page_pool.c PANASONIC LAPTOP ACPI EXTRAS DRIVER @@ -14798,7 +14802,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g F: drivers/net/wireless/realtek/rtlwifi/ REALTEK WIRELESS DRIVER (rtw88) -M: Yan-Hsuan Chuang <yhchuang@realtek.com> +M: Yan-Hsuan Chuang <tony0620emma@gmail.com> L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/realtek/rtw88/ @@ -15771,9 +15775,8 @@ F: drivers/slimbus/ F: include/linux/slimbus.h SFC NETWORK DRIVER -M: Solarflare linux maintainers <linux-net-drivers@solarflare.com> -M: Edward Cree <ecree@solarflare.com> -M: Martin Habets <mhabets@solarflare.com> +M: Edward Cree <ecree.xilinx@gmail.com> +M: Martin Habets <habetsm.xilinx@gmail.com> L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/sfc/ @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 10 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Kleptomaniac Octopus # *DOCUMENTATION* diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h index c6606f4d20d6..fb98440c0bd4 100644 --- a/arch/arc/include/asm/bitops.h +++ b/arch/arc/include/asm/bitops.h @@ -243,10 +243,8 @@ static inline int constant_fls(unsigned int x) x <<= 2; r -= 2; } - if (!(x & 0x80000000u)) { - x <<= 1; + if (!(x & 0x80000000u)) r -= 1; - } return r; } diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index f1ed17edb085..163641726a2b 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -134,8 +134,10 @@ #ifdef CONFIG_ARC_HAS_PAE40 #define PTE_BITS_NON_RWX_IN_PD1 (0xff00000000 | PAGE_MASK | _PAGE_CACHEABLE) +#define MAX_POSSIBLE_PHYSMEM_BITS 40 #else #define PTE_BITS_NON_RWX_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE) +#define MAX_POSSIBLE_PHYSMEM_BITS 32 #endif /************************************************************************** diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c index b23986f98450..f73da203b170 100644 --- a/arch/arc/kernel/stacktrace.c +++ b/arch/arc/kernel/stacktrace.c @@ -38,15 +38,27 @@ #ifdef CONFIG_ARC_DW2_UNWIND -static void seed_unwind_frame_info(struct task_struct *tsk, - struct pt_regs *regs, - struct unwind_frame_info *frame_info) +static int +seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs, + struct unwind_frame_info *frame_info) { - /* - * synchronous unwinding (e.g. dump_stack) - * - uses current values of SP and friends - */ - if (tsk == NULL && regs == NULL) { + if (regs) { + /* + * Asynchronous unwinding of intr/exception + * - Just uses the pt_regs passed + */ + frame_info->task = tsk; + + frame_info->regs.r27 = regs->fp; + frame_info->regs.r28 = regs->sp; + frame_info->regs.r31 = regs->blink; + frame_info->regs.r63 = regs->ret; + frame_info->call_frame = 0; + } else if (tsk == NULL || tsk == current) { + /* + * synchronous unwinding (e.g. dump_stack) + * - uses current values of SP and friends + */ unsigned long fp, sp, blink, ret; frame_info->task = current; @@ -63,13 +75,17 @@ static void seed_unwind_frame_info(struct task_struct *tsk, frame_info->regs.r31 = blink; frame_info->regs.r63 = ret; frame_info->call_frame = 0; - } else if (regs == NULL) { + } else { /* - * Asynchronous unwinding of sleeping task - * - Gets SP etc from task's pt_regs (saved bottom of kernel - * mode stack of task) + * Asynchronous unwinding of a likely sleeping task + * - first ensure it is actually sleeping + * - if so, it will be in __switch_to, kernel mode SP of task + * is safe-kept and BLINK at a well known location in there */ + if (tsk->state == TASK_RUNNING) + return -1; + frame_info->task = tsk; frame_info->regs.r27 = TSK_K_FP(tsk); @@ -90,19 +106,8 @@ static void seed_unwind_frame_info(struct task_struct *tsk, frame_info->regs.r28 += 60; frame_info->call_frame = 0; - } else { - /* - * Asynchronous unwinding of intr/exception - * - Just uses the pt_regs passed - */ - frame_info->task = tsk; - - frame_info->regs.r27 = regs->fp; - frame_info->regs.r28 = regs->sp; - frame_info->regs.r31 = regs->blink; - frame_info->regs.r63 = regs->ret; - frame_info->call_frame = 0; } + return 0; } #endif @@ -116,7 +121,8 @@ arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs, unsigned int address; struct unwind_frame_info frame_info; - seed_unwind_frame_info(tsk, regs, &frame_info); + if (seed_unwind_frame_info(tsk, regs, &frame_info)) + return 0; while (1) { address = UNW_PC(&frame_info); diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index c340acd989a0..9bb3c24f3677 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -30,14 +30,14 @@ * -Changes related to MMU v2 (Rel 4.8) * * Vineetg: Aug 29th 2008 - * -In TLB Flush operations (Metal Fix MMU) there is a explict command to + * -In TLB Flush operations (Metal Fix MMU) there is a explicit command to * flush Micro-TLBS. If TLB Index Reg is invalid prior to TLBIVUTLB cmd, * it fails. Thus need to load it with ANY valid value before invoking * TLBIVUTLB cmd * * Vineetg: Aug 21th 2008: * -Reduced the duration of IRQ lockouts in TLB Flush routines - * -Multiple copies of TLB erase code seperated into a "single" function + * -Multiple copies of TLB erase code separated into a "single" function * -In TLB Flush routines, interrupt disabling moved UP to retrieve ASID * in interrupt-safe region. * @@ -66,7 +66,7 @@ * * Although J-TLB is 2 way set assoc, ARC700 caches J-TLB into uTLBS which has * much higher associativity. u-D-TLB is 8 ways, u-I-TLB is 4 ways. - * Given this, the thrasing problem should never happen because once the 3 + * Given this, the thrashing problem should never happen because once the 3 * J-TLB entries are created (even though 3rd will knock out one of the prev * two), the u-D-TLB and u-I-TLB will have what is required to accomplish memcpy * @@ -127,7 +127,7 @@ static void utlb_invalidate(void) * There was however an obscure hardware bug, where uTLB flush would * fail when a prior probe for J-TLB (both totally unrelated) would * return lkup err - because the entry didn't exist in MMU. - * The Workround was to set Index reg with some valid value, prior to + * The Workaround was to set Index reg with some valid value, prior to * flush. This was fixed in MMU v3 */ unsigned int idx; @@ -272,7 +272,7 @@ noinline void local_flush_tlb_all(void) } /* - * Flush the entrie MM for userland. The fastest way is to move to Next ASID + * Flush the entire MM for userland. The fastest way is to move to Next ASID */ noinline void local_flush_tlb_mm(struct mm_struct *mm) { @@ -303,7 +303,7 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm) * Difference between this and Kernel Range Flush is * -Here the fastest way (if range is too large) is to move to next ASID * without doing any explicit Shootdown - * -In case of kernel Flush, entry has to be shot down explictly + * -In case of kernel Flush, entry has to be shot down explicitly */ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) @@ -620,7 +620,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned, * Super Page size is configurable in hardware (4K to 16M), but fixed once * RTL builds. * - * The exact THP size a Linx configuration will support is a function of: + * The exact THP size a Linux configuration will support is a function of: * - MMU page size (typical 8K, RTL fixed) * - software page walker address split between PGD:PTE:PFN (typical * 11:8:13, but can be changed with 1 line) @@ -698,7 +698,7 @@ void local_flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, #endif -/* Read the Cache Build Confuration Registers, Decode them and save into +/* Read the Cache Build Configuration Registers, Decode them and save into * the cpuinfo structure for later use. * No Validation is done here, simply read/convert the BCRs */ @@ -803,13 +803,13 @@ void arc_mmu_init(void) pr_info("%s", arc_mmu_mumbojumbo(0, str, sizeof(str))); /* - * Can't be done in processor.h due to header include depenedencies + * Can't be done in processor.h due to header include dependencies */ BUILD_BUG_ON(!IS_ALIGNED((CONFIG_ARC_KVADDR_SIZE << 20), PMD_SIZE)); /* * stack top size sanity check, - * Can't be done in processor.h due to header include depenedencies + * Can't be done in processor.h due to header include dependencies */ BUILD_BUG_ON(!IS_ALIGNED(STACK_TOP, PMD_SIZE)); @@ -881,7 +881,7 @@ void arc_mmu_init(void) * the duplicate one. * -Knob to be verbose abt it.(TODO: hook them up to debugfs) */ -volatile int dup_pd_silent; /* Be slient abt it or complain (default) */ +volatile int dup_pd_silent; /* Be silent abt it or complain (default) */ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, struct pt_regs *regs) @@ -948,7 +948,7 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, /*********************************************************************** * Diagnostic Routines - * -Called from Low Level TLB Hanlders if things don;t look good + * -Called from Low Level TLB Handlers if things don;t look good **********************************************************************/ #ifdef CONFIG_ARC_DBG_TLB_PARANOIA diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 2e04ec5b5446..caa27322a0ab 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -1472,6 +1472,9 @@ ENTRY(efi_enter_kernel) @ issued from HYP mode take us to the correct handler code. We @ will disable the MMU before jumping to the kernel proper. @ + ARM( bic r1, r1, #(1 << 30) ) @ clear HSCTLR.TE + THUMB( orr r1, r1, #(1 << 30) ) @ set HSCTLR.TE + mcr p15, 4, r1, c1, c0, 0 adr r0, __hyp_reentry_vectors mcr p15, 4, r0, c12, c0, 0 @ set HYP vector base (HVBAR) isb diff --git a/arch/arm/boot/dts/am437x-l4.dtsi b/arch/arm/boot/dts/am437x-l4.dtsi index c220dc3c4e0f..243e35f7a56c 100644 --- a/arch/arm/boot/dts/am437x-l4.dtsi +++ b/arch/arm/boot/dts/am437x-l4.dtsi @@ -521,7 +521,7 @@ ranges = <0x0 0x100000 0x8000>; mac_sw: switch@0 { - compatible = "ti,am4372-cpsw","ti,cpsw-switch"; + compatible = "ti,am4372-cpsw-switch", "ti,cpsw-switch"; reg = <0x0 0x4000>; ranges = <0 0 0x4000>; clocks = <&cpsw_125mhz_gclk>, <&dpll_clksel_mac_clk>; diff --git a/arch/arm/boot/dts/dra76x.dtsi b/arch/arm/boot/dts/dra76x.dtsi index b69c7d40f5d8..2f326151116b 100644 --- a/arch/arm/boot/dts/dra76x.dtsi +++ b/arch/arm/boot/dts/dra76x.dtsi @@ -32,8 +32,8 @@ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "int0", "int1"; - clocks = <&mcan_clk>, <&l3_iclk_div>; - clock-names = "cclk", "hclk"; + clocks = <&l3_iclk_div>, <&mcan_clk>; + clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>; }; }; diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index 3502c2f746ca..baf7d0204eb5 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -75,6 +75,8 @@ #define PTE_HWTABLE_OFF (PTE_HWTABLE_PTRS * sizeof(pte_t)) #define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u32)) +#define MAX_POSSIBLE_PHYSMEM_BITS 32 + /* * PMD_SHIFT determines the size of the area a second-level page table can map * PGDIR_SHIFT determines what a third-level page table entry can map diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index fbb6693c3352..2b85d175e999 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -25,6 +25,8 @@ #define PTE_HWTABLE_OFF (0) #define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u64)) +#define MAX_POSSIBLE_PHYSMEM_BITS 40 + /* * PGDIR_SHIFT determines the size a top-level page table entry can map. */ diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 3ee7bdff86b2..3f62a0c9450d 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -7,7 +7,6 @@ config ARCH_OMAP2 depends on ARCH_MULTI_V6 select ARCH_OMAP2PLUS select CPU_V6 - select PM_GENERIC_DOMAINS if PM select SOC_HAS_OMAP2_SDRC config ARCH_OMAP3 @@ -106,6 +105,8 @@ config ARCH_OMAP2PLUS select OMAP_DM_TIMER select OMAP_GPMC select PINCTRL + select PM_GENERIC_DOMAINS if PM + select PM_GENERIC_DOMAINS_OF if PM select RESET_CONTROLLER select SOC_BUS select TI_SYSC diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index a92d277f81a0..c8d317fafe2e 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -175,8 +175,11 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, if (mpuss_can_lose_context) { error = cpu_cluster_pm_enter(); if (error) { - omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON); - goto cpu_cluster_pm_out; + index = 0; + cx = state_ptr + index; + pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); + omap_set_pwrdm_state(mpu_pd, cx->mpu_state); + mpuss_can_lose_context = 0; } } } @@ -184,7 +187,6 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, omap4_enter_lowpower(dev->cpu, cx->cpu_state); cpu_done[dev->cpu] = true; -cpu_cluster_pm_out: /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi index 55259f973b5a..aef8f2b00778 100644 --- a/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi +++ b/arch/arm64/boot/dts/broadcom/stingray/stingray-usb.dtsi @@ -5,20 +5,20 @@ usb { compatible = "simple-bus"; dma-ranges; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x68500000 0x00400000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x68500000 0x0 0x00400000>; usbphy0: usb-phy@0 { compatible = "brcm,sr-usb-combo-phy"; - reg = <0x00000000 0x100>; + reg = <0x0 0x00000000 0x0 0x100>; #phy-cells = <1>; status = "disabled"; }; xhci0: usb@1000 { compatible = "generic-xhci"; - reg = <0x00001000 0x1000>; + reg = <0x0 0x00001000 0x0 0x1000>; interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy0 1>, <&usbphy0 0>; phy-names = "phy0", "phy1"; @@ -28,7 +28,7 @@ bdc0: usb@2000 { compatible = "brcm,bdc-v0.16"; - reg = <0x00002000 0x1000>; + reg = <0x0 0x00002000 0x0 0x1000>; interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy0 0>, <&usbphy0 1>; phy-names = "phy0", "phy1"; @@ -38,21 +38,21 @@ usbphy1: usb-phy@10000 { compatible = "brcm,sr-usb-combo-phy"; - reg = <0x00010000 0x100>; + reg = <0x0 0x00010000 0x0 0x100>; #phy-cells = <1>; status = "disabled"; }; usbphy2: usb-phy@20000 { compatible = "brcm,sr-usb-hs-phy"; - reg = <0x00020000 0x100>; + reg = <0x0 0x00020000 0x0 0x100>; #phy-cells = <0>; status = "disabled"; }; xhci1: usb@11000 { compatible = "generic-xhci"; - reg = <0x00011000 0x1000>; + reg = <0x0 0x00011000 0x0 0x1000>; interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy1 1>, <&usbphy2>, <&usbphy1 0>; phy-names = "phy0", "phy1", "phy2"; @@ -62,7 +62,7 @@ bdc1: usb@21000 { compatible = "brcm,bdc-v0.16"; - reg = <0x00021000 0x1000>; + reg = <0x0 0x00021000 0x0 0x1000>; interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>; phys = <&usbphy2>; phy-names = "phy0"; diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts index 381a84912ba8..c28d51cc5797 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts @@ -10,18 +10,6 @@ model = "NVIDIA Jetson TX2 Developer Kit"; compatible = "nvidia,p2771-0000", "nvidia,tegra186"; - aconnect { - status = "okay"; - - dma-controller@2930000 { - status = "okay"; - }; - - interrupt-controller@2a40000 { - status = "okay"; - }; - }; - i2c@3160000 { power-monitor@42 { compatible = "ti,ina3221"; diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3668-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3668-0000.dtsi index a2893be80507..0dc8304a2edd 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p3668-0000.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194-p3668-0000.dtsi @@ -54,7 +54,7 @@ status = "okay"; }; - serial@c280000 { + serial@3100000 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi index e9c90f0f44ff..93438d2b9469 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi @@ -1161,7 +1161,7 @@ hsp_aon: hsp@c150000 { compatible = "nvidia,tegra194-hsp", "nvidia,tegra186-hsp"; - reg = <0x0c150000 0xa0000>; + reg = <0x0c150000 0x90000>; interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi index e18e1a9a3011..a9caaf7c0d67 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi @@ -1663,16 +1663,6 @@ vin-supply = <&vdd_5v0_sys>; }; - vdd_usb_vbus_otg: regulator@11 { - compatible = "regulator-fixed"; - regulator-name = "USB_VBUS_EN0"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio TEGRA_GPIO(CC, 4) GPIO_ACTIVE_HIGH>; - enable-active-high; - vin-supply = <&vdd_5v0_sys>; - }; - vdd_hdmi: regulator@10 { compatible = "regulator-fixed"; regulator-name = "VDD_HDMI_5V0"; @@ -1712,4 +1702,14 @@ enable-active-high; vin-supply = <&vdd_3v3_sys>; }; + + vdd_usb_vbus_otg: regulator@14 { + compatible = "regulator-fixed"; + regulator-name = "USB_VBUS_EN0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio TEGRA_GPIO(CC, 4) GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&vdd_5v0_sys>; + }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra234-sim-vdk.dts b/arch/arm64/boot/dts/nvidia/tegra234-sim-vdk.dts index f6e6a24829af..b5d9a5526272 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234-sim-vdk.dts +++ b/arch/arm64/boot/dts/nvidia/tegra234-sim-vdk.dts @@ -8,7 +8,7 @@ compatible = "nvidia,tegra234-vdk", "nvidia,tegra234"; aliases { - sdhci3 = "/cbb@0/sdhci@3460000"; + mmc3 = "/bus@0/mmc@3460000"; serial0 = &uarta; }; @@ -17,12 +17,12 @@ stdout-path = "serial0:115200n8"; }; - cbb@0 { + bus@0 { serial@3100000 { status = "okay"; }; - sdhci@3460000 { + mmc@3460000 { status = "okay"; bus-width = <8>; non-removable; diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index a94dac76bf3f..59e0cbfa2214 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -179,22 +179,22 @@ }; soc: soc { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0 0 0xffffffff>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0 0 0 0 0x0 0xffffffff>; dma-ranges; compatible = "simple-bus"; prng: qrng@e1000 { compatible = "qcom,prng-ee"; - reg = <0xe3000 0x1000>; + reg = <0x0 0xe3000 0x0 0x1000>; clocks = <&gcc GCC_PRNG_AHB_CLK>; clock-names = "core"; }; cryptobam: dma@704000 { compatible = "qcom,bam-v1.7.0"; - reg = <0x00704000 0x20000>; + reg = <0x0 0x00704000 0x0 0x20000>; interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gcc GCC_CRYPTO_AHB_CLK>; clock-names = "bam_clk"; @@ -206,7 +206,7 @@ crypto: crypto@73a000 { compatible = "qcom,crypto-v5.1"; - reg = <0x0073a000 0x6000>; + reg = <0x0 0x0073a000 0x0 0x6000>; clocks = <&gcc GCC_CRYPTO_AHB_CLK>, <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_CLK>; @@ -217,7 +217,7 @@ tlmm: pinctrl@1000000 { compatible = "qcom,ipq6018-pinctrl"; - reg = <0x01000000 0x300000>; + reg = <0x0 0x01000000 0x0 0x300000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; @@ -235,7 +235,7 @@ gcc: gcc@1800000 { compatible = "qcom,gcc-ipq6018"; - reg = <0x01800000 0x80000>; + reg = <0x0 0x01800000 0x0 0x80000>; clocks = <&xo>, <&sleep_clk>; clock-names = "xo", "sleep_clk"; #clock-cells = <1>; @@ -244,17 +244,17 @@ tcsr_mutex_regs: syscon@1905000 { compatible = "syscon"; - reg = <0x01905000 0x8000>; + reg = <0x0 0x01905000 0x0 0x8000>; }; tcsr_q6: syscon@1945000 { compatible = "syscon"; - reg = <0x01945000 0xe000>; + reg = <0x0 0x01945000 0x0 0xe000>; }; blsp_dma: dma@7884000 { compatible = "qcom,bam-v1.7.0"; - reg = <0x07884000 0x2b000>; + reg = <0x0 0x07884000 0x0 0x2b000>; interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gcc GCC_BLSP1_AHB_CLK>; clock-names = "bam_clk"; @@ -264,7 +264,7 @@ blsp1_uart3: serial@78b1000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; - reg = <0x078b1000 0x200>; + reg = <0x0 0x078b1000 0x0 0x200>; interrupts = <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gcc GCC_BLSP1_UART3_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>; @@ -276,7 +276,7 @@ compatible = "qcom,spi-qup-v2.2.1"; #address-cells = <1>; #size-cells = <0>; - reg = <0x078b5000 0x600>; + reg = <0x0 0x078b5000 0x0 0x600>; interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; spi-max-frequency = <50000000>; clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>, @@ -291,7 +291,7 @@ compatible = "qcom,spi-qup-v2.2.1"; #address-cells = <1>; #size-cells = <0>; - reg = <0x078b6000 0x600>; + reg = <0x0 0x078b6000 0x0 0x600>; interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; spi-max-frequency = <50000000>; clocks = <&gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>, @@ -306,7 +306,7 @@ compatible = "qcom,i2c-qup-v2.2.1"; #address-cells = <1>; #size-cells = <0>; - reg = <0x078b6000 0x600>; + reg = <0x0 0x078b6000 0x0 0x600>; interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gcc GCC_BLSP1_AHB_CLK>, <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; @@ -321,7 +321,7 @@ compatible = "qcom,i2c-qup-v2.2.1"; #address-cells = <1>; #size-cells = <0>; - reg = <0x078b7000 0x600>; + reg = <0x0 0x078b7000 0x0 0x600>; interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; clocks = <&gcc GCC_BLSP1_AHB_CLK>, <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; @@ -336,24 +336,24 @@ compatible = "qcom,msm-qgic2"; interrupt-controller; #interrupt-cells = <0x3>; - reg = <0x0b000000 0x1000>, /*GICD*/ - <0x0b002000 0x1000>, /*GICC*/ - <0x0b001000 0x1000>, /*GICH*/ - <0x0b004000 0x1000>; /*GICV*/ + reg = <0x0 0x0b000000 0x0 0x1000>, /*GICD*/ + <0x0 0x0b002000 0x0 0x1000>, /*GICC*/ + <0x0 0x0b001000 0x0 0x1000>, /*GICH*/ + <0x0 0x0b004000 0x0 0x1000>; /*GICV*/ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>; }; watchdog@b017000 { compatible = "qcom,kpss-wdt"; interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>; - reg = <0x0b017000 0x40>; + reg = <0x0 0x0b017000 0x0 0x40>; clocks = <&sleep_clk>; timeout-sec = <10>; }; apcs_glb: mailbox@b111000 { compatible = "qcom,ipq6018-apcs-apps-global"; - reg = <0x0b111000 0x1000>; + reg = <0x0 0x0b111000 0x0 0x1000>; #clock-cells = <1>; clocks = <&a53pll>, <&xo>; clock-names = "pll", "xo"; @@ -362,7 +362,7 @@ a53pll: clock@b116000 { compatible = "qcom,ipq6018-a53pll"; - reg = <0x0b116000 0x40>; + reg = <0x0 0x0b116000 0x0 0x40>; #clock-cells = <0>; clocks = <&xo>; clock-names = "xo"; @@ -377,68 +377,68 @@ }; timer@b120000 { - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; ranges; compatible = "arm,armv7-timer-mem"; - reg = <0x0b120000 0x1000>; + reg = <0x0 0x0b120000 0x0 0x1000>; clock-frequency = <19200000>; frame@b120000 { frame-number = <0>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b121000 0x1000>, - <0x0b122000 0x1000>; + reg = <0x0 0x0b121000 0x0 0x1000>, + <0x0 0x0b122000 0x0 0x1000>; }; frame@b123000 { frame-number = <1>; interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; - reg = <0xb123000 0x1000>; + reg = <0x0 0xb123000 0x0 0x1000>; status = "disabled"; }; frame@b124000 { frame-number = <2>; interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b124000 0x1000>; + reg = <0x0 0x0b124000 0x0 0x1000>; status = "disabled"; }; frame@b125000 { frame-number = <3>; interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b125000 0x1000>; + reg = <0x0 0x0b125000 0x0 0x1000>; status = "disabled"; }; frame@b126000 { frame-number = <4>; interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b126000 0x1000>; + reg = <0x0 0x0b126000 0x0 0x1000>; status = "disabled"; }; frame@b127000 { frame-number = <5>; interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b127000 0x1000>; + reg = <0x0 0x0b127000 0x0 0x1000>; status = "disabled"; }; frame@b128000 { frame-number = <6>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; - reg = <0x0b128000 0x1000>; + reg = <0x0 0x0b128000 0x0 0x1000>; status = "disabled"; }; }; q6v5_wcss: remoteproc@cd00000 { compatible = "qcom,ipq8074-wcss-pil"; - reg = <0x0cd00000 0x4040>, - <0x004ab000 0x20>; + reg = <0x0 0x0cd00000 0x0 0x4040>, + <0x0 0x004ab000 0x0 0x20>; reg-names = "qdsp6", "rmb"; interrupts-extended = <&intc GIC_SPI 325 IRQ_TYPE_EDGE_RISING>, diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts index 35bd6b904b9c..337681038519 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts @@ -243,7 +243,6 @@ interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "rk808-clkout1", "xin32k"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts index be7a31d81632..2ee07d15a6e3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts @@ -20,7 +20,7 @@ gmac_clk: gmac-clock { compatible = "fixed-clock"; clock-frequency = <125000000>; - clock-output-names = "gmac_clk"; + clock-output-names = "gmac_clkin"; #clock-cells = <0>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi index e7a459fa4322..20309076dbac 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi @@ -74,14 +74,14 @@ label = "red:diy"; gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "mmc1"; + linux,default-trigger = "mmc2"; }; yellow_led: led-2 { label = "yellow:yellow-led"; gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "mmc0"; + linux,default-trigger = "mmc1"; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index ada724b12f01..7a9a7aca86c6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -29,6 +29,9 @@ i2c6 = &i2c6; i2c7 = &i2c7; i2c8 = &i2c8; + mmc0 = &sdio0; + mmc1 = &sdmmc; + mmc2 = &sdhci; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 4ff12a7adcfd..5628289b9d5e 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -115,8 +115,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID)) #define pte_valid_not_user(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID) -#define pte_valid_young(pte) \ - ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF)) #define pte_valid_user(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) @@ -124,9 +122,12 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; * Could the pte be present in the TLB? We must check mm_tlb_flush_pending * so that we don't erroneously return false for pages that have been * remapped as PROT_NONE but are yet to be flushed from the TLB. + * Note that we can't make any assumptions based on the state of the access + * flag, since ptep_clear_flush_young() elides a DSB when invalidating the + * TLB. */ #define pte_accessible(mm, pte) \ - (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte)) + (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte)) /* * p??_access_permitted() is true for valid user mappings (subject to the @@ -164,13 +165,6 @@ static inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot) return pmd; } -static inline pte_t pte_wrprotect(pte_t pte) -{ - pte = clear_pte_bit(pte, __pgprot(PTE_WRITE)); - pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); - return pte; -} - static inline pte_t pte_mkwrite(pte_t pte) { pte = set_pte_bit(pte, __pgprot(PTE_WRITE)); @@ -196,6 +190,20 @@ static inline pte_t pte_mkdirty(pte_t pte) return pte; } +static inline pte_t pte_wrprotect(pte_t pte) +{ + /* + * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY + * clear), set the PTE_DIRTY bit. + */ + if (pte_hw_dirty(pte)) + pte = pte_mkdirty(pte); + + pte = clear_pte_bit(pte, __pgprot(PTE_WRITE)); + pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); + return pte; +} + static inline pte_t pte_mkold(pte_t pte) { return clear_pte_bit(pte, __pgprot(PTE_AF)); @@ -845,12 +853,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres pte = READ_ONCE(*ptep); do { old_pte = pte; - /* - * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY - * clear), set the PTE_DIRTY bit. - */ - if (pte_hw_dirty(pte)) - pte = pte_mkdirty(pte); pte = pte_wrprotect(pte); pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), pte_val(old_pte), pte_val(pte)); diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h index 4266262101fe..006946745352 100644 --- a/arch/arm64/include/asm/probes.h +++ b/arch/arm64/include/asm/probes.h @@ -7,6 +7,8 @@ #ifndef _ARM_PROBES_H #define _ARM_PROBES_H +#include <asm/insn.h> + typedef u32 probe_opcode_t; typedef void (probes_handler_t) (u32 opcode, long addr, struct pt_regs *); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S index bb2d986ff696..a797abace13f 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S +++ b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S @@ -13,6 +13,11 @@ SECTIONS { HYP_SECTION(.text) + /* + * .hyp..data..percpu needs to be page aligned to maintain the same + * alignment for when linking into vmlinux. + */ + . = ALIGN(PAGE_SIZE); HYP_SECTION_NAME(.data..percpu) : { PERCPU_INPUT(L1_CACHE_BYTES) } diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 52d6f24f65dc..15a6c98ee92f 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -273,6 +273,23 @@ static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu, return extract_bytes(value, addr & 7, len); } +static unsigned long vgic_uaccess_read_v3r_typer(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len) +{ + unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu); + int target_vcpu_id = vcpu->vcpu_id; + u64 value; + + value = (u64)(mpidr & GENMASK(23, 0)) << 32; + value |= ((target_vcpu_id & 0xffff) << 8); + + if (vgic_has_its(vcpu->kvm)) + value |= GICR_TYPER_PLPIS; + + /* reporting of the Last bit is not supported for userspace */ + return extract_bytes(value, addr & 7, len); +} + static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len) { @@ -593,8 +610,9 @@ static const struct vgic_register_region vgic_v3_rd_registers[] = { REGISTER_DESC_WITH_LENGTH(GICR_IIDR, vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4, VGIC_ACCESS_32bit), - REGISTER_DESC_WITH_LENGTH(GICR_TYPER, - vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8, + REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_TYPER, + vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, + vgic_uaccess_read_v3r_typer, vgic_mmio_uaccess_write_wi, 8, VGIC_ACCESS_64bit | VGIC_ACCESS_32bit), REGISTER_DESC_WITH_LENGTH(GICR_WAKER, vgic_mmio_read_raz, vgic_mmio_write_wi, 4, diff --git a/arch/ia64/include/asm/sparsemem.h b/arch/ia64/include/asm/sparsemem.h index 336d0570e1fa..dd8c166ffd7b 100644 --- a/arch/ia64/include/asm/sparsemem.h +++ b/arch/ia64/include/asm/sparsemem.h @@ -18,4 +18,10 @@ #endif #endif /* CONFIG_SPARSEMEM */ + +#ifdef CONFIG_MEMORY_HOTPLUG +int memory_add_physaddr_to_nid(u64 addr); +#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid +#endif + #endif /* _ASM_IA64_SPARSEMEM_H */ diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index a950fc1ddb4d..6c0532d7b211 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -154,6 +154,7 @@ static inline void pmd_clear(pmd_t *pmdp) #if defined(CONFIG_XPA) +#define MAX_POSSIBLE_PHYSMEM_BITS 40 #define pte_pfn(x) (((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT)) static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) @@ -169,6 +170,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#define MAX_POSSIBLE_PHYSMEM_BITS 36 #define pte_pfn(x) ((unsigned long)((x).pte_high >> 6)) static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) @@ -183,6 +185,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) #else +#define MAX_POSSIBLE_PHYSMEM_BITS 32 #ifdef CONFIG_CPU_VR41XX #define pte_pfn(x) ((unsigned long)((x).pte >> (PAGE_SHIFT + 2))) #define pfn_pte(pfn, prot) __pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot)) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a4d56f0a41d9..16b8336f91dd 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -248,7 +248,6 @@ KBUILD_CFLAGS += $(call cc-option,-mno-string) cpu-as-$(CONFIG_40x) += -Wa,-m405 cpu-as-$(CONFIG_44x) += -Wa,-m440 cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) -cpu-as-$(CONFIG_E200) += -Wa,-me200 cpu-as-$(CONFIG_E500) += -Wa,-me500 # When using '-many -mpower4' gas will first try and find a matching power4 diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 36443cda8dcf..1376be95e975 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -36,8 +36,10 @@ static inline bool pte_user(pte_t pte) */ #ifdef CONFIG_PTE_64BIT #define PTE_RPN_MASK (~((1ULL << PTE_RPN_SHIFT) - 1)) +#define MAX_POSSIBLE_PHYSMEM_BITS 36 #else #define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) +#define MAX_POSSIBLE_PHYSMEM_BITS 32 #endif /* diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup-radix.h index 28716e2f13e3..a39e2d193fdc 100644 --- a/arch/powerpc/include/asm/book3s/64/kup-radix.h +++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h @@ -63,6 +63,8 @@ #else /* !__ASSEMBLY__ */ +#include <linux/jump_label.h> + DECLARE_STATIC_KEY_FALSE(uaccess_flush_key); #ifdef CONFIG_PPC_KUAP diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h index 91c69ff53a8a..6cda76b57c5d 100644 --- a/arch/powerpc/include/asm/mmzone.h +++ b/arch/powerpc/include/asm/mmzone.h @@ -46,5 +46,10 @@ u64 memory_hotplug_max(void); #define __HAVE_ARCH_RESERVED_KERNEL_PAGES #endif +#ifdef CONFIG_MEMORY_HOTPLUG +extern int create_section_mapping(unsigned long start, unsigned long end, + int nid, pgprot_t prot); +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_MMZONE_H_ */ diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index ee2243ba96cf..96522f7f0618 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -153,8 +153,10 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot); */ #if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) #define PTE_RPN_MASK (~((1ULL << PTE_RPN_SHIFT) - 1)) +#define MAX_POSSIBLE_PHYSMEM_BITS 36 #else #define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) +#define MAX_POSSIBLE_PHYSMEM_BITS 32 #endif /* diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 1e6fa371cc38..d072866842e4 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -13,9 +13,9 @@ #endif /* CONFIG_SPARSEMEM */ #ifdef CONFIG_MEMORY_HOTPLUG -extern int create_section_mapping(unsigned long start, unsigned long end, - int nid, pgprot_t prot); extern int remove_section_mapping(unsigned long start, unsigned long end); +extern int memory_add_physaddr_to_nid(u64 start); +#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid #ifdef CONFIG_NUMA extern int hot_add_scn_to_nid(unsigned long scn_addr); @@ -26,6 +26,5 @@ static inline int hot_add_scn_to_nid(unsigned long scn_addr) } #endif /* CONFIG_NUMA */ #endif /* CONFIG_MEMORY_HOTPLUG */ - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SPARSEMEM_H */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index f63a3d3bca3d..4d01f09ecf80 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1000,8 +1000,6 @@ TRAMP_REAL_BEGIN(system_reset_idle_wake) * Vectors for the FWNMI option. Share common code. */ TRAMP_REAL_BEGIN(system_reset_fwnmi) - /* XXX: fwnmi guest could run a nested/PR guest, so why no test? */ - __IKVM_REAL(system_reset)=0 GEN_INT_ENTRY system_reset, virt=0 #endif /* CONFIG_PPC_PSERIES */ @@ -1412,6 +1410,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) * If none is found, do a Linux page fault. Linux page faults can happen in * kernel mode due to user copy operations of course. * + * KVM: The KVM HDSI handler may perform a load with MSR[DR]=1 in guest + * MMU context, which may cause a DSI in the host, which must go to the + * KVM handler. MSR[IR] is not enabled, so the real-mode handler will + * always be used regardless of AIL setting. + * * - Radix MMU * The hardware loads from the Linux page table directly, so a fault goes * immediately to Linux page fault. @@ -1422,10 +1425,8 @@ INT_DEFINE_BEGIN(data_access) IVEC=0x300 IDAR=1 IDSISR=1 -#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE IKVM_SKIP=1 IKVM_REAL=1 -#endif INT_DEFINE_END(data_access) EXC_REAL_BEGIN(data_access, 0x300, 0x80) @@ -1464,6 +1465,8 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) * ppc64_bolted_size (first segment). The kernel handler must avoid stomping * on user-handler data structures. * + * KVM: Same as 0x300, DSLB must test for KVM guest. + * * A dedicated save area EXSLB is used (XXX: but it actually need not be * these days, we could use EXGEN). */ @@ -1472,10 +1475,8 @@ INT_DEFINE_BEGIN(data_access_slb) IAREA=PACA_EXSLB IRECONCILE=0 IDAR=1 -#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE IKVM_SKIP=1 IKVM_REAL=1 -#endif INT_DEFINE_END(data_access_slb) EXC_REAL_BEGIN(data_access_slb, 0x380, 0x80) diff --git a/arch/powerpc/kernel/head_book3s_32.S b/arch/powerpc/kernel/head_book3s_32.S index 2aa16d5368e1..a0dda2a1f2df 100644 --- a/arch/powerpc/kernel/head_book3s_32.S +++ b/arch/powerpc/kernel/head_book3s_32.S @@ -156,6 +156,7 @@ __after_mmu_off: bl initial_bats bl load_segment_registers BEGIN_MMU_FTR_SECTION + bl reloc_offset bl early_hash_table END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE) #if defined(CONFIG_BOOTX_TEXT) @@ -920,7 +921,7 @@ early_hash_table: ori r6, r6, 3 /* 256kB table */ mtspr SPRN_SDR1, r6 lis r6, early_hash@h - lis r3, Hash@ha + addis r3, r3, Hash@ha stw r6, Hash@l(r3) blr diff --git a/arch/powerpc/kvm/book3s_xive_native.c b/arch/powerpc/kvm/book3s_xive_native.c index d0c2db0e07fa..a59a94f02733 100644 --- a/arch/powerpc/kvm/book3s_xive_native.c +++ b/arch/powerpc/kvm/book3s_xive_native.c @@ -251,6 +251,13 @@ static vm_fault_t xive_native_esb_fault(struct vm_fault *vmf) } state = &sb->irq_state[src]; + + /* Some sanity checking */ + if (!state->valid) { + pr_devel("%s: source %lx invalid !\n", __func__, irq); + return VM_FAULT_SIGBUS; + } + kvmppc_xive_select_irq(state, &hw_num, &xd); arch_spin_lock(&sb->lock); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 01ec2a252f09..3fc325bebe4d 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -50,6 +50,7 @@ #include <asm/rtas.h> #include <asm/kasan.h> #include <asm/svm.h> +#include <asm/mmzone.h> #include <mm/mmu_decl.h> diff --git a/arch/riscv/include/asm/pgtable-32.h b/arch/riscv/include/asm/pgtable-32.h index b0ab66e5fdb1..5b2e79e5bfa5 100644 --- a/arch/riscv/include/asm/pgtable-32.h +++ b/arch/riscv/include/asm/pgtable-32.h @@ -14,4 +14,6 @@ #define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE - 1)) +#define MAX_POSSIBLE_PHYSMEM_BITS 34 + #endif /* _ASM_RISCV_PGTABLE_32_H */ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 2012c1cf0853..483051e10db3 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -53,11 +53,11 @@ int main(void) /* stack_frame offsets */ OFFSET(__SF_BACKCHAIN, stack_frame, back_chain); OFFSET(__SF_GPRS, stack_frame, gprs); - OFFSET(__SF_EMPTY, stack_frame, empty1); - OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[0]); - OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[1]); - OFFSET(__SF_SIE_REASON, stack_frame, empty1[2]); - OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[3]); + OFFSET(__SF_EMPTY, stack_frame, empty1[0]); + OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[1]); + OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[2]); + OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]); + OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]); BLANK(); OFFSET(__VDSO_GETCPU_VAL, vdso_per_cpu_data, getcpu_val); BLANK(); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 5346545b9860..26bb0603c5a1 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -1068,6 +1068,7 @@ EXPORT_SYMBOL(save_fpu_regs) * %r4 */ load_fpu_regs: + stnsm __SF_EMPTY(%r15),0xfc lg %r4,__LC_CURRENT aghi %r4,__TASK_thread TSTMSK __LC_CPU_FLAGS,_CIF_FPU @@ -1099,6 +1100,7 @@ load_fpu_regs: .Lload_fpu_regs_done: ni __LC_CPU_FLAGS+7,255-_CIF_FPU .Lload_fpu_regs_exit: + ssm __SF_EMPTY(%r15) BR_EX %r14 .Lload_fpu_regs_end: ENDPROC(load_fpu_regs) diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 14bd9d58edc9..883bfed9f5c2 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -129,8 +129,15 @@ int uv_destroy_page(unsigned long paddr) .paddr = paddr }; - if (uv_call(0, (u64)&uvcb)) + if (uv_call(0, (u64)&uvcb)) { + /* + * Older firmware uses 107/d as an indication of a non secure + * page. Let us emulate the newer variant (no-op). + */ + if (uvcb.header.rc == 0x107 && uvcb.header.rrc == 0xd) + return 0; return -EINVAL; + } return 0; } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 6b74b92c1a58..425d3d75320b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2312,7 +2312,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) struct kvm_s390_pv_unp unp = {}; r = -EINVAL; - if (!kvm_s390_pv_is_protected(kvm)) + if (!kvm_s390_pv_is_protected(kvm) || !mm_is_protected(kvm->mm)) break; r = -EFAULT; @@ -3564,7 +3564,6 @@ static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->pp = 0; vcpu->arch.sie_block->fpf &= ~FPF_BPBC; vcpu->arch.sie_block->todpr = 0; - vcpu->arch.sie_block->cpnc = 0; } } @@ -3582,7 +3581,6 @@ static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu) regs->etoken = 0; regs->etoken_extension = 0; - regs->diag318 = 0; } int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index eb99e2f95ebe..f5847f9dec7c 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -208,7 +208,6 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) return -EIO; } kvm->arch.gmap->guest_handle = uvcb.guest_handle; - atomic_set(&kvm->mm->context.is_protected, 1); return 0; } @@ -228,6 +227,8 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, *rrc = uvcb.header.rrc; KVM_UV_EVENT(kvm, 3, "PROTVIRT VM SET PARMS: rc %x rrc %x", *rc, *rrc); + if (!cc) + atomic_set(&kvm->mm->context.is_protected, 1); return cc ? -EINVAL : 0; } diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index cfb0017f33a7..64795d034926 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2690,6 +2690,8 @@ static const struct mm_walk_ops reset_acc_walk_ops = { #include <linux/sched/mm.h> void s390_reset_acc(struct mm_struct *mm) { + if (!mm_is_protected(mm)) + return; /* * we might be called during * reset: we walk the pages and clear diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 442e1ed4acd4..4eb7ee5fed72 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -107,14 +107,14 @@ MODULE_LICENSE("GPL"); #define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format) \ -static ssize_t __cstate_##_var##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ +static ssize_t __cstate_##_var##_show(struct device *dev, \ + struct device_attribute *attr, \ char *page) \ { \ BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ return sprintf(page, _format "\n"); \ } \ -static struct kobj_attribute format_attr_##_var = \ +static struct device_attribute format_attr_##_var = \ __ATTR(_name, 0444, __cstate_##_var##_show, NULL) static ssize_t cstate_get_attr_cpumask(struct device *dev, diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 86d012b3e0b4..80d52cbe2fde 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -94,8 +94,8 @@ end: return map; } -ssize_t uncore_event_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +ssize_t uncore_event_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct uncore_event_desc *event = container_of(attr, struct uncore_event_desc, attr); diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h index 83d2a7d490e0..9efea154349d 100644 --- a/arch/x86/events/intel/uncore.h +++ b/arch/x86/events/intel/uncore.h @@ -157,7 +157,7 @@ struct intel_uncore_box { #define UNCORE_BOX_FLAG_CFL8_CBOX_MSR_OFFS 2 struct uncore_event_desc { - struct kobj_attribute attr; + struct device_attribute attr; const char *config; }; @@ -179,8 +179,8 @@ struct pci2phy_map { struct pci2phy_map *__find_pci2phy_map(int segment); int uncore_pcibus_to_physid(struct pci_bus *bus); -ssize_t uncore_event_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf); +ssize_t uncore_event_show(struct device *dev, + struct device_attribute *attr, char *buf); static inline struct intel_uncore_pmu *dev_to_uncore_pmu(struct device *dev) { @@ -201,14 +201,14 @@ extern int __uncore_max_dies; } #define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format) \ -static ssize_t __uncore_##_var##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ +static ssize_t __uncore_##_var##_show(struct device *dev, \ + struct device_attribute *attr, \ char *page) \ { \ BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ return sprintf(page, _format "\n"); \ } \ -static struct kobj_attribute format_attr_##_var = \ +static struct device_attribute format_attr_##_var = \ __ATTR(_name, 0444, __uncore_##_var##_show, NULL) static inline bool uncore_pmc_fixed(int idx) diff --git a/arch/x86/events/rapl.c b/arch/x86/events/rapl.c index 7c0120e2e957..7dbbeaacd995 100644 --- a/arch/x86/events/rapl.c +++ b/arch/x86/events/rapl.c @@ -93,18 +93,6 @@ static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { * any other bit is reserved */ #define RAPL_EVENT_MASK 0xFFULL - -#define DEFINE_RAPL_FORMAT_ATTR(_var, _name, _format) \ -static ssize_t __rapl_##_var##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ - char *page) \ -{ \ - BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ - return sprintf(page, _format "\n"); \ -} \ -static struct kobj_attribute format_attr_##_var = \ - __ATTR(_name, 0444, __rapl_##_var##_show, NULL) - #define RAPL_CNTR_WIDTH 32 #define RAPL_EVENT_ATTR_STR(_name, v, str) \ @@ -441,7 +429,7 @@ static struct attribute_group rapl_pmu_events_group = { .attrs = attrs_empty, }; -DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7"); +PMU_FORMAT_ATTR(event, "config:0-7"); static struct attribute *rapl_formats_attr[] = { &format_attr_event.attr, NULL, diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 324ddd7fd0aa..7e5f33a0d0e2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1656,6 +1656,7 @@ int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_cpu_has_extint(struct kvm_vcpu *v); int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); int kvm_cpu_get_interrupt(struct kvm_vcpu *v); void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event); diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h index 6bfc878f6771..6a9ccc1b2be5 100644 --- a/arch/x86/include/asm/sparsemem.h +++ b/arch/x86/include/asm/sparsemem.h @@ -28,4 +28,14 @@ #endif #endif /* CONFIG_SPARSEMEM */ + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_NUMA_KEEP_MEMINFO +extern int phys_to_target_node(phys_addr_t start); +#define phys_to_target_node phys_to_target_node +extern int memory_add_physaddr_to_nid(u64 start); +#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid +#endif +#endif /* __ASSEMBLY__ */ + #endif /* _ASM_X86_SPARSEMEM_H */ diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 6a99535d7f37..7e8e07bddd5f 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -100,53 +100,6 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev return find_matching_signature(mc, csig, cpf); } -/* - * Given CPU signature and a microcode patch, this function finds if the - * microcode patch has matching family and model with the CPU. - * - * %true - if there's a match - * %false - otherwise - */ -static bool microcode_matches(struct microcode_header_intel *mc_header, - unsigned long sig) -{ - unsigned long total_size = get_totalsize(mc_header); - unsigned long data_size = get_datasize(mc_header); - struct extended_sigtable *ext_header; - unsigned int fam_ucode, model_ucode; - struct extended_signature *ext_sig; - unsigned int fam, model; - int ext_sigcount, i; - - fam = x86_family(sig); - model = x86_model(sig); - - fam_ucode = x86_family(mc_header->sig); - model_ucode = x86_model(mc_header->sig); - - if (fam == fam_ucode && model == model_ucode) - return true; - - /* Look for ext. headers: */ - if (total_size <= data_size + MC_HEADER_SIZE) - return false; - - ext_header = (void *) mc_header + data_size + MC_HEADER_SIZE; - ext_sig = (void *)ext_header + EXT_HEADER_SIZE; - ext_sigcount = ext_header->count; - - for (i = 0; i < ext_sigcount; i++) { - fam_ucode = x86_family(ext_sig->sig); - model_ucode = x86_model(ext_sig->sig); - - if (fam == fam_ucode && model == model_ucode) - return true; - - ext_sig++; - } - return false; -} - static struct ucode_patch *memdup_patch(void *data, unsigned int size) { struct ucode_patch *p; @@ -164,7 +117,7 @@ static struct ucode_patch *memdup_patch(void *data, unsigned int size) return p; } -static void save_microcode_patch(void *data, unsigned int size) +static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size) { struct microcode_header_intel *mc_hdr, *mc_saved_hdr; struct ucode_patch *iter, *tmp, *p = NULL; @@ -210,6 +163,9 @@ static void save_microcode_patch(void *data, unsigned int size) if (!p) return; + if (!find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf)) + return; + /* * Save for early loading. On 32-bit, that needs to be a physical * address as the APs are running from physical addresses, before @@ -344,13 +300,14 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save) size -= mc_size; - if (!microcode_matches(mc_header, uci->cpu_sig.sig)) { + if (!find_matching_signature(data, uci->cpu_sig.sig, + uci->cpu_sig.pf)) { data += mc_size; continue; } if (save) { - save_microcode_patch(data, mc_size); + save_microcode_patch(uci, data, mc_size); goto next; } @@ -483,14 +440,14 @@ static void show_saved_mc(void) * Save this microcode patch. It will be loaded early when a CPU is * hot-added or resumes. */ -static void save_mc_for_early(u8 *mc, unsigned int size) +static void save_mc_for_early(struct ucode_cpu_info *uci, u8 *mc, unsigned int size) { /* Synchronization during CPU hotplug. */ static DEFINE_MUTEX(x86_cpu_microcode_mutex); mutex_lock(&x86_cpu_microcode_mutex); - save_microcode_patch(mc, size); + save_microcode_patch(uci, mc, size); show_saved_mc(); mutex_unlock(&x86_cpu_microcode_mutex); @@ -935,7 +892,7 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter) * permanent memory. So it will be loaded early when a CPU is hot added * or resumes. */ - save_mc_for_early(new_mc, new_mc_size); + save_mc_for_early(uci, new_mc, new_mc_size); pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", cpu, new_rev, uci->cpu_sig.rev); diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 25c06b67e7e0..97aa900386cb 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src, if (!user_mode(regs)) return copy_from_kernel_nofault(buf, (u8 *)src, nbytes); + /* The user space code from other tasks cannot be accessed. */ + if (regs != task_pt_regs(current)) + return -EPERM; /* * Make sure userspace isn't trying to trick us into dumping kernel * memory by pointing the userspace instruction pointer at it. @@ -85,6 +88,12 @@ static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src, if (__chk_range_not_ok(src, nbytes, TASK_SIZE_MAX)) return -EINVAL; + /* + * Even if named copy_from_user_nmi() this can be invoked from + * other contexts and will not try to resolve a pagefault, which is + * the correct thing to do here as this code can be called from any + * context. + */ return copy_from_user_nmi(buf, (void __user *)src, nbytes); } @@ -115,13 +124,19 @@ void show_opcodes(struct pt_regs *regs, const char *loglvl) u8 opcodes[OPCODE_BUFSIZE]; unsigned long prologue = regs->ip - PROLOGUE_SIZE; - if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) { - printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n", - loglvl, prologue); - } else { + switch (copy_code(regs, opcodes, prologue, sizeof(opcodes))) { + case 0: printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %" __stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes, opcodes[PROLOGUE_SIZE], opcodes + PROLOGUE_SIZE + 1); + break; + case -EPERM: + /* No access to the user space stack of other tasks. Ignore. */ + break; + default: + printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n", + loglvl, prologue); + break; } } diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index 992fb1415c0f..ae64f98ec2ab 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -514,16 +514,10 @@ int tboot_force_iommu(void) if (!tboot_enabled()) return 0; - if (intel_iommu_tboot_noforce) - return 1; - - if (no_iommu || swiotlb || dmar_disabled) + if (no_iommu || dmar_disabled) pr_warn("Forcing Intel-IOMMU to enabled\n"); dmar_disabled = 0; -#ifdef CONFIG_SWIOTLB - swiotlb = 0; -#endif no_iommu = 0; return 1; diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 99d118ffc67d..814698e5b152 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -40,29 +40,10 @@ static int pending_userspace_extint(struct kvm_vcpu *v) * check if there is pending interrupt from * non-APIC source without intack. */ -static int kvm_cpu_has_extint(struct kvm_vcpu *v) -{ - u8 accept = kvm_apic_accept_pic_intr(v); - - if (accept) { - if (irqchip_split(v->kvm)) - return pending_userspace_extint(v); - else - return v->kvm->arch.vpic->output; - } else - return 0; -} - -/* - * check if there is injectable interrupt: - * when virtual interrupt delivery enabled, - * interrupt from apic will handled by hardware, - * we don't need to check it here. - */ -int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) +int kvm_cpu_has_extint(struct kvm_vcpu *v) { /* - * FIXME: interrupt.injected represents an interrupt that it's + * FIXME: interrupt.injected represents an interrupt whose * side-effects have already been applied (e.g. bit from IRR * already moved to ISR). Therefore, it is incorrect to rely * on interrupt.injected to know if there is a pending @@ -75,6 +56,23 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) if (!lapic_in_kernel(v)) return v->arch.interrupt.injected; + if (!kvm_apic_accept_pic_intr(v)) + return 0; + + if (irqchip_split(v->kvm)) + return pending_userspace_extint(v); + else + return v->kvm->arch.vpic->output; +} + +/* + * check if there is injectable interrupt: + * when virtual interrupt delivery enabled, + * interrupt from apic will handled by hardware, + * we don't need to check it here. + */ +int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) +{ if (kvm_cpu_has_extint(v)) return 1; @@ -91,20 +89,6 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr); */ int kvm_cpu_has_interrupt(struct kvm_vcpu *v) { - /* - * FIXME: interrupt.injected represents an interrupt that it's - * side-effects have already been applied (e.g. bit from IRR - * already moved to ISR). Therefore, it is incorrect to rely - * on interrupt.injected to know if there is a pending - * interrupt in the user-mode LAPIC. - * This leads to nVMX/nSVM not be able to distinguish - * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on - * pending interrupt or should re-inject an injected - * interrupt. - */ - if (!lapic_in_kernel(v)) - return v->arch.interrupt.injected; - if (kvm_cpu_has_extint(v)) return 1; @@ -118,16 +102,21 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); */ static int kvm_cpu_get_extint(struct kvm_vcpu *v) { - if (kvm_cpu_has_extint(v)) { - if (irqchip_split(v->kvm)) { - int vector = v->arch.pending_external_vector; - - v->arch.pending_external_vector = -1; - return vector; - } else - return kvm_pic_read_irq(v->kvm); /* PIC */ - } else + if (!kvm_cpu_has_extint(v)) { + WARN_ON(!lapic_in_kernel(v)); return -1; + } + + if (!lapic_in_kernel(v)) + return v->arch.interrupt.nr; + + if (irqchip_split(v->kvm)) { + int vector = v->arch.pending_external_vector; + + v->arch.pending_external_vector = -1; + return vector; + } else + return kvm_pic_read_irq(v->kvm); /* PIC */ } /* @@ -135,13 +124,7 @@ static int kvm_cpu_get_extint(struct kvm_vcpu *v) */ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) { - int vector; - - if (!lapic_in_kernel(v)) - return v->arch.interrupt.nr; - - vector = kvm_cpu_get_extint(v); - + int vector = kvm_cpu_get_extint(v); if (vector != -1) return vector; /* PIC */ diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 105e7859d1f2..86c33d53c90a 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2465,7 +2465,7 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) struct kvm_lapic *apic = vcpu->arch.apic; u32 ppr; - if (!kvm_apic_hw_enabled(apic)) + if (!kvm_apic_present(vcpu)) return -1; __apic_update_ppr(apic, &ppr); diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 5bb1939b65d8..7a6ae9e90bd7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3517,7 +3517,7 @@ static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) { u64 sptes[PT64_ROOT_MAX_LEVEL]; struct rsvd_bits_validate *rsvd_check; - int root = vcpu->arch.mmu->root_level; + int root = vcpu->arch.mmu->shadow_root_level; int leaf; int level; bool reserved = false; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index c0b14106258a..566f4d18185b 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -642,8 +642,8 @@ static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr, * Its safe to read more than we are asked, caller should ensure that * destination has enough space. */ - src_paddr = round_down(src_paddr, 16); offset = src_paddr & 15; + src_paddr = round_down(src_paddr, 16); sz = round_up(sz + offset, 16); return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 1e81cfebd491..79b3a564f1c9 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1309,8 +1309,10 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) svm->avic_is_running = true; svm->msrpm = svm_vcpu_alloc_msrpm(); - if (!svm->msrpm) + if (!svm->msrpm) { + err = -ENOMEM; goto error_free_vmcb_page; + } svm_vcpu_init_msrpm(vcpu, svm->msrpm); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 078a39d489fe..e545a8a613b1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4051,21 +4051,23 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu) { + /* + * We can accept userspace's request for interrupt injection + * as long as we have a place to store the interrupt number. + * The actual injection will happen when the CPU is able to + * deliver the interrupt. + */ + if (kvm_cpu_has_extint(vcpu)) + return false; + + /* Acknowledging ExtINT does not happen if LINT0 is masked. */ return (!lapic_in_kernel(vcpu) || kvm_apic_accept_pic_intr(vcpu)); } -/* - * if userspace requested an interrupt window, check that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu) { return kvm_arch_interrupt_allowed(vcpu) && - !kvm_cpu_has_interrupt(vcpu) && - !kvm_event_needs_reinjection(vcpu) && kvm_cpu_accept_dm_intr(vcpu); } diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 44148691d78b..5eb4dc2b97da 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -938,6 +938,7 @@ int phys_to_target_node(phys_addr_t start) return meminfo_to_nid(&numa_reserved_meminfo, start); } +EXPORT_SYMBOL_GPL(phys_to_target_node); int memory_add_physaddr_to_nid(u64 start) { @@ -947,4 +948,5 @@ int memory_add_physaddr_to_nid(u64 start) nid = numa_meminfo.blk[0].nid; return nid; } +EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); #endif diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 8f5759df7776..e1e8d4e3a213 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -78,28 +78,30 @@ int __init efi_alloc_page_tables(void) gfp_mask = GFP_KERNEL | __GFP_ZERO; efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER); if (!efi_pgd) - return -ENOMEM; + goto fail; pgd = efi_pgd + pgd_index(EFI_VA_END); p4d = p4d_alloc(&init_mm, pgd, EFI_VA_END); - if (!p4d) { - free_page((unsigned long)efi_pgd); - return -ENOMEM; - } + if (!p4d) + goto free_pgd; pud = pud_alloc(&init_mm, p4d, EFI_VA_END); - if (!pud) { - if (pgtable_l5_enabled()) - free_page((unsigned long) pgd_page_vaddr(*pgd)); - free_pages((unsigned long)efi_pgd, PGD_ALLOCATION_ORDER); - return -ENOMEM; - } + if (!pud) + goto free_p4d; efi_mm.pgd = efi_pgd; mm_init_cpumask(&efi_mm); init_new_context(NULL, &efi_mm); return 0; + +free_p4d: + if (pgtable_l5_enabled()) + free_page((unsigned long)pgd_page_vaddr(*pgd)); +free_pgd: + free_pages((unsigned long)efi_pgd, PGD_ALLOCATION_ORDER); +fail: + return -ENOMEM; } /* diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 799f4eba0a62..043c73dfd2c9 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -93,10 +93,20 @@ void xen_init_lock_cpu(int cpu) void xen_uninit_lock_cpu(int cpu) { + int irq; + if (!xen_pvspin) return; - unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL); + /* + * When booting the kernel with 'mitigations=auto,nosmt', the secondary + * CPUs are not activated, and lock_kicker_irq is not initialized. + */ + irq = per_cpu(lock_kicker_irq, cpu); + if (irq == -1) + return; + + unbind_from_irqhandler(irq, NULL); per_cpu(lock_kicker_irq, cpu) = -1; kfree(per_cpu(irq_name, cpu)); per_cpu(irq_name, cpu) = NULL; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index c68bdf58c9a6..54fbe1e80cc4 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -849,6 +849,7 @@ static void blkcg_fill_root_iostats(void) blkg_iostat_set(&blkg->iostat.cur, &tmp); u64_stats_update_end(&blkg->iostat.sync); } + disk_put_part(part); } } diff --git a/block/blk-flush.c b/block/blk-flush.c index e32958f0b687..fd5cee9f1a3b 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -225,13 +225,18 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error) /* release the tag's ownership to the req cloned from */ spin_lock_irqsave(&fq->mq_flush_lock, flags); - WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE); if (!refcount_dec_and_test(&flush_rq->ref)) { fq->rq_status = error; spin_unlock_irqrestore(&fq->mq_flush_lock, flags); return; } + /* + * Flush request has to be marked as IDLE when it is really ended + * because its .end_io() is called from timeout code path too for + * avoiding use-after-free. + */ + WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE); if (fq->rq_status != BLK_STS_OK) error = fq->rq_status; diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c index 35abcb1ec051..86f8195d8039 100644 --- a/block/keyslot-manager.c +++ b/block/keyslot-manager.c @@ -103,6 +103,13 @@ int blk_ksm_init(struct blk_keyslot_manager *ksm, unsigned int num_slots) spin_lock_init(&ksm->idle_slots_lock); slot_hashtable_size = roundup_pow_of_two(num_slots); + /* + * hash_ptr() assumes bits != 0, so ensure the hash table has at least 2 + * buckets. This only makes a difference when there is only 1 keyslot. + */ + if (slot_hashtable_size < 2) + slot_hashtable_size = 2; + ksm->log_slot_ht_size = ilog2(slot_hashtable_size); ksm->slot_hashtable = kvmalloc_array(slot_hashtable_size, sizeof(ksm->slot_hashtable[0]), diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index ecc39983e946..669392f31d4e 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -49,15 +49,25 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty) if (!tty->ops->write) return -EOPNOTSUPP; + + mutex_lock(&speakup_tty_mutex); + if (speakup_tty) { + mutex_unlock(&speakup_tty_mutex); + return -EBUSY; + } speakup_tty = tty; ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL); - if (!ldisc_data) + if (!ldisc_data) { + speakup_tty = NULL; + mutex_unlock(&speakup_tty_mutex); return -ENOMEM; + } init_completion(&ldisc_data->completion); ldisc_data->buf_free = true; speakup_tty->disc_data = ldisc_data; + mutex_unlock(&speakup_tty_mutex); return 0; } diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 9929ff50c0c0..770d84071a32 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -44,7 +44,7 @@ static DEFINE_SPINLOCK(iort_fwnode_lock); * iort_set_fwnode() - Create iort_fwnode and use it to register * iommu data in the iort_fwnode_list * - * @node: IORT table node associated with the IOMMU + * @iort_node: IORT table node associated with the IOMMU * @fwnode: fwnode associated with the IORT node * * Returns: 0 on success @@ -673,7 +673,8 @@ static int iort_dev_find_its_id(struct device *dev, u32 id, /** * iort_get_device_domain() - Find MSI domain related to a device * @dev: The device. - * @req_id: Requester ID for the device. + * @id: Requester ID for the device. + * @bus_token: irq domain bus token. * * Returns: the MSI domain for this device, NULL otherwise */ @@ -1136,7 +1137,7 @@ static int rc_dma_get_range(struct device *dev, u64 *size) * * @dev: device to configure * @dma_addr: device DMA address result pointer - * @size: DMA range size result pointer + * @dma_size: DMA range size result pointer */ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) { @@ -1526,6 +1527,7 @@ static __init const struct iort_dev_config *iort_get_dev_cfg( /** * iort_add_platform_device() - Allocate a platform device for IORT node * @node: Pointer to device ACPI IORT node + * @ops: Pointer to IORT device config struct * * Returns: 0 on success, <0 failure */ diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index efb088df1276..92ecf1a78ec7 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -227,6 +227,9 @@ static int sysc_wait_softreset(struct sysc *ddata) u32 sysc_mask, syss_done, rstval; int syss_offset, error = 0; + if (ddata->cap->regbits->srst_shift < 0) + return 0; + syss_offset = ddata->offsets[SYSC_SYSSTATUS]; sysc_mask = BIT(ddata->cap->regbits->srst_shift); @@ -970,9 +973,15 @@ static int sysc_enable_module(struct device *dev) return error; } } - error = sysc_wait_softreset(ddata); - if (error) - dev_warn(ddata->dev, "OCP softreset timed out\n"); + /* + * Some modules like i2c and hdq1w have unusable reset status unless + * the module reset quirk is enabled. Skip status check on enable. + */ + if (!(ddata->cfg.quirks & SYSC_MODULE_QUIRK_ENA_RESETDONE)) { + error = sysc_wait_softreset(ddata); + if (error) + dev_warn(ddata->dev, "OCP softreset timed out\n"); + } if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) sysc_disable_opt_clocks(ddata); @@ -1373,17 +1382,17 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff, SYSC_QUIRK_OPT_CLKS_NEEDED), SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, - SYSC_MODULE_QUIRK_HDQ1W), + SYSC_MODULE_QUIRK_HDQ1W | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, - SYSC_MODULE_QUIRK_HDQ1W), + SYSC_MODULE_QUIRK_HDQ1W | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000036, 0x000000ff, - SYSC_MODULE_QUIRK_I2C), + SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x0000003c, 0x000000ff, - SYSC_MODULE_QUIRK_I2C), + SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000040, 0x000000ff, - SYSC_MODULE_QUIRK_I2C), + SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, - SYSC_MODULE_QUIRK_I2C), + SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0), SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, SYSC_MODULE_QUIRK_SGX), @@ -2880,7 +2889,7 @@ static int sysc_check_active_timer(struct sysc *ddata) if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) && (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)) - return -EBUSY; + return -ENXIO; return 0; } diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index e27771df8e23..a60aee1a1a29 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -368,7 +368,7 @@ static const struct regmap_config ti_eqep_regmap32_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = 0x24, + .max_register = QUPRD, }; static const struct regmap_config ti_eqep_regmap16_config = { @@ -376,7 +376,7 @@ static const struct regmap_config ti_eqep_regmap16_config = { .reg_bits = 16, .val_bits = 16, .reg_stride = 2, - .max_register = 0x1e, + .max_register = QCPRDLAT, }; static int ti_eqep_probe(struct platform_device *pdev) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 78318508a6d6..8286205c7165 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -236,13 +236,15 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev) if (!handle || !handle->perf_ops) return -ENODEV; +#ifdef CONFIG_COMMON_CLK /* dummy clock provider as needed by OPP if clocks property is used */ if (of_find_property(dev->of_node, "#clock-cells", NULL)) devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL); +#endif ret = cpufreq_register_driver(&scmi_cpufreq_driver); if (ret) { - dev_err(&sdev->dev, "%s: registering cpufreq failed, err: %d\n", + dev_err(dev, "%s: registering cpufreq failed, err: %d\n", __func__, ret); } diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index 567428e10b7b..d2834c2cfa10 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig @@ -50,7 +50,6 @@ config DEV_DAX_HMEM Say M if unsure. config DEV_DAX_HMEM_DEVICES - depends on NUMA_KEEP_MEMINFO # for phys_to_target_node() depends on DEV_DAX_HMEM && DAX=y def_bool y diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 7974fa0400d8..962cbb5e5f7f 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1039,16 +1039,15 @@ static int get_dma_id(struct dma_device *device) static int __dma_async_device_channel_register(struct dma_device *device, struct dma_chan *chan) { - int rc = 0; + int rc; chan->local = alloc_percpu(typeof(*chan->local)); if (!chan->local) - goto err_out; + return -ENOMEM; chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL); if (!chan->dev) { - free_percpu(chan->local); - chan->local = NULL; - goto err_out; + rc = -ENOMEM; + goto err_free_local; } /* @@ -1061,7 +1060,8 @@ static int __dma_async_device_channel_register(struct dma_device *device, if (chan->chan_id < 0) { pr_err("%s: unable to alloc ida for chan: %d\n", __func__, chan->chan_id); - goto err_out; + rc = chan->chan_id; + goto err_free_dev; } chan->dev->device.class = &dma_devclass; @@ -1082,9 +1082,10 @@ static int __dma_async_device_channel_register(struct dma_device *device, mutex_lock(&device->chan_mutex); ida_free(&device->chan_ida, chan->chan_id); mutex_unlock(&device->chan_mutex); - err_out: - free_percpu(chan->local); + err_free_dev: kfree(chan->dev); + err_free_local: + free_percpu(chan->local); return rc; } diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 200b9109cacf..663344987e3f 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -271,7 +271,7 @@ int idxd_wq_map_portal(struct idxd_wq *wq) resource_size_t start; start = pci_resource_start(pdev, IDXD_WQ_BAR); - start = start + wq->id * IDXD_PORTAL_SIZE; + start += idxd_get_wq_portal_full_offset(wq->id, IDXD_PORTAL_LIMITED); wq->dportal = devm_ioremap(dev, start, IDXD_PORTAL_SIZE); if (!wq->dportal) @@ -295,7 +295,7 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq) int i, wq_offset; lockdep_assert_held(&idxd->dev_lock); - memset(&wq->wqcfg, 0, sizeof(wq->wqcfg)); + memset(wq->wqcfg, 0, idxd->wqcfg_size); wq->type = IDXD_WQT_NONE; wq->size = 0; wq->group = NULL; @@ -304,8 +304,8 @@ void idxd_wq_disable_cleanup(struct idxd_wq *wq) clear_bit(WQ_FLAG_DEDICATED, &wq->flags); memset(wq->name, 0, WQ_NAME_SIZE); - for (i = 0; i < 8; i++) { - wq_offset = idxd->wqcfg_offset + wq->id * 32 + i * sizeof(u32); + for (i = 0; i < WQCFG_STRIDES(idxd); i++) { + wq_offset = WQCFG_OFFSET(idxd, wq->id, i); iowrite32(0, idxd->reg_base + wq_offset); dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n", wq->id, i, wq_offset, @@ -539,10 +539,10 @@ static int idxd_wq_config_write(struct idxd_wq *wq) if (!wq->group) return 0; - memset(&wq->wqcfg, 0, sizeof(union wqcfg)); + memset(wq->wqcfg, 0, idxd->wqcfg_size); /* byte 0-3 */ - wq->wqcfg.wq_size = wq->size; + wq->wqcfg->wq_size = wq->size; if (wq->size == 0) { dev_warn(dev, "Incorrect work queue size: 0\n"); @@ -550,22 +550,21 @@ static int idxd_wq_config_write(struct idxd_wq *wq) } /* bytes 4-7 */ - wq->wqcfg.wq_thresh = wq->threshold; + wq->wqcfg->wq_thresh = wq->threshold; /* byte 8-11 */ - wq->wqcfg.priv = !!(wq->type == IDXD_WQT_KERNEL); - wq->wqcfg.mode = 1; - - wq->wqcfg.priority = wq->priority; + wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL); + wq->wqcfg->mode = 1; + wq->wqcfg->priority = wq->priority; /* bytes 12-15 */ - wq->wqcfg.max_xfer_shift = ilog2(wq->max_xfer_bytes); - wq->wqcfg.max_batch_shift = ilog2(wq->max_batch_size); + wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes); + wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size); dev_dbg(dev, "WQ %d CFGs\n", wq->id); - for (i = 0; i < 8; i++) { - wq_offset = idxd->wqcfg_offset + wq->id * 32 + i * sizeof(u32); - iowrite32(wq->wqcfg.bits[i], idxd->reg_base + wq_offset); + for (i = 0; i < WQCFG_STRIDES(idxd); i++) { + wq_offset = WQCFG_OFFSET(idxd, wq->id, i); + iowrite32(wq->wqcfg->bits[i], idxd->reg_base + wq_offset); dev_dbg(dev, "WQ[%d][%d][%#x]: %#x\n", wq->id, i, wq_offset, ioread32(idxd->reg_base + wq_offset)); diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index c64df197e724..d48f193daacc 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -103,7 +103,7 @@ struct idxd_wq { u32 priority; enum idxd_wq_state state; unsigned long flags; - union wqcfg wqcfg; + union wqcfg *wqcfg; u32 vec_ptr; /* interrupt steering */ struct dsa_hw_desc **hw_descs; int num_descs; @@ -183,6 +183,7 @@ struct idxd_device { int max_wq_size; int token_limit; int nr_tokens; /* non-reserved tokens */ + unsigned int wqcfg_size; union sw_err_reg sw_err; wait_queue_head_t cmd_waitq; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 11e5ce168177..0a4432b063b5 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -178,6 +178,9 @@ static int idxd_setup_internals(struct idxd_device *idxd) wq->idxd_cdev.minor = -1; wq->max_xfer_bytes = idxd->max_xfer_bytes; wq->max_batch_size = idxd->max_batch_size; + wq->wqcfg = devm_kzalloc(dev, idxd->wqcfg_size, GFP_KERNEL); + if (!wq->wqcfg) + return -ENOMEM; } for (i = 0; i < idxd->max_engines; i++) { @@ -251,6 +254,8 @@ static void idxd_read_caps(struct idxd_device *idxd) dev_dbg(dev, "total workqueue size: %u\n", idxd->max_wq_size); idxd->max_wqs = idxd->hw.wq_cap.num_wqs; dev_dbg(dev, "max workqueues: %u\n", idxd->max_wqs); + idxd->wqcfg_size = 1 << (idxd->hw.wq_cap.wqcfg_size + IDXD_WQCFG_MIN); + dev_dbg(dev, "wqcfg size: %u\n", idxd->wqcfg_size); /* reading operation capabilities */ for (i = 0; i < 4; i++) { diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index a39e7ae6b3d9..54390334c243 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -8,7 +8,7 @@ #define IDXD_MMIO_BAR 0 #define IDXD_WQ_BAR 2 -#define IDXD_PORTAL_SIZE 0x4000 +#define IDXD_PORTAL_SIZE PAGE_SIZE /* MMIO Device BAR0 Registers */ #define IDXD_VER_OFFSET 0x00 @@ -43,7 +43,8 @@ union wq_cap_reg { struct { u64 total_wq_size:16; u64 num_wqs:8; - u64 rsvd:24; + u64 wqcfg_size:4; + u64 rsvd:20; u64 shared_mode:1; u64 dedicated_mode:1; u64 rsvd2:1; @@ -55,6 +56,7 @@ union wq_cap_reg { u64 bits; } __packed; #define IDXD_WQCAP_OFFSET 0x20 +#define IDXD_WQCFG_MIN 5 union group_cap_reg { struct { @@ -333,4 +335,23 @@ union wqcfg { }; u32 bits[8]; } __packed; + +/* + * This macro calculates the offset into the WQCFG register + * idxd - struct idxd * + * n - wq id + * ofs - the index of the 32b dword for the config register + * + * The WQCFG register block is divided into groups per each wq. The n index + * allows us to move to the register group that's for that particular wq. + * Each register is 32bits. The ofs gives us the number of register to access. + */ +#define WQCFG_OFFSET(_idxd_dev, n, ofs) \ +({\ + typeof(_idxd_dev) __idxd_dev = (_idxd_dev); \ + (__idxd_dev)->wqcfg_offset + (n) * (__idxd_dev)->wqcfg_size + sizeof(u32) * (ofs); \ +}) + +#define WQCFG_STRIDES(_idxd_dev) ((_idxd_dev)->wqcfg_size / sizeof(u32)) + #endif diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 156a1ee233aa..417048e3c42a 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -74,7 +74,7 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) if (idxd->state != IDXD_DEV_ENABLED) return -EIO; - portal = wq->dportal + idxd_get_wq_portal_offset(IDXD_PORTAL_UNLIMITED); + portal = wq->dportal; /* * The wmb() flushes writes to coherent DMA data before possibly * triggering a DMA read. The wmb() is necessary even on UP because diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 0be385587c4c..289c59ed74b9 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -40,16 +40,6 @@ #define DCA2_TAG_MAP_BYTE3 0x82 #define DCA2_TAG_MAP_BYTE4 0x82 -/* verify if tag map matches expected values */ -static inline int dca2_tag_map_valid(u8 *tag_map) -{ - return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) && - (tag_map[1] == DCA2_TAG_MAP_BYTE1) && - (tag_map[2] == DCA2_TAG_MAP_BYTE2) && - (tag_map[3] == DCA2_TAG_MAP_BYTE3) && - (tag_map[4] == DCA2_TAG_MAP_BYTE4)); -} - /* * "Legacy" DCA systems do not implement the DCA register set in the * I/OAT device. Software needs direct support for their tag mappings. diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index e9f0101d92fa..0f5c19370f6d 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2799,7 +2799,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, * If burst size is smaller than bus width then make sure we only * transfer one at a time to avoid a burst stradling an MFIFO entry. */ - if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width) + if (burst * 8 < pl330->pcfg.data_bus_width) desc->rqcfg.brst_len = 1; desc->bytes_requested = len; diff --git a/drivers/dma/ti/k3-udma-private.c b/drivers/dma/ti/k3-udma-private.c index aa24e554f7b4..8563a392f30b 100644 --- a/drivers/dma/ti/k3-udma-private.c +++ b/drivers/dma/ti/k3-udma-private.c @@ -83,7 +83,7 @@ EXPORT_SYMBOL(xudma_rflow_is_gp); #define XUDMA_GET_PUT_RESOURCE(res) \ struct udma_##res *xudma_##res##_get(struct udma_dev *ud, int id) \ { \ - return __udma_reserve_##res(ud, false, id); \ + return __udma_reserve_##res(ud, UDMA_TP_NORMAL, id); \ } \ EXPORT_SYMBOL(xudma_##res##_get); \ \ diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index c9fe5e3a6b55..268a08058714 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1522,29 +1522,38 @@ static void omap_dma_free(struct omap_dmadev *od) } } +/* Currently used by omap2 & 3 to block deeper SoC idle states */ +static bool omap_dma_busy(struct omap_dmadev *od) +{ + struct omap_chan *c; + int lch = -1; + + while (1) { + lch = find_next_bit(od->lch_bitmap, od->lch_count, lch + 1); + if (lch >= od->lch_count) + break; + c = od->lch_map[lch]; + if (!c) + continue; + if (omap_dma_chan_read(c, CCR) & CCR_ENABLE) + return true; + } + + return false; +} + /* Currently only used for omap2. For omap1, also a check for lcd_dma is needed */ static int omap_dma_busy_notifier(struct notifier_block *nb, unsigned long cmd, void *v) { struct omap_dmadev *od; - struct omap_chan *c; - int lch = -1; od = container_of(nb, struct omap_dmadev, nb); switch (cmd) { case CPU_CLUSTER_PM_ENTER: - while (1) { - lch = find_next_bit(od->lch_bitmap, od->lch_count, - lch + 1); - if (lch >= od->lch_count) - break; - c = od->lch_map[lch]; - if (!c) - continue; - if (omap_dma_chan_read(c, CCR) & CCR_ENABLE) - return NOTIFY_BAD; - } + if (omap_dma_busy(od)) + return NOTIFY_BAD; break; case CPU_CLUSTER_PM_ENTER_FAILED: case CPU_CLUSTER_PM_EXIT: @@ -1595,6 +1604,8 @@ static int omap_dma_context_notifier(struct notifier_block *nb, switch (cmd) { case CPU_CLUSTER_PM_ENTER: + if (omap_dma_busy(od)) + return NOTIFY_BAD; omap_dma_context_save(od); break; case CPU_CLUSTER_PM_ENTER_FAILED: diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index ecff35402860..22faea653ea8 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -517,8 +517,8 @@ struct xilinx_dma_device { #define to_dma_tx_descriptor(tx) \ container_of(tx, struct xilinx_dma_tx_descriptor, async_tx) #define xilinx_dma_poll_timeout(chan, reg, val, cond, delay_us, timeout_us) \ - readl_poll_timeout(chan->xdev->regs + chan->ctrl_offset + reg, val, \ - cond, delay_us, timeout_us) + readl_poll_timeout_atomic(chan->xdev->regs + chan->ctrl_offset + reg, \ + val, cond, delay_us, timeout_us) /* IO accessors */ static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg) @@ -948,8 +948,10 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan, { struct xilinx_cdma_tx_segment *cdma_seg; struct xilinx_axidma_tx_segment *axidma_seg; + struct xilinx_aximcdma_tx_segment *aximcdma_seg; struct xilinx_cdma_desc_hw *cdma_hw; struct xilinx_axidma_desc_hw *axidma_hw; + struct xilinx_aximcdma_desc_hw *aximcdma_hw; struct list_head *entry; u32 residue = 0; @@ -961,13 +963,23 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan, cdma_hw = &cdma_seg->hw; residue += (cdma_hw->control - cdma_hw->status) & chan->xdev->max_buffer_len; - } else { + } else if (chan->xdev->dma_config->dmatype == + XDMA_TYPE_AXIDMA) { axidma_seg = list_entry(entry, struct xilinx_axidma_tx_segment, node); axidma_hw = &axidma_seg->hw; residue += (axidma_hw->control - axidma_hw->status) & chan->xdev->max_buffer_len; + } else { + aximcdma_seg = + list_entry(entry, + struct xilinx_aximcdma_tx_segment, + node); + aximcdma_hw = &aximcdma_seg->hw; + residue += + (aximcdma_hw->control - aximcdma_hw->status) & + chan->xdev->max_buffer_len; } } @@ -1135,7 +1147,7 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) upper_32_bits(chan->seg_p + sizeof(*chan->seg_mv) * ((i + 1) % XILINX_DMA_NUM_DESCS)); chan->seg_mv[i].phys = chan->seg_p + - sizeof(*chan->seg_v) * i; + sizeof(*chan->seg_mv) * i; list_add_tail(&chan->seg_mv[i].node, &chan->free_seg_list); } @@ -1560,7 +1572,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan) { struct xilinx_dma_tx_descriptor *head_desc, *tail_desc; - struct xilinx_axidma_tx_segment *tail_segment; + struct xilinx_aximcdma_tx_segment *tail_segment; u32 reg; /* @@ -1582,7 +1594,7 @@ static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan) tail_desc = list_last_entry(&chan->pending_list, struct xilinx_dma_tx_descriptor, node); tail_segment = list_last_entry(&tail_desc->segments, - struct xilinx_axidma_tx_segment, node); + struct xilinx_aximcdma_tx_segment, node); reg = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_CR_OFFSET(chan->tdest)); @@ -1864,6 +1876,7 @@ static void append_desc_queue(struct xilinx_dma_chan *chan, struct xilinx_vdma_tx_segment *tail_segment; struct xilinx_dma_tx_descriptor *tail_desc; struct xilinx_axidma_tx_segment *axidma_tail_segment; + struct xilinx_aximcdma_tx_segment *aximcdma_tail_segment; struct xilinx_cdma_tx_segment *cdma_tail_segment; if (list_empty(&chan->pending_list)) @@ -1885,11 +1898,17 @@ static void append_desc_queue(struct xilinx_dma_chan *chan, struct xilinx_cdma_tx_segment, node); cdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys; - } else { + } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { axidma_tail_segment = list_last_entry(&tail_desc->segments, struct xilinx_axidma_tx_segment, node); axidma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys; + } else { + aximcdma_tail_segment = + list_last_entry(&tail_desc->segments, + struct xilinx_aximcdma_tx_segment, + node); + aximcdma_tail_segment->hw.next_desc = (u32)desc->async_tx.phys; } /* @@ -2836,10 +2855,11 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->stop_transfer = xilinx_dma_stop_transfer; } - /* check if SG is enabled (only for AXIDMA and CDMA) */ + /* check if SG is enabled (only for AXIDMA, AXIMCDMA, and CDMA) */ if (xdev->dma_config->dmatype != XDMA_TYPE_VDMA) { - if (dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) & - XILINX_DMA_DMASR_SG_MASK) + if (xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA || + dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) & + XILINX_DMA_DMASR_SG_MASK) chan->has_sg = true; dev_dbg(chan->dev, "ch %d: SG %s\n", chan->id, chan->has_sg ? "enabled" : "disabled"); diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index efb8a66efc68..d08ac824c993 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -20,12 +20,28 @@ #include <linux/of_platform.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/hashtable.h> #include <linux/firmware/xlnx-zynqmp.h> #include "zynqmp-debug.h" +/* Max HashMap Order for PM API feature check (1<<7 = 128) */ +#define PM_API_FEATURE_CHECK_MAX_ORDER 7 + static bool feature_check_enabled; -static u32 zynqmp_pm_features[PM_API_MAX]; +DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); + +/** + * struct pm_api_feature_data - PM API Feature data + * @pm_api_id: PM API Id, used as key to index into hashmap + * @feature_status: status of PM API feature: valid, invalid + * @hentry: hlist_node that hooks this entry into hashtable + */ +struct pm_api_feature_data { + u32 pm_api_id; + int feature_status; + struct hlist_node hentry; +}; static const struct mfd_cell firmware_devs[] = { { @@ -142,29 +158,37 @@ static int zynqmp_pm_feature(u32 api_id) int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; u64 smc_arg[2]; + struct pm_api_feature_data *feature_data; if (!feature_check_enabled) return 0; - /* Return value if feature is already checked */ - if (api_id > ARRAY_SIZE(zynqmp_pm_features)) - return PM_FEATURE_INVALID; + /* Check for existing entry in hash table for given api */ + hash_for_each_possible(pm_api_features_map, feature_data, hentry, + api_id) { + if (feature_data->pm_api_id == api_id) + return feature_data->feature_status; + } - if (zynqmp_pm_features[api_id] != PM_FEATURE_UNCHECKED) - return zynqmp_pm_features[api_id]; + /* Add new entry if not present */ + feature_data = kmalloc(sizeof(*feature_data), GFP_KERNEL); + if (!feature_data) + return -ENOMEM; + feature_data->pm_api_id = api_id; smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK; smc_arg[1] = api_id; ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload); - if (ret) { - zynqmp_pm_features[api_id] = PM_FEATURE_INVALID; - return PM_FEATURE_INVALID; - } + if (ret) + ret = -EOPNOTSUPP; + else + ret = ret_payload[1]; - zynqmp_pm_features[api_id] = ret_payload[1]; + feature_data->feature_status = ret; + hash_add(pm_api_features_map, &feature_data->hentry, api_id); - return zynqmp_pm_features[api_id]; + return ret; } /** @@ -200,9 +224,12 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1, * Make sure to stay in x0 register */ u64 smc_arg[4]; + int ret; - if (zynqmp_pm_feature(pm_api_id) == PM_FEATURE_INVALID) - return -ENOTSUPP; + /* Check if feature is supported or not */ + ret = zynqmp_pm_feature(pm_api_id); + if (ret < 0) + return ret; smc_arg[0] = PM_SIP_SVC | pm_api_id; smc_arg[1] = ((u64)arg1 << 32) | arg0; @@ -615,7 +642,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); */ int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY, + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET, type, 0, NULL); } EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); @@ -1252,9 +1279,17 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) static int zynqmp_firmware_remove(struct platform_device *pdev) { + struct pm_api_feature_data *feature_data; + int i; + mfd_remove_devices(&pdev->dev); zynqmp_pm_api_debugfs_exit(); + hash_for_each(pm_api_features_map, i, feature_data, hentry) { + hash_del(&feature_data->hentry); + kfree(feature_data); + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e3783f5a459d..026789b466db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4852,7 +4852,7 @@ int amdgpu_device_baco_enter(struct drm_device *dev) if (!amdgpu_device_supports_baco(adev_to_drm(adev))) return -ENOTSUPP; - if (ras && ras->supported) + if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) adev->nbio.funcs->enable_doorbell_interrupt(adev, false); return amdgpu_dpm_baco_enter(adev); @@ -4871,7 +4871,7 @@ int amdgpu_device_baco_exit(struct drm_device *dev) if (ret) return ret; - if (ras && ras->supported) + if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) adev->nbio.funcs->enable_doorbell_interrupt(adev, true); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 42d9748921f5..8e988f07f085 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1055,10 +1055,10 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU}, {0x1002, 0x15d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU}, /* Arcturus */ - {0x1002, 0x738C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x7388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x738E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x7390, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x738C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS}, + {0x1002, 0x7388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS}, + {0x1002, 0x738E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS}, + {0x1002, 0x7390, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS}, /* Navi10 */ {0x1002, 0x7310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10}, {0x1002, 0x7312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10}, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8039d2399584..a0248d78190f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -69,10 +69,10 @@ static int amdgpu_ttm_backend_bind(struct ttm_bo_device *bdev, static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, unsigned int type, - uint64_t size) + uint64_t size_in_page) { return ttm_range_man_init(&adev->mman.bdev, type, - false, size >> PAGE_SHIFT); + false, size_in_page); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h index 5eb63288d157..edbb8194ee81 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h @@ -67,6 +67,7 @@ struct amdgpu_uvd { unsigned harvest_config; /* store image width to adjust nb memory state */ unsigned decode_image_width; + uint32_t keyselect; }; int amdgpu_uvd_sw_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 3579565e0eab..55f4b8c3b933 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3105,6 +3105,8 @@ static const struct soc15_reg_golden golden_settings_gc_10_3[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0xffffffff, 0x00000280), SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x00800000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_EXCEPTION_CONTROL, 0x7fff0f1f, 0x00b80000), + SOC15_REG_GOLDEN_VALUE(GC, 0 ,mmGCEA_SDP_TAG_RESERVE0, 0xffffffff, 0x10100100), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCEA_SDP_TAG_RESERVE1, 0xffffffff, 0x17000088), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Sienna_Cichlid, 0x1ff1ffff, 0x00000500), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGE_PC_CNTL, 0x003fffff, 0x00280400), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2A_ADDR_MATCH_MASK, 0xffffffff, 0xffffffcf), diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c index 7cf4b11a65c5..41800fcad410 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c @@ -277,15 +277,8 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) */ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) { - void *ptr; - uint32_t ucode_len, i; - uint32_t keysel; - - ptr = adev->uvd.inst[0].cpu_addr; - ptr += 192 + 16; - memcpy(&ucode_len, ptr, 4); - ptr += ucode_len; - memcpy(&keysel, ptr, 4); + int i; + uint32_t keysel = adev->uvd.keyselect; WREG32(mmUVD_FW_START, keysel); @@ -550,6 +543,8 @@ static int uvd_v3_1_sw_init(void *handle) struct amdgpu_ring *ring; struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; + void *ptr; + uint32_t ucode_len; /* UVD TRAP */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 124, &adev->uvd.inst->irq); @@ -571,6 +566,13 @@ static int uvd_v3_1_sw_init(void *handle) if (r) return r; + /* Retrieval firmware validate key */ + ptr = adev->uvd.inst[0].cpu_addr; + ptr += 192 + 16; + memcpy(&ucode_len, ptr, 4); + ptr += ucode_len; + memcpy(&adev->uvd.keyselect, ptr, 4); + r = amdgpu_uvd_entity_init(adev); return r; 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 e93e18c06c0e..9b6809f309f4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1041,7 +1041,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) amdgpu_dm_init_color_mod(); #ifdef CONFIG_DRM_AMD_DC_HDCP - if (adev->asic_type >= CHIP_RAVEN) { + if (adev->dm.dc->caps.max_links > 0 && adev->asic_type >= CHIP_RAVEN) { adev->dm.hdcp_workqueue = hdcp_create_workqueue(adev, &init_params.cp_psp, adev->dm.dc); if (!adev->dm.hdcp_workqueue) @@ -7506,7 +7506,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) bool mode_set_reset_required = false; drm_atomic_helper_update_legacy_modeset_state(dev, state); - drm_atomic_helper_calc_timestamping_constants(state); dm_state = dm_atomic_get_new_state(state); if (dm_state && dm_state->context) { @@ -7533,6 +7532,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) } } + drm_atomic_helper_calc_timestamping_constants(state); + /* update changed items */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c index 2a1fea501f8c..3f1e7a196a23 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c @@ -299,8 +299,8 @@ irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = { pflip_int_entry(1), pflip_int_entry(2), pflip_int_entry(3), - [DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(), - [DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(), + pflip_int_entry(4), + pflip_int_entry(5), [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(), gpio_pad_int_entry(0), gpio_pad_int_entry(1), diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 834a156e3a75..0a1e1cf57e19 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -742,7 +742,6 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_SUSPEND: if (ast->tx_chip_type == AST_TX_DP501) ast_set_dp501_video_output(crtc->dev, 1); - ast_crtc_load_lut(ast, crtc); break; case DRM_MODE_DPMS_OFF: if (ast->tx_chip_type == AST_TX_DP501) @@ -778,6 +777,21 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, } static void +ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) +{ + struct ast_private *ast = to_ast_private(crtc->dev); + struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc->state); + struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); + + /* + * The gamma LUT has to be reloaded after changing the primary + * plane's color format. + */ + if (old_ast_crtc_state->format != ast_crtc_state->format) + ast_crtc_load_lut(ast, crtc); +} + +static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -830,6 +844,7 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { .atomic_check = ast_crtc_helper_atomic_check, + .atomic_flush = ast_crtc_helper_atomic_flush, .atomic_enable = ast_crtc_helper_atomic_enable, .atomic_disable = ast_crtc_helper_atomic_disable, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 748df1cacd2b..0c79a9ba48bb 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2327,12 +2327,6 @@ static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) { enum drm_connector_status result; - mutex_lock(&hdmi->mutex); - hdmi->force = DRM_FORCE_UNSPECIFIED; - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); - result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); mutex_lock(&hdmi->mutex); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 50cad0e4a92e..375c79e23ca5 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -140,7 +140,7 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, unsigned int c = 0; if (pl_flag & DRM_GEM_VRAM_PL_FLAG_TOPDOWN) - pl_flag = TTM_PL_FLAG_TOPDOWN; + invariant_flags = TTM_PL_FLAG_TOPDOWN; gbo->placement.placement = gbo->placements; gbo->placement.busy_placement = gbo->placements; diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 6417f374b923..951d5f708e92 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_EXYNOS tristate "DRM Support for Samsung SoC Exynos Series" - depends on OF && DRM && (ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_MULTIPLATFORM || COMPILE_TEST) + depends on OF && DRM && COMMON_CLK + depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_MULTIPLATFORM || COMPILE_TEST depends on MMU select DRM_KMS_HELPER select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 31337d2a2cde..99e682563d47 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12878,10 +12878,11 @@ compute_sink_pipe_bpp(const struct drm_connector_state *conn_state, case 10 ... 11: bpp = 10 * 3; break; - case 12: + case 12 ... 16: bpp = 12 * 3; break; default: + MISSING_CASE(conn_state->max_bpc); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index d8b206e53660..cf6e05ea4d8f 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -30,18 +30,21 @@ #include "i915_trace.h" #include "intel_breadcrumbs.h" #include "intel_context.h" +#include "intel_engine_pm.h" #include "intel_gt_pm.h" #include "intel_gt_requests.h" -static void irq_enable(struct intel_engine_cs *engine) +static bool irq_enable(struct intel_engine_cs *engine) { if (!engine->irq_enable) - return; + return false; /* Caller disables interrupts */ spin_lock(&engine->gt->irq_lock); engine->irq_enable(engine); spin_unlock(&engine->gt->irq_lock); + + return true; } static void irq_disable(struct intel_engine_cs *engine) @@ -57,12 +60,11 @@ static void irq_disable(struct intel_engine_cs *engine) static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { - lockdep_assert_held(&b->irq_lock); - - if (!b->irq_engine || b->irq_armed) - return; - - if (!intel_gt_pm_get_if_awake(b->irq_engine->gt)) + /* + * Since we are waiting on a request, the GPU should be busy + * and should have its own rpm reference. + */ + if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) return; /* @@ -73,25 +75,24 @@ static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) */ WRITE_ONCE(b->irq_armed, true); - /* - * Since we are waiting on a request, the GPU should be busy - * and should have its own rpm reference. This is tracked - * by i915->gt.awake, we can forgo holding our own wakref - * for the interrupt as before i915->gt.awake is released (when - * the driver is idle) we disarm the breadcrumbs. - */ - - if (!b->irq_enabled++) - irq_enable(b->irq_engine); + /* Requests may have completed before we could enable the interrupt. */ + if (!b->irq_enabled++ && irq_enable(b->irq_engine)) + irq_work_queue(&b->irq_work); } -static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) +static void intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { - lockdep_assert_held(&b->irq_lock); - - if (!b->irq_engine || !b->irq_armed) + if (!b->irq_engine) return; + spin_lock(&b->irq_lock); + if (!b->irq_armed) + __intel_breadcrumbs_arm_irq(b); + spin_unlock(&b->irq_lock); +} + +static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) +{ GEM_BUG_ON(!b->irq_enabled); if (!--b->irq_enabled) irq_disable(b->irq_engine); @@ -105,8 +106,6 @@ static void add_signaling_context(struct intel_breadcrumbs *b, { intel_context_get(ce); list_add_tail(&ce->signal_link, &b->signalers); - if (list_is_first(&ce->signal_link, &b->signalers)) - __intel_breadcrumbs_arm_irq(b); } static void remove_signaling_context(struct intel_breadcrumbs *b, @@ -174,34 +173,65 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl) intel_engine_add_retire(b->irq_engine, tl); } -static bool __signal_request(struct i915_request *rq, struct list_head *signals) +static bool __signal_request(struct i915_request *rq) { - clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags); - if (!__dma_fence_signal(&rq->fence)) { i915_request_put(rq); return false; } - list_add_tail(&rq->signal_link, signals); return true; } +static struct llist_node * +slist_add(struct llist_node *node, struct llist_node *head) +{ + node->next = head; + return node; +} + static void signal_irq_work(struct irq_work *work) { struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work); const ktime_t timestamp = ktime_get(); + struct llist_node *signal, *sn; struct intel_context *ce, *cn; struct list_head *pos, *next; - LIST_HEAD(signal); + + signal = NULL; + if (unlikely(!llist_empty(&b->signaled_requests))) + signal = llist_del_all(&b->signaled_requests); spin_lock(&b->irq_lock); - if (list_empty(&b->signalers)) + /* + * Keep the irq armed until the interrupt after all listeners are gone. + * + * Enabling/disabling the interrupt is rather costly, roughly a couple + * of hundred microseconds. If we are proactive and enable/disable + * the interrupt around every request that wants a breadcrumb, we + * quickly drown in the extra orders of magnitude of latency imposed + * on request submission. + * + * So we try to be lazy, and keep the interrupts enabled until no + * more listeners appear within a breadcrumb interrupt interval (that + * is until a request completes that no one cares about). The + * observation is that listeners come in batches, and will often + * listen to a bunch of requests in succession. Though note on icl+, + * interrupts are always enabled due to concerns with rc6 being + * dysfunctional with per-engine interrupt masking. + * + * We also try to avoid raising too many interrupts, as they may + * be generated by userspace batches and it is unfortunately rather + * too easy to drown the CPU under a flood of GPU interrupts. Thus + * whenever no one appears to be listening, we turn off the interrupts. + * Fewer interrupts should conserve power -- at the very least, fewer + * interrupt draw less ire from other users of the system and tools + * like powertop. + */ + if (!signal && b->irq_armed && list_empty(&b->signalers)) __intel_breadcrumbs_disarm_irq(b); - list_splice_init(&b->signaled_requests, &signal); - list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) { GEM_BUG_ON(list_empty(&ce->signals)); @@ -218,7 +248,10 @@ static void signal_irq_work(struct irq_work *work) * spinlock as the callback chain may end up adding * more signalers to the same context or engine. */ - __signal_request(rq, &signal); + clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags); + if (__signal_request(rq)) + /* We own signal_node now, xfer to local list */ + signal = slist_add(&rq->signal_node, signal); } /* @@ -238,9 +271,9 @@ static void signal_irq_work(struct irq_work *work) spin_unlock(&b->irq_lock); - list_for_each_safe(pos, next, &signal) { + llist_for_each_safe(signal, sn, signal) { struct i915_request *rq = - list_entry(pos, typeof(*rq), signal_link); + llist_entry(signal, typeof(*rq), signal_node); struct list_head cb_list; spin_lock(&rq->lock); @@ -251,6 +284,9 @@ static void signal_irq_work(struct irq_work *work) i915_request_put(rq); } + + if (!READ_ONCE(b->irq_armed) && !list_empty(&b->signalers)) + intel_breadcrumbs_arm_irq(b); } struct intel_breadcrumbs * @@ -264,7 +300,7 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine) spin_lock_init(&b->irq_lock); INIT_LIST_HEAD(&b->signalers); - INIT_LIST_HEAD(&b->signaled_requests); + init_llist_head(&b->signaled_requests); init_irq_work(&b->irq_work, signal_irq_work); @@ -292,21 +328,22 @@ void intel_breadcrumbs_reset(struct intel_breadcrumbs *b) void intel_breadcrumbs_park(struct intel_breadcrumbs *b) { - unsigned long flags; - - if (!READ_ONCE(b->irq_armed)) - return; - - spin_lock_irqsave(&b->irq_lock, flags); - __intel_breadcrumbs_disarm_irq(b); - spin_unlock_irqrestore(&b->irq_lock, flags); - - if (!list_empty(&b->signalers)) - irq_work_queue(&b->irq_work); + /* Kick the work once more to drain the signalers */ + irq_work_sync(&b->irq_work); + while (unlikely(READ_ONCE(b->irq_armed))) { + local_irq_disable(); + signal_irq_work(&b->irq_work); + local_irq_enable(); + cond_resched(); + } + GEM_BUG_ON(!list_empty(&b->signalers)); } void intel_breadcrumbs_free(struct intel_breadcrumbs *b) { + irq_work_sync(&b->irq_work); + GEM_BUG_ON(!list_empty(&b->signalers)); + GEM_BUG_ON(b->irq_armed); kfree(b); } @@ -327,7 +364,8 @@ static void insert_breadcrumb(struct i915_request *rq, * its signal completion. */ if (__request_completed(rq)) { - if (__signal_request(rq, &b->signaled_requests)) + if (__signal_request(rq) && + llist_add(&rq->signal_node, &b->signaled_requests)) irq_work_queue(&b->irq_work); return; } @@ -362,9 +400,12 @@ static void insert_breadcrumb(struct i915_request *rq, GEM_BUG_ON(!check_signal_order(ce, rq)); set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags); - /* Check after attaching to irq, interrupt may have already fired. */ - if (__request_completed(rq)) - irq_work_queue(&b->irq_work); + /* + * Defer enabling the interrupt to after HW submission and recheck + * the request as it may have completed and raised the interrupt as + * we were attaching it into the lists. + */ + irq_work_queue(&b->irq_work); } bool i915_request_enable_breadcrumb(struct i915_request *rq) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h index 8e53b9942695..3fa19820b37a 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h @@ -35,7 +35,7 @@ struct intel_breadcrumbs { struct intel_engine_cs *irq_engine; struct list_head signalers; - struct list_head signaled_requests; + struct llist_head signaled_requests; struct irq_work irq_work; /* for use from inside irq_lock */ diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index f82c6dd1de18..0952bf157234 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -182,6 +182,7 @@ struct virtual_engine { struct intel_engine_cs base; struct intel_context context; + struct rcu_work rcu; /* * We allow only a single request through the virtual engine at a time @@ -5425,44 +5426,90 @@ static struct list_head *virtual_queue(struct virtual_engine *ve) return &ve->base.execlists.default_priolist.requests[0]; } -static void virtual_context_destroy(struct kref *kref) +static void rcu_virtual_context_destroy(struct work_struct *wrk) { struct virtual_engine *ve = - container_of(kref, typeof(*ve), context.ref); + container_of(wrk, typeof(*ve), rcu.work); unsigned int n; - GEM_BUG_ON(!list_empty(virtual_queue(ve))); - GEM_BUG_ON(ve->request); GEM_BUG_ON(ve->context.inflight); + /* Preempt-to-busy may leave a stale request behind. */ + if (unlikely(ve->request)) { + struct i915_request *old; + + spin_lock_irq(&ve->base.active.lock); + + old = fetch_and_zero(&ve->request); + if (old) { + GEM_BUG_ON(!i915_request_completed(old)); + __i915_request_submit(old); + i915_request_put(old); + } + + spin_unlock_irq(&ve->base.active.lock); + } + + /* + * Flush the tasklet in case it is still running on another core. + * + * This needs to be done before we remove ourselves from the siblings' + * rbtrees as in the case it is running in parallel, it may reinsert + * the rb_node into a sibling. + */ + tasklet_kill(&ve->base.execlists.tasklet); + + /* Decouple ourselves from the siblings, no more access allowed. */ for (n = 0; n < ve->num_siblings; n++) { struct intel_engine_cs *sibling = ve->siblings[n]; struct rb_node *node = &ve->nodes[sibling->id].rb; - unsigned long flags; if (RB_EMPTY_NODE(node)) continue; - spin_lock_irqsave(&sibling->active.lock, flags); + spin_lock_irq(&sibling->active.lock); /* Detachment is lazily performed in the execlists tasklet */ if (!RB_EMPTY_NODE(node)) rb_erase_cached(node, &sibling->execlists.virtual); - spin_unlock_irqrestore(&sibling->active.lock, flags); + spin_unlock_irq(&sibling->active.lock); } GEM_BUG_ON(__tasklet_is_scheduled(&ve->base.execlists.tasklet)); + GEM_BUG_ON(!list_empty(virtual_queue(ve))); if (ve->context.state) __execlists_context_fini(&ve->context); intel_context_fini(&ve->context); + intel_breadcrumbs_free(ve->base.breadcrumbs); intel_engine_free_request_pool(&ve->base); kfree(ve->bonds); kfree(ve); } +static void virtual_context_destroy(struct kref *kref) +{ + struct virtual_engine *ve = + container_of(kref, typeof(*ve), context.ref); + + GEM_BUG_ON(!list_empty(&ve->context.signals)); + + /* + * When destroying the virtual engine, we have to be aware that + * it may still be in use from an hardirq/softirq context causing + * the resubmission of a completed request (background completion + * due to preempt-to-busy). Before we can free the engine, we need + * to flush the submission code and tasklets that are still potentially + * accessing the engine. Flushing the tasklets requires process context, + * and since we can guard the resubmit onto the engine with an RCU read + * lock, we can delegate the free of the engine to an RCU worker. + */ + INIT_RCU_WORK(&ve->rcu, rcu_virtual_context_destroy); + queue_rcu_work(system_wq, &ve->rcu); +} + static void virtual_engine_initial_hint(struct virtual_engine *ve) { int swp; diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index b8f56e62158e..313e51e7d4f7 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -243,8 +243,9 @@ static const struct drm_i915_mocs_entry tgl_mocs_table[] = { * only, __init_mocs_table() take care to program unused index with * this entry. */ - MOCS_ENTRY(1, LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), - L3_3_WB), + MOCS_ENTRY(I915_MOCS_PTE, + LE_0_PAGETABLE | LE_TC_0_PAGETABLE, + L3_1_UC), GEN11_MOCS_ENTRIES, /* Implicitly enable L1 - HDC:L1 + L3 + LLC */ diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index ab675d35030d..d7b8e4457fc2 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -56,9 +56,12 @@ static inline void set(struct intel_uncore *uncore, i915_reg_t reg, u32 val) static void gen11_rc6_enable(struct intel_rc6 *rc6) { - struct intel_uncore *uncore = rc6_to_uncore(rc6); + struct intel_gt *gt = rc6_to_gt(rc6); + struct intel_uncore *uncore = gt->uncore; struct intel_engine_cs *engine; enum intel_engine_id id; + u32 pg_enable; + int i; /* 2b: Program RC6 thresholds.*/ set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16 | 85); @@ -102,10 +105,19 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6) GEN6_RC_CTL_RC6_ENABLE | GEN6_RC_CTL_EI_MODE(1); - set(uncore, GEN9_PG_ENABLE, - GEN9_RENDER_PG_ENABLE | - GEN9_MEDIA_PG_ENABLE | - GEN11_MEDIA_SAMPLER_PG_ENABLE); + pg_enable = + GEN9_RENDER_PG_ENABLE | + GEN9_MEDIA_PG_ENABLE | + GEN11_MEDIA_SAMPLER_PG_ENABLE; + + if (INTEL_GEN(gt->i915) >= 12) { + for (i = 0; i < I915_MAX_VCS; i++) + if (HAS_ENGINE(gt, _VCS(i))) + pg_enable |= (VDN_HCP_POWERGATE_ENABLE(i) | + VDN_MFX_POWERGATE_ENABLE(i)); + } + + set(uncore, GEN9_PG_ENABLE, pg_enable); } static void gen9_rc6_enable(struct intel_rc6 *rc6) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 6c580d0d9ea8..4a3bde7c9f21 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -131,8 +131,10 @@ static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa) return; } - if (wal->list) + if (wal->list) { memcpy(list, wal->list, sizeof(*wa) * wal->count); + kfree(wal->list); + } wal->list = list; } diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 7ba16ddfe75f..d7898e87791f 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -164,7 +164,7 @@ static unsigned char virtual_dp_monitor_edid[GVT_EDID_NUM][EDID_SIZE] = { /* let the virtual display supports DP1.2 */ static u8 dpcd_fix_data[DPCD_HEADER_SIZE] = { - 0x12, 0x014, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x12, 0x014, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static void emulate_monitor_status_change(struct intel_vgpu *vgpu) diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 9831361f181e..a81cf0f01e78 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -255,7 +255,7 @@ struct intel_gvt_mmio { #define F_CMD_ACCESS (1 << 3) /* This reg has been accessed by a VM */ #define F_ACCESSED (1 << 4) -/* This reg has been accessed through GPU commands */ +/* This reg could be accessed by unaligned address */ #define F_UNALIGN (1 << 6) /* This reg is in GVT's mmio save-restor list and in hardware * logical context image diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index ad8a9df49f29..778eb8cab610 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -829,8 +829,10 @@ static int intel_vgpu_open(struct mdev_device *mdev) /* Take a module reference as mdev core doesn't take * a reference for vendor driver. */ - if (!try_module_get(THIS_MODULE)) + if (!try_module_get(THIS_MODULE)) { + ret = -ENODEV; goto undo_group; + } ret = kvmgt_guest_init(mdev); if (ret) diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index f6d7e33c7099..399582aeeefb 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -439,7 +439,8 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, if (IS_BROADWELL(dev_priv)) ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_B); - else + /* FixMe: Re-enable APL/BXT once vfio_edid enabled */ + else if (!IS_BROXTON(dev_priv)) ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D); if (ret) goto out_clean_sched_policy; diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index e94976976571..3640d0e229d2 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -909,8 +909,13 @@ static int gen8_oa_read(struct i915_perf_stream *stream, DRM_I915_PERF_RECORD_OA_REPORT_LOST); if (ret) return ret; - intel_uncore_write(uncore, oastatus_reg, - oastatus & ~GEN8_OASTATUS_REPORT_LOST); + + intel_uncore_rmw(uncore, oastatus_reg, + GEN8_OASTATUS_COUNTER_OVERFLOW | + GEN8_OASTATUS_REPORT_LOST, + IS_GEN_RANGE(uncore->i915, 8, 10) ? + (GEN8_OASTATUS_HEAD_POINTER_WRAP | + GEN8_OASTATUS_TAIL_POINTER_WRAP) : 0); } return gen8_append_oa_reports(stream, buf, count, offset); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d805d4da6181..5cd83eac940c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -676,6 +676,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN7_OASTATUS2_MEM_SELECT_GGTT (1 << 0) /* 0: PPGTT, 1: GGTT */ #define GEN8_OASTATUS _MMIO(0x2b08) +#define GEN8_OASTATUS_TAIL_POINTER_WRAP (1 << 17) +#define GEN8_OASTATUS_HEAD_POINTER_WRAP (1 << 16) #define GEN8_OASTATUS_OVERRUN_STATUS (1 << 3) #define GEN8_OASTATUS_COUNTER_OVERFLOW (1 << 2) #define GEN8_OASTATUS_OABUFFER_OVERFLOW (1 << 1) @@ -8971,10 +8973,6 @@ enum { #define GEN9_PWRGT_MEDIA_STATUS_MASK (1 << 0) #define GEN9_PWRGT_RENDER_STATUS_MASK (1 << 1) -#define POWERGATE_ENABLE _MMIO(0xa210) -#define VDN_HCP_POWERGATE_ENABLE(n) BIT(((n) * 2) + 3) -#define VDN_MFX_POWERGATE_ENABLE(n) BIT(((n) * 2) + 4) - #define GTFIFODBG _MMIO(0x120000) #define GT_FIFO_SBDEDICATE_FREE_ENTRY_CHV (0x1f << 20) #define GT_FIFO_FREE_ENTRIES_CHV (0x7f << 13) @@ -9114,9 +9112,11 @@ enum { #define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4) #define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xA0C8) #define GEN9_PG_ENABLE _MMIO(0xA210) -#define GEN9_RENDER_PG_ENABLE REG_BIT(0) -#define GEN9_MEDIA_PG_ENABLE REG_BIT(1) -#define GEN11_MEDIA_SAMPLER_PG_ENABLE REG_BIT(2) +#define GEN9_RENDER_PG_ENABLE REG_BIT(0) +#define GEN9_MEDIA_PG_ENABLE REG_BIT(1) +#define GEN11_MEDIA_SAMPLER_PG_ENABLE REG_BIT(2) +#define VDN_HCP_POWERGATE_ENABLE(n) REG_BIT(3 + 2 * (n)) +#define VDN_MFX_POWERGATE_ENABLE(n) REG_BIT(4 + 2 * (n)) #define GEN8_PUSHBUS_CONTROL _MMIO(0xA248) #define GEN8_PUSHBUS_ENABLE _MMIO(0xA250) #define GEN8_PUSHBUS_SHIFT _MMIO(0xA25C) diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 16b721080195..874af6db6103 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -176,7 +176,11 @@ struct i915_request { struct intel_context *context; struct intel_ring *ring; struct intel_timeline __rcu *timeline; - struct list_head signal_link; + + union { + struct list_head signal_link; + struct llist_node signal_node; + }; /* * The rcu epoch of when this request was allocated. Used to judiciously diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 34e0d22d456b..cfb806767fc5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7118,23 +7118,10 @@ static void icl_init_clock_gating(struct drm_i915_private *dev_priv) static void tgl_init_clock_gating(struct drm_i915_private *dev_priv) { - u32 vd_pg_enable = 0; - unsigned int i; - /* Wa_1409120013:tgl */ I915_WRITE(ILK_DPFC_CHICKEN, ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL); - /* This is not a WA. Enable VD HCP & MFX_ENC powergate */ - for (i = 0; i < I915_MAX_VCS; i++) { - if (HAS_ENGINE(&dev_priv->gt, _VCS(i))) - vd_pg_enable |= VDN_HCP_POWERGATE_ENABLE(i) | - VDN_MFX_POWERGATE_ENABLE(i); - } - - I915_WRITE(POWERGATE_ENABLE, - I915_READ(POWERGATE_ENABLE) | vd_pg_enable); - /* Wa_1409825376:tgl (pre-prod)*/ if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1)) I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) | diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 64bbb8288249..e424a6d1a68c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -2293,8 +2293,10 @@ static int perf_request_latency(void *arg) struct intel_context *ce; ce = intel_context_create(engine); - if (IS_ERR(ce)) + if (IS_ERR(ce)) { + err = PTR_ERR(ce); goto out; + } err = intel_context_pin(ce); if (err) { @@ -2467,8 +2469,10 @@ static int perf_series_engines(void *arg) struct intel_context *ce; ce = intel_context_create(engine); - if (IS_ERR(ce)) + if (IS_ERR(ce)) { + err = PTR_ERR(ce); goto out; + } err = intel_context_pin(ce); if (err) { diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index cf11c4850b40..52f11a63a330 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -522,15 +522,6 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, return 0; } -static void mtk_dpi_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -static const struct drm_encoder_funcs mtk_dpi_encoder_funcs = { - .destroy = mtk_dpi_encoder_destroy, -}; - static int mtk_dpi_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 4a188a942c38..65fd99c528af 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -444,7 +444,10 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) u32 horizontal_sync_active_byte; u32 horizontal_backporch_byte; u32 horizontal_frontporch_byte; + u32 horizontal_front_back_byte; + u32 data_phy_cycles_byte; u32 dsi_tmp_buf_bpp, data_phy_cycles; + u32 delta; struct mtk_phy_timing *timing = &dsi->phy_timing; struct videomode *vm = &dsi->vm; @@ -466,50 +469,30 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10); if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) - horizontal_backporch_byte = vm->hback_porch * dsi_tmp_buf_bpp; + horizontal_backporch_byte = vm->hback_porch * dsi_tmp_buf_bpp - 10; else horizontal_backporch_byte = (vm->hback_porch + vm->hsync_len) * - dsi_tmp_buf_bpp; + dsi_tmp_buf_bpp - 10; data_phy_cycles = timing->lpx + timing->da_hs_prepare + - timing->da_hs_zero + timing->da_hs_exit; - - if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { - if ((vm->hfront_porch + vm->hback_porch) * dsi_tmp_buf_bpp > - data_phy_cycles * dsi->lanes + 18) { - horizontal_frontporch_byte = - vm->hfront_porch * dsi_tmp_buf_bpp - - (data_phy_cycles * dsi->lanes + 18) * - vm->hfront_porch / - (vm->hfront_porch + vm->hback_porch); - - horizontal_backporch_byte = - horizontal_backporch_byte - - (data_phy_cycles * dsi->lanes + 18) * - vm->hback_porch / - (vm->hfront_porch + vm->hback_porch); - } else { - DRM_WARN("HFP less than d-phy, FPS will under 60Hz\n"); - horizontal_frontporch_byte = vm->hfront_porch * - dsi_tmp_buf_bpp; - } + timing->da_hs_zero + timing->da_hs_exit + 3; + + delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12; + + horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp; + horizontal_front_back_byte = horizontal_frontporch_byte + horizontal_backporch_byte; + data_phy_cycles_byte = data_phy_cycles * dsi->lanes + delta; + + if (horizontal_front_back_byte > data_phy_cycles_byte) { + horizontal_frontporch_byte -= data_phy_cycles_byte * + horizontal_frontporch_byte / + horizontal_front_back_byte; + + horizontal_backporch_byte -= data_phy_cycles_byte * + horizontal_backporch_byte / + horizontal_front_back_byte; } else { - if ((vm->hfront_porch + vm->hback_porch) * dsi_tmp_buf_bpp > - data_phy_cycles * dsi->lanes + 12) { - horizontal_frontporch_byte = - vm->hfront_porch * dsi_tmp_buf_bpp - - (data_phy_cycles * dsi->lanes + 12) * - vm->hfront_porch / - (vm->hfront_porch + vm->hback_porch); - horizontal_backporch_byte = horizontal_backporch_byte - - (data_phy_cycles * dsi->lanes + 12) * - vm->hback_porch / - (vm->hfront_porch + vm->hback_porch); - } else { - DRM_WARN("HFP less than d-phy, FPS will under 60Hz\n"); - horizontal_frontporch_byte = vm->hfront_porch * - dsi_tmp_buf_bpp; - } + DRM_WARN("HFP + HBP less than d-phy, FPS will under 60Hz\n"); } writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 549bc67feabb..c2051380d18c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -558,8 +558,10 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, NV_PRINTK(err, cli, "validating bo list\n"); validate_fini(op, chan, NULL, NULL); return ret; + } else if (ret > 0) { + *apply_relocs = true; } - *apply_relocs = ret; + return 0; } @@ -662,7 +664,6 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); } - u_free(reloc); return ret; } @@ -872,9 +873,10 @@ out: break; } } - u_free(reloc); } out_prevalid: + if (!IS_ERR(reloc)) + u_free(reloc); u_free(bo); u_free(push); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 77497b45f9a2..55960cbb1019 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -814,9 +814,15 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, * * XXX(hch): this has no business in a driver and needs to move * to the device tree. + * + * If we have two subsequent calls to dma_direct_set_offset + * returns -EINVAL. Unfortunately, this happens when we have two + * backends in the system, and will result in the driver + * reporting an error while it has been setup properly before. + * Ignore EINVAL, but it should really be removed eventually. */ ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret) + if (ret && ret != -EINVAL) return ret; } diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index d4c08043dd81..92add2cef2e7 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -208,6 +208,7 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, phy_node = of_parse_phandle(dev->of_node, "phys", 0); if (!phy_node) { dev_err(dev, "Can't found PHY phandle\n"); + ret = -EINVAL; goto err_disable_clk_tmds; } diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 19b75bebd35f..c5f2944d5bc6 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -219,6 +219,7 @@ struct vc4_dev { struct drm_modeset_lock ctm_state_lock; struct drm_private_obj ctm_manager; + struct drm_private_obj hvs_channels; struct drm_private_obj load_tracker; /* List of vc4_debugfs_info_entry for adding to debugfs once @@ -531,6 +532,9 @@ struct vc4_crtc_state { unsigned int top; unsigned int bottom; } margins; + + /* Transitional state below, only valid during atomic commits */ + bool update_muxing; }; #define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 95779d50cca0..afc178b0d89f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -760,12 +760,54 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) { } +#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL +#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL + +static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + unsigned long long pixel_rate = mode->clock * 1000; + unsigned long long tmds_rate; + + if (vc4_hdmi->variant->unsupported_odd_h_timings && + ((mode->hdisplay % 2) || (mode->hsync_start % 2) || + (mode->hsync_end % 2) || (mode->htotal % 2))) + return -EINVAL; + + /* + * The 1440p@60 pixel rate is in the same range than the first + * WiFi channel (between 2.4GHz and 2.422GHz with 22MHz + * bandwidth). Slightly lower the frequency to bring it out of + * the WiFi range. + */ + tmds_rate = pixel_rate * 10; + if (vc4_hdmi->disable_wifi_frequencies && + (tmds_rate >= WIFI_2_4GHz_CH1_MIN_FREQ && + tmds_rate <= WIFI_2_4GHz_CH1_MAX_FREQ)) { + mode->clock = 238560; + pixel_rate = mode->clock * 1000; + } + + if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) + return -EINVAL; + + return 0; +} + static enum drm_mode_status vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, const struct drm_display_mode *mode) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + if (vc4_hdmi->variant->unsupported_odd_h_timings && + ((mode->hdisplay % 2) || (mode->hsync_start % 2) || + (mode->hsync_end % 2) || (mode->htotal % 2))) + return MODE_H_ILLEGAL; + if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) return MODE_CLOCK_HIGH; @@ -773,6 +815,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, } static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { + .atomic_check = vc4_hdmi_encoder_atomic_check, .mode_valid = vc4_hdmi_encoder_mode_valid, .disable = vc4_hdmi_encoder_disable, .enable = vc4_hdmi_encoder_enable, @@ -1694,6 +1737,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; } + vc4_hdmi->disable_wifi_frequencies = + of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence"); + pm_runtime_enable(dev); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); @@ -1817,6 +1863,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { PHY_LANE_2, PHY_LANE_CK, }, + .unsupported_odd_h_timings = true, .init_resources = vc5_hdmi_init_resources, .csc_setup = vc5_hdmi_csc_setup, @@ -1842,6 +1889,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { PHY_LANE_CK, PHY_LANE_2, }, + .unsupported_odd_h_timings = true, .init_resources = vc5_hdmi_init_resources, .csc_setup = vc5_hdmi_csc_setup, diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 63c6f8bddf1d..0526a9cf608a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -62,6 +62,9 @@ struct vc4_hdmi_variant { */ enum vc4_hdmi_phy_channel phy_lane_mapping[4]; + /* The BCM2711 cannot deal with odd horizontal pixel timings */ + bool unsupported_odd_h_timings; + /* Callback to get the resources (memory region, interrupts, * clocks, etc) for that variant. */ @@ -139,6 +142,14 @@ struct vc4_hdmi { int hpd_gpio; bool hpd_active_low; + /* + * On some systems (like the RPi4), some modes are in the same + * frequency range than the WiFi channels (1440p@60Hz for + * example). Should we take evasive actions because that system + * has a wifi adapter? + */ + bool disable_wifi_frequencies; + struct cec_adapter *cec_adap; struct cec_msg cec_rx_msg; bool cec_tx_ok; diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 2b951cae04ad..ba310c0ab5f6 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -24,6 +24,8 @@ #include "vc4_drv.h" #include "vc4_regs.h" +#define HVS_NUM_CHANNELS 3 + struct vc4_ctm_state { struct drm_private_state base; struct drm_color_ctm *ctm; @@ -35,6 +37,17 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv) return container_of(priv, struct vc4_ctm_state, base); } +struct vc4_hvs_state { + struct drm_private_state base; + unsigned int unassigned_channels; +}; + +static struct vc4_hvs_state * +to_vc4_hvs_state(struct drm_private_state *priv) +{ + return container_of(priv, struct vc4_hvs_state, base); +} + struct vc4_load_tracker_state { struct drm_private_state base; u64 hvs_load; @@ -113,7 +126,7 @@ static int vc4_ctm_obj_init(struct vc4_dev *vc4) drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, &ctm_state->base, &vc4_ctm_state_funcs); - return drmm_add_action(&vc4->base, vc4_ctm_obj_fini, NULL); + return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL); } /* Converts a DRM S31.32 value to the HW S0.9 format. */ @@ -169,6 +182,19 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); } +static struct vc4_hvs_state * +vc4_hvs_get_global_state(struct drm_atomic_state *state) +{ + struct vc4_dev *vc4 = to_vc4_dev(state->dev); + struct drm_private_state *priv_state; + + priv_state = drm_atomic_get_private_obj_state(state, &vc4->hvs_channels); + if (IS_ERR(priv_state)) + return ERR_CAST(priv_state); + + return to_vc4_hvs_state(priv_state); +} + static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) { @@ -213,10 +239,7 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, { struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; - unsigned char dsp2_mux = 0; - unsigned char dsp3_mux = 3; - unsigned char dsp4_mux = 3; - unsigned char dsp5_mux = 3; + unsigned char mux; unsigned int i; u32 reg; @@ -224,50 +247,59 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - if (!crtc_state->active) + if (!vc4_state->update_muxing) continue; switch (vc4_crtc->data->hvs_output) { case 2: - dsp2_mux = (vc4_state->assigned_channel == 2) ? 0 : 1; + mux = (vc4_state->assigned_channel == 2) ? 0 : 1; + reg = HVS_READ(SCALER_DISPECTRL); + HVS_WRITE(SCALER_DISPECTRL, + (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPECTRL_DSP2_MUX)); break; case 3: - dsp3_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPCTRL); + HVS_WRITE(SCALER_DISPCTRL, + (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPCTRL_DSP3_MUX)); break; case 4: - dsp4_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPEOLN); + HVS_WRITE(SCALER_DISPEOLN, + (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPEOLN_DSP4_MUX)); + break; case 5: - dsp5_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPDITHER); + HVS_WRITE(SCALER_DISPDITHER, + (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPDITHER_DSP5_MUX)); break; default: break; } } - - reg = HVS_READ(SCALER_DISPECTRL); - HVS_WRITE(SCALER_DISPECTRL, - (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | - VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX)); - - reg = HVS_READ(SCALER_DISPCTRL); - HVS_WRITE(SCALER_DISPCTRL, - (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | - VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX)); - - reg = HVS_READ(SCALER_DISPEOLN); - HVS_WRITE(SCALER_DISPEOLN, - (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | - VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX)); - - reg = HVS_READ(SCALER_DISPDITHER); - HVS_WRITE(SCALER_DISPDITHER, - (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | - VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX)); } static void @@ -657,53 +689,123 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4) &load_state->base, &vc4_load_tracker_state_funcs); - return drmm_add_action(&vc4->base, vc4_load_tracker_obj_fini, NULL); + return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL); } -#define NUM_OUTPUTS 6 -#define NUM_CHANNELS 3 +static struct drm_private_state * +vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) +{ + struct vc4_hvs_state *old_state = to_vc4_hvs_state(obj->state); + struct vc4_hvs_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; -static int -vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + + state->unassigned_channels = old_state->unassigned_channels; + + return &state->base; +} + +static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj, + struct drm_private_state *state) { - unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0); - struct drm_crtc_state *old_crtc_state, *new_crtc_state; - struct drm_crtc *crtc; - int i, ret; + struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); - /* - * Since the HVS FIFOs are shared across all the pixelvalves and - * the TXP (and thus all the CRTCs), we need to pull the current - * state of all the enabled CRTCs so that an update to a single - * CRTC still keeps the previous FIFOs enabled and assigned to - * the same CRTCs, instead of evaluating only the CRTC being - * modified. - */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_state *crtc_state; + kfree(hvs_state); +} - if (!crtc->state->enable) - continue; +static const struct drm_private_state_funcs vc4_hvs_state_funcs = { + .atomic_duplicate_state = vc4_hvs_channels_duplicate_state, + .atomic_destroy_state = vc4_hvs_channels_destroy_state, +}; - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } +static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused) +{ + struct vc4_dev *vc4 = to_vc4_dev(dev); + + drm_atomic_private_obj_fini(&vc4->hvs_channels); +} + +static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4) +{ + struct vc4_hvs_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->unassigned_channels = GENMASK(HVS_NUM_CHANNELS - 1, 0); + drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels, + &state->base, + &vc4_hvs_state_funcs); + + return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL); +} + +/* + * The BCM2711 HVS has up to 7 outputs connected to the pixelvalves and + * the TXP (and therefore all the CRTCs found on that platform). + * + * The naive (and our initial) implementation would just iterate over + * all the active CRTCs, try to find a suitable FIFO, and then remove it + * from the pool of available FIFOs. However, there are a few corner + * cases that need to be considered: + * + * - When running in a dual-display setup (so with two CRTCs involved), + * we can update the state of a single CRTC (for example by changing + * its mode using xrandr under X11) without affecting the other. In + * this case, the other CRTC wouldn't be in the state at all, so we + * need to consider all the running CRTCs in the DRM device to assign + * a FIFO, not just the one in the state. + * + * - To fix the above, we can't use drm_atomic_get_crtc_state on all + * enabled CRTCs to pull their CRTC state into the global state, since + * a page flip would start considering their vblank to complete. Since + * we don't have a guarantee that they are actually active, that + * vblank might never happen, and shouldn't even be considered if we + * want to do a page flip on a single CRTC. That can be tested by + * doing a modetest -v first on HDMI1 and then on HDMI0. + * + * - Since we need the pixelvalve to be disabled and enabled back when + * the FIFO is changed, we should keep the FIFO assigned for as long + * as the CRTC is enabled, only considering it free again once that + * CRTC has been disabled. This can be tested by booting X11 on a + * single display, and changing the resolution down and then back up. + */ +static int vc4_pv_muxing_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct vc4_hvs_state *hvs_new_state; + struct drm_crtc_state *old_crtc_state, *new_crtc_state; + struct drm_crtc *crtc; + unsigned int i; + + hvs_new_state = vc4_hvs_get_global_state(state); + if (!hvs_new_state) + return -EINVAL; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct vc4_crtc_state *old_vc4_crtc_state = + to_vc4_crtc_state(old_crtc_state); struct vc4_crtc_state *new_vc4_crtc_state = to_vc4_crtc_state(new_crtc_state); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); unsigned int matching_channels; - if (old_crtc_state->enable && !new_crtc_state->enable) - new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; - - if (!new_crtc_state->enable) + /* Nothing to do here, let's skip it */ + if (old_crtc_state->enable == new_crtc_state->enable) continue; - if (new_vc4_crtc_state->assigned_channel != VC4_HVS_CHANNEL_DISABLED) { - unassigned_channels &= ~BIT(new_vc4_crtc_state->assigned_channel); + /* Muxing will need to be modified, mark it as such */ + new_vc4_crtc_state->update_muxing = true; + + /* If we're disabling our CRTC, we put back our channel */ + if (!new_crtc_state->enable) { + hvs_new_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel); + new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; continue; } @@ -731,17 +833,29 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) * the future, we will need to have something smarter, * but it works so far. */ - matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels; + matching_channels = hvs_new_state->unassigned_channels & vc4_crtc->data->hvs_available_channels; if (matching_channels) { unsigned int channel = ffs(matching_channels) - 1; new_vc4_crtc_state->assigned_channel = channel; - unassigned_channels &= ~BIT(channel); + hvs_new_state->unassigned_channels &= ~BIT(channel); } else { return -EINVAL; } } + return 0; +} + +static int +vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) +{ + int ret; + + ret = vc4_pv_muxing_atomic_check(dev, state); + if (ret) + return ret; + ret = vc4_ctm_atomic_check(dev, state); if (ret < 0) return ret; @@ -808,6 +922,10 @@ int vc4_kms_load(struct drm_device *dev) if (ret) return ret; + ret = vc4_hvs_channels_obj_init(vc4); + if (ret) + return ret; + drm_mode_config_reset(dev); drm_kms_helper_poll_init(dev); diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index a50ba4a4a1d7..b88f889b3932 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -23,19 +23,17 @@ #define CP_2WHEEL_MOUSE_HACK 0x02 #define CP_2WHEEL_MOUSE_HACK_ON 0x04 +#define VA_INVAL_LOGICAL_BOUNDARY 0x08 + /* * Some USB barcode readers from cypress have usage min and usage max in * the wrong order */ -static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, +static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); unsigned int i; - if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) - return rdesc; - if (*rsize < 4) return rdesc; @@ -48,6 +46,40 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } +static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* + * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly + * reports Logical Minimum of its Consumer Control device as 572 + * (0x02 0x3c). Fix this by setting its Logical Minimum to zero. + */ + if (*rsize == 25 && + rdesc[0] == 0x05 && rdesc[1] == 0x0c && + rdesc[2] == 0x09 && rdesc[3] == 0x01 && + rdesc[6] == 0x19 && rdesc[7] == 0x00 && + rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) { + hid_info(hdev, + "fixing up varmilo VA104M consumer control report descriptor\n"); + rdesc[12] = 0x00; + rdesc[13] = 0x00; + } + return rdesc; +} + +static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if (quirks & CP_RDESC_SWAPPED_MIN_MAX) + rdesc = cp_rdesc_fixup(hdev, rdesc, rsize); + if (quirks & VA_INVAL_LOGICAL_BOUNDARY) + rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize); + + return rdesc; +} + static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -128,6 +160,8 @@ static const struct hid_device_id cp_devices[] = { .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), .driver_data = CP_2WHEEL_MOUSE_HACK }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1), + .driver_data = VA_INVAL_LOGICAL_BOUNDARY }, { } }; MODULE_DEVICE_TABLE(hid, cp_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d69842f79fc6..f170feaac40b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -331,6 +331,8 @@ #define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81 #define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 +#define USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1 0X07b1 + #define USB_VENDOR_ID_DATA_MODUL 0x7374 #define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201 @@ -443,6 +445,10 @@ #define USB_VENDOR_ID_FRUCTEL 0x25B6 #define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002 +#define USB_VENDOR_ID_GAMEVICE 0x27F8 +#define USB_DEVICE_ID_GAMEVICE_GV186 0x0BBE +#define USB_DEVICE_ID_GAMEVICE_KISHI 0x0BBF + #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 @@ -485,6 +491,7 @@ #define USB_DEVICE_ID_PENPOWER 0x00f4 #define USB_VENDOR_ID_GREENASIA 0x0e8f +#define USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR 0x3010 #define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013 #define USB_VENDOR_ID_GRETAGMACBETH 0x0971 @@ -743,6 +750,7 @@ #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e #define USB_DEVICE_ID_LOGITECH_T651 0xb00c +#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 #define USB_DEVICE_ID_LOGITECH_C007 0xc007 #define USB_DEVICE_ID_LOGITECH_C077 0xc077 #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 @@ -1298,6 +1306,7 @@ #define USB_VENDOR_ID_UGTIZER 0x2179 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 +#define USB_DEVICE_ID_UGTIZER_TABLET_GT5040 0x0077 #define USB_VENDOR_ID_VIEWSONIC 0x0543 #define USB_DEVICE_ID_VIEWSONIC_PD1011 0xe621 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9770db624bfa..4dca11392459 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -319,6 +319,9 @@ static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), HID_BATTERY_QUIRK_IGNORE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, + USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD), + HID_BATTERY_QUIRK_IGNORE }, {} }; diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 044a93f3c117..742c052b0110 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -11,6 +11,48 @@ #include "hid-ids.h" +#define QUIRK_TOUCHPAD_ON_OFF_REPORT BIT(0) + +static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { + if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { + hid_info(hdev, "Fixing up ITE keyboard report descriptor\n"); + rdesc[163] = HID_MAIN_ITEM_RELATIVE; + } + } + + return rdesc; +} + +static int ite_input_mapping(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, + int *max) +{ + + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) && + (usage->hid & HID_USAGE_PAGE) == 0x00880000) { + if (usage->hid == 0x00880078) { + /* Touchpad on, userspace expects F22 for this */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F22); + return 1; + } + if (usage->hid == 0x00880079) { + /* Touchpad off, userspace expects F23 for this */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F23); + return 1; + } + return -1; + } + + return 0; +} + static int ite_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -37,13 +79,27 @@ static int ite_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static int ite_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hid_set_drvdata(hdev, (void *)id->driver_data); + + ret = hid_open_report(hdev); + if (ret) + return ret; + + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); +} + static const struct hid_device_id ite_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_SYNAPTICS, - USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) }, + USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), + .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_SYNAPTICS, @@ -55,6 +111,9 @@ MODULE_DEVICE_TABLE(hid, ite_devices); static struct hid_driver ite_driver = { .name = "itetech", .id_table = ite_devices, + .probe = ite_probe, + .report_fixup = ite_report_fixup, + .input_mapping = ite_input_mapping, .event = ite_event, }; module_hid_driver(ite_driver); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 72fb6e54a50a..1ffcfc9a1e03 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -328,7 +328,7 @@ static const char mse_bluetooth_descriptor[] = { 0x25, 0x01, /* LOGICAL_MAX (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x95, 0x04, /* REPORT_COUNT (4) */ - 0x81, 0x06, /* INPUT */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 0xC0, /* END_COLLECTION */ 0xC0, /* END_COLLECTION */ }; @@ -866,11 +866,24 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, schedule_work(&djrcv_dev->work); } +/* + * Some quad/bluetooth keyboards have a builtin touchpad in this case we see + * only 1 paired device with a device_type of REPORT_TYPE_KEYBOARD. For the + * touchpad to work we must also forward mouse input reports to the dj_hiddev + * created for the keyboard (instead of forwarding them to a second paired + * device with a device_type of REPORT_TYPE_MOUSE as we normally would). + */ +static const u16 kbd_builtin_touchpad_ids[] = { + 0xb309, /* Dinovo Edge */ + 0xb30c, /* Dinovo Mini */ +}; + static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev, struct hidpp_event *hidpp_report, struct dj_workitem *workitem) { struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); + int i, id; workitem->type = WORKITEM_TYPE_PAIRED; workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & @@ -882,6 +895,13 @@ static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev, workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA | POWER_KEYS | MEDIA_CENTER | HIDPP; + id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb; + for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) { + if (id == kbd_builtin_touchpad_ids[i]) { + workitem->reports_supported |= STD_MOUSE; + break; + } + } break; case REPORT_TYPE_MOUSE: workitem->reports_supported |= STD_MOUSE | HIDPP; diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index b8b53dc95e86..0ca723119547 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -93,6 +93,8 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3) #define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4) +#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) + /* * There are two hidpp protocols in use, the first version hidpp10 is known * as register access protocol or RAP, the second version hidpp20 is known as @@ -2951,6 +2953,26 @@ static int g920_get_config(struct hidpp_device *hidpp, } /* -------------------------------------------------------------------------- */ +/* Logitech Dinovo Mini keyboard with builtin touchpad */ +/* -------------------------------------------------------------------------- */ +#define DINOVO_MINI_PRODUCT_ID 0xb30c + +static int lg_dinovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x00d: lg_map_key_clear(KEY_MEDIA); break; + default: + return 0; + } + return 1; +} + +/* -------------------------------------------------------------------------- */ /* HID++1.0 devices which use HID++ reports for their wheels */ /* -------------------------------------------------------------------------- */ static int hidpp10_wheel_connect(struct hidpp_device *hidpp) @@ -3185,6 +3207,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_GD_MOUSE) return m560_input_mapping(hdev, hi, field, usage, bit, max); + if (hdev->product == DINOVO_MINI_PRODUCT_ID) + return lg_dinovo_input_mapping(hdev, hi, field, usage, bit, max); + return 0; } @@ -3947,6 +3972,7 @@ static const struct hid_device_id hidpp_devices[] = { LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, { /* Mouse Logitech MX Anywhere 2 */ LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, @@ -3971,6 +3997,9 @@ static const struct hid_device_id hidpp_devices[] = { { /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */ LDJ_DEVICE(0xb305), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, + { /* Dinovo Edge (Bluetooth-receiver in HID proxy mode) */ + LDJ_DEVICE(0xb309), + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, { /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */ LDJ_DEVICE(0xb30b), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, @@ -4013,6 +4042,9 @@ static const struct hid_device_id hidpp_devices[] = { { /* MX5000 keyboard over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, + { /* Dinovo Edge keyboard over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb309), + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, { /* MX5500 keyboard over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 0d27ccb55dd9..4211b9839209 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -49,6 +49,36 @@ enum { MCP2221_ALT_F_NOT_GPIOD = 0xEF, }; +/* MCP GPIO direction encoding */ +enum { + MCP2221_DIR_OUT = 0x00, + MCP2221_DIR_IN = 0x01, +}; + +#define MCP_NGPIO 4 + +/* MCP GPIO set command layout */ +struct mcp_set_gpio { + u8 cmd; + u8 dummy; + struct { + u8 change_value; + u8 value; + u8 change_direction; + u8 direction; + } gpio[MCP_NGPIO]; +} __packed; + +/* MCP GPIO get command layout */ +struct mcp_get_gpio { + u8 cmd; + u8 dummy; + struct { + u8 direction; + u8 value; + } gpio[MCP_NGPIO]; +} __packed; + /* * There is no way to distinguish responses. Therefore next command * is sent only after response to previous has been received. Mutex @@ -542,7 +572,7 @@ static int mcp_gpio_get(struct gpio_chip *gc, mcp->txbuf[0] = MCP2221_GPIO_GET; - mcp->gp_idx = (offset + 1) * 2; + mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].value); mutex_lock(&mcp->lock); ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); @@ -559,7 +589,7 @@ static void mcp_gpio_set(struct gpio_chip *gc, memset(mcp->txbuf, 0, 18); mcp->txbuf[0] = MCP2221_GPIO_SET; - mcp->gp_idx = ((offset + 1) * 4) - 1; + mcp->gp_idx = offsetof(struct mcp_set_gpio, gpio[offset].value); mcp->txbuf[mcp->gp_idx - 1] = 1; mcp->txbuf[mcp->gp_idx] = !!value; @@ -575,7 +605,7 @@ static int mcp_gpio_dir_set(struct mcp2221 *mcp, memset(mcp->txbuf, 0, 18); mcp->txbuf[0] = MCP2221_GPIO_SET; - mcp->gp_idx = (offset + 1) * 5; + mcp->gp_idx = offsetof(struct mcp_set_gpio, gpio[offset].direction); mcp->txbuf[mcp->gp_idx - 1] = 1; mcp->txbuf[mcp->gp_idx] = val; @@ -590,7 +620,7 @@ static int mcp_gpio_direction_input(struct gpio_chip *gc, struct mcp2221 *mcp = gpiochip_get_data(gc); mutex_lock(&mcp->lock); - ret = mcp_gpio_dir_set(mcp, offset, 0); + ret = mcp_gpio_dir_set(mcp, offset, MCP2221_DIR_IN); mutex_unlock(&mcp->lock); return ret; @@ -603,7 +633,7 @@ static int mcp_gpio_direction_output(struct gpio_chip *gc, struct mcp2221 *mcp = gpiochip_get_data(gc); mutex_lock(&mcp->lock); - ret = mcp_gpio_dir_set(mcp, offset, 1); + ret = mcp_gpio_dir_set(mcp, offset, MCP2221_DIR_OUT); mutex_unlock(&mcp->lock); /* Can't configure as output, bailout early */ @@ -623,7 +653,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc, mcp->txbuf[0] = MCP2221_GPIO_GET; - mcp->gp_idx = (offset + 1) * 2; + mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].direction); mutex_lock(&mcp->lock); ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); @@ -632,7 +662,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc, if (ret) return ret; - if (mcp->gpio_dir) + if (mcp->gpio_dir == MCP2221_DIR_IN) return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; @@ -758,7 +788,7 @@ static int mcp2221_raw_event(struct hid_device *hdev, mcp->status = -ENOENT; } else { mcp->status = !!data[mcp->gp_idx]; - mcp->gpio_dir = !!data[mcp->gp_idx + 1]; + mcp->gpio_dir = data[mcp->gp_idx + 1]; } break; default: @@ -860,7 +890,7 @@ static int mcp2221_probe(struct hid_device *hdev, mcp->gc->get_direction = mcp_gpio_get_direction; mcp->gc->set = mcp_gpio_set; mcp->gc->get = mcp_gpio_get; - mcp->gc->ngpio = 4; + mcp->gc->ngpio = MCP_NGPIO; mcp->gc->base = -1; mcp->gc->can_sleep = 1; mcp->gc->parent = &hdev->dev; diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 7a2be0205dfd..bf7ecab5d9e5 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -83,7 +83,12 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD), HID_QUIRK_MULTI_INPUT }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_GV186), + HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_KISHI), + HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 94c7398b5c27..3dd7d3246737 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -483,7 +483,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev, return 1; ptr = raw_data; - ptr++; /* Skip report id */ + if (report->id) + ptr++; /* Skip report id */ spin_lock_irqsave(&pdata->lock, flags); diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 86b568037cb8..8e9c9e646cb7 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -385,6 +385,8 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, + USB_DEVICE_ID_UGTIZER_TABLET_GT5040) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_G5) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 7d20d1fcf8d2..d26d8cd98efc 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -997,6 +997,8 @@ int uclogic_params_init(struct uclogic_params *params, break; case VID_PID(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610): + case VID_PID(USB_VENDOR_ID_UGTIZER, + USB_DEVICE_ID_UGTIZER_TABLET_GT5040): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540): case VID_PID(USB_VENDOR_ID_UGEE, diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 786e3e9af1c9..aeff1ffb0c8b 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -943,6 +943,11 @@ static void i2c_hid_acpi_enable_wakeup(struct device *dev) } } +static void i2c_hid_acpi_shutdown(struct device *dev) +{ + acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D3_COLD); +} + static const struct acpi_device_id i2c_hid_acpi_match[] = { {"ACPI0C50", 0 }, {"PNP0C50", 0 }, @@ -959,6 +964,8 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client, static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {} static inline void i2c_hid_acpi_enable_wakeup(struct device *dev) {} + +static inline void i2c_hid_acpi_shutdown(struct device *dev) {} #endif #ifdef CONFIG_OF @@ -1175,6 +1182,8 @@ static void i2c_hid_shutdown(struct i2c_client *client) i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); free_irq(client->irq, ihid); + + i2c_hid_acpi_shutdown(&client->dev); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index beb38d9d607d..560a3373ff20 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -126,6 +126,12 @@ enum kx_chipset { KX_MAX_CHIPS /* this must be last */ }; +enum kx_acpi_type { + ACPI_GENERIC, + ACPI_SMO8500, + ACPI_KIOX010A, +}; + struct kxcjk1013_data { struct i2c_client *client; struct iio_trigger *dready_trig; @@ -143,7 +149,7 @@ struct kxcjk1013_data { bool motion_trigger_on; int64_t timestamp; enum kx_chipset chipset; - bool is_smo8500_device; + enum kx_acpi_type acpi_type; }; enum kxcjk1013_axis { @@ -270,6 +276,32 @@ static const struct { {19163, 1, 0}, {38326, 0, 1} }; +#ifdef CONFIG_ACPI +enum kiox010a_fn_index { + KIOX010A_SET_LAPTOP_MODE = 1, + KIOX010A_SET_TABLET_MODE = 2, +}; + +static int kiox010a_dsm(struct device *dev, int fn_index) +{ + acpi_handle handle = ACPI_HANDLE(dev); + guid_t kiox010a_dsm_guid; + union acpi_object *obj; + + if (!handle) + return -ENODEV; + + guid_parse("1f339696-d475-4e26-8cad-2e9f8e6d7a91", &kiox010a_dsm_guid); + + obj = acpi_evaluate_dsm(handle, &kiox010a_dsm_guid, 1, fn_index, NULL); + if (!obj) + return -EIO; + + ACPI_FREE(obj); + return 0; +} +#endif + static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { @@ -347,6 +379,13 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) { int ret; +#ifdef CONFIG_ACPI + if (data->acpi_type == ACPI_KIOX010A) { + /* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */ + kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE); + } +#endif + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_WHO_AM_I); if (ret < 0) { dev_err(&data->client->dev, "Error reading who_am_i\n"); @@ -1247,7 +1286,7 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) static const char *kxcjk1013_match_acpi_device(struct device *dev, enum kx_chipset *chipset, - bool *is_smo8500_device) + enum kx_acpi_type *acpi_type) { const struct acpi_device_id *id; @@ -1256,7 +1295,9 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, return NULL; if (strcmp(id->id, "SMO8500") == 0) - *is_smo8500_device = true; + *acpi_type = ACPI_SMO8500; + else if (strcmp(id->id, "KIOX010A") == 0) + *acpi_type = ACPI_KIOX010A; *chipset = (enum kx_chipset)id->driver_data; @@ -1299,7 +1340,7 @@ static int kxcjk1013_probe(struct i2c_client *client, } else if (ACPI_HANDLE(&client->dev)) { name = kxcjk1013_match_acpi_device(&client->dev, &data->chipset, - &data->is_smo8500_device); + &data->acpi_type); } else return -ENODEV; @@ -1316,7 +1357,7 @@ static int kxcjk1013_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &kxcjk1013_info; - if (client->irq > 0 && !data->is_smo8500_device) { + if (client->irq > 0 && data->acpi_type != ACPI_SMO8500) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 92b25083e23f..1aafbe2cfe67 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -71,7 +71,7 @@ #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986) #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12 -#define JZ4770_ADC_BATTERY_VREF 6600 +#define JZ4770_ADC_BATTERY_VREF 1200 #define JZ4770_ADC_BATTERY_VREF_BITS 12 #define JZ_ADC_IRQ_AUX BIT(0) @@ -177,13 +177,12 @@ static void ingenic_adc_set_config(struct ingenic_adc *adc, mutex_unlock(&adc->lock); } -static void ingenic_adc_enable(struct ingenic_adc *adc, - int engine, - bool enabled) +static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc, + int engine, + bool enabled) { u8 val; - mutex_lock(&adc->lock); val = readb(adc->base + JZ_ADC_REG_ENABLE); if (enabled) @@ -192,20 +191,41 @@ static void ingenic_adc_enable(struct ingenic_adc *adc, val &= ~BIT(engine); writeb(val, adc->base + JZ_ADC_REG_ENABLE); +} + +static void ingenic_adc_enable(struct ingenic_adc *adc, + int engine, + bool enabled) +{ + mutex_lock(&adc->lock); + ingenic_adc_enable_unlocked(adc, engine, enabled); mutex_unlock(&adc->lock); } static int ingenic_adc_capture(struct ingenic_adc *adc, int engine) { + u32 cfg; u8 val; int ret; - ingenic_adc_enable(adc, engine, true); + /* + * Disable CMD_SEL temporarily, because it causes wrong VBAT readings, + * probably due to the switch of VREF. We must keep the lock here to + * avoid races with the buffer enable/disable functions. + */ + mutex_lock(&adc->lock); + cfg = readl(adc->base + JZ_ADC_REG_CFG); + writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); + + ingenic_adc_enable_unlocked(adc, engine, true); ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val, !(val & BIT(engine)), 250, 1000); if (ret) - ingenic_adc_enable(adc, engine, false); + ingenic_adc_enable_unlocked(adc, engine, false); + + writel(cfg, adc->base + JZ_ADC_REG_CFG); + mutex_unlock(&adc->lock); return ret; } diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index ac415cb089cd..79c1dd68b909 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -9,9 +9,9 @@ #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/iopoll.h> #include <linux/io.h> #include <linux/iio/iio.h> @@ -276,6 +276,8 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) goto err_disable_clk; } + adc_dev->dev_comp = device_get_match_data(&pdev->dev); + mutex_init(&adc_dev->lock); mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index cd870c089182..a83199b212a4 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -41,18 +41,16 @@ * struct stm32_adc_common_regs - stm32 common registers * @csr: common status register offset * @ccr: common control register offset - * @eoc1_msk: adc1 end of conversion flag in @csr - * @eoc2_msk: adc2 end of conversion flag in @csr - * @eoc3_msk: adc3 end of conversion flag in @csr + * @eoc_msk: array of eoc (end of conversion flag) masks in csr for adc1..n + * @ovr_msk: array of ovr (overrun flag) masks in csr for adc1..n * @ier: interrupt enable register offset for each adc * @eocie_msk: end of conversion interrupt enable mask in @ier */ struct stm32_adc_common_regs { u32 csr; u32 ccr; - u32 eoc1_msk; - u32 eoc2_msk; - u32 eoc3_msk; + u32 eoc_msk[STM32_ADC_MAX_ADCS]; + u32 ovr_msk[STM32_ADC_MAX_ADCS]; u32 ier; u32 eocie_msk; }; @@ -282,21 +280,20 @@ out: static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { .csr = STM32F4_ADC_CSR, .ccr = STM32F4_ADC_CCR, - .eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1, - .eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2, - .eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3, + .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3}, + .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3}, .ier = STM32F4_ADC_CR1, - .eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE, + .eocie_msk = STM32F4_EOCIE, }; /* STM32H7 common registers definitions */ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { .csr = STM32H7_ADC_CSR, .ccr = STM32H7_ADC_CCR, - .eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST, - .eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV, + .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV}, + .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV}, .ier = STM32H7_ADC_IER, - .eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE, + .eocie_msk = STM32H7_EOCIE, }; static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = { @@ -318,6 +315,7 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) { struct stm32_adc_priv *priv = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + int i; u32 status; chained_irq_enter(chip, desc); @@ -335,17 +333,12 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) * before invoking the interrupt handler (e.g. call ISR only for * IRQ-enabled ADCs). */ - if (status & priv->cfg->regs->eoc1_msk && - stm32_adc_eoc_enabled(priv, 0)) - generic_handle_irq(irq_find_mapping(priv->domain, 0)); - - if (status & priv->cfg->regs->eoc2_msk && - stm32_adc_eoc_enabled(priv, 1)) - generic_handle_irq(irq_find_mapping(priv->domain, 1)); - - if (status & priv->cfg->regs->eoc3_msk && - stm32_adc_eoc_enabled(priv, 2)) - generic_handle_irq(irq_find_mapping(priv->domain, 2)); + for (i = 0; i < priv->cfg->num_irqs; i++) { + if ((status & priv->cfg->regs->eoc_msk[i] && + stm32_adc_eoc_enabled(priv, i)) || + (status & priv->cfg->regs->ovr_msk[i])) + generic_handle_irq(irq_find_mapping(priv->domain, i)); + } chained_irq_exit(chip, desc); }; diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index b3f31f147347..16c02c30dec7 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -154,6 +154,7 @@ struct stm32_adc; * @start_conv: routine to start conversions * @stop_conv: routine to stop conversions * @unprepare: optional unprepare routine (disable, power-down) + * @irq_clear: routine to clear irqs * @smp_cycles: programmable sampling time (ADC clock cycles) */ struct stm32_adc_cfg { @@ -166,6 +167,7 @@ struct stm32_adc_cfg { void (*start_conv)(struct iio_dev *, bool dma); void (*stop_conv)(struct iio_dev *); void (*unprepare)(struct iio_dev *); + void (*irq_clear)(struct iio_dev *indio_dev, u32 msk); const unsigned int *smp_cycles; }; @@ -621,6 +623,13 @@ static void stm32f4_adc_stop_conv(struct iio_dev *indio_dev) STM32F4_ADON | STM32F4_DMA | STM32F4_DDS); } +static void stm32f4_adc_irq_clear(struct iio_dev *indio_dev, u32 msk) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + stm32_adc_clr_bits(adc, adc->cfg->regs->isr_eoc.reg, msk); +} + static void stm32h7_adc_start_conv(struct iio_dev *indio_dev, bool dma) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -659,6 +668,13 @@ static void stm32h7_adc_stop_conv(struct iio_dev *indio_dev) stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK); } +static void stm32h7_adc_irq_clear(struct iio_dev *indio_dev, u32 msk) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + /* On STM32H7 IRQs are cleared by writing 1 into ISR register */ + stm32_adc_set_bits(adc, adc->cfg->regs->isr_eoc.reg, msk); +} + static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -1235,17 +1251,40 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, } } +static void stm32_adc_irq_clear(struct iio_dev *indio_dev, u32 msk) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + adc->cfg->irq_clear(indio_dev, msk); +} + static irqreturn_t stm32_adc_threaded_isr(int irq, void *data) { struct iio_dev *indio_dev = data; struct stm32_adc *adc = iio_priv(indio_dev); const struct stm32_adc_regspec *regs = adc->cfg->regs; u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); + u32 mask = stm32_adc_readl(adc, regs->ier_eoc.reg); - if (status & regs->isr_ovr.mask) + /* Check ovr status right now, as ovr mask should be already disabled */ + if (status & regs->isr_ovr.mask) { + /* + * Clear ovr bit to avoid subsequent calls to IRQ handler. + * This requires to stop ADC first. OVR bit state in ISR, + * is propaged to CSR register by hardware. + */ + adc->cfg->stop_conv(indio_dev); + stm32_adc_irq_clear(indio_dev, regs->isr_ovr.mask); dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n"); + return IRQ_HANDLED; + } - return IRQ_HANDLED; + if (!(status & mask)) + dev_err_ratelimited(&indio_dev->dev, + "Unexpected IRQ: IER=0x%08x, ISR=0x%08x\n", + mask, status); + + return IRQ_NONE; } static irqreturn_t stm32_adc_isr(int irq, void *data) @@ -1254,6 +1293,10 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) struct stm32_adc *adc = iio_priv(indio_dev); const struct stm32_adc_regspec *regs = adc->cfg->regs; u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); + u32 mask = stm32_adc_readl(adc, regs->ier_eoc.reg); + + if (!(status & mask)) + return IRQ_WAKE_THREAD; if (status & regs->isr_ovr.mask) { /* @@ -2046,6 +2089,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { .start_conv = stm32f4_adc_start_conv, .stop_conv = stm32f4_adc_stop_conv, .smp_cycles = stm32f4_adc_smp_cycles, + .irq_clear = stm32f4_adc_irq_clear, }; static const struct stm32_adc_cfg stm32h7_adc_cfg = { @@ -2057,6 +2101,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .prepare = stm32h7_adc_prepare, .unprepare = stm32h7_adc_unprepare, .smp_cycles = stm32h7_adc_smp_cycles, + .irq_clear = stm32h7_adc_irq_clear, }; static const struct stm32_adc_cfg stm32mp1_adc_cfg = { @@ -2069,6 +2114,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .prepare = stm32h7_adc_prepare, .unprepare = stm32h7_adc_unprepare, .smp_cycles = stm32h7_adc_smp_cycles, + .irq_clear = stm32h7_adc_irq_clear, }; static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index c62cacc04672..e3f507771f17 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -256,7 +256,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent); struct cros_ec_dev *ec = sensor_hub->ec; struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); - u32 ver_mask; + u32 ver_mask, temp; int frequencies[ARRAY_SIZE(state->frequencies) / 2] = { 0 }; int ret, i; @@ -311,10 +311,16 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, &frequencies[2], &state->fifo_max_event_count); } else { - frequencies[1] = state->resp->info_3.min_frequency; - frequencies[2] = state->resp->info_3.max_frequency; - state->fifo_max_event_count = - state->resp->info_3.fifo_max_event_count; + if (state->resp->info_3.max_frequency == 0) { + get_default_min_max_freq(state->resp->info.type, + &frequencies[1], + &frequencies[2], + &temp); + } else { + frequencies[1] = state->resp->info_3.min_frequency; + frequencies[2] = state->resp->info_3.max_frequency; + } + state->fifo_max_event_count = state->resp->info_3.fifo_max_event_count; } for (i = 0; i < ARRAY_SIZE(frequencies); i++) { state->frequencies[2 * i] = frequencies[i] / 1000; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index 8c8d8870ca07..99562ba85ee4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -156,11 +156,13 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) { struct st_lsm6dsx_sensor *sensor; - u32 odr; + u32 odr, timeout; sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 12500; - msleep((2000000U / odr) + 1); + /* set 10ms as minimum timeout for i2c slave configuration */ + timeout = max_t(u32, 2000000U / odr + 1, 10); + msleep(timeout); } /* diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index cade6dc0305b..33ad4dd0b5c7 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -544,6 +544,7 @@ config VCNL4000 config VCNL4035 tristate "VCNL4035 combined ALS and proximity sensor" + select IIO_BUFFER select IIO_TRIGGERED_BUFFER select REGMAP_I2C depends on I2C diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 8ca51e43cf53..329ee4f48d95 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -1,4 +1,5 @@ /* + * Copyright(c) 2020 Cornelis Networks, Inc. * Copyright(c) 2015-2020 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -206,8 +207,6 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) spin_lock_init(&fd->tid_lock); spin_lock_init(&fd->invalid_lock); fd->rec_cpu_num = -1; /* no cpu affinity by default */ - fd->mm = current->mm; - mmgrab(fd->mm); fd->dd = dd; fp->private_data = fd; return 0; @@ -711,7 +710,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) deallocate_ctxt(uctxt); done: - mmdrop(fdata->mm); if (atomic_dec_and_test(&dd->user_refcount)) complete(&dd->user_comp); diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index b4c6bff60a4e..e09e8244a94c 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1,6 +1,7 @@ #ifndef _HFI1_KERNEL_H #define _HFI1_KERNEL_H /* + * Copyright(c) 2020 Cornelis Networks, Inc. * Copyright(c) 2015-2020 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -1451,7 +1452,6 @@ struct hfi1_filedata { u32 invalid_tid_idx; /* protect invalid_tids array and invalid_tid_idx */ spinlock_t invalid_lock; - struct mm_struct *mm; }; extern struct xarray hfi1_dev_table; diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c index 24ca17b77b72..f3fb28e3d5d7 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.c +++ b/drivers/infiniband/hw/hfi1/mmu_rb.c @@ -1,4 +1,5 @@ /* + * Copyright(c) 2020 Cornelis Networks, Inc. * Copyright(c) 2016 - 2017 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -48,23 +49,11 @@ #include <linux/rculist.h> #include <linux/mmu_notifier.h> #include <linux/interval_tree_generic.h> +#include <linux/sched/mm.h> #include "mmu_rb.h" #include "trace.h" -struct mmu_rb_handler { - struct mmu_notifier mn; - struct rb_root_cached root; - void *ops_arg; - spinlock_t lock; /* protect the RB tree */ - struct mmu_rb_ops *ops; - struct mm_struct *mm; - struct list_head lru_list; - struct work_struct del_work; - struct list_head del_list; - struct workqueue_struct *wq; -}; - static unsigned long mmu_node_start(struct mmu_rb_node *); static unsigned long mmu_node_last(struct mmu_rb_node *); static int mmu_notifier_range_start(struct mmu_notifier *, @@ -92,37 +81,36 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node) return PAGE_ALIGN(node->addr + node->len) - 1; } -int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm, +int hfi1_mmu_rb_register(void *ops_arg, struct mmu_rb_ops *ops, struct workqueue_struct *wq, struct mmu_rb_handler **handler) { - struct mmu_rb_handler *handlr; + struct mmu_rb_handler *h; int ret; - handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); - if (!handlr) + h = kmalloc(sizeof(*h), GFP_KERNEL); + if (!h) return -ENOMEM; - handlr->root = RB_ROOT_CACHED; - handlr->ops = ops; - handlr->ops_arg = ops_arg; - INIT_HLIST_NODE(&handlr->mn.hlist); - spin_lock_init(&handlr->lock); - handlr->mn.ops = &mn_opts; - handlr->mm = mm; - INIT_WORK(&handlr->del_work, handle_remove); - INIT_LIST_HEAD(&handlr->del_list); - INIT_LIST_HEAD(&handlr->lru_list); - handlr->wq = wq; - - ret = mmu_notifier_register(&handlr->mn, handlr->mm); + h->root = RB_ROOT_CACHED; + h->ops = ops; + h->ops_arg = ops_arg; + INIT_HLIST_NODE(&h->mn.hlist); + spin_lock_init(&h->lock); + h->mn.ops = &mn_opts; + INIT_WORK(&h->del_work, handle_remove); + INIT_LIST_HEAD(&h->del_list); + INIT_LIST_HEAD(&h->lru_list); + h->wq = wq; + + ret = mmu_notifier_register(&h->mn, current->mm); if (ret) { - kfree(handlr); + kfree(h); return ret; } - *handler = handlr; + *handler = h; return 0; } @@ -134,7 +122,7 @@ void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) struct list_head del_list; /* Unregister first so we don't get any more notifications. */ - mmu_notifier_unregister(&handler->mn, handler->mm); + mmu_notifier_unregister(&handler->mn, handler->mn.mm); /* * Make sure the wq delete handler is finished running. It will not @@ -166,6 +154,10 @@ int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, int ret = 0; trace_hfi1_mmu_rb_insert(mnode->addr, mnode->len); + + if (current->mm != handler->mn.mm) + return -EPERM; + spin_lock_irqsave(&handler->lock, flags); node = __mmu_rb_search(handler, mnode->addr, mnode->len); if (node) { @@ -180,6 +172,7 @@ int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, __mmu_int_rb_remove(mnode, &handler->root); list_del(&mnode->list); /* remove from LRU list */ } + mnode->handler = handler; unlock: spin_unlock_irqrestore(&handler->lock, flags); return ret; @@ -217,6 +210,9 @@ bool hfi1_mmu_rb_remove_unless_exact(struct mmu_rb_handler *handler, unsigned long flags; bool ret = false; + if (current->mm != handler->mn.mm) + return ret; + spin_lock_irqsave(&handler->lock, flags); node = __mmu_rb_search(handler, addr, len); if (node) { @@ -239,6 +235,9 @@ void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg) unsigned long flags; bool stop = false; + if (current->mm != handler->mn.mm) + return; + INIT_LIST_HEAD(&del_list); spin_lock_irqsave(&handler->lock, flags); @@ -272,6 +271,9 @@ void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, { unsigned long flags; + if (current->mm != handler->mn.mm) + return; + /* Validity of handler and node pointers has been checked by caller. */ trace_hfi1_mmu_rb_remove(node->addr, node->len); spin_lock_irqsave(&handler->lock, flags); diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.h b/drivers/infiniband/hw/hfi1/mmu_rb.h index f04cec1e99d1..423aacc67e94 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.h +++ b/drivers/infiniband/hw/hfi1/mmu_rb.h @@ -1,4 +1,5 @@ /* + * Copyright(c) 2020 Cornelis Networks, Inc. * Copyright(c) 2016 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -54,6 +55,7 @@ struct mmu_rb_node { unsigned long len; unsigned long __last; struct rb_node node; + struct mmu_rb_handler *handler; struct list_head list; }; @@ -71,7 +73,19 @@ struct mmu_rb_ops { void *evict_arg, bool *stop); }; -int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm, +struct mmu_rb_handler { + struct mmu_notifier mn; + struct rb_root_cached root; + void *ops_arg; + spinlock_t lock; /* protect the RB tree */ + struct mmu_rb_ops *ops; + struct list_head lru_list; + struct work_struct del_work; + struct list_head del_list; + struct workqueue_struct *wq; +}; + +int hfi1_mmu_rb_register(void *ops_arg, struct mmu_rb_ops *ops, struct workqueue_struct *wq, struct mmu_rb_handler **handler); diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c index f81ca20f4b69..b94fc7fd75a9 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c @@ -1,4 +1,5 @@ /* + * Copyright(c) 2020 Cornelis Networks, Inc. * Copyright(c) 2015-2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -173,15 +174,18 @@ static void unpin_rcv_pages(struct hfi1_filedata *fd, { struct page **pages; struct hfi1_devdata *dd = fd->uctxt->dd; + struct mm_struct *mm; if (mapped) { pci_unmap_single(dd->pcidev, node->dma_addr, node->npages * PAGE_SIZE, PCI_DMA_FROMDEVICE); pages = &node->pages[idx]; + mm = mm_from_tid_node(node); } else { pages = &tidbuf->pages[idx]; + mm = current->mm; } - hfi1_release_user_pages(fd->mm, pages, npages, mapped); + hfi1_release_user_pages(mm, pages, npages, mapped); fd->tid_n_pinned -= npages; } @@ -216,12 +220,12 @@ static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf) * pages, accept the amount pinned so far and program only that. * User space knows how to deal with partially programmed buffers. */ - if (!hfi1_can_pin_pages(dd, fd->mm, fd->tid_n_pinned, npages)) { + if (!hfi1_can_pin_pages(dd, current->mm, fd->tid_n_pinned, npages)) { kfree(pages); return -ENOMEM; } - pinned = hfi1_acquire_user_pages(fd->mm, vaddr, npages, true, pages); + pinned = hfi1_acquire_user_pages(current->mm, vaddr, npages, true, pages); if (pinned <= 0) { kfree(pages); return pinned; @@ -756,7 +760,7 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd, if (fd->use_mn) { ret = mmu_interval_notifier_insert( - &node->notifier, fd->mm, + &node->notifier, current->mm, tbuf->vaddr + (pageidx * PAGE_SIZE), npages * PAGE_SIZE, &tid_mn_ops); if (ret) diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.h b/drivers/infiniband/hw/hfi1/user_exp_rcv.h index 332abb446861..d45c7b6988d4 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.h +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.h @@ -1,6 +1,7 @@ #ifndef _HFI1_USER_EXP_RCV_H #define _HFI1_USER_EXP_RCV_H /* + * Copyright(c) 2020 - Cornelis Networks, Inc. * Copyright(c) 2015 - 2017 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -95,4 +96,9 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, int hfi1_user_exp_rcv_invalid(struct hfi1_filedata *fd, struct hfi1_tid_info *tinfo); +static inline struct mm_struct *mm_from_tid_node(struct tid_rb_node *node) +{ + return node->notifier.mm; +} + #endif /* _HFI1_USER_EXP_RCV_H */ diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index a92346e88628..4a4956f96a7e 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -1,4 +1,5 @@ /* + * Copyright(c) 2020 - Cornelis Networks, Inc. * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -188,7 +189,6 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, atomic_set(&pq->n_reqs, 0); init_waitqueue_head(&pq->wait); atomic_set(&pq->n_locked, 0); - pq->mm = fd->mm; iowait_init(&pq->busy, 0, NULL, NULL, defer_packet_queue, activate_packet_queue, NULL, NULL); @@ -230,7 +230,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, cq->nentries = hfi1_sdma_comp_ring_size; - ret = hfi1_mmu_rb_register(pq, pq->mm, &sdma_rb_ops, dd->pport->hfi1_wq, + ret = hfi1_mmu_rb_register(pq, &sdma_rb_ops, dd->pport->hfi1_wq, &pq->handler); if (ret) { dd_dev_err(dd, "Failed to register with MMU %d", ret); @@ -980,13 +980,13 @@ static int pin_sdma_pages(struct user_sdma_request *req, npages -= node->npages; retry: - if (!hfi1_can_pin_pages(pq->dd, pq->mm, + if (!hfi1_can_pin_pages(pq->dd, current->mm, atomic_read(&pq->n_locked), npages)) { cleared = sdma_cache_evict(pq, npages); if (cleared >= npages) goto retry; } - pinned = hfi1_acquire_user_pages(pq->mm, + pinned = hfi1_acquire_user_pages(current->mm, ((unsigned long)iovec->iov.iov_base + (node->npages * PAGE_SIZE)), npages, 0, pages + node->npages); @@ -995,7 +995,7 @@ retry: return pinned; } if (pinned != npages) { - unpin_vector_pages(pq->mm, pages, node->npages, pinned); + unpin_vector_pages(current->mm, pages, node->npages, pinned); return -EFAULT; } kfree(node->pages); @@ -1008,7 +1008,8 @@ retry: static void unpin_sdma_pages(struct sdma_mmu_node *node) { if (node->npages) { - unpin_vector_pages(node->pq->mm, node->pages, 0, node->npages); + unpin_vector_pages(mm_from_sdma_node(node), node->pages, 0, + node->npages); atomic_sub(node->npages, &node->pq->n_locked); } } diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index 9972e0e6545e..1e8c02fe8ad1 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -1,6 +1,7 @@ #ifndef _HFI1_USER_SDMA_H #define _HFI1_USER_SDMA_H /* + * Copyright(c) 2020 - Cornelis Networks, Inc. * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or @@ -133,7 +134,6 @@ struct hfi1_user_sdma_pkt_q { unsigned long unpinned; struct mmu_rb_handler *handler; atomic_t n_locked; - struct mm_struct *mm; }; struct hfi1_user_sdma_comp_q { @@ -250,4 +250,9 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, struct iovec *iovec, unsigned long dim, unsigned long *count); +static inline struct mm_struct *mm_from_sdma_node(struct sdma_mmu_node *node) +{ + return node->rb.handler->mn.mm; +} + #endif /* _HFI1_USER_SDMA_H */ diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 6d30850696c5..0468028ffe39 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2936,6 +2936,7 @@ static int hns_roce_v2_mw_write_mtpt(void *mb_buf, struct hns_roce_mw *mw) roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_LW_EN_S, 1); roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0); roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 1); @@ -4989,11 +4990,11 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, V2_QPC_BYTE_28_AT_M, V2_QPC_BYTE_28_AT_S); qp_attr->retry_cnt = roce_get_field(context.byte_212_lsn, - V2_QPC_BYTE_212_RETRY_CNT_M, - V2_QPC_BYTE_212_RETRY_CNT_S); + V2_QPC_BYTE_212_RETRY_NUM_INIT_M, + V2_QPC_BYTE_212_RETRY_NUM_INIT_S); qp_attr->rnr_retry = roce_get_field(context.byte_244_rnr_rxack, - V2_QPC_BYTE_244_RNR_CNT_M, - V2_QPC_BYTE_244_RNR_CNT_S); + V2_QPC_BYTE_244_RNR_NUM_INIT_M, + V2_QPC_BYTE_244_RNR_NUM_INIT_S); done: qp_attr->cur_qp_state = qp_attr->qp_state; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 29c9dd4bcbc6..be7f2fe1e883 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -1661,7 +1661,7 @@ struct hns_roce_query_pf_caps_d { __le32 rsv_uars_rsv_qps; }; #define V2_QUERY_PF_CAPS_D_NUM_SRQS_S 0 -#define V2_QUERY_PF_CAPS_D_NUM_SRQS_M GENMASK(20, 0) +#define V2_QUERY_PF_CAPS_D_NUM_SRQS_M GENMASK(19, 0) #define V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_S 20 #define V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_M GENMASK(21, 20) diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 2408b279e4c2..584932d3cc44 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -54,10 +54,6 @@ #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." __stringify(DRV_VERSION_BUILD) -static int push_mode; -module_param(push_mode, int, 0644); -MODULE_PARM_DESC(push_mode, "Low latency mode: 0=disabled (default), 1=enabled)"); - static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug flags: 0=disabled (default), 0x7fffffff=all"); @@ -1580,7 +1576,6 @@ static enum i40iw_status_code i40iw_setup_init_state(struct i40iw_handler *hdl, if (status) goto exit; iwdev->obj_next = iwdev->obj_mem; - iwdev->push_mode = push_mode; init_waitqueue_head(&iwdev->vchnl_waitq); init_waitqueue_head(&dev->vf_reqs); diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 581ecbadf586..533f3caecb7a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -167,39 +167,16 @@ static void i40iw_dealloc_ucontext(struct ib_ucontext *context) */ static int i40iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { - struct i40iw_ucontext *ucontext; - u64 db_addr_offset, push_offset, pfn; - - ucontext = to_ucontext(context); - if (ucontext->iwdev->sc_dev.is_pf) { - db_addr_offset = I40IW_DB_ADDR_OFFSET; - push_offset = I40IW_PUSH_OFFSET; - if (vma->vm_pgoff) - vma->vm_pgoff += I40IW_PF_FIRST_PUSH_PAGE_INDEX - 1; - } else { - db_addr_offset = I40IW_VF_DB_ADDR_OFFSET; - push_offset = I40IW_VF_PUSH_OFFSET; - if (vma->vm_pgoff) - vma->vm_pgoff += I40IW_VF_FIRST_PUSH_PAGE_INDEX - 1; - } + struct i40iw_ucontext *ucontext = to_ucontext(context); + u64 dbaddr; - vma->vm_pgoff += db_addr_offset >> PAGE_SHIFT; - - if (vma->vm_pgoff == (db_addr_offset >> PAGE_SHIFT)) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - } else { - if ((vma->vm_pgoff - (push_offset >> PAGE_SHIFT)) % 2) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - else - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - } + if (vma->vm_pgoff || vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; - pfn = vma->vm_pgoff + - (pci_resource_start(ucontext->iwdev->ldev->pcidev, 0) >> - PAGE_SHIFT); + dbaddr = I40IW_DB_ADDR_OFFSET + pci_resource_start(ucontext->iwdev->ldev->pcidev, 0); - return rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE, - vma->vm_page_prot, NULL); + return rdma_user_mmap_io(context, vma, dbaddr >> PAGE_SHIFT, PAGE_SIZE, + pgprot_noncached(vma->vm_page_prot), NULL); } /** diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index c3cfea243af8..119b2573c9a0 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -803,8 +803,10 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, } mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); - if (IS_ERR(mailbox)) + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); goto err_out_arm; + } cq_context = mailbox->buf; @@ -846,9 +848,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, } spin_lock_irq(&dev->cq_table.lock); - if (mthca_array_set(&dev->cq_table.cq, - cq->cqn & (dev->limits.num_cqs - 1), - cq)) { + err = mthca_array_set(&dev->cq_table.cq, + cq->cqn & (dev->limits.num_cqs - 1), cq); + if (err) { spin_unlock_irq(&dev->cq_table.lock); goto err_out_free_mr; } diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 82e4af8f09bb..23a790f8f550 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -29,6 +29,7 @@ #include <asm/iommu_table.h> #include <asm/io_apic.h> #include <asm/irq_remapping.h> +#include <asm/set_memory.h> #include <linux/crash_dump.h> @@ -672,11 +673,27 @@ static void __init free_command_buffer(struct amd_iommu *iommu) free_pages((unsigned long)iommu->cmd_buf, get_order(CMD_BUFFER_SIZE)); } +static void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu, + gfp_t gfp, size_t size) +{ + int order = get_order(size); + void *buf = (void *)__get_free_pages(gfp, order); + + if (buf && + iommu_feature(iommu, FEATURE_SNP) && + set_memory_4k((unsigned long)buf, (1 << order))) { + free_pages((unsigned long)buf, order); + buf = NULL; + } + + return buf; +} + /* allocates the memory where the IOMMU will log its events to */ static int __init alloc_event_buffer(struct amd_iommu *iommu) { - iommu->evt_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(EVT_BUFFER_SIZE)); + iommu->evt_buf = iommu_alloc_4k_pages(iommu, GFP_KERNEL | __GFP_ZERO, + EVT_BUFFER_SIZE); return iommu->evt_buf ? 0 : -ENOMEM; } @@ -715,8 +732,8 @@ static void __init free_event_buffer(struct amd_iommu *iommu) /* allocates the memory where the IOMMU will log its events to */ static int __init alloc_ppr_log(struct amd_iommu *iommu) { - iommu->ppr_log = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(PPR_LOG_SIZE)); + iommu->ppr_log = iommu_alloc_4k_pages(iommu, GFP_KERNEL | __GFP_ZERO, + PPR_LOG_SIZE); return iommu->ppr_log ? 0 : -ENOMEM; } @@ -838,7 +855,7 @@ static int iommu_init_ga(struct amd_iommu *iommu) static int __init alloc_cwwb_sem(struct amd_iommu *iommu) { - iommu->cmd_sem = (void *)get_zeroed_page(GFP_KERNEL); + iommu->cmd_sem = iommu_alloc_4k_pages(iommu, GFP_KERNEL | __GFP_ZERO, 1); return iommu->cmd_sem ? 0 : -ENOMEM; } diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index be4318044f96..702fbaa6c9ad 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -69,6 +69,10 @@ struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) { struct qcom_smmu *qsmmu; + /* Check to make sure qcom_scm has finished probing */ + if (!qcom_scm_is_available()) + return ERR_PTR(-EPROBE_DEFER); + qsmmu = devm_kzalloc(smmu->dev, sizeof(*qsmmu), GFP_KERNEL); if (!qsmmu) return ERR_PTR(-ENOMEM); diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index b2e804473209..b46dbfa6d0ed 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -335,7 +335,9 @@ static void dmar_pci_bus_del_dev(struct dmar_pci_notify_info *info) static inline void vf_inherit_msi_domain(struct pci_dev *pdev) { - dev_set_msi_domain(&pdev->dev, dev_get_msi_domain(&pdev->physfn->dev)); + struct pci_dev *physfn = pci_physfn(pdev); + + dev_set_msi_domain(&pdev->dev, dev_get_msi_domain(&physfn->dev)); } static int dmar_pci_bus_notifier(struct notifier_block *nb, @@ -984,7 +986,8 @@ static int map_iommu(struct intel_iommu *iommu, u64 phys_addr) warn_invalid_dmar(phys_addr, " returns all ones"); goto unmap; } - iommu->vccap = dmar_readq(iommu->reg + DMAR_VCCAP_REG); + if (ecap_vcs(iommu->ecap)) + iommu->vccap = dmar_readq(iommu->reg + DMAR_VCCAP_REG); /* the registers might be more than one page */ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index c6622011d493..a49afa11673c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -179,7 +179,7 @@ static int rwbf_quirk; * (used when kernel is launched w/ TXT) */ static int force_on = 0; -int intel_iommu_tboot_noforce; +static int intel_iommu_tboot_noforce; static int no_platform_optin; #define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry)) @@ -1833,7 +1833,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu) if (ecap_prs(iommu->ecap)) intel_svm_finish_prq(iommu); } - if (ecap_vcs(iommu->ecap) && vccap_pasid(iommu->vccap)) + if (vccap_pasid(iommu->vccap)) ioasid_unregister_allocator(&iommu->pasid_allocator); #endif @@ -3212,7 +3212,7 @@ static void register_pasid_allocator(struct intel_iommu *iommu) * is active. All vIOMMU allocators will eventually be calling the same * host allocator. */ - if (!ecap_vcs(iommu->ecap) || !vccap_pasid(iommu->vccap)) + if (!vccap_pasid(iommu->vccap)) return; pr_info("Register custom PASID allocator\n"); @@ -4884,7 +4884,8 @@ int __init intel_iommu_init(void) * Intel IOMMU is required for a TXT/tboot launch or platform * opt in, so enforce that. */ - force_on = tboot_force_iommu() || platform_optin_force_iommu(); + force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) || + platform_optin_force_iommu(); if (iommu_init_mempool()) { if (force_on) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index b53446bb8c6b..0f4dc25d46c9 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -264,16 +264,18 @@ int iommu_probe_device(struct device *dev) */ iommu_alloc_default_domain(group, dev); - if (group->default_domain) + if (group->default_domain) { ret = __iommu_attach_device(group->default_domain, dev); + if (ret) { + iommu_group_put(group); + goto err_release; + } + } iommu_create_device_direct_mappings(group, dev); iommu_group_put(group); - if (ret) - goto err_release; - if (ops->probe_finalize) ops->probe_finalize(dev); diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a3cb104956d5..7e152bbb4fa6 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -253,17 +253,31 @@ config VIDEO_MEDIATEK_VCODEC depends on MTK_IOMMU || COMPILE_TEST depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_MEDIATEK || COMPILE_TEST + depends on VIDEO_MEDIATEK_VPU || MTK_SCP + # The two following lines ensure we have the same state ("m" or "y") as + # our dependencies, to avoid missing symbols during link. + depends on VIDEO_MEDIATEK_VPU || !VIDEO_MEDIATEK_VPU + depends on MTK_SCP || !MTK_SCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - select VIDEO_MEDIATEK_VPU - select MTK_SCP + select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU + select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP help - Mediatek video codec driver provides HW capability to - encode and decode in a range of video formats - This driver rely on VPU driver to communicate with VPU. + Mediatek video codec driver provides HW capability to + encode and decode in a range of video formats on MT8173 + and MT8183. + + Note that support for MT8173 requires VIDEO_MEDIATEK_VPU to + also be selected. Support for MT8183 depends on MTK_SCP. + + To compile this driver as modules, choose M here: the + modules will be called mtk-vcodec-dec and mtk-vcodec-enc. + +config VIDEO_MEDIATEK_VCODEC_VPU + bool - To compile this driver as modules, choose M here: the - modules will be called mtk-vcodec-dec and mtk-vcodec-enc. +config VIDEO_MEDIATEK_VCODEC_SCP + bool config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index cd902b180669..63fce1b85d26 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -307,6 +307,7 @@ static int mmpcam_platform_remove(struct platform_device *pdev) * Suspend/resume support. */ +#ifdef CONFIG_PM static int mmpcam_runtime_resume(struct device *dev) { struct mmp_camera *cam = dev_get_drvdata(dev); @@ -352,6 +353,7 @@ static int __maybe_unused mmpcam_resume(struct device *dev) return mccic_resume(&cam->mcam); return 0; } +#endif static const struct dev_pm_ops mmpcam_pm_ops = { SET_RUNTIME_PM_OPS(mmpcam_runtime_suspend, mmpcam_runtime_resume, NULL) diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index f679c6e1a3e9..4618d43dbbc8 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -24,4 +24,12 @@ mtk-vcodec-enc-y := venc/venc_vp8_if.o \ mtk-vcodec-common-y := mtk_vcodec_intr.o \ mtk_vcodec_util.o \ - mtk_vcodec_fw.o + mtk_vcodec_fw.o \ + +ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU),) +mtk-vcodec-common-y += mtk_vcodec_fw_vpu.o +endif + +ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP),) +mtk-vcodec-common-y += mtk_vcodec_fw_scp.o +endif diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index d14bc208ea5e..145686d2c219 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -241,7 +241,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_DEC); + dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, DECODER); if (IS_ERR(dev->fw_handler)) return PTR_ERR(dev->fw_handler); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index dcfa2c2d4def..3be8a04c4c67 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -293,7 +293,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_ENC); + dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, ENCODER); if (IS_ERR(dev->fw_handler)) return PTR_ERR(dev->fw_handler); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c index 6c2a2568d844..94b39ae5c2e1 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c @@ -1,193 +1,29 @@ // SPDX-License-Identifier: GPL-2.0 #include "mtk_vcodec_fw.h" +#include "mtk_vcodec_fw_priv.h" #include "mtk_vcodec_util.h" #include "mtk_vcodec_drv.h" -struct mtk_vcodec_fw_ops { - int (*load_firmware)(struct mtk_vcodec_fw *fw); - unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw); - unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw); - void * (*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr); - int (*ipi_register)(struct mtk_vcodec_fw *fw, int id, - mtk_vcodec_ipi_handler handler, const char *name, void *priv); - int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf, - unsigned int len, unsigned int wait); -}; - -struct mtk_vcodec_fw { - enum mtk_vcodec_fw_type type; - const struct mtk_vcodec_fw_ops *ops; - struct platform_device *pdev; - struct mtk_scp *scp; -}; - -static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw) -{ - return vpu_load_firmware(fw->pdev); -} - -static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw) -{ - return vpu_get_vdec_hw_capa(fw->pdev); -} - -static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw) -{ - return vpu_get_venc_hw_capa(fw->pdev); -} - -static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw, - u32 dtcm_dmem_addr) -{ - return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr); -} - -static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id, - mtk_vcodec_ipi_handler handler, - const char *name, void *priv) -{ - /* - * The handler we receive takes a void * as its first argument. We - * cannot change this because it needs to be passed down to the rproc - * subsystem when SCP is used. VPU takes a const argument, which is - * more constrained, so the conversion below is safe. - */ - ipi_handler_t handler_const = (ipi_handler_t)handler; - - return vpu_ipi_register(fw->pdev, id, handler_const, name, priv); -} - -static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, - unsigned int len, unsigned int wait) -{ - return vpu_ipi_send(fw->pdev, id, buf, len); -} - -static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { - .load_firmware = mtk_vcodec_vpu_load_firmware, - .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa, - .get_venc_capa = mtk_vcodec_vpu_get_venc_capa, - .map_dm_addr = mtk_vcodec_vpu_map_dm_addr, - .ipi_register = mtk_vcodec_vpu_set_ipi_register, - .ipi_send = mtk_vcodec_vpu_ipi_send, -}; - -static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw) -{ - return rproc_boot(scp_get_rproc(fw->scp)); -} - -static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw) -{ - return scp_get_vdec_hw_capa(fw->scp); -} - -static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw) -{ - return scp_get_venc_hw_capa(fw->scp); -} - -static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw, - u32 dtcm_dmem_addr) -{ - return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr); -} - -static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id, - mtk_vcodec_ipi_handler handler, - const char *name, void *priv) -{ - return scp_ipi_register(fw->scp, id, handler, priv); -} - -static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, - unsigned int len, unsigned int wait) -{ - return scp_ipi_send(fw->scp, id, buf, len, wait); -} - -static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = { - .load_firmware = mtk_vcodec_scp_load_firmware, - .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa, - .get_venc_capa = mtk_vcodec_scp_get_venc_capa, - .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr, - .ipi_register = mtk_vcodec_scp_set_ipi_register, - .ipi_send = mtk_vcodec_scp_ipi_send, -}; - -static void mtk_vcodec_reset_handler(void *priv) -{ - struct mtk_vcodec_dev *dev = priv; - struct mtk_vcodec_ctx *ctx; - - mtk_v4l2_err("Watchdog timeout!!"); - - mutex_lock(&dev->dev_mutex); - list_for_each_entry(ctx, &dev->ctx_list, list) { - ctx->state = MTK_STATE_ABORT; - mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", - ctx->id); - } - mutex_unlock(&dev->dev_mutex); -} - struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev, enum mtk_vcodec_fw_type type, - enum rst_id rst_id) + enum mtk_vcodec_fw_use fw_use) { - const struct mtk_vcodec_fw_ops *ops; - struct mtk_vcodec_fw *fw; - struct platform_device *fw_pdev = NULL; - struct mtk_scp *scp = NULL; - switch (type) { case VPU: - ops = &mtk_vcodec_vpu_msg; - fw_pdev = vpu_get_plat_device(dev->plat_dev); - if (!fw_pdev) { - mtk_v4l2_err("firmware device is not ready"); - return ERR_PTR(-EINVAL); - } - vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_reset_handler, - dev, rst_id); - break; + return mtk_vcodec_fw_vpu_init(dev, fw_use); case SCP: - ops = &mtk_vcodec_rproc_msg; - scp = scp_get(dev->plat_dev); - if (!scp) { - mtk_v4l2_err("could not get vdec scp handle"); - return ERR_PTR(-EPROBE_DEFER); - } - break; + return mtk_vcodec_fw_scp_init(dev); default: mtk_v4l2_err("invalid vcodec fw type"); return ERR_PTR(-EINVAL); } - - fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); - if (!fw) - return ERR_PTR(-EINVAL); - - fw->type = type; - fw->ops = ops; - fw->pdev = fw_pdev; - fw->scp = scp; - - return fw; } EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select); void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw) { - switch (fw->type) { - case VPU: - put_device(&fw->pdev->dev); - break; - case SCP: - scp_put(fw->scp); - break; - } + fw->ops->release(fw); } EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h index fadbbe6ba6cd..539bb626772c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h @@ -15,6 +15,11 @@ enum mtk_vcodec_fw_type { SCP, }; +enum mtk_vcodec_fw_use { + DECODER, + ENCODER, +}; + struct mtk_vcodec_fw; typedef void (*mtk_vcodec_ipi_handler) (void *data, @@ -22,7 +27,7 @@ typedef void (*mtk_vcodec_ipi_handler) (void *data, struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev, enum mtk_vcodec_fw_type type, - enum rst_id rst_id); + enum mtk_vcodec_fw_use fw_use); void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw); int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h new file mode 100644 index 000000000000..b41e66185cec --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _MTK_VCODEC_FW_PRIV_H_ +#define _MTK_VCODEC_FW_PRIV_H_ + +#include "mtk_vcodec_fw.h" + +struct mtk_vcodec_dev; + +struct mtk_vcodec_fw { + enum mtk_vcodec_fw_type type; + const struct mtk_vcodec_fw_ops *ops; + struct platform_device *pdev; + struct mtk_scp *scp; +}; + +struct mtk_vcodec_fw_ops { + int (*load_firmware)(struct mtk_vcodec_fw *fw); + unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw); + unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw); + void *(*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr); + int (*ipi_register)(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, const char *name, + void *priv); + int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait); + void (*release)(struct mtk_vcodec_fw *fw); +}; + +#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU) +struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev, + enum mtk_vcodec_fw_use fw_use); +#else +static inline struct mtk_vcodec_fw * +mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev, + enum mtk_vcodec_fw_use fw_use) +{ + return ERR_PTR(-ENODEV); +} +#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_VPU */ + +#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP) +struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev); +#else +static inline struct mtk_vcodec_fw * +mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev) +{ + return ERR_PTR(-ENODEV); +} +#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_SCP */ + +#endif /* _MTK_VCODEC_FW_PRIV_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c new file mode 100644 index 000000000000..d8e66b645bd8 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "mtk_vcodec_fw_priv.h" +#include "mtk_vcodec_util.h" +#include "mtk_vcodec_drv.h" + +static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw) +{ + return rproc_boot(scp_get_rproc(fw->scp)); +} + +static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw) +{ + return scp_get_vdec_hw_capa(fw->scp); +} + +static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw) +{ + return scp_get_venc_hw_capa(fw->scp); +} + +static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw, + u32 dtcm_dmem_addr) +{ + return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr); +} + +static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) +{ + return scp_ipi_register(fw->scp, id, handler, priv); +} + +static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait) +{ + return scp_ipi_send(fw->scp, id, buf, len, wait); +} + +static void mtk_vcodec_scp_release(struct mtk_vcodec_fw *fw) +{ + scp_put(fw->scp); +} + +static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = { + .load_firmware = mtk_vcodec_scp_load_firmware, + .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa, + .get_venc_capa = mtk_vcodec_scp_get_venc_capa, + .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr, + .ipi_register = mtk_vcodec_scp_set_ipi_register, + .ipi_send = mtk_vcodec_scp_ipi_send, + .release = mtk_vcodec_scp_release, +}; + +struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev) +{ + struct mtk_vcodec_fw *fw; + struct mtk_scp *scp; + + scp = scp_get(dev->plat_dev); + if (!scp) { + mtk_v4l2_err("could not get vdec scp handle"); + return ERR_PTR(-EPROBE_DEFER); + } + + fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); + fw->type = SCP; + fw->ops = &mtk_vcodec_rproc_msg; + fw->scp = scp; + + return fw; +} diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c new file mode 100644 index 000000000000..cd27f637dbe7 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "mtk_vcodec_fw_priv.h" +#include "mtk_vcodec_util.h" +#include "mtk_vcodec_drv.h" + +static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw) +{ + return vpu_load_firmware(fw->pdev); +} + +static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw) +{ + return vpu_get_vdec_hw_capa(fw->pdev); +} + +static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw) +{ + return vpu_get_venc_hw_capa(fw->pdev); +} + +static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw, + u32 dtcm_dmem_addr) +{ + return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr); +} + +static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) +{ + /* + * The handler we receive takes a void * as its first argument. We + * cannot change this because it needs to be passed down to the rproc + * subsystem when SCP is used. VPU takes a const argument, which is + * more constrained, so the conversion below is safe. + */ + ipi_handler_t handler_const = (ipi_handler_t)handler; + + return vpu_ipi_register(fw->pdev, id, handler_const, name, priv); +} + +static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait) +{ + return vpu_ipi_send(fw->pdev, id, buf, len); +} + +static void mtk_vcodec_vpu_release(struct mtk_vcodec_fw *fw) +{ + put_device(&fw->pdev->dev); +} + +static void mtk_vcodec_vpu_reset_handler(void *priv) +{ + struct mtk_vcodec_dev *dev = priv; + struct mtk_vcodec_ctx *ctx; + + mtk_v4l2_err("Watchdog timeout!!"); + + mutex_lock(&dev->dev_mutex); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", + ctx->id); + } + mutex_unlock(&dev->dev_mutex); +} + +static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { + .load_firmware = mtk_vcodec_vpu_load_firmware, + .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa, + .get_venc_capa = mtk_vcodec_vpu_get_venc_capa, + .map_dm_addr = mtk_vcodec_vpu_map_dm_addr, + .ipi_register = mtk_vcodec_vpu_set_ipi_register, + .ipi_send = mtk_vcodec_vpu_ipi_send, + .release = mtk_vcodec_vpu_release, +}; + +struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev, + enum mtk_vcodec_fw_use fw_use) +{ + struct platform_device *fw_pdev; + struct mtk_vcodec_fw *fw; + enum rst_id rst_id; + + switch (fw_use) { + case ENCODER: + rst_id = VPU_RST_ENC; + break; + case DECODER: + default: + rst_id = VPU_RST_DEC; + break; + } + + fw_pdev = vpu_get_plat_device(dev->plat_dev); + if (!fw_pdev) { + mtk_v4l2_err("firmware device is not ready"); + return ERR_PTR(-EINVAL); + } + vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id); + + fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); + fw->type = VPU; + fw->ops = &mtk_vcodec_vpu_msg; + fw->pdev = fw_pdev; + + return fw; +} diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 7b79a33dc9d6..05c9fbd51f0c 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -243,8 +243,19 @@ struct venc_controls { u32 header_mode; - u32 profile; - u32 level; + struct { + u32 h264; + u32 mpeg4; + u32 hevc; + u32 vp8; + u32 vp9; + } profile; + struct { + u32 h264; + u32 mpeg4; + u32 hevc; + u32 vp9; + } level; }; struct venus_buffer { diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 57877eacecf0..a9538c2cc3c9 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -794,7 +794,7 @@ skip_pmdomains: return 0; opp_dl_add_err: - dev_pm_domain_detach(core->opp_pmdomain, true); + dev_pm_opp_detach_genpd(core->opp_table); opp_attach_err: if (core->pd_dl_venus) { device_link_del(core->pd_dl_venus); @@ -832,7 +832,7 @@ skip_pmdomains: if (core->opp_dl_venus) device_link_del(core->opp_dl_venus); - dev_pm_domain_detach(core->opp_pmdomain, true); + dev_pm_opp_detach_genpd(core->opp_table); } static int core_get_v4(struct device *dev) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index f8b1484e7dcd..47246528ac7e 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -537,6 +537,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_quantization quant; struct hfi_quantization_range quant_range; u32 ptype, rate_control, bitrate; + u32 profile, level; int ret; ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2); @@ -684,7 +685,35 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; - ret = venus_helper_set_profile_level(inst, ctr->profile, ctr->level); + switch (inst->hfi_codec) { + case HFI_VIDEO_CODEC_H264: + profile = ctr->profile.h264; + level = ctr->level.h264; + break; + case HFI_VIDEO_CODEC_MPEG4: + profile = ctr->profile.mpeg4; + level = ctr->level.mpeg4; + break; + case HFI_VIDEO_CODEC_VP8: + profile = ctr->profile.vp8; + level = 0; + break; + case HFI_VIDEO_CODEC_VP9: + profile = ctr->profile.vp9; + level = ctr->level.vp9; + break; + case HFI_VIDEO_CODEC_HEVC: + profile = ctr->profile.hevc; + level = ctr->level.hevc; + break; + case HFI_VIDEO_CODEC_MPEG2: + default: + profile = 0; + level = 0; + break; + } + + ret = venus_helper_set_profile_level(inst, profile, level); if (ret) return ret; diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 0708b3b89d0c..cf860e6446c0 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -103,15 +103,25 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->h264_entropy_mode = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + ctr->profile.mpeg4 = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + ctr->profile.h264 = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + ctr->profile.hevc = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - ctr->profile = ctrl->val; + ctr->profile.vp8 = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + ctr->level.mpeg4 = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + ctr->level.h264 = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - ctr->level = ctrl->val; + ctr->level.hevc = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctr->h264_i_qp = ctrl->val; diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 74b054947bbe..fc64d0c8492a 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -4,36 +4,43 @@ * validate the existing APIs in the media subsystem. It can also aid * developers working on userspace applications. * - * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' and 'dvb_vidtv_demod'. + * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' + * and 'dvb_vidtv_demod'. * * Copyright (C) 2020 Daniel W. S. Almeida */ +#include <linux/dev_printk.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/platform_device.h> -#include <linux/dev_printk.h> #include <linux/time.h> #include <linux/types.h> #include <linux/workqueue.h> #include "vidtv_bridge.h" +#include "vidtv_common.h" #include "vidtv_demod.h" -#include "vidtv_tuner.h" -#include "vidtv_ts.h" #include "vidtv_mux.h" -#include "vidtv_common.h" +#include "vidtv_ts.h" +#include "vidtv_tuner.h" -//#define MUX_BUF_MAX_SZ -//#define MUX_BUF_MIN_SZ +#define MUX_BUF_MIN_SZ 90164 +#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10) #define TUNER_DEFAULT_ADDR 0x68 #define DEMOD_DEFAULT_ADDR 0x60 +#define VIDTV_DEFAULT_NETWORK_ID 0xff44 +#define VIDTV_DEFAULT_NETWORK_NAME "LinuxTV.org" +#define VIDTV_DEFAULT_TS_ID 0x4081 -/* LNBf fake parameters: ranges used by an Universal (extended) European LNBf */ -#define LNB_CUT_FREQUENCY 11700000 -#define LNB_LOW_FREQ 9750000 -#define LNB_HIGH_FREQ 10600000 - +/* + * The LNBf fake parameters here are the ranges used by an + * Universal (extended) European LNBf, which is likely the most common LNBf + * found on Satellite digital TV system nowadays. + */ +#define LNB_CUT_FREQUENCY 11700000 /* high IF frequency */ +#define LNB_LOW_FREQ 9750000 /* low IF frequency */ +#define LNB_HIGH_FREQ 10600000 /* transition frequency */ static unsigned int drop_tslock_prob_on_low_snr; module_param(drop_tslock_prob_on_low_snr, uint, 0); @@ -92,7 +99,8 @@ MODULE_PARM_DESC(si_period_msec, "How often to send SI packets. Default: 40ms"); static unsigned int pcr_period_msec = 40; module_param(pcr_period_msec, uint, 0); -MODULE_PARM_DESC(pcr_period_msec, "How often to send PCR packets. Default: 40ms"); +MODULE_PARM_DESC(pcr_period_msec, + "How often to send PCR packets. Default: 40ms"); static unsigned int mux_rate_kbytes_sec = 4096; module_param(mux_rate_kbytes_sec, uint, 0); @@ -104,16 +112,14 @@ MODULE_PARM_DESC(pcr_pid, "PCR PID for all channels: defaults to 0x200"); static unsigned int mux_buf_sz_pkts; module_param(mux_buf_sz_pkts, uint, 0); -MODULE_PARM_DESC(mux_buf_sz_pkts, "Size for the internal mux buffer in multiples of 188 bytes"); - -#define MUX_BUF_MIN_SZ 90164 -#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10) +MODULE_PARM_DESC(mux_buf_sz_pkts, + "Size for the internal mux buffer in multiples of 188 bytes"); static u32 vidtv_bridge_mux_buf_sz_for_mux_rate(void) { u32 max_elapsed_time_msecs = VIDTV_MAX_SLEEP_USECS / USEC_PER_MSEC; - u32 nbytes_expected; u32 mux_buf_sz = mux_buf_sz_pkts * TS_PACKET_LEN; + u32 nbytes_expected; nbytes_expected = mux_rate_kbytes_sec; nbytes_expected *= max_elapsed_time_msecs; @@ -143,14 +149,12 @@ static bool vidtv_bridge_check_demod_lock(struct vidtv_dvb *dvb, u32 n) FE_HAS_LOCK); } -static void -vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts) +/* + * called on a separate thread by the mux when new packets become available + */ +static void vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts) { - /* - * called on a separate thread by the mux when new packets become - * available - */ - struct vidtv_dvb *dvb = (struct vidtv_dvb *)priv; + struct vidtv_dvb *dvb = priv; /* drop packets if we lose the lock */ if (vidtv_bridge_check_demod_lock(dvb, 0)) @@ -159,7 +163,17 @@ vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts) static int vidtv_start_streaming(struct vidtv_dvb *dvb) { - struct vidtv_mux_init_args mux_args = {0}; + struct vidtv_mux_init_args mux_args = { + .mux_rate_kbytes_sec = mux_rate_kbytes_sec, + .on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail, + .pcr_period_usecs = pcr_period_msec * USEC_PER_MSEC, + .si_period_usecs = si_period_msec * USEC_PER_MSEC, + .pcr_pid = pcr_pid, + .transport_stream_id = VIDTV_DEFAULT_TS_ID, + .network_id = VIDTV_DEFAULT_NETWORK_ID, + .network_name = VIDTV_DEFAULT_NETWORK_NAME, + .priv = dvb, + }; struct device *dev = &dvb->pdev->dev; u32 mux_buf_sz; @@ -168,19 +182,17 @@ static int vidtv_start_streaming(struct vidtv_dvb *dvb) return 0; } - mux_buf_sz = (mux_buf_sz_pkts) ? mux_buf_sz_pkts : vidtv_bridge_mux_buf_sz_for_mux_rate(); + if (mux_buf_sz_pkts) + mux_buf_sz = mux_buf_sz_pkts; + else + mux_buf_sz = vidtv_bridge_mux_buf_sz_for_mux_rate(); - mux_args.mux_rate_kbytes_sec = mux_rate_kbytes_sec; - mux_args.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail; - mux_args.mux_buf_sz = mux_buf_sz; - mux_args.pcr_period_usecs = pcr_period_msec * 1000; - mux_args.si_period_usecs = si_period_msec * 1000; - mux_args.pcr_pid = pcr_pid; - mux_args.transport_stream_id = VIDTV_DEFAULT_TS_ID; - mux_args.priv = dvb; + mux_args.mux_buf_sz = mux_buf_sz; dvb->streaming = true; - dvb->mux = vidtv_mux_init(dvb->fe[0], dev, mux_args); + dvb->mux = vidtv_mux_init(dvb->fe[0], dev, &mux_args); + if (!dvb->mux) + return -ENOMEM; vidtv_mux_start_thread(dvb->mux); dev_dbg_ratelimited(dev, "Started streaming\n"); @@ -204,8 +216,8 @@ static int vidtv_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct vidtv_dvb *dvb = demux->priv; - int rc; int ret; + int rc; if (!demux->dmx.frontend) return -EINVAL; @@ -243,9 +255,9 @@ static int vidtv_stop_feed(struct dvb_demux_feed *feed) static struct dvb_frontend *vidtv_get_frontend_ptr(struct i2c_client *c) { - /* the demod will set this when its probe function runs */ struct vidtv_demod_state *state = i2c_get_clientdata(c); + /* the demod will set this when its probe function runs */ return &state->frontend; } @@ -253,6 +265,11 @@ static int vidtv_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { + /* + * Right now, this virtual driver doesn't really send or receive + * messages from I2C. A real driver will require an implementation + * here. + */ return 0; } @@ -320,11 +337,10 @@ static int vidtv_bridge_dmxdev_init(struct vidtv_dvb *dvb) static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n) { - struct vidtv_demod_config cfg = {}; - - cfg.drop_tslock_prob_on_low_snr = drop_tslock_prob_on_low_snr; - cfg.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr; - + struct vidtv_demod_config cfg = { + .drop_tslock_prob_on_low_snr = drop_tslock_prob_on_low_snr, + .recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr, + }; dvb->i2c_client_demod[n] = dvb_module_probe("dvb_vidtv_demod", NULL, &dvb->i2c_adapter, @@ -343,14 +359,14 @@ static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n) static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n) { - struct vidtv_tuner_config cfg = {}; + struct vidtv_tuner_config cfg = { + .fe = dvb->fe[n], + .mock_power_up_delay_msec = mock_power_up_delay_msec, + .mock_tune_delay_msec = mock_tune_delay_msec, + }; u32 freq; int i; - cfg.fe = dvb->fe[n]; - cfg.mock_power_up_delay_msec = mock_power_up_delay_msec; - cfg.mock_tune_delay_msec = mock_tune_delay_msec; - /* TODO: check if the frequencies are at a valid range */ memcpy(cfg.vidtv_valid_dvb_t_freqs, @@ -389,9 +405,7 @@ static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n) static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb) { - int ret; - int i; - int j; + int ret, i, j; ret = vidtv_bridge_i2c_register_adap(dvb); if (ret < 0) diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.h b/drivers/media/test-drivers/vidtv/vidtv_bridge.h index 78fe8472fa37..2528adaee27d 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.h +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.h @@ -20,9 +20,11 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/types.h> + #include <media/dmxdev.h> #include <media/dvb_demux.h> #include <media/dvb_frontend.h> + #include "vidtv_mux.h" /** @@ -32,7 +34,7 @@ * @adapter: Represents a DTV adapter. See 'dvb_register_adapter'. * @demux: The demux used by the dvb_dmx_swfilter_packets() call. * @dmx_dev: Represents a demux device. - * @dmx_frontend: The frontends associated with the demux. + * @dmx_fe: The frontends associated with the demux. * @i2c_adapter: The i2c_adapter associated with the bridge driver. * @i2c_client_demod: The i2c_clients associated with the demodulator modules. * @i2c_client_tuner: The i2c_clients associated with the tuner modules. diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c b/drivers/media/test-drivers/vidtv/vidtv_channel.c index f2b97cf08e87..8ad6c0744d36 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_channel.c +++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c @@ -9,6 +9,7 @@ * When vidtv boots, it will create some hardcoded channels. * Their services will be concatenated to populate the SDT. * Their programs will be concatenated to populate the PAT + * Their events will be concatenated to populate the EIT * For each program in the PAT, a PMT section will be created * The PMT section for a channel will be assigned its streams. * Every stream will have its corresponding encoder polled to produce TS packets @@ -18,22 +19,22 @@ * Copyright (C) 2020 Daniel W. S. Almeida */ -#include <linux/types.h> -#include <linux/slab.h> #include <linux/dev_printk.h> #include <linux/ratelimit.h> +#include <linux/slab.h> +#include <linux/types.h> #include "vidtv_channel.h" -#include "vidtv_psi.h" +#include "vidtv_common.h" #include "vidtv_encoder.h" #include "vidtv_mux.h" -#include "vidtv_common.h" +#include "vidtv_psi.h" #include "vidtv_s302m.h" static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e) { - struct vidtv_encoder *curr = e; struct vidtv_encoder *tmp = NULL; + struct vidtv_encoder *curr = e; while (curr) { /* forward the call to the derived type */ @@ -44,55 +45,88 @@ static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e) } #define ENCODING_ISO8859_15 "\x0b" +#define TS_NIT_PID 0x10 +/* + * init an audio only channel with a s302m encoder + */ struct vidtv_channel *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id) { - /* - * init an audio only channel with a s302m encoder - */ - const u16 s302m_service_id = 0x880; - const u16 s302m_program_num = 0x880; - const u16 s302m_program_pid = 0x101; /* packet id for PMT*/ - const u16 s302m_es_pid = 0x111; /* packet id for the ES */ const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER); - - char *name = ENCODING_ISO8859_15 "Beethoven"; + char *event_text = ENCODING_ISO8859_15 "Bagatelle No. 25 in A minor for solo piano, also known as F\xfcr Elise, composed by Ludwig van Beethoven"; + char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise"; + struct vidtv_s302m_encoder_init_args encoder_args = {}; + char *iso_language_code = ENCODING_ISO8859_15 "eng"; char *provider = ENCODING_ISO8859_15 "LinuxTV.org"; + char *name = ENCODING_ISO8859_15 "Beethoven"; + const u16 s302m_es_pid = 0x111; /* packet id for the ES */ + const u16 s302m_program_pid = 0x101; /* packet id for PMT*/ + const u16 s302m_service_id = 0x880; + const u16 s302m_program_num = 0x880; + const u16 s302m_beethoven_event_id = 1; + struct vidtv_channel *s302m; - struct vidtv_channel *s302m = kzalloc(sizeof(*s302m), GFP_KERNEL); - struct vidtv_s302m_encoder_init_args encoder_args = {}; + s302m = kzalloc(sizeof(*s302m), GFP_KERNEL); + if (!s302m) + return NULL; s302m->name = kstrdup(name, GFP_KERNEL); + if (!s302m->name) + goto free_s302m; - s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id); + s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true); + if (!s302m->service) + goto free_name; s302m->service->descriptor = (struct vidtv_psi_desc *) vidtv_psi_service_desc_init(NULL, - DIGITAL_TELEVISION_SERVICE, + DIGITAL_RADIO_SOUND_SERVICE, name, provider); + if (!s302m->service->descriptor) + goto free_service; s302m->transport_stream_id = transport_stream_id; s302m->program = vidtv_psi_pat_program_init(NULL, s302m_service_id, s302m_program_pid); + if (!s302m->program) + goto free_service; s302m->program_num = s302m_program_num; s302m->streams = vidtv_psi_pmt_stream_init(NULL, STREAM_PRIVATE_DATA, s302m_es_pid); + if (!s302m->streams) + goto free_program; s302m->streams->descriptor = (struct vidtv_psi_desc *) vidtv_psi_registration_desc_init(NULL, s302m_fid, NULL, 0); + if (!s302m->streams->descriptor) + goto free_streams; + encoder_args.es_pid = s302m_es_pid; s302m->encoders = vidtv_s302m_encoder_init(encoder_args); + if (!s302m->encoders) + goto free_streams; + + s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id); + if (!s302m->events) + goto free_encoders; + s302m->events->descriptor = (struct vidtv_psi_desc *) + vidtv_psi_short_event_desc_init(NULL, + iso_language_code, + event_name, + event_text); + if (!s302m->events->descriptor) + goto free_events; if (head) { while (head->next) @@ -102,6 +136,68 @@ struct vidtv_channel } return s302m; + +free_events: + vidtv_psi_eit_event_destroy(s302m->events); +free_encoders: + vidtv_s302m_encoder_destroy(s302m->encoders); +free_streams: + vidtv_psi_pmt_stream_destroy(s302m->streams); +free_program: + vidtv_psi_pat_program_destroy(s302m->program); +free_service: + vidtv_psi_sdt_service_destroy(s302m->service); +free_name: + kfree(s302m->name); +free_s302m: + kfree(s302m); + + return NULL; +} + +static struct vidtv_psi_table_eit_event +*vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m) +{ + /* Concatenate the events */ + const struct vidtv_channel *cur_chnl = m->channels; + struct vidtv_psi_table_eit_event *curr = NULL; + struct vidtv_psi_table_eit_event *head = NULL; + struct vidtv_psi_table_eit_event *tail = NULL; + struct vidtv_psi_desc *desc = NULL; + u16 event_id; + + if (!cur_chnl) + return NULL; + + while (cur_chnl) { + curr = cur_chnl->events; + + if (!curr) + dev_warn_ratelimited(m->dev, + "No events found for channel %s\n", + cur_chnl->name); + + while (curr) { + event_id = be16_to_cpu(curr->event_id); + tail = vidtv_psi_eit_event_init(tail, event_id); + if (!tail) { + vidtv_psi_eit_event_destroy(head); + return NULL; + } + + desc = vidtv_psi_desc_clone(curr->descriptor); + vidtv_psi_desc_assign(&tail->descriptor, desc); + + if (!head) + head = tail; + + curr = curr->next; + } + + cur_chnl = cur_chnl->next; + } + + return head; } static struct vidtv_psi_table_sdt_service @@ -125,13 +221,21 @@ static struct vidtv_psi_table_sdt_service if (!curr) dev_warn_ratelimited(m->dev, - "No services found for channel %s\n", cur_chnl->name); + "No services found for channel %s\n", + cur_chnl->name); while (curr) { service_id = be16_to_cpu(curr->service_id); - tail = vidtv_psi_sdt_service_init(tail, service_id); + tail = vidtv_psi_sdt_service_init(tail, + service_id, + curr->EIT_schedule, + curr->EIT_present_following); + if (!tail) + goto free; desc = vidtv_psi_desc_clone(curr->descriptor); + if (!desc) + goto free_tail; vidtv_psi_desc_assign(&tail->descriptor, desc); if (!head) @@ -144,6 +248,12 @@ static struct vidtv_psi_table_sdt_service } return head; + +free_tail: + vidtv_psi_sdt_service_destroy(tail); +free: + vidtv_psi_sdt_service_destroy(head); + return NULL; } static struct vidtv_psi_table_pat_program* @@ -174,6 +284,10 @@ vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m) tail = vidtv_psi_pat_program_init(tail, serv_id, pid); + if (!tail) { + vidtv_psi_pat_program_destroy(head); + return NULL; + } if (!head) head = tail; @@ -183,30 +297,30 @@ vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m) cur_chnl = cur_chnl->next; } + /* Add the NIT table */ + vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID); return head; } +/* + * Match channels to their respective PMT sections, then assign the + * streams + */ static void vidtv_channel_pmt_match_sections(struct vidtv_channel *channels, struct vidtv_psi_table_pmt **sections, u32 nsections) { - /* - * Match channels to their respective PMT sections, then assign the - * streams - */ struct vidtv_psi_table_pmt *curr_section = NULL; - struct vidtv_channel *cur_chnl = channels; - - struct vidtv_psi_table_pmt_stream *s = NULL; struct vidtv_psi_table_pmt_stream *head = NULL; struct vidtv_psi_table_pmt_stream *tail = NULL; - + struct vidtv_psi_table_pmt_stream *s = NULL; + struct vidtv_channel *cur_chnl = channels; struct vidtv_psi_desc *desc = NULL; - u32 j; - u16 curr_id; u16 e_pid; /* elementary stream pid */ + u16 curr_id; + u32 j; while (cur_chnl) { for (j = 0; j < nsections; ++j) { @@ -232,7 +346,8 @@ vidtv_channel_pmt_match_sections(struct vidtv_channel *channels, head = tail; desc = vidtv_psi_desc_clone(s->descriptor); - vidtv_psi_desc_assign(&tail->descriptor, desc); + vidtv_psi_desc_assign(&tail->descriptor, + desc); s = s->next; } @@ -246,17 +361,103 @@ vidtv_channel_pmt_match_sections(struct vidtv_channel *channels, } } -void vidtv_channel_si_init(struct vidtv_mux *m) +static void +vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e) +{ + struct vidtv_psi_desc_service_list_entry *tmp; + + while (e) { + tmp = e; + e = e->next; + kfree(tmp); + } +} + +static struct vidtv_psi_desc_service_list_entry +*vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s) +{ + struct vidtv_psi_desc_service_list_entry *curr_e = NULL; + struct vidtv_psi_desc_service_list_entry *head_e = NULL; + struct vidtv_psi_desc_service_list_entry *prev_e = NULL; + struct vidtv_psi_desc *desc = s->descriptor; + struct vidtv_psi_desc_service *s_desc; + + while (s) { + while (desc) { + if (s->descriptor->type != SERVICE_DESCRIPTOR) + goto next_desc; + + s_desc = (struct vidtv_psi_desc_service *)desc; + + curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL); + if (!curr_e) { + vidtv_channel_destroy_service_list(head_e); + return NULL; + } + + curr_e->service_id = s->service_id; + curr_e->service_type = s_desc->service_type; + + if (!head_e) + head_e = curr_e; + if (prev_e) + prev_e->next = curr_e; + + prev_e = curr_e; + +next_desc: + desc = desc->next; + } + s = s->next; + } + return head_e; +} + +int vidtv_channel_si_init(struct vidtv_mux *m) { + struct vidtv_psi_desc_service_list_entry *service_list = NULL; struct vidtv_psi_table_pat_program *programs = NULL; struct vidtv_psi_table_sdt_service *services = NULL; + struct vidtv_psi_table_eit_event *events = NULL; m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id); + if (!m->si.pat) + return -ENOMEM; - m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id); + m->si.sdt = vidtv_psi_sdt_table_init(m->network_id, + m->transport_stream_id); + if (!m->si.sdt) + goto free_pat; programs = vidtv_channel_pat_prog_cat_into_new(m); + if (!programs) + goto free_sdt; services = vidtv_channel_sdt_serv_cat_into_new(m); + if (!services) + goto free_programs; + + events = vidtv_channel_eit_event_cat_into_new(m); + if (!events) + goto free_services; + + /* look for a service descriptor for every service */ + service_list = vidtv_channel_build_service_list(services); + if (!service_list) + goto free_events; + + /* use these descriptors to build the NIT */ + m->si.nit = vidtv_psi_nit_table_init(m->network_id, + m->transport_stream_id, + m->network_name, + service_list); + if (!m->si.nit) + goto free_service_list; + + m->si.eit = vidtv_psi_eit_table_init(m->network_id, + m->transport_stream_id, + programs->service_id); + if (!m->si.eit) + goto free_nit; /* assemble all programs and assign to PAT */ vidtv_psi_pat_program_assign(m->si.pat, programs); @@ -264,31 +465,65 @@ void vidtv_channel_si_init(struct vidtv_mux *m) /* assemble all services and assign to SDT */ vidtv_psi_sdt_service_assign(m->si.sdt, services); - m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid); + /* assemble all events and assign to EIT */ + vidtv_psi_eit_event_assign(m->si.eit, events); + + m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, + m->pcr_pid); + if (!m->si.pmt_secs) + goto free_eit; vidtv_channel_pmt_match_sections(m->channels, m->si.pmt_secs, - m->si.pat->programs); + m->si.pat->num_pmt); + + vidtv_channel_destroy_service_list(service_list); + + return 0; + +free_eit: + vidtv_psi_eit_table_destroy(m->si.eit); +free_nit: + vidtv_psi_nit_table_destroy(m->si.nit); +free_service_list: + vidtv_channel_destroy_service_list(service_list); +free_events: + vidtv_psi_eit_event_destroy(events); +free_services: + vidtv_psi_sdt_service_destroy(services); +free_programs: + vidtv_psi_pat_program_destroy(programs); +free_sdt: + vidtv_psi_sdt_table_destroy(m->si.sdt); +free_pat: + vidtv_psi_pat_table_destroy(m->si.pat); + return 0; } void vidtv_channel_si_destroy(struct vidtv_mux *m) { u32 i; - u16 num_programs = m->si.pat->programs; vidtv_psi_pat_table_destroy(m->si.pat); - for (i = 0; i < num_programs; ++i) + for (i = 0; i < m->si.pat->num_pmt; ++i) vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]); kfree(m->si.pmt_secs); vidtv_psi_sdt_table_destroy(m->si.sdt); + vidtv_psi_nit_table_destroy(m->si.nit); + vidtv_psi_eit_table_destroy(m->si.eit); } -void vidtv_channels_init(struct vidtv_mux *m) +int vidtv_channels_init(struct vidtv_mux *m) { /* this is the place to add new 'channels' for vidtv */ m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id); + + if (!m->channels) + return -ENOMEM; + + return 0; } void vidtv_channels_destroy(struct vidtv_mux *m) @@ -302,6 +537,7 @@ void vidtv_channels_destroy(struct vidtv_mux *m) vidtv_psi_pat_program_destroy(curr->program); vidtv_psi_pmt_stream_destroy(curr->streams); vidtv_channel_encoder_destroy(curr->encoders); + vidtv_psi_eit_event_destroy(curr->events); tmp = curr; curr = curr->next; diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.h b/drivers/media/test-drivers/vidtv/vidtv_channel.h index 2c3cba4313b0..fff2e501d375 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_channel.h +++ b/drivers/media/test-drivers/vidtv/vidtv_channel.h @@ -9,6 +9,7 @@ * When vidtv boots, it will create some hardcoded channels. * Their services will be concatenated to populate the SDT. * Their programs will be concatenated to populate the PAT + * Their events will be concatenated to populate the EIT * For each program in the PAT, a PMT section will be created * The PMT section for a channel will be assigned its streams. * Every stream will have its corresponding encoder polled to produce TS packets @@ -22,9 +23,10 @@ #define VIDTV_CHANNEL_H #include <linux/types.h> -#include "vidtv_psi.h" + #include "vidtv_encoder.h" #include "vidtv_mux.h" +#include "vidtv_psi.h" /** * struct vidtv_channel - A 'channel' abstraction @@ -37,6 +39,7 @@ * Every stream will have its corresponding encoder polled to produce TS packets * These packets may be interleaved by the mux and then delivered to the bridge * + * @name: name of the channel * @transport_stream_id: a number to identify the TS, chosen at will. * @service: A _single_ service. Will be concatenated into the SDT. * @program_num: The link between PAT, PMT and SDT. @@ -44,6 +47,7 @@ * Will be concatenated into the PAT. * @streams: A stream loop used to populate the PMT section for 'program' * @encoders: A encoder loop. There must be one encoder for each stream. + * @events: Optional event information. This will feed into the EIT. * @next: Optionally chain this channel. */ struct vidtv_channel { @@ -54,6 +58,7 @@ struct vidtv_channel { struct vidtv_psi_table_pat_program *program; struct vidtv_psi_table_pmt_stream *streams; struct vidtv_encoder *encoders; + struct vidtv_psi_table_eit_event *events; struct vidtv_channel *next; }; @@ -61,14 +66,14 @@ struct vidtv_channel { * vidtv_channel_si_init - Init the PSI tables from the channels in the mux * @m: The mux containing the channels. */ -void vidtv_channel_si_init(struct vidtv_mux *m); +int vidtv_channel_si_init(struct vidtv_mux *m); void vidtv_channel_si_destroy(struct vidtv_mux *m); /** * vidtv_channels_init - Init hardcoded, fake 'channels'. * @m: The mux to store the channels into. */ -void vidtv_channels_init(struct vidtv_mux *m); +int vidtv_channels_init(struct vidtv_mux *m); struct vidtv_channel *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id); void vidtv_channels_destroy(struct vidtv_mux *m); diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.h b/drivers/media/test-drivers/vidtv/vidtv_common.h index 818e7f2b9ec5..42f63fdee681 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_common.h +++ b/drivers/media/test-drivers/vidtv/vidtv_common.h @@ -16,7 +16,6 @@ #define CLOCK_UNIT_27MHZ 27000000 #define VIDTV_SLEEP_USECS 10000 #define VIDTV_MAX_SLEEP_USECS (2 * VIDTV_SLEEP_USECS) -#define VIDTV_DEFAULT_TS_ID 0x744 u32 vidtv_memcpy(void *to, size_t to_offset, diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.c b/drivers/media/test-drivers/vidtv/vidtv_demod.c index eba7fe1a1b48..b7823d97b30d 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_demod.c +++ b/drivers/media/test-drivers/vidtv/vidtv_demod.c @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/workqueue.h> + #include <media/dvb_frontend.h> #include "vidtv_demod.h" @@ -192,7 +193,6 @@ static void vidtv_demod_update_stats(struct dvb_frontend *fe) c->cnr.stat[0].svalue = state->tuner_cnr; c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50); - } static int vidtv_demod_read_status(struct dvb_frontend *fe, diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.h b/drivers/media/test-drivers/vidtv/vidtv_demod.h index 87651b0193e6..2b8404661348 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_demod.h +++ b/drivers/media/test-drivers/vidtv/vidtv_demod.h @@ -12,6 +12,7 @@ #define VIDTV_DEMOD_H #include <linux/dvb/frontend.h> + #include <media/dvb_frontend.h> /** @@ -19,6 +20,9 @@ * modulation and fec_inner * @modulation: see enum fe_modulation * @fec: see enum fe_fec_rate + * @cnr_ok: S/N threshold to consider the signal as OK. Below that, there's + * a chance of losing sync. + * @cnr_good: S/N threshold to consider the signal strong. * * This struct matches values for 'good' and 'ok' CNRs given the combination * of modulation and fec_inner in use. We might simulate some noise if the @@ -52,13 +56,8 @@ struct vidtv_demod_config { * struct vidtv_demod_state - The demodulator state * @frontend: The frontend structure allocated by the demod. * @config: The config used to init the demod. - * @poll_snr: The task responsible for periodically checking the simulated - * signal quality, eventually dropping or reacquiring the TS lock. * @status: the demod status. - * @cold_start: Whether the demod has not been init yet. - * @poll_snr_thread_running: Whether the task responsible for periodically - * checking the simulated signal quality is running. - * @poll_snr_thread_restart: Whether we should restart the poll_snr task. + * @tuner_cnr: current S/N ratio for the signal carrier */ struct vidtv_demod_state { struct dvb_frontend frontend; diff --git a/drivers/media/test-drivers/vidtv/vidtv_encoder.h b/drivers/media/test-drivers/vidtv/vidtv_encoder.h index 65d81daef4c3..50e3cf4eb4eb 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_encoder.h +++ b/drivers/media/test-drivers/vidtv/vidtv_encoder.h @@ -28,7 +28,7 @@ struct vidtv_access_unit { struct vidtv_access_unit *next; }; -/* Some musical notes, used by a tone generator */ +/* Some musical notes, used by a tone generator. Values are in Hz */ enum musical_notes { NOTE_SILENT = 0, @@ -103,14 +103,16 @@ enum musical_notes { * @encoder_buf_sz: The encoder buffer size, in bytes * @encoder_buf_offset: Our byte position in the encoder buffer. * @sample_count: How many samples we have encoded in total. + * @access_units: encoder payload units, used for clock references * @src_buf: The source of raw data to be encoded, encoder might set a * default if null. + * @src_buf_sz: size of @src_buf. * @src_buf_offset: Our position in the source buffer. * @is_video_encoder: Whether this a video encoder (as opposed to audio) * @ctx: Encoder-specific state. * @stream_id: Examples: Audio streams (0xc0-0xdf), Video streams * (0xe0-0xef). - * @es_id: The TS PID to use for the elementary stream in this encoder. + * @es_pid: The TS PID to use for the elementary stream in this encoder. * @encode: Prepare enough AUs for the given amount of time. * @clear: Clear the encoder output. * @sync: Attempt to synchronize with this encoder. @@ -131,9 +133,6 @@ struct vidtv_encoder { u32 encoder_buf_offset; u64 sample_count; - int last_duration; - int note_offset; - enum musical_notes last_tone; struct vidtv_access_unit *access_units; diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.c b/drivers/media/test-drivers/vidtv/vidtv_mux.c index 082740ae9d44..b51e6a3b8cbe 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_mux.c +++ b/drivers/media/test-drivers/vidtv/vidtv_mux.c @@ -12,23 +12,23 @@ * Copyright (C) 2020 Daniel W. S. Almeida */ -#include <linux/types.h> -#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> #include <linux/jiffies.h> #include <linux/kernel.h> -#include <linux/dev_printk.h> +#include <linux/math64.h> #include <linux/ratelimit.h> -#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/types.h> #include <linux/vmalloc.h> -#include <linux/math64.h> -#include "vidtv_mux.h" -#include "vidtv_ts.h" -#include "vidtv_pes.h" -#include "vidtv_encoder.h" #include "vidtv_channel.h" #include "vidtv_common.h" +#include "vidtv_encoder.h" +#include "vidtv_mux.h" +#include "vidtv_pes.h" #include "vidtv_psi.h" +#include "vidtv_ts.h" static struct vidtv_mux_pid_ctx *vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid) @@ -47,33 +47,56 @@ static struct vidtv_mux_pid_ctx struct vidtv_mux_pid_ctx *ctx; ctx = vidtv_mux_get_pid_ctx(m, pid); - if (ctx) - goto end; + return ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx->pid = pid; ctx->cc = 0; hash_add(m->pid_ctx, &ctx->h, pid); -end: return ctx; } -static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m) +static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) +{ + struct vidtv_mux_pid_ctx *ctx; + struct hlist_node *tmp; + int bkt; + + hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { + hash_del(&ctx->h); + kfree(ctx); + } +} + +static int vidtv_mux_pid_ctx_init(struct vidtv_mux *m) { struct vidtv_psi_table_pat_program *p = m->si.pat->program; u16 pid; hash_init(m->pid_ctx); /* push the pcr pid ctx */ - vidtv_mux_create_pid_ctx_once(m, m->pcr_pid); - /* push the null packet pid ctx */ - vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID); + if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid)) + return -ENOMEM; + /* push the NULL packet pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID)) + goto free; /* push the PAT pid ctx */ - vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID); + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID)) + goto free; /* push the SDT pid ctx */ - vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID); + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID)) + goto free; + /* push the NIT pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID)) + goto free; + /* push the EIT pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID)) + goto free; /* add a ctx for all PMT sections */ while (p) { @@ -81,18 +104,12 @@ static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m) vidtv_mux_create_pid_ctx_once(m, pid); p = p->next; } -} -static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) -{ - int bkt; - struct vidtv_mux_pid_ctx *ctx; - struct hlist_node *tmp; + return 0; - hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { - hash_del(&ctx->h); - kfree(ctx); - } +free: + vidtv_mux_pid_ctx_destroy(m); + return -ENOMEM; } static void vidtv_mux_update_clk(struct vidtv_mux *m) @@ -112,32 +129,53 @@ static void vidtv_mux_update_clk(struct vidtv_mux *m) static u32 vidtv_mux_push_si(struct vidtv_mux *m) { + struct vidtv_psi_pat_write_args pat_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .pat = m->si.pat, + }; + struct vidtv_psi_pmt_write_args pmt_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .pcr_pid = m->pcr_pid, + }; + struct vidtv_psi_sdt_write_args sdt_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .sdt = m->si.sdt, + }; + struct vidtv_psi_nit_write_args nit_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .nit = m->si.nit, + + }; + struct vidtv_psi_eit_write_args eit_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .eit = m->si.eit, + }; u32 initial_offset = m->mux_buf_offset; - struct vidtv_mux_pid_ctx *pat_ctx; struct vidtv_mux_pid_ctx *pmt_ctx; struct vidtv_mux_pid_ctx *sdt_ctx; - - struct vidtv_psi_pat_write_args pat_args = {}; - struct vidtv_psi_pmt_write_args pmt_args = {}; - struct vidtv_psi_sdt_write_args sdt_args = {}; - - u32 nbytes; /* the number of bytes written by this function */ + struct vidtv_mux_pid_ctx *nit_ctx; + struct vidtv_mux_pid_ctx *eit_ctx; + u32 nbytes; u16 pmt_pid; u32 i; pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID); sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID); + nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID); + eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID); - pat_args.buf = m->mux_buf; pat_args.offset = m->mux_buf_offset; - pat_args.pat = m->si.pat; - pat_args.buf_sz = m->mux_buf_sz; pat_args.continuity_counter = &pat_ctx->cc; - m->mux_buf_offset += vidtv_psi_pat_write_into(pat_args); + m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args); - for (i = 0; i < m->si.pat->programs; ++i) { + for (i = 0; i < m->si.pat->num_pmt; ++i) { pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i], m->si.pat); @@ -149,25 +187,29 @@ static u32 vidtv_mux_push_si(struct vidtv_mux *m) pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid); - pmt_args.buf = m->mux_buf; pmt_args.offset = m->mux_buf_offset; pmt_args.pmt = m->si.pmt_secs[i]; pmt_args.pid = pmt_pid; - pmt_args.buf_sz = m->mux_buf_sz; pmt_args.continuity_counter = &pmt_ctx->cc; - pmt_args.pcr_pid = m->pcr_pid; /* write each section into buffer */ - m->mux_buf_offset += vidtv_psi_pmt_write_into(pmt_args); + m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args); } - sdt_args.buf = m->mux_buf; sdt_args.offset = m->mux_buf_offset; - sdt_args.sdt = m->si.sdt; - sdt_args.buf_sz = m->mux_buf_sz; sdt_args.continuity_counter = &sdt_ctx->cc; - m->mux_buf_offset += vidtv_psi_sdt_write_into(sdt_args); + m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args); + + nit_args.offset = m->mux_buf_offset; + nit_args.continuity_counter = &nit_ctx->cc; + + m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args); + + eit_args.offset = m->mux_buf_offset; + eit_args.continuity_counter = &eit_ctx->cc; + + m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args); nbytes = m->mux_buf_offset - initial_offset; @@ -230,23 +272,29 @@ static bool vidtv_mux_should_push_si(struct vidtv_mux *m) static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, struct vidtv_encoder *e) { - u32 nbytes = 0; - - struct pes_write_args args = {}; - u32 initial_offset = m->mux_buf_offset; + struct pes_write_args args = { + .dest_buf = m->mux_buf, + .dest_buf_sz = m->mux_buf_sz, + .pid = be16_to_cpu(e->es_pid), + .encoder_id = e->id, + .stream_id = be16_to_cpu(e->stream_id), + .send_pts = true, /* forbidden value '01'... */ + .send_dts = false, /* ...for PTS_DTS flags */ + }; struct vidtv_access_unit *au = e->access_units; - + u32 initial_offset = m->mux_buf_offset; + struct vidtv_mux_pid_ctx *pid_ctx; + u32 nbytes = 0; u8 *buf = NULL; - struct vidtv_mux_pid_ctx *pid_ctx = vidtv_mux_create_pid_ctx_once(m, - be16_to_cpu(e->es_pid)); - args.dest_buf = m->mux_buf; - args.dest_buf_sz = m->mux_buf_sz; - args.pid = be16_to_cpu(e->es_pid); - args.encoder_id = e->id; + /* see SMPTE 302M clause 6.4 */ + if (args.encoder_id == S302M) { + args.send_dts = false; + args.send_pts = true; + } + + pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid)); args.continuity_counter = &pid_ctx->cc; - args.stream_id = be16_to_cpu(e->stream_id); - args.send_pts = true; while (au) { buf = e->encoder_buf + au->offset; @@ -256,7 +304,7 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, args.pts = au->pts; args.pcr = m->timing.clk; - m->mux_buf_offset += vidtv_pes_write_into(args); + m->mux_buf_offset += vidtv_pes_write_into(&args); au = au->next; } @@ -273,10 +321,10 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) { - u32 nbytes = 0; - u32 au_nbytes; struct vidtv_channel *cur_chnl = m->channels; struct vidtv_encoder *e = NULL; + u32 nbytes = 0; + u32 au_nbytes; while (cur_chnl) { e = cur_chnl->encoders; @@ -300,18 +348,19 @@ static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) static u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts) { - struct null_packet_write_args args = {}; + struct null_packet_write_args args = { + .dest_buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .dest_offset = m->mux_buf_offset, + }; u32 initial_offset = m->mux_buf_offset; - u32 nbytes; /* the number of bytes written by this function */ - u32 i; struct vidtv_mux_pid_ctx *ctx; + u32 nbytes; + u32 i; ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID); - args.dest_buf = m->mux_buf; - args.buf_sz = m->mux_buf_sz; args.continuity_counter = &ctx->cc; - args.dest_offset = m->mux_buf_offset; for (i = 0; i < npkts; ++i) { m->mux_buf_offset += vidtv_ts_null_write_into(args); @@ -343,9 +392,9 @@ static void vidtv_mux_tick(struct work_struct *work) struct vidtv_mux, mpeg_thread); struct dtv_frontend_properties *c = &m->fe->dtv_property_cache; + u32 tot_bits = 0; u32 nbytes; u32 npkts; - u32 tot_bits = 0; while (m->streaming) { nbytes = 0; @@ -427,40 +476,62 @@ void vidtv_mux_stop_thread(struct vidtv_mux *m) struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, struct device *dev, - struct vidtv_mux_init_args args) + struct vidtv_mux_init_args *args) { - struct vidtv_mux *m = kzalloc(sizeof(*m), GFP_KERNEL); + struct vidtv_mux *m; + + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return NULL; m->dev = dev; m->fe = fe; - m->timing.pcr_period_usecs = args.pcr_period_usecs; - m->timing.si_period_usecs = args.si_period_usecs; + m->timing.pcr_period_usecs = args->pcr_period_usecs; + m->timing.si_period_usecs = args->si_period_usecs; + + m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec; - m->mux_rate_kbytes_sec = args.mux_rate_kbytes_sec; + m->on_new_packets_available_cb = args->on_new_packets_available_cb; - m->on_new_packets_available_cb = args.on_new_packets_available_cb; + m->mux_buf = vzalloc(args->mux_buf_sz); + if (!m->mux_buf) + goto free_mux; - m->mux_buf = vzalloc(args.mux_buf_sz); - m->mux_buf_sz = args.mux_buf_sz; + m->mux_buf_sz = args->mux_buf_sz; - m->pcr_pid = args.pcr_pid; - m->transport_stream_id = args.transport_stream_id; - m->priv = args.priv; + m->pcr_pid = args->pcr_pid; + m->transport_stream_id = args->transport_stream_id; + m->priv = args->priv; + m->network_id = args->network_id; + m->network_name = kstrdup(args->network_name, GFP_KERNEL); m->timing.current_jiffies = get_jiffies_64(); - if (args.channels) - m->channels = args.channels; + if (args->channels) + m->channels = args->channels; else - vidtv_channels_init(m); + if (vidtv_channels_init(m) < 0) + goto free_mux_buf; /* will alloc data for pmt_sections after initializing pat */ - vidtv_channel_si_init(m); + if (vidtv_channel_si_init(m) < 0) + goto free_channels; INIT_WORK(&m->mpeg_thread, vidtv_mux_tick); - vidtv_mux_pid_ctx_init(m); + if (vidtv_mux_pid_ctx_init(m) < 0) + goto free_channel_si; return m; + +free_channel_si: + vidtv_channel_si_destroy(m); +free_channels: + vidtv_channels_destroy(m); +free_mux_buf: + vfree(m->mux_buf); +free_mux: + kfree(m); + return NULL; } void vidtv_mux_destroy(struct vidtv_mux *m) @@ -469,6 +540,7 @@ void vidtv_mux_destroy(struct vidtv_mux *m) vidtv_mux_pid_ctx_destroy(m); vidtv_channel_si_destroy(m); vidtv_channels_destroy(m); + kfree(m->network_name); vfree(m->mux_buf); kfree(m); } diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.h b/drivers/media/test-drivers/vidtv/vidtv_mux.h index 2caa60623e97..ad82eb72b841 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_mux.h +++ b/drivers/media/test-drivers/vidtv/vidtv_mux.h @@ -15,9 +15,10 @@ #ifndef VIDTV_MUX_H #define VIDTV_MUX_H -#include <linux/types.h> #include <linux/hashtable.h> +#include <linux/types.h> #include <linux/workqueue.h> + #include <media/dvb_frontend.h> #include "vidtv_psi.h" @@ -58,12 +59,16 @@ struct vidtv_mux_timing { * @pat: The PAT in use by the muxer. * @pmt_secs: The PMT sections in use by the muxer. One for each program in the PAT. * @sdt: The SDT in use by the muxer. + * @nit: The NIT in use by the muxer. + * @eit: the EIT in use by the muxer. */ struct vidtv_mux_si { /* the SI tables */ struct vidtv_psi_table_pat *pat; struct vidtv_psi_table_pmt **pmt_secs; /* the PMT sections */ struct vidtv_psi_table_sdt *sdt; + struct vidtv_psi_table_nit *nit; + struct vidtv_psi_table_eit *eit; }; /** @@ -82,8 +87,10 @@ struct vidtv_mux_pid_ctx { /** * struct vidtv_mux - A muxer abstraction loosely based in libavcodec/mpegtsenc.c - * @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes. + * @fe: The frontend structure allocated by the muxer. + * @dev: pointer to struct device. * @timing: Keeps track of timing related information. + * @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes. * @pid_ctx: A hash table to keep track of per-PID metadata. * @on_new_packets_available_cb: A callback to inform of new TS packets ready. * @mux_buf: A pointer to a buffer for this muxer. TS packets are stored there @@ -99,6 +106,8 @@ struct vidtv_mux_pid_ctx { * @pcr_pid: The TS PID used for the PSI packets. All channels will share the * same PCR. * @transport_stream_id: The transport stream ID + * @network_id: The network ID + * @network_name: The network name * @priv: Private data. */ struct vidtv_mux { @@ -128,6 +137,8 @@ struct vidtv_mux { u16 pcr_pid; u16 transport_stream_id; + u16 network_id; + char *network_name; void *priv; }; @@ -142,6 +153,8 @@ struct vidtv_mux { * same PCR. * @transport_stream_id: The transport stream ID * @channels: an optional list of channels to use + * @network_id: The network ID + * @network_name: The network name * @priv: Private data. */ struct vidtv_mux_init_args { @@ -153,12 +166,14 @@ struct vidtv_mux_init_args { u16 pcr_pid; u16 transport_stream_id; struct vidtv_channel *channels; + u16 network_id; + char *network_name; void *priv; }; struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, struct device *dev, - struct vidtv_mux_init_args args); + struct vidtv_mux_init_args *args); void vidtv_mux_destroy(struct vidtv_mux *m); void vidtv_mux_start_thread(struct vidtv_mux *m); diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.c b/drivers/media/test-drivers/vidtv/vidtv_pes.c index 1c75f88070e9..782e5e7fbb02 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_pes.c +++ b/drivers/media/test-drivers/vidtv/vidtv_pes.c @@ -16,7 +16,6 @@ #include <linux/types.h> #include <linux/printk.h> #include <linux/ratelimit.h> -#include <asm/byteorder.h> #include "vidtv_pes.h" #include "vidtv_common.h" @@ -57,7 +56,7 @@ static u32 vidtv_pes_h_get_len(bool send_pts, bool send_dts) return len; } -static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args args) +static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args *args) { /* * This is a fixed 8-bit value equal to '0xFF' that can be inserted @@ -65,20 +64,20 @@ static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args args) * It is discarded by the decoder. No more than 32 stuffing bytes shall * be present in one PES packet header. */ - if (args.n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) { + if (args->n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) { pr_warn_ratelimited("More than %d stuffing bytes in PES packet header\n", PES_HEADER_MAX_STUFFING_BYTES); - args.n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES; + args->n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES; } - return vidtv_memset(args.dest_buf, - args.dest_offset, - args.dest_buf_sz, + return vidtv_memset(args->dest_buf, + args->dest_offset, + args->dest_buf_sz, TS_FILL_BYTE, - args.n_pes_h_s_bytes); + args->n_pes_h_s_bytes); } -static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args) +static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args *args) { u32 nbytes = 0; /* the number of bytes written by this function */ @@ -90,7 +89,7 @@ static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args) u64 mask2; u64 mask3; - if (!args.send_pts && args.send_dts) + if (!args->send_pts && args->send_dts) return 0; mask1 = GENMASK_ULL(32, 30); @@ -98,80 +97,81 @@ static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args) mask3 = GENMASK_ULL(14, 0); /* see ISO/IEC 13818-1 : 2000 p. 32 */ - if (args.send_pts && args.send_dts) { - pts_dts.pts1 = (0x3 << 4) | ((args.pts & mask1) >> 29) | 0x1; - pts_dts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1); - pts_dts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1); + if (args->send_pts && args->send_dts) { + pts_dts.pts1 = (0x3 << 4) | ((args->pts & mask1) >> 29) | 0x1; + pts_dts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); + pts_dts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); - pts_dts.dts1 = (0x1 << 4) | ((args.dts & mask1) >> 29) | 0x1; - pts_dts.dts2 = cpu_to_be16(((args.dts & mask2) >> 14) | 0x1); - pts_dts.dts3 = cpu_to_be16(((args.dts & mask3) << 1) | 0x1); + pts_dts.dts1 = (0x1 << 4) | ((args->dts & mask1) >> 29) | 0x1; + pts_dts.dts2 = cpu_to_be16(((args->dts & mask2) >> 14) | 0x1); + pts_dts.dts3 = cpu_to_be16(((args->dts & mask3) << 1) | 0x1); op = &pts_dts; op_sz = sizeof(pts_dts); - } else if (args.send_pts) { - pts.pts1 = (0x1 << 5) | ((args.pts & mask1) >> 29) | 0x1; - pts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1); - pts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1); + } else if (args->send_pts) { + pts.pts1 = (0x1 << 5) | ((args->pts & mask1) >> 29) | 0x1; + pts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); + pts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); op = &pts; op_sz = sizeof(pts); } /* copy PTS/DTS optional */ - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, op, op_sz); return nbytes; } -static u32 vidtv_pes_write_h(struct pes_header_write_args args) +static u32 vidtv_pes_write_h(struct pes_header_write_args *args) { u32 nbytes = 0; /* the number of bytes written by this function */ struct vidtv_mpeg_pes pes_header = {}; struct vidtv_pes_optional pes_optional = {}; - struct pes_header_write_args pts_dts_args = args; - u32 stream_id = (args.encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args.stream_id; + struct pes_header_write_args pts_dts_args; + u32 stream_id = (args->encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args->stream_id; u16 pes_opt_bitfield = 0x01 << 15; pes_header.bitfield = cpu_to_be32((PES_START_CODE_PREFIX << 8) | stream_id); - pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args.send_pts, - args.send_dts) + - args.access_unit_len); + pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args->send_pts, + args->send_dts) + + args->access_unit_len); - if (args.send_pts && args.send_dts) + if (args->send_pts && args->send_dts) pes_opt_bitfield |= (0x3 << 6); - else if (args.send_pts) + else if (args->send_pts) pes_opt_bitfield |= (0x1 << 7); pes_optional.bitfield = cpu_to_be16(pes_opt_bitfield); - pes_optional.length = vidtv_pes_op_get_len(args.send_pts, args.send_dts) + - args.n_pes_h_s_bytes - + pes_optional.length = vidtv_pes_op_get_len(args->send_pts, args->send_dts) + + args->n_pes_h_s_bytes - sizeof(struct vidtv_pes_optional); /* copy header */ - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, &pes_header, sizeof(pes_header)); /* copy optional header bits */ - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, &pes_optional, sizeof(pes_optional)); /* copy the timing information */ - pts_dts_args.dest_offset = args.dest_offset + nbytes; - nbytes += vidtv_pes_write_pts_dts(pts_dts_args); + pts_dts_args = *args; + pts_dts_args.dest_offset = args->dest_offset + nbytes; + nbytes += vidtv_pes_write_pts_dts(&pts_dts_args); /* write any PES header stuffing */ nbytes += vidtv_pes_write_header_stuffing(args); @@ -300,14 +300,31 @@ static u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args, return nbytes; } -u32 vidtv_pes_write_into(struct pes_write_args args) +u32 vidtv_pes_write_into(struct pes_write_args *args) { - u32 unaligned_bytes = (args.dest_offset % TS_PACKET_LEN); - struct pes_ts_header_write_args ts_header_args = {}; - struct pes_header_write_args pes_header_args = {}; - u32 remaining_len = args.access_unit_len; + u32 unaligned_bytes = (args->dest_offset % TS_PACKET_LEN); + struct pes_ts_header_write_args ts_header_args = { + .dest_buf = args->dest_buf, + .dest_buf_sz = args->dest_buf_sz, + .pid = args->pid, + .pcr = args->pcr, + .continuity_counter = args->continuity_counter, + }; + struct pes_header_write_args pes_header_args = { + .dest_buf = args->dest_buf, + .dest_buf_sz = args->dest_buf_sz, + .encoder_id = args->encoder_id, + .send_pts = args->send_pts, + .pts = args->pts, + .send_dts = args->send_dts, + .dts = args->dts, + .stream_id = args->stream_id, + .n_pes_h_s_bytes = args->n_pes_h_s_bytes, + .access_unit_len = args->access_unit_len, + }; + u32 remaining_len = args->access_unit_len; bool wrote_pes_header = false; - u64 last_pcr = args.pcr; + u64 last_pcr = args->pcr; bool need_pcr = true; u32 available_space; u32 payload_size; @@ -318,25 +335,13 @@ u32 vidtv_pes_write_into(struct pes_write_args args) pr_warn_ratelimited("buffer is misaligned, while starting PES\n"); /* forcibly align and hope for the best */ - nbytes += vidtv_memset(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + nbytes += vidtv_memset(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, TS_FILL_BYTE, TS_PACKET_LEN - unaligned_bytes); } - if (args.send_dts && !args.send_pts) { - pr_warn_ratelimited("forbidden value '01' for PTS_DTS flags\n"); - args.send_pts = true; - args.pts = args.dts; - } - - /* see SMPTE 302M clause 6.4 */ - if (args.encoder_id == S302M) { - args.send_dts = false; - args.send_pts = true; - } - while (remaining_len) { available_space = TS_PAYLOAD_LEN; /* @@ -345,14 +350,14 @@ u32 vidtv_pes_write_into(struct pes_write_args args) * the space needed for the TS header _and_ for the PES header */ if (!wrote_pes_header) - available_space -= vidtv_pes_h_get_len(args.send_pts, - args.send_dts); + available_space -= vidtv_pes_h_get_len(args->send_pts, + args->send_dts); /* * if the encoder has inserted stuffing bytes in the PES * header, account for them. */ - available_space -= args.n_pes_h_s_bytes; + available_space -= args->n_pes_h_s_bytes; /* Take the extra adaptation into account if need to send PCR */ if (need_pcr) { @@ -387,14 +392,9 @@ u32 vidtv_pes_write_into(struct pes_write_args args) } /* write ts header */ - ts_header_args.dest_buf = args.dest_buf; - ts_header_args.dest_offset = args.dest_offset + nbytes; - ts_header_args.dest_buf_sz = args.dest_buf_sz; - ts_header_args.pid = args.pid; - ts_header_args.pcr = args.pcr; - ts_header_args.continuity_counter = args.continuity_counter; - ts_header_args.wrote_pes_header = wrote_pes_header; - ts_header_args.n_stuffing_bytes = stuff_bytes; + ts_header_args.dest_offset = args->dest_offset + nbytes; + ts_header_args.wrote_pes_header = wrote_pes_header; + ts_header_args.n_stuffing_bytes = stuff_bytes; nbytes += vidtv_pes_write_ts_h(ts_header_args, need_pcr, &last_pcr); @@ -403,33 +403,20 @@ u32 vidtv_pes_write_into(struct pes_write_args args) if (!wrote_pes_header) { /* write the PES header only once */ - pes_header_args.dest_buf = args.dest_buf; - - pes_header_args.dest_offset = args.dest_offset + - nbytes; - - pes_header_args.dest_buf_sz = args.dest_buf_sz; - pes_header_args.encoder_id = args.encoder_id; - pes_header_args.send_pts = args.send_pts; - pes_header_args.pts = args.pts; - pes_header_args.send_dts = args.send_dts; - pes_header_args.dts = args.dts; - pes_header_args.stream_id = args.stream_id; - pes_header_args.n_pes_h_s_bytes = args.n_pes_h_s_bytes; - pes_header_args.access_unit_len = args.access_unit_len; - - nbytes += vidtv_pes_write_h(pes_header_args); - wrote_pes_header = true; + pes_header_args.dest_offset = args->dest_offset + + nbytes; + nbytes += vidtv_pes_write_h(&pes_header_args); + wrote_pes_header = true; } /* write as much of the payload as we possibly can */ - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, - args.from, + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, + args->from, payload_size); - args.from += payload_size; + args->from += payload_size; remaining_len -= payload_size; } diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.h b/drivers/media/test-drivers/vidtv/vidtv_pes.h index 0ea9e863024d..963c59155e72 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_pes.h +++ b/drivers/media/test-drivers/vidtv/vidtv_pes.h @@ -14,7 +14,6 @@ #ifndef VIDTV_PES_H #define VIDTV_PES_H -#include <asm/byteorder.h> #include <linux/types.h> #include "vidtv_common.h" @@ -114,8 +113,10 @@ struct pes_header_write_args { * @dest_buf_sz: The size of the dest_buffer * @pid: The PID to use for the TS packets. * @continuity_counter: Incremented on every new TS packet. - * @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets + * @wrote_pes_header: Flag to indicate that the PES header was written + * @n_stuffing_bytes: Padding bytes. Might be used by an encoder if needed, gets * discarded by the decoder. + * @pcr: counter driven by a 27Mhz clock. */ struct pes_ts_header_write_args { void *dest_buf; @@ -146,6 +147,7 @@ struct pes_ts_header_write_args { * @dts: DTS value to send. * @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets * discarded by the decoder. + * @pcr: counter driven by a 27Mhz clock. */ struct pes_write_args { void *dest_buf; @@ -186,6 +188,6 @@ struct pes_write_args { * equal to the size of the access unit, since we need space for PES headers, TS headers * and padding bytes, if any. */ -u32 vidtv_pes_write_into(struct pes_write_args args); +u32 vidtv_pes_write_into(struct pes_write_args *args); #endif // VIDTV_PES_H diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index 82cf67dd27c0..4511a2a98405 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -6,31 +6,31 @@ * technically be broken into one or more sections, we do not do this here, * hence 'table' and 'section' are interchangeable for vidtv. * - * This code currently supports three tables: PAT, PMT and SDT. These are the - * bare minimum to get userspace to recognize our MPEG transport stream. It can - * be extended to support more PSI tables in the future. - * * Copyright (C) 2020 Daniel W. S. Almeida */ #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/slab.h> +#include <linux/bcd.h> #include <linux/crc32.h> -#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/printk.h> #include <linux/ratelimit.h> +#include <linux/slab.h> #include <linux/string.h> -#include <asm/byteorder.h> +#include <linux/string.h> +#include <linux/time.h> +#include <linux/types.h> -#include "vidtv_psi.h" #include "vidtv_common.h" +#include "vidtv_psi.h" #include "vidtv_ts.h" #define CRC_SIZE_IN_BYTES 4 #define MAX_VERSION_NUM 32 +#define INITIAL_CRC 0xffffffff +#define ISO_LANGUAGE_CODE_LEN 3 static const u32 CRC_LUT[256] = { /* from libdvbv5 */ @@ -79,7 +79,7 @@ static const u32 CRC_LUT[256] = { 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; -static inline u32 dvb_crc32(u32 crc, u8 *data, u32 len) +static u32 dvb_crc32(u32 crc, u8 *data, u32 len) { /* from libdvbv5 */ while (len--) @@ -92,40 +92,7 @@ static void vidtv_psi_update_version_num(struct vidtv_psi_table_header *h) h->version++; } -static inline u16 vidtv_psi_sdt_serv_get_desc_loop_len(struct vidtv_psi_table_sdt_service *s) -{ - u16 mask; - u16 ret; - - mask = GENMASK(11, 0); - - ret = be16_to_cpu(s->bitfield) & mask; - return ret; -} - -static inline u16 vidtv_psi_pmt_stream_get_desc_loop_len(struct vidtv_psi_table_pmt_stream *s) -{ - u16 mask; - u16 ret; - - mask = GENMASK(9, 0); - - ret = be16_to_cpu(s->bitfield2) & mask; - return ret; -} - -static inline u16 vidtv_psi_pmt_get_desc_loop_len(struct vidtv_psi_table_pmt *p) -{ - u16 mask; - u16 ret; - - mask = GENMASK(9, 0); - - ret = be16_to_cpu(p->bitfield2) & mask; - return ret; -} - -static inline u16 vidtv_psi_get_sec_len(struct vidtv_psi_table_header *h) +static u16 vidtv_psi_get_sec_len(struct vidtv_psi_table_header *h) { u16 mask; u16 ret; @@ -136,7 +103,7 @@ static inline u16 vidtv_psi_get_sec_len(struct vidtv_psi_table_header *h) return ret; } -inline u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p) +u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p) { u16 mask; u16 ret; @@ -147,7 +114,7 @@ inline u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p) return ret; } -inline u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s) +u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s) { u16 mask; u16 ret; @@ -158,10 +125,11 @@ inline u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream * return ret; } -static inline void vidtv_psi_set_desc_loop_len(__be16 *bitfield, u16 new_len, u8 desc_len_nbits) +static void vidtv_psi_set_desc_loop_len(__be16 *bitfield, u16 new_len, + u8 desc_len_nbits) { - u16 mask; __be16 new; + u16 mask; mask = GENMASK(15, desc_len_nbits); @@ -188,90 +156,81 @@ static void vidtv_psi_set_sec_len(struct vidtv_psi_table_header *h, u16 new_len) h->bitfield = new; } -static u32 vidtv_psi_ts_psi_write_into(struct psi_write_args args) +/* + * Packetize PSI sections into TS packets: + * push a TS header (4bytes) every 184 bytes + * manage the continuity_counter + * add stuffing (i.e. padding bytes) after the CRC + */ +static u32 vidtv_psi_ts_psi_write_into(struct psi_write_args *args) { - /* - * Packetize PSI sections into TS packets: - * push a TS header (4bytes) every 184 bytes - * manage the continuity_counter - * add stuffing (i.e. padding bytes) after the CRC - */ - - u32 nbytes_past_boundary = (args.dest_offset % TS_PACKET_LEN); + struct vidtv_mpeg_ts ts_header = { + .sync_byte = TS_SYNC_BYTE, + .bitfield = cpu_to_be16((args->new_psi_section << 14) | args->pid), + .scrambling = 0, + .payload = 1, + .adaptation_field = 0, /* no adaptation field */ + }; + u32 nbytes_past_boundary = (args->dest_offset % TS_PACKET_LEN); bool aligned = (nbytes_past_boundary == 0); - struct vidtv_mpeg_ts ts_header = {}; - - /* number of bytes written by this function */ - u32 nbytes = 0; - /* how much there is left to write */ - u32 remaining_len = args.len; - /* how much we can be written in this packet */ + u32 remaining_len = args->len; u32 payload_write_len = 0; - /* where we are in the source */ u32 payload_offset = 0; + u32 nbytes = 0; - const u16 PAYLOAD_START = args.new_psi_section; - - if (!args.crc && !args.is_crc) + if (!args->crc && !args->is_crc) pr_warn_ratelimited("Missing CRC for chunk\n"); - if (args.crc) - *args.crc = dvb_crc32(*args.crc, args.from, args.len); + if (args->crc) + *args->crc = dvb_crc32(*args->crc, args->from, args->len); - if (args.new_psi_section && !aligned) { + if (args->new_psi_section && !aligned) { pr_warn_ratelimited("Cannot write a new PSI section in a misaligned buffer\n"); /* forcibly align and hope for the best */ - nbytes += vidtv_memset(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + nbytes += vidtv_memset(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, TS_FILL_BYTE, TS_PACKET_LEN - nbytes_past_boundary); } while (remaining_len) { - nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN; + nbytes_past_boundary = (args->dest_offset + nbytes) % TS_PACKET_LEN; aligned = (nbytes_past_boundary == 0); if (aligned) { /* if at a packet boundary, write a new TS header */ - ts_header.sync_byte = TS_SYNC_BYTE; - ts_header.bitfield = cpu_to_be16((PAYLOAD_START << 14) | args.pid); - ts_header.scrambling = 0; - ts_header.continuity_counter = *args.continuity_counter; - ts_header.payload = 1; - /* no adaptation field */ - ts_header.adaptation_field = 0; - - /* copy the header */ - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + ts_header.continuity_counter = *args->continuity_counter; + + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, &ts_header, sizeof(ts_header)); /* * This will trigger a discontinuity if the buffer is full, * effectively dropping the packet. */ - vidtv_ts_inc_cc(args.continuity_counter); + vidtv_ts_inc_cc(args->continuity_counter); } /* write the pointer_field in the first byte of the payload */ - if (args.new_psi_section) - nbytes += vidtv_memset(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + if (args->new_psi_section) + nbytes += vidtv_memset(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, 0x0, 1); /* write as much of the payload as possible */ - nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN; + nbytes_past_boundary = (args->dest_offset + nbytes) % TS_PACKET_LEN; payload_write_len = min(TS_PACKET_LEN - nbytes_past_boundary, remaining_len); - nbytes += vidtv_memcpy(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, - args.from + payload_offset, + nbytes += vidtv_memcpy(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, + args->from + payload_offset, payload_write_len); /* 'payload_write_len' written from a total of 'len' requested*/ @@ -283,37 +242,45 @@ static u32 vidtv_psi_ts_psi_write_into(struct psi_write_args args) * fill the rest of the packet if there is any remaining space unused */ - nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN; + nbytes_past_boundary = (args->dest_offset + nbytes) % TS_PACKET_LEN; - if (args.is_crc) - nbytes += vidtv_memset(args.dest_buf, - args.dest_offset + nbytes, - args.dest_buf_sz, + if (args->is_crc) + nbytes += vidtv_memset(args->dest_buf, + args->dest_offset + nbytes, + args->dest_buf_sz, TS_FILL_BYTE, TS_PACKET_LEN - nbytes_past_boundary); return nbytes; } -static u32 table_section_crc32_write_into(struct crc32_write_args args) +static u32 table_section_crc32_write_into(struct crc32_write_args *args) { + struct psi_write_args psi_args = { + .dest_buf = args->dest_buf, + .from = &args->crc, + .len = CRC_SIZE_IN_BYTES, + .dest_offset = args->dest_offset, + .pid = args->pid, + .new_psi_section = false, + .continuity_counter = args->continuity_counter, + .is_crc = true, + .dest_buf_sz = args->dest_buf_sz, + }; + /* the CRC is the last entry in the section */ - u32 nbytes = 0; - struct psi_write_args psi_args = {}; - psi_args.dest_buf = args.dest_buf; - psi_args.from = &args.crc; - psi_args.len = CRC_SIZE_IN_BYTES; - psi_args.dest_offset = args.dest_offset; - psi_args.pid = args.pid; - psi_args.new_psi_section = false; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = true; - psi_args.dest_buf_sz = args.dest_buf_sz; + return vidtv_psi_ts_psi_write_into(&psi_args); +} - nbytes += vidtv_psi_ts_psi_write_into(psi_args); +static void vidtv_psi_desc_chain(struct vidtv_psi_desc *head, struct vidtv_psi_desc *desc) +{ + if (head) { + while (head->next) + head = head->next; - return nbytes; + head->next = desc; + } } struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc *head, @@ -326,6 +293,8 @@ struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc u32 provider_name_len = provider_name ? strlen(provider_name) : 0; desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; desc->type = SERVICE_DESCRIPTOR; @@ -347,12 +316,7 @@ struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc if (provider_name && provider_name_len) desc->provider_name = kstrdup(provider_name, GFP_KERNEL); - if (head) { - while (head->next) - head = head->next; - - head->next = (struct vidtv_psi_desc *)desc; - } + vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); return desc; } @@ -365,6 +329,8 @@ struct vidtv_psi_desc_registration struct vidtv_psi_desc_registration *desc; desc = kzalloc(sizeof(*desc) + sizeof(format_id) + additional_info_len, GFP_KERNEL); + if (!desc) + return NULL; desc->type = REGISTRATION_DESCRIPTOR; @@ -378,44 +344,178 @@ struct vidtv_psi_desc_registration additional_ident_info, additional_info_len); - if (head) { - while (head->next) - head = head->next; + vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); + return desc; +} - head->next = (struct vidtv_psi_desc *)desc; +struct vidtv_psi_desc_network_name +*vidtv_psi_network_name_desc_init(struct vidtv_psi_desc *head, char *network_name) +{ + u32 network_name_len = network_name ? strlen(network_name) : 0; + struct vidtv_psi_desc_network_name *desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + desc->type = NETWORK_NAME_DESCRIPTOR; + + desc->length = network_name_len; + + if (network_name && network_name_len) + desc->network_name = kstrdup(network_name, GFP_KERNEL); + + vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); + return desc; +} + +struct vidtv_psi_desc_service_list +*vidtv_psi_service_list_desc_init(struct vidtv_psi_desc *head, + struct vidtv_psi_desc_service_list_entry *entry) +{ + struct vidtv_psi_desc_service_list_entry *curr_e = NULL; + struct vidtv_psi_desc_service_list_entry *head_e = NULL; + struct vidtv_psi_desc_service_list_entry *prev_e = NULL; + struct vidtv_psi_desc_service_list *desc; + u16 length = 0; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + desc->type = SERVICE_LIST_DESCRIPTOR; + + while (entry) { + curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL); + if (!curr_e) { + while (head_e) { + curr_e = head_e; + head_e = head_e->next; + kfree(curr_e); + } + kfree(desc); + return NULL; + } + + curr_e->service_id = entry->service_id; + curr_e->service_type = entry->service_type; + + length += sizeof(struct vidtv_psi_desc_service_list_entry) - + sizeof(struct vidtv_psi_desc_service_list_entry *); + + if (!head_e) + head_e = curr_e; + if (prev_e) + prev_e->next = curr_e; + + prev_e = curr_e; + entry = entry->next; } + desc->length = length; + desc->service_list = head_e; + + vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); + return desc; +} + +struct vidtv_psi_desc_short_event +*vidtv_psi_short_event_desc_init(struct vidtv_psi_desc *head, + char *iso_language_code, + char *event_name, + char *text) +{ + u32 iso_len = iso_language_code ? strlen(iso_language_code) : 0; + u32 event_name_len = event_name ? strlen(event_name) : 0; + struct vidtv_psi_desc_short_event *desc; + u32 text_len = text ? strlen(text) : 0; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + desc->type = SHORT_EVENT_DESCRIPTOR; + + desc->length = ISO_LANGUAGE_CODE_LEN + + sizeof_field(struct vidtv_psi_desc_short_event, event_name_len) + + event_name_len + + sizeof_field(struct vidtv_psi_desc_short_event, text_len) + + text_len; + + desc->event_name_len = event_name_len; + desc->text_len = text_len; + + if (iso_len != ISO_LANGUAGE_CODE_LEN) + iso_language_code = "eng"; + + desc->iso_language_code = kstrdup(iso_language_code, GFP_KERNEL); + + if (event_name && event_name_len) + desc->event_name = kstrdup(event_name, GFP_KERNEL); + + if (text && text_len) + desc->text = kstrdup(text, GFP_KERNEL); + + vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); return desc; } struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc) { + struct vidtv_psi_desc_network_name *desc_network_name; + struct vidtv_psi_desc_service_list *desc_service_list; + struct vidtv_psi_desc_short_event *desc_short_event; + struct vidtv_psi_desc_service *service; struct vidtv_psi_desc *head = NULL; struct vidtv_psi_desc *prev = NULL; struct vidtv_psi_desc *curr = NULL; - struct vidtv_psi_desc_service *service; - while (desc) { switch (desc->type) { case SERVICE_DESCRIPTOR: service = (struct vidtv_psi_desc_service *)desc; curr = (struct vidtv_psi_desc *) - vidtv_psi_service_desc_init(head, - service->service_type, - service->service_name, - service->provider_name); + vidtv_psi_service_desc_init(head, + service->service_type, + service->service_name, + service->provider_name); + break; + + case NETWORK_NAME_DESCRIPTOR: + desc_network_name = (struct vidtv_psi_desc_network_name *)desc; + curr = (struct vidtv_psi_desc *) + vidtv_psi_network_name_desc_init(head, + desc_network_name->network_name); + break; + + case SERVICE_LIST_DESCRIPTOR: + desc_service_list = (struct vidtv_psi_desc_service_list *)desc; + curr = (struct vidtv_psi_desc *) + vidtv_psi_service_list_desc_init(head, + desc_service_list->service_list); + break; + + case SHORT_EVENT_DESCRIPTOR: + desc_short_event = (struct vidtv_psi_desc_short_event *)desc; + curr = (struct vidtv_psi_desc *) + vidtv_psi_short_event_desc_init(head, + desc_short_event->iso_language_code, + desc_short_event->event_name, + desc_short_event->text); break; case REGISTRATION_DESCRIPTOR: default: curr = kzalloc(sizeof(*desc) + desc->length, GFP_KERNEL); + if (!curr) + return NULL; memcpy(curr, desc, sizeof(*desc) + desc->length); - break; - } + } - if (curr) - curr->next = NULL; + if (!curr) + return NULL; + + curr->next = NULL; if (!head) head = curr; if (prev) @@ -430,6 +530,8 @@ struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc) void vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc) { + struct vidtv_psi_desc_service_list_entry *sl_entry_tmp = NULL; + struct vidtv_psi_desc_service_list_entry *sl_entry = NULL; struct vidtv_psi_desc *curr = desc; struct vidtv_psi_desc *tmp = NULL; @@ -447,6 +549,25 @@ void vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc) /* nothing to do */ break; + case NETWORK_NAME_DESCRIPTOR: + kfree(((struct vidtv_psi_desc_network_name *)tmp)->network_name); + break; + + case SERVICE_LIST_DESCRIPTOR: + sl_entry = ((struct vidtv_psi_desc_service_list *)tmp)->service_list; + while (sl_entry) { + sl_entry_tmp = sl_entry; + sl_entry = sl_entry->next; + kfree(sl_entry_tmp); + } + break; + + case SHORT_EVENT_DESCRIPTOR: + kfree(((struct vidtv_psi_desc_short_event *)tmp)->iso_language_code); + kfree(((struct vidtv_psi_desc_short_event *)tmp)->event_name); + kfree(((struct vidtv_psi_desc_short_event *)tmp)->text); + break; + default: pr_warn_ratelimited("Possible leak: not handling descriptor type %d\n", tmp->type); @@ -513,63 +634,119 @@ void vidtv_sdt_desc_assign(struct vidtv_psi_table_sdt *sdt, vidtv_psi_update_version_num(&sdt->header); } -static u32 vidtv_psi_desc_write_into(struct desc_write_args args) +static u32 vidtv_psi_desc_write_into(struct desc_write_args *args) { - /* the number of bytes written by this function */ + struct psi_write_args psi_args = { + .dest_buf = args->dest_buf, + .from = &args->desc->type, + .pid = args->pid, + .new_psi_section = false, + .continuity_counter = args->continuity_counter, + .is_crc = false, + .dest_buf_sz = args->dest_buf_sz, + .crc = args->crc, + .len = sizeof_field(struct vidtv_psi_desc, type) + + sizeof_field(struct vidtv_psi_desc, length), + }; + struct vidtv_psi_desc_service_list_entry *serv_list_entry = NULL; u32 nbytes = 0; - struct psi_write_args psi_args = {}; - - psi_args.dest_buf = args.dest_buf; - psi_args.from = &args.desc->type; - psi_args.len = sizeof_field(struct vidtv_psi_desc, type) + - sizeof_field(struct vidtv_psi_desc, length); + psi_args.dest_offset = args->dest_offset + nbytes; - psi_args.dest_offset = args.dest_offset + nbytes; - psi_args.pid = args.pid; - psi_args.new_psi_section = false; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = false; - psi_args.dest_buf_sz = args.dest_buf_sz; - psi_args.crc = args.crc; + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - nbytes += vidtv_psi_ts_psi_write_into(psi_args); - - switch (args.desc->type) { + switch (args->desc->type) { case SERVICE_DESCRIPTOR: - psi_args.dest_offset = args.dest_offset + nbytes; + psi_args.dest_offset = args->dest_offset + nbytes; psi_args.len = sizeof_field(struct vidtv_psi_desc_service, service_type) + sizeof_field(struct vidtv_psi_desc_service, provider_name_len); - psi_args.from = &((struct vidtv_psi_desc_service *)args.desc)->service_type; + psi_args.from = &((struct vidtv_psi_desc_service *)args->desc)->service_type; - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - psi_args.dest_offset = args.dest_offset + nbytes; - psi_args.len = ((struct vidtv_psi_desc_service *)args.desc)->provider_name_len; - psi_args.from = ((struct vidtv_psi_desc_service *)args.desc)->provider_name; + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = ((struct vidtv_psi_desc_service *)args->desc)->provider_name_len; + psi_args.from = ((struct vidtv_psi_desc_service *)args->desc)->provider_name; - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - psi_args.dest_offset = args.dest_offset + nbytes; + psi_args.dest_offset = args->dest_offset + nbytes; psi_args.len = sizeof_field(struct vidtv_psi_desc_service, service_name_len); - psi_args.from = &((struct vidtv_psi_desc_service *)args.desc)->service_name_len; + psi_args.from = &((struct vidtv_psi_desc_service *)args->desc)->service_name_len; - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - psi_args.dest_offset = args.dest_offset + nbytes; - psi_args.len = ((struct vidtv_psi_desc_service *)args.desc)->service_name_len; - psi_args.from = ((struct vidtv_psi_desc_service *)args.desc)->service_name; + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = ((struct vidtv_psi_desc_service *)args->desc)->service_name_len; + psi_args.from = ((struct vidtv_psi_desc_service *)args->desc)->service_name; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + break; + + case NETWORK_NAME_DESCRIPTOR: + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = args->desc->length; + psi_args.from = ((struct vidtv_psi_desc_network_name *)args->desc)->network_name; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + break; + + case SERVICE_LIST_DESCRIPTOR: + serv_list_entry = ((struct vidtv_psi_desc_service_list *)args->desc)->service_list; + while (serv_list_entry) { + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = sizeof(struct vidtv_psi_desc_service_list_entry) - + sizeof(struct vidtv_psi_desc_service_list_entry *); + psi_args.from = serv_list_entry; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + serv_list_entry = serv_list_entry->next; + } + break; + + case SHORT_EVENT_DESCRIPTOR: + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = ISO_LANGUAGE_CODE_LEN; + psi_args.from = ((struct vidtv_psi_desc_short_event *) + args->desc)->iso_language_code; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = sizeof_field(struct vidtv_psi_desc_short_event, event_name_len); + psi_args.from = &((struct vidtv_psi_desc_short_event *) + args->desc)->event_name_len; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = ((struct vidtv_psi_desc_short_event *)args->desc)->event_name_len; + psi_args.from = ((struct vidtv_psi_desc_short_event *)args->desc)->event_name; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = sizeof_field(struct vidtv_psi_desc_short_event, text_len); + psi_args.from = &((struct vidtv_psi_desc_short_event *)args->desc)->text_len; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = ((struct vidtv_psi_desc_short_event *)args->desc)->text_len; + psi_args.from = ((struct vidtv_psi_desc_short_event *)args->desc)->text; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - nbytes += vidtv_psi_ts_psi_write_into(psi_args); break; case REGISTRATION_DESCRIPTOR: default: - psi_args.dest_offset = args.dest_offset + nbytes; - psi_args.len = args.desc->length; - psi_args.from = &args.desc->data; + psi_args.dest_offset = args->dest_offset + nbytes; + psi_args.len = args->desc->length; + psi_args.from = &args->desc->data; - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); break; } @@ -577,40 +754,37 @@ static u32 vidtv_psi_desc_write_into(struct desc_write_args args) } static u32 -vidtv_psi_table_header_write_into(struct header_write_args args) +vidtv_psi_table_header_write_into(struct header_write_args *args) { - /* the number of bytes written by this function */ - u32 nbytes = 0; - struct psi_write_args psi_args = {}; - - psi_args.dest_buf = args.dest_buf; - psi_args.from = args.h; - psi_args.len = sizeof(struct vidtv_psi_table_header); - psi_args.dest_offset = args.dest_offset; - psi_args.pid = args.pid; - psi_args.new_psi_section = true; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = false; - psi_args.dest_buf_sz = args.dest_buf_sz; - psi_args.crc = args.crc; - - nbytes += vidtv_psi_ts_psi_write_into(psi_args); - - return nbytes; + struct psi_write_args psi_args = { + .dest_buf = args->dest_buf, + .from = args->h, + .len = sizeof(struct vidtv_psi_table_header), + .dest_offset = args->dest_offset, + .pid = args->pid, + .new_psi_section = true, + .continuity_counter = args->continuity_counter, + .is_crc = false, + .dest_buf_sz = args->dest_buf_sz, + .crc = args->crc, + }; + + return vidtv_psi_ts_psi_write_into(&psi_args); } void vidtv_psi_pat_table_update_sec_len(struct vidtv_psi_table_pat *pat) { - /* see ISO/IEC 13818-1 : 2000 p.43 */ u16 length = 0; u32 i; + /* see ISO/IEC 13818-1 : 2000 p.43 */ + /* from immediately after 'section_length' until 'last_section_number'*/ length += PAT_LEN_UNTIL_LAST_SECTION_NUMBER; /* do not count the pointer */ - for (i = 0; i < pat->programs; ++i) + for (i = 0; i < pat->num_pat; ++i) length += sizeof(struct vidtv_psi_table_pat_program) - sizeof(struct vidtv_psi_table_pat_program *); @@ -621,10 +795,11 @@ vidtv_psi_pat_table_update_sec_len(struct vidtv_psi_table_pat *pat) void vidtv_psi_pmt_table_update_sec_len(struct vidtv_psi_table_pmt *pmt) { - /* see ISO/IEC 13818-1 : 2000 p.46 */ - u16 length = 0; struct vidtv_psi_table_pmt_stream *s = pmt->stream; u16 desc_loop_len; + u16 length = 0; + + /* see ISO/IEC 13818-1 : 2000 p.46 */ /* from immediately after 'section_length' until 'program_info_length'*/ length += PMT_LEN_UNTIL_PROGRAM_INFO_LENGTH; @@ -655,10 +830,11 @@ void vidtv_psi_pmt_table_update_sec_len(struct vidtv_psi_table_pmt *pmt) void vidtv_psi_sdt_table_update_sec_len(struct vidtv_psi_table_sdt *sdt) { - /* see ETSI EN 300 468 V 1.10.1 p.24 */ - u16 length = 0; struct vidtv_psi_table_sdt_service *s = sdt->service; u16 desc_loop_len; + u16 length = 0; + + /* see ETSI EN 300 468 V 1.10.1 p.24 */ /* * from immediately after 'section_length' until @@ -681,7 +857,6 @@ void vidtv_psi_sdt_table_update_sec_len(struct vidtv_psi_table_sdt *sdt) } length += CRC_SIZE_IN_BYTES; - vidtv_psi_set_sec_len(&sdt->header, length); } @@ -694,6 +869,8 @@ vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head, const u16 RESERVED = 0x07; program = kzalloc(sizeof(*program), GFP_KERNEL); + if (!program) + return NULL; program->service_id = cpu_to_be16(service_id); @@ -714,8 +891,8 @@ vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head, void vidtv_psi_pat_program_destroy(struct vidtv_psi_table_pat_program *p) { - struct vidtv_psi_table_pat_program *curr = p; struct vidtv_psi_table_pat_program *tmp = NULL; + struct vidtv_psi_table_pat_program *curr = p; while (curr) { tmp = curr; @@ -724,42 +901,49 @@ vidtv_psi_pat_program_destroy(struct vidtv_psi_table_pat_program *p) } } +/* This function transfers ownership of p to the table */ void vidtv_psi_pat_program_assign(struct vidtv_psi_table_pat *pat, struct vidtv_psi_table_pat_program *p) { - /* This function transfers ownership of p to the table */ + struct vidtv_psi_table_pat_program *program; + u16 program_count; - u16 program_count = 0; - struct vidtv_psi_table_pat_program *program = p; + do { + program_count = 0; + program = p; - if (p == pat->program) - return; + if (p == pat->program) + return; - while (program) { - ++program_count; - program = program->next; - } + while (program) { + ++program_count; + program = program->next; + } - pat->programs = program_count; - pat->program = p; + pat->num_pat = program_count; + pat->program = p; - /* Recompute section length */ - vidtv_psi_pat_table_update_sec_len(pat); + /* Recompute section length */ + vidtv_psi_pat_table_update_sec_len(pat); - if (vidtv_psi_get_sec_len(&pat->header) > MAX_SECTION_LEN) - vidtv_psi_pat_program_assign(pat, NULL); + p = NULL; + } while (vidtv_psi_get_sec_len(&pat->header) > MAX_SECTION_LEN); vidtv_psi_update_version_num(&pat->header); } struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id) { - struct vidtv_psi_table_pat *pat = kzalloc(sizeof(*pat), GFP_KERNEL); + struct vidtv_psi_table_pat *pat; const u16 SYNTAX = 0x1; const u16 ZERO = 0x0; const u16 ONES = 0x03; + pat = kzalloc(sizeof(*pat), GFP_KERNEL); + if (!pat) + return NULL; + pat->header.table_id = 0x0; pat->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ZERO << 14) | (ONES << 12)); @@ -772,70 +956,68 @@ struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id) pat->header.section_id = 0x0; pat->header.last_section = 0x0; - pat->programs = 0; - vidtv_psi_pat_table_update_sec_len(pat); return pat; } -u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args args) +u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args *args) { - /* the number of bytes written by this function */ + struct vidtv_psi_table_pat_program *p = args->pat->program; + struct header_write_args h_args = { + .dest_buf = args->buf, + .dest_offset = args->offset, + .pid = VIDTV_PAT_PID, + .h = &args->pat->header, + .continuity_counter = args->continuity_counter, + .dest_buf_sz = args->buf_sz, + }; + struct psi_write_args psi_args = { + .dest_buf = args->buf, + .pid = VIDTV_PAT_PID, + .new_psi_section = false, + .continuity_counter = args->continuity_counter, + .is_crc = false, + .dest_buf_sz = args->buf_sz, + }; + struct crc32_write_args c_args = { + .dest_buf = args->buf, + .pid = VIDTV_PAT_PID, + .dest_buf_sz = args->buf_sz, + }; + u32 crc = INITIAL_CRC; u32 nbytes = 0; - const u16 pat_pid = VIDTV_PAT_PID; - u32 crc = 0xffffffff; - - struct vidtv_psi_table_pat_program *p = args.pat->program; - struct header_write_args h_args = {}; - struct psi_write_args psi_args = {}; - struct crc32_write_args c_args = {}; + vidtv_psi_pat_table_update_sec_len(args->pat); - vidtv_psi_pat_table_update_sec_len(args.pat); - - h_args.dest_buf = args.buf; - h_args.dest_offset = args.offset; - h_args.h = &args.pat->header; - h_args.pid = pat_pid; - h_args.continuity_counter = args.continuity_counter; - h_args.dest_buf_sz = args.buf_sz; h_args.crc = &crc; - nbytes += vidtv_psi_table_header_write_into(h_args); + nbytes += vidtv_psi_table_header_write_into(&h_args); /* note that the field 'u16 programs' is not really part of the PAT */ - psi_args.dest_buf = args.buf; - psi_args.pid = pat_pid; - psi_args.new_psi_section = false; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = false; - psi_args.dest_buf_sz = args.buf_sz; - psi_args.crc = &crc; + psi_args.crc = &crc; while (p) { /* copy the PAT programs */ psi_args.from = p; /* skip the pointer */ psi_args.len = sizeof(*p) - - sizeof(struct vidtv_psi_table_pat_program *); - psi_args.dest_offset = args.offset + nbytes; + sizeof(struct vidtv_psi_table_pat_program *); + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); p = p->next; } - c_args.dest_buf = args.buf; - c_args.dest_offset = args.offset + nbytes; + c_args.dest_offset = args->offset + nbytes; + c_args.continuity_counter = args->continuity_counter; c_args.crc = cpu_to_be32(crc); - c_args.pid = pat_pid; - c_args.continuity_counter = args.continuity_counter; - c_args.dest_buf_sz = args.buf_sz; /* Write the CRC32 at the end */ - nbytes += table_section_crc32_write_into(c_args); + nbytes += table_section_crc32_write_into(&c_args); return nbytes; } @@ -859,6 +1041,8 @@ vidtv_psi_pmt_stream_init(struct vidtv_psi_table_pmt_stream *head, u16 desc_loop_len; stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return NULL; stream->type = stream_type; @@ -883,8 +1067,8 @@ vidtv_psi_pmt_stream_init(struct vidtv_psi_table_pmt_stream *head, void vidtv_psi_pmt_stream_destroy(struct vidtv_psi_table_pmt_stream *s) { - struct vidtv_psi_table_pmt_stream *curr_stream = s; struct vidtv_psi_table_pmt_stream *tmp_stream = NULL; + struct vidtv_psi_table_pmt_stream *curr_stream = s; while (curr_stream) { tmp_stream = curr_stream; @@ -897,15 +1081,16 @@ void vidtv_psi_pmt_stream_destroy(struct vidtv_psi_table_pmt_stream *s) void vidtv_psi_pmt_stream_assign(struct vidtv_psi_table_pmt *pmt, struct vidtv_psi_table_pmt_stream *s) { - /* This function transfers ownership of s to the table */ - if (s == pmt->stream) - return; + do { + /* This function transfers ownership of s to the table */ + if (s == pmt->stream) + return; - pmt->stream = s; - vidtv_psi_pmt_table_update_sec_len(pmt); + pmt->stream = s; + vidtv_psi_pmt_table_update_sec_len(pmt); - if (vidtv_psi_get_sec_len(&pmt->header) > MAX_SECTION_LEN) - vidtv_psi_pmt_stream_assign(pmt, NULL); + s = NULL; + } while (vidtv_psi_get_sec_len(&pmt->header) > MAX_SECTION_LEN); vidtv_psi_update_version_num(&pmt->header); } @@ -933,14 +1118,18 @@ u16 vidtv_psi_pmt_get_pid(struct vidtv_psi_table_pmt *section, struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number, u16 pcr_pid) { - struct vidtv_psi_table_pmt *pmt = kzalloc(sizeof(*pmt), GFP_KERNEL); - const u16 SYNTAX = 0x1; - const u16 ZERO = 0x0; - const u16 ONES = 0x03; + struct vidtv_psi_table_pmt *pmt; const u16 RESERVED1 = 0x07; const u16 RESERVED2 = 0x0f; + const u16 SYNTAX = 0x1; + const u16 ONES = 0x03; + const u16 ZERO = 0x0; u16 desc_loop_len; + pmt = kzalloc(sizeof(*pmt), GFP_KERNEL); + if (!pmt) + return NULL; + if (!pcr_pid) pcr_pid = 0x1fff; @@ -970,87 +1159,84 @@ struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number, return pmt; } -u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args) +u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args *args) { - /* the number of bytes written by this function */ + struct vidtv_psi_desc *table_descriptor = args->pmt->descriptor; + struct vidtv_psi_table_pmt_stream *stream = args->pmt->stream; + struct vidtv_psi_desc *stream_descriptor; + struct header_write_args h_args = { + .dest_buf = args->buf, + .dest_offset = args->offset, + .h = &args->pmt->header, + .pid = args->pid, + .continuity_counter = args->continuity_counter, + .dest_buf_sz = args->buf_sz, + }; + struct psi_write_args psi_args = { + .dest_buf = args->buf, + .from = &args->pmt->bitfield, + .len = sizeof_field(struct vidtv_psi_table_pmt, bitfield) + + sizeof_field(struct vidtv_psi_table_pmt, bitfield2), + .pid = args->pid, + .new_psi_section = false, + .is_crc = false, + .dest_buf_sz = args->buf_sz, + }; + struct desc_write_args d_args = { + .dest_buf = args->buf, + .desc = table_descriptor, + .pid = args->pid, + .dest_buf_sz = args->buf_sz, + }; + struct crc32_write_args c_args = { + .dest_buf = args->buf, + .pid = args->pid, + .dest_buf_sz = args->buf_sz, + }; + u32 crc = INITIAL_CRC; u32 nbytes = 0; - u32 crc = 0xffffffff; - - struct vidtv_psi_desc *table_descriptor = args.pmt->descriptor; - struct vidtv_psi_table_pmt_stream *stream = args.pmt->stream; - struct vidtv_psi_desc *stream_descriptor = (stream) ? - args.pmt->stream->descriptor : - NULL; - - struct header_write_args h_args = {}; - struct psi_write_args psi_args = {}; - struct desc_write_args d_args = {}; - struct crc32_write_args c_args = {}; - - vidtv_psi_pmt_table_update_sec_len(args.pmt); - - h_args.dest_buf = args.buf; - h_args.dest_offset = args.offset; - h_args.h = &args.pmt->header; - h_args.pid = args.pid; - h_args.continuity_counter = args.continuity_counter; - h_args.dest_buf_sz = args.buf_sz; + + vidtv_psi_pmt_table_update_sec_len(args->pmt); + h_args.crc = &crc; - nbytes += vidtv_psi_table_header_write_into(h_args); + nbytes += vidtv_psi_table_header_write_into(&h_args); /* write the two bitfields */ - psi_args.dest_buf = args.buf; - psi_args.from = &args.pmt->bitfield; - psi_args.len = sizeof_field(struct vidtv_psi_table_pmt, bitfield) + - sizeof_field(struct vidtv_psi_table_pmt, bitfield2); - - psi_args.dest_offset = args.offset + nbytes; - psi_args.pid = args.pid; - psi_args.new_psi_section = false; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = false; - psi_args.dest_buf_sz = args.buf_sz; - psi_args.crc = &crc; - - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); while (table_descriptor) { /* write the descriptors, if any */ - d_args.dest_buf = args.buf; - d_args.dest_offset = args.offset + nbytes; - d_args.desc = table_descriptor; - d_args.pid = args.pid; - d_args.continuity_counter = args.continuity_counter; - d_args.dest_buf_sz = args.buf_sz; + d_args.dest_offset = args->offset + nbytes; + d_args.continuity_counter = args->continuity_counter; d_args.crc = &crc; - nbytes += vidtv_psi_desc_write_into(d_args); + nbytes += vidtv_psi_desc_write_into(&d_args); table_descriptor = table_descriptor->next; } + psi_args.len += sizeof_field(struct vidtv_psi_table_pmt_stream, type); while (stream) { /* write the streams, if any */ psi_args.from = stream; - psi_args.len = sizeof_field(struct vidtv_psi_table_pmt_stream, type) + - sizeof_field(struct vidtv_psi_table_pmt_stream, bitfield) + - sizeof_field(struct vidtv_psi_table_pmt_stream, bitfield2); - psi_args.dest_offset = args.offset + nbytes; + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + stream_descriptor = stream->descriptor; while (stream_descriptor) { /* write the stream descriptors, if any */ - d_args.dest_buf = args.buf; - d_args.dest_offset = args.offset + nbytes; + d_args.dest_offset = args->offset + nbytes; d_args.desc = stream_descriptor; - d_args.pid = args.pid; - d_args.continuity_counter = args.continuity_counter; - d_args.dest_buf_sz = args.buf_sz; + d_args.continuity_counter = args->continuity_counter; d_args.crc = &crc; - nbytes += vidtv_psi_desc_write_into(d_args); + nbytes += vidtv_psi_desc_write_into(&d_args); stream_descriptor = stream_descriptor->next; } @@ -1058,15 +1244,12 @@ u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args) stream = stream->next; } - c_args.dest_buf = args.buf; - c_args.dest_offset = args.offset + nbytes; + c_args.dest_offset = args->offset + nbytes; c_args.crc = cpu_to_be32(crc); - c_args.pid = args.pid; - c_args.continuity_counter = args.continuity_counter; - c_args.dest_buf_sz = args.buf_sz; + c_args.continuity_counter = args->continuity_counter; /* Write the CRC32 at the end */ - nbytes += table_section_crc32_write_into(c_args); + nbytes += table_section_crc32_write_into(&c_args); return nbytes; } @@ -1078,16 +1261,20 @@ void vidtv_psi_pmt_table_destroy(struct vidtv_psi_table_pmt *pmt) kfree(pmt); } -struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id) +struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 network_id, + u16 transport_stream_id) { - struct vidtv_psi_table_sdt *sdt = kzalloc(sizeof(*sdt), GFP_KERNEL); + struct vidtv_psi_table_sdt *sdt; + const u16 RESERVED = 0xff; const u16 SYNTAX = 0x1; - const u16 ONE = 0x1; const u16 ONES = 0x03; - const u16 RESERVED = 0xff; + const u16 ONE = 0x1; - sdt->header.table_id = 0x42; + sdt = kzalloc(sizeof(*sdt), GFP_KERNEL); + if (!sdt) + return NULL; + sdt->header.table_id = 0x42; sdt->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ONE << 14) | (ONES << 12)); /* @@ -1111,7 +1298,7 @@ struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id) * This can be changed to something more useful, when support for * NIT gets added */ - sdt->network_id = cpu_to_be16(0xff01); + sdt->network_id = cpu_to_be16(network_id); sdt->reserved = RESERVED; vidtv_psi_sdt_table_update_sec_len(sdt); @@ -1119,74 +1306,79 @@ struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id) return sdt; } -u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args) +u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args *args) { + struct header_write_args h_args = { + .dest_buf = args->buf, + .dest_offset = args->offset, + .h = &args->sdt->header, + .pid = VIDTV_SDT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct psi_write_args psi_args = { + .dest_buf = args->buf, + .len = sizeof_field(struct vidtv_psi_table_sdt, network_id) + + sizeof_field(struct vidtv_psi_table_sdt, reserved), + .pid = VIDTV_SDT_PID, + .new_psi_section = false, + .is_crc = false, + .dest_buf_sz = args->buf_sz, + }; + struct desc_write_args d_args = { + .dest_buf = args->buf, + .pid = VIDTV_SDT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct crc32_write_args c_args = { + .dest_buf = args->buf, + .pid = VIDTV_SDT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct vidtv_psi_table_sdt_service *service = args->sdt->service; + struct vidtv_psi_desc *service_desc; u32 nbytes = 0; - u16 sdt_pid = VIDTV_SDT_PID; /* see ETSI EN 300 468 v1.15.1 p. 11 */ + u32 crc = INITIAL_CRC; - u32 crc = 0xffffffff; + /* see ETSI EN 300 468 v1.15.1 p. 11 */ - struct vidtv_psi_table_sdt_service *service = args.sdt->service; - struct vidtv_psi_desc *service_desc = (args.sdt->service) ? - args.sdt->service->descriptor : - NULL; + vidtv_psi_sdt_table_update_sec_len(args->sdt); - struct header_write_args h_args = {}; - struct psi_write_args psi_args = {}; - struct desc_write_args d_args = {}; - struct crc32_write_args c_args = {}; - - vidtv_psi_sdt_table_update_sec_len(args.sdt); - - h_args.dest_buf = args.buf; - h_args.dest_offset = args.offset; - h_args.h = &args.sdt->header; - h_args.pid = sdt_pid; - h_args.continuity_counter = args.continuity_counter; - h_args.dest_buf_sz = args.buf_sz; + h_args.continuity_counter = args->continuity_counter; h_args.crc = &crc; - nbytes += vidtv_psi_table_header_write_into(h_args); - - psi_args.dest_buf = args.buf; - psi_args.from = &args.sdt->network_id; + nbytes += vidtv_psi_table_header_write_into(&h_args); - psi_args.len = sizeof_field(struct vidtv_psi_table_sdt, network_id) + - sizeof_field(struct vidtv_psi_table_sdt, reserved); - - psi_args.dest_offset = args.offset + nbytes; - psi_args.pid = sdt_pid; - psi_args.new_psi_section = false; - psi_args.continuity_counter = args.continuity_counter; - psi_args.is_crc = false; - psi_args.dest_buf_sz = args.buf_sz; + psi_args.from = &args->sdt->network_id; + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; psi_args.crc = &crc; /* copy u16 network_id + u8 reserved)*/ - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + /* skip both pointers at the end */ + psi_args.len = sizeof(struct vidtv_psi_table_sdt_service) - + sizeof(struct vidtv_psi_desc *) - + sizeof(struct vidtv_psi_table_sdt_service *); while (service) { /* copy the services, if any */ psi_args.from = service; - /* skip both pointers at the end */ - psi_args.len = sizeof(struct vidtv_psi_table_sdt_service) - - sizeof(struct vidtv_psi_desc *) - - sizeof(struct vidtv_psi_table_sdt_service *); - psi_args.dest_offset = args.offset + nbytes; + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); - nbytes += vidtv_psi_ts_psi_write_into(psi_args); + service_desc = service->descriptor; while (service_desc) { /* copy the service descriptors, if any */ - d_args.dest_buf = args.buf; - d_args.dest_offset = args.offset + nbytes; + d_args.dest_offset = args->offset + nbytes; d_args.desc = service_desc; - d_args.pid = sdt_pid; - d_args.continuity_counter = args.continuity_counter; - d_args.dest_buf_sz = args.buf_sz; + d_args.continuity_counter = args->continuity_counter; d_args.crc = &crc; - nbytes += vidtv_psi_desc_write_into(d_args); + nbytes += vidtv_psi_desc_write_into(&d_args); service_desc = service_desc->next; } @@ -1194,15 +1386,12 @@ u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args) service = service->next; } - c_args.dest_buf = args.buf; - c_args.dest_offset = args.offset + nbytes; + c_args.dest_offset = args->offset + nbytes; c_args.crc = cpu_to_be32(crc); - c_args.pid = sdt_pid; - c_args.continuity_counter = args.continuity_counter; - c_args.dest_buf_sz = args.buf_sz; + c_args.continuity_counter = args->continuity_counter; /* Write the CRC at the end */ - nbytes += table_section_crc32_write_into(c_args); + nbytes += table_section_crc32_write_into(&c_args); return nbytes; } @@ -1215,11 +1404,15 @@ void vidtv_psi_sdt_table_destroy(struct vidtv_psi_table_sdt *sdt) struct vidtv_psi_table_sdt_service *vidtv_psi_sdt_service_init(struct vidtv_psi_table_sdt_service *head, - u16 service_id) + u16 service_id, + bool eit_schedule, + bool eit_present_following) { struct vidtv_psi_table_sdt_service *service; service = kzalloc(sizeof(*service), GFP_KERNEL); + if (!service) + return NULL; /* * ETSI 300 468: this is a 16bit field which serves as a label to @@ -1228,8 +1421,8 @@ struct vidtv_psi_table_sdt_service * corresponding program_map_section */ service->service_id = cpu_to_be16(service_id); - service->EIT_schedule = 0x0; - service->EIT_present_following = 0x0; + service->EIT_schedule = eit_schedule; + service->EIT_present_following = eit_present_following; service->reserved = 0x3f; service->bitfield = cpu_to_be16(RUNNING << 13); @@ -1262,53 +1455,78 @@ void vidtv_psi_sdt_service_assign(struct vidtv_psi_table_sdt *sdt, struct vidtv_psi_table_sdt_service *service) { - if (service == sdt->service) - return; + do { + if (service == sdt->service) + return; - sdt->service = service; + sdt->service = service; - /* recompute section length */ - vidtv_psi_sdt_table_update_sec_len(sdt); + /* recompute section length */ + vidtv_psi_sdt_table_update_sec_len(sdt); - if (vidtv_psi_get_sec_len(&sdt->header) > MAX_SECTION_LEN) - vidtv_psi_sdt_service_assign(sdt, NULL); + service = NULL; + } while (vidtv_psi_get_sec_len(&sdt->header) > MAX_SECTION_LEN); vidtv_psi_update_version_num(&sdt->header); } +/* + * PMTs contain information about programs. For each program, + * there is one PMT section. This function will create a section + * for each program found in the PAT + */ struct vidtv_psi_table_pmt** -vidtv_psi_pmt_create_sec_for_each_pat_entry(struct vidtv_psi_table_pat *pat, u16 pcr_pid) +vidtv_psi_pmt_create_sec_for_each_pat_entry(struct vidtv_psi_table_pat *pat, + u16 pcr_pid) { + struct vidtv_psi_table_pat_program *program; + struct vidtv_psi_table_pmt **pmt_secs; + u32 i = 0, num_pmt = 0; + /* - * PMTs contain information about programs. For each program, - * there is one PMT section. This function will create a section - * for each program found in the PAT + * The number of PMT entries is the number of PAT entries + * that contain service_id. That exclude special tables, like NIT */ - struct vidtv_psi_table_pat_program *program = pat->program; - struct vidtv_psi_table_pmt **pmt_secs; - u32 i = 0; + program = pat->program; + while (program) { + if (program->service_id) + num_pmt++; + program = program->next; + } - /* a section for each program_id */ - pmt_secs = kcalloc(pat->programs, + pmt_secs = kcalloc(num_pmt, sizeof(struct vidtv_psi_table_pmt *), GFP_KERNEL); - - while (program) { - pmt_secs[i] = vidtv_psi_pmt_table_init(be16_to_cpu(program->service_id), pcr_pid); - ++i; - program = program->next; + if (!pmt_secs) + return NULL; + + for (program = pat->program; program; program = program->next) { + if (!program->service_id) + continue; + pmt_secs[i] = vidtv_psi_pmt_table_init(be16_to_cpu(program->service_id), + pcr_pid); + + if (!pmt_secs[i]) { + while (i > 0) { + i--; + vidtv_psi_pmt_table_destroy(pmt_secs[i]); + } + return NULL; + } + i++; } + pat->num_pmt = num_pmt; return pmt_secs; } +/* find the PMT section associated with 'program_num' */ struct vidtv_psi_table_pmt *vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt **pmt_sections, u16 nsections, u16 program_num) { - /* find the PMT section associated with 'program_num' */ struct vidtv_psi_table_pmt *sec = NULL; u32 i; @@ -1320,3 +1538,488 @@ struct vidtv_psi_table_pmt return NULL; /* not found */ } + +static void vidtv_psi_nit_table_update_sec_len(struct vidtv_psi_table_nit *nit) +{ + u16 length = 0; + struct vidtv_psi_table_transport *t = nit->transport; + u16 desc_loop_len; + u16 transport_loop_len = 0; + + /* + * from immediately after 'section_length' until + * 'network_descriptor_length' + */ + length += NIT_LEN_UNTIL_NETWORK_DESCRIPTOR_LEN; + + desc_loop_len = vidtv_psi_desc_comp_loop_len(nit->descriptor); + vidtv_psi_set_desc_loop_len(&nit->bitfield, desc_loop_len, 12); + + length += desc_loop_len; + + length += sizeof_field(struct vidtv_psi_table_nit, bitfield2); + + while (t) { + /* skip both pointers at the end */ + transport_loop_len += sizeof(struct vidtv_psi_table_transport) - + sizeof(struct vidtv_psi_desc *) - + sizeof(struct vidtv_psi_table_transport *); + + length += transport_loop_len; + + desc_loop_len = vidtv_psi_desc_comp_loop_len(t->descriptor); + vidtv_psi_set_desc_loop_len(&t->bitfield, desc_loop_len, 12); + + length += desc_loop_len; + + t = t->next; + } + + // Actually sets the transport stream loop len, maybe rename this function later + vidtv_psi_set_desc_loop_len(&nit->bitfield2, transport_loop_len, 12); + length += CRC_SIZE_IN_BYTES; + + vidtv_psi_set_sec_len(&nit->header, length); +} + +struct vidtv_psi_table_nit +*vidtv_psi_nit_table_init(u16 network_id, + u16 transport_stream_id, + char *network_name, + struct vidtv_psi_desc_service_list_entry *service_list) +{ + struct vidtv_psi_table_transport *transport; + struct vidtv_psi_table_nit *nit; + const u16 SYNTAX = 0x1; + const u16 ONES = 0x03; + const u16 ONE = 0x1; + + nit = kzalloc(sizeof(*nit), GFP_KERNEL); + if (!nit) + return NULL; + + transport = kzalloc(sizeof(*transport), GFP_KERNEL); + if (!transport) + goto free_nit; + + nit->header.table_id = 0x40; // ACTUAL_NETWORK + + nit->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ONE << 14) | (ONES << 12)); + + nit->header.id = cpu_to_be16(network_id); + nit->header.current_next = ONE; + + nit->header.version = 0x1f; + + nit->header.one2 = ONES; + nit->header.section_id = 0; + nit->header.last_section = 0; + + nit->bitfield = cpu_to_be16(0xf); + nit->bitfield2 = cpu_to_be16(0xf); + + nit->descriptor = (struct vidtv_psi_desc *) + vidtv_psi_network_name_desc_init(NULL, network_name); + if (!nit->descriptor) + goto free_transport; + + transport->transport_id = cpu_to_be16(transport_stream_id); + transport->network_id = cpu_to_be16(network_id); + transport->bitfield = cpu_to_be16(0xf); + transport->descriptor = (struct vidtv_psi_desc *) + vidtv_psi_service_list_desc_init(NULL, service_list); + if (!transport->descriptor) + goto free_nit_desc; + + nit->transport = transport; + + vidtv_psi_nit_table_update_sec_len(nit); + + return nit; + +free_nit_desc: + vidtv_psi_desc_destroy((struct vidtv_psi_desc *)nit->descriptor); + +free_transport: + kfree(transport); +free_nit: + kfree(nit); + return NULL; +} + +u32 vidtv_psi_nit_write_into(struct vidtv_psi_nit_write_args *args) +{ + struct header_write_args h_args = { + .dest_buf = args->buf, + .dest_offset = args->offset, + .h = &args->nit->header, + .pid = VIDTV_NIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct psi_write_args psi_args = { + .dest_buf = args->buf, + .from = &args->nit->bitfield, + .len = sizeof_field(struct vidtv_psi_table_nit, bitfield), + .pid = VIDTV_NIT_PID, + .new_psi_section = false, + .is_crc = false, + .dest_buf_sz = args->buf_sz, + }; + struct desc_write_args d_args = { + .dest_buf = args->buf, + .pid = VIDTV_NIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct crc32_write_args c_args = { + .dest_buf = args->buf, + .pid = VIDTV_NIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct vidtv_psi_desc *table_descriptor = args->nit->descriptor; + struct vidtv_psi_table_transport *transport = args->nit->transport; + struct vidtv_psi_desc *transport_descriptor; + u32 crc = INITIAL_CRC; + u32 nbytes = 0; + + vidtv_psi_nit_table_update_sec_len(args->nit); + + h_args.continuity_counter = args->continuity_counter; + h_args.crc = &crc; + + nbytes += vidtv_psi_table_header_write_into(&h_args); + + /* write the bitfield */ + + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; + psi_args.crc = &crc; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + while (table_descriptor) { + /* write the descriptors, if any */ + d_args.dest_offset = args->offset + nbytes; + d_args.desc = table_descriptor; + d_args.continuity_counter = args->continuity_counter; + d_args.crc = &crc; + + nbytes += vidtv_psi_desc_write_into(&d_args); + + table_descriptor = table_descriptor->next; + } + + /* write the second bitfield */ + psi_args.from = &args->nit->bitfield2; + psi_args.len = sizeof_field(struct vidtv_psi_table_nit, bitfield2); + psi_args.dest_offset = args->offset + nbytes; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + psi_args.len = sizeof_field(struct vidtv_psi_table_transport, transport_id) + + sizeof_field(struct vidtv_psi_table_transport, network_id) + + sizeof_field(struct vidtv_psi_table_transport, bitfield); + while (transport) { + /* write the transport sections, if any */ + psi_args.from = transport; + psi_args.dest_offset = args->offset + nbytes; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + transport_descriptor = transport->descriptor; + + while (transport_descriptor) { + /* write the transport descriptors, if any */ + d_args.dest_offset = args->offset + nbytes; + d_args.desc = transport_descriptor; + d_args.continuity_counter = args->continuity_counter; + d_args.crc = &crc; + + nbytes += vidtv_psi_desc_write_into(&d_args); + + transport_descriptor = transport_descriptor->next; + } + + transport = transport->next; + } + + c_args.dest_offset = args->offset + nbytes; + c_args.crc = cpu_to_be32(crc); + c_args.continuity_counter = args->continuity_counter; + + /* Write the CRC32 at the end */ + nbytes += table_section_crc32_write_into(&c_args); + + return nbytes; +} + +static void vidtv_psi_transport_destroy(struct vidtv_psi_table_transport *t) +{ + struct vidtv_psi_table_transport *tmp_t = NULL; + struct vidtv_psi_table_transport *curr_t = t; + + while (curr_t) { + tmp_t = curr_t; + curr_t = curr_t->next; + vidtv_psi_desc_destroy(tmp_t->descriptor); + kfree(tmp_t); + } +} + +void vidtv_psi_nit_table_destroy(struct vidtv_psi_table_nit *nit) +{ + vidtv_psi_desc_destroy(nit->descriptor); + vidtv_psi_transport_destroy(nit->transport); + kfree(nit); +} + +void vidtv_psi_eit_table_update_sec_len(struct vidtv_psi_table_eit *eit) +{ + struct vidtv_psi_table_eit_event *e = eit->event; + u16 desc_loop_len; + u16 length = 0; + + /* + * from immediately after 'section_length' until + * 'last_table_id' + */ + length += EIT_LEN_UNTIL_LAST_TABLE_ID; + + while (e) { + /* skip both pointers at the end */ + length += sizeof(struct vidtv_psi_table_eit_event) - + sizeof(struct vidtv_psi_desc *) - + sizeof(struct vidtv_psi_table_eit_event *); + + desc_loop_len = vidtv_psi_desc_comp_loop_len(e->descriptor); + vidtv_psi_set_desc_loop_len(&e->bitfield, desc_loop_len, 12); + + length += desc_loop_len; + + e = e->next; + } + + length += CRC_SIZE_IN_BYTES; + + vidtv_psi_set_sec_len(&eit->header, length); +} + +void vidtv_psi_eit_event_assign(struct vidtv_psi_table_eit *eit, + struct vidtv_psi_table_eit_event *e) +{ + do { + if (e == eit->event) + return; + + eit->event = e; + vidtv_psi_eit_table_update_sec_len(eit); + + e = NULL; + } while (vidtv_psi_get_sec_len(&eit->header) > EIT_MAX_SECTION_LEN); + + vidtv_psi_update_version_num(&eit->header); +} + +struct vidtv_psi_table_eit +*vidtv_psi_eit_table_init(u16 network_id, + u16 transport_stream_id, + __be16 service_id) +{ + struct vidtv_psi_table_eit *eit; + const u16 SYNTAX = 0x1; + const u16 ONE = 0x1; + const u16 ONES = 0x03; + + eit = kzalloc(sizeof(*eit), GFP_KERNEL); + if (!eit) + return NULL; + + eit->header.table_id = 0x4e; //actual_transport_stream: present/following + + eit->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ONE << 14) | (ONES << 12)); + + eit->header.id = service_id; + eit->header.current_next = ONE; + + eit->header.version = 0x1f; + + eit->header.one2 = ONES; + eit->header.section_id = 0; + eit->header.last_section = 0; + + eit->transport_id = cpu_to_be16(transport_stream_id); + eit->network_id = cpu_to_be16(network_id); + + eit->last_segment = eit->header.last_section; /* not implemented */ + eit->last_table_id = eit->header.table_id; /* not implemented */ + + vidtv_psi_eit_table_update_sec_len(eit); + + return eit; +} + +u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args) +{ + struct header_write_args h_args = { + .dest_buf = args->buf, + .dest_offset = args->offset, + .h = &args->eit->header, + .pid = VIDTV_EIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct psi_write_args psi_args = { + .dest_buf = args->buf, + .len = sizeof_field(struct vidtv_psi_table_eit, transport_id) + + sizeof_field(struct vidtv_psi_table_eit, network_id) + + sizeof_field(struct vidtv_psi_table_eit, last_segment) + + sizeof_field(struct vidtv_psi_table_eit, last_table_id), + .pid = VIDTV_EIT_PID, + .new_psi_section = false, + .is_crc = false, + .dest_buf_sz = args->buf_sz, + }; + struct desc_write_args d_args = { + .dest_buf = args->buf, + .pid = VIDTV_EIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct crc32_write_args c_args = { + .dest_buf = args->buf, + .pid = VIDTV_EIT_PID, + .dest_buf_sz = args->buf_sz, + }; + struct vidtv_psi_table_eit_event *event = args->eit->event; + struct vidtv_psi_desc *event_descriptor; + u32 crc = INITIAL_CRC; + u32 nbytes = 0; + + vidtv_psi_eit_table_update_sec_len(args->eit); + + h_args.continuity_counter = args->continuity_counter; + h_args.crc = &crc; + + nbytes += vidtv_psi_table_header_write_into(&h_args); + + psi_args.from = &args->eit->transport_id; + psi_args.dest_offset = args->offset + nbytes; + psi_args.continuity_counter = args->continuity_counter; + psi_args.crc = &crc; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + /* skip both pointers at the end */ + psi_args.len = sizeof(struct vidtv_psi_table_eit_event) - + sizeof(struct vidtv_psi_desc *) - + sizeof(struct vidtv_psi_table_eit_event *); + while (event) { + /* copy the events, if any */ + psi_args.from = event; + psi_args.dest_offset = args->offset + nbytes; + + nbytes += vidtv_psi_ts_psi_write_into(&psi_args); + + event_descriptor = event->descriptor; + + while (event_descriptor) { + /* copy the event descriptors, if any */ + d_args.dest_offset = args->offset + nbytes; + d_args.desc = event_descriptor; + d_args.continuity_counter = args->continuity_counter; + d_args.crc = &crc; + + nbytes += vidtv_psi_desc_write_into(&d_args); + + event_descriptor = event_descriptor->next; + } + + event = event->next; + } + + c_args.dest_offset = args->offset + nbytes; + c_args.crc = cpu_to_be32(crc); + c_args.continuity_counter = args->continuity_counter; + + /* Write the CRC at the end */ + nbytes += table_section_crc32_write_into(&c_args); + + return nbytes; +} + +struct vidtv_psi_table_eit_event +*vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id) +{ + const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */ + struct vidtv_psi_table_eit_event *e; + struct timespec64 ts; + struct tm time; + int mjd, l; + __be16 mjd_be; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return NULL; + + e->event_id = cpu_to_be16(event_id); + + ts = ktime_to_timespec64(ktime_get_real()); + time64_to_tm(ts.tv_sec, 0, &time); + + /* Convert date to Modified Julian Date - per EN 300 468 Annex C */ + if (time.tm_mon < 2) + l = 1; + else + l = 0; + + mjd = 14956 + time.tm_mday; + mjd += (time.tm_year - l) * 36525 / 100; + mjd += (time.tm_mon + 2 + l * 12) * 306001 / 10000; + mjd_be = cpu_to_be16(mjd); + + /* + * Store MJD and hour/min/sec to the event. + * + * Let's make the event to start on a full hour + */ + memcpy(e->start_time, &mjd_be, sizeof(mjd_be)); + e->start_time[2] = bin2bcd(time.tm_hour); + e->start_time[3] = 0; + e->start_time[4] = 0; + + /* + * TODO: for now, the event will last for a day. Should be + * enough for testing purposes, but if one runs the driver + * for more than that, the current event will become invalid. + * So, we need a better code here in order to change the start + * time once the event expires. + */ + memcpy(e->duration, DURATION, sizeof(e->duration)); + + e->bitfield = cpu_to_be16(RUNNING << 13); + + if (head) { + while (head->next) + head = head->next; + + head->next = e; + } + + return e; +} + +void vidtv_psi_eit_event_destroy(struct vidtv_psi_table_eit_event *e) +{ + struct vidtv_psi_table_eit_event *tmp_e = NULL; + struct vidtv_psi_table_eit_event *curr_e = e; + + while (curr_e) { + tmp_e = curr_e; + curr_e = curr_e->next; + vidtv_psi_desc_destroy(tmp_e->descriptor); + kfree(tmp_e); + } +} + +void vidtv_psi_eit_table_destroy(struct vidtv_psi_table_eit *eit) +{ + vidtv_psi_eit_event_destroy(eit->event); + kfree(eit); +} diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.h b/drivers/media/test-drivers/vidtv/vidtv_psi.h index 3f962cc78278..340c9fb8d583 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.h +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.h @@ -6,10 +6,6 @@ * technically be broken into one or more sections, we do not do this here, * hence 'table' and 'section' are interchangeable for vidtv. * - * This code currently supports three tables: PAT, PMT and SDT. These are the - * bare minimum to get userspace to recognize our MPEG transport stream. It can - * be extended to support more PSI tables in the future. - * * Copyright (C) 2020 Daniel W. S. Almeida */ @@ -17,7 +13,6 @@ #define VIDTV_PSI_H #include <linux/types.h> -#include <asm/byteorder.h> /* * all section lengths start immediately after the 'section_length' field @@ -27,20 +22,28 @@ #define PAT_LEN_UNTIL_LAST_SECTION_NUMBER 5 #define PMT_LEN_UNTIL_PROGRAM_INFO_LENGTH 9 #define SDT_LEN_UNTIL_RESERVED_FOR_FUTURE_USE 8 +#define NIT_LEN_UNTIL_NETWORK_DESCRIPTOR_LEN 7 +#define EIT_LEN_UNTIL_LAST_TABLE_ID 11 #define MAX_SECTION_LEN 1021 +#define EIT_MAX_SECTION_LEN 4093 /* see ETSI 300 468 v.1.10.1 p. 26 */ #define VIDTV_PAT_PID 0 /* mandated by the specs */ #define VIDTV_SDT_PID 0x0011 /* mandated by the specs */ +#define VIDTV_NIT_PID 0x0010 /* mandated by the specs */ +#define VIDTV_EIT_PID 0x0012 /*mandated by the specs */ enum vidtv_psi_descriptors { REGISTRATION_DESCRIPTOR = 0x05, /* See ISO/IEC 13818-1 section 2.6.8 */ + NETWORK_NAME_DESCRIPTOR = 0x40, /* See ETSI EN 300 468 section 6.2.27 */ + SERVICE_LIST_DESCRIPTOR = 0x41, /* See ETSI EN 300 468 section 6.2.35 */ SERVICE_DESCRIPTOR = 0x48, /* See ETSI EN 300 468 section 6.2.33 */ + SHORT_EVENT_DESCRIPTOR = 0x4d, /* See ETSI EN 300 468 section 6.2.37 */ }; enum vidtv_psi_stream_types { STREAM_PRIVATE_DATA = 0x06, /* see ISO/IEC 13818-1 2000 p. 48 */ }; -/** +/* * struct vidtv_psi_desc - A generic PSI descriptor type. * The descriptor length is an 8-bit field specifying the total number of bytes of the data portion * of the descriptor following the byte defining the value of this field. @@ -52,7 +55,7 @@ struct vidtv_psi_desc { u8 data[]; } __packed; -/** +/* * struct vidtv_psi_desc_service - Service descriptor. * See ETSI EN 300 468 section 6.2.33. */ @@ -68,7 +71,7 @@ struct vidtv_psi_desc_service { char *service_name; } __packed; -/** +/* * struct vidtv_psi_desc_registration - A registration descriptor. * See ISO/IEC 13818-1 section 2.6.8 */ @@ -90,7 +93,56 @@ struct vidtv_psi_desc_registration { u8 additional_identification_info[]; } __packed; -/** +/* + * struct vidtv_psi_desc_network_name - A network name descriptor + * see ETSI EN 300 468 v1.15.1 section 6.2.27 + */ +struct vidtv_psi_desc_network_name { + struct vidtv_psi_desc *next; + u8 type; + u8 length; + char *network_name; +} __packed; + +struct vidtv_psi_desc_service_list_entry { + __be16 service_id; + u8 service_type; + struct vidtv_psi_desc_service_list_entry *next; +} __packed; + +/* + * struct vidtv_psi_desc_service_list - A service list descriptor + * see ETSI EN 300 468 v1.15.1 section 6.2.35 + */ +struct vidtv_psi_desc_service_list { + struct vidtv_psi_desc *next; + u8 type; + u8 length; + struct vidtv_psi_desc_service_list_entry *service_list; +} __packed; + +/* + * struct vidtv_psi_desc_short_event - A short event descriptor + * see ETSI EN 300 468 v1.15.1 section 6.2.37 + */ +struct vidtv_psi_desc_short_event { + struct vidtv_psi_desc *next; + u8 type; + u8 length; + char *iso_language_code; + u8 event_name_len; + char *event_name; + u8 text_len; + char *text; +} __packed; + +struct vidtv_psi_desc_short_event +*vidtv_psi_short_event_desc_init(struct vidtv_psi_desc *head, + char *iso_language_code, + char *event_name, + char *text); + +/* * struct vidtv_psi_table_header - A header that is present for all PSI tables. */ struct vidtv_psi_table_header { @@ -106,7 +158,7 @@ struct vidtv_psi_table_header { u8 last_section; /* last_section_number */ } __packed; -/** +/* * struct vidtv_psi_table_pat_program - A single program in the PAT * See ISO/IEC 13818-1 : 2000 p.43 */ @@ -116,17 +168,18 @@ struct vidtv_psi_table_pat_program { struct vidtv_psi_table_pat_program *next; } __packed; -/** +/* * struct vidtv_psi_table_pat - The Program Allocation Table (PAT) * See ISO/IEC 13818-1 : 2000 p.43 */ struct vidtv_psi_table_pat { struct vidtv_psi_table_header header; - u16 programs; /* Included by libdvbv5, not part of the table and not actually serialized */ + u16 num_pat; + u16 num_pmt; struct vidtv_psi_table_pat_program *program; } __packed; -/** +/* * struct vidtv_psi_table_sdt_service - Represents a service in the SDT. * see ETSI EN 300 468 v1.15.1 section 5.2.3. */ @@ -140,7 +193,7 @@ struct vidtv_psi_table_sdt_service { struct vidtv_psi_table_sdt_service *next; } __packed; -/** +/* * struct vidtv_psi_table_sdt - Represents the Service Description Table * see ETSI EN 300 468 v1.15.1 section 5.2.3. */ @@ -152,7 +205,7 @@ struct vidtv_psi_table_sdt { struct vidtv_psi_table_sdt_service *service; } __packed; -/** +/* * enum service_running_status - Status of a SDT service. * see ETSI EN 300 468 v1.15.1 section 5.2.3 table 6. */ @@ -160,16 +213,17 @@ enum service_running_status { RUNNING = 0x4, }; -/** +/* * enum service_type - The type of a SDT service. * see ETSI EN 300 468 v1.15.1 section 6.2.33, table 81. */ enum service_type { /* see ETSI EN 300 468 v1.15.1 p. 77 */ DIGITAL_TELEVISION_SERVICE = 0x1, + DIGITAL_RADIO_SOUND_SERVICE = 0X2, }; -/** +/* * struct vidtv_psi_table_pmt_stream - A single stream in the PMT. * See ISO/IEC 13818-1 : 2000 p.46. */ @@ -181,7 +235,7 @@ struct vidtv_psi_table_pmt_stream { struct vidtv_psi_table_pmt_stream *next; } __packed; -/** +/* * struct vidtv_psi_table_pmt - The Program Map Table (PMT). * See ISO/IEC 13818-1 : 2000 p.46. */ @@ -290,6 +344,13 @@ struct vidtv_psi_desc_registration u8 *additional_ident_info, u32 additional_info_len); +struct vidtv_psi_desc_network_name +*vidtv_psi_network_name_desc_init(struct vidtv_psi_desc *head, char *network_name); + +struct vidtv_psi_desc_service_list +*vidtv_psi_service_list_desc_init(struct vidtv_psi_desc *head, + struct vidtv_psi_desc_service_list_entry *entry); + struct vidtv_psi_table_pat_program *vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head, u16 service_id, @@ -305,11 +366,14 @@ struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id); struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number, u16 pcr_pid); -struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id); +struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 network_id, + u16 transport_stream_id); struct vidtv_psi_table_sdt_service* vidtv_psi_sdt_service_init(struct vidtv_psi_table_sdt_service *head, - u16 service_id); + u16 service_id, + bool eit_schedule, + bool eit_present_following); void vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc); @@ -413,7 +477,6 @@ struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc); * vidtv_psi_create_sec_for_each_pat_entry - Create a PMT section for each * program found in the PAT * @pat: The PAT to look for programs. - * @s: The stream loop (one or more streams) * @pcr_pid: packet ID for the PCR to be used for the program described in this * PMT section */ @@ -492,7 +555,7 @@ struct vidtv_psi_pat_write_args { * equal to the size of the PAT, since more space is needed for TS headers during TS * encapsulation. */ -u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args args); +u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args *args); /** * struct vidtv_psi_sdt_write_args - Arguments for writing a SDT table @@ -524,16 +587,18 @@ struct vidtv_psi_sdt_write_args { * equal to the size of the SDT, since more space is needed for TS headers during TS * encapsulation. */ -u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args); +u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args *args); /** * struct vidtv_psi_pmt_write_args - Arguments for writing a PMT section * @buf: The destination buffer. * @offset: The offset into the destination buffer. * @pmt: A pointer to the PMT. + * @pid: Program ID * @buf_sz: The size of the destination buffer. * @continuity_counter: A pointer to the CC. Incremented on every new packet. - * + * @pcr_pid: The TS PID used for the PSI packets. All channels will share the + * same PCR. */ struct vidtv_psi_pmt_write_args { char *buf; @@ -557,7 +622,7 @@ struct vidtv_psi_pmt_write_args { * equal to the size of the PMT section, since more space is needed for TS headers * during TS encapsulation. */ -u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args); +u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args *args); /** * vidtv_psi_find_pmt_sec - Finds the PMT section for 'program_num' @@ -574,4 +639,171 @@ struct vidtv_psi_table_pmt *vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt ** u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p); u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s); +/** + * struct vidtv_psi_table_transport - A entry in the TS loop for the NIT and/or other tables. + * See ETSI 300 468 section 5.2.1 + * @transport_id: The TS ID being described + * @network_id: The network_id that contains the TS ID + * @bitfield: Contains the descriptor loop length + * @descriptor: A descriptor loop + * @next: Pointer to the next entry + * + */ +struct vidtv_psi_table_transport { + __be16 transport_id; + __be16 network_id; + __be16 bitfield; /* desc_len: 12, reserved: 4 */ + struct vidtv_psi_desc *descriptor; + struct vidtv_psi_table_transport *next; +} __packed; + +/** + * struct vidtv_psi_table_nit - A Network Information Table (NIT). See ETSI 300 + * 468 section 5.2.1 + * @header: A PSI table header + * @bitfield: Contains the network descriptor length + * @descriptor: A descriptor loop describing the network + * @bitfield2: Contains the transport stream loop length + * @transport: The transport stream loop + * + */ +struct vidtv_psi_table_nit { + struct vidtv_psi_table_header header; + __be16 bitfield; /* network_desc_len: 12, reserved:4 */ + struct vidtv_psi_desc *descriptor; + __be16 bitfield2; /* ts_loop_len: 12, reserved: 4 */ + struct vidtv_psi_table_transport *transport; +} __packed; + +struct vidtv_psi_table_nit +*vidtv_psi_nit_table_init(u16 network_id, + u16 transport_stream_id, + char *network_name, + struct vidtv_psi_desc_service_list_entry *service_list); + +/** + * struct vidtv_psi_nit_write_args - Arguments for writing a NIT section + * @buf: The destination buffer. + * @offset: The offset into the destination buffer. + * @nit: A pointer to the NIT + * @buf_sz: The size of the destination buffer. + * @continuity_counter: A pointer to the CC. Incremented on every new packet. + * + */ +struct vidtv_psi_nit_write_args { + char *buf; + u32 offset; + struct vidtv_psi_table_nit *nit; + u32 buf_sz; + u8 *continuity_counter; +}; + +/** + * vidtv_psi_nit_write_into - Write NIT as MPEG-TS packets into a buffer. + * @args: an instance of struct vidtv_psi_nit_write_args + * + * This function writes the MPEG TS packets for a NIT table into a buffer. + * Calling code will usually generate the NIT via a call to its init function + * and thus is responsible for freeing it. + * + * Return: The number of bytes written into the buffer. This is NOT + * equal to the size of the NIT, since more space is needed for TS headers during TS + * encapsulation. + */ +u32 vidtv_psi_nit_write_into(struct vidtv_psi_nit_write_args *args); + +void vidtv_psi_nit_table_destroy(struct vidtv_psi_table_nit *nit); + +/* + * struct vidtv_psi_desc_short_event - A short event descriptor + * see ETSI EN 300 468 v1.15.1 section 6.2.37 + */ +struct vidtv_psi_table_eit_event { + __be16 event_id; + u8 start_time[5]; + u8 duration[3]; + __be16 bitfield; /* desc_length: 12, free_CA_mode: 1, running_status: 1 */ + struct vidtv_psi_desc *descriptor; + struct vidtv_psi_table_eit_event *next; +} __packed; + +/* + * struct vidtv_psi_table_eit - A Event Information Table (EIT) + * See ETSI 300 468 section 5.2.4 + */ +struct vidtv_psi_table_eit { + struct vidtv_psi_table_header header; + __be16 transport_id; + __be16 network_id; + u8 last_segment; + u8 last_table_id; + struct vidtv_psi_table_eit_event *event; +} __packed; + +struct vidtv_psi_table_eit +*vidtv_psi_eit_table_init(u16 network_id, + u16 transport_stream_id, + u16 service_id); + +/** + * struct vidtv_psi_eit_write_args - Arguments for writing an EIT section + * @buf: The destination buffer. + * @offset: The offset into the destination buffer. + * @eit: A pointer to the EIT + * @buf_sz: The size of the destination buffer. + * @continuity_counter: A pointer to the CC. Incremented on every new packet. + * + */ +struct vidtv_psi_eit_write_args { + char *buf; + u32 offset; + struct vidtv_psi_table_eit *eit; + u32 buf_sz; + u8 *continuity_counter; +}; + +/** + * vidtv_psi_eit_write_into - Write EIT as MPEG-TS packets into a buffer. + * @args: an instance of struct vidtv_psi_nit_write_args + * + * This function writes the MPEG TS packets for a EIT table into a buffer. + * Calling code will usually generate the EIT via a call to its init function + * and thus is responsible for freeing it. + * + * Return: The number of bytes written into the buffer. This is NOT + * equal to the size of the EIT, since more space is needed for TS headers during TS + * encapsulation. + */ +u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args); + +void vidtv_psi_eit_table_destroy(struct vidtv_psi_table_eit *eit); + +/** + * vidtv_psi_eit_table_update_sec_len - Recompute and update the EIT section length. + * @eit: The EIT whose length is to be updated. + * + * This will traverse the table and accumulate the length of its components, + * which is then used to replace the 'section_length' field. + * + * If section_length > EIT_MAX_SECTION_LEN, the operation fails. + */ +void vidtv_psi_eit_table_update_sec_len(struct vidtv_psi_table_eit *eit); + +/** + * vidtv_psi_eit_event_assign - Assigns the event loop to the EIT. + * @eit: The EIT to assign to. + * @e: The event loop + * + * This will free the previous event loop in the table. + * This will assign ownership of the stream loop to the table, i.e. the table + * will free this stream loop when a call to its destroy function is made. + */ +void vidtv_psi_eit_event_assign(struct vidtv_psi_table_eit *eit, + struct vidtv_psi_table_eit_event *e); + +struct vidtv_psi_table_eit_event +*vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id); + +void vidtv_psi_eit_event_destroy(struct vidtv_psi_table_eit_event *e); + #endif // VIDTV_PSI_H diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media/test-drivers/vidtv/vidtv_s302m.c index a447ccbd68d5..ce7dd6cafc8b 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_s302m.c +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c @@ -17,23 +17,22 @@ #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ -#include <linux/types.h> -#include <linux/slab.h> +#include <linux/bug.h> #include <linux/crc32.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/kernel.h> +#include <linux/fixp-arith.h> #include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/math64.h> #include <linux/printk.h> #include <linux/ratelimit.h> -#include <linux/fixp-arith.h> - -#include <linux/math64.h> -#include <asm/byteorder.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/vmalloc.h> -#include "vidtv_s302m.h" -#include "vidtv_encoder.h" #include "vidtv_common.h" +#include "vidtv_encoder.h" +#include "vidtv_s302m.h" #define S302M_SAMPLING_RATE_HZ 48000 #define PES_PRIVATE_STREAM_1 0xbd /* PES: private_stream_1 */ @@ -79,8 +78,9 @@ struct tone_duration { int duration; }; -#define COMPASS 120 /* beats per minute (Allegro) */ -static const struct tone_duration beethoven_5th_symphony[] = { +#define COMPASS 100 /* beats per minute */ +static const struct tone_duration beethoven_fur_elise[] = { + { NOTE_SILENT, 512}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, @@ -121,31 +121,36 @@ static const struct tone_duration beethoven_5th_symphony[] = { { NOTE_E_5, 128}, { NOTE_D_5, 128}, { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_4, 128}, { NOTE_D_5, 128}, { NOTE_C_5, 128}, { NOTE_E_3, 128}, - { NOTE_E_4, 128}, { NOTE_E_5, 255}, { NOTE_E_6, 128}, - { NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_E_5, 255}, + { NOTE_E_4, 128}, { NOTE_E_5, 128}, { NOTE_E_5, 128}, + { NOTE_E_6, 128}, { NOTE_E_5, 128}, { NOTE_E_6, 128}, + { NOTE_E_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_5, 128}, + { NOTE_E_5, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_6, 128}, - { NOTE_E_6, 128}, { NOTE_DS_5, 128}, { NOTE_E_5, 128}, - { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, - { NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128}, - { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128}, - { NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128}, - { NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128}, - { NOTE_E_5, 128}, { NOTE_GS_5, 128}, { NOTE_B_5, 128}, - { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128}, - { NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, + { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, + { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, + { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, + { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, + { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, + { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, + { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, - { NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128}, - { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128}, - { NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128}, - { NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128}, - { NOTE_E_5, 128}, { NOTE_C_6, 128}, { NOTE_B_5, 128}, - { NOTE_C_5, 255}, { NOTE_C_5, 255}, { NOTE_SILENT, 512}, + { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, + { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, + { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, + { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, + { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, + { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_5, 512}, + { NOTE_SILENT, 256}, }; static struct vidtv_access_unit *vidtv_s302m_access_unit_init(struct vidtv_access_unit *head) { - struct vidtv_access_unit *au = kzalloc(sizeof(*au), GFP_KERNEL); + struct vidtv_access_unit *au; + + au = kzalloc(sizeof(*au), GFP_KERNEL); + if (!au) + return NULL; if (head) { while (head->next) @@ -196,10 +201,10 @@ static void vidtv_s302m_alloc_au(struct vidtv_encoder *e) static void vidtv_s302m_compute_sample_count_from_video(struct vidtv_encoder *e) { - struct vidtv_access_unit *au = e->access_units; struct vidtv_access_unit *sync_au = e->sync->access_units; - u32 vau_duration_usecs; + struct vidtv_access_unit *au = e->access_units; u32 sample_duration_usecs; + u32 vau_duration_usecs; u32 s; vau_duration_usecs = USEC_PER_SEC / e->sync->sampling_rate_hz; @@ -230,36 +235,32 @@ static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e) { u16 sample; int pos; + struct vidtv_s302m_ctx *ctx = e->ctx; if (!e->src_buf) { /* * Simple tone generator: play the tones at the - * beethoven_5th_symphony array. + * beethoven_fur_elise array. */ - if (e->last_duration <= 0) { - if (e->src_buf_offset >= ARRAY_SIZE(beethoven_5th_symphony)) + if (ctx->last_duration <= 0) { + if (e->src_buf_offset >= ARRAY_SIZE(beethoven_fur_elise)) e->src_buf_offset = 0; - e->last_tone = beethoven_5th_symphony[e->src_buf_offset].note; - e->last_duration = beethoven_5th_symphony[e->src_buf_offset].duration * S302M_SAMPLING_RATE_HZ / COMPASS / 5; + ctx->last_tone = beethoven_fur_elise[e->src_buf_offset].note; + ctx->last_duration = beethoven_fur_elise[e->src_buf_offset].duration * + S302M_SAMPLING_RATE_HZ / COMPASS / 5; e->src_buf_offset++; - e->note_offset = 0; + ctx->note_offset = 0; } else { - e->last_duration--; + ctx->last_duration--; } - /* Handle silent */ - if (!e->last_tone) { - e->src_buf_offset = 0; + /* Handle pause notes */ + if (!ctx->last_tone) return 0x8000; - } - pos = (2 * PI * e->note_offset * e->last_tone / S302M_SAMPLING_RATE_HZ); - - if (pos == 360) - e->note_offset = 0; - else - e->note_offset++; + pos = (2 * PI * ctx->note_offset * ctx->last_tone) / S302M_SAMPLING_RATE_HZ; + ctx->note_offset++; return (fixp_sin32(pos % (2 * PI)) >> 16) + 0x8000; } @@ -289,9 +290,9 @@ static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e) static u32 vidtv_s302m_write_frame(struct vidtv_encoder *e, u16 sample) { - u32 nbytes = 0; - struct vidtv_s302m_frame_16 f = {}; struct vidtv_s302m_ctx *ctx = e->ctx; + struct vidtv_s302m_frame_16 f = {}; + u32 nbytes = 0; /* from ffmpeg: see s302enc.c */ @@ -388,6 +389,8 @@ static void vidtv_s302m_write_frames(struct vidtv_encoder *e) static void *vidtv_s302m_encode(struct vidtv_encoder *e) { + struct vidtv_s302m_ctx *ctx = e->ctx; + /* * According to SMPTE 302M, an audio access unit is specified as those * AES3 words that are associated with a corresponding video frame. @@ -401,8 +404,6 @@ static void *vidtv_s302m_encode(struct vidtv_encoder *e) * ffmpeg */ - struct vidtv_s302m_ctx *ctx = e->ctx; - vidtv_s302m_access_unit_destroy(e); vidtv_s302m_alloc_au(e); @@ -440,8 +441,13 @@ static u32 vidtv_s302m_clear(struct vidtv_encoder *e) struct vidtv_encoder *vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args) { - struct vidtv_encoder *e = kzalloc(sizeof(*e), GFP_KERNEL); u32 priv_sz = sizeof(struct vidtv_s302m_ctx); + struct vidtv_s302m_ctx *ctx; + struct vidtv_encoder *e; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return NULL; e->id = S302M; @@ -453,14 +459,19 @@ struct vidtv_encoder e->encoder_buf_offset = 0; e->sample_count = 0; - e->last_duration = 0; e->src_buf = (args.src_buf) ? args.src_buf : NULL; e->src_buf_sz = (args.src_buf) ? args.src_buf_sz : 0; e->src_buf_offset = 0; e->is_video_encoder = false; - e->ctx = kzalloc(priv_sz, GFP_KERNEL); + + ctx = kzalloc(priv_sz, GFP_KERNEL); + if (!ctx) + return NULL; + + e->ctx = ctx; + ctx->last_duration = 0; e->encode = vidtv_s302m_encode; e->clear = vidtv_s302m_clear; diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.h b/drivers/media/test-drivers/vidtv/vidtv_s302m.h index eca5e3150ede..9cc94e4a8924 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_s302m.h +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.h @@ -19,7 +19,6 @@ #define VIDTV_S302M_H #include <linux/types.h> -#include <asm/byteorder.h> #include "vidtv_encoder.h" @@ -34,14 +33,20 @@ * @enc: A pointer to the containing encoder structure. * @frame_index: The current frame in a block * @au_count: The total number of access units encoded up to now + * @last_duration: Duration of the tone currently being played + * @note_offset: Position at the music tone array + * @last_tone: Tone currently being played */ struct vidtv_s302m_ctx { struct vidtv_encoder *enc; u32 frame_index; u32 au_count; + int last_duration; + unsigned int note_offset; + enum musical_notes last_tone; }; -/** +/* * struct vidtv_smpte_s302m_es - s302m MPEG Elementary Stream header. * * See SMPTE 302M 2007 table 1. diff --git a/drivers/media/test-drivers/vidtv/vidtv_ts.c b/drivers/media/test-drivers/vidtv/vidtv_ts.c index 190b9e4438dc..ca4bb9c40b78 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_ts.c +++ b/drivers/media/test-drivers/vidtv/vidtv_ts.c @@ -9,14 +9,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ +#include <linux/math64.h> #include <linux/printk.h> #include <linux/ratelimit.h> #include <linux/types.h> -#include <linux/math64.h> -#include <asm/byteorder.h> -#include "vidtv_ts.h" #include "vidtv_common.h" +#include "vidtv_ts.h" static u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr) { diff --git a/drivers/media/test-drivers/vidtv/vidtv_ts.h b/drivers/media/test-drivers/vidtv/vidtv_ts.h index 83dcc9183b45..10838a2b8389 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_ts.h +++ b/drivers/media/test-drivers/vidtv/vidtv_ts.h @@ -11,7 +11,6 @@ #define VIDTV_TS_H #include <linux/types.h> -#include <asm/byteorder.h> #define TS_SYNC_BYTE 0x47 #define TS_PACKET_LEN 188 @@ -54,7 +53,7 @@ struct vidtv_mpeg_ts { * @dest_offset: The byte offset into the buffer. * @pid: The TS PID for the PCR packets. * @buf_sz: The size of the buffer in bytes. - * @countinuity_counter: The TS continuity_counter. + * @continuity_counter: The TS continuity_counter. * @pcr: A sample from the system clock. */ struct pcr_write_args { @@ -71,7 +70,7 @@ struct pcr_write_args { * @dest_buf: The buffer to write into. * @dest_offset: The byte offset into the buffer. * @buf_sz: The size of the buffer in bytes. - * @countinuity_counter: The TS continuity_counter. + * @continuity_counter: The TS continuity_counter. */ struct null_packet_write_args { void *dest_buf; diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.c b/drivers/media/test-drivers/vidtv/vidtv_tuner.c index 9bc49e099f65..14b6bc902ee1 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_tuner.c +++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.c @@ -13,11 +13,12 @@ #include <linux/errno.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/printk.h> +#include <linux/ratelimit.h> #include <linux/slab.h> #include <linux/types.h> + #include <media/dvb_frontend.h> -#include <linux/printk.h> -#include <linux/ratelimit.h> #include "vidtv_tuner.h" diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.h b/drivers/media/test-drivers/vidtv/vidtv_tuner.h index 8455b2d564b3..fd55346a5c87 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_tuner.h +++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.h @@ -11,6 +11,7 @@ #define VIDTV_TUNER_H #include <linux/types.h> + #include <media/dvb_frontend.h> #define NUM_VALID_TUNER_FREQS 8 diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 829ccef87426..d25a4b50c2f3 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -30,7 +30,10 @@ #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 #define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 +#define SDHCI_ARASAN_ITAPDLY_SEL_MASK 0xFF + #define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC +#define SDHCI_ARASAN_OTAPDLY_SEL_MASK 0x3F #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 #define VENDOR_ENHANCED_STROBE BIT(0) @@ -600,14 +603,8 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) u8 tap_delay, tap_max = 0; int ret; - /* - * This is applicable for SDHCI_SPEC_300 and above - * ZynqMP does not set phase for <=25MHz clock. - * If degrees is zero, no need to do anything. - */ - if (host->version < SDHCI_SPEC_300 || - host->timing == MMC_TIMING_LEGACY || - host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + /* This is applicable for SDHCI_SPEC_300 and above */ + if (host->version < SDHCI_SPEC_300) return 0; switch (host->timing) { @@ -638,6 +635,9 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) if (ret) pr_err("Error setting Output Tap Delay\n"); + /* Release DLL Reset */ + zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE); + return ret; } @@ -668,16 +668,13 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) u8 tap_delay, tap_max = 0; int ret; - /* - * This is applicable for SDHCI_SPEC_300 and above - * ZynqMP does not set phase for <=25MHz clock. - * If degrees is zero, no need to do anything. - */ - if (host->version < SDHCI_SPEC_300 || - host->timing == MMC_TIMING_LEGACY || - host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + /* This is applicable for SDHCI_SPEC_300 and above */ + if (host->version < SDHCI_SPEC_300) return 0; + /* Assert DLL Reset */ + zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT); + switch (host->timing) { case MMC_TIMING_MMC_HS: case MMC_TIMING_SD_HS: @@ -733,14 +730,8 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) struct sdhci_host *host = sdhci_arasan->host; u8 tap_delay, tap_max = 0; - /* - * This is applicable for SDHCI_SPEC_300 and above - * Versal does not set phase for <=25MHz clock. - * If degrees is zero, no need to do anything. - */ - if (host->version < SDHCI_SPEC_300 || - host->timing == MMC_TIMING_LEGACY || - host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + /* This is applicable for SDHCI_SPEC_300 and above */ + if (host->version < SDHCI_SPEC_300) return 0; switch (host->timing) { @@ -773,6 +764,7 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); regval |= SDHCI_OTAPDLY_ENABLE; sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); + regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK; regval |= tap_delay; sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); } @@ -804,14 +796,8 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) struct sdhci_host *host = sdhci_arasan->host; u8 tap_delay, tap_max = 0; - /* - * This is applicable for SDHCI_SPEC_300 and above - * Versal does not set phase for <=25MHz clock. - * If degrees is zero, no need to do anything. - */ - if (host->version < SDHCI_SPEC_300 || - host->timing == MMC_TIMING_LEGACY || - host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + /* This is applicable for SDHCI_SPEC_300 and above */ + if (host->version < SDHCI_SPEC_300) return 0; switch (host->timing) { @@ -846,6 +832,7 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); regval |= SDHCI_ITAPDLY_ENABLE; sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK; regval |= tap_delay; sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); regval &= ~SDHCI_ITAPDLY_CHGWIN; diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 23da7f7fe093..9552708846ca 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -665,6 +665,15 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, } } +static void sdhci_intel_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + /* Set UHS timing to SDR25 for High Speed mode */ + if (timing == MMC_TIMING_MMC_HS || timing == MMC_TIMING_SD_HS) + timing = MMC_TIMING_UHS_SDR25; + sdhci_set_uhs_signaling(host, timing); +} + #define INTEL_HS400_ES_REG 0x78 #define INTEL_HS400_ES_BIT BIT(0) @@ -721,7 +730,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = { .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = sdhci_intel_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, }; @@ -731,7 +740,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = { .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_cqhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = sdhci_intel_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, .irq = sdhci_cqhci_irq, }; diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index d3c5cc513c8f..0c352b39ad4b 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -215,8 +215,17 @@ static int gpio_nand_setup_interface(struct nand_chip *this, int csline, return 0; } +static int gpio_nand_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + static const struct nand_controller_ops gpio_nand_ops = { .exec_op = gpio_nand_exec_op, + .attach_chip = gpio_nand_attach_chip, .setup_interface = gpio_nand_setup_interface, }; @@ -260,9 +269,6 @@ static int gpio_nand_probe(struct platform_device *pdev) return err; } - this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - this->ecc.algo = NAND_ECC_ALGO_HAMMING; - platform_set_drvdata(pdev, priv); /* Set chip enabled but write protected */ diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index 79b057400fe9..7892022bd6dd 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -236,8 +236,17 @@ static int au1550nd_exec_op(struct nand_chip *this, return ret; } +static int au1550nd_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + static const struct nand_controller_ops au1550nd_ops = { .exec_op = au1550nd_exec_op, + .attach_chip = au1550nd_attach_chip, }; static int au1550nd_probe(struct platform_device *pdev) @@ -294,8 +303,6 @@ static int au1550nd_probe(struct platform_device *pdev) nand_controller_init(&ctx->controller); ctx->controller.ops = &au1550nd_ops; this->controller = &ctx->controller; - this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - this->ecc.algo = NAND_ECC_ALGO_HAMMING; if (pd->devwidth) this->options |= NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index b7f3f6347761..282203debd0c 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -243,8 +243,24 @@ static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat, static struct cs553x_nand_controller *controllers[4]; +static int cs553x_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.size = 256; + chip->ecc.bytes = 3; + chip->ecc.hwctl = cs_enable_hwecc; + chip->ecc.calculate = cs_calculate_ecc; + chip->ecc.correct = nand_correct_data; + chip->ecc.strength = 1; + + return 0; +} + static const struct nand_controller_ops cs553x_nand_controller_ops = { .exec_op = cs553x_exec_op, + .attach_chip = cs553x_attach_chip, }; static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) @@ -286,14 +302,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_mtd; } - this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - this->ecc.size = 256; - this->ecc.bytes = 3; - this->ecc.hwctl = cs_enable_hwecc; - this->ecc.calculate = cs_calculate_ecc; - this->ecc.correct = nand_correct_data; - this->ecc.strength = 1; - /* Enable the following for a flash based bad block table */ this->bbt_options = NAND_BBT_USE_FLASH; diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 427f320fb79b..f8c36d19ab47 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -585,6 +585,10 @@ static int davinci_nand_attach_chip(struct nand_chip *chip) if (IS_ERR(pdata)) return PTR_ERR(pdata); + /* Use board-specific ECC config */ + info->chip.ecc.engine_type = pdata->engine_type; + info->chip.ecc.placement = pdata->ecc_placement; + switch (info->chip.ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_NONE: pdata->ecc_bits = 0; @@ -850,10 +854,6 @@ static int nand_davinci_probe(struct platform_device *pdev) info->mask_ale = pdata->mask_ale ? : MASK_ALE; info->mask_cle = pdata->mask_cle ? : MASK_CLE; - /* Use board-specific ECC config */ - info->chip.ecc.engine_type = pdata->engine_type; - info->chip.ecc.placement = pdata->ecc_placement; - spin_lock_irq(&davinci_nand_lock); /* put CSxNAND into NAND mode */ diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 94432a453e5e..26b265e4384a 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1269,12 +1269,31 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) return 1; } +static int doc200x_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; + chip->ecc.size = 512; + chip->ecc.bytes = 6; + chip->ecc.strength = 2; + chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; + chip->ecc.hwctl = doc200x_enable_hwecc; + chip->ecc.calculate = doc200x_calculate_ecc; + chip->ecc.correct = doc200x_correct_data; + + return 0; +} + static const struct nand_controller_ops doc200x_ops = { .exec_op = doc200x_exec_op, + .attach_chip = doc200x_attach_chip, }; static const struct nand_controller_ops doc2001plus_ops = { .exec_op = doc2001plus_exec_op, + .attach_chip = doc200x_attach_chip, }; static int __init doc_probe(unsigned long physadr) @@ -1452,16 +1471,6 @@ static int __init doc_probe(unsigned long physadr) nand->controller = &doc->base; nand_set_controller_data(nand, doc); - nand->ecc.hwctl = doc200x_enable_hwecc; - nand->ecc.calculate = doc200x_calculate_ecc; - nand->ecc.correct = doc200x_correct_data; - - nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - nand->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; - nand->ecc.size = 512; - nand->ecc.bytes = 6; - nand->ecc.strength = 2; - nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; nand->bbt_options = NAND_BBT_USE_FLASH; /* Skip the automatic BBT scan so we can run it manually */ nand->options |= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK; diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 4191831df182..c88421a1c078 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -880,6 +880,20 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) struct mtd_info *mtd = nand_to_mtd(nand); struct fsmc_nand_data *host = nand_to_fsmc(nand); + if (nand->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID) + nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; + + if (!nand->ecc.size) + nand->ecc.size = 512; + + if (AMBA_REV_BITS(host->pid) >= 8) { + nand->ecc.read_page = fsmc_read_page_hwecc; + nand->ecc.calculate = fsmc_read_hwecc_ecc4; + nand->ecc.correct = fsmc_bch8_correct_data; + nand->ecc.bytes = 13; + nand->ecc.strength = 8; + } + if (AMBA_REV_BITS(host->pid) >= 8) { switch (mtd->oobsize) { case 16: @@ -905,6 +919,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) dev_info(host->dev, "Using 1-bit HW ECC scheme\n"); nand->ecc.calculate = fsmc_read_hwecc_ecc1; nand->ecc.correct = nand_correct_data; + nand->ecc.hwctl = fsmc_enable_hwecc; nand->ecc.bytes = 3; nand->ecc.strength = 1; nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; @@ -1055,13 +1070,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; - /* - * Setup default ECC mode. nand_dt_init() called from nand_scan_ident() - * can overwrite this value if the DT provides a different value. - */ - nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - nand->ecc.hwctl = fsmc_enable_hwecc; - nand->ecc.size = 512; nand->badblockbits = 7; if (host->mode == USE_DMA_ACCESS) { @@ -1084,14 +1092,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->options |= NAND_KEEP_TIMINGS; } - if (AMBA_REV_BITS(host->pid) >= 8) { - nand->ecc.read_page = fsmc_read_page_hwecc; - nand->ecc.calculate = fsmc_read_hwecc_ecc4; - nand->ecc.correct = fsmc_bch8_correct_data; - nand->ecc.bytes = 13; - nand->ecc.strength = 8; - } - nand_controller_init(&host->base); host->base.ops = &fsmc_nand_controller_ops; nand->controller = &host->base; diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index 4ec0a1e10867..eb03b8cea1cb 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -161,8 +161,17 @@ static int gpio_nand_exec_op(struct nand_chip *chip, return ret; } +static int gpio_nand_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + static const struct nand_controller_ops gpio_nand_ops = { .exec_op = gpio_nand_exec_op, + .attach_chip = gpio_nand_attach_chip, }; #ifdef CONFIG_OF @@ -342,8 +351,6 @@ static int gpio_nand_probe(struct platform_device *pdev) gpiomtd->base.ops = &gpio_nand_ops; nand_set_flash_node(chip, pdev->dev.of_node); - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - chip->ecc.algo = NAND_ECC_ALGO_HAMMING; chip->options = gpiomtd->plat.options; chip->controller = &gpiomtd->base; diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 4940bb2e3c07..9e728c731795 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -648,6 +648,9 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip) struct lpc32xx_nand_host *host = nand_get_controller_data(chip); struct device *dev = &host->pdev->dev; + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL); if (!host->dma_buf) return -ENOMEM; @@ -656,8 +659,17 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip) if (!host->dummy_buf) return -ENOMEM; - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; chip->ecc.size = 512; + chip->ecc.hwctl = lpc32xx_ecc_enable; + chip->ecc.read_page_raw = lpc32xx_read_page; + chip->ecc.read_page = lpc32xx_read_page; + chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; + chip->ecc.write_page = lpc32xx_write_page_lowlevel; + chip->ecc.write_oob = lpc32xx_write_oob; + chip->ecc.read_oob = lpc32xx_read_oob; + chip->ecc.strength = 4; + chip->ecc.bytes = 10; + mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops); host->mlcsubpages = mtd->writesize / 512; @@ -741,15 +753,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); /* Initialize function pointers */ - nand_chip->ecc.hwctl = lpc32xx_ecc_enable; - nand_chip->ecc.read_page_raw = lpc32xx_read_page; - nand_chip->ecc.read_page = lpc32xx_read_page; - nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; - nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel; - nand_chip->ecc.write_oob = lpc32xx_write_oob; - nand_chip->ecc.read_oob = lpc32xx_read_oob; - nand_chip->ecc.strength = 4; - nand_chip->ecc.bytes = 10; nand_chip->legacy.waitfunc = lpc32xx_waitfunc; nand_chip->options = NAND_NO_SUBPAGE_WRITE; diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 6db9d2ed6881..dc7785e30d2f 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -775,6 +775,9 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip) struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + /* OOB and ECC CPU and DMA work areas */ host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE); @@ -786,11 +789,22 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip) if (mtd->writesize <= 512) mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops); + chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; /* These sizes remain the same regardless of page size */ chip->ecc.size = 256; + chip->ecc.strength = 1; chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES; chip->ecc.prepad = 0; chip->ecc.postpad = 0; + chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome; + chip->ecc.read_page = lpc32xx_nand_read_page_syndrome; + chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome; + chip->ecc.write_page = lpc32xx_nand_write_page_syndrome; + chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome; + chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome; + chip->ecc.calculate = lpc32xx_nand_ecc_calculate; + chip->ecc.correct = nand_correct_data; + chip->ecc.hwctl = lpc32xx_nand_ecc_enable; /* * Use a custom BBT marker setup for small page FLASH that @@ -881,21 +895,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); /* NAND callbacks for LPC32xx SLC hardware */ - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; chip->legacy.read_byte = lpc32xx_nand_read_byte; chip->legacy.read_buf = lpc32xx_nand_read_buf; chip->legacy.write_buf = lpc32xx_nand_write_buf; - chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome; - chip->ecc.read_page = lpc32xx_nand_read_page_syndrome; - chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome; - chip->ecc.write_page = lpc32xx_nand_write_page_syndrome; - chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome; - chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome; - chip->ecc.calculate = lpc32xx_nand_ecc_calculate; - chip->ecc.correct = nand_correct_data; - chip->ecc.strength = 1; - chip->ecc.hwctl = lpc32xx_nand_ecc_enable; /* * Allocate a large enough buffer for a single huge page plus diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index dfd0d3ed5ed0..fb4c0b11689f 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -104,6 +104,7 @@ #define NFC_TIMEOUT (HZ / 10) /* 1/10 s */ struct mpc5121_nfc_prv { + struct nand_controller controller; struct nand_chip chip; int irq; void __iomem *regs; @@ -602,6 +603,18 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) iounmap(prv->csreg); } +static int mpc5121_nfc_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops mpc5121_nfc_ops = { + .attach_chip = mpc5121_nfc_attach_chip, +}; + static int mpc5121_nfc_probe(struct platform_device *op) { struct device_node *dn = op->dev.of_node; @@ -634,6 +647,10 @@ static int mpc5121_nfc_probe(struct platform_device *op) chip = &prv->chip; mtd = nand_to_mtd(chip); + nand_controller_init(&prv->controller); + prv->controller.ops = &mpc5121_nfc_ops; + chip->controller = &prv->controller; + mtd->dev.parent = dev; nand_set_controller_data(chip, prv); nand_set_flash_node(chip, dn); @@ -688,8 +705,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) chip->legacy.set_features = nand_get_set_features_notsupp; chip->legacy.get_features = nand_get_set_features_notsupp; chip->bbt_options = NAND_BBT_USE_FLASH; - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - chip->ecc.algo = NAND_ECC_ALGO_HAMMING; /* Support external chip-select logic on ADS5121 board */ if (of_machine_is_compatible("fsl,mpc5121ads")) { diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c index df9c0f8e4b4e..e3bb65fd3ab2 100644 --- a/drivers/mtd/nand/raw/orion_nand.c +++ b/drivers/mtd/nand/raw/orion_nand.c @@ -22,6 +22,7 @@ #include <linux/platform_data/mtd-orion_nand.h> struct orion_nand_info { + struct nand_controller controller; struct nand_chip chip; struct clk *clk; }; @@ -82,6 +83,18 @@ static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) buf[i++] = readb(io_base); } +static int orion_nand_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops orion_nand_ops = { + .attach_chip = orion_nand_attach_chip, +}; + static int __init orion_nand_probe(struct platform_device *pdev) { struct orion_nand_info *info; @@ -101,6 +114,10 @@ static int __init orion_nand_probe(struct platform_device *pdev) nc = &info->chip; mtd = nand_to_mtd(nc); + nand_controller_init(&info->controller); + info->controller.ops = &orion_nand_ops; + nc->controller = &info->controller; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); io_base = devm_ioremap_resource(&pdev->dev, res); @@ -139,8 +156,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base; nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl; nc->legacy.read_buf = orion_nand_read_buf; - nc->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - nc->ecc.algo = NAND_ECC_ALGO_HAMMING; if (board->chip_delay) nc->legacy.chip_delay = board->chip_delay; diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c index 2b8f155cc0c5..4dfff34800f4 100644 --- a/drivers/mtd/nand/raw/pasemi_nand.c +++ b/drivers/mtd/nand/raw/pasemi_nand.c @@ -29,6 +29,7 @@ static unsigned int lpcctl; static struct mtd_info *pasemi_nand_mtd; +static struct nand_controller controller; static const char driver_name[] = "pasemi-nand"; static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len) @@ -73,6 +74,18 @@ static int pasemi_device_ready(struct nand_chip *chip) return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); } +static int pasemi_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops pasemi_ops = { + .attach_chip = pasemi_attach_chip, +}; + static int pasemi_nand_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; @@ -100,6 +113,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev) goto out; } + controller.ops = &pasemi_ops; + nand_controller_init(&controller); + chip->controller = &controller; + pasemi_nand_mtd = nand_to_mtd(chip); /* Link the private data with the MTD structure */ @@ -132,8 +149,6 @@ static int pasemi_nand_probe(struct platform_device *ofdev) chip->legacy.read_buf = pasemi_read_buf; chip->legacy.write_buf = pasemi_write_buf; chip->legacy.chip_delay = 0; - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - chip->ecc.algo = NAND_ECC_ALGO_HAMMING; /* Enable the following for a flash based bad block table */ chip->bbt_options = NAND_BBT_USE_FLASH; diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index b98c0d5c413f..93d9f1694dc1 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -14,10 +14,23 @@ #include <linux/mtd/platnand.h> struct plat_nand_data { + struct nand_controller controller; struct nand_chip chip; void __iomem *io_base; }; +static int plat_nand_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops plat_nand_ops = { + .attach_chip = plat_nand_attach_chip, +}; + /* * Probe for the NAND device. */ @@ -46,6 +59,10 @@ static int plat_nand_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->controller.ops = &plat_nand_ops; + nand_controller_init(&data->controller); + data->chip.controller = &data->controller; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(data->io_base)) @@ -66,9 +83,6 @@ static int plat_nand_probe(struct platform_device *pdev) data->chip.options |= pdata->chip.options; data->chip.bbt_options |= pdata->chip.bbt_options; - data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - data->chip.ecc.algo = NAND_ECC_ALGO_HAMMING; - platform_set_drvdata(pdev, data); /* Handle any platform specific setup */ diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index 6b7addd2c420..c742354c1b0b 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -817,6 +817,29 @@ out: return ret; } +static int r852_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; + chip->ecc.size = R852_DMA_LEN; + chip->ecc.bytes = SM_OOB_SIZE; + chip->ecc.strength = 2; + chip->ecc.hwctl = r852_ecc_hwctl; + chip->ecc.calculate = r852_ecc_calculate; + chip->ecc.correct = r852_ecc_correct; + + /* TODO: hack */ + chip->ecc.read_oob = r852_read_oob; + + return 0; +} + +static const struct nand_controller_ops r852_ops = { + .attach_chip = r852_attach_chip, +}; + static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { int error; @@ -858,19 +881,6 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) chip->legacy.read_buf = r852_read_buf; chip->legacy.write_buf = r852_write_buf; - /* ecc */ - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED; - chip->ecc.size = R852_DMA_LEN; - chip->ecc.bytes = SM_OOB_SIZE; - chip->ecc.strength = 2; - chip->ecc.hwctl = r852_ecc_hwctl; - chip->ecc.calculate = r852_ecc_calculate; - chip->ecc.correct = r852_ecc_correct; - - /* TODO: hack */ - chip->ecc.read_oob = r852_read_oob; - /* init our device structure */ dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL); @@ -882,6 +892,10 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) dev->pci_dev = pci_dev; pci_set_drvdata(pci_dev, dev); + nand_controller_init(&dev->controller); + dev->controller.ops = &r852_ops; + chip->controller = &dev->controller; + dev->bounce_buffer = dma_alloc_coherent(&pci_dev->dev, R852_DMA_LEN, &dev->phys_bounce_buffer, GFP_KERNEL); diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h index e9ce299c499d..96fe301d15da 100644 --- a/drivers/mtd/nand/raw/r852.h +++ b/drivers/mtd/nand/raw/r852.h @@ -104,6 +104,7 @@ #define DMA_MEMORY 1 struct r852_device { + struct nand_controller controller; void __iomem *mmio; /* mmio */ struct nand_chip *chip; /* nand chip backpointer */ struct pci_dev *pci_dev; /* pci backpointer */ diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index 1327bfb3d5d3..af98bcc9d689 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -20,6 +20,7 @@ #include <linux/io.h> struct sharpsl_nand { + struct nand_controller controller; struct nand_chip chip; void __iomem *io; @@ -96,6 +97,25 @@ static int sharpsl_nand_calculate_ecc(struct nand_chip *chip, return readb(sharpsl->io + ECCCNTR) != 0; } +static int sharpsl_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.size = 256; + chip->ecc.bytes = 3; + chip->ecc.strength = 1; + chip->ecc.hwctl = sharpsl_nand_enable_hwecc; + chip->ecc.calculate = sharpsl_nand_calculate_ecc; + chip->ecc.correct = nand_correct_data; + + return 0; +} + +static const struct nand_controller_ops sharpsl_ops = { + .attach_chip = sharpsl_attach_chip, +}; + /* * Main initialization routine */ @@ -136,6 +156,10 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Get pointer to private data */ this = (struct nand_chip *)(&sharpsl->chip); + nand_controller_init(&sharpsl->controller); + sharpsl->controller.ops = &sharpsl_ops; + this->controller = &sharpsl->controller; + /* Link the private data with the MTD structure */ mtd = nand_to_mtd(this); mtd->dev.parent = &pdev->dev; @@ -156,15 +180,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) this->legacy.dev_ready = sharpsl_nand_dev_ready; /* 15 us command delay time */ this->legacy.chip_delay = 15; - /* set eccmode using hardware ECC */ - this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - this->ecc.size = 256; - this->ecc.bytes = 3; - this->ecc.strength = 1; this->badblock_pattern = data->badblock_pattern; - this->ecc.hwctl = sharpsl_nand_enable_hwecc; - this->ecc.calculate = sharpsl_nand_calculate_ecc; - this->ecc.correct = nand_correct_data; /* Scan to find existence of the device */ err = nand_scan(this, 1); diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index 0f63ff6f7fe7..107208311987 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -22,6 +22,7 @@ #define FPGA_NAND_DATA_SHIFT 16 struct socrates_nand_host { + struct nand_controller controller; struct nand_chip nand_chip; void __iomem *io_base; struct device *dev; @@ -116,6 +117,18 @@ static int socrates_nand_device_ready(struct nand_chip *nand_chip) return 1; } +static int socrates_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops socrates_ops = { + .attach_chip = socrates_attach_chip, +}; + /* * Probe for the NAND device. */ @@ -141,6 +154,10 @@ static int socrates_nand_probe(struct platform_device *ofdev) mtd = nand_to_mtd(nand_chip); host->dev = &ofdev->dev; + nand_controller_init(&host->controller); + host->controller.ops = &socrates_ops; + nand_chip->controller = &host->controller; + /* link the private data structures */ nand_set_controller_data(nand_chip, host); nand_set_flash_node(nand_chip, ofdev->dev.of_node); @@ -153,10 +170,6 @@ static int socrates_nand_probe(struct platform_device *ofdev) nand_chip->legacy.read_buf = socrates_nand_read_buf; nand_chip->legacy.dev_ready = socrates_nand_device_ready; - /* enable ECC */ - nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - nand_chip->ecc.algo = NAND_ECC_ALGO_HAMMING; - /* TODO: I have no idea what real delay is. */ nand_chip->legacy.chip_delay = 20; /* 20us command delay time */ diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c index 235a2f7b1bad..aa6c7e7bbf1b 100644 --- a/drivers/mtd/nand/raw/tmio_nand.c +++ b/drivers/mtd/nand/raw/tmio_nand.c @@ -103,6 +103,7 @@ /*--------------------------------------------------------------------------*/ struct tmio_nand { + struct nand_controller controller; struct nand_chip chip; struct completion comp; @@ -355,6 +356,25 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) cell->disable(dev); } +static int tmio_attach_chip(struct nand_chip *chip) +{ + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.size = 512; + chip->ecc.bytes = 6; + chip->ecc.strength = 2; + chip->ecc.hwctl = tmio_nand_enable_hwecc; + chip->ecc.calculate = tmio_nand_calculate_ecc; + chip->ecc.correct = tmio_nand_correct_data; + + return 0; +} + +static const struct nand_controller_ops tmio_ops = { + .attach_chip = tmio_attach_chip, +}; + static int tmio_probe(struct platform_device *dev) { struct tmio_nand_data *data = dev_get_platdata(&dev->dev); @@ -385,6 +405,10 @@ static int tmio_probe(struct platform_device *dev) mtd->name = "tmio-nand"; mtd->dev.parent = &dev->dev; + nand_controller_init(&tmio->controller); + tmio->controller.ops = &tmio_ops; + nand_chip->controller = &tmio->controller; + tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr)); if (!tmio->ccr) return -EIO; @@ -409,15 +433,6 @@ static int tmio_probe(struct platform_device *dev) nand_chip->legacy.write_buf = tmio_nand_write_buf; nand_chip->legacy.read_buf = tmio_nand_read_buf; - /* set eccmode using hardware ECC */ - nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - nand_chip->ecc.size = 512; - nand_chip->ecc.bytes = 6; - nand_chip->ecc.strength = 2; - nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; - nand_chip->ecc.calculate = tmio_nand_calculate_ecc; - nand_chip->ecc.correct = tmio_nand_correct_data; - if (data) nand_chip->badblock_pattern = data->badblock_pattern; diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index ef81dce6b5c4..fe8ed2441588 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -253,6 +253,11 @@ static int txx9ndfmc_attach_chip(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) + return 0; + + chip->ecc.strength = 1; + if (mtd->writesize >= 512) { chip->ecc.size = 512; chip->ecc.bytes = 6; @@ -261,6 +266,10 @@ static int txx9ndfmc_attach_chip(struct nand_chip *chip) chip->ecc.bytes = 3; } + chip->ecc.calculate = txx9ndfmc_calculate_ecc; + chip->ecc.correct = txx9ndfmc_correct_data; + chip->ecc.hwctl = txx9ndfmc_enable_hwecc; + return 0; } @@ -326,11 +335,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) chip->legacy.write_buf = txx9ndfmc_write_buf; chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl; chip->legacy.dev_ready = txx9ndfmc_dev_ready; - chip->ecc.calculate = txx9ndfmc_calculate_ecc; - chip->ecc.correct = txx9ndfmc_correct_data; - chip->ecc.hwctl = txx9ndfmc_enable_hwecc; - chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; - chip->ecc.strength = 1; chip->legacy.chip_delay = 100; chip->controller = &drvdata->controller; diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index f2dbd63a5c1f..efc5bf5434e0 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -62,6 +62,7 @@ #define NAND_CON_NANDM 1 struct xway_nand_data { + struct nand_controller controller; struct nand_chip chip; unsigned long csflags; void __iomem *nandaddr; @@ -145,6 +146,18 @@ static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len) xway_writeb(nand_to_mtd(chip), NAND_WRITE_DATA, buf[i]); } +static int xway_attach_chip(struct nand_chip *chip) +{ + chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; + + return 0; +} + +static const struct nand_controller_ops xway_nand_ops = { + .attach_chip = xway_attach_chip, +}; + /* * Probe for the NAND device. */ @@ -180,8 +193,9 @@ static int xway_nand_probe(struct platform_device *pdev) data->chip.legacy.read_byte = xway_read_byte; data->chip.legacy.chip_delay = 30; - data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; - data->chip.ecc.algo = NAND_ECC_ALGO_HAMMING; + nand_controller_init(&data->controller); + data->controller.ops = &xway_nand_ops; + data->chip.controller = &data->controller; platform_set_drvdata(pdev, data); nand_set_controller_data(&data->chip, data); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 71c9677d135f..e0880a3840d7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1459,7 +1459,39 @@ static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave) slave->dev->flags &= ~IFF_SLAVE; } -static struct slave *bond_alloc_slave(struct bonding *bond) +static void slave_kobj_release(struct kobject *kobj) +{ + struct slave *slave = to_slave(kobj); + struct bonding *bond = bond_get_bond_by_slave(slave); + + cancel_delayed_work_sync(&slave->notify_work); + if (BOND_MODE(bond) == BOND_MODE_8023AD) + kfree(SLAVE_AD_INFO(slave)); + + kfree(slave); +} + +static struct kobj_type slave_ktype = { + .release = slave_kobj_release, +#ifdef CONFIG_SYSFS + .sysfs_ops = &slave_sysfs_ops, +#endif +}; + +static int bond_kobj_init(struct slave *slave) +{ + int err; + + err = kobject_init_and_add(&slave->kobj, &slave_ktype, + &(slave->dev->dev.kobj), "bonding_slave"); + if (err) + kobject_put(&slave->kobj); + + return err; +} + +static struct slave *bond_alloc_slave(struct bonding *bond, + struct net_device *slave_dev) { struct slave *slave = NULL; @@ -1467,11 +1499,17 @@ static struct slave *bond_alloc_slave(struct bonding *bond) if (!slave) return NULL; + slave->bond = bond; + slave->dev = slave_dev; + + if (bond_kobj_init(slave)) + return NULL; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info), GFP_KERNEL); if (!SLAVE_AD_INFO(slave)) { - kfree(slave); + kobject_put(&slave->kobj); return NULL; } } @@ -1480,17 +1518,6 @@ static struct slave *bond_alloc_slave(struct bonding *bond) return slave; } -static void bond_free_slave(struct slave *slave) -{ - struct bonding *bond = bond_get_bond_by_slave(slave); - - cancel_delayed_work_sync(&slave->notify_work); - if (BOND_MODE(bond) == BOND_MODE_8023AD) - kfree(SLAVE_AD_INFO(slave)); - - kfree(slave); -} - static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info) { info->bond_mode = BOND_MODE(bond); @@ -1677,14 +1704,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, goto err_undo_flags; } - new_slave = bond_alloc_slave(bond); + new_slave = bond_alloc_slave(bond, slave_dev); if (!new_slave) { res = -ENOMEM; goto err_undo_flags; } - new_slave->bond = bond; - new_slave->dev = slave_dev; /* Set the new_slave's queue_id to be zero. Queue ID mapping * is set via sysfs or module option if desired. */ @@ -2006,7 +2031,7 @@ err_restore_mtu: dev_set_mtu(slave_dev, new_slave->original_mtu); err_free: - bond_free_slave(new_slave); + kobject_put(&new_slave->kobj); err_undo_flags: /* Enslave of first slave has failed and we need to fix master's mac */ @@ -2186,7 +2211,7 @@ static int __bond_release_one(struct net_device *bond_dev, if (!netif_is_bond_master(slave_dev)) slave_dev->priv_flags &= ~IFF_BONDING; - bond_free_slave(slave); + kobject_put(&slave->kobj); return 0; } diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c index 9b8346638f69..fd07561da034 100644 --- a/drivers/net/bonding/bond_sysfs_slave.c +++ b/drivers/net/bonding/bond_sysfs_slave.c @@ -121,7 +121,6 @@ static const struct slave_attribute *slave_attrs[] = { }; #define to_slave_attr(_at) container_of(_at, struct slave_attribute, attr) -#define to_slave(obj) container_of(obj, struct slave, kobj) static ssize_t slave_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -132,28 +131,15 @@ static ssize_t slave_show(struct kobject *kobj, return slave_attr->show(slave, buf); } -static const struct sysfs_ops slave_sysfs_ops = { +const struct sysfs_ops slave_sysfs_ops = { .show = slave_show, }; -static struct kobj_type slave_ktype = { -#ifdef CONFIG_SYSFS - .sysfs_ops = &slave_sysfs_ops, -#endif -}; - int bond_sysfs_slave_add(struct slave *slave) { const struct slave_attribute **a; int err; - err = kobject_init_and_add(&slave->kobj, &slave_ktype, - &(slave->dev->dev.kobj), "bonding_slave"); - if (err) { - kobject_put(&slave->kobj); - return err; - } - for (a = slave_attrs; *a; ++a) { err = sysfs_create_file(&slave->kobj, &((*a)->attr)); if (err) { @@ -171,6 +157,4 @@ void bond_sysfs_slave_del(struct slave *slave) for (a = slave_attrs; *a; ++a) sysfs_remove_file(&slave->kobj, &((*a)->attr)); - - kobject_put(&slave->kobj); } diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index a345e22f545e..553ff39199aa 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1033,7 +1033,7 @@ static const struct can_bittiming_const m_can_bittiming_const_31X = { .name = KBUILD_MODNAME, .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ .tseg1_max = 256, - .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ + .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ .tseg2_max = 128, .sjw_max = 128, .brp_min = 1, @@ -1385,6 +1385,8 @@ static int m_can_dev_setup(struct m_can_classdev *m_can_dev) &m_can_data_bittiming_const_31X; break; case 32: + case 33: + /* Support both MCAN version v3.2.x and v3.3.0 */ m_can_dev->can.bittiming_const = m_can_dev->bit_timing ? m_can_dev->bit_timing : &m_can_bittiming_const_31X; @@ -1653,7 +1655,7 @@ static int m_can_open(struct net_device *dev) INIT_WORK(&cdev->tx_work, m_can_tx_work_queue); err = request_threaded_irq(dev->irq, NULL, m_can_isr, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + IRQF_ONESHOT, dev->name, dev); } else { err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name, diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 3297eb7ecc9c..d0f2f5c73907 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -2735,6 +2735,10 @@ static int mcp251xfd_probe(struct spi_device *spi) u32 freq; int err; + if (!spi->irq) + return dev_err_probe(&spi->dev, -ENXIO, + "No IRQ specified (maybe node \"interrupts-extended\" in DT missing)!\n"); + rx_int = devm_gpiod_get_optional(&spi->dev, "microchip,rx-int", GPIOD_IN); if (PTR_ERR(rx_int) == -EPROBE_DEFER) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index a0336e895d94..0487095e1fd0 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -64,21 +64,27 @@ enum gs_can_identify_mode { }; /* data types passed between host and device */ + +/* The firmware on the original USB2CAN by Geschwister Schneider + * Technologie Entwicklungs- und Vertriebs UG exchanges all data + * between the host and the device in host byte order. This is done + * with the struct gs_host_config::byte_order member, which is sent + * first to indicate the desired byte order. + * + * The widely used open source firmware candleLight doesn't support + * this feature and exchanges the data in little endian byte order. + */ struct gs_host_config { - u32 byte_order; + __le32 byte_order; } __packed; -/* All data exchanged between host and device is exchanged in host byte order, - * thanks to the struct gs_host_config byte_order member, which is sent first - * to indicate the desired byte order. - */ struct gs_device_config { u8 reserved1; u8 reserved2; u8 reserved3; u8 icount; - u32 sw_version; - u32 hw_version; + __le32 sw_version; + __le32 hw_version; } __packed; #define GS_CAN_MODE_NORMAL 0 @@ -88,26 +94,26 @@ struct gs_device_config { #define GS_CAN_MODE_ONE_SHOT BIT(3) struct gs_device_mode { - u32 mode; - u32 flags; + __le32 mode; + __le32 flags; } __packed; struct gs_device_state { - u32 state; - u32 rxerr; - u32 txerr; + __le32 state; + __le32 rxerr; + __le32 txerr; } __packed; struct gs_device_bittiming { - u32 prop_seg; - u32 phase_seg1; - u32 phase_seg2; - u32 sjw; - u32 brp; + __le32 prop_seg; + __le32 phase_seg1; + __le32 phase_seg2; + __le32 sjw; + __le32 brp; } __packed; struct gs_identify_mode { - u32 mode; + __le32 mode; } __packed; #define GS_CAN_FEATURE_LISTEN_ONLY BIT(0) @@ -118,23 +124,23 @@ struct gs_identify_mode { #define GS_CAN_FEATURE_IDENTIFY BIT(5) struct gs_device_bt_const { - u32 feature; - u32 fclk_can; - u32 tseg1_min; - u32 tseg1_max; - u32 tseg2_min; - u32 tseg2_max; - u32 sjw_max; - u32 brp_min; - u32 brp_max; - u32 brp_inc; + __le32 feature; + __le32 fclk_can; + __le32 tseg1_min; + __le32 tseg1_max; + __le32 tseg2_min; + __le32 tseg2_max; + __le32 sjw_max; + __le32 brp_min; + __le32 brp_max; + __le32 brp_inc; } __packed; #define GS_CAN_FLAG_OVERFLOW 1 struct gs_host_frame { u32 echo_id; - u32 can_id; + __le32 can_id; u8 can_dlc; u8 channel; @@ -330,13 +336,13 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) if (!skb) return; - cf->can_id = hf->can_id; + cf->can_id = le32_to_cpu(hf->can_id); can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode); memcpy(cf->data, hf->data, 8); /* ERROR frames tell us information about the controller */ - if (hf->can_id & CAN_ERR_FLAG) + if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG) gs_update_state(dev, cf); netdev->stats.rx_packets++; @@ -419,11 +425,11 @@ static int gs_usb_set_bittiming(struct net_device *netdev) if (!dbt) return -ENOMEM; - dbt->prop_seg = bt->prop_seg; - dbt->phase_seg1 = bt->phase_seg1; - dbt->phase_seg2 = bt->phase_seg2; - dbt->sjw = bt->sjw; - dbt->brp = bt->brp; + dbt->prop_seg = cpu_to_le32(bt->prop_seg); + dbt->phase_seg1 = cpu_to_le32(bt->phase_seg1); + dbt->phase_seg2 = cpu_to_le32(bt->phase_seg2); + dbt->sjw = cpu_to_le32(bt->sjw); + dbt->brp = cpu_to_le32(bt->brp); /* request bit timings */ rc = usb_control_msg(interface_to_usbdev(intf), @@ -504,7 +510,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, cf = (struct can_frame *)skb->data; - hf->can_id = cf->can_id; + hf->can_id = cpu_to_le32(cf->can_id); hf->can_dlc = can_get_cc_dlc(cf, dev->can.ctrlmode); memcpy(hf->data, cf->data, cf->len); @@ -575,6 +581,7 @@ static int gs_can_open(struct net_device *netdev) int rc, i; struct gs_device_mode *dm; u32 ctrlmode; + u32 flags = 0; rc = open_candev(netdev); if (rc) @@ -642,24 +649,24 @@ static int gs_can_open(struct net_device *netdev) /* flags */ ctrlmode = dev->can.ctrlmode; - dm->flags = 0; if (ctrlmode & CAN_CTRLMODE_LOOPBACK) - dm->flags |= GS_CAN_MODE_LOOP_BACK; + flags |= GS_CAN_MODE_LOOP_BACK; else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) - dm->flags |= GS_CAN_MODE_LISTEN_ONLY; + flags |= GS_CAN_MODE_LISTEN_ONLY; /* Controller is not allowed to retry TX * this mode is unavailable on atmels uc3c hardware */ if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) - dm->flags |= GS_CAN_MODE_ONE_SHOT; + flags |= GS_CAN_MODE_ONE_SHOT; if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) - dm->flags |= GS_CAN_MODE_TRIPLE_SAMPLE; + flags |= GS_CAN_MODE_TRIPLE_SAMPLE; /* finally start device */ - dm->mode = GS_CAN_MODE_START; + dm->mode = cpu_to_le32(GS_CAN_MODE_START); + dm->flags = cpu_to_le32(flags); rc = usb_control_msg(interface_to_usbdev(dev->iface), usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0), GS_USB_BREQ_MODE, @@ -739,9 +746,9 @@ static int gs_usb_set_identify(struct net_device *netdev, bool do_identify) return -ENOMEM; if (do_identify) - imode->mode = GS_CAN_IDENTIFY_ON; + imode->mode = cpu_to_le32(GS_CAN_IDENTIFY_ON); else - imode->mode = GS_CAN_IDENTIFY_OFF; + imode->mode = cpu_to_le32(GS_CAN_IDENTIFY_OFF); rc = usb_control_msg(interface_to_usbdev(dev->iface), usb_sndctrlpipe(interface_to_usbdev(dev->iface), @@ -792,6 +799,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct net_device *netdev; int rc; struct gs_device_bt_const *bt_const; + u32 feature; bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL); if (!bt_const) @@ -832,14 +840,14 @@ static struct gs_can *gs_make_candev(unsigned int channel, /* dev setup */ strcpy(dev->bt_const.name, "gs_usb"); - dev->bt_const.tseg1_min = bt_const->tseg1_min; - dev->bt_const.tseg1_max = bt_const->tseg1_max; - dev->bt_const.tseg2_min = bt_const->tseg2_min; - dev->bt_const.tseg2_max = bt_const->tseg2_max; - dev->bt_const.sjw_max = bt_const->sjw_max; - dev->bt_const.brp_min = bt_const->brp_min; - dev->bt_const.brp_max = bt_const->brp_max; - dev->bt_const.brp_inc = bt_const->brp_inc; + dev->bt_const.tseg1_min = le32_to_cpu(bt_const->tseg1_min); + dev->bt_const.tseg1_max = le32_to_cpu(bt_const->tseg1_max); + dev->bt_const.tseg2_min = le32_to_cpu(bt_const->tseg2_min); + dev->bt_const.tseg2_max = le32_to_cpu(bt_const->tseg2_max); + dev->bt_const.sjw_max = le32_to_cpu(bt_const->sjw_max); + dev->bt_const.brp_min = le32_to_cpu(bt_const->brp_min); + dev->bt_const.brp_max = le32_to_cpu(bt_const->brp_max); + dev->bt_const.brp_inc = le32_to_cpu(bt_const->brp_inc); dev->udev = interface_to_usbdev(intf); dev->iface = intf; @@ -856,28 +864,29 @@ static struct gs_can *gs_make_candev(unsigned int channel, /* can setup */ dev->can.state = CAN_STATE_STOPPED; - dev->can.clock.freq = bt_const->fclk_can; + dev->can.clock.freq = le32_to_cpu(bt_const->fclk_can); dev->can.bittiming_const = &dev->bt_const; dev->can.do_set_bittiming = gs_usb_set_bittiming; dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC; - if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY) + feature = le32_to_cpu(bt_const->feature); + if (feature & GS_CAN_FEATURE_LISTEN_ONLY) dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY; - if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK) + if (feature & GS_CAN_FEATURE_LOOP_BACK) dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK; - if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE) + if (feature & GS_CAN_FEATURE_TRIPLE_SAMPLE) dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; - if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT) + if (feature & GS_CAN_FEATURE_ONE_SHOT) dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; SET_NETDEV_DEV(netdev, &intf->dev); - if (dconf->sw_version > 1) - if (bt_const->feature & GS_CAN_FEATURE_IDENTIFY) + if (le32_to_cpu(dconf->sw_version) > 1) + if (feature & GS_CAN_FEATURE_IDENTIFY) netdev->ethtool_ops = &gs_usb_ethtool_ops; kfree(bt_const); @@ -912,7 +921,7 @@ static int gs_usb_probe(struct usb_interface *intf, if (!hconf) return -ENOMEM; - hconf->byte_order = 0x0000beef; + hconf->byte_order = cpu_to_le32(0x0000beef); /* send host config */ rc = usb_control_msg(interface_to_usbdev(intf), diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index ad30cacc1622..032ab9f20438 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -516,6 +516,7 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, { struct ena_com_rx_buf_info *ena_buf = &ena_rx_ctx->ena_bufs[0]; struct ena_eth_io_rx_cdesc_base *cdesc = NULL; + u16 q_depth = io_cq->q_depth; u16 cdesc_idx = 0; u16 nb_hw_desc; u16 i = 0; @@ -543,6 +544,8 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, do { ena_buf[i].len = cdesc->length; ena_buf[i].req_id = cdesc->req_id; + if (unlikely(ena_buf[i].req_id >= q_depth)) + return -EIO; if (++i >= nb_hw_desc) break; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e8131dadc22c..df1884d57d1a 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -789,24 +789,6 @@ static void ena_free_all_io_tx_resources(struct ena_adapter *adapter) adapter->num_io_queues); } -static int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id) -{ - if (likely(req_id < rx_ring->ring_size)) - return 0; - - netif_err(rx_ring->adapter, rx_err, rx_ring->netdev, - "Invalid rx req_id: %hu\n", req_id); - - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->rx_stats.bad_req_id++; - u64_stats_update_end(&rx_ring->syncp); - - /* Trigger device reset */ - rx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID; - set_bit(ENA_FLAG_TRIGGER_RESET, &rx_ring->adapter->flags); - return -EFAULT; -} - /* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors) * @adapter: network interface device structure * @qid: queue index @@ -926,10 +908,14 @@ static void ena_free_all_io_rx_resources(struct ena_adapter *adapter) static int ena_alloc_rx_page(struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info, gfp_t gfp) { + int headroom = rx_ring->rx_headroom; struct ena_com_buf *ena_buf; struct page *page; dma_addr_t dma; + /* restore page offset value in case it has been changed by device */ + rx_info->page_offset = headroom; + /* if previous allocated page is not used */ if (unlikely(rx_info->page)) return 0; @@ -959,10 +945,9 @@ static int ena_alloc_rx_page(struct ena_ring *rx_ring, "Allocate page %p, rx_info %p\n", page, rx_info); rx_info->page = page; - rx_info->page_offset = 0; ena_buf = &rx_info->ena_buf; - ena_buf->paddr = dma + rx_ring->rx_headroom; - ena_buf->len = ENA_PAGE_SIZE - rx_ring->rx_headroom; + ena_buf->paddr = dma + headroom; + ena_buf->len = ENA_PAGE_SIZE - headroom; return 0; } @@ -1356,15 +1341,10 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info; u16 len, req_id, buf = 0; void *va; - int rc; len = ena_bufs[buf].len; req_id = ena_bufs[buf].req_id; - rc = validate_rx_req_id(rx_ring, req_id); - if (unlikely(rc < 0)) - return NULL; - rx_info = &rx_ring->rx_buffer_info[req_id]; if (unlikely(!rx_info->page)) { @@ -1379,7 +1359,8 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, /* save virt address of first buffer */ va = page_address(rx_info->page) + rx_info->page_offset; - prefetch(va + NET_IP_ALIGN); + + prefetch(va); if (len <= rx_ring->rx_copybreak) { skb = ena_alloc_skb(rx_ring, false); @@ -1420,8 +1401,6 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, rx_info->page_offset, len, ENA_PAGE_SIZE); - /* The offset is non zero only for the first buffer */ - rx_info->page_offset = 0; netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "RX skb updated. len %d. data_len %d\n", @@ -1440,10 +1419,6 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, len = ena_bufs[buf].len; req_id = ena_bufs[buf].req_id; - rc = validate_rx_req_id(rx_ring, req_id); - if (unlikely(rc < 0)) - return NULL; - rx_info = &rx_ring->rx_buffer_info[req_id]; } while (1); @@ -1544,8 +1519,7 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp) int ret; rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id]; - xdp->data = page_address(rx_info->page) + - rx_info->page_offset + rx_ring->rx_headroom; + xdp->data = page_address(rx_info->page) + rx_info->page_offset; xdp_set_data_meta_invalid(xdp); xdp->data_hard_start = page_address(rx_info->page); xdp->data_end = xdp->data + rx_ring->ena_bufs[0].len; @@ -1612,8 +1586,9 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, if (unlikely(ena_rx_ctx.descs == 0)) break; + /* First descriptor might have an offset set by the device */ rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id]; - rx_info->page_offset = ena_rx_ctx.pkt_offset; + rx_info->page_offset += ena_rx_ctx.pkt_offset; netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n", @@ -1697,12 +1672,18 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, error: adapter = netdev_priv(rx_ring->netdev); - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->rx_stats.bad_desc_num++; - u64_stats_update_end(&rx_ring->syncp); + if (rc == -ENOSPC) { + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->rx_stats.bad_desc_num++; + u64_stats_update_end(&rx_ring->syncp); + adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS; + } else { + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->rx_stats.bad_req_id++; + u64_stats_update_end(&rx_ring->syncp); + adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID; + } - /* Too many desc from the device. Trigger reset */ - adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS; set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); return 0; @@ -3388,16 +3369,9 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev, goto err_mmio_read_less; } - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_width)); + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_width)); if (rc) { - dev_err(dev, "pci_set_dma_mask failed 0x%x\n", rc); - goto err_mmio_read_less; - } - - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(dma_width)); - if (rc) { - dev_err(dev, "err_pci_set_consistent_dma_mask failed 0x%x\n", - rc); + dev_err(dev, "dma_set_mask_and_coherent failed %d\n", rc); goto err_mmio_read_less; } @@ -4167,6 +4141,12 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(ENA_MAX_PHYS_ADDR_SIZE_BITS)); + if (rc) { + dev_err(&pdev->dev, "dma_set_mask_and_coherent failed %d\n", rc); + goto err_disable_device; + } + pci_set_master(pdev); ena_dev = vzalloc(sizeof(*ena_dev)); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 4f913658eea4..24122ccda614 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -413,85 +413,63 @@ int aq_ring_rx_clean(struct aq_ring_s *self, buff->rxdata.pg_off, buff->len, DMA_FROM_DEVICE); - /* for single fragment packets use build_skb() */ - if (buff->is_eop && - buff->len <= AQ_CFG_RX_FRAME_MAX - AQ_SKB_ALIGN) { - skb = build_skb(aq_buf_vaddr(&buff->rxdata), + skb = napi_alloc_skb(napi, AQ_CFG_RX_HDR_SIZE); + if (unlikely(!skb)) { + u64_stats_update_begin(&self->stats.rx.syncp); + self->stats.rx.skb_alloc_fails++; + u64_stats_update_end(&self->stats.rx.syncp); + err = -ENOMEM; + goto err_exit; + } + if (is_ptp_ring) + buff->len -= + aq_ptp_extract_ts(self->aq_nic, skb, + aq_buf_vaddr(&buff->rxdata), + buff->len); + + hdr_len = buff->len; + if (hdr_len > AQ_CFG_RX_HDR_SIZE) + hdr_len = eth_get_headlen(skb->dev, + aq_buf_vaddr(&buff->rxdata), + AQ_CFG_RX_HDR_SIZE); + + memcpy(__skb_put(skb, hdr_len), aq_buf_vaddr(&buff->rxdata), + ALIGN(hdr_len, sizeof(long))); + + if (buff->len - hdr_len > 0) { + skb_add_rx_frag(skb, 0, buff->rxdata.page, + buff->rxdata.pg_off + hdr_len, + buff->len - hdr_len, AQ_CFG_RX_FRAME_MAX); - if (unlikely(!skb)) { - u64_stats_update_begin(&self->stats.rx.syncp); - self->stats.rx.skb_alloc_fails++; - u64_stats_update_end(&self->stats.rx.syncp); - err = -ENOMEM; - goto err_exit; - } - if (is_ptp_ring) - buff->len -= - aq_ptp_extract_ts(self->aq_nic, skb, - aq_buf_vaddr(&buff->rxdata), - buff->len); - skb_put(skb, buff->len); page_ref_inc(buff->rxdata.page); - } else { - skb = napi_alloc_skb(napi, AQ_CFG_RX_HDR_SIZE); - if (unlikely(!skb)) { - u64_stats_update_begin(&self->stats.rx.syncp); - self->stats.rx.skb_alloc_fails++; - u64_stats_update_end(&self->stats.rx.syncp); - err = -ENOMEM; - goto err_exit; - } - if (is_ptp_ring) - buff->len -= - aq_ptp_extract_ts(self->aq_nic, skb, - aq_buf_vaddr(&buff->rxdata), - buff->len); - - hdr_len = buff->len; - if (hdr_len > AQ_CFG_RX_HDR_SIZE) - hdr_len = eth_get_headlen(skb->dev, - aq_buf_vaddr(&buff->rxdata), - AQ_CFG_RX_HDR_SIZE); - - memcpy(__skb_put(skb, hdr_len), aq_buf_vaddr(&buff->rxdata), - ALIGN(hdr_len, sizeof(long))); - - if (buff->len - hdr_len > 0) { - skb_add_rx_frag(skb, 0, buff->rxdata.page, - buff->rxdata.pg_off + hdr_len, - buff->len - hdr_len, - AQ_CFG_RX_FRAME_MAX); - page_ref_inc(buff->rxdata.page); - } + } - if (!buff->is_eop) { - buff_ = buff; - i = 1U; - do { - next_ = buff_->next, - buff_ = &self->buff_ring[next_]; + if (!buff->is_eop) { + buff_ = buff; + i = 1U; + do { + next_ = buff_->next; + buff_ = &self->buff_ring[next_]; - dma_sync_single_range_for_cpu( - aq_nic_get_dev(self->aq_nic), - buff_->rxdata.daddr, - buff_->rxdata.pg_off, - buff_->len, - DMA_FROM_DEVICE); - skb_add_rx_frag(skb, i++, - buff_->rxdata.page, - buff_->rxdata.pg_off, - buff_->len, - AQ_CFG_RX_FRAME_MAX); - page_ref_inc(buff_->rxdata.page); - buff_->is_cleaned = 1; - - buff->is_ip_cso &= buff_->is_ip_cso; - buff->is_udp_cso &= buff_->is_udp_cso; - buff->is_tcp_cso &= buff_->is_tcp_cso; - buff->is_cso_err |= buff_->is_cso_err; + dma_sync_single_range_for_cpu(aq_nic_get_dev(self->aq_nic), + buff_->rxdata.daddr, + buff_->rxdata.pg_off, + buff_->len, + DMA_FROM_DEVICE); + skb_add_rx_frag(skb, i++, + buff_->rxdata.page, + buff_->rxdata.pg_off, + buff_->len, + AQ_CFG_RX_FRAME_MAX); + page_ref_inc(buff_->rxdata.page); + buff_->is_cleaned = 1; - } while (!buff_->is_eop); - } + buff->is_ip_cso &= buff_->is_ip_cso; + buff->is_udp_cso &= buff_->is_udp_cso; + buff->is_tcp_cso &= buff_->is_tcp_cso; + buff->is_cso_err |= buff_->is_cso_err; + + } while (!buff_->is_eop); } if (buff->is_vlan) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7c21aaa8b9af..0af0af2b70fe 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -11590,7 +11590,8 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) != 0 && dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) { dev_err(&pdev->dev, "System does not support DMA, aborting\n"); - goto init_err_disable; + rc = -EIO; + goto init_err_release; } pci_set_master(pdev); @@ -12674,6 +12675,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) create_singlethread_workqueue("bnxt_pf_wq"); if (!bnxt_pf_wq) { dev_err(&pdev->dev, "Unable to create workqueue.\n"); + rc = -ENOMEM; goto init_err_pci_clean; } } diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig index 87cc0ef68b31..8ba0e08e5e64 100644 --- a/drivers/net/ethernet/chelsio/Kconfig +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -68,7 +68,7 @@ config CHELSIO_T3 config CHELSIO_T4 tristate "Chelsio Communications T4/T5/T6 Ethernet support" - depends on PCI && (IPV6 || IPV6=n) + depends on PCI && (IPV6 || IPV6=n) && (TLS || TLS=n) select FW_LOADER select MDIO select ZLIB_DEFLATE diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index 4e55f7081644..83b46440408b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -880,7 +880,8 @@ int set_filter_wr(struct adapter *adapter, int fidx) FW_FILTER_WR_OVLAN_VLD_V(f->fs.val.ovlan_vld) | FW_FILTER_WR_IVLAN_VLDM_V(f->fs.mask.ivlan_vld) | FW_FILTER_WR_OVLAN_VLDM_V(f->fs.mask.ovlan_vld)); - fwr->smac_sel = f->smt->idx; + if (f->fs.newsmac) + fwr->smac_sel = f->smt->idx; fwr->rx_chan_rx_rpl_iq = htons(FW_FILTER_WR_RX_CHAN_V(0) | FW_FILTER_WR_RX_RPL_IQ_V(adapter->sge.fw_evtq.abs_id)); diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c index c24485c0d512..7f90b828d159 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c @@ -544,7 +544,9 @@ static int chcr_ktls_dev_add(struct net_device *netdev, struct sock *sk, /* need to wait for hw response, can't free tx_info yet. */ if (tx_info->open_state == CH_KTLS_OPEN_PENDING) tx_info->pending_close = true; - /* free the lock after the cleanup */ + else + spin_unlock_bh(&tx_info->lock); + /* if in pending close, free the lock after the cleanup */ goto put_module; } spin_unlock_bh(&tx_info->lock); diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index cfd369cf4c8c..ee7a906e30b3 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -4,6 +4,8 @@ config FSL_DPAA2_ETH depends on FSL_MC_BUS && FSL_MC_DPIO select PHYLINK select PCS_LYNX + select FSL_XGMAC_MDIO + select NET_DEVLINK help This is the DPAA2 Ethernet driver supporting Freescale SoCs with DPAA2 (DataPath Acceleration Architecture v2). diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index aeb21dc48099..a9aee219fb58 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -92,18 +92,8 @@ static int enetc_setup_taprio(struct net_device *ndev, gcl_config->atc = 0xff; gcl_config->acl_len = cpu_to_le16(gcl_len); - if (!admin_conf->base_time) { - gcl_data->btl = - cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0)); - gcl_data->bth = - cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1)); - } else { - gcl_data->btl = - cpu_to_le32(lower_32_bits(admin_conf->base_time)); - gcl_data->bth = - cpu_to_le32(upper_32_bits(admin_conf->base_time)); - } - + gcl_data->btl = cpu_to_le32(lower_32_bits(admin_conf->base_time)); + gcl_data->bth = cpu_to_le32(upper_32_bits(admin_conf->base_time)); gcl_data->ct = cpu_to_le32(admin_conf->cycle_time); gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension); diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 9fe43ab0496d..cdd1ff9aa9c4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2156,8 +2156,11 @@ static int do_reset(struct ibmvnic_adapter *adapter, for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); - if (adapter->reset_reason != VNIC_RESET_FAILOVER) + if (adapter->reset_reason == VNIC_RESET_FAILOVER || + adapter->reset_reason == VNIC_RESET_MOBILITY) { call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev); + call_netdevice_notifiers(NETDEV_RESEND_IGMP, netdev); + } rc = 0; @@ -2227,6 +2230,9 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter, if (rc) return IBMVNIC_OPEN_FAILED; + call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, netdev); + call_netdevice_notifiers(NETDEV_RESEND_IGMP, netdev); + return 0; } @@ -2291,7 +2297,6 @@ static void __ibmvnic_reset(struct work_struct *work) if (!saved_state) { reset_state = adapter->state; - adapter->state = VNIC_RESETTING; saved_state = true; } spin_unlock_irqrestore(&adapter->state_lock, flags); @@ -2432,6 +2437,12 @@ static void ibmvnic_tx_timeout(struct net_device *dev, unsigned int txqueue) { struct ibmvnic_adapter *adapter = netdev_priv(dev); + if (test_bit(0, &adapter->resetting)) { + netdev_err(adapter->netdev, + "Adapter is resetting, skip timeout reset\n"); + return; + } + ibmvnic_reset(adapter, VNIC_RESET_TIMEOUT); } @@ -2963,6 +2974,9 @@ static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter) { int i, rc; + if (!adapter->tx_scrq || !adapter->rx_scrq) + return -EINVAL; + for (i = 0; i < adapter->req_tx_queues; i++) { netdev_dbg(adapter->netdev, "Re-setting tx_scrq[%d]\n", i); rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]); @@ -5044,6 +5058,9 @@ static int ibmvnic_reset_crq(struct ibmvnic_adapter *adapter) } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); /* Clean out the queue */ + if (!crq->msgs) + return -EINVAL; + memset(crq->msgs, 0, PAGE_SIZE); crq->cur = 0; crq->active = false; @@ -5348,7 +5365,7 @@ static int ibmvnic_remove(struct vio_dev *dev) unsigned long flags; spin_lock_irqsave(&adapter->state_lock, flags); - if (adapter->state == VNIC_RESETTING) { + if (test_bit(0, &adapter->resetting)) { spin_unlock_irqrestore(&adapter->state_lock, flags); return -EBUSY; } diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 9911d926dd7f..9d0c32ad763b 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -943,8 +943,7 @@ enum vnic_state {VNIC_PROBING = 1, VNIC_CLOSING, VNIC_CLOSED, VNIC_REMOVING, - VNIC_REMOVED, - VNIC_RESETTING}; + VNIC_REMOVED}; enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1, VNIC_RESET_MOBILITY, diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 537300e762f0..d231a2cdd98f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -140,6 +140,7 @@ enum i40e_state_t { __I40E_CLIENT_RESET, __I40E_VIRTCHNL_OP_PENDING, __I40E_RECOVERY_MODE, + __I40E_VF_RESETS_DISABLED, /* disable resets during i40e_remove */ /* This must be last as it determines the size of the BITMAP */ __I40E_STATE_SIZE__, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 4f8a2154b93f..1337686bd099 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4010,8 +4010,16 @@ static irqreturn_t i40e_intr(int irq, void *data) } if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) { - ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; - set_bit(__I40E_VFLR_EVENT_PENDING, pf->state); + /* disable any further VFLR event notifications */ + if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) { + u32 reg = rd32(hw, I40E_PFINT_ICR0_ENA); + + reg &= ~I40E_PFINT_ICR0_VFLR_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, reg); + } else { + ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; + set_bit(__I40E_VFLR_EVENT_PENDING, pf->state); + } } if (icr0 & I40E_PFINT_ICR0_GRST_MASK) { @@ -15311,6 +15319,11 @@ static void i40e_remove(struct pci_dev *pdev) while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) usleep_range(1000, 2000); + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + set_bit(__I40E_VF_RESETS_DISABLED, pf->state); + i40e_free_vfs(pf); + pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; + } /* no more scheduling of any task */ set_bit(__I40E_SUSPENDED, pf->state); set_bit(__I40E_DOWN, pf->state); @@ -15337,11 +15350,6 @@ static void i40e_remove(struct pci_dev *pdev) */ i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false); - if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { - i40e_free_vfs(pf); - pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; - } - i40e_fdir_teardown(pf); /* If there is a switch structure or any orphans, remove them. diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 2532f8eed6a8..729c4f0d5ac5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1403,7 +1403,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) * @vf: pointer to the VF structure * @flr: VFLR was issued or not * - * Returns true if the VF is reset, false otherwise. + * Returns true if the VF is in reset, resets successfully, or resets + * are disabled and false otherwise. **/ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) { @@ -1413,11 +1414,14 @@ bool i40e_reset_vf(struct i40e_vf *vf, bool flr) u32 reg; int i; + if (test_bit(__I40E_VF_RESETS_DISABLED, pf->state)) + return true; + /* If the VFs have been disabled, this means something else is * resetting the VF, so we shouldn't continue. */ if (test_and_set_bit(__I40E_VF_DISABLE, pf->state)) - return false; + return true; i40e_trigger_vf_reset(vf, flr); @@ -1581,6 +1585,15 @@ void i40e_free_vfs(struct i40e_pf *pf) i40e_notify_client_of_vf_enable(pf, 0); + /* Disable IOV before freeing resources. This lets any VF drivers + * running in the host get themselves cleaned up before we yank + * the carpet out from underneath their feet. + */ + if (!pci_vfs_assigned(pf->pdev)) + pci_disable_sriov(pf->pdev); + else + dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n"); + /* Amortize wait time by stopping all VFs at the same time */ for (i = 0; i < pf->num_alloc_vfs; i++) { if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states)) @@ -1596,15 +1609,6 @@ void i40e_free_vfs(struct i40e_pf *pf) i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]); } - /* Disable IOV before freeing resources. This lets any VF drivers - * running in the host get themselves cleaned up before we yank - * the carpet out from underneath their feet. - */ - if (!pci_vfs_assigned(pf->pdev)) - pci_disable_sriov(pf->pdev); - else - dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n"); - /* free up VF resources */ tmp = pf->num_alloc_vfs; pf->num_alloc_vfs = 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 3ed4f4cda7f9..29f765a246a0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -1193,7 +1193,6 @@ const struct stmmac_ops dwmac4_ops = { .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, - .flex_pps_config = dwmac5_flex_pps_config, .set_mac_loopback = dwmac4_set_mac_loopback, .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, @@ -1236,6 +1235,7 @@ const struct stmmac_ops dwmac410_ops = { .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, + .flex_pps_config = dwmac5_flex_pps_config, .set_mac_loopback = dwmac4_set_mac_loopback, .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7c62d82c57db..2dc1988a8973 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1921,12 +1921,15 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from) struct tun_file *tfile = file->private_data; struct tun_struct *tun = tun_get(tfile); ssize_t result; + int noblock = 0; if (!tun) return -EBADFD; - result = tun_get_user(tun, tfile, NULL, from, - file->f_flags & O_NONBLOCK, false); + if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT)) + noblock = 1; + + result = tun_get_user(tun, tfile, NULL, from, noblock, false); tun_put(tun); return result; @@ -2137,10 +2140,15 @@ static ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to) struct tun_file *tfile = file->private_data; struct tun_struct *tun = tun_get(tfile); ssize_t len = iov_iter_count(to), ret; + int noblock = 0; if (!tun) return -EBADFD; - ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL); + + if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT)) + noblock = 1; + + ret = tun_do_read(tun, tfile, to, noblock, NULL); ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index b09b45382faf..207e59e74935 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,7 +59,7 @@ #define IPHETH_USBINTF_SUBCLASS 253 #define IPHETH_USBINTF_PROTO 1 -#define IPHETH_BUF_SIZE 1516 +#define IPHETH_BUF_SIZE 1514 #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ #define IPHETH_TX_TIMEOUT (5 * HZ) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index d43e0d3f3a12..052413eef059 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2012-2014, 2018 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2012-2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -128,7 +126,9 @@ enum iwl_sta_flags { STA_FLG_MAX_AGG_SIZE_256K = (5 << STA_FLG_MAX_AGG_SIZE_SHIFT), STA_FLG_MAX_AGG_SIZE_512K = (6 << STA_FLG_MAX_AGG_SIZE_SHIFT), STA_FLG_MAX_AGG_SIZE_1024K = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), - STA_FLG_MAX_AGG_SIZE_MSK = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT), + STA_FLG_MAX_AGG_SIZE_2M = (8 << STA_FLG_MAX_AGG_SIZE_SHIFT), + STA_FLG_MAX_AGG_SIZE_4M = (9 << STA_FLG_MAX_AGG_SIZE_SHIFT), + STA_FLG_MAX_AGG_SIZE_MSK = (0xf << STA_FLG_MAX_AGG_SIZE_SHIFT), STA_FLG_AGG_MPDU_DENS_SHIFT = 23, STA_FLG_AGG_MPDU_DENS_2US = (4 << STA_FLG_AGG_MPDU_DENS_SHIFT), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index a731f28e101a..53b438d709db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -421,12 +421,14 @@ struct iwl_hs20_roc_res { * able to run the GO Negotiation. Will not be fragmented and not * repetitive. Valid only on the P2P Device MAC. Only the duration will * be taken into account. + * @SESSION_PROTECT_CONF_MAX_ID: not used */ enum iwl_mvm_session_prot_conf_id { SESSION_PROTECT_CONF_ASSOC, SESSION_PROTECT_CONF_GO_CLIENT_ASSOC, SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV, SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION, + SESSION_PROTECT_CONF_MAX_ID, }; /* SESSION_PROTECTION_CONF_ID_E_VER_1 */ /** @@ -459,7 +461,7 @@ struct iwl_mvm_session_prot_cmd { * @mac_id: the mac id for which the session protection started / ended * @status: 1 means success, 0 means failure * @start: 1 means the session protection started, 0 means it ended - * @conf_id: the configuration id of the session that started / eneded + * @conf_id: see &enum iwl_mvm_session_prot_conf_id * * Note that any session protection will always get two notifications: start * and end even the firmware could not schedule it. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index cb9e8e189a1a..1d48c7d7fffd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -147,6 +147,16 @@ #define CSR_MAC_SHADOW_REG_CTL2 (CSR_BASE + 0x0AC) #define CSR_MAC_SHADOW_REG_CTL2_RX_WAKE 0xFFFF +/* LTR control (since IWL_DEVICE_FAMILY_22000) */ +#define CSR_LTR_LONG_VAL_AD (CSR_BASE + 0x0D4) +#define CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ 0x80000000 +#define CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE 0x1c000000 +#define CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL 0x03ff0000 +#define CSR_LTR_LONG_VAL_AD_SNOOP_REQ 0x00008000 +#define CSR_LTR_LONG_VAL_AD_SNOOP_SCALE 0x00001c00 +#define CSR_LTR_LONG_VAL_AD_SNOOP_VAL 0x000003ff +#define CSR_LTR_LONG_VAL_AD_SCALE_USEC 2 + /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 688c1125e67b..b627e7da7ac9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3080,7 +3080,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, /* this would be a mac80211 bug ... but don't crash */ if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) - return -EINVAL; + return test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) ? 0 : -EINVAL; /* * If we are in a STA removal flow and in DQA mode: @@ -3127,6 +3127,9 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, goto out_unlock; } + if (vif->type == NL80211_IFTYPE_STATION) + vif->bss_conf.he_support = sta->he_cap.has_he; + if (sta->tdls && (vif->p2p || iwl_mvm_tdls_sta_count(mvm, NULL) == diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 017537944fd0..799d8219463c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -196,6 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, mpdu_dens = sta->ht_cap.ampdu_density; } + if (sta->vht_cap.vht_supported) { agg_size = sta->vht_cap.cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; @@ -205,6 +206,23 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, agg_size = sta->ht_cap.ampdu_factor; } + /* D6.0 10.12.2 A-MPDU length limit rules + * A STA indicates the maximum length of the A-MPDU preEOF padding + * that it can receive in an HE PPDU in the Maximum A-MPDU Length + * Exponent field in its HT Capabilities, VHT Capabilities, + * and HE 6 GHz Band Capabilities elements (if present) and the + * Maximum AMPDU Length Exponent Extension field in its HE + * Capabilities element + */ + if (sta->he_cap.has_he) + agg_size += u8_get_bits(sta->he_cap.he_cap_elem.mac_cap_info[3], + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); + + /* Limit to max A-MPDU supported by FW */ + if (agg_size > (STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT)) + agg_size = (STA_FLG_MAX_AGG_SIZE_4M >> + STA_FLG_MAX_AGG_SIZE_SHIFT); + add_sta_cmd.station_flags |= cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT); add_sta_cmd.station_flags |= diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 7fce79c1c114..1db6d8d38822 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -641,11 +641,32 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, } } +static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif) +{ + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + .conf_id = cpu_to_le32(mvmvif->time_event_data.id), + }; + int ret; + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); +} + static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data, u32 *uid) { u32 id; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); /* * It is possible that by the time we got to this point the time @@ -663,14 +684,29 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); spin_unlock_bh(&mvm->time_event_lock); - /* - * It is possible that by the time we try to remove it, the time event - * has already ended and removed. In such a case there is no need to - * send a removal command. + /* When session protection is supported, the te_data->id field + * is reused to save session protection's configuration. */ - if (id == TE_MAX) { - IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { + /* Session protection is still ongoing. Cancel it */ + iwl_mvm_cancel_session_protection(mvm, mvmvif); + if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_roc_finished(mvm); + } + } return false; + } else { + /* It is possible that by the time we try to remove it, the + * time event has already ended and removed. In such a case + * there is no need to send a removal command. + */ + if (id == TE_MAX) { + IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); + return false; + } } return true; @@ -771,6 +807,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; struct ieee80211_vif *vif; + struct iwl_mvm_vif *mvmvif; rcu_read_lock(); vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id), @@ -779,9 +816,10 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (!vif) goto out_unlock; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + /* The vif is not a P2P_DEVICE, maintain its time_event_data */ if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; @@ -816,10 +854,14 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { /* End TE, notify mac80211 */ + mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; ieee80211_remain_on_channel_expired(mvm->hw); set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); iwl_mvm_roc_finished(mvm); } else if (le32_to_cpu(notif->start)) { + if (WARN_ON(mvmvif->time_event_data.id != + le32_to_cpu(notif->conf_id))) + goto out_unlock; set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); ieee80211_ready_on_channel(mvm->hw); /* Start TE */ } @@ -845,20 +887,24 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + /* The time_event_data.id field is reused to save session + * protection's configuration. + */ switch (type) { case IEEE80211_ROC_TYPE_NORMAL: - cmd.conf_id = - cpu_to_le32(SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV); + mvmvif->time_event_data.id = + SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV; break; case IEEE80211_ROC_TYPE_MGMT_TX: - cmd.conf_id = - cpu_to_le32(SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION); + mvmvif->time_event_data.id = + SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION; break; default: WARN_ONCE(1, "Got an invalid ROC type\n"); return -EINVAL; } + cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id); return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, MAC_CONF_GROUP, 0), 0, sizeof(cmd), &cmd); @@ -960,25 +1006,6 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) __iwl_mvm_remove_time_event(mvm, te_data, &uid); } -static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif) -{ - struct iwl_mvm_session_prot_cmd cmd = { - .id_and_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)), - .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), - }; - int ret; - - ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, - MAC_CONF_GROUP, 0), - 0, sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, - "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); -} - void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif; @@ -988,10 +1015,13 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { mvmvif = iwl_mvm_vif_from_mac80211(vif); - iwl_mvm_cancel_session_protection(mvm, mvmvif); - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + iwl_mvm_cancel_session_protection(mvm, mvmvif); set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + } else { + iwl_mvm_remove_aux_roc_te(mvm, mvmvif, + &mvmvif->time_event_data); + } iwl_mvm_roc_finished(mvm); @@ -1126,10 +1156,15 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), - .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; + /* The time_event_data.id field is reused to save session + * protection's configuration. + */ + mvmvif->time_event_data.id = SESSION_PROTECT_CONF_ASSOC; + cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id); + lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->time_event_lock); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index a0352fa873d9..5512e3c630c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -252,6 +252,26 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, iwl_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL, CSR_AUTO_FUNC_BOOT_ENA); + + if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { + /* + * The firmware initializes this again later (to a smaller + * value), but for the boot process initialize the LTR to + * ~250 usec. + */ + u32 val = CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ | + u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC, + CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) | + u32_encode_bits(250, + CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) | + CSR_LTR_LONG_VAL_AD_SNOOP_REQ | + u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC, + CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) | + u32_encode_bits(250, CSR_LTR_LONG_VAL_AD_SNOOP_VAL); + + iwl_write32(trans, CSR_LTR_LONG_VAL_AD, val); + } + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); else diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d2e69ad53b27..2fffbbc8462f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2156,18 +2156,36 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords) { unsigned long flags; - int offs, ret = 0; + int offs = 0; u32 *vals = buf; - if (iwl_trans_grab_nic_access(trans, &flags)) { - iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); - for (offs = 0; offs < dwords; offs++) - vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - iwl_trans_release_nic_access(trans, &flags); - } else { - ret = -EBUSY; + while (offs < dwords) { + /* limit the time we spin here under lock to 1/2s */ + ktime_t timeout = ktime_add_us(ktime_get(), 500 * USEC_PER_MSEC); + + if (iwl_trans_grab_nic_access(trans, &flags)) { + iwl_write32(trans, HBUS_TARG_MEM_RADDR, + addr + 4 * offs); + + while (offs < dwords) { + vals[offs] = iwl_read32(trans, + HBUS_TARG_MEM_RDAT); + offs++; + + /* calling ktime_get is expensive so + * do it once in 128 reads + */ + if (offs % 128 == 0 && ktime_after(ktime_get(), + timeout)) + break; + } + iwl_trans_release_nic_access(trans, &flags); + } else { + return -EBUSY; + } } - return ret; + + return 0; } static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 042015bc8055..b2fd87834f23 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -1482,7 +1482,7 @@ static bool rtw_fw_dump_check_size(struct rtw_dev *rtwdev, int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size, u32 *buffer) { - if (!rtwdev->chip->fw_fifo_addr) { + if (!rtwdev->chip->fw_fifo_addr[0]) { rtw_dbg(rtwdev, RTW_DBG_FW, "chip not support dump fw fifo\n"); return -ENOTSUPP; } diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c index 0ffa389066a0..ae26594c7302 100644 --- a/drivers/nfc/s3fwrn5/i2c.c +++ b/drivers/nfc/s3fwrn5/i2c.c @@ -25,8 +25,8 @@ struct s3fwrn5_i2c_phy { struct i2c_client *i2c_dev; struct nci_dev *ndev; - unsigned int gpio_en; - unsigned int gpio_fw_wake; + int gpio_en; + int gpio_fw_wake; struct mutex mutex; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 9b01afcb7777..9a270e49df17 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2929,7 +2929,7 @@ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi, static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi, struct nvme_effects_log **log) { - struct nvme_cel *cel = xa_load(&ctrl->cels, csi); + struct nvme_effects_log *cel = xa_load(&ctrl->cels, csi); int ret; if (cel) @@ -2940,16 +2940,15 @@ static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi, return -ENOMEM; ret = nvme_get_log(ctrl, 0x00, NVME_LOG_CMD_EFFECTS, 0, csi, - &cel->log, sizeof(cel->log), 0); + cel, sizeof(*cel), 0); if (ret) { kfree(cel); return ret; } - cel->csi = csi; - xa_store(&ctrl->cels, cel->csi, cel, GFP_KERNEL); + xa_store(&ctrl->cels, csi, cel, GFP_KERNEL); out: - *log = &cel->log; + *log = cel; return 0; } @@ -4374,6 +4373,19 @@ void nvme_uninit_ctrl(struct nvme_ctrl *ctrl) } EXPORT_SYMBOL_GPL(nvme_uninit_ctrl); +static void nvme_free_cels(struct nvme_ctrl *ctrl) +{ + struct nvme_effects_log *cel; + unsigned long i; + + xa_for_each (&ctrl->cels, i, cel) { + xa_erase(&ctrl->cels, i); + kfree(cel); + } + + xa_destroy(&ctrl->cels); +} + static void nvme_free_ctrl(struct device *dev) { struct nvme_ctrl *ctrl = @@ -4383,8 +4395,7 @@ static void nvme_free_ctrl(struct device *dev) if (!subsys || ctrl->instance != subsys->instance) ida_simple_remove(&nvme_instance_ida, ctrl->instance); - xa_destroy(&ctrl->cels); - + nvme_free_cels(ctrl); nvme_mpath_uninit(ctrl); __free_page(ctrl->discard_page); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bc330bf0d3bd..567f7ad18a91 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -226,12 +226,6 @@ struct nvme_fault_inject { #endif }; -struct nvme_cel { - struct list_head entry; - struct nvme_effects_log log; - u8 csi; -}; - struct nvme_ctrl { bool comp_seen; enum nvme_ctrl_state state; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 0578ff253c47..3be352403839 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -292,9 +292,21 @@ static void nvme_dbbuf_init(struct nvme_dev *dev, nvmeq->dbbuf_cq_ei = &dev->dbbuf_eis[cq_idx(qid, dev->db_stride)]; } +static void nvme_dbbuf_free(struct nvme_queue *nvmeq) +{ + if (!nvmeq->qid) + return; + + nvmeq->dbbuf_sq_db = NULL; + nvmeq->dbbuf_cq_db = NULL; + nvmeq->dbbuf_sq_ei = NULL; + nvmeq->dbbuf_cq_ei = NULL; +} + static void nvme_dbbuf_set(struct nvme_dev *dev) { struct nvme_command c; + unsigned int i; if (!dev->dbbuf_dbs) return; @@ -308,6 +320,9 @@ static void nvme_dbbuf_set(struct nvme_dev *dev) dev_warn(dev->ctrl.device, "unable to set dbbuf\n"); /* Free memory and continue on */ nvme_dbbuf_dma_free(dev); + + for (i = 1; i <= dev->online_queues; i++) + nvme_dbbuf_free(&dev->queues[i]); } } diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 49f4b73be513..5592a929b593 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -111,6 +111,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = { {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ {KE_IGNORE, 0x81, {KEY_SLEEP} }, {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */ + {KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */ {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index f5901b0b07cd..0419c8001fe3 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -206,6 +206,12 @@ static const struct dmi_system_id dmi_switches_allow_list[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Stream x360 Convertible PC 11"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion 13 x360 PC"), + }, + }, {} /* Array terminator */ }; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e3810675090a..c404706379d9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3218,7 +3218,14 @@ static int hotkey_init_tablet_mode(void) in_tablet_mode = hotkey_gmms_get_tablet_mode(res, &has_tablet_mode); - if (has_tablet_mode) + /* + * The Yoga 11e series has 2 accelerometers described by a + * BOSC0200 ACPI node. This setup relies on a Windows service + * which calls special ACPI methods on this node to report + * the laptop/tent/tablet mode to the EC. The bmc150 iio driver + * does not support this, so skip the hotkey on these models. + */ + if (has_tablet_mode && !acpi_dev_present("BOSC0200", "1", -1)) tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GMMS; type = "GMMS"; } else if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) { @@ -4228,6 +4235,7 @@ static void hotkey_resume(void) pr_err("error while attempting to reset the event firmware interface\n"); tpacpi_send_radiosw_update(); + tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); hotkey_wakeup_reason_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change(); @@ -8776,6 +8784,8 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { TPACPI_Q_LNV3('N', '2', 'C', TPACPI_FAN_2CTL), /* P52 / P72 */ TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (1st gen) */ TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */ + TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (3nd gen) */ + TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */ }; static int __init fan_init(struct ibm_init_struct *iibm) @@ -9703,6 +9713,7 @@ static const struct tpacpi_quirk battery_quirk_table[] __initconst = { TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */ TPACPI_Q_LNV3('R', '0', 'C', true), /* Thinkpad 13 */ TPACPI_Q_LNV3('R', '0', 'J', true), /* Thinkpad 13 gen 2 */ + TPACPI_Q_LNV3('R', '0', 'K', true), /* Thinkpad 11e gen 4 celeron BIOS */ }; static int __init tpacpi_battery_init(struct ibm_init_struct *ibm) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index e557d757c647..fa7232ad8c39 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1478,7 +1478,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char *buffer; char *cmd; - int lcd_out, crt_out, tv_out; + int lcd_out = -1, crt_out = -1, tv_out = -1; int remain = count; int value; int ret; @@ -1510,7 +1510,6 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, kfree(cmd); - lcd_out = crt_out = tv_out = -1; ret = get_video_status(dev, &video_out); if (!ret) { unsigned int new_video_out = video_out; diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index dda60f89c951..5783139d0a11 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -295,6 +295,21 @@ static const struct ts_dmi_data irbis_tw90_data = { .properties = irbis_tw90_props, }; +static const struct property_entry irbis_tw118_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 20), + PROPERTY_ENTRY_U32("touchscreen-min-y", 30), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1960), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1510), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-irbis-tw118.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data irbis_tw118_data = { + .acpi_name = "MSSL1680:00", + .properties = irbis_tw118_props, +}; + static const struct property_entry itworks_tw891_props[] = { PROPERTY_ENTRY_U32("touchscreen-min-x", 1), PROPERTY_ENTRY_U32("touchscreen-min-y", 5), @@ -623,6 +638,23 @@ static const struct ts_dmi_data pov_mobii_wintab_p1006w_v10_data = { .properties = pov_mobii_wintab_p1006w_v10_props, }; +static const struct property_entry predia_basic_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 3), + PROPERTY_ENTRY_U32("touchscreen-min-y", 10), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1144), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-predia-basic.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data predia_basic_data = { + .acpi_name = "MSSL1680:00", + .properties = predia_basic_props, +}; + static const struct property_entry schneider_sct101ctm_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1715), PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), @@ -937,6 +969,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = { }, }, { + /* Irbis TW118 */ + .driver_data = (void *)&irbis_tw118_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"), + DMI_MATCH(DMI_PRODUCT_NAME, "TW118"), + }, + }, + { /* I.T.Works TW891 */ .driver_data = (void *)&itworks_tw891_data, .matches = { @@ -1110,6 +1150,16 @@ const struct dmi_system_id touchscreen_dmi_table[] = { }, }, { + /* Predia Basic tablet) */ + .driver_data = (void *)&predia_basic_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"), + /* Above matches are too generic, add bios-version match */ + DMI_MATCH(DMI_BIOS_VERSION, "Mx.WT107.KUBNGEA"), + }, + }, + { /* Point of View mobii wintab p800w (v2.1) */ .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, .matches = { diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index e020faff7da5..663255774c0b 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -103,43 +103,26 @@ static int timespec_to_char_array(struct timespec64 const *ts, return 0; } -static int idtcm_strverscmp(const char *ver1, const char *ver2) +static int idtcm_strverscmp(const char *version1, const char *version2) { - u8 num1; - u8 num2; - int result = 0; - - /* loop through each level of the version string */ - while (result == 0) { - /* extract leading version numbers */ - if (kstrtou8(ver1, 10, &num1) < 0) - return -1; + u8 ver1[3], ver2[3]; + int i; - if (kstrtou8(ver2, 10, &num2) < 0) - return -1; + if (sscanf(version1, "%hhu.%hhu.%hhu", + &ver1[0], &ver1[1], &ver1[2]) != 3) + return -1; + if (sscanf(version2, "%hhu.%hhu.%hhu", + &ver2[0], &ver2[1], &ver2[2]) != 3) + return -1; - /* if numbers differ, then set the result */ - if (num1 < num2) - result = -1; - else if (num1 > num2) - result = 1; - else { - /* if numbers are the same, go to next level */ - ver1 = strchr(ver1, '.'); - ver2 = strchr(ver2, '.'); - if (!ver1 && !ver2) - break; - else if (!ver1) - result = -1; - else if (!ver2) - result = 1; - else { - ver1++; - ver2++; - } - } + for (i = 0; i < 3; i++) { + if (ver1[i] > ver2[i]) + return 1; + if (ver1[i] < ver2[i]) + return -1; } - return result; + + return 0; } static int idtcm_xfer_read(struct idtcm *idtcm, diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index eb17fea8075c..217a7b84abdf 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2980,6 +2980,12 @@ static int _dasd_requeue_request(struct dasd_ccw_req *cqr) if (!block) return -EINVAL; + /* + * If the request is an ERP request there is nothing to requeue. + * This will be done with the remaining original request. + */ + if (cqr->refers) + return 0; spin_lock_irq(&cqr->dq->lock); req = (struct request *) cqr->callback_data; blk_mq_requeue_request(req, false); diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 32ea41b4356b..0e9af2fbaa76 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -417,10 +417,13 @@ enum qeth_qdio_out_buffer_state { QETH_QDIO_BUF_EMPTY, /* Filled by driver; owned by hardware in order to be sent. */ QETH_QDIO_BUF_PRIMED, - /* Identified to be pending in TPQ. */ + /* Discovered by the TX completion code: */ QETH_QDIO_BUF_PENDING, - /* Found in completion queue. */ - QETH_QDIO_BUF_IN_CQ, + /* Finished by the TX completion code: */ + QETH_QDIO_BUF_NEED_QAOB, + /* Received QAOB notification on CQ: */ + QETH_QDIO_BUF_QAOB_OK, + QETH_QDIO_BUF_QAOB_ERROR, /* Handled via transfer pending / completion queue. */ QETH_QDIO_BUF_HANDLED_DELAYED, }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d9ba0586373b..319190824cd2 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -33,6 +33,7 @@ #include <net/iucv/af_iucv.h> #include <net/dsfield.h> +#include <net/sock.h> #include <asm/ebcdic.h> #include <asm/chpid.h> @@ -499,17 +500,12 @@ static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx, } } - if (forced_cleanup && (atomic_read(&(q->bufs[bidx]->state)) == - QETH_QDIO_BUF_HANDLED_DELAYED)) { - /* for recovery situations */ - qeth_init_qdio_out_buf(q, bidx); - QETH_CARD_TEXT(q->card, 2, "clprecov"); - } } static void qeth_qdio_handle_aob(struct qeth_card *card, unsigned long phys_aob_addr) { + enum qeth_qdio_out_buffer_state new_state = QETH_QDIO_BUF_QAOB_OK; struct qaob *aob; struct qeth_qdio_out_buffer *buffer; enum iucv_tx_notify notification; @@ -521,22 +517,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card, buffer = (struct qeth_qdio_out_buffer *) aob->user1; QETH_CARD_TEXT_(card, 5, "%lx", aob->user1); - if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED, - QETH_QDIO_BUF_IN_CQ) == QETH_QDIO_BUF_PRIMED) { - notification = TX_NOTIFY_OK; - } else { - WARN_ON_ONCE(atomic_read(&buffer->state) != - QETH_QDIO_BUF_PENDING); - atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ); - notification = TX_NOTIFY_DELAYED_OK; - } - - if (aob->aorc != 0) { - QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc); - notification = qeth_compute_cq_notification(aob->aorc, 1); - } - qeth_notify_skbs(buffer->q, buffer, notification); - /* Free dangling allocations. The attached skbs are handled by * qeth_cleanup_handled_pending(). */ @@ -548,7 +528,33 @@ static void qeth_qdio_handle_aob(struct qeth_card *card, if (data && buffer->is_header[i]) kmem_cache_free(qeth_core_header_cache, data); } - atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED); + + if (aob->aorc) { + QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc); + new_state = QETH_QDIO_BUF_QAOB_ERROR; + } + + switch (atomic_xchg(&buffer->state, new_state)) { + case QETH_QDIO_BUF_PRIMED: + /* Faster than TX completion code. */ + notification = qeth_compute_cq_notification(aob->aorc, 0); + qeth_notify_skbs(buffer->q, buffer, notification); + atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED); + break; + case QETH_QDIO_BUF_PENDING: + /* TX completion code is active and will handle the async + * completion for us. + */ + break; + case QETH_QDIO_BUF_NEED_QAOB: + /* TX completion code is already finished. */ + notification = qeth_compute_cq_notification(aob->aorc, 1); + qeth_notify_skbs(buffer->q, buffer, notification); + atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED); + break; + default: + WARN_ON_ONCE(1); + } qdio_release_aob(aob); } @@ -1405,7 +1411,7 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q, skb_queue_walk(&buf->skb_list, skb) { QETH_CARD_TEXT_(q->card, 5, "skbn%d", notification); QETH_CARD_TEXT_(q->card, 5, "%lx", (long) skb); - if (skb->protocol == htons(ETH_P_AF_IUCV) && skb->sk) + if (skb->sk && skb->sk->sk_family == PF_IUCV) iucv_sk(skb->sk)->sk_txnotify(skb, notification); } } @@ -1416,9 +1422,6 @@ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error, struct qeth_qdio_out_q *queue = buf->q; struct sk_buff *skb; - /* release may never happen from within CQ tasklet scope */ - WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ); - if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) qeth_notify_skbs(queue, buf, TX_NOTIFY_GENERALERROR); @@ -6078,9 +6081,32 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue, if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED, QETH_QDIO_BUF_PENDING) == - QETH_QDIO_BUF_PRIMED) + QETH_QDIO_BUF_PRIMED) { qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING); + /* Handle race with qeth_qdio_handle_aob(): */ + switch (atomic_xchg(&buffer->state, + QETH_QDIO_BUF_NEED_QAOB)) { + case QETH_QDIO_BUF_PENDING: + /* No concurrent QAOB notification. */ + break; + case QETH_QDIO_BUF_QAOB_OK: + qeth_notify_skbs(queue, buffer, + TX_NOTIFY_DELAYED_OK); + atomic_set(&buffer->state, + QETH_QDIO_BUF_HANDLED_DELAYED); + break; + case QETH_QDIO_BUF_QAOB_ERROR: + qeth_notify_skbs(queue, buffer, + TX_NOTIFY_DELAYED_GENERALERROR); + atomic_set(&buffer->state, + QETH_QDIO_BUF_HANDLED_DELAYED); + break; + default: + WARN_ON_ONCE(1); + } + } + QETH_CARD_TEXT_(card, 5, "pel%u", bidx); /* prepare the queue slot for re-use: */ diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index daeb837abec3..393aef681e44 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -983,32 +983,19 @@ static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) * change notification' and thus can support the learning_sync bridgeport * attribute * @card: qeth_card structure pointer - * - * This is a destructive test and must be called before dev2br or - * bridgeport address notification is enabled! */ static void qeth_l2_detect_dev2br_support(struct qeth_card *card) { struct qeth_priv *priv = netdev_priv(card->dev); bool dev2br_supported; - int rc; QETH_CARD_TEXT(card, 2, "d2brsup"); if (!IS_IQD(card)) return; /* dev2br requires valid cssid,iid,chid */ - if (!card->info.ids_valid) { - dev2br_supported = false; - } else if (css_general_characteristics.enarf) { - dev2br_supported = true; - } else { - /* Old machines don't have the feature bit: - * Probe by testing whether a disable succeeds - */ - rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL); - dev2br_supported = !rc; - } + dev2br_supported = card->info.ids_valid && + css_general_characteristics.enarf; QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported); if (dev2br_supported) @@ -2233,7 +2220,6 @@ static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok) struct net_device *dev = card->dev; int rc = 0; - /* query before bridgeport_notification may be enabled */ qeth_l2_detect_dev2br_support(card); mutex_lock(&card->sbp_lock); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 1e9c3171fa9f..f9314f1393fb 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -533,8 +533,8 @@ static void iscsi_complete_task(struct iscsi_task *task, int state) if (conn->task == task) conn->task = NULL; - if (conn->ping_task == task) - conn->ping_task = NULL; + if (READ_ONCE(conn->ping_task) == task) + WRITE_ONCE(conn->ping_task, NULL); /* release get from queueing */ __iscsi_put_task(task); @@ -738,6 +738,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, task->conn->session->age); } + if (unlikely(READ_ONCE(conn->ping_task) == INVALID_SCSI_TASK)) + WRITE_ONCE(conn->ping_task, task); + if (!ihost->workq) { if (iscsi_prep_mgmt_task(conn, task)) goto free_task; @@ -941,8 +944,11 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) struct iscsi_nopout hdr; struct iscsi_task *task; - if (!rhdr && conn->ping_task) - return -EINVAL; + if (!rhdr) { + if (READ_ONCE(conn->ping_task)) + return -EINVAL; + WRITE_ONCE(conn->ping_task, INVALID_SCSI_TASK); + } memset(&hdr, 0, sizeof(struct iscsi_nopout)); hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; @@ -957,11 +963,12 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); if (!task) { + if (!rhdr) + WRITE_ONCE(conn->ping_task, NULL); iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); return -EIO; } else if (!rhdr) { /* only track our nops */ - conn->ping_task = task; conn->last_ping = jiffies; } @@ -984,7 +991,7 @@ static int iscsi_nop_out_rsp(struct iscsi_task *task, struct iscsi_conn *conn = task->conn; int rc = 0; - if (conn->ping_task != task) { + if (READ_ONCE(conn->ping_task) != task) { /* * If this is not in response to one of our * nops then it must be from userspace. @@ -1923,7 +1930,7 @@ static void iscsi_start_tx(struct iscsi_conn *conn) */ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) { - if (conn->ping_task && + if (READ_ONCE(conn->ping_task) && time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + (conn->ping_timeout * HZ), jiffies)) return 1; @@ -2058,7 +2065,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) * Checking the transport already or nop from a cmd timeout still * running */ - if (conn->ping_task) { + if (READ_ONCE(conn->ping_task)) { task->have_checked_conn = true; rc = BLK_EH_RESET_TIMER; goto done; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7a160b86adc6..0c148fcd24de 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1294,8 +1294,15 @@ static int ufshcd_devfreq_target(struct device *dev, } spin_unlock_irqrestore(hba->host->host_lock, irq_flags); + pm_runtime_get_noresume(hba->dev); + if (!pm_runtime_active(hba->dev)) { + pm_runtime_put_noidle(hba->dev); + ret = -EAGAIN; + goto out; + } start = ktime_get(); ret = ufshcd_devfreq_scale(hba, scale_up); + pm_runtime_put(hba->dev); trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), (scale_up ? "up" : "down"), @@ -3192,13 +3199,19 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, /* Get the length of descriptor */ ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); if (!buff_len) { - dev_err(hba->dev, "%s: Failed to get desc length", __func__); + dev_err(hba->dev, "%s: Failed to get desc length\n", __func__); + return -EINVAL; + } + + if (param_offset >= buff_len) { + dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n", + __func__, param_offset, desc_id, buff_len); return -EINVAL; } /* Check whether we need temp memory */ if (param_offset != 0 || param_size < buff_len) { - desc_buf = kmalloc(buff_len, GFP_KERNEL); + desc_buf = kzalloc(buff_len, GFP_KERNEL); if (!desc_buf) return -ENOMEM; } else { @@ -3212,14 +3225,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, desc_buf, &buff_len); if (ret) { - dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", + dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n", __func__, desc_id, desc_index, param_offset, ret); goto out; } /* Sanity check */ if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { - dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", + dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n", __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); ret = -EINVAL; goto out; @@ -3229,12 +3242,12 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET]; ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len); - /* Check wherher we will not copy more data, than available */ - if (is_kmalloc && (param_offset + param_size) > buff_len) - param_size = buff_len - param_offset; - - if (is_kmalloc) + if (is_kmalloc) { + /* Make sure we don't copy more data than available */ + if (param_offset + param_size > buff_len) + param_size = buff_len - param_offset; memcpy(param_read_buf, &desc_buf[param_offset], param_size); + } out: if (is_kmalloc) kfree(desc_buf); @@ -8900,11 +8913,7 @@ int ufshcd_shutdown(struct ufs_hba *hba) if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) goto out; - if (pm_runtime_suspended(hba->dev)) { - ret = ufshcd_runtime_resume(hba); - if (ret) - goto out; - } + pm_runtime_get_sync(hba->dev); ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM); out: diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 7b642c330977..7f397b4ad878 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -95,7 +95,6 @@ static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) { int error; struct fsl_mc_device_irq *irq; - cpumask_t mask; irq = dpio_dev->irqs[0]; error = devm_request_irq(&dpio_dev->dev, @@ -112,9 +111,7 @@ static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) } /* set the affinity hint */ - cpumask_clear(&mask); - cpumask_set_cpu(cpu, &mask); - if (irq_set_affinity_hint(irq->msi_desc->irq, &mask)) + if (irq_set_affinity_hint(irq->msi_desc->irq, cpumask_of(cpu))) dev_err(&dpio_dev->dev, "irq_set_affinity failed irq %d cpu %d\n", irq->msi_desc->irq, cpu); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 0b2236ade412..c33866f747db 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -875,7 +875,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->set_cs = dw_spi_set_cs; master->transfer_one = dw_spi_transfer_one; master->handle_err = dw_spi_handle_err; - master->mem_ops = &dws->mem_ops; + if (dws->mem_ops.exec_op) + master->mem_ops = &dws->mem_ops; master->max_speed_hz = dws->max_freq; master->dev.of_node = dev->of_node; master->dev.fwnode = dev->fwnode; diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 4b80e27ecdbf..0b597905ee72 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1686,6 +1686,7 @@ static int spi_imx_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(spi_imx->dev, MXC_RPM_TIMEOUT); pm_runtime_use_autosuspend(spi_imx->dev); + pm_runtime_get_noresume(spi_imx->dev); pm_runtime_set_active(spi_imx->dev); pm_runtime_enable(spi_imx->dev); diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 0d41406c036d..ab9035662717 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1001,6 +1001,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) struct resource *res; struct nxp_fspi *f; int ret; + u32 reg; ctlr = spi_alloc_master(&pdev->dev, sizeof(*f)); if (!ctlr) @@ -1032,6 +1033,12 @@ static int nxp_fspi_probe(struct platform_device *pdev) goto err_put_ctrl; } + /* Clear potential interrupts */ + reg = fspi_readl(f, f->iobase + FSPI_INTR); + if (reg) + fspi_writel(f, reg, f->iobase + FSPI_INTR); + + /* find the resources - controller memory mapped space */ if (is_acpi_node(f->dev->fwnode)) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 05c75f890ace..fc9a59788d2e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3372,12 +3372,15 @@ int spi_setup(struct spi_device *spi) if (!spi->max_speed_hz) spi->max_speed_hz = spi->controller->max_speed_hz; + mutex_lock(&spi->controller->io_mutex); + if (spi->controller->setup) status = spi->controller->setup(spi); if (spi->controller->auto_runtime_pm && spi->controller->set_cs) { status = pm_runtime_get_sync(spi->controller->dev.parent); if (status < 0) { + mutex_unlock(&spi->controller->io_mutex); pm_runtime_put_noidle(spi->controller->dev.parent); dev_err(&spi->controller->dev, "Failed to power device: %d\n", status); @@ -3399,6 +3402,8 @@ int spi_setup(struct spi_device *spi) spi_set_cs(spi, false); } + mutex_unlock(&spi->controller->io_mutex); + if (spi->rt && !spi->controller->rt) { spi->controller->rt = true; spi_set_thread_rt(spi->controller); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index 28319351e909..781c84a9b1b7 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -446,7 +446,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16; reg |= (pps->chroma_qp_index_offset & 0x3f) << 8; reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f; - if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) + if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) reg |= VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT; cedrus_write(dev, VE_H264_SHS_QP, reg); diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index f961b353c22e..8831db383fad 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -653,16 +653,11 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie) return 0; } -static int mt7621_pcie_request_resources(struct mt7621_pcie *pcie, - struct list_head *res) +static void mt7621_pcie_add_resources(struct mt7621_pcie *pcie, + struct list_head *res) { - struct device *dev = pcie->dev; - pci_add_resource_offset(res, &pcie->io, pcie->offset.io); pci_add_resource_offset(res, &pcie->mem, pcie->offset.mem); - pci_add_resource(res, &pcie->busn); - - return devm_request_pci_bus_resources(dev, res); } static int mt7621_pcie_register_host(struct pci_host_bridge *host, @@ -738,11 +733,7 @@ static int mt7621_pci_probe(struct platform_device *pdev) setup_cm_memory_region(pcie); - err = mt7621_pcie_request_resources(pcie, &res); - if (err) { - dev_err(dev, "Error requesting resources\n"); - return err; - } + mt7621_pcie_add_resources(pcie, &res); err = mt7621_pcie_register_host(bridge, &res); if (err) { diff --git a/drivers/staging/ralink-gdma/Kconfig b/drivers/staging/ralink-gdma/Kconfig index 54e8029e6b1a..0017376234e2 100644 --- a/drivers/staging/ralink-gdma/Kconfig +++ b/drivers/staging/ralink-gdma/Kconfig @@ -2,6 +2,7 @@ config DMA_RALINK tristate "RALINK DMA support" depends on RALINK && !SOC_RT288X + depends on DMADEVICES select DMA_ENGINE select DMA_VIRTUAL_CHANNELS diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 79b55ec827a4..b2208e5f190a 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -20,6 +20,7 @@ static const struct sdio_device_id sdio_ids[] = { { SDIO_DEVICE(0x024c, 0x0525), }, { SDIO_DEVICE(0x024c, 0x0623), }, { SDIO_DEVICE(0x024c, 0x0626), }, + { SDIO_DEVICE(0x024c, 0x0627), }, { SDIO_DEVICE(0x024c, 0xb723), }, { /* end: all zeroes */ }, }; diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index f77e5eee6b80..518fac4864cf 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -483,8 +483,7 @@ EXPORT_SYMBOL(iscsit_queue_rsp); void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) { spin_lock_bh(&conn->cmd_lock); - if (!list_empty(&cmd->i_conn_node) && - !(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP)) + if (!list_empty(&cmd->i_conn_node)) list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); @@ -4083,12 +4082,22 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) spin_lock_bh(&conn->cmd_lock); list_splice_init(&conn->conn_cmd_list, &tmp_list); - list_for_each_entry(cmd, &tmp_list, i_conn_node) { + list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) { struct se_cmd *se_cmd = &cmd->se_cmd; if (se_cmd->se_tfo != NULL) { spin_lock_irq(&se_cmd->t_state_lock); - se_cmd->transport_state |= CMD_T_FABRIC_STOP; + if (se_cmd->transport_state & CMD_T_ABORTED) { + /* + * LIO's abort path owns the cleanup for this, + * so put it back on the list and let + * aborted_task handle it. + */ + list_move_tail(&cmd->i_conn_node, + &conn->conn_cmd_list); + } else { + se_cmd->transport_state |= CMD_T_FABRIC_STOP; + } spin_unlock_irq(&se_cmd->t_state_lock); } } diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 20b6fd7383c5..c981757ba0d4 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -534,7 +534,8 @@ void optee_free_pages_list(void *list, size_t num_entries) static bool is_normal_memory(pgprot_t p) { #if defined(CONFIG_ARM) - return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC; + return (((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC) || + ((pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEBACK)); #elif defined(CONFIG_ARM64) return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL); #else diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 0c80a79d7442..c2be7cf91399 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -789,8 +789,10 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; up->gpios = mctrl_gpio_init(port, 0); - if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) - return PTR_ERR(up->gpios); + if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) { + ret = PTR_ERR(up->gpios); + goto err_disable_clk; + } up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 1731d9728865..cacf7266a262 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -942,8 +942,14 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; + unsigned long flags = 0; - spin_lock(&sport->port.lock); + /* + * IRQs might not be disabled upon entering this interrupt handler, + * e.g. when interrupt handlers are forced to be threaded. To support + * this scenario as well, disable IRQs when acquiring the spinlock. + */ + spin_lock_irqsave(&sport->port.lock, flags); usr1 = imx_uart_readl(sport, USR1); usr2 = imx_uart_readl(sport, USR2); @@ -1013,7 +1019,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - spin_unlock(&sport->port.lock); + spin_unlock_irqrestore(&sport->port.lock, flags); return ret; } @@ -2002,16 +2008,6 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) unsigned int ucr1; unsigned long flags = 0; int locked = 1; - int retval; - - retval = clk_enable(sport->clk_per); - if (retval) - return; - retval = clk_enable(sport->clk_ipg); - if (retval) { - clk_disable(sport->clk_per); - return; - } if (sport->port.sysrq) locked = 0; @@ -2047,9 +2043,6 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) if (locked) spin_unlock_irqrestore(&sport->port.lock, flags); - - clk_disable(sport->clk_ipg); - clk_disable(sport->clk_per); } /* @@ -2150,15 +2143,14 @@ imx_uart_console_setup(struct console *co, char *options) retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); - clk_disable(sport->clk_ipg); if (retval) { - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); goto error_console; } - retval = clk_prepare(sport->clk_per); + retval = clk_prepare_enable(sport->clk_per); if (retval) - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); error_console: return retval; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 5bc86f481a78..c8b0ae676809 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -1093,7 +1093,12 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) goto err1; } - fb_virt = ioremap(par->mem->start, screen_fb_size); + /* + * Map the VRAM cacheable for performance. This is also required for + * VM Connect to display properly for ARM64 Linux VM, as the host also + * maps the VRAM cacheable. + */ + fb_virt = ioremap_cache(par->mem->start, screen_fb_size); if (!fb_virt) goto err2; diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 1bb5b9d7f0a2..9068d5578a26 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -823,6 +823,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, vp->cb_break_before = afs_calc_vnode_cb_break(vnode); vp->vnode = vnode; vp->put_vnode = true; + vp->speculative = true; /* vnode not locked */ } } } diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 0fe8844b4bee..b0d7b892090d 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -294,6 +294,13 @@ void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *v op->flags &= ~AFS_OPERATION_DIR_CONFLICT; } } else if (vp->scb.have_status) { + if (vp->dv_before + vp->dv_delta != vp->scb.status.data_version && + vp->speculative) + /* Ignore the result of a speculative bulk status fetch + * if it splits around a modification op, thereby + * appearing to regress the data version. + */ + goto out; afs_apply_status(op, vp); if (vp->scb.have_cb) afs_apply_callback(op, vp); @@ -305,6 +312,7 @@ void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *v } } +out: write_sequnlock(&vnode->cb_lock); if (vp->scb.have_status) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 14d5d75f4b6e..0d150a29e39e 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -755,6 +755,7 @@ struct afs_vnode_param { bool update_ctime:1; /* Need to update the ctime */ bool set_size:1; /* Must update i_size */ bool op_unlinked:1; /* True if file was unlinked by op */ + bool speculative:1; /* T if speculative status fetch (no vnode lock) */ }; /* diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0378933d163c..0b29bdb25105 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -878,7 +878,10 @@ struct btrfs_fs_info { */ struct ulist *qgroup_ulist; - /* protect user change for quota operations */ + /* + * Protect user change for quota operations. If a transaction is needed, + * it must be started before locking this lock. + */ struct mutex qgroup_ioctl_lock; /* list of dirty qgroups to be written at next commit */ diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 87355a38a654..4373da7bcc0d 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -452,46 +452,6 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages) } } -static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode, - const u64 start, - const u64 len, - struct extent_state **cached_state) -{ - u64 search_start = start; - const u64 end = start + len - 1; - - while (search_start < end) { - const u64 search_len = end - search_start + 1; - struct extent_map *em; - u64 em_len; - int ret = 0; - - em = btrfs_get_extent(inode, NULL, 0, search_start, search_len); - if (IS_ERR(em)) - return PTR_ERR(em); - - if (em->block_start != EXTENT_MAP_HOLE) - goto next; - - em_len = em->len; - if (em->start < search_start) - em_len -= search_start - em->start; - if (em_len > search_len) - em_len = search_len; - - ret = set_extent_bit(&inode->io_tree, search_start, - search_start + em_len - 1, - EXTENT_DELALLOC_NEW, - NULL, cached_state, GFP_NOFS); -next: - search_start = extent_map_end(em); - free_extent_map(em); - if (ret) - return ret; - } - return 0; -} - /* * after copy_from_user, pages need to be dirtied and we need to make * sure holes are created between the current EOF and the start of @@ -528,23 +488,6 @@ int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages, EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, cached); - if (!btrfs_is_free_space_inode(inode)) { - if (start_pos >= isize && - !(inode->flags & BTRFS_INODE_PREALLOC)) { - /* - * There can't be any extents following eof in this case - * so just set the delalloc new bit for the range - * directly. - */ - extra_bits |= EXTENT_DELALLOC_NEW; - } else { - err = btrfs_find_new_delalloc_bytes(inode, start_pos, - num_bytes, cached); - if (err) - return err; - } - } - err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, extra_bits, cached); if (err) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index da58c58ef9aa..7e8d8169779d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2253,11 +2253,69 @@ static int add_pending_csums(struct btrfs_trans_handle *trans, return 0; } +static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode, + const u64 start, + const u64 len, + struct extent_state **cached_state) +{ + u64 search_start = start; + const u64 end = start + len - 1; + + while (search_start < end) { + const u64 search_len = end - search_start + 1; + struct extent_map *em; + u64 em_len; + int ret = 0; + + em = btrfs_get_extent(inode, NULL, 0, search_start, search_len); + if (IS_ERR(em)) + return PTR_ERR(em); + + if (em->block_start != EXTENT_MAP_HOLE) + goto next; + + em_len = em->len; + if (em->start < search_start) + em_len -= search_start - em->start; + if (em_len > search_len) + em_len = search_len; + + ret = set_extent_bit(&inode->io_tree, search_start, + search_start + em_len - 1, + EXTENT_DELALLOC_NEW, + NULL, cached_state, GFP_NOFS); +next: + search_start = extent_map_end(em); + free_extent_map(em); + if (ret) + return ret; + } + return 0; +} + int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end, unsigned int extra_bits, struct extent_state **cached_state) { WARN_ON(PAGE_ALIGNED(end)); + + if (start >= i_size_read(&inode->vfs_inode) && + !(inode->flags & BTRFS_INODE_PREALLOC)) { + /* + * There can't be any extents following eof in this case so just + * set the delalloc new bit for the range directly. + */ + extra_bits |= EXTENT_DELALLOC_NEW; + } else { + int ret; + + ret = btrfs_find_new_delalloc_bytes(inode, start, + end + 1 - start, + cached_state); + if (ret) + return ret; + } + return set_extent_delalloc(&inode->io_tree, start, end, extra_bits, cached_state); } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 77c54749f432..87bd37b70738 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/btrfs.h> +#include <linux/sched/mm.h> #include "ctree.h" #include "transaction.h" @@ -497,13 +498,13 @@ next2: break; } out: + btrfs_free_path(path); fs_info->qgroup_flags |= flags; if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && ret >= 0) ret = qgroup_rescan_init(fs_info, rescan_progress, 0); - btrfs_free_path(path); if (ret < 0) { ulist_free(fs_info->qgroup_ulist); @@ -936,6 +937,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) struct btrfs_key found_key; struct btrfs_qgroup *qgroup = NULL; struct btrfs_trans_handle *trans = NULL; + struct ulist *ulist = NULL; int ret = 0; int slot; @@ -943,8 +945,8 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) if (fs_info->quota_root) goto out; - fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); - if (!fs_info->qgroup_ulist) { + ulist = ulist_alloc(GFP_KERNEL); + if (!ulist) { ret = -ENOMEM; goto out; } @@ -952,6 +954,22 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) ret = btrfs_sysfs_add_qgroups(fs_info); if (ret < 0) goto out; + + /* + * Unlock qgroup_ioctl_lock before starting the transaction. This is to + * avoid lock acquisition inversion problems (reported by lockdep) between + * qgroup_ioctl_lock and the vfs freeze semaphores, acquired when we + * start a transaction. + * After we started the transaction lock qgroup_ioctl_lock again and + * check if someone else created the quota root in the meanwhile. If so, + * just return success and release the transaction handle. + * + * Also we don't need to worry about someone else calling + * btrfs_sysfs_add_qgroups() after we unlock and getting an error because + * that function returns 0 (success) when the sysfs entries already exist. + */ + mutex_unlock(&fs_info->qgroup_ioctl_lock); + /* * 1 for quota root item * 1 for BTRFS_QGROUP_STATUS item @@ -961,12 +979,20 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) * would be a lot of overkill. */ trans = btrfs_start_transaction(tree_root, 2); + + mutex_lock(&fs_info->qgroup_ioctl_lock); if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; goto out; } + if (fs_info->quota_root) + goto out; + + fs_info->qgroup_ulist = ulist; + ulist = NULL; + /* * initially create the quota tree */ @@ -1124,11 +1150,14 @@ out: if (ret) { ulist_free(fs_info->qgroup_ulist); fs_info->qgroup_ulist = NULL; - if (trans) - btrfs_end_transaction(trans); btrfs_sysfs_del_qgroups(fs_info); } mutex_unlock(&fs_info->qgroup_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + ulist_free(ulist); return ret; } @@ -1141,19 +1170,29 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) goto out; + mutex_unlock(&fs_info->qgroup_ioctl_lock); /* * 1 For the root item * * We should also reserve enough items for the quota tree deletion in * btrfs_clean_quota_tree but this is not done. + * + * Also, we must always start a transaction without holding the mutex + * qgroup_ioctl_lock, see btrfs_quota_enable(). */ trans = btrfs_start_transaction(fs_info->tree_root, 1); + + mutex_lock(&fs_info->qgroup_ioctl_lock); if (IS_ERR(trans)) { ret = PTR_ERR(trans); + trans = NULL; goto out; } + if (!fs_info->quota_root) + goto out; + clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); btrfs_qgroup_wait_for_completion(fs_info, false); spin_lock(&fs_info->qgroup_lock); @@ -1167,13 +1206,13 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) ret = btrfs_clean_quota_tree(trans, quota_root); if (ret) { btrfs_abort_transaction(trans, ret); - goto end_trans; + goto out; } ret = btrfs_del_root(trans, "a_root->root_key); if (ret) { btrfs_abort_transaction(trans, ret); - goto end_trans; + goto out; } list_del("a_root->dirty_list); @@ -1185,10 +1224,13 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) btrfs_put_root(quota_root); -end_trans: - ret = btrfs_end_transaction(trans); out: mutex_unlock(&fs_info->qgroup_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + return ret; } @@ -1324,13 +1366,17 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, struct btrfs_qgroup *member; struct btrfs_qgroup_list *list; struct ulist *tmp; + unsigned int nofs_flag; int ret = 0; /* Check the level of src and dst first */ if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst)) return -EINVAL; + /* We hold a transaction handle open, must do a NOFS allocation. */ + nofs_flag = memalloc_nofs_save(); tmp = ulist_alloc(GFP_KERNEL); + memalloc_nofs_restore(nofs_flag); if (!tmp) return -ENOMEM; @@ -1387,10 +1433,14 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, struct btrfs_qgroup_list *list; struct ulist *tmp; bool found = false; + unsigned int nofs_flag; int ret = 0; int ret2; + /* We hold a transaction handle open, must do a NOFS allocation. */ + nofs_flag = memalloc_nofs_save(); tmp = ulist_alloc(GFP_KERNEL); + memalloc_nofs_restore(nofs_flag); if (!tmp) return -ENOMEM; @@ -3512,6 +3562,7 @@ static int try_flush_qgroup(struct btrfs_root *root) { struct btrfs_trans_handle *trans; int ret; + bool can_commit = true; /* * We don't want to run flush again and again, so if there is a running @@ -3523,6 +3574,20 @@ static int try_flush_qgroup(struct btrfs_root *root) return 0; } + /* + * If current process holds a transaction, we shouldn't flush, as we + * assume all space reservation happens before a transaction handle is + * held. + * + * But there are cases like btrfs_delayed_item_reserve_metadata() where + * we try to reserve space with one transction handle already held. + * In that case we can't commit transaction, but at least try to end it + * and hope the started data writes can free some space. + */ + if (current->journal_info && + current->journal_info != BTRFS_SEND_TRANS_STUB) + can_commit = false; + ret = btrfs_start_delalloc_snapshot(root); if (ret < 0) goto out; @@ -3534,7 +3599,10 @@ static int try_flush_qgroup(struct btrfs_root *root) goto out; } - ret = btrfs_commit_transaction(trans); + if (can_commit) + ret = btrfs_commit_transaction(trans); + else + ret = btrfs_end_transaction(trans); out: clear_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state); wake_up(&root->qgroup_flush_wait); diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c index e6719f7db386..04022069761d 100644 --- a/fs/btrfs/tests/inode-tests.c +++ b/fs/btrfs/tests/inode-tests.c @@ -983,7 +983,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, BTRFS_MAX_EXTENT_SIZE >> 1, (BTRFS_MAX_EXTENT_SIZE >> 1) + sectorsize - 1, - EXTENT_DELALLOC | EXTENT_UPTODATE, 0, 0, NULL); + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_UPTODATE, 0, 0, NULL); if (ret) { test_err("clear_extent_bit returned %d", ret); goto out; @@ -1050,7 +1051,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, BTRFS_MAX_EXTENT_SIZE + sectorsize, BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, - EXTENT_DELALLOC | EXTENT_UPTODATE, 0, 0, NULL); + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_UPTODATE, 0, 0, NULL); if (ret) { test_err("clear_extent_bit returned %d", ret); goto out; @@ -1082,7 +1084,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) /* Empty */ ret = clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1, - EXTENT_DELALLOC | EXTENT_UPTODATE, 0, 0, NULL); + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_UPTODATE, 0, 0, NULL); if (ret) { test_err("clear_extent_bit returned %d", ret); goto out; @@ -1097,7 +1100,8 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize) out: if (ret) clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, (u64)-1, - EXTENT_DELALLOC | EXTENT_UPTODATE, 0, 0, NULL); + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_UPTODATE, 0, 0, NULL); iput(inode); btrfs_free_dummy_root(root); btrfs_free_dummy_fs_info(fs_info); diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 8784b74f5232..ea2bb4cb5890 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1068,6 +1068,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, "invalid root item size, have %u expect %zu or %u", btrfs_item_size_nr(leaf, slot), sizeof(ri), btrfs_legacy_root_item_size()); + return -EUCLEAN; } /* @@ -1423,6 +1424,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf, "invalid item size, have %u expect aligned to %zu for key type %u", btrfs_item_size_nr(leaf, slot), sizeof(*dref), key->type); + return -EUCLEAN; } if (!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize)) { generic_err(leaf, slot, @@ -1451,6 +1453,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf, extent_err(leaf, slot, "invalid extent data backref offset, have %llu expect aligned to %u", offset, leaf->fs_info->sectorsize); + return -EUCLEAN; } } return 0; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a6406b3b8c2b..78637665166e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -940,7 +940,13 @@ static noinline struct btrfs_device *device_list_add(const char *path, if (device->bdev != path_bdev) { bdput(path_bdev); mutex_unlock(&fs_devices->device_list_mutex); - btrfs_warn_in_rcu(device->fs_info, + /* + * device->fs_info may not be reliable here, so + * pass in a NULL instead. This avoids a + * possible use-after-free when the fs_info and + * fs_info->sb are already torn down. + */ + btrfs_warn_in_rcu(NULL, "duplicate device %s devid %llu generation %llu scanned by %s (%d)", path, devid, found_transid, current->comm, diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 23b21e943652..ef4784e72b1d 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1266,6 +1266,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); } else if (mode_from_special_sid) { rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true); + kfree(pntsd); } else { /* get approximated mode from ACL */ rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 504766cb6c19..dab94f67c988 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -264,7 +264,7 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val) } static struct mid_q_entry * -smb2_find_mid(struct TCP_Server_Info *server, char *buf) +__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue) { struct mid_q_entry *mid; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; @@ -281,6 +281,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) (mid->mid_state == MID_REQUEST_SUBMITTED) && (mid->command == shdr->Command)) { kref_get(&mid->refcount); + if (dequeue) { + list_del_init(&mid->qhead); + mid->mid_flags |= MID_DELETED; + } spin_unlock(&GlobalMid_Lock); return mid; } @@ -289,6 +293,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) return NULL; } +static struct mid_q_entry * +smb2_find_mid(struct TCP_Server_Info *server, char *buf) +{ + return __smb2_find_mid(server, buf, false); +} + +static struct mid_q_entry * +smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf) +{ + return __smb2_find_mid(server, buf, true); +} + static void smb2_dump_detail(void *buf, struct TCP_Server_Info *server) { @@ -4356,7 +4372,8 @@ init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size, static int handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, char *buf, unsigned int buf_len, struct page **pages, - unsigned int npages, unsigned int page_data_size) + unsigned int npages, unsigned int page_data_size, + bool is_offloaded) { unsigned int data_offset; unsigned int data_len; @@ -4378,7 +4395,8 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, if (server->ops->is_session_expired && server->ops->is_session_expired(buf)) { - cifs_reconnect(server); + if (!is_offloaded) + cifs_reconnect(server); return -1; } @@ -4402,7 +4420,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, cifs_dbg(FYI, "%s: server returned error %d\n", __func__, rdata->result); /* normal error on read response */ - dequeue_mid(mid, false); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_RECEIVED; + else + dequeue_mid(mid, false); return 0; } @@ -4426,7 +4447,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", __func__, data_offset); rdata->result = -EIO; - dequeue_mid(mid, rdata->result); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_MALFORMED; + else + dequeue_mid(mid, rdata->result); return 0; } @@ -4442,21 +4466,30 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n", __func__, data_offset); rdata->result = -EIO; - dequeue_mid(mid, rdata->result); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_MALFORMED; + else + dequeue_mid(mid, rdata->result); return 0; } if (data_len > page_data_size - pad_len) { /* data_len is corrupt -- discard frame */ rdata->result = -EIO; - dequeue_mid(mid, rdata->result); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_MALFORMED; + else + dequeue_mid(mid, rdata->result); return 0; } rdata->result = init_read_bvec(pages, npages, page_data_size, cur_off, &bvec); if (rdata->result != 0) { - dequeue_mid(mid, rdata->result); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_MALFORMED; + else + dequeue_mid(mid, rdata->result); return 0; } @@ -4471,7 +4504,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, /* read response payload cannot be in both buf and pages */ WARN_ONCE(1, "buf can not contain only a part of read data"); rdata->result = -EIO; - dequeue_mid(mid, rdata->result); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_MALFORMED; + else + dequeue_mid(mid, rdata->result); return 0; } @@ -4482,7 +4518,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, if (length < 0) return length; - dequeue_mid(mid, false); + if (is_offloaded) + mid->mid_state = MID_RESPONSE_RECEIVED; + else + dequeue_mid(mid, false); return length; } @@ -4511,15 +4550,34 @@ static void smb2_decrypt_offload(struct work_struct *work) } dw->server->lstrp = jiffies; - mid = smb2_find_mid(dw->server, dw->buf); + mid = smb2_find_dequeue_mid(dw->server, dw->buf); if (mid == NULL) cifs_dbg(FYI, "mid not found\n"); else { mid->decrypted = true; rc = handle_read_data(dw->server, mid, dw->buf, dw->server->vals->read_rsp_size, - dw->ppages, dw->npages, dw->len); - mid->callback(mid); + dw->ppages, dw->npages, dw->len, + true); + if (rc >= 0) { +#ifdef CONFIG_CIFS_STATS2 + mid->when_received = jiffies; +#endif + mid->callback(mid); + } else { + spin_lock(&GlobalMid_Lock); + if (dw->server->tcpStatus == CifsNeedReconnect) { + mid->mid_state = MID_RETRY_NEEDED; + spin_unlock(&GlobalMid_Lock); + mid->callback(mid); + } else { + mid->mid_state = MID_REQUEST_SUBMITTED; + mid->mid_flags &= ~(MID_DELETED); + list_add_tail(&mid->qhead, + &dw->server->pending_mid_q); + spin_unlock(&GlobalMid_Lock); + } + } cifs_mid_q_entry_release(mid); } @@ -4622,7 +4680,7 @@ non_offloaded_decrypt: (*mid)->decrypted = true; rc = handle_read_data(server, *mid, buf, server->vals->read_rsp_size, - pages, npages, len); + pages, npages, len, false); } free_pages: @@ -4765,7 +4823,7 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid) char *buf = server->large_buf ? server->bigbuf : server->smallbuf; return handle_read_data(server, mid, buf, server->pdu_size, - NULL, 0, 0); + NULL, 0, 0, false); } static int diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 15880a68faad..f943fd0b0699 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -21,6 +21,7 @@ LIST_HEAD(efivarfs_list); static void efivarfs_evict_inode(struct inode *inode) { clear_inode(inode); + kfree(inode->i_private); } static const struct super_operations efivarfs_ops = { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index bf9429484462..65ecaf96d0a4 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2695,7 +2695,8 @@ void ext4_insert_dentry(struct inode *inode, struct ext4_filename *fname); static inline void ext4_update_dx_flag(struct inode *inode) { - if (!ext4_has_feature_dir_index(inode->i_sb)) { + if (!ext4_has_feature_dir_index(inode->i_sb) && + ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) { /* ext4_iget() should have caught this... */ WARN_ON_ONCE(ext4_has_feature_metadata_csum(inode->i_sb)); ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6633b20224d5..94472044f4c1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2638,10 +2638,6 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, } else if (test_opt2(sb, DAX_INODE)) { SEQ_OPTS_PUTS("dax=inode"); } - - if (test_opt2(sb, JOURNAL_FAST_COMMIT)) - SEQ_OPTS_PUTS("fast_commit"); - ext4_show_quota_options(seq, sb); return 0; } diff --git a/fs/io_uring.c b/fs/io_uring.c index 4ead291b2976..1023f7b44cea 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -205,6 +205,7 @@ struct fixed_file_ref_node { struct list_head file_list; struct fixed_file_data *file_data; struct llist_node llist; + bool done; }; struct fixed_file_data { @@ -478,6 +479,7 @@ struct io_sr_msg { struct io_open { struct file *file; int dfd; + bool ignore_nonblock; struct filename *filename; struct open_how how; unsigned long nofile; @@ -1311,22 +1313,6 @@ static bool io_grab_identity(struct io_kiocb *req) return false; req->work.flags |= IO_WQ_WORK_FSIZE; } - - if (!(req->work.flags & IO_WQ_WORK_FILES) && - (def->work_flags & IO_WQ_WORK_FILES) && - !(req->flags & REQ_F_NO_FILE_TABLE)) { - if (id->files != current->files || - id->nsproxy != current->nsproxy) - return false; - atomic_inc(&id->files->count); - get_nsproxy(id->nsproxy); - req->flags |= REQ_F_INFLIGHT; - - spin_lock_irq(&ctx->inflight_lock); - list_add(&req->inflight_entry, &ctx->inflight_list); - spin_unlock_irq(&ctx->inflight_lock); - req->work.flags |= IO_WQ_WORK_FILES; - } #ifdef CONFIG_BLK_CGROUP if (!(req->work.flags & IO_WQ_WORK_BLKCG) && (def->work_flags & IO_WQ_WORK_BLKCG)) { @@ -1368,6 +1354,21 @@ static bool io_grab_identity(struct io_kiocb *req) } spin_unlock(¤t->fs->lock); } + if (!(req->work.flags & IO_WQ_WORK_FILES) && + (def->work_flags & IO_WQ_WORK_FILES) && + !(req->flags & REQ_F_NO_FILE_TABLE)) { + if (id->files != current->files || + id->nsproxy != current->nsproxy) + return false; + atomic_inc(&id->files->count); + get_nsproxy(id->nsproxy); + req->flags |= REQ_F_INFLIGHT; + + spin_lock_irq(&ctx->inflight_lock); + list_add(&req->inflight_entry, &ctx->inflight_list); + spin_unlock_irq(&ctx->inflight_lock); + req->work.flags |= IO_WQ_WORK_FILES; + } return true; } @@ -2577,7 +2578,6 @@ static bool io_resubmit_prep(struct io_kiocb *req, int error) } end_req: req_set_fail_links(req); - io_req_complete(req, ret); return false; } #endif @@ -3192,7 +3192,7 @@ static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec, rw->free_iovec = iovec; rw->bytes_done = 0; /* can only be fixed buffers, no need to do anything */ - if (iter->type == ITER_BVEC) + if (iov_iter_is_bvec(iter)) return; if (!iovec) { unsigned iov_off = 0; @@ -3795,6 +3795,7 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe return ret; } req->open.nofile = rlimit(RLIMIT_NOFILE); + req->open.ignore_nonblock = false; req->flags |= REQ_F_NEED_CLEANUP; return 0; } @@ -3838,7 +3839,7 @@ static int io_openat2(struct io_kiocb *req, bool force_nonblock) struct file *file; int ret; - if (force_nonblock) + if (force_nonblock && !req->open.ignore_nonblock) return -EAGAIN; ret = build_open_flags(&req->open.how, &op); @@ -3853,6 +3854,21 @@ static int io_openat2(struct io_kiocb *req, bool force_nonblock) if (IS_ERR(file)) { put_unused_fd(ret); ret = PTR_ERR(file); + /* + * A work-around to ensure that /proc/self works that way + * that it should - if we get -EOPNOTSUPP back, then assume + * that proc_self_get_link() failed us because we're in async + * context. We should be safe to retry this from the task + * itself with force_nonblock == false set, as it should not + * block on lookup. Would be nice to know this upfront and + * avoid the async dance, but doesn't seem feasible. + */ + if (ret == -EOPNOTSUPP && io_wq_current_is_worker()) { + req->open.ignore_nonblock = true; + refcount_inc(&req->refs); + io_req_task_queue(req); + return 0; + } } else { fsnotify_open(file); fd_install(ret, file); @@ -6957,9 +6973,7 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx) return -ENXIO; spin_lock(&data->lock); - if (!list_empty(&data->ref_list)) - ref_node = list_first_entry(&data->ref_list, - struct fixed_file_ref_node, node); + ref_node = data->node; spin_unlock(&data->lock); if (ref_node) percpu_ref_kill(&ref_node->refs); @@ -7308,10 +7322,6 @@ static void __io_file_put_work(struct fixed_file_ref_node *ref_node) kfree(pfile); } - spin_lock(&file_data->lock); - list_del(&ref_node->node); - spin_unlock(&file_data->lock); - percpu_ref_exit(&ref_node->refs); kfree(ref_node); percpu_ref_put(&file_data->refs); @@ -7338,17 +7348,32 @@ static void io_file_put_work(struct work_struct *work) static void io_file_data_ref_zero(struct percpu_ref *ref) { struct fixed_file_ref_node *ref_node; + struct fixed_file_data *data; struct io_ring_ctx *ctx; - bool first_add; + bool first_add = false; int delay = HZ; ref_node = container_of(ref, struct fixed_file_ref_node, refs); - ctx = ref_node->file_data->ctx; + data = ref_node->file_data; + ctx = data->ctx; + + spin_lock(&data->lock); + ref_node->done = true; - if (percpu_ref_is_dying(&ctx->file_data->refs)) + while (!list_empty(&data->ref_list)) { + ref_node = list_first_entry(&data->ref_list, + struct fixed_file_ref_node, node); + /* recycle ref nodes in order */ + if (!ref_node->done) + break; + list_del(&ref_node->node); + first_add |= llist_add(&ref_node->llist, &ctx->file_put_llist); + } + spin_unlock(&data->lock); + + if (percpu_ref_is_dying(&data->refs)) delay = 0; - first_add = llist_add(&ref_node->llist, &ctx->file_put_llist); if (!delay) mod_delayed_work(system_wq, &ctx->file_put_work, 0); else if (first_add) @@ -7372,6 +7397,7 @@ static struct fixed_file_ref_node *alloc_fixed_file_ref_node( INIT_LIST_HEAD(&ref_node->node); INIT_LIST_HEAD(&ref_node->file_list); ref_node->file_data = ctx->file_data; + ref_node->done = false; return ref_node; } @@ -7467,7 +7493,7 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg, file_data->node = ref_node; spin_lock(&file_data->lock); - list_add(&ref_node->node, &file_data->ref_list); + list_add_tail(&ref_node->node, &file_data->ref_list); spin_unlock(&file_data->lock); percpu_ref_get(&file_data->refs); return ret; @@ -7626,7 +7652,7 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx, if (needs_switch) { percpu_ref_kill(&data->node->refs); spin_lock(&data->lock); - list_add(&ref_node->node, &data->ref_list); + list_add_tail(&ref_node->node, &data->ref_list); data->node = ref_node; spin_unlock(&data->lock); percpu_ref_get(&ctx->file_data->refs); @@ -9225,14 +9251,16 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p, * to a power-of-two, if it isn't already. We do NOT impose * any cq vs sq ring sizing. */ - p->cq_entries = roundup_pow_of_two(p->cq_entries); - if (p->cq_entries < p->sq_entries) + if (!p->cq_entries) return -EINVAL; if (p->cq_entries > IORING_MAX_CQ_ENTRIES) { if (!(p->flags & IORING_SETUP_CLAMP)) return -EINVAL; p->cq_entries = IORING_MAX_CQ_ENTRIES; } + p->cq_entries = roundup_pow_of_two(p->cq_entries); + if (p->cq_entries < p->sq_entries) + return -EINVAL; } else { p->cq_entries = 2 * p->sq_entries; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 0c3d5e3b24b2..188f79d76988 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -566,12 +566,14 @@ static int __jbd2_journal_force_commit(journal_t *journal) } /** - * Force and wait upon a commit if the calling process is not within - * transaction. This is used for forcing out undo-protected data which contains - * bitmaps, when the fs is running out of space. + * jbd2_journal_force_commit_nested - Force and wait upon a commit if the + * calling process is not within transaction. * * @journal: journal to force * Returns true if progress was made. + * + * This is used for forcing out undo-protected data which contains + * bitmaps, when the fs is running out of space. */ int jbd2_journal_force_commit_nested(journal_t *journal) { @@ -582,7 +584,7 @@ int jbd2_journal_force_commit_nested(journal_t *journal) } /** - * int journal_force_commit() - force any uncommitted transactions + * jbd2_journal_force_commit() - force any uncommitted transactions * @journal: journal to force * * Caller want unconditional commit. We can only force the running transaction @@ -1881,7 +1883,7 @@ static int load_superblock(journal_t *journal) /** - * int jbd2_journal_load() - Read journal from disk. + * jbd2_journal_load() - Read journal from disk. * @journal: Journal to act on. * * Given a journal_t structure which tells us which disk blocks contain @@ -1951,7 +1953,7 @@ recovery_error: } /** - * void jbd2_journal_destroy() - Release a journal_t structure. + * jbd2_journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. * * Release a journal_t structure once it is no longer in use by the @@ -2028,7 +2030,7 @@ int jbd2_journal_destroy(journal_t *journal) /** - *int jbd2_journal_check_used_features() - Check if features specified are used. + * jbd2_journal_check_used_features() - Check if features specified are used. * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -2063,7 +2065,7 @@ int jbd2_journal_check_used_features(journal_t *journal, unsigned long compat, } /** - * int jbd2_journal_check_available_features() - Check feature set in journalling layer + * jbd2_journal_check_available_features() - Check feature set in journalling layer * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -2126,7 +2128,7 @@ jbd2_journal_initialize_fast_commit(journal_t *journal) } /** - * int jbd2_journal_set_features() - Mark a given journal feature in the superblock + * jbd2_journal_set_features() - Mark a given journal feature in the superblock * @journal: Journal to act on. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount @@ -2217,7 +2219,7 @@ int jbd2_journal_set_features(journal_t *journal, unsigned long compat, } /* - * jbd2_journal_clear_features () - Clear a given journal feature in the + * jbd2_journal_clear_features() - Clear a given journal feature in the * superblock * @journal: Journal to act on. * @compat: bitmask of compatible features @@ -2246,7 +2248,7 @@ void jbd2_journal_clear_features(journal_t *journal, unsigned long compat, EXPORT_SYMBOL(jbd2_journal_clear_features); /** - * int jbd2_journal_flush () - Flush journal + * jbd2_journal_flush() - Flush journal * @journal: Journal to act on. * * Flush all data for a given journal to disk and empty the journal. @@ -2321,7 +2323,7 @@ out: } /** - * int jbd2_journal_wipe() - Wipe journal contents + * jbd2_journal_wipe() - Wipe journal contents * @journal: Journal to act on. * @write: flag (see below) * @@ -2362,7 +2364,7 @@ int jbd2_journal_wipe(journal_t *journal, int write) } /** - * void jbd2_journal_abort () - Shutdown the journal immediately. + * jbd2_journal_abort () - Shutdown the journal immediately. * @journal: the journal to shutdown. * @errno: an error number to record in the journal indicating * the reason for the shutdown. @@ -2453,7 +2455,7 @@ void jbd2_journal_abort(journal_t *journal, int errno) } /** - * int jbd2_journal_errno () - returns the journal's error state. + * jbd2_journal_errno() - returns the journal's error state. * @journal: journal to examine. * * This is the errno number set with jbd2_journal_abort(), the last @@ -2477,7 +2479,7 @@ int jbd2_journal_errno(journal_t *journal) } /** - * int jbd2_journal_clear_err () - clears the journal's error state + * jbd2_journal_clear_err() - clears the journal's error state * @journal: journal to act on. * * An error must be cleared or acked to take a FS out of readonly @@ -2497,7 +2499,7 @@ int jbd2_journal_clear_err(journal_t *journal) } /** - * void jbd2_journal_ack_err() - Ack journal err. + * jbd2_journal_ack_err() - Ack journal err. * @journal: journal to act on. * * An error must be cleared or acked to take a FS out of readonly diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index d54f04674e8e..9396666b7314 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -519,7 +519,7 @@ EXPORT_SYMBOL(jbd2__journal_start); /** - * handle_t *jbd2_journal_start() - Obtain a new handle. + * jbd2_journal_start() - Obtain a new handle. * @journal: Journal to start transaction on. * @nblocks: number of block buffer we might modify * @@ -566,7 +566,7 @@ void jbd2_journal_free_reserved(handle_t *handle) EXPORT_SYMBOL(jbd2_journal_free_reserved); /** - * int jbd2_journal_start_reserved() - start reserved handle + * jbd2_journal_start_reserved() - start reserved handle * @handle: handle to start * @type: for handle statistics * @line_no: for handle statistics @@ -620,7 +620,7 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, EXPORT_SYMBOL(jbd2_journal_start_reserved); /** - * int jbd2_journal_extend() - extend buffer credits. + * jbd2_journal_extend() - extend buffer credits. * @handle: handle to 'extend' * @nblocks: nr blocks to try to extend by. * @revoke_records: number of revoke records to try to extend by. @@ -745,7 +745,7 @@ static void stop_this_handle(handle_t *handle) } /** - * int jbd2_journal_restart() - restart a handle . + * jbd2__journal_restart() - restart a handle . * @handle: handle to restart * @nblocks: nr credits requested * @revoke_records: number of revoke record credits requested @@ -815,7 +815,7 @@ int jbd2_journal_restart(handle_t *handle, int nblocks) EXPORT_SYMBOL(jbd2_journal_restart); /** - * void jbd2_journal_lock_updates () - establish a transaction barrier. + * jbd2_journal_lock_updates () - establish a transaction barrier. * @journal: Journal to establish a barrier on. * * This locks out any further updates from being started, and blocks @@ -874,7 +874,7 @@ void jbd2_journal_lock_updates(journal_t *journal) } /** - * void jbd2_journal_unlock_updates (journal_t* journal) - release barrier + * jbd2_journal_unlock_updates () - release barrier * @journal: Journal to release the barrier on. * * Release a transaction barrier obtained with jbd2_journal_lock_updates(). @@ -1182,7 +1182,8 @@ out: } /** - * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. + * jbd2_journal_get_write_access() - notify intent to modify a buffer + * for metadata (not data) update. * @handle: transaction to add buffer modifications to * @bh: bh to be used for metadata writes * @@ -1226,7 +1227,7 @@ int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh) * unlocked buffer beforehand. */ /** - * int jbd2_journal_get_create_access () - notify intent to use newly created bh + * jbd2_journal_get_create_access () - notify intent to use newly created bh * @handle: transaction to new buffer to * @bh: new buffer. * @@ -1306,7 +1307,7 @@ out: } /** - * int jbd2_journal_get_undo_access() - Notify intent to modify metadata with + * jbd2_journal_get_undo_access() - Notify intent to modify metadata with * non-rewindable consequences * @handle: transaction * @bh: buffer to undo @@ -1383,7 +1384,7 @@ out: } /** - * void jbd2_journal_set_triggers() - Add triggers for commit writeout + * jbd2_journal_set_triggers() - Add triggers for commit writeout * @bh: buffer to trigger on * @type: struct jbd2_buffer_trigger_type containing the trigger(s). * @@ -1425,7 +1426,7 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh, } /** - * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata + * jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata * @handle: transaction to add buffer to. * @bh: buffer to mark * @@ -1593,7 +1594,7 @@ out: } /** - * void jbd2_journal_forget() - bforget() for potentially-journaled buffers. + * jbd2_journal_forget() - bforget() for potentially-journaled buffers. * @handle: transaction handle * @bh: bh to 'forget' * @@ -1762,7 +1763,7 @@ drop: } /** - * int jbd2_journal_stop() - complete a transaction + * jbd2_journal_stop() - complete a transaction * @handle: transaction to complete. * * All done for a particular handle. @@ -2080,7 +2081,7 @@ out: } /** - * int jbd2_journal_try_to_free_buffers() - try to free page buffers. + * jbd2_journal_try_to_free_buffers() - try to free page buffers. * @journal: journal for operation * @page: to try and free * @@ -2411,7 +2412,7 @@ zap_buffer_unlocked: } /** - * void jbd2_journal_invalidatepage() + * jbd2_journal_invalidatepage() * @journal: journal to use for flush... * @page: page to flush * @offset: start of the range to invalidate diff --git a/fs/libfs.c b/fs/libfs.c index fc34361c1489..7124c2e8df2f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -959,7 +959,7 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct simple_attr *attr; - u64 val; + unsigned long long val; size_t size; ssize_t ret; @@ -977,7 +977,9 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, goto out; attr->set_buf[size] = '\0'; - val = simple_strtoll(attr->set_buf, NULL, 0); + ret = kstrtoull(attr->set_buf, 0, &val); + if (ret) + goto out; ret = attr->set(attr->data, val); if (ret == 0) ret = len; /* on success, claim we got the whole input */ diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index a960ec3a569a..8d3ad5ef2925 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -178,6 +178,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, struct inode *inode = d_inode(dentry); struct dentry *parent; bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED; + bool parent_needed, parent_interested; __u32 p_mask; struct inode *p_inode = NULL; struct name_snapshot name; @@ -193,7 +194,8 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, return 0; parent = NULL; - if (!parent_watched && !fsnotify_event_needs_parent(inode, mnt, mask)) + parent_needed = fsnotify_event_needs_parent(inode, mnt, mask); + if (!parent_watched && !parent_needed) goto notify; /* Does parent inode care about events on children? */ @@ -205,17 +207,17 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, /* * Include parent/name in notification either if some notification - * groups require parent info (!parent_watched case) or the parent is - * interested in this event. + * groups require parent info or the parent is interested in this event. */ - if (!parent_watched || (mask & p_mask & ALL_FSNOTIFY_EVENTS)) { + parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS; + if (parent_needed || parent_interested) { /* When notifying parent, child should be passed as data */ WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type)); /* Notify both parent and child with child name info */ take_dentry_name_snapshot(&name, dentry); file_name = &name.name; - if (parent_watched) + if (parent_interested) mask |= FS_EVENT_ON_CHILD; } diff --git a/fs/proc/self.c b/fs/proc/self.c index 72cd69bcaf4a..cc71ce3466dc 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -16,6 +16,13 @@ static const char *proc_self_get_link(struct dentry *dentry, pid_t tgid = task_tgid_nr_ns(current, ns); char *name; + /* + * Not currently supported. Once we can inherit all of struct pid, + * we can allow this. + */ + if (current->flags & PF_KTHREAD) + return ERR_PTR(-EOPNOTSUPP); + if (!tgid) return ERR_PTR(-ENOENT); /* max length of unsigned int in decimal + NULL term */ diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index bb128db220ac..d6ef69ab1c67 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -515,7 +515,7 @@ xfs_attr_copy_value( *========================================================================*/ /* - * Query whether the requested number of additional bytes of extended + * Query whether the total requested number of attr fork bytes of extended * attribute space will be able to fit inline. * * Returns zero if not, else the di_forkoff fork offset to be used in the @@ -535,6 +535,12 @@ xfs_attr_shortform_bytesfit( int maxforkoff; int offset; + /* + * Check if the new size could fit at all first: + */ + if (bytes > XFS_LITINO(mp)) + return 0; + /* rounded down */ offset = (XFS_LITINO(mp) - bytes) >> 3; diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c index 577a66381327..beb81c84a937 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.c +++ b/fs/xfs/libxfs/xfs_rmap_btree.c @@ -243,8 +243,8 @@ xfs_rmapbt_key_diff( else if (y > x) return -1; - x = be64_to_cpu(kp->rm_offset); - y = xfs_rmap_irec_offset_pack(rec); + x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset)); + y = rec->rm_offset; if (x > y) return 1; else if (y > x) @@ -275,8 +275,8 @@ xfs_rmapbt_diff_two_keys( else if (y > x) return -1; - x = be64_to_cpu(kp1->rm_offset); - y = be64_to_cpu(kp2->rm_offset); + x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset)); + y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset)); if (x > y) return 1; else if (y > x) @@ -390,8 +390,8 @@ xfs_rmapbt_keys_inorder( return 1; else if (a > b) return 0; - a = be64_to_cpu(k1->rmap.rm_offset); - b = be64_to_cpu(k2->rmap.rm_offset); + a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset)); + b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset)); if (a <= b) return 1; return 0; @@ -420,8 +420,8 @@ xfs_rmapbt_recs_inorder( return 1; else if (a > b) return 0; - a = be64_to_cpu(r1->rmap.rm_offset); - b = be64_to_cpu(r2->rmap.rm_offset); + a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset)); + b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset)); if (a <= b) return 1; return 0; diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index 412e2ec55e38..fed56d213a3f 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -218,13 +218,13 @@ xchk_bmap_xref_rmap( * which doesn't track unwritten state. */ if (owner != XFS_RMAP_OWN_COW && - irec->br_state == XFS_EXT_UNWRITTEN && - !(rmap.rm_flags & XFS_RMAP_UNWRITTEN)) + !!(irec->br_state == XFS_EXT_UNWRITTEN) != + !!(rmap.rm_flags & XFS_RMAP_UNWRITTEN)) xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, irec->br_startoff); - if (info->whichfork == XFS_ATTR_FORK && - !(rmap.rm_flags & XFS_RMAP_ATTR_FORK)) + if (!!(info->whichfork == XFS_ATTR_FORK) != + !!(rmap.rm_flags & XFS_RMAP_ATTR_FORK)) xchk_fblock_xref_set_corrupt(info->sc, info->whichfork, irec->br_startoff); if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK) diff --git a/fs/xfs/scrub/btree.c b/fs/xfs/scrub/btree.c index f52a7b8256f9..debf392e0515 100644 --- a/fs/xfs/scrub/btree.c +++ b/fs/xfs/scrub/btree.c @@ -452,32 +452,41 @@ xchk_btree_check_minrecs( int level, struct xfs_btree_block *block) { - unsigned int numrecs; - int ok_level; - - numrecs = be16_to_cpu(block->bb_numrecs); + struct xfs_btree_cur *cur = bs->cur; + unsigned int root_level = cur->bc_nlevels - 1; + unsigned int numrecs = be16_to_cpu(block->bb_numrecs); /* More records than minrecs means the block is ok. */ - if (numrecs >= bs->cur->bc_ops->get_minrecs(bs->cur, level)) + if (numrecs >= cur->bc_ops->get_minrecs(cur, level)) return; /* - * Certain btree blocks /can/ have fewer than minrecs records. Any - * level greater than or equal to the level of the highest dedicated - * btree block are allowed to violate this constraint. - * - * For a btree rooted in a block, the btree root can have fewer than - * minrecs records. If the btree is rooted in an inode and does not - * store records in the root, the direct children of the root and the - * root itself can have fewer than minrecs records. + * For btrees rooted in the inode, it's possible that the root block + * contents spilled into a regular ondisk block because there wasn't + * enough space in the inode root. The number of records in that + * child block might be less than the standard minrecs, but that's ok + * provided that there's only one direct child of the root. */ - ok_level = bs->cur->bc_nlevels - 1; - if (bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) - ok_level--; - if (level >= ok_level) + if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && + level == cur->bc_nlevels - 2) { + struct xfs_btree_block *root_block; + struct xfs_buf *root_bp; + int root_maxrecs; + + root_block = xfs_btree_get_block(cur, root_level, &root_bp); + root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level); + if (be16_to_cpu(root_block->bb_numrecs) != 1 || + numrecs <= root_maxrecs) + xchk_btree_set_corrupt(bs->sc, cur, level); return; + } - xchk_btree_set_corrupt(bs->sc, bs->cur, level); + /* + * Otherwise, only the root level is allowed to have fewer than minrecs + * records or keyptrs. + */ + if (level < root_level) + xchk_btree_set_corrupt(bs->sc, cur, level); } /* diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 7c432997edad..b045e95c2ea7 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -558,14 +558,27 @@ xchk_directory_leaf1_bestfree( /* Check all the bestfree entries. */ for (i = 0; i < bestcount; i++, bestp++) { best = be16_to_cpu(*bestp); - if (best == NULLDATAOFF) - continue; error = xfs_dir3_data_read(sc->tp, sc->ip, - i * args->geo->fsbcount, 0, &dbp); + xfs_dir2_db_to_da(args->geo, i), + XFS_DABUF_MAP_HOLE_OK, + &dbp); if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error)) break; - xchk_directory_check_freesp(sc, lblk, dbp, best); + + if (!dbp) { + if (best != NULLDATAOFF) { + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, + lblk); + break; + } + continue; + } + + if (best == NULLDATAOFF) + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk); + else + xchk_directory_check_freesp(sc, lblk, dbp, best); xfs_trans_brelse(sc->tp, dbp); if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) break; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 3abb8b9d6f4c..7b9ff824e82d 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -706,6 +706,23 @@ relock: return 0; } +/* + * Check that the imap we are going to return to the caller spans the entire + * range that the caller requested for the IO. + */ +static bool +imap_spans_range( + struct xfs_bmbt_irec *imap, + xfs_fileoff_t offset_fsb, + xfs_fileoff_t end_fsb) +{ + if (imap->br_startoff > offset_fsb) + return false; + if (imap->br_startoff + imap->br_blockcount < end_fsb) + return false; + return true; +} + static int xfs_direct_write_iomap_begin( struct inode *inode, @@ -766,6 +783,18 @@ xfs_direct_write_iomap_begin( if (imap_needs_alloc(inode, flags, &imap, nimaps)) goto allocate_blocks; + /* + * NOWAIT IO needs to span the entire requested IO with a single map so + * that we avoid partial IO failures due to the rest of the IO range not + * covered by this map triggering an EAGAIN condition when it is + * subsequently mapped and aborting the IO. + */ + if ((flags & IOMAP_NOWAIT) && + !imap_spans_range(&imap, offset_fsb, end_fsb)) { + error = -EAGAIN; + goto out_unlock; + } + xfs_iunlock(ip, lockmode); trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap); return xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags); diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c index 233dcc8784db..2a45138831e3 100644 --- a/fs/xfs/xfs_iwalk.c +++ b/fs/xfs/xfs_iwalk.c @@ -55,6 +55,9 @@ struct xfs_iwalk_ag { /* Where do we start the traversal? */ xfs_ino_t startino; + /* What was the last inode number we saw when iterating the inobt? */ + xfs_ino_t lastino; + /* Array of inobt records we cache. */ struct xfs_inobt_rec_incore *recs; @@ -301,6 +304,9 @@ xfs_iwalk_ag_start( if (XFS_IS_CORRUPT(mp, *has_more != 1)) return -EFSCORRUPTED; + iwag->lastino = XFS_AGINO_TO_INO(mp, agno, + irec->ir_startino + XFS_INODES_PER_CHUNK - 1); + /* * If the LE lookup yielded an inobt record before the cursor position, * skip it and see if there's another one after it. @@ -347,15 +353,17 @@ xfs_iwalk_run_callbacks( struct xfs_mount *mp = iwag->mp; struct xfs_trans *tp = iwag->tp; struct xfs_inobt_rec_incore *irec; - xfs_agino_t restart; + xfs_agino_t next_agino; int error; + next_agino = XFS_INO_TO_AGINO(mp, iwag->lastino) + 1; + ASSERT(iwag->nr_recs > 0); /* Delete cursor but remember the last record we cached... */ xfs_iwalk_del_inobt(tp, curpp, agi_bpp, 0); irec = &iwag->recs[iwag->nr_recs - 1]; - restart = irec->ir_startino + XFS_INODES_PER_CHUNK - 1; + ASSERT(next_agino == irec->ir_startino + XFS_INODES_PER_CHUNK); error = xfs_iwalk_ag_recs(iwag); if (error) @@ -372,7 +380,7 @@ xfs_iwalk_run_callbacks( if (error) return error; - return xfs_inobt_lookup(*curpp, restart, XFS_LOOKUP_GE, has_more); + return xfs_inobt_lookup(*curpp, next_agino, XFS_LOOKUP_GE, has_more); } /* Walk all inodes in a single AG, from @iwag->startino to the end of the AG. */ @@ -396,6 +404,7 @@ xfs_iwalk_ag( while (!error && has_more) { struct xfs_inobt_rec_incore *irec; + xfs_ino_t rec_fsino; cond_resched(); if (xfs_pwork_want_abort(&iwag->pwork)) @@ -407,6 +416,15 @@ xfs_iwalk_ag( if (error || !has_more) break; + /* Make sure that we always move forward. */ + rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino); + if (iwag->lastino != NULLFSINO && + XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) { + error = -EFSCORRUPTED; + goto out; + } + iwag->lastino = rec_fsino + XFS_INODES_PER_CHUNK - 1; + /* No allocated inodes in this chunk; skip it. */ if (iwag->skip_empty && irec->ir_freecount == irec->ir_count) { error = xfs_btree_increment(cur, 0, &has_more); @@ -535,6 +553,7 @@ xfs_iwalk( .trim_start = 1, .skip_empty = 1, .pwork = XFS_PWORK_SINGLE_THREADED, + .lastino = NULLFSINO, }; xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); int error; @@ -623,6 +642,7 @@ xfs_iwalk_threaded( iwag->data = data; iwag->startino = startino; iwag->sz_recs = xfs_iwalk_prefetch(inode_records); + iwag->lastino = NULLFSINO; xfs_pwork_queue(&pctl, &iwag->pwork); startino = XFS_AGINO_TO_INO(mp, agno + 1, 0); if (flags & XFS_INOBT_WALK_SAME_AG) @@ -696,6 +716,7 @@ xfs_inobt_walk( .startino = startino, .sz_recs = xfs_inobt_walk_prefetch(inobt_records), .pwork = XFS_PWORK_SINGLE_THREADED, + .lastino = NULLFSINO, }; xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); int error; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 150ee5cb8645..7110507a2b6b 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -194,20 +194,25 @@ xfs_initialize_perag( } pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); - if (!pag) + if (!pag) { + error = -ENOMEM; goto out_unwind_new_pags; + } pag->pag_agno = index; pag->pag_mount = mp; spin_lock_init(&pag->pag_ici_lock); INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); - if (xfs_buf_hash_init(pag)) + + error = xfs_buf_hash_init(pag); + if (error) goto out_free_pag; init_waitqueue_head(&pag->pagb_wait); spin_lock_init(&pag->pagb_lock); pag->pagb_count = 0; pag->pagb_tree = RB_ROOT; - if (radix_tree_preload(GFP_NOFS)) + error = radix_tree_preload(GFP_NOFS); + if (error) goto out_hash_destroy; spin_lock(&mp->m_perag_lock); diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index dd7233c48bf3..98cff1b4b088 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -8,8 +8,10 @@ + __clang_patchlevel__) #if CLANG_VERSION < 100001 +#ifndef __BPF_TRACING__ # error Sorry, your version of Clang is too old - please use 10.0.1 or newer. #endif +#endif /* Compiler specific definitions for Clang compiler */ diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 5968df82b991..41a1bab98b7e 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -50,10 +50,6 @@ #define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U #define ZYNQMP_PM_CAPABILITY_UNUSABLE 0x8U -/* Feature check status */ -#define PM_FEATURE_INVALID -1 -#define PM_FEATURE_UNCHECKED 0 - /* * Firmware FPGA Manager flags * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index fbf5b3e7707e..d956987ed032 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -798,7 +798,6 @@ extern int iommu_calculate_agaw(struct intel_iommu *iommu); extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu); extern int dmar_disabled; extern int intel_iommu_enabled; -extern int intel_iommu_tboot_noforce; extern int intel_iommu_gfx_mapped; #else static inline int iommu_calculate_agaw(struct intel_iommu *iommu) diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 1c49fd62ff2e..578ff196b3ce 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -401,7 +401,7 @@ static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) #define JI_WAIT_DATA (1 << __JI_WAIT_DATA) /** - * struct jbd_inode - The jbd_inode type is the structure linking inodes in + * struct jbd2_inode - The jbd_inode type is the structure linking inodes in * ordered mode present in a transaction so that we can sync them during commit. */ struct jbd2_inode { diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index a80c59af2c60..922a7f600465 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -282,20 +282,6 @@ struct mem_cgroup { MEMCG_PADDING(_pad1_); - /* - * set > 0 if pages under this cgroup are moving to other cgroup. - */ - atomic_t moving_account; - struct task_struct *move_lock_task; - - /* Legacy local VM stats and events */ - struct memcg_vmstats_percpu __percpu *vmstats_local; - - /* Subtree VM stats and events (batched updates) */ - struct memcg_vmstats_percpu __percpu *vmstats_percpu; - - MEMCG_PADDING(_pad2_); - atomic_long_t vmstats[MEMCG_NR_STAT]; atomic_long_t vmevents[NR_VM_EVENT_ITEMS]; @@ -317,6 +303,20 @@ struct mem_cgroup { struct list_head objcg_list; /* list of inherited objcgs */ #endif + MEMCG_PADDING(_pad2_); + + /* + * set > 0 if pages under this cgroup are moving to other cgroup. + */ + atomic_t moving_account; + struct task_struct *move_lock_task; + + /* Legacy local VM stats and events */ + struct memcg_vmstats_percpu __percpu *vmstats_local; + + /* Subtree VM stats and events (batched updates) */ + struct memcg_vmstats_percpu __percpu *vmstats_percpu; + #ifdef CONFIG_CGROUP_WRITEBACK struct list_head cgwb_list; struct wb_domain cgwb_domain; diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index d65c6fdc5cfc..551093b74596 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -281,20 +281,6 @@ static inline bool movable_node_is_enabled(void) } #endif /* ! CONFIG_MEMORY_HOTPLUG */ -#ifdef CONFIG_NUMA -extern int memory_add_physaddr_to_nid(u64 start); -extern int phys_to_target_node(u64 start); -#else -static inline int memory_add_physaddr_to_nid(u64 start) -{ - return 0; -} -static inline int phys_to_target_node(u64 start) -{ - return 0; -} -#endif - #if defined(CONFIG_MEMORY_HOTPLUG) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT) /* * pgdat resizing functions diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0049e8fe4905..8eeb73ac58bd 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3163,6 +3163,11 @@ static inline bool dev_validate_header(const struct net_device *dev, return false; } +static inline bool dev_has_header(const struct net_device *dev) +{ + return dev->header_ops && dev->header_ops->create; +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len, int size); int register_gifconf(unsigned int family, gifconf_func_t *gifconf); diff --git a/include/linux/numa.h b/include/linux/numa.h index 8cb33ccfb671..cb44cfe2b725 100644 --- a/include/linux/numa.h +++ b/include/linux/numa.h @@ -21,13 +21,41 @@ #endif #ifdef CONFIG_NUMA +#include <linux/printk.h> +#include <asm/sparsemem.h> + /* Generic implementation available */ int numa_map_to_online_node(int node); -#else + +#ifndef memory_add_physaddr_to_nid +static inline int memory_add_physaddr_to_nid(u64 start) +{ + pr_info_once("Unknown online node for memory at 0x%llx, assuming node 0\n", + start); + return 0; +} +#endif +#ifndef phys_to_target_node +static inline int phys_to_target_node(u64 start) +{ + pr_info_once("Unknown target node for memory at 0x%llx, assuming node 0\n", + start); + return 0; +} +#endif +#else /* !CONFIG_NUMA */ static inline int numa_map_to_online_node(int node) { return NUMA_NO_NODE; } +static inline int memory_add_physaddr_to_nid(u64 start) +{ + return 0; +} +static inline int phys_to_target_node(u64 start) +{ + return 0; +} #endif #endif /* _LINUX_NUMA_H */ diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index e1e19c1f9ec9..d5570deff400 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -906,6 +906,8 @@ static inline unsigned int __readahead_batch(struct readahead_control *rac, xas_set(&xas, rac->_index); rcu_read_lock(); xas_for_each(&xas, page, rac->_index + rac->_nr_pages - 1) { + if (xas_retry(&xas, page)) + continue; VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(PageTail(page), page); array[i++] = page; diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index 71125a4676c4..e237004d498d 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -1427,6 +1427,19 @@ typedef unsigned int pgtbl_mod_mask; #endif /* !__ASSEMBLY__ */ +#if !defined(MAX_POSSIBLE_PHYSMEM_BITS) && !defined(CONFIG_64BIT) +#ifdef CONFIG_PHYS_ADDR_T_64BIT +/* + * ZSMALLOC needs to know the highest PFN on 32-bit architectures + * with physical address space extension, but falls back to + * BITS_PER_LONG otherwise. + */ +#error Missing MAX_POSSIBLE_PHYSMEM_BITS definition +#else +#define MAX_POSSIBLE_PHYSMEM_BITS 32 +#endif +#endif + #ifndef has_transparent_hugepage #ifdef CONFIG_TRANSPARENT_HUGEPAGE #define has_transparent_hugepage() 1 diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h index c59999ce044e..240dce553a0b 100644 --- a/include/linux/platform_data/ti-sysc.h +++ b/include/linux/platform_data/ti-sysc.h @@ -50,6 +50,7 @@ struct sysc_regbits { s8 emufree_shift; }; +#define SYSC_MODULE_QUIRK_ENA_RESETDONE BIT(25) #define SYSC_MODULE_QUIRK_PRUSS BIT(24) #define SYSC_MODULE_QUIRK_DSS_RESET BIT(23) #define SYSC_MODULE_QUIRK_RTC_UNLOCK BIT(22) diff --git a/include/linux/sched.h b/include/linux/sched.h index 063cd120b459..76cd21fa5501 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -552,7 +552,6 @@ struct sched_dl_entity { * overruns. */ unsigned int dl_throttled : 1; - unsigned int dl_boosted : 1; unsigned int dl_yielded : 1; unsigned int dl_non_contending : 1; unsigned int dl_overrun : 1; @@ -571,6 +570,15 @@ struct sched_dl_entity { * time. */ struct hrtimer inactive_timer; + +#ifdef CONFIG_RT_MUTEXES + /* + * Priority Inheritance. When a DEADLINE scheduling entity is boosted + * pi_se points to the donor, otherwise points to the dl_se it belongs + * to (the original one/itself). + */ + struct sched_dl_entity *pi_se; +#endif }; #ifdef CONFIG_UCLAMP_TASK @@ -770,7 +778,6 @@ struct task_struct { unsigned sched_reset_on_fork:1; unsigned sched_contributes_to_load:1; unsigned sched_migrated:1; - unsigned sched_remote_wakeup:1; #ifdef CONFIG_PSI unsigned sched_psi_wake_requeue:1; #endif @@ -780,6 +787,21 @@ struct task_struct { /* Unserialized, strictly 'current' */ + /* + * This field must not be in the scheduler word above due to wakelist + * queueing no longer being serialized by p->on_cpu. However: + * + * p->XXX = X; ttwu() + * schedule() if (p->on_rq && ..) // false + * smp_mb__after_spinlock(); if (smp_load_acquire(&p->on_cpu) && //true + * deactivate_task() ttwu_queue_wakelist()) + * p->on_rq = 0; p->sched_remote_wakeup = Y; + * + * guarantees all stores of 'current' are visible before + * ->sched_remote_wakeup gets used, so it can be in this word. + */ + unsigned sched_remote_wakeup:1; + /* Bit to tell LSMs we're in execve(): */ unsigned in_execve:1; unsigned in_iowait:1; diff --git a/include/net/bonding.h b/include/net/bonding.h index 7d132cc1e584..d9d0ff3b0ad3 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -185,6 +185,11 @@ struct slave { struct rtnl_link_stats64 slave_stats; }; +static inline struct slave *to_slave(struct kobject *kobj) +{ + return container_of(kobj, struct slave, kobj); +} + struct bond_up_slave { unsigned int count; struct rcu_head rcu; @@ -750,6 +755,9 @@ extern struct bond_parm_tbl ad_select_tbl[]; /* exported from bond_netlink.c */ extern struct rtnl_link_ops bond_link_ops; +/* exported from bond_sysfs_slave.c */ +extern const struct sysfs_ops slave_sysfs_ops; + static inline netdev_tx_t bond_tx_drop(struct net_device *dev, struct sk_buff *skb) { atomic_long_inc(&dev->tx_dropped); diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 92560974ea67..ca6a3ea9057e 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -247,8 +247,9 @@ void inet_hashinfo2_init(struct inet_hashinfo *h, const char *name, unsigned long high_limit); int inet_hashinfo2_init_mod(struct inet_hashinfo *h); -bool inet_ehash_insert(struct sock *sk, struct sock *osk); -bool inet_ehash_nolisten(struct sock *sk, struct sock *osk); +bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk); +bool inet_ehash_nolisten(struct sock *sk, struct sock *osk, + bool *found_dup_sk); int __inet_hash(struct sock *sk, struct sock *osk); int inet_hash(struct sock *sk); void inet_unhash(struct sock *sk); diff --git a/include/net/tls.h b/include/net/tls.h index b2637edc2726..3eccb525e8f7 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -199,6 +199,12 @@ enum tls_context_flags { * to be atomic. */ TLS_TX_SYNC_SCHED = 1, + /* tls_dev_del was called for the RX side, device state was released, + * but tls_ctx->netdev might still be kept, because TX-side driver + * resources might not be released yet. Used to prevent the second + * tls_dev_del call in tls_device_down if it happens simultaneously. + */ + TLS_RX_DEV_CLOSED = 2, }; struct cipher_context { diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index c25fb86ffae9..b3bbd10eb3f0 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -132,6 +132,9 @@ struct iscsi_task { void *dd_data; /* driver/transport data */ }; +/* invalid scsi_task pointer */ +#define INVALID_SCSI_TASK (struct iscsi_task *)-1l + static inline int iscsi_task_has_unsol_data(struct iscsi_task *task) { return task->unsol_r2t.data_length > task->unsol_r2t.sent; diff --git a/include/sound/rt1015.h b/include/sound/rt1015.h new file mode 100644 index 000000000000..70a7538d4c89 --- /dev/null +++ b/include/sound/rt1015.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/sound/rt1015.h -- Platform data for RT1015 + * + * Copyright 2020 Realtek Microelectronics + */ + +#ifndef __LINUX_SND_RT1015_H +#define __LINUX_SND_RT1015_H + +struct rt1015_platform_data { + unsigned int power_up_delay_ms; +}; + +#endif diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index e7cbccc7c14c..57d795365987 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -190,7 +190,7 @@ TRACE_EVENT(inode_foreign_history, ), TP_fast_assign( - strncpy(__entry->name, bdi_dev_name(inode_to_bdi(inode)), 32); + strscpy_pad(__entry->name, bdi_dev_name(inode_to_bdi(inode)), 32); __entry->ino = inode->i_ino; __entry->cgroup_ino = __trace_wbc_assign_cgroup(wbc); __entry->history = history; @@ -219,7 +219,7 @@ TRACE_EVENT(inode_switch_wbs, ), TP_fast_assign( - strncpy(__entry->name, bdi_dev_name(old_wb->bdi), 32); + strscpy_pad(__entry->name, bdi_dev_name(old_wb->bdi), 32); __entry->ino = inode->i_ino; __entry->old_cgroup_ino = __trace_wb_assign_cgroup(old_wb); __entry->new_cgroup_ino = __trace_wb_assign_cgroup(new_wb); @@ -252,7 +252,7 @@ TRACE_EVENT(track_foreign_dirty, struct address_space *mapping = page_mapping(page); struct inode *inode = mapping ? mapping->host : NULL; - strncpy(__entry->name, bdi_dev_name(wb->bdi), 32); + strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32); __entry->bdi_id = wb->bdi->id; __entry->ino = inode ? inode->i_ino : 0; __entry->memcg_id = wb->memcg_css->id; @@ -285,7 +285,7 @@ TRACE_EVENT(flush_foreign, ), TP_fast_assign( - strncpy(__entry->name, bdi_dev_name(wb->bdi), 32); + strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32); __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); __entry->frn_bdi_id = frn_bdi_id; __entry->frn_memcg_id = frn_memcg_id; diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 0113bc4db9f5..5203f54a2be1 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -526,6 +526,8 @@ enum devlink_attr { DEVLINK_ATTR_RELOAD_STATS_LIMIT, /* u8 */ DEVLINK_ATTR_RELOAD_STATS_VALUE, /* u32 */ DEVLINK_ATTR_REMOTE_RELOAD_STATS, /* nested */ + DEVLINK_ATTR_RELOAD_ACTION_INFO, /* nested */ + DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */ /* add new attributes above here, update the policy in devlink.c */ diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 8300cc29dec8..8d16744edc31 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -1058,4 +1058,6 @@ enum ovs_dec_ttl_attr { __OVS_DEC_TTL_ATTR_MAX }; +#define OVS_DEC_TTL_ATTR_MAX (__OVS_DEC_TTL_ATTR_MAX - 1) + #endif /* _LINUX_OPENVSWITCH_H */ diff --git a/init/Kconfig b/init/Kconfig index c9446911cf41..02d13ae27abb 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -719,7 +719,7 @@ config LOG_CPU_MAX_BUF_SHIFT with more CPUs. Therefore this value is used only when the sum of contributions is greater than the half of the default kernel ring buffer as defined by LOG_BUF_SHIFT. The default values are set - so that more than 64 CPUs are needed to trigger the allocation. + so that more than 16 CPUs are needed to trigger the allocation. Also this option is ignored when "log_buf_len" kernel parameter is used as it forces an exact (power of two) size of the ring buffer. diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index d9fb9e19d2ed..c1418b47f625 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -108,19 +108,21 @@ static inline void lockdep_lock(void) { DEBUG_LOCKS_WARN_ON(!irqs_disabled()); + __this_cpu_inc(lockdep_recursion); arch_spin_lock(&__lock); __owner = current; - __this_cpu_inc(lockdep_recursion); } static inline void lockdep_unlock(void) { + DEBUG_LOCKS_WARN_ON(!irqs_disabled()); + if (debug_locks && DEBUG_LOCKS_WARN_ON(__owner != current)) return; - __this_cpu_dec(lockdep_recursion); __owner = NULL; arch_spin_unlock(&__lock); + __this_cpu_dec(lockdep_recursion); } static inline bool lockdep_assert_locked(void) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index fe64a49344bf..bc1e3b5a97bd 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -528,8 +528,8 @@ static int log_store(u32 caller_id, int facility, int level, if (dev_info) memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info)); - /* insert message */ - if ((flags & LOG_CONT) || !(flags & LOG_NEWLINE)) + /* A message without a trailing newline can be continued. */ + if (!(flags & LOG_NEWLINE)) prb_commit(&e); else prb_final_commit(&e); diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c index 6b1525685277..74e25a1704f2 100644 --- a/kernel/printk/printk_ringbuffer.c +++ b/kernel/printk/printk_ringbuffer.c @@ -882,8 +882,6 @@ static bool desc_reserve(struct printk_ringbuffer *rb, unsigned long *id_out) head_id = atomic_long_read(&desc_ring->head_id); /* LMM(desc_reserve:A) */ do { - desc = to_desc(desc_ring, head_id); - id = DESC_ID(head_id + 1); id_prev_wrap = DESC_ID_PREV_WRAP(desc_ring, id); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 43d6179508d6..79de1294f8eb 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -264,17 +264,11 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state) return ret; } -static bool ptrace_has_cap(const struct cred *cred, struct user_namespace *ns, - unsigned int mode) +static bool ptrace_has_cap(struct user_namespace *ns, unsigned int mode) { - int ret; - if (mode & PTRACE_MODE_NOAUDIT) - ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NOAUDIT); - else - ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NONE); - - return ret == 0; + return ns_capable_noaudit(ns, CAP_SYS_PTRACE); + return ns_capable(ns, CAP_SYS_PTRACE); } /* Returns 0 on success, -errno on denial. */ @@ -326,7 +320,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) gid_eq(caller_gid, tcred->sgid) && gid_eq(caller_gid, tcred->gid)) goto ok; - if (ptrace_has_cap(cred, tcred->user_ns, mode)) + if (ptrace_has_cap(tcred->user_ns, mode)) goto ok; rcu_read_unlock(); return -EPERM; @@ -345,7 +339,7 @@ ok: mm = task->mm; if (mm && ((get_dumpable(mm) != SUID_DUMP_USER) && - !ptrace_has_cap(cred, mm->user_ns, mode))) + !ptrace_has_cap(mm->user_ns, mode))) return -EPERM; return security_ptrace_access_check(task, mode); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index d2003a7d5ab5..e7e453492cff 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2501,7 +2501,12 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags, #ifdef CONFIG_SMP if (wake_flags & WF_MIGRATED) en_flags |= ENQUEUE_MIGRATED; + else #endif + if (p->in_iowait) { + delayacct_blkio_end(p); + atomic_dec(&task_rq(p)->nr_iowait); + } activate_task(rq, p, en_flags); ttwu_do_wakeup(rq, p, wake_flags, rf); @@ -2888,11 +2893,6 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags)) goto unlock; - if (p->in_iowait) { - delayacct_blkio_end(p); - atomic_dec(&task_rq(p)->nr_iowait); - } - #ifdef CONFIG_SMP /* * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be @@ -2963,6 +2963,11 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags); if (task_cpu(p) != cpu) { + if (p->in_iowait) { + delayacct_blkio_end(p); + atomic_dec(&task_rq(p)->nr_iowait); + } + wake_flags |= WF_MIGRATED; psi_ttwu_dequeue(p); set_task_cpu(p, cpu); @@ -4907,20 +4912,21 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) if (!dl_prio(p->normal_prio) || (pi_task && dl_prio(pi_task->prio) && dl_entity_preempt(&pi_task->dl, &p->dl))) { - p->dl.dl_boosted = 1; + p->dl.pi_se = pi_task->dl.pi_se; queue_flag |= ENQUEUE_REPLENISH; - } else - p->dl.dl_boosted = 0; + } else { + p->dl.pi_se = &p->dl; + } p->sched_class = &dl_sched_class; } else if (rt_prio(prio)) { if (dl_prio(oldprio)) - p->dl.dl_boosted = 0; + p->dl.pi_se = &p->dl; if (oldprio < prio) queue_flag |= ENQUEUE_HEAD; p->sched_class = &rt_sched_class; } else { if (dl_prio(oldprio)) - p->dl.dl_boosted = 0; + p->dl.pi_se = &p->dl; if (rt_prio(oldprio)) p->rt.timeout = 0; p->sched_class = &fair_sched_class; diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index f232305dcefe..1d3c97268ec0 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -43,6 +43,28 @@ static inline int on_dl_rq(struct sched_dl_entity *dl_se) return !RB_EMPTY_NODE(&dl_se->rb_node); } +#ifdef CONFIG_RT_MUTEXES +static inline struct sched_dl_entity *pi_of(struct sched_dl_entity *dl_se) +{ + return dl_se->pi_se; +} + +static inline bool is_dl_boosted(struct sched_dl_entity *dl_se) +{ + return pi_of(dl_se) != dl_se; +} +#else +static inline struct sched_dl_entity *pi_of(struct sched_dl_entity *dl_se) +{ + return dl_se; +} + +static inline bool is_dl_boosted(struct sched_dl_entity *dl_se) +{ + return false; +} +#endif + #ifdef CONFIG_SMP static inline struct dl_bw *dl_bw_of(int i) { @@ -698,7 +720,7 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se) struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rq *rq = rq_of_dl_rq(dl_rq); - WARN_ON(dl_se->dl_boosted); + WARN_ON(is_dl_boosted(dl_se)); WARN_ON(dl_time_before(rq_clock(rq), dl_se->deadline)); /* @@ -736,21 +758,20 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se) * could happen are, typically, a entity voluntarily trying to overcome its * runtime, or it just underestimated it during sched_setattr(). */ -static void replenish_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se) +static void replenish_dl_entity(struct sched_dl_entity *dl_se) { struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rq *rq = rq_of_dl_rq(dl_rq); - BUG_ON(pi_se->dl_runtime <= 0); + BUG_ON(pi_of(dl_se)->dl_runtime <= 0); /* * This could be the case for a !-dl task that is boosted. * Just go with full inherited parameters. */ if (dl_se->dl_deadline == 0) { - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; + dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline; + dl_se->runtime = pi_of(dl_se)->dl_runtime; } if (dl_se->dl_yielded && dl_se->runtime > 0) @@ -763,8 +784,8 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se, * arbitrary large. */ while (dl_se->runtime <= 0) { - dl_se->deadline += pi_se->dl_period; - dl_se->runtime += pi_se->dl_runtime; + dl_se->deadline += pi_of(dl_se)->dl_period; + dl_se->runtime += pi_of(dl_se)->dl_runtime; } /* @@ -778,8 +799,8 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se, */ if (dl_time_before(dl_se->deadline, rq_clock(rq))) { printk_deferred_once("sched: DL replenish lagged too much\n"); - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; + dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline; + dl_se->runtime = pi_of(dl_se)->dl_runtime; } if (dl_se->dl_yielded) @@ -812,8 +833,7 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se, * task with deadline equal to period this is the same of using * dl_period instead of dl_deadline in the equation above. */ -static bool dl_entity_overflow(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se, u64 t) +static bool dl_entity_overflow(struct sched_dl_entity *dl_se, u64 t) { u64 left, right; @@ -835,9 +855,9 @@ static bool dl_entity_overflow(struct sched_dl_entity *dl_se, * of anything below microseconds resolution is actually fiction * (but still we want to give the user that illusion >;). */ - left = (pi_se->dl_deadline >> DL_SCALE) * (dl_se->runtime >> DL_SCALE); + left = (pi_of(dl_se)->dl_deadline >> DL_SCALE) * (dl_se->runtime >> DL_SCALE); right = ((dl_se->deadline - t) >> DL_SCALE) * - (pi_se->dl_runtime >> DL_SCALE); + (pi_of(dl_se)->dl_runtime >> DL_SCALE); return dl_time_before(right, left); } @@ -922,24 +942,23 @@ static inline bool dl_is_implicit(struct sched_dl_entity *dl_se) * Please refer to the comments update_dl_revised_wakeup() function to find * more about the Revised CBS rule. */ -static void update_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se) +static void update_dl_entity(struct sched_dl_entity *dl_se) { struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rq *rq = rq_of_dl_rq(dl_rq); if (dl_time_before(dl_se->deadline, rq_clock(rq)) || - dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) { + dl_entity_overflow(dl_se, rq_clock(rq))) { if (unlikely(!dl_is_implicit(dl_se) && !dl_time_before(dl_se->deadline, rq_clock(rq)) && - !dl_se->dl_boosted)){ + !is_dl_boosted(dl_se))) { update_dl_revised_wakeup(dl_se, rq); return; } - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; + dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline; + dl_se->runtime = pi_of(dl_se)->dl_runtime; } } @@ -1038,7 +1057,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer) * The task might have been boosted by someone else and might be in the * boosting/deboosting path, its not throttled. */ - if (dl_se->dl_boosted) + if (is_dl_boosted(dl_se)) goto unlock; /* @@ -1066,7 +1085,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer) * but do not enqueue -- wait for our wakeup to do that. */ if (!task_on_rq_queued(p)) { - replenish_dl_entity(dl_se, dl_se); + replenish_dl_entity(dl_se); goto unlock; } @@ -1156,7 +1175,7 @@ static inline void dl_check_constrained_dl(struct sched_dl_entity *dl_se) if (dl_time_before(dl_se->deadline, rq_clock(rq)) && dl_time_before(rq_clock(rq), dl_next_period(dl_se))) { - if (unlikely(dl_se->dl_boosted || !start_dl_timer(p))) + if (unlikely(is_dl_boosted(dl_se) || !start_dl_timer(p))) return; dl_se->dl_throttled = 1; if (dl_se->runtime > 0) @@ -1287,7 +1306,7 @@ throttle: dl_se->dl_overrun = 1; __dequeue_task_dl(rq, curr, 0); - if (unlikely(dl_se->dl_boosted || !start_dl_timer(curr))) + if (unlikely(is_dl_boosted(dl_se) || !start_dl_timer(curr))) enqueue_task_dl(rq, curr, ENQUEUE_REPLENISH); if (!is_leftmost(curr, &rq->dl)) @@ -1481,8 +1500,7 @@ static void __dequeue_dl_entity(struct sched_dl_entity *dl_se) } static void -enqueue_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se, int flags) +enqueue_dl_entity(struct sched_dl_entity *dl_se, int flags) { BUG_ON(on_dl_rq(dl_se)); @@ -1493,9 +1511,9 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se, */ if (flags & ENQUEUE_WAKEUP) { task_contending(dl_se, flags); - update_dl_entity(dl_se, pi_se); + update_dl_entity(dl_se); } else if (flags & ENQUEUE_REPLENISH) { - replenish_dl_entity(dl_se, pi_se); + replenish_dl_entity(dl_se); } else if ((flags & ENQUEUE_RESTORE) && dl_time_before(dl_se->deadline, rq_clock(rq_of_dl_rq(dl_rq_of_se(dl_se))))) { @@ -1512,19 +1530,7 @@ static void dequeue_dl_entity(struct sched_dl_entity *dl_se) static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) { - struct task_struct *pi_task = rt_mutex_get_top_task(p); - struct sched_dl_entity *pi_se = &p->dl; - - /* - * Use the scheduling parameters of the top pi-waiter task if: - * - we have a top pi-waiter which is a SCHED_DEADLINE task AND - * - our dl_boosted is set (i.e. the pi-waiter's (absolute) deadline is - * smaller than our deadline OR we are a !SCHED_DEADLINE task getting - * boosted due to a SCHED_DEADLINE pi-waiter). - * Otherwise we keep our runtime and deadline. - */ - if (pi_task && dl_prio(pi_task->normal_prio) && p->dl.dl_boosted) { - pi_se = &pi_task->dl; + if (is_dl_boosted(&p->dl)) { /* * Because of delays in the detection of the overrun of a * thread's runtime, it might be the case that a thread @@ -1557,7 +1563,7 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) * the throttle. */ p->dl.dl_throttled = 0; - BUG_ON(!p->dl.dl_boosted || flags != ENQUEUE_REPLENISH); + BUG_ON(!is_dl_boosted(&p->dl) || flags != ENQUEUE_REPLENISH); return; } @@ -1594,7 +1600,7 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) return; } - enqueue_dl_entity(&p->dl, pi_se, flags); + enqueue_dl_entity(&p->dl, flags); if (!task_current(rq, p) && p->nr_cpus_allowed > 1) enqueue_pushable_dl_task(rq, p); @@ -2787,11 +2793,14 @@ void __dl_clear_params(struct task_struct *p) dl_se->dl_bw = 0; dl_se->dl_density = 0; - dl_se->dl_boosted = 0; dl_se->dl_throttled = 0; dl_se->dl_yielded = 0; dl_se->dl_non_contending = 0; dl_se->dl_overrun = 0; + +#ifdef CONFIG_RT_MUTEXES + dl_se->pi_se = dl_se; +#endif } bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 8917d2d715ef..ae7ceba8fd4f 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5477,6 +5477,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; int idle_h_nr_running = task_has_idle_policy(p); + int task_new = !(flags & ENQUEUE_WAKEUP); /* * The code below (indirectly) updates schedutil which looks at @@ -5549,7 +5550,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) * into account, but that is not straightforward to implement, * and the following generally works well enough in practice. */ - if (flags & ENQUEUE_WAKEUP) + if (!task_new) update_overutilized_status(rq); enqueue_throttle: diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 8ad7a293255a..53a7d1512dd7 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -38,7 +38,7 @@ #include <linux/filter.h> #include <linux/pid.h> #include <linux/ptrace.h> -#include <linux/security.h> +#include <linux/capability.h> #include <linux/tracehook.h> #include <linux/uaccess.h> #include <linux/anon_inodes.h> @@ -558,8 +558,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) * behavior of privileged children. */ if (!task_no_new_privs(current) && - security_capable(current_cred(), current_user_ns(), - CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0) + !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN)) return ERR_PTR(-EACCES); /* Allocate a new seccomp_filter */ diff --git a/mm/filemap.c b/mm/filemap.c index d5e7c2029d16..0b2067b3c328 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1484,11 +1484,19 @@ void end_page_writeback(struct page *page) rotate_reclaimable_page(page); } + /* + * Writeback does not hold a page reference of its own, relying + * on truncation to wait for the clearing of PG_writeback. + * But here we must make sure that the page is not freed and + * reused before the wake_up_page(). + */ + get_page(page); if (!test_clear_page_writeback(page)) BUG(); smp_mb__after_atomic(); wake_up_page(page, PG_writeback); + put_page(page); } EXPORT_SYMBOL(end_page_writeback); @@ -2347,10 +2355,15 @@ page_ok: page_not_up_to_date: /* Get exclusive access to the page ... */ - if (iocb->ki_flags & IOCB_WAITQ) + if (iocb->ki_flags & IOCB_WAITQ) { + if (written) { + put_page(page); + goto out; + } error = lock_page_async(page, iocb->ki_waitq); - else + } else { error = lock_page_killable(page); + } if (unlikely(error)) goto readpage_error; @@ -2393,10 +2406,15 @@ readpage: } if (!PageUptodate(page)) { - if (iocb->ki_flags & IOCB_WAITQ) + if (iocb->ki_flags & IOCB_WAITQ) { + if (written) { + put_page(page); + goto out; + } error = lock_page_async(page, iocb->ki_waitq); - else + } else { error = lock_page_killable(page); + } if (unlikely(error)) goto readpage_error; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9474dbc150ed..ec2bb93f7431 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -710,7 +710,6 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf) transparent_hugepage_use_zero_page()) { pgtable_t pgtable; struct page *zero_page; - bool set; vm_fault_t ret; pgtable = pte_alloc_one(vma->vm_mm); if (unlikely(!pgtable)) @@ -723,25 +722,25 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf) } vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd); ret = 0; - set = false; if (pmd_none(*vmf->pmd)) { ret = check_stable_address_space(vma->vm_mm); if (ret) { spin_unlock(vmf->ptl); + pte_free(vma->vm_mm, pgtable); } else if (userfaultfd_missing(vma)) { spin_unlock(vmf->ptl); + pte_free(vma->vm_mm, pgtable); ret = handle_userfault(vmf, VM_UFFD_MISSING); VM_BUG_ON(ret & VM_FAULT_FALLBACK); } else { set_huge_zero_page(pgtable, vma->vm_mm, vma, haddr, vmf->pmd, zero_page); spin_unlock(vmf->ptl); - set = true; } - } else + } else { spin_unlock(vmf->ptl); - if (!set) pte_free(vma->vm_mm, pgtable); + } return ret; } gfp = alloc_hugepage_direct_gfpmask(vma); diff --git a/mm/madvise.c b/mm/madvise.c index 416a56b8e757..a8d8d48a57fe 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -226,7 +226,7 @@ static void force_shm_swapin_readahead(struct vm_area_struct *vma, struct address_space *mapping) { XA_STATE(xas, &mapping->i_pages, linear_page_index(vma, start)); - pgoff_t end_index = end / PAGE_SIZE; + pgoff_t end_index = linear_page_index(vma, end + PAGE_SIZE - 1); struct page *page; rcu_read_lock(); @@ -1231,8 +1231,6 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec, ret = total_len - iov_iter_count(&iter); mmput(mm); - return ret; - release_task: put_task_struct(task); put_pid: diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3dcbf24d2227..29459a6ce1c7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -867,8 +867,13 @@ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val) rcu_read_lock(); memcg = mem_cgroup_from_obj(p); - /* Untracked pages have no memcg, no lruvec. Update only the node */ - if (!memcg || memcg == root_mem_cgroup) { + /* + * Untracked pages have no memcg, no lruvec. Update only the + * node. If we reparent the slab objects to the root memcg, + * when we free the slab object, we need to update the per-memcg + * vmstats to keep it correct for the root memcg. + */ + if (!memcg) { __mod_node_page_state(pgdat, idx, val); } else { lruvec = mem_cgroup_lruvec(memcg, pgdat); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index b44d4c7ba73b..63b2e46b6555 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -350,24 +350,6 @@ int __ref __add_pages(int nid, unsigned long pfn, unsigned long nr_pages, return err; } -#ifdef CONFIG_NUMA -int __weak memory_add_physaddr_to_nid(u64 start) -{ - pr_info_once("Unknown online node for memory at 0x%llx, assuming node 0\n", - start); - return 0; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); - -int __weak phys_to_target_node(u64 start) -{ - pr_info_once("Unknown target node for memory at 0x%llx, assuming node 0\n", - start); - return 0; -} -EXPORT_SYMBOL_GPL(phys_to_target_node); -#endif - /* find the smallest valid pfn in the range [start_pfn, end_pfn) */ static unsigned long find_smallest_section_pfn(int nid, struct zone *zone, unsigned long start_pfn, diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 7709f0e223f5..586042472ac9 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2754,12 +2754,6 @@ int test_clear_page_writeback(struct page *page) } else { ret = TestClearPageWriteback(page); } - /* - * NOTE: Page might be free now! Writeback doesn't hold a page - * reference on its own, it relies on truncation to wait for - * the clearing of PG_writeback. The below can only access - * page state that is static across allocation cycles. - */ if (ret) { dec_lruvec_state(lruvec, NR_WRITEBACK); dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c index a67b2b091447..c0ca5fbe5b08 100644 --- a/net/batman-adv/log.c +++ b/net/batman-adv/log.c @@ -180,6 +180,7 @@ static const struct file_operations batadv_log_fops = { .read = batadv_log_read, .poll = batadv_log_poll, .llseek = no_llseek, + .owner = THIS_MODULE, }; /** diff --git a/net/can/af_can.c b/net/can/af_can.c index 963bd7145517..837bb8af0ec3 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -541,10 +541,13 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, /* Check for bugs in CAN protocol implementations using af_can.c: * 'rcv' will be NULL if no matching list item was found for removal. + * As this case may potentially happen when closing a socket while + * the notifier for removing the CAN netdev is running we just print + * a warning here. */ if (!rcv) { - WARN(1, "BUG: receive list entry not found for dev %s, id %03X, mask %03X\n", - DNAME(dev), can_id, mask); + pr_warn("can: receive list entry not found for dev %s, id %03X, mask %03X\n", + DNAME(dev), can_id, mask); goto out; } diff --git a/net/core/devlink.c b/net/core/devlink.c index 7c05e8603bff..88c0ac8ed444 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -517,7 +517,7 @@ devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_l return test_bit(limit, &devlink->ops->reload_limits); } -static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_action action, +static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_limit limit, u32 value) { struct nlattr *reload_stats_entry; @@ -526,8 +526,7 @@ static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_acti if (!reload_stats_entry) return -EMSGSIZE; - if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, action) || - nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) || + if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) || nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value)) goto nla_put_failure; nla_nest_end(msg, reload_stats_entry); @@ -540,7 +539,7 @@ nla_put_failure: static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote) { - struct nlattr *reload_stats_attr; + struct nlattr *reload_stats_attr, *act_info, *act_stats; int i, j, stat_idx; u32 value; @@ -552,17 +551,29 @@ static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink if (!reload_stats_attr) return -EMSGSIZE; - for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { - /* Remote stats are shown even if not locally supported. Stats - * of actions with unspecified limit are shown though drivers - * don't need to register unspecified limit. - */ - if (!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && - !devlink_reload_limit_is_supported(devlink, j)) + for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { + if ((!is_remote && + !devlink_reload_action_is_supported(devlink, i)) || + i == DEVLINK_RELOAD_ACTION_UNSPEC) continue; - for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { - if ((!is_remote && !devlink_reload_action_is_supported(devlink, i)) || - i == DEVLINK_RELOAD_ACTION_UNSPEC || + act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO); + if (!act_info) + goto nla_put_failure; + + if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i)) + goto action_info_nest_cancel; + act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS); + if (!act_stats) + goto action_info_nest_cancel; + + for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { + /* Remote stats are shown even if not locally supported. + * Stats of actions with unspecified limit are shown + * though drivers don't need to register unspecified + * limit. + */ + if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && + !devlink_reload_limit_is_supported(devlink, j)) || devlink_reload_combination_is_invalid(i, j)) continue; @@ -571,13 +582,19 @@ static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink value = devlink->stats.reload_stats[stat_idx]; else value = devlink->stats.remote_reload_stats[stat_idx]; - if (devlink_reload_stat_put(msg, i, j, value)) - goto nla_put_failure; + if (devlink_reload_stat_put(msg, j, value)) + goto action_stats_nest_cancel; } + nla_nest_end(msg, act_stats); + nla_nest_end(msg, act_info); } nla_nest_end(msg, reload_stats_attr); return 0; +action_stats_nest_cancel: + nla_nest_cancel(msg, act_stats); +action_info_nest_cancel: + nla_nest_cancel(msg, act_info); nla_put_failure: nla_nest_cancel(msg, reload_stats_attr); return -EMSGSIZE; @@ -755,6 +772,8 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) goto nla_put_failure; + /* Hold rtnl lock while accessing port's netdev attributes. */ + rtnl_lock(); spin_lock_bh(&devlink_port->type_lock); if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type)) goto nla_put_failure_type_locked; @@ -763,9 +782,10 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, devlink_port->desired_type)) goto nla_put_failure_type_locked; if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) { + struct net *net = devlink_net(devlink_port->devlink); struct net_device *netdev = devlink_port->type_dev; - if (netdev && + if (netdev && net_eq(net, dev_net(netdev)) && (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX, netdev->ifindex) || nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME, @@ -781,6 +801,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, goto nla_put_failure_type_locked; } spin_unlock_bh(&devlink_port->type_lock); + rtnl_unlock(); if (devlink_nl_port_attrs_put(msg, devlink_port)) goto nla_put_failure; if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack)) @@ -791,6 +812,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, nla_put_failure_type_locked: spin_unlock_bh(&devlink_port->type_lock); + rtnl_unlock(); nla_put_failure: genlmsg_cancel(msg, hdr); return -EMSGSIZE; diff --git a/net/core/gro_cells.c b/net/core/gro_cells.c index e095fb871d91..6eb2e5ec2c50 100644 --- a/net/core/gro_cells.c +++ b/net/core/gro_cells.c @@ -99,9 +99,14 @@ void gro_cells_destroy(struct gro_cells *gcells) struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); napi_disable(&cell->napi); - netif_napi_del(&cell->napi); + __netif_napi_del(&cell->napi); __skb_queue_purge(&cell->napi_skbs); } + /* This barrier is needed because netpoll could access dev->napi_list + * under rcu protection. + */ + synchronize_net(); + free_percpu(gcells->cells); gcells->cells = NULL; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index effa19da8681..ad98265f1dd1 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4562,7 +4562,7 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk) if (skb && (skb_next = skb_peek(q))) { icmp_next = is_icmp_err_skb(skb_next); if (icmp_next) - sk->sk_err = SKB_EXT_ERR(skb_next)->ee.ee_origin; + sk->sk_err = SKB_EXT_ERR(skb_next)->ee.ee_errno; } spin_unlock_irqrestore(&q->lock, flags); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index bb3d70664dde..b0b6e6a4784e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -427,7 +427,7 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); if (*own_req) ireq->ireq_opt = NULL; else diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index ef4ab28cfde0..78ee1b5acf1f 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -533,7 +533,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, dccp_done(newsk); goto out; } - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); /* Clone pktoptions received with SYN, if we own the req */ if (*own_req && ireq->pktopts) { newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 4148f5f78f31..f60869acbef0 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -787,7 +787,7 @@ static void reqsk_queue_hash_req(struct request_sock *req, timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED); mod_timer(&req->rsk_timer, jiffies + timeout); - inet_ehash_insert(req_to_sk(req), NULL); + inet_ehash_insert(req_to_sk(req), NULL, NULL); /* before letting lookups find us, make sure all req fields * are committed to memory and refcnt initialized. */ diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 8cbe74313f38..45fb450b4522 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -20,6 +20,9 @@ #include <net/addrconf.h> #include <net/inet_connection_sock.h> #include <net/inet_hashtables.h> +#if IS_ENABLED(CONFIG_IPV6) +#include <net/inet6_hashtables.h> +#endif #include <net/secure_seq.h> #include <net/ip.h> #include <net/tcp.h> @@ -508,10 +511,52 @@ static u32 inet_sk_port_offset(const struct sock *sk) inet->inet_dport); } -/* insert a socket into ehash, and eventually remove another one - * (The another one can be a SYN_RECV or TIMEWAIT +/* Searches for an exsiting socket in the ehash bucket list. + * Returns true if found, false otherwise. */ -bool inet_ehash_insert(struct sock *sk, struct sock *osk) +static bool inet_ehash_lookup_by_sk(struct sock *sk, + struct hlist_nulls_head *list) +{ + const __portpair ports = INET_COMBINED_PORTS(sk->sk_dport, sk->sk_num); + const int sdif = sk->sk_bound_dev_if; + const int dif = sk->sk_bound_dev_if; + const struct hlist_nulls_node *node; + struct net *net = sock_net(sk); + struct sock *esk; + + INET_ADDR_COOKIE(acookie, sk->sk_daddr, sk->sk_rcv_saddr); + + sk_nulls_for_each_rcu(esk, node, list) { + if (esk->sk_hash != sk->sk_hash) + continue; + if (sk->sk_family == AF_INET) { + if (unlikely(INET_MATCH(esk, net, acookie, + sk->sk_daddr, + sk->sk_rcv_saddr, + ports, dif, sdif))) { + return true; + } + } +#if IS_ENABLED(CONFIG_IPV6) + else if (sk->sk_family == AF_INET6) { + if (unlikely(INET6_MATCH(esk, net, + &sk->sk_v6_daddr, + &sk->sk_v6_rcv_saddr, + ports, dif, sdif))) { + return true; + } + } +#endif + } + return false; +} + +/* Insert a socket into ehash, and eventually remove another one + * (The another one can be a SYN_RECV or TIMEWAIT) + * If an existing socket already exists, socket sk is not inserted, + * and sets found_dup_sk parameter to true. + */ +bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_nulls_head *list; @@ -530,16 +575,23 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk) if (osk) { WARN_ON_ONCE(sk->sk_hash != osk->sk_hash); ret = sk_nulls_del_node_init_rcu(osk); + } else if (found_dup_sk) { + *found_dup_sk = inet_ehash_lookup_by_sk(sk, list); + if (*found_dup_sk) + ret = false; } + if (ret) __sk_nulls_add_node_rcu(sk, list); + spin_unlock(lock); + return ret; } -bool inet_ehash_nolisten(struct sock *sk, struct sock *osk) +bool inet_ehash_nolisten(struct sock *sk, struct sock *osk, bool *found_dup_sk) { - bool ok = inet_ehash_insert(sk, osk); + bool ok = inet_ehash_insert(sk, osk, found_dup_sk); if (ok) { sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); @@ -583,7 +635,7 @@ int __inet_hash(struct sock *sk, struct sock *osk) int err = 0; if (sk->sk_state != TCP_LISTEN) { - inet_ehash_nolisten(sk, osk); + inet_ehash_nolisten(sk, osk, NULL); return 0; } WARN_ON(!sk_unhashed(sk)); @@ -679,7 +731,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, tb = inet_csk(sk)->icsk_bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { - inet_ehash_nolisten(sk, NULL); + inet_ehash_nolisten(sk, NULL, NULL); spin_unlock_bh(&head->lock); return 0; } @@ -758,7 +810,7 @@ ok: inet_bind_hash(sk, tb, port); if (sk_unhashed(sk)) { inet_sk(sk)->inet_sport = htons(port); - inet_ehash_nolisten(sk, (struct sock *)tw); + inet_ehash_nolisten(sk, (struct sock *)tw, NULL); } if (tw) inet_twsk_bind_unhash(tw, hinfo); diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index db47ac24d057..563d016e7478 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -198,6 +198,11 @@ static void tcp_reinit_congestion_control(struct sock *sk, icsk->icsk_ca_setsockopt = 1; memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); + if (ca->flags & TCP_CONG_NEEDS_ECN) + INET_ECN_xmit(sk); + else + INET_ECN_dontxmit(sk); + if (!((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) tcp_init_congestion_control(sk); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c2d5132c523c..e4b31e70bd30 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -980,17 +980,22 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb); - tos = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ? - tcp_rsk(req)->syn_tos : inet_sk(sk)->tos; - if (skb) { __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); + tos = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ? + tcp_rsk(req)->syn_tos & ~INET_ECN_MASK : + inet_sk(sk)->tos; + + if (!INET_ECN_is_capable(tos) && + tcp_bpf_ca_needs_ecn((struct sock *)req)) + tos |= INET_ECN_ECT_0; + rcu_read_lock(); err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, rcu_dereference(ireq->ireq_opt), - tos & ~INET_ECN_MASK); + tos); rcu_read_unlock(); err = net_xmit_eval(err); } @@ -1498,6 +1503,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, bool *own_req) { struct inet_request_sock *ireq; + bool found_dup_sk = false; struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; @@ -1575,12 +1581,22 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), + &found_dup_sk); if (likely(*own_req)) { tcp_move_syn(newtp, req); ireq->ireq_opt = NULL; } else { - newinet->inet_opt = NULL; + if (!req_unhash && found_dup_sk) { + /* This code path should only be executed in the + * syncookie case only + */ + bh_unlock_sock(newsk); + sock_put(newsk); + newsk = NULL; + } else { + newinet->inet_opt = NULL; + } } return newsk; diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 642fc6ac13d2..8a22486cf270 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -306,7 +306,9 @@ static int ip6addrlbl_del(struct net *net, /* add default label */ static int __net_init ip6addrlbl_net_init(struct net *net) { - int err = 0; + struct ip6addrlbl_entry *p = NULL; + struct hlist_node *n; + int err; int i; ADDRLABEL(KERN_DEBUG "%s\n", __func__); @@ -315,14 +317,20 @@ static int __net_init ip6addrlbl_net_init(struct net *net) INIT_HLIST_HEAD(&net->ipv6.ip6addrlbl_table.head); for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { - int ret = ip6addrlbl_add(net, - ip6addrlbl_init_table[i].prefix, - ip6addrlbl_init_table[i].prefixlen, - 0, - ip6addrlbl_init_table[i].label, 0); - /* XXX: should we free all rules when we catch an error? */ - if (ret && (!err || err != -ENOMEM)) - err = ret; + err = ip6addrlbl_add(net, + ip6addrlbl_init_table[i].prefix, + ip6addrlbl_init_table[i].prefixlen, + 0, + ip6addrlbl_init_table[i].label, 0); + if (err) + goto err_ip6addrlbl_add; + } + return 0; + +err_ip6addrlbl_add: + hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) { + hlist_del_rcu(&p->list); + kfree_rcu(p, rcu); } return err; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8db59f4e5f13..992cbf3eb9e3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -527,15 +527,20 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, if (np->repflow && ireq->pktopts) fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); + tclass = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ? + tcp_rsk(req)->syn_tos & ~INET_ECN_MASK : + np->tclass; + + if (!INET_ECN_is_capable(tclass) && + tcp_bpf_ca_needs_ecn((struct sock *)req)) + tclass |= INET_ECN_ECT_0; + rcu_read_lock(); opt = ireq->ipv6_opt; - tclass = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ? - tcp_rsk(req)->syn_tos : np->tclass; if (!opt) opt = rcu_dereference(np->opt); err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, - tclass & ~INET_ECN_MASK, - sk->sk_priority); + tclass, sk->sk_priority); rcu_read_unlock(); err = net_xmit_eval(err); } @@ -1193,6 +1198,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * const struct ipv6_pinfo *np = tcp_inet6_sk(sk); struct ipv6_txoptions *opt; struct inet_sock *newinet; + bool found_dup_sk = false; struct tcp_sock *newtp; struct sock *newsk; #ifdef CONFIG_TCP_MD5SIG @@ -1368,7 +1374,8 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * tcp_done(newsk); goto out; } - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), + &found_dup_sk); if (*own_req) { tcp_move_syn(newtp, req); @@ -1383,6 +1390,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * skb_set_owner_r(newnp->pktoptions, newsk); } } + } else { + if (!req_unhash && found_dup_sk) { + /* This code path should only be executed in the + * syncookie case only + */ + bh_unlock_sock(newsk); + sock_put(newsk); + newsk = NULL; + } } return newsk; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 047238f01ba6..db7d888914fa 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1645,7 +1645,7 @@ static int iucv_callback_connreq(struct iucv_path *path, } /* Create the new socket */ - nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC, 0); + nsk = iucv_sock_alloc(NULL, sk->sk_protocol, GFP_ATOMIC, 0); if (!nsk) { err = pr_iucv->path_sever(path, user_data); iucv_path_free(path); @@ -1851,7 +1851,7 @@ static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb) goto out; } - nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC, 0); + nsk = iucv_sock_alloc(NULL, sk->sk_protocol, GFP_ATOMIC, 0); bh_lock_sock(sk); if ((sk->sk_state != IUCV_LISTEN) || sk_acceptq_is_full(sk) || diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 4d8abff1be18..2e5c3f4da3a4 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -543,9 +543,8 @@ create_msk: fallback = true; } else if (subflow_req->mp_join) { mptcp_get_options(skb, &mp_opt); - if (!mp_opt.mp_join || - !mptcp_can_accept_new_subflow(subflow_req->msk) || - !subflow_hmac_valid(req, &mp_opt)) { + if (!mp_opt.mp_join || !subflow_hmac_valid(req, &mp_opt) || + !mptcp_can_accept_new_subflow(subflow_req->msk)) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC); fallback = true; } diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index b87bfc82f44f..5829a020b81c 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -958,14 +958,13 @@ static int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb, { /* The first action is always 'OVS_DEC_TTL_ATTR_ARG'. */ struct nlattr *dec_ttl_arg = nla_data(attr); - int rem = nla_len(attr); if (nla_len(dec_ttl_arg)) { - struct nlattr *actions = nla_next(dec_ttl_arg, &rem); + struct nlattr *actions = nla_data(dec_ttl_arg); if (actions) - return clone_execute(dp, skb, key, 0, actions, rem, - last, false); + return clone_execute(dp, skb, key, 0, nla_data(actions), + nla_len(actions), last, false); } consume_skb(skb); return 0; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 9d3e50c4d29f..ec0689ddc635 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2503,28 +2503,42 @@ static int validate_and_copy_dec_ttl(struct net *net, __be16 eth_type, __be16 vlan_tci, u32 mpls_label_count, bool log) { - int start, err; - u32 nested = true; + const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; + int start, action_start, err, rem; + const struct nlattr *a, *actions; + + memset(attrs, 0, sizeof(attrs)); + nla_for_each_nested(a, attr, rem) { + int type = nla_type(a); - if (!nla_len(attr)) - return ovs_nla_add_action(sfa, OVS_ACTION_ATTR_DEC_TTL, - NULL, 0, log); + /* Ignore unknown attributes to be future proof. */ + if (type > OVS_DEC_TTL_ATTR_MAX) + continue; + + if (!type || attrs[type]) + return -EINVAL; + + attrs[type] = a; + } + + actions = attrs[OVS_DEC_TTL_ATTR_ACTION]; + if (rem || !actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN)) + return -EINVAL; start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log); if (start < 0) return start; - err = ovs_nla_add_action(sfa, OVS_DEC_TTL_ATTR_ACTION, &nested, - sizeof(nested), log); - - if (err) - return err; + action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log); + if (action_start < 0) + return start; - err = __ovs_nla_copy_actions(net, attr, key, sfa, eth_type, + err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, vlan_tci, mpls_label_count, log); if (err) return err; + add_nested_action_end(*sfa, action_start); add_nested_action_end(*sfa, start); return 0; } @@ -3487,20 +3501,42 @@ out: static int dec_ttl_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) { - int err = 0, rem = nla_len(attr); - struct nlattr *start; + struct nlattr *start, *action_start; + const struct nlattr *a; + int err = 0, rem; start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL); - if (!start) return -EMSGSIZE; - err = ovs_nla_put_actions(nla_data(attr), rem, skb); - if (err) - nla_nest_cancel(skb, start); - else - nla_nest_end(skb, start); + nla_for_each_attr(a, nla_data(attr), nla_len(attr), rem) { + switch (nla_type(a)) { + case OVS_DEC_TTL_ATTR_ACTION: + + action_start = nla_nest_start_noflag(skb, OVS_DEC_TTL_ATTR_ACTION); + if (!action_start) { + err = -EMSGSIZE; + goto out; + } + + err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb); + if (err) + goto out; + + nla_nest_end(skb, action_start); + break; + default: + /* Ignore all other option to be future compatible */ + break; + } + } + + nla_nest_end(skb, start); + return 0; + +out: + nla_nest_cancel(skb, start); return err; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 48a0ed836b46..a667b19eab78 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -94,8 +94,8 @@ /* Assumptions: - - If the device has no dev->header_ops, there is no LL header visible - above the device. In this case, its hard_header_len should be 0. + - If the device has no dev->header_ops->create, there is no LL header + visible above the device. In this case, its hard_header_len should be 0. The device may prepend its own header internally. In this case, its needed_headroom should be set to the space needed for it to add its internal header. @@ -109,26 +109,26 @@ On receive: ----------- -Incoming, dev->header_ops != NULL +Incoming, dev_has_header(dev) == true mac_header -> ll header data -> data -Outgoing, dev->header_ops != NULL +Outgoing, dev_has_header(dev) == true mac_header -> ll header data -> ll header -Incoming, dev->header_ops == NULL +Incoming, dev_has_header(dev) == false mac_header -> data However drivers often make it point to the ll header. This is incorrect because the ll header should be invisible to us. data -> data -Outgoing, dev->header_ops == NULL +Outgoing, dev_has_header(dev) == false mac_header -> data. ll header is invisible to us. data -> data Resume - If dev->header_ops == NULL we are unable to restore the ll header, + If dev_has_header(dev) == false we are unable to restore the ll header, because it is invisible to us. @@ -2083,7 +2083,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, skb->dev = dev; - if (dev->header_ops) { + if (dev_has_header(dev)) { /* The device has an explicit notion of ll header, * exported to higher levels. * @@ -2212,7 +2212,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; - if (dev->header_ops) { + if (dev_has_header(dev)) { if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb_mac_header(skb)); else if (skb->pkt_type == PACKET_OUTGOING) { diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c index 7b094275ea8b..11c45c8c6c16 100644 --- a/net/rose/rose_loopback.c +++ b/net/rose/rose_loopback.c @@ -96,10 +96,19 @@ static void rose_loopback_timer(struct timer_list *unused) } if (frametype == ROSE_CALL_REQUEST) { - if ((dev = rose_dev_get(dest)) != NULL) { - if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) - kfree_skb(skb); - } else { + if (!rose_loopback_neigh->dev) { + kfree_skb(skb); + continue; + } + + dev = rose_dev_get(dest); + if (!dev) { + kfree_skb(skb); + continue; + } + + if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) { + dev_put(dev); kfree_skb(skb); } } else { diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 6f93ad5b7200..6cc9fe778356 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -1262,6 +1262,8 @@ void tls_device_offload_cleanup_rx(struct sock *sk) if (tls_ctx->tx_conf != TLS_HW) { dev_put(netdev); tls_ctx->netdev = NULL; + } else { + set_bit(TLS_RX_DEV_CLOSED, &tls_ctx->flags); } out: up_read(&device_offload_lock); @@ -1291,7 +1293,8 @@ static int tls_device_down(struct net_device *netdev) if (ctx->tx_conf == TLS_HW) netdev->tlsdev_ops->tls_dev_del(netdev, ctx, TLS_OFFLOAD_CTX_DIR_TX); - if (ctx->rx_conf == TLS_HW) + if (ctx->rx_conf == TLS_HW && + !test_bit(TLS_RX_DEV_CLOSED, &ctx->flags)) netdev->tlsdev_ops->tls_dev_del(netdev, ctx, TLS_OFFLOAD_CTX_DIR_RX); WRITE_ONCE(ctx->netdev, NULL); diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 53106f02def2..01d933ae5f16 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1294,6 +1294,12 @@ static struct sk_buff *tls_wait_data(struct sock *sk, struct sk_psock *psock, return NULL; } + if (!skb_queue_empty(&sk->sk_receive_queue)) { + __strp_unpause(&ctx->strp); + if (ctx->recv_pkt) + return ctx->recv_pkt; + } + if (sk->sk_shutdown & RCV_SHUTDOWN) return NULL; diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index 0edda1edf988..5956939eebb7 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -841,8 +841,10 @@ void virtio_transport_release(struct vsock_sock *vsk) virtio_transport_free_pkt(pkt); } - if (remove_sock) + if (remove_sock) { + sock_set_flag(sk, SOCK_DONE); vsock_remove_sock(vsk); + } } EXPORT_SYMBOL_GPL(virtio_transport_release); @@ -1132,8 +1134,8 @@ void virtio_transport_recv_pkt(struct virtio_transport *t, lock_sock(sk); - /* Check if sk has been released before lock_sock */ - if (sk->sk_shutdown == SHUTDOWN_MASK) { + /* Check if sk has been closed before lock_sock */ + if (sock_flag(sk, SOCK_DONE)) { (void)virtio_transport_reset_no_sock(t, pkt); release_sock(sk); sock_put(sk); diff --git a/sound/core/control.c b/sound/core/control.c index 4373de42a5a0..3b44378b9dec 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1539,7 +1539,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, unlock: up_write(&card->controls_rwsem); - return 0; + return err; } static int snd_ctl_elem_add_user(struct snd_ctl_file *file, diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c index 0f533f5bd960..9f8c53b39f95 100644 --- a/sound/firewire/fireworks/fireworks_transaction.c +++ b/sound/firewire/fireworks/fireworks_transaction.c @@ -123,7 +123,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) t = (struct snd_efw_transaction *)data; length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length); - spin_lock_irq(&efw->lock); + spin_lock(&efw->lock); if (efw->push_ptr < efw->pull_ptr) capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr); @@ -190,7 +190,7 @@ handle_resp_for_user(struct fw_card *card, int generation, int source, copy_resp_to_buf(efw, data, length, rcode); end: - spin_unlock_irq(&instances_lock); + spin_unlock(&instances_lock); } static void diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d539f52009a1..6852668f1bcb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2506,6 +2506,9 @@ static const struct pci_device_id azx_ids[] = { /* DG1 */ { PCI_DEVICE(0x8086, 0x490d), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* Alderlake-S */ + { PCI_DEVICE(0x8086, 0x7ad0), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Elkhart Lake */ { PCI_DEVICE(0x8086, 0x4b55), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index e0c38f2735c6..d8370a417e3d 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -9183,6 +9183,8 @@ static void ca0132_mmio_init(struct hda_codec *codec) case QUIRK_AE5: ca0132_mmio_init_ae5(codec); break; + default: + break; } } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ccd1df059654..b0068f8ca46d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4274,6 +4274,7 @@ HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6899089d132e..739dbaf54517 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2522,13 +2522,23 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x950A, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), - SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), @@ -4216,6 +4226,12 @@ static void alc286_fixup_hp_gpio_led(struct hda_codec *codec, alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20); } +static void alc287_fixup_hp_gpio_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_hp_gpio_led(codec, action, 0x10, 0); +} + /* turn on/off mic-mute LED per capture hook via VREF change */ static int vref_micmute_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) @@ -6301,6 +6317,9 @@ enum { ALC274_FIXUP_HP_MIC, ALC274_FIXUP_HP_HEADSET_MIC, ALC256_FIXUP_ASUS_HPE, + ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + ALC287_FIXUP_HP_GPIO_LED, + ALC256_FIXUP_HP_HEADSET_MIC, }; static const struct hda_fixup alc269_fixups[] = { @@ -7705,6 +7724,20 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC }, + [ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_jack, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI + }, + [ALC287_FIXUP_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_hp_gpio_led, + }, + [ALC256_FIXUP_HP_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc274_fixup_hp_headset_mic, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -7859,6 +7892,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -7924,11 +7959,49 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1325, "System76 Darter Pro (darp5)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50a3, "Clevo NJ51GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50b3, "Clevo NK50S[BEZ]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50b6, "Clevo NK50S5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50b8, "Clevo NK50SZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50d5, "Clevo NP50D5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50f0, "Clevo NH50A[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x50f3, "Clevo NH58DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8535, "Clevo NH50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8536, "Clevo NH79D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8550, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8551, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x951d, "Clevo N950T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL53RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS), SND_PCI_QUIRK(0x17aa, 0x1048, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), @@ -7966,6 +8039,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), + SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK), + SND_PCI_QUIRK(0x17aa, 0x22c2, "Thinkpad X1 Extreme Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), @@ -8278,6 +8353,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x19, 0x02a11020}, {0x1a, 0x02a11030}, {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC, + {0x14, 0x90170110}, + {0x19, 0x02a11020}, + {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -8380,6 +8459,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1a, 0x90a70130}, {0x1b, 0x90170110}, {0x21, 0x03211020}), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC, + {0x14, 0x90170110}, + {0x19, 0x02a11020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0274, 0x103c, "HP", ALC274_FIXUP_HP_HEADSET_MIC, {0x17, 0x90170110}, {0x19, 0x03a11030}, diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 0bdd33b0af65..fb8895af0363 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -70,7 +70,6 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, unsigned int i; #endif - mutex_lock(&mgr->msg_lock); err = 0; /* copy message descriptor from miXart to driver */ @@ -119,8 +118,6 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); _clean_exit: - mutex_unlock(&mgr->msg_lock); - return err; } @@ -258,7 +255,9 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int resp.data = resp_data; resp.size = max_resp_size; + mutex_lock(&mgr->msg_lock); err = get_msg(mgr, &resp, msg_frame); + mutex_unlock(&mgr->msg_lock); if( request->message_id != resp.message_id ) dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 25fe2ddedd54..3db07293c70b 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -27,10 +27,15 @@ #include <sound/soc-dapm.h> #include <sound/soc.h> #include <sound/tlv.h> +#include <sound/rt1015.h> #include "rl6231.h" #include "rt1015.h" +static const struct rt1015_platform_data i2s_default_platform_data = { + .power_up_delay_ms = 50, +}; + static const struct reg_default rt1015_reg[] = { { 0x0000, 0x0000 }, { 0x0004, 0xa000 }, @@ -539,7 +544,7 @@ static void rt1015_flush_work(struct work_struct *work) struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv, flush_work.work); struct snd_soc_component *component = rt1015->component; - unsigned int val, i = 0, count = 20; + unsigned int val, i = 0, count = 200; while (i < count) { usleep_range(1000, 1500); @@ -650,6 +655,7 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: if (rt1015->hw_config == RT1015_HW_28) schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10)); + msleep(rt1015->pdata.power_up_delay_ms); break; default: break; @@ -1067,9 +1073,16 @@ static struct acpi_device_id rt1015_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt1015_acpi_match); #endif +static void rt1015_parse_dt(struct rt1015_priv *rt1015, struct device *dev) +{ + device_property_read_u32(dev, "realtek,power-up-delay-ms", + &rt1015->pdata.power_up_delay_ms); +} + static int rt1015_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct rt1015_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt1015_priv *rt1015; int ret; unsigned int val; @@ -1081,6 +1094,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt1015); + rt1015->pdata = i2s_default_platform_data; + + if (pdata) + rt1015->pdata = *pdata; + else + rt1015_parse_dt(rt1015, &i2c->dev); + rt1015->regmap = devm_regmap_init_i2c(i2c, &rt1015_regmap); if (IS_ERR(rt1015->regmap)) { ret = PTR_ERR(rt1015->regmap); diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h index d3fdd30aca6d..15cadb361ec3 100644 --- a/sound/soc/codecs/rt1015.h +++ b/sound/soc/codecs/rt1015.h @@ -12,6 +12,7 @@ #ifndef __RT1015_H__ #define __RT1015_H__ +#include <sound/rt1015.h> #define RT1015_DEVICE_ID_VAL 0x1011 #define RT1015_DEVICE_ID_VAL2 0x1015 @@ -380,6 +381,7 @@ enum { struct rt1015_priv { struct snd_soc_component *component; + struct rt1015_platform_data pdata; struct regmap *regmap; int sysclk; int sysclk_src; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 922cd0176e1f..f95546c184aa 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -700,6 +700,8 @@ static int kabylake_set_bias_level(struct snd_soc_card *card, switch (level) { case SND_SOC_BIAS_PREPARE: if (dapm->bias_level == SND_SOC_BIAS_ON) { + if (!__clk_is_enabled(priv->mclk)) + return 0; dev_dbg(card->dev, "Disable mclk"); clk_disable_unprepare(priv->mclk); } else { diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index ba653ebea7d1..408e64e3b5fb 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -458,10 +458,6 @@ static int catpt_dai_prepare(struct snd_pcm_substream *substream, if (ret) return CATPT_IPC_ERROR(ret); - ret = catpt_dsp_update_lpclock(cdev); - if (ret) - return ret; - ret = catpt_dai_apply_usettings(dai, stream); if (ret) return ret; @@ -500,6 +496,7 @@ static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: resume_stream: + catpt_dsp_update_lpclock(cdev); ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id); if (ret) return CATPT_IPC_ERROR(ret); @@ -507,11 +504,11 @@ static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: stream->prepared = false; - catpt_dsp_update_lpclock(cdev); fallthrough; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id); + catpt_dsp_update_lpclock(cdev); if (ret) return CATPT_IPC_ERROR(ret); break; @@ -534,6 +531,8 @@ void catpt_stream_update_position(struct catpt_dev *cdev, dsppos = bytes_to_frames(r, pos->stream_position); + if (!stream->prepared) + goto exit; /* only offload is set_write_pos driven */ if (stream->template->type != CATPT_STRM_TYPE_RENDER) goto exit; diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index f54b710ee1c2..291a686568c2 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -487,9 +487,9 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, kmb_i2s->xfer_resolution = 0x02; break; case SNDRV_PCM_FORMAT_S24_LE: - config->data_width = 24; - kmb_i2s->ccr = 0x08; - kmb_i2s->xfer_resolution = 0x04; + config->data_width = 32; + kmb_i2s->ccr = 0x14; + kmb_i2s->xfer_resolution = 0x05; break; case SNDRV_PCM_FORMAT_S32_LE: config->data_width = 32; diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 36d1512ffd1f..7a3fdf89968a 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -122,8 +122,10 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, else dma_ch = 0; - if (dma_ch < 0) + if (dma_ch < 0) { + kfree(data); return dma_ch; + } if (cpu_dai->driver->id == LPASS_DP_RX) { map = drvdata->hdmiif_map; @@ -147,6 +149,7 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { + kfree(data); dev_err(soc_runtime->dev, "setting constraints failed: %d\n", ret); return -EINVAL; diff --git a/sound/usb/card.c b/sound/usb/card.c index fa764b61fe9c..4457214a3ae6 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -379,6 +379,10 @@ static const struct usb_audio_device_name usb_audio_names[] = { DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"), + /* ASUS ROG Strix */ + PROFILE_NAME(0x0b05, 0x1917, + "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), + /* Dell WD15 Dock */ PROFILE_NAME(0x0bda, 0x4014, "Dell", "WD15 Dock", "Dell-WD15-Dock"), /* Dell WD19 Dock */ diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index c369c81e74c4..a7212f16660e 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -561,7 +561,8 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { }, { /* ASUS ROG Strix */ .id = USB_ID(0x0b05, 0x1917), - .map = asus_rog_map, + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, }, { /* MSI TRX40 Creator */ .id = USB_ID(0x0db0, 0x0d64), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index c989ad8052ae..c50be2f75f70 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1672,13 +1672,13 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) msleep(20); - /* Zoom R16/24, Logitech H650e/H570e, Jabra 550a, Kingston HyperX - * needs a tiny delay here, otherwise requests like get/set - * frequency return as failed despite actually succeeding. + /* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950), + * Jabra 550a, Kingston HyperX needs a tiny delay here, + * otherwise requests like get/set frequency return + * as failed despite actually succeeding. */ if ((chip->usb_id == USB_ID(0x1686, 0x00dd) || - chip->usb_id == USB_ID(0x046d, 0x0a46) || - chip->usb_id == USB_ID(0x046d, 0x0a56) || + USB_ID_VENDOR(chip->usb_id) == 0x046d || /* Logitech */ chip->usb_id == USB_ID(0x0b0e, 0x0349) || chip->usb_id == USB_ID(0x0951, 0x16ad)) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 4a180439ee9e..26c72f2b61b1 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1758,10 +1758,10 @@ TEST_F(TRACE_poke, getpid_runs_normally) * and the code is stored as a positive value. \ */ \ if (_result < 0) { \ - SYSCALL_RET(_regs) = -result; \ + SYSCALL_RET(_regs) = -_result; \ (_regs).ccr |= 0x10000000; \ } else { \ - SYSCALL_RET(_regs) = result; \ + SYSCALL_RET(_regs) = _result; \ (_regs).ccr &= ~0x10000000; \ } \ } while (0) @@ -1804,8 +1804,8 @@ TEST_F(TRACE_poke, getpid_runs_normally) #define SYSCALL_RET(_regs) (_regs).a[(_regs).windowbase * 4 + 2] #elif defined(__sh__) # define ARCH_REGS struct pt_regs -# define SYSCALL_NUM(_regs) (_regs).gpr[3] -# define SYSCALL_RET(_regs) (_regs).gpr[0] +# define SYSCALL_NUM(_regs) (_regs).regs[3] +# define SYSCALL_RET(_regs) (_regs).regs[0] #else # error "Do not know how to find your architecture's registers and syscalls" #endif |