Merge 34e1a5d43c ("Merge tag 'random-6.12-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random") into android-mainline
Steps on the way to 6.12-rc1 Bug: 367265496 Change-Id: I3233ffc3cac200a93cc7c94857d2accad78fa535 Signed-off-by: Matthias Maennich <maennich@google.com>
This commit is contained in:
@@ -3,29 +3,52 @@ dm-delay
|
||||
========
|
||||
|
||||
Device-Mapper's "delay" target delays reads and/or writes
|
||||
and maps them to different devices.
|
||||
and/or flushs and optionally maps them to different devices.
|
||||
|
||||
Parameters::
|
||||
Arguments::
|
||||
|
||||
<device> <offset> <delay> [<write_device> <write_offset> <write_delay>
|
||||
[<flush_device> <flush_offset> <flush_delay>]]
|
||||
|
||||
With separate write parameters, the first set is only used for reads.
|
||||
Table line has to either have 3, 6 or 9 arguments:
|
||||
|
||||
3: apply offset and delay to read, write and flush operations on device
|
||||
|
||||
6: apply offset and delay to device, also apply write_offset and write_delay
|
||||
to write and flush operations on optionally different write_device with
|
||||
optionally different sector offset
|
||||
|
||||
9: same as 6 arguments plus define flush_offset and flush_delay explicitely
|
||||
on/with optionally different flush_device/flush_offset.
|
||||
|
||||
Offsets are specified in sectors.
|
||||
|
||||
Delays are specified in milliseconds.
|
||||
|
||||
|
||||
Example scripts
|
||||
===============
|
||||
|
||||
::
|
||||
|
||||
#!/bin/sh
|
||||
# Create device delaying rw operation for 500ms
|
||||
echo "0 `blockdev --getsz $1` delay $1 0 500" | dmsetup create delayed
|
||||
#
|
||||
# Create mapped device named "delayed" delaying read, write and flush operations for 500ms.
|
||||
#
|
||||
dmsetup create delayed --table "0 `blockdev --getsz $1` delay $1 0 500"
|
||||
|
||||
::
|
||||
|
||||
#!/bin/sh
|
||||
# Create device delaying only write operation for 500ms and
|
||||
# splitting reads and writes to different devices $1 $2
|
||||
echo "0 `blockdev --getsz $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
|
||||
#
|
||||
# Create mapped device delaying write and flush operations for 400ms and
|
||||
# splitting reads to device $1 but writes and flushs to different device $2
|
||||
# to different offsets of 2048 and 4096 sectors respectively.
|
||||
#
|
||||
dmsetup create delayed --table "0 `blockdev --getsz $1` delay $1 2048 0 $2 4096 400"
|
||||
|
||||
::
|
||||
#!/bin/sh
|
||||
#
|
||||
# Create mapped device delaying reads for 50ms, writes for 100ms and flushs for 333ms
|
||||
# onto the same backing device at offset 0 sectors.
|
||||
#
|
||||
dmsetup create delayed --table "0 `blockdev --getsz $1` delay $1 0 50 $2 0 100 $1 0 333"
|
||||
|
||||
@@ -160,6 +160,10 @@ iv_large_sectors
|
||||
The <iv_offset> must be multiple of <sector_size> (in 512 bytes units)
|
||||
if this flag is specified.
|
||||
|
||||
integrity_key_size:<bytes>
|
||||
Use an integrity key of <bytes> size instead of using an integrity key size
|
||||
of the digest size of the used HMAC algorithm.
|
||||
|
||||
|
||||
Module parameters::
|
||||
max_read_size
|
||||
|
||||
@@ -251,7 +251,12 @@ The messages are:
|
||||
by the vdostats userspace program to interpret the output
|
||||
buffer.
|
||||
|
||||
dump:
|
||||
config:
|
||||
Outputs useful vdo configuration information. Mostly used
|
||||
by users who want to recreate a similar VDO volume and
|
||||
want to know the creation configuration used.
|
||||
|
||||
dump:
|
||||
Dumps many internal structures to the system log. This is
|
||||
not always safe to run, so it should only be used to debug
|
||||
a hung vdo. Optional parameters to specify structures to
|
||||
|
||||
@@ -85,6 +85,38 @@ to CPUINTC directly::
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
Advanced Extended IRQ model
|
||||
===========================
|
||||
|
||||
In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt go
|
||||
to CPUINTC directly, CPU UARTS interrupts go to LIOINTC, PCH-MSI interrupts go
|
||||
to AVECINTC, and then go to CPUINTC directly, while all other devices interrupts
|
||||
go to PCH-PIC/PCH-LPC and gathered by EIOINTC, and then go to CPUINTC directly::
|
||||
|
||||
+-----+ +-----------------------+ +-------+
|
||||
| IPI | --> | CPUINTC | <-- | Timer |
|
||||
+-----+ +-----------------------+ +-------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+---------+ +----------+ +---------+ +-------+
|
||||
| EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs |
|
||||
+---------+ +----------+ +---------+ +-------+
|
||||
^ ^
|
||||
| |
|
||||
+---------+ +---------+
|
||||
| PCH-PIC | | PCH-MSI |
|
||||
+---------+ +---------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+---------+ +---------+ +---------+
|
||||
| Devices | | PCH-LPC | | Devices |
|
||||
+---------+ +---------+ +---------+
|
||||
^
|
||||
|
|
||||
+---------+
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
ACPI-related definitions
|
||||
========================
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
==================================
|
||||
CXL Access Coordinates Computation
|
||||
==================================
|
||||
|
||||
Shared Upstream Link Calculation
|
||||
================================
|
||||
For certain CXL region construction with endpoints behind CXL switches (SW) or
|
||||
Root Ports (RP), there is the possibility of the total bandwidth for all
|
||||
the endpoints behind a switch being more than the switch upstream link.
|
||||
A similar situation can occur within the host, upstream of the root ports.
|
||||
The CXL driver performs an additional pass after all the targets have
|
||||
arrived for a region in order to recalculate the bandwidths with possible
|
||||
upstream link being a limiting factor in mind.
|
||||
|
||||
The algorithm assumes the configuration is a symmetric topology as that
|
||||
maximizes performance. When asymmetric topology is detected, the calculation
|
||||
is aborted. An asymmetric topology is detected during topology walk where the
|
||||
number of RPs detected as a grandparent is not equal to the number of devices
|
||||
iterated in the same iteration loop. The assumption is made that subtle
|
||||
asymmetry in properties does not happen and all paths to EPs are equal.
|
||||
|
||||
There can be multiple switches under an RP. There can be multiple RPs under
|
||||
a CXL Host Bridge (HB). There can be multiple HBs under a CXL Fixed Memory
|
||||
Window Structure (CFMWS).
|
||||
|
||||
An example hierarchy:
|
||||
|
||||
> CFMWS 0
|
||||
> |
|
||||
> _________|_________
|
||||
> | |
|
||||
> ACPI0017-0 ACPI0017-1
|
||||
> GP0/HB0/ACPI0016-0 GP1/HB1/ACPI0016-1
|
||||
> | | | |
|
||||
> RP0 RP1 RP2 RP3
|
||||
> | | | |
|
||||
> SW 0 SW 1 SW 2 SW 3
|
||||
> | | | | | | | |
|
||||
> EP0 EP1 EP2 EP3 EP4 EP5 EP6 EP7
|
||||
|
||||
Computation for the example hierarchy:
|
||||
|
||||
Min (GP0 to CPU BW,
|
||||
Min(SW 0 Upstream Link to RP0 BW,
|
||||
Min(SW0SSLBIS for SW0DSP0 (EP0), EP0 DSLBIS, EP0 Upstream Link) +
|
||||
Min(SW0SSLBIS for SW0DSP1 (EP1), EP1 DSLBIS, EP1 Upstream link)) +
|
||||
Min(SW 1 Upstream Link to RP1 BW,
|
||||
Min(SW1SSLBIS for SW1DSP0 (EP2), EP2 DSLBIS, EP2 Upstream Link) +
|
||||
Min(SW1SSLBIS for SW1DSP1 (EP3), EP3 DSLBIS, EP3 Upstream link))) +
|
||||
Min (GP1 to CPU BW,
|
||||
Min(SW 2 Upstream Link to RP2 BW,
|
||||
Min(SW2SSLBIS for SW2DSP0 (EP4), EP4 DSLBIS, EP4 Upstream Link) +
|
||||
Min(SW2SSLBIS for SW2DSP1 (EP5), EP5 DSLBIS, EP5 Upstream link)) +
|
||||
Min(SW 3 Upstream Link to RP3 BW,
|
||||
Min(SW3SSLBIS for SW3DSP0 (EP6), EP6 DSLBIS, EP6 Upstream Link) +
|
||||
Min(SW3SSLBIS for SW3DSP1 (EP7), EP7 DSLBIS, EP7 Upstream link))))
|
||||
|
||||
The calculation starts at cxl_region_shared_upstream_perf_update(). A xarray
|
||||
is created to collect all the endpoint bandwidths via the
|
||||
cxl_endpoint_gather_bandwidth() function. The min() of bandwidth from the
|
||||
endpoint CDAT and the upstream link bandwidth is calculated. If the endpoint
|
||||
has a CXL switch as a parent, then min() of calculated bandwidth and the
|
||||
bandwidth from the SSLBIS for the switch downstream port that is associated
|
||||
with the endpoint is calculated. The final bandwidth is stored in a
|
||||
'struct cxl_perf_ctx' in the xarray indexed by a device pointer. If the
|
||||
endpoint is direct attached to a root port (RP), the device pointer would be an
|
||||
RP device. If the endpoint is behind a switch, the device pointer would be the
|
||||
upstream device of the parent switch.
|
||||
|
||||
At the next stage, the code walks through one or more switches if they exist
|
||||
in the topology. For endpoints directly attached to RPs, this step is skipped.
|
||||
If there is another switch upstream, the code takes the min() of the current
|
||||
gathered bandwidth and the upstream link bandwidth. If there's a switch
|
||||
upstream, then the SSLBIS of the upstream switch.
|
||||
|
||||
Once the topology walk reaches the RP, whether it's direct attached endpoints
|
||||
or walking through the switch(es), cxl_rp_gather_bandwidth() is called. At
|
||||
this point all the bandwidths are aggregated per each host bridge, which is
|
||||
also the index for the resulting xarray.
|
||||
|
||||
The next step is to take the min() of the per host bridge bandwidth and the
|
||||
bandwidth from the Generic Port (GP). The bandwidths for the GP is retrieved
|
||||
via ACPI tables SRAT/HMAT. The min bandwidth are aggregated under the same
|
||||
ACPI0017 device to form a new xarray.
|
||||
|
||||
Finally, the cxl_region_update_bandwidth() is called and the aggregated
|
||||
bandwidth from all the members of the last xarray is updated for the
|
||||
access coordinates residing in the cxl region (cxlr) context.
|
||||
@@ -8,6 +8,7 @@ Compute Express Link
|
||||
:maxdepth: 1
|
||||
|
||||
memory-devices
|
||||
access-coordinates
|
||||
|
||||
maturity-map
|
||||
|
||||
|
||||
@@ -87,6 +87,38 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC::
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
高级扩展IRQ模型
|
||||
===============
|
||||
|
||||
在这种模型里面,IPI(Inter-Processor Interrupt)和CPU本地时钟中断直接发送到CPUINTC,
|
||||
CPU串口(UARTs)中断发送到LIOINTC,PCH-MSI中断发送到AVECINTC,而后通过AVECINTC直接
|
||||
送达CPUINTC,而其他所有设备的中断则分别发送到所连接的PCH-PIC/PCH-LPC,然后由EIOINTC
|
||||
统一收集,再直接到达CPUINTC::
|
||||
|
||||
+-----+ +-----------------------+ +-------+
|
||||
| IPI | --> | CPUINTC | <-- | Timer |
|
||||
+-----+ +-----------------------+ +-------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+---------+ +----------+ +---------+ +-------+
|
||||
| EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs |
|
||||
+---------+ +----------+ +---------+ +-------+
|
||||
^ ^
|
||||
| |
|
||||
+---------+ +---------+
|
||||
| PCH-PIC | | PCH-MSI |
|
||||
+---------+ +---------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
+---------+ +---------+ +---------+
|
||||
| Devices | | PCH-LPC | | Devices |
|
||||
+---------+ +---------+ +---------+
|
||||
^
|
||||
|
|
||||
+---------+
|
||||
| Devices |
|
||||
+---------+
|
||||
|
||||
ACPI相关的定义
|
||||
==============
|
||||
|
||||
|
||||
+2
-6
@@ -5728,8 +5728,7 @@ L: linux-cxl@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/driver-api/cxl
|
||||
F: drivers/cxl/
|
||||
F: include/linux/einj-cxl.h
|
||||
F: include/linux/cxl-event.h
|
||||
F: include/cxl/
|
||||
F: include/uapi/linux/cxl_mem.h
|
||||
F: tools/testing/cxl/
|
||||
|
||||
@@ -19352,10 +19351,7 @@ F: drivers/char/random.c
|
||||
F: include/linux/random.h
|
||||
F: include/uapi/linux/random.h
|
||||
F: drivers/virt/vmgenid.c
|
||||
F: include/vdso/getrandom.h
|
||||
F: lib/vdso/getrandom.c
|
||||
F: arch/x86/entry/vdso/vgetrandom*
|
||||
F: arch/x86/include/asm/vdso/getrandom*
|
||||
N: ^.*/vdso/[^/]*getrandom[^/]+$
|
||||
|
||||
RAPIDIO SUBSYSTEM
|
||||
M: Matt Porter <mporter@kernel.crashing.org>
|
||||
|
||||
@@ -25,6 +25,8 @@ config LOONGARCH
|
||||
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
|
||||
select ARCH_HAS_PTE_DEVMAP
|
||||
select ARCH_HAS_PTE_SPECIAL
|
||||
select ARCH_HAS_SET_MEMORY
|
||||
select ARCH_HAS_SET_DIRECT_MAP
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_INLINE_READ_LOCK if !PREEMPTION
|
||||
select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION
|
||||
@@ -82,6 +84,7 @@ config LOONGARCH
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
select GENERIC_CPU_DEVICES
|
||||
select GENERIC_CPU_VULNERABILITIES
|
||||
select GENERIC_ENTRY
|
||||
select GENERIC_GETTIMEOFDAY
|
||||
select GENERIC_IOREMAP if !ARCH_IOREMAP
|
||||
@@ -147,7 +150,7 @@ config LOONGARCH
|
||||
select HAVE_LIVEPATCH
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_NMI
|
||||
select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB && !CC_IS_CLANG
|
||||
select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB
|
||||
select HAVE_PCI
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
@@ -267,7 +270,7 @@ config AS_HAS_FCSR_CLASS
|
||||
def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0)
|
||||
|
||||
config AS_HAS_THIN_ADD_SUB
|
||||
def_bool $(cc-option,-Wa$(comma)-mthin-add-sub)
|
||||
def_bool $(cc-option,-Wa$(comma)-mthin-add-sub) || AS_IS_LLVM
|
||||
|
||||
config AS_HAS_LSX_EXTENSION
|
||||
def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define __LL "ll.w "
|
||||
#define __SC "sc.w "
|
||||
#define __AMADD "amadd.w "
|
||||
#define __AMOR "amor.w "
|
||||
#define __AMAND_DB "amand_db.w "
|
||||
#define __AMOR_DB "amor_db.w "
|
||||
#define __AMXOR_DB "amxor_db.w "
|
||||
@@ -22,6 +23,7 @@
|
||||
#define __LL "ll.d "
|
||||
#define __SC "sc.d "
|
||||
#define __AMADD "amadd.d "
|
||||
#define __AMOR "amor.d "
|
||||
#define __AMAND_DB "amand_db.d "
|
||||
#define __AMOR_DB "amor_db.d "
|
||||
#define __AMXOR_DB "amxor_db.d "
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#define cpu_has_lbt_mips cpu_opt(LOONGARCH_CPU_LBT_MIPS)
|
||||
#define cpu_has_lbt (cpu_has_lbt_x86|cpu_has_lbt_arm|cpu_has_lbt_mips)
|
||||
#define cpu_has_csr cpu_opt(LOONGARCH_CPU_CSR)
|
||||
#define cpu_has_iocsr cpu_opt(LOONGARCH_CPU_IOCSR)
|
||||
#define cpu_has_tlb cpu_opt(LOONGARCH_CPU_TLB)
|
||||
#define cpu_has_watch cpu_opt(LOONGARCH_CPU_WATCH)
|
||||
#define cpu_has_vint cpu_opt(LOONGARCH_CPU_VINT)
|
||||
@@ -65,6 +66,7 @@
|
||||
#define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID)
|
||||
#define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR)
|
||||
#define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW)
|
||||
#define cpu_has_lspw cpu_opt(LOONGARCH_CPU_LSPW)
|
||||
#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT)
|
||||
|
||||
#endif /* __ASM_CPU_FEATURES_H */
|
||||
|
||||
@@ -87,19 +87,21 @@ enum cpu_type_enum {
|
||||
#define CPU_FEATURE_LBT_MIPS 12 /* CPU has MIPS Binary Translation */
|
||||
#define CPU_FEATURE_TLB 13 /* CPU has TLB */
|
||||
#define CPU_FEATURE_CSR 14 /* CPU has CSR */
|
||||
#define CPU_FEATURE_WATCH 15 /* CPU has watchpoint registers */
|
||||
#define CPU_FEATURE_VINT 16 /* CPU has vectored interrupts */
|
||||
#define CPU_FEATURE_CSRIPI 17 /* CPU has CSR-IPI */
|
||||
#define CPU_FEATURE_EXTIOI 18 /* CPU has EXT-IOI */
|
||||
#define CPU_FEATURE_PREFETCH 19 /* CPU has prefetch instructions */
|
||||
#define CPU_FEATURE_PMP 20 /* CPU has perfermance counter */
|
||||
#define CPU_FEATURE_SCALEFREQ 21 /* CPU supports cpufreq scaling */
|
||||
#define CPU_FEATURE_FLATMODE 22 /* CPU has flat mode */
|
||||
#define CPU_FEATURE_EIODECODE 23 /* CPU has EXTIOI interrupt pin decode mode */
|
||||
#define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */
|
||||
#define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */
|
||||
#define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */
|
||||
#define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */
|
||||
#define CPU_FEATURE_IOCSR 15 /* CPU has IOCSR */
|
||||
#define CPU_FEATURE_WATCH 16 /* CPU has watchpoint registers */
|
||||
#define CPU_FEATURE_VINT 17 /* CPU has vectored interrupts */
|
||||
#define CPU_FEATURE_CSRIPI 18 /* CPU has CSR-IPI */
|
||||
#define CPU_FEATURE_EXTIOI 19 /* CPU has EXT-IOI */
|
||||
#define CPU_FEATURE_PREFETCH 20 /* CPU has prefetch instructions */
|
||||
#define CPU_FEATURE_PMP 21 /* CPU has perfermance counter */
|
||||
#define CPU_FEATURE_SCALEFREQ 22 /* CPU supports cpufreq scaling */
|
||||
#define CPU_FEATURE_FLATMODE 23 /* CPU has flat mode */
|
||||
#define CPU_FEATURE_EIODECODE 24 /* CPU has EXTIOI interrupt pin decode mode */
|
||||
#define CPU_FEATURE_GUESTID 25 /* CPU has GuestID feature */
|
||||
#define CPU_FEATURE_HYPERVISOR 26 /* CPU has hypervisor (running in VM) */
|
||||
#define CPU_FEATURE_PTW 27 /* CPU has hardware page table walker */
|
||||
#define CPU_FEATURE_LSPW 28 /* CPU has LSPW (lddir/ldpte instructions) */
|
||||
#define CPU_FEATURE_AVECINT 29 /* CPU has AVEC interrupt */
|
||||
|
||||
#define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG)
|
||||
#define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM)
|
||||
@@ -115,6 +117,7 @@ enum cpu_type_enum {
|
||||
#define LOONGARCH_CPU_LBT_ARM BIT_ULL(CPU_FEATURE_LBT_ARM)
|
||||
#define LOONGARCH_CPU_LBT_MIPS BIT_ULL(CPU_FEATURE_LBT_MIPS)
|
||||
#define LOONGARCH_CPU_TLB BIT_ULL(CPU_FEATURE_TLB)
|
||||
#define LOONGARCH_CPU_IOCSR BIT_ULL(CPU_FEATURE_IOCSR)
|
||||
#define LOONGARCH_CPU_CSR BIT_ULL(CPU_FEATURE_CSR)
|
||||
#define LOONGARCH_CPU_WATCH BIT_ULL(CPU_FEATURE_WATCH)
|
||||
#define LOONGARCH_CPU_VINT BIT_ULL(CPU_FEATURE_VINT)
|
||||
@@ -128,6 +131,7 @@ enum cpu_type_enum {
|
||||
#define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID)
|
||||
#define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR)
|
||||
#define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW)
|
||||
#define LOONGARCH_CPU_LSPW BIT_ULL(CPU_FEATURE_LSPW)
|
||||
#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT)
|
||||
|
||||
#endif /* _ASM_CPU_H */
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#define LOONGARCH_CPUCFG1 0x1
|
||||
#define CPUCFG1_ISGR32 BIT(0)
|
||||
#define CPUCFG1_ISGR64 BIT(1)
|
||||
#define CPUCFG1_ISA GENMASK(1, 0)
|
||||
#define CPUCFG1_PAGING BIT(2)
|
||||
#define CPUCFG1_IOCSR BIT(3)
|
||||
#define CPUCFG1_PABITS GENMASK(11, 4)
|
||||
|
||||
@@ -49,12 +49,12 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
|
||||
|
||||
/* Normal, classic get_new_mmu_context */
|
||||
static inline void
|
||||
get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
|
||||
get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, bool *need_flush)
|
||||
{
|
||||
u64 asid = asid_cache(cpu);
|
||||
|
||||
if (!((++asid) & cpu_asid_mask(&cpu_data[cpu])))
|
||||
local_flush_tlb_user(); /* start new asid cycle */
|
||||
*need_flush = true; /* start new asid cycle */
|
||||
|
||||
cpu_context(cpu, mm) = asid_cache(cpu) = asid;
|
||||
}
|
||||
@@ -74,21 +74,34 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void atomic_update_pgd_asid(unsigned long asid, unsigned long pgdl)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"csrwr %[pgdl_val], %[pgdl_reg] \n\t"
|
||||
"csrwr %[asid_val], %[asid_reg] \n\t"
|
||||
: [asid_val] "+r" (asid), [pgdl_val] "+r" (pgdl)
|
||||
: [asid_reg] "i" (LOONGARCH_CSR_ASID), [pgdl_reg] "i" (LOONGARCH_CSR_PGDL)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
bool need_flush = false;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
/* Check if our ASID is of an older version and thus invalid */
|
||||
if (!asid_valid(next, cpu))
|
||||
get_new_mmu_context(next, cpu);
|
||||
|
||||
write_csr_asid(cpu_asid(cpu, next));
|
||||
get_new_mmu_context(next, cpu, &need_flush);
|
||||
|
||||
if (next != &init_mm)
|
||||
csr_write64((unsigned long)next->pgd, LOONGARCH_CSR_PGDL);
|
||||
atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)next->pgd);
|
||||
else
|
||||
csr_write64((unsigned long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
|
||||
atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)invalid_pg_dir);
|
||||
|
||||
if (need_flush)
|
||||
local_flush_tlb_user(); /* Flush tlb after update ASID */
|
||||
|
||||
/*
|
||||
* Mark current->active_mm as not "active" anymore.
|
||||
@@ -135,9 +148,15 @@ drop_mmu_context(struct mm_struct *mm, unsigned int cpu)
|
||||
asid = read_csr_asid() & cpu_asid_mask(¤t_cpu_data);
|
||||
|
||||
if (asid == cpu_asid(cpu, mm)) {
|
||||
bool need_flush = false;
|
||||
|
||||
if (!current->mm || (current->mm == mm)) {
|
||||
get_new_mmu_context(mm, cpu);
|
||||
get_new_mmu_context(mm, cpu, &need_flush);
|
||||
|
||||
write_csr_asid(cpu_asid(cpu, mm));
|
||||
if (need_flush)
|
||||
local_flush_tlb_user(); /* Flush tlb after update ASID */
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,75 +68,6 @@ PERCPU_OP(and, and, &)
|
||||
PERCPU_OP(or, or, |)
|
||||
#undef PERCPU_OP
|
||||
|
||||
static __always_inline unsigned long __percpu_read(void __percpu *ptr, int size)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__ ("ldx.b %[ret], $r21, %[ptr] \n"
|
||||
: [ret] "=&r"(ret)
|
||||
: [ptr] "r"(ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__ ("ldx.h %[ret], $r21, %[ptr] \n"
|
||||
: [ret] "=&r"(ret)
|
||||
: [ptr] "r"(ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__ ("ldx.w %[ret], $r21, %[ptr] \n"
|
||||
: [ret] "=&r"(ret)
|
||||
: [ptr] "r"(ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 8:
|
||||
__asm__ __volatile__ ("ldx.d %[ret], $r21, %[ptr] \n"
|
||||
: [ret] "=&r"(ret)
|
||||
: [ptr] "r"(ptr)
|
||||
: "memory");
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
BUILD_BUG();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline void __percpu_write(void __percpu *ptr, unsigned long val, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("stx.b %[val], $r21, %[ptr] \n"
|
||||
:
|
||||
: [val] "r" (val), [ptr] "r" (ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__("stx.h %[val], $r21, %[ptr] \n"
|
||||
:
|
||||
: [val] "r" (val), [ptr] "r" (ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__("stx.w %[val], $r21, %[ptr] \n"
|
||||
:
|
||||
: [val] "r" (val), [ptr] "r" (ptr)
|
||||
: "memory");
|
||||
break;
|
||||
case 8:
|
||||
__asm__ __volatile__("stx.d %[val], $r21, %[ptr] \n"
|
||||
:
|
||||
: [val] "r" (val), [ptr] "r" (ptr)
|
||||
: "memory");
|
||||
break;
|
||||
default:
|
||||
BUILD_BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, int size)
|
||||
{
|
||||
switch (size) {
|
||||
@@ -157,6 +88,33 @@ static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __pcpu_op_1(op) op ".b "
|
||||
#define __pcpu_op_2(op) op ".h "
|
||||
#define __pcpu_op_4(op) op ".w "
|
||||
#define __pcpu_op_8(op) op ".d "
|
||||
|
||||
#define _percpu_read(size, _pcp) \
|
||||
({ \
|
||||
typeof(_pcp) __pcp_ret; \
|
||||
\
|
||||
__asm__ __volatile__( \
|
||||
__pcpu_op_##size("ldx") "%[ret], $r21, %[ptr] \n" \
|
||||
: [ret] "=&r"(__pcp_ret) \
|
||||
: [ptr] "r"(&(_pcp)) \
|
||||
: "memory"); \
|
||||
\
|
||||
__pcp_ret; \
|
||||
})
|
||||
|
||||
#define _percpu_write(size, _pcp, _val) \
|
||||
do { \
|
||||
__asm__ __volatile__( \
|
||||
__pcpu_op_##size("stx") "%[val], $r21, %[ptr] \n" \
|
||||
: \
|
||||
: [val] "r"(_val), [ptr] "r"(&(_pcp)) \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
|
||||
/* this_cpu_cmpxchg */
|
||||
#define _protect_cmpxchg_local(pcp, o, n) \
|
||||
({ \
|
||||
@@ -167,18 +125,6 @@ static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define _percpu_read(pcp) \
|
||||
({ \
|
||||
typeof(pcp) __retval; \
|
||||
__retval = (typeof(pcp))__percpu_read(&(pcp), sizeof(pcp)); \
|
||||
__retval; \
|
||||
})
|
||||
|
||||
#define _percpu_write(pcp, val) \
|
||||
do { \
|
||||
__percpu_write(&(pcp), (unsigned long)(val), sizeof(pcp)); \
|
||||
} while (0) \
|
||||
|
||||
#define _pcp_protect(operation, pcp, val) \
|
||||
({ \
|
||||
typeof(pcp) __retval; \
|
||||
@@ -215,15 +161,15 @@ do { \
|
||||
#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val)
|
||||
#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val)
|
||||
|
||||
#define this_cpu_read_1(pcp) _percpu_read(pcp)
|
||||
#define this_cpu_read_2(pcp) _percpu_read(pcp)
|
||||
#define this_cpu_read_4(pcp) _percpu_read(pcp)
|
||||
#define this_cpu_read_8(pcp) _percpu_read(pcp)
|
||||
#define this_cpu_read_1(pcp) _percpu_read(1, pcp)
|
||||
#define this_cpu_read_2(pcp) _percpu_read(2, pcp)
|
||||
#define this_cpu_read_4(pcp) _percpu_read(4, pcp)
|
||||
#define this_cpu_read_8(pcp) _percpu_read(8, pcp)
|
||||
|
||||
#define this_cpu_write_1(pcp, val) _percpu_write(pcp, val)
|
||||
#define this_cpu_write_2(pcp, val) _percpu_write(pcp, val)
|
||||
#define this_cpu_write_4(pcp, val) _percpu_write(pcp, val)
|
||||
#define this_cpu_write_8(pcp, val) _percpu_write(pcp, val)
|
||||
#define this_cpu_write_1(pcp, val) _percpu_write(1, pcp, val)
|
||||
#define this_cpu_write_2(pcp, val) _percpu_write(2, pcp, val)
|
||||
#define this_cpu_write_4(pcp, val) _percpu_write(4, pcp, val)
|
||||
#define this_cpu_write_8(pcp, val) _percpu_write(8, pcp, val)
|
||||
|
||||
#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val)
|
||||
#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val)
|
||||
|
||||
@@ -331,29 +331,23 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
|
||||
* Make sure the buddy is global too (if it's !none,
|
||||
* it better already be global)
|
||||
*/
|
||||
if (pte_none(ptep_get(buddy))) {
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* For SMP, multiple CPUs can race, so we need to do
|
||||
* this atomically.
|
||||
*/
|
||||
unsigned long page_global = _PAGE_GLOBAL;
|
||||
unsigned long tmp;
|
||||
/*
|
||||
* For SMP, multiple CPUs can race, so we need
|
||||
* to do this atomically.
|
||||
*/
|
||||
__asm__ __volatile__(
|
||||
__AMOR "$zero, %[global], %[buddy] \n"
|
||||
: [buddy] "+ZB" (buddy->pte)
|
||||
: [global] "r" (_PAGE_GLOBAL)
|
||||
: "memory");
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"1:" __LL "%[tmp], %[buddy] \n"
|
||||
" bnez %[tmp], 2f \n"
|
||||
" or %[tmp], %[tmp], %[global] \n"
|
||||
__SC "%[tmp], %[buddy] \n"
|
||||
" beqz %[tmp], 1b \n"
|
||||
" nop \n"
|
||||
"2: \n"
|
||||
__WEAK_LLSC_MB
|
||||
: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
|
||||
: [global] "r" (page_global));
|
||||
DBAR(0b11000); /* o_wrw = 0b11000 */
|
||||
#else /* !CONFIG_SMP */
|
||||
if (pte_none(ptep_get(buddy)))
|
||||
WRITE_ONCE(*buddy, __pte(pte_val(ptep_get(buddy)) | _PAGE_GLOBAL));
|
||||
#endif /* CONFIG_SMP */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef _ASM_LOONGARCH_SET_MEMORY_H
|
||||
#define _ASM_LOONGARCH_SET_MEMORY_H
|
||||
|
||||
/*
|
||||
* Functions to change memory attributes.
|
||||
*/
|
||||
int set_memory_x(unsigned long addr, int numpages);
|
||||
int set_memory_nx(unsigned long addr, int numpages);
|
||||
int set_memory_ro(unsigned long addr, int numpages);
|
||||
int set_memory_rw(unsigned long addr, int numpages);
|
||||
|
||||
bool kernel_page_present(struct page *page);
|
||||
int set_direct_map_default_noflush(struct page *page);
|
||||
int set_direct_map_invalid_noflush(struct page *page);
|
||||
|
||||
#endif /* _ASM_LOONGARCH_SET_MEMORY_H */
|
||||
@@ -17,5 +17,6 @@
|
||||
#define HWCAP_LOONGARCH_LBT_ARM (1 << 11)
|
||||
#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12)
|
||||
#define HWCAP_LOONGARCH_PTW (1 << 13)
|
||||
#define HWCAP_LOONGARCH_LSPW (1 << 14)
|
||||
|
||||
#endif /* _UAPI_ASM_HWCAP_H */
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#define _UAPI_ASM_SIGCONTEXT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/posix_types.h>
|
||||
|
||||
/* FP context was used */
|
||||
#define SC_USED_FP (1 << 0)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/efi-bgrt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/memblock.h>
|
||||
@@ -212,6 +213,9 @@ void __init acpi_boot_table_init(void)
|
||||
/* Do not enable ACPI SPCR console by default */
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ACPI_BGRT))
|
||||
acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
|
||||
|
||||
return;
|
||||
|
||||
fdt_earlycon:
|
||||
|
||||
@@ -91,12 +91,30 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
unsigned int config;
|
||||
unsigned long asid_mask;
|
||||
|
||||
c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR |
|
||||
LOONGARCH_CPU_TLB | LOONGARCH_CPU_VINT | LOONGARCH_CPU_WATCH;
|
||||
c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR | LOONGARCH_CPU_VINT;
|
||||
|
||||
elf_hwcap = HWCAP_LOONGARCH_CPUCFG;
|
||||
|
||||
config = read_cpucfg(LOONGARCH_CPUCFG1);
|
||||
|
||||
switch (config & CPUCFG1_ISA) {
|
||||
case 0:
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA32R);
|
||||
break;
|
||||
case 1:
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA32S);
|
||||
break;
|
||||
case 2:
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
break;
|
||||
default:
|
||||
pr_warn("Warning: unknown ISA level\n");
|
||||
}
|
||||
|
||||
if (config & CPUCFG1_PAGING)
|
||||
c->options |= LOONGARCH_CPU_TLB;
|
||||
if (config & CPUCFG1_IOCSR)
|
||||
c->options |= LOONGARCH_CPU_IOCSR;
|
||||
if (config & CPUCFG1_UAL) {
|
||||
c->options |= LOONGARCH_CPU_UAL;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_UAL;
|
||||
@@ -139,6 +157,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
c->options |= LOONGARCH_CPU_PTW;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_PTW;
|
||||
}
|
||||
if (config & CPUCFG2_LSPW) {
|
||||
c->options |= LOONGARCH_CPU_LSPW;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LSPW;
|
||||
}
|
||||
if (config & CPUCFG2_LVZP) {
|
||||
c->options |= LOONGARCH_CPU_LVZ;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LVZ;
|
||||
@@ -162,22 +184,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
if (config & CPUCFG6_PMP)
|
||||
c->options |= LOONGARCH_CPU_PMP;
|
||||
|
||||
config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
|
||||
if (config & IOCSRF_CSRIPI)
|
||||
c->options |= LOONGARCH_CPU_CSRIPI;
|
||||
if (config & IOCSRF_EXTIOI)
|
||||
c->options |= LOONGARCH_CPU_EXTIOI;
|
||||
if (config & IOCSRF_FREQSCALE)
|
||||
c->options |= LOONGARCH_CPU_SCALEFREQ;
|
||||
if (config & IOCSRF_FLATMODE)
|
||||
c->options |= LOONGARCH_CPU_FLATMODE;
|
||||
if (config & IOCSRF_EIODECODE)
|
||||
c->options |= LOONGARCH_CPU_EIODECODE;
|
||||
if (config & IOCSRF_AVEC)
|
||||
c->options |= LOONGARCH_CPU_AVECINT;
|
||||
if (config & IOCSRF_VM)
|
||||
c->options |= LOONGARCH_CPU_HYPERVISOR;
|
||||
|
||||
config = csr_read32(LOONGARCH_CSR_ASID);
|
||||
config = (config & CSR_ASID_BIT) >> CSR_ASID_BIT_SHIFT;
|
||||
asid_mask = GENMASK(config - 1, 0);
|
||||
@@ -210,6 +216,9 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
||||
default:
|
||||
pr_warn("Warning: unknown TLB type\n");
|
||||
}
|
||||
|
||||
if (get_num_brps() + get_num_wrps())
|
||||
c->options |= LOONGARCH_CPU_WATCH;
|
||||
}
|
||||
|
||||
#define MAX_NAME_LEN 32
|
||||
@@ -220,8 +229,45 @@ static char cpu_full_name[MAX_NAME_LEN] = " - ";
|
||||
|
||||
static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int cpu)
|
||||
{
|
||||
uint32_t config;
|
||||
uint64_t *vendor = (void *)(&cpu_full_name[VENDOR_OFFSET]);
|
||||
uint64_t *cpuname = (void *)(&cpu_full_name[CPUNAME_OFFSET]);
|
||||
const char *core_name = "Unknown";
|
||||
|
||||
switch (BIT(fls(c->isa_level) - 1)) {
|
||||
case LOONGARCH_CPU_ISA_LA32R:
|
||||
case LOONGARCH_CPU_ISA_LA32S:
|
||||
c->cputype = CPU_LOONGSON32;
|
||||
__cpu_family[cpu] = "Loongson-32bit";
|
||||
break;
|
||||
case LOONGARCH_CPU_ISA_LA64:
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c->processor_id & PRID_SERIES_MASK) {
|
||||
case PRID_SERIES_LA132:
|
||||
core_name = "LA132";
|
||||
break;
|
||||
case PRID_SERIES_LA264:
|
||||
core_name = "LA264";
|
||||
break;
|
||||
case PRID_SERIES_LA364:
|
||||
core_name = "LA364";
|
||||
break;
|
||||
case PRID_SERIES_LA464:
|
||||
core_name = "LA464";
|
||||
break;
|
||||
case PRID_SERIES_LA664:
|
||||
core_name = "LA664";
|
||||
break;
|
||||
}
|
||||
|
||||
pr_info("%s Processor probed (%s Core)\n", __cpu_family[cpu], core_name);
|
||||
|
||||
if (!cpu_has_iocsr)
|
||||
return;
|
||||
|
||||
if (!__cpu_full_name[cpu])
|
||||
__cpu_full_name[cpu] = cpu_full_name;
|
||||
@@ -229,43 +275,21 @@ static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int
|
||||
*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
|
||||
*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
|
||||
|
||||
switch (c->processor_id & PRID_SERIES_MASK) {
|
||||
case PRID_SERIES_LA132:
|
||||
c->cputype = CPU_LOONGSON32;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA32S);
|
||||
__cpu_family[cpu] = "Loongson-32bit";
|
||||
pr_info("32-bit Loongson Processor probed (LA132 Core)\n");
|
||||
break;
|
||||
case PRID_SERIES_LA264:
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
pr_info("64-bit Loongson Processor probed (LA264 Core)\n");
|
||||
break;
|
||||
case PRID_SERIES_LA364:
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
pr_info("64-bit Loongson Processor probed (LA364 Core)\n");
|
||||
break;
|
||||
case PRID_SERIES_LA464:
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
pr_info("64-bit Loongson Processor probed (LA464 Core)\n");
|
||||
break;
|
||||
case PRID_SERIES_LA664:
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
pr_info("64-bit Loongson Processor probed (LA664 Core)\n");
|
||||
break;
|
||||
default: /* Default to 64 bit */
|
||||
c->cputype = CPU_LOONGSON64;
|
||||
set_isa(c, LOONGARCH_CPU_ISA_LA64);
|
||||
__cpu_family[cpu] = "Loongson-64bit";
|
||||
pr_info("64-bit Loongson Processor probed (Unknown Core)\n");
|
||||
}
|
||||
config = iocsr_read32(LOONGARCH_IOCSR_FEATURES);
|
||||
if (config & IOCSRF_CSRIPI)
|
||||
c->options |= LOONGARCH_CPU_CSRIPI;
|
||||
if (config & IOCSRF_EXTIOI)
|
||||
c->options |= LOONGARCH_CPU_EXTIOI;
|
||||
if (config & IOCSRF_FREQSCALE)
|
||||
c->options |= LOONGARCH_CPU_SCALEFREQ;
|
||||
if (config & IOCSRF_FLATMODE)
|
||||
c->options |= LOONGARCH_CPU_FLATMODE;
|
||||
if (config & IOCSRF_EIODECODE)
|
||||
c->options |= LOONGARCH_CPU_EIODECODE;
|
||||
if (config & IOCSRF_AVEC)
|
||||
c->options |= LOONGARCH_CPU_AVECINT;
|
||||
if (config & IOCSRF_VM)
|
||||
c->options |= LOONGARCH_CPU_HYPERVISOR;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
|
||||
@@ -31,6 +31,7 @@ int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v)
|
||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
{
|
||||
unsigned long n = (unsigned long) v - 1;
|
||||
unsigned int isa = cpu_data[n].isa_level;
|
||||
unsigned int version = cpu_data[n].processor_id & 0xff;
|
||||
unsigned int fp_version = cpu_data[n].fpu_vers;
|
||||
struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args;
|
||||
@@ -64,9 +65,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
cpu_pabits + 1, cpu_vabits + 1);
|
||||
|
||||
seq_printf(m, "ISA\t\t\t:");
|
||||
if (cpu_has_loongarch32)
|
||||
seq_printf(m, " loongarch32");
|
||||
if (cpu_has_loongarch64)
|
||||
if (isa & LOONGARCH_CPU_ISA_LA32R)
|
||||
seq_printf(m, " loongarch32r");
|
||||
if (isa & LOONGARCH_CPU_ISA_LA32S)
|
||||
seq_printf(m, " loongarch32s");
|
||||
if (isa & LOONGARCH_CPU_ISA_LA64)
|
||||
seq_printf(m, " loongarch64");
|
||||
seq_printf(m, "\n");
|
||||
|
||||
@@ -81,6 +84,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
if (cpu_has_complex) seq_printf(m, " complex");
|
||||
if (cpu_has_crypto) seq_printf(m, " crypto");
|
||||
if (cpu_has_ptw) seq_printf(m, " ptw");
|
||||
if (cpu_has_lspw) seq_printf(m, " lspw");
|
||||
if (cpu_has_lvz) seq_printf(m, " lvz");
|
||||
if (cpu_has_lbt_x86) seq_printf(m, " lbt_x86");
|
||||
if (cpu_has_lbt_arm) seq_printf(m, " lbt_arm");
|
||||
|
||||
@@ -79,7 +79,3 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
|
||||
|
||||
syscall_exit_to_user_mode(regs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
|
||||
STACK_FRAME_NON_STANDARD(do_syscall);
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#
|
||||
|
||||
obj-y += init.o cache.o tlb.o tlbex.o extable.o \
|
||||
fault.o ioremap.o maccess.o mmap.o pgtable.o page.o
|
||||
fault.o ioremap.o maccess.o mmap.o pgtable.o \
|
||||
page.o pageattr.o
|
||||
|
||||
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
||||
obj-$(CONFIG_KASAN) += kasan_init.o
|
||||
|
||||
@@ -31,11 +31,52 @@
|
||||
|
||||
int show_unhandled_signals = 1;
|
||||
|
||||
static int __kprobes spurious_fault(unsigned long write, unsigned long address)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
|
||||
if (!(address & __UA_LIMIT))
|
||||
return 0;
|
||||
|
||||
pgd = pgd_offset_k(address);
|
||||
if (!pgd_present(pgdp_get(pgd)))
|
||||
return 0;
|
||||
|
||||
p4d = p4d_offset(pgd, address);
|
||||
if (!p4d_present(p4dp_get(p4d)))
|
||||
return 0;
|
||||
|
||||
pud = pud_offset(p4d, address);
|
||||
if (!pud_present(pudp_get(pud)))
|
||||
return 0;
|
||||
|
||||
pmd = pmd_offset(pud, address);
|
||||
if (!pmd_present(pmdp_get(pmd)))
|
||||
return 0;
|
||||
|
||||
if (pmd_leaf(*pmd)) {
|
||||
return write ? pmd_write(pmdp_get(pmd)) : 1;
|
||||
} else {
|
||||
pte = pte_offset_kernel(pmd, address);
|
||||
if (!pte_present(ptep_get(pte)))
|
||||
return 0;
|
||||
|
||||
return write ? pte_write(ptep_get(pte)) : 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __kprobes no_context(struct pt_regs *regs,
|
||||
unsigned long write, unsigned long address)
|
||||
{
|
||||
const int field = sizeof(unsigned long) * 2;
|
||||
|
||||
if (spurious_fault(write, address))
|
||||
return;
|
||||
|
||||
/* Are we prepared to handle this kernel fault? */
|
||||
if (fixup_exception(regs))
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/pagewalk.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
struct pageattr_masks {
|
||||
pgprot_t set_mask;
|
||||
pgprot_t clear_mask;
|
||||
};
|
||||
|
||||
static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk)
|
||||
{
|
||||
unsigned long new_val = val;
|
||||
struct pageattr_masks *masks = walk->private;
|
||||
|
||||
new_val &= ~(pgprot_val(masks->clear_mask));
|
||||
new_val |= (pgprot_val(masks->set_mask));
|
||||
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
pgd_t val = pgdp_get(pgd);
|
||||
|
||||
if (pgd_leaf(val)) {
|
||||
val = __pgd(set_pageattr_masks(pgd_val(val), walk));
|
||||
set_pgd(pgd, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
p4d_t val = p4dp_get(p4d);
|
||||
|
||||
if (p4d_leaf(val)) {
|
||||
val = __p4d(set_pageattr_masks(p4d_val(val), walk));
|
||||
set_p4d(p4d, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
pud_t val = pudp_get(pud);
|
||||
|
||||
if (pud_leaf(val)) {
|
||||
val = __pud(set_pageattr_masks(pud_val(val), walk));
|
||||
set_pud(pud, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
pmd_t val = pmdp_get(pmd);
|
||||
|
||||
if (pmd_leaf(val)) {
|
||||
val = __pmd(set_pageattr_masks(pmd_val(val), walk));
|
||||
set_pmd(pmd, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pageattr_pte_entry(pte_t *pte, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk)
|
||||
{
|
||||
pte_t val = ptep_get(pte);
|
||||
|
||||
val = __pte(set_pageattr_masks(pte_val(val), walk));
|
||||
set_pte(pte, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pageattr_pte_hole(unsigned long addr, unsigned long next,
|
||||
int depth, struct mm_walk *walk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mm_walk_ops pageattr_ops = {
|
||||
.pgd_entry = pageattr_pgd_entry,
|
||||
.p4d_entry = pageattr_p4d_entry,
|
||||
.pud_entry = pageattr_pud_entry,
|
||||
.pmd_entry = pageattr_pmd_entry,
|
||||
.pte_entry = pageattr_pte_entry,
|
||||
.pte_hole = pageattr_pte_hole,
|
||||
.walk_lock = PGWALK_RDLOCK,
|
||||
};
|
||||
|
||||
static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, pgprot_t clear_mask)
|
||||
{
|
||||
int ret;
|
||||
unsigned long start = addr;
|
||||
unsigned long end = start + PAGE_SIZE * numpages;
|
||||
struct pageattr_masks masks = {
|
||||
.set_mask = set_mask,
|
||||
.clear_mask = clear_mask
|
||||
};
|
||||
|
||||
if (!numpages)
|
||||
return 0;
|
||||
|
||||
mmap_write_lock(&init_mm);
|
||||
ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, &masks);
|
||||
mmap_write_unlock(&init_mm);
|
||||
|
||||
flush_tlb_kernel_range(start, end);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_memory_x(unsigned long addr, int numpages)
|
||||
{
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_NO_EXEC));
|
||||
}
|
||||
|
||||
int set_memory_nx(unsigned long addr, int numpages)
|
||||
{
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, numpages, __pgprot(_PAGE_NO_EXEC), __pgprot(0));
|
||||
}
|
||||
|
||||
int set_memory_ro(unsigned long addr, int numpages)
|
||||
{
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_WRITE | _PAGE_DIRTY));
|
||||
}
|
||||
|
||||
int set_memory_rw(unsigned long addr, int numpages)
|
||||
{
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, numpages, __pgprot(_PAGE_WRITE | _PAGE_DIRTY), __pgprot(0));
|
||||
}
|
||||
|
||||
bool kernel_page_present(struct page *page)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long addr = (unsigned long)page_address(page);
|
||||
|
||||
if (addr < vm_map_base)
|
||||
return true;
|
||||
|
||||
pgd = pgd_offset_k(addr);
|
||||
if (pgd_none(pgdp_get(pgd)))
|
||||
return false;
|
||||
if (pgd_leaf(pgdp_get(pgd)))
|
||||
return true;
|
||||
|
||||
p4d = p4d_offset(pgd, addr);
|
||||
if (p4d_none(p4dp_get(p4d)))
|
||||
return false;
|
||||
if (p4d_leaf(p4dp_get(p4d)))
|
||||
return true;
|
||||
|
||||
pud = pud_offset(p4d, addr);
|
||||
if (pud_none(pudp_get(pud)))
|
||||
return false;
|
||||
if (pud_leaf(pudp_get(pud)))
|
||||
return true;
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
if (pmd_none(pmdp_get(pmd)))
|
||||
return false;
|
||||
if (pmd_leaf(pmdp_get(pmd)))
|
||||
return true;
|
||||
|
||||
pte = pte_offset_kernel(pmd, addr);
|
||||
return pte_present(ptep_get(pte));
|
||||
}
|
||||
|
||||
int set_direct_map_default_noflush(struct page *page)
|
||||
{
|
||||
unsigned long addr = (unsigned long)page_address(page);
|
||||
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, 1, PAGE_KERNEL, __pgprot(0));
|
||||
}
|
||||
|
||||
int set_direct_map_invalid_noflush(struct page *page)
|
||||
{
|
||||
unsigned long addr = (unsigned long)page_address(page);
|
||||
|
||||
if (addr < vm_map_base)
|
||||
return 0;
|
||||
|
||||
return __set_memory(addr, 1, __pgprot(0), __pgprot(_PAGE_PRESENT | _PAGE_VALID));
|
||||
}
|
||||
@@ -225,6 +225,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
||||
if (bus) {
|
||||
memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window));
|
||||
kfree(info);
|
||||
kfree(root_ops);
|
||||
} else {
|
||||
struct pci_bus *child;
|
||||
|
||||
|
||||
@@ -9,23 +9,11 @@
|
||||
|
||||
.text
|
||||
|
||||
/* Salsa20 quarter-round */
|
||||
.macro QR a b c d
|
||||
add.w \a, \a, \b
|
||||
xor \d, \d, \a
|
||||
rotri.w \d, \d, 16
|
||||
|
||||
add.w \c, \c, \d
|
||||
xor \b, \b, \c
|
||||
rotri.w \b, \b, 20
|
||||
|
||||
add.w \a, \a, \b
|
||||
xor \d, \d, \a
|
||||
rotri.w \d, \d, 24
|
||||
|
||||
add.w \c, \c, \d
|
||||
xor \b, \b, \c
|
||||
rotri.w \b, \b, 25
|
||||
.macro OP_4REG op d0 d1 d2 d3 s0 s1 s2 s3
|
||||
\op \d0, \d0, \s0
|
||||
\op \d1, \d1, \s1
|
||||
\op \d2, \d2, \s2
|
||||
\op \d3, \d3, \s3
|
||||
.endm
|
||||
|
||||
/*
|
||||
@@ -74,6 +62,23 @@ SYM_FUNC_START(__arch_chacha20_blocks_nostack)
|
||||
/* Reuse i as copy3 */
|
||||
#define copy3 i
|
||||
|
||||
/* Packs to be used with OP_4REG */
|
||||
#define line0 state0, state1, state2, state3
|
||||
#define line1 state4, state5, state6, state7
|
||||
#define line2 state8, state9, state10, state11
|
||||
#define line3 state12, state13, state14, state15
|
||||
|
||||
#define line1_perm state5, state6, state7, state4
|
||||
#define line2_perm state10, state11, state8, state9
|
||||
#define line3_perm state15, state12, state13, state14
|
||||
|
||||
#define copy copy0, copy1, copy2, copy3
|
||||
|
||||
#define _16 16, 16, 16, 16
|
||||
#define _20 20, 20, 20, 20
|
||||
#define _24 24, 24, 24, 24
|
||||
#define _25 25, 25, 25, 25
|
||||
|
||||
/*
|
||||
* The ABI requires s0-s9 saved, and sp aligned to 16-byte.
|
||||
* This does not violate the stack-less requirement: no sensitive data
|
||||
@@ -126,16 +131,38 @@ SYM_FUNC_START(__arch_chacha20_blocks_nostack)
|
||||
li.w i, 10
|
||||
.Lpermute:
|
||||
/* odd round */
|
||||
QR state0, state4, state8, state12
|
||||
QR state1, state5, state9, state13
|
||||
QR state2, state6, state10, state14
|
||||
QR state3, state7, state11, state15
|
||||
OP_4REG add.w line0, line1
|
||||
OP_4REG xor line3, line0
|
||||
OP_4REG rotri.w line3, _16
|
||||
|
||||
OP_4REG add.w line2, line3
|
||||
OP_4REG xor line1, line2
|
||||
OP_4REG rotri.w line1, _20
|
||||
|
||||
OP_4REG add.w line0, line1
|
||||
OP_4REG xor line3, line0
|
||||
OP_4REG rotri.w line3, _24
|
||||
|
||||
OP_4REG add.w line2, line3
|
||||
OP_4REG xor line1, line2
|
||||
OP_4REG rotri.w line1, _25
|
||||
|
||||
/* even round */
|
||||
QR state0, state5, state10, state15
|
||||
QR state1, state6, state11, state12
|
||||
QR state2, state7, state8, state13
|
||||
QR state3, state4, state9, state14
|
||||
OP_4REG add.w line0, line1_perm
|
||||
OP_4REG xor line3_perm, line0
|
||||
OP_4REG rotri.w line3_perm, _16
|
||||
|
||||
OP_4REG add.w line2_perm, line3_perm
|
||||
OP_4REG xor line1_perm, line2_perm
|
||||
OP_4REG rotri.w line1_perm, _20
|
||||
|
||||
OP_4REG add.w line0, line1_perm
|
||||
OP_4REG xor line3_perm, line0
|
||||
OP_4REG rotri.w line3_perm, _24
|
||||
|
||||
OP_4REG add.w line2_perm, line3_perm
|
||||
OP_4REG xor line1_perm, line2_perm
|
||||
OP_4REG rotri.w line1_perm, _25
|
||||
|
||||
addi.w i, i, -1
|
||||
bnez i, .Lpermute
|
||||
@@ -147,10 +174,7 @@ SYM_FUNC_START(__arch_chacha20_blocks_nostack)
|
||||
li.w copy3, 0x6b206574
|
||||
|
||||
/* output[0,1,2,3] = copy[0,1,2,3] + state[0,1,2,3] */
|
||||
add.w state0, state0, copy0
|
||||
add.w state1, state1, copy1
|
||||
add.w state2, state2, copy2
|
||||
add.w state3, state3, copy3
|
||||
OP_4REG add.w line0, copy
|
||||
st.w state0, output, 0
|
||||
st.w state1, output, 4
|
||||
st.w state2, output, 8
|
||||
@@ -165,10 +189,7 @@ SYM_FUNC_START(__arch_chacha20_blocks_nostack)
|
||||
ld.w state3, key, 12
|
||||
|
||||
/* output[4,5,6,7] = state[0,1,2,3] + state[4,5,6,7] */
|
||||
add.w state4, state4, state0
|
||||
add.w state5, state5, state1
|
||||
add.w state6, state6, state2
|
||||
add.w state7, state7, state3
|
||||
OP_4REG add.w line1, line0
|
||||
st.w state4, output, 16
|
||||
st.w state5, output, 20
|
||||
st.w state6, output, 24
|
||||
@@ -181,10 +202,7 @@ SYM_FUNC_START(__arch_chacha20_blocks_nostack)
|
||||
ld.w state3, key, 28
|
||||
|
||||
/* output[8,9,10,11] = state[0,1,2,3] + state[8,9,10,11] */
|
||||
add.w state8, state8, state0
|
||||
add.w state9, state9, state1
|
||||
add.w state10, state10, state2
|
||||
add.w state11, state11, state3
|
||||
OP_4REG add.w line2, line0
|
||||
st.w state8, output, 32
|
||||
st.w state9, output, 36
|
||||
st.w state10, output, 40
|
||||
|
||||
@@ -13,12 +13,6 @@
|
||||
*/
|
||||
#define NO_IRQ_IGNORE ((unsigned int)-1)
|
||||
|
||||
/*
|
||||
* Simple Mask Register Support
|
||||
*/
|
||||
extern void make_maskreg_irq(unsigned int irq);
|
||||
extern unsigned short *irq_mask_register;
|
||||
|
||||
/*
|
||||
* PINT IRQs
|
||||
*/
|
||||
|
||||
@@ -270,5 +270,26 @@ static inline bool gup_fast_permitted(unsigned long start, unsigned long end)
|
||||
|
||||
#include <asm/pgtable-invert.h>
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
#define l4_index(x) (((x) >> 39) & 511)
|
||||
#define pud_index(x) (((x) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
|
||||
|
||||
L4_PAGE_OFFSET = l4_index(__PAGE_OFFSET_BASE_L4)
|
||||
L4_START_KERNEL = l4_index(__START_KERNEL_map)
|
||||
|
||||
L3_START_KERNEL = pud_index(__START_KERNEL_map)
|
||||
|
||||
#define SYM_DATA_START_PAGE_ALIGNED(name) \
|
||||
SYM_START(name, SYM_L_GLOBAL, .balign PAGE_SIZE)
|
||||
|
||||
/* Automate the creation of 1 to 1 mapping pmd entries */
|
||||
#define PMDS(START, PERM, COUNT) \
|
||||
i = 0 ; \
|
||||
.rept (COUNT) ; \
|
||||
.quad (START) + (i << PMD_SHIFT) + (PERM) ; \
|
||||
i = i + 1 ; \
|
||||
.endr
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* _ASM_X86_PGTABLE_64_H */
|
||||
|
||||
@@ -32,13 +32,6 @@
|
||||
* We are not able to switch in one step to the final KERNEL ADDRESS SPACE
|
||||
* because we need identity-mapped pages.
|
||||
*/
|
||||
#define l4_index(x) (((x) >> 39) & 511)
|
||||
#define pud_index(x) (((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
|
||||
|
||||
L4_PAGE_OFFSET = l4_index(__PAGE_OFFSET_BASE_L4)
|
||||
L4_START_KERNEL = l4_index(__START_KERNEL_map)
|
||||
|
||||
L3_START_KERNEL = pud_index(__START_KERNEL_map)
|
||||
|
||||
__HEAD
|
||||
.code64
|
||||
@@ -577,9 +570,6 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
|
||||
SYM_CODE_END(vc_no_ghcb)
|
||||
#endif
|
||||
|
||||
#define SYM_DATA_START_PAGE_ALIGNED(name) \
|
||||
SYM_START(name, SYM_L_GLOBAL, .balign PAGE_SIZE)
|
||||
|
||||
#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
|
||||
/*
|
||||
* Each PGD needs to be 8k long and 8k aligned. We do not
|
||||
@@ -601,14 +591,6 @@ SYM_CODE_END(vc_no_ghcb)
|
||||
#define PTI_USER_PGD_FILL 0
|
||||
#endif
|
||||
|
||||
/* Automate the creation of 1 to 1 mapping pmd entries */
|
||||
#define PMDS(START, PERM, COUNT) \
|
||||
i = 0 ; \
|
||||
.rept (COUNT) ; \
|
||||
.quad (START) + (i << PMD_SHIFT) + (PERM) ; \
|
||||
i = i + 1 ; \
|
||||
.endr
|
||||
|
||||
__INITDATA
|
||||
.balign 4
|
||||
|
||||
@@ -708,8 +690,6 @@ SYM_DATA_START_PAGE_ALIGNED(level1_fixmap_pgt)
|
||||
.endr
|
||||
SYM_DATA_END(level1_fixmap_pgt)
|
||||
|
||||
#undef PMDS
|
||||
|
||||
.data
|
||||
.align 16
|
||||
|
||||
|
||||
+149
-12
@@ -7,6 +7,7 @@
|
||||
.code32
|
||||
.text
|
||||
#define _pa(x) ((x) - __START_KERNEL_map)
|
||||
#define rva(x) ((x) - pvh_start_xen)
|
||||
|
||||
#include <linux/elfnote.h>
|
||||
#include <linux/init.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <asm/segment.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/boot.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
@@ -54,7 +56,25 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
|
||||
UNWIND_HINT_END_OF_STACK
|
||||
cld
|
||||
|
||||
lgdt (_pa(gdt))
|
||||
/*
|
||||
* See the comment for startup_32 for more details. We need to
|
||||
* execute a call to get the execution address to be position
|
||||
* independent, but we don't have a stack. Save and restore the
|
||||
* magic field of start_info in ebx, and use that as the stack.
|
||||
*/
|
||||
mov (%ebx), %eax
|
||||
leal 4(%ebx), %esp
|
||||
ANNOTATE_INTRA_FUNCTION_CALL
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
mov %eax, (%ebx)
|
||||
subl $rva(1b), %ebp
|
||||
movl $0, %esp
|
||||
|
||||
leal rva(gdt)(%ebp), %eax
|
||||
leal rva(gdt_start)(%ebp), %ecx
|
||||
movl %ecx, 2(%eax)
|
||||
lgdt (%eax)
|
||||
|
||||
mov $PVH_DS_SEL,%eax
|
||||
mov %eax,%ds
|
||||
@@ -62,14 +82,14 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
|
||||
mov %eax,%ss
|
||||
|
||||
/* Stash hvm_start_info. */
|
||||
mov $_pa(pvh_start_info), %edi
|
||||
leal rva(pvh_start_info)(%ebp), %edi
|
||||
mov %ebx, %esi
|
||||
mov _pa(pvh_start_info_sz), %ecx
|
||||
movl rva(pvh_start_info_sz)(%ebp), %ecx
|
||||
shr $2,%ecx
|
||||
rep
|
||||
movsl
|
||||
|
||||
mov $_pa(early_stack_end), %esp
|
||||
leal rva(early_stack_end)(%ebp), %esp
|
||||
|
||||
/* Enable PAE mode. */
|
||||
mov %cr4, %eax
|
||||
@@ -83,31 +103,86 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
|
||||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
mov %ebp, %ebx
|
||||
subl $_pa(pvh_start_xen), %ebx /* offset */
|
||||
jz .Lpagetable_done
|
||||
|
||||
/* Fixup page-tables for relocation. */
|
||||
leal rva(pvh_init_top_pgt)(%ebp), %edi
|
||||
movl $PTRS_PER_PGD, %ecx
|
||||
2:
|
||||
testl $_PAGE_PRESENT, 0x00(%edi)
|
||||
jz 1f
|
||||
addl %ebx, 0x00(%edi)
|
||||
1:
|
||||
addl $8, %edi
|
||||
decl %ecx
|
||||
jnz 2b
|
||||
|
||||
/* L3 ident has a single entry. */
|
||||
leal rva(pvh_level3_ident_pgt)(%ebp), %edi
|
||||
addl %ebx, 0x00(%edi)
|
||||
|
||||
leal rva(pvh_level3_kernel_pgt)(%ebp), %edi
|
||||
addl %ebx, (PAGE_SIZE - 16)(%edi)
|
||||
addl %ebx, (PAGE_SIZE - 8)(%edi)
|
||||
|
||||
/* pvh_level2_ident_pgt is fine - large pages */
|
||||
|
||||
/* pvh_level2_kernel_pgt needs adjustment - large pages */
|
||||
leal rva(pvh_level2_kernel_pgt)(%ebp), %edi
|
||||
movl $PTRS_PER_PMD, %ecx
|
||||
2:
|
||||
testl $_PAGE_PRESENT, 0x00(%edi)
|
||||
jz 1f
|
||||
addl %ebx, 0x00(%edi)
|
||||
1:
|
||||
addl $8, %edi
|
||||
decl %ecx
|
||||
jnz 2b
|
||||
|
||||
.Lpagetable_done:
|
||||
/* Enable pre-constructed page tables. */
|
||||
mov $_pa(init_top_pgt), %eax
|
||||
leal rva(pvh_init_top_pgt)(%ebp), %eax
|
||||
mov %eax, %cr3
|
||||
mov $(X86_CR0_PG | X86_CR0_PE), %eax
|
||||
mov %eax, %cr0
|
||||
|
||||
/* Jump to 64-bit mode. */
|
||||
ljmp $PVH_CS_SEL, $_pa(1f)
|
||||
pushl $PVH_CS_SEL
|
||||
leal rva(1f)(%ebp), %eax
|
||||
pushl %eax
|
||||
lretl
|
||||
|
||||
/* 64-bit entry point. */
|
||||
.code64
|
||||
1:
|
||||
UNWIND_HINT_END_OF_STACK
|
||||
|
||||
/* Set base address in stack canary descriptor. */
|
||||
mov $MSR_GS_BASE,%ecx
|
||||
mov $_pa(canary), %eax
|
||||
leal canary(%rip), %eax
|
||||
xor %edx, %edx
|
||||
wrmsr
|
||||
|
||||
/*
|
||||
* Calculate load offset and store in phys_base. __pa() needs
|
||||
* phys_base set to calculate the hypercall page in xen_pvh_init().
|
||||
*/
|
||||
movq %rbp, %rbx
|
||||
subq $_pa(pvh_start_xen), %rbx
|
||||
movq %rbx, phys_base(%rip)
|
||||
call xen_prepare_pvh
|
||||
/*
|
||||
* Clear phys_base. __startup_64 will *add* to its value,
|
||||
* so reset to 0.
|
||||
*/
|
||||
xor %rbx, %rbx
|
||||
movq %rbx, phys_base(%rip)
|
||||
|
||||
/* startup_64 expects boot_params in %rsi. */
|
||||
mov $_pa(pvh_bootparams), %rsi
|
||||
mov $_pa(startup_64), %rax
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
jmp *%rax
|
||||
lea pvh_bootparams(%rip), %rsi
|
||||
jmp startup_64
|
||||
|
||||
#else /* CONFIG_X86_64 */
|
||||
|
||||
@@ -143,7 +218,7 @@ SYM_CODE_END(pvh_start_xen)
|
||||
.balign 8
|
||||
SYM_DATA_START_LOCAL(gdt)
|
||||
.word gdt_end - gdt_start
|
||||
.long _pa(gdt_start)
|
||||
.long _pa(gdt_start) /* x86-64 will overwrite if relocated. */
|
||||
.word 0
|
||||
SYM_DATA_END(gdt)
|
||||
SYM_DATA_START_LOCAL(gdt_start)
|
||||
@@ -163,5 +238,67 @@ SYM_DATA_START_LOCAL(early_stack)
|
||||
.fill BOOT_STACK_SIZE, 1, 0
|
||||
SYM_DATA_END_LABEL(early_stack, SYM_L_LOCAL, early_stack_end)
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Xen PVH needs a set of identity mapped and kernel high mapping
|
||||
* page tables. pvh_start_xen starts running on the identity mapped
|
||||
* page tables, but xen_prepare_pvh calls into the high mapping.
|
||||
* These page tables need to be relocatable and are only used until
|
||||
* startup_64 transitions to init_top_pgt.
|
||||
*/
|
||||
SYM_DATA_START_PAGE_ALIGNED(pvh_init_top_pgt)
|
||||
.quad pvh_level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
|
||||
.org pvh_init_top_pgt + L4_PAGE_OFFSET * 8, 0
|
||||
.quad pvh_level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
|
||||
.org pvh_init_top_pgt + L4_START_KERNEL * 8, 0
|
||||
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
|
||||
.quad pvh_level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
|
||||
SYM_DATA_END(pvh_init_top_pgt)
|
||||
|
||||
SYM_DATA_START_PAGE_ALIGNED(pvh_level3_ident_pgt)
|
||||
.quad pvh_level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
|
||||
.fill 511, 8, 0
|
||||
SYM_DATA_END(pvh_level3_ident_pgt)
|
||||
SYM_DATA_START_PAGE_ALIGNED(pvh_level2_ident_pgt)
|
||||
/*
|
||||
* Since I easily can, map the first 1G.
|
||||
* Don't set NX because code runs from these pages.
|
||||
*
|
||||
* Note: This sets _PAGE_GLOBAL despite whether
|
||||
* the CPU supports it or it is enabled. But,
|
||||
* the CPU should ignore the bit.
|
||||
*/
|
||||
PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
|
||||
SYM_DATA_END(pvh_level2_ident_pgt)
|
||||
SYM_DATA_START_PAGE_ALIGNED(pvh_level3_kernel_pgt)
|
||||
.fill L3_START_KERNEL, 8, 0
|
||||
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
|
||||
.quad pvh_level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
|
||||
.quad 0 /* no fixmap */
|
||||
SYM_DATA_END(pvh_level3_kernel_pgt)
|
||||
|
||||
SYM_DATA_START_PAGE_ALIGNED(pvh_level2_kernel_pgt)
|
||||
/*
|
||||
* Kernel high mapping.
|
||||
*
|
||||
* The kernel code+data+bss must be located below KERNEL_IMAGE_SIZE in
|
||||
* virtual address space, which is 1 GiB if RANDOMIZE_BASE is enabled,
|
||||
* 512 MiB otherwise.
|
||||
*
|
||||
* (NOTE: after that starts the module area, see MODULES_VADDR.)
|
||||
*
|
||||
* This table is eventually used by the kernel during normal runtime.
|
||||
* Care must be taken to clear out undesired bits later, like _PAGE_RW
|
||||
* or _PAGE_GLOBAL in some cases.
|
||||
*/
|
||||
PMDS(0, __PAGE_KERNEL_LARGE_EXEC, KERNEL_IMAGE_SIZE / PMD_SIZE)
|
||||
SYM_DATA_END(pvh_level2_kernel_pgt)
|
||||
|
||||
ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_RELOC,
|
||||
.long CONFIG_PHYSICAL_ALIGN;
|
||||
.long LOAD_PHYSICAL_ADDR;
|
||||
.long KERNEL_IMAGE_SIZE - 1)
|
||||
#endif
|
||||
|
||||
ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY,
|
||||
_ASM_PTR (pvh_start_xen - __START_KERNEL_map))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <xen/hvc-console.h>
|
||||
#include <xen/acpi.h>
|
||||
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/io_apic.h>
|
||||
@@ -28,6 +29,28 @@
|
||||
bool __ro_after_init xen_pvh;
|
||||
EXPORT_SYMBOL_GPL(xen_pvh);
|
||||
|
||||
#ifdef CONFIG_XEN_DOM0
|
||||
int xen_pvh_setup_gsi(int gsi, int trigger, int polarity)
|
||||
{
|
||||
int ret;
|
||||
struct physdev_setup_gsi setup_gsi;
|
||||
|
||||
setup_gsi.gsi = gsi;
|
||||
setup_gsi.triggering = (trigger == ACPI_EDGE_SENSITIVE ? 0 : 1);
|
||||
setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
|
||||
|
||||
ret = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
|
||||
if (ret == -EEXIST) {
|
||||
xen_raw_printk("Already setup the GSI :%d\n", gsi);
|
||||
ret = 0;
|
||||
} else if (ret)
|
||||
xen_raw_printk("Fail to setup GSI (%d)!\n", gsi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xen_pvh_setup_gsi);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reserve e820 UNUSABLE regions to inflate the memory balloon.
|
||||
*
|
||||
|
||||
@@ -451,7 +451,7 @@ config ACPI_HED
|
||||
|
||||
config ACPI_BGRT
|
||||
bool "Boottime Graphics Resource Table support"
|
||||
depends on EFI && (X86 || ARM64)
|
||||
depends on EFI && (X86 || ARM64 || LOONGARCH)
|
||||
help
|
||||
This driver adds support for exposing the ACPI Boottime Graphics
|
||||
Resource Table, which allows the operating system to obtain
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*
|
||||
* Author: Ben Cheatham <benjamin.cheatham@amd.com>
|
||||
*/
|
||||
#include <linux/einj-cxl.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/pci.h>
|
||||
#include <cxl/einj.h>
|
||||
|
||||
#include "apei-internal.h"
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <linux/timer.h>
|
||||
#include <linux/cper.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/cxl-event.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ratelimit.h>
|
||||
@@ -50,6 +49,7 @@
|
||||
#include <acpi/apei.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <cxl/event.h>
|
||||
#include <ras/ras_event.h>
|
||||
|
||||
#include "apei-internal.h"
|
||||
|
||||
@@ -288,7 +288,7 @@ static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
|
||||
}
|
||||
#endif /* CONFIG_X86_IO_APIC */
|
||||
|
||||
static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
||||
struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
||||
{
|
||||
struct acpi_prt_entry *entry = NULL;
|
||||
struct pci_dev *bridge;
|
||||
|
||||
@@ -2256,10 +2256,15 @@ static inline u16 ata_xlat_cdl_limit(u8 *buf)
|
||||
static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
|
||||
u8 spg)
|
||||
{
|
||||
u8 *b, *cdl = dev->cdl->desc_log_buf, *desc;
|
||||
u8 *b, *cdl, *desc;
|
||||
u32 policy;
|
||||
int i;
|
||||
|
||||
if (!(dev->flags & ATA_DFLAG_CDL) || !dev->cdl)
|
||||
return 0;
|
||||
|
||||
cdl = dev->cdl->desc_log_buf;
|
||||
|
||||
/*
|
||||
* Fill the subpage. The first four bytes of the T2A/T2B mode pages
|
||||
* are a header. The PAGE LENGTH field is the size of the page
|
||||
@@ -2356,7 +2361,7 @@ static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf,
|
||||
case ALL_SUB_MPAGES:
|
||||
n = ata_msense_control_spg0(dev, buf, changeable);
|
||||
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
|
||||
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
|
||||
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2B_SUB_MPAGE);
|
||||
n += ata_msense_control_ata_feature(dev, buf + n);
|
||||
return n;
|
||||
default:
|
||||
|
||||
@@ -2115,8 +2115,10 @@ static void zram_destroy_comps(struct zram *zram)
|
||||
zram->num_active_comps--;
|
||||
}
|
||||
|
||||
for (prio = ZRAM_SECONDARY_COMP; prio < ZRAM_MAX_COMPS; prio++) {
|
||||
kfree(zram->comp_algs[prio]);
|
||||
for (prio = ZRAM_PRIMARY_COMP; prio < ZRAM_MAX_COMPS; prio++) {
|
||||
/* Do not free statically defined compression algorithms */
|
||||
if (zram->comp_algs[prio] != default_compressor)
|
||||
kfree(zram->comp_algs[prio]);
|
||||
zram->comp_algs[prio] = NULL;
|
||||
}
|
||||
|
||||
|
||||
+496
-16
@@ -9,13 +9,12 @@
|
||||
#include "cxlmem.h"
|
||||
#include "core.h"
|
||||
#include "cxl.h"
|
||||
#include "core.h"
|
||||
|
||||
struct dsmas_entry {
|
||||
struct range dpa_range;
|
||||
u8 handle;
|
||||
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
|
||||
|
||||
struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
|
||||
int entries;
|
||||
int qos_class;
|
||||
};
|
||||
@@ -163,7 +162,7 @@ static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg,
|
||||
val = cdat_normalize(le16_to_cpu(le_val), le64_to_cpu(le_base),
|
||||
dslbis->data_type);
|
||||
|
||||
cxl_access_coordinate_set(dent->coord, dslbis->data_type, val);
|
||||
cxl_access_coordinate_set(dent->cdat_coord, dslbis->data_type, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -220,7 +219,7 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,
|
||||
xa_for_each(dsmas_xa, index, dent) {
|
||||
int qos_class;
|
||||
|
||||
cxl_coordinates_combine(dent->coord, dent->coord, ep_c);
|
||||
cxl_coordinates_combine(dent->coord, dent->cdat_coord, ep_c);
|
||||
dent->entries = 1;
|
||||
rc = cxl_root->ops->qos_class(cxl_root,
|
||||
&dent->coord[ACCESS_COORDINATE_CPU],
|
||||
@@ -241,8 +240,10 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,
|
||||
static void update_perf_entry(struct device *dev, struct dsmas_entry *dent,
|
||||
struct cxl_dpa_perf *dpa_perf)
|
||||
{
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++)
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
dpa_perf->coord[i] = dent->coord[i];
|
||||
dpa_perf->cdat_coord[i] = dent->cdat_coord[i];
|
||||
}
|
||||
dpa_perf->dpa_range = dent->dpa_range;
|
||||
dpa_perf->qos_class = dent->qos_class;
|
||||
dev_dbg(dev,
|
||||
@@ -546,19 +547,37 @@ void cxl_coordinates_combine(struct access_coordinate *out,
|
||||
|
||||
MODULE_IMPORT_NS(CXL);
|
||||
|
||||
void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled)
|
||||
static void cxl_bandwidth_add(struct access_coordinate *coord,
|
||||
struct access_coordinate *c1,
|
||||
struct access_coordinate *c2)
|
||||
{
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
coord[i].read_bandwidth = c1[i].read_bandwidth +
|
||||
c2[i].read_bandwidth;
|
||||
coord[i].write_bandwidth = c1[i].write_bandwidth +
|
||||
c2[i].write_bandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dpa_perf_contains(struct cxl_dpa_perf *perf,
|
||||
struct resource *dpa_res)
|
||||
{
|
||||
struct range dpa = {
|
||||
.start = dpa_res->start,
|
||||
.end = dpa_res->end,
|
||||
};
|
||||
|
||||
return range_contains(&perf->dpa_range, &dpa);
|
||||
}
|
||||
|
||||
static struct cxl_dpa_perf *cxled_get_dpa_perf(struct cxl_endpoint_decoder *cxled,
|
||||
enum cxl_decoder_mode mode)
|
||||
{
|
||||
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
|
||||
struct range dpa = {
|
||||
.start = cxled->dpa_res->start,
|
||||
.end = cxled->dpa_res->end,
|
||||
};
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_dpa_perf *perf;
|
||||
|
||||
switch (cxlr->mode) {
|
||||
switch (mode) {
|
||||
case CXL_DECODER_RAM:
|
||||
perf = &mds->ram_perf;
|
||||
break;
|
||||
@@ -566,12 +585,473 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
|
||||
perf = &mds->pmem_perf;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!dpa_perf_contains(perf, cxled->dpa_res))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return perf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transient context for containing the current calculation of bandwidth when
|
||||
* doing walking the port hierarchy to deal with shared upstream link.
|
||||
*/
|
||||
struct cxl_perf_ctx {
|
||||
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
|
||||
struct cxl_port *port;
|
||||
};
|
||||
|
||||
/**
|
||||
* cxl_endpoint_gather_bandwidth - collect all the endpoint bandwidth in an xarray
|
||||
* @cxlr: CXL region for the bandwidth calculation
|
||||
* @cxled: endpoint decoder to start on
|
||||
* @usp_xa: (output) the xarray that collects all the bandwidth coordinates
|
||||
* indexed by the upstream device with data of 'struct cxl_perf_ctx'.
|
||||
* @gp_is_root: (output) bool of whether the grandparent is cxl root.
|
||||
*
|
||||
* Return: 0 for success or -errno
|
||||
*
|
||||
* Collects aggregated endpoint bandwidth and store the bandwidth in
|
||||
* an xarray indexed by the upstream device of the switch or the RP
|
||||
* device. Each endpoint consists the minimum of the bandwidth from DSLBIS
|
||||
* from the endpoint CDAT, the endpoint upstream link bandwidth, and the
|
||||
* bandwidth from the SSLBIS of the switch CDAT for the switch upstream port to
|
||||
* the downstream port that's associated with the endpoint. If the
|
||||
* device is directly connected to a RP, then no SSLBIS is involved.
|
||||
*/
|
||||
static int cxl_endpoint_gather_bandwidth(struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled,
|
||||
struct xarray *usp_xa,
|
||||
bool *gp_is_root)
|
||||
{
|
||||
struct cxl_port *endpoint = to_cxl_port(cxled->cxld.dev.parent);
|
||||
struct cxl_port *parent_port = to_cxl_port(endpoint->dev.parent);
|
||||
struct cxl_port *gp_port = to_cxl_port(parent_port->dev.parent);
|
||||
struct access_coordinate pci_coord[ACCESS_COORDINATE_MAX];
|
||||
struct access_coordinate sw_coord[ACCESS_COORDINATE_MAX];
|
||||
struct access_coordinate ep_coord[ACCESS_COORDINATE_MAX];
|
||||
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
struct cxl_perf_ctx *perf_ctx;
|
||||
struct cxl_dpa_perf *perf;
|
||||
unsigned long index;
|
||||
void *ptr;
|
||||
int rc;
|
||||
|
||||
if (cxlds->rcd)
|
||||
return -ENODEV;
|
||||
|
||||
perf = cxled_get_dpa_perf(cxled, cxlr->mode);
|
||||
if (IS_ERR(perf))
|
||||
return PTR_ERR(perf);
|
||||
|
||||
gp_port = to_cxl_port(parent_port->dev.parent);
|
||||
*gp_is_root = is_cxl_root(gp_port);
|
||||
|
||||
/*
|
||||
* If the grandparent is cxl root, then index is the root port,
|
||||
* otherwise it's the parent switch upstream device.
|
||||
*/
|
||||
if (*gp_is_root)
|
||||
index = (unsigned long)endpoint->parent_dport->dport_dev;
|
||||
else
|
||||
index = (unsigned long)parent_port->uport_dev;
|
||||
|
||||
perf_ctx = xa_load(usp_xa, index);
|
||||
if (!perf_ctx) {
|
||||
struct cxl_perf_ctx *c __free(kfree) =
|
||||
kzalloc(sizeof(*perf_ctx), GFP_KERNEL);
|
||||
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
ptr = xa_store(usp_xa, index, c, GFP_KERNEL);
|
||||
if (xa_is_err(ptr))
|
||||
return xa_err(ptr);
|
||||
perf_ctx = no_free_ptr(c);
|
||||
perf_ctx->port = parent_port;
|
||||
}
|
||||
|
||||
/* Direct upstream link from EP bandwidth */
|
||||
rc = cxl_pci_get_bandwidth(pdev, pci_coord);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Min of upstream link bandwidth and Endpoint CDAT bandwidth from
|
||||
* DSLBIS.
|
||||
*/
|
||||
cxl_coordinates_combine(ep_coord, pci_coord, perf->cdat_coord);
|
||||
|
||||
/*
|
||||
* If grandparent port is root, then there's no switch involved and
|
||||
* the endpoint is connected to a root port.
|
||||
*/
|
||||
if (!*gp_is_root) {
|
||||
/*
|
||||
* Retrieve the switch SSLBIS for switch downstream port
|
||||
* associated with the endpoint bandwidth.
|
||||
*/
|
||||
rc = cxl_port_get_switch_dport_bandwidth(endpoint, sw_coord);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Min of the earlier coordinates with the switch SSLBIS
|
||||
* bandwidth
|
||||
*/
|
||||
cxl_coordinates_combine(ep_coord, ep_coord, sw_coord);
|
||||
}
|
||||
|
||||
/*
|
||||
* Aggregate the computed bandwidth with the current aggregated bandwidth
|
||||
* of the endpoints with the same switch upstream device or RP.
|
||||
*/
|
||||
cxl_bandwidth_add(perf_ctx->coord, perf_ctx->coord, ep_coord);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_perf_xa(struct xarray *xa)
|
||||
{
|
||||
struct cxl_perf_ctx *ctx;
|
||||
unsigned long index;
|
||||
|
||||
if (!xa)
|
||||
return;
|
||||
|
||||
xa_for_each(xa, index, ctx)
|
||||
kfree(ctx);
|
||||
xa_destroy(xa);
|
||||
kfree(xa);
|
||||
}
|
||||
DEFINE_FREE(free_perf_xa, struct xarray *, if (_T) free_perf_xa(_T))
|
||||
|
||||
/**
|
||||
* cxl_switch_gather_bandwidth - collect all the bandwidth at switch level in an xarray
|
||||
* @cxlr: The region being operated on
|
||||
* @input_xa: xarray indexed by upstream device of a switch with data of 'struct
|
||||
* cxl_perf_ctx'
|
||||
* @gp_is_root: (output) bool of whether the grandparent is cxl root.
|
||||
*
|
||||
* Return: a xarray of resulting cxl_perf_ctx per parent switch or root port
|
||||
* or ERR_PTR(-errno)
|
||||
*
|
||||
* Iterate through the xarray. Take the minimum of the downstream calculated
|
||||
* bandwidth, the upstream link bandwidth, and the SSLBIS of the upstream
|
||||
* switch if exists. Sum the resulting bandwidth under the switch upstream
|
||||
* device or a RP device. The function can be iterated over multiple switches
|
||||
* if the switches are present.
|
||||
*/
|
||||
static struct xarray *cxl_switch_gather_bandwidth(struct cxl_region *cxlr,
|
||||
struct xarray *input_xa,
|
||||
bool *gp_is_root)
|
||||
{
|
||||
struct xarray *res_xa __free(free_perf_xa) =
|
||||
kzalloc(sizeof(*res_xa), GFP_KERNEL);
|
||||
struct access_coordinate coords[ACCESS_COORDINATE_MAX];
|
||||
struct cxl_perf_ctx *ctx, *us_ctx;
|
||||
unsigned long index, us_index;
|
||||
int dev_count = 0;
|
||||
int gp_count = 0;
|
||||
void *ptr;
|
||||
int rc;
|
||||
|
||||
if (!res_xa)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
xa_init(res_xa);
|
||||
|
||||
xa_for_each(input_xa, index, ctx) {
|
||||
struct device *dev = (struct device *)index;
|
||||
struct cxl_port *port = ctx->port;
|
||||
struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
|
||||
struct cxl_port *gp_port = to_cxl_port(parent_port->dev.parent);
|
||||
struct cxl_dport *dport = port->parent_dport;
|
||||
bool is_root = false;
|
||||
|
||||
dev_count++;
|
||||
if (is_cxl_root(gp_port)) {
|
||||
is_root = true;
|
||||
gp_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the grandparent is cxl root, then index is the root port,
|
||||
* otherwise it's the parent switch upstream device.
|
||||
*/
|
||||
if (is_root)
|
||||
us_index = (unsigned long)port->parent_dport->dport_dev;
|
||||
else
|
||||
us_index = (unsigned long)parent_port->uport_dev;
|
||||
|
||||
us_ctx = xa_load(res_xa, us_index);
|
||||
if (!us_ctx) {
|
||||
struct cxl_perf_ctx *n __free(kfree) =
|
||||
kzalloc(sizeof(*n), GFP_KERNEL);
|
||||
|
||||
if (!n)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ptr = xa_store(res_xa, us_index, n, GFP_KERNEL);
|
||||
if (xa_is_err(ptr))
|
||||
return ERR_PTR(xa_err(ptr));
|
||||
us_ctx = no_free_ptr(n);
|
||||
us_ctx->port = parent_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the device isn't an upstream PCIe port, there's something
|
||||
* wrong with the topology.
|
||||
*/
|
||||
if (!dev_is_pci(dev))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Retrieve the upstream link bandwidth */
|
||||
rc = cxl_pci_get_bandwidth(to_pci_dev(dev), coords);
|
||||
if (rc)
|
||||
return ERR_PTR(-ENXIO);
|
||||
|
||||
/*
|
||||
* Take the min of downstream bandwidth and the upstream link
|
||||
* bandwidth.
|
||||
*/
|
||||
cxl_coordinates_combine(coords, coords, ctx->coord);
|
||||
|
||||
/*
|
||||
* Take the min of the calculated bandwdith and the upstream
|
||||
* switch SSLBIS bandwidth if there's a parent switch
|
||||
*/
|
||||
if (!is_root)
|
||||
cxl_coordinates_combine(coords, coords, dport->coord);
|
||||
|
||||
/*
|
||||
* Aggregate the calculated bandwidth common to an upstream
|
||||
* switch.
|
||||
*/
|
||||
cxl_bandwidth_add(us_ctx->coord, us_ctx->coord, coords);
|
||||
}
|
||||
|
||||
/* Asymmetric topology detected. */
|
||||
if (gp_count) {
|
||||
if (gp_count != dev_count) {
|
||||
dev_dbg(&cxlr->dev,
|
||||
"Asymmetric hierarchy detected, bandwidth not updated\n");
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
*gp_is_root = true;
|
||||
}
|
||||
|
||||
return no_free_ptr(res_xa);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxl_rp_gather_bandwidth - handle the root port level bandwidth collection
|
||||
* @xa: the xarray that holds the cxl_perf_ctx that has the bandwidth calculated
|
||||
* below each root port device.
|
||||
*
|
||||
* Return: xarray that holds cxl_perf_ctx per host bridge or ERR_PTR(-errno)
|
||||
*/
|
||||
static struct xarray *cxl_rp_gather_bandwidth(struct xarray *xa)
|
||||
{
|
||||
struct xarray *hb_xa __free(free_perf_xa) =
|
||||
kzalloc(sizeof(*hb_xa), GFP_KERNEL);
|
||||
struct cxl_perf_ctx *ctx;
|
||||
unsigned long index;
|
||||
|
||||
if (!hb_xa)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
xa_init(hb_xa);
|
||||
|
||||
xa_for_each(xa, index, ctx) {
|
||||
struct cxl_port *port = ctx->port;
|
||||
unsigned long hb_index = (unsigned long)port->uport_dev;
|
||||
struct cxl_perf_ctx *hb_ctx;
|
||||
void *ptr;
|
||||
|
||||
hb_ctx = xa_load(hb_xa, hb_index);
|
||||
if (!hb_ctx) {
|
||||
struct cxl_perf_ctx *n __free(kfree) =
|
||||
kzalloc(sizeof(*n), GFP_KERNEL);
|
||||
|
||||
if (!n)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ptr = xa_store(hb_xa, hb_index, n, GFP_KERNEL);
|
||||
if (xa_is_err(ptr))
|
||||
return ERR_PTR(xa_err(ptr));
|
||||
hb_ctx = no_free_ptr(n);
|
||||
hb_ctx->port = port;
|
||||
}
|
||||
|
||||
cxl_bandwidth_add(hb_ctx->coord, hb_ctx->coord, ctx->coord);
|
||||
}
|
||||
|
||||
return no_free_ptr(hb_xa);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxl_hb_gather_bandwidth - handle the host bridge level bandwidth collection
|
||||
* @xa: the xarray that holds the cxl_perf_ctx that has the bandwidth calculated
|
||||
* below each host bridge.
|
||||
*
|
||||
* Return: xarray that holds cxl_perf_ctx per ACPI0017 device or ERR_PTR(-errno)
|
||||
*/
|
||||
static struct xarray *cxl_hb_gather_bandwidth(struct xarray *xa)
|
||||
{
|
||||
struct xarray *mw_xa __free(free_perf_xa) =
|
||||
kzalloc(sizeof(*mw_xa), GFP_KERNEL);
|
||||
struct cxl_perf_ctx *ctx;
|
||||
unsigned long index;
|
||||
|
||||
if (!mw_xa)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
xa_init(mw_xa);
|
||||
|
||||
xa_for_each(xa, index, ctx) {
|
||||
struct cxl_port *port = ctx->port;
|
||||
struct cxl_port *parent_port;
|
||||
struct cxl_perf_ctx *mw_ctx;
|
||||
struct cxl_dport *dport;
|
||||
unsigned long mw_index;
|
||||
void *ptr;
|
||||
|
||||
parent_port = to_cxl_port(port->dev.parent);
|
||||
mw_index = (unsigned long)parent_port->uport_dev;
|
||||
|
||||
mw_ctx = xa_load(mw_xa, mw_index);
|
||||
if (!mw_ctx) {
|
||||
struct cxl_perf_ctx *n __free(kfree) =
|
||||
kzalloc(sizeof(*n), GFP_KERNEL);
|
||||
|
||||
if (!n)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ptr = xa_store(mw_xa, mw_index, n, GFP_KERNEL);
|
||||
if (xa_is_err(ptr))
|
||||
return ERR_PTR(xa_err(ptr));
|
||||
mw_ctx = no_free_ptr(n);
|
||||
}
|
||||
|
||||
dport = port->parent_dport;
|
||||
cxl_coordinates_combine(ctx->coord, ctx->coord, dport->coord);
|
||||
cxl_bandwidth_add(mw_ctx->coord, mw_ctx->coord, ctx->coord);
|
||||
}
|
||||
|
||||
return no_free_ptr(mw_xa);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxl_region_update_bandwidth - Update the bandwidth access coordinates of a region
|
||||
* @cxlr: The region being operated on
|
||||
* @input_xa: xarray holds cxl_perf_ctx wht calculated bandwidth per ACPI0017 instance
|
||||
*/
|
||||
static void cxl_region_update_bandwidth(struct cxl_region *cxlr,
|
||||
struct xarray *input_xa)
|
||||
{
|
||||
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
|
||||
struct cxl_perf_ctx *ctx;
|
||||
unsigned long index;
|
||||
|
||||
memset(coord, 0, sizeof(coord));
|
||||
xa_for_each(input_xa, index, ctx)
|
||||
cxl_bandwidth_add(coord, coord, ctx->coord);
|
||||
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
cxlr->coord[i].read_bandwidth = coord[i].read_bandwidth;
|
||||
cxlr->coord[i].write_bandwidth = coord[i].write_bandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cxl_region_shared_upstream_bandwidth_update - Recalculate the bandwidth for
|
||||
* the region
|
||||
* @cxlr: the cxl region to recalculate
|
||||
*
|
||||
* The function walks the topology from bottom up and calculates the bandwidth. It
|
||||
* starts at the endpoints, processes at the switches if any, processes at the rootport
|
||||
* level, at the host bridge level, and finally aggregates at the region.
|
||||
*/
|
||||
void cxl_region_shared_upstream_bandwidth_update(struct cxl_region *cxlr)
|
||||
{
|
||||
struct xarray *working_xa;
|
||||
int root_count = 0;
|
||||
bool is_root;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&cxl_dpa_rwsem);
|
||||
|
||||
if (!range_contains(&perf->dpa_range, &dpa))
|
||||
struct xarray *usp_xa __free(free_perf_xa) =
|
||||
kzalloc(sizeof(*usp_xa), GFP_KERNEL);
|
||||
|
||||
if (!usp_xa)
|
||||
return;
|
||||
|
||||
xa_init(usp_xa);
|
||||
|
||||
/* Collect bandwidth data from all the endpoints. */
|
||||
for (int i = 0; i < cxlr->params.nr_targets; i++) {
|
||||
struct cxl_endpoint_decoder *cxled = cxlr->params.targets[i];
|
||||
|
||||
is_root = false;
|
||||
rc = cxl_endpoint_gather_bandwidth(cxlr, cxled, usp_xa, &is_root);
|
||||
if (rc)
|
||||
return;
|
||||
root_count += is_root;
|
||||
}
|
||||
|
||||
/* Detect asymmetric hierarchy with some direct attached endpoints. */
|
||||
if (root_count && root_count != cxlr->params.nr_targets) {
|
||||
dev_dbg(&cxlr->dev,
|
||||
"Asymmetric hierarchy detected, bandwidth not updated\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk up one or more switches to deal with the bandwidth of the
|
||||
* switches if they exist. Endpoints directly attached to RPs skip
|
||||
* over this part.
|
||||
*/
|
||||
if (!root_count) {
|
||||
do {
|
||||
working_xa = cxl_switch_gather_bandwidth(cxlr, usp_xa,
|
||||
&is_root);
|
||||
if (IS_ERR(working_xa))
|
||||
return;
|
||||
free_perf_xa(usp_xa);
|
||||
usp_xa = working_xa;
|
||||
} while (!is_root);
|
||||
}
|
||||
|
||||
/* Handle the bandwidth at the root port of the hierarchy */
|
||||
working_xa = cxl_rp_gather_bandwidth(usp_xa);
|
||||
if (IS_ERR(working_xa))
|
||||
return;
|
||||
free_perf_xa(usp_xa);
|
||||
usp_xa = working_xa;
|
||||
|
||||
/* Handle the bandwidth at the host bridge of the hierarchy */
|
||||
working_xa = cxl_hb_gather_bandwidth(usp_xa);
|
||||
if (IS_ERR(working_xa))
|
||||
return;
|
||||
free_perf_xa(usp_xa);
|
||||
usp_xa = working_xa;
|
||||
|
||||
/*
|
||||
* Aggregate all the bandwidth collected per CFMWS (ACPI0017) and
|
||||
* update the region bandwidth with the final calculated values.
|
||||
*/
|
||||
cxl_region_update_bandwidth(cxlr, usp_xa);
|
||||
}
|
||||
|
||||
void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled)
|
||||
{
|
||||
struct cxl_dpa_perf *perf;
|
||||
|
||||
lockdep_assert_held(&cxl_dpa_rwsem);
|
||||
|
||||
perf = cxled_get_dpa_perf(cxled, cxlr->mode);
|
||||
if (IS_ERR(perf))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
|
||||
@@ -103,9 +103,11 @@ enum cxl_poison_trace_type {
|
||||
};
|
||||
|
||||
long cxl_pci_get_latency(struct pci_dev *pdev);
|
||||
|
||||
int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c);
|
||||
int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr,
|
||||
enum access_coordinate_class access);
|
||||
bool cxl_need_node_perf_attrs_update(int nid);
|
||||
int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
|
||||
struct access_coordinate *c);
|
||||
|
||||
#endif /* __CXL_CORE_H__ */
|
||||
|
||||
+61
-35
@@ -225,7 +225,7 @@ static const char *cxl_mem_opcode_to_name(u16 opcode)
|
||||
|
||||
/**
|
||||
* cxl_internal_send_cmd() - Kernel internal interface to send a mailbox command
|
||||
* @mds: The driver data for the operation
|
||||
* @cxl_mbox: CXL mailbox context
|
||||
* @mbox_cmd: initialized command to execute
|
||||
*
|
||||
* Context: Any context.
|
||||
@@ -241,19 +241,19 @@ static const char *cxl_mem_opcode_to_name(u16 opcode)
|
||||
* error. While this distinction can be useful for commands from userspace, the
|
||||
* kernel will only be able to use results when both are successful.
|
||||
*/
|
||||
int cxl_internal_send_cmd(struct cxl_memdev_state *mds,
|
||||
int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox,
|
||||
struct cxl_mbox_cmd *mbox_cmd)
|
||||
{
|
||||
size_t out_size, min_out;
|
||||
int rc;
|
||||
|
||||
if (mbox_cmd->size_in > mds->payload_size ||
|
||||
mbox_cmd->size_out > mds->payload_size)
|
||||
if (mbox_cmd->size_in > cxl_mbox->payload_size ||
|
||||
mbox_cmd->size_out > cxl_mbox->payload_size)
|
||||
return -E2BIG;
|
||||
|
||||
out_size = mbox_cmd->size_out;
|
||||
min_out = mbox_cmd->min_out;
|
||||
rc = mds->mbox_send(mds, mbox_cmd);
|
||||
rc = cxl_mbox->mbox_send(cxl_mbox, mbox_cmd);
|
||||
/*
|
||||
* EIO is reserved for a payload size mismatch and mbox_send()
|
||||
* may not return this error.
|
||||
@@ -353,6 +353,7 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox,
|
||||
struct cxl_memdev_state *mds, u16 opcode,
|
||||
size_t in_size, size_t out_size, u64 in_payload)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
*mbox = (struct cxl_mbox_cmd) {
|
||||
.opcode = opcode,
|
||||
.size_in = in_size,
|
||||
@@ -374,7 +375,7 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox,
|
||||
|
||||
/* Prepare to handle a full payload for variable sized output */
|
||||
if (out_size == CXL_VARIABLE_PAYLOAD)
|
||||
mbox->size_out = mds->payload_size;
|
||||
mbox->size_out = cxl_mbox->payload_size;
|
||||
else
|
||||
mbox->size_out = out_size;
|
||||
|
||||
@@ -398,6 +399,8 @@ static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd,
|
||||
const struct cxl_send_command *send_cmd,
|
||||
struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
|
||||
if (send_cmd->raw.rsvd)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -406,7 +409,7 @@ static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd,
|
||||
* gets passed along without further checking, so it must be
|
||||
* validated here.
|
||||
*/
|
||||
if (send_cmd->out.size > mds->payload_size)
|
||||
if (send_cmd->out.size > cxl_mbox->payload_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode))
|
||||
@@ -494,6 +497,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd,
|
||||
struct cxl_memdev_state *mds,
|
||||
const struct cxl_send_command *send_cmd)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mem_command mem_cmd;
|
||||
int rc;
|
||||
|
||||
@@ -505,7 +509,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd,
|
||||
* supports, but output can be arbitrarily large (simply write out as
|
||||
* much data as the hardware provides).
|
||||
*/
|
||||
if (send_cmd->in.size > mds->payload_size)
|
||||
if (send_cmd->in.size > cxl_mbox->payload_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* Sanitize and construct a cxl_mem_command */
|
||||
@@ -542,7 +546,7 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd,
|
||||
return put_user(ARRAY_SIZE(cxl_mem_commands), &q->n_commands);
|
||||
|
||||
/*
|
||||
* otherwise, return max(n_commands, total commands) cxl_command_info
|
||||
* otherwise, return min(n_commands, total commands) cxl_command_info
|
||||
* structures.
|
||||
*/
|
||||
cxl_for_each_cmd(cmd) {
|
||||
@@ -591,6 +595,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_memdev_state *mds,
|
||||
u64 out_payload, s32 *size_out,
|
||||
u32 *retval)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct device *dev = mds->cxlds.dev;
|
||||
int rc;
|
||||
|
||||
@@ -601,7 +606,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_memdev_state *mds,
|
||||
cxl_mem_opcode_to_name(mbox_cmd->opcode),
|
||||
mbox_cmd->opcode, mbox_cmd->size_in);
|
||||
|
||||
rc = mds->mbox_send(mds, mbox_cmd);
|
||||
rc = cxl_mbox->mbox_send(cxl_mbox, mbox_cmd);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@@ -659,11 +664,12 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
|
||||
static int cxl_xfer_log(struct cxl_memdev_state *mds, uuid_t *uuid,
|
||||
u32 *size, u8 *out)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
u32 remaining = *size;
|
||||
u32 offset = 0;
|
||||
|
||||
while (remaining) {
|
||||
u32 xfer_size = min_t(u32, remaining, mds->payload_size);
|
||||
u32 xfer_size = min_t(u32, remaining, cxl_mbox->payload_size);
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
struct cxl_mbox_get_log log;
|
||||
int rc;
|
||||
@@ -682,7 +688,7 @@ static int cxl_xfer_log(struct cxl_memdev_state *mds, uuid_t *uuid,
|
||||
.payload_out = out,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
|
||||
/*
|
||||
* The output payload length that indicates the number
|
||||
@@ -752,22 +758,23 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)
|
||||
|
||||
static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_get_supported_logs *ret;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
|
||||
ret = kvmalloc(mds->payload_size, GFP_KERNEL);
|
||||
ret = kvmalloc(cxl_mbox->payload_size, GFP_KERNEL);
|
||||
if (!ret)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mbox_cmd = (struct cxl_mbox_cmd) {
|
||||
.opcode = CXL_MBOX_OP_GET_SUPPORTED_LOGS,
|
||||
.size_out = mds->payload_size,
|
||||
.size_out = cxl_mbox->payload_size,
|
||||
.payload_out = ret,
|
||||
/* At least the record number field must be valid */
|
||||
.min_out = 2,
|
||||
};
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0) {
|
||||
kvfree(ret);
|
||||
return ERR_PTR(rc);
|
||||
@@ -910,6 +917,7 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
enum cxl_event_log_type log,
|
||||
struct cxl_get_event_payload *get_pl)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_clear_event_payload *payload;
|
||||
u16 total = le16_to_cpu(get_pl->record_count);
|
||||
u8 max_handles = CXL_CLEAR_EVENT_MAX_HANDLES;
|
||||
@@ -920,8 +928,8 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
int i;
|
||||
|
||||
/* Payload size may limit the max handles */
|
||||
if (pl_size > mds->payload_size) {
|
||||
max_handles = (mds->payload_size - sizeof(*payload)) /
|
||||
if (pl_size > cxl_mbox->payload_size) {
|
||||
max_handles = (cxl_mbox->payload_size - sizeof(*payload)) /
|
||||
sizeof(__le16);
|
||||
pl_size = struct_size(payload, handles, max_handles);
|
||||
}
|
||||
@@ -955,7 +963,7 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
|
||||
if (i == max_handles) {
|
||||
payload->nr_recs = i;
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
goto free_pl;
|
||||
i = 0;
|
||||
@@ -966,7 +974,7 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
|
||||
if (i) {
|
||||
payload->nr_recs = i;
|
||||
mbox_cmd.size_in = struct_size(payload, handles, i);
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
goto free_pl;
|
||||
}
|
||||
@@ -979,6 +987,7 @@ free_pl:
|
||||
static void cxl_mem_get_records_log(struct cxl_memdev_state *mds,
|
||||
enum cxl_event_log_type type)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_memdev *cxlmd = mds->cxlds.cxlmd;
|
||||
struct device *dev = mds->cxlds.dev;
|
||||
struct cxl_get_event_payload *payload;
|
||||
@@ -995,11 +1004,11 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds,
|
||||
.payload_in = &log_type,
|
||||
.size_in = sizeof(log_type),
|
||||
.payload_out = payload,
|
||||
.size_out = mds->payload_size,
|
||||
.size_out = cxl_mbox->payload_size,
|
||||
.min_out = struct_size(payload, records, 0),
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc) {
|
||||
dev_err_ratelimited(dev,
|
||||
"Event log '%d': Failed to query event records : %d",
|
||||
@@ -1070,6 +1079,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, CXL);
|
||||
*/
|
||||
static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_get_partition_info pi;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -1079,7 +1089,7 @@ static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
|
||||
.size_out = sizeof(pi),
|
||||
.payload_out = &pi,
|
||||
};
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -1106,6 +1116,7 @@ static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
|
||||
*/
|
||||
int cxl_dev_state_identify(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
/* See CXL 2.0 Table 175 Identify Memory Device Output Payload */
|
||||
struct cxl_mbox_identify id;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
@@ -1120,7 +1131,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds)
|
||||
.size_out = sizeof(id),
|
||||
.payload_out = &id,
|
||||
};
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -1148,6 +1159,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
|
||||
|
||||
static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
int rc;
|
||||
u32 sec_out = 0;
|
||||
struct cxl_get_security_output {
|
||||
@@ -1159,14 +1171,13 @@ static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd)
|
||||
.size_out = sizeof(out),
|
||||
};
|
||||
struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
|
||||
if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)
|
||||
return -EINVAL;
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &sec_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &sec_cmd);
|
||||
if (rc < 0) {
|
||||
dev_err(cxlds->dev, "Failed to get security state : %d", rc);
|
||||
dev_err(cxl_mbox->host, "Failed to get security state : %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1183,9 +1194,9 @@ static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd)
|
||||
sec_out & CXL_PMEM_SEC_STATE_LOCKED)
|
||||
return -EINVAL;
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0) {
|
||||
dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
|
||||
dev_err(cxl_mbox->host, "Failed to sanitize device : %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1214,7 +1225,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
|
||||
int rc;
|
||||
|
||||
/* synchronize with cxl_mem_probe() and decoder write operations */
|
||||
device_lock(&cxlmd->dev);
|
||||
guard(device)(&cxlmd->dev);
|
||||
endpoint = cxlmd->endpoint;
|
||||
down_read(&cxl_region_rwsem);
|
||||
/*
|
||||
@@ -1226,7 +1237,6 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
|
||||
else
|
||||
rc = -EBUSY;
|
||||
up_read(&cxl_region_rwsem);
|
||||
device_unlock(&cxlmd->dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1300,6 +1310,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
|
||||
|
||||
int cxl_set_timestamp(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
struct cxl_mbox_set_timestamp_in pi;
|
||||
int rc;
|
||||
@@ -1311,7 +1322,7 @@ int cxl_set_timestamp(struct cxl_memdev_state *mds)
|
||||
.payload_in = &pi,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
/*
|
||||
* Command is optional. Devices may have another way of providing
|
||||
* a timestamp, or may return all 0s in timestamp fields.
|
||||
@@ -1328,6 +1339,7 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
|
||||
struct cxl_region *cxlr)
|
||||
{
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_poison_out *po;
|
||||
struct cxl_mbox_poison_in pi;
|
||||
int nr_records = 0;
|
||||
@@ -1346,12 +1358,12 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
|
||||
.opcode = CXL_MBOX_OP_GET_POISON,
|
||||
.size_in = sizeof(pi),
|
||||
.payload_in = &pi,
|
||||
.size_out = mds->payload_size,
|
||||
.size_out = cxl_mbox->payload_size,
|
||||
.payload_out = po,
|
||||
.min_out = struct_size(po, record, 0),
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
@@ -1382,7 +1394,9 @@ static void free_poison_buf(void *buf)
|
||||
/* Get Poison List output buffer is protected by mds->poison.lock */
|
||||
static int cxl_poison_alloc_buf(struct cxl_memdev_state *mds)
|
||||
{
|
||||
mds->poison.list_out = kvmalloc(mds->payload_size, GFP_KERNEL);
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
|
||||
mds->poison.list_out = kvmalloc(cxl_mbox->payload_size, GFP_KERNEL);
|
||||
if (!mds->poison.list_out)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1408,6 +1422,19 @@ int cxl_poison_state_init(struct cxl_memdev_state *mds)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, CXL);
|
||||
|
||||
int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host)
|
||||
{
|
||||
if (!cxl_mbox || !host)
|
||||
return -EINVAL;
|
||||
|
||||
cxl_mbox->host = host;
|
||||
mutex_init(&cxl_mbox->mbox_mutex);
|
||||
rcuwait_init(&cxl_mbox->mbox_wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_mailbox_init, CXL);
|
||||
|
||||
struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev)
|
||||
{
|
||||
struct cxl_memdev_state *mds;
|
||||
@@ -1418,7 +1445,6 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
mutex_init(&mds->mbox_mutex);
|
||||
mutex_init(&mds->event.log_lock);
|
||||
mds->cxlds.dev = dev;
|
||||
mds->cxlds.reg_map.host = dev;
|
||||
|
||||
+24
-17
@@ -58,7 +58,7 @@ static ssize_t payload_max_show(struct device *dev,
|
||||
|
||||
if (!mds)
|
||||
return sysfs_emit(buf, "\n");
|
||||
return sysfs_emit(buf, "%zu\n", mds->payload_size);
|
||||
return sysfs_emit(buf, "%zu\n", cxlds->cxl_mbox.payload_size);
|
||||
}
|
||||
static DEVICE_ATTR_RO(payload_max);
|
||||
|
||||
@@ -124,15 +124,16 @@ static ssize_t security_state_show(struct device *dev,
|
||||
{
|
||||
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
|
||||
unsigned long state = mds->security.state;
|
||||
int rc = 0;
|
||||
|
||||
/* sync with latest submission state */
|
||||
mutex_lock(&mds->mbox_mutex);
|
||||
mutex_lock(&cxl_mbox->mbox_mutex);
|
||||
if (mds->security.sanitize_active)
|
||||
rc = sysfs_emit(buf, "sanitize\n");
|
||||
mutex_unlock(&mds->mbox_mutex);
|
||||
mutex_unlock(&cxl_mbox->mbox_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -277,7 +278,7 @@ static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa)
|
||||
|
||||
int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa)
|
||||
{
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_inject_poison inject;
|
||||
struct cxl_poison_record record;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
@@ -307,13 +308,13 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa)
|
||||
.size_in = sizeof(inject),
|
||||
.payload_in = &inject,
|
||||
};
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
cxlr = cxl_dpa_to_region(cxlmd, dpa);
|
||||
if (cxlr)
|
||||
dev_warn_once(mds->cxlds.dev,
|
||||
dev_warn_once(cxl_mbox->host,
|
||||
"poison inject dpa:%#llx region: %s\n", dpa,
|
||||
dev_name(&cxlr->dev));
|
||||
|
||||
@@ -332,7 +333,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, CXL);
|
||||
|
||||
int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa)
|
||||
{
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_clear_poison clear;
|
||||
struct cxl_poison_record record;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
@@ -371,13 +372,13 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa)
|
||||
.payload_in = &clear,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
cxlr = cxl_dpa_to_region(cxlmd, dpa);
|
||||
if (cxlr)
|
||||
dev_warn_once(mds->cxlds.dev,
|
||||
dev_warn_once(cxl_mbox->host,
|
||||
"poison clear dpa:%#llx region: %s\n", dpa,
|
||||
dev_name(&cxlr->dev));
|
||||
|
||||
@@ -714,6 +715,7 @@ static int cxl_memdev_release_file(struct inode *inode, struct file *file)
|
||||
*/
|
||||
static int cxl_mem_get_fw_info(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_get_fw_info info;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -724,7 +726,7 @@ static int cxl_mem_get_fw_info(struct cxl_memdev_state *mds)
|
||||
.payload_out = &info,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -748,6 +750,7 @@ static int cxl_mem_get_fw_info(struct cxl_memdev_state *mds)
|
||||
*/
|
||||
static int cxl_mem_activate_fw(struct cxl_memdev_state *mds, int slot)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_activate_fw activate;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
|
||||
@@ -764,7 +767,7 @@ static int cxl_mem_activate_fw(struct cxl_memdev_state *mds, int slot)
|
||||
activate.action = CXL_FW_ACTIVATE_OFFLINE;
|
||||
activate.slot = slot;
|
||||
|
||||
return cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,6 +782,7 @@ static int cxl_mem_activate_fw(struct cxl_memdev_state *mds, int slot)
|
||||
*/
|
||||
static int cxl_mem_abort_fw_xfer(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_transfer_fw *transfer;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -798,7 +802,7 @@ static int cxl_mem_abort_fw_xfer(struct cxl_memdev_state *mds)
|
||||
|
||||
transfer->action = CXL_FW_TRANSFER_ACTION_ABORT;
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
kfree(transfer);
|
||||
return rc;
|
||||
}
|
||||
@@ -829,12 +833,13 @@ static enum fw_upload_err cxl_fw_prepare(struct fw_upload *fwl, const u8 *data,
|
||||
{
|
||||
struct cxl_memdev_state *mds = fwl->dd_handle;
|
||||
struct cxl_mbox_transfer_fw *transfer;
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
|
||||
if (!size)
|
||||
return FW_UPLOAD_ERR_INVALID_SIZE;
|
||||
|
||||
mds->fw.oneshot = struct_size(transfer, data, size) <
|
||||
mds->payload_size;
|
||||
cxl_mbox->payload_size;
|
||||
|
||||
if (cxl_mem_get_fw_info(mds))
|
||||
return FW_UPLOAD_ERR_HW_ERROR;
|
||||
@@ -854,6 +859,7 @@ static enum fw_upload_err cxl_fw_write(struct fw_upload *fwl, const u8 *data,
|
||||
{
|
||||
struct cxl_memdev_state *mds = fwl->dd_handle;
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;
|
||||
struct cxl_memdev *cxlmd = cxlds->cxlmd;
|
||||
struct cxl_mbox_transfer_fw *transfer;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
@@ -877,7 +883,7 @@ static enum fw_upload_err cxl_fw_write(struct fw_upload *fwl, const u8 *data,
|
||||
* sizeof(*transfer) is 128. These constraints imply that @cur_size
|
||||
* will always be 128b aligned.
|
||||
*/
|
||||
cur_size = min_t(size_t, size, mds->payload_size - sizeof(*transfer));
|
||||
cur_size = min_t(size_t, size, cxl_mbox->payload_size - sizeof(*transfer));
|
||||
|
||||
remaining = size - cur_size;
|
||||
size_in = struct_size(transfer, data, cur_size);
|
||||
@@ -921,7 +927,7 @@ static enum fw_upload_err cxl_fw_write(struct fw_upload *fwl, const u8 *data,
|
||||
.poll_count = 30,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0) {
|
||||
rc = FW_UPLOAD_ERR_RW_ERROR;
|
||||
goto out_free;
|
||||
@@ -1059,16 +1065,17 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL);
|
||||
static void sanitize_teardown_notifier(void *data)
|
||||
{
|
||||
struct cxl_memdev_state *mds = data;
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct kernfs_node *state;
|
||||
|
||||
/*
|
||||
* Prevent new irq triggered invocations of the workqueue and
|
||||
* flush inflight invocations.
|
||||
*/
|
||||
mutex_lock(&mds->mbox_mutex);
|
||||
mutex_lock(&cxl_mbox->mbox_mutex);
|
||||
state = mds->security.sanitize_node;
|
||||
mds->security.sanitize_node = NULL;
|
||||
mutex_unlock(&mds->mbox_mutex);
|
||||
mutex_unlock(&cxl_mbox->mbox_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&mds->security.poll_dwork);
|
||||
sysfs_put(state);
|
||||
|
||||
+71
-93
@@ -211,37 +211,6 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, CXL);
|
||||
|
||||
static int wait_for_valid(struct pci_dev *pdev, int d)
|
||||
{
|
||||
u32 val;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Memory_Info_Valid: When set, indicates that the CXL Range 1 Size high
|
||||
* and Size Low registers are valid. Must be set within 1 second of
|
||||
* deassertion of reset to CXL device. Likely it is already set by the
|
||||
* time this runs, but otherwise give a 1.5 second timeout in case of
|
||||
* clock skew.
|
||||
*/
|
||||
rc = pci_read_config_dword(pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &val);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (val & CXL_DVSEC_MEM_INFO_VALID)
|
||||
return 0;
|
||||
|
||||
msleep(1500);
|
||||
|
||||
rc = pci_read_config_dword(pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &val);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (val & CXL_DVSEC_MEM_INFO_VALID)
|
||||
return 0;
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
@@ -322,11 +291,13 @@ static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm)
|
||||
return devm_add_action_or_reset(host, disable_hdm, cxlhdm);
|
||||
}
|
||||
|
||||
int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
int cxl_dvsec_rr_decode(struct device *dev, struct cxl_port *port,
|
||||
struct cxl_endpoint_dvsec_info *info)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
|
||||
int hdm_count, rc, i, ranges = 0;
|
||||
int d = cxlds->cxl_dvsec;
|
||||
u16 cap, ctrl;
|
||||
|
||||
if (!d) {
|
||||
@@ -353,12 +324,6 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
if (!hdm_count || hdm_count > 2)
|
||||
return -EINVAL;
|
||||
|
||||
rc = wait_for_valid(pdev, d);
|
||||
if (rc) {
|
||||
dev_dbg(dev, "Failure awaiting MEM_INFO_VALID (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current DVSEC values are moot if the memory capability is
|
||||
* disabled, and they will remain moot after the HDM Decoder
|
||||
@@ -376,6 +341,10 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
u64 base, size;
|
||||
u32 temp;
|
||||
|
||||
rc = cxl_dvsec_mem_range_valid(cxlds, i);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_read_config_dword(
|
||||
pdev, d + CXL_DVSEC_RANGE_SIZE_HIGH(i), &temp);
|
||||
if (rc)
|
||||
@@ -390,10 +359,6 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
|
||||
size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;
|
||||
if (!size) {
|
||||
info->dvsec_range[i] = (struct range) {
|
||||
.start = 0,
|
||||
.end = CXL_RESOURCE_NONE,
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -411,12 +376,10 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
|
||||
base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;
|
||||
|
||||
info->dvsec_range[i] = (struct range) {
|
||||
info->dvsec_range[ranges++] = (struct range) {
|
||||
.start = base,
|
||||
.end = base + size - 1
|
||||
};
|
||||
|
||||
ranges++;
|
||||
}
|
||||
|
||||
info->ranges = ranges;
|
||||
@@ -463,7 +426,15 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0, allowed = 0; info->mem_enabled && i < info->ranges; i++) {
|
||||
if (!info->mem_enabled) {
|
||||
rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return devm_cxl_enable_mem(&port->dev, cxlds);
|
||||
}
|
||||
|
||||
for (i = 0, allowed = 0; i < info->ranges; i++) {
|
||||
struct device *cxld_dev;
|
||||
|
||||
cxld_dev = device_find_child(&root->dev, &info->dvsec_range[i],
|
||||
@@ -477,7 +448,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
|
||||
allowed++;
|
||||
}
|
||||
|
||||
if (!allowed && info->mem_enabled) {
|
||||
if (!allowed) {
|
||||
dev_err(dev, "Range register decodes outside platform defined CXL ranges.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
@@ -491,14 +462,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
|
||||
* match. If at least one DVSEC range is enabled and allowed, skip HDM
|
||||
* Decoder Capability Enable.
|
||||
*/
|
||||
if (info->mem_enabled)
|
||||
return 0;
|
||||
|
||||
rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return devm_cxl_enable_mem(&port->dev, cxlds);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL);
|
||||
|
||||
@@ -772,22 +736,20 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
|
||||
|
||||
static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
|
||||
{
|
||||
struct cxl_rcrb_info *ri = &dport->rcrb;
|
||||
void __iomem *dport_aer = NULL;
|
||||
resource_size_t aer_phys;
|
||||
struct device *host;
|
||||
u16 aer_cap;
|
||||
|
||||
if (dport->rch && ri->aer_cap) {
|
||||
aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
|
||||
if (aer_cap) {
|
||||
host = dport->reg_map.host;
|
||||
aer_phys = ri->aer_cap + ri->base;
|
||||
dport_aer = devm_cxl_iomap_block(host, aer_phys,
|
||||
sizeof(struct aer_capability_regs));
|
||||
aer_phys = aer_cap + dport->rcrb.base;
|
||||
dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
|
||||
sizeof(struct aer_capability_regs));
|
||||
}
|
||||
|
||||
dport->regs.dport_aer = dport_aer;
|
||||
}
|
||||
|
||||
static void cxl_dport_map_regs(struct cxl_dport *dport)
|
||||
static void cxl_dport_map_ras(struct cxl_dport *dport)
|
||||
{
|
||||
struct cxl_register_map *map = &dport->reg_map;
|
||||
struct device *dev = dport->dport_dev;
|
||||
@@ -797,22 +759,16 @@ static void cxl_dport_map_regs(struct cxl_dport *dport)
|
||||
else if (cxl_map_component_regs(map, &dport->regs.component,
|
||||
BIT(CXL_CM_CAP_CAP_ID_RAS)))
|
||||
dev_dbg(dev, "Failed to map RAS capability.\n");
|
||||
|
||||
if (dport->rch)
|
||||
cxl_dport_map_rch_aer(dport);
|
||||
}
|
||||
|
||||
static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
|
||||
{
|
||||
void __iomem *aer_base = dport->regs.dport_aer;
|
||||
struct pci_host_bridge *bridge;
|
||||
u32 aer_cmd_mask, aer_cmd;
|
||||
|
||||
if (!aer_base)
|
||||
return;
|
||||
|
||||
bridge = to_pci_host_bridge(dport->dport_dev);
|
||||
|
||||
/*
|
||||
* Disable RCH root port command interrupts.
|
||||
* CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
|
||||
@@ -821,34 +777,35 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
|
||||
* the root cmd register's interrupts is required. But, PCI spec
|
||||
* shows these are disabled by default on reset.
|
||||
*/
|
||||
if (bridge->native_aer) {
|
||||
aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
|
||||
PCI_ERR_ROOT_CMD_NONFATAL_EN |
|
||||
PCI_ERR_ROOT_CMD_FATAL_EN);
|
||||
aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
|
||||
aer_cmd &= ~aer_cmd_mask;
|
||||
writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
|
||||
}
|
||||
aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
|
||||
PCI_ERR_ROOT_CMD_NONFATAL_EN |
|
||||
PCI_ERR_ROOT_CMD_FATAL_EN);
|
||||
aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
|
||||
aer_cmd &= ~aer_cmd_mask;
|
||||
writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
|
||||
}
|
||||
|
||||
void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport)
|
||||
/**
|
||||
* cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
|
||||
* @dport: the cxl_dport that needs to be initialized
|
||||
* @host: host device for devm operations
|
||||
*/
|
||||
void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
|
||||
{
|
||||
struct device *dport_dev = dport->dport_dev;
|
||||
dport->reg_map.host = host;
|
||||
cxl_dport_map_ras(dport);
|
||||
|
||||
if (dport->rch) {
|
||||
struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport_dev);
|
||||
struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
|
||||
|
||||
if (host_bridge->native_aer)
|
||||
dport->rcrb.aer_cap = cxl_rcrb_to_aer(dport_dev, dport->rcrb.base);
|
||||
}
|
||||
if (!host_bridge->native_aer)
|
||||
return;
|
||||
|
||||
dport->reg_map.host = host;
|
||||
cxl_dport_map_regs(dport);
|
||||
|
||||
if (dport->rch)
|
||||
cxl_dport_map_rch_aer(dport);
|
||||
cxl_disable_rch_root_ints(dport);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_setup_parent_dport, CXL);
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, CXL);
|
||||
|
||||
static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
|
||||
struct cxl_dport *dport)
|
||||
@@ -915,15 +872,13 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
|
||||
struct pci_dev *pdev = to_pci_dev(cxlds->dev);
|
||||
struct aer_capability_regs aer_regs;
|
||||
struct cxl_dport *dport;
|
||||
struct cxl_port *port;
|
||||
int severity;
|
||||
|
||||
port = cxl_pci_find_port(pdev, &dport);
|
||||
struct cxl_port *port __free(put_cxl_port) =
|
||||
cxl_pci_find_port(pdev, &dport);
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
put_device(&port->dev);
|
||||
|
||||
if (!cxl_rch_get_aer_info(dport->regs.dport_aer, &aer_regs))
|
||||
return;
|
||||
|
||||
@@ -1076,3 +1031,26 @@ bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port)
|
||||
__cxl_endpoint_decoder_reset_detected);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_reset_detected, CXL);
|
||||
|
||||
int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c)
|
||||
{
|
||||
int speed, bw;
|
||||
u16 lnksta;
|
||||
u32 width;
|
||||
|
||||
speed = pcie_link_speed_mbps(pdev);
|
||||
if (speed < 0)
|
||||
return speed;
|
||||
speed /= BITS_PER_BYTE;
|
||||
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta);
|
||||
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
|
||||
bw = speed * width;
|
||||
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
c[i].read_bandwidth = bw;
|
||||
c[i].write_bandwidth = bw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+114
-98
@@ -3,7 +3,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/memregion.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/einj-cxl.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
@@ -11,6 +10,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/node.h>
|
||||
#include <cxl/einj.h>
|
||||
#include <cxlmem.h>
|
||||
#include <cxlpci.h>
|
||||
#include <cxl.h>
|
||||
@@ -828,27 +828,20 @@ static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
|
||||
&cxl_einj_inject_fops);
|
||||
}
|
||||
|
||||
static struct cxl_port *__devm_cxl_add_port(struct device *host,
|
||||
struct device *uport_dev,
|
||||
resource_size_t component_reg_phys,
|
||||
struct cxl_dport *parent_dport)
|
||||
static int cxl_port_add(struct cxl_port *port,
|
||||
resource_size_t component_reg_phys,
|
||||
struct cxl_dport *parent_dport)
|
||||
{
|
||||
struct cxl_port *port;
|
||||
struct device *dev;
|
||||
struct device *dev __free(put_device) = &port->dev;
|
||||
int rc;
|
||||
|
||||
port = cxl_port_alloc(uport_dev, parent_dport);
|
||||
if (IS_ERR(port))
|
||||
return port;
|
||||
|
||||
dev = &port->dev;
|
||||
if (is_cxl_memdev(uport_dev)) {
|
||||
struct cxl_memdev *cxlmd = to_cxl_memdev(uport_dev);
|
||||
if (is_cxl_memdev(port->uport_dev)) {
|
||||
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
|
||||
rc = dev_set_name(dev, "endpoint%d", port->id);
|
||||
if (rc)
|
||||
goto err;
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* The endpoint driver already enumerated the component and RAS
|
||||
@@ -861,19 +854,41 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
|
||||
} else if (parent_dport) {
|
||||
rc = dev_set_name(dev, "port%d", port->id);
|
||||
if (rc)
|
||||
goto err;
|
||||
return rc;
|
||||
|
||||
rc = cxl_port_setup_regs(port, component_reg_phys);
|
||||
if (rc)
|
||||
goto err;
|
||||
} else
|
||||
return rc;
|
||||
} else {
|
||||
rc = dev_set_name(dev, "root%d", port->id);
|
||||
if (rc)
|
||||
goto err;
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = device_add(dev);
|
||||
if (rc)
|
||||
goto err;
|
||||
return rc;
|
||||
|
||||
/* Inhibit the cleanup function invoked */
|
||||
dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cxl_port *__devm_cxl_add_port(struct device *host,
|
||||
struct device *uport_dev,
|
||||
resource_size_t component_reg_phys,
|
||||
struct cxl_dport *parent_dport)
|
||||
{
|
||||
struct cxl_port *port;
|
||||
int rc;
|
||||
|
||||
port = cxl_port_alloc(uport_dev, parent_dport);
|
||||
if (IS_ERR(port))
|
||||
return port;
|
||||
|
||||
rc = cxl_port_add(port, component_reg_phys, parent_dport);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
rc = devm_add_action_or_reset(host, unregister_port, port);
|
||||
if (rc)
|
||||
@@ -891,10 +906,6 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
|
||||
port->pci_latency = cxl_pci_get_latency(to_pci_dev(uport_dev));
|
||||
|
||||
return port;
|
||||
|
||||
err:
|
||||
put_device(dev);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -941,7 +952,7 @@ struct cxl_root *devm_cxl_add_root(struct device *host,
|
||||
|
||||
port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
|
||||
if (IS_ERR(port))
|
||||
return (struct cxl_root *)port;
|
||||
return ERR_CAST(port);
|
||||
|
||||
cxl_root = to_cxl_root(port);
|
||||
cxl_root->ops = ops;
|
||||
@@ -1258,18 +1269,13 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_add_rch_dport, CXL);
|
||||
static int add_ep(struct cxl_ep *new)
|
||||
{
|
||||
struct cxl_port *port = new->dport->port;
|
||||
int rc;
|
||||
|
||||
device_lock(&port->dev);
|
||||
if (port->dead) {
|
||||
device_unlock(&port->dev);
|
||||
guard(device)(&port->dev);
|
||||
if (port->dead)
|
||||
return -ENXIO;
|
||||
}
|
||||
rc = xa_insert(&port->endpoints, (unsigned long)new->ep, new,
|
||||
GFP_KERNEL);
|
||||
device_unlock(&port->dev);
|
||||
|
||||
return rc;
|
||||
return xa_insert(&port->endpoints, (unsigned long)new->ep,
|
||||
new, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1393,14 +1399,14 @@ static void delete_endpoint(void *data)
|
||||
struct cxl_port *endpoint = cxlmd->endpoint;
|
||||
struct device *host = endpoint_host(endpoint);
|
||||
|
||||
device_lock(host);
|
||||
if (host->driver && !endpoint->dead) {
|
||||
devm_release_action(host, cxl_unlink_parent_dport, endpoint);
|
||||
devm_release_action(host, cxl_unlink_uport, endpoint);
|
||||
devm_release_action(host, unregister_port, endpoint);
|
||||
scoped_guard(device, host) {
|
||||
if (host->driver && !endpoint->dead) {
|
||||
devm_release_action(host, cxl_unlink_parent_dport, endpoint);
|
||||
devm_release_action(host, cxl_unlink_uport, endpoint);
|
||||
devm_release_action(host, unregister_port, endpoint);
|
||||
}
|
||||
cxlmd->endpoint = NULL;
|
||||
}
|
||||
cxlmd->endpoint = NULL;
|
||||
device_unlock(host);
|
||||
put_device(&endpoint->dev);
|
||||
put_device(host);
|
||||
}
|
||||
@@ -1477,12 +1483,11 @@ static void cxl_detach_ep(void *data)
|
||||
.cxlmd = cxlmd,
|
||||
.depth = i,
|
||||
};
|
||||
struct device *dev;
|
||||
struct cxl_ep *ep;
|
||||
bool died = false;
|
||||
|
||||
dev = bus_find_device(&cxl_bus_type, NULL, &ctx,
|
||||
port_has_memdev);
|
||||
struct device *dev __free(put_device) =
|
||||
bus_find_device(&cxl_bus_type, NULL, &ctx, port_has_memdev);
|
||||
if (!dev)
|
||||
continue;
|
||||
port = to_cxl_port(dev);
|
||||
@@ -1512,7 +1517,6 @@ static void cxl_detach_ep(void *data)
|
||||
dev_name(&port->dev));
|
||||
delete_switch_port(port);
|
||||
}
|
||||
put_device(&port->dev);
|
||||
device_unlock(&parent_port->dev);
|
||||
}
|
||||
}
|
||||
@@ -1540,7 +1544,6 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
|
||||
struct device *dport_dev)
|
||||
{
|
||||
struct device *dparent = grandparent(dport_dev);
|
||||
struct cxl_port *port, *parent_port = NULL;
|
||||
struct cxl_dport *dport, *parent_dport;
|
||||
resource_size_t component_reg_phys;
|
||||
int rc;
|
||||
@@ -1556,50 +1559,52 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
parent_port = find_cxl_port(dparent, &parent_dport);
|
||||
struct cxl_port *parent_port __free(put_cxl_port) =
|
||||
find_cxl_port(dparent, &parent_dport);
|
||||
if (!parent_port) {
|
||||
/* iterate to create this parent_port */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
device_lock(&parent_port->dev);
|
||||
if (!parent_port->dev.driver) {
|
||||
dev_warn(&cxlmd->dev,
|
||||
"port %s:%s disabled, failed to enumerate CXL.mem\n",
|
||||
dev_name(&parent_port->dev), dev_name(uport_dev));
|
||||
port = ERR_PTR(-ENXIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = find_cxl_port_at(parent_port, dport_dev, &dport);
|
||||
if (!port) {
|
||||
component_reg_phys = find_component_registers(uport_dev);
|
||||
port = devm_cxl_add_port(&parent_port->dev, uport_dev,
|
||||
component_reg_phys, parent_dport);
|
||||
/* retry find to pick up the new dport information */
|
||||
if (!IS_ERR(port))
|
||||
port = find_cxl_port_at(parent_port, dport_dev, &dport);
|
||||
}
|
||||
out:
|
||||
device_unlock(&parent_port->dev);
|
||||
|
||||
if (IS_ERR(port))
|
||||
rc = PTR_ERR(port);
|
||||
else {
|
||||
dev_dbg(&cxlmd->dev, "add to new port %s:%s\n",
|
||||
dev_name(&port->dev), dev_name(port->uport_dev));
|
||||
rc = cxl_add_ep(dport, &cxlmd->dev);
|
||||
if (rc == -EBUSY) {
|
||||
/*
|
||||
* "can't" happen, but this error code means
|
||||
* something to the caller, so translate it.
|
||||
*/
|
||||
rc = -ENXIO;
|
||||
/*
|
||||
* Definition with __free() here to keep the sequence of
|
||||
* dereferencing the device of the port before the parent_port releasing.
|
||||
*/
|
||||
struct cxl_port *port __free(put_cxl_port) = NULL;
|
||||
scoped_guard(device, &parent_port->dev) {
|
||||
if (!parent_port->dev.driver) {
|
||||
dev_warn(&cxlmd->dev,
|
||||
"port %s:%s disabled, failed to enumerate CXL.mem\n",
|
||||
dev_name(&parent_port->dev), dev_name(uport_dev));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
port = find_cxl_port_at(parent_port, dport_dev, &dport);
|
||||
if (!port) {
|
||||
component_reg_phys = find_component_registers(uport_dev);
|
||||
port = devm_cxl_add_port(&parent_port->dev, uport_dev,
|
||||
component_reg_phys, parent_dport);
|
||||
if (IS_ERR(port))
|
||||
return PTR_ERR(port);
|
||||
|
||||
/* retry find to pick up the new dport information */
|
||||
port = find_cxl_port_at(parent_port, dport_dev, &dport);
|
||||
if (!port)
|
||||
return -ENXIO;
|
||||
}
|
||||
put_device(&port->dev);
|
||||
}
|
||||
|
||||
put_device(&parent_port->dev);
|
||||
dev_dbg(&cxlmd->dev, "add to new port %s:%s\n",
|
||||
dev_name(&port->dev), dev_name(port->uport_dev));
|
||||
rc = cxl_add_ep(dport, &cxlmd->dev);
|
||||
if (rc == -EBUSY) {
|
||||
/*
|
||||
* "can't" happen, but this error code means
|
||||
* something to the caller, so translate it.
|
||||
*/
|
||||
rc = -ENXIO;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1630,7 +1635,6 @@ retry:
|
||||
struct device *dport_dev = grandparent(iter);
|
||||
struct device *uport_dev;
|
||||
struct cxl_dport *dport;
|
||||
struct cxl_port *port;
|
||||
|
||||
/*
|
||||
* The terminal "grandparent" in PCI is NULL and @platform_bus
|
||||
@@ -1649,7 +1653,8 @@ retry:
|
||||
dev_dbg(dev, "scan: iter: %s dport_dev: %s parent: %s\n",
|
||||
dev_name(iter), dev_name(dport_dev),
|
||||
dev_name(uport_dev));
|
||||
port = find_cxl_port(dport_dev, &dport);
|
||||
struct cxl_port *port __free(put_cxl_port) =
|
||||
find_cxl_port(dport_dev, &dport);
|
||||
if (port) {
|
||||
dev_dbg(&cxlmd->dev,
|
||||
"found already registered port %s:%s\n",
|
||||
@@ -1664,18 +1669,13 @@ retry:
|
||||
* the parent_port lock as the current port may be being
|
||||
* reaped.
|
||||
*/
|
||||
if (rc && rc != -EBUSY) {
|
||||
put_device(&port->dev);
|
||||
if (rc && rc != -EBUSY)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Any more ports to add between this one and the root? */
|
||||
if (!dev_is_cxl_root_child(&port->dev)) {
|
||||
put_device(&port->dev);
|
||||
if (!dev_is_cxl_root_child(&port->dev))
|
||||
continue;
|
||||
}
|
||||
|
||||
put_device(&port->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1983,7 +1983,6 @@ EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL);
|
||||
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
|
||||
{
|
||||
struct cxl_port *port;
|
||||
int rc;
|
||||
|
||||
if (WARN_ON_ONCE(!cxld))
|
||||
return -EINVAL;
|
||||
@@ -1993,11 +1992,8 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
|
||||
|
||||
port = to_cxl_port(cxld->dev.parent);
|
||||
|
||||
device_lock(&port->dev);
|
||||
rc = cxl_decoder_add_locked(cxld, target_map);
|
||||
device_unlock(&port->dev);
|
||||
|
||||
return rc;
|
||||
guard(device)(&port->dev);
|
||||
return cxl_decoder_add_locked(cxld, target_map);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL);
|
||||
|
||||
@@ -2241,6 +2237,26 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, CXL);
|
||||
|
||||
int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
|
||||
struct access_coordinate *c)
|
||||
{
|
||||
struct cxl_dport *dport = port->parent_dport;
|
||||
|
||||
/* Check this port is connected to a switch DSP and not an RP */
|
||||
if (parent_port_is_cxl_root(to_cxl_port(port->dev.parent)))
|
||||
return -ENODEV;
|
||||
|
||||
if (!coordinates_valid(dport->coord))
|
||||
return -EINVAL;
|
||||
|
||||
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
|
||||
c[i].read_bandwidth = dport->coord[i].read_bandwidth;
|
||||
c[i].write_bandwidth = dport->coord[i].write_bandwidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for user tooling to ensure port disable work has completed */
|
||||
static ssize_t flush_store(const struct bus_type *bus, const char *buf, size_t count)
|
||||
{
|
||||
|
||||
+45
-36
@@ -1983,6 +1983,7 @@ static int cxl_region_attach(struct cxl_region *cxlr,
|
||||
* then the region is already committed.
|
||||
*/
|
||||
p->state = CXL_CONFIG_COMMIT;
|
||||
cxl_region_shared_upstream_bandwidth_update(cxlr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2004,6 +2005,7 @@ static int cxl_region_attach(struct cxl_region *cxlr,
|
||||
if (rc)
|
||||
return rc;
|
||||
p->state = CXL_CONFIG_ACTIVE;
|
||||
cxl_region_shared_upstream_bandwidth_update(cxlr);
|
||||
}
|
||||
|
||||
cxled->cxld.interleave_ways = p->interleave_ways;
|
||||
@@ -2313,8 +2315,6 @@ static void unregister_region(void *_cxlr)
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
int i;
|
||||
|
||||
unregister_memory_notifier(&cxlr->memory_notifier);
|
||||
unregister_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
device_del(&cxlr->dev);
|
||||
|
||||
/*
|
||||
@@ -2391,18 +2391,6 @@ static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cxl_region_nid(struct cxl_region *cxlr)
|
||||
{
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
struct resource *res;
|
||||
|
||||
guard(rwsem_read)(&cxl_region_rwsem);
|
||||
res = p->res;
|
||||
if (!res)
|
||||
return NUMA_NO_NODE;
|
||||
return phys_to_target_node(res->start);
|
||||
}
|
||||
|
||||
static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
|
||||
unsigned long action, void *arg)
|
||||
{
|
||||
@@ -2415,7 +2403,11 @@ static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
|
||||
if (nid == NUMA_NO_NODE || action != MEM_ONLINE)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
region_nid = cxl_region_nid(cxlr);
|
||||
/*
|
||||
* No need to hold cxl_region_rwsem; region parameters are stable
|
||||
* within the cxl_region driver.
|
||||
*/
|
||||
region_nid = phys_to_target_node(cxlr->params.res->start);
|
||||
if (nid != region_nid)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@@ -2434,7 +2426,11 @@ static int cxl_region_calculate_adistance(struct notifier_block *nb,
|
||||
int *adist = data;
|
||||
int region_nid;
|
||||
|
||||
region_nid = cxl_region_nid(cxlr);
|
||||
/*
|
||||
* No need to hold cxl_region_rwsem; region parameters are stable
|
||||
* within the cxl_region driver.
|
||||
*/
|
||||
region_nid = phys_to_target_node(cxlr->params.res->start);
|
||||
if (nid != region_nid)
|
||||
return NOTIFY_OK;
|
||||
|
||||
@@ -2484,14 +2480,6 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback;
|
||||
cxlr->memory_notifier.priority = CXL_CALLBACK_PRI;
|
||||
register_memory_notifier(&cxlr->memory_notifier);
|
||||
|
||||
cxlr->adist_notifier.notifier_call = cxl_region_calculate_adistance;
|
||||
cxlr->adist_notifier.priority = 100;
|
||||
register_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
|
||||
rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
@@ -3094,11 +3082,11 @@ static void cxlr_release_nvdimm(void *_cxlr)
|
||||
struct cxl_region *cxlr = _cxlr;
|
||||
struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
|
||||
|
||||
device_lock(&cxl_nvb->dev);
|
||||
if (cxlr->cxlr_pmem)
|
||||
devm_release_action(&cxl_nvb->dev, cxlr_pmem_unregister,
|
||||
cxlr->cxlr_pmem);
|
||||
device_unlock(&cxl_nvb->dev);
|
||||
scoped_guard(device, &cxl_nvb->dev) {
|
||||
if (cxlr->cxlr_pmem)
|
||||
devm_release_action(&cxl_nvb->dev, cxlr_pmem_unregister,
|
||||
cxlr->cxlr_pmem);
|
||||
}
|
||||
cxlr->cxl_nvb = NULL;
|
||||
put_device(&cxl_nvb->dev);
|
||||
}
|
||||
@@ -3134,13 +3122,14 @@ static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
|
||||
dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
|
||||
dev_name(dev));
|
||||
|
||||
device_lock(&cxl_nvb->dev);
|
||||
if (cxl_nvb->dev.driver)
|
||||
rc = devm_add_action_or_reset(&cxl_nvb->dev,
|
||||
cxlr_pmem_unregister, cxlr_pmem);
|
||||
else
|
||||
rc = -ENXIO;
|
||||
device_unlock(&cxl_nvb->dev);
|
||||
scoped_guard(device, &cxl_nvb->dev) {
|
||||
if (cxl_nvb->dev.driver)
|
||||
rc = devm_add_action_or_reset(&cxl_nvb->dev,
|
||||
cxlr_pmem_unregister,
|
||||
cxlr_pmem);
|
||||
else
|
||||
rc = -ENXIO;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
goto err_bridge;
|
||||
@@ -3386,6 +3375,14 @@ static int is_system_ram(struct resource *res, void *arg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shutdown_notifiers(void *_cxlr)
|
||||
{
|
||||
struct cxl_region *cxlr = _cxlr;
|
||||
|
||||
unregister_memory_notifier(&cxlr->memory_notifier);
|
||||
unregister_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
}
|
||||
|
||||
static int cxl_region_probe(struct device *dev)
|
||||
{
|
||||
struct cxl_region *cxlr = to_cxl_region(dev);
|
||||
@@ -3418,6 +3415,18 @@ static int cxl_region_probe(struct device *dev)
|
||||
out:
|
||||
up_read(&cxl_region_rwsem);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback;
|
||||
cxlr->memory_notifier.priority = CXL_CALLBACK_PRI;
|
||||
register_memory_notifier(&cxlr->memory_notifier);
|
||||
|
||||
cxlr->adist_notifier.notifier_call = cxl_region_calculate_adistance;
|
||||
cxlr->adist_notifier.priority = 100;
|
||||
register_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
|
||||
rc = devm_add_action_or_reset(&cxlr->dev, shutdown_notifiers, cxlr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
||||
+6
-3
@@ -744,6 +744,7 @@ struct cxl_root *find_cxl_root(struct cxl_port *port);
|
||||
void put_cxl_root(struct cxl_root *cxl_root);
|
||||
DEFINE_FREE(put_cxl_root, struct cxl_root *, if (_T) put_cxl_root(_T))
|
||||
|
||||
DEFINE_FREE(put_cxl_port, struct cxl_port *, if (!IS_ERR_OR_NULL(_T)) put_device(&_T->dev))
|
||||
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
|
||||
void cxl_bus_rescan(void);
|
||||
void cxl_bus_drain(void);
|
||||
@@ -762,9 +763,10 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
|
||||
|
||||
#ifdef CONFIG_PCIEAER_CXL
|
||||
void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
|
||||
void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
|
||||
#else
|
||||
static inline void cxl_setup_parent_dport(struct device *host,
|
||||
struct cxl_dport *dport) { }
|
||||
static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
|
||||
struct device *host) { }
|
||||
#endif
|
||||
|
||||
struct cxl_decoder *to_cxl_decoder(struct device *dev);
|
||||
@@ -809,7 +811,7 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
|
||||
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
|
||||
struct cxl_endpoint_dvsec_info *info);
|
||||
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
|
||||
int cxl_dvsec_rr_decode(struct device *dev, int dvsec,
|
||||
int cxl_dvsec_rr_decode(struct device *dev, struct cxl_port *port,
|
||||
struct cxl_endpoint_dvsec_info *info);
|
||||
|
||||
bool is_cxl_region(struct device *dev);
|
||||
@@ -889,6 +891,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
|
||||
struct access_coordinate *coord);
|
||||
void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled);
|
||||
void cxl_region_shared_upstream_bandwidth_update(struct cxl_region *cxlr);
|
||||
|
||||
void cxl_memdev_update_perf(struct cxl_memdev *cxlmd);
|
||||
|
||||
|
||||
+13
-14
@@ -3,11 +3,12 @@
|
||||
#ifndef __CXL_MEM_H__
|
||||
#define __CXL_MEM_H__
|
||||
#include <uapi/linux/cxl_mem.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/rcuwait.h>
|
||||
#include <linux/cxl-event.h>
|
||||
#include <linux/node.h>
|
||||
#include <cxl/event.h>
|
||||
#include <cxl/mailbox.h>
|
||||
#include "cxl.h"
|
||||
|
||||
/* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
|
||||
@@ -397,11 +398,13 @@ enum cxl_devtype {
|
||||
* struct cxl_dpa_perf - DPA performance property entry
|
||||
* @dpa_range: range for DPA address
|
||||
* @coord: QoS performance data (i.e. latency, bandwidth)
|
||||
* @cdat_coord: raw QoS performance data from CDAT
|
||||
* @qos_class: QoS Class cookies
|
||||
*/
|
||||
struct cxl_dpa_perf {
|
||||
struct range dpa_range;
|
||||
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
|
||||
struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
|
||||
int qos_class;
|
||||
};
|
||||
|
||||
@@ -424,6 +427,7 @@ struct cxl_dpa_perf {
|
||||
* @ram_res: Active Volatile memory capacity configuration
|
||||
* @serial: PCIe Device Serial Number
|
||||
* @type: Generic Memory Class device or Vendor Specific Memory device
|
||||
* @cxl_mbox: CXL mailbox context
|
||||
*/
|
||||
struct cxl_dev_state {
|
||||
struct device *dev;
|
||||
@@ -438,8 +442,14 @@ struct cxl_dev_state {
|
||||
struct resource ram_res;
|
||||
u64 serial;
|
||||
enum cxl_devtype type;
|
||||
struct cxl_mailbox cxl_mbox;
|
||||
};
|
||||
|
||||
static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox)
|
||||
{
|
||||
return dev_get_drvdata(cxl_mbox->host);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct cxl_memdev_state - Generic Type-3 Memory Device Class driver data
|
||||
*
|
||||
@@ -448,11 +458,8 @@ struct cxl_dev_state {
|
||||
* the functionality related to that like Identify Memory Device and Get
|
||||
* Partition Info
|
||||
* @cxlds: Core driver state common across Type-2 and Type-3 devices
|
||||
* @payload_size: Size of space for payload
|
||||
* (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
|
||||
* @lsa_size: Size of Label Storage Area
|
||||
* (CXL 2.0 8.2.9.5.1.1 Identify Memory Device)
|
||||
* @mbox_mutex: Mutex to synchronize mailbox access.
|
||||
* @firmware_version: Firmware version for the memory device.
|
||||
* @enabled_cmds: Hardware commands found enabled in CEL.
|
||||
* @exclusive_cmds: Commands that are kernel-internal only
|
||||
@@ -470,17 +477,13 @@ struct cxl_dev_state {
|
||||
* @poison: poison driver state info
|
||||
* @security: security driver state info
|
||||
* @fw: firmware upload / activation state
|
||||
* @mbox_wait: RCU wait for mbox send completely
|
||||
* @mbox_send: @dev specific transport for transmitting mailbox commands
|
||||
*
|
||||
* See CXL 3.0 8.2.9.8.2 Capacity Configuration and Label Storage for
|
||||
* details on capacity parameters.
|
||||
*/
|
||||
struct cxl_memdev_state {
|
||||
struct cxl_dev_state cxlds;
|
||||
size_t payload_size;
|
||||
size_t lsa_size;
|
||||
struct mutex mbox_mutex; /* Protects device mailbox and firmware */
|
||||
char firmware_version[0x10];
|
||||
DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX);
|
||||
DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
|
||||
@@ -500,10 +503,6 @@ struct cxl_memdev_state {
|
||||
struct cxl_poison_state poison;
|
||||
struct cxl_security_state security;
|
||||
struct cxl_fw_state fw;
|
||||
|
||||
struct rcuwait mbox_wait;
|
||||
int (*mbox_send)(struct cxl_memdev_state *mds,
|
||||
struct cxl_mbox_cmd *cmd);
|
||||
};
|
||||
|
||||
static inline struct cxl_memdev_state *
|
||||
@@ -814,7 +813,7 @@ enum {
|
||||
CXL_PMEM_SEC_PASS_USER,
|
||||
};
|
||||
|
||||
int cxl_internal_send_cmd(struct cxl_memdev_state *mds,
|
||||
int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox,
|
||||
struct cxl_mbox_cmd *cmd);
|
||||
int cxl_dev_state_identify(struct cxl_memdev_state *mds);
|
||||
int cxl_await_media_ready(struct cxl_dev_state *cxlds);
|
||||
|
||||
+13
-16
@@ -109,7 +109,6 @@ static int cxl_mem_probe(struct device *dev)
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
struct device *endpoint_parent;
|
||||
struct cxl_port *parent_port;
|
||||
struct cxl_dport *dport;
|
||||
struct dentry *dentry;
|
||||
int rc;
|
||||
@@ -146,7 +145,8 @@ static int cxl_mem_probe(struct device *dev)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
parent_port = cxl_mem_find_port(cxlmd, &dport);
|
||||
struct cxl_port *parent_port __free(put_cxl_port) =
|
||||
cxl_mem_find_port(cxlmd, &dport);
|
||||
if (!parent_port) {
|
||||
dev_err(dev, "CXL port topology not found\n");
|
||||
return -ENXIO;
|
||||
@@ -166,23 +166,20 @@ static int cxl_mem_probe(struct device *dev)
|
||||
else
|
||||
endpoint_parent = &parent_port->dev;
|
||||
|
||||
cxl_setup_parent_dport(dev, dport);
|
||||
cxl_dport_init_ras_reporting(dport, dev);
|
||||
|
||||
device_lock(endpoint_parent);
|
||||
if (!endpoint_parent->driver) {
|
||||
dev_err(dev, "CXL port topology %s not enabled\n",
|
||||
dev_name(endpoint_parent));
|
||||
rc = -ENXIO;
|
||||
goto unlock;
|
||||
scoped_guard(device, endpoint_parent) {
|
||||
if (!endpoint_parent->driver) {
|
||||
dev_err(dev, "CXL port topology %s not enabled\n",
|
||||
dev_name(endpoint_parent));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rc = devm_cxl_add_endpoint(endpoint_parent, cxlmd, dport);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = devm_cxl_add_endpoint(endpoint_parent, cxlmd, dport);
|
||||
unlock:
|
||||
device_unlock(endpoint_parent);
|
||||
put_device(&parent_port->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* The kernel may be operating out of CXL memory on this device,
|
||||
* there is no spec defined way to determine whether this device
|
||||
|
||||
+58
-33
@@ -11,6 +11,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/aer.h>
|
||||
#include <linux/io.h>
|
||||
#include <cxl/mailbox.h>
|
||||
#include "cxlmem.h"
|
||||
#include "cxlpci.h"
|
||||
#include "cxl.h"
|
||||
@@ -124,6 +125,7 @@ static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
|
||||
u16 opcode;
|
||||
struct cxl_dev_id *dev_id = id;
|
||||
struct cxl_dev_state *cxlds = dev_id->cxlds;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
|
||||
|
||||
if (!cxl_mbox_background_complete(cxlds))
|
||||
@@ -132,13 +134,13 @@ static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
|
||||
reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
|
||||
opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
|
||||
if (opcode == CXL_MBOX_OP_SANITIZE) {
|
||||
mutex_lock(&mds->mbox_mutex);
|
||||
mutex_lock(&cxl_mbox->mbox_mutex);
|
||||
if (mds->security.sanitize_node)
|
||||
mod_delayed_work(system_wq, &mds->security.poll_dwork, 0);
|
||||
mutex_unlock(&mds->mbox_mutex);
|
||||
mutex_unlock(&cxl_mbox->mbox_mutex);
|
||||
} else {
|
||||
/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
|
||||
rcuwait_wake_up(&mds->mbox_wait);
|
||||
rcuwait_wake_up(&cxl_mbox->mbox_wait);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -152,8 +154,9 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
|
||||
struct cxl_memdev_state *mds =
|
||||
container_of(work, typeof(*mds), security.poll_dwork.work);
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;
|
||||
|
||||
mutex_lock(&mds->mbox_mutex);
|
||||
mutex_lock(&cxl_mbox->mbox_mutex);
|
||||
if (cxl_mbox_background_complete(cxlds)) {
|
||||
mds->security.poll_tmo_secs = 0;
|
||||
if (mds->security.sanitize_node)
|
||||
@@ -167,12 +170,12 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
|
||||
mds->security.poll_tmo_secs = min(15 * 60, timeout);
|
||||
schedule_delayed_work(&mds->security.poll_dwork, timeout * HZ);
|
||||
}
|
||||
mutex_unlock(&mds->mbox_mutex);
|
||||
mutex_unlock(&cxl_mbox->mbox_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* __cxl_pci_mbox_send_cmd() - Execute a mailbox command
|
||||
* @mds: The memory device driver data
|
||||
* @cxl_mbox: CXL mailbox context
|
||||
* @mbox_cmd: Command to send to the memory device.
|
||||
*
|
||||
* Context: Any context. Expects mbox_mutex to be held.
|
||||
@@ -192,17 +195,18 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
|
||||
* not need to coordinate with each other. The driver only uses the primary
|
||||
* mailbox.
|
||||
*/
|
||||
static int __cxl_pci_mbox_send_cmd(struct cxl_memdev_state *mds,
|
||||
static int __cxl_pci_mbox_send_cmd(struct cxl_mailbox *cxl_mbox,
|
||||
struct cxl_mbox_cmd *mbox_cmd)
|
||||
{
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct cxl_dev_state *cxlds = mbox_to_cxlds(cxl_mbox);
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
|
||||
void __iomem *payload = cxlds->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET;
|
||||
struct device *dev = cxlds->dev;
|
||||
u64 cmd_reg, status_reg;
|
||||
size_t out_len;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&mds->mbox_mutex);
|
||||
lockdep_assert_held(&cxl_mbox->mbox_mutex);
|
||||
|
||||
/*
|
||||
* Here are the steps from 8.2.8.4 of the CXL 2.0 spec.
|
||||
@@ -315,10 +319,10 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_memdev_state *mds,
|
||||
|
||||
timeout = mbox_cmd->poll_interval_ms;
|
||||
for (i = 0; i < mbox_cmd->poll_count; i++) {
|
||||
if (rcuwait_wait_event_timeout(&mds->mbox_wait,
|
||||
cxl_mbox_background_complete(cxlds),
|
||||
TASK_UNINTERRUPTIBLE,
|
||||
msecs_to_jiffies(timeout)) > 0)
|
||||
if (rcuwait_wait_event_timeout(&cxl_mbox->mbox_wait,
|
||||
cxl_mbox_background_complete(cxlds),
|
||||
TASK_UNINTERRUPTIBLE,
|
||||
msecs_to_jiffies(timeout)) > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -360,7 +364,7 @@ success:
|
||||
*/
|
||||
size_t n;
|
||||
|
||||
n = min3(mbox_cmd->size_out, mds->payload_size, out_len);
|
||||
n = min3(mbox_cmd->size_out, cxl_mbox->payload_size, out_len);
|
||||
memcpy_fromio(mbox_cmd->payload_out, payload, n);
|
||||
mbox_cmd->size_out = n;
|
||||
} else {
|
||||
@@ -370,14 +374,14 @@ success:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_pci_mbox_send(struct cxl_memdev_state *mds,
|
||||
static int cxl_pci_mbox_send(struct cxl_mailbox *cxl_mbox,
|
||||
struct cxl_mbox_cmd *cmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock_io(&mds->mbox_mutex);
|
||||
rc = __cxl_pci_mbox_send_cmd(mds, cmd);
|
||||
mutex_unlock(&mds->mbox_mutex);
|
||||
mutex_lock_io(&cxl_mbox->mbox_mutex);
|
||||
rc = __cxl_pci_mbox_send_cmd(cxl_mbox, cmd);
|
||||
mutex_unlock(&cxl_mbox->mbox_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -385,6 +389,7 @@ static int cxl_pci_mbox_send(struct cxl_memdev_state *mds,
|
||||
static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail)
|
||||
{
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;
|
||||
const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET);
|
||||
struct device *dev = cxlds->dev;
|
||||
unsigned long timeout;
|
||||
@@ -417,8 +422,8 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
mds->mbox_send = cxl_pci_mbox_send;
|
||||
mds->payload_size =
|
||||
cxl_mbox->mbox_send = cxl_pci_mbox_send;
|
||||
cxl_mbox->payload_size =
|
||||
1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap);
|
||||
|
||||
/*
|
||||
@@ -428,16 +433,15 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail)
|
||||
* there's no point in going forward. If the size is too large, there's
|
||||
* no harm is soft limiting it.
|
||||
*/
|
||||
mds->payload_size = min_t(size_t, mds->payload_size, SZ_1M);
|
||||
if (mds->payload_size < 256) {
|
||||
cxl_mbox->payload_size = min_t(size_t, cxl_mbox->payload_size, SZ_1M);
|
||||
if (cxl_mbox->payload_size < 256) {
|
||||
dev_err(dev, "Mailbox is too small (%zub)",
|
||||
mds->payload_size);
|
||||
cxl_mbox->payload_size);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Mailbox payload sized %zu", mds->payload_size);
|
||||
dev_dbg(dev, "Mailbox payload sized %zu", cxl_mbox->payload_size);
|
||||
|
||||
rcuwait_init(&mds->mbox_wait);
|
||||
INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work);
|
||||
|
||||
/* background command interrupts are optional */
|
||||
@@ -473,7 +477,6 @@ static bool is_cxl_restricted(struct pci_dev *pdev)
|
||||
static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev,
|
||||
struct cxl_register_map *map)
|
||||
{
|
||||
struct cxl_port *port;
|
||||
struct cxl_dport *dport;
|
||||
resource_size_t component_reg_phys;
|
||||
|
||||
@@ -482,14 +485,12 @@ static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev,
|
||||
.resource = CXL_RESOURCE_NONE,
|
||||
};
|
||||
|
||||
port = cxl_pci_find_port(pdev, &dport);
|
||||
struct cxl_port *port __free(put_cxl_port) =
|
||||
cxl_pci_find_port(pdev, &dport);
|
||||
if (!port)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
component_reg_phys = cxl_rcd_component_reg_phys(&pdev->dev, dport);
|
||||
|
||||
put_device(&port->dev);
|
||||
|
||||
if (component_reg_phys == CXL_RESOURCE_NONE)
|
||||
return -ENXIO;
|
||||
|
||||
@@ -578,9 +579,10 @@ static void free_event_buf(void *buf)
|
||||
*/
|
||||
static int cxl_mem_alloc_event_buf(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_get_event_payload *buf;
|
||||
|
||||
buf = kvmalloc(mds->payload_size, GFP_KERNEL);
|
||||
buf = kvmalloc(cxl_mbox->payload_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
mds->event.buf = buf;
|
||||
@@ -653,6 +655,7 @@ static int cxl_event_req_irq(struct cxl_dev_state *cxlds, u8 setting)
|
||||
static int cxl_event_get_int_policy(struct cxl_memdev_state *mds,
|
||||
struct cxl_event_interrupt_policy *policy)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd = {
|
||||
.opcode = CXL_MBOX_OP_GET_EVT_INT_POLICY,
|
||||
.payload_out = policy,
|
||||
@@ -660,7 +663,7 @@ static int cxl_event_get_int_policy(struct cxl_memdev_state *mds,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
dev_err(mds->cxlds.dev,
|
||||
"Failed to get event interrupt policy : %d", rc);
|
||||
@@ -671,6 +674,7 @@ static int cxl_event_get_int_policy(struct cxl_memdev_state *mds,
|
||||
static int cxl_event_config_msgnums(struct cxl_memdev_state *mds,
|
||||
struct cxl_event_interrupt_policy *policy)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
|
||||
@@ -687,7 +691,7 @@ static int cxl_event_config_msgnums(struct cxl_memdev_state *mds,
|
||||
.size_in = sizeof(*policy),
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0) {
|
||||
dev_err(mds->cxlds.dev, "Failed to set event interrupt policy : %d",
|
||||
rc);
|
||||
@@ -786,6 +790,23 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_pci_type3_init_mailbox(struct cxl_dev_state *cxlds)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Fail the init if there's no mailbox. For a type3 this is out of spec.
|
||||
*/
|
||||
if (!cxlds->reg_map.device_map.mbox.valid)
|
||||
return -ENODEV;
|
||||
|
||||
rc = cxl_mailbox_init(&cxlds->cxl_mbox, cxlds->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);
|
||||
@@ -846,6 +867,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
if (rc)
|
||||
dev_dbg(&pdev->dev, "Failed to map RAS capability.\n");
|
||||
|
||||
rc = cxl_pci_type3_init_mailbox(cxlds);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = cxl_await_media_ready(cxlds);
|
||||
if (rc == 0)
|
||||
cxlds->media_ready = true;
|
||||
|
||||
+14
-12
@@ -102,13 +102,15 @@ static int cxl_pmem_get_config_size(struct cxl_memdev_state *mds,
|
||||
struct nd_cmd_get_config_size *cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
|
||||
if (sizeof(*cmd) > buf_len)
|
||||
return -EINVAL;
|
||||
|
||||
*cmd = (struct nd_cmd_get_config_size){
|
||||
.config_size = mds->lsa_size,
|
||||
.max_xfer =
|
||||
mds->payload_size - sizeof(struct cxl_mbox_set_lsa),
|
||||
cxl_mbox->payload_size - sizeof(struct cxl_mbox_set_lsa),
|
||||
};
|
||||
|
||||
return 0;
|
||||
@@ -118,6 +120,7 @@ static int cxl_pmem_get_config_data(struct cxl_memdev_state *mds,
|
||||
struct nd_cmd_get_config_data_hdr *cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_get_lsa get_lsa;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -139,7 +142,7 @@ static int cxl_pmem_get_config_data(struct cxl_memdev_state *mds,
|
||||
.payload_out = cmd->out_buf,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
cmd->status = 0;
|
||||
|
||||
return rc;
|
||||
@@ -149,6 +152,7 @@ static int cxl_pmem_set_config_data(struct cxl_memdev_state *mds,
|
||||
struct nd_cmd_set_config_hdr *cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_set_lsa *set_lsa;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -175,7 +179,7 @@ static int cxl_pmem_set_config_data(struct cxl_memdev_state *mds,
|
||||
.size_in = struct_size(set_lsa, data, cmd->in_length),
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
|
||||
/*
|
||||
* Set "firmware" status (4-packed bytes at the end of the input
|
||||
@@ -233,15 +237,13 @@ static int detach_nvdimm(struct device *dev, void *data)
|
||||
if (!is_cxl_nvdimm(dev))
|
||||
return 0;
|
||||
|
||||
device_lock(dev);
|
||||
if (!dev->driver)
|
||||
goto out;
|
||||
|
||||
cxl_nvd = to_cxl_nvdimm(dev);
|
||||
if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
|
||||
release = true;
|
||||
out:
|
||||
device_unlock(dev);
|
||||
scoped_guard(device, dev) {
|
||||
if (dev->driver) {
|
||||
cxl_nvd = to_cxl_nvdimm(dev);
|
||||
if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
|
||||
release = true;
|
||||
}
|
||||
}
|
||||
if (release)
|
||||
device_release_driver(dev);
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
|
||||
struct cxl_port *root;
|
||||
int rc;
|
||||
|
||||
rc = cxl_dvsec_rr_decode(cxlds->dev, cxlds->cxl_dvsec, &info);
|
||||
rc = cxl_dvsec_rr_decode(cxlds->dev, port, &info);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
||||
+12
-11
@@ -14,6 +14,7 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
unsigned long security_flags = 0;
|
||||
struct cxl_get_security_output {
|
||||
@@ -29,7 +30,7 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
|
||||
.payload_out = &out,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
return 0;
|
||||
|
||||
@@ -70,7 +71,7 @@ static int cxl_pmem_security_change_key(struct nvdimm *nvdimm,
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
struct cxl_set_pass set_pass;
|
||||
|
||||
@@ -87,7 +88,7 @@ static int cxl_pmem_security_change_key(struct nvdimm *nvdimm,
|
||||
.payload_in = &set_pass,
|
||||
};
|
||||
|
||||
return cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
}
|
||||
|
||||
static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
|
||||
@@ -96,7 +97,7 @@ static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_disable_pass dis_pass;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
|
||||
@@ -112,7 +113,7 @@ static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
|
||||
.payload_in = &dis_pass,
|
||||
};
|
||||
|
||||
return cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
}
|
||||
|
||||
static int cxl_pmem_security_disable(struct nvdimm *nvdimm,
|
||||
@@ -131,12 +132,12 @@ static int cxl_pmem_security_freeze(struct nvdimm *nvdimm)
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd = {
|
||||
.opcode = CXL_MBOX_OP_FREEZE_SECURITY,
|
||||
};
|
||||
|
||||
return cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
}
|
||||
|
||||
static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
|
||||
@@ -144,7 +145,7 @@ static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
u8 pass[NVDIMM_PASSPHRASE_LEN];
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
int rc;
|
||||
@@ -156,7 +157,7 @@ static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
|
||||
.payload_in = pass,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -169,7 +170,7 @@ static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm,
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
|
||||
struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
struct cxl_pass_erase erase;
|
||||
int rc;
|
||||
@@ -185,7 +186,7 @@ static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm,
|
||||
.payload_in = &erase,
|
||||
};
|
||||
|
||||
rc = cxl_internal_send_cmd(mds, &mbox_cmd);
|
||||
rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
||||
@@ -529,9 +529,6 @@ static struct dm_buffer *list_to_buffer(struct list_head *l)
|
||||
{
|
||||
struct lru_entry *le = list_entry(l, struct lru_entry, list);
|
||||
|
||||
if (!le)
|
||||
return NULL;
|
||||
|
||||
return le_to_buffer(le);
|
||||
}
|
||||
|
||||
|
||||
@@ -1368,7 +1368,7 @@ static void mg_copy(struct work_struct *ws)
|
||||
*/
|
||||
bool rb = bio_detain_shared(mg->cache, mg->op->oblock, mg->overwrite_bio);
|
||||
|
||||
BUG_ON(rb); /* An exclussive lock must _not_ be held for this block */
|
||||
BUG_ON(rb); /* An exclusive lock must _not_ be held for this block */
|
||||
mg->overwrite_bio = NULL;
|
||||
inc_io_migrations(mg->cache);
|
||||
mg_full_copy(ws);
|
||||
@@ -3200,8 +3200,6 @@ static int parse_cblock_range(struct cache *cache, const char *str,
|
||||
* Try and parse form (ii) first.
|
||||
*/
|
||||
r = sscanf(str, "%llu-%llu%c", &b, &e, &dummy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 2) {
|
||||
result->begin = to_cblock(b);
|
||||
@@ -3213,8 +3211,6 @@ static int parse_cblock_range(struct cache *cache, const char *str,
|
||||
* That didn't work, try form (i).
|
||||
*/
|
||||
r = sscanf(str, "%llu%c", &b, &dummy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 1) {
|
||||
result->begin = to_cblock(b);
|
||||
|
||||
@@ -530,10 +530,7 @@ static int __load_bitset_in_core(struct dm_clone_metadata *cmd)
|
||||
return r;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
if (dm_bitset_cursor_get_value(&c))
|
||||
__set_bit(i, cmd->region_map);
|
||||
else
|
||||
__clear_bit(i, cmd->region_map);
|
||||
__assign_bit(i, cmd->region_map, dm_bitset_cursor_get_value(&c));
|
||||
|
||||
if (i >= (cmd->nr_regions - 1))
|
||||
break;
|
||||
|
||||
+27
-20
@@ -147,6 +147,7 @@ enum cipher_flags {
|
||||
CRYPT_MODE_INTEGRITY_AEAD, /* Use authenticated mode for cipher */
|
||||
CRYPT_IV_LARGE_SECTORS, /* Calculate IV from sector_size, not 512B sectors */
|
||||
CRYPT_ENCRYPT_PREPROCESS, /* Must preprocess data for encryption (elephant) */
|
||||
CRYPT_KEY_MAC_SIZE_SET, /* The integrity_key_size option was used */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2613,35 +2614,31 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string
|
||||
|
||||
key = request_key(type, key_desc + 1, NULL);
|
||||
if (IS_ERR(key)) {
|
||||
kfree_sensitive(new_key_string);
|
||||
return PTR_ERR(key);
|
||||
ret = PTR_ERR(key);
|
||||
goto free_new_key_string;
|
||||
}
|
||||
|
||||
down_read(&key->sem);
|
||||
|
||||
ret = set_key(cc, key);
|
||||
if (ret < 0) {
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
kfree_sensitive(new_key_string);
|
||||
return ret;
|
||||
}
|
||||
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
if (ret < 0)
|
||||
goto free_new_key_string;
|
||||
|
||||
/* clear the flag since following operations may invalidate previously valid key */
|
||||
clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
|
||||
|
||||
ret = crypt_setkey(cc);
|
||||
if (ret)
|
||||
goto free_new_key_string;
|
||||
|
||||
if (!ret) {
|
||||
set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
|
||||
kfree_sensitive(cc->key_string);
|
||||
cc->key_string = new_key_string;
|
||||
} else
|
||||
kfree_sensitive(new_key_string);
|
||||
set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
|
||||
kfree_sensitive(cc->key_string);
|
||||
cc->key_string = new_key_string;
|
||||
return 0;
|
||||
|
||||
free_new_key_string:
|
||||
kfree_sensitive(new_key_string);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2937,7 +2934,8 @@ static int crypt_ctr_auth_cipher(struct crypt_config *cc, char *cipher_api)
|
||||
if (IS_ERR(mac))
|
||||
return PTR_ERR(mac);
|
||||
|
||||
cc->key_mac_size = crypto_ahash_digestsize(mac);
|
||||
if (!test_bit(CRYPT_KEY_MAC_SIZE_SET, &cc->cipher_flags))
|
||||
cc->key_mac_size = crypto_ahash_digestsize(mac);
|
||||
crypto_free_ahash(mac);
|
||||
|
||||
cc->authenc_key = kmalloc(crypt_authenckey_size(cc), GFP_KERNEL);
|
||||
@@ -3219,6 +3217,13 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar
|
||||
cc->cipher_auth = kstrdup(sval, GFP_KERNEL);
|
||||
if (!cc->cipher_auth)
|
||||
return -ENOMEM;
|
||||
} else if (sscanf(opt_string, "integrity_key_size:%u%c", &val, &dummy) == 1) {
|
||||
if (!val) {
|
||||
ti->error = "Invalid integrity_key_size argument";
|
||||
return -EINVAL;
|
||||
}
|
||||
cc->key_mac_size = val;
|
||||
set_bit(CRYPT_KEY_MAC_SIZE_SET, &cc->cipher_flags);
|
||||
} else if (sscanf(opt_string, "sector_size:%hu%c", &cc->sector_size, &dummy) == 1) {
|
||||
if (cc->sector_size < (1 << SECTOR_SHIFT) ||
|
||||
cc->sector_size > 4096 ||
|
||||
@@ -3607,10 +3612,10 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
|
||||
num_feature_args += test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
|
||||
num_feature_args += test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags);
|
||||
num_feature_args += test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags);
|
||||
num_feature_args += !!cc->used_tag_size;
|
||||
num_feature_args += cc->sector_size != (1 << SECTOR_SHIFT);
|
||||
num_feature_args += test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags);
|
||||
if (cc->used_tag_size)
|
||||
num_feature_args++;
|
||||
num_feature_args += test_bit(CRYPT_KEY_MAC_SIZE_SET, &cc->cipher_flags);
|
||||
if (num_feature_args) {
|
||||
DMEMIT(" %d", num_feature_args);
|
||||
if (ti->num_discard_bios)
|
||||
@@ -3631,6 +3636,8 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
|
||||
DMEMIT(" sector_size:%d", cc->sector_size);
|
||||
if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
|
||||
DMEMIT(" iv_large_sectors");
|
||||
if (test_bit(CRYPT_KEY_MAC_SIZE_SET, &cc->cipher_flags))
|
||||
DMEMIT(" integrity_key_size:%u", cc->key_mac_size);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3758,7 +3765,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
|
||||
|
||||
static struct target_type crypt_target = {
|
||||
.name = "crypt",
|
||||
.version = {1, 27, 0},
|
||||
.version = {1, 28, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = crypt_ctr,
|
||||
.dtr = crypt_dtr,
|
||||
|
||||
+268
-58
@@ -284,6 +284,7 @@ struct dm_integrity_c {
|
||||
|
||||
mempool_t recheck_pool;
|
||||
struct bio_set recheck_bios;
|
||||
struct bio_set recalc_bios;
|
||||
|
||||
struct notifier_block reboot_notifier;
|
||||
};
|
||||
@@ -321,7 +322,9 @@ struct dm_integrity_io {
|
||||
struct dm_bio_details bio_details;
|
||||
|
||||
char *integrity_payload;
|
||||
unsigned payload_len;
|
||||
bool integrity_payload_from_mempool;
|
||||
bool integrity_range_locked;
|
||||
};
|
||||
|
||||
struct journal_completion {
|
||||
@@ -359,7 +362,7 @@ static struct kmem_cache *journal_io_cache;
|
||||
#endif
|
||||
|
||||
static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map);
|
||||
static int dm_integrity_map_inline(struct dm_integrity_io *dio);
|
||||
static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map);
|
||||
static void integrity_bio_wait(struct work_struct *w);
|
||||
static void dm_integrity_dtr(struct dm_target *ti);
|
||||
|
||||
@@ -491,7 +494,8 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
|
||||
__u8 *sb = (__u8 *)ic->sb;
|
||||
__u8 *mac = sb + (1 << SECTOR_SHIFT) - mac_size;
|
||||
|
||||
if (sizeof(struct superblock) + mac_size > 1 << SECTOR_SHIFT) {
|
||||
if (sizeof(struct superblock) + mac_size > 1 << SECTOR_SHIFT ||
|
||||
mac_size > HASH_MAX_DIGESTSIZE) {
|
||||
dm_integrity_io_error(ic, "digest is too long", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1500,15 +1504,15 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat
|
||||
if (!ic->meta_dev)
|
||||
flush_data = false;
|
||||
if (flush_data) {
|
||||
fr.io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC,
|
||||
fr.io_req.mem.type = DM_IO_KMEM,
|
||||
fr.io_req.mem.ptr.addr = NULL,
|
||||
fr.io_req.notify.fn = flush_notify,
|
||||
fr.io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC;
|
||||
fr.io_req.mem.type = DM_IO_KMEM;
|
||||
fr.io_req.mem.ptr.addr = NULL;
|
||||
fr.io_req.notify.fn = flush_notify;
|
||||
fr.io_req.notify.context = &fr;
|
||||
fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio),
|
||||
fr.io_reg.bdev = ic->dev->bdev,
|
||||
fr.io_reg.sector = 0,
|
||||
fr.io_reg.count = 0,
|
||||
fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio);
|
||||
fr.io_reg.bdev = ic->dev->bdev;
|
||||
fr.io_reg.sector = 0;
|
||||
fr.io_reg.count = 0;
|
||||
fr.ic = ic;
|
||||
init_completion(&fr.comp);
|
||||
r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL, IOPRIO_DEFAULT);
|
||||
@@ -1946,8 +1950,13 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
|
||||
dio->bi_status = 0;
|
||||
dio->op = bio_op(bio);
|
||||
|
||||
if (ic->mode == 'I')
|
||||
return dm_integrity_map_inline(dio);
|
||||
if (ic->mode == 'I') {
|
||||
bio->bi_iter.bi_sector = dm_target_offset(ic->ti, bio->bi_iter.bi_sector);
|
||||
dio->integrity_payload = NULL;
|
||||
dio->integrity_payload_from_mempool = false;
|
||||
dio->integrity_range_locked = false;
|
||||
return dm_integrity_map_inline(dio, true);
|
||||
}
|
||||
|
||||
if (unlikely(dio->op == REQ_OP_DISCARD)) {
|
||||
if (ti->max_io_len) {
|
||||
@@ -2397,15 +2406,13 @@ journal_read_write:
|
||||
do_endio_flush(ic, dio);
|
||||
}
|
||||
|
||||
static int dm_integrity_map_inline(struct dm_integrity_io *dio)
|
||||
static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map)
|
||||
{
|
||||
struct dm_integrity_c *ic = dio->ic;
|
||||
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
|
||||
struct bio_integrity_payload *bip;
|
||||
unsigned payload_len, digest_size, extra_size, ret;
|
||||
|
||||
dio->integrity_payload = NULL;
|
||||
dio->integrity_payload_from_mempool = false;
|
||||
unsigned ret;
|
||||
sector_t recalc_sector;
|
||||
|
||||
if (unlikely(bio_integrity(bio))) {
|
||||
bio->bi_status = BLK_STS_NOTSUPP;
|
||||
@@ -2418,28 +2425,67 @@ static int dm_integrity_map_inline(struct dm_integrity_io *dio)
|
||||
return DM_MAPIO_REMAPPED;
|
||||
|
||||
retry:
|
||||
payload_len = ic->tuple_size * (bio_sectors(bio) >> ic->sb->log2_sectors_per_block);
|
||||
digest_size = crypto_shash_digestsize(ic->internal_hash);
|
||||
extra_size = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
|
||||
payload_len += extra_size;
|
||||
dio->integrity_payload = kmalloc(payload_len, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
|
||||
if (unlikely(!dio->integrity_payload)) {
|
||||
const unsigned x_size = PAGE_SIZE << 1;
|
||||
if (payload_len > x_size) {
|
||||
unsigned sectors = ((x_size - extra_size) / ic->tuple_size) << ic->sb->log2_sectors_per_block;
|
||||
if (WARN_ON(!sectors || sectors >= bio_sectors(bio))) {
|
||||
bio->bi_status = BLK_STS_NOTSUPP;
|
||||
bio_endio(bio);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
if (!dio->integrity_payload) {
|
||||
unsigned digest_size, extra_size;
|
||||
dio->payload_len = ic->tuple_size * (bio_sectors(bio) >> ic->sb->log2_sectors_per_block);
|
||||
digest_size = crypto_shash_digestsize(ic->internal_hash);
|
||||
extra_size = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
|
||||
dio->payload_len += extra_size;
|
||||
dio->integrity_payload = kmalloc(dio->payload_len, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
|
||||
if (unlikely(!dio->integrity_payload)) {
|
||||
const unsigned x_size = PAGE_SIZE << 1;
|
||||
if (dio->payload_len > x_size) {
|
||||
unsigned sectors = ((x_size - extra_size) / ic->tuple_size) << ic->sb->log2_sectors_per_block;
|
||||
if (WARN_ON(!sectors || sectors >= bio_sectors(bio))) {
|
||||
bio->bi_status = BLK_STS_NOTSUPP;
|
||||
bio_endio(bio);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
dm_accept_partial_bio(bio, sectors);
|
||||
goto retry;
|
||||
}
|
||||
dm_accept_partial_bio(bio, sectors);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
dio->range.logical_sector = bio->bi_iter.bi_sector;
|
||||
dio->range.n_sectors = bio_sectors(bio);
|
||||
|
||||
if (!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)))
|
||||
goto skip_spinlock;
|
||||
#ifdef CONFIG_64BIT
|
||||
/*
|
||||
* On 64-bit CPUs we can optimize the lock away (so that it won't cause
|
||||
* cache line bouncing) and use acquire/release barriers instead.
|
||||
*
|
||||
* Paired with smp_store_release in integrity_recalc_inline.
|
||||
*/
|
||||
recalc_sector = le64_to_cpu(smp_load_acquire(&ic->sb->recalc_sector));
|
||||
if (likely(dio->range.logical_sector + dio->range.n_sectors <= recalc_sector))
|
||||
goto skip_spinlock;
|
||||
#endif
|
||||
spin_lock_irq(&ic->endio_wait.lock);
|
||||
recalc_sector = le64_to_cpu(ic->sb->recalc_sector);
|
||||
if (dio->range.logical_sector + dio->range.n_sectors <= recalc_sector)
|
||||
goto skip_unlock;
|
||||
if (unlikely(!add_new_range(ic, &dio->range, true))) {
|
||||
if (from_map) {
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
INIT_WORK(&dio->work, integrity_bio_wait);
|
||||
queue_work(ic->wait_wq, &dio->work);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
wait_and_add_new_range(ic, &dio->range);
|
||||
}
|
||||
dio->integrity_range_locked = true;
|
||||
skip_unlock:
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
skip_spinlock:
|
||||
|
||||
if (unlikely(!dio->integrity_payload)) {
|
||||
dio->integrity_payload = page_to_virt((struct page *)mempool_alloc(&ic->recheck_pool, GFP_NOIO));
|
||||
dio->integrity_payload_from_mempool = true;
|
||||
}
|
||||
|
||||
bio->bi_iter.bi_sector = dm_target_offset(ic->ti, bio->bi_iter.bi_sector);
|
||||
dio->bio_details.bi_iter = bio->bi_iter;
|
||||
|
||||
if (unlikely(!dm_integrity_check_limits(ic, bio->bi_iter.bi_sector, bio))) {
|
||||
@@ -2449,7 +2495,7 @@ retry:
|
||||
bio->bi_iter.bi_sector += ic->start + SB_SECTORS;
|
||||
|
||||
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
|
||||
if (unlikely(IS_ERR(bip))) {
|
||||
if (IS_ERR(bip)) {
|
||||
bio->bi_status = errno_to_blk_status(PTR_ERR(bip));
|
||||
bio_endio(bio);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
@@ -2470,8 +2516,8 @@ retry:
|
||||
}
|
||||
|
||||
ret = bio_integrity_add_page(bio, virt_to_page(dio->integrity_payload),
|
||||
payload_len, offset_in_page(dio->integrity_payload));
|
||||
if (unlikely(ret != payload_len)) {
|
||||
dio->payload_len, offset_in_page(dio->integrity_payload));
|
||||
if (unlikely(ret != dio->payload_len)) {
|
||||
bio->bi_status = BLK_STS_RESOURCE;
|
||||
bio_endio(bio);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
@@ -2522,7 +2568,7 @@ static void dm_integrity_inline_recheck(struct work_struct *w)
|
||||
}
|
||||
|
||||
bip = bio_integrity_alloc(outgoing_bio, GFP_NOIO, 1);
|
||||
if (unlikely(IS_ERR(bip))) {
|
||||
if (IS_ERR(bip)) {
|
||||
bio_put(outgoing_bio);
|
||||
bio->bi_status = errno_to_blk_status(PTR_ERR(bip));
|
||||
bio_endio(bio);
|
||||
@@ -2579,6 +2625,9 @@ static int dm_integrity_end_io(struct dm_target *ti, struct bio *bio, blk_status
|
||||
struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
|
||||
if (dio->op == REQ_OP_READ && likely(*status == BLK_STS_OK)) {
|
||||
unsigned pos = 0;
|
||||
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
|
||||
unlikely(dio->integrity_range_locked))
|
||||
goto skip_check;
|
||||
while (dio->bio_details.bi_iter.bi_size) {
|
||||
char digest[HASH_MAX_DIGESTSIZE];
|
||||
struct bio_vec bv = bio_iter_iovec(bio, dio->bio_details.bi_iter);
|
||||
@@ -2598,9 +2647,10 @@ static int dm_integrity_end_io(struct dm_target *ti, struct bio *bio, blk_status
|
||||
bio_advance_iter_single(bio, &dio->bio_details.bi_iter, ic->sectors_per_block << SECTOR_SHIFT);
|
||||
}
|
||||
}
|
||||
if (likely(dio->op == REQ_OP_READ) || likely(dio->op == REQ_OP_WRITE)) {
|
||||
dm_integrity_free_payload(dio);
|
||||
}
|
||||
skip_check:
|
||||
dm_integrity_free_payload(dio);
|
||||
if (unlikely(dio->integrity_range_locked))
|
||||
remove_range(ic, &dio->range);
|
||||
}
|
||||
return DM_ENDIO_DONE;
|
||||
}
|
||||
@@ -2608,8 +2658,26 @@ static int dm_integrity_end_io(struct dm_target *ti, struct bio *bio, blk_status
|
||||
static void integrity_bio_wait(struct work_struct *w)
|
||||
{
|
||||
struct dm_integrity_io *dio = container_of(w, struct dm_integrity_io, work);
|
||||
struct dm_integrity_c *ic = dio->ic;
|
||||
|
||||
dm_integrity_map_continue(dio, false);
|
||||
if (ic->mode == 'I') {
|
||||
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
|
||||
int r = dm_integrity_map_inline(dio, false);
|
||||
switch (r) {
|
||||
case DM_MAPIO_KILL:
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
fallthrough;
|
||||
case DM_MAPIO_REMAPPED:
|
||||
submit_bio_noacct(bio);
|
||||
fallthrough;
|
||||
case DM_MAPIO_SUBMITTED:
|
||||
return;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
} else {
|
||||
dm_integrity_map_continue(dio, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void pad_uncommitted(struct dm_integrity_c *ic)
|
||||
@@ -3081,6 +3149,133 @@ free_ret:
|
||||
kvfree(recalc_tags);
|
||||
}
|
||||
|
||||
static void integrity_recalc_inline(struct work_struct *w)
|
||||
{
|
||||
struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, recalc_work);
|
||||
size_t recalc_tags_size;
|
||||
u8 *recalc_buffer = NULL;
|
||||
u8 *recalc_tags = NULL;
|
||||
struct dm_integrity_range range;
|
||||
struct bio *bio;
|
||||
struct bio_integrity_payload *bip;
|
||||
__u8 *t;
|
||||
unsigned int i;
|
||||
int r;
|
||||
unsigned ret;
|
||||
unsigned int super_counter = 0;
|
||||
unsigned recalc_sectors = RECALC_SECTORS;
|
||||
|
||||
retry:
|
||||
recalc_buffer = kmalloc(recalc_sectors << SECTOR_SHIFT, GFP_NOIO | __GFP_NOWARN);
|
||||
if (!recalc_buffer) {
|
||||
oom:
|
||||
recalc_sectors >>= 1;
|
||||
if (recalc_sectors >= 1U << ic->sb->log2_sectors_per_block)
|
||||
goto retry;
|
||||
DMCRIT("out of memory for recalculate buffer - recalculation disabled");
|
||||
goto free_ret;
|
||||
}
|
||||
|
||||
recalc_tags_size = (recalc_sectors >> ic->sb->log2_sectors_per_block) * ic->tuple_size;
|
||||
if (crypto_shash_digestsize(ic->internal_hash) > ic->tuple_size)
|
||||
recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tuple_size;
|
||||
recalc_tags = kmalloc(recalc_tags_size, GFP_NOIO | __GFP_NOWARN);
|
||||
if (!recalc_tags) {
|
||||
kfree(recalc_buffer);
|
||||
recalc_buffer = NULL;
|
||||
goto oom;
|
||||
}
|
||||
|
||||
spin_lock_irq(&ic->endio_wait.lock);
|
||||
|
||||
next_chunk:
|
||||
if (unlikely(dm_post_suspending(ic->ti)))
|
||||
goto unlock_ret;
|
||||
|
||||
range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
|
||||
if (unlikely(range.logical_sector >= ic->provided_data_sectors))
|
||||
goto unlock_ret;
|
||||
range.n_sectors = min((sector_t)recalc_sectors, ic->provided_data_sectors - range.logical_sector);
|
||||
|
||||
add_new_range_and_wait(ic, &range);
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
|
||||
if (unlikely(++super_counter == RECALC_WRITE_SUPER)) {
|
||||
recalc_write_super(ic);
|
||||
super_counter = 0;
|
||||
}
|
||||
|
||||
if (unlikely(dm_integrity_failed(ic)))
|
||||
goto err;
|
||||
|
||||
DEBUG_print("recalculating: %llx - %llx\n", range.logical_sector, range.n_sectors);
|
||||
|
||||
bio = bio_alloc_bioset(ic->dev->bdev, 1, REQ_OP_READ, GFP_NOIO, &ic->recalc_bios);
|
||||
bio->bi_iter.bi_sector = ic->start + SB_SECTORS + range.logical_sector;
|
||||
__bio_add_page(bio, virt_to_page(recalc_buffer), range.n_sectors << SECTOR_SHIFT, offset_in_page(recalc_buffer));
|
||||
r = submit_bio_wait(bio);
|
||||
bio_put(bio);
|
||||
if (unlikely(r)) {
|
||||
dm_integrity_io_error(ic, "reading data", r);
|
||||
goto err;
|
||||
}
|
||||
|
||||
t = recalc_tags;
|
||||
for (i = 0; i < range.n_sectors; i += ic->sectors_per_block) {
|
||||
memset(t, 0, ic->tuple_size);
|
||||
integrity_sector_checksum(ic, range.logical_sector + i, recalc_buffer + (i << SECTOR_SHIFT), t);
|
||||
t += ic->tuple_size;
|
||||
}
|
||||
|
||||
bio = bio_alloc_bioset(ic->dev->bdev, 1, REQ_OP_WRITE, GFP_NOIO, &ic->recalc_bios);
|
||||
bio->bi_iter.bi_sector = ic->start + SB_SECTORS + range.logical_sector;
|
||||
__bio_add_page(bio, virt_to_page(recalc_buffer), range.n_sectors << SECTOR_SHIFT, offset_in_page(recalc_buffer));
|
||||
|
||||
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
|
||||
if (unlikely(IS_ERR(bip))) {
|
||||
bio_put(bio);
|
||||
DMCRIT("out of memory for bio integrity payload - recalculation disabled");
|
||||
goto err;
|
||||
}
|
||||
ret = bio_integrity_add_page(bio, virt_to_page(recalc_tags), t - recalc_tags, offset_in_page(recalc_tags));
|
||||
if (unlikely(ret != t - recalc_tags)) {
|
||||
bio_put(bio);
|
||||
dm_integrity_io_error(ic, "attaching integrity tags", -ENOMEM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = submit_bio_wait(bio);
|
||||
bio_put(bio);
|
||||
if (unlikely(r)) {
|
||||
dm_integrity_io_error(ic, "writing data", r);
|
||||
goto err;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
spin_lock_irq(&ic->endio_wait.lock);
|
||||
remove_range_unlocked(ic, &range);
|
||||
#ifdef CONFIG_64BIT
|
||||
/* Paired with smp_load_acquire in dm_integrity_map_inline. */
|
||||
smp_store_release(&ic->sb->recalc_sector, cpu_to_le64(range.logical_sector + range.n_sectors));
|
||||
#else
|
||||
ic->sb->recalc_sector = cpu_to_le64(range.logical_sector + range.n_sectors);
|
||||
#endif
|
||||
goto next_chunk;
|
||||
|
||||
err:
|
||||
remove_range(ic, &range);
|
||||
goto free_ret;
|
||||
|
||||
unlock_ret:
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
|
||||
recalc_write_super(ic);
|
||||
|
||||
free_ret:
|
||||
kfree(recalc_buffer);
|
||||
kfree(recalc_tags);
|
||||
}
|
||||
|
||||
static void bitmap_block_work(struct work_struct *w)
|
||||
{
|
||||
struct bitmap_block_status *bbs = container_of(w, struct bitmap_block_status, work);
|
||||
@@ -4619,6 +4814,17 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
|
||||
r = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
r = bioset_init(&ic->recalc_bios, 1, 0, BIOSET_NEED_BVECS);
|
||||
if (r) {
|
||||
ti->error = "Cannot allocate bio set";
|
||||
goto bad;
|
||||
}
|
||||
r = bioset_integrity_create(&ic->recalc_bios, 1);
|
||||
if (r) {
|
||||
ti->error = "Cannot allocate bio integrity set";
|
||||
r = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
ic->metadata_wq = alloc_workqueue("dm-integrity-metadata",
|
||||
@@ -4717,13 +4923,18 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
|
||||
ti->error = "Block size doesn't match the information in superblock";
|
||||
goto bad;
|
||||
}
|
||||
if (!le32_to_cpu(ic->sb->journal_sections) != (ic->mode == 'I')) {
|
||||
r = -EINVAL;
|
||||
if (ic->mode != 'I')
|
||||
if (ic->mode != 'I') {
|
||||
if (!le32_to_cpu(ic->sb->journal_sections)) {
|
||||
r = -EINVAL;
|
||||
ti->error = "Corrupted superblock, journal_sections is 0";
|
||||
else
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (le32_to_cpu(ic->sb->journal_sections)) {
|
||||
r = -EINVAL;
|
||||
ti->error = "Corrupted superblock, journal_sections is not 0";
|
||||
goto bad;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
/* make sure that ti->max_io_len doesn't overflow */
|
||||
if (!ic->meta_dev) {
|
||||
@@ -4830,7 +5041,7 @@ try_smaller_buffer:
|
||||
r = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
INIT_WORK(&ic->recalc_work, integrity_recalc);
|
||||
INIT_WORK(&ic->recalc_work, ic->mode == 'I' ? integrity_recalc_inline : integrity_recalc);
|
||||
} else {
|
||||
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
|
||||
ti->error = "Recalculate can only be specified with internal_hash";
|
||||
@@ -4847,17 +5058,15 @@ try_smaller_buffer:
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (ic->mode != 'I') {
|
||||
ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev,
|
||||
1U << (SECTOR_SHIFT + ic->log2_buffer_sectors), 1, 0, NULL, NULL, 0);
|
||||
if (IS_ERR(ic->bufio)) {
|
||||
r = PTR_ERR(ic->bufio);
|
||||
ti->error = "Cannot initialize dm-bufio";
|
||||
ic->bufio = NULL;
|
||||
goto bad;
|
||||
}
|
||||
dm_bufio_set_sector_offset(ic->bufio, ic->start + ic->initial_sectors);
|
||||
ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev,
|
||||
1U << (SECTOR_SHIFT + ic->log2_buffer_sectors), 1, 0, NULL, NULL, 0);
|
||||
if (IS_ERR(ic->bufio)) {
|
||||
r = PTR_ERR(ic->bufio);
|
||||
ti->error = "Cannot initialize dm-bufio";
|
||||
ic->bufio = NULL;
|
||||
goto bad;
|
||||
}
|
||||
dm_bufio_set_sector_offset(ic->bufio, ic->start + ic->initial_sectors);
|
||||
|
||||
if (ic->mode != 'R' && ic->mode != 'I') {
|
||||
r = create_journal(ic, &ti->error);
|
||||
@@ -4979,6 +5188,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
|
||||
kvfree(ic->bbs);
|
||||
if (ic->bufio)
|
||||
dm_bufio_client_destroy(ic->bufio);
|
||||
bioset_exit(&ic->recalc_bios);
|
||||
bioset_exit(&ic->recheck_bios);
|
||||
mempool_exit(&ic->recheck_pool);
|
||||
mempool_exit(&ic->journal_io_mempool);
|
||||
@@ -5033,7 +5243,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
|
||||
|
||||
static struct target_type integrity_target = {
|
||||
.name = "integrity",
|
||||
.version = {1, 12, 0},
|
||||
.version = {1, 13, 0},
|
||||
.module = THIS_MODULE,
|
||||
.features = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
|
||||
.ctr = dm_integrity_ctr,
|
||||
|
||||
@@ -2519,7 +2519,7 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
|
||||
rdev->saved_raid_disk = rdev->raid_disk;
|
||||
}
|
||||
|
||||
/* Reshape support -> restore repective data offsets */
|
||||
/* Reshape support -> restore respective data offsets */
|
||||
rdev->data_offset = le64_to_cpu(sb->data_offset);
|
||||
rdev->new_data_offset = le64_to_cpu(sb->new_data_offset);
|
||||
|
||||
|
||||
+3
-1
@@ -496,8 +496,10 @@ static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
|
||||
map = dm_get_live_table(md, &srcu_idx);
|
||||
if (unlikely(!map)) {
|
||||
DMERR_LIMIT("%s: mapping table unavailable, erroring io",
|
||||
dm_device_name(md));
|
||||
dm_put_live_table(md, srcu_idx);
|
||||
return BLK_STS_RESOURCE;
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
ti = dm_table_find_target(map, 0);
|
||||
dm_put_live_table(md, srcu_idx);
|
||||
|
||||
@@ -2948,7 +2948,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
|
||||
pmd = dm_pool_metadata_open(metadata_dev, block_size, format_device);
|
||||
if (IS_ERR(pmd)) {
|
||||
*error = "Error creating metadata object";
|
||||
return (struct pool *)pmd;
|
||||
return ERR_CAST(pmd);
|
||||
}
|
||||
|
||||
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
|
||||
|
||||
@@ -501,6 +501,7 @@ static void launch_data_vio(struct data_vio *data_vio, logical_block_number_t lb
|
||||
|
||||
memset(&data_vio->record_name, 0, sizeof(data_vio->record_name));
|
||||
memset(&data_vio->duplicate, 0, sizeof(data_vio->duplicate));
|
||||
vdo_reset_completion(&data_vio->decrement_completion);
|
||||
vdo_reset_completion(completion);
|
||||
completion->error_handler = handle_data_vio_error;
|
||||
set_data_vio_logical_callback(data_vio, attempt_logical_block_lock);
|
||||
@@ -1273,12 +1274,14 @@ static void clean_hash_lock(struct vdo_completion *completion)
|
||||
static void finish_cleanup(struct data_vio *data_vio)
|
||||
{
|
||||
struct vdo_completion *completion = &data_vio->vio.completion;
|
||||
u32 discard_size = min_t(u32, data_vio->remaining_discard,
|
||||
VDO_BLOCK_SIZE - data_vio->offset);
|
||||
|
||||
VDO_ASSERT_LOG_ONLY(data_vio->allocation.lock == NULL,
|
||||
"complete data_vio has no allocation lock");
|
||||
VDO_ASSERT_LOG_ONLY(data_vio->hash_lock == NULL,
|
||||
"complete data_vio has no hash lock");
|
||||
if ((data_vio->remaining_discard <= VDO_BLOCK_SIZE) ||
|
||||
if ((data_vio->remaining_discard <= discard_size) ||
|
||||
(completion->result != VDO_SUCCESS)) {
|
||||
struct data_vio_pool *pool = completion->vdo->data_vio_pool;
|
||||
|
||||
@@ -1287,12 +1290,12 @@ static void finish_cleanup(struct data_vio *data_vio)
|
||||
return;
|
||||
}
|
||||
|
||||
data_vio->remaining_discard -= min_t(u32, data_vio->remaining_discard,
|
||||
VDO_BLOCK_SIZE - data_vio->offset);
|
||||
data_vio->remaining_discard -= discard_size;
|
||||
data_vio->is_partial = (data_vio->remaining_discard < VDO_BLOCK_SIZE);
|
||||
data_vio->read = data_vio->is_partial;
|
||||
data_vio->offset = 0;
|
||||
completion->requeue = true;
|
||||
data_vio->first_reference_operation_complete = false;
|
||||
launch_data_vio(data_vio, data_vio->logical.lbn + 1);
|
||||
}
|
||||
|
||||
@@ -1965,7 +1968,8 @@ static void allocate_block(struct vdo_completion *completion)
|
||||
.state = VDO_MAPPING_STATE_UNCOMPRESSED,
|
||||
};
|
||||
|
||||
if (data_vio->fua) {
|
||||
if (data_vio->fua ||
|
||||
data_vio->remaining_discard > (u32) (VDO_BLOCK_SIZE - data_vio->offset)) {
|
||||
prepare_for_dedupe(data_vio);
|
||||
return;
|
||||
}
|
||||
@@ -2042,7 +2046,6 @@ void continue_data_vio_with_block_map_slot(struct vdo_completion *completion)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We don't need to write any data, so skip allocation and just update the block map and
|
||||
* reference counts (via the journal).
|
||||
@@ -2051,7 +2054,7 @@ void continue_data_vio_with_block_map_slot(struct vdo_completion *completion)
|
||||
if (data_vio->is_zero)
|
||||
data_vio->new_mapped.state = VDO_MAPPING_STATE_UNCOMPRESSED;
|
||||
|
||||
if (data_vio->remaining_discard > VDO_BLOCK_SIZE) {
|
||||
if (data_vio->remaining_discard > (u32) (VDO_BLOCK_SIZE - data_vio->offset)) {
|
||||
/* This is not the final block of a discard so we can't acknowledge it yet. */
|
||||
update_metadata_for_data_vio_write(data_vio, NULL);
|
||||
return;
|
||||
|
||||
@@ -729,6 +729,7 @@ static void process_update_result(struct data_vio *agent)
|
||||
!change_context_state(context, DEDUPE_CONTEXT_COMPLETE, DEDUPE_CONTEXT_IDLE))
|
||||
return;
|
||||
|
||||
agent->dedupe_context = NULL;
|
||||
release_context(context);
|
||||
}
|
||||
|
||||
@@ -1648,6 +1649,7 @@ static void process_query_result(struct data_vio *agent)
|
||||
|
||||
if (change_context_state(context, DEDUPE_CONTEXT_COMPLETE, DEDUPE_CONTEXT_IDLE)) {
|
||||
agent->is_duplicate = decode_uds_advice(context);
|
||||
agent->dedupe_context = NULL;
|
||||
release_context(context);
|
||||
}
|
||||
}
|
||||
@@ -2321,6 +2323,7 @@ static void timeout_index_operations_callback(struct vdo_completion *completion)
|
||||
* send its requestor on its way.
|
||||
*/
|
||||
list_del_init(&context->list_entry);
|
||||
context->requestor->dedupe_context = NULL;
|
||||
continue_data_vio(context->requestor);
|
||||
timed_out++;
|
||||
}
|
||||
|
||||
@@ -1105,6 +1105,9 @@ static int vdo_message(struct dm_target *ti, unsigned int argc, char **argv,
|
||||
if ((argc == 1) && (strcasecmp(argv[0], "stats") == 0)) {
|
||||
vdo_write_stats(vdo, result_buffer, maxlen);
|
||||
result = 1;
|
||||
} else if ((argc == 1) && (strcasecmp(argv[0], "config") == 0)) {
|
||||
vdo_write_config(vdo, &result_buffer, &maxlen);
|
||||
result = 1;
|
||||
} else {
|
||||
result = vdo_status_to_errno(process_vdo_message(vdo, argc, argv));
|
||||
}
|
||||
@@ -2293,6 +2296,14 @@ static void handle_load_error(struct vdo_completion *completion)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((completion->result == VDO_UNSUPPORTED_VERSION) &&
|
||||
(vdo->admin.phase == LOAD_PHASE_MAKE_DIRTY)) {
|
||||
vdo_log_error("Aborting load due to unsupported version");
|
||||
vdo->admin.phase = LOAD_PHASE_FINISHED;
|
||||
load_callback(completion);
|
||||
return;
|
||||
}
|
||||
|
||||
vdo_log_error_strerror(completion->result,
|
||||
"Entering read-only mode due to load error");
|
||||
vdo->admin.phase = LOAD_PHASE_WAIT_FOR_READ_ONLY;
|
||||
@@ -2737,6 +2748,19 @@ static int vdo_preresume_registered(struct dm_target *ti, struct vdo *vdo)
|
||||
vdo_log_info("starting device '%s'", device_name);
|
||||
result = perform_admin_operation(vdo, LOAD_PHASE_START, load_callback,
|
||||
handle_load_error, "load");
|
||||
if (result == VDO_UNSUPPORTED_VERSION) {
|
||||
/*
|
||||
* A component version is not supported. This can happen when the
|
||||
* recovery journal metadata is in an old version format. Abort the
|
||||
* load without saving the state.
|
||||
*/
|
||||
vdo->suspend_type = VDO_ADMIN_STATE_SUSPENDING;
|
||||
perform_admin_operation(vdo, SUSPEND_PHASE_START,
|
||||
suspend_callback, suspend_callback,
|
||||
"suspend");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result != VDO_SUCCESS) && (result != VDO_READ_ONLY)) {
|
||||
/*
|
||||
* Something has gone very wrong. Make sure everything has drained and
|
||||
@@ -2808,7 +2832,8 @@ static int vdo_preresume(struct dm_target *ti)
|
||||
|
||||
vdo_register_thread_device_id(&instance_thread, &vdo->instance);
|
||||
result = vdo_preresume_registered(ti, vdo);
|
||||
if ((result == VDO_PARAMETER_MISMATCH) || (result == VDO_INVALID_ADMIN_STATE))
|
||||
if ((result == VDO_PARAMETER_MISMATCH) || (result == VDO_INVALID_ADMIN_STATE) ||
|
||||
(result == VDO_UNSUPPORTED_VERSION))
|
||||
result = -EINVAL;
|
||||
vdo_unregister_thread_device_id();
|
||||
return vdo_status_to_errno(result);
|
||||
@@ -2832,7 +2857,7 @@ static void vdo_resume(struct dm_target *ti)
|
||||
static struct target_type vdo_target_bio = {
|
||||
.features = DM_TARGET_SINGLETON,
|
||||
.name = "vdo",
|
||||
.version = { 9, 0, 0 },
|
||||
.version = { 9, 1, 0 },
|
||||
.module = THIS_MODULE,
|
||||
.ctr = vdo_ctr,
|
||||
.dtr = vdo_dtr,
|
||||
|
||||
@@ -177,7 +177,7 @@ int uds_pack_open_chapter_index_page(struct open_chapter_index *chapter_index,
|
||||
if (list_number < 0)
|
||||
return UDS_OVERFLOW;
|
||||
|
||||
next_list = first_list + list_number--,
|
||||
next_list = first_list + list_number--;
|
||||
result = uds_start_delta_index_search(delta_index, next_list, 0,
|
||||
&entry);
|
||||
if (result != UDS_SUCCESS)
|
||||
|
||||
@@ -346,7 +346,6 @@ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
|
||||
|
||||
|
||||
VDO_ASSERT_LOG_ONLY(!code->quiescent, "I/O not allowed in state %s", code->name);
|
||||
VDO_ASSERT_LOG_ONLY(vio->bio->bi_next == NULL, "metadata bio has no next bio");
|
||||
|
||||
vdo_reset_completion(completion);
|
||||
completion->error_handler = error_handler;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "dedupe.h"
|
||||
#include "indexer.h"
|
||||
#include "logger.h"
|
||||
#include "memory-alloc.h"
|
||||
#include "message-stats.h"
|
||||
@@ -430,3 +431,50 @@ int vdo_write_stats(struct vdo *vdo, char *buf, unsigned int maxlen)
|
||||
vdo_free(stats);
|
||||
return VDO_SUCCESS;
|
||||
}
|
||||
|
||||
static void write_index_memory(u32 mem, char **buf, unsigned int *maxlen)
|
||||
{
|
||||
char *prefix = "memorySize : ";
|
||||
|
||||
/* Convert index memory to fractional value */
|
||||
if (mem == (u32)UDS_MEMORY_CONFIG_256MB)
|
||||
write_string(prefix, "0.25, ", NULL, buf, maxlen);
|
||||
else if (mem == (u32)UDS_MEMORY_CONFIG_512MB)
|
||||
write_string(prefix, "0.50, ", NULL, buf, maxlen);
|
||||
else if (mem == (u32)UDS_MEMORY_CONFIG_768MB)
|
||||
write_string(prefix, "0.75, ", NULL, buf, maxlen);
|
||||
else
|
||||
write_u32(prefix, mem, ", ", buf, maxlen);
|
||||
}
|
||||
|
||||
static void write_index_config(struct index_config *config, char **buf,
|
||||
unsigned int *maxlen)
|
||||
{
|
||||
write_string("index : ", "{ ", NULL, buf, maxlen);
|
||||
/* index mem size */
|
||||
write_index_memory(config->mem, buf, maxlen);
|
||||
/* whether the index is sparse or not */
|
||||
write_bool("isSparse : ", config->sparse, ", ", buf, maxlen);
|
||||
write_string(NULL, "}", ", ", buf, maxlen);
|
||||
}
|
||||
|
||||
int vdo_write_config(struct vdo *vdo, char **buf, unsigned int *maxlen)
|
||||
{
|
||||
struct vdo_config *config = &vdo->states.vdo.config;
|
||||
|
||||
write_string(NULL, "{ ", NULL, buf, maxlen);
|
||||
/* version */
|
||||
write_u32("version : ", 1, ", ", buf, maxlen);
|
||||
/* physical size */
|
||||
write_block_count_t("physicalSize : ", config->physical_blocks * VDO_BLOCK_SIZE, ", ",
|
||||
buf, maxlen);
|
||||
/* logical size */
|
||||
write_block_count_t("logicalSize : ", config->logical_blocks * VDO_BLOCK_SIZE, ", ",
|
||||
buf, maxlen);
|
||||
/* slab size */
|
||||
write_block_count_t("slabSize : ", config->slab_size, ", ", buf, maxlen);
|
||||
/* index config */
|
||||
write_index_config(&vdo->geometry.index_config, buf, maxlen);
|
||||
write_string(NULL, "}", NULL, buf, maxlen);
|
||||
return VDO_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
int vdo_write_config(struct vdo *vdo, char **buf, unsigned int *maxlen);
|
||||
int vdo_write_stats(struct vdo *vdo, char *buf, unsigned int maxlen);
|
||||
|
||||
#endif /* VDO_MESSAGE_STATS_H */
|
||||
|
||||
+22
-19
@@ -1202,17 +1202,14 @@ static bool __must_check is_valid_recovery_journal_block(const struct recovery_j
|
||||
* @journal: The journal to use.
|
||||
* @header: The unpacked block header to check.
|
||||
* @sequence: The expected sequence number.
|
||||
* @type: The expected metadata type.
|
||||
*
|
||||
* Return: True if the block matches.
|
||||
*/
|
||||
static bool __must_check is_exact_recovery_journal_block(const struct recovery_journal *journal,
|
||||
const struct recovery_block_header *header,
|
||||
sequence_number_t sequence,
|
||||
enum vdo_metadata_type type)
|
||||
sequence_number_t sequence)
|
||||
{
|
||||
return ((header->metadata_type == type) &&
|
||||
(header->sequence_number == sequence) &&
|
||||
return ((header->sequence_number == sequence) &&
|
||||
(is_valid_recovery_journal_block(journal, header, true)));
|
||||
}
|
||||
|
||||
@@ -1371,7 +1368,8 @@ static void extract_entries_from_block(struct repair_completion *repair,
|
||||
get_recovery_journal_block_header(journal, repair->journal_data,
|
||||
sequence);
|
||||
|
||||
if (!is_exact_recovery_journal_block(journal, &header, sequence, format)) {
|
||||
if (!is_exact_recovery_journal_block(journal, &header, sequence) ||
|
||||
(header.metadata_type != format)) {
|
||||
/* This block is invalid, so skip it. */
|
||||
return;
|
||||
}
|
||||
@@ -1557,10 +1555,13 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
|
||||
sequence_number_t i, head;
|
||||
bool found_entries = false;
|
||||
struct recovery_journal *journal = repair->completion.vdo->recovery_journal;
|
||||
struct recovery_block_header header;
|
||||
enum vdo_metadata_type expected_format;
|
||||
|
||||
head = min(repair->block_map_head, repair->slab_journal_head);
|
||||
header = get_recovery_journal_block_header(journal, repair->journal_data, head);
|
||||
expected_format = header.metadata_type;
|
||||
for (i = head; i <= repair->highest_tail; i++) {
|
||||
struct recovery_block_header header;
|
||||
journal_entry_count_t block_entries;
|
||||
u8 j;
|
||||
|
||||
@@ -1572,19 +1573,15 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
|
||||
};
|
||||
|
||||
header = get_recovery_journal_block_header(journal, repair->journal_data, i);
|
||||
if (header.metadata_type == VDO_METADATA_RECOVERY_JOURNAL) {
|
||||
/* This is an old format block, so we need to upgrade */
|
||||
vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
|
||||
"Recovery journal is in the old format, a read-only rebuild is required.");
|
||||
vdo_enter_read_only_mode(repair->completion.vdo,
|
||||
VDO_UNSUPPORTED_VERSION);
|
||||
return VDO_UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
if (!is_exact_recovery_journal_block(journal, &header, i,
|
||||
VDO_METADATA_RECOVERY_JOURNAL_2)) {
|
||||
if (!is_exact_recovery_journal_block(journal, &header, i)) {
|
||||
/* A bad block header was found so this must be the end of the journal. */
|
||||
break;
|
||||
} else if (header.metadata_type != expected_format) {
|
||||
/* There is a mix of old and new format blocks, so we need to rebuild. */
|
||||
vdo_log_error_strerror(VDO_CORRUPT_JOURNAL,
|
||||
"Recovery journal is in an invalid format, a read-only rebuild is required.");
|
||||
vdo_enter_read_only_mode(repair->completion.vdo, VDO_CORRUPT_JOURNAL);
|
||||
return VDO_CORRUPT_JOURNAL;
|
||||
}
|
||||
|
||||
block_entries = header.entry_count;
|
||||
@@ -1620,8 +1617,14 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found_entries)
|
||||
if (!found_entries) {
|
||||
return validate_heads(repair);
|
||||
} else if (expected_format == VDO_METADATA_RECOVERY_JOURNAL) {
|
||||
/* All journal blocks have the old format, so we need to upgrade. */
|
||||
vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
|
||||
"Recovery journal is in the old format. Downgrade and complete recovery, then upgrade with a clean volume");
|
||||
return VDO_UNSUPPORTED_VERSION;
|
||||
}
|
||||
|
||||
/* Set the tail to the last valid tail block, if there is one. */
|
||||
if (repair->tail_recovery_point.sector_count == 0)
|
||||
|
||||
@@ -28,7 +28,7 @@ const struct error_info vdo_status_list[] = {
|
||||
{ "VDO_LOCK_ERROR", "A lock is held incorrectly" },
|
||||
{ "VDO_READ_ONLY", "The device is in read-only mode" },
|
||||
{ "VDO_SHUTTING_DOWN", "The device is shutting down" },
|
||||
{ "VDO_CORRUPT_JOURNAL", "Recovery journal entries corrupted" },
|
||||
{ "VDO_CORRUPT_JOURNAL", "Recovery journal corrupted" },
|
||||
{ "VDO_TOO_MANY_SLABS", "Exceeds maximum number of slabs supported" },
|
||||
{ "VDO_INVALID_FRAGMENT", "Compressed block fragment is invalid" },
|
||||
{ "VDO_RETRY_AFTER_REBUILD", "Retry operation after rebuilding finishes" },
|
||||
|
||||
@@ -52,7 +52,7 @@ enum vdo_status_codes {
|
||||
VDO_READ_ONLY,
|
||||
/* the VDO is shutting down */
|
||||
VDO_SHUTTING_DOWN,
|
||||
/* the recovery journal has corrupt entries */
|
||||
/* the recovery journal has corrupt entries or corrupt metadata */
|
||||
VDO_CORRUPT_JOURNAL,
|
||||
/* exceeds maximum number of slabs supported */
|
||||
VDO_TOO_MANY_SLABS,
|
||||
|
||||
@@ -273,8 +273,10 @@ out:
|
||||
if (v->mode == DM_VERITY_MODE_LOGGING)
|
||||
return 0;
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_RESTART)
|
||||
kernel_restart("dm-verity device corrupted");
|
||||
if (v->mode == DM_VERITY_MODE_RESTART) {
|
||||
pr_emerg("dm-verity device corrupted\n");
|
||||
emergency_restart();
|
||||
}
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_PANIC)
|
||||
panic("dm-verity device corrupted");
|
||||
@@ -597,6 +599,23 @@ static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
|
||||
if (!static_branch_unlikely(&use_bh_wq_enabled) || !io->in_bh)
|
||||
verity_fec_finish_io(io);
|
||||
|
||||
if (unlikely(status != BLK_STS_OK) &&
|
||||
unlikely(!(bio->bi_opf & REQ_RAHEAD)) &&
|
||||
!verity_is_system_shutting_down()) {
|
||||
if (v->mode == DM_VERITY_MODE_RESTART ||
|
||||
v->mode == DM_VERITY_MODE_PANIC)
|
||||
DMERR_LIMIT("%s has error: %s", v->data_dev->name,
|
||||
blk_status_to_str(status));
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_RESTART) {
|
||||
pr_emerg("dm-verity device corrupted\n");
|
||||
emergency_restart();
|
||||
}
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_PANIC)
|
||||
panic("dm-verity device corrupted");
|
||||
}
|
||||
|
||||
bio_endio(bio);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
|
||||
#endif
|
||||
VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL);
|
||||
#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING
|
||||
if (ret == -ENOKEY)
|
||||
if (ret == -ENOKEY || ret == -EKEYREJECTED)
|
||||
ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
|
||||
sig_len,
|
||||
VERIFY_USE_PLATFORM_KEYRING,
|
||||
|
||||
+8
-3
@@ -2030,10 +2030,15 @@ static void dm_submit_bio(struct bio *bio)
|
||||
struct dm_table *map;
|
||||
|
||||
map = dm_get_live_table(md, &srcu_idx);
|
||||
if (unlikely(!map)) {
|
||||
DMERR_LIMIT("%s: mapping table unavailable, erroring io",
|
||||
dm_device_name(md));
|
||||
bio_io_error(bio);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If suspended, or map not yet available, queue this IO for later */
|
||||
if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) ||
|
||||
unlikely(!map)) {
|
||||
/* If suspended, queue this IO for later */
|
||||
if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) {
|
||||
if (bio->bi_opf & REQ_NOWAIT)
|
||||
bio_wouldblock_error(bio);
|
||||
else if (bio->bi_opf & REQ_RAHEAD)
|
||||
|
||||
@@ -109,7 +109,6 @@ void dm_zone_endio(struct dm_io *io, struct bio *clone);
|
||||
int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
|
||||
unsigned int nr_zones, report_zones_cb cb, void *data);
|
||||
bool dm_is_zone_write(struct mapped_device *md, struct bio *bio);
|
||||
int dm_zone_map_bio(struct dm_target_io *io);
|
||||
int dm_zone_get_reset_bitmap(struct mapped_device *md, struct dm_table *t,
|
||||
sector_t sector, unsigned int nr_zones,
|
||||
unsigned long *need_reset);
|
||||
@@ -119,10 +118,6 @@ static inline bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline int dm_zone_map_bio(struct dm_target_io *tio)
|
||||
{
|
||||
return DM_MAPIO_KILL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -32,8 +32,11 @@ store_intc_userimask(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long level;
|
||||
int ret;
|
||||
|
||||
level = simple_strtoul(buf, NULL, 10);
|
||||
ret = kstrtoul(buf, 10, &level);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Minimal acceptable IRQ levels are in the 2 - 16 range, but
|
||||
|
||||
@@ -261,6 +261,7 @@ config XEN_SCSI_BACKEND
|
||||
config XEN_PRIVCMD
|
||||
tristate "Xen hypercall passthrough driver"
|
||||
depends on XEN
|
||||
imply CONFIG_XEN_PCIDEV_BACKEND
|
||||
default m
|
||||
help
|
||||
The hypercall passthrough driver allows privileged user programs to
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <xen/acpi.h>
|
||||
#include <xen/interface/platform.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
@@ -75,3 +76,52 @@ int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
|
||||
return xen_acpi_notify_hypervisor_state(sleep_state, val_a,
|
||||
val_b, true);
|
||||
}
|
||||
|
||||
struct acpi_prt_entry {
|
||||
struct acpi_pci_id id;
|
||||
u8 pin;
|
||||
acpi_handle link;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
int xen_acpi_get_gsi_info(struct pci_dev *dev,
|
||||
int *gsi_out,
|
||||
int *trigger_out,
|
||||
int *polarity_out)
|
||||
{
|
||||
int gsi;
|
||||
u8 pin;
|
||||
struct acpi_prt_entry *entry;
|
||||
int trigger = ACPI_LEVEL_SENSITIVE;
|
||||
int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
|
||||
ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
|
||||
|
||||
if (!dev || !gsi_out || !trigger_out || !polarity_out)
|
||||
return -EINVAL;
|
||||
|
||||
pin = dev->pin;
|
||||
if (!pin)
|
||||
return -EINVAL;
|
||||
|
||||
entry = acpi_pci_irq_lookup(dev, pin);
|
||||
if (entry) {
|
||||
if (entry->link)
|
||||
gsi = acpi_pci_link_allocate_irq(entry->link,
|
||||
entry->index,
|
||||
&trigger, &polarity,
|
||||
NULL);
|
||||
else
|
||||
gsi = entry->index;
|
||||
} else
|
||||
gsi = -1;
|
||||
|
||||
if (gsi < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*gsi_out = gsi;
|
||||
*trigger_out = trigger;
|
||||
*polarity_out = polarity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xen_acpi_get_gsi_info);
|
||||
|
||||
@@ -173,6 +173,19 @@ static int xen_remove_device(struct device *dev)
|
||||
return r;
|
||||
}
|
||||
|
||||
int xen_reset_device(const struct pci_dev *dev)
|
||||
{
|
||||
struct pci_device_reset device = {
|
||||
.dev.seg = pci_domain_nr(dev->bus),
|
||||
.dev.bus = dev->bus->number,
|
||||
.dev.devfn = dev->devfn,
|
||||
.flags = PCI_DEVICE_RESET_FLR,
|
||||
};
|
||||
|
||||
return HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_reset, &device);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xen_reset_device);
|
||||
|
||||
static int xen_pci_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
#include <xen/page.h>
|
||||
#include <xen/xen-ops.h>
|
||||
#include <xen/balloon.h>
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
#include <xen/acpi.h>
|
||||
#endif
|
||||
|
||||
#include "privcmd.h"
|
||||
|
||||
@@ -844,6 +847,31 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long privcmd_ioctl_pcidev_get_gsi(struct file *file, void __user *udata)
|
||||
{
|
||||
#if defined(CONFIG_XEN_ACPI)
|
||||
int rc = -EINVAL;
|
||||
struct privcmd_pcidev_get_gsi kdata;
|
||||
|
||||
if (copy_from_user(&kdata, udata, sizeof(kdata)))
|
||||
return -EFAULT;
|
||||
|
||||
if (IS_REACHABLE(CONFIG_XEN_PCIDEV_BACKEND))
|
||||
rc = pcistub_get_gsi_from_sbdf(kdata.sbdf);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
kdata.gsi = rc;
|
||||
if (copy_to_user(udata, &kdata, sizeof(kdata)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_PRIVCMD_EVENTFD
|
||||
/* Irqfd support */
|
||||
static struct workqueue_struct *irqfd_cleanup_wq;
|
||||
@@ -1543,6 +1571,10 @@ static long privcmd_ioctl(struct file *file,
|
||||
ret = privcmd_ioctl_ioeventfd(file, udata);
|
||||
break;
|
||||
|
||||
case IOCTL_PRIVCMD_PCIDEV_GET_GSI:
|
||||
ret = privcmd_ioctl_pcidev_get_gsi(file, udata);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
|
||||
new_state = (__force pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
|
||||
|
||||
new_value &= PM_OK_BITS;
|
||||
if ((old_value & PM_OK_BITS) != new_value) {
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <xen/events.h>
|
||||
#include <xen/pci.h>
|
||||
#include <xen/xen.h>
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
#include <xen/acpi.h>
|
||||
#endif
|
||||
#include <asm/xen/hypervisor.h>
|
||||
#include <xen/interface/physdev.h>
|
||||
#include "pciback.h"
|
||||
@@ -53,6 +56,9 @@ struct pcistub_device {
|
||||
|
||||
struct pci_dev *dev;
|
||||
struct xen_pcibk_device *pdev;/* non-NULL if struct pci_dev is in use */
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
int gsi;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Access to pcistub_devices & seized_devices lists and the initialize_devices
|
||||
@@ -85,10 +91,23 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
|
||||
|
||||
kref_init(&psdev->kref);
|
||||
spin_lock_init(&psdev->lock);
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
psdev->gsi = -1;
|
||||
#endif
|
||||
|
||||
return psdev;
|
||||
}
|
||||
|
||||
static int pcistub_reset_device_state(struct pci_dev *dev)
|
||||
{
|
||||
__pci_reset_function_locked(dev);
|
||||
|
||||
if (!xen_pv_domain())
|
||||
return xen_reset_device(dev);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't call this directly as it's called by pcistub_device_put */
|
||||
static void pcistub_device_release(struct kref *kref)
|
||||
{
|
||||
@@ -107,7 +126,7 @@ static void pcistub_device_release(struct kref *kref)
|
||||
/* Call the reset function which does not take lock as this
|
||||
* is called from "unbind" which takes a device_lock mutex.
|
||||
*/
|
||||
__pci_reset_function_locked(dev);
|
||||
pcistub_reset_device_state(dev);
|
||||
if (dev_data &&
|
||||
pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
|
||||
dev_info(&dev->dev, "Could not reload PCI state\n");
|
||||
@@ -207,6 +226,25 @@ static struct pci_dev *pcistub_device_get_pci_dev(struct xen_pcibk_device *pdev,
|
||||
return pci_dev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
int pcistub_get_gsi_from_sbdf(unsigned int sbdf)
|
||||
{
|
||||
struct pcistub_device *psdev;
|
||||
int domain = (sbdf >> 16) & 0xffff;
|
||||
int bus = PCI_BUS_NUM(sbdf);
|
||||
int slot = PCI_SLOT(sbdf);
|
||||
int func = PCI_FUNC(sbdf);
|
||||
|
||||
psdev = pcistub_device_find(domain, bus, slot, func);
|
||||
|
||||
if (!psdev)
|
||||
return -ENODEV;
|
||||
|
||||
return psdev->gsi;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcistub_get_gsi_from_sbdf);
|
||||
#endif
|
||||
|
||||
struct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev,
|
||||
int domain, int bus,
|
||||
int slot, int func)
|
||||
@@ -284,7 +322,7 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
|
||||
* (so it's ready for the next domain)
|
||||
*/
|
||||
device_lock_assert(&dev->dev);
|
||||
__pci_reset_function_locked(dev);
|
||||
pcistub_reset_device_state(dev);
|
||||
|
||||
dev_data = pci_get_drvdata(dev);
|
||||
ret = pci_load_saved_state(dev, dev_data->pci_saved_state);
|
||||
@@ -354,11 +392,20 @@ static int pcistub_match(struct pci_dev *dev)
|
||||
return found;
|
||||
}
|
||||
|
||||
static int pcistub_init_device(struct pci_dev *dev)
|
||||
static int pcistub_init_device(struct pcistub_device *psdev)
|
||||
{
|
||||
struct xen_pcibk_dev_data *dev_data;
|
||||
struct pci_dev *dev;
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
int gsi, trigger, polarity;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
if (!psdev)
|
||||
return -EINVAL;
|
||||
|
||||
dev = psdev->dev;
|
||||
|
||||
dev_dbg(&dev->dev, "initializing...\n");
|
||||
|
||||
/* The PCI backend is not intended to be a module (or to work with
|
||||
@@ -420,9 +467,26 @@ static int pcistub_init_device(struct pci_dev *dev)
|
||||
dev_err(&dev->dev, "Could not store PCI conf saved state!\n");
|
||||
else {
|
||||
dev_dbg(&dev->dev, "resetting (FLR, D3, etc) the device\n");
|
||||
__pci_reset_function_locked(dev);
|
||||
err = pcistub_reset_device_state(dev);
|
||||
if (err)
|
||||
goto config_release;
|
||||
pci_restore_state(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_ACPI
|
||||
if (xen_initial_domain() && xen_pvh_domain()) {
|
||||
err = xen_acpi_get_gsi_info(dev, &gsi, &trigger, &polarity);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Fail to get gsi info!\n");
|
||||
goto config_release;
|
||||
}
|
||||
err = xen_pvh_setup_gsi(gsi, trigger, polarity);
|
||||
if (err)
|
||||
goto config_release;
|
||||
psdev->gsi = gsi;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now disable the device (this also ensures some private device
|
||||
* data is setup before we export)
|
||||
*/
|
||||
@@ -462,7 +526,7 @@ static int __init pcistub_init_devices_late(void)
|
||||
|
||||
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
|
||||
|
||||
err = pcistub_init_device(psdev->dev);
|
||||
err = pcistub_init_device(psdev);
|
||||
if (err) {
|
||||
dev_err(&psdev->dev->dev,
|
||||
"error %d initializing device\n", err);
|
||||
@@ -532,7 +596,7 @@ static int pcistub_seize(struct pci_dev *dev,
|
||||
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
|
||||
|
||||
/* don't want irqs disabled when calling pcistub_init_device */
|
||||
err = pcistub_init_device(psdev->dev);
|
||||
err = pcistub_init_device(psdev);
|
||||
|
||||
spin_lock_irqsave(&pcistub_devices_lock, flags);
|
||||
|
||||
@@ -757,7 +821,7 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
|
||||
}
|
||||
clear_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags);
|
||||
|
||||
res = (pci_ers_result_t)aer_op->err;
|
||||
res = (__force pci_ers_result_t)aer_op->err;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -156,9 +156,8 @@ int ocfs2_get_block(struct inode *inode, sector_t iblock,
|
||||
err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count,
|
||||
&ext_flags);
|
||||
if (err) {
|
||||
mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
|
||||
"%llu, NULL)\n", err, inode, (unsigned long long)iblock,
|
||||
(unsigned long long)p_blkno);
|
||||
mlog(ML_ERROR, "get_blocks() failed, inode: 0x%p, "
|
||||
"block: %llu\n", inode, (unsigned long long)iblock);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
||||
@@ -973,7 +973,13 @@ int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr,
|
||||
}
|
||||
|
||||
while (done < nr) {
|
||||
down_read(&OCFS2_I(inode)->ip_alloc_sem);
|
||||
if (!down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem)) {
|
||||
rc = -EAGAIN;
|
||||
mlog(ML_ERROR,
|
||||
"Inode #%llu ip_alloc_sem is temporarily unavailable\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
break;
|
||||
}
|
||||
rc = ocfs2_extent_map_get_blocks(inode, v_block + done,
|
||||
&p_block, &p_count, NULL);
|
||||
up_read(&OCFS2_I(inode)->ip_alloc_sem);
|
||||
|
||||
+24
-2
@@ -25,6 +25,7 @@
|
||||
#include "namei.h"
|
||||
#include "ocfs2_trace.h"
|
||||
#include "file.h"
|
||||
#include "symlink.h"
|
||||
|
||||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
@@ -4148,8 +4149,9 @@ static int __ocfs2_reflink(struct dentry *old_dentry,
|
||||
int ret;
|
||||
struct inode *inode = d_inode(old_dentry);
|
||||
struct buffer_head *new_bh = NULL;
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
|
||||
if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) {
|
||||
if (oi->ip_flags & OCFS2_INODE_SYSTEM_FILE) {
|
||||
ret = -EINVAL;
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
@@ -4175,6 +4177,26 @@ static int __ocfs2_reflink(struct dentry *old_dentry,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if ((oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) &&
|
||||
(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
|
||||
/*
|
||||
* Adjust extent record count to reserve space for extended attribute.
|
||||
* Inline data count had been adjusted in ocfs2_duplicate_inline_data().
|
||||
*/
|
||||
struct ocfs2_inode_info *new_oi = OCFS2_I(new_inode);
|
||||
|
||||
if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
|
||||
!(ocfs2_inode_is_fast_symlink(new_inode))) {
|
||||
struct ocfs2_dinode *new_di = (struct ocfs2_dinode *)new_bh->b_data;
|
||||
struct ocfs2_dinode *old_di = (struct ocfs2_dinode *)old_bh->b_data;
|
||||
struct ocfs2_extent_list *el = &new_di->id2.i_list;
|
||||
int inline_size = le16_to_cpu(old_di->i_xattr_inline_size);
|
||||
|
||||
le16_add_cpu(&el->l_count, -(inline_size /
|
||||
sizeof(struct ocfs2_extent_rec)));
|
||||
}
|
||||
}
|
||||
|
||||
ret = ocfs2_create_reflink_node(inode, old_bh,
|
||||
new_inode, new_bh, preserve);
|
||||
if (ret) {
|
||||
@@ -4182,7 +4204,7 @@ static int __ocfs2_reflink(struct dentry *old_dentry,
|
||||
goto inode_unlock;
|
||||
}
|
||||
|
||||
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
|
||||
if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
|
||||
ret = ocfs2_reflink_xattrs(inode, old_bh,
|
||||
new_inode, new_bh,
|
||||
preserve);
|
||||
|
||||
+1
-10
@@ -6511,16 +6511,7 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
|
||||
}
|
||||
|
||||
new_oi = OCFS2_I(args->new_inode);
|
||||
/*
|
||||
* Adjust extent record count to reserve space for extended attribute.
|
||||
* Inline data count had been adjusted in ocfs2_duplicate_inline_data().
|
||||
*/
|
||||
if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
|
||||
!(ocfs2_inode_is_fast_symlink(args->new_inode))) {
|
||||
struct ocfs2_extent_list *el = &new_di->id2.i_list;
|
||||
le16_add_cpu(&el->l_count, -(inline_size /
|
||||
sizeof(struct ocfs2_extent_rec)));
|
||||
}
|
||||
|
||||
spin_lock(&new_oi->ip_lock);
|
||||
new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL | OCFS2_INLINE_XATTR_FL;
|
||||
new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright(c) 2024 Intel Corporation. */
|
||||
#ifndef __CXL_MBOX_H__
|
||||
#define __CXL_MBOX_H__
|
||||
#include <linux/rcuwait.h>
|
||||
|
||||
struct cxl_mbox_cmd;
|
||||
|
||||
/**
|
||||
* struct cxl_mailbox - context for CXL mailbox operations
|
||||
* @host: device that hosts the mailbox
|
||||
* @payload_size: Size of space for payload
|
||||
* (CXL 3.1 8.2.8.4.3 Mailbox Capabilities Register)
|
||||
* @mbox_mutex: mutex protects device mailbox and firmware
|
||||
* @mbox_wait: rcuwait for mailbox
|
||||
* @mbox_send: @dev specific transport for transmitting mailbox commands
|
||||
*/
|
||||
struct cxl_mailbox {
|
||||
struct device *host;
|
||||
size_t payload_size;
|
||||
struct mutex mbox_mutex; /* lock to protect mailbox context */
|
||||
struct rcuwait mbox_wait;
|
||||
int (*mbox_send)(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *cmd);
|
||||
};
|
||||
|
||||
int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host);
|
||||
|
||||
#endif
|
||||
@@ -363,6 +363,7 @@ void acpi_unregister_gsi (u32 gsi);
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin);
|
||||
int acpi_pci_irq_enable (struct pci_dev *dev);
|
||||
void acpi_penalize_isa_irq(int irq, int active);
|
||||
bool acpi_isa_irq_available(int irq);
|
||||
|
||||
+76
-64
@@ -203,12 +203,12 @@ unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
|
||||
* the bit offset of all zero areas this function finds is multiples of that
|
||||
* power of 2. A @align_mask of 0 means no alignment is required.
|
||||
*/
|
||||
static inline unsigned long
|
||||
bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned int nr,
|
||||
unsigned long align_mask)
|
||||
static __always_inline
|
||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned int nr,
|
||||
unsigned long align_mask)
|
||||
{
|
||||
return bitmap_find_next_zero_area_off(map, size, start, nr,
|
||||
align_mask, 0);
|
||||
@@ -228,7 +228,7 @@ void bitmap_fold(unsigned long *dst, const unsigned long *orig,
|
||||
|
||||
#define bitmap_size(nbits) (ALIGN(nbits, BITS_PER_LONG) / BITS_PER_BYTE)
|
||||
|
||||
static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
|
||||
static __always_inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
|
||||
{
|
||||
unsigned int len = bitmap_size(nbits);
|
||||
|
||||
@@ -238,7 +238,7 @@ static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
|
||||
memset(dst, 0, len);
|
||||
}
|
||||
|
||||
static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
|
||||
static __always_inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
|
||||
{
|
||||
unsigned int len = bitmap_size(nbits);
|
||||
|
||||
@@ -248,8 +248,8 @@ static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
|
||||
memset(dst, 0xff, len);
|
||||
}
|
||||
|
||||
static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_copy(unsigned long *dst, const unsigned long *src, unsigned int nbits)
|
||||
{
|
||||
unsigned int len = bitmap_size(nbits);
|
||||
|
||||
@@ -262,8 +262,8 @@ static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
|
||||
/*
|
||||
* Copy bitmap and clear tail bits in last word.
|
||||
*/
|
||||
static inline void bitmap_copy_clear_tail(unsigned long *dst,
|
||||
const unsigned long *src, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_copy_clear_tail(unsigned long *dst, const unsigned long *src, unsigned int nbits)
|
||||
{
|
||||
bitmap_copy(dst, src, nbits);
|
||||
if (nbits % BITS_PER_LONG)
|
||||
@@ -318,16 +318,18 @@ void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits);
|
||||
bitmap_copy_clear_tail((unsigned long *)(buf), (const unsigned long *)(bitmap), (nbits))
|
||||
#endif
|
||||
|
||||
static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_and(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0;
|
||||
return __bitmap_and(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_or(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src1 | *src2;
|
||||
@@ -335,8 +337,9 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
|
||||
__bitmap_or(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_xor(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = *src1 ^ *src2;
|
||||
@@ -344,16 +347,17 @@ static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
|
||||
__bitmap_xor(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
|
||||
return __bitmap_andnot(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_complement(unsigned long *dst, const unsigned long *src, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = ~(*src);
|
||||
@@ -368,8 +372,8 @@ static inline void bitmap_complement(unsigned long *dst, const unsigned long *sr
|
||||
#endif
|
||||
#define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1)
|
||||
|
||||
static inline bool bitmap_equal(const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_equal(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
|
||||
@@ -388,10 +392,9 @@ static inline bool bitmap_equal(const unsigned long *src1,
|
||||
*
|
||||
* Returns: True if (*@src1 | *@src2) == *@src3, false otherwise
|
||||
*/
|
||||
static inline bool bitmap_or_equal(const unsigned long *src1,
|
||||
const unsigned long *src2,
|
||||
const unsigned long *src3,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_or_equal(const unsigned long *src1, const unsigned long *src2,
|
||||
const unsigned long *src3, unsigned int nbits)
|
||||
{
|
||||
if (!small_const_nbits(nbits))
|
||||
return __bitmap_or_equal(src1, src2, src3, nbits);
|
||||
@@ -399,9 +402,8 @@ static inline bool bitmap_or_equal(const unsigned long *src1,
|
||||
return !(((*src1 | *src2) ^ *src3) & BITMAP_LAST_WORD_MASK(nbits));
|
||||
}
|
||||
|
||||
static inline bool bitmap_intersects(const unsigned long *src1,
|
||||
const unsigned long *src2,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_intersects(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
|
||||
@@ -409,8 +411,8 @@ static inline bool bitmap_intersects(const unsigned long *src1,
|
||||
return __bitmap_intersects(src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline bool bitmap_subset(const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_subset(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
|
||||
@@ -418,7 +420,8 @@ static inline bool bitmap_subset(const unsigned long *src1,
|
||||
return __bitmap_subset(src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline bool bitmap_empty(const unsigned long *src, unsigned nbits)
|
||||
static __always_inline
|
||||
bool bitmap_empty(const unsigned long *src, unsigned nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
|
||||
@@ -426,7 +429,8 @@ static inline bool bitmap_empty(const unsigned long *src, unsigned nbits)
|
||||
return find_first_bit(src, nbits) == nbits;
|
||||
}
|
||||
|
||||
static inline bool bitmap_full(const unsigned long *src, unsigned int nbits)
|
||||
static __always_inline
|
||||
bool bitmap_full(const unsigned long *src, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
|
||||
@@ -460,8 +464,8 @@ unsigned long bitmap_weight_andnot(const unsigned long *src1,
|
||||
return __bitmap_weight_andnot(src1, src2, nbits);
|
||||
}
|
||||
|
||||
static __always_inline void bitmap_set(unsigned long *map, unsigned int start,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
|
||||
{
|
||||
if (__builtin_constant_p(nbits) && nbits == 1)
|
||||
__set_bit(start, map);
|
||||
@@ -476,8 +480,8 @@ static __always_inline void bitmap_set(unsigned long *map, unsigned int start,
|
||||
__bitmap_set(map, start, nbits);
|
||||
}
|
||||
|
||||
static __always_inline void bitmap_clear(unsigned long *map, unsigned int start,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_clear(unsigned long *map, unsigned int start, unsigned int nbits)
|
||||
{
|
||||
if (__builtin_constant_p(nbits) && nbits == 1)
|
||||
__clear_bit(start, map);
|
||||
@@ -492,8 +496,9 @@ static __always_inline void bitmap_clear(unsigned long *map, unsigned int start,
|
||||
__bitmap_clear(map, start, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_shift_right(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> shift;
|
||||
@@ -501,8 +506,9 @@ static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *s
|
||||
__bitmap_shift_right(dst, src, shift, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_shift_left(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = (*src << shift) & BITMAP_LAST_WORD_MASK(nbits);
|
||||
@@ -510,11 +516,12 @@ static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *sr
|
||||
__bitmap_shift_left(dst, src, shift, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_replace(unsigned long *dst,
|
||||
const unsigned long *old,
|
||||
const unsigned long *new,
|
||||
const unsigned long *mask,
|
||||
unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_replace(unsigned long *dst,
|
||||
const unsigned long *old,
|
||||
const unsigned long *new,
|
||||
const unsigned long *mask,
|
||||
unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
*dst = (*old & ~(*mask)) | (*new & *mask);
|
||||
@@ -557,8 +564,9 @@ static inline void bitmap_replace(unsigned long *dst,
|
||||
* bitmap_gather() can be seen as the 'reverse' bitmap_scatter() operation.
|
||||
* See bitmap_scatter() for details related to this relationship.
|
||||
*/
|
||||
static inline void bitmap_scatter(unsigned long *dst, const unsigned long *src,
|
||||
const unsigned long *mask, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_scatter(unsigned long *dst, const unsigned long *src,
|
||||
const unsigned long *mask, unsigned int nbits)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
unsigned int bit;
|
||||
@@ -611,8 +619,9 @@ static inline void bitmap_scatter(unsigned long *dst, const unsigned long *src,
|
||||
* bitmap_scatter(res, src, mask, n) and a call to
|
||||
* bitmap_scatter(res, result, mask, n) will lead to the same res value.
|
||||
*/
|
||||
static inline void bitmap_gather(unsigned long *dst, const unsigned long *src,
|
||||
const unsigned long *mask, unsigned int nbits)
|
||||
static __always_inline
|
||||
void bitmap_gather(unsigned long *dst, const unsigned long *src,
|
||||
const unsigned long *mask, unsigned int nbits)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
unsigned int bit;
|
||||
@@ -623,9 +632,9 @@ static inline void bitmap_gather(unsigned long *dst, const unsigned long *src,
|
||||
__assign_bit(n++, dst, test_bit(bit, src));
|
||||
}
|
||||
|
||||
static inline void bitmap_next_set_region(unsigned long *bitmap,
|
||||
unsigned int *rs, unsigned int *re,
|
||||
unsigned int end)
|
||||
static __always_inline
|
||||
void bitmap_next_set_region(unsigned long *bitmap, unsigned int *rs,
|
||||
unsigned int *re, unsigned int end)
|
||||
{
|
||||
*rs = find_next_bit(bitmap, end, *rs);
|
||||
*re = find_next_zero_bit(bitmap, end, *rs + 1);
|
||||
@@ -640,7 +649,8 @@ static inline void bitmap_next_set_region(unsigned long *bitmap,
|
||||
* This is the complement to __bitmap_find_free_region() and releases
|
||||
* the found region (by clearing it in the bitmap).
|
||||
*/
|
||||
static inline void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order)
|
||||
static __always_inline
|
||||
void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order)
|
||||
{
|
||||
bitmap_clear(bitmap, pos, BIT(order));
|
||||
}
|
||||
@@ -656,7 +666,8 @@ static inline void bitmap_release_region(unsigned long *bitmap, unsigned int pos
|
||||
* Returns: 0 on success, or %-EBUSY if specified region wasn't
|
||||
* free (not all bits were zero).
|
||||
*/
|
||||
static inline int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order)
|
||||
static __always_inline
|
||||
int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order)
|
||||
{
|
||||
unsigned int len = BIT(order);
|
||||
|
||||
@@ -680,7 +691,8 @@ static inline int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos
|
||||
* Returns: the bit offset in bitmap of the allocated region,
|
||||
* or -errno on failure.
|
||||
*/
|
||||
static inline int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order)
|
||||
static __always_inline
|
||||
int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order)
|
||||
{
|
||||
unsigned int pos, end; /* scans bitmap by regions of size order */
|
||||
|
||||
@@ -734,7 +746,7 @@ static inline int bitmap_find_free_region(unsigned long *bitmap, unsigned int bi
|
||||
* That is ``(u32 *)(&val)[0]`` gets the upper 32 bits,
|
||||
* but we expect the lower 32-bits of u64.
|
||||
*/
|
||||
static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
|
||||
static __always_inline void bitmap_from_u64(unsigned long *dst, u64 mask)
|
||||
{
|
||||
bitmap_from_arr64(dst, &mask, 64);
|
||||
}
|
||||
@@ -749,9 +761,8 @@ static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
|
||||
* @map memory region. For @nbits = 0 and @nbits > BITS_PER_LONG the return
|
||||
* value is undefined.
|
||||
*/
|
||||
static inline unsigned long bitmap_read(const unsigned long *map,
|
||||
unsigned long start,
|
||||
unsigned long nbits)
|
||||
static __always_inline
|
||||
unsigned long bitmap_read(const unsigned long *map, unsigned long start, unsigned long nbits)
|
||||
{
|
||||
size_t index = BIT_WORD(start);
|
||||
unsigned long offset = start % BITS_PER_LONG;
|
||||
@@ -784,8 +795,9 @@ static inline unsigned long bitmap_read(const unsigned long *map,
|
||||
*
|
||||
* For @nbits == 0 and @nbits > BITS_PER_LONG no writes are performed.
|
||||
*/
|
||||
static inline void bitmap_write(unsigned long *map, unsigned long value,
|
||||
unsigned long start, unsigned long nbits)
|
||||
static __always_inline
|
||||
void bitmap_write(unsigned long *map, unsigned long value,
|
||||
unsigned long start, unsigned long nbits)
|
||||
{
|
||||
size_t index;
|
||||
unsigned long offset;
|
||||
|
||||
@@ -36,4 +36,19 @@
|
||||
#define GENMASK_ULL(h, l) \
|
||||
(GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l))
|
||||
|
||||
#if !defined(__ASSEMBLY__)
|
||||
/*
|
||||
* Missing asm support
|
||||
*
|
||||
* __GENMASK_U128() depends on _BIT128() which would not work
|
||||
* in the asm code, as it shifts an 'unsigned __init128' data
|
||||
* type instead of direct representation of 128 bit constants
|
||||
* such as long and unsigned long. The fundamental problem is
|
||||
* that a 128 bit constant will get silently truncated by the
|
||||
* gcc compiler.
|
||||
*/
|
||||
#define GENMASK_U128(h, l) \
|
||||
(GENMASK_INPUT_CHECK(h, l) + __GENMASK_U128(h, l))
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_BITS_H */
|
||||
|
||||
@@ -133,7 +133,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
|
||||
#define annotate_unreachable() __annotate_unreachable(__COUNTER__)
|
||||
|
||||
/* Annotate a C jump table to allow objtool to follow the code flow */
|
||||
#define __annotate_jump_table __section(".rodata..c_jump_table")
|
||||
#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
|
||||
|
||||
#else /* !CONFIG_OBJTOOL */
|
||||
#define annotate_reachable()
|
||||
|
||||
+112
-100
@@ -30,7 +30,7 @@
|
||||
extern unsigned int nr_cpu_ids;
|
||||
#endif
|
||||
|
||||
static inline void set_nr_cpu_ids(unsigned int nr)
|
||||
static __always_inline void set_nr_cpu_ids(unsigned int nr)
|
||||
{
|
||||
#if (NR_CPUS == 1) || defined(CONFIG_FORCE_NR_CPUS)
|
||||
WARN_ON(nr != nr_cpu_ids);
|
||||
@@ -149,7 +149,7 @@ static __always_inline unsigned int cpumask_check(unsigned int cpu)
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no cpus set.
|
||||
*/
|
||||
static inline unsigned int cpumask_first(const struct cpumask *srcp)
|
||||
static __always_inline unsigned int cpumask_first(const struct cpumask *srcp)
|
||||
{
|
||||
return find_first_bit(cpumask_bits(srcp), small_cpumask_bits);
|
||||
}
|
||||
@@ -160,7 +160,7 @@ static inline unsigned int cpumask_first(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: >= nr_cpu_ids if all cpus are set.
|
||||
*/
|
||||
static inline unsigned int cpumask_first_zero(const struct cpumask *srcp)
|
||||
static __always_inline unsigned int cpumask_first_zero(const struct cpumask *srcp)
|
||||
{
|
||||
return find_first_zero_bit(cpumask_bits(srcp), small_cpumask_bits);
|
||||
}
|
||||
@@ -172,7 +172,7 @@ static inline unsigned int cpumask_first_zero(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and().
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_first_and(const struct cpumask *srcp1, const struct cpumask *srcp2)
|
||||
{
|
||||
return find_first_and_bit(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits);
|
||||
@@ -186,7 +186,7 @@ unsigned int cpumask_first_and(const struct cpumask *srcp1, const struct cpumask
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no cpus set in all.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_first_and_and(const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2,
|
||||
const struct cpumask *srcp3)
|
||||
@@ -201,7 +201,7 @@ unsigned int cpumask_first_and_and(const struct cpumask *srcp1,
|
||||
*
|
||||
* Return: >= nr_cpumask_bits if no CPUs set.
|
||||
*/
|
||||
static inline unsigned int cpumask_last(const struct cpumask *srcp)
|
||||
static __always_inline unsigned int cpumask_last(const struct cpumask *srcp)
|
||||
{
|
||||
return find_last_bit(cpumask_bits(srcp), small_cpumask_bits);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ static inline unsigned int cpumask_last(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no further cpus set.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_next(int n, const struct cpumask *srcp)
|
||||
{
|
||||
/* -1 is a legal arg here. */
|
||||
@@ -229,7 +229,8 @@ unsigned int cpumask_next(int n, const struct cpumask *srcp)
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no further cpus unset.
|
||||
*/
|
||||
static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
|
||||
static __always_inline
|
||||
unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
|
||||
{
|
||||
/* -1 is a legal arg here. */
|
||||
if (n != -1)
|
||||
@@ -239,18 +240,21 @@ static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
|
||||
|
||||
#if NR_CPUS == 1
|
||||
/* Uniprocessor: there is only one valid CPU */
|
||||
static inline unsigned int cpumask_local_spread(unsigned int i, int node)
|
||||
static __always_inline
|
||||
unsigned int cpumask_local_spread(unsigned int i, int node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int cpumask_any_and_distribute(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
unsigned int cpumask_any_and_distribute(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
return cpumask_first_and(src1p, src2p);
|
||||
}
|
||||
|
||||
static inline unsigned int cpumask_any_distribute(const struct cpumask *srcp)
|
||||
static __always_inline
|
||||
unsigned int cpumask_any_distribute(const struct cpumask *srcp)
|
||||
{
|
||||
return cpumask_first(srcp);
|
||||
}
|
||||
@@ -269,9 +273,9 @@ unsigned int cpumask_any_distribute(const struct cpumask *srcp);
|
||||
*
|
||||
* Return: >= nr_cpu_ids if no further cpus set in both.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_next_and(int n, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
/* -1 is a legal arg here. */
|
||||
if (n != -1)
|
||||
@@ -291,7 +295,7 @@ unsigned int cpumask_next_and(int n, const struct cpumask *src1p,
|
||||
for_each_set_bit(cpu, cpumask_bits(mask), small_cpumask_bits)
|
||||
|
||||
#if NR_CPUS == 1
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
|
||||
{
|
||||
cpumask_check(start);
|
||||
@@ -394,7 +398,7 @@ unsigned int __pure cpumask_next_wrap(int n, const struct cpumask *mask, int sta
|
||||
* Often used to find any cpu but smp_processor_id() in a mask.
|
||||
* Return: >= nr_cpu_ids if no cpus set.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -414,7 +418,7 @@ unsigned int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
|
||||
*
|
||||
* Returns >= nr_cpu_ids if no cpus set.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_any_and_but(const struct cpumask *mask1,
|
||||
const struct cpumask *mask2,
|
||||
unsigned int cpu)
|
||||
@@ -436,7 +440,8 @@ unsigned int cpumask_any_and_but(const struct cpumask *mask1,
|
||||
*
|
||||
* Return: >= nr_cpu_ids if such cpu doesn't exist.
|
||||
*/
|
||||
static inline unsigned int cpumask_nth(unsigned int cpu, const struct cpumask *srcp)
|
||||
static __always_inline
|
||||
unsigned int cpumask_nth(unsigned int cpu, const struct cpumask *srcp)
|
||||
{
|
||||
return find_nth_bit(cpumask_bits(srcp), small_cpumask_bits, cpumask_check(cpu));
|
||||
}
|
||||
@@ -449,7 +454,7 @@ static inline unsigned int cpumask_nth(unsigned int cpu, const struct cpumask *s
|
||||
*
|
||||
* Return: >= nr_cpu_ids if such cpu doesn't exist.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_nth_and(unsigned int cpu, const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2)
|
||||
{
|
||||
@@ -465,7 +470,7 @@ unsigned int cpumask_nth_and(unsigned int cpu, const struct cpumask *srcp1,
|
||||
*
|
||||
* Return: >= nr_cpu_ids if such cpu doesn't exist.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned int cpumask_nth_andnot(unsigned int cpu, const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2)
|
||||
{
|
||||
@@ -508,12 +513,14 @@ unsigned int cpumask_nth_and_andnot(unsigned int cpu, const struct cpumask *srcp
|
||||
* @cpu: cpu number (< nr_cpu_ids)
|
||||
* @dstp: the cpumask pointer
|
||||
*/
|
||||
static __always_inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
|
||||
static __always_inline
|
||||
void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
|
||||
{
|
||||
set_bit(cpumask_check(cpu), cpumask_bits(dstp));
|
||||
}
|
||||
|
||||
static __always_inline void __cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
|
||||
static __always_inline
|
||||
void __cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
|
||||
{
|
||||
__set_bit(cpumask_check(cpu), cpumask_bits(dstp));
|
||||
}
|
||||
@@ -557,7 +564,8 @@ static __always_inline void __cpumask_assign_cpu(int cpu, struct cpumask *dstp,
|
||||
*
|
||||
* Return: true if @cpu is set in @cpumask, else returns false
|
||||
*/
|
||||
static __always_inline bool cpumask_test_cpu(int cpu, const struct cpumask *cpumask)
|
||||
static __always_inline
|
||||
bool cpumask_test_cpu(int cpu, const struct cpumask *cpumask)
|
||||
{
|
||||
return test_bit(cpumask_check(cpu), cpumask_bits((cpumask)));
|
||||
}
|
||||
@@ -571,7 +579,8 @@ static __always_inline bool cpumask_test_cpu(int cpu, const struct cpumask *cpum
|
||||
*
|
||||
* Return: true if @cpu is set in old bitmap of @cpumask, else returns false
|
||||
*/
|
||||
static __always_inline bool cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
|
||||
static __always_inline
|
||||
bool cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
|
||||
{
|
||||
return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask));
|
||||
}
|
||||
@@ -585,7 +594,8 @@ static __always_inline bool cpumask_test_and_set_cpu(int cpu, struct cpumask *cp
|
||||
*
|
||||
* Return: true if @cpu is set in old bitmap of @cpumask, else returns false
|
||||
*/
|
||||
static __always_inline bool cpumask_test_and_clear_cpu(int cpu, struct cpumask *cpumask)
|
||||
static __always_inline
|
||||
bool cpumask_test_and_clear_cpu(int cpu, struct cpumask *cpumask)
|
||||
{
|
||||
return test_and_clear_bit(cpumask_check(cpu), cpumask_bits(cpumask));
|
||||
}
|
||||
@@ -594,7 +604,7 @@ static __always_inline bool cpumask_test_and_clear_cpu(int cpu, struct cpumask *
|
||||
* cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask
|
||||
* @dstp: the cpumask pointer
|
||||
*/
|
||||
static inline void cpumask_setall(struct cpumask *dstp)
|
||||
static __always_inline void cpumask_setall(struct cpumask *dstp)
|
||||
{
|
||||
if (small_const_nbits(small_cpumask_bits)) {
|
||||
cpumask_bits(dstp)[0] = BITMAP_LAST_WORD_MASK(nr_cpumask_bits);
|
||||
@@ -607,7 +617,7 @@ static inline void cpumask_setall(struct cpumask *dstp)
|
||||
* cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask
|
||||
* @dstp: the cpumask pointer
|
||||
*/
|
||||
static inline void cpumask_clear(struct cpumask *dstp)
|
||||
static __always_inline void cpumask_clear(struct cpumask *dstp)
|
||||
{
|
||||
bitmap_zero(cpumask_bits(dstp), large_cpumask_bits);
|
||||
}
|
||||
@@ -620,9 +630,9 @@ static inline void cpumask_clear(struct cpumask *dstp)
|
||||
*
|
||||
* Return: false if *@dstp is empty, else returns true
|
||||
*/
|
||||
static inline bool cpumask_and(struct cpumask *dstp,
|
||||
const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
bool cpumask_and(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
return bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p),
|
||||
cpumask_bits(src2p), small_cpumask_bits);
|
||||
@@ -634,8 +644,9 @@ static inline bool cpumask_and(struct cpumask *dstp,
|
||||
* @src1p: the first input
|
||||
* @src2p: the second input
|
||||
*/
|
||||
static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p),
|
||||
cpumask_bits(src2p), small_cpumask_bits);
|
||||
@@ -647,9 +658,9 @@ static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
* @src1p: the first input
|
||||
* @src2p: the second input
|
||||
*/
|
||||
static inline void cpumask_xor(struct cpumask *dstp,
|
||||
const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
void cpumask_xor(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p),
|
||||
cpumask_bits(src2p), small_cpumask_bits);
|
||||
@@ -663,9 +674,9 @@ static inline void cpumask_xor(struct cpumask *dstp,
|
||||
*
|
||||
* Return: false if *@dstp is empty, else returns true
|
||||
*/
|
||||
static inline bool cpumask_andnot(struct cpumask *dstp,
|
||||
const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
bool cpumask_andnot(struct cpumask *dstp, const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
{
|
||||
return bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p),
|
||||
cpumask_bits(src2p), small_cpumask_bits);
|
||||
@@ -678,8 +689,8 @@ static inline bool cpumask_andnot(struct cpumask *dstp,
|
||||
*
|
||||
* Return: true if the cpumasks are equal, false if not
|
||||
*/
|
||||
static inline bool cpumask_equal(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
bool cpumask_equal(const struct cpumask *src1p, const struct cpumask *src2p)
|
||||
{
|
||||
return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p),
|
||||
small_cpumask_bits);
|
||||
@@ -694,9 +705,9 @@ static inline bool cpumask_equal(const struct cpumask *src1p,
|
||||
* Return: true if first cpumask ORed with second cpumask == third cpumask,
|
||||
* otherwise false
|
||||
*/
|
||||
static inline bool cpumask_or_equal(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p,
|
||||
const struct cpumask *src3p)
|
||||
static __always_inline
|
||||
bool cpumask_or_equal(const struct cpumask *src1p, const struct cpumask *src2p,
|
||||
const struct cpumask *src3p)
|
||||
{
|
||||
return bitmap_or_equal(cpumask_bits(src1p), cpumask_bits(src2p),
|
||||
cpumask_bits(src3p), small_cpumask_bits);
|
||||
@@ -710,8 +721,8 @@ static inline bool cpumask_or_equal(const struct cpumask *src1p,
|
||||
* Return: true if first cpumask ANDed with second cpumask is non-empty,
|
||||
* otherwise false
|
||||
*/
|
||||
static inline bool cpumask_intersects(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
bool cpumask_intersects(const struct cpumask *src1p, const struct cpumask *src2p)
|
||||
{
|
||||
return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p),
|
||||
small_cpumask_bits);
|
||||
@@ -724,8 +735,8 @@ static inline bool cpumask_intersects(const struct cpumask *src1p,
|
||||
*
|
||||
* Return: true if *@src1p is a subset of *@src2p, else returns false
|
||||
*/
|
||||
static inline bool cpumask_subset(const struct cpumask *src1p,
|
||||
const struct cpumask *src2p)
|
||||
static __always_inline
|
||||
bool cpumask_subset(const struct cpumask *src1p, const struct cpumask *src2p)
|
||||
{
|
||||
return bitmap_subset(cpumask_bits(src1p), cpumask_bits(src2p),
|
||||
small_cpumask_bits);
|
||||
@@ -737,7 +748,7 @@ static inline bool cpumask_subset(const struct cpumask *src1p,
|
||||
*
|
||||
* Return: true if srcp is empty (has no bits set), else false
|
||||
*/
|
||||
static inline bool cpumask_empty(const struct cpumask *srcp)
|
||||
static __always_inline bool cpumask_empty(const struct cpumask *srcp)
|
||||
{
|
||||
return bitmap_empty(cpumask_bits(srcp), small_cpumask_bits);
|
||||
}
|
||||
@@ -748,7 +759,7 @@ static inline bool cpumask_empty(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: true if srcp is full (has all bits set), else false
|
||||
*/
|
||||
static inline bool cpumask_full(const struct cpumask *srcp)
|
||||
static __always_inline bool cpumask_full(const struct cpumask *srcp)
|
||||
{
|
||||
return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits);
|
||||
}
|
||||
@@ -759,7 +770,7 @@ static inline bool cpumask_full(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: count of bits set in *srcp
|
||||
*/
|
||||
static inline unsigned int cpumask_weight(const struct cpumask *srcp)
|
||||
static __always_inline unsigned int cpumask_weight(const struct cpumask *srcp)
|
||||
{
|
||||
return bitmap_weight(cpumask_bits(srcp), small_cpumask_bits);
|
||||
}
|
||||
@@ -771,8 +782,8 @@ static inline unsigned int cpumask_weight(const struct cpumask *srcp)
|
||||
*
|
||||
* Return: count of bits set in both *srcp1 and *srcp2
|
||||
*/
|
||||
static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2)
|
||||
static __always_inline
|
||||
unsigned int cpumask_weight_and(const struct cpumask *srcp1, const struct cpumask *srcp2)
|
||||
{
|
||||
return bitmap_weight_and(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits);
|
||||
}
|
||||
@@ -784,8 +795,9 @@ static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1,
|
||||
*
|
||||
* Return: count of bits set in both *srcp1 and *srcp2
|
||||
*/
|
||||
static inline unsigned int cpumask_weight_andnot(const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2)
|
||||
static __always_inline
|
||||
unsigned int cpumask_weight_andnot(const struct cpumask *srcp1,
|
||||
const struct cpumask *srcp2)
|
||||
{
|
||||
return bitmap_weight_andnot(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits);
|
||||
}
|
||||
@@ -796,8 +808,8 @@ static inline unsigned int cpumask_weight_andnot(const struct cpumask *srcp1,
|
||||
* @srcp: the input to shift
|
||||
* @n: the number of bits to shift by
|
||||
*/
|
||||
static inline void cpumask_shift_right(struct cpumask *dstp,
|
||||
const struct cpumask *srcp, int n)
|
||||
static __always_inline
|
||||
void cpumask_shift_right(struct cpumask *dstp, const struct cpumask *srcp, int n)
|
||||
{
|
||||
bitmap_shift_right(cpumask_bits(dstp), cpumask_bits(srcp), n,
|
||||
small_cpumask_bits);
|
||||
@@ -809,8 +821,8 @@ static inline void cpumask_shift_right(struct cpumask *dstp,
|
||||
* @srcp: the input to shift
|
||||
* @n: the number of bits to shift by
|
||||
*/
|
||||
static inline void cpumask_shift_left(struct cpumask *dstp,
|
||||
const struct cpumask *srcp, int n)
|
||||
static __always_inline
|
||||
void cpumask_shift_left(struct cpumask *dstp, const struct cpumask *srcp, int n)
|
||||
{
|
||||
bitmap_shift_left(cpumask_bits(dstp), cpumask_bits(srcp), n,
|
||||
nr_cpumask_bits);
|
||||
@@ -821,8 +833,8 @@ static inline void cpumask_shift_left(struct cpumask *dstp,
|
||||
* @dstp: the result
|
||||
* @srcp: the input cpumask
|
||||
*/
|
||||
static inline void cpumask_copy(struct cpumask *dstp,
|
||||
const struct cpumask *srcp)
|
||||
static __always_inline
|
||||
void cpumask_copy(struct cpumask *dstp, const struct cpumask *srcp)
|
||||
{
|
||||
bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), large_cpumask_bits);
|
||||
}
|
||||
@@ -858,8 +870,8 @@ static inline void cpumask_copy(struct cpumask *dstp,
|
||||
*
|
||||
* Return: -errno, or 0 for success.
|
||||
*/
|
||||
static inline int cpumask_parse_user(const char __user *buf, int len,
|
||||
struct cpumask *dstp)
|
||||
static __always_inline
|
||||
int cpumask_parse_user(const char __user *buf, int len, struct cpumask *dstp)
|
||||
{
|
||||
return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
|
||||
}
|
||||
@@ -872,8 +884,8 @@ static inline int cpumask_parse_user(const char __user *buf, int len,
|
||||
*
|
||||
* Return: -errno, or 0 for success.
|
||||
*/
|
||||
static inline int cpumask_parselist_user(const char __user *buf, int len,
|
||||
struct cpumask *dstp)
|
||||
static __always_inline
|
||||
int cpumask_parselist_user(const char __user *buf, int len, struct cpumask *dstp)
|
||||
{
|
||||
return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
|
||||
nr_cpumask_bits);
|
||||
@@ -886,7 +898,7 @@ static inline int cpumask_parselist_user(const char __user *buf, int len,
|
||||
*
|
||||
* Return: -errno, or 0 for success.
|
||||
*/
|
||||
static inline int cpumask_parse(const char *buf, struct cpumask *dstp)
|
||||
static __always_inline int cpumask_parse(const char *buf, struct cpumask *dstp)
|
||||
{
|
||||
return bitmap_parse(buf, UINT_MAX, cpumask_bits(dstp), nr_cpumask_bits);
|
||||
}
|
||||
@@ -898,7 +910,7 @@ static inline int cpumask_parse(const char *buf, struct cpumask *dstp)
|
||||
*
|
||||
* Return: -errno, or 0 for success.
|
||||
*/
|
||||
static inline int cpulist_parse(const char *buf, struct cpumask *dstp)
|
||||
static __always_inline int cpulist_parse(const char *buf, struct cpumask *dstp)
|
||||
{
|
||||
return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpumask_bits);
|
||||
}
|
||||
@@ -908,7 +920,7 @@ static inline int cpulist_parse(const char *buf, struct cpumask *dstp)
|
||||
*
|
||||
* Return: size to allocate for a &struct cpumask in bytes
|
||||
*/
|
||||
static inline unsigned int cpumask_size(void)
|
||||
static __always_inline unsigned int cpumask_size(void)
|
||||
{
|
||||
return bitmap_size(large_cpumask_bits);
|
||||
}
|
||||
@@ -920,7 +932,7 @@ static inline unsigned int cpumask_size(void)
|
||||
|
||||
bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node);
|
||||
|
||||
static inline
|
||||
static __always_inline
|
||||
bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
|
||||
{
|
||||
return alloc_cpumask_var_node(mask, flags | __GFP_ZERO, node);
|
||||
@@ -938,13 +950,13 @@ bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
|
||||
*
|
||||
* Return: %true if allocation succeeded, %false if not
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
{
|
||||
return alloc_cpumask_var_node(mask, flags, NUMA_NO_NODE);
|
||||
}
|
||||
|
||||
static inline
|
||||
static __always_inline
|
||||
bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
{
|
||||
return alloc_cpumask_var(mask, flags | __GFP_ZERO);
|
||||
@@ -954,7 +966,7 @@ void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
|
||||
void free_cpumask_var(cpumask_var_t mask);
|
||||
void free_bootmem_cpumask_var(cpumask_var_t mask);
|
||||
|
||||
static inline bool cpumask_available(cpumask_var_t mask)
|
||||
static __always_inline bool cpumask_available(cpumask_var_t mask)
|
||||
{
|
||||
return mask != NULL;
|
||||
}
|
||||
@@ -964,43 +976,43 @@ static inline bool cpumask_available(cpumask_var_t mask)
|
||||
#define this_cpu_cpumask_var_ptr(x) this_cpu_ptr(x)
|
||||
#define __cpumask_var_read_mostly
|
||||
|
||||
static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
static __always_inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags,
|
||||
static __always_inline bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags,
|
||||
int node)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
static __always_inline bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
|
||||
{
|
||||
cpumask_clear(*mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags,
|
||||
static __always_inline bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags,
|
||||
int node)
|
||||
{
|
||||
cpumask_clear(*mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
|
||||
static __always_inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void free_cpumask_var(cpumask_var_t mask)
|
||||
static __always_inline void free_cpumask_var(cpumask_var_t mask)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
|
||||
static __always_inline void free_bootmem_cpumask_var(cpumask_var_t mask)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool cpumask_available(cpumask_var_t mask)
|
||||
static __always_inline bool cpumask_available(cpumask_var_t mask)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1058,7 +1070,7 @@ void set_cpu_online(unsigned int cpu, bool online);
|
||||
((struct cpumask *)(1 ? (bitmap) \
|
||||
: (void *)sizeof(__check_is_bitmap(bitmap))))
|
||||
|
||||
static inline int __check_is_bitmap(const unsigned long *bitmap)
|
||||
static __always_inline int __check_is_bitmap(const unsigned long *bitmap)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -1073,7 +1085,7 @@ static inline int __check_is_bitmap(const unsigned long *bitmap)
|
||||
extern const unsigned long
|
||||
cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)];
|
||||
|
||||
static inline const struct cpumask *get_cpu_mask(unsigned int cpu)
|
||||
static __always_inline const struct cpumask *get_cpu_mask(unsigned int cpu)
|
||||
{
|
||||
const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG];
|
||||
p -= cpu / BITS_PER_LONG;
|
||||
@@ -1100,32 +1112,32 @@ static __always_inline unsigned int num_online_cpus(void)
|
||||
#define num_present_cpus() cpumask_weight(cpu_present_mask)
|
||||
#define num_active_cpus() cpumask_weight(cpu_active_mask)
|
||||
|
||||
static inline bool cpu_online(unsigned int cpu)
|
||||
static __always_inline bool cpu_online(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_online_mask);
|
||||
}
|
||||
|
||||
static inline bool cpu_enabled(unsigned int cpu)
|
||||
static __always_inline bool cpu_enabled(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_enabled_mask);
|
||||
}
|
||||
|
||||
static inline bool cpu_possible(unsigned int cpu)
|
||||
static __always_inline bool cpu_possible(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_possible_mask);
|
||||
}
|
||||
|
||||
static inline bool cpu_present(unsigned int cpu)
|
||||
static __always_inline bool cpu_present(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_present_mask);
|
||||
}
|
||||
|
||||
static inline bool cpu_active(unsigned int cpu)
|
||||
static __always_inline bool cpu_active(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_active_mask);
|
||||
}
|
||||
|
||||
static inline bool cpu_dying(unsigned int cpu)
|
||||
static __always_inline bool cpu_dying(unsigned int cpu)
|
||||
{
|
||||
return cpumask_test_cpu(cpu, cpu_dying_mask);
|
||||
}
|
||||
@@ -1138,32 +1150,32 @@ static inline bool cpu_dying(unsigned int cpu)
|
||||
#define num_present_cpus() 1U
|
||||
#define num_active_cpus() 1U
|
||||
|
||||
static inline bool cpu_online(unsigned int cpu)
|
||||
static __always_inline bool cpu_online(unsigned int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static inline bool cpu_possible(unsigned int cpu)
|
||||
static __always_inline bool cpu_possible(unsigned int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static inline bool cpu_enabled(unsigned int cpu)
|
||||
static __always_inline bool cpu_enabled(unsigned int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static inline bool cpu_present(unsigned int cpu)
|
||||
static __always_inline bool cpu_present(unsigned int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static inline bool cpu_active(unsigned int cpu)
|
||||
static __always_inline bool cpu_active(unsigned int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static inline bool cpu_dying(unsigned int cpu)
|
||||
static __always_inline bool cpu_dying(unsigned int cpu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1197,7 +1209,7 @@ static inline bool cpu_dying(unsigned int cpu)
|
||||
* Return: the length of the (null-terminated) @buf string, zero if
|
||||
* nothing is copied.
|
||||
*/
|
||||
static inline ssize_t
|
||||
static __always_inline ssize_t
|
||||
cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask)
|
||||
{
|
||||
return bitmap_print_to_pagebuf(list, buf, cpumask_bits(mask),
|
||||
@@ -1220,9 +1232,9 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask)
|
||||
* Return: the length of how many bytes have been copied, excluding
|
||||
* terminating '\0'.
|
||||
*/
|
||||
static inline ssize_t
|
||||
cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask,
|
||||
loff_t off, size_t count)
|
||||
static __always_inline
|
||||
ssize_t cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
return bitmap_print_bitmask_to_buf(buf, cpumask_bits(mask),
|
||||
nr_cpu_ids, off, count) - 1;
|
||||
@@ -1242,9 +1254,9 @@ cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask,
|
||||
* Return: the length of how many bytes have been copied, excluding
|
||||
* terminating '\0'.
|
||||
*/
|
||||
static inline ssize_t
|
||||
cpumap_print_list_to_buf(char *buf, const struct cpumask *mask,
|
||||
loff_t off, size_t count)
|
||||
static __always_inline
|
||||
ssize_t cpumap_print_list_to_buf(char *buf, const struct cpumask *mask,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
return bitmap_print_list_to_buf(buf, cpumask_bits(mask),
|
||||
nr_cpu_ids, off, count) - 1;
|
||||
|
||||
@@ -524,7 +524,6 @@ int dm_post_suspending(struct dm_target *ti);
|
||||
int dm_noflush_suspending(struct dm_target *ti);
|
||||
void dm_accept_partial_bio(struct bio *bio, unsigned int n_sectors);
|
||||
void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone);
|
||||
union map_info *dm_get_rq_mapinfo(struct request *rq);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
struct dm_report_zones_args {
|
||||
|
||||
+25
-25
@@ -52,7 +52,7 @@ unsigned long _find_next_bit_le(const unsigned long *addr, unsigned
|
||||
* Returns the bit number for the next set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
|
||||
* Returns the bit number for the next set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_and_bit(const unsigned long *addr1,
|
||||
const unsigned long *addr2, unsigned long size,
|
||||
unsigned long offset)
|
||||
@@ -112,7 +112,7 @@ unsigned long find_next_and_bit(const unsigned long *addr1,
|
||||
* Returns the bit number for the next set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_andnot_bit(const unsigned long *addr1,
|
||||
const unsigned long *addr2, unsigned long size,
|
||||
unsigned long offset)
|
||||
@@ -142,7 +142,7 @@ unsigned long find_next_andnot_bit(const unsigned long *addr1,
|
||||
* Returns the bit number for the next set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_or_bit(const unsigned long *addr1,
|
||||
const unsigned long *addr2, unsigned long size,
|
||||
unsigned long offset)
|
||||
@@ -171,7 +171,7 @@ unsigned long find_next_or_bit(const unsigned long *addr1,
|
||||
* Returns the bit number of the next zero bit
|
||||
* If no bits are zero, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
@@ -198,7 +198,7 @@ unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
|
||||
* Returns the bit number of the first set bit.
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
|
||||
{
|
||||
if (small_const_nbits(size)) {
|
||||
@@ -224,7 +224,7 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
|
||||
* Returns the bit number of the N'th set bit.
|
||||
* If no such, returns >= @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n)
|
||||
{
|
||||
if (n >= size)
|
||||
@@ -249,7 +249,7 @@ unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsign
|
||||
* Returns the bit number of the N'th set bit.
|
||||
* If no such, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2,
|
||||
unsigned long size, unsigned long n)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long *
|
||||
* Returns the bit number of the N'th set bit.
|
||||
* If no such, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
|
||||
unsigned long size, unsigned long n)
|
||||
{
|
||||
@@ -332,7 +332,7 @@ unsigned long find_nth_and_andnot_bit(const unsigned long *addr1,
|
||||
* Returns the bit number for the next set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_first_and_bit(const unsigned long *addr1,
|
||||
const unsigned long *addr2,
|
||||
unsigned long size)
|
||||
@@ -357,7 +357,7 @@ unsigned long find_first_and_bit(const unsigned long *addr1,
|
||||
* Returns the bit number for the first set bit
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_first_and_and_bit(const unsigned long *addr1,
|
||||
const unsigned long *addr2,
|
||||
const unsigned long *addr3,
|
||||
@@ -381,7 +381,7 @@ unsigned long find_first_and_and_bit(const unsigned long *addr1,
|
||||
* Returns the bit number of the first cleared bit.
|
||||
* If no bits are zero, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
|
||||
{
|
||||
if (small_const_nbits(size)) {
|
||||
@@ -402,7 +402,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
|
||||
*
|
||||
* Returns the bit number of the last set bit, or size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
|
||||
{
|
||||
if (small_const_nbits(size)) {
|
||||
@@ -425,7 +425,7 @@ unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
|
||||
* Returns the bit number for the next set bit, or first set bit up to @offset
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_and_bit_wrap(const unsigned long *addr1,
|
||||
const unsigned long *addr2,
|
||||
unsigned long size, unsigned long offset)
|
||||
@@ -448,7 +448,7 @@ unsigned long find_next_and_bit_wrap(const unsigned long *addr1,
|
||||
* Returns the bit number for the next set bit, or first set bit up to @offset
|
||||
* If no bits are set, returns @size.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_bit_wrap(const unsigned long *addr,
|
||||
unsigned long size, unsigned long offset)
|
||||
{
|
||||
@@ -465,7 +465,7 @@ unsigned long find_next_bit_wrap(const unsigned long *addr,
|
||||
* Helper for for_each_set_bit_wrap(). Make sure you're doing right thing
|
||||
* before using it alone.
|
||||
*/
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long __for_each_wrap(const unsigned long *bitmap, unsigned long size,
|
||||
unsigned long start, unsigned long n)
|
||||
{
|
||||
@@ -506,20 +506,20 @@ extern unsigned long find_next_clump8(unsigned long *clump,
|
||||
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
|
||||
static inline unsigned long find_next_zero_bit_le(const void *addr,
|
||||
unsigned long size, unsigned long offset)
|
||||
static __always_inline
|
||||
unsigned long find_next_zero_bit_le(const void *addr, unsigned long size, unsigned long offset)
|
||||
{
|
||||
return find_next_zero_bit(addr, size, offset);
|
||||
}
|
||||
|
||||
static inline unsigned long find_next_bit_le(const void *addr,
|
||||
unsigned long size, unsigned long offset)
|
||||
static __always_inline
|
||||
unsigned long find_next_bit_le(const void *addr, unsigned long size, unsigned long offset)
|
||||
{
|
||||
return find_next_bit(addr, size, offset);
|
||||
}
|
||||
|
||||
static inline unsigned long find_first_zero_bit_le(const void *addr,
|
||||
unsigned long size)
|
||||
static __always_inline
|
||||
unsigned long find_first_zero_bit_le(const void *addr, unsigned long size)
|
||||
{
|
||||
return find_first_zero_bit(addr, size);
|
||||
}
|
||||
@@ -527,7 +527,7 @@ static inline unsigned long find_first_zero_bit_le(const void *addr,
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
|
||||
#ifndef find_next_zero_bit_le
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_zero_bit_le(const void *addr, unsigned
|
||||
long size, unsigned long offset)
|
||||
{
|
||||
@@ -546,7 +546,7 @@ unsigned long find_next_zero_bit_le(const void *addr, unsigned
|
||||
#endif
|
||||
|
||||
#ifndef find_first_zero_bit_le
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_first_zero_bit_le(const void *addr, unsigned long size)
|
||||
{
|
||||
if (small_const_nbits(size)) {
|
||||
@@ -560,7 +560,7 @@ unsigned long find_first_zero_bit_le(const void *addr, unsigned long size)
|
||||
#endif
|
||||
|
||||
#ifndef find_next_bit_le
|
||||
static inline
|
||||
static __always_inline
|
||||
unsigned long find_next_bit_le(const void *addr, unsigned
|
||||
long size, unsigned long offset)
|
||||
{
|
||||
|
||||
@@ -692,6 +692,9 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
|
||||
struct folio *alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
|
||||
nodemask_t *nmask, gfp_t gfp_mask,
|
||||
bool allow_alloc_fallback);
|
||||
struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
|
||||
nodemask_t *nmask, gfp_t gfp_mask);
|
||||
|
||||
int hugetlb_add_to_page_cache(struct folio *folio, struct address_space *mapping,
|
||||
pgoff_t idx);
|
||||
void restore_reserve_on_error(struct hstate *h, struct vm_area_struct *vma,
|
||||
@@ -1059,6 +1062,13 @@ static inline struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct folio *
|
||||
alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
|
||||
nodemask_t *nmask, gfp_t gfp_mask)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct folio *
|
||||
alloc_hugetlb_folio_nodemask(struct hstate *h, int preferred_nid,
|
||||
nodemask_t *nmask, gfp_t gfp_mask,
|
||||
|
||||
+43
-43
@@ -107,11 +107,11 @@ extern nodemask_t _unused_nodemask_arg_;
|
||||
*/
|
||||
#define nodemask_pr_args(maskp) __nodemask_pr_numnodes(maskp), \
|
||||
__nodemask_pr_bits(maskp)
|
||||
static inline unsigned int __nodemask_pr_numnodes(const nodemask_t *m)
|
||||
static __always_inline unsigned int __nodemask_pr_numnodes(const nodemask_t *m)
|
||||
{
|
||||
return m ? MAX_NUMNODES : 0;
|
||||
}
|
||||
static inline const unsigned long *__nodemask_pr_bits(const nodemask_t *m)
|
||||
static __always_inline const unsigned long *__nodemask_pr_bits(const nodemask_t *m)
|
||||
{
|
||||
return m ? m->bits : NULL;
|
||||
}
|
||||
@@ -132,19 +132,19 @@ static __always_inline void __node_set(int node, volatile nodemask_t *dstp)
|
||||
}
|
||||
|
||||
#define node_clear(node, dst) __node_clear((node), &(dst))
|
||||
static inline void __node_clear(int node, volatile nodemask_t *dstp)
|
||||
static __always_inline void __node_clear(int node, volatile nodemask_t *dstp)
|
||||
{
|
||||
clear_bit(node, dstp->bits);
|
||||
}
|
||||
|
||||
#define nodes_setall(dst) __nodes_setall(&(dst), MAX_NUMNODES)
|
||||
static inline void __nodes_setall(nodemask_t *dstp, unsigned int nbits)
|
||||
static __always_inline void __nodes_setall(nodemask_t *dstp, unsigned int nbits)
|
||||
{
|
||||
bitmap_fill(dstp->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodes_clear(dst) __nodes_clear(&(dst), MAX_NUMNODES)
|
||||
static inline void __nodes_clear(nodemask_t *dstp, unsigned int nbits)
|
||||
static __always_inline void __nodes_clear(nodemask_t *dstp, unsigned int nbits)
|
||||
{
|
||||
bitmap_zero(dstp->bits, nbits);
|
||||
}
|
||||
@@ -154,14 +154,14 @@ static inline void __nodes_clear(nodemask_t *dstp, unsigned int nbits)
|
||||
|
||||
#define node_test_and_set(node, nodemask) \
|
||||
__node_test_and_set((node), &(nodemask))
|
||||
static inline bool __node_test_and_set(int node, nodemask_t *addr)
|
||||
static __always_inline bool __node_test_and_set(int node, nodemask_t *addr)
|
||||
{
|
||||
return test_and_set_bit(node, addr->bits);
|
||||
}
|
||||
|
||||
#define nodes_and(dst, src1, src2) \
|
||||
__nodes_and(&(dst), &(src1), &(src2), MAX_NUMNODES)
|
||||
static inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
static __always_inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
|
||||
@@ -169,7 +169,7 @@ static inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
|
||||
#define nodes_or(dst, src1, src2) \
|
||||
__nodes_or(&(dst), &(src1), &(src2), MAX_NUMNODES)
|
||||
static inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
static __always_inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
|
||||
@@ -177,7 +177,7 @@ static inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
|
||||
#define nodes_xor(dst, src1, src2) \
|
||||
__nodes_xor(&(dst), &(src1), &(src2), MAX_NUMNODES)
|
||||
static inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
static __always_inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
|
||||
@@ -185,7 +185,7 @@ static inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
|
||||
#define nodes_andnot(dst, src1, src2) \
|
||||
__nodes_andnot(&(dst), &(src1), &(src2), MAX_NUMNODES)
|
||||
static inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
static __always_inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
|
||||
@@ -193,7 +193,7 @@ static inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p,
|
||||
|
||||
#define nodes_complement(dst, src) \
|
||||
__nodes_complement(&(dst), &(src), MAX_NUMNODES)
|
||||
static inline void __nodes_complement(nodemask_t *dstp,
|
||||
static __always_inline void __nodes_complement(nodemask_t *dstp,
|
||||
const nodemask_t *srcp, unsigned int nbits)
|
||||
{
|
||||
bitmap_complement(dstp->bits, srcp->bits, nbits);
|
||||
@@ -201,7 +201,7 @@ static inline void __nodes_complement(nodemask_t *dstp,
|
||||
|
||||
#define nodes_equal(src1, src2) \
|
||||
__nodes_equal(&(src1), &(src2), MAX_NUMNODES)
|
||||
static inline bool __nodes_equal(const nodemask_t *src1p,
|
||||
static __always_inline bool __nodes_equal(const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
return bitmap_equal(src1p->bits, src2p->bits, nbits);
|
||||
@@ -209,7 +209,7 @@ static inline bool __nodes_equal(const nodemask_t *src1p,
|
||||
|
||||
#define nodes_intersects(src1, src2) \
|
||||
__nodes_intersects(&(src1), &(src2), MAX_NUMNODES)
|
||||
static inline bool __nodes_intersects(const nodemask_t *src1p,
|
||||
static __always_inline bool __nodes_intersects(const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
return bitmap_intersects(src1p->bits, src2p->bits, nbits);
|
||||
@@ -217,33 +217,33 @@ static inline bool __nodes_intersects(const nodemask_t *src1p,
|
||||
|
||||
#define nodes_subset(src1, src2) \
|
||||
__nodes_subset(&(src1), &(src2), MAX_NUMNODES)
|
||||
static inline bool __nodes_subset(const nodemask_t *src1p,
|
||||
static __always_inline bool __nodes_subset(const nodemask_t *src1p,
|
||||
const nodemask_t *src2p, unsigned int nbits)
|
||||
{
|
||||
return bitmap_subset(src1p->bits, src2p->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodes_empty(src) __nodes_empty(&(src), MAX_NUMNODES)
|
||||
static inline bool __nodes_empty(const nodemask_t *srcp, unsigned int nbits)
|
||||
static __always_inline bool __nodes_empty(const nodemask_t *srcp, unsigned int nbits)
|
||||
{
|
||||
return bitmap_empty(srcp->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodes_full(nodemask) __nodes_full(&(nodemask), MAX_NUMNODES)
|
||||
static inline bool __nodes_full(const nodemask_t *srcp, unsigned int nbits)
|
||||
static __always_inline bool __nodes_full(const nodemask_t *srcp, unsigned int nbits)
|
||||
{
|
||||
return bitmap_full(srcp->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodes_weight(nodemask) __nodes_weight(&(nodemask), MAX_NUMNODES)
|
||||
static inline int __nodes_weight(const nodemask_t *srcp, unsigned int nbits)
|
||||
static __always_inline int __nodes_weight(const nodemask_t *srcp, unsigned int nbits)
|
||||
{
|
||||
return bitmap_weight(srcp->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodes_shift_right(dst, src, n) \
|
||||
__nodes_shift_right(&(dst), &(src), (n), MAX_NUMNODES)
|
||||
static inline void __nodes_shift_right(nodemask_t *dstp,
|
||||
static __always_inline void __nodes_shift_right(nodemask_t *dstp,
|
||||
const nodemask_t *srcp, int n, int nbits)
|
||||
{
|
||||
bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
|
||||
@@ -251,7 +251,7 @@ static inline void __nodes_shift_right(nodemask_t *dstp,
|
||||
|
||||
#define nodes_shift_left(dst, src, n) \
|
||||
__nodes_shift_left(&(dst), &(src), (n), MAX_NUMNODES)
|
||||
static inline void __nodes_shift_left(nodemask_t *dstp,
|
||||
static __always_inline void __nodes_shift_left(nodemask_t *dstp,
|
||||
const nodemask_t *srcp, int n, int nbits)
|
||||
{
|
||||
bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
|
||||
@@ -261,13 +261,13 @@ static inline void __nodes_shift_left(nodemask_t *dstp,
|
||||
> MAX_NUMNODES, then the silly min_ts could be dropped. */
|
||||
|
||||
#define first_node(src) __first_node(&(src))
|
||||
static inline unsigned int __first_node(const nodemask_t *srcp)
|
||||
static __always_inline unsigned int __first_node(const nodemask_t *srcp)
|
||||
{
|
||||
return min_t(unsigned int, MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES));
|
||||
}
|
||||
|
||||
#define next_node(n, src) __next_node((n), &(src))
|
||||
static inline unsigned int __next_node(int n, const nodemask_t *srcp)
|
||||
static __always_inline unsigned int __next_node(int n, const nodemask_t *srcp)
|
||||
{
|
||||
return min_t(unsigned int, MAX_NUMNODES, find_next_bit(srcp->bits, MAX_NUMNODES, n+1));
|
||||
}
|
||||
@@ -277,7 +277,7 @@ static inline unsigned int __next_node(int n, const nodemask_t *srcp)
|
||||
* the first node in src if needed. Returns MAX_NUMNODES if src is empty.
|
||||
*/
|
||||
#define next_node_in(n, src) __next_node_in((n), &(src))
|
||||
static inline unsigned int __next_node_in(int node, const nodemask_t *srcp)
|
||||
static __always_inline unsigned int __next_node_in(int node, const nodemask_t *srcp)
|
||||
{
|
||||
unsigned int ret = __next_node(node, srcp);
|
||||
|
||||
@@ -286,7 +286,7 @@ static inline unsigned int __next_node_in(int node, const nodemask_t *srcp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void init_nodemask_of_node(nodemask_t *mask, int node)
|
||||
static __always_inline void init_nodemask_of_node(nodemask_t *mask, int node)
|
||||
{
|
||||
nodes_clear(*mask);
|
||||
node_set(node, *mask);
|
||||
@@ -304,7 +304,7 @@ static inline void init_nodemask_of_node(nodemask_t *mask, int node)
|
||||
})
|
||||
|
||||
#define first_unset_node(mask) __first_unset_node(&(mask))
|
||||
static inline unsigned int __first_unset_node(const nodemask_t *maskp)
|
||||
static __always_inline unsigned int __first_unset_node(const nodemask_t *maskp)
|
||||
{
|
||||
return min_t(unsigned int, MAX_NUMNODES,
|
||||
find_first_zero_bit(maskp->bits, MAX_NUMNODES));
|
||||
@@ -338,21 +338,21 @@ static inline unsigned int __first_unset_node(const nodemask_t *maskp)
|
||||
|
||||
#define nodemask_parse_user(ubuf, ulen, dst) \
|
||||
__nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES)
|
||||
static inline int __nodemask_parse_user(const char __user *buf, int len,
|
||||
static __always_inline int __nodemask_parse_user(const char __user *buf, int len,
|
||||
nodemask_t *dstp, int nbits)
|
||||
{
|
||||
return bitmap_parse_user(buf, len, dstp->bits, nbits);
|
||||
}
|
||||
|
||||
#define nodelist_parse(buf, dst) __nodelist_parse((buf), &(dst), MAX_NUMNODES)
|
||||
static inline int __nodelist_parse(const char *buf, nodemask_t *dstp, int nbits)
|
||||
static __always_inline int __nodelist_parse(const char *buf, nodemask_t *dstp, int nbits)
|
||||
{
|
||||
return bitmap_parselist(buf, dstp->bits, nbits);
|
||||
}
|
||||
|
||||
#define node_remap(oldbit, old, new) \
|
||||
__node_remap((oldbit), &(old), &(new), MAX_NUMNODES)
|
||||
static inline int __node_remap(int oldbit,
|
||||
static __always_inline int __node_remap(int oldbit,
|
||||
const nodemask_t *oldp, const nodemask_t *newp, int nbits)
|
||||
{
|
||||
return bitmap_bitremap(oldbit, oldp->bits, newp->bits, nbits);
|
||||
@@ -360,7 +360,7 @@ static inline int __node_remap(int oldbit,
|
||||
|
||||
#define nodes_remap(dst, src, old, new) \
|
||||
__nodes_remap(&(dst), &(src), &(old), &(new), MAX_NUMNODES)
|
||||
static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,
|
||||
static __always_inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,
|
||||
const nodemask_t *oldp, const nodemask_t *newp, int nbits)
|
||||
{
|
||||
bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits);
|
||||
@@ -368,7 +368,7 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,
|
||||
|
||||
#define nodes_onto(dst, orig, relmap) \
|
||||
__nodes_onto(&(dst), &(orig), &(relmap), MAX_NUMNODES)
|
||||
static inline void __nodes_onto(nodemask_t *dstp, const nodemask_t *origp,
|
||||
static __always_inline void __nodes_onto(nodemask_t *dstp, const nodemask_t *origp,
|
||||
const nodemask_t *relmapp, int nbits)
|
||||
{
|
||||
bitmap_onto(dstp->bits, origp->bits, relmapp->bits, nbits);
|
||||
@@ -376,7 +376,7 @@ static inline void __nodes_onto(nodemask_t *dstp, const nodemask_t *origp,
|
||||
|
||||
#define nodes_fold(dst, orig, sz) \
|
||||
__nodes_fold(&(dst), &(orig), sz, MAX_NUMNODES)
|
||||
static inline void __nodes_fold(nodemask_t *dstp, const nodemask_t *origp,
|
||||
static __always_inline void __nodes_fold(nodemask_t *dstp, const nodemask_t *origp,
|
||||
int sz, int nbits)
|
||||
{
|
||||
bitmap_fold(dstp->bits, origp->bits, sz, nbits);
|
||||
@@ -418,22 +418,22 @@ enum node_states {
|
||||
extern nodemask_t node_states[NR_NODE_STATES];
|
||||
|
||||
#if MAX_NUMNODES > 1
|
||||
static inline int node_state(int node, enum node_states state)
|
||||
static __always_inline int node_state(int node, enum node_states state)
|
||||
{
|
||||
return node_isset(node, node_states[state]);
|
||||
}
|
||||
|
||||
static inline void node_set_state(int node, enum node_states state)
|
||||
static __always_inline void node_set_state(int node, enum node_states state)
|
||||
{
|
||||
__node_set(node, &node_states[state]);
|
||||
}
|
||||
|
||||
static inline void node_clear_state(int node, enum node_states state)
|
||||
static __always_inline void node_clear_state(int node, enum node_states state)
|
||||
{
|
||||
__node_clear(node, &node_states[state]);
|
||||
}
|
||||
|
||||
static inline int num_node_state(enum node_states state)
|
||||
static __always_inline int num_node_state(enum node_states state)
|
||||
{
|
||||
return nodes_weight(node_states[state]);
|
||||
}
|
||||
@@ -443,11 +443,11 @@ static inline int num_node_state(enum node_states state)
|
||||
|
||||
#define first_online_node first_node(node_states[N_ONLINE])
|
||||
#define first_memory_node first_node(node_states[N_MEMORY])
|
||||
static inline unsigned int next_online_node(int nid)
|
||||
static __always_inline unsigned int next_online_node(int nid)
|
||||
{
|
||||
return next_node(nid, node_states[N_ONLINE]);
|
||||
}
|
||||
static inline unsigned int next_memory_node(int nid)
|
||||
static __always_inline unsigned int next_memory_node(int nid)
|
||||
{
|
||||
return next_node(nid, node_states[N_MEMORY]);
|
||||
}
|
||||
@@ -455,13 +455,13 @@ static inline unsigned int next_memory_node(int nid)
|
||||
extern unsigned int nr_node_ids;
|
||||
extern unsigned int nr_online_nodes;
|
||||
|
||||
static inline void node_set_online(int nid)
|
||||
static __always_inline void node_set_online(int nid)
|
||||
{
|
||||
node_set_state(nid, N_ONLINE);
|
||||
nr_online_nodes = num_node_state(N_ONLINE);
|
||||
}
|
||||
|
||||
static inline void node_set_offline(int nid)
|
||||
static __always_inline void node_set_offline(int nid)
|
||||
{
|
||||
node_clear_state(nid, N_ONLINE);
|
||||
nr_online_nodes = num_node_state(N_ONLINE);
|
||||
@@ -469,20 +469,20 @@ static inline void node_set_offline(int nid)
|
||||
|
||||
#else
|
||||
|
||||
static inline int node_state(int node, enum node_states state)
|
||||
static __always_inline int node_state(int node, enum node_states state)
|
||||
{
|
||||
return node == 0;
|
||||
}
|
||||
|
||||
static inline void node_set_state(int node, enum node_states state)
|
||||
static __always_inline void node_set_state(int node, enum node_states state)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void node_clear_state(int node, enum node_states state)
|
||||
static __always_inline void node_clear_state(int node, enum node_states state)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int num_node_state(enum node_states state)
|
||||
static __always_inline int num_node_state(enum node_states state)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -502,7 +502,7 @@ static inline int num_node_state(enum node_states state)
|
||||
|
||||
#endif
|
||||
|
||||
static inline int node_random(const nodemask_t *maskp)
|
||||
static __always_inline int node_random(const nodemask_t *maskp)
|
||||
{
|
||||
#if defined(CONFIG_NUMA) && (MAX_NUMNODES > 1)
|
||||
int w, bit;
|
||||
|
||||
@@ -12,4 +12,7 @@
|
||||
(((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \
|
||||
(~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h))))
|
||||
|
||||
#define __GENMASK_U128(h, l) \
|
||||
((_BIT128((h)) << 1) - (_BIT128(l)))
|
||||
|
||||
#endif /* _UAPI_LINUX_BITS_H */
|
||||
|
||||
@@ -28,6 +28,23 @@
|
||||
#define _BITUL(x) (_UL(1) << (x))
|
||||
#define _BITULL(x) (_ULL(1) << (x))
|
||||
|
||||
#if !defined(__ASSEMBLY__)
|
||||
/*
|
||||
* Missing asm support
|
||||
*
|
||||
* __BIT128() would not work in the asm code, as it shifts an
|
||||
* 'unsigned __init128' data type as direct representation of
|
||||
* 128 bit constants is not supported in the gcc compiler, as
|
||||
* they get silently truncated.
|
||||
*
|
||||
* TODO: Please revisit this implementation when gcc compiler
|
||||
* starts representing 128 bit constants directly like long
|
||||
* and unsigned long etc. Subsequently drop the comment for
|
||||
* GENMASK_U128() which would then start supporting asm code.
|
||||
*/
|
||||
#define _BIT128(x) ((unsigned __int128)(1) << (x))
|
||||
#endif
|
||||
|
||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
|
||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user