mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
Merge fdo/drm/drm-fixes into drm-misc-fixes
Backmerging to get drm-misc-fixes up to v7.3-rc3. Signed-off-by: Maxime Ripard <mripard@kernel.org>
This commit is contained in:
commit
666f12ae9f
4
.mailmap
4
.mailmap
|
|
@ -421,6 +421,7 @@ Jens Axboe <axboe@kernel.dk> <axboe@suse.de>
|
|||
Jens Axboe <axboe@kernel.dk> <jens.axboe@oracle.com>
|
||||
Jens Axboe <axboe@kernel.dk> <axboe@fb.com>
|
||||
Jens Axboe <axboe@kernel.dk> <axboe@meta.com>
|
||||
Jens Axboe <axboe@kernel.dk> <axboe@anthropic.com>
|
||||
Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
|
||||
Jens Wiklander <jenswi@kernel.org> <jens.wiklander@linaro.org>
|
||||
Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
|
||||
|
|
@ -551,6 +552,9 @@ Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
|
|||
Lior David <quic_liord@quicinc.com> <liord@codeaurora.org>
|
||||
Loic Poulain <loic.poulain@oss.qualcomm.com> <loic.poulain@linaro.org>
|
||||
Loic Poulain <loic.poulain@oss.qualcomm.com> <loic.poulain@intel.com>
|
||||
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi@redhat.com>
|
||||
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi@st.com>
|
||||
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi83@gmail.com>
|
||||
Lorenzo Pieralisi <lpieralisi@kernel.org> <lorenzo.pieralisi@arm.com>
|
||||
Lorenzo Stoakes <ljs@kernel.org> <lstoakes@gmail.com>
|
||||
Lorenzo Stoakes <ljs@kernel.org> <lorenzo.stoakes@oracle.com>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Description: Shows all enabled kernel features.
|
|||
Supported features:
|
||||
compr_cfgs, big_pcluster, chunked_file, device_table,
|
||||
compr_head2, sb_chksum, ztailpacking, dedupe, fragments,
|
||||
48bit, metabox.
|
||||
xattr_prefixes, 48bit, metabox.
|
||||
|
||||
What: /sys/fs/erofs/<disk>/sync_decompress
|
||||
Date: November 2021
|
||||
|
|
|
|||
|
|
@ -4987,18 +4987,6 @@ Kernel parameters
|
|||
Set to non-zero if a chip is present that snoops speed
|
||||
changes. Disabled by default.
|
||||
|
||||
pata_legacy.ht6560a= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to 1, 2, or 3 for HT 6560A on the primary channel,
|
||||
the secondary channel, or both channels respectively.
|
||||
Disabled by default.
|
||||
|
||||
pata_legacy.ht6560b= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to 1, 2, or 3 for HT 6560B on the primary channel,
|
||||
the secondary channel, or both channels respectively.
|
||||
Disabled by default.
|
||||
|
||||
pata_legacy.iordy_mask= [HW,LIBATA]
|
||||
Format: <int>
|
||||
IORDY enable mask. Set individual bits to allow IORDY
|
||||
|
|
@ -5011,18 +4999,6 @@ Kernel parameters
|
|||
with the sequence. By default IORDY is allowed across
|
||||
all channels.
|
||||
|
||||
pata_legacy.opti82c46x= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to 1, 2, or 3 for Opti 82c611A on the primary
|
||||
channel, the secondary channel, or both channels
|
||||
respectively. Disabled by default.
|
||||
|
||||
pata_legacy.opti82c611a= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to 1, 2, or 3 for Opti 82c465MV on the primary
|
||||
channel, the secondary channel, or both channels
|
||||
respectively. Disabled by default.
|
||||
|
||||
pata_legacy.pio_mask= [HW,LIBATA]
|
||||
Format: <int>
|
||||
PIO mode mask for autospeed devices. Set individual
|
||||
|
|
@ -5046,19 +5022,6 @@ Kernel parameters
|
|||
the first port in the list above (0x1f0), and so on.
|
||||
By default all supported ports are probed.
|
||||
|
||||
pata_legacy.qdi= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to non-zero to probe QDI controllers. By default
|
||||
set to 1 if CONFIG_PATA_QDI_MODULE, 0 otherwise.
|
||||
|
||||
pata_legacy.winbond= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Set to non-zero to probe Winbond controllers. Use
|
||||
the standard I/O port (0x130) if 1, otherwise the
|
||||
value given is the I/O port to use (typically 0x1b0).
|
||||
By default set to 1 if CONFIG_PATA_WINBOND_VLB_MODULE,
|
||||
0 otherwise.
|
||||
|
||||
pata_platform.pio_mask= [HW,LIBATA]
|
||||
Format: <int>
|
||||
Supported PIO mode mask. Set individual bits to allow
|
||||
|
|
|
|||
|
|
@ -1416,7 +1416,7 @@ Controls whether userspace may arm Syscall User Dispatch via
|
|||
== ===================================================================
|
||||
|
||||
Only present when the kernel is built with ``CONFIG_SYSCALL_USER_DISPATCH``
|
||||
and ``CONFIG_PROC_SYSCTL``.
|
||||
and ``CONFIG_SYSCTL``.
|
||||
|
||||
|
||||
sysctl_writes_strict
|
||||
|
|
|
|||
|
|
@ -155,7 +155,8 @@ The following keys are defined:
|
|||
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
|
||||
as defined in the RISC-V ISA manual.
|
||||
as defined in the RISC-V ISA manual. Zfh is a superset of Zfhmin, so
|
||||
RISCV_HWPROBE_EXT_ZFHMIN is reported whenever RISCV_HWPROBE_EXT_ZFH is.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
|
||||
supported as defined in the RISC-V ISA manual.
|
||||
|
|
@ -164,8 +165,9 @@ The following keys are defined:
|
|||
is supported as defined in the RISC-V ISA manual.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
|
||||
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
|
||||
("Remove draft warnings from Zvfh[min]").
|
||||
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
|
||||
("Remove draft warnings from Zvfh[min]"). Zvfh is a superset of Zvfhmin,
|
||||
so RISCV_HWPROBE_EXT_ZVFHMIN is reported whenever RISCV_HWPROBE_EXT_ZVFH is.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
|
||||
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- silergy,syr827
|
||||
- silergy,syr828
|
||||
- tcs,tcs4525
|
||||
- tcs,tcs4526
|
||||
- items:
|
||||
- const: rockchip,rk8601
|
||||
- const: rockchip,rk8600
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
VLEN/8, the vector register length in bytes. This property is required on
|
||||
thead systems where the vector register length is not identical on all harts, or
|
||||
the vlenb CSR is not available.
|
||||
thead systems where the vector register length is not identical on all
|
||||
harts, or the vlenb CSR is not available.
|
||||
|
||||
# RISC-V has multiple properties for cache op block sizes as the sizes
|
||||
# differ between individual CBO extensions
|
||||
|
|
@ -151,8 +151,8 @@ anyOf:
|
|||
- riscv,isa-base
|
||||
|
||||
dependencies:
|
||||
riscv,isa-base: [ "riscv,isa-extensions" ]
|
||||
riscv,isa-extensions: [ "riscv,isa-base" ]
|
||||
riscv,isa-base: ["riscv,isa-extensions"]
|
||||
riscv,isa-extensions: ["riscv,isa-base"]
|
||||
|
||||
required:
|
||||
- interrupt-controller
|
||||
|
|
|
|||
|
|
@ -44,6 +44,21 @@ allOf:
|
|||
else:
|
||||
properties:
|
||||
starfive,sfc-filter-syscon: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ultrarisc,dp1000-spi
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
clocks:
|
||||
minItems: 2
|
||||
clock-names:
|
||||
minItems: 2
|
||||
required:
|
||||
- clock-names
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -63,6 +78,7 @@ properties:
|
|||
- mscc,jaguar2-spi
|
||||
- sophgo,sg2042-spi
|
||||
- thead,th1520-spi
|
||||
- ultrarisc,dp1000-spi
|
||||
- const: snps,dw-apb-ssi
|
||||
- description: Vendor controllers compatible with v1.01a
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pwm1_enable
|
|||
at full speed. Write "1" to set to manual, write "2" to let the EC control
|
||||
decide fan speed. Read this attribute to see current status.
|
||||
|
||||
NB:In consideration of the safety of the device, when setting to manual mode,
|
||||
NB: In consideration of the safety of the device, when setting to manual mode,
|
||||
the pwm speed will be set to the maximum value (255) by default. You can set
|
||||
a different value by writing pwm1 later.
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ register/unregister functions::
|
|||
|
||||
char *devm_hwmon_sanitize_name(struct device *dev, const char *name);
|
||||
|
||||
int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel);
|
||||
|
||||
void hwmon_lock(struct device *dev);
|
||||
void hwmon_unlock(struct device *dev);
|
||||
|
||||
|
|
@ -90,6 +93,18 @@ implemented in the driver, or debugfs functions, hwmon_lock() and hwmon_unlock()
|
|||
can be used to ensure that calls to those functions are serialized. Those
|
||||
functions also support guard() and scoped_guard() variants.
|
||||
|
||||
Drivers can call hwmon_notify_event() to notify userspace and the thermal
|
||||
subsystem when a hardware monitoring event (such as an alarm or a fault
|
||||
condition) occurs or clears. The parameters are the hwmon device, the sensor
|
||||
type, the attribute identifier associated with the event (such as
|
||||
hwmon_temp_max_alarm or hwmon_fan_fault), and the sensor channel number.
|
||||
hwmon_notify_event() generates a sysfs event (calling sysfs_notify()) and a
|
||||
udev event with the attribute name passed in the NAME environment property
|
||||
(e.g., "NAME=temp1_max_alarm"). If the event is for a temperature sensor and
|
||||
the sensor is attached to a thermal zone, it also notifies the thermal
|
||||
subsystem to update the thermal zone. hwmon_notify_event() returns 0 on
|
||||
success or a negative error code on failure.
|
||||
|
||||
Using devm_hwmon_device_register_with_info()
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -898,6 +898,8 @@ attribute-sets:
|
|||
-
|
||||
name: txqlen
|
||||
type: u32
|
||||
checks:
|
||||
max: 32767
|
||||
-
|
||||
name: map
|
||||
type: binary
|
||||
|
|
|
|||
|
|
@ -15,19 +15,41 @@ arch/riscv 开发者维护指南
|
|||
|
||||
概述
|
||||
----
|
||||
RISC-V指令集体系结构是公开开发的:
|
||||
RISC-V 指令集体系结构是公开开发的:
|
||||
正在进行的草案可供所有人查看和测试实现。新模块或者扩展草案可能会在开发过程中发
|
||||
生更改---有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给RISC-V Linux
|
||||
维护者带来挑战。Linux开发过程更喜欢经过良好检查和测试的代码,而不是试验代码。我
|
||||
们希望推广同样的规则到即将被内核合并的RISC-V相关代码。
|
||||
生更改 --- 有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给 RISC-V
|
||||
Linux 维护者带来挑战。Linux 维护者不赞成频繁的变更,且 Linux 开发过程更喜欢经过
|
||||
良好检查和测试的代码,而不是试验代码。我们希望推广同样的规则到即将被内核合并的
|
||||
RISC-V 相关代码。
|
||||
|
||||
Patchwork
|
||||
---------
|
||||
|
||||
RISC-V 有一个 patchwork 实例,可以在那里查看补丁的状态:
|
||||
|
||||
https://patchwork.kernel.org/project/linux-riscv/list/
|
||||
|
||||
如果你的补丁不在默认视图中出现,那么 RISC-V 维护者很有可能已要求修改,或者希望
|
||||
将其应用到另一个代码树上。
|
||||
|
||||
自动化流程会在该 patchwork 实例上运行,在每个补丁到达时立刻对其进行构建/测试。
|
||||
自动化流程会根据补丁是否被识别为修复,选用 RISC-V `for-next` 或 `fixes` 分支
|
||||
当前的 HEAD;若上述均应用失败,则使用 RISC-V `master` 分支。补丁系列被应用到的具
|
||||
体提交将标注在 patchwork 上。任何检查未通过的补丁通常不会被应用,并且在大多数情
|
||||
况下将需要重新提交。
|
||||
|
||||
附加的提交检查单
|
||||
----------------
|
||||
我们仅接受相关标准已经被RISC-V基金会标准为“已批准”或“已冻结”的扩展或模块的补丁。
|
||||
(开发者当然可以维护自己的Linux内核树,其中包含所需代码扩展草案的代码。)
|
||||
我们仅接受针对新模块或扩展的补丁,前提是这些模块或扩展的规范被列为未来不太可能发
|
||||
生不兼容的变更。对于来自 RISC-V 基金会的规范,这意味着“已冻结”或“已批准”,对于
|
||||
UEFI 论坛的规范,这意味着已发布的 ECR。(开发者当然可以维护自己的 Linux 内核树,
|
||||
其中包含他们所需的任何扩展草案的代码。)
|
||||
|
||||
此外,RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V
|
||||
基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来
|
||||
的维护复杂性和对性能的潜在影响,我们将只接受RISC-V基金会正式冻结或批准的的扩展
|
||||
补丁。(开发者当然可以维护自己的Linux内核树,其中包含他们想要的任何自定义扩展
|
||||
的代码。)
|
||||
此外,RISC-V 规范允许实现者创建自己的自定义扩展。这些自定义扩展不需要通过 RISC-V
|
||||
基金会的任何审核或批准流程。为了避免因添加实现者特定的 RISC-V 扩展带来的维护复杂
|
||||
性和对性能的潜在影响,我们将只考虑符合以下任一条件的扩展补丁:
|
||||
|
||||
- 已由 RISC-V 基金会正式冻结或批准
|
||||
- 已按照标准 Linux 惯例,在广泛可用的硬件中实现
|
||||
|
||||
(实现者当然可以维护自己的 Linux 内核树,其中包含他们所需的任何自定义扩展的代码。)
|
||||
|
|
|
|||
22
MAINTAINERS
22
MAINTAINERS
|
|
@ -4512,7 +4512,7 @@ AYANEO PLATFORM EC DRIVER
|
|||
M: Antheas Kapenekakis <lkml@antheas.dev>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-platform-ayaneo
|
||||
F: Documentation/ABI/testing/sysfs-platform-ayaneo-ec
|
||||
F: drivers/platform/x86/ayaneo-ec.c
|
||||
|
||||
AZ6007 DVB DRIVER
|
||||
|
|
@ -15020,6 +15020,8 @@ M: Madhavan Srinivasan <maddy@linux.ibm.com>
|
|||
R: Michael Ellerman <mpe@ellerman.id.au>
|
||||
R: Nicholas Piggin <npiggin@gmail.com>
|
||||
R: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
|
||||
R: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
|
||||
R: Shrikanth Hegde <sshegde@linux.ibm.com>
|
||||
L: linuxppc-dev@lists.ozlabs.org
|
||||
S: Supported
|
||||
W: https://github.com/linuxppc/wiki/wiki
|
||||
|
|
@ -25334,8 +25336,8 @@ F: Documentation/networking/timestamping.rst
|
|||
F: include/linux/net_tstamp.h
|
||||
F: include/uapi/linux/net_tstamp.h
|
||||
F: tools/testing/selftests/bpf/*/net_timestamping*
|
||||
F: tools/testing/selftests/drivers/net/so_txtime.*
|
||||
F: tools/testing/selftests/net/*timestamp*
|
||||
F: tools/testing/selftests/net/so_txtime.c
|
||||
|
||||
SOEKRIS NET48XX LED SUPPORT
|
||||
M: Chris Boot <bootc@bootc.net>
|
||||
|
|
@ -28607,7 +28609,6 @@ L: iommu@lists.linux.dev
|
|||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iommu/verisilicon,iommu.yaml
|
||||
F: drivers/iommu/vsi-iommu.c
|
||||
F: include/linux/vsi-iommu.h
|
||||
|
||||
VF610 NAND DRIVER
|
||||
M: Stefan Agner <stefan@agner.ch>
|
||||
|
|
@ -28867,8 +28868,8 @@ F: include/uapi/linux/virtio_console.h
|
|||
VIRTIO CORE
|
||||
M: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
M: Jason Wang <jasowangio@gmail.com>
|
||||
M: Eugenio Pérez <eperezma@redhat.com>
|
||||
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
|
||||
R: Eugenio Pérez <eperezma@redhat.com>
|
||||
L: virtualization@lists.linux.dev
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-vdpa
|
||||
|
|
@ -28945,7 +28946,7 @@ F: include/uapi/linux/virtio_gpu.h
|
|||
VIRTIO HOST (VHOST)
|
||||
M: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
M: Jason Wang <jasowangio@gmail.com>
|
||||
R: Eugenio Pérez <eperezma@redhat.com>
|
||||
M: Eugenio Pérez <eperezma@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
L: virtualization@lists.linux.dev
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
@ -29000,8 +29001,8 @@ F: include/uapi/linux/virtio_mem.h
|
|||
VIRTIO NET DRIVER
|
||||
M: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
M: Jason Wang <jasowangio@gmail.com>
|
||||
M: Eugenio Pérez <eperezma@redhat.com>
|
||||
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
|
||||
R: Eugenio Pérez <eperezma@redhat.com>
|
||||
L: netdev@vger.kernel.org
|
||||
L: virtualization@lists.linux.dev
|
||||
S: Maintained
|
||||
|
|
@ -29017,6 +29018,13 @@ S: Maintained
|
|||
F: drivers/nvdimm/nd_virtio.c
|
||||
F: drivers/nvdimm/virtio_pmem.c
|
||||
|
||||
VIRTIO RNG DRIVER
|
||||
M: Laurent Vivier <lvivier@redhat.com>
|
||||
L: virtualization@lists.linux.dev
|
||||
S: Maintained
|
||||
F: drivers/char/hw_random/virtio-rng.c
|
||||
F: include/uapi/linux/virtio_rng.h
|
||||
|
||||
VIRTIO RTC DRIVER
|
||||
M: Peter Hilber <peter.hilber@oss.qualcomm.com>
|
||||
L: virtualization@lists.linux.dev
|
||||
|
|
@ -29348,7 +29356,7 @@ M: Guenter Roeck <linux@roeck-us.net>
|
|||
L: linux-watchdog@vger.kernel.org
|
||||
S: Maintained
|
||||
W: http://www.linux-watchdog.org/
|
||||
T: git git://www.linux-watchdog.org/linux-watchdog.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
|
||||
F: Documentation/devicetree/bindings/watchdog/
|
||||
F: Documentation/watchdog/
|
||||
F: drivers/watchdog/
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc2
|
||||
EXTRAVERSION = -rc3
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -3761,7 +3761,9 @@ Sysreg ICC_CR0_EL1 3 1 12 0 1
|
|||
Res0 63:39
|
||||
Field 38 PID
|
||||
Field 37:32 IPPT
|
||||
Res0 31:1
|
||||
Res0 31:3
|
||||
Field 2 LINK_IDLE
|
||||
Field 1 LINK
|
||||
Field 0 EN
|
||||
EndSysreg
|
||||
|
||||
|
|
|
|||
|
|
@ -222,8 +222,6 @@ static inline void arch_interrupt_enter_prepare(struct pt_regs *regs)
|
|||
|
||||
if (user_mode(regs)) {
|
||||
kuap_lock();
|
||||
account_cpu_user_entry();
|
||||
account_stolen_time();
|
||||
} else {
|
||||
kuap_save_and_lock(regs);
|
||||
/*
|
||||
|
|
@ -270,7 +268,7 @@ static inline void arch_interrupt_exit_prepare(struct pt_regs *regs)
|
|||
}
|
||||
|
||||
/* irqentry_exit expects to be called with interrupts disabled */
|
||||
local_irq_disable();
|
||||
hard_irq_disable();
|
||||
}
|
||||
|
||||
static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs)
|
||||
|
|
@ -515,8 +513,14 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
|
|||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
local_paca->tm_scratch = regs->msr;
|
||||
#endif
|
||||
/* Restore user access locks last */
|
||||
kuap_user_restore(regs);
|
||||
/*
|
||||
* Do not restore KUAP here. Generic entry might treat this as the last
|
||||
* arch step before userspace but PowerPC still has kernel work after
|
||||
* irqentry_exit()/syscall_exit_to_user_mode() i.e. in
|
||||
* interrupt_exit_user_prepare() / syscall_exit_prepare() may enable
|
||||
* IRQs and retry. Those functions restore KUAP immediately before rfi,
|
||||
* which is where it should belong.
|
||||
*/
|
||||
}
|
||||
|
||||
#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
|
||||
|
|
|
|||
|
|
@ -533,9 +533,7 @@ static void eeh_rmv_device(struct eeh_dev *edev, void *userdata)
|
|||
if (rmv_data)
|
||||
list_add(&edev->rmv_entry, &rmv_data->removed_vf_list);
|
||||
} else {
|
||||
pci_lock_rescan_remove();
|
||||
pci_stop_and_remove_bus_device(dev);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *reg
|
|||
current_thread_info()->exit_flags &= ~_TIF_RESTOREALL;
|
||||
regs->exit_result |= ret;
|
||||
|
||||
return ret;
|
||||
return regs->exit_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -824,7 +824,6 @@ void __init early_init_devtree(void *params)
|
|||
fadump_append_bootargs();
|
||||
|
||||
/* Scan memory nodes and rebuild MEMBLOCKs */
|
||||
early_init_dt_scan_root();
|
||||
early_init_dt_scan_memory_ppc();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ int rtas_pci_dn_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
|
|||
if (!config_access_valid(pdn, where))
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
#ifdef CONFIG_EEH
|
||||
if (pdn->edev &&
|
||||
(pdn->edev->mode & EEH_DEV_REMOVED))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (pdn->edev && pdn->edev->pe &&
|
||||
(pdn->edev->pe->state & EEH_PE_CFG_BLOCKED))
|
||||
return PCIBIOS_SET_FAILED;
|
||||
|
|
@ -105,6 +109,10 @@ int rtas_pci_dn_write_config(struct pci_dn *pdn, int where, int size, u32 val)
|
|||
if (!config_access_valid(pdn, where))
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
#ifdef CONFIG_EEH
|
||||
if (pdn->edev &&
|
||||
(pdn->edev->mode & EEH_DEV_REMOVED))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (pdn->edev && pdn->edev->pe &&
|
||||
(pdn->edev->pe->state & EEH_PE_CFG_BLOCKED))
|
||||
return PCIBIOS_SET_FAILED;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
|
|||
long ret;
|
||||
syscall_fn f;
|
||||
|
||||
if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0)))
|
||||
if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))) {
|
||||
clear_thread_flag(TIF_SYSCALL_RET);
|
||||
return syscall_get_error(current, regs);
|
||||
}
|
||||
|
||||
if (unlikely(test_and_clear_thread_flag(TIF_SYSCALL_RET)))
|
||||
return syscall_get_error(current, regs);
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
|
|||
cmdline = modified_cmdline;
|
||||
}
|
||||
|
||||
kexec_dprintk("Command line: %s", cmdline ? cmdline : "");
|
||||
|
||||
if (initrd != NULL) {
|
||||
kbuf.buffer = initrd;
|
||||
kbuf.bufsz = kbuf.memsz = initrd_len;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ int arch_check_excluded_range(struct kimage *image, unsigned long start,
|
|||
|
||||
emem = image->arch.exclude_ranges;
|
||||
for (i = 0; i < emem->nr_ranges; i++)
|
||||
if (start < emem->ranges[i].end && end > emem->ranges[i].start)
|
||||
if (start <= emem->ranges[i].end && end >= emem->ranges[i].start)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -113,7 +113,7 @@ static int add_usable_mem(struct umem_info *um_info, u64 base, u64 end)
|
|||
loc_end = um_info->ranges[i].end;
|
||||
if (loc_base >= base && loc_end <= end)
|
||||
add = true;
|
||||
else if (base < loc_end && end > loc_base) {
|
||||
else if (base <= loc_end && end >= loc_base) {
|
||||
if (loc_base < base)
|
||||
loc_base = base;
|
||||
if (loc_end > end)
|
||||
|
|
@ -377,16 +377,12 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf)
|
|||
static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
|
||||
{
|
||||
#if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG)
|
||||
unsigned int extra_sz = 0;
|
||||
|
||||
if (CONFIG_CRASH_MAX_MEMORY_RANGES > (unsigned int)PN_XNUM)
|
||||
pr_warn("Number of Phdrs %u exceeds max\n", CONFIG_CRASH_MAX_MEMORY_RANGES);
|
||||
else if (cmem->nr_ranges >= CONFIG_CRASH_MAX_MEMORY_RANGES)
|
||||
pr_warn("Configured crash mem ranges may not be enough\n");
|
||||
else
|
||||
extra_sz = (CONFIG_CRASH_MAX_MEMORY_RANGES - cmem->nr_ranges) * sizeof(Elf64_Phdr);
|
||||
|
||||
return extra_sz;
|
||||
return (CONFIG_CRASH_MAX_MEMORY_RANGES - cmem->nr_ranges) * sizeof(Elf64_Phdr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6140,12 +6140,12 @@ static int kvmppc_irq_bypass_add_producer_hv(struct irq_bypass_consumer *cons,
|
|||
struct kvm_kernel_irqfd *irqfd =
|
||||
container_of(cons, struct kvm_kernel_irqfd, consumer);
|
||||
|
||||
irqfd->producer = prod;
|
||||
|
||||
ret = kvmppc_set_passthru_irq(irqfd->kvm, prod->irq, irqfd->gsi);
|
||||
if (ret)
|
||||
pr_info("kvmppc_set_passthru_irq (irq %d, gsi %d) fails: %d\n",
|
||||
prod->irq, irqfd->gsi, ret);
|
||||
else
|
||||
irqfd->producer = prod;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ static int __init pas_setup_mce_regs(void)
|
|||
while (dev && reg < MAX_MCE_REGS) {
|
||||
mce_regs[reg].name = kasprintf(GFP_KERNEL,
|
||||
"mc%d_mcdebug_errsta", reg);
|
||||
if (!mce_regs[reg].name)
|
||||
return -ENOMEM;
|
||||
mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730);
|
||||
dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev);
|
||||
reg++;
|
||||
|
|
|
|||
|
|
@ -1623,15 +1623,13 @@ int64_t pnv_opal_pci_msi_eoi(struct irq_data *d)
|
|||
return opal_pci_msi_eoi(phb->opal_id, d->parent_data->hwirq);
|
||||
}
|
||||
|
||||
static struct irq_chip pnv_pci_msi_irq_chip;
|
||||
|
||||
/*
|
||||
* Returns true iff chip is something that we could call
|
||||
* pnv_opal_pci_msi_eoi for.
|
||||
*/
|
||||
bool is_pnv_opal_msi(struct irq_chip *chip)
|
||||
{
|
||||
return chip == &pnv_pci_msi_irq_chip;
|
||||
return chip && chip->name && str_has_prefix(chip->name, "PNV-");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(is_pnv_opal_msi);
|
||||
|
||||
|
|
@ -1728,7 +1726,7 @@ static const struct msi_parent_ops pnv_msi_parent_ops = {
|
|||
.chip_flags = MSI_CHIP_FLAG_SET_EOI,
|
||||
.bus_select_token = DOMAIN_BUS_NEXUS,
|
||||
.bus_select_mask = MATCH_PCI_MSI,
|
||||
.prefix = "PNV-",
|
||||
.prefix = "PNV-", /* Note: is_pnv_opal_msi() uses this */
|
||||
.init_dev_msi_info = pnv_init_dev_msi_info,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
* Copyright 2006 Sony Corp.
|
||||
*/
|
||||
|
||||
#include <linux/minmax.h>
|
||||
|
||||
#include <asm/lv1call.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
|
@ -74,8 +76,9 @@ static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
|
|||
static u64 make_first_field(const char *text, u64 index)
|
||||
{
|
||||
u64 n = 0;
|
||||
size_t len = min(strlen(text), sizeof(n));
|
||||
|
||||
memcpy((char *)&n, text, strnlen(text, sizeof(n)));
|
||||
memcpy(&n, text, len);
|
||||
return PS3_VENDOR_ID_NONE + (n >> 32) + index;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -527,28 +527,28 @@ static int htmdump_init_debugfs(void)
|
|||
htm_status_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!htm_status_buf) {
|
||||
pr_err("Failed to allocate htmstatus buf\n");
|
||||
return -ENOMEM;
|
||||
goto htm_status_buf_err;
|
||||
}
|
||||
|
||||
/* Debugfs interface file to present System Processor Configuration */
|
||||
htm_info_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!htm_info_buf) {
|
||||
pr_err("Failed to allocate htm info buf\n");
|
||||
return -ENOMEM;
|
||||
goto htm_info_buf_err;
|
||||
}
|
||||
|
||||
/* Debugfs interface file to present HTM capabilities */
|
||||
htm_caps_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!htm_caps_buf) {
|
||||
pr_err("Failed to allocate htm caps buf\n");
|
||||
return -ENOMEM;
|
||||
goto htm_caps_buf_err;
|
||||
}
|
||||
|
||||
/* Memory to present HTM system memory configuration */
|
||||
htm_mem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!htm_mem_buf) {
|
||||
pr_err("Failed to allocate htm mem buf\n");
|
||||
return -ENOMEM;
|
||||
goto htm_mem_buf_err;
|
||||
}
|
||||
|
||||
debugfs_create_file("htmstatus", 0400, htmdump_debugfs_dir, htm_status_buf, &htmstatus_fops);
|
||||
|
|
@ -557,6 +557,17 @@ static int htmdump_init_debugfs(void)
|
|||
debugfs_create_file("htmsystem_mem", 0400, htmdump_debugfs_dir, htm_mem_buf, &htmsystem_mem_fops);
|
||||
|
||||
return 0;
|
||||
|
||||
htm_mem_buf_err:
|
||||
kfree(htm_caps_buf);
|
||||
htm_caps_buf_err:
|
||||
kfree(htm_info_buf);
|
||||
htm_info_buf_err:
|
||||
kfree(htm_status_buf);
|
||||
htm_status_buf_err:
|
||||
debugfs_remove_recursive(htmdump_debugfs_dir);
|
||||
kfree(htm_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int __init htmdump_init(void)
|
||||
|
|
|
|||
|
|
@ -132,11 +132,14 @@ static int pseries_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
|
|||
|
||||
/* First integer stores max config */
|
||||
max_config_vfs = of_read_number(&max_vfs[0], 1);
|
||||
if (max_config_vfs < num_vfs || num_vfs > MAX_VFS_FOR_MAP_PE) {
|
||||
dev_err(&pdev->dev,
|
||||
"Num VFs %x > %x Configurable VFs\n",
|
||||
num_vfs, (num_vfs > MAX_VFS_FOR_MAP_PE) ?
|
||||
MAX_VFS_FOR_MAP_PE : max_config_vfs);
|
||||
if (max_config_vfs < num_vfs) {
|
||||
dev_err(&pdev->dev, "Num VFs %x > %x Configurable VFs\n",
|
||||
num_vfs, max_config_vfs);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (num_vfs > MAX_VFS_FOR_MAP_PE) {
|
||||
dev_err(&pdev->dev, "Num VFs %x > %x PE mapping limit\n",
|
||||
num_vfs, MAX_VFS_FOR_MAP_PE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ config STACKTRACE_SUPPORT
|
|||
config GENERIC_BUG
|
||||
def_bool y
|
||||
depends on BUG
|
||||
select GENERIC_BUG_RELATIVE_POINTERS if 64BIT
|
||||
select GENERIC_BUG_RELATIVE_POINTERS
|
||||
|
||||
config GENERIC_BUG_RELATIVE_POINTERS
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -29,13 +29,8 @@
|
|||
|
||||
typedef u32 bug_insn_t;
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
||||
#define __BUG_ENTRY_ADDR RISCV_INT " 1b - ."
|
||||
#define __BUG_ENTRY_FILE(file) RISCV_INT " " file " - ."
|
||||
#else
|
||||
#define __BUG_ENTRY_ADDR RISCV_PTR " 1b"
|
||||
#define __BUG_ENTRY_FILE(file) RISCV_PTR " " file
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define __BUG_ENTRY(file, line, flags) \
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ static inline void __switch_to_fpu(struct task_struct *prev,
|
|||
|
||||
static __always_inline bool has_fpu(void)
|
||||
{
|
||||
return riscv_has_extension_likely(RISCV_ISA_EXT_F) ||
|
||||
riscv_has_extension_likely(RISCV_ISA_EXT_D);
|
||||
/* D extension depends on F, so checking D alone is sufficient. */
|
||||
return riscv_has_extension_likely(RISCV_ISA_EXT_D);
|
||||
}
|
||||
#else
|
||||
static __always_inline bool has_fpu(void) { return false; }
|
||||
|
|
|
|||
|
|
@ -412,6 +412,19 @@ static const unsigned int riscv_zvbb_exts[] = {
|
|||
RISCV_ISA_EXT_ZVKB
|
||||
};
|
||||
|
||||
/*
|
||||
* The RISC-V ISA manual specifies that Zfh implies Zfhmin and Zvfh implies
|
||||
* Zvfhmin. Report the implied subset extensions whenever the supersets are
|
||||
* detected (see https://github.com/riscv/riscv-isa-manual/pull/3070).
|
||||
*/
|
||||
static const unsigned int riscv_zfh_exts[] = {
|
||||
RISCV_ISA_EXT_ZFHMIN
|
||||
};
|
||||
|
||||
static const unsigned int riscv_zvfh_exts[] = {
|
||||
RISCV_ISA_EXT_ZVFHMIN
|
||||
};
|
||||
|
||||
#define RISCV_ISA_EXT_ZVE64F_IMPLY_LIST \
|
||||
RISCV_ISA_EXT_ZVE64X, \
|
||||
RISCV_ISA_EXT_ZVE32F, \
|
||||
|
|
@ -550,7 +563,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
|
|||
__RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zfa, RISCV_ISA_EXT_ZFA, riscv_ext_f_depends),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zfbfmin, RISCV_ISA_EXT_ZFBFMIN, riscv_ext_f_depends),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zfh, RISCV_ISA_EXT_ZFH, riscv_ext_f_depends),
|
||||
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zfh, RISCV_ISA_EXT_ZFH,
|
||||
riscv_zfh_exts, riscv_ext_f_depends),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zfhmin, RISCV_ISA_EXT_ZFHMIN, riscv_ext_f_depends),
|
||||
__RISCV_ISA_EXT_DATA(zca, RISCV_ISA_EXT_ZCA),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zcb, RISCV_ISA_EXT_ZCB, riscv_ext_zca_depends),
|
||||
|
|
@ -586,7 +600,9 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
|
|||
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts, riscv_ext_vector_x_validate),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zvfbfmin, RISCV_ISA_EXT_ZVFBFMIN, riscv_vector_f_validate),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zvfbfwma, RISCV_ISA_EXT_ZVFBFWMA, riscv_ext_zvfbfwma_validate),
|
||||
__RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH),
|
||||
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zvfh, RISCV_ISA_EXT_ZVFH,
|
||||
riscv_zvfh_exts,
|
||||
riscv_ext_vector_float_validate),
|
||||
__RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zvkb, RISCV_ISA_EXT_ZVKB, riscv_ext_vector_crypto_validate),
|
||||
__RISCV_ISA_EXT_DATA_VALIDATE(zvkg, RISCV_ISA_EXT_ZVKG, riscv_ext_vector_crypto_validate),
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
|
|||
phys_addr_t phys;
|
||||
|
||||
if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) {
|
||||
if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
||||
return addr;
|
||||
phys = __pa_symbol(addr);
|
||||
} else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) {
|
||||
struct page *page = vmalloc_to_page(addr);
|
||||
|
|
|
|||
|
|
@ -349,10 +349,8 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
|
|||
if (arg & PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(arg & PR_TAGGED_ADDR_ENABLE)) {
|
||||
if (!(arg & PR_TAGGED_ADDR_ENABLE))
|
||||
pmlen = PMLEN_0;
|
||||
pmm = ENVCFG_PMM_PMLEN_0;
|
||||
}
|
||||
|
||||
if (mmap_write_lock_killable(mm))
|
||||
return -EINTR;
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ static u64 hwprobe_vec_misaligned(const struct cpumask *cpus)
|
|||
static void hwprobe_one_pair(struct riscv_hwprobe *pair,
|
||||
const struct cpumask *cpus)
|
||||
{
|
||||
pair->value = 0;
|
||||
|
||||
switch (pair->key) {
|
||||
case RISCV_HWPROBE_KEY_MVENDORID:
|
||||
case RISCV_HWPROBE_KEY_MARCHID:
|
||||
|
|
@ -331,17 +333,14 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
|
|||
break;
|
||||
|
||||
case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE:
|
||||
pair->value = 0;
|
||||
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ))
|
||||
pair->value = riscv_cboz_block_size;
|
||||
break;
|
||||
case RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE:
|
||||
pair->value = 0;
|
||||
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOM))
|
||||
pair->value = riscv_cbom_block_size;
|
||||
break;
|
||||
case RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE:
|
||||
pair->value = 0;
|
||||
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOP))
|
||||
pair->value = riscv_cbop_block_size;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -525,9 +525,8 @@ static int __init setup_global_riscv_enable(char *str)
|
|||
|
||||
if (riscv_nousercfi)
|
||||
pr_info("RISC-V user CFI disabled via cmdline - shadow stack status : %s, landing pad status : %s\n",
|
||||
(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI) ? "disabled" :
|
||||
"enabled", (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI) ?
|
||||
"disabled" : "enabled");
|
||||
str_disabled_enabled(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI),
|
||||
str_disabled_enabled(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
|
|||
li a3, 9*SZREG-1 /* size must >= (word_copy stride + SZREG-1) */
|
||||
bltu a2, a3, .Lbyte_copy_tail
|
||||
|
||||
#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
/*
|
||||
* Copy first bytes until dst is aligned to word boundary.
|
||||
* a0 - start of dst
|
||||
|
|
@ -103,7 +104,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
|
|||
/* a1 - start of src */
|
||||
andi a3, a1, SZREG-1
|
||||
bnez a3, .Lshift_copy
|
||||
|
||||
#endif
|
||||
.Lword_copy:
|
||||
/*
|
||||
* Both src and dst are aligned, unrolled word copy
|
||||
|
|
@ -137,6 +138,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
|
|||
addi t0, t0, 8*SZREG /* revert to original value */
|
||||
j .Lbyte_copy_tail
|
||||
|
||||
#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
.Lshift_copy:
|
||||
|
||||
/*
|
||||
|
|
@ -189,6 +191,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
|
|||
|
||||
/* Revert src to original unaligned value */
|
||||
add a1, a1, a3
|
||||
#endif
|
||||
|
||||
.Lbyte_copy_tail:
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1465,7 +1465,9 @@ struct execmem_info __init *execmem_arch_setup(void)
|
|||
[EXECMEM_KPROBES] = {
|
||||
.start = VMALLOC_START,
|
||||
.end = VMALLOC_END,
|
||||
.pgprot = PAGE_KERNEL_READ_EXEC,
|
||||
.pgprot = IS_ENABLED(CONFIG_STRICT_MODULE_RWX) ?
|
||||
PAGE_KERNEL_READ_EXEC :
|
||||
PAGE_KERNEL_EXEC,
|
||||
.alignment = 1,
|
||||
},
|
||||
[EXECMEM_BPF] = {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
# Cryptographic API
|
||||
#
|
||||
|
||||
CONTEXT_ANALYSIS := y
|
||||
|
||||
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
|
||||
obj-$(CONFIG_CRYPTO_PAES_S390) += paes_s390.o
|
||||
obj-$(CONFIG_S390_PRNG) += prng.o
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/fips.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/string.h>
|
||||
#include <crypto/xts.h>
|
||||
#include <asm/cpacf.h>
|
||||
|
||||
static u8 *ctrblk;
|
||||
static DEFINE_MUTEX(ctrblk_lock);
|
||||
static DEFINE_SEMAPHORE(ctrblk_sem, 1);
|
||||
|
||||
static cpacf_mask_t km_functions, kmc_functions, kmctr_functions,
|
||||
kma_functions;
|
||||
|
|
@ -129,7 +129,7 @@ static int ecb_aes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
return fallback_skcipher_crypt(sctx, req, modifier);
|
||||
|
||||
ret = skcipher_walk_virt(&walk, req, false);
|
||||
while ((nbytes = walk.nbytes) != 0) {
|
||||
while (!ret && ((nbytes = walk.nbytes) != 0)) {
|
||||
/* only use complete blocks */
|
||||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
cpacf_km(sctx->fc | modifier, sctx->key,
|
||||
|
|
@ -233,7 +233,7 @@ static int cbc_aes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
return ret;
|
||||
memcpy(param.iv, walk.iv, AES_BLOCK_SIZE);
|
||||
memcpy(param.key, sctx->key, sctx->key_len);
|
||||
while ((nbytes = walk.nbytes) != 0) {
|
||||
while (!ret && ((nbytes = walk.nbytes) != 0)) {
|
||||
/* only use complete blocks */
|
||||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
cpacf_kmc(sctx->fc | modifier, ¶m,
|
||||
|
|
@ -359,7 +359,7 @@ static int xts_aes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
memcpy(xts_param.key + offset, xts_ctx->key, xts_ctx->key_len);
|
||||
memcpy(xts_param.init, pcc_param.xts, 16);
|
||||
|
||||
while ((nbytes = walk.nbytes) != 0) {
|
||||
while (!ret && ((nbytes = walk.nbytes) != 0)) {
|
||||
/* only use complete blocks */
|
||||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
cpacf_km(xts_ctx->fc | modifier, xts_param.key + offset,
|
||||
|
|
@ -487,7 +487,7 @@ static int fullxts_aes_crypt(struct skcipher_request *req, unsigned long modifi
|
|||
memcpy(fxts_param.tweak, req->iv, AES_BLOCK_SIZE);
|
||||
fxts_param.nap[0] = 0x01; /* initial alpha power (1, little-endian) */
|
||||
|
||||
while ((nbytes = walk.nbytes) != 0) {
|
||||
while (!ret && ((nbytes = walk.nbytes) != 0)) {
|
||||
/* only use complete blocks */
|
||||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
cpacf_km(xts_ctx->fc | modifier, fxts_param.key + offset,
|
||||
|
|
@ -562,48 +562,64 @@ static unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
|
|||
return n;
|
||||
}
|
||||
|
||||
static int __ctr_aes_crypt(struct s390_aes_ctx *sctx,
|
||||
struct skcipher_walk *walk, bool locked)
|
||||
{
|
||||
unsigned int n, nbytes;
|
||||
int ret = 0;
|
||||
u8 *ctrptr;
|
||||
|
||||
while (!ret && ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE)) {
|
||||
n = AES_BLOCK_SIZE;
|
||||
if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
|
||||
n = __ctrblk_init(ctrblk, walk->iv, nbytes);
|
||||
ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
|
||||
cpacf_kmctr(sctx->fc, sctx->key, walk->dst.virt.addr,
|
||||
walk->src.virt.addr, n, ctrptr);
|
||||
if (ctrptr == ctrblk)
|
||||
memcpy(walk->iv, ctrptr + n - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE);
|
||||
crypto_inc(walk->iv, AES_BLOCK_SIZE);
|
||||
ret = skcipher_walk_done(walk, nbytes - n);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ctr_aes_crypt(struct skcipher_request *req)
|
||||
{
|
||||
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
|
||||
struct s390_aes_ctx *sctx = crypto_skcipher_ctx(tfm);
|
||||
u8 buf[AES_BLOCK_SIZE], *ctrptr;
|
||||
struct skcipher_walk walk;
|
||||
unsigned int n, nbytes;
|
||||
int ret, locked;
|
||||
u8 buf[AES_BLOCK_SIZE];
|
||||
int ret;
|
||||
|
||||
if (unlikely(!sctx->fc))
|
||||
return fallback_skcipher_crypt(sctx, req, 0);
|
||||
|
||||
locked = mutex_trylock(&ctrblk_lock);
|
||||
|
||||
ret = skcipher_walk_virt(&walk, req, false);
|
||||
while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
|
||||
n = AES_BLOCK_SIZE;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nbytes >= 2*AES_BLOCK_SIZE && locked)
|
||||
n = __ctrblk_init(ctrblk, walk.iv, nbytes);
|
||||
ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
|
||||
cpacf_kmctr(sctx->fc, sctx->key, walk.dst.virt.addr,
|
||||
walk.src.virt.addr, n, ctrptr);
|
||||
if (ctrptr == ctrblk)
|
||||
memcpy(walk.iv, ctrptr + n - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE);
|
||||
crypto_inc(walk.iv, AES_BLOCK_SIZE);
|
||||
ret = skcipher_walk_done(&walk, nbytes - n);
|
||||
if (down_trylock(&ctrblk_sem) == 0) {
|
||||
ret = __ctr_aes_crypt(sctx, &walk, true);
|
||||
up(&ctrblk_sem);
|
||||
} else {
|
||||
ret = __ctr_aes_crypt(sctx, &walk, false);
|
||||
}
|
||||
if (locked)
|
||||
mutex_unlock(&ctrblk_lock);
|
||||
|
||||
/*
|
||||
* final block may be < AES_BLOCK_SIZE, copy only nbytes
|
||||
*/
|
||||
if (nbytes) {
|
||||
if (!ret && walk.nbytes > 0) {
|
||||
memset(buf, 0, AES_BLOCK_SIZE);
|
||||
memcpy(buf, walk.src.virt.addr, nbytes);
|
||||
memcpy(buf, walk.src.virt.addr, walk.nbytes);
|
||||
cpacf_kmctr(sctx->fc, sctx->key, buf, buf,
|
||||
AES_BLOCK_SIZE, walk.iv);
|
||||
memcpy(walk.dst.virt.addr, buf, nbytes);
|
||||
memcpy(walk.dst.virt.addr, buf, walk.nbytes);
|
||||
crypto_inc(walk.iv, AES_BLOCK_SIZE);
|
||||
ret = skcipher_walk_done(&walk, 0);
|
||||
memzero_explicit(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -895,10 +911,14 @@ static int gcm_aes_crypt(struct aead_request *req, unsigned int flags)
|
|||
gw_in.ptr, aad_bytes);
|
||||
|
||||
n = aad_bytes + pc_bytes;
|
||||
if (gcm_in_walk_done(&gw_in, n) != n)
|
||||
return -ENOMEM;
|
||||
if (gcm_out_walk_done(&gw_out, n) != n)
|
||||
return -ENOMEM;
|
||||
if (gcm_in_walk_done(&gw_in, n) != n) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (gcm_out_walk_done(&gw_out, n) != n) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
aadlen -= aad_bytes;
|
||||
pclen -= pc_bytes;
|
||||
} while (aadlen + pclen > 0);
|
||||
|
|
@ -910,7 +930,10 @@ static int gcm_aes_crypt(struct aead_request *req, unsigned int flags)
|
|||
} else
|
||||
scatterwalk_map_and_copy(param.t, req->dst, len, taglen, 1);
|
||||
|
||||
out:
|
||||
memzero_explicit(¶m, sizeof(param));
|
||||
memzero_explicit(gw_in.buf, sizeof(gw_in.buf));
|
||||
memzero_explicit(gw_out.buf, sizeof(gw_out.buf));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/algapi.h>
|
||||
|
|
@ -45,7 +45,7 @@ module_param_named(clrkey, pkey_clrkey_allowed, bool, 0444);
|
|||
MODULE_PARM_DESC(clrkey, "Allow clear key material (default N)");
|
||||
|
||||
static u8 *ctrblk;
|
||||
static DEFINE_MUTEX(ctrblk_lock);
|
||||
static DEFINE_SEMAPHORE(ctrblk_sem, 1);
|
||||
|
||||
static cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
|
||||
|
||||
|
|
@ -220,6 +220,10 @@ static inline int convert_key(const u8 *key, unsigned int keylen,
|
|||
xflags);
|
||||
}
|
||||
|
||||
/* But finally map -EBUSY to -EIO to indicate an IO failure */
|
||||
if (rc == -EBUSY)
|
||||
rc = -EIO;
|
||||
|
||||
out:
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -432,8 +436,11 @@ static int ecb_paes_do_crypt(struct s390_paes_ctx *ctx,
|
|||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
k = cpacf_km(ctx->fc | req_ctx->modifier, param,
|
||||
walk->dst.virt.addr, walk->src.virt.addr, n);
|
||||
if (k)
|
||||
if (k) {
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
rc = -EKEYEXPIRED;
|
||||
|
|
@ -460,6 +467,7 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct skcipher_walk *walk = &req_ctx->walk;
|
||||
bool tested = crypto_skcipher_tested(tfm);
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
|
|
@ -491,15 +499,17 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
if (rc == 0 || rc == -EKEYEXPIRED) {
|
||||
atomic_inc(&ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_skcipher_request_to_engine(paes_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup && walk->nbytes)
|
||||
skcipher_walk_done(walk, rc);
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(&req_ctx->param, sizeof(req_ctx->param));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -549,7 +559,7 @@ static int ecb_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
rc = ecb_paes_do_crypt(ctx, req_ctx, tested, true);
|
||||
if (rc == -EKEYEXPIRED) {
|
||||
return pkey_handle_expired();
|
||||
} else if (rc) {
|
||||
} else if (rc && walk->nbytes) {
|
||||
skcipher_walk_done(walk, rc);
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +569,7 @@ static int ecb_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
atomic_dec(&ctx->via_engine_ctr);
|
||||
crypto_finalize_skcipher_request(engine, req, rc);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skcipher_engine_alg ecb_paes_alg = {
|
||||
|
|
@ -567,6 +577,7 @@ static struct skcipher_engine_alg ecb_paes_alg = {
|
|||
.base.cra_name = "ecb(paes)",
|
||||
.base.cra_driver_name = "ecb-paes-s390",
|
||||
.base.cra_priority = 401, /* combo: aes + ecb + 1 */
|
||||
.base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NO_FALLBACK,
|
||||
.base.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.base.cra_ctxsize = sizeof(struct s390_paes_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
|
@ -690,6 +701,8 @@ static int cbc_paes_do_crypt(struct s390_paes_ctx *ctx,
|
|||
if (k) {
|
||||
memcpy(walk->iv, param->iv, AES_BLOCK_SIZE);
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
|
|
@ -717,6 +730,7 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct skcipher_walk *walk = &req_ctx->walk;
|
||||
bool tested = crypto_skcipher_tested(tfm);
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
|
|
@ -748,15 +762,17 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
|
|||
if (rc == 0 || rc == -EKEYEXPIRED) {
|
||||
atomic_inc(&ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_skcipher_request_to_engine(paes_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup && walk->nbytes)
|
||||
skcipher_walk_done(walk, rc);
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(&req_ctx->param, sizeof(req_ctx->param));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -806,7 +822,7 @@ static int cbc_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
rc = cbc_paes_do_crypt(ctx, req_ctx, tested, true);
|
||||
if (rc == -EKEYEXPIRED) {
|
||||
return pkey_handle_expired();
|
||||
} else if (rc) {
|
||||
} else if (rc && walk->nbytes) {
|
||||
skcipher_walk_done(walk, rc);
|
||||
}
|
||||
|
||||
|
|
@ -816,7 +832,7 @@ static int cbc_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
atomic_dec(&ctx->via_engine_ctr);
|
||||
crypto_finalize_skcipher_request(engine, req, rc);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skcipher_engine_alg cbc_paes_alg = {
|
||||
|
|
@ -824,6 +840,7 @@ static struct skcipher_engine_alg cbc_paes_alg = {
|
|||
.base.cra_name = "cbc(paes)",
|
||||
.base.cra_driver_name = "cbc-paes-s390",
|
||||
.base.cra_priority = 402, /* cbc-paes-s390 + 1 */
|
||||
.base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NO_FALLBACK,
|
||||
.base.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.base.cra_ctxsize = sizeof(struct s390_paes_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
|
@ -914,15 +931,62 @@ static inline unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes
|
|||
return n;
|
||||
}
|
||||
|
||||
static int __ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
|
||||
struct ctr_param *param,
|
||||
struct skcipher_walk *walk,
|
||||
bool tested, bool maysleep, bool locked)
|
||||
{
|
||||
unsigned int nbytes, n, k;
|
||||
u8 *ctrptr;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* Note that in case of partial processing or failure the walk
|
||||
* is NOT unmapped here. So a follow up task may reuse the walk
|
||||
* or in case of unrecoverable failure needs to unmap it.
|
||||
*/
|
||||
while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
|
||||
n = AES_BLOCK_SIZE;
|
||||
if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
|
||||
n = __ctrblk_init(ctrblk, walk->iv, nbytes);
|
||||
ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
|
||||
k = cpacf_kmctr(ctx->fc, param, walk->dst.virt.addr,
|
||||
walk->src.virt.addr, n, ctrptr);
|
||||
if (k) {
|
||||
if (ctrptr == ctrblk)
|
||||
memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE);
|
||||
crypto_inc(walk->iv, AES_BLOCK_SIZE);
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
rc = -EKEYEXPIRED;
|
||||
goto out;
|
||||
}
|
||||
rc = paes_convert_key(ctx, tested);
|
||||
if (rc)
|
||||
goto out;
|
||||
spin_lock_bh(&ctx->pk_lock);
|
||||
memcpy(param->key, ctx->pk.protkey, sizeof(param->key));
|
||||
spin_unlock_bh(&ctx->pk_lock);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
|
||||
struct s390_pctr_req_ctx *req_ctx,
|
||||
bool tested, bool maysleep)
|
||||
{
|
||||
struct ctr_param *param = &req_ctx->param;
|
||||
struct skcipher_walk *walk = &req_ctx->walk;
|
||||
u8 buf[AES_BLOCK_SIZE], *ctrptr;
|
||||
unsigned int nbytes, n, k;
|
||||
int pk_state, locked, rc = 0;
|
||||
u8 buf[AES_BLOCK_SIZE];
|
||||
int pk_state, rc = 0;
|
||||
|
||||
if (!req_ctx->param_init_done) {
|
||||
/* fetch and check protected key state */
|
||||
|
|
@ -948,52 +1012,17 @@ static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
locked = mutex_trylock(&ctrblk_lock);
|
||||
|
||||
/*
|
||||
* Note that in case of partial processing or failure the walk
|
||||
* is NOT unmapped here. So a follow up task may reuse the walk
|
||||
* or in case of unrecoverable failure needs to unmap it.
|
||||
*/
|
||||
while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
|
||||
n = AES_BLOCK_SIZE;
|
||||
if (nbytes >= 2 * AES_BLOCK_SIZE && locked)
|
||||
n = __ctrblk_init(ctrblk, walk->iv, nbytes);
|
||||
ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk->iv;
|
||||
k = cpacf_kmctr(ctx->fc, param, walk->dst.virt.addr,
|
||||
walk->src.virt.addr, n, ctrptr);
|
||||
if (k) {
|
||||
if (ctrptr == ctrblk)
|
||||
memcpy(walk->iv, ctrptr + k - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE);
|
||||
crypto_inc(walk->iv, AES_BLOCK_SIZE);
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
if (locked)
|
||||
mutex_unlock(&ctrblk_lock);
|
||||
rc = -EKEYEXPIRED;
|
||||
goto out;
|
||||
}
|
||||
rc = paes_convert_key(ctx, tested);
|
||||
if (rc) {
|
||||
if (locked)
|
||||
mutex_unlock(&ctrblk_lock);
|
||||
goto out;
|
||||
}
|
||||
spin_lock_bh(&ctx->pk_lock);
|
||||
memcpy(param->key, ctx->pk.protkey, sizeof(param->key));
|
||||
spin_unlock_bh(&ctx->pk_lock);
|
||||
}
|
||||
if (down_trylock(&ctrblk_sem) == 0) {
|
||||
rc = __ctr_paes_do_crypt(ctx, param, walk, tested, maysleep, true);
|
||||
up(&ctrblk_sem);
|
||||
} else {
|
||||
rc = __ctr_paes_do_crypt(ctx, param, walk, tested, maysleep, false);
|
||||
}
|
||||
if (locked)
|
||||
mutex_unlock(&ctrblk_lock);
|
||||
|
||||
/* final block may be < AES_BLOCK_SIZE, copy only nbytes */
|
||||
if (nbytes) {
|
||||
if (!rc && walk->nbytes > 0) {
|
||||
memset(buf, 0, AES_BLOCK_SIZE);
|
||||
memcpy(buf, walk->src.virt.addr, nbytes);
|
||||
memcpy(buf, walk->src.virt.addr, walk->nbytes);
|
||||
while (1) {
|
||||
if (cpacf_kmctr(ctx->fc, param, buf,
|
||||
buf, AES_BLOCK_SIZE,
|
||||
|
|
@ -1010,12 +1039,13 @@ static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
|
|||
memcpy(param->key, ctx->pk.protkey, sizeof(param->key));
|
||||
spin_unlock_bh(&ctx->pk_lock);
|
||||
}
|
||||
memcpy(walk->dst.virt.addr, buf, nbytes);
|
||||
memcpy(walk->dst.virt.addr, buf, walk->nbytes);
|
||||
crypto_inc(walk->iv, AES_BLOCK_SIZE);
|
||||
rc = skcipher_walk_done(walk, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
memzero_explicit(buf, sizeof(buf));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1027,6 +1057,7 @@ static int ctr_paes_crypt(struct skcipher_request *req)
|
|||
struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct skcipher_walk *walk = &req_ctx->walk;
|
||||
bool tested = crypto_skcipher_tested(tfm);
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
|
|
@ -1057,15 +1088,17 @@ static int ctr_paes_crypt(struct skcipher_request *req)
|
|||
if (rc == 0 || rc == -EKEYEXPIRED) {
|
||||
atomic_inc(&ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_skcipher_request_to_engine(paes_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup && walk->nbytes)
|
||||
skcipher_walk_done(walk, rc);
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(&req_ctx->param, sizeof(req_ctx->param));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -1105,7 +1138,7 @@ static int ctr_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
rc = ctr_paes_do_crypt(ctx, req_ctx, tested, true);
|
||||
if (rc == -EKEYEXPIRED) {
|
||||
return pkey_handle_expired();
|
||||
} else if (rc) {
|
||||
} else if (rc && walk->nbytes) {
|
||||
skcipher_walk_done(walk, rc);
|
||||
}
|
||||
|
||||
|
|
@ -1115,7 +1148,7 @@ static int ctr_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
atomic_dec(&ctx->via_engine_ctr);
|
||||
crypto_finalize_skcipher_request(engine, req, rc);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skcipher_engine_alg ctr_paes_alg = {
|
||||
|
|
@ -1123,6 +1156,7 @@ static struct skcipher_engine_alg ctr_paes_alg = {
|
|||
.base.cra_name = "ctr(paes)",
|
||||
.base.cra_driver_name = "ctr-paes-s390",
|
||||
.base.cra_priority = 402, /* ecb-paes-s390 + 1 */
|
||||
.base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NO_FALLBACK,
|
||||
.base.cra_blocksize = 1,
|
||||
.base.cra_ctxsize = sizeof(struct s390_paes_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
|
@ -1283,8 +1317,11 @@ static int xts_paes_do_crypt_fullkey(struct s390_pxts_ctx *ctx,
|
|||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
k = cpacf_km(ctx->fc | req_ctx->modifier, param->key + offset,
|
||||
walk->dst.virt.addr, walk->src.virt.addr, n);
|
||||
if (k)
|
||||
if (k) {
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
rc = -EKEYEXPIRED;
|
||||
|
|
@ -1337,7 +1374,7 @@ static inline int __xts_2keys_prep_param(struct s390_pxts_ctx *ctx,
|
|||
memcpy(param->init, pcc_param.xts, 16);
|
||||
}
|
||||
|
||||
memzero_explicit(pcc_param.key, sizeof(pcc_param.key));
|
||||
memzero_explicit(&pcc_param, sizeof(pcc_param));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1377,8 +1414,11 @@ static int xts_paes_do_crypt_2keys(struct s390_pxts_ctx *ctx,
|
|||
n = nbytes & ~(AES_BLOCK_SIZE - 1);
|
||||
k = cpacf_km(ctx->fc | req_ctx->modifier, param->key + offset,
|
||||
walk->dst.virt.addr, walk->src.virt.addr, n);
|
||||
if (k)
|
||||
if (k) {
|
||||
rc = skcipher_walk_done(walk, nbytes - k);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
if (k < n) {
|
||||
if (!maysleep) {
|
||||
rc = -EKEYEXPIRED;
|
||||
|
|
@ -1450,6 +1490,7 @@ static inline int xts_paes_crypt(struct skcipher_request *req, unsigned long mod
|
|||
struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct skcipher_walk *walk = &req_ctx->walk;
|
||||
bool tested = crypto_skcipher_tested(tfm);
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
|
|
@ -1481,15 +1522,17 @@ static inline int xts_paes_crypt(struct skcipher_request *req, unsigned long mod
|
|||
if (rc == 0 || rc == -EKEYEXPIRED) {
|
||||
atomic_inc(&ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_skcipher_request_to_engine(paes_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup && walk->nbytes)
|
||||
skcipher_walk_done(walk, rc);
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(&req_ctx->param, sizeof(req_ctx->param));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -1539,7 +1582,7 @@ static int xts_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
rc = xts_paes_do_crypt(ctx, req_ctx, tested, true);
|
||||
if (rc == -EKEYEXPIRED) {
|
||||
return pkey_handle_expired();
|
||||
} else if (rc) {
|
||||
} else if (rc && walk->nbytes) {
|
||||
skcipher_walk_done(walk, rc);
|
||||
}
|
||||
|
||||
|
|
@ -1549,7 +1592,7 @@ static int xts_paes_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
atomic_dec(&ctx->via_engine_ctr);
|
||||
crypto_finalize_skcipher_request(engine, req, rc);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skcipher_engine_alg xts_paes_alg = {
|
||||
|
|
@ -1557,6 +1600,7 @@ static struct skcipher_engine_alg xts_paes_alg = {
|
|||
.base.cra_name = "xts(paes)",
|
||||
.base.cra_driver_name = "xts-paes-s390",
|
||||
.base.cra_priority = 402, /* ecb-paes-s390 + 1 */
|
||||
.base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NO_FALLBACK,
|
||||
.base.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.base.cra_ctxsize = sizeof(struct s390_pxts_ctx),
|
||||
.base.cra_module = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -62,8 +62,10 @@ static inline int hwh_prepare(struct ahash_request *req,
|
|||
*/
|
||||
static inline int hwh_advance(struct hash_walk_helper *hwh, int n)
|
||||
{
|
||||
if (n < 0)
|
||||
if (n < 0) {
|
||||
hwh->walkbytes = n;
|
||||
return crypto_hash_walk_done(&hwh->walk, n);
|
||||
}
|
||||
|
||||
hwh->walkbytes -= n;
|
||||
hwh->walkaddr += n;
|
||||
|
|
@ -339,6 +341,10 @@ static inline int convert_key(const u8 *key, unsigned int keylen,
|
|||
xflags);
|
||||
}
|
||||
|
||||
/* But finally map -EBUSY to -EIO to indicate an IO failure */
|
||||
if (rc == -EBUSY)
|
||||
rc = -EIO;
|
||||
|
||||
out:
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -606,6 +612,7 @@ static int phmac_update(struct ahash_request *req)
|
|||
struct phmac_tfm_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
|
||||
struct kmac_sha2_ctx *kmac_ctx = &req_ctx->kmac_ctx;
|
||||
struct hash_walk_helper *hwh = &req_ctx->hwh;
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/* prep the walk in the request context */
|
||||
|
|
@ -629,12 +636,15 @@ static int phmac_update(struct ahash_request *req)
|
|||
req_ctx->async_op = OP_UPDATE;
|
||||
atomic_inc(&tfm_ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_hash_request_to_engine(phmac_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&tfm_ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS) {
|
||||
hwh_advance(hwh, rc);
|
||||
if (cleanup) {
|
||||
if (hwh->walkbytes > 0)
|
||||
hwh_advance(hwh, rc);
|
||||
memzero_explicit(kmac_ctx, sizeof(*kmac_ctx));
|
||||
}
|
||||
|
||||
|
|
@ -649,6 +659,7 @@ static int phmac_final(struct ahash_request *req)
|
|||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct phmac_tfm_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
|
||||
struct kmac_sha2_ctx *kmac_ctx = &req_ctx->kmac_ctx;
|
||||
bool cleanup = true;
|
||||
int rc = 0;
|
||||
|
||||
/* Try synchronous operation if no active engine usage */
|
||||
|
|
@ -667,12 +678,14 @@ static int phmac_final(struct ahash_request *req)
|
|||
req_ctx->async_op = OP_FINAL;
|
||||
atomic_inc(&tfm_ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_hash_request_to_engine(phmac_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&tfm_ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(kmac_ctx, sizeof(*kmac_ctx));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -685,6 +698,7 @@ static int phmac_finup(struct ahash_request *req)
|
|||
struct phmac_tfm_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
|
||||
struct kmac_sha2_ctx *kmac_ctx = &req_ctx->kmac_ctx;
|
||||
struct hash_walk_helper *hwh = &req_ctx->hwh;
|
||||
bool cleanup = true;
|
||||
int rc;
|
||||
|
||||
/* prep the walk in the request context */
|
||||
|
|
@ -716,15 +730,17 @@ static int phmac_finup(struct ahash_request *req)
|
|||
/* req->async_op has been set to either OP_FINUP or OP_FINAL */
|
||||
atomic_inc(&tfm_ctx->via_engine_ctr);
|
||||
rc = crypto_transfer_hash_request_to_engine(phmac_crypto_engine, req);
|
||||
if (rc != -EINPROGRESS)
|
||||
if (rc == -EINPROGRESS || rc == -EBUSY)
|
||||
cleanup = false;
|
||||
else
|
||||
atomic_dec(&tfm_ctx->via_engine_ctr);
|
||||
}
|
||||
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup && hwh->walkbytes > 0)
|
||||
hwh_advance(hwh, rc);
|
||||
|
||||
out:
|
||||
if (rc != -EINPROGRESS)
|
||||
if (cleanup)
|
||||
memzero_explicit(kmac_ctx, sizeof(*kmac_ctx));
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
|
|
@ -914,7 +930,7 @@ static int phmac_do_one_request(struct crypto_engine *engine, void *areq)
|
|||
atomic_dec(&tfm_ctx->via_engine_ctr);
|
||||
crypto_finalize_hash_request(engine, req, rc);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define S390_ASYNC_PHMAC_ALG(x) \
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ static __always_inline void pai_kernel_exit(struct pt_regs *regs)
|
|||
}
|
||||
|
||||
#define PAI_SAVE_AREA(x) ((x)->hw.event_base)
|
||||
#define PAI_CPU_MASK(x) ((x)->hw.addr_filters)
|
||||
#define PAI_PMU_IDX(x) ((x)->hw.last_tag)
|
||||
#define PAI_SWLIST(x) (&(x)->hw.tp_list)
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ static struct debug_param_t {
|
|||
static int debug_param_num;
|
||||
|
||||
/* functions */
|
||||
static void debug_get_param(const char *name, int *level, int *pages)
|
||||
static void debug_get_param(const char *name, int *level, int *pages, bool quiet)
|
||||
{
|
||||
struct debug_param_t *p;
|
||||
int i;
|
||||
|
|
@ -192,11 +192,13 @@ static void debug_get_param(const char *name, int *level, int *pages)
|
|||
if (!glob_match(p->name, name))
|
||||
continue;
|
||||
if (level && p->level != PARAM_UNSET) {
|
||||
pr_info("%s: override level to %d\n", name, p->level);
|
||||
if (!quiet)
|
||||
pr_info("%s: override level to %d\n", name, p->level);
|
||||
*level = p->level;
|
||||
}
|
||||
if (pages && p->pages != PARAM_UNSET) {
|
||||
pr_info("%s: override pages to %d\n", name, p->pages);
|
||||
if (!quiet)
|
||||
pr_info("%s: override pages to %d\n", name, p->pages);
|
||||
*pages = p->pages;
|
||||
}
|
||||
}
|
||||
|
|
@ -251,7 +253,7 @@ static int __init s390dbf_parse(char *arg)
|
|||
* regular memory allocations are possible.
|
||||
*/
|
||||
for (i = 0, id = __s390dbf_info; &id[i] < __s390dbf_info_end; i++)
|
||||
debug_get_param(id[i]->name, &id[i]->level, NULL);
|
||||
debug_get_param(id[i]->name, &id[i]->level, NULL, false);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -395,7 +397,7 @@ static debug_info_t *debug_info_create(const char *name, int pages_per_area,
|
|||
int level = DEBUG_DEFAULT_LEVEL;
|
||||
debug_info_t *rc;
|
||||
|
||||
debug_get_param(name, &level, &pages_per_area);
|
||||
debug_get_param(name, &level, &pages_per_area, false);
|
||||
rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size, level, ALL_AREAS);
|
||||
if (!rc)
|
||||
goto out;
|
||||
|
|
@ -960,7 +962,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
return;
|
||||
}
|
||||
|
||||
debug_get_param(id->name, &id->level, &pages_per_area);
|
||||
debug_get_param(id->name, &id->level, &pages_per_area, false);
|
||||
copy = debug_info_alloc("", pages_per_area, nr_areas, id->buf_size,
|
||||
id->level, ALL_AREAS);
|
||||
if (!copy) {
|
||||
|
|
@ -1074,9 +1076,6 @@ static void _debug_set_level(debug_info_t *id, int new_level)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
if (new_level == DEBUG_OFF_LEVEL) {
|
||||
pr_info("%s: switched off\n", id->name);
|
||||
} else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
|
||||
|
|
@ -1101,8 +1100,14 @@ static void _debug_set_level(debug_info_t *id, int new_level)
|
|||
*/
|
||||
void debug_set_level(debug_info_t *id, int new_level)
|
||||
{
|
||||
/* Level specified via kernel parameter takes precedence */
|
||||
debug_get_param(id->name, &new_level, NULL);
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Level specified via kernel parameter takes precedence. The override
|
||||
* was already announced during registration, so stay quiet here.
|
||||
*/
|
||||
debug_get_param(id->name, &new_level, NULL, true);
|
||||
|
||||
_debug_set_level(id, new_level);
|
||||
}
|
||||
|
|
@ -1278,7 +1283,7 @@ void debug_set_critical(void)
|
|||
debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
||||
int len)
|
||||
{
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
|
|
@ -1289,6 +1294,8 @@ debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
do {
|
||||
active = get_active_entry(id);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
|
|
@ -1298,7 +1305,7 @@ debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
|
|||
len -= id->buf_size;
|
||||
buf += id->buf_size;
|
||||
} while (len > 0);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
return active;
|
||||
}
|
||||
|
|
@ -1311,7 +1318,7 @@ EXPORT_SYMBOL(debug_event_common);
|
|||
debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
||||
const void *buf, int len)
|
||||
{
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
|
|
@ -1322,6 +1329,8 @@ debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
do {
|
||||
active = get_active_entry(id);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
|
|
@ -1331,7 +1340,7 @@ debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
|||
len -= id->buf_size;
|
||||
buf += id->buf_size;
|
||||
} while (len > 0);
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
return active;
|
||||
}
|
||||
|
|
@ -1357,7 +1366,7 @@ static inline int debug_count_numargs(char *string)
|
|||
debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
|
||||
{
|
||||
debug_sprintf_entry_t *curr_event;
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
int numargs, idx;
|
||||
va_list ap;
|
||||
|
|
@ -1372,6 +1381,8 @@ debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string,
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
active = get_active_entry(id);
|
||||
curr_event = (debug_sprintf_entry_t *) DEBUG_DATA(active);
|
||||
va_start(ap, string);
|
||||
|
|
@ -1380,6 +1391,7 @@ debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string,
|
|||
curr_event->args[idx] = va_arg(ap, long);
|
||||
va_end(ap);
|
||||
debug_finish_entry(id, active, level, 0);
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return active;
|
||||
|
|
@ -1392,7 +1404,7 @@ EXPORT_SYMBOL(__debug_sprintf_event);
|
|||
debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
|
||||
{
|
||||
debug_sprintf_entry_t *curr_event;
|
||||
debug_entry_t *active;
|
||||
debug_entry_t *active = NULL;
|
||||
unsigned long flags;
|
||||
int numargs, idx;
|
||||
va_list ap;
|
||||
|
|
@ -1408,6 +1420,8 @@ debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *stri
|
|||
} else {
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
}
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
active = get_active_entry(id);
|
||||
curr_event = (debug_sprintf_entry_t *)DEBUG_DATA(active);
|
||||
va_start(ap, string);
|
||||
|
|
@ -1416,6 +1430,7 @@ debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *stri
|
|||
curr_event->args[idx] = va_arg(ap, long);
|
||||
va_end(ap);
|
||||
debug_finish_entry(id, active, level, 1);
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return active;
|
||||
|
|
@ -1658,9 +1673,11 @@ static void debug_flush(debug_info_t *id, int area)
|
|||
unsigned long flags;
|
||||
int i, j;
|
||||
|
||||
if (!id || !id->areas)
|
||||
if (!id)
|
||||
return;
|
||||
raw_spin_lock_irqsave(&id->lock, flags);
|
||||
if (!id->areas)
|
||||
goto out;
|
||||
if (area == DEBUG_FLUSH_ALL) {
|
||||
id->active_area = 0;
|
||||
memset(id->active_entries, 0, id->nr_areas * sizeof(int));
|
||||
|
|
@ -1675,6 +1692,7 @@ static void debug_flush(debug_info_t *id, int area)
|
|||
for (i = 0; i < id->pages_per_area; i++)
|
||||
memset(id->areas[area][i], 0, PAGE_SIZE);
|
||||
}
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ struct pai_mapptr {
|
|||
|
||||
static struct pai_root { /* Anchor to per CPU data */
|
||||
refcount_t refcnt; /* Overall active events */
|
||||
atomic_t tskctx; /* Overall per-task events */
|
||||
struct pai_mapptr __percpu *mapptr;
|
||||
} pai_root[PAI_PMU_MAX];
|
||||
|
||||
|
|
@ -93,14 +94,15 @@ struct pai_pmu { /* Define PAI PMU characteristics */
|
|||
static struct pai_pmu pai_pmu[]; /* Forward declaration */
|
||||
|
||||
/* Free per CPU data when the last event is removed. */
|
||||
static void pai_root_free(int idx)
|
||||
static void pai_root_free(int idx, int tasks)
|
||||
{
|
||||
if (refcount_dec_and_test(&pai_root[idx].refcnt)) {
|
||||
if (refcount_sub_and_test(tasks, &pai_root[idx].refcnt)) {
|
||||
free_percpu(pai_root[idx].mapptr);
|
||||
pai_root[idx].mapptr = NULL;
|
||||
}
|
||||
debug_sprintf_event(paidbg, 5, "%s root[%d].refcount %d\n", __func__,
|
||||
idx, refcount_read(&pai_root[idx].refcnt));
|
||||
debug_sprintf_event(paidbg, 5, "%s root[%d].refcount %d tskctx %d\n",
|
||||
__func__, idx, refcount_read(&pai_root[idx].refcnt),
|
||||
atomic_read(&pai_root[idx].tskctx));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -137,40 +139,54 @@ static void pai_free(struct pai_mapptr *mp)
|
|||
mp->mapptr = NULL;
|
||||
}
|
||||
|
||||
/* Adjust usage counters and remove allocated memory when all users are
|
||||
* gone.
|
||||
*/
|
||||
static void pai_event_destroy_cpu(struct perf_event *event, int cpu)
|
||||
/* Called under mutex_lock */
|
||||
static void pai_event_destroy_cpu(int idx, int cpu, bool hotplug)
|
||||
{
|
||||
int idx = PAI_PMU_IDX(event);
|
||||
struct pai_mapptr *mp = per_cpu_ptr(pai_root[idx].mapptr, cpu);
|
||||
struct pai_map *cpump = mp->mapptr;
|
||||
struct pai_mapptr *mp;
|
||||
struct pai_map *cpump;
|
||||
int tasks = 1;
|
||||
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
debug_sprintf_event(paidbg, 5, "%s event %#llx idx %d cpu %d users %d "
|
||||
"refcnt %u\n", __func__, event->attr.config, idx,
|
||||
event->cpu, cpump->active_events,
|
||||
refcount_read(&cpump->refcnt));
|
||||
if (refcount_dec_and_test(&cpump->refcnt))
|
||||
/* Check reference count and return when all gone.
|
||||
* 1. An event is installed on online CPU X.
|
||||
* 2. CPU x is offlined and the per-CPU data is removed.
|
||||
* 3. Event is destroyed via close system call.
|
||||
*/
|
||||
if (!refcount_read(&pai_root[idx].refcnt))
|
||||
return; /* No events at all */
|
||||
mp = per_cpu_ptr(pai_root[idx].mapptr, cpu);
|
||||
if (!mp || !mp->mapptr) /* No events on that CPU */
|
||||
return;
|
||||
|
||||
/* When hotplug is true, invocation is from CPU hotplug callback.
|
||||
* Delete per-CPU resource and adjust refcnt when per-task events
|
||||
* are currently active. This can be more than one.
|
||||
* In this case adjust counters.
|
||||
*/
|
||||
if (hotplug)
|
||||
tasks = atomic_read(&pai_root[idx].tskctx);
|
||||
|
||||
cpump = mp->mapptr;
|
||||
if (refcount_sub_and_test(tasks, &cpump->refcnt))
|
||||
pai_free(mp);
|
||||
pai_root_free(idx);
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
pai_root_free(idx, tasks);
|
||||
}
|
||||
|
||||
static void pai_event_destroy(struct perf_event *event)
|
||||
{
|
||||
int cpu;
|
||||
int cpu = 0, idx = PAI_PMU_IDX(event);
|
||||
|
||||
free_page(PAI_SAVE_AREA(event));
|
||||
cpus_read_lock();
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
if (event->cpu == -1) {
|
||||
struct cpumask *mask = PAI_CPU_MASK(event);
|
||||
|
||||
for_each_cpu(cpu, mask)
|
||||
pai_event_destroy_cpu(event, cpu);
|
||||
kfree(mask);
|
||||
atomic_dec(&pai_root[idx].tskctx);
|
||||
for_each_online_cpu(cpu)
|
||||
pai_event_destroy_cpu(idx, cpu, false);
|
||||
} else {
|
||||
pai_event_destroy_cpu(event, event->cpu);
|
||||
pai_event_destroy_cpu(idx, event->cpu, false);
|
||||
}
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
static void paicrypt_event_destroy(struct perf_event *event)
|
||||
|
|
@ -234,25 +250,30 @@ static u64 paicrypt_getall(struct perf_event *event)
|
|||
return sum;
|
||||
}
|
||||
|
||||
/* Check concurrent access of counting and sampling for crypto events.
|
||||
* This function is called in process context and it is save to block.
|
||||
* When the event initialization functions fails, no other call back will
|
||||
* be invoked.
|
||||
*
|
||||
* Allocate the memory for the event.
|
||||
*/
|
||||
static int pai_alloc_cpu(struct perf_event *event, int cpu)
|
||||
/* Called under mutex_lock */
|
||||
static int pai_alloc_cpu(int idx, int cpu, bool hotplug)
|
||||
{
|
||||
int rc, idx = PAI_PMU_IDX(event);
|
||||
struct pai_map *cpump = NULL;
|
||||
bool need_paiext_cb = false;
|
||||
struct pai_mapptr *mp;
|
||||
int tasks = 1, rc = 0;
|
||||
|
||||
/* When hotplug is true, invocation is from CPU hotplug callback.
|
||||
* Allocate per-CPU resource when per-task events are currently active.
|
||||
* This can be more than one. In this case adjust all reference
|
||||
* counters. Otherwise return, this ensures memory is only allocated
|
||||
* when needed.
|
||||
*/
|
||||
if (hotplug) {
|
||||
tasks = atomic_read(&pai_root[idx].tskctx);
|
||||
if (!tasks)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
/* Allocate root node */
|
||||
rc = pai_root_alloc(idx);
|
||||
if (rc)
|
||||
goto unlock;
|
||||
goto out;
|
||||
|
||||
/* Allocate node for this event */
|
||||
mp = per_cpu_ptr(pai_root[idx].mapptr, cpu);
|
||||
|
|
@ -296,28 +317,45 @@ static int pai_alloc_cpu(struct perf_event *event, int cpu)
|
|||
goto undo;
|
||||
}
|
||||
INIT_LIST_HEAD(&cpump->syswide_list);
|
||||
refcount_set(&cpump->refcnt, 1);
|
||||
refcount_set(&cpump->refcnt, tasks);
|
||||
rc = 0;
|
||||
} else {
|
||||
refcount_inc(&cpump->refcnt);
|
||||
refcount_add(tasks, &cpump->refcnt);
|
||||
}
|
||||
/* If tasks is greater than 1, we are called from CPU hotplug path
|
||||
* and need to adjust the pai_root[idx].refcnt by the number of
|
||||
* per-process events. Function pai_root_alloc(idx) already
|
||||
* incremented by one. Adjust for the rest.
|
||||
*/
|
||||
if (tasks > 1)
|
||||
refcount_add(tasks - 1, &pai_root[idx].refcnt);
|
||||
|
||||
undo:
|
||||
if (rc) {
|
||||
/* Error in allocation of event, decrement anchor. Since
|
||||
* the event in not created, its destroy() function is never
|
||||
* invoked. Adjust the reference counter for the anchor.
|
||||
* The failure happened in the case of variable
|
||||
* cpump == NULL branch above. The pai_root[XXX].refcnt has
|
||||
* been incremented by one. Then the per-CPU allocation
|
||||
* failed, so decrement it by one, regardless of tasks.
|
||||
*/
|
||||
pai_root_free(idx);
|
||||
pai_root_free(idx, 1);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
out:
|
||||
/* If rc is non-zero, no increment of counter/sampler was done. */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check concurrent access of counting and sampling for PAI events.
|
||||
* This function is called in process context and it is safe to block.
|
||||
* When the event initialization functions fails, no other call back will
|
||||
* be invoked.
|
||||
* Called under mutex_lock.
|
||||
*/
|
||||
static int pai_alloc(struct perf_event *event)
|
||||
{
|
||||
int idx = PAI_PMU_IDX(event);
|
||||
struct cpumask *maskptr;
|
||||
int cpu, rc = -ENOMEM;
|
||||
|
||||
|
|
@ -326,24 +364,20 @@ static int pai_alloc(struct perf_event *event)
|
|||
goto out;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
rc = pai_alloc_cpu(event, cpu);
|
||||
rc = pai_alloc_cpu(idx, cpu, false);
|
||||
if (rc) {
|
||||
for_each_cpu(cpu, maskptr)
|
||||
pai_event_destroy_cpu(event, cpu);
|
||||
kfree(maskptr);
|
||||
goto out;
|
||||
pai_event_destroy_cpu(idx, cpu, false);
|
||||
goto undo;
|
||||
}
|
||||
cpumask_set_cpu(cpu, maskptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* On error all cpumask are freed and all events have been destroyed.
|
||||
* Save of which CPUs data structures have been allocated for.
|
||||
* Release them in pai_event_destroy call back function
|
||||
* for this event.
|
||||
*/
|
||||
PAI_CPU_MASK(event) = maskptr;
|
||||
rc = 0;
|
||||
/* Trace per-task events for CPU hotplug. */
|
||||
atomic_inc(&pai_root[idx].tskctx);
|
||||
undo:
|
||||
kfree(maskptr);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -391,10 +425,14 @@ static int pai_event_init(struct perf_event *event, int idx)
|
|||
}
|
||||
}
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
if (event->cpu >= 0)
|
||||
rc = pai_alloc_cpu(event, event->cpu);
|
||||
rc = pai_alloc_cpu(idx, event->cpu, false);
|
||||
else
|
||||
rc = pai_alloc(event);
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
cpus_read_unlock();
|
||||
if (rc) {
|
||||
free_page(PAI_SAVE_AREA(event));
|
||||
goto out;
|
||||
|
|
@ -1239,8 +1277,35 @@ static int __init paipmu_setup(void)
|
|||
return install_ok;
|
||||
}
|
||||
|
||||
static int pai_online_cpu(unsigned int cpu)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
rc = pai_alloc_cpu(PAI_PMU_CRYPTO, cpu, true);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = pai_alloc_cpu(PAI_PMU_EXT, cpu, true);
|
||||
if (rc)
|
||||
pai_event_destroy_cpu(PAI_PMU_CRYPTO, cpu, true);
|
||||
out:
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pai_offline_cpu(unsigned int cpu)
|
||||
{
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
pai_event_destroy_cpu(PAI_PMU_CRYPTO, cpu, true);
|
||||
pai_event_destroy_cpu(PAI_PMU_EXT, cpu, true);
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init pai_init(void)
|
||||
{
|
||||
int state, rc;
|
||||
|
||||
/* Setup s390dbf facility */
|
||||
paidbg = debug_register("pai", 1, 1, 128);
|
||||
if (!paidbg) {
|
||||
|
|
@ -1249,13 +1314,24 @@ static int __init pai_init(void)
|
|||
}
|
||||
debug_register_view(paidbg, &debug_sprintf_view);
|
||||
|
||||
if (!paipmu_setup()) {
|
||||
/* No PMU registration, no need for debug buffer */
|
||||
debug_unregister_view(paidbg, &debug_sprintf_view);
|
||||
debug_unregister(paidbg);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* CPUHP_BP_PREPARE_DYN --> before CPU is brought online */
|
||||
state = cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "perf/pai:prepare",
|
||||
pai_online_cpu, pai_offline_cpu);
|
||||
rc = state < 0 ? state : 0;
|
||||
if (rc < 0)
|
||||
goto out_debug;
|
||||
|
||||
rc = -ENODEV;
|
||||
if (!paipmu_setup())
|
||||
goto out_cpuhp;
|
||||
return 0;
|
||||
|
||||
out_cpuhp:
|
||||
cpuhp_remove_state(state);
|
||||
out_debug:
|
||||
debug_unregister_view(paidbg, &debug_sprintf_view);
|
||||
debug_unregister(paidbg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
device_initcall(pai_init);
|
||||
|
|
|
|||
|
|
@ -982,6 +982,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_encrypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_encrypt_32way)
|
||||
|
|
@ -1007,6 +1008,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_decrypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_decrypt_32way)
|
||||
|
|
@ -1209,6 +1211,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_ctr_crypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %r10);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_ctr_crypt_32way)
|
||||
|
|
@ -1359,6 +1362,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfni_encrypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_gfni_encrypt_32way)
|
||||
|
|
@ -1384,6 +1388,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfni_decrypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_gfni_decrypt_32way)
|
||||
|
|
@ -1428,6 +1433,7 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfni_ctr_crypt_32way)
|
|||
%ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
|
||||
%ymm15, %r10);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_aesni_avx2_gfni_ctr_crypt_32way)
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_encrypt_64way)
|
|||
%zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14,
|
||||
%zmm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_gfni_avx512_encrypt_64way)
|
||||
|
|
@ -825,6 +826,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_decrypt_64way)
|
|||
%zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14,
|
||||
%zmm15, %rax);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_gfni_avx512_decrypt_64way)
|
||||
|
|
@ -966,6 +968,7 @@ SYM_TYPED_FUNC_START(aria_gfni_avx512_ctr_crypt_64way)
|
|||
%zmm9, %zmm8, %zmm11, %zmm10, %zmm12, %zmm13, %zmm14,
|
||||
%zmm15, %r10);
|
||||
|
||||
vzeroupper;
|
||||
FRAME_END
|
||||
RET;
|
||||
SYM_FUNC_END(aria_gfni_avx512_ctr_crypt_64way)
|
||||
|
|
|
|||
|
|
@ -3125,6 +3125,27 @@ static void intel_pmu_del_event(struct perf_event *event)
|
|||
this_cpu_ptr(&cpu_hw_events)->n_late_setup--;
|
||||
}
|
||||
|
||||
int __intel_pmu_quiesce(void)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
int pmu_enabled = cpuc->enabled;
|
||||
|
||||
cpuc->enabled = 0;
|
||||
if (pmu_enabled)
|
||||
intel_pmu_disable_all();
|
||||
|
||||
return pmu_enabled;
|
||||
}
|
||||
|
||||
void __intel_pmu_resume(int pmu_enabled)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
|
||||
cpuc->enabled = pmu_enabled;
|
||||
if (pmu_enabled)
|
||||
intel_pmu_enable_all(0);
|
||||
}
|
||||
|
||||
static int icl_set_topdown_event_period(struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
|
|
@ -3316,16 +3337,13 @@ static void intel_pmu_read_event(struct perf_event *event)
|
|||
if (event->hw.flags & (PERF_X86_EVENT_AUTO_RELOAD | PERF_X86_EVENT_TOPDOWN) ||
|
||||
is_pebs_counter_event_group(event)) {
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
bool pmu_enabled = cpuc->enabled;
|
||||
int pmu_enabled;
|
||||
|
||||
/* Only need to call update_topdown_event() once for group read. */
|
||||
if (is_metric_event(event) && (cpuc->txn_flags & PERF_PMU_TXN_READ))
|
||||
return;
|
||||
|
||||
cpuc->enabled = 0;
|
||||
if (pmu_enabled)
|
||||
intel_pmu_disable_all();
|
||||
|
||||
pmu_enabled = __intel_pmu_quiesce();
|
||||
/*
|
||||
* If the PEBS counters snapshotting is enabled,
|
||||
* the topdown event is available in PEBS records.
|
||||
|
|
@ -3334,10 +3352,7 @@ static void intel_pmu_read_event(struct perf_event *event)
|
|||
static_call(intel_pmu_update_topdown_event)(event, NULL);
|
||||
else
|
||||
intel_pmu_drain_pebs_buffer();
|
||||
|
||||
cpuc->enabled = pmu_enabled;
|
||||
if (pmu_enabled)
|
||||
intel_pmu_enable_all(0);
|
||||
__intel_pmu_resume(pmu_enabled);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1242,8 +1242,11 @@ int intel_pmu_drain_bts_buffer(void)
|
|||
|
||||
void intel_pmu_drain_pebs_buffer(void)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
||||
struct perf_sample_data data;
|
||||
|
||||
WARN_ON_ONCE(cpuc->enabled);
|
||||
|
||||
static_call(x86_pmu_drain_pebs)(NULL, &data);
|
||||
}
|
||||
|
||||
|
|
@ -1864,8 +1867,11 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
|
|||
static inline void intel_pmu_drain_large_pebs(struct cpu_hw_events *cpuc)
|
||||
{
|
||||
if (cpuc->n_pebs == cpuc->n_large_pebs &&
|
||||
cpuc->n_pebs != cpuc->n_pebs_via_pt)
|
||||
cpuc->n_pebs != cpuc->n_pebs_via_pt) {
|
||||
int enabled = __intel_pmu_quiesce();
|
||||
intel_pmu_drain_pebs_buffer();
|
||||
__intel_pmu_resume(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static void __intel_pmu_pebs_enable(struct perf_event *event)
|
||||
|
|
@ -2432,7 +2438,7 @@ static inline void __setup_pebs_basic_group(struct perf_event *event,
|
|||
{
|
||||
/* The ip in basic is EventingIP */
|
||||
set_linear_ip(regs, ip);
|
||||
regs->flags = PERF_EFLAGS_EXACT;
|
||||
regs->flags |= PERF_EFLAGS_EXACT;
|
||||
setup_pebs_time(event, data, tsc);
|
||||
|
||||
if (sample_type & PERF_SAMPLE_WEIGHT_STRUCT)
|
||||
|
|
@ -2444,9 +2450,17 @@ static inline void __setup_pebs_gpr_group(struct perf_event *event,
|
|||
struct pebs_gprs *gprs,
|
||||
u64 sample_type)
|
||||
{
|
||||
/*
|
||||
* Update flags with PEBS data. PERF_EFLAGS_EXACT must be set
|
||||
* in previous basic group handling.
|
||||
*/
|
||||
regs->flags = gprs->flags | PERF_EFLAGS_EXACT;
|
||||
|
||||
if (event->attr.precise_ip < 2) {
|
||||
set_linear_ip(regs, gprs->ip);
|
||||
regs->flags &= ~PERF_EFLAGS_EXACT;
|
||||
} else if (regs->flags & X86_VM_MASK) {
|
||||
regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK);
|
||||
}
|
||||
|
||||
if (sample_type & (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER))
|
||||
|
|
|
|||
|
|
@ -1638,6 +1638,9 @@ static __always_inline void __intel_pmu_lbr_disable(void)
|
|||
wrmsrq(MSR_IA32_DEBUGCTLMSR, debugctl);
|
||||
}
|
||||
|
||||
extern int __intel_pmu_quiesce(void);
|
||||
extern void __intel_pmu_resume(int pmu_enabled);
|
||||
|
||||
int intel_pmu_save_and_restart(struct perf_event *event);
|
||||
|
||||
struct event_constraint *
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ static struct pci_dev **amd_roots;
|
|||
|
||||
/* Protect the PCI config register pairs used for SMN. */
|
||||
static DEFINE_MUTEX(smn_mutex);
|
||||
static bool smn_exclusive;
|
||||
|
||||
#define SMN_INDEX_OFFSET 0x60
|
||||
#define SMN_DATA_OFFSET 0x64
|
||||
|
|
@ -91,11 +90,16 @@ static int __amd_smn_rw(u8 i_off, u8 d_off, u16 node, u32 address, u32 *value, b
|
|||
if (node >= amd_num_nodes())
|
||||
return err;
|
||||
|
||||
root = amd_roots[node];
|
||||
if (!root)
|
||||
/*
|
||||
* Uninitialized amd_roots indicates pci_request_config_region_exclusive()
|
||||
* didn't run or failed and thus the kernel cannot rely on having
|
||||
* exclusive access to SMN registers so prevent that.
|
||||
*/
|
||||
if (!amd_roots)
|
||||
return err;
|
||||
|
||||
if (!smn_exclusive)
|
||||
root = amd_roots[node];
|
||||
if (!root)
|
||||
return err;
|
||||
|
||||
guard(mutex)(&smn_mutex);
|
||||
|
|
@ -287,6 +291,11 @@ static int __init amd_smn_init(void)
|
|||
return -ENOMEM;
|
||||
|
||||
roots_per_node = num_roots / num_nodes;
|
||||
if (!roots_per_node) {
|
||||
if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
|
||||
pr_warn(FW_BUG "Error detecting roots per node.\n");
|
||||
roots_per_node = 1;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
node = 0;
|
||||
|
|
@ -308,8 +317,6 @@ static int __init amd_smn_init(void)
|
|||
debugfs_create_file("value", 0600, debugfs_dir, NULL, &smn_value_fops);
|
||||
}
|
||||
|
||||
smn_exclusive = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -865,7 +865,7 @@ static void amd_deferred_error_interrupt(void)
|
|||
|
||||
void mce_amd_handle_storm(unsigned int bank, bool on)
|
||||
{
|
||||
threshold_restart_bank(bank, on);
|
||||
threshold_restart_bank(bank, !on);
|
||||
}
|
||||
|
||||
static void amd_reset_thr_limit(unsigned int bank)
|
||||
|
|
|
|||
|
|
@ -525,6 +525,23 @@ static int __send_request(struct request *req)
|
|||
err = __vdc_tx_trigger(port);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err);
|
||||
/*
|
||||
* If the port was reset (-ENOTCONN), the dring and the
|
||||
* LDC channel including all of its mappings are already
|
||||
* torn down and reallocated - there is nothing to undo
|
||||
* and @desc must not be touched.
|
||||
*
|
||||
* For any other failure the descriptor was never handed
|
||||
* to the peer: unmap the cookies and free the descriptor
|
||||
* again, so that a later retry of the request does not
|
||||
* leak LDC map table entries.
|
||||
*/
|
||||
if (err != -ENOTCONN) {
|
||||
ldc_unmap(port->vio.lp, desc->cookies,
|
||||
desc->ncookies);
|
||||
desc->hdr.state = VIO_DESC_FREE;
|
||||
rqe->req = NULL;
|
||||
}
|
||||
} else {
|
||||
port->req_id++;
|
||||
dr->prod = vio_dring_next(dr, dr->prod);
|
||||
|
|
@ -539,6 +556,7 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
struct vdc_port *port = hctx->queue->queuedata;
|
||||
struct vio_dring_state *dr;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dr = &port->vio.drings[VIO_DRIVER_TX_RING];
|
||||
|
||||
|
|
@ -560,7 +578,13 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
return BLK_STS_DEV_RESOURCE;
|
||||
}
|
||||
|
||||
if (__send_request(bd->rq) < 0) {
|
||||
ret = __send_request(bd->rq);
|
||||
if (ret == -EAGAIN) {
|
||||
spin_unlock_irqrestore(&port->vio.lock, flags);
|
||||
/* already spun for 10msec, defer 10msec and retry */
|
||||
blk_mq_delay_kick_requeue_list(hctx->queue, 10);
|
||||
return BLK_STS_DEV_RESOURCE;
|
||||
} else if (ret < 0) {
|
||||
spin_unlock_irqrestore(&port->vio.lock, flags);
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3030,6 +3030,7 @@ static void ublk_queue_reset_io_flags(struct ublk_queue *ubq)
|
|||
ubq->canceling = false;
|
||||
spin_unlock(&ubq->cancel_lock);
|
||||
ubq->fail_io = false;
|
||||
ubq->force_abort = false;
|
||||
}
|
||||
|
||||
/* device can only be started after all IOs are ready */
|
||||
|
|
|
|||
|
|
@ -1099,7 +1099,7 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
|
|||
|
||||
urbd0 = &txq->urbd0s[cr_tia];
|
||||
|
||||
if (urbd0->tfd_index > txq->count)
|
||||
if (urbd0->tfd_index >= txq->count)
|
||||
return;
|
||||
|
||||
cr_tia = (cr_tia + 1) % txq->count;
|
||||
|
|
@ -1599,7 +1599,9 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status
|
|||
rfh_hdr = buf;
|
||||
|
||||
len = rfh_hdr->packet_len;
|
||||
if (len <= 0) {
|
||||
if (len == 0 || len > BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr)) {
|
||||
bt_dev_err(data->hdev, "Invalid packet_len %d (max %zu)", len,
|
||||
BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr));
|
||||
ret = -EINVAL;
|
||||
goto resubmit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1374,16 +1374,6 @@ int btmtk_usb_setup(struct hci_dev *hdev)
|
|||
break;
|
||||
case 0x7922:
|
||||
case 0x7925:
|
||||
/*
|
||||
* A remote wakeup could cause the device completely unresponsive, and
|
||||
* recovering from such a state needs a power cycle.
|
||||
*
|
||||
* Since the remote wakeup capability is super broken, just disable it
|
||||
* to get rid of the troubles. The device can still be autosuspended
|
||||
* when the bluetooth interface is closed.
|
||||
*/
|
||||
device_set_wakeup_capable(&btmtk_data->udev->dev, false);
|
||||
fallthrough;
|
||||
case 0x7961:
|
||||
case 0x7902:
|
||||
case 0x6639:
|
||||
|
|
@ -1587,5 +1577,6 @@ MODULE_FIRMWARE(FIRMWARE_MT7663);
|
|||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7922);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7961);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7920);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7925);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7927);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"
|
||||
#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"
|
||||
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
|
||||
#define FIRMWARE_MT7920 "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin"
|
||||
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
|
||||
#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,10 @@ static int btqcomsmd_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
hci_free_dev:
|
||||
rpmsg_destroy_ept(btq->cmd_channel);
|
||||
rpmsg_destroy_ept(btq->acl_channel);
|
||||
hci_free_dev(hdev);
|
||||
return ret;
|
||||
destroy_cmd_channel:
|
||||
rpmsg_destroy_ept(btq->cmd_channel);
|
||||
destroy_acl_channel:
|
||||
|
|
@ -202,10 +205,11 @@ static void btqcomsmd_remove(struct platform_device *pdev)
|
|||
struct btqcomsmd *btq = platform_get_drvdata(pdev);
|
||||
|
||||
hci_unregister_dev(btq->hdev);
|
||||
hci_free_dev(btq->hdev);
|
||||
|
||||
rpmsg_destroy_ept(btq->cmd_channel);
|
||||
rpmsg_destroy_ept(btq->acl_channel);
|
||||
|
||||
hci_free_dev(btq->hdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id btqcomsmd_of_match[] = {
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
|
|||
* headers.
|
||||
*/
|
||||
if (!key_id)
|
||||
break;
|
||||
continue;
|
||||
rc = btrtl_parse_section(hdev, btrtl_dev, opcode,
|
||||
ptr, section_len);
|
||||
break;
|
||||
|
|
@ -600,8 +600,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
|
|||
ptr, section_len);
|
||||
break;
|
||||
default:
|
||||
rc = 0;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (rc < 0) {
|
||||
rtl_dev_err(hdev, "RTL: Parse section (%u) err %d",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
*/
|
||||
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
|
@ -980,6 +981,8 @@ struct btqca_data {
|
|||
#define BTUSB_USE_ALT3_FOR_WBS 15
|
||||
#define BTUSB_ALT6_CONTINUOUS_TX 16
|
||||
#define BTUSB_HW_SSR_ACTIVE 17
|
||||
#define BTUSB_WAKEUP_BROKEN 18
|
||||
#define BTUSB_RESET 19
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
|
|
@ -1054,13 +1057,15 @@ static void btusb_reset(struct hci_dev *hdev)
|
|||
int err;
|
||||
|
||||
data = hci_get_drvdata(hdev);
|
||||
/* This is not an unbalanced PM reference since the device will reset */
|
||||
err = usb_autopm_get_interface(data->intf);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(BTUSB_RESET, &data->flags))
|
||||
usb_autopm_put_interface_no_suspend(data->intf);
|
||||
|
||||
bt_dev_err(hdev, "Resetting usb device.");
|
||||
usb_queue_reset_device(data->intf);
|
||||
}
|
||||
|
|
@ -2092,18 +2097,24 @@ static int btusb_close(struct hci_dev *hdev)
|
|||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
cancel_delayed_work(&data->rx_work);
|
||||
cancel_work_sync(&data->work);
|
||||
cancel_work_sync(&data->waker);
|
||||
|
||||
skb_queue_purge(&data->acl_q);
|
||||
|
||||
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
|
||||
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
|
||||
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
||||
clear_bit(BTUSB_DIAG_RUNNING, &data->flags);
|
||||
|
||||
btusb_stop_traffic(data);
|
||||
|
||||
/* rx_work must only be canceled once the URBs that can rearm it are
|
||||
* gone, and it must be canceled synchronously since btusb_disconnect()
|
||||
* frees the btusb_data it dereferences right after hci_unregister_dev().
|
||||
*/
|
||||
cancel_delayed_work_sync(&data->rx_work);
|
||||
|
||||
skb_queue_purge(&data->acl_q);
|
||||
|
||||
btusb_free_frags(data);
|
||||
|
||||
err = usb_autopm_get_interface(data->intf);
|
||||
|
|
@ -2129,7 +2140,7 @@ static int btusb_flush(struct hci_dev *hdev)
|
|||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
cancel_delayed_work(&data->rx_work);
|
||||
cancel_delayed_work_sync(&data->rx_work);
|
||||
|
||||
skb_queue_purge(&data->acl_q);
|
||||
|
||||
|
|
@ -2923,8 +2934,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
|
|||
}
|
||||
|
||||
err = usb_autopm_get_interface(data->intf);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
|
||||
clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Release MediaTek ISO data interface */
|
||||
btusb_mtk_release_iso_intf(hdev);
|
||||
|
|
@ -2946,6 +2960,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
|
|||
|
||||
err = btmtk_usb_subsys_reset(hdev, btmtk_data->dev_id);
|
||||
|
||||
if (test_and_set_bit(BTUSB_RESET, &data->flags)) {
|
||||
bt_dev_err(hdev, "last usb reset failed? Resetting again");
|
||||
usb_autopm_put_interface_no_suspend(data->intf);
|
||||
}
|
||||
|
||||
usb_queue_reset_device(data->intf);
|
||||
clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
|
||||
|
||||
|
|
@ -2969,10 +2988,25 @@ static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool platform_is_ryzen(void)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
return boot_cpu_has(X86_FEATURE_ZEN);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool is_direct_child_of_root_hub(struct usb_device *udev)
|
||||
{
|
||||
return udev->parent == udev->bus->root_hub;
|
||||
}
|
||||
|
||||
static int btusb_mtk_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
||||
int err;
|
||||
|
||||
/* MediaTek WMT vendor cmd requiring below USB resources to
|
||||
* complete the handshake.
|
||||
|
|
@ -2989,7 +3023,40 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
|||
btusb_mtk_claim_iso_intf(data);
|
||||
}
|
||||
|
||||
return btmtk_usb_setup(hdev);
|
||||
err = btmtk_usb_setup(hdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (btmtk_data->dev_id) {
|
||||
case 0x7922:
|
||||
case 0x7925:
|
||||
/*
|
||||
* All reports seen to be relevant to Ryzen-based laptops. These
|
||||
* NICs are usually used as OEM components thanks to some sort
|
||||
* of reference designs.
|
||||
*
|
||||
* Their popularity on other platforms is unclear. While there
|
||||
* is still a chance that the quirk may exist on other
|
||||
* platforms, be cautious and only apply the quirk to direct
|
||||
* children of Ryzen platforms's root hubs for the time being.
|
||||
*
|
||||
* In most cases the root hub is on the SoC or PCH, which needs
|
||||
* the quirk. Unfortunately, this can't distinguish root hubs on
|
||||
* PCIe add-in cards. Such roughness should be acceptable, as
|
||||
* PCIe USB controller add-in cards are less commonly used
|
||||
* nowadays. On the other hand, applying the quirk doesn't hurt
|
||||
* any functionalities either, as the device can still be used
|
||||
* as a wakeup source if desired.
|
||||
*
|
||||
* Theoretically, we could retrieve the root hub's PCI vendor ID
|
||||
* with some hierarchy magic, but that's too intrusive...
|
||||
*/
|
||||
if (platform_is_ryzen() && is_direct_child_of_root_hub(data->udev))
|
||||
set_bit(BTUSB_WAKEUP_BROKEN, &data->flags);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_mtk_shutdown(struct hci_dev *hdev)
|
||||
|
|
@ -4540,6 +4607,9 @@ static void btusb_disconnect(struct usb_interface *intf)
|
|||
if (data->reset_gpio)
|
||||
gpiod_put(data->reset_gpio);
|
||||
|
||||
if (test_and_clear_bit(BTUSB_RESET, &data->flags))
|
||||
usb_autopm_put_interface_no_suspend(data->intf);
|
||||
|
||||
if (intf == data->intf) {
|
||||
if (data->isoc)
|
||||
usb_driver_release_interface(&btusb_driver, data->isoc);
|
||||
|
|
@ -4565,11 +4635,26 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
|
||||
BT_DBG("intf %p", intf);
|
||||
|
||||
/* Don't auto-suspend if there are connections or discovery in
|
||||
* progress; external suspend calls shall never fail.
|
||||
/*
|
||||
* It is reported that remote wakeup events could sometimes cause some
|
||||
* adapters completely unresponsive. Resetting the xHCI root hub doesn't
|
||||
* help at all, and recovering from such a state needs a power cycle.
|
||||
* Since disabling remote wakeup simply causes the USB core to gate
|
||||
* runtime autosuspend as well due to needs_remote_wakeup == 1, let's do
|
||||
* this ourselves to make our life easier. The interface can be safely
|
||||
* autosuspended as long as remote wakeup is disabled, i.e., after
|
||||
* closing the HCI device.
|
||||
*
|
||||
* Don't auto-suspend if there are connections or discovery in progress.
|
||||
*
|
||||
* External suspend calls shall never fail. Specifically, a device with
|
||||
* broken remote wakeup may still take the advantage of remote wakeup in
|
||||
* order to wake up the system from sleep if userspace has enabled it as
|
||||
* a wakeup source.
|
||||
*/
|
||||
if (PMSG_IS_AUTO(message) &&
|
||||
(hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
|
||||
((test_bit(BTUSB_WAKEUP_BROKEN, &data->flags) && data->intf->needs_remote_wakeup) ||
|
||||
hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
|
||||
return -EBUSY;
|
||||
|
||||
if (data->suspend_count++)
|
||||
|
|
|
|||
|
|
@ -1964,13 +1964,28 @@ static const struct file_operations portdev_fops = {
|
|||
static void remove_vqs(struct ports_device *portdev)
|
||||
{
|
||||
struct virtqueue *vq;
|
||||
bool multiport = use_multiport(portdev);
|
||||
|
||||
virtio_device_for_each_vq(portdev->vdev, vq) {
|
||||
struct port_buffer *buf;
|
||||
unsigned int len;
|
||||
|
||||
flush_bufs(vq, true);
|
||||
while ((buf = virtqueue_detach_unused_buf(vq)))
|
||||
free_buf(buf, true);
|
||||
/*
|
||||
* c_ovq cookies are &portdev->cpkt, not port_buffer.
|
||||
* Detach them but do not free_buf().
|
||||
*/
|
||||
if (multiport && vq == portdev->c_ovq) {
|
||||
spin_lock(&portdev->c_ovq_lock);
|
||||
while (virtqueue_get_buf(vq, &len))
|
||||
;
|
||||
while (virtqueue_detach_unused_buf(vq))
|
||||
;
|
||||
spin_unlock(&portdev->c_ovq_lock);
|
||||
} else {
|
||||
flush_bufs(vq, true);
|
||||
while ((buf = virtqueue_detach_unused_buf(vq)))
|
||||
free_buf(buf, true);
|
||||
}
|
||||
cond_resched();
|
||||
}
|
||||
portdev->vdev->config->del_vqs(portdev->vdev);
|
||||
|
|
|
|||
|
|
@ -1249,7 +1249,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
if (!policy)
|
||||
return NULL;
|
||||
|
||||
if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
|
||||
if (!zalloc_cpumask_var(&policy->cpus, GFP_KERNEL))
|
||||
goto err_free_policy;
|
||||
|
||||
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
|
||||
|
|
@ -1258,6 +1258,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
|
||||
goto err_free_rcpumask;
|
||||
|
||||
init_rwsem(&policy->rwsem);
|
||||
|
||||
init_completion(&policy->kobj_unregister);
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
|
||||
cpufreq_global_kobject, "policy%u", cpu);
|
||||
|
|
@ -1272,8 +1274,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
goto err_free_real_cpus;
|
||||
}
|
||||
|
||||
init_rwsem(&policy->rwsem);
|
||||
|
||||
freq_constraints_init(&policy->constraints);
|
||||
|
||||
policy->nb_min.notifier_call = cpufreq_notifier_min;
|
||||
|
|
|
|||
|
|
@ -251,13 +251,19 @@ static int __init dibs_init(void)
|
|||
|
||||
rc = class_register(&dibs_class);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err;
|
||||
|
||||
rc = dibs_loopback_init();
|
||||
if (rc)
|
||||
pr_err("%s fails with %d\n", __func__, rc);
|
||||
goto err_unregister;
|
||||
|
||||
return rc;
|
||||
|
||||
err_unregister:
|
||||
class_unregister(&dibs_class);
|
||||
err:
|
||||
pr_err("%s fails with %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit dibs_exit(void)
|
||||
|
|
|
|||
|
|
@ -1534,7 +1534,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
altdev = dci->pvt_info;
|
||||
*altdev = *device;
|
||||
|
||||
if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL))
|
||||
if (!devres_open_group(device->edac->dev, altr_portb_setup, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Update PortB specific values */
|
||||
|
|
@ -1562,7 +1562,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
rc = -ENODEV;
|
||||
goto err_release_group_1;
|
||||
}
|
||||
rc = devm_request_irq(&altdev->ddev, altdev->sb_irq,
|
||||
rc = devm_request_irq(device->edac->dev, altdev->sb_irq,
|
||||
prv->ecc_irq_handler, IRQF_TRIGGER_HIGH,
|
||||
ecc_name, altdev);
|
||||
if (rc) {
|
||||
|
|
@ -1584,7 +1584,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
rc = -ENODEV;
|
||||
goto err_release_group_1;
|
||||
}
|
||||
rc = devm_request_irq(&altdev->ddev, altdev->db_irq,
|
||||
rc = devm_request_irq(device->edac->dev, altdev->db_irq,
|
||||
prv->ecc_irq_handler, IRQF_TRIGGER_HIGH,
|
||||
ecc_name, altdev);
|
||||
if (rc) {
|
||||
|
|
@ -1604,13 +1604,13 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
|
|||
|
||||
list_add(&altdev->next, &altdev->edac->a10_ecc_devices);
|
||||
|
||||
devres_remove_group(&altdev->ddev, altr_portb_setup);
|
||||
devres_remove_group(device->edac->dev, altr_portb_setup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_release_group_1:
|
||||
edac_device_free_ctl_info(dci);
|
||||
devres_release_group(&altdev->ddev, altr_portb_setup);
|
||||
devres_release_group(device->edac->dev, altr_portb_setup);
|
||||
edac_printk(KERN_ERR, EDAC_DEVICE,
|
||||
"%s:Error setting up EDAC device: %d\n", ecc_name, rc);
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -1701,9 +1701,8 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m)
|
|||
if (dma_resv_trylock(bo->tbo.base.resv)) {
|
||||
dma_resv_describe(bo->tbo.base.resv, m);
|
||||
dma_resv_unlock(bo->tbo.base.resv);
|
||||
} else {
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
seq_puts(m, "\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,6 +191,8 @@ amdgpu_ttm_job_submit(struct amdgpu_device *adev, struct amdgpu_ttm_buffer_entit
|
|||
* @tmz: if we should setup a TMZ enabled mapping
|
||||
* @size: in number of bytes to map, out number of bytes mapped
|
||||
* @addr: resulting address inside the MC address space
|
||||
* @vm_needs_flush: out, set true if a GART window was programmed (VMID 0 flush
|
||||
* needed) or false for a direct address
|
||||
*
|
||||
* Setup one of the GART windows to access a specific piece of memory or return
|
||||
* the physical address for local memory.
|
||||
|
|
@ -200,7 +202,8 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity,
|
|||
struct ttm_resource *mem,
|
||||
struct amdgpu_res_cursor *mm_cur,
|
||||
unsigned int window,
|
||||
bool tmz, uint64_t *size, uint64_t *addr)
|
||||
bool tmz, uint64_t *size, uint64_t *addr,
|
||||
bool *vm_needs_flush)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
|
||||
unsigned int offset, num_pages, num_dw, num_bytes;
|
||||
|
|
@ -221,9 +224,12 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity,
|
|||
if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
|
||||
*addr = amdgpu_ttm_domain_start(adev, mem->mem_type) +
|
||||
mm_cur->start;
|
||||
*vm_needs_flush = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A GART window is programmed below, so its VMID 0 TLB needs a flush */
|
||||
*vm_needs_flush = true;
|
||||
|
||||
/*
|
||||
* If start begins at an offset inside the page, then adjust the size
|
||||
|
|
@ -324,6 +330,7 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
while (src_mm.remaining) {
|
||||
uint64_t from, to, cur_size, tiling_flags;
|
||||
uint32_t num_type, data_format, max_com, write_compress_disable;
|
||||
bool src_vm_flush, dst_vm_flush;
|
||||
struct dma_fence *next;
|
||||
|
||||
/* Never copy more than 256MiB at once to avoid a timeout */
|
||||
|
|
@ -331,12 +338,12 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
|
||||
/* Map src to window 0 and dst to window 1. */
|
||||
r = amdgpu_ttm_map_buffer(entity, src->bo, src->mem, &src_mm,
|
||||
0, tmz, &cur_size, &from);
|
||||
0, tmz, &cur_size, &from, &src_vm_flush);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
r = amdgpu_ttm_map_buffer(entity, dst->bo, dst->mem, &dst_mm,
|
||||
1, tmz, &cur_size, &to);
|
||||
1, tmz, &cur_size, &to, &dst_vm_flush);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
|
@ -364,7 +371,7 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
r = amdgpu_copy_buffer(adev, entity, from, to, cur_size, resv,
|
||||
&next, true, copy_flags);
|
||||
&next, src_vm_flush || dst_vm_flush, copy_flags);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
|
@ -2624,6 +2631,7 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_ttm_buffer_entity *entity,
|
|||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
struct dma_fence *fence = NULL;
|
||||
struct amdgpu_res_cursor dst;
|
||||
bool vm_needs_flush = false;
|
||||
int r;
|
||||
|
||||
if (!entity)
|
||||
|
|
@ -2645,13 +2653,13 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_ttm_buffer_entity *entity,
|
|||
cur_size = min(dst.size, 256ULL << 20);
|
||||
|
||||
r = amdgpu_ttm_map_buffer(entity, &bo->tbo, bo->tbo.resource, &dst,
|
||||
0, false, &cur_size, &to);
|
||||
0, false, &cur_size, &to, &vm_needs_flush);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
r = amdgpu_ttm_fill_mem(adev, entity,
|
||||
0, to, cur_size, resv,
|
||||
&next, true, k_job_id);
|
||||
&next, vm_needs_flush, k_job_id);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
|
|
|||
|
|
@ -747,9 +747,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
|
|||
}
|
||||
if (adev->dm.dc->caps.max_links > 0) {
|
||||
adev->dm.hdmi_frl_status_polling_wq =
|
||||
create_singlethread_workqueue("hdmi_frl_status_polling_workqueue");
|
||||
create_singlethread_workqueue("hdmi_frl_status_polling_wq");
|
||||
if (!adev->dm.hdmi_frl_status_polling_wq)
|
||||
drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n");
|
||||
drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_wq\n");
|
||||
}
|
||||
if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
|
||||
init_completion(&adev->dm.dmub_aux_transfer_done);
|
||||
|
|
@ -1972,6 +1972,10 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
|
|||
/* On resume we need to rewrite the MSTM control bits to enable MST*/
|
||||
s3_handle_mst(ddev, false);
|
||||
|
||||
/* Exit IPS before the detection loop's first AUX/DDC access. */
|
||||
scoped_guard(mutex, &dm->dc_lock)
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
|
||||
/* Do detection*/
|
||||
drm_connector_list_iter_begin(ddev, &iter);
|
||||
drm_for_each_connector_iter(connector, &iter) {
|
||||
|
|
|
|||
|
|
@ -756,10 +756,14 @@ amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
|
|||
break;
|
||||
case DRM_MODE_COLORIMETRY_BT2020_RGB:
|
||||
case DRM_MODE_COLORIMETRY_BT2020_YCC:
|
||||
if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
|
||||
color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
|
||||
else
|
||||
if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
|
||||
if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
|
||||
color_space = COLOR_SPACE_2020_RGB_LIMITEDRANGE;
|
||||
else
|
||||
color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
|
||||
} else {
|
||||
color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
|
||||
}
|
||||
break;
|
||||
case DRM_MODE_COLORIMETRY_DEFAULT: /* ITU601 */
|
||||
default:
|
||||
|
|
@ -3937,17 +3941,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
|||
}
|
||||
|
||||
/* Handle MCCS */
|
||||
if (do_mccs)
|
||||
if (do_mccs) {
|
||||
dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
|
||||
if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||
as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) &&
|
||||
(!sink->edid_caps.freesync_vcp_code ||
|
||||
(sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)))
|
||||
freesync_capable = false;
|
||||
if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)
|
||||
freesync_capable = false;
|
||||
|
||||
if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable)
|
||||
dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
if (sink->mccs_caps.freesync_supported && freesync_capable)
|
||||
dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
}
|
||||
|
||||
update:
|
||||
if (dm_con_state)
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
|
|||
char *rd_buf_ptr = NULL;
|
||||
const uint32_t rd_buf_size = 100;
|
||||
uint32_t result = 0;
|
||||
uint8_t str_len = 0;
|
||||
int r;
|
||||
|
||||
if (*pos & 3 || size & 3)
|
||||
|
|
@ -208,29 +207,26 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
|
|||
|
||||
rd_buf_ptr = rd_buf;
|
||||
|
||||
str_len = strlen("Current: %d 0x%x %d ");
|
||||
snprintf(rd_buf_ptr, str_len, "Current: %d 0x%x %d ",
|
||||
rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf),
|
||||
"Current: %d 0x%x %d ",
|
||||
link->cur_link_settings.lane_count,
|
||||
link->cur_link_settings.link_rate,
|
||||
link->cur_link_settings.link_spread);
|
||||
rd_buf_ptr += str_len;
|
||||
|
||||
str_len = strlen("Verified: %d 0x%x %d ");
|
||||
snprintf(rd_buf_ptr, str_len, "Verified: %d 0x%x %d ",
|
||||
rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf),
|
||||
"Verified: %d 0x%x %d ",
|
||||
link->verified_link_cap.lane_count,
|
||||
link->verified_link_cap.link_rate,
|
||||
link->verified_link_cap.link_spread);
|
||||
rd_buf_ptr += str_len;
|
||||
|
||||
str_len = strlen("Reported: %d 0x%x %d ");
|
||||
snprintf(rd_buf_ptr, str_len, "Reported: %d 0x%x %d ",
|
||||
rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf),
|
||||
"Reported: %d 0x%x %d ",
|
||||
link->reported_link_cap.lane_count,
|
||||
link->reported_link_cap.link_rate,
|
||||
link->reported_link_cap.link_spread);
|
||||
rd_buf_ptr += str_len;
|
||||
|
||||
str_len = strlen("Preferred: %d 0x%x %d ");
|
||||
snprintf(rd_buf_ptr, str_len, "Preferred: %d 0x%x %d\n",
|
||||
rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf),
|
||||
"Preferred: %d 0x%x %d\n",
|
||||
link->preferred_link_setting.lane_count,
|
||||
link->preferred_link_setting.link_rate,
|
||||
link->preferred_link_setting.link_spread);
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
|
|||
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
|
||||
|
||||
if (edid_caps->edid_hdmi) {
|
||||
edid_caps->qs_bit = connector->display_info.rgb_quant_range_selectable;
|
||||
populate_hdmi_info_from_connector(link->dc->config.enable_frl, &connector->display_info.hdmi, edid_caps);
|
||||
drm_dbg_driver(connector->dev, "%s: HDMI_FRL [%s] max_frl_rate %d\n", __func__, connector->name, edid_caps->max_frl_rate);
|
||||
if (edid_caps->frl_dsc_support)
|
||||
|
|
@ -1202,9 +1203,10 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd
|
|||
edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes, hdmi->max_frl_rate_per_lane);
|
||||
edid_caps->frl_dsc_support = hdmi->dsc_cap.v_1p2;
|
||||
if (edid_caps->frl_dsc_support) {
|
||||
if (hdmi->dsc_cap.bpc_supported == 10)
|
||||
/* HF-VSDB DSC max bpc is cumulative: >=12 implies 10 and 8. */
|
||||
if (hdmi->dsc_cap.bpc_supported >= 10)
|
||||
edid_caps->frl_dsc_10bpc = true;
|
||||
else if (hdmi->dsc_cap.bpc_supported == 12)
|
||||
if (hdmi->dsc_cap.bpc_supported >= 12)
|
||||
edid_caps->frl_dsc_12bpc = true;
|
||||
edid_caps->frl_dsc_all_bpp = hdmi->dsc_cap.all_bpp;
|
||||
edid_caps->frl_dsc_native_420 = hdmi->dsc_cap.native_420;
|
||||
|
|
|
|||
|
|
@ -567,6 +567,23 @@ static void dm_test_output_color_space_bt2020_rgb(struct kunit *test)
|
|||
(int)COLOR_SPACE_2020_RGB_FULLRANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_output_color_space_bt2020_rgb_limited - Test limited BT.2020 RGB
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_output_color_space_bt2020_rgb_limited(struct kunit *test)
|
||||
{
|
||||
struct dc_crtc_timing timing = {};
|
||||
struct drm_connector_state state = {};
|
||||
|
||||
timing.pixel_encoding = PIXEL_ENCODING_RGB;
|
||||
state.colorspace = DRM_MODE_COLORIMETRY_BT2020_RGB;
|
||||
state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state),
|
||||
(int)COLOR_SPACE_2020_RGB_LIMITEDRANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_output_color_space_bt2020_ycc - Test Output color space bt2020 ycc
|
||||
* @test: The KUnit test context
|
||||
|
|
@ -638,6 +655,24 @@ static void dm_test_output_color_space_bt2020_ycc_rgb_encoding(struct kunit *tes
|
|||
(int)COLOR_SPACE_2020_RGB_FULLRANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited - Test limited
|
||||
* BT.2020 RGB output selected through the BT.2020 YCC connector colorspace
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited(struct kunit *test)
|
||||
{
|
||||
struct dc_crtc_timing timing = {};
|
||||
struct drm_connector_state state = {};
|
||||
|
||||
timing.pixel_encoding = PIXEL_ENCODING_RGB;
|
||||
state.colorspace = DRM_MODE_COLORIMETRY_BT2020_YCC;
|
||||
state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state),
|
||||
(int)COLOR_SPACE_2020_RGB_LIMITEDRANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_output_color_space_bt2020_rgb_ycc_encoding - Test Output color space
|
||||
* bt2020 rgb with non-rgb pixel encoding falls back to limited ycbcr
|
||||
|
|
@ -5422,10 +5457,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
|
|||
KUNIT_CASE(dm_test_output_color_space_bt709_y_only),
|
||||
KUNIT_CASE(dm_test_output_color_space_oprgb),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_rgb),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_rgb_limited),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_ycc),
|
||||
KUNIT_CASE(dm_test_output_color_space_default_ycbcr709_y_only),
|
||||
KUNIT_CASE(dm_test_output_color_space_default_ycbcr601),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_ycc_rgb_encoding),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited),
|
||||
KUNIT_CASE(dm_test_output_color_space_bt2020_rgb_ycc_encoding),
|
||||
/* Tests for amdgpu_dm_convert_dc_color_depth_into_bpc */
|
||||
KUNIT_CASE(dm_test_convert_color_depth_bpc_mappings),
|
||||
|
|
|
|||
|
|
@ -358,12 +358,14 @@ static void dm_test_parse_edid_caps_hdmi_frl(struct kunit *test)
|
|||
|
||||
/* Drive the HDMI/FRL branch */
|
||||
connector->display_info.is_hdmi = true;
|
||||
connector->display_info.rgb_quant_range_selectable = true;
|
||||
connector->display_info.hdmi.scdc.supported = true;
|
||||
connector->display_info.hdmi.max_lanes = 4;
|
||||
connector->display_info.hdmi.max_frl_rate_per_lane = 12;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_helpers_parse_edid_caps(link, dc_edid, edid_caps), EDID_OK);
|
||||
KUNIT_EXPECT_TRUE(test, edid_caps->edid_hdmi);
|
||||
KUNIT_EXPECT_EQ(test, edid_caps->qs_bit, 1);
|
||||
KUNIT_EXPECT_TRUE(test, edid_caps->scdc_present);
|
||||
/* max_lanes 4 + max_frl_rate_per_lane 12 -> rate index 6 */
|
||||
KUNIT_EXPECT_EQ(test, edid_caps->max_frl_rate, 6);
|
||||
|
|
@ -909,7 +911,7 @@ static void dm_test_populate_hdmi_frl_dsc_12bpc(struct kunit *test)
|
|||
|
||||
KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 2);
|
||||
KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support);
|
||||
KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc);
|
||||
KUNIT_EXPECT_TRUE(test, caps->frl_dsc_10bpc);
|
||||
KUNIT_EXPECT_TRUE(test, caps->frl_dsc_12bpc);
|
||||
KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 7);
|
||||
KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 1);
|
||||
|
|
|
|||
|
|
@ -3198,6 +3198,7 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
|
|||
}
|
||||
|
||||
if ((stream_update->hdr_static_metadata && !stream_update->stream->use_dynamic_meta) ||
|
||||
stream_update->output_color_space ||
|
||||
stream_update->vrr_infopacket ||
|
||||
stream_update->vsc_infopacket ||
|
||||
stream_update->vsp_infopacket ||
|
||||
|
|
@ -4188,6 +4189,7 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc,
|
|||
hwss_add_setup_periodic_interrupt(&seq_state, dc, pipe_ctx);
|
||||
|
||||
if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
|
||||
stream_update->output_color_space ||
|
||||
stream_update->vrr_infopacket ||
|
||||
stream_update->vsc_infopacket ||
|
||||
stream_update->vsp_infopacket ||
|
||||
|
|
@ -4370,6 +4372,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
|
|||
dc->hwss.setup_periodic_interrupt(dc, pipe_ctx);
|
||||
|
||||
if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
|
||||
stream_update->output_color_space ||
|
||||
stream_update->vrr_infopacket ||
|
||||
stream_update->vsc_infopacket ||
|
||||
stream_update->vsp_infopacket ||
|
||||
|
|
|
|||
|
|
@ -348,7 +348,8 @@ int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
|
|||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
int ret = 0;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
if (amdgpu_sriov_vf(adev) ||
|
||||
amdgpu_in_reset(adev))
|
||||
return 0;
|
||||
|
||||
if (pp_funcs && pp_funcs->switch_power_profile) {
|
||||
|
|
@ -367,7 +368,8 @@ int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev,
|
|||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
int ret = 0;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
if (amdgpu_sriov_vf(adev) ||
|
||||
amdgpu_in_reset(adev))
|
||||
return 0;
|
||||
|
||||
if (pp_funcs && pp_funcs->pause_power_profile) {
|
||||
|
|
|
|||
|
|
@ -2092,11 +2092,11 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
|||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
|
||||
if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) ||
|
||||
(mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800))
|
||||
if ((mp1_ver == IP_VERSION(13, 0, 0) &&
|
||||
(smu->smc_fw_version <= 0x004e1e00 || smu->smc_fw_version >= 0x004e8600)) ||
|
||||
(mp1_ver == IP_VERSION(13, 0, 10) &&
|
||||
smu->smc_fw_version <= 0x00500800))
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
else
|
||||
gpu_metrics->energy_accumulator = UINT_MAX;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -2097,8 +2097,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ?
|
||||
metrics->EnergyAccumulator : UINT_MAX;
|
||||
if (smu->smc_fw_version <= 0x00521400)
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -407,8 +407,8 @@ fn push(&mut self, data: u64, len: usize) {
|
|||
for i in (0..self.len).rev() {
|
||||
self.decimals[i + len] = self.decimals[i];
|
||||
}
|
||||
for i in 0..len {
|
||||
self.decimals[i] = (chunk % 10) as u8;
|
||||
for decimal in &mut self.decimals[..len] {
|
||||
*decimal = (chunk % 10) as u8;
|
||||
chunk = div10(chunk);
|
||||
}
|
||||
self.len += len;
|
||||
|
|
|
|||
|
|
@ -1946,6 +1946,8 @@ struct intel_dp {
|
|||
|
||||
bool colorimetry_support;
|
||||
|
||||
bool sst_split_sdp_support;
|
||||
|
||||
struct {
|
||||
enum transcoder transcoder;
|
||||
struct mutex lock;
|
||||
|
|
|
|||
|
|
@ -3409,12 +3409,22 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder,
|
|||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
pipe_config->has_audio =
|
||||
intel_dp_has_audio(encoder, conn_state) &&
|
||||
intel_audio_compute_config(encoder, pipe_config, conn_state);
|
||||
|
||||
pipe_config->sdp_split_enable = pipe_config->has_audio &&
|
||||
intel_dp_is_uhbr(pipe_config);
|
||||
|
||||
/*
|
||||
* SDP splitting for UHBR audio requires explicit sink capability in
|
||||
* SST mode, whereas in MST mode it is inherently supported.
|
||||
*/
|
||||
if (pipe_config->sdp_split_enable &&
|
||||
!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST))
|
||||
pipe_config->sdp_split_enable = intel_dp->sst_split_sdp_support;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4462,16 +4472,25 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
|
|||
str_enable_disable(tmp));
|
||||
}
|
||||
|
||||
static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
|
||||
static u8 intel_dp_read_dprx_feature_enum(struct intel_dp *intel_dp)
|
||||
{
|
||||
u8 dprx = 0;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
|
||||
&dprx) != 1)
|
||||
return false;
|
||||
drm_dp_dpcd_read_data(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
|
||||
&dprx, sizeof(dprx));
|
||||
return dprx;
|
||||
}
|
||||
|
||||
static bool intel_dp_get_colorimetry_status(u8 dprx)
|
||||
{
|
||||
return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
|
||||
}
|
||||
|
||||
static bool intel_dp_get_sst_split_sdp_status(u8 dprx)
|
||||
{
|
||||
return dprx & DP_SST_SPLIT_SDP_CAP;
|
||||
}
|
||||
|
||||
static int intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux,
|
||||
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
|
|
@ -4771,6 +4790,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
|
|||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
int ret;
|
||||
u8 dprx;
|
||||
|
||||
/* this function is meant to be called only once */
|
||||
drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
|
||||
|
|
@ -4782,8 +4802,13 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
|
|||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
|
||||
|
||||
dprx = intel_dp_read_dprx_feature_enum(intel_dp);
|
||||
|
||||
intel_dp->colorimetry_support =
|
||||
intel_dp_get_colorimetry_status(intel_dp);
|
||||
intel_dp_get_colorimetry_status(dprx);
|
||||
|
||||
intel_dp->sst_split_sdp_support =
|
||||
intel_dp_get_sst_split_sdp_status(dprx);
|
||||
|
||||
/*
|
||||
* Read the eDP display control registers.
|
||||
|
|
@ -4874,13 +4899,20 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|||
* the OUI/ID since we know it won't change.
|
||||
*/
|
||||
if (!intel_dp_is_edp(intel_dp)) {
|
||||
u8 dprx;
|
||||
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
|
||||
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
|
||||
|
||||
dprx = intel_dp_read_dprx_feature_enum(intel_dp);
|
||||
|
||||
intel_dp->colorimetry_support =
|
||||
intel_dp_get_colorimetry_status(intel_dp);
|
||||
intel_dp_get_colorimetry_status(dprx);
|
||||
|
||||
intel_dp->sst_split_sdp_support =
|
||||
intel_dp_get_sst_split_sdp_status(dprx);
|
||||
|
||||
intel_dp_update_sink_caps(intel_dp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -403,8 +403,10 @@ static int query_perf_config_list(struct drm_i915_private *i915,
|
|||
ids = krealloc(oa_config_ids,
|
||||
n_configs * sizeof(*oa_config_ids),
|
||||
GFP_KERNEL);
|
||||
if (!ids)
|
||||
if (!ids) {
|
||||
kfree(oa_config_ids);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
alloc = fetch_and_zero(&n_configs);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2))
|
||||
|
||||
#define PIPE_CONTROL0_QUEUE_DRAIN_MODE BIT(12)
|
||||
#define PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH BIT(11) /* gen12 */
|
||||
#define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10) /* gen12 */
|
||||
#define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9) /* gen12 */
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "xe_hw_engine.h"
|
||||
#include "xe_pagefault.h"
|
||||
#include "xe_pagefault_types.h"
|
||||
#include "xe_pm.h"
|
||||
#include "xe_svm.h"
|
||||
#include "xe_trace_bo.h"
|
||||
#include "xe_vm.h"
|
||||
|
|
@ -292,9 +293,17 @@ static void xe_pagefault_queue_work(struct work_struct *w)
|
|||
{
|
||||
struct xe_pagefault_queue *pf_queue =
|
||||
container_of(w, typeof(*pf_queue), worker);
|
||||
struct xe_device *xe = pf_queue->xe;
|
||||
struct xe_pagefault pf;
|
||||
unsigned long threshold;
|
||||
|
||||
/*
|
||||
* A live VM holds a PM reference, but a torn-down VM does not.
|
||||
* Guard the entire worker loop to safely drain stale faults and
|
||||
* prevent autosuspends from desyncing batched CT flushes.
|
||||
*/
|
||||
guard(xe_pm_runtime)(xe);
|
||||
|
||||
#define USM_QUEUE_MAX_RUNTIME_MS 20
|
||||
threshold = jiffies + msecs_to_jiffies(USM_QUEUE_MAX_RUNTIME_MS);
|
||||
|
||||
|
|
@ -365,6 +374,7 @@ static int xe_pagefault_queue_init(struct xe_device *xe,
|
|||
drm_dbg(&xe->drm, "xe_pagefault_entry_size=%d, total_num_eus=%d, pf_queue->size=%u",
|
||||
xe_pagefault_entry_size(), total_num_eus, pf_queue->size);
|
||||
|
||||
pf_queue->xe = xe;
|
||||
spin_lock_init(&pf_queue->lock);
|
||||
INIT_WORK(&pf_queue->worker, xe_pagefault_queue_work);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct xe_device;
|
||||
struct xe_gt;
|
||||
struct xe_pagefault;
|
||||
|
||||
|
|
@ -118,6 +119,8 @@ struct xe_pagefault {
|
|||
* queue to absorb the device’s worst-case number of outstanding faults.
|
||||
*/
|
||||
struct xe_pagefault_queue {
|
||||
/** @xe: Back-pointer to the Xe device */
|
||||
struct xe_device *xe;
|
||||
/**
|
||||
* @data: Data in queue containing struct xe_pagefault, protected by
|
||||
* @lock
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i)
|
|||
{
|
||||
struct xe_exec_queue *q = job->q;
|
||||
struct xe_gt *gt = q->gt;
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
bool lacks_render = !(gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK);
|
||||
u32 flags0, flags1;
|
||||
|
||||
|
|
@ -220,6 +221,16 @@ static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i)
|
|||
LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR, 0);
|
||||
|
||||
flags0 = PIPE_CONTROL0_HDC_PIPELINE_FLUSH;
|
||||
/*
|
||||
* Prior to MTL, HDC Pipeline Flush reliably also flushes the LSC
|
||||
* untyped L1 dataport cache, provided HDC_CHICKEN0 is programmed
|
||||
* correctly. Starting with MTL that coupling no longer holds
|
||||
* regardless of how HDC_CHICKEN0 is programmed, but explicitly
|
||||
* requesting the flush via PIPE_CONTROL is itself only reliable
|
||||
* from Xe2 onward, so only gate it in on Xe2+.
|
||||
*/
|
||||
if (GRAPHICS_VERx100(xe) >= 2000)
|
||||
flags0 |= PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH;
|
||||
flags1 = (PIPE_CONTROL_TILE_CACHE_FLUSH |
|
||||
PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH |
|
||||
PIPE_CONTROL_DEPTH_CACHE_FLUSH |
|
||||
|
|
|
|||
|
|
@ -1128,12 +1128,17 @@ static void applesmc_release_light_sensor(void)
|
|||
|
||||
static int applesmc_create_key_backlight(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!smcreg.has_key_backlight)
|
||||
return 0;
|
||||
applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
|
||||
if (!applesmc_led_wq)
|
||||
return -ENOMEM;
|
||||
return led_classdev_register(&pdev->dev, &applesmc_backlight);
|
||||
ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
|
||||
if (ret)
|
||||
destroy_workqueue(applesmc_led_wq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void applesmc_release_key_backlight(void)
|
||||
|
|
|
|||
|
|
@ -934,7 +934,9 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
|
|||
"missing or invalid reset controller device tree entry");
|
||||
return PTR_ERR(priv->rst);
|
||||
}
|
||||
reset_control_deassert(priv->rst);
|
||||
ret = reset_control_deassert(priv->rst);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd
|
|||
static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length,
|
||||
struct completion *status_completion)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
|
@ -191,9 +192,9 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
|
|||
* completion. Reinit is done because hidraw could have triggered
|
||||
* the raw event parsing and marked the passed in completion as done.
|
||||
*/
|
||||
spin_lock_bh(&priv->status_report_request_lock);
|
||||
spin_lock_irqsave(&priv->status_report_request_lock, flags);
|
||||
reinit_completion(status_completion);
|
||||
spin_unlock_bh(&priv->status_report_request_lock);
|
||||
spin_unlock_irqrestore(&priv->status_report_request_lock, flags);
|
||||
|
||||
/* Send command for getting data */
|
||||
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
|
||||
|
|
@ -421,11 +422,19 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
int size)
|
||||
{
|
||||
struct rog_ryujin_data *priv = hid_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
|
||||
if (data[0] != RYUJIN_CMD_PREFIX)
|
||||
if (size < 2 || data[0] != RYUJIN_CMD_PREFIX)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&priv->status_report_request_lock, flags);
|
||||
|
||||
if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) {
|
||||
if (size <= priv->info->temp_offset + 1 ||
|
||||
size <= priv->info->pump_speed_offset + 1 ||
|
||||
size <= priv->info->fan_speed_offset + 1)
|
||||
goto unlock;
|
||||
|
||||
/* Received coolant temp and speeds of pump and internal fan */
|
||||
priv->temp_input[0] = data[priv->info->temp_offset] * 1000 +
|
||||
data[priv->info->temp_offset + 1] * 100;
|
||||
|
|
@ -437,6 +446,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
if (!completion_done(&priv->cooler_status_received))
|
||||
complete_all(&priv->cooler_status_received);
|
||||
} else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) {
|
||||
if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1)
|
||||
goto unlock;
|
||||
|
||||
/* Received speeds of four fans attached to the controller */
|
||||
priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1);
|
||||
priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2);
|
||||
|
|
@ -446,6 +458,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
if (!completion_done(&priv->controller_status_received))
|
||||
complete_all(&priv->controller_status_received);
|
||||
} else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) {
|
||||
if (size <= RYUJIN_INTERNAL_FAN_DUTY)
|
||||
goto unlock;
|
||||
|
||||
/* Received report for pump and internal fan duties (in %) */
|
||||
if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) {
|
||||
/*
|
||||
|
|
@ -463,7 +478,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
* We're expecting a report, so parse it.
|
||||
*/
|
||||
goto read_cooler_duty;
|
||||
return 0;
|
||||
goto unlock;
|
||||
}
|
||||
read_cooler_duty:
|
||||
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
|
||||
|
|
@ -472,6 +487,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
if (!completion_done(&priv->cooler_duty_received))
|
||||
complete_all(&priv->cooler_duty_received);
|
||||
} else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) {
|
||||
if (size <= RYUJIN_CONTROLLER_DUTY)
|
||||
goto unlock;
|
||||
|
||||
/* Received report for controller duty for fans (in PWM) */
|
||||
if (data[RYUJIN_CONTROLLER_DUTY] == 0) {
|
||||
/*
|
||||
|
|
@ -489,7 +507,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
* We're expecting a report, so parse it.
|
||||
*/
|
||||
goto read_controller_duty;
|
||||
return 0;
|
||||
goto unlock;
|
||||
}
|
||||
read_controller_duty:
|
||||
priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY];
|
||||
|
|
@ -498,6 +516,8 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
|
|||
complete_all(&priv->controller_duty_received);
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->status_report_request_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,11 +92,6 @@ struct cc2_data {
|
|||
bool process_irqs;
|
||||
};
|
||||
|
||||
enum cc2_chan_addr {
|
||||
CC2_CHAN_TEMP = 0,
|
||||
CC2_CHAN_HUMIDITY,
|
||||
};
|
||||
|
||||
/* %RH as a per cent mille from a register value */
|
||||
static long cc2_rh_convert(u16 data)
|
||||
{
|
||||
|
|
@ -499,7 +494,7 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
|
|||
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_min_alarm, CC2_CHAN_HUMIDITY);
|
||||
hwmon_humidity_min_alarm, 0);
|
||||
cc2->rh_alarm.low_alarm = true;
|
||||
}
|
||||
|
||||
|
|
@ -512,7 +507,7 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
|
|||
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_max_alarm, CC2_CHAN_HUMIDITY);
|
||||
hwmon_humidity_max_alarm, 0);
|
||||
cc2->rh_alarm.high_alarm = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -566,21 +566,18 @@ static int bootloader_show(struct seq_file *seqf, void *unused)
|
|||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(bootloader);
|
||||
|
||||
static void ccp_debugfs_init(struct ccp_device *ccp)
|
||||
static void ccp_debugfs_init(struct ccp_device *ccp, bool fw_valid, bool bl_valid)
|
||||
{
|
||||
char name[32];
|
||||
int ret;
|
||||
|
||||
scnprintf(name, sizeof(name), "corsaircpro-%s", dev_name(&ccp->hdev->dev));
|
||||
ccp->debugfs = debugfs_create_dir(name, NULL);
|
||||
|
||||
ret = get_fw_version(ccp);
|
||||
if (!ret)
|
||||
if (fw_valid)
|
||||
debugfs_create_file("firmware_version", 0444,
|
||||
ccp->debugfs, ccp, &firmware_fops);
|
||||
|
||||
ret = get_bl_version(ccp);
|
||||
if (!ret)
|
||||
if (bl_valid)
|
||||
debugfs_create_file("bootloader_version", 0444,
|
||||
ccp->debugfs, ccp, &bootloader_fops);
|
||||
}
|
||||
|
|
@ -588,6 +585,7 @@ static void ccp_debugfs_init(struct ccp_device *ccp)
|
|||
static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
struct ccp_device *ccp;
|
||||
bool fw_valid, bl_valid;
|
||||
int ret;
|
||||
|
||||
ccp = devm_kzalloc(&hdev->dev, sizeof(*ccp), GFP_KERNEL);
|
||||
|
|
@ -632,17 +630,27 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
if (ret)
|
||||
goto out_hw_close;
|
||||
|
||||
ccp_debugfs_init(ccp);
|
||||
/*
|
||||
* Query the versions before registering the hwmon device: they send
|
||||
* USB commands without holding ccp->mutex, which is only safe while
|
||||
* nothing else can call send_usb_cmd().
|
||||
*/
|
||||
fw_valid = !get_fw_version(ccp);
|
||||
bl_valid = !get_bl_version(ccp);
|
||||
|
||||
ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro",
|
||||
ccp, &ccp_chip_info, NULL);
|
||||
if (IS_ERR(ccp->hwmon_dev)) {
|
||||
ret = PTR_ERR(ccp->hwmon_dev);
|
||||
goto out_hw_close;
|
||||
goto out_debugfs_remove;
|
||||
}
|
||||
|
||||
ccp_debugfs_init(ccp, fw_valid, bl_valid);
|
||||
|
||||
return 0;
|
||||
|
||||
out_debugfs_remove:
|
||||
debugfs_remove_recursive(ccp->debugfs);
|
||||
out_hw_close:
|
||||
hid_hw_close(hdev);
|
||||
hid_device_io_stop(hdev);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/devm-helpers.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kstrtox.h>
|
||||
|
|
@ -84,6 +85,7 @@ static DEVICE_ATTR_RO(fan1_alarm);
|
|||
static int fan_alarm_init(struct gpio_fan_data *fan_data)
|
||||
{
|
||||
int alarm_irq;
|
||||
int err;
|
||||
struct device *dev = fan_data->dev;
|
||||
|
||||
/*
|
||||
|
|
@ -94,7 +96,11 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data)
|
|||
if (alarm_irq <= 0)
|
||||
return 0;
|
||||
|
||||
INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
|
||||
err = devm_work_autocancel(dev, &fan_data->alarm_work,
|
||||
fan_alarm_notify);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
|
||||
return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
|
||||
IRQF_SHARED, "GPIO fan alarm", fan_data);
|
||||
|
|
@ -606,8 +612,11 @@ static void gpio_fan_shutdown(struct platform_device *pdev)
|
|||
{
|
||||
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
|
||||
|
||||
if (fan_data->gpios)
|
||||
if (fan_data->gpios) {
|
||||
mutex_lock(&fan_data->lock);
|
||||
set_fan_speed(fan_data, 0);
|
||||
mutex_unlock(&fan_data->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_fan_runtime_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -318,6 +318,11 @@ static int hwmon_attr_base(enum hwmon_sensor_types type)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static bool is_hwmon_device(struct device *dev)
|
||||
{
|
||||
return dev->class == &hwmon_class;
|
||||
}
|
||||
|
||||
#if IS_REACHABLE(CONFIG_I2C)
|
||||
|
||||
/*
|
||||
|
|
@ -338,7 +343,7 @@ static int hwmon_attr_base(enum hwmon_sensor_types type)
|
|||
|
||||
static int hwmon_match_device(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->class == &hwmon_class;
|
||||
return is_hwmon_device(dev);
|
||||
}
|
||||
|
||||
static ssize_t pec_show(struct device *dev, const struct device_attribute *dummy,
|
||||
|
|
@ -371,18 +376,17 @@ static ssize_t pec_store(struct device *dev, const struct device_attribute *deva
|
|||
* handling is not required.
|
||||
*/
|
||||
hwdev = to_hwmon_device(hdev);
|
||||
guard(mutex)(&hwdev->lock);
|
||||
if (hwdev->chip->ops->write) {
|
||||
err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto put;
|
||||
scoped_guard(mutex, &hwdev->lock) {
|
||||
if (hwdev->chip->ops->write) {
|
||||
err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto put;
|
||||
}
|
||||
if (!val)
|
||||
client->flags &= ~I2C_CLIENT_PEC;
|
||||
else
|
||||
client->flags |= I2C_CLIENT_PEC;
|
||||
}
|
||||
|
||||
if (!val)
|
||||
client->flags &= ~I2C_CLIENT_PEC;
|
||||
else
|
||||
client->flags |= I2C_CLIENT_PEC;
|
||||
|
||||
err = count;
|
||||
put:
|
||||
put_device(hdev);
|
||||
|
|
@ -782,6 +786,9 @@ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
|
|||
const char *template;
|
||||
int base;
|
||||
|
||||
if (WARN(!is_hwmon_device(dev), "%s is not a hardware monitoring device\n",
|
||||
dev_name(dev)))
|
||||
return -EINVAL;
|
||||
if (type >= ARRAY_SIZE(__templates))
|
||||
return -EINVAL;
|
||||
if (attr >= __templates_size[type])
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -129,6 +130,17 @@ enum ina2xx_ids {
|
|||
sy24655
|
||||
};
|
||||
|
||||
enum ina2xx_alert_type {
|
||||
INA2XX_ALERT_NONE,
|
||||
INA2XX_ALERT_CURRENT_LOW,
|
||||
INA2XX_ALERT_CURRENT_HIGH,
|
||||
INA2XX_ALERT_POWER_HIGH,
|
||||
INA2XX_ALERT_BUS_VOLTAGE_LOW,
|
||||
INA2XX_ALERT_BUS_VOLTAGE_HIGH,
|
||||
INA2XX_ALERT_SHUNT_VOLTAGE_LOW,
|
||||
INA2XX_ALERT_SHUNT_VOLTAGE_HIGH,
|
||||
};
|
||||
|
||||
struct ina2xx_config {
|
||||
u16 config_default;
|
||||
bool has_alerts; /* chip supports alerts and limits */
|
||||
|
|
@ -148,6 +160,7 @@ struct ina2xx_data {
|
|||
const struct ina2xx_config *config;
|
||||
enum ina2xx_ids chip;
|
||||
|
||||
enum ina2xx_alert_type active_alert;
|
||||
long rshunt;
|
||||
long current_lsb_uA;
|
||||
long power_lsb_uW;
|
||||
|
|
@ -428,16 +441,78 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
|
|||
}
|
||||
}
|
||||
|
||||
static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, long *val)
|
||||
static u32 ina2xx_alert_type_to_mask(enum ina2xx_alert_type alert)
|
||||
{
|
||||
switch (alert) {
|
||||
case INA2XX_ALERT_CURRENT_LOW:
|
||||
case INA2XX_ALERT_SHUNT_VOLTAGE_LOW:
|
||||
return INA226_SHUNT_UNDER_VOLTAGE_MASK;
|
||||
case INA2XX_ALERT_CURRENT_HIGH:
|
||||
case INA2XX_ALERT_SHUNT_VOLTAGE_HIGH:
|
||||
return INA226_SHUNT_OVER_VOLTAGE_MASK;
|
||||
case INA2XX_ALERT_BUS_VOLTAGE_LOW:
|
||||
return INA226_BUS_UNDER_VOLTAGE_MASK;
|
||||
case INA2XX_ALERT_BUS_VOLTAGE_HIGH:
|
||||
return INA226_BUS_OVER_VOLTAGE_MASK;
|
||||
case INA2XX_ALERT_POWER_HIGH:
|
||||
return INA226_POWER_OVER_LIMIT_MASK;
|
||||
case INA2XX_ALERT_NONE:
|
||||
return 0;
|
||||
default:
|
||||
/* programmer error */
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static enum ina2xx_alert_type ina2xx_mask_to_alert_type(u32 mask)
|
||||
{
|
||||
int top_bit = fls(mask & INA226_ALERT_CONFIG_MASK);
|
||||
|
||||
if (!top_bit)
|
||||
return INA2XX_ALERT_NONE;
|
||||
|
||||
/*
|
||||
* Multiple bits may be set, with the highest-set function taking
|
||||
* precedence according to the datasheet. Shunt voltage masks are
|
||||
* assumed to map to voltage monitoring rather than current monitoring,
|
||||
* since the latter isn't directly implemented in the hardware.
|
||||
*/
|
||||
switch (BIT(top_bit - 1)) {
|
||||
case INA226_SHUNT_OVER_VOLTAGE_MASK:
|
||||
return INA2XX_ALERT_SHUNT_VOLTAGE_HIGH;
|
||||
case INA226_SHUNT_UNDER_VOLTAGE_MASK:
|
||||
return INA2XX_ALERT_SHUNT_VOLTAGE_LOW;
|
||||
case INA226_BUS_OVER_VOLTAGE_MASK:
|
||||
return INA2XX_ALERT_BUS_VOLTAGE_HIGH;
|
||||
case INA226_BUS_UNDER_VOLTAGE_MASK:
|
||||
return INA2XX_ALERT_BUS_VOLTAGE_LOW;
|
||||
case INA226_POWER_OVER_LIMIT_MASK:
|
||||
return INA2XX_ALERT_POWER_HIGH;
|
||||
default:
|
||||
return INA2XX_ALERT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int ina226_alert_limit_read(struct ina2xx_data *data, enum ina2xx_alert_type alert,
|
||||
int reg, long *val)
|
||||
{
|
||||
struct regmap *regmap = data->regmap;
|
||||
int regval;
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
/* Avoid nonzero reads from inactive alerts caused by shared limit register */
|
||||
if (data->active_alert != alert) {
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, INA226_MASK_ENABLE, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = ina2xx_alert_type_to_mask(alert);
|
||||
if (regval & mask) {
|
||||
ret = regmap_read(regmap, INA226_ALERT_LIMIT, ®val);
|
||||
if (ret)
|
||||
|
|
@ -449,9 +524,11 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val)
|
||||
static int ina226_alert_limit_write(struct ina2xx_data *data, enum ina2xx_alert_type alert,
|
||||
int reg, long val)
|
||||
{
|
||||
struct regmap *regmap = data->regmap;
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
if (val < 0)
|
||||
|
|
@ -466,15 +543,22 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg,
|
|||
INA226_ALERT_CONFIG_MASK, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->active_alert = INA2XX_ALERT_NONE;
|
||||
|
||||
ret = regmap_write(regmap, INA226_ALERT_LIMIT,
|
||||
ina226_alert_to_reg(data, reg, val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
return regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_CONFIG_MASK, mask);
|
||||
if (val) {
|
||||
mask = ina2xx_alert_type_to_mask(alert);
|
||||
ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_CONFIG_MASK, mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->active_alert = alert;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -498,15 +582,26 @@ static int ina2xx_chip_read(struct device *dev, u32 attr, long *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val)
|
||||
static int ina226_alert_read(struct ina2xx_data *data, enum ina2xx_alert_type alert, long *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read_bypassed(regmap, INA226_MASK_ENABLE, ®val);
|
||||
/*
|
||||
* With alert latching, reading alerts from hardware also clears the
|
||||
* alert, so return early if the alert is inactive.
|
||||
*/
|
||||
if (data->active_alert != alert) {
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read_bypassed(data->regmap, INA226_MASK_ENABLE, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = ina2xx_alert_type_to_mask(alert);
|
||||
*val = (regval & mask) && (regval & INA226_ALERT_FUNCTION_FLAG);
|
||||
|
||||
return 0;
|
||||
|
|
@ -515,10 +610,10 @@ static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val)
|
|||
static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
|
||||
{
|
||||
int voltage_reg = channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE;
|
||||
u32 under_voltage_mask = channel ? INA226_BUS_UNDER_VOLTAGE_MASK
|
||||
: INA226_SHUNT_UNDER_VOLTAGE_MASK;
|
||||
u32 over_voltage_mask = channel ? INA226_BUS_OVER_VOLTAGE_MASK
|
||||
: INA226_SHUNT_OVER_VOLTAGE_MASK;
|
||||
enum ina2xx_alert_type under_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW
|
||||
: INA2XX_ALERT_SHUNT_VOLTAGE_LOW;
|
||||
enum ina2xx_alert_type over_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH
|
||||
: INA2XX_ALERT_SHUNT_VOLTAGE_HIGH;
|
||||
struct ina2xx_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
unsigned int regval;
|
||||
|
|
@ -532,15 +627,15 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
|
|||
*val = ina2xx_get_value(data, voltage_reg, regval);
|
||||
break;
|
||||
case hwmon_in_lcrit:
|
||||
return ina226_alert_limit_read(data, under_voltage_mask,
|
||||
return ina226_alert_limit_read(data, under_voltage_alert,
|
||||
voltage_reg, val);
|
||||
case hwmon_in_crit:
|
||||
return ina226_alert_limit_read(data, over_voltage_mask,
|
||||
return ina226_alert_limit_read(data, over_voltage_alert,
|
||||
voltage_reg, val);
|
||||
case hwmon_in_lcrit_alarm:
|
||||
return ina226_alert_read(regmap, under_voltage_mask, val);
|
||||
return ina226_alert_read(data, under_voltage_alert, val);
|
||||
case hwmon_in_crit_alarm:
|
||||
return ina226_alert_read(regmap, over_voltage_mask, val);
|
||||
return ina226_alert_read(data, over_voltage_alert, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -594,10 +689,10 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val)
|
|||
case hwmon_power_average:
|
||||
return sy24655_average_power_read(data, SY24655_EIN, val);
|
||||
case hwmon_power_crit:
|
||||
return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK,
|
||||
return ina226_alert_limit_read(data, INA2XX_ALERT_POWER_HIGH,
|
||||
INA2XX_POWER, val);
|
||||
case hwmon_power_crit_alarm:
|
||||
return ina226_alert_read(data->regmap, INA226_POWER_OVER_LIMIT_MASK, val);
|
||||
return ina226_alert_read(data, INA2XX_ALERT_POWER_HIGH, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -633,15 +728,15 @@ static int ina2xx_curr_read(struct device *dev, u32 attr, long *val)
|
|||
*val = ina2xx_get_value(data, INA2XX_CURRENT, regval);
|
||||
return 0;
|
||||
case hwmon_curr_lcrit:
|
||||
return ina226_alert_limit_read(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
|
||||
return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_LOW,
|
||||
INA2XX_CURRENT, val);
|
||||
case hwmon_curr_crit:
|
||||
return ina226_alert_limit_read(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
|
||||
return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_HIGH,
|
||||
INA2XX_CURRENT, val);
|
||||
case hwmon_curr_lcrit_alarm:
|
||||
return ina226_alert_read(regmap, INA226_SHUNT_UNDER_VOLTAGE_MASK, val);
|
||||
return ina226_alert_read(data, INA2XX_ALERT_CURRENT_LOW, val);
|
||||
case hwmon_curr_crit_alarm:
|
||||
return ina226_alert_read(regmap, INA226_SHUNT_OVER_VOLTAGE_MASK, val);
|
||||
return ina226_alert_read(data, INA2XX_ALERT_CURRENT_HIGH, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -685,12 +780,12 @@ static int ina2xx_in_write(struct device *dev, u32 attr, int channel, long val)
|
|||
switch (attr) {
|
||||
case hwmon_in_lcrit:
|
||||
return ina226_alert_limit_write(data,
|
||||
channel ? INA226_BUS_UNDER_VOLTAGE_MASK : INA226_SHUNT_UNDER_VOLTAGE_MASK,
|
||||
channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW : INA2XX_ALERT_SHUNT_VOLTAGE_LOW,
|
||||
channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE,
|
||||
val);
|
||||
case hwmon_in_crit:
|
||||
return ina226_alert_limit_write(data,
|
||||
channel ? INA226_BUS_OVER_VOLTAGE_MASK : INA226_SHUNT_OVER_VOLTAGE_MASK,
|
||||
channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH : INA2XX_ALERT_SHUNT_VOLTAGE_HIGH,
|
||||
channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE,
|
||||
val);
|
||||
default:
|
||||
|
|
@ -705,7 +800,7 @@ static int ina2xx_power_write(struct device *dev, u32 attr, long val)
|
|||
|
||||
switch (attr) {
|
||||
case hwmon_power_crit:
|
||||
return ina226_alert_limit_write(data, INA226_POWER_OVER_LIMIT_MASK,
|
||||
return ina226_alert_limit_write(data, INA2XX_ALERT_POWER_HIGH,
|
||||
INA2XX_POWER, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -719,10 +814,10 @@ static int ina2xx_curr_write(struct device *dev, u32 attr, long val)
|
|||
|
||||
switch (attr) {
|
||||
case hwmon_curr_lcrit:
|
||||
return ina226_alert_limit_write(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
|
||||
return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_LOW,
|
||||
INA2XX_CURRENT, val);
|
||||
case hwmon_curr_crit:
|
||||
return ina226_alert_limit_write(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
|
||||
return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_HIGH,
|
||||
INA2XX_CURRENT, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -883,8 +978,12 @@ static ssize_t shunt_resistor_show(struct device *dev,
|
|||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct ina2xx_data *data = dev_get_drvdata(dev);
|
||||
long rshunt;
|
||||
|
||||
return sysfs_emit(buf, "%li\n", data->rshunt);
|
||||
scoped_guard(hwmon_lock, dev) {
|
||||
rshunt = data->rshunt;
|
||||
}
|
||||
return sysfs_emit(buf, "%li\n", rshunt);
|
||||
}
|
||||
|
||||
static ssize_t shunt_resistor_store(struct device *dev,
|
||||
|
|
@ -940,6 +1039,16 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data)
|
|||
|
||||
if (data->config->has_alerts) {
|
||||
bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high");
|
||||
unsigned int mask_enable;
|
||||
|
||||
/*
|
||||
* Infer active alert from MASK_ENABLE in case it's already
|
||||
* configured (e.g., by a past probe or firmware)
|
||||
*/
|
||||
ret = regmap_read(regmap, INA226_MASK_ENABLE, &mask_enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->active_alert = ina2xx_mask_to_alert_type(mask_enable);
|
||||
|
||||
regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_LATCH_ENABLE | INA226_ALERT_POLARITY,
|
||||
|
|
|
|||
|
|
@ -1106,7 +1106,7 @@ static const struct clk_ops ltc4282_ops = {
|
|||
static int ltc428_clk_provider_setup(struct ltc4282_state *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_init_data init = {};
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ static int mcp9982_read(struct device *dev, enum hwmon_sensor_types type, u32 at
|
|||
reg_status, !(reg_status & MCP9982_STATUS_BUSY),
|
||||
MCP9982_WAKE_UP_TIME_US,
|
||||
MCP9982_WAKE_UP_TIME_US * 10);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ static inline s8 temp_to_reg(long val)
|
|||
#define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE | \
|
||||
HWMON_T_MAX | HWMON_T_MAX_HYST | \
|
||||
HWMON_T_MAX_ALARM)
|
||||
#define NCT6694_HWMON_DTIN_CONFIG (HWMON_T_INPUT | \
|
||||
HWMON_T_MAX | HWMON_T_MAX_HYST | \
|
||||
HWMON_T_MAX_ALARM)
|
||||
#define NCT6694_HWMON_FAN_CONFIG (HWMON_F_INPUT | HWMON_F_ENABLE | \
|
||||
HWMON_F_MIN | HWMON_F_MIN_ALARM)
|
||||
#define NCT6694_HWMON_PWM_CONFIG (HWMON_PWM_INPUT | HWMON_PWM_ENABLE | \
|
||||
|
|
@ -193,22 +196,22 @@ static const struct hwmon_channel_info *nct6694_info[] = {
|
|||
NCT6694_HWMON_TEMP_CONFIG, /* TDP2 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* TDP3 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* TDP4 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN0 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN1 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN2 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN3 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN4 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN5 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN6 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN7 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN8 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN9 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN10 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN11 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN12 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN13 */
|
||||
NCT6694_HWMON_TEMP_CONFIG, /* DTIN14 */
|
||||
NCT6694_HWMON_TEMP_CONFIG), /* DTIN15 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN0 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN1 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN2 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN3 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN4 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN5 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN6 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN7 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN8 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN9 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN10 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN11 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN12 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN13 */
|
||||
NCT6694_HWMON_DTIN_CONFIG, /* DTIN14 */
|
||||
NCT6694_HWMON_DTIN_CONFIG), /* DTIN15 */
|
||||
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
NCT6694_HWMON_FAN_CONFIG, /* FIN0 */
|
||||
|
|
|
|||
|
|
@ -1275,7 +1275,9 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
|
|||
|
||||
regval = status & mask;
|
||||
if (regval) {
|
||||
if (data->revision >= PMBUS_REV_12) {
|
||||
/* Generic STATUS_WORD alarms are not individually clearable. */
|
||||
if (data->revision >= PMBUS_REV_12 &&
|
||||
reg != PMBUS_STATUS_WORD) {
|
||||
ret = _pmbus_write_byte_data(client, page, reg, regval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -277,6 +277,8 @@ static ssize_t heater_enable_store(struct device *dev,
|
|||
heating_time_bound = 1100;
|
||||
}
|
||||
|
||||
guard(hwmon_lock)(dev);
|
||||
|
||||
if (time_before(jiffies, data->heating_complete))
|
||||
return -EBUSY;
|
||||
|
||||
|
|
@ -286,7 +288,7 @@ static ssize_t heater_enable_store(struct device *dev,
|
|||
|
||||
data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound);
|
||||
data->data_pending = true;
|
||||
return 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t heater_power_show(struct device *dev,
|
||||
|
|
@ -314,6 +316,8 @@ static ssize_t heater_power_store(struct device *dev,
|
|||
if (power != 20 && power != 110 && power != 200)
|
||||
return -EINVAL;
|
||||
|
||||
guard(hwmon_lock)(dev);
|
||||
|
||||
data->heater_power = power;
|
||||
|
||||
return count;
|
||||
|
|
@ -344,6 +348,8 @@ static ssize_t heater_time_store(struct device *dev,
|
|||
if (time != 100 && time != 1000)
|
||||
return -EINVAL;
|
||||
|
||||
guard(hwmon_lock)(dev);
|
||||
|
||||
data->heater_time = time;
|
||||
|
||||
return count;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* yoga_fan.c - Lenovo Yoga/Legion Fan Hardware Monitoring Driver
|
||||
*
|
||||
* Provides fan speed monitoring for Lenovo Yoga, Legion, and IdeaPad
|
||||
|
|
|
|||
|
|
@ -54,9 +54,6 @@ struct protection_domain *protection_domain_alloc(void);
|
|||
struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev,
|
||||
struct mm_struct *mm);
|
||||
void amd_iommu_domain_free(struct iommu_domain *dom);
|
||||
int iommu_sva_set_dev_pasid(struct iommu_domain *domain,
|
||||
struct device *dev, ioasid_t pasid,
|
||||
struct iommu_domain *old);
|
||||
void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
|
||||
struct iommu_domain *domain);
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user