mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:07:50 +01:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.3-rc4). Conflicts: net/core/neighbour.c979aabdad8("neighbour: Skip default parms when resumed in neightbl_dump_info().")7b430fcfc9("neighbour: Don't render blackhole_netdev via RTM_GETNEIGHTBL.")fae1c59810("neighbour: Remove unnecessary net_eq().") https://lore.kernel.org/20260911173056.44ec06e0@kernel.org https://lore.kernel.org/aqfbJi7nAX4IbmnR@sirena.co.uk Adjacent changes: net/netlink/af_netlink.cceac0de741("netlink: do not free nlk->groups while lockless readers can use it")7c0ec6288b("net: Replace %pK output with 0") net/bridge/br_vlan.c2842ce397d("net: bridge: vlan: fix bugs caused by switchdev deletion errors")5bec8f8611("net: bridge: vlan: annotate lockless use of num_vlans")2b1f8fd311("net: bridge: vlan: annotate lockless vlan flags use") net/bridge/br_mst.c18a6fe05fb("net: bridge: mst: move switchdev call outside rcu")120207a08f("net: bridge: vlan: annotate lockless use of msti") drivers/net/ethernet/stmicro/stmmac/hwif.h90e4b849df("net: stmmac: propagate FPE preemption-class mapping errors")85ca3292d7("net: stmmac: Remove ARP offload code") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f2b5c73c03
|
|
@ -4,6 +4,8 @@ Alyssa Rosenzweig <alyssa@rosenzweig.io>
|
|||
Askar Safin <safinaskar@gmail.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
Johannes Berg <johannes.berg@intel.com>
|
||||
Johannes Berg <johannes@sipsolutions.net>
|
||||
Marc Gonzalez <marc.w.gonzalez@free.fr>
|
||||
Nathan Chancellor <nathan@kernel.org>
|
||||
Ralf Baechle <ralf@linux-mips.org>
|
||||
|
|
|
|||
5
.mailmap
5
.mailmap
|
|
@ -211,7 +211,8 @@ Christophe Leroy <chleroy@kernel.org> <christophe.leroy@c-s.fr>
|
|||
Christophe Leroy <chleroy@kernel.org> <christophe.leroy@csgroup.eu>
|
||||
Christophe Leroy <chleroy@kernel.org> <christophe.leroy2@cs-soprasteria.com>
|
||||
Christophe Ricard <christophe.ricard@gmail.com>
|
||||
Christopher Obbard <christopher.obbard@linaro.org> <chris.obbard@collabora.com>
|
||||
Christopher Obbard <chris.obbard@oss.qualcomm.com> <chris.obbard@collabora.com>
|
||||
Christopher Obbard <chris.obbard@oss.qualcomm.com> <christopher.obbard@linaro.org>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Christoph Manszewski <c.manszewski@gmail.com> <christoph.manszewski@intel.com>
|
||||
Christoph Paasch <cpaasch@openai.com> <christoph.paasch@gmail.com>
|
||||
|
|
@ -222,6 +223,7 @@ Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
|
|||
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
||||
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
|
||||
Coiby Xu <coiby.xu@gmail.com> <coxu@redhat.com>
|
||||
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
||||
Corey Minyard <minyard@acm.org>
|
||||
Damian Hobson-Garcia <dhobsong@igel.co.jp>
|
||||
|
|
@ -421,6 +423,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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -341,6 +341,9 @@ attribute-sets:
|
|||
-
|
||||
name: interval-probe-time-ms
|
||||
type: u64
|
||||
checks:
|
||||
min: 1
|
||||
max: 86400000
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ neigh/default/unres_qlen - INTEGER
|
|||
|
||||
neigh/default/interval_probe_time_ms - INTEGER
|
||||
The probe interval for neighbor entries with NTF_MANAGED flag,
|
||||
the min value is 1.
|
||||
the min value is 1, and the max value is 86400000 (1 day).
|
||||
|
||||
Default: 5000
|
||||
|
||||
|
|
@ -874,6 +874,8 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
|
|||
case this value is ignored.
|
||||
Default: between 131072 and 32MB, depending on RAM size.
|
||||
|
||||
Each of the three values cannot be set below 4096.
|
||||
|
||||
tcp_sack - BOOLEAN
|
||||
Enable select acknowledgments (SACKS).
|
||||
|
||||
|
|
|
|||
|
|
@ -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 内核树,其中包含他们所需的任何自定义扩展的代码。)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17032,8 +17032,8 @@ MEMBLOCK AND MEMORY MANAGEMENT INITIALIZATION
|
|||
M: Mike Rapoport <rppt@kernel.org>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git for-next
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git fixes
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/memblock.git for-next
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/memblock.git fixes
|
||||
F: Documentation/core-api/boot-time-mm.rst
|
||||
F: include/linux/kho/abi/memblock.h
|
||||
F: include/linux/memblock.h
|
||||
|
|
@ -28616,7 +28616,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>
|
||||
|
|
|
|||
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);
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ int iommu_tce_check_ioba(unsigned long page_shift,
|
|||
if (ioba < offset)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ioba + 1) > (offset + size))
|
||||
if ((ioba + npages < ioba) || (ioba - offset + npages > size))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1204,8 +1204,10 @@ static void kvmhv_emulate_tlbie_all_lpid(struct kvm_vcpu *vcpu, int ric)
|
|||
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
idr_for_each_entry(&kvm->arch.kvm_nested_guest_idr, gp, lpid) {
|
||||
++gp->refcnt;
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
kvmhv_emulate_tlbie_lpid(vcpu, gp, ric);
|
||||
kvmhv_put_nested(gp);
|
||||
spin_lock(&kvm->mmu_lock);
|
||||
}
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
|
|
|
|||
|
|
@ -779,8 +779,11 @@ static int kvmppc_svm_page_in(struct vm_area_struct *vma,
|
|||
if (spage) {
|
||||
ret = uv_page_in(kvm->arch.lpid, pfn << page_shift,
|
||||
gpa, 0, page_shift);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
unlock_page(dpage);
|
||||
put_page(dpage);
|
||||
goto out_finalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ static inline u64 mul_u64_add_u64_div_u64(u64 rax, u64 mul, u64 add, u64 div)
|
|||
|
||||
if (!statically_true(!add))
|
||||
asm ("addq %[add], %[lo]; adcq $0, %[hi]" :
|
||||
[lo] "+r" (rax), [hi] "+r" (rdx) : [add] "irm" (add));
|
||||
[lo] "+r" (rax), [hi] "+r" (rdx) : [add] "erm" (add));
|
||||
|
||||
asm ("divq %[div]" : "+a" (rax), "+d" (rdx) : [div] "rm" (div));
|
||||
|
||||
|
|
|
|||
|
|
@ -806,7 +806,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
|
|||
pmdval_t val = pmd_val(pmd), oldval = val;
|
||||
pmd_t pmd_result;
|
||||
|
||||
val &= (_HPAGE_CHG_MASK & ~_PAGE_DIRTY);
|
||||
val &= _HPAGE_CHG_MASK;
|
||||
val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK;
|
||||
val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/execmem.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/mmap_lock.h>
|
||||
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/insn.h>
|
||||
|
|
@ -1198,6 +1201,41 @@ static bool cfi_debug __ro_after_init;
|
|||
bool cfi_bhi __ro_after_init = false;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FINEIBT
|
||||
/*
|
||||
* <fineibt_preamble_start>:
|
||||
* 0: f3 0f 1e fa endbr64
|
||||
* 4: 2d 78 56 34 12 sub $0x12345678, %eax
|
||||
* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13>
|
||||
* 10: 0f 1f 40 d6 nopl -0x2a(%rax)
|
||||
*
|
||||
* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as
|
||||
* UDB on x86_64 and raises #UD.
|
||||
*/
|
||||
asm( ".pushsection .rodata \n"
|
||||
"fineibt_preamble_start: \n"
|
||||
" endbr64 \n"
|
||||
" subl $0x12345678, %eax \n"
|
||||
"fineibt_preamble_bhi: \n"
|
||||
" cs jne.d32 fineibt_preamble_start+0x13 \n"
|
||||
"#fineibt_func: \n"
|
||||
" nopl -42(%rax) \n"
|
||||
"fineibt_preamble_end: \n"
|
||||
".popsection\n"
|
||||
);
|
||||
|
||||
extern u8 fineibt_preamble_start[];
|
||||
extern u8 fineibt_preamble_bhi[];
|
||||
extern u8 fineibt_preamble_end[];
|
||||
|
||||
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
|
||||
#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
|
||||
#define fineibt_preamble_ud 0x13
|
||||
#define fineibt_preamble_hash 5
|
||||
|
||||
#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE)
|
||||
#endif /* CONFIG_FINEIBT */
|
||||
|
||||
#ifdef CONFIG_CFI
|
||||
u32 cfi_get_func_hash(void *func)
|
||||
{
|
||||
|
|
@ -1205,9 +1243,11 @@ u32 cfi_get_func_hash(void *func)
|
|||
|
||||
func -= cfi_get_offset();
|
||||
switch (cfi_mode) {
|
||||
#ifdef CONFIG_FINEIBT
|
||||
case CFI_FINEIBT:
|
||||
func += 7;
|
||||
func += fineibt_preamble_hash;
|
||||
break;
|
||||
#endif
|
||||
case CFI_KCFI:
|
||||
func += 1;
|
||||
break;
|
||||
|
|
@ -1363,39 +1403,6 @@ early_param("cfi", cfi_parse_cmdline);
|
|||
* anyway.
|
||||
*/
|
||||
|
||||
/*
|
||||
* <fineibt_preamble_start>:
|
||||
* 0: f3 0f 1e fa endbr64
|
||||
* 4: 2d 78 56 34 12 sub $0x12345678, %eax
|
||||
* 9: 2e 0f 85 03 00 00 00 jne,pn 13 <fineibt_preamble_start+0x13>
|
||||
* 10: 0f 1f 40 d6 nopl -0x2a(%rax)
|
||||
*
|
||||
* Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as
|
||||
* UDB on x86_64 and raises #UD.
|
||||
*/
|
||||
asm( ".pushsection .rodata \n"
|
||||
"fineibt_preamble_start: \n"
|
||||
" endbr64 \n"
|
||||
" subl $0x12345678, %eax \n"
|
||||
"fineibt_preamble_bhi: \n"
|
||||
" cs jne.d32 fineibt_preamble_start+0x13 \n"
|
||||
"#fineibt_func: \n"
|
||||
" nopl -42(%rax) \n"
|
||||
"fineibt_preamble_end: \n"
|
||||
".popsection\n"
|
||||
);
|
||||
|
||||
extern u8 fineibt_preamble_start[];
|
||||
extern u8 fineibt_preamble_bhi[];
|
||||
extern u8 fineibt_preamble_end[];
|
||||
|
||||
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
|
||||
#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
|
||||
#define fineibt_preamble_ud 0x13
|
||||
#define fineibt_preamble_hash 5
|
||||
|
||||
#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE)
|
||||
|
||||
/*
|
||||
* <fineibt_caller_start>:
|
||||
* 0: b8 78 56 34 12 mov $0x12345678, %eax
|
||||
|
|
@ -2372,6 +2379,38 @@ static void text_poke_memset(void *dst, const void *src, size_t len)
|
|||
|
||||
typedef void text_poke_f(void *dst, const void *src, size_t len);
|
||||
|
||||
static void __poke_vmalloc_pages(struct page **pages, void *addr,
|
||||
bool cross_page_boundary)
|
||||
{
|
||||
pages[0] = vmalloc_to_page(addr);
|
||||
if (cross_page_boundary)
|
||||
pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
|
||||
}
|
||||
|
||||
static void poke_vmalloc_pages(struct page **pages, void *addr,
|
||||
bool cross_page_boundary)
|
||||
{
|
||||
if (in_dbg_master()) {
|
||||
/*
|
||||
* If called from kgdb cannot sleep, but all other CPUs stopped
|
||||
* anyway so safe to proceed without locks
|
||||
*/
|
||||
__poke_vmalloc_pages(pages, addr, cross_page_boundary);
|
||||
} else {
|
||||
/*
|
||||
* execmem ROX ranges are shared between modules and can be
|
||||
* collapsed to huge PMD entries, and this collapse can happen
|
||||
* concurrently with a racing set_memory_rox().
|
||||
*
|
||||
* Prevent vmalloc_to_page() from racing by acquiring an
|
||||
* init_mm read lock which pairs with the init_mm write lock in
|
||||
* cpa_collapse_large_pages().
|
||||
*/
|
||||
guard(mmap_read_lock)(&init_mm);
|
||||
__poke_vmalloc_pages(pages, addr, cross_page_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t len)
|
||||
{
|
||||
bool cross_page_boundary = offset_in_page(addr) + len > PAGE_SIZE;
|
||||
|
|
@ -2389,9 +2428,7 @@ static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t l
|
|||
BUG_ON(!after_bootmem);
|
||||
|
||||
if (!core_kernel_text((unsigned long)addr)) {
|
||||
pages[0] = vmalloc_to_page(addr);
|
||||
if (cross_page_boundary)
|
||||
pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
|
||||
poke_vmalloc_pages(pages, addr, cross_page_boundary);
|
||||
} else {
|
||||
pages[0] = virt_to_page(addr);
|
||||
WARN_ON(!PageReserved(pages[0]));
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ __setup("amd_smn_debugfs_enable", amd_smn_enable_dfs);
|
|||
static int __init amd_smn_init(void)
|
||||
{
|
||||
u16 count, num_roots, roots_per_node, node, num_nodes;
|
||||
struct pci_dev *root;
|
||||
struct pci_dev *root __free(pci_dev_put) = NULL;
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_ZEN))
|
||||
return 0;
|
||||
|
|
@ -262,7 +262,6 @@ static int __init amd_smn_init(void)
|
|||
return 0;
|
||||
|
||||
num_roots = 0;
|
||||
root = NULL;
|
||||
while ((root = get_next_root(root))) {
|
||||
pci_dbg(root, "Reserving PCI config space\n");
|
||||
|
||||
|
|
@ -299,14 +298,13 @@ static int __init amd_smn_init(void)
|
|||
|
||||
count = 0;
|
||||
node = 0;
|
||||
root = NULL;
|
||||
while (node < num_nodes && (root = get_next_root(root))) {
|
||||
/* Use one root for each node and skip the rest. */
|
||||
if (count++ % roots_per_node)
|
||||
continue;
|
||||
|
||||
pci_dbg(root, "is root for AMD node %u\n", node);
|
||||
amd_roots[node++] = root;
|
||||
amd_roots[node++] = pci_dev_get(root);
|
||||
}
|
||||
|
||||
if (enable_dfs) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/cc_platform.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
#include <linux/virtio_anchor.h>
|
||||
#include <linux/iommu-dma.h>
|
||||
|
||||
#include <asm/sev.h>
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ bool force_dma_unencrypted(struct device *dev)
|
|||
* device does not support DMA to addresses that include the
|
||||
* encryption mask.
|
||||
*/
|
||||
if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
|
||||
if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT) && !use_dma_iommu(dev)) {
|
||||
u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask));
|
||||
u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask,
|
||||
dev->bus_dma_limit);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/cc_platform.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/memregion.h>
|
||||
#include <linux/cleanup.h>
|
||||
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/processor.h>
|
||||
|
|
@ -49,7 +50,8 @@ struct cpa_data {
|
|||
unsigned int flags;
|
||||
unsigned int force_split : 1,
|
||||
force_static_prot : 1,
|
||||
force_flush_all : 1;
|
||||
force_flush_all : 1,
|
||||
init_mm_read_locked : 1;
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
|
|
@ -409,7 +411,7 @@ static void __cpa_flush_tlb(void *data)
|
|||
|
||||
static int collapse_large_pages(unsigned long addr, struct list_head *pgtables);
|
||||
|
||||
static void cpa_collapse_large_pages(struct cpa_data *cpa)
|
||||
static void __cpa_collapse_large_pages(struct cpa_data *cpa)
|
||||
{
|
||||
unsigned long start, addr, end;
|
||||
struct ptdesc *ptdesc, *tmp;
|
||||
|
|
@ -439,10 +441,30 @@ static void cpa_collapse_large_pages(struct cpa_data *cpa)
|
|||
|
||||
list_for_each_entry_safe(ptdesc, tmp, &pgtables, pt_list) {
|
||||
list_del(&ptdesc->pt_list);
|
||||
pagetable_free(ptdesc);
|
||||
/*
|
||||
* Only early alloc'd direct map should not be flagged PG_table
|
||||
* here and those shouldn't be collapsed. However be abundantly
|
||||
* cautious and handle the !PG_table case too.
|
||||
*/
|
||||
if (PageTable((ptdesc_page(ptdesc))))
|
||||
pagetable_dtor_free(ptdesc);
|
||||
else
|
||||
pagetable_free(ptdesc);
|
||||
}
|
||||
}
|
||||
|
||||
static void cpa_collapse_large_pages(struct cpa_data *cpa)
|
||||
{
|
||||
/*
|
||||
* Take the mmap write lock on init_mm to:
|
||||
* - Avoid a use-after-free if raced by ptdump (which takes its own
|
||||
* write lock on init_mm).
|
||||
* - Serialise concurrent CPA walkers.
|
||||
*/
|
||||
scoped_guard(mmap_write_lock, &init_mm)
|
||||
__cpa_collapse_large_pages(cpa);
|
||||
}
|
||||
|
||||
static void cpa_flush(struct cpa_data *cpa, int cache)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
@ -1120,11 +1142,10 @@ static void split_set_pte(struct cpa_data *cpa, pte_t *pte, unsigned long pfn,
|
|||
|
||||
static int
|
||||
__split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
|
||||
struct ptdesc *ptdesc)
|
||||
pte_t *pbase)
|
||||
{
|
||||
unsigned long lpaddr, lpinc, ref_pfn, pfn, pfninc = 1;
|
||||
struct page *base = ptdesc_page(ptdesc);
|
||||
pte_t *pbase = (pte_t *)page_address(base);
|
||||
struct page *base = virt_to_page(pbase);
|
||||
unsigned int i, level;
|
||||
pgprot_t ref_prot;
|
||||
bool nx, rw;
|
||||
|
|
@ -1224,16 +1245,20 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
|
|||
static int split_large_page(struct cpa_data *cpa, pte_t *kpte,
|
||||
unsigned long address)
|
||||
{
|
||||
struct ptdesc *ptdesc;
|
||||
pte_t *pte;
|
||||
|
||||
spin_unlock(&cpa_lock);
|
||||
ptdesc = pagetable_alloc(GFP_KERNEL, 0);
|
||||
if (cpa->init_mm_read_locked)
|
||||
mmap_read_unlock(&init_mm);
|
||||
pte = pte_alloc_one_kernel(&init_mm);
|
||||
if (cpa->init_mm_read_locked)
|
||||
mmap_read_lock(&init_mm);
|
||||
spin_lock(&cpa_lock);
|
||||
if (!ptdesc)
|
||||
if (!pte)
|
||||
return -ENOMEM;
|
||||
|
||||
if (__split_large_page(cpa, kpte, address, ptdesc))
|
||||
pagetable_free(ptdesc);
|
||||
if (__split_large_page(cpa, kpte, address, pte))
|
||||
pte_free_kernel(&init_mm, pte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2121,7 +2146,11 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
|
|||
cpa.curpage = 0;
|
||||
cpa.force_split = force_split;
|
||||
|
||||
ret = __change_page_attr_set_clr(&cpa, 1);
|
||||
/* Avoid race with concurrent CPA collapse. */
|
||||
cpa.init_mm_read_locked = true;
|
||||
scoped_guard(mmap_read_lock, &init_mm)
|
||||
ret = __change_page_attr_set_clr(&cpa, 1);
|
||||
cpa.init_mm_read_locked = false;
|
||||
|
||||
/*
|
||||
* Check whether we really changed something:
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ struct gen_pool;
|
|||
#define PMU_EV_TYPE_IDLE 0x20
|
||||
|
||||
enum ethosu_cmds {
|
||||
NPU_OP_STOP = 0x0,
|
||||
NPU_OP_CONV = 0x2,
|
||||
NPU_OP_DEPTHWISE = 0x3,
|
||||
NPU_OP_POOL = 0x5,
|
||||
|
|
|
|||
|
|
@ -281,8 +281,6 @@ static int ethosu_device_suspend(struct device *dev)
|
|||
|
||||
static int ethosu_sram_init(struct ethosu_device *ethosudev)
|
||||
{
|
||||
ethosudev->npu_info.sram_size = 0;
|
||||
|
||||
ethosudev->srampool = of_gen_pool_get(ethosudev->base.dev->of_node, "sram", 0);
|
||||
if (!ethosudev->srampool)
|
||||
return 0;
|
||||
|
|
@ -293,6 +291,7 @@ static int ethosu_sram_init(struct ethosu_device *ethosudev)
|
|||
ethosudev->npu_info.sram_size,
|
||||
ðosudev->sramphys);
|
||||
if (!ethosudev->sram) {
|
||||
ethosudev->npu_info.sram_size = 0;
|
||||
dev_err(ethosudev->base.dev, "failed to allocate from SRAM pool\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
struct ethosu_validated_cmdstream_info __free(kfree) *info = kzalloc_obj(*info);
|
||||
struct ethosu_device *edev = to_ethosu_device(ddev);
|
||||
u32 *bocmds = bo->base.vaddr;
|
||||
bool ends_with_stop = false;
|
||||
struct cmd_state st;
|
||||
int i, ret;
|
||||
|
||||
|
|
@ -426,6 +427,11 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
}
|
||||
|
||||
switch (cmd) {
|
||||
case NPU_OP_STOP:
|
||||
if (i != size / 4 - 1)
|
||||
return -EINVAL;
|
||||
ends_with_stop = true;
|
||||
break;
|
||||
case NPU_OP_DMA_START:
|
||||
srclen = dma_length(info, &st.dma, &st.dma.src);
|
||||
dstlen = dma_length(info, &st.dma, &st.dma.dst);
|
||||
|
|
@ -688,6 +694,9 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
}
|
||||
}
|
||||
|
||||
if (!ends_with_stop)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < NPU_BASEP_REGION_MAX; i++) {
|
||||
if (!info->region_size[i])
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ int ethosu_job_init(struct ethosu_device *edev)
|
|||
ret = devm_request_threaded_irq(dev, edev->irq,
|
||||
ethosu_job_irq_handler,
|
||||
ethosu_job_irq_handler_thread,
|
||||
IRQF_SHARED, KBUILD_MODNAME,
|
||||
0, KBUILD_MODNAME,
|
||||
edev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request irq\n");
|
||||
|
|
@ -374,12 +374,10 @@ int ethosu_job_open(struct ethosu_file_priv *ethosu_priv)
|
|||
{
|
||||
struct ethosu_device *dev = ethosu_priv->edev;
|
||||
struct drm_gpu_scheduler *sched = &dev->sched;
|
||||
int ret;
|
||||
|
||||
ret = drm_sched_entity_init(ðosu_priv->sched_entity,
|
||||
DRM_SCHED_PRIORITY_NORMAL,
|
||||
&sched, 1, NULL);
|
||||
return WARN_ON(ret);
|
||||
return drm_sched_entity_init(ðosu_priv->sched_entity,
|
||||
DRM_SCHED_PRIORITY_NORMAL,
|
||||
&sched, 1, NULL);
|
||||
}
|
||||
|
||||
void ethosu_job_close(struct ethosu_file_priv *ethosu_priv)
|
||||
|
|
@ -449,13 +447,13 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file
|
|||
if (!cmd_info->region_size[i])
|
||||
continue;
|
||||
if (i == ETHOSU_SRAM_REGION) {
|
||||
if (cmd_info->region_size[i] <= edev->npu_info.sram_size)
|
||||
if (cmd_info->region_size[i] <= ejob->sram_size)
|
||||
continue;
|
||||
|
||||
dev_err(dev->dev,
|
||||
"cmd stream region %d size greater than SRAM size (%llu > %u)\n",
|
||||
"cmd stream region %d size greater than job SRAM size (%llu > %u)\n",
|
||||
i, cmd_info->region_size[i],
|
||||
edev->npu_info.sram_size);
|
||||
ejob->sram_size);
|
||||
ret = -EINVAL;
|
||||
goto out_cleanup_job;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,17 @@ MODULE_PARM_DESC(fw_log_level,
|
|||
" error=" __stringify(IVPU_FW_LOG_ERROR)
|
||||
" fatal=" __stringify(IVPU_FW_LOG_FATAL));
|
||||
|
||||
struct ivpu_fw_log_desc {
|
||||
struct vpu_tracing_buffer_header *log;
|
||||
u32 header_size;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset,
|
||||
struct vpu_tracing_buffer_header **out_log)
|
||||
struct ivpu_fw_log_desc *desc)
|
||||
{
|
||||
struct vpu_tracing_buffer_header *log;
|
||||
u32 header_size, size;
|
||||
|
||||
if ((*offset + sizeof(*log)) > ivpu_bo_size(bo))
|
||||
return -EINVAL;
|
||||
|
|
@ -39,26 +46,32 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
|
|||
if (log->vpu_canary_start != VPU_TRACING_BUFFER_CANARY)
|
||||
return -EINVAL;
|
||||
|
||||
if (log->header_size < sizeof(*log) || log->header_size > 1024) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
|
||||
header_size = READ_ONCE(log->header_size);
|
||||
size = READ_ONCE(log->size);
|
||||
|
||||
if (header_size < sizeof(*log) || header_size > 1024) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", header_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (log->size < log->header_size) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
if ((char *)log + size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
if (size < header_size) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x < header size 0x%x\n",
|
||||
size, header_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*out_log = log;
|
||||
*offset += log->size;
|
||||
desc->log = log;
|
||||
desc->header_size = header_size;
|
||||
desc->size = size;
|
||||
*offset += size;
|
||||
|
||||
ivpu_dbg(vdev, FW_BOOT,
|
||||
"FW log name \"%s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
|
||||
log->name, log->write_index, log->size, log->wrap_count, log->header_version,
|
||||
log->header_size, log->format, log->alignment);
|
||||
"FW log name \"%.*s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d",
|
||||
(int)ARRAY_SIZE(log->name), log->name, log->write_index, size, log->wrap_count,
|
||||
log->header_version, header_size, log->format, log->alignment);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -94,11 +107,12 @@ static void fw_log_print_lines(char *buffer, u32 size, struct drm_printer *p)
|
|||
drm_printf(p, "%s", line);
|
||||
}
|
||||
|
||||
static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const char *prefix,
|
||||
static void fw_log_print_buffer(struct ivpu_fw_log_desc *desc, const char *prefix,
|
||||
bool only_new_msgs, struct drm_printer *p)
|
||||
{
|
||||
char *log_data = (void *)log + log->header_size;
|
||||
u32 data_size = log->size - log->header_size;
|
||||
struct vpu_tracing_buffer_header *log = desc->log;
|
||||
char *log_data = (void *)log + desc->header_size;
|
||||
u32 data_size = desc->size - desc->header_size;
|
||||
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
|
||||
u32 log_end = READ_ONCE(log->write_index);
|
||||
|
||||
|
|
@ -109,7 +123,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
|
||||
if (log->wrap_count == log->read_wrap_count) {
|
||||
if (log_end <= log_start) {
|
||||
drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name);
|
||||
drm_printf(p, "==== %s \"%.*s\" log empty ====\n", prefix,
|
||||
(int)ARRAY_SIZE(log->name), log->name);
|
||||
return;
|
||||
}
|
||||
} else if (log->wrap_count == log->read_wrap_count + 1) {
|
||||
|
|
@ -119,7 +134,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
log_start = log_end;
|
||||
}
|
||||
|
||||
drm_printf(p, "==== %s \"%s\" log start ====\n", prefix, log->name);
|
||||
drm_printf(p, "==== %s \"%.*s\" log start ====\n", prefix, (int)ARRAY_SIZE(log->name),
|
||||
log->name);
|
||||
if (log_end > log_start) {
|
||||
fw_log_print_lines(log_data + log_start, log_end - log_start, p);
|
||||
} else {
|
||||
|
|
@ -127,18 +143,19 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
fw_log_print_lines(log_data, log_end, p);
|
||||
}
|
||||
drm_printf(p, "\n\x1b[0m"); /* add new line and clear formatting */
|
||||
drm_printf(p, "==== %s \"%s\" log end ====\n", prefix, log->name);
|
||||
drm_printf(p, "==== %s \"%.*s\" log end ====\n", prefix, (int)ARRAY_SIZE(log->name),
|
||||
log->name);
|
||||
}
|
||||
|
||||
static void
|
||||
fw_log_print_all_in_bo(struct ivpu_device *vdev, const char *name,
|
||||
struct ivpu_bo *bo, bool only_new_msgs, struct drm_printer *p)
|
||||
{
|
||||
struct vpu_tracing_buffer_header *log;
|
||||
struct ivpu_fw_log_desc desc;
|
||||
u32 next = 0;
|
||||
|
||||
while (fw_log_from_bo(vdev, bo, &next, &log) == 0)
|
||||
fw_log_print_buffer(log, name, only_new_msgs, p);
|
||||
while (fw_log_from_bo(vdev, bo, &next, &desc) == 0)
|
||||
fw_log_print_buffer(&desc, name, only_new_msgs, p);
|
||||
}
|
||||
|
||||
void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p)
|
||||
|
|
@ -149,36 +166,36 @@ void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_
|
|||
|
||||
void ivpu_fw_log_mark_read(struct ivpu_device *vdev)
|
||||
{
|
||||
struct vpu_tracing_buffer_header *log;
|
||||
struct ivpu_fw_log_desc desc;
|
||||
u32 next;
|
||||
|
||||
next = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
|
||||
log->read_index = READ_ONCE(log->write_index);
|
||||
log->read_wrap_count = READ_ONCE(log->wrap_count);
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
|
||||
desc.log->read_index = READ_ONCE(desc.log->write_index);
|
||||
desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
|
||||
}
|
||||
|
||||
next = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
|
||||
log->read_index = READ_ONCE(log->write_index);
|
||||
log->read_wrap_count = READ_ONCE(log->wrap_count);
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
|
||||
desc.log->read_index = READ_ONCE(desc.log->write_index);
|
||||
desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count);
|
||||
}
|
||||
}
|
||||
|
||||
void ivpu_fw_log_reset(struct ivpu_device *vdev)
|
||||
{
|
||||
struct vpu_tracing_buffer_header *log;
|
||||
struct ivpu_fw_log_desc desc;
|
||||
u32 next;
|
||||
|
||||
next = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) {
|
||||
log->read_index = 0;
|
||||
log->read_wrap_count = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) {
|
||||
desc.log->read_index = 0;
|
||||
desc.log->read_wrap_count = 0;
|
||||
}
|
||||
|
||||
next = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) {
|
||||
log->read_index = 0;
|
||||
log->read_wrap_count = 0;
|
||||
while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) {
|
||||
desc.log->read_index = 0;
|
||||
desc.log->read_wrap_count = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,15 +87,23 @@ static inline bool ivpu_bo_is_resident(struct ivpu_bo *bo)
|
|||
return !!bo->base.pages;
|
||||
}
|
||||
|
||||
static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr)
|
||||
static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u64 vpu_addr, u64 size)
|
||||
{
|
||||
u64 bo_size = ivpu_bo_size(bo);
|
||||
u64 offset;
|
||||
|
||||
if (vpu_addr < bo->vpu_addr)
|
||||
return NULL;
|
||||
|
||||
if (vpu_addr >= (bo->vpu_addr + ivpu_bo_size(bo)))
|
||||
if (size > bo_size)
|
||||
return NULL;
|
||||
|
||||
return ivpu_bo_vaddr(bo) + (vpu_addr - bo->vpu_addr);
|
||||
offset = vpu_addr - bo->vpu_addr;
|
||||
|
||||
if (offset > bo_size - size)
|
||||
return NULL;
|
||||
|
||||
return ivpu_bo_vaddr(bo) + offset;
|
||||
}
|
||||
|
||||
static inline u32 cpu_to_vpu_addr(struct ivpu_bo *bo, void *cpu_addr)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr);
|
||||
tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
|
||||
if (drm_WARN_ON(&vdev->drm, !tx_buf)) {
|
||||
gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
|
||||
return -EIO;
|
||||
|
|
@ -420,7 +420,7 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
|
|||
return;
|
||||
}
|
||||
|
||||
ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr);
|
||||
ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr, sizeof(*ipc_hdr));
|
||||
if (!ipc_hdr) {
|
||||
ivpu_warn_ratelimited(vdev, "IPC msg 0x%x out of range\n", vpu_addr);
|
||||
continue;
|
||||
|
|
@ -429,7 +429,8 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
|
|||
|
||||
jsm_msg = NULL;
|
||||
if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) {
|
||||
jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr);
|
||||
jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr,
|
||||
sizeof(*jsm_msg));
|
||||
if (!jsm_msg) {
|
||||
ivpu_warn_ratelimited(vdev, "JSM msg 0x%x out of range\n",
|
||||
ipc_hdr->data_addr);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -404,6 +404,12 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
|||
if (tfd_index > txq->count)
|
||||
return -ERANGE;
|
||||
|
||||
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
|
||||
bt_dev_err(hdev, "TX skb too large (%u > %u)", skb->len,
|
||||
BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* Firmware raises alive interrupt on HCI_OP_RESET or
|
||||
* BTINTEL_HCI_OP_RESET
|
||||
*/
|
||||
|
|
@ -502,7 +508,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data)
|
|||
|
||||
frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM];
|
||||
|
||||
if (frbd_index > rxq->count)
|
||||
if (frbd_index >= rxq->count)
|
||||
return -ERANGE;
|
||||
|
||||
/* Prepare for RX submit. It updates the FRBD with the address of DMA
|
||||
|
|
|
|||
|
|
@ -721,7 +721,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
|
|||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(data->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
status = BTMTK_WMT_ON_UNDONE;
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
|
||||
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
|
||||
if (!wmt_evt) {
|
||||
bt_dev_err(hdev, "WMT event too short (%u bytes)",
|
||||
bdev->evt_skb->len);
|
||||
err = -EINVAL;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
if (wmt_evt->whdr.op != hdr->op) {
|
||||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
|
|
@ -233,6 +240,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(bdev->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
|
|
@ -1244,10 +1262,8 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
|
|||
wmt_params.status = NULL;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ignore_wmt_cmd:
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
|
|
|
|||
|
|
@ -151,7 +151,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
|
||||
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
|
||||
if (!wmt_evt) {
|
||||
bt_dev_err(hdev, "WMT event too short (%u bytes)",
|
||||
bdev->evt_skb->len);
|
||||
err = -EINVAL;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
if (wmt_evt->whdr.op != hdr->op) {
|
||||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
|
|
@ -167,6 +174,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(bdev->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ static struct usb_driver btusb_driver;
|
|||
#define BTUSB_BROKEN_EXT_SCAN BIT(29)
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/*
|
||||
* NXP IW610 (0471:0215): the composite device reports Bluetooth
|
||||
* class at the whole-device level, so the generic entry below
|
||||
* would also match this WiFi vendor interface. Ignore it here
|
||||
* first so mwifiex-nxp can bind it instead.
|
||||
*/
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff),
|
||||
.driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
|
|
@ -477,6 +486,14 @@ static const struct usb_device_id quirks_table[] = {
|
|||
{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
|
||||
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
|
||||
|
||||
/*
|
||||
* NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as
|
||||
* the 0x1286 entries above). Scoped to the BT interface class,
|
||||
* not just VID/PID -- see the btusb_table entry above.
|
||||
*/
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_MARVELL },
|
||||
|
||||
/* Intel Bluetooth devices */
|
||||
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
|
|
|
|||
|
|
@ -2228,8 +2228,8 @@ static void qca_power_off(struct hci_uart *hu)
|
|||
bool sw_ctrl_state;
|
||||
struct qca_power *power;
|
||||
|
||||
/* From this point we go into power off state. But serial port is
|
||||
* still open, stop queueing the IBS data and flush all the buffered
|
||||
/* From this point we go into power off state. But serial port may
|
||||
* still be open, stop queueing the IBS data and flush all the buffered
|
||||
* data in skb's.
|
||||
*/
|
||||
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
||||
|
|
@ -2251,8 +2251,14 @@ static void qca_power_off(struct hci_uart *hu)
|
|||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
/* Both of these write to the serial port which may have
|
||||
* already been closed by hci_uart_close(), which closes
|
||||
* the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set.
|
||||
*/
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1202,6 +1202,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
const enum dpll_pin_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
void *pin_priv, *ref_sync_pin_priv;
|
||||
const struct dpll_pin_ops *ops;
|
||||
enum dpll_pin_state old_state;
|
||||
struct dpll_pin *ref_sync_pin;
|
||||
|
|
@ -1230,9 +1231,15 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
dpll = ref->dpll;
|
||||
ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
pin_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
|
||||
/* Pin may have been unregistered from this dpll already */
|
||||
if (!ref_sync_pin_priv) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"reference sync pin not registered with the dpll");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
|
||||
&old_state, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG(extack, "unable to get old reference sync state");
|
||||
|
|
@ -1241,9 +1248,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
if (state == old_state)
|
||||
return 0;
|
||||
|
||||
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
ret = ops->ref_sync_set(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
|
||||
state, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -692,7 +692,8 @@ static int gpio_virtuser_interrupts_set(void *data, u64 val)
|
|||
atomic_set(&ld->irq, irq);
|
||||
} else {
|
||||
irq = atomic_xchg(&ld->irq, 0);
|
||||
free_irq(irq, ld);
|
||||
if (irq)
|
||||
free_irq(irq, ld);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -788,13 +788,13 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
|
|||
if (!of_property_read_bool(rd->dn, "gpio-hog"))
|
||||
return NOTIFY_DONE; /* not for us */
|
||||
|
||||
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
gdev = of_find_gpio_device_by_node(rd->dn->parent);
|
||||
if (!gdev)
|
||||
return NOTIFY_DONE; /* not for us */
|
||||
|
||||
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
ret = gpiochip_add_hog(gpio_device_get_chip(gdev), of_fwnode_handle(rd->dn));
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to add hogs for %pOF\n", __func__,
|
||||
|
|
|
|||
|
|
@ -261,10 +261,13 @@ static int gpio_shared_of_traverse(struct device_node *curr)
|
|||
con_id[con_id_len - suffix_len] = '\0';
|
||||
}
|
||||
|
||||
ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)),
|
||||
con_id, args.args[1]);
|
||||
if (!ref)
|
||||
struct fwnode_handle *curr_fwnode =
|
||||
fwnode_handle_get(of_fwnode_handle(curr));
|
||||
ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]);
|
||||
if (!ref) {
|
||||
fwnode_handle_put(curr_fwnode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!list_empty(&entry->refs))
|
||||
pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ config DRM_ADP
|
|||
select DRM_KMS_HELPER
|
||||
select DRM_BRIDGE_CONNECTOR
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_DMA_HELPER
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select DRM_PANEL_BRIDGE
|
||||
select VIDEOMODE_HELPERS
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/sizes.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
|
|
@ -355,6 +356,8 @@ int ast_cursor_plane_init(struct ast_device *ast)
|
|||
}
|
||||
drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs);
|
||||
drm_plane_enable_fb_damage_clips(cursor_plane);
|
||||
drm_plane_create_blend_mode_property(cursor_plane,
|
||||
BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1263,10 +1263,13 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
|||
return input_fmts;
|
||||
}
|
||||
|
||||
static bool tc358768_mode_fixup(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static int tc358768_bridge_atomic_check(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
|
||||
/* Default to positive sync */
|
||||
|
||||
if (!(adjusted_mode->flags &
|
||||
|
|
@ -1277,13 +1280,15 @@ static bool tc358768_mode_fixup(struct drm_bridge *bridge,
|
|||
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
|
||||
adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
return true;
|
||||
bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs tc358768_bridge_funcs = {
|
||||
.attach = tc358768_bridge_attach,
|
||||
.mode_valid = tc358768_bridge_mode_valid,
|
||||
.mode_fixup = tc358768_mode_fixup,
|
||||
.atomic_check = tc358768_bridge_atomic_check,
|
||||
.atomic_pre_enable = tc358768_bridge_atomic_pre_enable,
|
||||
.atomic_enable = tc358768_bridge_atomic_enable,
|
||||
.atomic_disable = tc358768_bridge_atomic_disable,
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ static int sn65dsi83_reset_pipe(struct sn65dsi83 *sn65dsi83)
|
|||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sn65dsi83_reset_work(struct work_struct *ws)
|
||||
|
|
@ -419,11 +419,13 @@ static void sn65dsi83_reset_work(struct work_struct *ws)
|
|||
ret = sn65dsi83_reset_pipe(ctx);
|
||||
if (ret) {
|
||||
dev_err(ctx->dev, "reset pipe failed %pe\n", ERR_PTR(ret));
|
||||
return;
|
||||
goto bridge_exit;
|
||||
}
|
||||
|
||||
if (ctx->irq)
|
||||
enable_irq(ctx->irq);
|
||||
|
||||
bridge_exit:
|
||||
drm_bridge_exit(idx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -322,6 +322,19 @@ int drm_exec_prepare_array(struct drm_exec *exec,
|
|||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Make sure to lock a contended object even when no objects are
|
||||
* given, otherwise drm_exec_retry_on_contention() would loop
|
||||
* forever on patterns like:
|
||||
*
|
||||
* ret = drm_exec_prepare_array(exec, objs, num_objects, ...);
|
||||
* drm_exec_retry_on_contention(exec);
|
||||
*
|
||||
* with num_objects == 0.
|
||||
*/
|
||||
if (!num_objects)
|
||||
return drm_exec_lock_contended(exec);
|
||||
|
||||
for (unsigned int i = 0; i < num_objects; ++i) {
|
||||
ret = drm_exec_prepare_obj(exec, objects[i], num_fences);
|
||||
if (unlikely(ret))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ config DRM_LOGICVC
|
|||
depends on OF || COMPILE_TEST
|
||||
select DRM_CLIENT_SELECTION
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_DMA_HELPER
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select REGMAP
|
||||
select REGMAP_MMIO
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
|
@ -993,6 +994,9 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
|
|||
|
||||
drm_plane_helper_add(plane, helper_funcs);
|
||||
|
||||
drm_plane_create_blend_mode_property(plane,
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
|
||||
return plane;
|
||||
|
||||
free_plane:
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ config ROCKCHIP_CDN_DP
|
|||
|
||||
config ROCKCHIP_DW_DP
|
||||
bool "Rockchip specific extensions for Synopsys DW DP"
|
||||
select DRM_BRIDGE_CONNECTOR
|
||||
help
|
||||
This selects support for Rockchip SoC specific extensions
|
||||
to enable Synopsys DesignWare Cores based DisplayPort transmit
|
||||
|
|
@ -145,6 +146,8 @@ config ROCKCHIP_RGB
|
|||
config ROCKCHIP_RK3066_HDMI
|
||||
bool "Rockchip specific extensions for RK3066 HDMI"
|
||||
depends on DRM_ROCKCHIP
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_BRIDGE_CONNECTOR
|
||||
help
|
||||
This selects support for Rockchip SoC specific extensions
|
||||
for the RK3066 HDMI driver. If you want to enable
|
||||
|
|
|
|||
|
|
@ -241,10 +241,11 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
|
|||
of_graph_get_remote_port(endpoint.local_node);
|
||||
|
||||
of_property_read_u32(remote_port, "reg", &port_id);
|
||||
sprintf(name, "%s vp%d", remote_port_parent->full_name, port_id);
|
||||
snprintf(name, sizeof(name), "%s vp%d",
|
||||
remote_port_parent->full_name, port_id);
|
||||
} else {
|
||||
sprintf(name, "%s %s",
|
||||
remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb");
|
||||
snprintf(name, sizeof(name), "%s %s",
|
||||
remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb");
|
||||
}
|
||||
|
||||
DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2025 Valve Corporation */
|
||||
|
||||
#include <kunit/device.h>
|
||||
|
||||
#include "sched_tests.h"
|
||||
|
||||
/*
|
||||
|
|
@ -288,6 +290,7 @@ static const struct drm_sched_backend_ops drm_mock_scheduler_ops = {
|
|||
*/
|
||||
struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout)
|
||||
{
|
||||
static unsigned int instance;
|
||||
struct drm_sched_init_args args = {
|
||||
.ops = &drm_mock_scheduler_ops,
|
||||
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
|
||||
|
|
@ -297,11 +300,19 @@ struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout)
|
|||
.name = "drm-mock-scheduler",
|
||||
};
|
||||
struct drm_mock_scheduler *sched;
|
||||
struct device *dev;
|
||||
char name[64];
|
||||
int ret;
|
||||
|
||||
sched = kunit_kzalloc(test, sizeof(*sched), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, sched);
|
||||
|
||||
snprintf(name, sizeof(name), "%s-%u", args.name, instance++);
|
||||
dev = kunit_device_register(test, name);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
|
||||
|
||||
args.dev = dev;
|
||||
|
||||
ret = drm_sched_init(&sched->base, &args);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
|
@ -540,6 +541,9 @@ static struct drm_plane *vbox_create_plane(struct vbox_private *vbox,
|
|||
|
||||
drm_plane_helper_add(plane, helper_funcs);
|
||||
|
||||
drm_plane_create_blend_mode_property(plane,
|
||||
BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
|
||||
return plane;
|
||||
|
||||
free_plane:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
|
|
@ -609,6 +610,9 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
|
|||
|
||||
if (type == DRM_PLANE_TYPE_PRIMARY)
|
||||
drm_plane_enable_fb_damage_clips(plane);
|
||||
else if (type == DRM_PLANE_TYPE_CURSOR)
|
||||
drm_plane_create_blend_mode_property(plane,
|
||||
BIT(DRM_MODE_BLEND_PREMULTI));
|
||||
|
||||
return plane;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user