Merge tag 'v6.12-rc5' into android-mainline
Linux 6.12-rc5 Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: Ie9f51e6441eda54ae6a21cad31da6edecae7e349
This commit is contained in:
@@ -306,6 +306,11 @@ Jens Axboe <axboe@kernel.dk> <axboe@fb.com>
|
||||
Jens Axboe <axboe@kernel.dk> <axboe@meta.com>
|
||||
Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
|
||||
Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <brouer@redhat.com>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <hawk@comx.dk>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <jbrouer@redhat.com>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <jdb@comx.dk>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <netoptimizer@brouer.com>
|
||||
Jessica Zhang <quic_jesszhan@quicinc.com> <jesszhan@codeaurora.org>
|
||||
Jilai Wang <quic_jilaiw@quicinc.com> <jilaiw@codeaurora.org>
|
||||
Jiri Kosina <jikos@kernel.org> <jikos@jikos.cz>
|
||||
|
||||
@@ -425,8 +425,8 @@ This governor exposes only one tunable:
|
||||
|
||||
``rate_limit_us``
|
||||
Minimum time (in microseconds) that has to pass between two consecutive
|
||||
runs of governor computations (default: 1000 times the scaling driver's
|
||||
transition latency).
|
||||
runs of governor computations (default: 1.5 times the scaling driver's
|
||||
transition latency or the maximum 2ms).
|
||||
|
||||
The purpose of this tunable is to reduce the scheduler context overhead
|
||||
of the governor which might be excessive without it.
|
||||
@@ -474,17 +474,17 @@ This governor exposes the following tunables:
|
||||
This is how often the governor's worker routine should run, in
|
||||
microseconds.
|
||||
|
||||
Typically, it is set to values of the order of 10000 (10 ms). Its
|
||||
default value is equal to the value of ``cpuinfo_transition_latency``
|
||||
for each policy this governor is attached to (but since the unit here
|
||||
is greater by 1000, this means that the time represented by
|
||||
``sampling_rate`` is 1000 times greater than the transition latency by
|
||||
default).
|
||||
Typically, it is set to values of the order of 2000 (2 ms). Its
|
||||
default value is to add a 50% breathing room
|
||||
to ``cpuinfo_transition_latency`` on each policy this governor is
|
||||
attached to. The minimum is typically the length of two scheduler
|
||||
ticks.
|
||||
|
||||
If this tunable is per-policy, the following shell command sets the time
|
||||
represented by it to be 750 times as high as the transition latency::
|
||||
represented by it to be 1.5 times as high as the transition latency
|
||||
(the default)::
|
||||
|
||||
# echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) > ondemand/sampling_rate
|
||||
# echo `$(($(cat cpuinfo_transition_latency) * 3 / 2)) > ondemand/sampling_rate
|
||||
|
||||
``up_threshold``
|
||||
If the estimated CPU load is above this value (in percent), the governor
|
||||
|
||||
@@ -102,21 +102,21 @@ properties:
|
||||
default: 2
|
||||
|
||||
interrupts:
|
||||
oneOf:
|
||||
- minItems: 1
|
||||
items:
|
||||
- description: TX interrupt
|
||||
- description: RX interrupt
|
||||
- items:
|
||||
- description: common/combined interrupt
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
oneOf:
|
||||
- minItems: 1
|
||||
- description: TX interrupt
|
||||
const: tx
|
||||
- description: RX interrupt
|
||||
const: rx
|
||||
- description: TX and RX interrupts
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
- const: common
|
||||
- description: Common/combined interrupt
|
||||
const: common
|
||||
|
||||
fck_parent:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
|
||||
@@ -592,4 +592,3 @@ API Function Reference
|
||||
|
||||
.. kernel-doc:: include/linux/netfs.h
|
||||
.. kernel-doc:: fs/netfs/buffered_read.c
|
||||
.. kernel-doc:: fs/netfs/io.c
|
||||
|
||||
@@ -8098,13 +8098,15 @@ KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS By default, KVM emulates MONITOR/MWAIT (if
|
||||
KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is
|
||||
disabled.
|
||||
|
||||
KVM_X86_QUIRK_SLOT_ZAP_ALL By default, KVM invalidates all SPTEs in
|
||||
fast way for memslot deletion when VM type
|
||||
is KVM_X86_DEFAULT_VM.
|
||||
When this quirk is disabled or when VM type
|
||||
is other than KVM_X86_DEFAULT_VM, KVM zaps
|
||||
only leaf SPTEs that are within the range of
|
||||
the memslot being deleted.
|
||||
KVM_X86_QUIRK_SLOT_ZAP_ALL By default, for KVM_X86_DEFAULT_VM VMs, KVM
|
||||
invalidates all SPTEs in all memslots and
|
||||
address spaces when a memslot is deleted or
|
||||
moved. When this quirk is disabled (or the
|
||||
VM type isn't KVM_X86_DEFAULT_VM), KVM only
|
||||
ensures the backing memory of the deleted
|
||||
or moved memslot isn't reachable, i.e KVM
|
||||
_may_ invalidate only SPTEs related to the
|
||||
memslot.
|
||||
=================================== ============================================
|
||||
|
||||
7.32 KVM_CAP_MAX_VCPU_ID
|
||||
|
||||
@@ -136,7 +136,7 @@ For direct sp, we can easily avoid it since the spte of direct sp is fixed
|
||||
to gfn. For indirect sp, we disabled fast page fault for simplicity.
|
||||
|
||||
A solution for indirect sp could be to pin the gfn, for example via
|
||||
kvm_vcpu_gfn_to_pfn_atomic, before the cmpxchg. After the pinning:
|
||||
gfn_to_pfn_memslot_atomic, before the cmpxchg. After the pinning:
|
||||
|
||||
- We have held the refcount of pfn; that means the pfn can not be freed and
|
||||
be reused for another gfn.
|
||||
|
||||
+7
-1
@@ -9723,6 +9723,7 @@ F: include/dt-bindings/gpio/
|
||||
F: include/linux/gpio.h
|
||||
F: include/linux/gpio/
|
||||
F: include/linux/of_gpio.h
|
||||
K: (devm_)?gpio_(request|free|direction|get|set)
|
||||
|
||||
GPIO UAPI
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
@@ -14993,6 +14994,7 @@ F: drivers/spi/spi-at91-usart.c
|
||||
|
||||
MICROCHIP AUDIO ASOC DRIVERS
|
||||
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
|
||||
M: Andrei Simion <andrei.simion@microchip.com>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/sound/atmel*
|
||||
@@ -15101,6 +15103,7 @@ F: include/video/atmel_lcdc.h
|
||||
|
||||
MICROCHIP MCP16502 PMIC DRIVER
|
||||
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
|
||||
M: Andrei Simion <andrei.simion@microchip.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/regulator/microchip,mcp16502.yaml
|
||||
@@ -15231,6 +15234,7 @@ F: drivers/spi/spi-atmel.*
|
||||
|
||||
MICROCHIP SSC DRIVER
|
||||
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
|
||||
M: Andrei Simion <andrei.simion@microchip.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/misc/atmel-ssc.txt
|
||||
@@ -16049,6 +16053,7 @@ M: "David S. Miller" <davem@davemloft.net>
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Jakub Kicinski <kuba@kernel.org>
|
||||
M: Paolo Abeni <pabeni@redhat.com>
|
||||
R: Simon Horman <horms@kernel.org>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
P: Documentation/process/maintainer-netdev.rst
|
||||
@@ -16091,6 +16096,7 @@ F: include/uapi/linux/rtnetlink.h
|
||||
F: lib/net_utils.c
|
||||
F: lib/random32.c
|
||||
F: net/
|
||||
F: samples/pktgen/
|
||||
F: tools/net/
|
||||
F: tools/testing/selftests/net/
|
||||
X: Documentation/networking/mac80211-injection.rst
|
||||
@@ -23150,7 +23156,7 @@ F: Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml
|
||||
F: drivers/iio/adc/ti-lmp92064.c
|
||||
|
||||
TI PCM3060 ASoC CODEC DRIVER
|
||||
M: Kirill Marinushkin <kmarinushkin@birdec.com>
|
||||
M: Kirill Marinushkin <k.marinushkin@gmail.com>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/pcm3060.txt
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 12
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -178,6 +178,7 @@ struct kvm_nvhe_init_params {
|
||||
unsigned long hcr_el2;
|
||||
unsigned long vttbr;
|
||||
unsigned long vtcr;
|
||||
unsigned long tmp;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#define KVM_REQ_RELOAD_PMU KVM_ARCH_REQ(5)
|
||||
#define KVM_REQ_SUSPEND KVM_ARCH_REQ(6)
|
||||
#define KVM_REQ_RESYNC_PMU_EL0 KVM_ARCH_REQ(7)
|
||||
#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
|
||||
|
||||
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
|
||||
KVM_DIRTY_LOG_INITIALLY_SET)
|
||||
@@ -211,6 +212,12 @@ struct kvm_s2_mmu {
|
||||
*/
|
||||
bool nested_stage2_enabled;
|
||||
|
||||
/*
|
||||
* true when this MMU needs to be unmapped before being used for a new
|
||||
* purpose.
|
||||
*/
|
||||
bool pending_unmap;
|
||||
|
||||
/*
|
||||
* 0: Nobody is currently using this, check vttbr for validity
|
||||
* >0: Somebody is actively using this.
|
||||
|
||||
@@ -166,7 +166,8 @@ int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
|
||||
int create_hyp_stack(phys_addr_t phys_addr, unsigned long *haddr);
|
||||
void __init free_hyp_pgds(void);
|
||||
|
||||
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size);
|
||||
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
|
||||
u64 size, bool may_block);
|
||||
void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end);
|
||||
void kvm_stage2_wp_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end);
|
||||
|
||||
|
||||
@@ -78,6 +78,8 @@ extern void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
|
||||
extern void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu);
|
||||
|
||||
extern void check_nested_vcpu_requests(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_s2_trans {
|
||||
phys_addr_t output;
|
||||
unsigned long block_size;
|
||||
@@ -124,7 +126,7 @@ extern int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu,
|
||||
struct kvm_s2_trans *trans);
|
||||
extern int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2);
|
||||
extern void kvm_nested_s2_wp(struct kvm *kvm);
|
||||
extern void kvm_nested_s2_unmap(struct kvm *kvm);
|
||||
extern void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block);
|
||||
extern void kvm_nested_s2_flush(struct kvm *kvm);
|
||||
|
||||
unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val);
|
||||
|
||||
@@ -146,6 +146,7 @@ int main(void)
|
||||
DEFINE(NVHE_INIT_HCR_EL2, offsetof(struct kvm_nvhe_init_params, hcr_el2));
|
||||
DEFINE(NVHE_INIT_VTTBR, offsetof(struct kvm_nvhe_init_params, vttbr));
|
||||
DEFINE(NVHE_INIT_VTCR, offsetof(struct kvm_nvhe_init_params, vtcr));
|
||||
DEFINE(NVHE_INIT_TMP, offsetof(struct kvm_nvhe_init_params, tmp));
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_PM
|
||||
DEFINE(CPU_CTX_SP, offsetof(struct cpu_suspend_ctx, sp));
|
||||
|
||||
@@ -997,6 +997,9 @@ static int kvm_vcpu_suspend(struct kvm_vcpu *vcpu)
|
||||
static int check_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_request_pending(vcpu)) {
|
||||
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu))
|
||||
return -EIO;
|
||||
|
||||
if (kvm_check_request(KVM_REQ_SLEEP, vcpu))
|
||||
kvm_vcpu_sleep(vcpu);
|
||||
|
||||
@@ -1031,6 +1034,8 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (kvm_dirty_ring_check_request(vcpu))
|
||||
return 0;
|
||||
|
||||
check_nested_vcpu_requests(vcpu);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -24,28 +24,25 @@
|
||||
.align 11
|
||||
|
||||
SYM_CODE_START(__kvm_hyp_init)
|
||||
ventry __invalid // Synchronous EL2t
|
||||
ventry __invalid // IRQ EL2t
|
||||
ventry __invalid // FIQ EL2t
|
||||
ventry __invalid // Error EL2t
|
||||
ventry . // Synchronous EL2t
|
||||
ventry . // IRQ EL2t
|
||||
ventry . // FIQ EL2t
|
||||
ventry . // Error EL2t
|
||||
|
||||
ventry __invalid // Synchronous EL2h
|
||||
ventry __invalid // IRQ EL2h
|
||||
ventry __invalid // FIQ EL2h
|
||||
ventry __invalid // Error EL2h
|
||||
ventry . // Synchronous EL2h
|
||||
ventry . // IRQ EL2h
|
||||
ventry . // FIQ EL2h
|
||||
ventry . // Error EL2h
|
||||
|
||||
ventry __do_hyp_init // Synchronous 64-bit EL1
|
||||
ventry __invalid // IRQ 64-bit EL1
|
||||
ventry __invalid // FIQ 64-bit EL1
|
||||
ventry __invalid // Error 64-bit EL1
|
||||
ventry . // IRQ 64-bit EL1
|
||||
ventry . // FIQ 64-bit EL1
|
||||
ventry . // Error 64-bit EL1
|
||||
|
||||
ventry __invalid // Synchronous 32-bit EL1
|
||||
ventry __invalid // IRQ 32-bit EL1
|
||||
ventry __invalid // FIQ 32-bit EL1
|
||||
ventry __invalid // Error 32-bit EL1
|
||||
|
||||
__invalid:
|
||||
b .
|
||||
ventry . // Synchronous 32-bit EL1
|
||||
ventry . // IRQ 32-bit EL1
|
||||
ventry . // FIQ 32-bit EL1
|
||||
ventry . // Error 32-bit EL1
|
||||
|
||||
/*
|
||||
* Only uses x0..x3 so as to not clobber callee-saved SMCCC registers.
|
||||
@@ -76,6 +73,13 @@ __do_hyp_init:
|
||||
eret
|
||||
SYM_CODE_END(__kvm_hyp_init)
|
||||
|
||||
SYM_CODE_START_LOCAL(__kvm_init_el2_state)
|
||||
/* Initialize EL2 CPU state to sane values. */
|
||||
init_el2_state // Clobbers x0..x2
|
||||
finalise_el2_state
|
||||
ret
|
||||
SYM_CODE_END(__kvm_init_el2_state)
|
||||
|
||||
/*
|
||||
* Initialize the hypervisor in EL2.
|
||||
*
|
||||
@@ -102,9 +106,12 @@ SYM_CODE_START_LOCAL(___kvm_hyp_init)
|
||||
// TPIDR_EL2 is used to preserve x0 across the macro maze...
|
||||
isb
|
||||
msr tpidr_el2, x0
|
||||
init_el2_state
|
||||
finalise_el2_state
|
||||
str lr, [x0, #NVHE_INIT_TMP]
|
||||
|
||||
bl __kvm_init_el2_state
|
||||
|
||||
mrs x0, tpidr_el2
|
||||
ldr lr, [x0, #NVHE_INIT_TMP]
|
||||
|
||||
1:
|
||||
ldr x1, [x0, #NVHE_INIT_TPIDR_EL2]
|
||||
@@ -199,9 +206,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
|
||||
|
||||
2: msr SPsel, #1 // We want to use SP_EL{1,2}
|
||||
|
||||
/* Initialize EL2 CPU state to sane values. */
|
||||
init_el2_state // Clobbers x0..x2
|
||||
finalise_el2_state
|
||||
bl __kvm_init_el2_state
|
||||
|
||||
__init_el2_nvhe_prepare_eret
|
||||
|
||||
/* Enable MMU, set vectors and stack. */
|
||||
|
||||
@@ -317,7 +317,7 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
|
||||
* to the guest, and hide SSBS so that the
|
||||
* guest stays protected.
|
||||
*/
|
||||
if (cpus_have_final_cap(ARM64_SSBS))
|
||||
if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SSBS, IMP))
|
||||
break;
|
||||
fallthrough;
|
||||
case SPECTRE_UNAFFECTED:
|
||||
@@ -428,7 +428,7 @@ int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
* Convert the workaround level into an easy-to-compare number, where higher
|
||||
* values mean better protection.
|
||||
*/
|
||||
static int get_kernel_wa_level(u64 regid)
|
||||
static int get_kernel_wa_level(struct kvm_vcpu *vcpu, u64 regid)
|
||||
{
|
||||
switch (regid) {
|
||||
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
|
||||
@@ -449,7 +449,7 @@ static int get_kernel_wa_level(u64 regid)
|
||||
* don't have any FW mitigation if SSBS is there at
|
||||
* all times.
|
||||
*/
|
||||
if (cpus_have_final_cap(ARM64_SSBS))
|
||||
if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SSBS, IMP))
|
||||
return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
|
||||
fallthrough;
|
||||
case SPECTRE_UNAFFECTED:
|
||||
@@ -486,7 +486,7 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
|
||||
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
|
||||
case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
|
||||
val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
|
||||
val = get_kernel_wa_level(vcpu, reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
|
||||
break;
|
||||
case KVM_REG_ARM_STD_BMAP:
|
||||
val = READ_ONCE(smccc_feat->std_bmap);
|
||||
@@ -588,7 +588,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_kernel_wa_level(reg->id) < val)
|
||||
if (get_kernel_wa_level(vcpu, reg->id) < val)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -624,7 +624,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||
* We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
|
||||
* other way around.
|
||||
*/
|
||||
if (get_kernel_wa_level(reg->id) < wa_level)
|
||||
if (get_kernel_wa_level(vcpu, reg->id) < wa_level)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -328,9 +328,10 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64
|
||||
may_block));
|
||||
}
|
||||
|
||||
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size)
|
||||
void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
|
||||
u64 size, bool may_block)
|
||||
{
|
||||
__unmap_stage2_range(mmu, start, size, true);
|
||||
__unmap_stage2_range(mmu, start, size, may_block);
|
||||
}
|
||||
|
||||
void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys_addr_t end)
|
||||
@@ -1015,7 +1016,7 @@ static void stage2_unmap_memslot(struct kvm *kvm,
|
||||
|
||||
if (!(vma->vm_flags & VM_PFNMAP)) {
|
||||
gpa_t gpa = addr + (vm_start - memslot->userspace_addr);
|
||||
kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, vm_end - vm_start);
|
||||
kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, vm_end - vm_start, true);
|
||||
}
|
||||
hva = vm_end;
|
||||
} while (hva < reg_end);
|
||||
@@ -1042,7 +1043,7 @@ void stage2_unmap_vm(struct kvm *kvm)
|
||||
kvm_for_each_memslot(memslot, bkt, slots)
|
||||
stage2_unmap_memslot(kvm, memslot);
|
||||
|
||||
kvm_nested_s2_unmap(kvm);
|
||||
kvm_nested_s2_unmap(kvm, true);
|
||||
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
mmap_read_unlock(current->mm);
|
||||
@@ -1912,7 +1913,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
|
||||
(range->end - range->start) << PAGE_SHIFT,
|
||||
range->may_block);
|
||||
|
||||
kvm_nested_s2_unmap(kvm);
|
||||
kvm_nested_s2_unmap(kvm, range->may_block);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2179,8 +2180,8 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
|
||||
phys_addr_t size = slot->npages << PAGE_SHIFT;
|
||||
|
||||
write_lock(&kvm->mmu_lock);
|
||||
kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, size);
|
||||
kvm_nested_s2_unmap(kvm);
|
||||
kvm_stage2_unmap_range(&kvm->arch.mmu, gpa, size, true);
|
||||
kvm_nested_s2_unmap(kvm, true);
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
}
|
||||
|
||||
|
||||
+46
-7
@@ -632,9 +632,9 @@ static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu)
|
||||
/* Set the scene for the next search */
|
||||
kvm->arch.nested_mmus_next = (i + 1) % kvm->arch.nested_mmus_size;
|
||||
|
||||
/* Clear the old state */
|
||||
/* Make sure we don't forget to do the laundry */
|
||||
if (kvm_s2_mmu_valid(s2_mmu))
|
||||
kvm_stage2_unmap_range(s2_mmu, 0, kvm_phys_size(s2_mmu));
|
||||
s2_mmu->pending_unmap = true;
|
||||
|
||||
/*
|
||||
* The virtual VMID (modulo CnP) will be used as a key when matching
|
||||
@@ -650,6 +650,16 @@ static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu)
|
||||
|
||||
out:
|
||||
atomic_inc(&s2_mmu->refcnt);
|
||||
|
||||
/*
|
||||
* Set the vCPU request to perform an unmap, even if the pending unmap
|
||||
* originates from another vCPU. This guarantees that the MMU has been
|
||||
* completely unmapped before any vCPU actually uses it, and allows
|
||||
* multiple vCPUs to lend a hand with completing the unmap.
|
||||
*/
|
||||
if (s2_mmu->pending_unmap)
|
||||
kvm_make_request(KVM_REQ_NESTED_S2_UNMAP, vcpu);
|
||||
|
||||
return s2_mmu;
|
||||
}
|
||||
|
||||
@@ -663,6 +673,13 @@ void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu)
|
||||
|
||||
void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* The vCPU kept its reference on the MMU after the last put, keep
|
||||
* rolling with it.
|
||||
*/
|
||||
if (vcpu->arch.hw_mmu)
|
||||
return;
|
||||
|
||||
if (is_hyp_ctxt(vcpu)) {
|
||||
vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
|
||||
} else {
|
||||
@@ -674,10 +691,18 @@ void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu)
|
||||
|
||||
void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_is_nested_s2_mmu(vcpu->kvm, vcpu->arch.hw_mmu)) {
|
||||
/*
|
||||
* Keep a reference on the associated stage-2 MMU if the vCPU is
|
||||
* scheduling out and not in WFI emulation, suggesting it is likely to
|
||||
* reuse the MMU sometime soon.
|
||||
*/
|
||||
if (vcpu->scheduled_out && !vcpu_get_flag(vcpu, IN_WFI))
|
||||
return;
|
||||
|
||||
if (kvm_is_nested_s2_mmu(vcpu->kvm, vcpu->arch.hw_mmu))
|
||||
atomic_dec(&vcpu->arch.hw_mmu->refcnt);
|
||||
vcpu->arch.hw_mmu = NULL;
|
||||
}
|
||||
|
||||
vcpu->arch.hw_mmu = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -730,7 +755,7 @@ void kvm_nested_s2_wp(struct kvm *kvm)
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_nested_s2_unmap(struct kvm *kvm)
|
||||
void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -740,7 +765,7 @@ void kvm_nested_s2_unmap(struct kvm *kvm)
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
|
||||
if (kvm_s2_mmu_valid(mmu))
|
||||
kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu));
|
||||
kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1184,3 +1209,17 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void check_nested_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_check_request(KVM_REQ_NESTED_S2_UNMAP, vcpu)) {
|
||||
struct kvm_s2_mmu *mmu = vcpu->arch.hw_mmu;
|
||||
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
if (mmu->pending_unmap) {
|
||||
kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), true);
|
||||
mmu->pending_unmap = false;
|
||||
}
|
||||
write_unlock(&vcpu->kvm->mmu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1527,6 +1527,14 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
|
||||
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RNDR_trap);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_GCS);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_THE);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_DF2);
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR);
|
||||
break;
|
||||
case SYS_ID_AA64PFR2_EL1:
|
||||
/* We only expose FPMR */
|
||||
@@ -1550,7 +1558,8 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
|
||||
val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
|
||||
break;
|
||||
case SYS_ID_AA64MMFR3_EL1:
|
||||
val &= ID_AA64MMFR3_EL1_TCRX | ID_AA64MMFR3_EL1_S1POE;
|
||||
val &= ID_AA64MMFR3_EL1_TCRX | ID_AA64MMFR3_EL1_S1POE |
|
||||
ID_AA64MMFR3_EL1_S1PIE;
|
||||
break;
|
||||
case SYS_ID_MMFR4_EL1:
|
||||
val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX);
|
||||
@@ -1985,7 +1994,7 @@ static u64 reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
|
||||
* one cache line.
|
||||
*/
|
||||
if (kvm_has_mte(vcpu->kvm))
|
||||
clidr |= 2 << CLIDR_TTYPE_SHIFT(loc);
|
||||
clidr |= 2ULL << CLIDR_TTYPE_SHIFT(loc);
|
||||
|
||||
__vcpu_sys_reg(vcpu, r->reg) = clidr;
|
||||
|
||||
@@ -2376,7 +2385,19 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
ID_AA64PFR0_EL1_RAS |
|
||||
ID_AA64PFR0_EL1_AdvSIMD |
|
||||
ID_AA64PFR0_EL1_FP), },
|
||||
ID_SANITISED(ID_AA64PFR1_EL1),
|
||||
ID_WRITABLE(ID_AA64PFR1_EL1, ~(ID_AA64PFR1_EL1_PFAR |
|
||||
ID_AA64PFR1_EL1_DF2 |
|
||||
ID_AA64PFR1_EL1_MTEX |
|
||||
ID_AA64PFR1_EL1_THE |
|
||||
ID_AA64PFR1_EL1_GCS |
|
||||
ID_AA64PFR1_EL1_MTE_frac |
|
||||
ID_AA64PFR1_EL1_NMI |
|
||||
ID_AA64PFR1_EL1_RNDR_trap |
|
||||
ID_AA64PFR1_EL1_SME |
|
||||
ID_AA64PFR1_EL1_RES0 |
|
||||
ID_AA64PFR1_EL1_MPAM_frac |
|
||||
ID_AA64PFR1_EL1_RAS_frac |
|
||||
ID_AA64PFR1_EL1_MTE)),
|
||||
ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR),
|
||||
ID_UNALLOCATED(4,3),
|
||||
ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
|
||||
@@ -2390,7 +2411,21 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
.get_user = get_id_reg,
|
||||
.set_user = set_id_aa64dfr0_el1,
|
||||
.reset = read_sanitised_id_aa64dfr0_el1,
|
||||
.val = ID_AA64DFR0_EL1_PMUVer_MASK |
|
||||
/*
|
||||
* Prior to FEAT_Debugv8.9, the architecture defines context-aware
|
||||
* breakpoints (CTX_CMPs) as the highest numbered breakpoints (BRPs).
|
||||
* KVM does not trap + emulate the breakpoint registers, and as such
|
||||
* cannot support a layout that misaligns with the underlying hardware.
|
||||
* While it may be possible to describe a subset that aligns with
|
||||
* hardware, just prevent changes to BRPs and CTX_CMPs altogether for
|
||||
* simplicity.
|
||||
*
|
||||
* See DDI0487K.a, section D2.8.3 Breakpoint types and linking
|
||||
* of breakpoints for more details.
|
||||
*/
|
||||
.val = ID_AA64DFR0_EL1_DoubleLock_MASK |
|
||||
ID_AA64DFR0_EL1_WRPs_MASK |
|
||||
ID_AA64DFR0_EL1_PMUVer_MASK |
|
||||
ID_AA64DFR0_EL1_DebugVer_MASK, },
|
||||
ID_SANITISED(ID_AA64DFR1_EL1),
|
||||
ID_UNALLOCATED(5,2),
|
||||
@@ -2433,6 +2468,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
ID_AA64MMFR2_EL1_NV |
|
||||
ID_AA64MMFR2_EL1_CCIDX)),
|
||||
ID_WRITABLE(ID_AA64MMFR3_EL1, (ID_AA64MMFR3_EL1_TCRX |
|
||||
ID_AA64MMFR3_EL1_S1PIE |
|
||||
ID_AA64MMFR3_EL1_S1POE)),
|
||||
ID_SANITISED(ID_AA64MMFR4_EL1),
|
||||
ID_UNALLOCATED(7,5),
|
||||
@@ -2903,7 +2939,7 @@ static bool handle_alle1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
* Drop all shadow S2s, resulting in S1/S2 TLBIs for each of the
|
||||
* corresponding VMIDs.
|
||||
*/
|
||||
kvm_nested_s2_unmap(vcpu->kvm);
|
||||
kvm_nested_s2_unmap(vcpu->kvm, true);
|
||||
|
||||
write_unlock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
@@ -2955,7 +2991,30 @@ union tlbi_info {
|
||||
static void s2_mmu_unmap_range(struct kvm_s2_mmu *mmu,
|
||||
const union tlbi_info *info)
|
||||
{
|
||||
kvm_stage2_unmap_range(mmu, info->range.start, info->range.size);
|
||||
/*
|
||||
* The unmap operation is allowed to drop the MMU lock and block, which
|
||||
* means that @mmu could be used for a different context than the one
|
||||
* currently being invalidated.
|
||||
*
|
||||
* This behavior is still safe, as:
|
||||
*
|
||||
* 1) The vCPU(s) that recycled the MMU are responsible for invalidating
|
||||
* the entire MMU before reusing it, which still honors the intent
|
||||
* of a TLBI.
|
||||
*
|
||||
* 2) Until the guest TLBI instruction is 'retired' (i.e. increment PC
|
||||
* and ERET to the guest), other vCPUs are allowed to use stale
|
||||
* translations.
|
||||
*
|
||||
* 3) Accidentally unmapping an unrelated MMU context is nonfatal, and
|
||||
* at worst may cause more aborts for shadow stage-2 fills.
|
||||
*
|
||||
* Dropping the MMU lock also implies that shadow stage-2 fills could
|
||||
* happen behind the back of the TLBI. This is still safe, though, as
|
||||
* the L1 needs to put its stage-2 in a consistent state before doing
|
||||
* the TLBI.
|
||||
*/
|
||||
kvm_stage2_unmap_range(mmu, info->range.start, info->range.size, true);
|
||||
}
|
||||
|
||||
static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
@@ -3050,7 +3109,11 @@ static void s2_mmu_unmap_ipa(struct kvm_s2_mmu *mmu,
|
||||
max_size = compute_tlb_inval_range(mmu, info->ipa.addr);
|
||||
base_addr &= ~(max_size - 1);
|
||||
|
||||
kvm_stage2_unmap_range(mmu, base_addr, max_size);
|
||||
/*
|
||||
* See comment in s2_mmu_unmap_range() for why this is allowed to
|
||||
* reschedule.
|
||||
*/
|
||||
kvm_stage2_unmap_range(mmu, base_addr, max_size, true);
|
||||
}
|
||||
|
||||
static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
|
||||
@@ -417,8 +417,28 @@ static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
kfree(vgic_cpu->private_irqs);
|
||||
vgic_cpu->private_irqs = NULL;
|
||||
|
||||
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
|
||||
/*
|
||||
* If this vCPU is being destroyed because of a failed creation
|
||||
* then unregister the redistributor to avoid leaving behind a
|
||||
* dangling pointer to the vCPU struct.
|
||||
*
|
||||
* vCPUs that have been successfully created (i.e. added to
|
||||
* kvm->vcpu_array) get unregistered in kvm_vgic_destroy(), as
|
||||
* this function gets called while holding kvm->arch.config_lock
|
||||
* in the VM teardown path and would otherwise introduce a lock
|
||||
* inversion w.r.t. kvm->srcu.
|
||||
*
|
||||
* vCPUs that failed creation are torn down outside of the
|
||||
* kvm->arch.config_lock and do not get unregistered in
|
||||
* kvm_vgic_destroy(), meaning it is both safe and necessary to
|
||||
* do so here.
|
||||
*/
|
||||
if (kvm_get_vcpu_by_id(vcpu->kvm, vcpu->vcpu_id) != vcpu)
|
||||
vgic_unregister_redist_iodev(vcpu);
|
||||
|
||||
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
@@ -524,22 +544,31 @@ int kvm_vgic_map_resources(struct kvm *kvm)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dist->ready = true;
|
||||
dist_base = dist->vgic_dist_base;
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
|
||||
ret = vgic_register_dist_iodev(kvm, dist_base, type);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kvm_err("Unable to register VGIC dist MMIO regions\n");
|
||||
goto out_slots;
|
||||
}
|
||||
|
||||
/*
|
||||
* kvm_io_bus_register_dev() guarantees all readers see the new MMIO
|
||||
* registration before returning through synchronize_srcu(), which also
|
||||
* implies a full memory barrier. As such, marking the distributor as
|
||||
* 'ready' here is guaranteed to be ordered after all vCPUs having seen
|
||||
* a completely configured distributor.
|
||||
*/
|
||||
dist->ready = true;
|
||||
goto out_slots;
|
||||
out:
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
out_slots:
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
|
||||
if (ret)
|
||||
kvm_vgic_destroy(kvm);
|
||||
kvm_vm_dead(kvm);
|
||||
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,12 @@ static int vgic_set_common_attr(struct kvm_device *dev,
|
||||
|
||||
mutex_lock(&dev->kvm->arch.config_lock);
|
||||
|
||||
if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
|
||||
/*
|
||||
* Either userspace has already configured NR_IRQS or
|
||||
* the vgic has already been initialized and vgic_init()
|
||||
* supplied a default amount of SPIs.
|
||||
*/
|
||||
if (dev->kvm->arch.vgic.nr_spis)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
dev->kvm->arch.vgic.nr_spis =
|
||||
|
||||
@@ -2220,7 +2220,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
emit(A64_STR64I(A64_R(20), A64_SP, regs_off + 8), ctx);
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
|
||||
/* for the first pass, assume the worst case */
|
||||
if (!ctx->image)
|
||||
ctx->idx += 4;
|
||||
else
|
||||
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
|
||||
emit_call((const u64)__bpf_tramp_enter, ctx);
|
||||
}
|
||||
|
||||
@@ -2264,7 +2268,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = ctx->ro_image + ctx->idx;
|
||||
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
|
||||
/* for the first pass, assume the worst case */
|
||||
if (!ctx->image)
|
||||
ctx->idx += 4;
|
||||
else
|
||||
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
|
||||
emit_call((const u64)__bpf_tramp_exit, ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ struct loongson_board_info {
|
||||
|
||||
#define NR_WORDS DIV_ROUND_UP(NR_CPUS, BITS_PER_LONG)
|
||||
|
||||
/*
|
||||
* The "core" of cores_per_node and cores_per_package stands for a
|
||||
* logical core, which means in a SMT system it stands for a thread.
|
||||
*/
|
||||
struct loongson_system_configuration {
|
||||
int nr_cpus;
|
||||
int nr_nodes;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#define XRANGE_SHIFT (48)
|
||||
|
||||
/* Valid address length */
|
||||
#define XRANGE_SHADOW_SHIFT (PGDIR_SHIFT + PAGE_SHIFT - 3)
|
||||
#define XRANGE_SHADOW_SHIFT min(cpu_vabits, VA_BITS)
|
||||
/* Used for taking out the valid address */
|
||||
#define XRANGE_SHADOW_MASK GENMASK_ULL(XRANGE_SHADOW_SHIFT - 1, 0)
|
||||
/* One segment whole address space size */
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
#define CSR_ESTAT_IS_WIDTH 15
|
||||
#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT)
|
||||
|
||||
#define LOONGARCH_CSR_ERA 0x6 /* ERA */
|
||||
#define LOONGARCH_CSR_ERA 0x6 /* Exception return address */
|
||||
|
||||
#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#define __HAVE_ARCH_PMD_ALLOC_ONE
|
||||
#define __HAVE_ARCH_PUD_ALLOC_ONE
|
||||
#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
|
||||
#include <asm-generic/pgalloc.h>
|
||||
|
||||
static inline void pmd_populate_kernel(struct mm_struct *mm,
|
||||
@@ -44,6 +45,16 @@ extern void pagetable_init(void);
|
||||
|
||||
extern pgd_t *pgd_alloc(struct mm_struct *mm);
|
||||
|
||||
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
|
||||
{
|
||||
pte_t *pte = __pte_alloc_one_kernel(mm);
|
||||
|
||||
if (pte)
|
||||
kernel_pte_init(pte);
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
#define __pte_free_tlb(tlb, pte, address) \
|
||||
do { \
|
||||
pagetable_pte_dtor(page_ptdesc(pte)); \
|
||||
|
||||
@@ -269,6 +269,7 @@ extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pm
|
||||
extern void pgd_init(void *addr);
|
||||
extern void pud_init(void *addr);
|
||||
extern void pmd_init(void *addr);
|
||||
extern void kernel_pte_init(void *addr);
|
||||
|
||||
/*
|
||||
* Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
|
||||
@@ -325,39 +326,17 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
|
||||
{
|
||||
WRITE_ONCE(*ptep, pteval);
|
||||
|
||||
if (pte_val(pteval) & _PAGE_GLOBAL) {
|
||||
pte_t *buddy = ptep_buddy(ptep);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
__asm__ __volatile__(
|
||||
__AMOR "$zero, %[global], %[buddy] \n"
|
||||
: [buddy] "+ZB" (buddy->pte)
|
||||
: [global] "r" (_PAGE_GLOBAL)
|
||||
: "memory");
|
||||
|
||||
DBAR(0b11000); /* o_wrw = 0b11000 */
|
||||
#else /* !CONFIG_SMP */
|
||||
WRITE_ONCE(*buddy, __pte(pte_val(ptep_get(buddy)) | _PAGE_GLOBAL));
|
||||
#endif /* CONFIG_SMP */
|
||||
}
|
||||
}
|
||||
if (pte_val(pteval) & _PAGE_GLOBAL)
|
||||
DBAR(0b11000); /* o_wrw = 0b11000 */
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
/* Preserve global status for the pair */
|
||||
if (pte_val(ptep_get(ptep_buddy(ptep))) & _PAGE_GLOBAL)
|
||||
set_pte(ptep, __pte(_PAGE_GLOBAL));
|
||||
else
|
||||
set_pte(ptep, __pte(0));
|
||||
pte_t pte = ptep_get(ptep);
|
||||
pte_val(pte) &= _PAGE_GLOBAL;
|
||||
set_pte(ptep, pte);
|
||||
}
|
||||
|
||||
#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1)
|
||||
|
||||
@@ -293,13 +293,15 @@ unsigned long stack_top(void)
|
||||
{
|
||||
unsigned long top = TASK_SIZE & PAGE_MASK;
|
||||
|
||||
/* Space for the VDSO & data page */
|
||||
top -= PAGE_ALIGN(current->thread.vdso->size);
|
||||
top -= VVAR_SIZE;
|
||||
if (current->thread.vdso) {
|
||||
/* Space for the VDSO & data page */
|
||||
top -= PAGE_ALIGN(current->thread.vdso->size);
|
||||
top -= VVAR_SIZE;
|
||||
|
||||
/* Space to randomize the VDSO base */
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
top -= VDSO_RANDOMIZE_SIZE;
|
||||
/* Space to randomize the VDSO base */
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
top -= VDSO_RANDOMIZE_SIZE;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#define SMBIOS_FREQHIGH_OFFSET 0x17
|
||||
#define SMBIOS_FREQLOW_MASK 0xFF
|
||||
#define SMBIOS_CORE_PACKAGE_OFFSET 0x23
|
||||
#define SMBIOS_THREAD_PACKAGE_OFFSET 0x25
|
||||
#define LOONGSON_EFI_ENABLE (1 << 3)
|
||||
|
||||
unsigned long fw_arg0, fw_arg1, fw_arg2;
|
||||
@@ -125,7 +126,7 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
|
||||
cpu_clock_freq = freq_temp * 1000000;
|
||||
|
||||
loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
|
||||
loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET);
|
||||
loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET);
|
||||
|
||||
pr_info("CpuClock = %llu\n", cpu_clock_freq);
|
||||
}
|
||||
|
||||
@@ -555,6 +555,9 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
|
||||
#else
|
||||
unsigned int *pc;
|
||||
|
||||
if (regs->csr_prmd & CSR_PRMD_PIE)
|
||||
local_irq_enable();
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);
|
||||
|
||||
/*
|
||||
@@ -579,6 +582,8 @@ sigbus:
|
||||
die_if_kernel("Kernel ale access", regs);
|
||||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
|
||||
out:
|
||||
if (regs->csr_prmd & CSR_PRMD_PIE)
|
||||
local_irq_disable();
|
||||
#endif
|
||||
irqentry_exit(regs, state);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ static union {
|
||||
struct loongarch_vdso_data vdata;
|
||||
} loongarch_vdso_data __page_aligned_data;
|
||||
|
||||
static struct page *vdso_pages[] = { NULL };
|
||||
struct vdso_data *vdso_data = generic_vdso_data.data;
|
||||
struct vdso_pcpu_data *vdso_pdata = loongarch_vdso_data.vdata.pdata;
|
||||
struct vdso_rng_data *vdso_rng_data = &loongarch_vdso_data.vdata.rng_data;
|
||||
@@ -85,10 +84,8 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
||||
|
||||
struct loongarch_vdso_info vdso_info = {
|
||||
.vdso = vdso_start,
|
||||
.size = PAGE_SIZE,
|
||||
.code_mapping = {
|
||||
.name = "[vdso]",
|
||||
.pages = vdso_pages,
|
||||
.mremap = vdso_mremap,
|
||||
},
|
||||
.data_mapping = {
|
||||
@@ -103,11 +100,14 @@ static int __init init_vdso(void)
|
||||
unsigned long i, cpu, pfn;
|
||||
|
||||
BUG_ON(!PAGE_ALIGNED(vdso_info.vdso));
|
||||
BUG_ON(!PAGE_ALIGNED(vdso_info.size));
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
vdso_pdata[cpu].node = cpu_to_node(cpu);
|
||||
|
||||
vdso_info.size = PAGE_ALIGN(vdso_end - vdso_start);
|
||||
vdso_info.code_mapping.pages =
|
||||
kcalloc(vdso_info.size / PAGE_SIZE, sizeof(struct page *), GFP_KERNEL);
|
||||
|
||||
pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso));
|
||||
for (i = 0; i < vdso_info.size / PAGE_SIZE; i++)
|
||||
vdso_info.code_mapping.pages[i] = pfn_to_page(pfn + i);
|
||||
|
||||
@@ -161,10 +161,11 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
|
||||
if (kvm_vcpu_is_blocking(vcpu)) {
|
||||
|
||||
/*
|
||||
* HRTIMER_MODE_PINNED is suggested since vcpu may run in
|
||||
* the same physical cpu in next time
|
||||
* HRTIMER_MODE_PINNED_HARD is suggested since vcpu may run in
|
||||
* the same physical cpu in next time, and the timer should run
|
||||
* in hardirq context even in the PREEMPT_RT case.
|
||||
*/
|
||||
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
|
||||
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1457,7 +1457,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
vcpu->arch.vpid = 0;
|
||||
vcpu->arch.flush_gpa = INVALID_GPA;
|
||||
|
||||
hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
|
||||
hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
|
||||
vcpu->arch.swtimer.function = kvm_swtimer_wakeup;
|
||||
|
||||
vcpu->arch.handle_exit = kvm_handle_exit;
|
||||
|
||||
@@ -201,7 +201,9 @@ pte_t * __init populate_kernel_pte(unsigned long addr)
|
||||
pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
|
||||
if (!pte)
|
||||
panic("%s: Failed to allocate memory\n", __func__);
|
||||
|
||||
pmd_populate_kernel(&init_mm, pmd, pte);
|
||||
kernel_pte_init(pte);
|
||||
}
|
||||
|
||||
return pte_offset_kernel(pmd, addr);
|
||||
|
||||
@@ -116,6 +116,26 @@ void pud_init(void *addr)
|
||||
EXPORT_SYMBOL_GPL(pud_init);
|
||||
#endif
|
||||
|
||||
void kernel_pte_init(void *addr)
|
||||
{
|
||||
unsigned long *p, *end;
|
||||
|
||||
p = (unsigned long *)addr;
|
||||
end = p + PTRS_PER_PTE;
|
||||
|
||||
do {
|
||||
p[0] = _PAGE_GLOBAL;
|
||||
p[1] = _PAGE_GLOBAL;
|
||||
p[2] = _PAGE_GLOBAL;
|
||||
p[3] = _PAGE_GLOBAL;
|
||||
p[4] = _PAGE_GLOBAL;
|
||||
p += 8;
|
||||
p[-3] = _PAGE_GLOBAL;
|
||||
p[-2] = _PAGE_GLOBAL;
|
||||
p[-1] = _PAGE_GLOBAL;
|
||||
} while (p != end);
|
||||
}
|
||||
|
||||
pmd_t mk_pmd(struct page *page, pgprot_t prot)
|
||||
{
|
||||
pmd_t pmd;
|
||||
|
||||
@@ -55,7 +55,7 @@ struct imsic {
|
||||
/* IMSIC SW-file */
|
||||
struct imsic_mrif *swfile;
|
||||
phys_addr_t swfile_pa;
|
||||
spinlock_t swfile_extirq_lock;
|
||||
raw_spinlock_t swfile_extirq_lock;
|
||||
};
|
||||
|
||||
#define imsic_vs_csr_read(__c) \
|
||||
@@ -622,7 +622,7 @@ static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu)
|
||||
* interruptions between reading topei and updating pending status.
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&imsic->swfile_extirq_lock, flags);
|
||||
raw_spin_lock_irqsave(&imsic->swfile_extirq_lock, flags);
|
||||
|
||||
if (imsic_mrif_atomic_read(mrif, &mrif->eidelivery) &&
|
||||
imsic_mrif_topei(mrif, imsic->nr_eix, imsic->nr_msis))
|
||||
@@ -630,7 +630,7 @@ static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu)
|
||||
else
|
||||
kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);
|
||||
|
||||
spin_unlock_irqrestore(&imsic->swfile_extirq_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&imsic->swfile_extirq_lock, flags);
|
||||
}
|
||||
|
||||
static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear,
|
||||
@@ -1051,7 +1051,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
imsic->swfile = page_to_virt(swfile_page);
|
||||
imsic->swfile_pa = page_to_phys(swfile_page);
|
||||
spin_lock_init(&imsic->swfile_extirq_lock);
|
||||
raw_spin_lock_init(&imsic->swfile_extirq_lock);
|
||||
|
||||
/* Setup IO device */
|
||||
kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops);
|
||||
|
||||
@@ -2257,6 +2257,7 @@ config RANDOMIZE_MEMORY_PHYSICAL_PADDING
|
||||
config ADDRESS_MASKING
|
||||
bool "Linear Address Masking support"
|
||||
depends on X86_64
|
||||
depends on COMPILE_TEST || !CPU_MITIGATIONS # wait for LASS
|
||||
help
|
||||
Linear Address Masking (LAM) modifies the checking that is applied
|
||||
to 64-bit linear addresses, allowing software to use of the
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
typeof(sym) __ret; \
|
||||
asm_inline("mov %1,%0\n1:\n" \
|
||||
".pushsection runtime_ptr_" #sym ",\"a\"\n\t" \
|
||||
".long 1b - %c2 - .\n\t" \
|
||||
".long 1b - %c2 - .\n" \
|
||||
".popsection" \
|
||||
:"=r" (__ret) \
|
||||
:"i" ((unsigned long)0x0123456789abcdefull), \
|
||||
@@ -20,7 +20,7 @@
|
||||
typeof(0u+(val)) __ret = (val); \
|
||||
asm_inline("shrl $12,%k0\n1:\n" \
|
||||
".pushsection runtime_shift_" #sym ",\"a\"\n\t" \
|
||||
".long 1b - 1 - .\n\t" \
|
||||
".long 1b - 1 - .\n" \
|
||||
".popsection" \
|
||||
:"+r" (__ret)); \
|
||||
__ret; })
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/runtime-const.h>
|
||||
|
||||
/*
|
||||
* Virtual variable: there's no actual backing store for this,
|
||||
* it can purely be used as 'runtime_const_ptr(USER_PTR_MAX)'
|
||||
*/
|
||||
extern unsigned long USER_PTR_MAX;
|
||||
|
||||
#ifdef CONFIG_ADDRESS_MASKING
|
||||
/*
|
||||
@@ -46,19 +53,24 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The virtual address space space is logically divided into a kernel
|
||||
* half and a user half. When cast to a signed type, user pointers
|
||||
* are positive and kernel pointers are negative.
|
||||
*/
|
||||
#define valid_user_address(x) ((__force long)(x) >= 0)
|
||||
#define valid_user_address(x) \
|
||||
((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
|
||||
|
||||
/*
|
||||
* Masking the user address is an alternative to a conditional
|
||||
* user_access_begin that can avoid the fencing. This only works
|
||||
* for dense accesses starting at the address.
|
||||
*/
|
||||
#define mask_user_address(x) ((typeof(x))((long)(x)|((long)(x)>>63)))
|
||||
static inline void __user *mask_user_address(const void __user *ptr)
|
||||
{
|
||||
unsigned long mask;
|
||||
asm("cmp %1,%0\n\t"
|
||||
"sbb %0,%0"
|
||||
:"=r" (mask)
|
||||
:"r" (ptr),
|
||||
"0" (runtime_const_ptr(USER_PTR_MAX)));
|
||||
return (__force void __user *)(mask | (__force unsigned long)ptr);
|
||||
}
|
||||
#define masked_user_access_begin(x) ({ \
|
||||
__auto_type __masked_ptr = (x); \
|
||||
__masked_ptr = mask_user_address(__masked_ptr); \
|
||||
@@ -69,23 +81,16 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
|
||||
* arbitrary values in those bits rather then masking them off.
|
||||
*
|
||||
* Enforce two rules:
|
||||
* 1. 'ptr' must be in the user half of the address space
|
||||
* 1. 'ptr' must be in the user part of the address space
|
||||
* 2. 'ptr+size' must not overflow into kernel addresses
|
||||
*
|
||||
* Note that addresses around the sign change are not valid addresses,
|
||||
* and will GP-fault even with LAM enabled if the sign bit is set (see
|
||||
* "CR3.LAM_SUP" that can narrow the canonicality check if we ever
|
||||
* enable it, but not remove it entirely).
|
||||
*
|
||||
* So the "overflow into kernel addresses" does not imply some sudden
|
||||
* exact boundary at the sign bit, and we can allow a lot of slop on the
|
||||
* size check.
|
||||
* Note that we always have at least one guard page between the
|
||||
* max user address and the non-canonical gap, allowing us to
|
||||
* ignore small sizes entirely.
|
||||
*
|
||||
* In fact, we could probably remove the size check entirely, since
|
||||
* any kernel accesses will be in increasing address order starting
|
||||
* at 'ptr', and even if the end might be in kernel space, we'll
|
||||
* hit the GP faults for non-canonical accesses before we ever get
|
||||
* there.
|
||||
* at 'ptr'.
|
||||
*
|
||||
* That's a separate optimization, for now just handle the small
|
||||
* constant case.
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include <asm/sev.h>
|
||||
#include <asm/tdx.h>
|
||||
#include <asm/posted_intr.h>
|
||||
#include <asm/runtime-const.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
@@ -2389,6 +2390,15 @@ void __init arch_cpu_finalize_init(void)
|
||||
alternative_instructions();
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||
unsigned long USER_PTR_MAX = TASK_SIZE_MAX-1;
|
||||
|
||||
/*
|
||||
* Enable this when LAM is gated on LASS support
|
||||
if (cpu_feature_enabled(X86_FEATURE_LAM))
|
||||
USER_PTR_MAX = (1ul << 63) - PAGE_SIZE - 1;
|
||||
*/
|
||||
runtime_const_init(ptr, USER_PTR_MAX);
|
||||
|
||||
/*
|
||||
* Make sure the first 2MB area is not mapped by huge pages
|
||||
* There are typically fixed size MTRRs in there and overlapping
|
||||
|
||||
@@ -584,7 +584,7 @@ void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_
|
||||
native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy);
|
||||
}
|
||||
|
||||
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
|
||||
static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size);
|
||||
|
||||
static int __init save_microcode_in_initrd(void)
|
||||
{
|
||||
@@ -605,7 +605,7 @@ static int __init save_microcode_in_initrd(void)
|
||||
if (!desc.mc)
|
||||
return -EINVAL;
|
||||
|
||||
ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
|
||||
ret = _load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
|
||||
if (ret > UCODE_UPDATED)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -613,16 +613,19 @@ static int __init save_microcode_in_initrd(void)
|
||||
}
|
||||
early_initcall(save_microcode_in_initrd);
|
||||
|
||||
static inline bool patch_cpus_equivalent(struct ucode_patch *p, struct ucode_patch *n)
|
||||
static inline bool patch_cpus_equivalent(struct ucode_patch *p,
|
||||
struct ucode_patch *n,
|
||||
bool ignore_stepping)
|
||||
{
|
||||
/* Zen and newer hardcode the f/m/s in the patch ID */
|
||||
if (x86_family(bsp_cpuid_1_eax) >= 0x17) {
|
||||
union cpuid_1_eax p_cid = ucode_rev_to_cpuid(p->patch_id);
|
||||
union cpuid_1_eax n_cid = ucode_rev_to_cpuid(n->patch_id);
|
||||
|
||||
/* Zap stepping */
|
||||
p_cid.stepping = 0;
|
||||
n_cid.stepping = 0;
|
||||
if (ignore_stepping) {
|
||||
p_cid.stepping = 0;
|
||||
n_cid.stepping = 0;
|
||||
}
|
||||
|
||||
return p_cid.full == n_cid.full;
|
||||
} else {
|
||||
@@ -644,13 +647,13 @@ static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equi
|
||||
WARN_ON_ONCE(!n.patch_id);
|
||||
|
||||
list_for_each_entry(p, µcode_cache, plist)
|
||||
if (patch_cpus_equivalent(p, &n))
|
||||
if (patch_cpus_equivalent(p, &n, false))
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
|
||||
static inline int patch_newer(struct ucode_patch *p, struct ucode_patch *n)
|
||||
{
|
||||
/* Zen and newer hardcode the f/m/s in the patch ID */
|
||||
if (x86_family(bsp_cpuid_1_eax) >= 0x17) {
|
||||
@@ -659,6 +662,9 @@ static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
|
||||
zp.ucode_rev = p->patch_id;
|
||||
zn.ucode_rev = n->patch_id;
|
||||
|
||||
if (zn.stepping != zp.stepping)
|
||||
return -1;
|
||||
|
||||
return zn.rev > zp.rev;
|
||||
} else {
|
||||
return n->patch_id > p->patch_id;
|
||||
@@ -668,10 +674,14 @@ static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
|
||||
static void update_cache(struct ucode_patch *new_patch)
|
||||
{
|
||||
struct ucode_patch *p;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(p, µcode_cache, plist) {
|
||||
if (patch_cpus_equivalent(p, new_patch)) {
|
||||
if (!patch_newer(p, new_patch)) {
|
||||
if (patch_cpus_equivalent(p, new_patch, true)) {
|
||||
ret = patch_newer(p, new_patch);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
else if (!ret) {
|
||||
/* we already have the latest patch */
|
||||
kfree(new_patch->data);
|
||||
kfree(new_patch);
|
||||
@@ -944,6 +954,20 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
|
||||
return UCODE_OK;
|
||||
}
|
||||
|
||||
static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size)
|
||||
{
|
||||
enum ucode_state ret;
|
||||
|
||||
/* free old equiv table */
|
||||
free_equiv_cpu_table();
|
||||
|
||||
ret = __load_microcode_amd(family, data, size);
|
||||
if (ret != UCODE_OK)
|
||||
cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
|
||||
{
|
||||
struct cpuinfo_x86 *c;
|
||||
@@ -951,14 +975,9 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz
|
||||
struct ucode_patch *p;
|
||||
enum ucode_state ret;
|
||||
|
||||
/* free old equiv table */
|
||||
free_equiv_cpu_table();
|
||||
|
||||
ret = __load_microcode_amd(family, data, size);
|
||||
if (ret != UCODE_OK) {
|
||||
cleanup();
|
||||
ret = _load_microcode_amd(family, data, size);
|
||||
if (ret != UCODE_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for_each_node(nid) {
|
||||
cpu = cpumask_first(cpumask_of_node(nid));
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <asm/apic.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/cpuidle_haltpoll.h>
|
||||
#include <asm/ptrace.h>
|
||||
@@ -980,6 +981,9 @@ static void __init kvm_init_platform(void)
|
||||
}
|
||||
kvmclock_init();
|
||||
x86_platform.apic_post_init = kvm_apic_init;
|
||||
|
||||
/* Set WB as the default cache mode for SEV-SNP and TDX */
|
||||
mtrr_overwrite_state(NULL, 0, MTRR_TYPE_WRBACK);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_AMD_MEM_ENCRYPT)
|
||||
|
||||
@@ -358,6 +358,7 @@ SECTIONS
|
||||
#endif
|
||||
|
||||
RUNTIME_CONST_VARIABLES
|
||||
RUNTIME_CONST(ptr, USER_PTR_MAX)
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
|
||||
|
||||
+17
-10
@@ -1556,6 +1556,17 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
|
||||
{
|
||||
bool flush = false;
|
||||
|
||||
/*
|
||||
* To prevent races with vCPUs faulting in a gfn using stale data,
|
||||
* zapping a gfn range must be protected by mmu_invalidate_in_progress
|
||||
* (and mmu_invalidate_seq). The only exception is memslot deletion;
|
||||
* in that case, SRCU synchronization ensures that SPTEs are zapped
|
||||
* after all vCPUs have unlocked SRCU, guaranteeing that vCPUs see the
|
||||
* invalid slot.
|
||||
*/
|
||||
lockdep_assert_once(kvm->mmu_invalidate_in_progress ||
|
||||
lockdep_is_held(&kvm->slots_lock));
|
||||
|
||||
if (kvm_memslots_have_rmaps(kvm))
|
||||
flush = __kvm_rmap_zap_gfn_range(kvm, range->slot,
|
||||
range->start, range->end,
|
||||
@@ -1884,14 +1895,10 @@ static bool sp_has_gptes(struct kvm_mmu_page *sp)
|
||||
if (is_obsolete_sp((_kvm), (_sp))) { \
|
||||
} else
|
||||
|
||||
#define for_each_gfn_valid_sp(_kvm, _sp, _gfn) \
|
||||
#define for_each_gfn_valid_sp_with_gptes(_kvm, _sp, _gfn) \
|
||||
for_each_valid_sp(_kvm, _sp, \
|
||||
&(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)]) \
|
||||
if ((_sp)->gfn != (_gfn)) {} else
|
||||
|
||||
#define for_each_gfn_valid_sp_with_gptes(_kvm, _sp, _gfn) \
|
||||
for_each_gfn_valid_sp(_kvm, _sp, _gfn) \
|
||||
if (!sp_has_gptes(_sp)) {} else
|
||||
if ((_sp)->gfn != (_gfn) || !sp_has_gptes(_sp)) {} else
|
||||
|
||||
static bool kvm_sync_page_check(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
|
||||
{
|
||||
@@ -7063,15 +7070,15 @@ static void kvm_mmu_zap_memslot_pages_and_flush(struct kvm *kvm,
|
||||
|
||||
/*
|
||||
* Since accounting information is stored in struct kvm_arch_memory_slot,
|
||||
* shadow pages deletion (e.g. unaccount_shadowed()) requires that all
|
||||
* gfns with a shadow page have a corresponding memslot. Do so before
|
||||
* the memslot goes away.
|
||||
* all MMU pages that are shadowing guest PTEs must be zapped before the
|
||||
* memslot is deleted, as freeing such pages after the memslot is freed
|
||||
* will result in use-after-free, e.g. in unaccount_shadowed().
|
||||
*/
|
||||
for (i = 0; i < slot->npages; i++) {
|
||||
struct kvm_mmu_page *sp;
|
||||
gfn_t gfn = slot->base_gfn + i;
|
||||
|
||||
for_each_gfn_valid_sp(kvm, sp, gfn)
|
||||
for_each_gfn_valid_sp_with_gptes(kvm, sp, gfn)
|
||||
kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
|
||||
|
||||
if (need_resched() || rwlock_needbreak(&kvm->mmu_lock)) {
|
||||
|
||||
@@ -63,8 +63,12 @@ static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
|
||||
u64 pdpte;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note, nCR3 is "assumed" to be 32-byte aligned, i.e. the CPU ignores
|
||||
* nCR3[4:0] when loading PDPTEs from memory.
|
||||
*/
|
||||
ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(cr3), &pdpte,
|
||||
offset_in_page(cr3) + index * 8, 8);
|
||||
(cr3 & GENMASK(11, 5)) + index * 8, 8);
|
||||
if (ret)
|
||||
return 0;
|
||||
return pdpte;
|
||||
|
||||
@@ -4888,9 +4888,6 @@ void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
vmx->hv_deadline_tsc = -1;
|
||||
kvm_set_cr8(vcpu, 0);
|
||||
|
||||
vmx_segment_cache_clear(vmx);
|
||||
kvm_register_mark_available(vcpu, VCPU_EXREG_SEGMENTS);
|
||||
|
||||
seg_setup(VCPU_SREG_CS);
|
||||
vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
|
||||
vmcs_writel(GUEST_CS_BASE, 0xffff0000ul);
|
||||
@@ -4917,6 +4914,9 @@ void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
vmcs_writel(GUEST_IDTR_BASE, 0);
|
||||
vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
|
||||
|
||||
vmx_segment_cache_clear(vmx);
|
||||
kvm_register_mark_available(vcpu, VCPU_EXREG_SEGMENTS);
|
||||
|
||||
vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE);
|
||||
vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
|
||||
vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, 0);
|
||||
|
||||
@@ -39,8 +39,13 @@
|
||||
|
||||
.macro check_range size:req
|
||||
.if IS_ENABLED(CONFIG_X86_64)
|
||||
mov %rax, %rdx
|
||||
sar $63, %rdx
|
||||
movq $0x0123456789abcdef,%rdx
|
||||
1:
|
||||
.pushsection runtime_ptr_USER_PTR_MAX,"a"
|
||||
.long 1b - 8 - .
|
||||
.popsection
|
||||
cmp %rax, %rdx
|
||||
sbb %rdx, %rdx
|
||||
or %rdx, %rax
|
||||
.else
|
||||
cmp $TASK_SIZE_MAX-\size+1, %eax
|
||||
|
||||
@@ -173,6 +173,8 @@ static void __init __snp_fixup_e820_tables(u64 pa)
|
||||
e820__range_update(pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
e820__range_update_table(e820_table_kexec, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
e820__range_update_table(e820_table_firmware, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
if (!memblock_is_region_reserved(pa, PMD_SIZE))
|
||||
memblock_reserve(pa, PMD_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -600,9 +600,7 @@ static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
|
||||
if (nsegs >= nr_segs || bytes > UINT_MAX - bv->bv_len)
|
||||
goto put_bio;
|
||||
if (bytes + bv->bv_len > nr_iter)
|
||||
goto put_bio;
|
||||
if (bv->bv_offset + bv->bv_len > PAGE_SIZE)
|
||||
goto put_bio;
|
||||
break;
|
||||
|
||||
nsegs++;
|
||||
bytes += bv->bv_len;
|
||||
|
||||
@@ -130,6 +130,17 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
|
||||
},
|
||||
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Samsung galaxybook2 ,initial _LID device notification returns
|
||||
* lid closed.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "750XED"),
|
||||
},
|
||||
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -1916,9 +1916,15 @@ unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf)
|
||||
u64 mul, div;
|
||||
|
||||
if (caps->lowest_freq && caps->nominal_freq) {
|
||||
mul = caps->nominal_freq - caps->lowest_freq;
|
||||
/* Avoid special case when nominal_freq is equal to lowest_freq */
|
||||
if (caps->lowest_freq == caps->nominal_freq) {
|
||||
mul = caps->nominal_freq;
|
||||
div = caps->nominal_perf;
|
||||
} else {
|
||||
mul = caps->nominal_freq - caps->lowest_freq;
|
||||
div = caps->nominal_perf - caps->lowest_perf;
|
||||
}
|
||||
mul *= KHZ_PER_MHZ;
|
||||
div = caps->nominal_perf - caps->lowest_perf;
|
||||
offset = caps->nominal_freq * KHZ_PER_MHZ -
|
||||
div64_u64(caps->nominal_perf * mul, div);
|
||||
} else {
|
||||
@@ -1939,11 +1945,17 @@ unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq)
|
||||
{
|
||||
s64 retval, offset = 0;
|
||||
static u64 max_khz;
|
||||
u64 mul, div;
|
||||
u64 mul, div;
|
||||
|
||||
if (caps->lowest_freq && caps->nominal_freq) {
|
||||
mul = caps->nominal_perf - caps->lowest_perf;
|
||||
div = caps->nominal_freq - caps->lowest_freq;
|
||||
/* Avoid special case when nominal_freq is equal to lowest_freq */
|
||||
if (caps->lowest_freq == caps->nominal_freq) {
|
||||
mul = caps->nominal_perf;
|
||||
div = caps->nominal_freq;
|
||||
} else {
|
||||
mul = caps->nominal_perf - caps->lowest_perf;
|
||||
div = caps->nominal_freq - caps->lowest_freq;
|
||||
}
|
||||
/*
|
||||
* We don't need to convert to kHz for computing offset and can
|
||||
* directly use nominal_freq and lowest_freq as the div64_u64
|
||||
|
||||
+23
-6
@@ -52,7 +52,7 @@ struct prm_context_buffer {
|
||||
static LIST_HEAD(prm_module_list);
|
||||
|
||||
struct prm_handler_info {
|
||||
guid_t guid;
|
||||
efi_guid_t guid;
|
||||
efi_status_t (__efiapi *handler_addr)(u64, void *);
|
||||
u64 static_data_buffer_addr;
|
||||
u64 acpi_param_buffer_addr;
|
||||
@@ -72,17 +72,21 @@ struct prm_module_info {
|
||||
struct prm_handler_info handlers[] __counted_by(handler_count);
|
||||
};
|
||||
|
||||
static u64 efi_pa_va_lookup(u64 pa)
|
||||
static u64 efi_pa_va_lookup(efi_guid_t *guid, u64 pa)
|
||||
{
|
||||
efi_memory_desc_t *md;
|
||||
u64 pa_offset = pa & ~PAGE_MASK;
|
||||
u64 page = pa & PAGE_MASK;
|
||||
|
||||
for_each_efi_memory_desc(md) {
|
||||
if (md->phys_addr < pa && pa < md->phys_addr + PAGE_SIZE * md->num_pages)
|
||||
if ((md->attribute & EFI_MEMORY_RUNTIME) &&
|
||||
(md->phys_addr < pa && pa < md->phys_addr + PAGE_SIZE * md->num_pages)) {
|
||||
return pa_offset + md->virt_addr + page - md->phys_addr;
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn("Failed to find VA for GUID: %pUL, PA: 0x%llx", guid, pa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -148,9 +152,15 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end)
|
||||
th = &tm->handlers[cur_handler];
|
||||
|
||||
guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
|
||||
th->handler_addr = (void *)efi_pa_va_lookup(handler_info->handler_address);
|
||||
th->static_data_buffer_addr = efi_pa_va_lookup(handler_info->static_data_buffer_address);
|
||||
th->acpi_param_buffer_addr = efi_pa_va_lookup(handler_info->acpi_param_buffer_address);
|
||||
th->handler_addr =
|
||||
(void *)efi_pa_va_lookup(&th->guid, handler_info->handler_address);
|
||||
|
||||
th->static_data_buffer_addr =
|
||||
efi_pa_va_lookup(&th->guid, handler_info->static_data_buffer_address);
|
||||
|
||||
th->acpi_param_buffer_addr =
|
||||
efi_pa_va_lookup(&th->guid, handler_info->acpi_param_buffer_address);
|
||||
|
||||
} while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
|
||||
|
||||
return 0;
|
||||
@@ -277,6 +287,13 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
|
||||
if (!handler || !module)
|
||||
goto invalid_guid;
|
||||
|
||||
if (!handler->handler_addr ||
|
||||
!handler->static_data_buffer_addr ||
|
||||
!handler->acpi_param_buffer_addr) {
|
||||
buffer->prm_status = PRM_HANDLER_ERROR;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_COPY_NAMESEG(context.signature, "PRMC");
|
||||
context.revision = 0x0;
|
||||
context.reserved = 0x0;
|
||||
|
||||
@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "17U70P"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* LG Electronics 16T90SP */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "16T90SP"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -651,6 +651,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
||||
/* the scmd has an associated qc */
|
||||
if (!(qc->flags & ATA_QCFLAG_EH)) {
|
||||
/* which hasn't failed yet, timeout */
|
||||
set_host_byte(scmd, DID_TIME_OUT);
|
||||
qc->err_mask |= AC_ERR_TIMEOUT;
|
||||
qc->flags |= ATA_QCFLAG_EH;
|
||||
nr_timedout++;
|
||||
|
||||
@@ -204,7 +204,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
||||
// the node->ports array where the parent node should be. Later,
|
||||
// when we handle the parent node, we fix up the reference.
|
||||
++parent_count;
|
||||
node->color = i;
|
||||
node->color = port_index;
|
||||
break;
|
||||
|
||||
case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD:
|
||||
|
||||
@@ -147,6 +147,7 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
|
||||
struct acpi_buffer *params)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
union acpi_object atif_arg_elements[2];
|
||||
struct acpi_object_list atif_arg;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
@@ -169,16 +170,24 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
|
||||
|
||||
status = acpi_evaluate_object(atif->handle, NULL, &atif_arg,
|
||||
&buffer);
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
|
||||
/* Fail only if calling the method fails and ATIF is supported */
|
||||
/* Fail if calling the method fails and ATIF is supported */
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
|
||||
acpi_format_exception(status));
|
||||
kfree(buffer.pointer);
|
||||
kfree(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer.pointer;
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
DRM_DEBUG_DRIVER("bad object returned from ATIF: %d\n",
|
||||
obj->type);
|
||||
kfree(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,12 @@ MODULE_FIRMWARE("amdgpu/sdma_7_0_1.bin");
|
||||
#define SDMA0_HYP_DEC_REG_END 0x589a
|
||||
#define SDMA1_HYP_DEC_REG_OFFSET 0x20
|
||||
|
||||
/*define for compression field for sdma7*/
|
||||
#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_offset 0
|
||||
#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_mask 0x00000001
|
||||
#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_shift 16
|
||||
#define SDMA_PKT_CONSTANT_FILL_HEADER_COMPRESS(x) (((x) & SDMA_PKT_CONSTANT_FILL_HEADER_compress_mask) << SDMA_PKT_CONSTANT_FILL_HEADER_compress_shift)
|
||||
|
||||
static const struct amdgpu_hwip_reg_entry sdma_reg_list_7_0[] = {
|
||||
SOC15_REG_ENTRY_STR(GC, 0, regSDMA0_STATUS_REG),
|
||||
SOC15_REG_ENTRY_STR(GC, 0, regSDMA0_STATUS1_REG),
|
||||
@@ -1724,7 +1730,8 @@ static void sdma_v7_0_emit_fill_buffer(struct amdgpu_ib *ib,
|
||||
uint64_t dst_offset,
|
||||
uint32_t byte_count)
|
||||
{
|
||||
ib->ptr[ib->length_dw++] = SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_CONST_FILL);
|
||||
ib->ptr[ib->length_dw++] = SDMA_PKT_CONSTANT_FILL_HEADER_OP(SDMA_OP_CONST_FILL) |
|
||||
SDMA_PKT_CONSTANT_FILL_HEADER_COMPRESS(1);
|
||||
ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset);
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset);
|
||||
ib->ptr[ib->length_dw++] = src_data;
|
||||
|
||||
@@ -8374,7 +8374,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
|
||||
IP_VERSION(3, 5, 0) ||
|
||||
acrtc_state->stream->link->psr_settings.psr_version <
|
||||
DC_PSR_VERSION_UNSUPPORTED) {
|
||||
DC_PSR_VERSION_UNSUPPORTED ||
|
||||
!(adev->flags & AMD_IS_APU)) {
|
||||
timing = &acrtc_state->stream->timing;
|
||||
|
||||
/* at least 2 frames */
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "dm_helpers.h"
|
||||
#include "ddc_service_types.h"
|
||||
#include "clk_mgr.h"
|
||||
|
||||
static u32 edid_extract_panel_id(struct edid *edid)
|
||||
{
|
||||
@@ -1121,6 +1122,8 @@ bool dm_helpers_dp_handle_test_pattern_request(
|
||||
struct pipe_ctx *pipe_ctx = NULL;
|
||||
struct amdgpu_dm_connector *aconnector = link->priv;
|
||||
struct drm_device *dev = aconnector->base.dev;
|
||||
struct dc_state *dc_state = ctx->dc->current_state;
|
||||
struct clk_mgr *clk_mgr = ctx->dc->clk_mgr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
@@ -1221,6 +1224,16 @@ bool dm_helpers_dp_handle_test_pattern_request(
|
||||
pipe_ctx->stream->test_pattern.type = test_pattern;
|
||||
pipe_ctx->stream->test_pattern.color_space = test_pattern_color_space;
|
||||
|
||||
/* Temp W/A for compliance test failure */
|
||||
dc_state->bw_ctx.bw.dcn.clk.p_state_change_support = false;
|
||||
dc_state->bw_ctx.bw.dcn.clk.dramclk_khz = clk_mgr->dc_mode_softmax_enabled ?
|
||||
clk_mgr->bw_params->dc_mode_softmax_memclk : clk_mgr->bw_params->max_memclk_mhz;
|
||||
dc_state->bw_ctx.bw.dcn.clk.idle_dramclk_khz = dc_state->bw_ctx.bw.dcn.clk.dramclk_khz;
|
||||
ctx->dc->clk_mgr->funcs->update_clocks(
|
||||
ctx->dc->clk_mgr,
|
||||
dc_state,
|
||||
false);
|
||||
|
||||
dc_link_dp_set_test_pattern(
|
||||
(struct dc_link *) link,
|
||||
test_pattern,
|
||||
|
||||
@@ -841,6 +841,8 @@ bool is_psr_su_specific_panel(struct dc_link *link)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x01)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1)
|
||||
isPSRSUSupported = true;
|
||||
}
|
||||
|
||||
@@ -1234,6 +1234,14 @@ static void smu_init_xgmi_plpd_mode(struct smu_context *smu)
|
||||
}
|
||||
}
|
||||
|
||||
static bool smu_is_workload_profile_available(struct smu_context *smu,
|
||||
u32 profile)
|
||||
{
|
||||
if (profile >= PP_SMC_POWER_PROFILE_COUNT)
|
||||
return false;
|
||||
return smu->workload_map && smu->workload_map[profile].valid_mapping;
|
||||
}
|
||||
|
||||
static int smu_sw_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
@@ -1265,7 +1273,8 @@ static int smu_sw_init(void *handle)
|
||||
smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
|
||||
smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
|
||||
|
||||
if (smu->is_apu)
|
||||
if (smu->is_apu ||
|
||||
!smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
|
||||
smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
|
||||
else
|
||||
smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#define SMU14_DRIVER_IF_V14_0_H
|
||||
|
||||
//Increment this version if SkuTable_t or BoardTable_t change
|
||||
#define PPTABLE_VERSION 0x18
|
||||
#define PPTABLE_VERSION 0x1B
|
||||
|
||||
#define NUM_GFXCLK_DPM_LEVELS 16
|
||||
#define NUM_SOCCLK_DPM_LEVELS 8
|
||||
@@ -145,7 +145,7 @@ typedef enum {
|
||||
} FEATURE_BTC_e;
|
||||
|
||||
// Debug Overrides Bitmask
|
||||
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_VCN_FCLK 0x00000001
|
||||
#define DEBUG_OVERRIDE_NOT_USE 0x00000001
|
||||
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_DCN_FCLK 0x00000002
|
||||
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_MP0_FCLK 0x00000004
|
||||
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_VCN_DCFCLK 0x00000008
|
||||
@@ -161,6 +161,7 @@ typedef enum {
|
||||
#define DEBUG_OVERRIDE_ENABLE_SOC_VF_BRINGUP_MODE 0x00002000
|
||||
#define DEBUG_OVERRIDE_ENABLE_PER_WGP_RESIENCY 0x00004000
|
||||
#define DEBUG_OVERRIDE_DISABLE_MEMORY_VOLTAGE_SCALING 0x00008000
|
||||
#define DEBUG_OVERRIDE_DFLL_BTC_FCW_LOG 0x00010000
|
||||
|
||||
// VR Mapping Bit Defines
|
||||
#define VR_MAPPING_VR_SELECT_MASK 0x01
|
||||
@@ -391,6 +392,21 @@ typedef struct {
|
||||
EccInfo_t EccInfo[24];
|
||||
} EccInfoTable_t;
|
||||
|
||||
#define EPCS_HIGH_POWER 600
|
||||
#define EPCS_NORMAL_POWER 450
|
||||
#define EPCS_LOW_POWER 300
|
||||
#define EPCS_SHORTED_POWER 150
|
||||
#define EPCS_NO_BOOTUP 0
|
||||
|
||||
typedef enum{
|
||||
EPCS_SHORTED_LIMIT,
|
||||
EPCS_LOW_POWER_LIMIT,
|
||||
EPCS_NORMAL_POWER_LIMIT,
|
||||
EPCS_HIGH_POWER_LIMIT,
|
||||
EPCS_NOT_CONFIGURED,
|
||||
EPCS_STATUS_COUNT,
|
||||
} EPCS_STATUS_e;
|
||||
|
||||
//D3HOT sequences
|
||||
typedef enum {
|
||||
BACO_SEQUENCE,
|
||||
@@ -662,7 +678,7 @@ typedef enum {
|
||||
} PP_GRTAVFS_FW_SEP_FUSE_e;
|
||||
|
||||
#define PP_NUM_RTAVFS_PWL_ZONES 5
|
||||
|
||||
#define PP_NUM_PSM_DIDT_PWL_ZONES 3
|
||||
|
||||
// VBIOS or PPLIB configures telemetry slope and offset. Only slope expected to be set for SVI3
|
||||
// Slope Q1.7, Offset Q1.2
|
||||
@@ -746,10 +762,10 @@ typedef struct {
|
||||
uint16_t Padding;
|
||||
|
||||
//Frequency changes
|
||||
int16_t GfxclkFmin; // MHz
|
||||
int16_t GfxclkFmax; // MHz
|
||||
uint16_t UclkFmin; // MHz
|
||||
uint16_t UclkFmax; // MHz
|
||||
int16_t GfxclkFoffset;
|
||||
uint16_t Padding1;
|
||||
uint16_t UclkFmin;
|
||||
uint16_t UclkFmax;
|
||||
uint16_t FclkFmin;
|
||||
uint16_t FclkFmax;
|
||||
|
||||
@@ -770,19 +786,23 @@ typedef struct {
|
||||
uint8_t MaxOpTemp;
|
||||
|
||||
uint8_t AdvancedOdModeEnabled;
|
||||
uint8_t Padding1[3];
|
||||
uint8_t Padding2[3];
|
||||
|
||||
uint16_t GfxVoltageFullCtrlMode;
|
||||
uint16_t SocVoltageFullCtrlMode;
|
||||
uint16_t GfxclkFullCtrlMode;
|
||||
uint16_t UclkFullCtrlMode;
|
||||
uint16_t FclkFullCtrlMode;
|
||||
uint16_t Padding2;
|
||||
uint16_t Padding3;
|
||||
|
||||
int16_t GfxEdc;
|
||||
int16_t GfxPccLimitControl;
|
||||
|
||||
uint32_t Spare[10];
|
||||
uint16_t GfxclkFmaxVmax;
|
||||
uint8_t GfxclkFmaxVmaxTemperature;
|
||||
uint8_t Padding4[1];
|
||||
|
||||
uint32_t Spare[9];
|
||||
uint32_t MmHubPadding[8]; // SMU internal use. Adding here instead of external as a workaround
|
||||
} OverDriveTable_t;
|
||||
|
||||
@@ -802,8 +822,8 @@ typedef struct {
|
||||
uint16_t VddSocVmax;
|
||||
|
||||
//gfxclk
|
||||
int16_t GfxclkFmin; // MHz
|
||||
int16_t GfxclkFmax; // MHz
|
||||
int16_t GfxclkFoffset;
|
||||
uint16_t Padding;
|
||||
//uclk
|
||||
uint16_t UclkFmin; // MHz
|
||||
uint16_t UclkFmax; // MHz
|
||||
@@ -828,7 +848,7 @@ typedef struct {
|
||||
uint8_t FanZeroRpmEnable;
|
||||
//temperature
|
||||
uint8_t MaxOpTemp;
|
||||
uint8_t Padding[2];
|
||||
uint8_t Padding1[2];
|
||||
|
||||
//Full Ctrl
|
||||
uint16_t GfxVoltageFullCtrlMode;
|
||||
@@ -839,7 +859,7 @@ typedef struct {
|
||||
//EDC
|
||||
int16_t GfxEdc;
|
||||
int16_t GfxPccLimitControl;
|
||||
int16_t Padding1;
|
||||
int16_t Padding2;
|
||||
|
||||
uint32_t Spare[5];
|
||||
} OverDriveLimits_t;
|
||||
@@ -987,8 +1007,9 @@ typedef struct {
|
||||
uint16_t BaseClockDc;
|
||||
uint16_t GameClockDc;
|
||||
uint16_t BoostClockDc;
|
||||
|
||||
uint32_t Reserved[4];
|
||||
uint16_t MaxReportedClock;
|
||||
uint16_t Padding;
|
||||
uint32_t Reserved[3];
|
||||
} DriverReportedClocks_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -1132,7 +1153,7 @@ typedef struct {
|
||||
uint32_t DcModeMaxFreq [PPCLK_COUNT ]; // In MHz
|
||||
|
||||
uint16_t GfxclkAibFmax;
|
||||
uint16_t GfxclkFreqCap;
|
||||
uint16_t GfxDpmPadding;
|
||||
|
||||
//GFX Idle Power Settings
|
||||
uint16_t GfxclkFgfxoffEntry; // Entry in RLC stage (PLL), in Mhz
|
||||
@@ -1172,8 +1193,7 @@ typedef struct {
|
||||
uint32_t DvoFmaxLowScaler; //Unitless float
|
||||
|
||||
// GFX DCS
|
||||
uint16_t DcsGfxOffVoltage; //Voltage in mV(Q2) applied to VDDGFX when entering DCS GFXOFF phase
|
||||
uint16_t PaddingDcs;
|
||||
uint32_t PaddingDcs;
|
||||
|
||||
uint16_t DcsMinGfxOffTime; //Minimum amount of time PMFW shuts GFX OFF as part of GFX DCS phase
|
||||
uint16_t DcsMaxGfxOffTime; //Maximum amount of time PMFW can shut GFX OFF as part of GFX DCS phase at a stretch.
|
||||
@@ -1205,8 +1225,7 @@ typedef struct {
|
||||
uint16_t DalDcModeMaxUclkFreq;
|
||||
uint8_t PaddingsMem[2];
|
||||
//FCLK Section
|
||||
uint16_t FclkDpmDisallowPstateFreq; //Frequency which FW will target when indicated that display config cannot support P-state. Set to 0 use FW calculated value
|
||||
uint16_t PaddingFclk;
|
||||
uint32_t PaddingFclk;
|
||||
|
||||
// Link DPM Settings
|
||||
uint8_t PcieGenSpeed[NUM_LINK_LEVELS]; ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 3:PciE-gen4 4:PciE-gen5
|
||||
@@ -1215,12 +1234,19 @@ typedef struct {
|
||||
|
||||
// SECTION: VDD_GFX AVFS
|
||||
uint8_t OverrideGfxAvfsFuses;
|
||||
uint8_t GfxAvfsPadding[3];
|
||||
uint8_t GfxAvfsPadding[1];
|
||||
uint16_t DroopGBStDev;
|
||||
|
||||
uint32_t SocHwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT]; //new added for Soc domain
|
||||
uint32_t GfxL2HwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT]; //see fusedoc for encoding
|
||||
//uint32_t GfxSeHwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT];
|
||||
uint32_t spare_HwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT];
|
||||
|
||||
uint16_t PsmDidt_Vcross[PP_NUM_PSM_DIDT_PWL_ZONES-1];
|
||||
uint32_t PsmDidt_StaticDroop_A[PP_NUM_PSM_DIDT_PWL_ZONES];
|
||||
uint32_t PsmDidt_StaticDroop_B[PP_NUM_PSM_DIDT_PWL_ZONES];
|
||||
uint32_t PsmDidt_DynDroop_A[PP_NUM_PSM_DIDT_PWL_ZONES];
|
||||
uint32_t PsmDidt_DynDroop_B[PP_NUM_PSM_DIDT_PWL_ZONES];
|
||||
uint32_t spare_HwRtAvfsFuses[19];
|
||||
|
||||
uint32_t SocCommonRtAvfs[PP_GRTAVFS_FW_COMMON_FUSE_COUNT];
|
||||
uint32_t GfxCommonRtAvfs[PP_GRTAVFS_FW_COMMON_FUSE_COUNT];
|
||||
@@ -1246,11 +1272,7 @@ typedef struct {
|
||||
uint32_t dGbV_dT_vmin;
|
||||
uint32_t dGbV_dT_vmax;
|
||||
|
||||
//Unused: PMFW-9370
|
||||
uint32_t V2F_vmin_range_low;
|
||||
uint32_t V2F_vmin_range_high;
|
||||
uint32_t V2F_vmax_range_low;
|
||||
uint32_t V2F_vmax_range_high;
|
||||
uint32_t PaddingV2F[4];
|
||||
|
||||
AvfsDcBtcParams_t DcBtcGfxParams;
|
||||
QuadraticInt_t SSCurve_GFX;
|
||||
@@ -1327,18 +1349,18 @@ typedef struct {
|
||||
uint16_t PsmDidtReleaseTimer;
|
||||
uint32_t PsmDidtStallPattern; //Will be written to both pattern 1 and didt_static_level_prog
|
||||
// CAC EDC
|
||||
uint32_t Leakage_C0; // in IEEE float
|
||||
uint32_t Leakage_C1; // in IEEE float
|
||||
uint32_t Leakage_C2; // in IEEE float
|
||||
uint32_t Leakage_C3; // in IEEE float
|
||||
uint32_t Leakage_C4; // in IEEE float
|
||||
uint32_t Leakage_C5; // in IEEE float
|
||||
uint32_t GFX_CLK_SCALAR; // in IEEE float
|
||||
uint32_t GFX_CLK_INTERCEPT; // in IEEE float
|
||||
uint32_t GFX_CAC_M; // in IEEE float
|
||||
uint32_t GFX_CAC_B; // in IEEE float
|
||||
uint32_t VDD_GFX_CurrentLimitGuardband; // in IEEE float
|
||||
uint32_t DynToTotalCacScalar; // in IEEE
|
||||
uint32_t CacEdcCacLeakageC0;
|
||||
uint32_t CacEdcCacLeakageC1;
|
||||
uint32_t CacEdcCacLeakageC2;
|
||||
uint32_t CacEdcCacLeakageC3;
|
||||
uint32_t CacEdcCacLeakageC4;
|
||||
uint32_t CacEdcCacLeakageC5;
|
||||
uint32_t CacEdcGfxClkScalar;
|
||||
uint32_t CacEdcGfxClkIntercept;
|
||||
uint32_t CacEdcCac_m;
|
||||
uint32_t CacEdcCac_b;
|
||||
uint32_t CacEdcCurrLimitGuardband;
|
||||
uint32_t CacEdcDynToTotalCacRatio;
|
||||
// GFX EDC XVMIN
|
||||
uint32_t XVmin_Gfx_EdcThreshScalar;
|
||||
uint32_t XVmin_Gfx_EdcEnableFreq;
|
||||
@@ -1467,7 +1489,7 @@ typedef struct {
|
||||
uint8_t VddqOffEnabled;
|
||||
uint8_t PaddingUmcFlags[2];
|
||||
|
||||
uint32_t PostVoltageSetBacoDelay; // in microseconds. Amount of time FW will wait after power good is established or PSI0 command is issued
|
||||
uint32_t Paddign1;
|
||||
uint32_t BacoEntryDelay; // in milliseconds. Amount of time FW will wait to trigger BACO entry after receiving entry notification from OS
|
||||
|
||||
uint8_t FuseWritePowerMuxPresent;
|
||||
@@ -1530,7 +1552,7 @@ typedef struct {
|
||||
int16_t FuzzyFan_ErrorSetDelta;
|
||||
int16_t FuzzyFan_ErrorRateSetDelta;
|
||||
int16_t FuzzyFan_PwmSetDelta;
|
||||
uint16_t FuzzyFan_Reserved;
|
||||
uint16_t FanPadding2;
|
||||
|
||||
uint16_t FwCtfLimit[TEMP_COUNT];
|
||||
|
||||
@@ -1547,9 +1569,10 @@ typedef struct {
|
||||
uint16_t FanSpare[1];
|
||||
uint8_t FanIntakeSensorSupport;
|
||||
uint8_t FanIntakePadding;
|
||||
uint32_t FanAmbientPerfBoostThreshold;
|
||||
uint32_t FanSpare2[12];
|
||||
|
||||
uint32_t ODFeatureCtrlMask;
|
||||
|
||||
uint16_t TemperatureLimit_Hynix; // In degrees Celsius. Memory temperature limit associated with Hynix
|
||||
uint16_t TemperatureLimit_Micron; // In degrees Celsius. Memory temperature limit associated with Micron
|
||||
uint16_t TemperatureFwCtfLimit_Hynix;
|
||||
@@ -1637,7 +1660,7 @@ typedef struct {
|
||||
uint16_t AverageDclk0Frequency ;
|
||||
uint16_t AverageVclk1Frequency ;
|
||||
uint16_t AverageDclk1Frequency ;
|
||||
uint16_t PCIeBusy ;
|
||||
uint16_t AveragePCIeBusy ;
|
||||
uint16_t dGPU_W_MAX ;
|
||||
uint16_t padding ;
|
||||
|
||||
@@ -1665,12 +1688,12 @@ typedef struct {
|
||||
|
||||
uint16_t AverageGfxActivity ;
|
||||
uint16_t AverageUclkActivity ;
|
||||
uint16_t Vcn0ActivityPercentage ;
|
||||
uint16_t AverageVcn0ActivityPercentage;
|
||||
uint16_t Vcn1ActivityPercentage ;
|
||||
|
||||
uint32_t EnergyAccumulator;
|
||||
uint16_t AverageSocketPower;
|
||||
uint16_t MovingAverageTotalBoardPower;
|
||||
uint16_t AverageTotalBoardPower;
|
||||
|
||||
uint16_t AvgTemperature[TEMP_COUNT];
|
||||
uint16_t AvgTemperatureFanIntake;
|
||||
@@ -1684,7 +1707,8 @@ typedef struct {
|
||||
|
||||
|
||||
uint8_t ThrottlingPercentage[THROTTLER_COUNT];
|
||||
uint8_t padding1[3];
|
||||
uint8_t VmaxThrottlingPercentage;
|
||||
uint8_t padding1[2];
|
||||
|
||||
//metrics for D3hot entry/exit and driver ARM msgs
|
||||
uint32_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT];
|
||||
@@ -1693,7 +1717,7 @@ typedef struct {
|
||||
|
||||
uint16_t ApuSTAPMSmartShiftLimit;
|
||||
uint16_t ApuSTAPMLimit;
|
||||
uint16_t MovingAvgApuSocketPower;
|
||||
uint16_t AvgApuSocketPower;
|
||||
|
||||
uint16_t AverageUclkActivity_MAX;
|
||||
|
||||
@@ -1823,6 +1847,17 @@ typedef struct {
|
||||
#define TABLE_TRANSFER_FAILED 0xFF
|
||||
#define TABLE_TRANSFER_PENDING 0xAB
|
||||
|
||||
#define TABLE_PPT_FAILED 0x100
|
||||
#define TABLE_TDC_FAILED 0x200
|
||||
#define TABLE_TEMP_FAILED 0x400
|
||||
#define TABLE_FAN_TARGET_TEMP_FAILED 0x800
|
||||
#define TABLE_FAN_STOP_TEMP_FAILED 0x1000
|
||||
#define TABLE_FAN_START_TEMP_FAILED 0x2000
|
||||
#define TABLE_FAN_PWM_MIN_FAILED 0x4000
|
||||
#define TABLE_ACOUSTIC_TARGET_RPM_FAILED 0x8000
|
||||
#define TABLE_ACOUSTIC_LIMIT_RPM_FAILED 0x10000
|
||||
#define TABLE_MGPU_ACOUSTIC_TARGET_RPM_FAILED 0x20000
|
||||
|
||||
// Table types
|
||||
#define TABLE_PPTABLE 0
|
||||
#define TABLE_COMBO_PPTABLE 1
|
||||
@@ -1849,5 +1884,6 @@ typedef struct {
|
||||
#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7
|
||||
#define IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8
|
||||
#define IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9
|
||||
#define IH_INTERRUPT_CONTEXT_ID_DYNAMIC_TABLE 0xA
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF
|
||||
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7
|
||||
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6
|
||||
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x26
|
||||
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E
|
||||
|
||||
#define FEATURE_MASK(feature) (1ULL << feature)
|
||||
|
||||
|
||||
@@ -1077,12 +1077,9 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
|
||||
|
||||
switch (od_feature_bit) {
|
||||
case PP_OD_FEATURE_GFXCLK_FMIN:
|
||||
od_min_setting = overdrive_lowerlimits->GfxclkFmin;
|
||||
od_max_setting = overdrive_upperlimits->GfxclkFmin;
|
||||
break;
|
||||
case PP_OD_FEATURE_GFXCLK_FMAX:
|
||||
od_min_setting = overdrive_lowerlimits->GfxclkFmax;
|
||||
od_max_setting = overdrive_upperlimits->GfxclkFmax;
|
||||
od_min_setting = overdrive_lowerlimits->GfxclkFoffset;
|
||||
od_max_setting = overdrive_upperlimits->GfxclkFoffset;
|
||||
break;
|
||||
case PP_OD_FEATURE_UCLK_FMIN:
|
||||
od_min_setting = overdrive_lowerlimits->UclkFmin;
|
||||
@@ -1269,10 +1266,16 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
|
||||
PP_OD_FEATURE_GFXCLK_BIT))
|
||||
break;
|
||||
|
||||
size += sysfs_emit_at(buf, size, "OD_SCLK:\n");
|
||||
size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
|
||||
od_table->OverDriveTable.GfxclkFmin,
|
||||
od_table->OverDriveTable.GfxclkFmax);
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
const OverDriveLimits_t * const overdrive_upperlimits =
|
||||
&pptable->SkuTable.OverDriveLimitsBasicMax;
|
||||
const OverDriveLimits_t * const overdrive_lowerlimits =
|
||||
&pptable->SkuTable.OverDriveLimitsBasicMin;
|
||||
|
||||
size += sysfs_emit_at(buf, size, "OD_SCLK_OFFSET:\n");
|
||||
size += sysfs_emit_at(buf, size, "0: %dMhz\n1: %uMhz\n",
|
||||
overdrive_lowerlimits->GfxclkFoffset,
|
||||
overdrive_upperlimits->GfxclkFoffset);
|
||||
break;
|
||||
|
||||
case SMU_OD_MCLK:
|
||||
@@ -1414,7 +1417,7 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
|
||||
PP_OD_FEATURE_GFXCLK_FMAX,
|
||||
NULL,
|
||||
&max_value);
|
||||
size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
|
||||
size += sysfs_emit_at(buf, size, "SCLK_OFFSET: %7dMhz %10uMhz\n",
|
||||
min_value, max_value);
|
||||
}
|
||||
|
||||
@@ -1796,7 +1799,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
|
||||
DpmActivityMonitorCoeffInt_t *activity_monitor =
|
||||
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
|
||||
int workload_type, ret = 0;
|
||||
|
||||
uint32_t current_profile_mode = smu->power_profile_mode;
|
||||
smu->power_profile_mode = input[size];
|
||||
|
||||
if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
|
||||
@@ -1854,6 +1857,11 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
|
||||
}
|
||||
}
|
||||
|
||||
if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
|
||||
smu_v14_0_deep_sleep_control(smu, false);
|
||||
else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
|
||||
smu_v14_0_deep_sleep_control(smu, true);
|
||||
|
||||
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
|
||||
workload_type = smu_cmn_to_asic_specific_index(smu,
|
||||
CMN2ASIC_MAPPING_WORKLOAD,
|
||||
@@ -2158,7 +2166,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
||||
|
||||
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
|
||||
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
|
||||
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
|
||||
gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage,
|
||||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
@@ -2217,8 +2225,7 @@ static void smu_v14_0_2_dump_od_table(struct smu_context *smu,
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
dev_dbg(adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->OverDriveTable.GfxclkFmin,
|
||||
od_table->OverDriveTable.GfxclkFmax);
|
||||
dev_dbg(adev->dev, "OD: Gfxclk offset: (%d)\n", od_table->OverDriveTable.GfxclkFoffset);
|
||||
dev_dbg(adev->dev, "OD: Uclk: (%d, %d)\n", od_table->OverDriveTable.UclkFmin,
|
||||
od_table->OverDriveTable.UclkFmax);
|
||||
}
|
||||
@@ -2309,10 +2316,8 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
|
||||
memcpy(user_od_table,
|
||||
boot_od_table,
|
||||
sizeof(OverDriveTableExternal_t));
|
||||
user_od_table->OverDriveTable.GfxclkFmin =
|
||||
user_od_table_bak.OverDriveTable.GfxclkFmin;
|
||||
user_od_table->OverDriveTable.GfxclkFmax =
|
||||
user_od_table_bak.OverDriveTable.GfxclkFmax;
|
||||
user_od_table->OverDriveTable.GfxclkFoffset =
|
||||
user_od_table_bak.OverDriveTable.GfxclkFoffset;
|
||||
user_od_table->OverDriveTable.UclkFmin =
|
||||
user_od_table_bak.OverDriveTable.UclkFmin;
|
||||
user_od_table->OverDriveTable.UclkFmax =
|
||||
@@ -2441,22 +2446,6 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
|
||||
}
|
||||
|
||||
switch (input[i]) {
|
||||
case 0:
|
||||
smu_v14_0_2_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_GFXCLK_FMIN,
|
||||
&minimum,
|
||||
&maximum);
|
||||
if (input[i + 1] < minimum ||
|
||||
input[i + 1] > maximum) {
|
||||
dev_info(adev->dev, "GfxclkFmin (%ld) must be within [%u, %u]!\n",
|
||||
input[i + 1], minimum, maximum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
od_table->OverDriveTable.GfxclkFmin = input[i + 1];
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
smu_v14_0_2_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_GFXCLK_FMAX,
|
||||
@@ -2469,7 +2458,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
od_table->OverDriveTable.GfxclkFmax = input[i + 1];
|
||||
od_table->OverDriveTable.GfxclkFoffset = input[i + 1];
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
|
||||
break;
|
||||
|
||||
@@ -2480,13 +2469,6 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
|
||||
}
|
||||
}
|
||||
|
||||
if (od_table->OverDriveTable.GfxclkFmin > od_table->OverDriveTable.GfxclkFmax) {
|
||||
dev_err(adev->dev,
|
||||
"Invalid setting: GfxclkFmin(%u) is bigger than GfxclkFmax(%u)\n",
|
||||
(uint32_t)od_table->OverDriveTable.GfxclkFmin,
|
||||
(uint32_t)od_table->OverDriveTable.GfxclkFmax);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_MCLK_VDDC_TABLE:
|
||||
|
||||
@@ -58,9 +58,10 @@ int drm_aux_bridge_register(struct device *parent)
|
||||
adev->id = ret;
|
||||
adev->name = "aux_bridge";
|
||||
adev->dev.parent = parent;
|
||||
adev->dev.of_node = of_node_get(parent->of_node);
|
||||
adev->dev.release = drm_aux_bridge_release;
|
||||
|
||||
device_set_of_node_from_dev(&adev->dev, parent);
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret) {
|
||||
ida_free(&drm_aux_bridge_ida, adev->id);
|
||||
|
||||
@@ -2391,6 +2391,7 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc)
|
||||
if (tc->pre_emphasis[0] < 0 || tc->pre_emphasis[0] > 2 ||
|
||||
tc->pre_emphasis[1] < 0 || tc->pre_emphasis[1] > 2) {
|
||||
dev_err(dev, "Incorrect Pre-Emphasis setting, use either 0=0dB 1=3.5dB 2=6dB\n");
|
||||
of_node_put(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +123,8 @@ config DRM_I915_USERPTR
|
||||
config DRM_I915_GVT_KVMGT
|
||||
tristate "Enable KVM host support Intel GVT-g graphics virtualization"
|
||||
depends on DRM_I915
|
||||
depends on X86
|
||||
depends on KVM_X86
|
||||
depends on 64BIT
|
||||
depends on KVM
|
||||
depends on VFIO
|
||||
select DRM_I915_GVT
|
||||
select KVM_EXTERNAL_WRITE_TRACKING
|
||||
|
||||
@@ -890,7 +890,7 @@ void xe_device_l2_flush(struct xe_device *xe)
|
||||
spin_lock(>->global_invl_lock);
|
||||
xe_mmio_write32(gt, XE2_GLOBAL_INVAL, 0x1);
|
||||
|
||||
if (xe_mmio_wait32(gt, XE2_GLOBAL_INVAL, 0x1, 0x0, 150, NULL, true))
|
||||
if (xe_mmio_wait32(gt, XE2_GLOBAL_INVAL, 0x1, 0x0, 500, NULL, true))
|
||||
xe_gt_err_once(gt, "Global invalidation timeout\n");
|
||||
spin_unlock(>->global_invl_lock);
|
||||
|
||||
|
||||
@@ -115,9 +115,15 @@ static int __domain_wait(struct xe_gt *gt, struct xe_force_wake_domain *domain,
|
||||
XE_FORCE_WAKE_ACK_TIMEOUT_MS * USEC_PER_MSEC,
|
||||
&value, true);
|
||||
if (ret)
|
||||
xe_gt_notice(gt, "Force wake domain %d failed to ack %s (%pe) reg[%#x] = %#x\n",
|
||||
domain->id, str_wake_sleep(wake), ERR_PTR(ret),
|
||||
domain->reg_ack.addr, value);
|
||||
xe_gt_err(gt, "Force wake domain %d failed to ack %s (%pe) reg[%#x] = %#x\n",
|
||||
domain->id, str_wake_sleep(wake), ERR_PTR(ret),
|
||||
domain->reg_ack.addr, value);
|
||||
if (value == ~0) {
|
||||
xe_gt_err(gt,
|
||||
"Force wake domain %d: %s. MMIO unreliable (forcewake register returns 0xFFFFFFFF)!\n",
|
||||
domain->id, str_wake_sleep(wake));
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -897,6 +897,24 @@ retry_same_fence:
|
||||
|
||||
ret = wait_event_timeout(ct->g2h_fence_wq, g2h_fence.done, HZ);
|
||||
|
||||
/*
|
||||
* Occasionally it is seen that the G2H worker starts running after a delay of more than
|
||||
* a second even after being queued and activated by the Linux workqueue subsystem. This
|
||||
* leads to G2H timeout error. The root cause of issue lies with scheduling latency of
|
||||
* Lunarlake Hybrid CPU. Issue dissappears if we disable Lunarlake atom cores from BIOS
|
||||
* and this is beyond xe kmd.
|
||||
*
|
||||
* TODO: Drop this change once workqueue scheduling delay issue is fixed on LNL Hybrid CPU.
|
||||
*/
|
||||
if (!ret) {
|
||||
flush_work(&ct->g2h_worker);
|
||||
if (g2h_fence.done) {
|
||||
xe_gt_warn(gt, "G2H fence %u, action %04x, done\n",
|
||||
g2h_fence.seqno, action[0]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we serialize with completion side to prevent UAF with fence going out of scope on
|
||||
* the stack, since we have no clue if it will fire after the timeout before we can erase
|
||||
|
||||
@@ -1726,8 +1726,13 @@ void xe_guc_submit_stop(struct xe_guc *guc)
|
||||
|
||||
mutex_lock(&guc->submission_state.lock);
|
||||
|
||||
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
|
||||
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) {
|
||||
/* Prevent redundant attempts to stop parallel queues */
|
||||
if (q->guc->id != index)
|
||||
continue;
|
||||
|
||||
guc_exec_queue_stop(guc, q);
|
||||
}
|
||||
|
||||
mutex_unlock(&guc->submission_state.lock);
|
||||
|
||||
@@ -1765,8 +1770,13 @@ int xe_guc_submit_start(struct xe_guc *guc)
|
||||
|
||||
mutex_lock(&guc->submission_state.lock);
|
||||
atomic_dec(&guc->submission_state.stopped);
|
||||
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
|
||||
xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) {
|
||||
/* Prevent redundant attempts to start parallel queues */
|
||||
if (q->guc->id != index)
|
||||
continue;
|
||||
|
||||
guc_exec_queue_start(q);
|
||||
}
|
||||
mutex_unlock(&guc->submission_state.lock);
|
||||
|
||||
wake_up_all(&guc->ct.wq);
|
||||
|
||||
@@ -54,8 +54,9 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
|
||||
{
|
||||
struct xe_user_fence *ufence;
|
||||
u64 __user *ptr = u64_to_user_ptr(addr);
|
||||
u64 __maybe_unused prefetch_val;
|
||||
|
||||
if (!access_ok(ptr, sizeof(*ptr)))
|
||||
if (get_user(prefetch_val, ptr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
|
||||
|
||||
@@ -509,6 +509,7 @@
|
||||
#define I2C_DEVICE_ID_GOODIX_01E8 0x01e8
|
||||
#define I2C_DEVICE_ID_GOODIX_01E9 0x01e9
|
||||
#define I2C_DEVICE_ID_GOODIX_01F0 0x01f0
|
||||
#define I2C_DEVICE_ID_GOODIX_0D42 0x0d42
|
||||
|
||||
#define USB_VENDOR_ID_GOODTOUCH 0x1aad
|
||||
#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f
|
||||
@@ -868,6 +869,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
|
||||
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
|
||||
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
|
||||
#define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548
|
||||
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
|
||||
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
|
||||
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
|
||||
|
||||
@@ -473,6 +473,7 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
|
||||
usage, bit, max);
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
|
||||
default:
|
||||
return 0;
|
||||
@@ -583,6 +584,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -776,6 +778,7 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||
return lenovo_event_cptkbd(hdev, field, usage, value);
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
return lenovo_event_tp10ubkbd(hdev, field, usage, value);
|
||||
default:
|
||||
return 0;
|
||||
@@ -1056,6 +1059,7 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
|
||||
break;
|
||||
}
|
||||
@@ -1286,6 +1290,7 @@ static int lenovo_probe(struct hid_device *hdev,
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_probe_tp10ubkbd(hdev);
|
||||
break;
|
||||
default:
|
||||
@@ -1372,6 +1377,7 @@ static void lenovo_remove(struct hid_device *hdev)
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
lenovo_remove_tp10ubkbd(hdev);
|
||||
break;
|
||||
}
|
||||
@@ -1421,6 +1427,8 @@ static const struct hid_device_id lenovo_devices[] = {
|
||||
*/
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -2146,6 +2146,10 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD) },
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER) },
|
||||
|
||||
/* MosArt panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3)
|
||||
#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4)
|
||||
#define I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND BIT(5)
|
||||
#define I2C_HID_QUIRK_DELAY_WAKEUP_AFTER_RESUME BIT(6)
|
||||
|
||||
/* Command opcodes */
|
||||
#define I2C_HID_OPCODE_RESET 0x01
|
||||
@@ -140,6 +141,8 @@ static const struct i2c_hid_quirks {
|
||||
{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
|
||||
I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET |
|
||||
I2C_HID_QUIRK_BOGUS_IRQ },
|
||||
{ I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_0D42,
|
||||
I2C_HID_QUIRK_DELAY_WAKEUP_AFTER_RESUME },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -981,6 +984,13 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* On Goodix 27c6:0d42 wait extra time before device wakeup.
|
||||
* It's not clear why but if we send wakeup too early, the device will
|
||||
* never trigger input interrupts.
|
||||
*/
|
||||
if (ihid->quirks & I2C_HID_QUIRK_DELAY_WAKEUP_AFTER_RESUME)
|
||||
msleep(1500);
|
||||
|
||||
/* Instead of resetting device, simply powers the device on. This
|
||||
* solves "incomplete reports" on Raydium devices 2386:3118 and
|
||||
* 2386:4B33 and fixes various SIS touchscreens no longer sending
|
||||
|
||||
+23
-1
@@ -546,6 +546,26 @@ static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_n
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The only difference from bio_chain_endio() is that the current
|
||||
* bi_status of bio does not affect the bi_status of parent.
|
||||
*/
|
||||
static void md_end_flush(struct bio *bio)
|
||||
{
|
||||
struct bio *parent = bio->bi_private;
|
||||
|
||||
/*
|
||||
* If any flush io error before the power failure,
|
||||
* disk data may be lost.
|
||||
*/
|
||||
if (bio->bi_status)
|
||||
pr_err("md: %pg flush io error %d\n", bio->bi_bdev,
|
||||
blk_status_to_errno(bio->bi_status));
|
||||
|
||||
bio_put(bio);
|
||||
bio_endio(parent);
|
||||
}
|
||||
|
||||
bool md_flush_request(struct mddev *mddev, struct bio *bio)
|
||||
{
|
||||
struct md_rdev *rdev;
|
||||
@@ -565,7 +585,9 @@ bool md_flush_request(struct mddev *mddev, struct bio *bio)
|
||||
new = bio_alloc_bioset(rdev->bdev, 0,
|
||||
REQ_OP_WRITE | REQ_PREFLUSH, GFP_NOIO,
|
||||
&mddev->bio_set);
|
||||
bio_chain(new, bio);
|
||||
new->bi_private = bio;
|
||||
new->bi_end_io = md_end_flush;
|
||||
bio_inc_remaining(bio);
|
||||
submit_bio(new);
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -4061,9 +4061,12 @@ static int raid10_run(struct mddev *mddev)
|
||||
}
|
||||
|
||||
if (!mddev_is_dm(conf->mddev)) {
|
||||
ret = raid10_set_queue_limits(mddev);
|
||||
if (ret)
|
||||
int err = raid10_set_queue_limits(mddev);
|
||||
|
||||
if (err) {
|
||||
ret = err;
|
||||
goto out_free_conf;
|
||||
}
|
||||
}
|
||||
|
||||
/* need to check that every block has at least one working mirror */
|
||||
|
||||
@@ -2733,26 +2733,27 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
|
||||
return MICREL_KSZ8_P1_ERRATA;
|
||||
break;
|
||||
case KSZ8567_CHIP_ID:
|
||||
/* KSZ8567R Errata DS80000752C Module 4 */
|
||||
case KSZ8765_CHIP_ID:
|
||||
case KSZ8794_CHIP_ID:
|
||||
case KSZ8795_CHIP_ID:
|
||||
/* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */
|
||||
case KSZ9477_CHIP_ID:
|
||||
/* KSZ9477S Errata DS80000754A Module 4 */
|
||||
case KSZ9567_CHIP_ID:
|
||||
/* KSZ9567S Errata DS80000756A Module 4 */
|
||||
case KSZ9896_CHIP_ID:
|
||||
/* KSZ9896C Errata DS80000757A Module 3 */
|
||||
case KSZ9897_CHIP_ID:
|
||||
/* KSZ9477 Errata DS80000754C
|
||||
*
|
||||
* Module 4: Energy Efficient Ethernet (EEE) feature select must
|
||||
* be manually disabled
|
||||
/* KSZ9897R Errata DS80000758C Module 4 */
|
||||
/* Energy Efficient Ethernet (EEE) feature select must be manually disabled
|
||||
* The EEE feature is enabled by default, but it is not fully
|
||||
* operational. It must be manually disabled through register
|
||||
* controls. If not disabled, the PHY ports can auto-negotiate
|
||||
* to enable EEE, and this feature can cause link drops when
|
||||
* linked to another device supporting EEE.
|
||||
*
|
||||
* The same item appears in the errata for the KSZ9567, KSZ9896,
|
||||
* and KSZ9897.
|
||||
*
|
||||
* A similar item appears in the errata for the KSZ8567, but
|
||||
* provides an alternative workaround. For now, use the simple
|
||||
* workaround of disabling the EEE feature for this device too.
|
||||
* The same item appears in the errata for all switches above.
|
||||
*/
|
||||
return MICREL_NO_EEE;
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ struct mv88e6xxx_gpio_ops;
|
||||
struct mv88e6xxx_avb_ops;
|
||||
struct mv88e6xxx_ptp_ops;
|
||||
struct mv88e6xxx_pcs_ops;
|
||||
struct mv88e6xxx_cc_coeffs;
|
||||
|
||||
struct mv88e6xxx_irq {
|
||||
u16 masked;
|
||||
@@ -408,6 +409,7 @@ struct mv88e6xxx_chip {
|
||||
struct cyclecounter tstamp_cc;
|
||||
struct timecounter tstamp_tc;
|
||||
struct delayed_work overflow_work;
|
||||
const struct mv88e6xxx_cc_coeffs *cc_coeffs;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_info;
|
||||
@@ -731,10 +733,6 @@ struct mv88e6xxx_ptp_ops {
|
||||
int arr1_sts_reg;
|
||||
int dep_sts_reg;
|
||||
u32 rx_filters;
|
||||
u32 cc_shift;
|
||||
u32 cc_mult;
|
||||
u32 cc_mult_num;
|
||||
u32 cc_mult_dem;
|
||||
};
|
||||
|
||||
struct mv88e6xxx_pcs_ops {
|
||||
|
||||
@@ -1713,6 +1713,7 @@ int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,
|
||||
ptr = shift / 8;
|
||||
shift %= 8;
|
||||
mask >>= ptr * 8;
|
||||
ptr <<= 8;
|
||||
|
||||
err = mv88e6393x_port_policy_read(chip, port, ptr, ®);
|
||||
if (err)
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
|
||||
#define MV88E6XXX_MAX_ADJ_PPB 1000000
|
||||
|
||||
struct mv88e6xxx_cc_coeffs {
|
||||
u32 cc_shift;
|
||||
u32 cc_mult;
|
||||
u32 cc_mult_num;
|
||||
u32 cc_mult_dem;
|
||||
};
|
||||
|
||||
/* Family MV88E6250:
|
||||
* Raw timestamps are in units of 10-ns clock periods.
|
||||
*
|
||||
@@ -25,22 +32,43 @@
|
||||
* simplifies to
|
||||
* clkadj = scaled_ppm * 2^7 / 5^5
|
||||
*/
|
||||
#define MV88E6250_CC_SHIFT 28
|
||||
#define MV88E6250_CC_MULT (10 << MV88E6250_CC_SHIFT)
|
||||
#define MV88E6250_CC_MULT_NUM (1 << 7)
|
||||
#define MV88E6250_CC_MULT_DEM 3125ULL
|
||||
#define MV88E6XXX_CC_10NS_SHIFT 28
|
||||
static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_10ns_coeffs = {
|
||||
.cc_shift = MV88E6XXX_CC_10NS_SHIFT,
|
||||
.cc_mult = 10 << MV88E6XXX_CC_10NS_SHIFT,
|
||||
.cc_mult_num = 1 << 7,
|
||||
.cc_mult_dem = 3125ULL,
|
||||
};
|
||||
|
||||
/* Other families:
|
||||
/* Other families except MV88E6393X in internal clock mode:
|
||||
* Raw timestamps are in units of 8-ns clock periods.
|
||||
*
|
||||
* clkadj = scaled_ppm * 8*2^28 / (10^6 * 2^16)
|
||||
* simplifies to
|
||||
* clkadj = scaled_ppm * 2^9 / 5^6
|
||||
*/
|
||||
#define MV88E6XXX_CC_SHIFT 28
|
||||
#define MV88E6XXX_CC_MULT (8 << MV88E6XXX_CC_SHIFT)
|
||||
#define MV88E6XXX_CC_MULT_NUM (1 << 9)
|
||||
#define MV88E6XXX_CC_MULT_DEM 15625ULL
|
||||
#define MV88E6XXX_CC_8NS_SHIFT 28
|
||||
static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_8ns_coeffs = {
|
||||
.cc_shift = MV88E6XXX_CC_8NS_SHIFT,
|
||||
.cc_mult = 8 << MV88E6XXX_CC_8NS_SHIFT,
|
||||
.cc_mult_num = 1 << 9,
|
||||
.cc_mult_dem = 15625ULL
|
||||
};
|
||||
|
||||
/* Family MV88E6393X using internal clock:
|
||||
* Raw timestamps are in units of 4-ns clock periods.
|
||||
*
|
||||
* clkadj = scaled_ppm * 4*2^28 / (10^6 * 2^16)
|
||||
* simplifies to
|
||||
* clkadj = scaled_ppm * 2^8 / 5^6
|
||||
*/
|
||||
#define MV88E6XXX_CC_4NS_SHIFT 28
|
||||
static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_4ns_coeffs = {
|
||||
.cc_shift = MV88E6XXX_CC_4NS_SHIFT,
|
||||
.cc_mult = 4 << MV88E6XXX_CC_4NS_SHIFT,
|
||||
.cc_mult_num = 1 << 8,
|
||||
.cc_mult_dem = 15625ULL
|
||||
};
|
||||
|
||||
#define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100)
|
||||
|
||||
@@ -83,6 +111,33 @@ static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
|
||||
return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
|
||||
}
|
||||
|
||||
static const struct mv88e6xxx_cc_coeffs *
|
||||
mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
|
||||
{
|
||||
u16 period_ps;
|
||||
int err;
|
||||
|
||||
err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_CLOCK_PERIOD, &period_ps, 1);
|
||||
if (err) {
|
||||
dev_err(chip->dev, "failed to read cycle counter period: %d\n",
|
||||
err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
switch (period_ps) {
|
||||
case 4000:
|
||||
return &mv88e6xxx_cc_4ns_coeffs;
|
||||
case 8000:
|
||||
return &mv88e6xxx_cc_8ns_coeffs;
|
||||
case 10000:
|
||||
return &mv88e6xxx_cc_10ns_coeffs;
|
||||
default:
|
||||
dev_err(chip->dev, "unexpected cycle counter period of %u ps\n",
|
||||
period_ps);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
|
||||
@@ -204,7 +259,6 @@ out:
|
||||
static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
|
||||
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
|
||||
int neg_adj = 0;
|
||||
u32 diff, mult;
|
||||
u64 adj;
|
||||
@@ -214,10 +268,10 @@ static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
scaled_ppm = -scaled_ppm;
|
||||
}
|
||||
|
||||
mult = ptp_ops->cc_mult;
|
||||
adj = ptp_ops->cc_mult_num;
|
||||
mult = chip->cc_coeffs->cc_mult;
|
||||
adj = chip->cc_coeffs->cc_mult_num;
|
||||
adj *= scaled_ppm;
|
||||
diff = div_u64(adj, ptp_ops->cc_mult_dem);
|
||||
diff = div_u64(adj, chip->cc_coeffs->cc_mult_dem);
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
@@ -364,10 +418,6 @@ const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
|
||||
.cc_shift = MV88E6XXX_CC_SHIFT,
|
||||
.cc_mult = MV88E6XXX_CC_MULT,
|
||||
.cc_mult_num = MV88E6XXX_CC_MULT_NUM,
|
||||
.cc_mult_dem = MV88E6XXX_CC_MULT_DEM,
|
||||
};
|
||||
|
||||
const struct mv88e6xxx_ptp_ops mv88e6250_ptp_ops = {
|
||||
@@ -391,10 +441,6 @@ const struct mv88e6xxx_ptp_ops mv88e6250_ptp_ops = {
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
|
||||
.cc_shift = MV88E6250_CC_SHIFT,
|
||||
.cc_mult = MV88E6250_CC_MULT,
|
||||
.cc_mult_num = MV88E6250_CC_MULT_NUM,
|
||||
.cc_mult_dem = MV88E6250_CC_MULT_DEM,
|
||||
};
|
||||
|
||||
const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
|
||||
@@ -418,10 +464,6 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
|
||||
.cc_shift = MV88E6XXX_CC_SHIFT,
|
||||
.cc_mult = MV88E6XXX_CC_MULT,
|
||||
.cc_mult_num = MV88E6XXX_CC_MULT_NUM,
|
||||
.cc_mult_dem = MV88E6XXX_CC_MULT_DEM,
|
||||
};
|
||||
|
||||
const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
|
||||
@@ -446,10 +488,6 @@ const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
|
||||
.cc_shift = MV88E6XXX_CC_SHIFT,
|
||||
.cc_mult = MV88E6XXX_CC_MULT,
|
||||
.cc_mult_num = MV88E6XXX_CC_MULT_NUM,
|
||||
.cc_mult_dem = MV88E6XXX_CC_MULT_DEM,
|
||||
};
|
||||
|
||||
static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
|
||||
@@ -462,10 +500,10 @@ static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
|
||||
/* With a 250MHz input clock, the 32-bit timestamp counter overflows in ~17.2
|
||||
* seconds; this task forces periodic reads so that we don't miss any.
|
||||
*/
|
||||
#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 16)
|
||||
#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 8)
|
||||
static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
@@ -484,11 +522,15 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
|
||||
int i;
|
||||
|
||||
/* Set up the cycle counter */
|
||||
chip->cc_coeffs = mv88e6xxx_cc_coeff_get(chip);
|
||||
if (IS_ERR(chip->cc_coeffs))
|
||||
return PTR_ERR(chip->cc_coeffs);
|
||||
|
||||
memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
|
||||
chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read;
|
||||
chip->tstamp_cc.mask = CYCLECOUNTER_MASK(32);
|
||||
chip->tstamp_cc.mult = ptp_ops->cc_mult;
|
||||
chip->tstamp_cc.shift = ptp_ops->cc_shift;
|
||||
chip->tstamp_cc.mult = chip->cc_coeffs->cc_mult;
|
||||
chip->tstamp_cc.shift = chip->cc_coeffs->cc_shift;
|
||||
|
||||
timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc,
|
||||
ktime_to_ns(ktime_get_real()));
|
||||
|
||||
@@ -2254,10 +2254,11 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
||||
|
||||
if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) {
|
||||
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
ns = timecounter_cyc2time(&ptp->tc, ts);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
memset(skb_hwtstamps(skb), 0,
|
||||
sizeof(*skb_hwtstamps(skb)));
|
||||
skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
|
||||
@@ -2757,17 +2758,18 @@ static int bnxt_async_event_process(struct bnxt *bp,
|
||||
case ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_FLAGS_PHC_RTC_UPDATE:
|
||||
if (BNXT_PTP_USE_RTC(bp)) {
|
||||
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
|
||||
if (!ptp)
|
||||
goto async_event_process_exit;
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
bnxt_ptp_update_current_time(bp);
|
||||
ns = (((u64)BNXT_EVENT_PHC_RTC_UPDATE(data1) <<
|
||||
BNXT_PHC_BITS) | ptp->current_time);
|
||||
bnxt_ptp_rtc_timecounter_init(ptp, ns);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -13494,9 +13496,11 @@ static void bnxt_force_fw_reset(struct bnxt *bp)
|
||||
return;
|
||||
|
||||
if (ptp) {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
} else {
|
||||
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
|
||||
}
|
||||
@@ -13561,9 +13565,11 @@ void bnxt_fw_reset(struct bnxt *bp)
|
||||
int n = 0, tmo;
|
||||
|
||||
if (ptp) {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
} else {
|
||||
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
|
||||
}
|
||||
|
||||
@@ -62,13 +62,14 @@ static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
|
||||
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
|
||||
ptp_info);
|
||||
u64 ns = timespec64_to_ns(ts);
|
||||
unsigned long flags;
|
||||
|
||||
if (BNXT_PTP_USE_RTC(ptp->bp))
|
||||
return bnxt_ptp_cfg_settime(ptp->bp, ns);
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
timecounter_init(&ptp->tc, &ptp->cc, ns);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,13 +101,14 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
|
||||
static void bnxt_ptp_get_current_time(struct bnxt *bp)
|
||||
{
|
||||
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
|
||||
unsigned long flags;
|
||||
|
||||
if (!ptp)
|
||||
return;
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
WRITE_ONCE(ptp->old_time, ptp->current_time);
|
||||
bnxt_refclk_read(bp, NULL, &ptp->current_time);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
}
|
||||
|
||||
static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts,
|
||||
@@ -149,17 +151,18 @@ static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
|
||||
{
|
||||
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
|
||||
ptp_info);
|
||||
unsigned long flags;
|
||||
u64 ns, cycles;
|
||||
int rc;
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
rc = bnxt_refclk_read(ptp->bp, sts, &cycles);
|
||||
if (rc) {
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
ns = timecounter_cyc2time(&ptp->tc, cycles);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
@@ -177,6 +180,7 @@ void bnxt_ptp_update_current_time(struct bnxt *bp)
|
||||
static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
|
||||
{
|
||||
struct hwrm_port_mac_cfg_input *req;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
rc = hwrm_req_init(ptp->bp, req, HWRM_PORT_MAC_CFG);
|
||||
@@ -190,9 +194,9 @@ static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
|
||||
if (rc) {
|
||||
netdev_err(ptp->bp->dev, "ptp adjphc failed. rc = %x\n", rc);
|
||||
} else {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
bnxt_ptp_update_current_time(ptp->bp);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -202,13 +206,14 @@ static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
|
||||
{
|
||||
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
|
||||
ptp_info);
|
||||
unsigned long flags;
|
||||
|
||||
if (BNXT_PTP_USE_RTC(ptp->bp))
|
||||
return bnxt_ptp_adjphc(ptp, delta);
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
timecounter_adjtime(&ptp->tc, delta);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -236,14 +241,15 @@ static int bnxt_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
|
||||
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
|
||||
ptp_info);
|
||||
struct bnxt *bp = ptp->bp;
|
||||
unsigned long flags;
|
||||
|
||||
if (!BNXT_MH(bp))
|
||||
return bnxt_ptp_adjfine_rtc(bp, scaled_ppm);
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
timecounter_read(&ptp->tc);
|
||||
ptp->cc.mult = adjust_by_scaled_ppm(ptp->cmult, scaled_ppm);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -251,12 +257,13 @@ void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2)
|
||||
{
|
||||
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
|
||||
struct ptp_clock_event event;
|
||||
unsigned long flags;
|
||||
u64 ns, pps_ts;
|
||||
|
||||
pps_ts = EVENT_PPS_TS(data2, data1);
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
ns = timecounter_cyc2time(&ptp->tc, pps_ts);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
|
||||
switch (EVENT_DATA2_PPS_EVENT_TYPE(data2)) {
|
||||
case ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_INTERNAL:
|
||||
@@ -393,16 +400,17 @@ static int bnxt_get_target_cycles(struct bnxt_ptp_cfg *ptp, u64 target_ns,
|
||||
{
|
||||
u64 cycles_now;
|
||||
u64 nsec_now, nsec_delta;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
rc = bnxt_refclk_read(ptp->bp, NULL, &cycles_now);
|
||||
if (rc) {
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
nsec_now = timecounter_cyc2time(&ptp->tc, cycles_now);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
|
||||
nsec_delta = target_ns - nsec_now;
|
||||
*cycles_delta = div64_u64(nsec_delta << ptp->cc.shift, ptp->cc.mult);
|
||||
@@ -689,6 +697,7 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot)
|
||||
struct skb_shared_hwtstamps timestamp;
|
||||
struct bnxt_ptp_tx_req *txts_req;
|
||||
unsigned long now = jiffies;
|
||||
unsigned long flags;
|
||||
u64 ts = 0, ns = 0;
|
||||
u32 tmo = 0;
|
||||
int rc;
|
||||
@@ -702,9 +711,9 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot)
|
||||
tmo, slot);
|
||||
if (!rc) {
|
||||
memset(×tamp, 0, sizeof(timestamp));
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
ns = timecounter_cyc2time(&ptp->tc, ts);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
timestamp.hwtstamp = ns_to_ktime(ns);
|
||||
skb_tstamp_tx(txts_req->tx_skb, ×tamp);
|
||||
ptp->stats.ts_pkts++;
|
||||
@@ -730,6 +739,7 @@ static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info)
|
||||
unsigned long now = jiffies;
|
||||
struct bnxt *bp = ptp->bp;
|
||||
u16 cons = ptp->txts_cons;
|
||||
unsigned long flags;
|
||||
u32 num_requests;
|
||||
int rc = 0;
|
||||
|
||||
@@ -757,9 +767,9 @@ next_slot:
|
||||
bnxt_ptp_get_current_time(bp);
|
||||
ptp->next_period = now + HZ;
|
||||
if (time_after_eq(now, ptp->next_overflow_check)) {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
timecounter_read(&ptp->tc);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD;
|
||||
}
|
||||
if (rc == -EAGAIN)
|
||||
@@ -819,6 +829,7 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi,
|
||||
u32 opaque = tscmp->tx_ts_cmp_opaque;
|
||||
struct bnxt_tx_ring_info *txr;
|
||||
struct bnxt_sw_tx_bd *tx_buf;
|
||||
unsigned long flags;
|
||||
u64 ts, ns;
|
||||
u16 cons;
|
||||
|
||||
@@ -833,9 +844,9 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi,
|
||||
le32_to_cpu(tscmp->tx_ts_cmp_flags_type),
|
||||
le32_to_cpu(tscmp->tx_ts_cmp_errors_v));
|
||||
} else {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
ns = timecounter_cyc2time(&ptp->tc, ts);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
timestamp.hwtstamp = ns_to_ktime(ns);
|
||||
skb_tstamp_tx(tx_buf->skb, ×tamp);
|
||||
}
|
||||
@@ -975,6 +986,7 @@ void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns)
|
||||
int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg)
|
||||
{
|
||||
struct timespec64 tsp;
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
int rc;
|
||||
|
||||
@@ -993,9 +1005,9 @@ int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg)
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
spin_lock_bh(&bp->ptp_cfg->ptp_lock);
|
||||
spin_lock_irqsave(&bp->ptp_cfg->ptp_lock, flags);
|
||||
bnxt_ptp_rtc_timecounter_init(bp->ptp_cfg, ns);
|
||||
spin_unlock_bh(&bp->ptp_cfg->ptp_lock);
|
||||
spin_unlock_irqrestore(&bp->ptp_cfg->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1063,10 +1075,12 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
|
||||
atomic64_set(&ptp->stats.ts_err, 0);
|
||||
|
||||
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
|
||||
spin_lock_bh(&ptp->ptp_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
bnxt_refclk_read(bp, NULL, &ptp->current_time);
|
||||
WRITE_ONCE(ptp->old_time, ptp->current_time);
|
||||
spin_unlock_bh(&ptp->ptp_lock);
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
ptp_schedule_worker(ptp->ptp_clock, 0);
|
||||
}
|
||||
ptp->txts_tmo = BNXT_PTP_DFLT_TX_TMO;
|
||||
|
||||
@@ -146,11 +146,13 @@ struct bnxt_ptp_cfg {
|
||||
};
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
#define BNXT_READ_TIME64(ptp, dst, src) \
|
||||
do { \
|
||||
spin_lock_bh(&(ptp)->ptp_lock); \
|
||||
(dst) = (src); \
|
||||
spin_unlock_bh(&(ptp)->ptp_lock); \
|
||||
#define BNXT_READ_TIME64(ptp, dst, src) \
|
||||
do { \
|
||||
unsigned long flags; \
|
||||
\
|
||||
spin_lock_irqsave(&(ptp)->ptp_lock, flags); \
|
||||
(dst) = (src); \
|
||||
spin_unlock_irqrestore(&(ptp)->ptp_lock, flags); \
|
||||
} while (0)
|
||||
#else
|
||||
#define BNXT_READ_TIME64(ptp, dst, src) \
|
||||
|
||||
@@ -1381,10 +1381,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
|
||||
|
||||
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
|
||||
if (unlikely(!wrb_cnt)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(!wrb_cnt))
|
||||
goto drop_skb;
|
||||
|
||||
/* if os2bmc is enabled and if the pkt is destined to bmc,
|
||||
* enqueue the pkt a 2nd time with mgmt bit set.
|
||||
@@ -1393,7 +1391,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
BE_WRB_F_SET(wrb_params.features, OS2BMC, 1);
|
||||
wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
|
||||
if (unlikely(!wrb_cnt))
|
||||
goto drop;
|
||||
goto drop_skb;
|
||||
else
|
||||
skb_get(skb);
|
||||
}
|
||||
@@ -1407,6 +1405,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
be_xmit_flush(adapter, txo);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
drop_skb:
|
||||
dev_kfree_skb_any(skb);
|
||||
drop:
|
||||
tx_stats(txo)->tx_drv_drops++;
|
||||
/* Flush the already enqueued tx requests */
|
||||
|
||||
@@ -197,55 +197,67 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
}
|
||||
mac_dev->fman_dev = &of_dev->dev;
|
||||
|
||||
/* Get the FMan cell-index */
|
||||
err = of_property_read_u32(dev_node, "cell-index", &val);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
|
||||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
/* cell-index 0 => FMan id 1 */
|
||||
fman_id = (u8)(val + 1);
|
||||
|
||||
priv->fman = fman_bind(&of_dev->dev);
|
||||
priv->fman = fman_bind(mac_dev->fman_dev);
|
||||
if (!priv->fman) {
|
||||
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
|
||||
err = -ENODEV;
|
||||
goto _return_of_node_put;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
/* Two references have been taken in of_find_device_by_node()
|
||||
* and fman_bind(). Release one of them here. The second one
|
||||
* will be released in mac_remove().
|
||||
*/
|
||||
put_device(mac_dev->fman_dev);
|
||||
of_node_put(dev_node);
|
||||
dev_node = NULL;
|
||||
|
||||
/* Get the address of the memory mapped registers */
|
||||
mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
|
||||
if (!mac_dev->res) {
|
||||
dev_err(dev, "could not get registers\n");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
|
||||
mac_dev->res);
|
||||
if (err) {
|
||||
dev_err_probe(dev, err, "could not request resource\n");
|
||||
return err;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
|
||||
resource_size(mac_dev->res));
|
||||
if (!mac_dev->vaddr) {
|
||||
dev_err(dev, "devm_ioremap() failed\n");
|
||||
return -EIO;
|
||||
err = -EIO;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(mac_node))
|
||||
return -ENODEV;
|
||||
if (!of_device_is_available(mac_node)) {
|
||||
err = -ENODEV;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
/* Get the cell-index */
|
||||
err = of_property_read_u32(mac_node, "cell-index", &val);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
priv->cell_index = (u8)val;
|
||||
|
||||
@@ -259,22 +271,26 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
if (unlikely(nph < 0)) {
|
||||
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
|
||||
mac_node);
|
||||
return nph;
|
||||
err = nph;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
if (nph != ARRAY_SIZE(mac_dev->port)) {
|
||||
dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
|
||||
mac_node);
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto _return_dev_put;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
|
||||
/* PORT_NUM determines the size of the port array */
|
||||
for (i = 0; i < PORT_NUM; i++) {
|
||||
/* Find the port node */
|
||||
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
|
||||
if (!dev_node) {
|
||||
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
|
||||
mac_node);
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto _return_dev_arr_put;
|
||||
}
|
||||
|
||||
of_dev = of_find_device_by_node(dev_node);
|
||||
@@ -282,17 +298,24 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
|
||||
dev_node);
|
||||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
goto _return_dev_arr_put;
|
||||
}
|
||||
mac_dev->fman_port_devs[i] = &of_dev->dev;
|
||||
|
||||
mac_dev->port[i] = fman_port_bind(&of_dev->dev);
|
||||
mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
|
||||
if (!mac_dev->port[i]) {
|
||||
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
|
||||
dev_node);
|
||||
err = -EINVAL;
|
||||
goto _return_of_node_put;
|
||||
goto _return_dev_arr_put;
|
||||
}
|
||||
/* Two references have been taken in of_find_device_by_node()
|
||||
* and fman_port_bind(). Release one of them here. The second
|
||||
* one will be released in mac_remove().
|
||||
*/
|
||||
put_device(mac_dev->fman_port_devs[i]);
|
||||
of_node_put(dev_node);
|
||||
dev_node = NULL;
|
||||
}
|
||||
|
||||
/* Get the PHY connection type */
|
||||
@@ -312,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
|
||||
err = init(mac_dev, mac_node, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto _return_dev_arr_put;
|
||||
|
||||
if (!is_zero_ether_addr(mac_dev->addr))
|
||||
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
|
||||
@@ -327,6 +350,12 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
|
||||
return err;
|
||||
|
||||
_return_dev_arr_put:
|
||||
/* mac_dev is kzalloc'ed */
|
||||
for (i = 0; i < PORT_NUM; i++)
|
||||
put_device(mac_dev->fman_port_devs[i]);
|
||||
_return_dev_put:
|
||||
put_device(mac_dev->fman_dev);
|
||||
_return_of_node_put:
|
||||
of_node_put(dev_node);
|
||||
return err;
|
||||
@@ -335,6 +364,11 @@ _return_of_node_put:
|
||||
static void mac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mac_device *mac_dev = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PORT_NUM; i++)
|
||||
put_device(mac_dev->fman_port_devs[i]);
|
||||
put_device(mac_dev->fman_dev);
|
||||
|
||||
platform_device_unregister(mac_dev->priv->eth_dev);
|
||||
}
|
||||
|
||||
@@ -19,12 +19,13 @@
|
||||
struct fman_mac;
|
||||
struct mac_priv_s;
|
||||
|
||||
#define PORT_NUM 2
|
||||
struct mac_device {
|
||||
void __iomem *vaddr;
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct fman_port *port[2];
|
||||
struct fman_port *port[PORT_NUM];
|
||||
struct phylink *phylink;
|
||||
struct phylink_config phylink_config;
|
||||
phy_interface_t phy_if;
|
||||
@@ -52,6 +53,9 @@ struct mac_device {
|
||||
|
||||
struct fman_mac *fman_mac;
|
||||
struct mac_priv_s *priv;
|
||||
|
||||
struct device *fman_dev;
|
||||
struct device *fman_port_devs[PORT_NUM];
|
||||
};
|
||||
|
||||
static inline struct mac_device
|
||||
|
||||
@@ -1012,6 +1012,7 @@ sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
|
||||
if(skb->len > XMIT_BUFF_SIZE)
|
||||
{
|
||||
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -336,6 +336,51 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
|
||||
return new_pkts;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_oq_next_pkt() - Move to the next packet in Rx queue.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
* @buff_info: Current packet buffer info.
|
||||
* @read_idx: Current packet index in the ring.
|
||||
* @desc_used: Current packet descriptor number.
|
||||
*
|
||||
* Free the resources associated with a packet.
|
||||
* Increment packet index in the ring and packet descriptor number.
|
||||
*/
|
||||
static void octep_oq_next_pkt(struct octep_oq *oq,
|
||||
struct octep_rx_buffer *buff_info,
|
||||
u32 *read_idx, u32 *desc_used)
|
||||
{
|
||||
dma_unmap_page(oq->dev, oq->desc_ring[*read_idx].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
buff_info->page = NULL;
|
||||
(*read_idx)++;
|
||||
(*desc_used)++;
|
||||
if (*read_idx == oq->max_count)
|
||||
*read_idx = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_oq_drop_rx() - Free the resources associated with a packet.
|
||||
*
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
* @buff_info: Current packet buffer info.
|
||||
* @read_idx: Current packet index in the ring.
|
||||
* @desc_used: Current packet descriptor number.
|
||||
*
|
||||
*/
|
||||
static void octep_oq_drop_rx(struct octep_oq *oq,
|
||||
struct octep_rx_buffer *buff_info,
|
||||
u32 *read_idx, u32 *desc_used)
|
||||
{
|
||||
int data_len = buff_info->len - oq->max_single_buffer_size;
|
||||
|
||||
while (data_len > 0) {
|
||||
octep_oq_next_pkt(oq, buff_info, read_idx, desc_used);
|
||||
data_len -= oq->buffer_size;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* __octep_oq_process_rx() - Process hardware Rx queue and push to stack.
|
||||
*
|
||||
@@ -367,10 +412,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
||||
desc_used = 0;
|
||||
for (pkt = 0; pkt < pkts_to_process; pkt++) {
|
||||
buff_info = (struct octep_rx_buffer *)&oq->buff_info[read_idx];
|
||||
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
resp_hw = page_address(buff_info->page);
|
||||
buff_info->page = NULL;
|
||||
|
||||
/* Swap the length field that is in Big-Endian to CPU */
|
||||
buff_info->len = be64_to_cpu(resp_hw->length);
|
||||
@@ -394,36 +436,33 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
||||
data_offset = OCTEP_OQ_RESP_HW_SIZE;
|
||||
rx_ol_flags = 0;
|
||||
}
|
||||
|
||||
octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
|
||||
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
if (!skb) {
|
||||
octep_oq_drop_rx(oq, buff_info,
|
||||
&read_idx, &desc_used);
|
||||
oq->stats.alloc_failures++;
|
||||
continue;
|
||||
}
|
||||
skb_reserve(skb, data_offset);
|
||||
|
||||
rx_bytes += buff_info->len;
|
||||
|
||||
if (buff_info->len <= oq->max_single_buffer_size) {
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
skb_reserve(skb, data_offset);
|
||||
skb_put(skb, buff_info->len);
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
} else {
|
||||
struct skb_shared_info *shinfo;
|
||||
u16 data_len;
|
||||
|
||||
skb = build_skb((void *)resp_hw, PAGE_SIZE);
|
||||
skb_reserve(skb, data_offset);
|
||||
/* Head fragment includes response header(s);
|
||||
* subsequent fragments contains only data.
|
||||
*/
|
||||
skb_put(skb, oq->max_single_buffer_size);
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
|
||||
shinfo = skb_shinfo(skb);
|
||||
data_len = buff_info->len - oq->max_single_buffer_size;
|
||||
while (data_len) {
|
||||
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
|
||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
buff_info = (struct octep_rx_buffer *)
|
||||
&oq->buff_info[read_idx];
|
||||
if (data_len < oq->buffer_size) {
|
||||
@@ -438,11 +477,8 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
||||
buff_info->page, 0,
|
||||
buff_info->len,
|
||||
buff_info->len);
|
||||
buff_info->page = NULL;
|
||||
read_idx++;
|
||||
desc_used++;
|
||||
if (read_idx == oq->max_count)
|
||||
read_idx = 0;
|
||||
|
||||
octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3197,7 +3197,6 @@ mlxsw_sp_nexthop_sh_counter_get(struct mlxsw_sp *mlxsw_sp,
|
||||
{
|
||||
struct mlxsw_sp_nexthop_group *nh_grp = nh->nhgi->nh_grp;
|
||||
struct mlxsw_sp_nexthop_counter *nhct;
|
||||
void *ptr;
|
||||
int err;
|
||||
|
||||
nhct = xa_load(&nh_grp->nhgi->nexthop_counters, nh->id);
|
||||
@@ -3210,12 +3209,10 @@ mlxsw_sp_nexthop_sh_counter_get(struct mlxsw_sp *mlxsw_sp,
|
||||
if (IS_ERR(nhct))
|
||||
return nhct;
|
||||
|
||||
ptr = xa_store(&nh_grp->nhgi->nexthop_counters, nh->id, nhct,
|
||||
GFP_KERNEL);
|
||||
if (IS_ERR(ptr)) {
|
||||
err = PTR_ERR(ptr);
|
||||
err = xa_err(xa_store(&nh_grp->nhgi->nexthop_counters, nh->id, nhct,
|
||||
GFP_KERNEL));
|
||||
if (err)
|
||||
goto err_store;
|
||||
}
|
||||
|
||||
return nhct;
|
||||
|
||||
|
||||
@@ -4682,7 +4682,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
|
||||
if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (unlikely(status & SYSErr)) {
|
||||
/* At least RTL8168fp may unexpectedly set the SYSErr bit */
|
||||
if (unlikely(status & SYSErr &&
|
||||
tp->mac_version <= RTL_GIGA_MAC_VER_06)) {
|
||||
rtl8169_pcierr_interrupt(tp->dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2798,6 +2798,31 @@ static struct hv_driver netvsc_drv = {
|
||||
},
|
||||
};
|
||||
|
||||
/* Set VF's namespace same as the synthetic NIC */
|
||||
static void netvsc_event_set_vf_ns(struct net_device *ndev)
|
||||
{
|
||||
struct net_device_context *ndev_ctx = netdev_priv(ndev);
|
||||
struct net_device *vf_netdev;
|
||||
int ret;
|
||||
|
||||
vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
|
||||
if (!vf_netdev)
|
||||
return;
|
||||
|
||||
if (!net_eq(dev_net(ndev), dev_net(vf_netdev))) {
|
||||
ret = dev_change_net_namespace(vf_netdev, dev_net(ndev),
|
||||
"eth%d");
|
||||
if (ret)
|
||||
netdev_err(vf_netdev,
|
||||
"Cannot move to same namespace as %s: %d\n",
|
||||
ndev->name, ret);
|
||||
else
|
||||
netdev_info(vf_netdev,
|
||||
"Moved VF to namespace with: %s\n",
|
||||
ndev->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* On Hyper-V, every VF interface is matched with a corresponding
|
||||
* synthetic interface. The synthetic interface is presented first
|
||||
@@ -2810,6 +2835,11 @@ static int netvsc_netdev_event(struct notifier_block *this,
|
||||
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
|
||||
int ret = 0;
|
||||
|
||||
if (event_dev->netdev_ops == &device_ops && event == NETDEV_REGISTER) {
|
||||
netvsc_event_set_vf_ns(event_dev);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
ret = check_dev_is_matching_vf(event_dev);
|
||||
if (ret != 0)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
/* Control Register 2 bits */
|
||||
#define DP83822_FX_ENABLE BIT(14)
|
||||
|
||||
#define DP83822_HW_RESET BIT(15)
|
||||
#define DP83822_SW_RESET BIT(14)
|
||||
#define DP83822_SW_RESET BIT(15)
|
||||
#define DP83822_DIG_RESTART BIT(14)
|
||||
|
||||
/* PHY STS bits */
|
||||
#define DP83822_PHYSTS_DUPLEX BIT(2)
|
||||
|
||||
@@ -815,7 +815,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
|
||||
return HS_TIMEOUT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
fallthrough;
|
||||
|
||||
case PLIP_PK_LENGTH_LSB:
|
||||
if (plip_send(nibble_timeout, dev,
|
||||
|
||||
@@ -113,7 +113,7 @@ static void pse_release_pis(struct pse_controller_dev *pcdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= pcdev->nr_lines; i++) {
|
||||
for (i = 0; i < pcdev->nr_lines; i++) {
|
||||
of_node_put(pcdev->pi[i].pairset[0].np);
|
||||
of_node_put(pcdev->pi[i].pairset[1].np);
|
||||
of_node_put(pcdev->pi[i].np);
|
||||
@@ -647,7 +647,7 @@ static int of_pse_match_pi(struct pse_controller_dev *pcdev,
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= pcdev->nr_lines; i++) {
|
||||
for (i = 0; i < pcdev->nr_lines; i++) {
|
||||
if (pcdev->pi[i].np == np)
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -1426,6 +1426,7 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */
|
||||
{QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)}, /* Quectel EM05GV2 */
|
||||
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
|
||||
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0112, 0)}, /* Fibocom FG132 */
|
||||
{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */
|
||||
{QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/
|
||||
{QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
|
||||
|
||||
@@ -1767,7 +1767,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
|
||||
// can rename the link if it knows better.
|
||||
if ((dev->driver_info->flags & FLAG_ETHER) != 0 &&
|
||||
((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 ||
|
||||
(net->dev_addr [0] & 0x02) == 0))
|
||||
/* somebody touched it*/
|
||||
!is_zero_ether_addr(net->dev_addr)))
|
||||
strscpy(net->name, "eth%d", sizeof(net->name));
|
||||
/* WLAN devices should always be named "wlan%d" */
|
||||
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
|
||||
|
||||
@@ -4155,7 +4155,7 @@ struct virtnet_stats_ctx {
|
||||
u32 desc_num[3];
|
||||
|
||||
/* The actual supported stat types. */
|
||||
u32 bitmap[3];
|
||||
u64 bitmap[3];
|
||||
|
||||
/* Used to calculate the reply buffer size. */
|
||||
u32 size[3];
|
||||
|
||||
@@ -1038,7 +1038,7 @@ static const struct nla_policy wwan_rtnl_policy[IFLA_WWAN_MAX + 1] = {
|
||||
|
||||
static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = {
|
||||
.kind = "wwan",
|
||||
.maxtype = __IFLA_WWAN_MAX,
|
||||
.maxtype = IFLA_WWAN_MAX,
|
||||
.alloc = wwan_rtnl_alloc,
|
||||
.validate = wwan_rtnl_validate,
|
||||
.newlink = wwan_rtnl_newlink,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user