mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'kvm-s390-next-7.2-2' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD
* Fix S390_USER_OPEREXEC so it can now be enabled regardless of other unrelated capabilities * Fix handling of the _PAGE_UNUSED pte bit that could lead to guest memory corruption in some scenarios * A bunch of misc gmap fixes (locking, behaviour under memory pressure) * Fix CMMA dirty tracking
This commit is contained in:
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: GPIO-based I2C Bus Mux
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa@kernel.org>
|
||||
- Peter Korsgaard <peter.korsgaard@barco.com>
|
||||
|
||||
description: |
|
||||
This binding describes an I2C bus multiplexer that uses GPIOs to route the I2C signals.
|
||||
|
||||
@@ -6840,7 +6840,7 @@ s390 specific.
|
||||
} s390_ucontrol;
|
||||
|
||||
s390 specific. A page fault has occurred for a user controlled virtual
|
||||
machine (KVM_VM_S390_UNCONTROL) on its host page table that cannot be
|
||||
machine (KVM_VM_S390_UCONTROL) on its host page table that cannot be
|
||||
resolved by the kernel.
|
||||
The program code and the translation exception code that were placed
|
||||
in the cpu's lowcore are presented here as defined by the z Architecture
|
||||
|
||||
@@ -10772,6 +10772,7 @@ GENERIC GPIO I2C MULTIPLEXER DRIVER
|
||||
M: Peter Korsgaard <peter.korsgaard@barco.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-mux-gpio.yaml
|
||||
F: Documentation/i2c/muxes/i2c-mux-gpio.rst
|
||||
F: drivers/i2c/muxes/i2c-mux-gpio.c
|
||||
F: include/linux/platform_data/i2c-mux-gpio.h
|
||||
@@ -12094,11 +12095,11 @@ F: Documentation/i2c/busses/i2c-parport.rst
|
||||
F: drivers/i2c/busses/i2c-parport.c
|
||||
|
||||
I2C SUBSYSTEM
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
M: Andi Shyti <andi.shyti@kernel.org>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
|
||||
F: Documentation/i2c/
|
||||
F: drivers/i2c/*
|
||||
F: include/dt-bindings/i2c/i2c.h
|
||||
@@ -20550,6 +20551,7 @@ PCI ENDPOINT SUBSYSTEM
|
||||
M: Manivannan Sadhasivam <mani@kernel.org>
|
||||
M: Krzysztof Wilczyński <kwilczynski@kernel.org>
|
||||
R: Kishon Vijay Abraham I <kishon@kernel.org>
|
||||
R: Frank Li <Frank.Li@kernel.org>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Supported
|
||||
Q: https://patchwork.kernel.org/project/linux-pci/list/
|
||||
@@ -25926,7 +25928,6 @@ F: drivers/media/platform/synopsys/hdmirx/*
|
||||
SYNOPSYS DESIGNWARE I2C DRIVER
|
||||
M: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
R: Jan Dabros <jsd@semihalf.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-designware-*
|
||||
|
||||
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc7
|
||||
EXTRAVERSION =
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -56,8 +56,19 @@ void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen);
|
||||
* the bus. Rather than special-case the machine, just let the compiler
|
||||
* generate the access for CPUs prior to ARMv6.
|
||||
*/
|
||||
#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
|
||||
#define __raw_writew(v,a) ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)))
|
||||
#define __raw_writew __raw_writew
|
||||
static __no_kasan_or_inline void __raw_writew(u16 val, volatile void __iomem *addr)
|
||||
{
|
||||
__chk_io_ptr(addr);
|
||||
*(volatile unsigned short __force *)addr = val;
|
||||
}
|
||||
|
||||
#define __raw_readw __raw_readw
|
||||
static __no_kasan_or_inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
{
|
||||
__chk_io_ptr(addr);
|
||||
return *(const volatile unsigned short __force *)addr;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* When running under a hypervisor, we want to avoid I/O accesses with
|
||||
|
||||
@@ -567,7 +567,7 @@ ENTRY(__switch_to)
|
||||
@ are using KASAN
|
||||
mov_l r2, KASAN_SHADOW_OFFSET
|
||||
add r2, r2, ip, lsr #KASAN_SHADOW_SCALE_SHIFT
|
||||
ldr r2, [r2]
|
||||
ldrb r2, [r2]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <asm/suspend.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "reboot.h"
|
||||
|
||||
int pfn_is_nosave(unsigned long pfn)
|
||||
@@ -82,6 +83,15 @@ static void notrace arch_restore_image(void *unused)
|
||||
{
|
||||
struct pbe *pbe;
|
||||
|
||||
/*
|
||||
* With CONFIG_CPU_TTBR0_PAN enabled, TTBCR.EPD0 is set to block
|
||||
* TTBR0 page-table walks. The identity mapping used here lives at
|
||||
* low (user-space) virtual addresses and is only reachable via
|
||||
* TTBR0, so re-enable those walks before switching page tables.
|
||||
* On non-PAN kernels this is a no-op.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_CPU_TTBR0_PAN))
|
||||
uaccess_save_and_enable();
|
||||
cpu_switch_mm(idmap_pgd, &init_mm);
|
||||
for (pbe = restore_pblist; pbe; pbe = pbe->next)
|
||||
copy_page(pbe->orig_address, pbe->address);
|
||||
|
||||
@@ -34,6 +34,7 @@ static int ncores;
|
||||
|
||||
static struct regmap *pmu;
|
||||
static int has_pmu = true;
|
||||
static struct reset_control *cpu_rstc[4];
|
||||
|
||||
static int pmu_power_domain_is_on(int pd)
|
||||
{
|
||||
@@ -64,9 +65,11 @@ static struct reset_control *rockchip_get_core_reset(int cpu)
|
||||
static int pmu_set_power_domain(int pd, bool on)
|
||||
{
|
||||
u32 val = (on) ? 0 : BIT(pd);
|
||||
struct reset_control *rstc = rockchip_get_core_reset(pd);
|
||||
struct reset_control *rstc;
|
||||
int ret;
|
||||
|
||||
rstc = pd < ARRAY_SIZE(cpu_rstc) ? cpu_rstc[pd] : ERR_PTR(-EINVAL);
|
||||
|
||||
if (IS_ERR(rstc) && read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
|
||||
pr_err("%s: could not get reset control for core %d\n",
|
||||
__func__, pd);
|
||||
@@ -100,11 +103,8 @@ static int pmu_set_power_domain(int pd, bool on)
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(rstc)) {
|
||||
if (on)
|
||||
reset_control_deassert(rstc);
|
||||
reset_control_put(rstc);
|
||||
}
|
||||
if (!IS_ERR(rstc) && on)
|
||||
reset_control_deassert(rstc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -312,6 +312,10 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
|
||||
ncores = ((l2ctlr >> 24) & 0x3) + 1;
|
||||
}
|
||||
|
||||
/* Collect cpu core reset control for each core */
|
||||
for (i = 0; i < ncores; i++)
|
||||
cpu_rstc[i] = rockchip_get_core_reset(i);
|
||||
|
||||
/* Make sure that all cores except the first are really off */
|
||||
for (i = 1; i < ncores; i++)
|
||||
pmu_set_power_domain(0 + i, false);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/system_info.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/*
|
||||
* Note: accesses outside of the kernel image and the identity map area
|
||||
@@ -133,6 +134,17 @@ early_initcall(init_static_idmap);
|
||||
*/
|
||||
void setup_mm_for_reboot(void)
|
||||
{
|
||||
/*
|
||||
* With CONFIG_CPU_TTBR0_PAN enabled, TTBCR.EPD0 is set whenever
|
||||
* user-space access is disabled in order to block TTBR0 page-table
|
||||
* walks. The identity mapping lives at low (user-space) virtual
|
||||
* addresses and can only be reached via TTBR0, so we must re-enable
|
||||
* those walks before switching page tables. On non-PAN kernels this
|
||||
* is a no-op.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_CPU_TTBR0_PAN))
|
||||
uaccess_save_and_enable();
|
||||
|
||||
/* Switch to the identity mapping. */
|
||||
cpu_switch_mm(idmap_pgd, &init_mm);
|
||||
local_flush_bp_all();
|
||||
|
||||
@@ -29,9 +29,6 @@ config GENERIC_BUG
|
||||
config GENERIC_BUG_RELATIVE_POINTERS
|
||||
def_bool y
|
||||
|
||||
config GENERIC_LOCKBREAK
|
||||
def_bool y if PREEMPTION
|
||||
|
||||
config AUDIT_ARCH
|
||||
def_bool y
|
||||
|
||||
|
||||
@@ -980,6 +980,8 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||||
|
||||
static inline void set_pte(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
if (pte_present(pte))
|
||||
pte = clear_pte_bit(pte, __pgprot(_PAGE_UNUSED));
|
||||
WRITE_ONCE(*ptep, pte);
|
||||
}
|
||||
|
||||
@@ -1332,8 +1334,6 @@ pgprot_t pgprot_writecombine(pgprot_t prot);
|
||||
static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
|
||||
pte_t *ptep, pte_t entry, unsigned int nr)
|
||||
{
|
||||
if (pte_present(entry))
|
||||
entry = clear_pte_bit(entry, __pgprot(_PAGE_UNUSED));
|
||||
page_table_check_ptes_set(mm, addr, ptep, entry, nr);
|
||||
for (;;) {
|
||||
set_pte(ptep, entry);
|
||||
|
||||
@@ -1209,7 +1209,7 @@ int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)
|
||||
int rc;
|
||||
|
||||
rc = _dat_walk_gfn_range(start, start + *count, asce, &ops, DAT_WALK_DEFAULT, &state);
|
||||
*count = state.end - start;
|
||||
*count = state.end >= start ? state.end - start : 0;
|
||||
/* Return success if at least one value was saved, otherwise an error. */
|
||||
return (rc == -EFAULT && *count > 0) ? 0 : rc;
|
||||
}
|
||||
@@ -1253,6 +1253,9 @@ int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values,
|
||||
};
|
||||
|
||||
_dat_walk_gfn_range(*start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, &state);
|
||||
/* If no dirty pages were found, wrap around and continue searching */
|
||||
if (*start && state.start == -1)
|
||||
_dat_walk_gfn_range(0, *start, asce, &ops, DAT_WALK_IGN_HOLES, &state);
|
||||
|
||||
if (state.start == -1) {
|
||||
*count = 0;
|
||||
|
||||
@@ -332,7 +332,7 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
|
||||
new.h.i = 1;
|
||||
new.s.fc1.y = 0;
|
||||
new.s.fc1.prefix_notif = 0;
|
||||
if (new.s.fc1.d || !new.h.p)
|
||||
if ((new.s.fc1.d || !new.h.p) && !new.s.fc1.s)
|
||||
folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
|
||||
new.s.fc1.d = 0;
|
||||
new.h.p = 1;
|
||||
@@ -1098,23 +1098,46 @@ int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gf
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
__atomic64_or(PGSTE_CMMA_D_BIT, &pgste_of(ptep)->val);
|
||||
union pgste pgste;
|
||||
|
||||
pgste = pgste_get_lock(ptep);
|
||||
pgste.cmma_d = 0;
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
|
||||
if (need_resched())
|
||||
return next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gmap_set_cmma_all_dirty(struct gmap *gmap)
|
||||
static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
const struct dat_walk_ops ops = { .pte_entry = __set_cmma_dirty_pte, };
|
||||
union pgste pgste;
|
||||
|
||||
pgste = pgste_get_lock(ptep);
|
||||
if (!pgste.cmma_d)
|
||||
atomic64_inc(walk->priv);
|
||||
pgste.cmma_d = 1;
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
|
||||
if (need_resched())
|
||||
return next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)
|
||||
{
|
||||
const struct dat_walk_ops ops = {
|
||||
.pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,
|
||||
};
|
||||
gfn_t gfn = 0;
|
||||
|
||||
do {
|
||||
scoped_guard(read_lock, &gmap->kvm->mmu_lock)
|
||||
gfn = _dat_walk_gfn_range(gfn, asce_end(gmap->asce), gmap->asce, &ops,
|
||||
DAT_WALK_IGN_HOLES, NULL);
|
||||
DAT_WALK_IGN_HOLES,
|
||||
&gmap->kvm->arch.cmma_dirty_pages);
|
||||
cond_resched();
|
||||
} while (gfn);
|
||||
}
|
||||
@@ -1287,7 +1310,7 @@ static int gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gma
|
||||
/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
|
||||
smp_rmb();
|
||||
|
||||
rc = kvm_s390_get_guest_pages(sg->kvm, context.f, asce.rsto, asce.dt + 1, false);
|
||||
rc = kvm_s390_get_guest_pages(sg->kvm, context.f, asce.rsto, asce.tl + 1, false);
|
||||
if (rc > 0)
|
||||
rc = -EFAULT;
|
||||
if (!rc)
|
||||
|
||||
@@ -104,7 +104,7 @@ int gmap_insert_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn
|
||||
gfn_t r_gfn, int level);
|
||||
int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,
|
||||
kvm_pfn_t pfn, int level, bool wr);
|
||||
void gmap_set_cmma_all_dirty(struct gmap *gmap);
|
||||
void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);
|
||||
void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn);
|
||||
struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
||||
union asce asce, int edat_level);
|
||||
@@ -198,6 +198,16 @@ static inline bool pte_needs_unshadow(union pte oldpte, union pte newpte, union
|
||||
return !newpte.h.p || !newpte.s.pr;
|
||||
}
|
||||
|
||||
static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)
|
||||
{
|
||||
_gmap_set_cmma_all(gmap, true);
|
||||
}
|
||||
|
||||
static inline void gmap_set_cmma_all_clean(struct gmap *gmap)
|
||||
{
|
||||
_gmap_set_cmma_all(gmap, false);
|
||||
}
|
||||
|
||||
static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,
|
||||
union pgste pgste, gfn_t gfn, bool needs_lock)
|
||||
{
|
||||
|
||||
@@ -1022,9 +1022,11 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
||||
if (!kvm->arch.use_cmma)
|
||||
break;
|
||||
|
||||
guard(mutex)(&kvm->lock);
|
||||
VM_EVENT(kvm, 3, "%s", "RESET: CMMA states");
|
||||
do {
|
||||
start_gfn = dat_reset_cmma(kvm->arch.gmap->asce, start_gfn);
|
||||
scoped_guard(read_lock, &kvm->mmu_lock)
|
||||
start_gfn = dat_reset_cmma(kvm->arch.gmap->asce, start_gfn);
|
||||
cond_resched();
|
||||
} while (start_gfn);
|
||||
ret = 0;
|
||||
@@ -1217,13 +1219,13 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
|
||||
|
||||
/*
|
||||
* Must be called with kvm->srcu held to avoid races on memslots, and with
|
||||
* kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration.
|
||||
* kvm->slots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),
|
||||
* and kvm_s390_get_cmma_bits().
|
||||
*/
|
||||
static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_memory_slot *ms;
|
||||
struct kvm_memslots *slots;
|
||||
unsigned long ram_pages = 0;
|
||||
int bkt;
|
||||
|
||||
/* migration mode already enabled */
|
||||
@@ -1240,28 +1242,54 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
||||
kvm_for_each_memslot(ms, bkt, slots) {
|
||||
if (!ms->dirty_bitmap)
|
||||
return -EINVAL;
|
||||
ram_pages += ms->npages;
|
||||
}
|
||||
/* mark all the pages as dirty */
|
||||
gmap_set_cmma_all_dirty(kvm->arch.gmap);
|
||||
atomic64_set(&kvm->arch.cmma_dirty_pages, ram_pages);
|
||||
kvm->arch.migration_mode = 1;
|
||||
/*
|
||||
* Set the flag and let KVM handle ESSA manually, potentially setting
|
||||
* the cmma_d bit in some PGSTEs and increasing cmma_dirty_pages.
|
||||
* At this point cmma_dirty_pages is still 0, and all existing PGSTEs
|
||||
* have their cmma_d bit set to 0.
|
||||
* Any newly allocated page table has its entries marked as cmma-clean,
|
||||
* which is fine because the CMMA values are not dirty.
|
||||
*/
|
||||
WRITE_ONCE(kvm->arch.migration_mode, 1);
|
||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION);
|
||||
/*
|
||||
* Mark all PGSTEs as cmma-dirty, increasing cmma_dirty_pages as needed,
|
||||
* but without double-counting pages that have become dirty on their own
|
||||
* in the meantime.
|
||||
* At this point some pages might have become dirty on their own already
|
||||
* and cmma_dirty_pages might therefore be non-zero.
|
||||
*/
|
||||
gmap_set_cmma_all_dirty(kvm->arch.gmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with kvm->slots_lock to avoid races with ourselves and
|
||||
* kvm_s390_vm_start_migration.
|
||||
* Must be called with kvm->slots_lock to avoid races with ourselves,
|
||||
* kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
|
||||
*/
|
||||
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
|
||||
{
|
||||
/* migration mode already disabled */
|
||||
if (!kvm->arch.migration_mode)
|
||||
return 0;
|
||||
kvm->arch.migration_mode = 0;
|
||||
/*
|
||||
* Unset the flag and propagate to all vCPUs. From now on the cmma_d
|
||||
* bit will not be touched on any PGSTE.
|
||||
* At this point cmma_dirty_pages is possibly non-zero, and thus some
|
||||
* PGSTEs might have cmma_d set.
|
||||
*/
|
||||
WRITE_ONCE(kvm->arch.migration_mode, 0);
|
||||
if (kvm->arch.use_cmma)
|
||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
|
||||
/* Clear cmma_d on all existing PGSTEs and set cmma_dirty_pages to 0. */
|
||||
gmap_set_cmma_all_clean(kvm->arch.gmap);
|
||||
atomic64_set(&kvm->arch.cmma_dirty_pages, 0);
|
||||
/*
|
||||
* At this point the system has the expected state: migration_mode is 0,
|
||||
* cmma_dirty_pages is 0, and all existing PGSTEs have their cmma_d bit
|
||||
* set to 0.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2317,8 +2345,8 @@ static int kvm_s390_get_cmma_bits(struct kvm *kvm,
|
||||
static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
||||
const struct kvm_s390_cmma_log *args)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc;
|
||||
u8 *bits = NULL;
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
u8 *bits __free(kvfree) = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!kvm->arch.use_cmma)
|
||||
@@ -2338,18 +2366,16 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
||||
return -ENOMEM;
|
||||
bits = vmalloc(array_size(sizeof(*bits), args->count));
|
||||
if (!bits)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
r = copy_from_user(bits, (void __user *)args->values, args->count);
|
||||
if (r) {
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (r)
|
||||
return -EFAULT;
|
||||
|
||||
do {
|
||||
r = kvm_s390_mmu_cache_topup(mc);
|
||||
if (r)
|
||||
break;
|
||||
return r;
|
||||
scoped_guard(read_lock, &kvm->mmu_lock) {
|
||||
r = dat_set_cmma_bits(mc, kvm->arch.gmap->asce, args->start_gfn,
|
||||
args->count, args->mask, bits);
|
||||
@@ -2357,9 +2383,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
||||
} while (r == -ENOMEM);
|
||||
|
||||
set_bit(GMAP_FLAG_USES_CMM, &kvm->arch.gmap->flags);
|
||||
out:
|
||||
kvm_s390_free_mmu_cache(mc);
|
||||
vfree(bits);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -3584,7 +3608,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
||||
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
||||
sca_add_vcpu(vcpu);
|
||||
}
|
||||
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0)
|
||||
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
|
||||
vcpu->kvm->arch.user_operexec)
|
||||
vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,9 @@ static int handle_sske(struct kvm_vcpu *vcpu)
|
||||
if (rc > 1)
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
||||
if (rc == -ENOMEM) {
|
||||
kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||
rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (rc < 0)
|
||||
@@ -1122,7 +1124,9 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
||||
if (rc > 1)
|
||||
return kvm_s390_inject_program_int(vcpu, rc);
|
||||
if (rc == -ENOMEM) {
|
||||
kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||
rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (rc < 0)
|
||||
@@ -1232,7 +1236,7 @@ static int handle_essa(struct kvm_vcpu *vcpu)
|
||||
: ESSA_SET_STABLE_IF_RESIDENT))
|
||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||
|
||||
if (!vcpu->kvm->arch.migration_mode) {
|
||||
if (!READ_ONCE(vcpu->kvm->arch.migration_mode)) {
|
||||
/*
|
||||
* CMMA is enabled in the KVM settings, but is disabled in
|
||||
* the SIE block and in the mm_context, and we are not doing
|
||||
|
||||
@@ -181,7 +181,8 @@ void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
||||
if (IS_ERR_OR_NULL(ptep))
|
||||
return;
|
||||
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
if (pte_present(*ptep))
|
||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gmap_helper_try_set_pte_unused);
|
||||
|
||||
@@ -999,6 +999,7 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
|
||||
|
||||
if (ret == -EBUSY) {
|
||||
amdxdna_umap_put(mapp);
|
||||
mmput(mm);
|
||||
goto again;
|
||||
}
|
||||
|
||||
@@ -1009,11 +1010,13 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
|
||||
if (mmu_interval_read_retry(&mapp->notifier, mapp->range.notifier_seq)) {
|
||||
up_write(&xdna->notifier_lock);
|
||||
amdxdna_umap_put(mapp);
|
||||
mmput(mm);
|
||||
goto again;
|
||||
}
|
||||
mapp->invalid = false;
|
||||
up_write(&xdna->notifier_lock);
|
||||
amdxdna_umap_put(mapp);
|
||||
mmput(mm);
|
||||
goto again;
|
||||
|
||||
put_mm:
|
||||
|
||||
@@ -276,7 +276,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
|
||||
if (ipc_buf)
|
||||
memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf));
|
||||
if (rx_msg->jsm_msg) {
|
||||
u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg));
|
||||
u32 size = min(rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg));
|
||||
|
||||
if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) {
|
||||
ivpu_err(vdev, "IPC resp result error: %d\n", rx_msg->jsm_msg->result);
|
||||
|
||||
@@ -977,7 +977,7 @@ static struct clk_rcg2 disp0_cc_mdss_mdp_clk_src = {
|
||||
.name = "disp0_cc_mdss_mdp_clk_src",
|
||||
.parent_data = disp0_cc_parent_data_5,
|
||||
.num_parents = ARRAY_SIZE(disp0_cc_parent_data_5),
|
||||
.ops = &clk_rcg2_shared_ops,
|
||||
.ops = &clk_rcg2_shared_no_init_park_ops,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -991,7 +991,7 @@ static struct clk_rcg2 disp1_cc_mdss_mdp_clk_src = {
|
||||
.name = "disp1_cc_mdss_mdp_clk_src",
|
||||
.parent_data = disp1_cc_parent_data_5,
|
||||
.num_parents = ARRAY_SIZE(disp1_cc_parent_data_5),
|
||||
.ops = &clk_rcg2_shared_ops,
|
||||
.ops = &clk_rcg2_shared_no_init_park_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -580,7 +580,7 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
|
||||
.parent_data = disp_cc_parent_data_6,
|
||||
.num_parents = ARRAY_SIZE(disp_cc_parent_data_6),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
.ops = &clk_rcg2_shared_ops,
|
||||
.ops = &clk_rcg2_shared_no_init_park_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -3921,7 +3921,7 @@ static const unsigned long peric0_clk_regs[] __initconst = {
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI4_USI,
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI5_USI,
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI6_USI,
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI6_USI,
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI7_USI,
|
||||
CLK_CON_DIV_DIV_CLK_PERIC0_USI8_USI,
|
||||
CLK_CON_BUF_CLKBUF_PERIC0_IP,
|
||||
CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK,
|
||||
|
||||
@@ -723,15 +723,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->client.dev = dev;
|
||||
priv->client.receive_cb = NULL;
|
||||
priv->client.priv = priv;
|
||||
priv->status.current_image = 0;
|
||||
priv->status.fail_image = 0;
|
||||
priv->status.error_location = 0;
|
||||
priv->status.error_details = 0;
|
||||
priv->status.version = 0;
|
||||
priv->status.state = 0;
|
||||
priv->retry_counter = INVALID_RETRY_COUNTER;
|
||||
priv->max_retry = INVALID_RETRY_COUNTER;
|
||||
priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION;
|
||||
priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION;
|
||||
priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION;
|
||||
@@ -740,11 +734,11 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
priv->dcmf_status.dcmf1 = INVALID_DCMF_STATUS;
|
||||
priv->dcmf_status.dcmf2 = INVALID_DCMF_STATUS;
|
||||
priv->dcmf_status.dcmf3 = INVALID_DCMF_STATUS;
|
||||
priv->max_retry = INVALID_RETRY_COUNTER;
|
||||
priv->spt0_address = INVALID_SPT_ADDRESS;
|
||||
priv->spt1_address = INVALID_SPT_ADDRESS;
|
||||
/* spt0/1_address and status fields default to 0 from kzalloc */
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
init_completion(&priv->completion);
|
||||
|
||||
priv->chan = stratix10_svc_request_channel_byname(&priv->client,
|
||||
SVC_CLIENT_RSU);
|
||||
if (IS_ERR(priv->chan)) {
|
||||
@@ -756,11 +750,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
ret = stratix10_svc_add_async_client(priv->chan, false);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add async client\n");
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
return ret;
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
init_completion(&priv->completion);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
/* get the initial state from firmware */
|
||||
@@ -768,41 +760,44 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
rsu_async_status_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting RSU status %i\n", ret);
|
||||
stratix10_svc_remove_async_client(priv->chan);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
return ret;
|
||||
goto remove_async_client;
|
||||
}
|
||||
|
||||
/* get DCMF version from firmware */
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION,
|
||||
0, rsu_dcmf_version_callback);
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION, 0,
|
||||
rsu_dcmf_version_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting DCMF version %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
goto remove_async_client;
|
||||
}
|
||||
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS,
|
||||
0, rsu_dcmf_status_callback);
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS, 0,
|
||||
rsu_dcmf_status_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting DCMF status %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
goto remove_async_client;
|
||||
}
|
||||
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
|
||||
rsu_max_retry_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting RSU max retry %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
goto remove_async_client;
|
||||
}
|
||||
|
||||
|
||||
ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0,
|
||||
rsu_async_get_spt_table_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting SPT table %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
goto remove_async_client;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_async_client:
|
||||
stratix10_svc_remove_async_client(priv->chan);
|
||||
free_channel:
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,6 +212,7 @@ struct stratix10_async_chan {
|
||||
/**
|
||||
* struct stratix10_async_ctrl - Control structure for Stratix10
|
||||
* asynchronous operations
|
||||
* @supported: Flag indicating whether the system supports async operations
|
||||
* @initialized: Flag indicating whether the control structure has
|
||||
* been initialized
|
||||
* @invoke_fn: Function pointer for invoking Stratix10 service calls
|
||||
@@ -228,6 +229,7 @@ struct stratix10_async_chan {
|
||||
*/
|
||||
|
||||
struct stratix10_async_ctrl {
|
||||
bool supported;
|
||||
bool initialized;
|
||||
void (*invoke_fn)(struct stratix10_async_ctrl *actrl,
|
||||
const struct arm_smccc_1_2_regs *args,
|
||||
@@ -1103,6 +1105,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname);
|
||||
* Return: 0 on success, or a negative error code on failure:
|
||||
* -EINVAL if the channel is NULL or the async controller is
|
||||
* not initialized.
|
||||
* -EOPNOTSUPP if async operations are not supported.
|
||||
* -EALREADY if the async channel is already allocated.
|
||||
* -ENOMEM if memory allocation fails.
|
||||
* Other negative values if ID allocation fails.
|
||||
@@ -1121,6 +1124,9 @@ int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan,
|
||||
ctrl = chan->ctrl;
|
||||
actrl = &ctrl->actrl;
|
||||
|
||||
if (!actrl->supported)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!actrl->initialized) {
|
||||
dev_err(ctrl->dev, "Async controller not initialized\n");
|
||||
return -EINVAL;
|
||||
@@ -1562,6 +1568,7 @@ static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl,
|
||||
* initialized, -ENOMEM if memory allocation fails,
|
||||
* -EADDRINUSE if the client ID is already reserved, or other
|
||||
* negative error codes on failure.
|
||||
* -EOPNOTSUPP if system doesn't support async operations.
|
||||
*/
|
||||
static int stratix10_svc_async_init(struct stratix10_svc_controller *controller)
|
||||
{
|
||||
@@ -1585,10 +1592,12 @@ static int stratix10_svc_async_init(struct stratix10_svc_controller *controller)
|
||||
!(res.a1 > ASYNC_ATF_MINIMUM_MAJOR_VERSION ||
|
||||
(res.a1 == ASYNC_ATF_MINIMUM_MAJOR_VERSION &&
|
||||
res.a2 >= ASYNC_ATF_MINIMUM_MINOR_VERSION))) {
|
||||
dev_err(dev,
|
||||
"Intel Service Layer Driver: ATF version is not compatible for async operation\n");
|
||||
return -EINVAL;
|
||||
dev_info(dev,
|
||||
"Intel Service Layer Driver: ATF version is not compatible for async operation\n");
|
||||
actrl->supported = false;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
actrl->supported = true;
|
||||
|
||||
actrl->invoke_fn = stratix10_smc_1_2;
|
||||
|
||||
@@ -1952,10 +1961,14 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
init_completion(&controller->complete_status);
|
||||
|
||||
ret = stratix10_svc_async_init(controller);
|
||||
if (ret) {
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
dev_info(dev, "Intel Service Layer Driver Initialized (sync-only mode)\n");
|
||||
} else if (ret) {
|
||||
dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_init %d\n",
|
||||
ret);
|
||||
goto err_destroy_pool;
|
||||
} else {
|
||||
dev_info(dev, "Intel Service Layer Driver Initialized\n");
|
||||
}
|
||||
|
||||
fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irq_sim.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -578,7 +579,7 @@ static int __init gpio_mockup_register_chip(int idx)
|
||||
|
||||
static int __init gpio_mockup_init(void)
|
||||
{
|
||||
int i, num_chips, err;
|
||||
int i, num_chips, err, base, ngpio;
|
||||
|
||||
if ((gpio_mockup_num_ranges % 2) ||
|
||||
(gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
|
||||
@@ -592,8 +593,19 @@ static int __init gpio_mockup_init(void)
|
||||
* always be greater than 0.
|
||||
*/
|
||||
for (i = 0; i < num_chips; i++) {
|
||||
if (gpio_mockup_range_ngpio(i) < 0)
|
||||
base = gpio_mockup_range_base(i);
|
||||
ngpio = gpio_mockup_range_ngpio(i);
|
||||
|
||||
if (ngpio <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (base < 0) {
|
||||
if (ngpio > U16_MAX)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (ngpio <= base || ngpio - base > U16_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL);
|
||||
|
||||
@@ -996,7 +996,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
|
||||
mvebu_pwm_suspend(mvchip);
|
||||
|
||||
return 0;
|
||||
@@ -1048,7 +1048,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_PWM))
|
||||
if (IS_REACHABLE(CONFIG_PWM) && mvchip->mvpwm)
|
||||
mvebu_pwm_resume(mvchip);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -802,8 +802,10 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
|
||||
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
|
||||
|
||||
irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
|
||||
if (bank->domain)
|
||||
if (bank->domain) {
|
||||
irq_domain_remove_generic_chips(bank->domain);
|
||||
irq_domain_remove(bank->domain);
|
||||
}
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
}
|
||||
|
||||
|
||||
@@ -1014,6 +1014,7 @@ static void zynq_gpio_remove(struct platform_device *pdev)
|
||||
gpiochip_remove(&gpio->chip);
|
||||
device_set_wakeup_capable(&pdev->dev, 0);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct platform_driver zynq_gpio_driver = {
|
||||
|
||||
@@ -1066,11 +1066,6 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
||||
|
||||
of_node_get(np);
|
||||
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
if (of_property_read_bool(child, "gpio-hog"))
|
||||
of_node_set_flag(child, OF_POPULATED);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1031,9 +1031,17 @@ static int gpiochip_hog_lines(struct gpio_chip *gc)
|
||||
if (!fwnode_property_present(fwnode, "gpio-hog"))
|
||||
continue;
|
||||
|
||||
/* The hog may have been handled by another gpio_chip on the same fwnode */
|
||||
if (is_of_node(fwnode) &&
|
||||
of_node_check_flag(to_of_node(fwnode), OF_POPULATED))
|
||||
continue;
|
||||
|
||||
ret = gpiochip_add_hog(gc, fwnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_of_node(fwnode))
|
||||
of_node_set_flag(to_of_node(fwnode), OF_POPULATED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1291,7 +1299,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
|
||||
ret = gpiochip_hog_lines(gc);
|
||||
if (ret)
|
||||
goto err_remove_of_chip;
|
||||
goto err_free_hogs;
|
||||
|
||||
ret = gpiochip_irqchip_init_valid_mask(gc);
|
||||
if (ret)
|
||||
|
||||
@@ -1277,6 +1277,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
|
||||
{
|
||||
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
|
||||
struct amdgpu_job *leader = p->gang_leader;
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
struct amdgpu_bo_list_entry *e;
|
||||
struct drm_gem_object *gobj;
|
||||
unsigned long index;
|
||||
@@ -1322,7 +1323,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
|
||||
amdgpu_hmm_range_free(e->range);
|
||||
e->range = NULL;
|
||||
}
|
||||
if (r) {
|
||||
|
||||
if (r || !list_empty(&vm->invalidated)) {
|
||||
r = -EAGAIN;
|
||||
mutex_unlock(&p->adev->notifier_lock);
|
||||
return r;
|
||||
|
||||
@@ -593,7 +593,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
|
||||
static int
|
||||
amdgpu_userq_wait_count_fences(struct drm_file *filp,
|
||||
struct drm_amdgpu_userq_wait *wait_info,
|
||||
u32 *syncobj_handles, u32 *timeline_points,
|
||||
u32 *syncobj_handles, u64 *timeline_points,
|
||||
u32 *timeline_handles,
|
||||
struct drm_gem_object **gobj_write,
|
||||
struct drm_gem_object **gobj_read)
|
||||
@@ -703,7 +703,7 @@ amdgpu_userq_wait_add_fence(struct drm_amdgpu_userq_wait *wait_info,
|
||||
static int
|
||||
amdgpu_userq_wait_return_fence_info(struct drm_file *filp,
|
||||
struct drm_amdgpu_userq_wait *wait_info,
|
||||
u32 *syncobj_handles, u32 *timeline_points,
|
||||
u32 *syncobj_handles, u64 *timeline_points,
|
||||
u32 *timeline_handles,
|
||||
struct drm_gem_object **gobj_write,
|
||||
struct drm_gem_object **gobj_read)
|
||||
@@ -906,7 +906,8 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
int num_points, num_syncobj, num_read_bo_handles, num_write_bo_handles;
|
||||
u32 *syncobj_handles, *timeline_points, *timeline_handles;
|
||||
u32 *syncobj_handles, *timeline_handles;
|
||||
u64 *timeline_points;
|
||||
struct drm_amdgpu_userq_wait *wait_info = data;
|
||||
struct drm_gem_object **gobj_write;
|
||||
struct drm_gem_object **gobj_read;
|
||||
@@ -935,7 +936,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
ptr = u64_to_user_ptr(wait_info->syncobj_timeline_points);
|
||||
timeline_points = memdup_array_user(ptr, num_points, sizeof(u32));
|
||||
timeline_points = memdup_array_user(ptr, num_points, sizeof(u64));
|
||||
if (IS_ERR(timeline_points)) {
|
||||
r = PTR_ERR(timeline_points);
|
||||
goto free_timeline_handles;
|
||||
|
||||
@@ -832,6 +832,12 @@ int kfd_dbg_trap_enable(struct kfd_process *target, uint32_t fd,
|
||||
|
||||
if (copy_to_user(runtime_info, (void *)&target->runtime_info, copy_size)) {
|
||||
kfd_dbg_trap_deactivate(target, false, 0);
|
||||
fput(target->dbg_ev_file);
|
||||
target->dbg_ev_file = NULL;
|
||||
if (target->debugger_process)
|
||||
atomic_dec(&target->debugger_process->debugged_process_count);
|
||||
target->debug_trap_enabled = false;
|
||||
kfd_unref_process(target);
|
||||
r = -EFAULT;
|
||||
}
|
||||
|
||||
|
||||
@@ -795,6 +795,8 @@ static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events)
|
||||
struct kfd_event_waiter *event_waiters;
|
||||
uint32_t i;
|
||||
|
||||
if (num_events > KFD_SIGNAL_EVENT_LIMIT)
|
||||
return NULL;
|
||||
event_waiters = kzalloc_objs(struct kfd_event_waiter, num_events);
|
||||
if (!event_waiters)
|
||||
return NULL;
|
||||
|
||||
@@ -254,8 +254,10 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid)
|
||||
if (task_info) {
|
||||
/* Report VM faults from user applications, not retry from kernel */
|
||||
if (task_info->task.pid)
|
||||
kfd_smi_event_add(0, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT(
|
||||
task_info->task.pid, task_info->task.comm));
|
||||
kfd_smi_event_add(task_info->tgid, dev,
|
||||
KFD_SMI_EVENT_VMFAULT,
|
||||
KFD_EVENT_FMT_VMFAULT(task_info->task.pid,
|
||||
task_info->task.comm));
|
||||
amdgpu_vm_put_task_info(task_info);
|
||||
}
|
||||
}
|
||||
@@ -356,7 +358,7 @@ void kfd_smi_event_process(struct kfd_process_device *pdd, bool start)
|
||||
task_info = amdgpu_vm_get_task_info_vm(avm);
|
||||
|
||||
if (task_info) {
|
||||
kfd_smi_event_add(0, pdd->dev,
|
||||
kfd_smi_event_add(task_info->tgid, pdd->dev,
|
||||
start ? KFD_SMI_EVENT_PROCESS_START :
|
||||
KFD_SMI_EVENT_PROCESS_END,
|
||||
KFD_EVENT_FMT_PROCESS(task_info->task.pid,
|
||||
|
||||
@@ -10083,7 +10083,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
|
||||
continue;
|
||||
|
||||
bundle->surface_updates[planes_count].surface = dc_plane;
|
||||
if (new_pcrtc_state->color_mgmt_changed) {
|
||||
if (new_pcrtc_state->color_mgmt_changed || new_plane_state->color_mgmt_changed) {
|
||||
bundle->surface_updates[planes_count].gamma = &dc_plane->gamma_correction;
|
||||
bundle->surface_updates[planes_count].in_transfer_func = &dc_plane->in_transfer_func;
|
||||
bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
|
||||
@@ -11824,6 +11824,10 @@ static bool should_reset_plane(struct drm_atomic_state *state,
|
||||
if (new_crtc_state->color_mgmt_changed)
|
||||
return true;
|
||||
|
||||
/* Plane color pipeline or its colorop changes. */
|
||||
if (new_plane_state->color_mgmt_changed)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* On zpos change, planes need to be reordered by removing and re-adding
|
||||
* them one by one to the dc state, in order of descending zpos.
|
||||
@@ -13446,17 +13450,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
/* Handle MCCS */
|
||||
if (do_mccs)
|
||||
if (do_mccs) {
|
||||
dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
|
||||
if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||
as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) &&
|
||||
(!sink->edid_caps.freesync_vcp_code ||
|
||||
(sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)))
|
||||
freesync_capable = false;
|
||||
if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)
|
||||
freesync_capable = false;
|
||||
|
||||
if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable)
|
||||
dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
if (sink->mccs_caps.freesync_supported && freesync_capable)
|
||||
dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
|
||||
}
|
||||
|
||||
update:
|
||||
if (dm_con_state)
|
||||
|
||||
@@ -830,7 +830,7 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
|
||||
case DRM_COLOROP_1D_LUT:
|
||||
drm_printf(p, "\tsize=%d\n", colorop->size);
|
||||
drm_printf(p, "\tinterpolation=%s\n",
|
||||
drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation));
|
||||
drm_get_colorop_lut1d_interpolation_name(state->lut1d_interpolation));
|
||||
drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
|
||||
break;
|
||||
case DRM_COLOROP_CTM_3X4:
|
||||
@@ -842,7 +842,7 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
|
||||
case DRM_COLOROP_3D_LUT:
|
||||
drm_printf(p, "\tsize=%d\n", colorop->size);
|
||||
drm_printf(p, "\tinterpolation=%s\n",
|
||||
drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation));
|
||||
drm_get_colorop_lut3d_interpolation_name(state->lut3d_interpolation));
|
||||
drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -265,13 +265,19 @@ EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
|
||||
*
|
||||
* Helper function to select the color pipeline on a plane by setting
|
||||
* it to the first drm_colorop element of the pipeline.
|
||||
*
|
||||
* Return: true if plane color pipeline value changed, false otherwise.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
|
||||
struct drm_colorop *colorop)
|
||||
{
|
||||
struct drm_plane *plane = plane_state->plane;
|
||||
|
||||
/* Color pipeline didn't change */
|
||||
if (plane_state->color_pipeline == colorop)
|
||||
return false;
|
||||
|
||||
if (colorop)
|
||||
drm_dbg_atomic(plane->dev,
|
||||
"Set [COLOROP:%d] for [PLANE:%d:%s] state %p\n",
|
||||
@@ -283,6 +289,8 @@ drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
|
||||
plane->base.id, plane->name, plane_state);
|
||||
|
||||
plane_state->color_pipeline = colorop;
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane);
|
||||
|
||||
@@ -604,7 +612,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
|
||||
if (val && !colorop)
|
||||
return -EACCES;
|
||||
|
||||
drm_atomic_set_colorop_for_plane(state, colorop);
|
||||
state->color_mgmt_changed |= drm_atomic_set_colorop_for_plane(state, colorop);
|
||||
} else if (property == config->prop_fb_damage_clips) {
|
||||
ret = drm_property_replace_blob_from_id(dev,
|
||||
&state->fb_damage_clips,
|
||||
@@ -713,11 +721,11 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
|
||||
static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
|
||||
struct drm_colorop_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
uint64_t val,
|
||||
bool *replaced)
|
||||
{
|
||||
ssize_t elem_size = -1;
|
||||
ssize_t size = -1;
|
||||
bool replaced = false;
|
||||
|
||||
switch (colorop->type) {
|
||||
case DRM_COLOROP_1D_LUT:
|
||||
@@ -739,28 +747,45 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
|
||||
&state->data,
|
||||
val,
|
||||
-1, size, elem_size,
|
||||
&replaced);
|
||||
replaced);
|
||||
}
|
||||
|
||||
static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
|
||||
struct drm_colorop_state *state,
|
||||
struct drm_file *file_priv,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
uint64_t val,
|
||||
bool *replaced)
|
||||
{
|
||||
if (property == colorop->bypass_property) {
|
||||
state->bypass = val;
|
||||
if (state->bypass != val) {
|
||||
state->bypass = val;
|
||||
*replaced = true;
|
||||
}
|
||||
} else if (property == colorop->lut1d_interpolation_property) {
|
||||
colorop->lut1d_interpolation = val;
|
||||
if (state->lut1d_interpolation != val) {
|
||||
state->lut1d_interpolation = val;
|
||||
*replaced = true;
|
||||
}
|
||||
} else if (property == colorop->curve_1d_type_property) {
|
||||
state->curve_1d_type = val;
|
||||
if (state->curve_1d_type != val) {
|
||||
state->curve_1d_type = val;
|
||||
*replaced = true;
|
||||
}
|
||||
} else if (property == colorop->multiplier_property) {
|
||||
state->multiplier = val;
|
||||
if (state->multiplier != val) {
|
||||
state->multiplier = val;
|
||||
*replaced = true;
|
||||
}
|
||||
} else if (property == colorop->lut3d_interpolation_property) {
|
||||
colorop->lut3d_interpolation = val;
|
||||
if (state->lut3d_interpolation != val) {
|
||||
state->lut3d_interpolation = val;
|
||||
*replaced = true;
|
||||
}
|
||||
} else if (property == colorop->data_property) {
|
||||
return drm_atomic_color_set_data_property(colorop, state,
|
||||
property, val);
|
||||
property, val,
|
||||
replaced);
|
||||
} else {
|
||||
drm_dbg_atomic(colorop->dev,
|
||||
"[COLOROP:%d:%d] unknown property [PROP:%d:%s]\n",
|
||||
@@ -782,7 +807,7 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
|
||||
else if (property == colorop->bypass_property)
|
||||
*val = state->bypass;
|
||||
else if (property == colorop->lut1d_interpolation_property)
|
||||
*val = colorop->lut1d_interpolation;
|
||||
*val = state->lut1d_interpolation;
|
||||
else if (property == colorop->curve_1d_type_property)
|
||||
*val = state->curve_1d_type;
|
||||
else if (property == colorop->multiplier_property)
|
||||
@@ -790,7 +815,7 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
|
||||
else if (property == colorop->size_property)
|
||||
*val = colorop->size;
|
||||
else if (property == colorop->lut3d_interpolation_property)
|
||||
*val = colorop->lut3d_interpolation;
|
||||
*val = state->lut3d_interpolation;
|
||||
else if (property == colorop->data_property)
|
||||
*val = (state->data) ? state->data->base.id : 0;
|
||||
else
|
||||
@@ -1275,8 +1300,10 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
|
||||
break;
|
||||
}
|
||||
case DRM_MODE_OBJECT_COLOROP: {
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_colorop *colorop = obj_to_colorop(obj);
|
||||
struct drm_colorop_state *colorop_state;
|
||||
bool replaced = false;
|
||||
|
||||
colorop_state = drm_atomic_get_colorop_state(state, colorop);
|
||||
if (IS_ERR(colorop_state)) {
|
||||
@@ -1285,7 +1312,18 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
|
||||
}
|
||||
|
||||
ret = drm_atomic_colorop_set_property(colorop, colorop_state,
|
||||
file_priv, prop, prop_value);
|
||||
file_priv, prop, prop_value,
|
||||
&replaced);
|
||||
if (ret || !replaced)
|
||||
break;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, colorop->plane);
|
||||
if (IS_ERR(plane_state)) {
|
||||
ret = PTR_ERR(plane_state);
|
||||
break;
|
||||
}
|
||||
plane_state->color_mgmt_changed |= replaced;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -342,7 +342,6 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_color
|
||||
|
||||
colorop->lut1d_interpolation_property = prop;
|
||||
drm_object_attach_property(&colorop->base, prop, interpolation);
|
||||
colorop->lut1d_interpolation = interpolation;
|
||||
|
||||
/* data */
|
||||
ret = drm_colorop_create_data_prop(dev, colorop);
|
||||
@@ -442,7 +441,6 @@ int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *col
|
||||
|
||||
colorop->lut3d_interpolation_property = prop;
|
||||
drm_object_attach_property(&colorop->base, prop, interpolation);
|
||||
colorop->lut3d_interpolation = interpolation;
|
||||
|
||||
/* data */
|
||||
ret = drm_colorop_create_data_prop(dev, colorop);
|
||||
@@ -521,6 +519,20 @@ static void __drm_colorop_state_reset(struct drm_colorop_state *colorop_state,
|
||||
&val);
|
||||
colorop_state->curve_1d_type = val;
|
||||
}
|
||||
|
||||
if (colorop->lut1d_interpolation_property) {
|
||||
if (!drm_object_property_get_default_value(&colorop->base,
|
||||
colorop->lut1d_interpolation_property,
|
||||
&val))
|
||||
colorop_state->lut1d_interpolation = val;
|
||||
}
|
||||
|
||||
if (colorop->lut3d_interpolation_property) {
|
||||
if (!drm_object_property_get_default_value(&colorop->base,
|
||||
colorop->lut3d_interpolation_property,
|
||||
&val))
|
||||
colorop_state->lut3d_interpolation = val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4678,10 +4678,17 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp)
|
||||
|
||||
if (intel_dp->edp_dpcd[0] >= DP_EDP_14) {
|
||||
__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
|
||||
sink_rates, sizeof(sink_rates));
|
||||
ret = drm_dp_dpcd_read_data(&intel_dp->aux,
|
||||
DP_SUPPORTED_LINK_RATES,
|
||||
sink_rates, sizeof(sink_rates));
|
||||
if (ret < 0) {
|
||||
drm_dbg_kms(display->drm,
|
||||
"Unable to read eDP supported link rates, using default rates\n");
|
||||
memset(sink_rates, 0, sizeof(sink_rates));
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
|
||||
int rate;
|
||||
|
||||
@@ -18,6 +18,17 @@
|
||||
#include "i915_gem_tiling.h"
|
||||
#include "i915_scatterlist.h"
|
||||
|
||||
/* Abuse scatterlist to store pointer instead of struct page. */
|
||||
static inline void __set_phys_vaddr(struct scatterlist *sg, void *vaddr)
|
||||
{
|
||||
sg_assign_page(sg, (struct page *)vaddr);
|
||||
}
|
||||
|
||||
static inline void *__get_phys_vaddr(struct scatterlist *sg)
|
||||
{
|
||||
return (void *)sg_page(sg);
|
||||
}
|
||||
|
||||
static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct address_space *mapping = obj->base.filp->f_mapping;
|
||||
@@ -58,7 +69,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
|
||||
sg->offset = 0;
|
||||
sg->length = obj->base.size;
|
||||
|
||||
sg_assign_page(sg, (struct page *)vaddr);
|
||||
__set_phys_vaddr(sg, vaddr);
|
||||
sg_dma_address(sg) = dma;
|
||||
sg_dma_len(sg) = obj->base.size;
|
||||
|
||||
@@ -99,7 +110,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
|
||||
struct sg_table *pages)
|
||||
{
|
||||
dma_addr_t dma = sg_dma_address(pages->sgl);
|
||||
void *vaddr = sg_page(pages->sgl);
|
||||
void *vaddr = __get_phys_vaddr(pages->sgl);
|
||||
|
||||
__i915_gem_object_release_shmem(obj, pages, false);
|
||||
|
||||
@@ -139,7 +150,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
|
||||
int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj,
|
||||
const struct drm_i915_gem_pwrite *args)
|
||||
{
|
||||
void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset;
|
||||
void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset;
|
||||
char __user *user_data = u64_to_user_ptr(args->data_ptr);
|
||||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
int err;
|
||||
@@ -170,7 +181,7 @@ int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj,
|
||||
int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj,
|
||||
const struct drm_i915_gem_pread *args)
|
||||
{
|
||||
void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset;
|
||||
void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset;
|
||||
char __user *user_data = u64_to_user_ptr(args->data_ptr);
|
||||
int err;
|
||||
|
||||
|
||||
@@ -290,15 +290,16 @@ static bool require_uniform_address_uniform(struct vc4_validated_shader_info *va
|
||||
{
|
||||
uint32_t o = validated_shader->num_uniform_addr_offsets;
|
||||
uint32_t num_uniforms = validated_shader->uniforms_size / 4;
|
||||
u32 *offsets;
|
||||
|
||||
validated_shader->uniform_addr_offsets =
|
||||
krealloc(validated_shader->uniform_addr_offsets,
|
||||
(o + 1) *
|
||||
sizeof(*validated_shader->uniform_addr_offsets),
|
||||
GFP_KERNEL);
|
||||
if (!validated_shader->uniform_addr_offsets)
|
||||
offsets = krealloc_array(validated_shader->uniform_addr_offsets,
|
||||
o + 1,
|
||||
sizeof(*validated_shader->uniform_addr_offsets),
|
||||
GFP_KERNEL);
|
||||
if (!offsets)
|
||||
return false;
|
||||
|
||||
validated_shader->uniform_addr_offsets = offsets;
|
||||
validated_shader->uniform_addr_offsets[o] = num_uniforms;
|
||||
validated_shader->num_uniform_addr_offsets++;
|
||||
|
||||
|
||||
@@ -124,7 +124,10 @@ static void virtio_gpu_remove(struct virtio_device *vdev)
|
||||
struct drm_device *dev = vdev->priv;
|
||||
|
||||
drm_dev_unplug(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_ATOMIC))
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
|
||||
virtio_gpu_deinit(dev);
|
||||
drm_dev_put(dev);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,10 @@ static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit,
|
||||
|
||||
dma_fence_unwrap_for_each(f, &itr, fence) {
|
||||
err = virtio_gpu_do_fence_wait(submit, f);
|
||||
if (err)
|
||||
if (err) {
|
||||
dma_fence_put(itr.chain);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -124,6 +124,15 @@ int xe_display_init_early(struct xe_device *xe)
|
||||
|
||||
intel_display_driver_early_probe(display);
|
||||
|
||||
intel_display_device_info_runtime_init(display);
|
||||
|
||||
/* Display may have been disabled at runtime init */
|
||||
if (!intel_display_device_present(display)) {
|
||||
xe->info.probe_display = false;
|
||||
unset_display_features(xe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Early display init.. */
|
||||
intel_opregion_setup(display);
|
||||
|
||||
@@ -137,8 +146,6 @@ int xe_display_init_early(struct xe_device *xe)
|
||||
|
||||
intel_bw_init_hw(display);
|
||||
|
||||
intel_display_device_info_runtime_init(display);
|
||||
|
||||
err = intel_display_driver_probe_noirq(display);
|
||||
if (err)
|
||||
goto err_opregion;
|
||||
|
||||
@@ -52,7 +52,7 @@ static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *x
|
||||
struct xe_drm_ras_counter *counter;
|
||||
int i;
|
||||
|
||||
counter = kcalloc(DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL);
|
||||
counter = drmm_kcalloc(&xe->drm, DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL);
|
||||
if (!counter)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -100,54 +100,47 @@ static int assign_node_params(struct xe_device *xe, struct drm_ras_node *node,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup_node_param(struct xe_drm_ras *ras, const enum drm_xe_ras_error_severity severity)
|
||||
static void cleanup_node_param(struct drm_ras_node *node)
|
||||
{
|
||||
struct drm_ras_node *node = &ras->node[severity];
|
||||
|
||||
kfree(ras->info[severity]);
|
||||
ras->info[severity] = NULL;
|
||||
|
||||
kfree(node->device_name);
|
||||
node->device_name = NULL;
|
||||
}
|
||||
|
||||
static void cleanup_node(struct drm_device *drm, void *node)
|
||||
{
|
||||
drm_ras_node_unregister(node);
|
||||
cleanup_node_param(node);
|
||||
}
|
||||
|
||||
static int register_nodes(struct xe_device *xe)
|
||||
{
|
||||
struct xe_drm_ras *ras = &xe->ras;
|
||||
int i;
|
||||
struct drm_ras_node *node;
|
||||
int i, ret;
|
||||
|
||||
for_each_error_severity(i) {
|
||||
struct drm_ras_node *node = &ras->node[i];
|
||||
int ret;
|
||||
node = &ras->node[i];
|
||||
|
||||
ret = assign_node_params(xe, node, i);
|
||||
if (ret) {
|
||||
cleanup_node_param(ras, i);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto free_param;
|
||||
|
||||
ret = drm_ras_node_register(node);
|
||||
if (ret) {
|
||||
cleanup_node_param(ras, i);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto free_param;
|
||||
|
||||
ret = drmm_add_action_or_reset(&xe->drm, cleanup_node, node);
|
||||
if (ret)
|
||||
goto null_info;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xe_drm_ras_unregister_nodes(struct drm_device *device, void *arg)
|
||||
{
|
||||
struct xe_device *xe = arg;
|
||||
struct xe_drm_ras *ras = &xe->ras;
|
||||
int i;
|
||||
|
||||
for_each_error_severity(i) {
|
||||
struct drm_ras_node *node = &ras->node[i];
|
||||
|
||||
drm_ras_node_unregister(node);
|
||||
cleanup_node_param(ras, i);
|
||||
}
|
||||
free_param:
|
||||
cleanup_node_param(node);
|
||||
null_info:
|
||||
ras->info[i] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,11 +169,5 @@ int xe_drm_ras_init(struct xe_device *xe)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = drmm_add_action_or_reset(&xe->drm, xe_drm_ras_unregister_nodes, xe);
|
||||
if (err) {
|
||||
drm_err(&xe->drm, "Failed to add action for Xe DRM RAS (%pe)\n", ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -157,6 +157,11 @@ static void set_exec_queue_banned(struct xe_exec_queue *q)
|
||||
atomic_or(EXEC_QUEUE_STATE_BANNED, &q->guc->state);
|
||||
}
|
||||
|
||||
static void clear_exec_queue_banned(struct xe_exec_queue *q)
|
||||
{
|
||||
atomic_andnot(EXEC_QUEUE_STATE_BANNED, &q->guc->state);
|
||||
}
|
||||
|
||||
static bool exec_queue_suspended(struct xe_exec_queue *q)
|
||||
{
|
||||
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_SUSPENDED;
|
||||
@@ -1361,7 +1366,8 @@ static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job)
|
||||
xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
|
||||
q->guc->id);
|
||||
|
||||
return xe_sched_invalidate_job(job, 2);
|
||||
/* GuC never scheduled this job - let the caller trigger a GT reset. */
|
||||
return true;
|
||||
}
|
||||
|
||||
ctx_timestamp = lower_32_bits(xe_lrc_timestamp(q->lrc[0]));
|
||||
@@ -1458,6 +1464,21 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate)
|
||||
G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recover via GT reset for a kernel queue, or for a GuC scheduling failure (job
|
||||
* never started) on a queue that was not already killed or banned. An already
|
||||
* banned queue must stay banned, so its unstarted jobs do not clear the ban or
|
||||
* trigger a reset.
|
||||
*/
|
||||
static bool timeout_needs_gt_reset(struct xe_exec_queue *q, struct xe_sched_job *job,
|
||||
bool skip_timeout_check)
|
||||
{
|
||||
if (q->flags & EXEC_QUEUE_FLAG_KERNEL)
|
||||
return true;
|
||||
|
||||
return !skip_timeout_check && !xe_sched_job_started(job);
|
||||
}
|
||||
|
||||
static enum drm_gpu_sched_stat
|
||||
guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
|
||||
{
|
||||
@@ -1606,19 +1627,19 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
|
||||
xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
|
||||
q->guc->id, q->flags);
|
||||
|
||||
/*
|
||||
* Kernel jobs should never fail, nor should VM jobs if they do
|
||||
* somethings has gone wrong and the GT needs a reset
|
||||
*/
|
||||
xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_KERNEL,
|
||||
"Kernel-submitted job timed out\n");
|
||||
xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q),
|
||||
"VM job timed out on non-killed execqueue\n");
|
||||
if (!wedged && (q->flags & EXEC_QUEUE_FLAG_KERNEL ||
|
||||
(q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)))) {
|
||||
if (!xe_sched_invalidate_job(job, 2)) {
|
||||
xe_gt_reset_async(q->gt);
|
||||
goto rearm;
|
||||
if (!wedged) {
|
||||
if (timeout_needs_gt_reset(q, job, skip_timeout_check)) {
|
||||
if (!xe_sched_invalidate_job(job, 2)) {
|
||||
clear_exec_queue_banned(q);
|
||||
xe_gt_reset_async(q->gt);
|
||||
goto rearm;
|
||||
}
|
||||
if (q->flags & EXEC_QUEUE_FLAG_KERNEL) {
|
||||
xe_gt_WARN(q->gt, true, "Kernel-submitted job timed out\n");
|
||||
xe_device_declare_wedged(gt_to_xe(q->gt));
|
||||
}
|
||||
} else if (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)) {
|
||||
xe_gt_WARN(q->gt, true, "VM job timed out on non-killed execqueue\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -255,9 +255,8 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno,
|
||||
#undef EXEC_QUEUE_COUNT_FULL_THRESHOLD
|
||||
|
||||
/*
|
||||
* Move exec queues to a temporary list to issue invalidations. The exec
|
||||
* queue must active and a reference must be taken to prevent concurrent
|
||||
* deregistrations.
|
||||
* Move exec queues to a temporary list to issue invalidations. A
|
||||
* reference must be taken to prevent concurrent deregistrations.
|
||||
*
|
||||
* List modification is safe because we hold 'vm->exec_queues.lock' for
|
||||
* reading, which prevents external modifications. Using a per-GT list
|
||||
@@ -266,7 +265,7 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno,
|
||||
*/
|
||||
list_for_each_entry_safe(q, next, &vm->exec_queues.list[id],
|
||||
vm_exec_queue_link) {
|
||||
if (q->ops->active(q) && xe_exec_queue_get_unless_zero(q)) {
|
||||
if (xe_exec_queue_get_unless_zero(q)) {
|
||||
last_q = q;
|
||||
list_move_tail(&q->vm_exec_queue_link, &tlb_inval_list);
|
||||
}
|
||||
|
||||
@@ -219,9 +219,9 @@ static void log_hw_error(struct xe_tile *tile, const char *name,
|
||||
struct xe_device *xe = tile_to_xe(tile);
|
||||
|
||||
if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE)
|
||||
drm_warn(&xe->drm, "%s %s detected\n", name, severity_str);
|
||||
drm_warn(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str);
|
||||
else
|
||||
drm_err_ratelimited(&xe->drm, "%s %s detected\n", name, severity_str);
|
||||
drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str);
|
||||
}
|
||||
|
||||
static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err,
|
||||
@@ -231,10 +231,10 @@ static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err,
|
||||
struct xe_device *xe = tile_to_xe(tile);
|
||||
|
||||
if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE)
|
||||
drm_warn(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n",
|
||||
drm_warn(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n",
|
||||
name, severity_str, i, err);
|
||||
else
|
||||
drm_err_ratelimited(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n",
|
||||
drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n",
|
||||
name, severity_str, i, err);
|
||||
}
|
||||
|
||||
@@ -251,9 +251,9 @@ static void log_soc_error(struct xe_tile *tile, const char * const *reg_info,
|
||||
|
||||
if (strcmp(name, "Undefined")) {
|
||||
if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE)
|
||||
drm_warn(&xe->drm, "%s SOC %s detected", name, severity_str);
|
||||
drm_warn(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str);
|
||||
else
|
||||
drm_err_ratelimited(&xe->drm, "%s SOC %s detected", name, severity_str);
|
||||
drm_err_ratelimited(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str);
|
||||
atomic_inc(&info[index].counter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ int xe_range_fence_insert(struct xe_range_fence_tree *tree,
|
||||
} else if (err == 0) {
|
||||
xe_range_fence_tree_insert(rfence, &tree->root);
|
||||
return 0;
|
||||
} else {
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
|
||||
free:
|
||||
|
||||
@@ -1383,55 +1383,66 @@ static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_exit(struct device *dev, struct lpi2c_imx_dma *dma)
|
||||
{
|
||||
if (dma->chan_rx)
|
||||
dma_release_channel(dma->chan_rx);
|
||||
|
||||
if (dma->chan_tx)
|
||||
dma_release_channel(dma->chan_tx);
|
||||
|
||||
devm_kfree(dev, dma);
|
||||
}
|
||||
|
||||
static int lpi2c_dma_init(struct device *dev, dma_addr_t phy_addr)
|
||||
{
|
||||
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
|
||||
struct lpi2c_imx_dma *dma;
|
||||
void *group;
|
||||
int ret;
|
||||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
/*
|
||||
* Open a devres group so that all resources allocated within
|
||||
* this function can be released together if DMA init fails but
|
||||
* probe continues in PIO mode.
|
||||
*/
|
||||
group = devres_open_group(dev, NULL, GFP_KERNEL);
|
||||
if (!group)
|
||||
return -ENOMEM;
|
||||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma) {
|
||||
ret = -ENOMEM;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
dma->phy_addr = phy_addr;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
dma->chan_tx = dma_request_chan(dev, "tx");
|
||||
dma->chan_tx = devm_dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
if (ret != -ENODEV && ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA tx channel (%d)\n", ret);
|
||||
dma->chan_tx = NULL;
|
||||
goto dma_exit;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
/* Prepare for RX DMA: */
|
||||
dma->chan_rx = dma_request_chan(dev, "rx");
|
||||
dma->chan_rx = devm_dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
if (ret != -ENODEV && ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA rx channel (%d)\n", ret);
|
||||
dma->chan_rx = NULL;
|
||||
goto dma_exit;
|
||||
goto release_group;
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA init succeeded. Remove the group marker but keep all resources
|
||||
* bound to the device, they will be freed at device removal.
|
||||
*/
|
||||
devres_remove_group(dev, group);
|
||||
|
||||
lpi2c_imx->can_use_dma = true;
|
||||
lpi2c_imx->dma = dma;
|
||||
return 0;
|
||||
|
||||
dma_exit:
|
||||
dma_exit(dev, dma);
|
||||
release_group:
|
||||
/*
|
||||
* DMA init failed. Release ALL resources allocated inside this
|
||||
* group (dma memory, TX channel if already acquired, etc.) so
|
||||
* that a successful PIO-mode probe does not hold unused resources
|
||||
* for the entire device lifetime.
|
||||
*/
|
||||
devres_release_group(dev, group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1892,9 +1892,15 @@ static void i2c_imx_remove(struct platform_device *pdev)
|
||||
static int i2c_imx_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_sleep_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_disable(i2c_imx->clk);
|
||||
return pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_runtime_resume(struct device *dev)
|
||||
@@ -1907,10 +1913,13 @@ static int i2c_imx_runtime_resume(struct device *dev)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(i2c_imx->clk);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_suspend(struct device *dev)
|
||||
|
||||
@@ -660,8 +660,8 @@ static void cci_remove(struct platform_device *pdev)
|
||||
if (cci->master[i].cci) {
|
||||
i2c_del_adapter(&cci->master[i].adap);
|
||||
of_node_put(cci->master[i].adap.dev.of_node);
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
|
||||
disable_irq(cci->irq);
|
||||
|
||||
@@ -725,8 +725,10 @@ static int riic_i2c_resume_noirq(struct device *dev)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
reset_control_assert(riic->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = riic_init_hw(riic);
|
||||
if (ret) {
|
||||
|
||||
@@ -694,6 +694,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
||||
if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
|
||||
i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
|
||||
|
||||
i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
|
||||
"i2c-analog-filter");
|
||||
|
||||
do {
|
||||
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
|
||||
&i2c_dev->timing);
|
||||
@@ -715,9 +718,6 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
|
||||
"i2c-analog-filter");
|
||||
|
||||
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
|
||||
setup->speed_freq, setup->clock_src);
|
||||
dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
|
||||
|
||||
@@ -2115,9 +2115,9 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
|
||||
static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
.clk_divisor_hs_mode = 1,
|
||||
.clk_divisor_hs_mode = 2,
|
||||
.clk_divisor_std_mode = 0x3f,
|
||||
.clk_divisor_fast_mode = 0x2c,
|
||||
.clk_divisor_fast_mode = 0x2f,
|
||||
.clk_divisor_fast_plus_mode = 0x11,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = true,
|
||||
@@ -2133,8 +2133,8 @@ static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
||||
.thigh_fast_mode = 0x2,
|
||||
.tlow_fastplus_mode = 0x2,
|
||||
.thigh_fastplus_mode = 0x2,
|
||||
.tlow_hs_mode = 0x8,
|
||||
.thigh_hs_mode = 0x6,
|
||||
.tlow_hs_mode = 0x5,
|
||||
.thigh_hs_mode = 0x2,
|
||||
.setup_hold_time_std_mode = 0x08080808,
|
||||
.setup_hold_time_fast_mode = 0x02020202,
|
||||
.setup_hold_time_fastplus_mode = 0x02020202,
|
||||
@@ -2401,29 +2401,38 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Bring the controller up and hold a usage count so it stays
|
||||
* available until the noirq phase.
|
||||
*/
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
i2c_mark_adapter_suspended(&i2c_dev->adapter);
|
||||
|
||||
if (!pm_runtime_status_suspended(dev)) {
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Runtime PM is already disabled at this point, so invoke the
|
||||
* runtime_suspend callback directly to put the controller down.
|
||||
*/
|
||||
return tegra_i2c_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
/*
|
||||
* We need to ensure that clocks are enabled so that registers can be
|
||||
* restored in tegra_i2c_init().
|
||||
* Runtime PM is still disabled at this point, so invoke the
|
||||
* runtime_resume callback directly to bring the controller back up
|
||||
* before re-initializing the hardware. The adapter is then marked
|
||||
* resumed so that consumers can issue transfers from their own
|
||||
* resume_noirq() handlers and onwards.
|
||||
*/
|
||||
err = tegra_i2c_runtime_resume(dev);
|
||||
if (err)
|
||||
@@ -2433,24 +2442,22 @@ static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* In case we are runtime suspended, disable clocks again so that we
|
||||
* don't unbalance the clock reference counts during the next runtime
|
||||
* resume transition.
|
||||
*/
|
||||
if (pm_runtime_status_suspended(dev)) {
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
{
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_i2c_pm = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend_noirq,
|
||||
tegra_i2c_resume_noirq)
|
||||
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
@@ -1918,12 +1918,18 @@ static int iommu_dma_iova_link_swiotlb(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* After removing the partial head and tail, there may be no aligned
|
||||
* middle left to map. The tail still gets bounced below.
|
||||
*/
|
||||
size -= iova_end_pad;
|
||||
error = __dma_iova_link(dev, addr + mapped, phys + mapped, size, dir,
|
||||
attrs);
|
||||
if (error)
|
||||
goto out_unmap;
|
||||
mapped += size;
|
||||
if (size) {
|
||||
error = __dma_iova_link(dev, addr + mapped, phys + mapped,
|
||||
size, dir, attrs);
|
||||
if (error)
|
||||
goto out_unmap;
|
||||
mapped += size;
|
||||
}
|
||||
|
||||
if (iova_end_pad) {
|
||||
error = iommu_dma_iova_bounce_and_link(dev, addr + mapped,
|
||||
@@ -1936,7 +1942,8 @@ static int iommu_dma_iova_link_swiotlb(struct device *dev,
|
||||
return 0;
|
||||
|
||||
out_unmap:
|
||||
dma_iova_unlink(dev, state, 0, mapped, dir, attrs);
|
||||
if (mapped)
|
||||
dma_iova_unlink(dev, state, offset, mapped, dir, attrs);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -310,6 +310,8 @@ struct fastrpc_user {
|
||||
spinlock_t lock;
|
||||
/* lock for allocations */
|
||||
struct mutex mutex;
|
||||
/* Reference count */
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
/* Extract SMMU PA from consolidated IOVA */
|
||||
@@ -386,7 +388,7 @@ static int fastrpc_map_get(struct fastrpc_map *map)
|
||||
|
||||
|
||||
static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
|
||||
struct fastrpc_map **ppmap)
|
||||
struct fastrpc_map **ppmap, bool take_ref)
|
||||
{
|
||||
struct fastrpc_map *map = NULL;
|
||||
struct dma_buf *buf;
|
||||
@@ -401,6 +403,12 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
|
||||
if (map->fd != fd || map->buf != buf)
|
||||
continue;
|
||||
|
||||
if (take_ref) {
|
||||
ret = fastrpc_map_get(map);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
*ppmap = map;
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -497,15 +505,57 @@ static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
|
||||
kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
|
||||
}
|
||||
|
||||
static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx);
|
||||
|
||||
static void fastrpc_user_free(struct kref *ref)
|
||||
{
|
||||
struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount);
|
||||
struct fastrpc_invoke_ctx *ctx, *n;
|
||||
struct fastrpc_map *map, *m;
|
||||
struct fastrpc_buf *buf, *b;
|
||||
|
||||
if (fl->init_mem)
|
||||
fastrpc_buf_free(fl->init_mem);
|
||||
|
||||
list_for_each_entry_safe(ctx, n, &fl->pending, node) {
|
||||
list_del(&ctx->node);
|
||||
fastrpc_context_put(ctx);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(map, m, &fl->maps, node)
|
||||
fastrpc_map_put(map);
|
||||
|
||||
list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
|
||||
list_del(&buf->node);
|
||||
fastrpc_buf_free(buf);
|
||||
}
|
||||
|
||||
fastrpc_channel_ctx_put(fl->cctx);
|
||||
mutex_destroy(&fl->mutex);
|
||||
kfree(fl);
|
||||
}
|
||||
|
||||
static void fastrpc_user_get(struct fastrpc_user *fl)
|
||||
{
|
||||
kref_get(&fl->refcount);
|
||||
}
|
||||
|
||||
static void fastrpc_user_put(struct fastrpc_user *fl)
|
||||
{
|
||||
kref_put(&fl->refcount, fastrpc_user_free);
|
||||
}
|
||||
|
||||
static void fastrpc_context_free(struct kref *ref)
|
||||
{
|
||||
struct fastrpc_invoke_ctx *ctx;
|
||||
struct fastrpc_channel_ctx *cctx;
|
||||
struct fastrpc_user *fl;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
|
||||
cctx = ctx->cctx;
|
||||
fl = ctx->fl;
|
||||
|
||||
for (i = 0; i < ctx->nbufs; i++)
|
||||
fastrpc_map_put(ctx->maps[i]);
|
||||
@@ -521,6 +571,8 @@ static void fastrpc_context_free(struct kref *ref)
|
||||
kfree(ctx->olaps);
|
||||
kfree(ctx);
|
||||
|
||||
/* Release the reference taken in fastrpc_context_alloc() */
|
||||
fastrpc_user_put(fl);
|
||||
fastrpc_channel_ctx_put(cctx);
|
||||
}
|
||||
|
||||
@@ -628,6 +680,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
|
||||
|
||||
/* Released in fastrpc_context_put() */
|
||||
fastrpc_channel_ctx_get(cctx);
|
||||
/* Take a reference to user, released in fastrpc_context_free() */
|
||||
fastrpc_user_get(user);
|
||||
|
||||
ctx->sc = sc;
|
||||
ctx->retval = -1;
|
||||
@@ -658,6 +712,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
|
||||
spin_lock(&user->lock);
|
||||
list_del(&ctx->node);
|
||||
spin_unlock(&user->lock);
|
||||
fastrpc_user_put(user);
|
||||
fastrpc_channel_ctx_put(cctx);
|
||||
kfree(ctx->maps);
|
||||
kfree(ctx->olaps);
|
||||
@@ -871,19 +926,10 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
|
||||
static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
|
||||
u64 len, u32 attr, struct fastrpc_map **ppmap)
|
||||
{
|
||||
struct fastrpc_session_ctx *sess = fl->sctx;
|
||||
int err = 0;
|
||||
if (!fastrpc_map_lookup(fl, fd, ppmap, true))
|
||||
return 0;
|
||||
|
||||
if (!fastrpc_map_lookup(fl, fd, ppmap)) {
|
||||
if (!fastrpc_map_get(*ppmap))
|
||||
return 0;
|
||||
dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n",
|
||||
__func__, fd);
|
||||
}
|
||||
|
||||
err = fastrpc_map_attach(fl, fd, len, attr, ppmap);
|
||||
|
||||
return err;
|
||||
return fastrpc_map_attach(fl, fd, len, attr, ppmap);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1041,7 +1087,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
|
||||
pages[i].addr = ctx->maps[i]->dma_addr;
|
||||
|
||||
mmap_read_lock(current->mm);
|
||||
vma = find_vma(current->mm, ctx->args[i].ptr);
|
||||
vma = vma_lookup(current->mm, ctx->args[i].ptr);
|
||||
if (vma)
|
||||
pages[i].addr += (ctx->args[i].ptr & PAGE_MASK) -
|
||||
vma->vm_start;
|
||||
@@ -1153,7 +1199,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
|
||||
for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
|
||||
if (!fdlist[i])
|
||||
break;
|
||||
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
|
||||
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
|
||||
fastrpc_map_put(mmap);
|
||||
}
|
||||
|
||||
@@ -1579,9 +1625,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
|
||||
struct fastrpc_channel_ctx *cctx = fl->cctx;
|
||||
struct fastrpc_invoke_ctx *ctx, *n;
|
||||
struct fastrpc_map *map, *m;
|
||||
struct fastrpc_buf *buf, *b;
|
||||
unsigned long flags;
|
||||
|
||||
fastrpc_release_current_dsp_process(fl);
|
||||
@@ -1590,28 +1633,10 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
|
||||
list_del(&fl->user);
|
||||
spin_unlock_irqrestore(&cctx->lock, flags);
|
||||
|
||||
if (fl->init_mem)
|
||||
fastrpc_buf_free(fl->init_mem);
|
||||
|
||||
list_for_each_entry_safe(ctx, n, &fl->pending, node) {
|
||||
list_del(&ctx->node);
|
||||
fastrpc_context_put(ctx);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(map, m, &fl->maps, node)
|
||||
fastrpc_map_put(map);
|
||||
|
||||
list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
|
||||
list_del(&buf->node);
|
||||
fastrpc_buf_free(buf);
|
||||
}
|
||||
|
||||
fastrpc_session_free(cctx, fl->sctx);
|
||||
fastrpc_channel_ctx_put(cctx);
|
||||
|
||||
mutex_destroy(&fl->mutex);
|
||||
kfree(fl);
|
||||
file->private_data = NULL;
|
||||
/* Release the reference taken in fastrpc_device_open */
|
||||
fastrpc_user_put(fl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1655,6 +1680,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
|
||||
spin_lock_irqsave(&cctx->lock, flags);
|
||||
list_add_tail(&fl->user, &cctx->users);
|
||||
spin_unlock_irqrestore(&cctx->lock, flags);
|
||||
kref_init(&fl->refcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2431,7 +2457,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
|
||||
|
||||
kref_init(&data->refcount);
|
||||
|
||||
dev_set_drvdata(&rpdev->dev, data);
|
||||
rdev->dma_mask = &data->dma_mask;
|
||||
dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
|
||||
INIT_LIST_HEAD(&data->users);
|
||||
@@ -2440,6 +2465,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
|
||||
idr_init(&data->ctx_idr);
|
||||
data->domain_id = domain_id;
|
||||
data->rpdev = rpdev;
|
||||
dev_set_drvdata(&rpdev->dev, data);
|
||||
|
||||
err = of_platform_populate(rdev->of_node, NULL, NULL, rdev);
|
||||
if (err)
|
||||
@@ -2513,6 +2539,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
|
||||
if (len < sizeof(*rsp))
|
||||
return -EINVAL;
|
||||
|
||||
if (!cctx)
|
||||
return -ENODEV;
|
||||
|
||||
ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
|
||||
|
||||
spin_lock_irqsave(&cctx->lock, flags);
|
||||
|
||||
@@ -1153,6 +1153,9 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
|
||||
|
||||
rmem = of_reserved_mem_lookup(np);
|
||||
of_node_put(np);
|
||||
if (!rmem)
|
||||
return -ENODEV;
|
||||
|
||||
dma_addr = rmem->base;
|
||||
/* Compute the number of hw descriptors according to the
|
||||
* reserved memory size and the payload buffer size
|
||||
|
||||
@@ -1880,6 +1880,11 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure PHC payload (timestamp, error_flags) is read
|
||||
* after req_id update is observed
|
||||
*/
|
||||
dma_rmb();
|
||||
|
||||
/* req_id was updated by the device which indicates that
|
||||
* PHC timestamp and error_flags are updated too,
|
||||
* checking errors before retrieving timestamp
|
||||
|
||||
@@ -277,7 +277,7 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd)
|
||||
struct hwrm_func_backing_store_qcaps_v2_output *resp;
|
||||
struct hwrm_func_backing_store_qcaps_v2_input *req;
|
||||
struct bnge_ctx_mem_info *ctx;
|
||||
u16 type;
|
||||
u16 type, next_type;
|
||||
int rc;
|
||||
|
||||
if (bd->ctx)
|
||||
@@ -294,8 +294,8 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd)
|
||||
|
||||
resp = bnge_hwrm_req_hold(bd, req);
|
||||
|
||||
for (type = 0; type < BNGE_CTX_V2_MAX; ) {
|
||||
struct bnge_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
|
||||
for (type = 0; type < BNGE_CTX_INV; type = next_type) {
|
||||
struct bnge_ctx_mem_type *ctxm;
|
||||
u8 init_val, init_off, i;
|
||||
__le32 *p;
|
||||
u32 flags;
|
||||
@@ -304,8 +304,14 @@ int bnge_hwrm_func_backing_store_qcaps(struct bnge_dev *bd)
|
||||
rc = bnge_hwrm_req_send(bd, req);
|
||||
if (rc)
|
||||
goto ctx_done;
|
||||
|
||||
next_type = le16_to_cpu(resp->next_valid_type);
|
||||
if (type >= BNGE_CTX_V2_MAX)
|
||||
continue;
|
||||
|
||||
ctxm = &ctx->ctx_arr[type];
|
||||
flags = le32_to_cpu(resp->flags);
|
||||
type = le16_to_cpu(resp->next_valid_type);
|
||||
|
||||
if (!(flags &
|
||||
FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID))
|
||||
continue;
|
||||
|
||||
@@ -5748,7 +5748,7 @@ static void bnxt_disable_int_sync(struct bnxt *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!bp->irq_tbl)
|
||||
if (!bp->irq_tbl || !bp->bnapi)
|
||||
return;
|
||||
|
||||
atomic_inc(&bp->intr_sem);
|
||||
|
||||
@@ -3144,7 +3144,7 @@ static int emac_probe(struct platform_device *ofdev)
|
||||
|
||||
netif_carrier_off(ndev);
|
||||
|
||||
err = devm_register_netdev(&ofdev->dev, ndev);
|
||||
err = register_netdev(ndev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%pOF: failed to register net device (%d)!\n",
|
||||
np, err);
|
||||
@@ -3197,6 +3197,13 @@ static void emac_remove(struct platform_device *ofdev)
|
||||
|
||||
DBG(dev, "remove" NL);
|
||||
|
||||
/* Unregister network device before tearing down hardware
|
||||
* to prevent use-after-free during deferred cleanup. This ensures
|
||||
* the network stack stops all operations before hardware resources
|
||||
* are released.
|
||||
*/
|
||||
unregister_netdev(dev->ndev);
|
||||
|
||||
cancel_work_sync(&dev->reset_work);
|
||||
|
||||
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
|
||||
|
||||
@@ -2633,6 +2633,8 @@ static const struct dpll_pin_ops ice_dpll_pin_ufl_ops = {
|
||||
.state_on_dpll_set = ice_dpll_ufl_pin_state_set,
|
||||
.state_on_dpll_get = ice_dpll_sw_pin_state_get,
|
||||
.direction_get = ice_dpll_pin_sw_direction_get,
|
||||
.prio_get = ice_dpll_sw_input_prio_get,
|
||||
.prio_set = ice_dpll_sw_input_prio_set,
|
||||
.frequency_get = ice_dpll_sw_pin_frequency_get,
|
||||
.frequency_set = ice_dpll_sw_pin_frequency_set,
|
||||
.esync_set = ice_dpll_sw_esync_set,
|
||||
|
||||
@@ -51,7 +51,7 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter)
|
||||
|
||||
/* Set the device clock time */
|
||||
direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME;
|
||||
mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME;
|
||||
mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB;
|
||||
ptp->set_dev_clk_time_access = idpf_ptp_get_access(adapter,
|
||||
direct,
|
||||
mailbox);
|
||||
|
||||
@@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
|
||||
goto put_err;
|
||||
}
|
||||
ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
ppdev->dev.of_node = pnp;
|
||||
ppdev->dev.of_node = of_node_get(pnp);
|
||||
|
||||
ret = platform_device_add_resources(ppdev, &res, 1);
|
||||
if (ret)
|
||||
|
||||
@@ -3917,10 +3917,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
struct mvpp2_bm_pool *bm_pool;
|
||||
struct page_pool *pp = NULL;
|
||||
struct sk_buff *skb;
|
||||
unsigned int frag_size;
|
||||
unsigned int frag_size, rx_sync_size;
|
||||
dma_addr_t dma_addr;
|
||||
phys_addr_t phys_addr;
|
||||
int pool, rx_bytes, err, ret;
|
||||
int pool, rx_bytes, rx_offset, err, ret;
|
||||
struct page *page;
|
||||
void *data;
|
||||
|
||||
@@ -3933,6 +3933,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
rx_status = mvpp2_rxdesc_status_get(port, rx_desc);
|
||||
rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc);
|
||||
rx_bytes -= MVPP2_MH_SIZE;
|
||||
rx_sync_size = rx_bytes + MVPP2_MH_SIZE;
|
||||
rx_offset = MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM;
|
||||
dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
|
||||
|
||||
pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >>
|
||||
@@ -3946,9 +3948,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
dma_dir = DMA_FROM_DEVICE;
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(dev->dev.parent, dma_addr,
|
||||
rx_bytes + MVPP2_MH_SIZE,
|
||||
dma_dir);
|
||||
dma_sync_single_range_for_cpu(dev->dev.parent, dma_addr,
|
||||
MVPP2_SKB_HEADROOM,
|
||||
rx_sync_size,
|
||||
dma_dir);
|
||||
|
||||
/* Buffer header not supported */
|
||||
if (rx_status & MVPP2_RXD_BUF_HDR)
|
||||
@@ -3970,6 +3973,12 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
else
|
||||
frag_size = bm_pool->frag_size;
|
||||
|
||||
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
|
||||
if (err) {
|
||||
netdev_err(port->dev, "failed to refill BM pools\n");
|
||||
goto err_drop_frame;
|
||||
}
|
||||
|
||||
if (xdp_prog) {
|
||||
struct xdp_rxq_info *xdp_rxq;
|
||||
|
||||
@@ -3978,7 +3987,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
else
|
||||
xdp_rxq = &rxq->xdp_rxq_long;
|
||||
|
||||
xdp_init_buff(&xdp, PAGE_SIZE, xdp_rxq);
|
||||
xdp_init_buff(&xdp, bm_pool->frag_size, xdp_rxq);
|
||||
xdp_prepare_buff(&xdp, data,
|
||||
MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM,
|
||||
rx_bytes, true);
|
||||
@@ -3987,17 +3996,19 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
|
||||
if (ret) {
|
||||
xdp_ret |= ret;
|
||||
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
|
||||
if (err) {
|
||||
netdev_err(port->dev, "failed to refill BM pools\n");
|
||||
goto err_drop_frame;
|
||||
}
|
||||
|
||||
ps.rx_packets++;
|
||||
ps.rx_bytes += rx_bytes;
|
||||
continue;
|
||||
}
|
||||
|
||||
rx_sync_size = max_t(unsigned int, rx_sync_size,
|
||||
xdp.data_end - xdp.data_hard_start -
|
||||
MVPP2_SKB_HEADROOM);
|
||||
|
||||
/* Update offset and length to reflect any XDP adjustments. */
|
||||
rx_offset = xdp.data - data;
|
||||
rx_bytes = xdp.data_end - xdp.data;
|
||||
|
||||
metasize = xdp.data - xdp.data_meta;
|
||||
}
|
||||
|
||||
@@ -4007,8 +4018,20 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
skb = slab_build_skb(data);
|
||||
if (!skb) {
|
||||
netdev_warn(port->dev, "skb build failed\n");
|
||||
goto err_drop_frame;
|
||||
if (pp) {
|
||||
page_pool_put_page(pp, virt_to_head_page(data),
|
||||
rx_sync_size, true);
|
||||
} else {
|
||||
dma_unmap_single_attrs(dev->dev.parent, dma_addr,
|
||||
bm_pool->buf_size,
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
mvpp2_frag_free(bm_pool, pp, data);
|
||||
}
|
||||
goto err_drop_frame_retired;
|
||||
}
|
||||
if (pp)
|
||||
skb_mark_for_recycle(skb);
|
||||
|
||||
/* If we have RX hardware timestamping enabled, grab the
|
||||
* timestamp from the queue and convert.
|
||||
@@ -4019,16 +4042,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
skb_hwtstamps(skb));
|
||||
}
|
||||
|
||||
err = mvpp2_rx_refill(port, bm_pool, pp, pool);
|
||||
if (err) {
|
||||
netdev_err(port->dev, "failed to refill BM pools\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
goto err_drop_frame;
|
||||
}
|
||||
|
||||
if (pp)
|
||||
skb_mark_for_recycle(skb);
|
||||
else
|
||||
if (!pp)
|
||||
dma_unmap_single_attrs(dev->dev.parent, dma_addr,
|
||||
bm_pool->buf_size, DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
@@ -4036,7 +4050,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
ps.rx_packets++;
|
||||
ps.rx_bytes += rx_bytes;
|
||||
|
||||
skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM);
|
||||
skb_reserve(skb, rx_offset);
|
||||
skb_put(skb, rx_bytes);
|
||||
if (metasize)
|
||||
skb_metadata_set(skb, metasize);
|
||||
@@ -4047,13 +4061,14 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
|
||||
continue;
|
||||
|
||||
err_drop_frame:
|
||||
dev->stats.rx_errors++;
|
||||
mvpp2_rx_error(port, rx_desc);
|
||||
/* Return the buffer to the pool */
|
||||
if (rx_status & MVPP2_RXD_BUF_HDR)
|
||||
mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status);
|
||||
else
|
||||
mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
|
||||
err_drop_frame_retired:
|
||||
dev->stats.rx_errors++;
|
||||
mvpp2_rx_error(port, rx_desc);
|
||||
}
|
||||
|
||||
if (xdp_ret & MVPP2_XDP_REDIR)
|
||||
|
||||
@@ -1571,53 +1571,49 @@ static u8 npc_map2cn20k_flag(u8 flag)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void npc_cn20k_translate_action_flags(struct npc_kpu_profile_action *act)
|
||||
{
|
||||
u8 ltype, val;
|
||||
|
||||
if (act->lid != NPC_LID_LC)
|
||||
return;
|
||||
|
||||
ltype = act->ltype;
|
||||
if (ltype != NPC_LT_LC_IP &&
|
||||
ltype != NPC_LT_LC_IP6 &&
|
||||
ltype != NPC_LT_LC_IP_OPT &&
|
||||
ltype != NPC_LT_LC_IP6_EXT)
|
||||
return;
|
||||
|
||||
switch (act->flags) {
|
||||
case NPC_F_LC_U_IP_FRAG:
|
||||
case NPC_F_LC_U_IP6_FRAG:
|
||||
case NPC_F_LC_L_6TO4:
|
||||
case NPC_F_LC_L_MPLS_IN_IP:
|
||||
case NPC_F_LC_L_IP6_TUN_IP6:
|
||||
case NPC_F_LC_L_IP6_MPLS_IN_IP:
|
||||
val = npc_map2cn20k_flag(act->flags);
|
||||
if (val != 0xFF)
|
||||
act->flags = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *pfl)
|
||||
{
|
||||
struct npc_kpu_profile_action *action;
|
||||
int entries, ltype;
|
||||
u8 flags, val;
|
||||
int entries;
|
||||
|
||||
for (int i = 0; i < pfl->kpus; i++) {
|
||||
action = pfl->kpu[i].action;
|
||||
entries = pfl->kpu[i].action_entries;
|
||||
|
||||
for (int j = 0; j < entries; j++) {
|
||||
if (action[j].lid != NPC_LID_LC)
|
||||
continue;
|
||||
|
||||
ltype = action[j].ltype;
|
||||
|
||||
if (ltype != NPC_LT_LC_IP &&
|
||||
ltype != NPC_LT_LC_IP6 &&
|
||||
ltype != NPC_LT_LC_IP_OPT &&
|
||||
ltype != NPC_LT_LC_IP6_EXT)
|
||||
continue;
|
||||
|
||||
flags = action[j].flags;
|
||||
|
||||
switch (flags) {
|
||||
case NPC_F_LC_U_IP_FRAG:
|
||||
case NPC_F_LC_U_IP6_FRAG:
|
||||
case NPC_F_LC_L_6TO4:
|
||||
case NPC_F_LC_L_MPLS_IN_IP:
|
||||
case NPC_F_LC_L_IP6_TUN_IP6:
|
||||
case NPC_F_LC_L_IP6_MPLS_IN_IP:
|
||||
val = npc_map2cn20k_flag(flags);
|
||||
if (val == 0xFF) {
|
||||
dev_err(rvu->dev,
|
||||
"%s: Error to get flag value\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
action[j].flags = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < entries; j++)
|
||||
npc_cn20k_translate_action_flags(&action[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1709,9 +1705,9 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
|
||||
for (entry = 0; entry < entries; entry++) {
|
||||
profile->kpu[kpu].cam[entry] = cam[entry];
|
||||
profile->kpu[kpu].action[entry] = action[entry];
|
||||
npc_cn20k_translate_action_flags(&profile->kpu[kpu].action[entry]);
|
||||
}
|
||||
}
|
||||
npc_cn20k_update_action_entries_n_flags(rvu, profile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1160,7 +1160,7 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
|
||||
err = rvu_npc_exact_init(rvu);
|
||||
if (err) {
|
||||
dev_err(rvu->dev, "failed to initialize exact match table\n");
|
||||
return err;
|
||||
goto cgx_err;
|
||||
}
|
||||
|
||||
/* Assign MACs for CGX mapped functions */
|
||||
|
||||
@@ -290,6 +290,7 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
|
||||
static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
|
||||
{
|
||||
int entries_per_copy = PAGE_SIZE / cqe_size;
|
||||
size_t copy_bytes;
|
||||
void *init_ents;
|
||||
int err = 0;
|
||||
int i;
|
||||
@@ -314,8 +315,14 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size)
|
||||
buf += PAGE_SIZE;
|
||||
}
|
||||
} else {
|
||||
copy_bytes = array_size(entries, cqe_size);
|
||||
if (WARN_ON_ONCE(copy_bytes > PAGE_SIZE)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = copy_to_user((void __user *)buf, init_ents,
|
||||
array_size(entries, cqe_size)) ?
|
||||
copy_bytes) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,9 +103,15 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
|
||||
|
||||
xdptxd->dma_addr = dma_addr;
|
||||
|
||||
if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
|
||||
mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL)))
|
||||
if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame,
|
||||
mlx5e_xmit_xdp_frame_mpwqe,
|
||||
mlx5e_xmit_xdp_frame,
|
||||
sq, xdptxd, 0, NULL))) {
|
||||
dma_unmap_single(sq->pdev, dma_addr, xdptxd->len,
|
||||
DMA_TO_DEVICE);
|
||||
xdp_return_frame(xdpf);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */
|
||||
mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo,
|
||||
|
||||
@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
|
||||
struct mlx5_vport *vport, int list_type)
|
||||
{
|
||||
bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
|
||||
u8 (*mac_list)[ETH_ALEN];
|
||||
u8 (*mac_list)[ETH_ALEN] = NULL;
|
||||
struct l2addr_node *node;
|
||||
struct vport_addr *addr;
|
||||
struct hlist_head *hash;
|
||||
struct hlist_node *tmp;
|
||||
int size;
|
||||
int size = 0;
|
||||
int err;
|
||||
int hi;
|
||||
int i;
|
||||
|
||||
size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
|
||||
MLX5_MAX_MC_PER_VPORT(esw->dev);
|
||||
|
||||
mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
|
||||
if (!mac_list)
|
||||
return;
|
||||
|
||||
hash = is_uc ? vport->uc_list : vport->mc_list;
|
||||
|
||||
for_each_l2hash_node(node, tmp, hash, hi) {
|
||||
@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
|
||||
goto out;
|
||||
|
||||
err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,
|
||||
mac_list, &size);
|
||||
&mac_list, &size);
|
||||
if (err)
|
||||
goto out;
|
||||
esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
|
||||
|
||||
@@ -105,9 +105,12 @@ irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req
|
||||
|
||||
lockdep_assert_held(&pool->lock);
|
||||
xa_for_each_range(&pool->irqs, index, iter, start, end) {
|
||||
struct cpumask *iter_mask = mlx5_irq_get_affinity_mask(iter);
|
||||
int iter_refcount = mlx5_irq_read_locked(iter);
|
||||
const struct cpumask *iter_mask;
|
||||
|
||||
iter_mask = irq_get_effective_affinity_mask(mlx5_irq_get_irq(iter));
|
||||
if (!iter_mask)
|
||||
continue;
|
||||
if (!cpumask_subset(iter_mask, req_mask))
|
||||
/* skip IRQs with a mask which is not subset of req_mask */
|
||||
continue;
|
||||
|
||||
@@ -324,35 +324,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu);
|
||||
|
||||
static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport,
|
||||
enum mlx5_list_type list_type)
|
||||
{
|
||||
void *query_ctx, *hca_caps;
|
||||
int ret = 0;
|
||||
|
||||
if (!vport && !mlx5_core_is_ecpf(dev))
|
||||
return list_type == MLX5_NVPRT_LIST_TYPE_UC ?
|
||||
1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
|
||||
1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
|
||||
|
||||
query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL);
|
||||
if (!query_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
|
||||
ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
|
||||
1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) :
|
||||
1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list);
|
||||
|
||||
out:
|
||||
kfree(query_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
|
||||
u16 vport,
|
||||
enum mlx5_list_type list_type,
|
||||
u8 addr_list[][ETH_ALEN],
|
||||
int *list_size)
|
||||
u8 (**addr_list)[ETH_ALEN],
|
||||
int *addr_list_size)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0};
|
||||
int allowed_list_size;
|
||||
void *nic_vport_ctx;
|
||||
int max_list_size;
|
||||
int req_list_size;
|
||||
int out_sz;
|
||||
void *out;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
req_list_size = *list_size;
|
||||
if (!addr_list || !addr_list_size)
|
||||
return -EINVAL;
|
||||
|
||||
max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
|
||||
1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
|
||||
1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
|
||||
*addr_list = NULL;
|
||||
*addr_list_size = 0;
|
||||
|
||||
if (req_list_size > max_list_size) {
|
||||
mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n",
|
||||
req_list_size, max_list_size);
|
||||
req_list_size = max_list_size;
|
||||
}
|
||||
max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type);
|
||||
if (max_list_size < 0)
|
||||
return max_list_size;
|
||||
|
||||
out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) +
|
||||
req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
|
||||
max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
|
||||
|
||||
out = kvzalloc(out_sz, GFP_KERNEL);
|
||||
if (!out)
|
||||
@@ -371,16 +399,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
|
||||
|
||||
nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out,
|
||||
nic_vport_context);
|
||||
req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
|
||||
allowed_list_size);
|
||||
allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
|
||||
allowed_list_size);
|
||||
if (!allowed_list_size)
|
||||
goto out;
|
||||
|
||||
*list_size = req_list_size;
|
||||
for (i = 0; i < req_list_size; i++) {
|
||||
*addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL);
|
||||
if (!*addr_list) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < allowed_list_size; i++) {
|
||||
u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context,
|
||||
nic_vport_ctx,
|
||||
current_uc_mac_address[i]) + 2;
|
||||
ether_addr_copy(addr_list[i], mac_addr);
|
||||
ether_addr_copy((*addr_list)[i], mac_addr);
|
||||
}
|
||||
*addr_list_size = allowed_list_size;
|
||||
out:
|
||||
kvfree(out);
|
||||
return err;
|
||||
|
||||
@@ -204,7 +204,7 @@ int txgbe_set_phy_link(struct wx *wx)
|
||||
static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
|
||||
DECLARE_PHY_INTERFACE_MASK(interfaces);
|
||||
DECLARE_PHY_INTERFACE_MASK_ZERO(interfaces);
|
||||
struct txgbe *txgbe = wx->priv;
|
||||
|
||||
if (id->cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) {
|
||||
@@ -271,7 +271,7 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
|
||||
static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
|
||||
DECLARE_PHY_INTERFACE_MASK(interfaces);
|
||||
DECLARE_PHY_INTERFACE_MASK_ZERO(interfaces);
|
||||
struct txgbe *txgbe = wx->priv;
|
||||
|
||||
if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) {
|
||||
@@ -335,7 +335,7 @@ static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
|
||||
|
||||
int txgbe_identify_module(struct wx *wx)
|
||||
{
|
||||
struct txgbe_hic_get_module_info buffer;
|
||||
struct txgbe_hic_get_module_info buffer = { 0 };
|
||||
struct txgbe_sff_id *id;
|
||||
int err = 0;
|
||||
u32 mod_abs;
|
||||
@@ -357,18 +357,16 @@ int txgbe_identify_module(struct wx *wx)
|
||||
}
|
||||
|
||||
id = &buffer.id;
|
||||
if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP &&
|
||||
id->identifier != TXGBE_SFF_IDENTIFIER_QSFP &&
|
||||
id->identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS &&
|
||||
id->identifier != TXGBE_SFF_IDENTIFIER_QSFP28) {
|
||||
wx_err(wx, "Invalid module\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (id->transceiver_type == 0xFF)
|
||||
if (id->identifier == TXGBE_SFF_IDENTIFIER_SFP)
|
||||
return txgbe_sfp_to_linkmodes(wx, id);
|
||||
|
||||
return txgbe_qsfp_to_linkmodes(wx, id);
|
||||
if (id->identifier == TXGBE_SFF_IDENTIFIER_QSFP ||
|
||||
id->identifier == TXGBE_SFF_IDENTIFIER_QSFP_PLUS ||
|
||||
id->identifier == TXGBE_SFF_IDENTIFIER_QSFP28)
|
||||
return txgbe_qsfp_to_linkmodes(wx, id);
|
||||
|
||||
wx_err(wx, "Invalid module\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void txgbe_setup_link(struct wx *wx)
|
||||
|
||||
@@ -315,6 +315,9 @@ void txgbe_up(struct wx *wx);
|
||||
int txgbe_setup_tc(struct net_device *dev, u8 tc);
|
||||
void txgbe_do_reset(struct net_device *netdev);
|
||||
|
||||
#define DECLARE_PHY_INTERFACE_MASK_ZERO(name) \
|
||||
unsigned long name[PHY_INTERFACE_MODE_MAX] = { 0, }
|
||||
|
||||
#define TXGBE_LINK_SPEED_UNKNOWN 0
|
||||
#define TXGBE_LINK_SPEED_10GB_FULL 4
|
||||
#define TXGBE_LINK_SPEED_25GB_FULL 0x10
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -965,12 +966,22 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device,
|
||||
}
|
||||
|
||||
for (i = 0; i < page_count; i++) {
|
||||
char *src = phys_to_virt(pb[i].pfn << HV_HYP_PAGE_SHIFT);
|
||||
u32 offset = pb[i].offset;
|
||||
phys_addr_t paddr = (pb[i].pfn << HV_HYP_PAGE_SHIFT) +
|
||||
pb[i].offset;
|
||||
u32 len = pb[i].len;
|
||||
|
||||
memcpy(dest, (src + offset), len);
|
||||
dest += len;
|
||||
while (len) {
|
||||
struct page *page = phys_to_page(paddr);
|
||||
u32 off = offset_in_page(paddr);
|
||||
u32 chunk = min_t(u32, len, PAGE_SIZE - off);
|
||||
char *src = kmap_local_page(page);
|
||||
|
||||
memcpy(dest, src + off, chunk);
|
||||
kunmap_local(src);
|
||||
dest += chunk;
|
||||
paddr += chunk;
|
||||
len -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
if (padding)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
struct mctp_usb {
|
||||
struct usb_device *usbdev;
|
||||
struct usb_interface *intf;
|
||||
bool stopped;
|
||||
|
||||
struct net_device *netdev;
|
||||
|
||||
@@ -32,6 +31,9 @@ struct mctp_usb {
|
||||
struct urb *tx_urb;
|
||||
struct urb *rx_urb;
|
||||
|
||||
/* enforces atomic access to rx_stopped and requeuing the retry work */
|
||||
spinlock_t rx_lock;
|
||||
bool rx_stopped;
|
||||
struct delayed_work rx_retry_work;
|
||||
};
|
||||
|
||||
@@ -122,6 +124,7 @@ static const unsigned long RX_RETRY_DELAY = HZ / 4;
|
||||
|
||||
static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
|
||||
@@ -147,8 +150,11 @@ static int mctp_usb_rx_queue(struct mctp_usb *mctp_usb, gfp_t gfp)
|
||||
return rc;
|
||||
|
||||
err_retry:
|
||||
schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY);
|
||||
return rc;
|
||||
spin_lock_irqsave(&mctp_usb->rx_lock, flags);
|
||||
if (!mctp_usb->rx_stopped)
|
||||
schedule_delayed_work(&mctp_usb->rx_retry_work, RX_RETRY_DELAY);
|
||||
spin_unlock_irqrestore(&mctp_usb->rx_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mctp_usb_in_complete(struct urb *urb)
|
||||
@@ -248,9 +254,6 @@ static void mctp_usb_rx_retry_work(struct work_struct *work)
|
||||
struct mctp_usb *mctp_usb = container_of(work, struct mctp_usb,
|
||||
rx_retry_work.work);
|
||||
|
||||
if (READ_ONCE(mctp_usb->stopped))
|
||||
return;
|
||||
|
||||
mctp_usb_rx_queue(mctp_usb, GFP_KERNEL);
|
||||
}
|
||||
|
||||
@@ -258,7 +261,7 @@ static int mctp_usb_open(struct net_device *dev)
|
||||
{
|
||||
struct mctp_usb *mctp_usb = netdev_priv(dev);
|
||||
|
||||
WRITE_ONCE(mctp_usb->stopped, false);
|
||||
WRITE_ONCE(mctp_usb->rx_stopped, false);
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
@@ -268,17 +271,21 @@ static int mctp_usb_open(struct net_device *dev)
|
||||
static int mctp_usb_stop(struct net_device *dev)
|
||||
{
|
||||
struct mctp_usb *mctp_usb = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
/* prevent RX submission retry */
|
||||
WRITE_ONCE(mctp_usb->stopped, true);
|
||||
spin_lock_irqsave(&mctp_usb->rx_lock, flags);
|
||||
mctp_usb->rx_stopped = true;
|
||||
cancel_delayed_work(&mctp_usb->rx_retry_work);
|
||||
spin_unlock_irqrestore(&mctp_usb->rx_lock, flags);
|
||||
|
||||
flush_delayed_work(&mctp_usb->rx_retry_work);
|
||||
|
||||
usb_kill_urb(mctp_usb->rx_urb);
|
||||
usb_kill_urb(mctp_usb->tx_urb);
|
||||
|
||||
cancel_delayed_work_sync(&mctp_usb->rx_retry_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -331,6 +338,7 @@ static int mctp_usb_probe(struct usb_interface *intf,
|
||||
dev->netdev = netdev;
|
||||
dev->usbdev = interface_to_usbdev(intf);
|
||||
dev->intf = intf;
|
||||
spin_lock_init(&dev->rx_lock);
|
||||
usb_set_intfdata(intf, dev);
|
||||
|
||||
dev->ep_in = ep_in->bEndpointAddress;
|
||||
|
||||
@@ -1718,6 +1718,9 @@ static int phy_sfp_probe(struct phy_device *phydev)
|
||||
|
||||
ret = sfp_bus_add_upstream(bus, phydev, &sfp_phydev_ops);
|
||||
sfp_bus_put(bus);
|
||||
|
||||
if (ret)
|
||||
phydev->sfp_bus = NULL;
|
||||
}
|
||||
|
||||
if (!ret && phydev->sfp_bus)
|
||||
@@ -3509,9 +3512,15 @@ static int phy_setup_ports(struct phy_device *phydev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_sfp_probe(phydev);
|
||||
if (ret)
|
||||
goto out;
|
||||
/* We don't support SFP with genphy drivers. Also, genphy driver
|
||||
* binding occurs with RTNL help, which will deadlock the call to
|
||||
* sfp_bus_add_upstream().
|
||||
*/
|
||||
if (!phydev->is_genphy_driven) {
|
||||
ret = phy_sfp_probe(phydev);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (phydev->n_ports < phydev->max_n_ports) {
|
||||
ret = phy_default_setup_single_port(phydev);
|
||||
@@ -3775,6 +3784,11 @@ static int phy_probe(struct device *dev)
|
||||
return 0;
|
||||
|
||||
out:
|
||||
sfp_bus_del_upstream(phydev->sfp_bus);
|
||||
phydev->sfp_bus = NULL;
|
||||
|
||||
phy_cleanup_ports(phydev);
|
||||
|
||||
if (!phydev->is_on_sfp_module)
|
||||
phy_led_triggers_unregister(phydev);
|
||||
|
||||
@@ -3798,11 +3812,11 @@ static int phy_remove(struct device *dev)
|
||||
|
||||
phydev->state = PHY_DOWN;
|
||||
|
||||
phy_cleanup_ports(phydev);
|
||||
|
||||
sfp_bus_del_upstream(phydev->sfp_bus);
|
||||
phydev->sfp_bus = NULL;
|
||||
|
||||
phy_cleanup_ports(phydev);
|
||||
|
||||
if (phydev->drv && phydev->drv->remove)
|
||||
phydev->drv->remove(phydev);
|
||||
|
||||
|
||||
@@ -2070,6 +2070,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
|
||||
struct virtio_net_hdr_v1_hash_tunnel hdr;
|
||||
struct virtio_net_hdr *gso;
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
ret = tun_vnet_hdr_tnl_from_skb(tun->flags, tun->dev, skb,
|
||||
&hdr);
|
||||
if (ret)
|
||||
|
||||
@@ -9851,7 +9851,12 @@ static int rtl8152_probe_once(struct usb_interface *intf,
|
||||
struct net_device *netdev;
|
||||
int ret;
|
||||
|
||||
usb_reset_device(udev);
|
||||
ret = usb_reset_device(udev);
|
||||
if (ret < 0) {
|
||||
dev_err(&intf->dev, "USB reset failed, errno=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
netdev = alloc_etherdev(sizeof(struct r8152));
|
||||
if (!netdev) {
|
||||
dev_err(&intf->dev, "Out of memory\n");
|
||||
|
||||
@@ -1468,18 +1468,16 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
|
||||
cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
|
||||
of_node_put(cell_np);
|
||||
if (!cell_entry) {
|
||||
__nvmem_device_put(nvmem);
|
||||
nvmem_layout_module_put(nvmem);
|
||||
if (nvmem->layout)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
else
|
||||
return ERR_PTR(-ENOENT);
|
||||
ret = nvmem->layout ? -EPROBE_DEFER : -ENOENT;
|
||||
__nvmem_device_put(nvmem);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
cell = nvmem_create_cell(cell_entry, id, cell_index);
|
||||
if (IS_ERR(cell)) {
|
||||
__nvmem_device_put(nvmem);
|
||||
nvmem_layout_module_put(nvmem);
|
||||
__nvmem_device_put(nvmem);
|
||||
}
|
||||
|
||||
return cell;
|
||||
@@ -1593,8 +1591,8 @@ void nvmem_cell_put(struct nvmem_cell *cell)
|
||||
kfree_const(cell->id);
|
||||
|
||||
kfree(cell);
|
||||
__nvmem_device_put(nvmem);
|
||||
nvmem_layout_module_put(nvmem);
|
||||
__nvmem_device_put(nvmem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvmem_cell_put);
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem,
|
||||
|
||||
cell.name = onie_tlv_cell_name(tlv.type);
|
||||
if (!cell.name)
|
||||
continue;
|
||||
goto next;
|
||||
|
||||
cell.offset = hdr_len + offset + sizeof(tlv.type) + sizeof(tlv.len);
|
||||
cell.bytes = tlv.len;
|
||||
@@ -132,6 +132,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem,
|
||||
return ret;
|
||||
}
|
||||
|
||||
next:
|
||||
offset += sizeof(tlv) + tlv.len;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/string_choices.h>
|
||||
@@ -40,39 +39,6 @@
|
||||
static struct amd_gpio *pinctrl_dev;
|
||||
#endif
|
||||
|
||||
static const struct dmi_system_id amd_gpio_quirk_yoga7_14agp11[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "83TD"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void amd_gpio_apply_quirks(struct amd_gpio *gpio_dev)
|
||||
{
|
||||
const unsigned int pin = 157; /* WACF2200 GpioInt per ACPI _CRS */
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
if (!dmi_check_system(amd_gpio_quirk_yoga7_14agp11))
|
||||
return;
|
||||
if (pin >= gpio_dev->gc.ngpio)
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
|
||||
reg = readl(gpio_dev->base + pin * 4);
|
||||
reg |= BIT(INTERRUPT_ENABLE_OFF) | BIT(INTERRUPT_MASK_OFF);
|
||||
writel(reg, gpio_dev->base + pin * 4);
|
||||
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
|
||||
|
||||
dev_info(&gpio_dev->pdev->dev,
|
||||
"Enabled IRQ for GPIO %u (Yoga 7 14AGP11 touchscreen)\n",
|
||||
pin);
|
||||
}
|
||||
|
||||
static int amd_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -1253,7 +1219,6 @@ static int amd_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
/* Disable and mask interrupts */
|
||||
amd_gpio_irq_init(gpio_dev);
|
||||
amd_gpio_apply_quirks(gpio_dev);
|
||||
|
||||
girq = &gpio_dev->gc.irq;
|
||||
gpio_irq_chip_set_chip(girq, &amd_gpio_irqchip);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "pinctrl-mcp23s08.h"
|
||||
|
||||
#define MCP_MAX_DEV_PER_CS 8
|
||||
#define MCP23S08_SPI_BASE 0x40
|
||||
|
||||
/*
|
||||
* A given spi_device can represent up to eight mcp23sxx chips
|
||||
@@ -143,13 +144,13 @@ static int mcp23s08_probe(struct spi_device *spi)
|
||||
unsigned int addr;
|
||||
int chips;
|
||||
int ret;
|
||||
u32 v;
|
||||
u8 v;
|
||||
|
||||
info = spi_get_device_match_data(spi);
|
||||
|
||||
ret = device_property_read_u32(dev, "microchip,spi-present-mask", &v);
|
||||
ret = device_property_read_u8(dev, "microchip,spi-present-mask", &v);
|
||||
if (ret) {
|
||||
ret = device_property_read_u32(dev, "mcp,spi-present-mask", &v);
|
||||
ret = device_property_read_u8(dev, "mcp,spi-present-mask", &v);
|
||||
if (ret) {
|
||||
dev_err(dev, "missing spi-present-mask");
|
||||
return ret;
|
||||
@@ -173,6 +174,8 @@ static int mcp23s08_probe(struct spi_device *spi)
|
||||
for_each_set_bit(addr, &spi_present_mask, MCP_MAX_DEV_PER_CS) {
|
||||
data->mcp[addr] = &data->chip[--chips];
|
||||
data->mcp[addr]->irq = spi->irq;
|
||||
data->mcp[addr]->dev = dev;
|
||||
data->mcp[addr]->addr = MCP23S08_SPI_BASE | (addr << 1);
|
||||
|
||||
ret = mcp23s08_spi_regmap_init(data->mcp[addr], dev, addr, info);
|
||||
if (ret)
|
||||
@@ -184,7 +187,7 @@ static int mcp23s08_probe(struct spi_device *spi)
|
||||
if (!data->mcp[addr]->pinctrl_desc.name)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mcp23s08_probe_one(data->mcp[addr], dev, 0x40 | (addr << 1),
|
||||
ret = mcp23s08_probe_one(data->mcp[addr], dev, MCP23S08_SPI_BASE | (addr << 1),
|
||||
info->type, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -487,7 +487,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
|
||||
domain->ipg_rate_mhz = ipg_rate_mhz;
|
||||
|
||||
pd_pdev->dev.parent = &pdev->dev;
|
||||
pd_pdev->dev.of_node = np;
|
||||
pd_pdev->dev.of_node = of_node_get(np);
|
||||
pd_pdev->dev.fwnode = of_fwnode_handle(np);
|
||||
|
||||
ret = platform_device_add(pd_pdev);
|
||||
|
||||
@@ -86,7 +86,7 @@ static inline void ti_sci_pd_set_wkup_constraint(struct device *dev)
|
||||
const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (device_may_wakeup(dev) || device_wakeup_path(dev)) {
|
||||
/*
|
||||
* If device can wakeup using IO daisy chain wakeups,
|
||||
* we do not want to set a constraint.
|
||||
|
||||
@@ -2479,8 +2479,13 @@ ptp_ocp_ts_enable(void *priv, u32 req, bool enable)
|
||||
iowrite32(1, ®->intr_mask);
|
||||
iowrite32(1, ®->intr);
|
||||
} else {
|
||||
int irq_vec = pci_irq_vector(bp->pdev, ext->irq_vec);
|
||||
|
||||
iowrite32(0, ®->intr_mask);
|
||||
iowrite32(0, ®->enable);
|
||||
ioread32(®->intr_mask);
|
||||
if (irq_vec > 0)
|
||||
synchronize_irq(irq_vec);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -4867,6 +4872,22 @@ ptp_ocp_detach(struct ptp_ocp *bp)
|
||||
ptp_ocp_detach_sysfs(bp);
|
||||
ptp_ocp_attr_group_del(bp);
|
||||
timer_delete_sync(&bp->watchdog);
|
||||
/* Disable interrupts on all timestampers */
|
||||
if (bp->ts0)
|
||||
ptp_ocp_ts_enable(bp->ts0, 0, false);
|
||||
if (bp->ts1)
|
||||
ptp_ocp_ts_enable(bp->ts1, 0, false);
|
||||
if (bp->ts2)
|
||||
ptp_ocp_ts_enable(bp->ts2, 0, false);
|
||||
if (bp->ts3)
|
||||
ptp_ocp_ts_enable(bp->ts3, 0, false);
|
||||
if (bp->ts4)
|
||||
ptp_ocp_ts_enable(bp->ts4, 0, false);
|
||||
if (bp->pps)
|
||||
ptp_ocp_ts_enable(bp->pps, ~0, false);
|
||||
if (bp->ptp)
|
||||
ptp_clock_unregister(bp->ptp);
|
||||
kfree(bp->ptp_info.pin_config);
|
||||
ptp_ocp_unregister_ext(bp->ts0);
|
||||
ptp_ocp_unregister_ext(bp->ts1);
|
||||
ptp_ocp_unregister_ext(bp->ts2);
|
||||
@@ -4884,9 +4905,6 @@ ptp_ocp_detach(struct ptp_ocp *bp)
|
||||
clk_hw_unregister_fixed_rate(bp->i2c_clk);
|
||||
if (bp->n_irqs)
|
||||
pci_free_irq_vectors(bp->pdev);
|
||||
if (bp->ptp)
|
||||
ptp_clock_unregister(bp->ptp);
|
||||
kfree(bp->ptp_info.pin_config);
|
||||
device_unregister(&bp->dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -1471,15 +1471,12 @@ static int qcom_slim_ngd_ssr_pdr_notify(struct qcom_slim_ngd_ctrl *ctrl,
|
||||
switch (action) {
|
||||
case QCOM_SSR_BEFORE_SHUTDOWN:
|
||||
case SERVREG_SERVICE_STATE_DOWN:
|
||||
/* Make sure the last dma xfer is finished */
|
||||
mutex_lock(&ctrl->tx_lock);
|
||||
if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) {
|
||||
pm_runtime_get_noresume(ctrl->ctrl.dev);
|
||||
ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN;
|
||||
qcom_slim_ngd_down(ctrl);
|
||||
qcom_slim_ngd_exit_dma(ctrl);
|
||||
}
|
||||
mutex_unlock(&ctrl->tx_lock);
|
||||
break;
|
||||
case QCOM_SSR_AFTER_POWERUP:
|
||||
case SERVREG_SERVICE_STATE_UP:
|
||||
@@ -1542,7 +1539,7 @@ static int of_qcom_slim_ngd_register(struct device *parent,
|
||||
kfree(ngd);
|
||||
return ret;
|
||||
}
|
||||
ngd->pdev->dev.of_node = node;
|
||||
ngd->pdev->dev.of_node = of_node_get(node);
|
||||
ctrl->ngd = ngd;
|
||||
|
||||
ret = platform_device_add(ngd->pdev);
|
||||
@@ -1560,6 +1557,13 @@ static int of_qcom_slim_ngd_register(struct device *parent,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void qcom_slim_ngd_unregister(struct qcom_slim_ngd_ctrl *ctrl)
|
||||
{
|
||||
struct qcom_slim_ngd *ngd = ctrl->ngd;
|
||||
|
||||
platform_device_del(ngd->pdev);
|
||||
}
|
||||
|
||||
static int qcom_slim_ngd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -1577,24 +1581,10 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
|
||||
ret = qcom_slim_ngd_qmi_svc_event_init(ctrl);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "QMI service registration failed:%d", ret);
|
||||
return ret;
|
||||
pm_runtime_dont_use_autosuspend(dev);
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
|
||||
INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
|
||||
ctrl->mwq = create_singlethread_workqueue("ngd_master");
|
||||
if (!ctrl->mwq) {
|
||||
dev_err(&pdev->dev, "Failed to start master worker\n");
|
||||
ret = -ENOMEM;
|
||||
goto wq_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
wq_err:
|
||||
qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
|
||||
if (ctrl->mwq)
|
||||
destroy_workqueue(ctrl->mwq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1602,6 +1592,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qcom_slim_ngd_ctrl *ctrl;
|
||||
int irq;
|
||||
int ret;
|
||||
struct pdr_service *pds;
|
||||
|
||||
@@ -1615,20 +1606,16 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ctrl->base))
|
||||
return PTR_ERR(ctrl->base);
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(dev, ret, qcom_slim_ngd_interrupt,
|
||||
IRQF_TRIGGER_HIGH, "slim-ngd", ctrl);
|
||||
ret = devm_request_irq(dev, irq, qcom_slim_ngd_interrupt,
|
||||
IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN,
|
||||
"slim-ngd", ctrl);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "request IRQ failed\n");
|
||||
|
||||
ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify;
|
||||
ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb);
|
||||
if (IS_ERR(ctrl->notifier))
|
||||
return PTR_ERR(ctrl->notifier);
|
||||
|
||||
ctrl->dev = dev;
|
||||
ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
|
||||
ctrl->framer.superfreq =
|
||||
@@ -1649,48 +1636,71 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
|
||||
init_completion(&ctrl->qmi.qmi_comp);
|
||||
init_completion(&ctrl->qmi_up);
|
||||
|
||||
INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
|
||||
INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
|
||||
|
||||
ctrl->mwq = create_singlethread_workqueue("ngd_master");
|
||||
if (!ctrl->mwq)
|
||||
return dev_err_probe(dev, -ENOMEM, "Failed to start master worker\n");
|
||||
|
||||
ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl);
|
||||
if (IS_ERR(ctrl->pdr)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr),
|
||||
"Failed to init PDR handle\n");
|
||||
goto err_pdr_alloc;
|
||||
ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
|
||||
goto err_destroy_mwq;
|
||||
}
|
||||
|
||||
ret = of_qcom_slim_ngd_register(dev, ctrl);
|
||||
if (ret)
|
||||
goto err_pdr_release;
|
||||
|
||||
pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd");
|
||||
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(pds), "pdr add lookup failed\n");
|
||||
goto err_pdr_lookup;
|
||||
goto err_unregister_ngd;
|
||||
}
|
||||
|
||||
platform_driver_register(&qcom_slim_ngd_driver);
|
||||
return of_qcom_slim_ngd_register(dev, ctrl);
|
||||
ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify;
|
||||
ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb);
|
||||
if (IS_ERR(ctrl->notifier)) {
|
||||
ret = PTR_ERR(ctrl->notifier);
|
||||
goto err_unregister_ngd;
|
||||
}
|
||||
|
||||
err_pdr_alloc:
|
||||
qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
|
||||
enable_irq(irq);
|
||||
|
||||
err_pdr_lookup:
|
||||
return 0;
|
||||
|
||||
err_unregister_ngd:
|
||||
qcom_slim_ngd_unregister(ctrl);
|
||||
err_pdr_release:
|
||||
pdr_handle_release(ctrl->pdr);
|
||||
err_destroy_mwq:
|
||||
destroy_workqueue(ctrl->mwq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
platform_driver_unregister(&qcom_slim_ngd_driver);
|
||||
struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
|
||||
|
||||
pdr_handle_release(ctrl->pdr);
|
||||
qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
|
||||
|
||||
qcom_slim_ngd_unregister(ctrl);
|
||||
|
||||
destroy_workqueue(ctrl->mwq);
|
||||
}
|
||||
|
||||
static void qcom_slim_ngd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pdr_handle_release(ctrl->pdr);
|
||||
qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
|
||||
qcom_slim_ngd_enable(ctrl, false);
|
||||
qcom_slim_ngd_exit_dma(ctrl);
|
||||
qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
|
||||
if (ctrl->mwq)
|
||||
destroy_workqueue(ctrl->mwq);
|
||||
|
||||
kfree(ctrl->ngd);
|
||||
ctrl->ngd = NULL;
|
||||
@@ -1752,6 +1762,28 @@ static struct platform_driver qcom_slim_ngd_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(qcom_slim_ngd_ctrl_driver);
|
||||
static int qcom_slim_ngd_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&qcom_slim_ngd_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&qcom_slim_ngd_ctrl_driver);
|
||||
if (ret)
|
||||
platform_driver_unregister(&qcom_slim_ngd_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_slim_ngd_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&qcom_slim_ngd_ctrl_driver);
|
||||
platform_driver_unregister(&qcom_slim_ngd_driver);
|
||||
}
|
||||
|
||||
module_init(qcom_slim_ngd_init);
|
||||
module_exit(qcom_slim_ngd_exit);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Qualcomm SLIMBus NGD controller");
|
||||
|
||||
@@ -158,8 +158,8 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
||||
|
||||
of_data = (struct mpfs_syscon_config *) device_get_match_data(dev);
|
||||
if (!of_data) {
|
||||
dev_err(dev, "Error getting match data\n");
|
||||
return -EINVAL;
|
||||
ret = dev_err_probe(dev, -EINVAL, "Error getting match data\n");
|
||||
goto out_free_channel;
|
||||
}
|
||||
|
||||
for (i = 0; i < of_data->nb_subdevs; i++) {
|
||||
@@ -173,6 +173,8 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_channel:
|
||||
mbox_free_channel(sys_controller->chan);
|
||||
out_free:
|
||||
kfree(sys_controller);
|
||||
return ret;
|
||||
|
||||
@@ -472,7 +472,9 @@ static inline void dw_spi_abort(struct spi_controller *ctlr)
|
||||
if (dws->dma_mapped)
|
||||
dws->dma_ops->dma_stop(dws);
|
||||
|
||||
disable_irq(dws->irq);
|
||||
dw_spi_reset_chip(dws);
|
||||
enable_irq(dws->irq);
|
||||
}
|
||||
|
||||
static void dw_spi_handle_err(struct spi_controller *ctlr,
|
||||
|
||||
@@ -440,10 +440,15 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!xfer->cs_change) {
|
||||
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
|
||||
peripheral.fragmentation = FRAGMENTATION;
|
||||
}
|
||||
/*
|
||||
* Set fragmentation to keep CS asserted after this transfer when:
|
||||
* - non-last transfer with cs_change=0: keep CS asserted between chained transfers
|
||||
* - last transfer with cs_change=1: keep CS asserted after the message
|
||||
* (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to
|
||||
* keep CS asserted across header, wait-state and data phases)
|
||||
*/
|
||||
peripheral.fragmentation = list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ?
|
||||
xfer->cs_change : !xfer->cs_change;
|
||||
|
||||
if (peripheral.cmd & SPI_RX) {
|
||||
dmaengine_slave_config(mas->rx, &config);
|
||||
@@ -849,10 +854,16 @@ static int setup_se_xfer(struct spi_transfer *xfer,
|
||||
mas->cur_xfer_mode = GENI_SE_DMA;
|
||||
geni_se_select_mode(se, mas->cur_xfer_mode);
|
||||
|
||||
if (!xfer->cs_change) {
|
||||
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
|
||||
m_params = FRAGMENTATION;
|
||||
}
|
||||
/*
|
||||
* Set FRAGMENTATION to keep CS asserted after this transfer when:
|
||||
* - non-last transfer with cs_change=0: keep CS asserted between chained transfers
|
||||
* - last transfer with cs_change=1: keep CS asserted after the message
|
||||
* (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to
|
||||
* keep CS asserted across header, wait-state and data phases)
|
||||
*/
|
||||
if (list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ?
|
||||
xfer->cs_change : !xfer->cs_change)
|
||||
m_params = FRAGMENTATION;
|
||||
|
||||
/*
|
||||
* Lock around right before we start the transfer since our
|
||||
|
||||
@@ -135,8 +135,9 @@ static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \
|
||||
RZV2H_RSPI_TX(writel, u32)
|
||||
RZV2H_RSPI_TX(writew, u16)
|
||||
RZV2H_RSPI_TX(writeb, u8)
|
||||
/* The read access size for RSPI_SPDR is fixed at 32 bits */
|
||||
RZV2H_RSPI_RX(readl, u32)
|
||||
RZV2H_RSPI_RX(readw, u16)
|
||||
RZV2H_RSPI_RX(readl, u16)
|
||||
RZV2H_RSPI_RX(readl, u8)
|
||||
|
||||
static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi,
|
||||
|
||||
@@ -464,8 +464,11 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex
|
||||
|
||||
if (check_fwstate(pmlmepriv, _FW_LINKED) && (is_same_network(&pmlmepriv->cur_network.network, pnetwork, 0))) {
|
||||
update_network(&pmlmepriv->cur_network.network, pnetwork, adapter, true);
|
||||
if (pmlmepriv->cur_network.network.ie_length < sizeof(struct ndis_802_11_fix_ie))
|
||||
return;
|
||||
|
||||
rtw_update_protection(adapter, (pmlmepriv->cur_network.network.ies) + sizeof(struct ndis_802_11_fix_ie),
|
||||
pmlmepriv->cur_network.network.ie_length);
|
||||
pmlmepriv->cur_network.network.ie_length - sizeof(struct ndis_802_11_fix_ie));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,6 +604,8 @@ static bool rtw_is_desired_network(struct adapter *adapter, struct wlan_network
|
||||
privacy = pnetwork->network.privacy;
|
||||
|
||||
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
|
||||
if (pnetwork->network.ie_length < _FIXED_IE_LENGTH_)
|
||||
return false;
|
||||
if (rtw_get_wps_ie(pnetwork->network.ies + _FIXED_IE_LENGTH_, pnetwork->network.ie_length - _FIXED_IE_LENGTH_, NULL, &wps_ielen))
|
||||
return true;
|
||||
else
|
||||
@@ -614,11 +619,15 @@ static bool rtw_is_desired_network(struct adapter *adapter, struct wlan_network
|
||||
bselected = false;
|
||||
|
||||
if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) {
|
||||
p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_));
|
||||
if (p && ie_len > 0)
|
||||
bselected = true;
|
||||
else
|
||||
if (pnetwork->network.ie_length < _BEACON_IE_OFFSET_) {
|
||||
bselected = false;
|
||||
} else {
|
||||
p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_));
|
||||
if (p && ie_len > 0)
|
||||
bselected = true;
|
||||
else
|
||||
bselected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1072,8 +1081,11 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur_network->network.ie_length < sizeof(struct ndis_802_11_fix_ie))
|
||||
return;
|
||||
|
||||
rtw_update_protection(padapter, (cur_network->network.ies) + sizeof(struct ndis_802_11_fix_ie),
|
||||
(cur_network->network.ie_length));
|
||||
(cur_network->network.ie_length - sizeof(struct ndis_802_11_fix_ie)));
|
||||
|
||||
rtw_update_ht_cap(padapter, cur_network->network.ies, cur_network->network.ie_length, (u8) cur_network->network.configuration.ds_config);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ static bool tb_property_entry_valid(const struct tb_property_entry *entry,
|
||||
case TB_PROPERTY_TYPE_DIRECTORY:
|
||||
case TB_PROPERTY_TYPE_DATA:
|
||||
case TB_PROPERTY_TYPE_TEXT:
|
||||
if (!entry->length)
|
||||
return false;
|
||||
if (entry->length > block_len)
|
||||
return false;
|
||||
if (check_add_overflow(entry->value, entry->length, &end) ||
|
||||
@@ -185,6 +187,10 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
|
||||
if (is_root) {
|
||||
content_offset = dir_offset + 2;
|
||||
content_len = dir_len;
|
||||
if (content_offset + content_len > block_len) {
|
||||
tb_property_free_dir(dir);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (dir_len < 4) {
|
||||
tb_property_free_dir(dir);
|
||||
|
||||
@@ -55,6 +55,7 @@ static const char * const state_names[] = {
|
||||
struct xdomain_request_work {
|
||||
struct work_struct work;
|
||||
struct tb_xdp_header *pkg;
|
||||
size_t pkg_len;
|
||||
struct tb *tb;
|
||||
};
|
||||
|
||||
@@ -122,7 +123,9 @@ static bool tb_xdomain_match(const struct tb_cfg_request *req,
|
||||
static bool tb_xdomain_copy(struct tb_cfg_request *req,
|
||||
const struct ctl_pkg *pkg)
|
||||
{
|
||||
memcpy(req->response, pkg->buffer, req->response_size);
|
||||
size_t len = min_t(size_t, pkg->frame.size, req->response_size);
|
||||
|
||||
memcpy(req->response, pkg->buffer, len);
|
||||
req->result.err = 0;
|
||||
return true;
|
||||
}
|
||||
@@ -393,6 +396,8 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route,
|
||||
}
|
||||
}
|
||||
|
||||
if (req.offset + len > data_len)
|
||||
len = data_len - req.offset;
|
||||
memcpy(data + req.offset, res->data, len * 4);
|
||||
req.offset += len;
|
||||
} while (!data_len || req.offset < data_len);
|
||||
@@ -731,6 +736,7 @@ static void tb_xdp_handle_request(struct work_struct *work)
|
||||
struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
|
||||
const struct tb_xdp_header *pkg = xw->pkg;
|
||||
const struct tb_xdomain_header *xhdr = &pkg->xd_hdr;
|
||||
size_t pkg_len = xw->pkg_len;
|
||||
struct tb *tb = xw->tb;
|
||||
struct tb_ctl *ctl = tb->ctl;
|
||||
struct tb_xdomain *xd;
|
||||
@@ -762,7 +768,7 @@ static void tb_xdp_handle_request(struct work_struct *work)
|
||||
switch (pkg->type) {
|
||||
case PROPERTIES_REQUEST:
|
||||
tb_dbg(tb, "%llx: received XDomain properties request\n", route);
|
||||
if (xd) {
|
||||
if (xd && pkg_len >= sizeof(struct tb_xdp_properties)) {
|
||||
ret = tb_xdp_properties_response(tb, ctl, xd, sequence,
|
||||
(const struct tb_xdp_properties *)pkg);
|
||||
}
|
||||
@@ -816,7 +822,8 @@ static void tb_xdp_handle_request(struct work_struct *work)
|
||||
tb_dbg(tb, "%llx: received XDomain link state change request\n",
|
||||
route);
|
||||
|
||||
if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) {
|
||||
if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH &&
|
||||
pkg_len >= sizeof(struct tb_xdp_link_state_change)) {
|
||||
const struct tb_xdp_link_state_change *lsc =
|
||||
(const struct tb_xdp_link_state_change *)pkg;
|
||||
|
||||
@@ -868,6 +875,7 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr,
|
||||
kfree(xw);
|
||||
return false;
|
||||
}
|
||||
xw->pkg_len = size;
|
||||
xw->tb = tb_domain_get(tb);
|
||||
|
||||
schedule_work(&xw->work);
|
||||
|
||||
@@ -773,6 +773,12 @@ static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer)
|
||||
}
|
||||
|
||||
/* Read the descriptor data */
|
||||
if (le16_to_cpu(rom_desc->Size) != sizeof(struct edge_ti_manuf_descriptor)) {
|
||||
dev_err(dev, "unexpected Edge descriptor length: %u\n",
|
||||
le16_to_cpu(rom_desc->Size));
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
|
||||
le16_to_cpu(rom_desc->Size), buffer);
|
||||
if (status)
|
||||
@@ -838,6 +844,11 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw)
|
||||
/* Pointer to fw_down memory image */
|
||||
img_header = (struct ti_i2c_image_header *)&fw->data[4];
|
||||
|
||||
if (le16_to_cpu(img_header->Length) >
|
||||
buffer_size - sizeof(struct ti_i2c_firmware_rec)) {
|
||||
kfree(buffer);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(buffer + sizeof(struct ti_i2c_firmware_rec),
|
||||
&fw->data[4 + sizeof(struct ti_i2c_image_header)],
|
||||
le16_to_cpu(img_header->Length));
|
||||
|
||||
@@ -330,8 +330,8 @@ static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
|
||||
unsigned char *buf = dest;
|
||||
int count;
|
||||
|
||||
count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
|
||||
&port->lock);
|
||||
count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN,
|
||||
size - KLSI_HDR_LEN, &port->lock);
|
||||
put_unaligned_le16(count, buf);
|
||||
|
||||
return count + KLSI_HDR_LEN;
|
||||
|
||||
@@ -202,6 +202,7 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define DELL_PRODUCT_5821E_ESIM 0x81e0
|
||||
#define DELL_PRODUCT_5829E_ESIM 0x81e4
|
||||
#define DELL_PRODUCT_5829E 0x81e6
|
||||
#define DELL_PRODUCT_5826E_ESIM 0x81ea
|
||||
|
||||
#define DELL_PRODUCT_FM101R_ESIM 0x8213
|
||||
#define DELL_PRODUCT_FM101R 0x8215
|
||||
@@ -1123,6 +1124,8 @@ static const struct usb_device_id option_ids[] = {
|
||||
.driver_info = RSVD(0) | RSVD(6) },
|
||||
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E_ESIM),
|
||||
.driver_info = RSVD(0) | RSVD(6) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_5826E_ESIM, 0xff),
|
||||
.driver_info = RSVD(1) | RSVD(4) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R, 0xff) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R_ESIM, 0xff) },
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#ifndef DRM_ATOMIC_UAPI_H_
|
||||
#define DRM_ATOMIC_UAPI_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct drm_crtc_state;
|
||||
struct drm_display_mode;
|
||||
struct drm_property_blob;
|
||||
@@ -50,7 +52,7 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
|
||||
struct drm_crtc *crtc);
|
||||
void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
|
||||
struct drm_framebuffer *fb);
|
||||
void drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
|
||||
bool drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
|
||||
struct drm_colorop *colorop);
|
||||
int __must_check
|
||||
drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user