Merge 8379d0cbd5 ("mmc: core: Add SD card quirk for broken poweroff notification") into android14-6.1-lts

Steps on the way to 6.1.121

Resolved merge conflicts in:
	drivers/mmc/core/card.h
	include/linux/mmc/card.h

Change-Id: I0f59989030d630651cfd6bc28c45db5f313db1fe
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2024-12-16 10:29:18 +00:00
83 changed files with 1133 additions and 412 deletions

View File

@@ -1342,7 +1342,7 @@ static int tagged_addr_ctrl_get(struct task_struct *target,
{ {
long ctrl = get_tagged_addr_ctrl(target); long ctrl = get_tagged_addr_ctrl(target);
if (IS_ERR_VALUE(ctrl)) if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl)))
return ctrl; return ctrl;
return membuf_write(&to, &ctrl, sizeof(ctrl)); return membuf_write(&to, &ctrl, sizeof(ctrl));
@@ -1356,6 +1356,10 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct
int ret; int ret;
long ctrl; long ctrl;
ctrl = get_tagged_addr_ctrl(target);
if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl)))
return ctrl;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1);
if (ret) if (ret)
return ret; return ret;

View File

@@ -32,9 +32,9 @@ static unsigned long nr_pinned_asids;
static unsigned long *pinned_asid_map; static unsigned long *pinned_asid_map;
#define ASID_MASK (~GENMASK(asid_bits - 1, 0)) #define ASID_MASK (~GENMASK(asid_bits - 1, 0))
#define ASID_FIRST_VERSION (1UL << asid_bits) #define ASID_FIRST_VERSION (1UL << 16)
#define NUM_USER_ASIDS ASID_FIRST_VERSION #define NUM_USER_ASIDS (1UL << asid_bits)
#define ctxid2asid(asid) ((asid) & ~ASID_MASK) #define ctxid2asid(asid) ((asid) & ~ASID_MASK)
#define asid2ctxid(asid, genid) ((asid) | (genid)) #define asid2ctxid(asid, genid) ((asid) | (genid))

View File

@@ -29,6 +29,16 @@ static inline int prepare_hugepage_range(struct file *file,
return 0; return 0;
} }
#define __HAVE_ARCH_HUGE_PTE_CLEAR
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long sz)
{
pte_t clear;
pte_val(clear) = (unsigned long)invalid_pte_table;
set_pte_at(mm, addr, ptep, clear);
}
#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR #define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)

View File

@@ -10,23 +10,11 @@ obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o not
ifneq ($(c-gettimeofday-y),) ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y) CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y)
CFLAGS_vgettimeofday-32.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_vgettimeofday-32.o += $(call cc-option, -fno-stack-protector)
CFLAGS_vgettimeofday-32.o += -DDISABLE_BRANCH_PROFILING
CFLAGS_vgettimeofday-32.o += -ffreestanding -fasynchronous-unwind-tables
CFLAGS_REMOVE_vgettimeofday-32.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_vgettimeofday-32.o += -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y)
CFLAGS_vgettimeofday-64.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_vgettimeofday-64.o += $(call cc-option, -fno-stack-protector)
CFLAGS_vgettimeofday-64.o += -DDISABLE_BRANCH_PROFILING
CFLAGS_vgettimeofday-64.o += -ffreestanding -fasynchronous-unwind-tables
CFLAGS_REMOVE_vgettimeofday-64.o = $(CC_FLAGS_FTRACE)
# Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true # Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true
# by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is # by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is
# compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code # compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code
# generation is minimal, it will just use r29 instead. # generation is minimal, it will just use r29 instead.
CFLAGS_vgettimeofday-64.o += $(call cc-option, -ffixed-r30) CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) $(call cc-option, -ffixed-r30)
endif endif
# Build rules # Build rules
@@ -47,14 +35,33 @@ KCOV_INSTRUMENT := n
UBSAN_SANITIZE := n UBSAN_SANITIZE := n
KASAN_SANITIZE := n KASAN_SANITIZE := n
ccflags-y := -shared -fno-common -fno-builtin -nostdlib -Wl,--hash-style=both ccflags-y := -fno-common -fno-builtin
ccflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld) ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN)
ccflags-y += $(call cc-option, -fno-stack-protector)
ccflags-y += -DDISABLE_BRANCH_PROFILING
ccflags-y += -ffreestanding -fasynchronous-unwind-tables
ccflags-remove-y := $(CC_FLAGS_FTRACE)
ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS)
ldflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld)
# Filter flags that clang will warn are unused for linking
ldflags-y += $(filter-out $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CFLAGS))
CC32FLAGS := -Wl,-soname=linux-vdso32.so.1 -m32 CC32FLAGS := -m32
AS32FLAGS := -D__VDSO32__ -s CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc
ifdef CONFIG_CC_IS_CLANG
# This flag is supported by clang for 64-bit but not 32-bit so it will cause
# an unused command line flag warning for this file.
CC32FLAGSREMOVE += -fno-stack-clash-protection
# -mstack-protector-guard values from the 64-bit build are not valid for the
# 32-bit one. clang validates the values passed to these arguments during
# parsing, even when -fno-stack-protector is passed afterwards.
CC32FLAGSREMOVE += -mstack-protector-guard%
endif
LD32FLAGS := -Wl,-soname=linux-vdso32.so.1
AS32FLAGS := -D__VDSO32__
CC64FLAGS := -Wl,-soname=linux-vdso64.so.1 LD64FLAGS := -Wl,-soname=linux-vdso64.so.1
AS64FLAGS := -D__VDSO64__ -s AS64FLAGS := -D__VDSO64__
targets += vdso32.lds targets += vdso32.lds
CPPFLAGS_vdso32.lds += -P -C -Upowerpc CPPFLAGS_vdso32.lds += -P -C -Upowerpc
@@ -92,13 +99,15 @@ include/generated/vdso64-offsets.h: $(obj)/vdso64.so.dbg FORCE
# actual build commands # actual build commands
quiet_cmd_vdso32ld_and_check = VDSO32L $@ quiet_cmd_vdso32ld_and_check = VDSO32L $@
cmd_vdso32ld_and_check = $(VDSOCC) $(c_flags) $(CC32FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^) -z noexecstack ; $(cmd_vdso_check) cmd_vdso32ld_and_check = $(VDSOCC) $(ldflags-y) $(CC32FLAGS) $(LD32FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
quiet_cmd_vdso32as = VDSO32A $@ quiet_cmd_vdso32as = VDSO32A $@
cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $< cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $<
quiet_cmd_vdso32cc = VDSO32C $@ quiet_cmd_vdso32cc = VDSO32C $@
cmd_vdso32cc = $(VDSOCC) $(c_flags) $(CC32FLAGS) -c -o $@ $< cmd_vdso32cc = $(VDSOCC) $(filter-out $(CC32FLAGSREMOVE), $(c_flags)) $(CC32FLAGS) -c -o $@ $<
quiet_cmd_vdso64ld_and_check = VDSO64L $@ quiet_cmd_vdso64ld_and_check = VDSO64L $@
cmd_vdso64ld_and_check = $(VDSOCC) $(c_flags) $(CC64FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^) -z noexecstack ; $(cmd_vdso_check) cmd_vdso64ld_and_check = $(VDSOCC) $(ldflags-y) $(LD64FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
quiet_cmd_vdso64as = VDSO64A $@ quiet_cmd_vdso64as = VDSO64A $@
cmd_vdso64as = $(VDSOCC) $(a_flags) $(CC64FLAGS) $(AS64FLAGS) -c -o $@ $< cmd_vdso64as = $(VDSOCC) $(a_flags) $(AS64FLAGS) -c -o $@ $<
OBJECT_FILES_NON_STANDARD := y

View File

@@ -1896,7 +1896,9 @@ static void cpumsf_pmu_stop(struct perf_event *event, int flags)
event->hw.state |= PERF_HES_STOPPED; event->hw.state |= PERF_HES_STOPPED;
if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) { if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
hw_perf_event_update(event, 1); /* CPU hotplug off removes SDBs. No samples to extract. */
if (cpuhw->flags & PMU_F_RESERVED)
hw_perf_event_update(event, 1);
event->hw.state |= PERF_HES_UPTODATE; event->hw.state |= PERF_HES_UPTODATE;
} }
perf_pmu_enable(event->pmu); perf_pmu_enable(event->pmu);

View File

@@ -881,11 +881,12 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
static int amd_pmu_v2_handle_irq(struct pt_regs *regs) static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
{ {
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
static atomic64_t status_warned = ATOMIC64_INIT(0);
u64 reserved, status, mask, new_bits, prev_bits;
struct perf_sample_data data; struct perf_sample_data data;
struct hw_perf_event *hwc; struct hw_perf_event *hwc;
struct perf_event *event; struct perf_event *event;
int handled = 0, idx; int handled = 0, idx;
u64 reserved, status, mask;
bool pmu_enabled; bool pmu_enabled;
/* /*
@@ -952,7 +953,12 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
* the corresponding PMCs are expected to be inactive according to the * the corresponding PMCs are expected to be inactive according to the
* active_mask * active_mask
*/ */
WARN_ON(status > 0); if (status > 0) {
prev_bits = atomic64_fetch_or(status, &status_warned);
// A new bit was set for the very first time.
new_bits = status & ~prev_bits;
WARN(new_bits, "New overflows for inactive PMCs: %llx\n", new_bits);
}
/* Clear overflow and freeze bits */ /* Clear overflow and freeze bits */
amd_pmu_ack_global_status(~status); amd_pmu_ack_global_status(~status);

View File

@@ -137,7 +137,7 @@ static void __fwnode_link_del(struct fwnode_link *link)
*/ */
static void __fwnode_link_cycle(struct fwnode_link *link) static void __fwnode_link_cycle(struct fwnode_link *link)
{ {
pr_debug("%pfwf: Relaxing link with %pfwf\n", pr_debug("%pfwf: cycle: depends on %pfwf\n",
link->consumer, link->supplier); link->consumer, link->supplier);
link->flags |= FWLINK_FLAG_CYCLE; link->flags |= FWLINK_FLAG_CYCLE;
} }
@@ -1082,7 +1082,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
return NULL; return NULL;
list_for_each_entry(link, &fwnode->suppliers, c_hook) list_for_each_entry(link, &fwnode->suppliers, c_hook)
if (!(link->flags & FWLINK_FLAG_CYCLE)) if (!(link->flags &
(FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE)))
return link->supplier; return link->supplier;
return NULL; return NULL;
@@ -1932,10 +1933,10 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
* *
* Return true if one or more cycles were found. Otherwise, return false. * Return true if one or more cycles were found. Otherwise, return false.
*/ */
static bool __fw_devlink_relax_cycles(struct device *con, static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
struct fwnode_handle *sup_handle) struct fwnode_handle *sup_handle)
{ {
struct device *sup_dev = NULL, *par_dev = NULL; struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL;
struct fwnode_link *link; struct fwnode_link *link;
struct device_link *dev_link; struct device_link *dev_link;
bool ret = false; bool ret = false;
@@ -1952,27 +1953,31 @@ static bool __fw_devlink_relax_cycles(struct device *con,
sup_handle->flags |= FWNODE_FLAG_VISITED; sup_handle->flags |= FWNODE_FLAG_VISITED;
sup_dev = get_dev_from_fwnode(sup_handle);
/* Termination condition. */ /* Termination condition. */
if (sup_dev == con) { if (sup_handle == con_handle) {
pr_debug("----- cycle: start -----\n");
ret = true; ret = true;
goto out; goto out;
} }
sup_dev = get_dev_from_fwnode(sup_handle);
con_dev = get_dev_from_fwnode(con_handle);
/* /*
* If sup_dev is bound to a driver and @con hasn't started binding to a * If sup_dev is bound to a driver and @con hasn't started binding to a
* driver, sup_dev can't be a consumer of @con. So, no need to check * driver, sup_dev can't be a consumer of @con. So, no need to check
* further. * further.
*/ */
if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND && if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND &&
con->links.status == DL_DEV_NO_DRIVER) { con_dev && con_dev->links.status == DL_DEV_NO_DRIVER) {
ret = false; ret = false;
goto out; goto out;
} }
list_for_each_entry(link, &sup_handle->suppliers, c_hook) { list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
if (__fw_devlink_relax_cycles(con, link->supplier)) { if (link->flags & FWLINK_FLAG_IGNORE)
continue;
if (__fw_devlink_relax_cycles(con_handle, link->supplier)) {
__fwnode_link_cycle(link); __fwnode_link_cycle(link);
ret = true; ret = true;
} }
@@ -1987,8 +1992,11 @@ static bool __fw_devlink_relax_cycles(struct device *con,
else else
par_dev = fwnode_get_next_parent_dev(sup_handle); par_dev = fwnode_get_next_parent_dev(sup_handle);
if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) if (par_dev && __fw_devlink_relax_cycles(con_handle, par_dev->fwnode)) {
pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle,
par_dev->fwnode);
ret = true; ret = true;
}
if (!sup_dev) if (!sup_dev)
goto out; goto out;
@@ -2002,8 +2010,10 @@ static bool __fw_devlink_relax_cycles(struct device *con,
!(dev_link->flags & DL_FLAG_CYCLE)) !(dev_link->flags & DL_FLAG_CYCLE))
continue; continue;
if (__fw_devlink_relax_cycles(con, if (__fw_devlink_relax_cycles(con_handle,
dev_link->supplier->fwnode)) { dev_link->supplier->fwnode)) {
pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
dev_link->supplier->fwnode);
fw_devlink_relax_link(dev_link); fw_devlink_relax_link(dev_link);
dev_link->flags |= DL_FLAG_CYCLE; dev_link->flags |= DL_FLAG_CYCLE;
ret = true; ret = true;
@@ -2045,10 +2055,8 @@ static int fw_devlink_create_devlink(struct device *con,
int ret = 0; int ret = 0;
u32 flags; u32 flags;
if (con->fwnode == link->consumer) if (link->flags & FWLINK_FLAG_IGNORE)
flags = fw_devlink_get_flags(link->flags); return 0;
else
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
/* /*
* In some cases, a device P might also be a supplier to its child node * In some cases, a device P might also be a supplier to its child node
@@ -2070,24 +2078,23 @@ static int fw_devlink_create_devlink(struct device *con,
return -EINVAL; return -EINVAL;
/* /*
* SYNC_STATE_ONLY device links don't block probing and supports cycles. * Don't try to optimize by not calling the cycle detection logic under
* So, one might expect that cycle detection isn't necessary for them. * certain conditions. There's always some corner case that won't get
* However, if the device link was marked as SYNC_STATE_ONLY because * detected.
* it's part of a cycle, then we still need to do cycle detection. This
* is because the consumer and supplier might be part of multiple cycles
* and we need to detect all those cycles.
*/ */
if (!device_link_flag_is_sync_state_only(flags) || device_links_write_lock();
flags & DL_FLAG_CYCLE) { if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) {
device_links_write_lock(); __fwnode_link_cycle(link);
if (__fw_devlink_relax_cycles(con, sup_handle)) { pr_debug("----- cycle: end -----\n");
__fwnode_link_cycle(link); pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n",
flags = fw_devlink_get_flags(link->flags); link->consumer, sup_handle);
dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
sup_handle);
}
device_links_write_unlock();
} }
device_links_write_unlock();
if (con->fwnode == link->consumer)
flags = fw_devlink_get_flags(link->flags);
else
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE) if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
sup_dev = fwnode_get_next_parent_dev(sup_handle); sup_dev = fwnode_get_next_parent_dev(sup_handle);

View File

@@ -783,7 +783,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
* fwnode pointer. Note that this function also puts a reference to @child * fwnode pointer. Note that this function also puts a reference to @child
* unconditionally. * unconditionally.
*/ */
struct fwnode_handle *device_get_next_child_node(struct device *dev, struct fwnode_handle *device_get_next_child_node(const struct device *dev,
struct fwnode_handle *child) struct fwnode_handle *child)
{ {
const struct fwnode_handle *fwnode = dev_fwnode(dev); const struct fwnode_handle *fwnode = dev_fwnode(dev);
@@ -826,7 +826,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
* The caller is responsible for calling fwnode_handle_put() on the returned * The caller is responsible for calling fwnode_handle_put() on the returned
* fwnode pointer. * fwnode pointer.
*/ */
struct fwnode_handle *device_get_named_child_node(struct device *dev, struct fwnode_handle *device_get_named_child_node(const struct device *dev,
const char *childname) const char *childname)
{ {
return fwnode_get_named_child_node(dev_fwnode(dev), childname); return fwnode_get_named_child_node(dev_fwnode(dev), childname);
@@ -892,7 +892,7 @@ EXPORT_SYMBOL_GPL(fwnode_device_is_available);
* *
* Return: the number of child nodes for a given device. * Return: the number of child nodes for a given device.
*/ */
unsigned int device_get_child_node_count(struct device *dev) unsigned int device_get_child_node_count(const struct device *dev)
{ {
struct fwnode_handle *child; struct fwnode_handle *child;
unsigned int count = 0; unsigned int count = 0;

View File

@@ -652,6 +652,17 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
} }
EXPORT_SYMBOL_GPL(regmap_attach_dev); EXPORT_SYMBOL_GPL(regmap_attach_dev);
static int dev_get_regmap_match(struct device *dev, void *res, void *data);
static int regmap_detach_dev(struct device *dev, struct regmap *map)
{
if (!dev)
return 0;
return devres_release(dev, dev_get_regmap_release,
dev_get_regmap_match, (void *)map->name);
}
static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
const struct regmap_config *config) const struct regmap_config *config)
{ {
@@ -1502,6 +1513,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
{ {
int ret; int ret;
regmap_detach_dev(map->dev, map);
regcache_exit(map); regcache_exit(map);
regmap_debugfs_exit(map); regmap_debugfs_exit(map);

View File

@@ -103,10 +103,36 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
static bool dma_fence_array_signaled(struct dma_fence *fence) static bool dma_fence_array_signaled(struct dma_fence *fence)
{ {
struct dma_fence_array *array = to_dma_fence_array(fence); struct dma_fence_array *array = to_dma_fence_array(fence);
int num_pending;
unsigned int i;
if (atomic_read(&array->num_pending) > 0) /*
* We need to read num_pending before checking the enable_signal bit
* to avoid racing with the enable_signaling() implementation, which
* might decrement the counter, and cause a partial check.
* atomic_read_acquire() pairs with atomic_dec_and_test() in
* dma_fence_array_enable_signaling()
*
* The !--num_pending check is here to account for the any_signaled case
* if we race with enable_signaling(), that means the !num_pending check
* in the is_signalling_enabled branch might be outdated (num_pending
* might have been decremented), but that's fine. The user will get the
* right value when testing again later.
*/
num_pending = atomic_read_acquire(&array->num_pending);
if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) {
if (num_pending <= 0)
goto signal;
return false; return false;
}
for (i = 0; i < array->num_fences; ++i) {
if (dma_fence_is_signaled(array->fences[i]) && !--num_pending)
goto signal;
}
return false;
signal:
dma_fence_array_clear_pending_error(array); dma_fence_array_clear_pending_error(array);
return true; return true;
} }

View File

@@ -12,6 +12,7 @@
#include <linux/dma-fence-chain.h> #include <linux/dma-fence-chain.h>
#include <linux/dma-fence-unwrap.h> #include <linux/dma-fence-unwrap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sort.h>
/* Internal helper to start new array iteration, don't use directly */ /* Internal helper to start new array iteration, don't use directly */
static struct dma_fence * static struct dma_fence *
@@ -59,6 +60,25 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
} }
EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
static int fence_cmp(const void *_a, const void *_b)
{
struct dma_fence *a = *(struct dma_fence **)_a;
struct dma_fence *b = *(struct dma_fence **)_b;
if (a->context < b->context)
return -1;
else if (a->context > b->context)
return 1;
if (dma_fence_is_later(b, a))
return 1;
else if (dma_fence_is_later(a, b))
return -1;
return 0;
}
/* Implementation for the dma_fence_merge() marco, don't use directly */ /* Implementation for the dma_fence_merge() marco, don't use directly */
struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
struct dma_fence **fences, struct dma_fence **fences,
@@ -67,8 +87,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
struct dma_fence_array *result; struct dma_fence_array *result;
struct dma_fence *tmp, **array; struct dma_fence *tmp, **array;
ktime_t timestamp; ktime_t timestamp;
unsigned int i; int i, j, count;
size_t count;
count = 0; count = 0;
timestamp = ns_to_ktime(0); timestamp = ns_to_ktime(0);
@@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
if (!array) if (!array)
return NULL; return NULL;
/*
* This trashes the input fence array and uses it as position for the
* following merge loop. This works because the dma_fence_merge()
* wrapper macro is creating this temporary array on the stack together
* with the iterators.
*/
for (i = 0; i < num_fences; ++i)
fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]);
count = 0; count = 0;
do { for (i = 0; i < num_fences; ++i) {
unsigned int sel; dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
if (!dma_fence_is_signaled(tmp)) {
restart: array[count++] = dma_fence_get(tmp);
tmp = NULL;
for (i = 0; i < num_fences; ++i) {
struct dma_fence *next;
while (fences[i] && dma_fence_is_signaled(fences[i]))
fences[i] = dma_fence_unwrap_next(&iter[i]);
next = fences[i];
if (!next)
continue;
/*
* We can't guarantee that inpute fences are ordered by
* context, but it is still quite likely when this
* function is used multiple times. So attempt to order
* the fences by context as we pass over them and merge
* fences with the same context.
*/
if (!tmp || tmp->context > next->context) {
tmp = next;
sel = i;
} else if (tmp->context < next->context) {
continue;
} else if (dma_fence_is_later(tmp, next)) {
fences[i] = dma_fence_unwrap_next(&iter[i]);
goto restart;
} else { } else {
fences[sel] = dma_fence_unwrap_next(&iter[sel]); ktime_t t = dma_fence_timestamp(tmp);
goto restart;
if (ktime_after(t, timestamp))
timestamp = t;
} }
} }
}
if (tmp) { if (count == 0 || count == 1)
array[count++] = dma_fence_get(tmp); goto return_fastpath;
fences[sel] = dma_fence_unwrap_next(&iter[sel]);
sort(array, count, sizeof(*array), fence_cmp, NULL);
/*
* Only keep the most recent fence for each context.
*/
j = 0;
for (i = 1; i < count; i++) {
if (array[i]->context == array[j]->context)
dma_fence_put(array[i]);
else
array[++j] = array[i];
}
count = ++j;
if (count > 1) {
result = dma_fence_array_create(count, array,
dma_fence_context_alloc(1),
1, false);
if (!result) {
for (i = 0; i < count; i++)
dma_fence_put(array[i]);
tmp = NULL;
goto return_tmp;
} }
} while (tmp); return &result->base;
if (count == 0) {
tmp = dma_fence_allocate_private_stub(ktime_get());
goto return_tmp;
} }
if (count == 1) { return_fastpath:
if (count == 0)
tmp = dma_fence_allocate_private_stub(timestamp);
else
tmp = array[0]; tmp = array[0];
goto return_tmp;
}
result = dma_fence_array_create(count, array,
dma_fence_context_alloc(1),
1, false);
if (!result) {
tmp = NULL;
goto return_tmp;
}
return &result->base;
return_tmp: return_tmp:
kfree(array); kfree(array);

View File

@@ -31,13 +31,15 @@
static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev, static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev,
struct amdgpu_ring *ring) struct amdgpu_ring *ring)
{ {
if (!ring || !ring->funcs->emit_wreg) if (!ring || !ring->funcs->emit_wreg) {
WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2,
0); 0);
else RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2);
} else {
amdgpu_ring_emit_wreg(ring, amdgpu_ring_emit_wreg(ring,
(adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2,
0); 0);
}
} }
static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev, static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev,

View File

@@ -2560,10 +2560,10 @@ static int it6505_poweron(struct it6505 *it6505)
/* time interval between OVDD and SYSRSTN at least be 10ms */ /* time interval between OVDD and SYSRSTN at least be 10ms */
if (pdata->gpiod_reset) { if (pdata->gpiod_reset) {
usleep_range(10000, 20000); usleep_range(10000, 20000);
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(pdata->gpiod_reset, 1); gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
usleep_range(10000, 20000); usleep_range(1000, 2000);
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
usleep_range(25000, 35000);
} }
it6505->powered = true; it6505->powered = true;
@@ -2589,7 +2589,7 @@ static int it6505_poweroff(struct it6505 *it6505)
} }
if (pdata->gpiod_reset) if (pdata->gpiod_reset)
gpiod_set_value_cansleep(pdata->gpiod_reset, 0); gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
if (pdata->pwr18) { if (pdata->pwr18) {
err = regulator_disable(pdata->pwr18); err = regulator_disable(pdata->pwr18);
@@ -3050,7 +3050,7 @@ static int it6505_init_pdata(struct it6505 *it6505)
return PTR_ERR(pdata->ovdd); return PTR_ERR(pdata->ovdd);
} }
pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(pdata->gpiod_reset)) { if (IS_ERR(pdata->gpiod_reset)) {
dev_err(dev, "gpiod_reset gpio not found"); dev_err(dev, "gpiod_reset gpio not found");
return PTR_ERR(pdata->gpiod_reset); return PTR_ERR(pdata->gpiod_reset);

View File

@@ -319,6 +319,9 @@ static bool drm_dp_decode_sideband_msg_hdr(const struct drm_dp_mst_topology_mgr
hdr->broadcast = (buf[idx] >> 7) & 0x1; hdr->broadcast = (buf[idx] >> 7) & 0x1;
hdr->path_msg = (buf[idx] >> 6) & 0x1; hdr->path_msg = (buf[idx] >> 6) & 0x1;
hdr->msg_len = buf[idx] & 0x3f; hdr->msg_len = buf[idx] & 0x3f;
if (hdr->msg_len < 1) /* min space for body CRC */
return false;
idx++; idx++;
hdr->somt = (buf[idx] >> 7) & 0x1; hdr->somt = (buf[idx] >> 7) & 0x1;
hdr->eomt = (buf[idx] >> 6) & 0x1; hdr->eomt = (buf[idx] >> 6) & 0x1;
@@ -3652,8 +3655,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
ret = 0; ret = 0;
mgr->payload_id_table_cleared = false; mgr->payload_id_table_cleared = false;
memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv)); mgr->reset_rx_state = true;
memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv));
} }
out_unlock: out_unlock:
@@ -3781,6 +3783,11 @@ out_fail:
} }
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume); EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
static void reset_msg_rx_state(struct drm_dp_sideband_msg_rx *msg)
{
memset(msg, 0, sizeof(*msg));
}
static bool static bool
drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
struct drm_dp_mst_branch **mstb) struct drm_dp_mst_branch **mstb)
@@ -3859,6 +3866,34 @@ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
return true; return true;
} }
static int get_msg_request_type(u8 data)
{
return data & 0x7f;
}
static bool verify_rx_request_type(struct drm_dp_mst_topology_mgr *mgr,
const struct drm_dp_sideband_msg_tx *txmsg,
const struct drm_dp_sideband_msg_rx *rxmsg)
{
const struct drm_dp_sideband_msg_hdr *hdr = &rxmsg->initial_hdr;
const struct drm_dp_mst_branch *mstb = txmsg->dst;
int tx_req_type = get_msg_request_type(txmsg->msg[0]);
int rx_req_type = get_msg_request_type(rxmsg->msg[0]);
char rad_str[64];
if (tx_req_type == rx_req_type)
return true;
drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, rad_str, sizeof(rad_str));
drm_dbg_kms(mgr->dev,
"Got unexpected MST reply, mstb: %p seqno: %d lct: %d rad: %s rx_req_type: %s (%02x) != tx_req_type: %s (%02x)\n",
mstb, hdr->seqno, mstb->lct, rad_str,
drm_dp_mst_req_type_str(rx_req_type), rx_req_type,
drm_dp_mst_req_type_str(tx_req_type), tx_req_type);
return false;
}
static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
{ {
struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_sideband_msg_tx *txmsg;
@@ -3888,6 +3923,9 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
goto out_clear_reply; goto out_clear_reply;
} }
if (!verify_rx_request_type(mgr, txmsg, msg))
goto out_clear_reply;
drm_dp_sideband_parse_reply(mgr, msg, &txmsg->reply); drm_dp_sideband_parse_reply(mgr, msg, &txmsg->reply);
if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) { if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
@@ -4063,6 +4101,17 @@ out:
return 0; return 0;
} }
static void update_msg_rx_state(struct drm_dp_mst_topology_mgr *mgr)
{
mutex_lock(&mgr->lock);
if (mgr->reset_rx_state) {
mgr->reset_rx_state = false;
reset_msg_rx_state(&mgr->down_rep_recv);
reset_msg_rx_state(&mgr->up_req_recv);
}
mutex_unlock(&mgr->lock);
}
/** /**
* drm_dp_mst_hpd_irq_handle_event() - MST hotplug IRQ handle MST event * drm_dp_mst_hpd_irq_handle_event() - MST hotplug IRQ handle MST event
* @mgr: manager to notify irq for. * @mgr: manager to notify irq for.
@@ -4097,6 +4146,8 @@ int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr, const u
*handled = true; *handled = true;
} }
update_msg_rx_state(mgr);
if (esi[1] & DP_DOWN_REP_MSG_RDY) { if (esi[1] & DP_DOWN_REP_MSG_RDY) {
ret = drm_dp_mst_handle_down_rep(mgr); ret = drm_dp_mst_handle_down_rep(mgr);
*handled = true; *handled = true;

View File

@@ -137,7 +137,7 @@ static void mixer_dbg_crb(struct seq_file *s, int val)
} }
} }
static void mixer_dbg_mxn(struct seq_file *s, void *addr) static void mixer_dbg_mxn(struct seq_file *s, void __iomem *addr)
{ {
int i; int i;

View File

@@ -49,9 +49,9 @@ void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon)
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_SRC_X(source), channel); V3D_CORE_WRITE(0, V3D_V4_PCTR_0_SRC_X(source), channel);
} }
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask);
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_CLR, mask); V3D_CORE_WRITE(0, V3D_V4_PCTR_0_CLR, mask);
V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask); V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask);
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask);
v3d->active_perfmon = perfmon; v3d->active_perfmon = perfmon;
} }

View File

@@ -2234,7 +2234,8 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
if (hid_is_usb(wacom->hdev)) { if (hid_is_usb(wacom->hdev)) {
struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent); struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
product_name = dev->product; if (dev->product != NULL)
product_name = dev->product;
} }
if (wacom->hdev->bus == BUS_I2C) { if (wacom->hdev->bus == BUS_I2C) {

View File

@@ -341,10 +341,10 @@ struct bus_type i3c_bus_type = {
}; };
static enum i3c_addr_slot_status static enum i3c_addr_slot_status
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
{ {
unsigned long status; unsigned long status;
int bitpos = addr * 2; int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
if (addr > I2C_MAX_ADDR) if (addr > I2C_MAX_ADDR)
return I3C_ADDR_SLOT_RSVD; return I3C_ADDR_SLOT_RSVD;
@@ -352,22 +352,33 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
status = bus->addrslots[bitpos / BITS_PER_LONG]; status = bus->addrslots[bitpos / BITS_PER_LONG];
status >>= bitpos % BITS_PER_LONG; status >>= bitpos % BITS_PER_LONG;
return status & I3C_ADDR_SLOT_STATUS_MASK; return status & mask;
} }
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, static enum i3c_addr_slot_status
enum i3c_addr_slot_status status) i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
{ {
int bitpos = addr * 2; return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK);
}
static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr,
enum i3c_addr_slot_status status, u32 mask)
{
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
unsigned long *ptr; unsigned long *ptr;
if (addr > I2C_MAX_ADDR) if (addr > I2C_MAX_ADDR)
return; return;
ptr = bus->addrslots + (bitpos / BITS_PER_LONG); ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
*ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << *ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
(bitpos % BITS_PER_LONG)); *ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG);
*ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG); }
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
enum i3c_addr_slot_status status)
{
i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK);
} }
static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
@@ -379,13 +390,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
return status == I3C_ADDR_SLOT_FREE; return status == I3C_ADDR_SLOT_FREE;
} }
/*
*
* S/Sr 7'h7E RnW=0 ACK ENTDAA T
*
*
*
* Sr7'h7E RnW=1 ACK48bit UID BCR DCRAssign 7bit AddrPAR ACK/NACK
*
* Some master controllers (such as HCI) need to prepare the entire above transaction before
* sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated
* before knowing the target device's UID information.
*
* However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is
* typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI
* priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is
* not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with
* the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise,
* if the "init_dyn_addr" is already in use by another I3C device, the target device will not be
* able to switch to its desired address.
*
* If the previous step fails, fallback returning one of the remaining unassigned address,
* regardless of its state in the desired list.
*/
static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr) static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
{ {
enum i3c_addr_slot_status status; enum i3c_addr_slot_status status;
u8 addr; u8 addr;
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
status = i3c_bus_get_addr_slot_status(bus, addr); status = i3c_bus_get_addr_slot_status_mask(bus, addr,
I3C_ADDR_SLOT_EXT_STATUS_MASK);
if (status == I3C_ADDR_SLOT_FREE)
return addr;
}
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
I3C_ADDR_SLOT_STATUS_MASK);
if (status == I3C_ADDR_SLOT_FREE) if (status == I3C_ADDR_SLOT_FREE)
return addr; return addr;
} }
@@ -514,6 +556,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
} }
static DEVICE_ATTR_RO(i2c_scl_frequency); static DEVICE_ATTR_RO(i2c_scl_frequency);
static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
{
int ret;
if (!master || !master->ops)
return -EINVAL;
if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin)
return -EINVAL;
i3c_bus_normaluse_lock(&master->bus);
if (enable)
ret = master->ops->enable_hotjoin(master);
else
ret = master->ops->disable_hotjoin(master);
master->hotjoin = enable;
i3c_bus_normaluse_unlock(&master->bus);
return ret;
}
static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
int ret;
bool res;
if (!i3cbus->cur_master)
return -EINVAL;
if (kstrtobool(buf, &res))
return -EINVAL;
ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res);
if (ret)
return ret;
return count;
}
/*
* i3c_master_enable_hotjoin - Enable hotjoin
* @master: I3C master object
*
* Return: a 0 in case of success, an negative error code otherwise.
*/
int i3c_master_enable_hotjoin(struct i3c_master_controller *master)
{
return i3c_set_hotjoin(master, true);
}
EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin);
/*
* i3c_master_disable_hotjoin - Disable hotjoin
* @master: I3C master object
*
* Return: a 0 in case of success, an negative error code otherwise.
*/
int i3c_master_disable_hotjoin(struct i3c_master_controller *master)
{
return i3c_set_hotjoin(master, false);
}
EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin);
static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf)
{
struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
ssize_t ret;
i3c_bus_normaluse_lock(i3cbus);
ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin);
i3c_bus_normaluse_unlock(i3cbus);
return ret;
}
static DEVICE_ATTR_RW(hotjoin);
static struct attribute *i3c_masterdev_attrs[] = { static struct attribute *i3c_masterdev_attrs[] = {
&dev_attr_mode.attr, &dev_attr_mode.attr,
&dev_attr_current_master.attr, &dev_attr_current_master.attr,
@@ -524,6 +648,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
&dev_attr_pid.attr, &dev_attr_pid.attr,
&dev_attr_dynamic_address.attr, &dev_attr_dynamic_address.attr,
&dev_attr_hdrcap.attr, &dev_attr_hdrcap.attr,
&dev_attr_hotjoin.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(i3c_masterdev); ATTRIBUTE_GROUPS(i3c_masterdev);
@@ -1366,16 +1491,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
u8 old_dyn_addr) u8 old_dyn_addr)
{ {
struct i3c_master_controller *master = i3c_dev_get_master(dev); struct i3c_master_controller *master = i3c_dev_get_master(dev);
enum i3c_addr_slot_status status;
int ret; int ret;
if (dev->info.dyn_addr != old_dyn_addr && if (dev->info.dyn_addr != old_dyn_addr) {
(!dev->boardinfo ||
dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) {
status = i3c_bus_get_addr_slot_status(&master->bus,
dev->info.dyn_addr);
if (status != I3C_ADDR_SLOT_FREE)
return -EBUSY;
i3c_bus_set_addr_slot_status(&master->bus, i3c_bus_set_addr_slot_status(&master->bus,
dev->info.dyn_addr, dev->info.dyn_addr,
I3C_ADDR_SLOT_I3C_DEV); I3C_ADDR_SLOT_I3C_DEV);
@@ -1727,6 +1845,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
goto err_bus_cleanup; goto err_bus_cleanup;
} }
if (master->ops->set_speed) {
ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED);
if (ret)
goto err_bus_cleanup;
}
/* /*
* Reset all dynamic address that may have been assigned before * Reset all dynamic address that may have been assigned before
* (assigned by the bootloader for example). * (assigned by the bootloader for example).
@@ -1735,6 +1859,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
if (ret && ret != I3C_ERROR_M2) if (ret && ret != I3C_ERROR_M2)
goto err_bus_cleanup; goto err_bus_cleanup;
if (master->ops->set_speed) {
master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
if (ret)
goto err_bus_cleanup;
}
/* Disable all slave events before starting DAA. */ /* Disable all slave events before starting DAA. */
ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |
@@ -1765,9 +1895,11 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
goto err_rstdaa; goto err_rstdaa;
} }
i3c_bus_set_addr_slot_status(&master->bus, /* Do not mark as occupied until real device exist in bus */
i3cboardinfo->init_dyn_addr, i3c_bus_set_addr_slot_status_mask(&master->bus,
I3C_ADDR_SLOT_I3C_DEV); i3cboardinfo->init_dyn_addr,
I3C_ADDR_SLOT_EXT_DESIRED,
I3C_ADDR_SLOT_EXT_STATUS_MASK);
/* /*
* Only try to create/attach devices that have a static * Only try to create/attach devices that have a static
@@ -1930,7 +2062,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
else else
expected_dyn_addr = newdev->info.dyn_addr; expected_dyn_addr = newdev->info.dyn_addr;
if (newdev->info.dyn_addr != expected_dyn_addr) { if (newdev->info.dyn_addr != expected_dyn_addr &&
i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) {
/* /*
* Try to apply the expected dynamic address. If it fails, keep * Try to apply the expected dynamic address. If it fails, keep
* the address assigned by the master. * the address assigned by the master.
@@ -2696,17 +2829,13 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
* @master: master used to send frames on the bus * @master: master used to send frames on the bus
* *
* Basically undo everything done in i3c_master_register(). * Basically undo everything done in i3c_master_register().
*
* Return: 0 in case of success, a negative error code otherwise.
*/ */
int i3c_master_unregister(struct i3c_master_controller *master) void i3c_master_unregister(struct i3c_master_controller *master)
{ {
i3c_master_i2c_adapter_cleanup(master); i3c_master_i2c_adapter_cleanup(master);
i3c_master_unregister_i3c_devs(master); i3c_master_unregister_i3c_devs(master);
i3c_master_bus_cleanup(master); i3c_master_bus_cleanup(master);
device_unregister(&master->dev); device_unregister(&master->dev);
return 0;
} }
EXPORT_SYMBOL_GPL(i3c_master_unregister); EXPORT_SYMBOL_GPL(i3c_master_unregister);

View File

@@ -1184,11 +1184,8 @@ err_disable_core_clk:
static int dw_i3c_remove(struct platform_device *pdev) static int dw_i3c_remove(struct platform_device *pdev)
{ {
struct dw_i3c_master *master = platform_get_drvdata(pdev); struct dw_i3c_master *master = platform_get_drvdata(pdev);
int ret;
ret = i3c_master_unregister(&master->base); i3c_master_unregister(&master->base);
if (ret)
return ret;
reset_control_assert(master->core_rst); reset_control_assert(master->core_rst);

View File

@@ -1666,11 +1666,8 @@ err_disable_pclk:
static int cdns_i3c_master_remove(struct platform_device *pdev) static int cdns_i3c_master_remove(struct platform_device *pdev)
{ {
struct cdns_i3c_master *master = platform_get_drvdata(pdev); struct cdns_i3c_master *master = platform_get_drvdata(pdev);
int ret;
ret = i3c_master_unregister(&master->base); i3c_master_unregister(&master->base);
if (ret)
return ret;
clk_disable_unprepare(master->sysclk); clk_disable_unprepare(master->sysclk);
clk_disable_unprepare(master->pclk); clk_disable_unprepare(master->pclk);

View File

@@ -769,7 +769,9 @@ static int i3c_hci_remove(struct platform_device *pdev)
{ {
struct i3c_hci *hci = platform_get_drvdata(pdev); struct i3c_hci *hci = platform_get_drvdata(pdev);
return i3c_master_unregister(&hci->master); i3c_master_unregister(&hci->master);
return 0;
} }
static const __maybe_unused struct of_device_id i3c_hci_of_match[] = { static const __maybe_unused struct of_device_id i3c_hci_of_match[] = {

View File

@@ -128,6 +128,9 @@
/* This parameter depends on the implementation and may be tuned */ /* This parameter depends on the implementation and may be tuned */
#define SVC_I3C_FIFO_SIZE 16 #define SVC_I3C_FIFO_SIZE 16
#define SVC_I3C_EVENT_IBI GENMASK(7, 0)
#define SVC_I3C_EVENT_HOTJOIN BIT(31)
struct svc_i3c_cmd { struct svc_i3c_cmd {
u8 addr; u8 addr;
bool rnw; bool rnw;
@@ -171,6 +174,8 @@ struct svc_i3c_xfer {
* @ibi.tbq_slot: To be queued IBI slot * @ibi.tbq_slot: To be queued IBI slot
* @ibi.lock: IBI lock * @ibi.lock: IBI lock
* @lock: Transfer lock, protect between IBI work thread and callbacks from master * @lock: Transfer lock, protect between IBI work thread and callbacks from master
* @enabled_events: Bit masks for enable events (IBI, HotJoin).
* @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back.
*/ */
struct svc_i3c_master { struct svc_i3c_master {
struct i3c_master_controller base; struct i3c_master_controller base;
@@ -199,6 +204,8 @@ struct svc_i3c_master {
spinlock_t lock; spinlock_t lock;
} ibi; } ibi;
struct mutex lock; struct mutex lock;
u32 enabled_events;
u32 mctrl_config;
}; };
/** /**
@@ -213,6 +220,11 @@ struct svc_i3c_i2c_dev_data {
struct i3c_generic_ibi_pool *ibi_pool; struct i3c_generic_ibi_pool *ibi_pool;
}; };
static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
{
return !!(master->enabled_events & mask);
}
static bool svc_i3c_master_error(struct svc_i3c_master *master) static bool svc_i3c_master_error(struct svc_i3c_master *master)
{ {
u32 mstatus, merrwarn; u32 mstatus, merrwarn;
@@ -432,13 +444,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
switch (ibitype) { switch (ibitype) {
case SVC_I3C_MSTATUS_IBITYPE_IBI: case SVC_I3C_MSTATUS_IBITYPE_IBI:
dev = svc_i3c_master_dev_from_addr(master, ibiaddr); dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
if (!dev) if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
svc_i3c_master_nack_ibi(master); svc_i3c_master_nack_ibi(master);
else else
svc_i3c_master_handle_ibi(master, dev); svc_i3c_master_handle_ibi(master, dev);
break; break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
svc_i3c_master_ack_ibi(master, false); if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
svc_i3c_master_ack_ibi(master, false);
else
svc_i3c_master_nack_ibi(master);
break; break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
svc_i3c_master_nack_ibi(master); svc_i3c_master_nack_ibi(master);
@@ -475,7 +490,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
svc_i3c_master_emit_stop(master); svc_i3c_master_emit_stop(master);
break; break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
queue_work(master->base.wq, &master->hj_work); svc_i3c_master_emit_stop(master);
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
queue_work(master->base.wq, &master->hj_work);
break; break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
default: default:
@@ -506,6 +523,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
enum i3c_open_drain_speed speed)
{
struct svc_i3c_master *master = to_svc_i3c_master(m);
struct i3c_bus *bus = i3c_master_get_bus(&master->base);
u32 ppbaud, odbaud, odhpp, mconfig;
unsigned long fclk_rate;
int ret;
ret = pm_runtime_resume_and_get(master->dev);
if (ret < 0) {
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
return ret;
}
switch (speed) {
case I3C_OPEN_DRAIN_SLOW_SPEED:
fclk_rate = clk_get_rate(master->fclk);
if (!fclk_rate) {
ret = -EINVAL;
goto rpm_out;
}
/*
* Set 50% duty-cycle I2C speed to I3C OPEN-DRAIN mode, so the first
* broadcast address is visible to all I2C/I3C devices on the I3C bus.
* I3C device working as a I2C device will turn off its 50ns Spike
* Filter to change to I3C mode.
*/
mconfig = master->mctrl_config;
ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
odhpp = 0;
odbaud = DIV_ROUND_UP(fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1;
mconfig &= ~GENMASK(24, 16);
mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp);
writel(mconfig, master->regs + SVC_I3C_MCONFIG);
break;
case I3C_OPEN_DRAIN_NORMAL_SPEED:
writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
break;
}
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
static int svc_i3c_master_bus_init(struct i3c_master_controller *m) static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
{ {
struct svc_i3c_master *master = to_svc_i3c_master(m); struct svc_i3c_master *master = to_svc_i3c_master(m);
@@ -588,6 +653,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
SVC_I3C_MCONFIG_I2CBAUD(i2cbaud); SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
writel(reg, master->regs + SVC_I3C_MCONFIG); writel(reg, master->regs + SVC_I3C_MCONFIG);
master->mctrl_config = reg;
/* Master core's registration */ /* Master core's registration */
ret = i3c_master_get_free_addr(m, 0); ret = i3c_master_get_free_addr(m, 0);
if (ret < 0) if (ret < 0)
@@ -1475,6 +1541,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
return ret; return ret;
} }
master->enabled_events++;
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1486,7 +1553,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
struct svc_i3c_master *master = to_svc_i3c_master(m); struct svc_i3c_master *master = to_svc_i3c_master(m);
int ret; int ret;
svc_i3c_master_disable_interrupts(master); master->enabled_events--;
if (!master->enabled_events)
svc_i3c_master_disable_interrupts(master);
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1496,6 +1565,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
return ret; return ret;
} }
static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
{
struct svc_i3c_master *master = to_svc_i3c_master(m);
int ret;
ret = pm_runtime_resume_and_get(master->dev);
if (ret < 0) {
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
return ret;
}
master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
return 0;
}
static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
{
struct svc_i3c_master *master = to_svc_i3c_master(m);
master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
if (!master->enabled_events)
svc_i3c_master_disable_interrupts(master);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
struct i3c_ibi_slot *slot) struct i3c_ibi_slot *slot)
{ {
@@ -1522,6 +1624,9 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
.recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot, .recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
.enable_ibi = svc_i3c_master_enable_ibi, .enable_ibi = svc_i3c_master_enable_ibi,
.disable_ibi = svc_i3c_master_disable_ibi, .disable_ibi = svc_i3c_master_disable_ibi,
.enable_hotjoin = svc_i3c_master_enable_hotjoin,
.disable_hotjoin = svc_i3c_master_disable_hotjoin,
.set_speed = svc_i3c_master_set_speed,
}; };
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master) static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
@@ -1651,11 +1756,8 @@ err_disable_clks:
static int svc_i3c_master_remove(struct platform_device *pdev) static int svc_i3c_master_remove(struct platform_device *pdev)
{ {
struct svc_i3c_master *master = platform_get_drvdata(pdev); struct svc_i3c_master *master = platform_get_drvdata(pdev);
int ret;
ret = i3c_master_unregister(&master->base); i3c_master_unregister(&master->base);
if (ret)
return ret;
pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);

View File

@@ -372,6 +372,7 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
u8 data[8]; u8 data[8];
u16 xy1y2[3]; u16 xy1y2[3];
s32 h[3], s[3]; s32 h[3], s[3];
int half_range = BIT(13);
int i, ret; int i, ret;
mutex_lock(&yas5xx->lock); mutex_lock(&yas5xx->lock);
@@ -406,13 +407,13 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
/* The second version of YAS537 needs to include calibration coefficients */ /* The second version of YAS537 needs to include calibration coefficients */
if (yas5xx->version == YAS537_VERSION_1) { if (yas5xx->version == YAS537_VERSION_1) {
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
s[i] = xy1y2[i] - BIT(13); s[i] = xy1y2[i] - half_range;
h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13); h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / half_range;
h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13); h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / half_range;
h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13); h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / half_range;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
clamp_val(h[i], -BIT(13), BIT(13) - 1); h[i] = clamp(h[i], -half_range, half_range - 1);
xy1y2[i] = h[i] + BIT(13); xy1y2[i] = h[i] + half_range;
} }
} }

View File

@@ -1363,6 +1363,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
goto out_free; goto out_free;
} else if (fwspec && fwspec->ops == &arm_smmu_ops) { } else if (fwspec && fwspec->ops == &arm_smmu_ops) {
smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
/*
* Defer probe if the relevant SMMU instance hasn't finished
* probing yet. This is a fragile hack and we'd ideally
* avoid this race in the core code. Until that's ironed
* out, however, this is the most pragmatic option on the
* table.
*/
if (!smmu)
return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER,
"smmu dev has not bound yet\n"));
} else { } else {
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }

View File

@@ -797,7 +797,6 @@ static void mt6360_v4l2_flash_release(struct mt6360_priv *priv)
static int mt6360_led_probe(struct platform_device *pdev) static int mt6360_led_probe(struct platform_device *pdev)
{ {
struct mt6360_priv *priv; struct mt6360_priv *priv;
struct fwnode_handle *child;
size_t count; size_t count;
int i = 0, ret; int i = 0, ret;
@@ -824,7 +823,7 @@ static int mt6360_led_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
device_for_each_child_node(&pdev->dev, child) { device_for_each_child_node_scoped(&pdev->dev, child) {
struct mt6360_led *led = priv->leds + i; struct mt6360_led *led = priv->leds + i;
struct led_init_data init_data = { .fwnode = child, }; struct led_init_data init_data = { .fwnode = child, };
u32 reg, led_color; u32 reg, led_color;

View File

@@ -1726,7 +1726,7 @@ static void cache_set_flush(struct closure *cl)
if (!IS_ERR_OR_NULL(c->gc_thread)) if (!IS_ERR_OR_NULL(c->gc_thread))
kthread_stop(c->gc_thread); kthread_stop(c->gc_thread);
if (!IS_ERR(c->root)) if (!IS_ERR_OR_NULL(c->root))
list_add(&c->root->list, &c->btree_cache); list_add(&c->root->list, &c->btree_cache);
/* /*

View File

@@ -994,6 +994,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
/* table of devices that work with this driver */ /* table of devices that work with this driver */
struct usb_device_id cx231xx_id_table[] = { struct usb_device_id cx231xx_id_table[] = {
{USB_DEVICE(0x1D19, 0x6108),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x1D19, 0x6109), {USB_DEVICE(0x1D19, 0x6109),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x0572, 0x5A3C), {USB_DEVICE(0x0572, 0x5A3C),

View File

@@ -2441,6 +2441,8 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* The Logitech cameras listed below have their interface class set to * The Logitech cameras listed below have their interface class set to
* VENDOR_SPEC because they don't announce themselves as UVC devices, even * VENDOR_SPEC because they don't announce themselves as UVC devices, even
* though they are compliant. * though they are compliant.
*
* Sort these by vendor/product ID.
*/ */
static const struct usb_device_id uvc_ids[] = { static const struct usb_device_id uvc_ids[] = {
/* Quanta USB2.0 HD UVC Webcam */ /* Quanta USB2.0 HD UVC Webcam */
@@ -2983,6 +2985,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_IGNORE_SELECTOR_UNIT) }, | UVC_QUIRK_IGNORE_SELECTOR_UNIT) },
/* NXP Semiconductors IR VIDEO */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x1fc9,
.idProduct = 0x009b,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
/* Oculus VR Positional Tracker DK2 */ /* Oculus VR Positional Tracker DK2 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO, | USB_DEVICE_ID_MATCH_INT_INFO,

View File

@@ -149,6 +149,8 @@ static void mmc_bus_shutdown(struct device *dev)
if (dev->driver && drv->shutdown) if (dev->driver && drv->shutdown)
drv->shutdown(card); drv->shutdown(card);
__mmc_stop_host(host);
if (host->bus_ops->shutdown) { if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host); ret = host->bus_ops->shutdown(host);
if (ret) if (ret)

View File

@@ -82,6 +82,7 @@ struct mmc_fixup {
#define CID_MANFID_SANDISK_SD 0x3 #define CID_MANFID_SANDISK_SD 0x3
#define CID_MANFID_ATP 0x9 #define CID_MANFID_ATP 0x9
#define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_TOSHIBA 0x11
#define CID_MANFID_GIGASTONE 0x12
#define CID_MANFID_MICRON 0x13 #define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15 #define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_APACER 0x27 #define CID_MANFID_APACER 0x27
@@ -280,4 +281,14 @@ static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE; return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
} }
static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
}
static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
}
#endif #endif

View File

@@ -2297,6 +2297,9 @@ void mmc_start_host(struct mmc_host *host)
void __mmc_stop_host(struct mmc_host *host) void __mmc_stop_host(struct mmc_host *host)
{ {
if (host->rescan_disable)
return;
if (host->slot.cd_irq >= 0) { if (host->slot.cd_irq >= 0) {
mmc_gpio_set_cd_wake(host, false); mmc_gpio_set_cd_wake(host, false);
disable_irq(host->slot.cd_irq); disable_irq(host->slot.cd_irq);

View File

@@ -25,6 +25,15 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
/*
* GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never
* clear Flush Cache bit and set Poweroff Notification Ready bit.
*/
_FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2,
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
EXT_CSD_REV_ANY),
END_FIXUP END_FIXUP
}; };

View File

@@ -1122,7 +1122,7 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
card->ext_power.rev = reg_buf[0] & 0xf; card->ext_power.rev = reg_buf[0] & 0xf;
/* Power Off Notification support at bit 4. */ /* Power Off Notification support at bit 4. */
if (reg_buf[1] & BIT(4)) if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card))
card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY; card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
/* Power Sustenance support at bit 5. */ /* Power Sustenance support at bit 5. */

View File

@@ -21,6 +21,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
@@ -1239,6 +1240,29 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
.priv_size = sizeof(struct intel_host), .priv_size = sizeof(struct intel_host),
}; };
/* DMI quirks for devices with missing or broken CD GPIO info */
static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = {
.dev_id = "0000:00:12.0",
.table = {
GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH),
{ }
},
};
static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = {
{
/* Vexia Edu Atla 10 tablet 9V version */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
/* Above strings are too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
},
.driver_data = (void *)&vexia_edu_atla10_cd_gpios,
},
{ }
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.resume = byt_resume, .resume = byt_resume,
@@ -1257,6 +1281,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.add_host = byt_add_host, .add_host = byt_add_host,
.remove_slot = byt_remove_slot, .remove_slot = byt_remove_slot,
.ops = &sdhci_intel_byt_ops, .ops = &sdhci_intel_byt_ops,
.cd_gpio_override = sdhci_intel_byt_cd_gpio_override,
.priv_size = sizeof(struct intel_host), .priv_size = sizeof(struct intel_host),
}; };
@@ -2036,6 +2061,42 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
* * * *
\*****************************************************************************/ \*****************************************************************************/
static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table(
struct sdhci_pci_chip *chip)
{
struct gpiod_lookup_table *cd_gpio_lookup_table;
const struct dmi_system_id *dmi_id = NULL;
size_t count;
if (chip->fixes && chip->fixes->cd_gpio_override)
dmi_id = dmi_first_match(chip->fixes->cd_gpio_override);
if (!dmi_id)
return NULL;
cd_gpio_lookup_table = dmi_id->driver_data;
for (count = 0; cd_gpio_lookup_table->table[count].key; count++)
;
cd_gpio_lookup_table = kmemdup(dmi_id->driver_data,
/* count + 1 terminating entry */
struct_size(cd_gpio_lookup_table, table, count + 1),
GFP_KERNEL);
if (!cd_gpio_lookup_table)
return ERR_PTR(-ENOMEM);
gpiod_add_lookup_table(cd_gpio_lookup_table);
return cd_gpio_lookup_table;
}
static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table)
{
if (lookup_table) {
gpiod_remove_lookup_table(lookup_table);
kfree(lookup_table);
}
}
static struct sdhci_pci_slot *sdhci_pci_probe_slot( static struct sdhci_pci_slot *sdhci_pci_probe_slot(
struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
int slotno) int slotno)
@@ -2111,8 +2172,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
device_init_wakeup(&pdev->dev, true); device_init_wakeup(&pdev->dev, true);
if (slot->cd_idx >= 0) { if (slot->cd_idx >= 0) {
struct gpiod_lookup_table *cd_gpio_lookup_table;
cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip);
if (IS_ERR(cd_gpio_lookup_table)) {
ret = PTR_ERR(cd_gpio_lookup_table);
goto remove;
}
ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx,
slot->cd_override_level, 0); slot->cd_override_level, 0);
sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table);
if (ret && ret != -EPROBE_DEFER) if (ret && ret != -EPROBE_DEFER)
ret = mmc_gpiod_request_cd(host->mmc, NULL, ret = mmc_gpiod_request_cd(host->mmc, NULL,
slot->cd_idx, slot->cd_idx,

View File

@@ -151,6 +151,7 @@ struct sdhci_pci_fixes {
#endif #endif
const struct sdhci_ops *ops; const struct sdhci_ops *ops;
const struct dmi_system_id *cd_gpio_override;
size_t priv_size; size_t priv_size;
}; };

View File

@@ -452,7 +452,7 @@ static int can_set_termination(struct net_device *ndev, u16 term)
else else
set = 0; set = 0;
gpiod_set_value(priv->termination_gpio, set); gpiod_set_value_cansleep(priv->termination_gpio, set);
return 0; return 0;
} }

View File

@@ -21,6 +21,11 @@ static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta)
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF; return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
} }
static inline bool mcp251xfd_tx_fifo_sta_less_than_half_full(u32 fifo_sta)
{
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFHRFHIF;
}
static inline int static inline int
mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv, mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
u8 *tef_tail) u8 *tef_tail)
@@ -147,7 +152,29 @@ mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)
BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len)); BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));
len = (chip_tx_tail << shift) - (tail << shift); len = (chip_tx_tail << shift) - (tail << shift);
*len_p = len >> shift; len >>= shift;
/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
* bits of a FIFOSTA register, here the TX-FIFO tail index
* might be corrupted.
*
* However here it seems the bit indicating that the TX-FIFO
* is empty (MCP251XFD_REG_FIFOSTA_TFERFFIF) is not correct
* while the TX-FIFO tail index is.
*
* We assume the TX-FIFO is empty, i.e. all pending CAN frames
* haven been send, if:
* - Chip's head and tail index are equal (len == 0).
* - The TX-FIFO is less than half full.
* (The TX-FIFO empty case has already been checked at the
* beginning of this function.)
* - No free buffers in the TX ring.
*/
if (len == 0 && mcp251xfd_tx_fifo_sta_less_than_half_full(fifo_sta) &&
mcp251xfd_get_tx_free(tx_ring) == 0)
len = tx_ring->obj_num;
*len_p = len;
return 0; return 0;
} }

View File

@@ -613,7 +613,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
if (type == SECONDARY_INTERFACE && epf->sec_epc) if (type == SECONDARY_INTERFACE && epf->sec_epc)
return -EBUSY; return -EBUSY;
mutex_lock(&epc->lock); mutex_lock(&epc->list_lock);
func_no = find_first_zero_bit(&epc->function_num_map, func_no = find_first_zero_bit(&epc->function_num_map,
BITS_PER_LONG); BITS_PER_LONG);
if (func_no >= BITS_PER_LONG) { if (func_no >= BITS_PER_LONG) {
@@ -640,7 +640,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
list_add_tail(list, &epc->pci_epf); list_add_tail(list, &epc->pci_epf);
ret: ret:
mutex_unlock(&epc->lock); mutex_unlock(&epc->list_lock);
return ret; return ret;
} }
@@ -664,19 +664,19 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
if (!epc || IS_ERR(epc) || !epf) if (!epc || IS_ERR(epc) || !epf)
return; return;
mutex_lock(&epc->list_lock);
if (type == PRIMARY_INTERFACE) { if (type == PRIMARY_INTERFACE) {
func_no = epf->func_no; func_no = epf->func_no;
list = &epf->list; list = &epf->list;
epf->epc = NULL;
} else { } else {
func_no = epf->sec_epc_func_no; func_no = epf->sec_epc_func_no;
list = &epf->sec_epc_list; list = &epf->sec_epc_list;
epf->sec_epc = NULL;
} }
mutex_lock(&epc->lock);
clear_bit(func_no, &epc->function_num_map); clear_bit(func_no, &epc->function_num_map);
list_del(list); list_del(list);
epf->epc = NULL; mutex_unlock(&epc->list_lock);
mutex_unlock(&epc->lock);
} }
EXPORT_SYMBOL_GPL(pci_epc_remove_epf); EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
@@ -773,6 +773,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
} }
mutex_init(&epc->lock); mutex_init(&epc->lock);
mutex_init(&epc->list_lock);
INIT_LIST_HEAD(&epc->pci_epf); INIT_LIST_HEAD(&epc->pci_epf);
ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier); ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);

View File

@@ -3312,6 +3312,7 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
.show_host_node_name = 1, .show_host_node_name = 1,
.show_host_port_name = 1, .show_host_port_name = 1,
.show_host_supported_classes = 1, .show_host_supported_classes = 1,
.show_host_supported_speeds = 1,
.get_host_port_id = qla2x00_get_host_port_id, .get_host_port_id = qla2x00_get_host_port_id,
.show_host_port_id = 1, .show_host_port_id = 1,

View File

@@ -24,6 +24,7 @@ void qla2x00_bsg_job_done(srb_t *sp, int res)
{ {
struct bsg_job *bsg_job = sp->u.bsg_job; struct bsg_job *bsg_job = sp->u.bsg_job;
struct fc_bsg_reply *bsg_reply = bsg_job->reply; struct fc_bsg_reply *bsg_reply = bsg_job->reply;
struct completion *comp = sp->comp;
ql_dbg(ql_dbg_user, sp->vha, 0x7009, ql_dbg(ql_dbg_user, sp->vha, 0x7009,
"%s: sp hdl %x, result=%x bsg ptr %p\n", "%s: sp hdl %x, result=%x bsg ptr %p\n",
@@ -35,6 +36,9 @@ void qla2x00_bsg_job_done(srb_t *sp, int res)
bsg_reply->result = res; bsg_reply->result = res;
bsg_job_done(bsg_job, bsg_reply->result, bsg_job_done(bsg_job, bsg_reply->result,
bsg_reply->reply_payload_rcv_len); bsg_reply->reply_payload_rcv_len);
if (comp)
complete(comp);
} }
void qla2x00_bsg_sp_free(srb_t *sp) void qla2x00_bsg_sp_free(srb_t *sp)
@@ -490,16 +494,6 @@ qla2x00_process_ct(struct bsg_job *bsg_job)
goto done; goto done;
} }
if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) ||
(rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
ql_log(ql_log_warn, vha, 0x7011,
"request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
"dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
rval = -EAGAIN;
goto done_unmap_sg;
}
if (!vha->flags.online) { if (!vha->flags.online) {
ql_log(ql_log_warn, vha, 0x7012, ql_log(ql_log_warn, vha, 0x7012,
"Host is not online.\n"); "Host is not online.\n");
@@ -3061,7 +3055,7 @@ skip_chip_chk:
static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job) static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job)
{ {
bool found = false; bool found, do_bsg_done;
struct fc_bsg_reply *bsg_reply = bsg_job->reply; struct fc_bsg_reply *bsg_reply = bsg_job->reply;
scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
@@ -3069,6 +3063,11 @@ static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job)
int cnt; int cnt;
unsigned long flags; unsigned long flags;
struct req_que *req; struct req_que *req;
int rval;
DECLARE_COMPLETION_ONSTACK(comp);
uint32_t ratov_j;
found = do_bsg_done = false;
spin_lock_irqsave(qpair->qp_lock_ptr, flags); spin_lock_irqsave(qpair->qp_lock_ptr, flags);
req = qpair->req; req = qpair->req;
@@ -3080,42 +3079,104 @@ static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job)
sp->type == SRB_ELS_CMD_HST || sp->type == SRB_ELS_CMD_HST ||
sp->type == SRB_ELS_CMD_HST_NOLOGIN) && sp->type == SRB_ELS_CMD_HST_NOLOGIN) &&
sp->u.bsg_job == bsg_job) { sp->u.bsg_job == bsg_job) {
req->outstanding_cmds[cnt] = NULL;
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
if (!ha->flags.eeh_busy && ha->isp_ops->abort_command(sp)) {
ql_log(ql_log_warn, vha, 0x7089,
"mbx abort_command failed.\n");
bsg_reply->result = -EIO;
} else {
ql_dbg(ql_dbg_user, vha, 0x708a,
"mbx abort_command success.\n");
bsg_reply->result = 0;
}
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
found = true; found = true;
goto done; sp->comp = &comp;
break;
} }
} }
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
done: if (!found)
return found; return false;
if (ha->flags.eeh_busy) {
/* skip over abort. EEH handling will return the bsg. Wait for it */
rval = QLA_SUCCESS;
ql_dbg(ql_dbg_user, vha, 0x802c,
"eeh encounter. bsg %p sp=%p handle=%x \n",
bsg_job, sp, sp->handle);
} else {
rval = ha->isp_ops->abort_command(sp);
ql_dbg(ql_dbg_user, vha, 0x802c,
"Aborting bsg %p sp=%p handle=%x rval=%x\n",
bsg_job, sp, sp->handle, rval);
}
switch (rval) {
case QLA_SUCCESS:
/* Wait for the command completion. */
ratov_j = ha->r_a_tov / 10 * 4 * 1000;
ratov_j = msecs_to_jiffies(ratov_j);
if (!wait_for_completion_timeout(&comp, ratov_j)) {
ql_log(ql_log_info, vha, 0x7089,
"bsg abort timeout. bsg=%p sp=%p handle %#x .\n",
bsg_job, sp, sp->handle);
do_bsg_done = true;
} else {
/* fw had returned the bsg */
ql_dbg(ql_dbg_user, vha, 0x708a,
"bsg abort success. bsg %p sp=%p handle=%#x\n",
bsg_job, sp, sp->handle);
do_bsg_done = false;
}
break;
default:
ql_log(ql_log_info, vha, 0x704f,
"bsg abort fail. bsg=%p sp=%p rval=%x.\n",
bsg_job, sp, rval);
do_bsg_done = true;
break;
}
if (!do_bsg_done)
return true;
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
/*
* recheck to make sure it's still the same bsg_job due to
* qp_lock_ptr was released earlier.
*/
if (req->outstanding_cmds[cnt] &&
req->outstanding_cmds[cnt]->u.bsg_job != bsg_job) {
/* fw had returned the bsg */
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
return true;
}
req->outstanding_cmds[cnt] = NULL;
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
/* ref: INIT */
sp->comp = NULL;
kref_put(&sp->cmd_kref, qla2x00_sp_release);
bsg_reply->result = -ENXIO;
bsg_reply->reply_payload_rcv_len = 0;
ql_dbg(ql_dbg_user, vha, 0x7051,
"%s bsg_job_done : bsg %p result %#x sp %p.\n",
__func__, bsg_job, bsg_reply->result, sp);
bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
return true;
} }
int int
qla24xx_bsg_timeout(struct bsg_job *bsg_job) qla24xx_bsg_timeout(struct bsg_job *bsg_job)
{ {
struct fc_bsg_reply *bsg_reply = bsg_job->reply; struct fc_bsg_request *bsg_request = bsg_job->request;
scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
int i; int i;
struct qla_qpair *qpair; struct qla_qpair *qpair;
ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n", ql_log(ql_log_info, vha, 0x708b,
__func__, bsg_job); "%s CMD timeout. bsg ptr %p msgcode %x vendor cmd %x\n",
__func__, bsg_job, bsg_request->msgcode,
bsg_request->rqst_data.h_vendor.vendor_cmd[0]);
if (qla2x00_isp_reg_stat(ha)) { if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x9007, ql_log(ql_log_info, vha, 0x9007,
@@ -3136,7 +3197,6 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job)
} }
ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n"); ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n");
bsg_reply->result = -ENXIO;
done: done:
return 0; return 0;

View File

@@ -515,6 +515,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
return(NULL); return(NULL);
} }
vha->irq_offset = QLA_BASE_VECTORS;
host = vha->host; host = vha->host;
fc_vport->dd_data = vha; fc_vport->dd_data = vha;
/* New host info */ /* New host info */

View File

@@ -6883,12 +6883,15 @@ qla2x00_do_dpc(void *data)
set_user_nice(current, MIN_NICE); set_user_nice(current, MIN_NICE);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) { while (1) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4000, ql_dbg(ql_dbg_dpc, base_vha, 0x4000,
"DPC handler sleeping.\n"); "DPC handler sleeping.\n");
schedule(); schedule();
if (kthread_should_stop())
break;
if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags)) if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags))
qla_pci_set_eeh_busy(base_vha); qla_pci_set_eeh_busy(base_vha);
@@ -6901,15 +6904,16 @@ qla2x00_do_dpc(void *data)
goto end_loop; goto end_loop;
} }
if (test_bit(UNLOADING, &base_vha->dpc_flags))
/* don't do any work. Wait to be terminated by kthread_stop */
goto end_loop;
ha->dpc_active = 1; ha->dpc_active = 1;
ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001, ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001,
"DPC handler waking up, dpc_flags=0x%lx.\n", "DPC handler waking up, dpc_flags=0x%lx.\n",
base_vha->dpc_flags); base_vha->dpc_flags);
if (test_bit(UNLOADING, &base_vha->dpc_flags))
break;
if (IS_P3P_TYPE(ha)) { if (IS_P3P_TYPE(ha)) {
if (IS_QLA8044(ha)) { if (IS_QLA8044(ha)) {
if (test_and_clear_bit(ISP_UNRECOVERABLE, if (test_and_clear_bit(ISP_UNRECOVERABLE,
@@ -7227,9 +7231,6 @@ end_loop:
*/ */
ha->dpc_active = 0; ha->dpc_active = 0;
/* Cleanup any residual CTX SRBs. */
qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
return 0; return 0;
} }

View File

@@ -5673,7 +5673,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
if (sdebug_host_max_queue) if (sdebug_host_max_queue)
sd_dp->hc_idx = get_tag(cmnd); sd_dp->hc_idx = get_tag(cmnd);
if (polled) if (polled || (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS))
ns_from_boot = ktime_get_boottime_ns(); ns_from_boot = ktime_get_boottime_ns();
/* one of the resp_*() response functions is called here */ /* one of the resp_*() response functions is called here */

View File

@@ -519,6 +519,7 @@ static int mpc52xx_spi_remove(struct platform_device *op)
struct mpc52xx_spi *ms = spi_master_get_devdata(master); struct mpc52xx_spi *ms = spi_master_get_devdata(master);
int i; int i;
cancel_work_sync(&ms->work);
free_irq(ms->irq0, ms); free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms); free_irq(ms->irq1, ms);

View File

@@ -454,6 +454,9 @@ static ssize_t read_req_latency_avg_show(struct device *dev,
struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_hba_monitor *m = &hba->monitor; struct ufs_hba_monitor *m = &hba->monitor;
if (!m->nr_req[READ])
return sysfs_emit(buf, "0\n");
return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]), return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]),
m->nr_req[READ])); m->nr_req[READ]));
} }
@@ -521,6 +524,9 @@ static ssize_t write_req_latency_avg_show(struct device *dev,
struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_hba_monitor *m = &hba->monitor; struct ufs_hba_monitor *m = &hba->monitor;
if (!m->nr_req[WRITE])
return sysfs_emit(buf, "0\n");
return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]), return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]),
m->nr_req[WRITE])); m->nr_req[WRITE]));
} }

View File

@@ -4633,9 +4633,6 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
dev_err(hba->dev, dev_err(hba->dev,
"%s: power mode change failed %d\n", __func__, ret); "%s: power mode change failed %d\n", __func__, ret);
} else { } else {
ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
pwr_mode);
memcpy(&hba->pwr_info, pwr_mode, memcpy(&hba->pwr_info, pwr_mode,
sizeof(struct ufs_pa_layer_attr)); sizeof(struct ufs_pa_layer_attr));
} }
@@ -4662,6 +4659,10 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba,
ret = ufshcd_change_power_mode(hba, &final_params); ret = ufshcd_change_power_mode(hba, &final_params);
if (!ret)
ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
&final_params);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);

View File

@@ -54,7 +54,7 @@
#define MAX_HW_ERROR 250 #define MAX_HW_ERROR 250
static int heartbeat = DEFAULT_HEARTBEAT; static int heartbeat;
/* /*
* struct to hold data for each WDT device * struct to hold data for each WDT device
@@ -240,6 +240,7 @@ static int rti_wdt_probe(struct platform_device *pdev)
wdd->min_timeout = 1; wdd->min_timeout = 1;
wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) / wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
wdt->freq * 1000; wdt->freq * 1000;
wdd->timeout = DEFAULT_HEARTBEAT;
wdd->parent = dev; wdd->parent = dev;
watchdog_set_drvdata(wdd, wdt); watchdog_set_drvdata(wdd, wdt);

View File

@@ -671,6 +671,42 @@ u8 *btrfs_sb_fsid_ptr(struct btrfs_super_block *sb)
return has_metadata_uuid ? sb->metadata_uuid : sb->fsid; return has_metadata_uuid ? sb->metadata_uuid : sb->fsid;
} }
static bool is_same_device(struct btrfs_device *device, const char *new_path)
{
struct path old = { .mnt = NULL, .dentry = NULL };
struct path new = { .mnt = NULL, .dentry = NULL };
char *old_path = NULL;
bool is_same = false;
int ret;
if (!device->name)
goto out;
old_path = kzalloc(PATH_MAX, GFP_NOFS);
if (!old_path)
goto out;
rcu_read_lock();
ret = strscpy(old_path, rcu_str_deref(device->name), PATH_MAX);
rcu_read_unlock();
if (ret < 0)
goto out;
ret = kern_path(old_path, LOOKUP_FOLLOW, &old);
if (ret)
goto out;
ret = kern_path(new_path, LOOKUP_FOLLOW, &new);
if (ret)
goto out;
if (path_equal(&old, &new))
is_same = true;
out:
kfree(old_path);
path_put(&old);
path_put(&new);
return is_same;
}
/* /*
* Handle scanned device having its CHANGING_FSID_V2 flag set and the fs_devices * Handle scanned device having its CHANGING_FSID_V2 flag set and the fs_devices
* being created with a disk that has already completed its fsid change. Such * being created with a disk that has already completed its fsid change. Such
@@ -889,7 +925,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
disk_super->fsid, devid, found_transid, path, disk_super->fsid, devid, found_transid, path,
current->comm, task_pid_nr(current)); current->comm, task_pid_nr(current));
} else if (!device->name || strcmp(device->name->str, path)) { } else if (!device->name || !is_same_device(device, path)) {
/* /*
* When FS is already mounted. * When FS is already mounted.
* 1. If you are here and if the device->name is NULL that * 1. If you are here and if the device->name is NULL that
@@ -2731,8 +2767,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE); set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
if (seeding_dev) { if (seeding_dev) {
btrfs_clear_sb_rdonly(sb);
/* GFP_KERNEL allocation must not be under device_list_mutex */ /* GFP_KERNEL allocation must not be under device_list_mutex */
seed_devices = btrfs_init_sprout(fs_info); seed_devices = btrfs_init_sprout(fs_info);
if (IS_ERR(seed_devices)) { if (IS_ERR(seed_devices)) {
@@ -2875,8 +2909,6 @@ error_sysfs:
mutex_unlock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->chunk_mutex);
mutex_unlock(&fs_info->fs_devices->device_list_mutex); mutex_unlock(&fs_info->fs_devices->device_list_mutex);
error_trans: error_trans:
if (seeding_dev)
btrfs_set_sb_rdonly(sb);
if (trans) if (trans)
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
error_free_zone: error_free_zone:

View File

@@ -743,7 +743,8 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
to_free = NULL; to_free = NULL;
head = file->f_ep; head = file->f_ep;
if (head->first == &epi->fllink && !epi->fllink.next) { if (head->first == &epi->fllink && !epi->fllink.next) {
file->f_ep = NULL; /* See eventpoll_release() for details. */
WRITE_ONCE(file->f_ep, NULL);
if (!is_file_epoll(file)) { if (!is_file_epoll(file)) {
struct epitems_head *v; struct epitems_head *v;
v = container_of(head, struct epitems_head, epitems); v = container_of(head, struct epitems_head, epitems);
@@ -1513,7 +1514,8 @@ allocate:
spin_unlock(&file->f_lock); spin_unlock(&file->f_lock);
goto allocate; goto allocate;
} }
file->f_ep = head; /* See eventpoll_release() for details. */
WRITE_ONCE(file->f_ep, head);
to_free = NULL; to_free = NULL;
} }
hlist_add_head_rcu(&epi->fllink, file->f_ep); hlist_add_head_rcu(&epi->fllink, file->f_ep);

View File

@@ -76,7 +76,7 @@ static inline void nilfs_put_page(struct page *page)
*/ */
static unsigned int nilfs_last_byte(struct inode *inode, unsigned long page_nr) static unsigned int nilfs_last_byte(struct inode *inode, unsigned long page_nr)
{ {
unsigned int last_byte = inode->i_size; u64 last_byte = inode->i_size;
last_byte -= page_nr << PAGE_SHIFT; last_byte -= page_nr << PAGE_SHIFT;
if (last_byte > PAGE_SIZE) if (last_byte > PAGE_SIZE)

View File

@@ -3108,6 +3108,7 @@ static void *ocfs2_dlm_seq_next(struct seq_file *m, void *v, loff_t *pos)
struct ocfs2_lock_res *iter = v; struct ocfs2_lock_res *iter = v;
struct ocfs2_lock_res *dummy = &priv->p_iter_res; struct ocfs2_lock_res *dummy = &priv->p_iter_res;
(*pos)++;
spin_lock(&ocfs2_dlm_tracking_lock); spin_lock(&ocfs2_dlm_tracking_lock);
iter = ocfs2_dlm_next_res(iter, priv); iter = ocfs2_dlm_next_res(iter, priv);
list_del_init(&dummy->l_debug_list); list_del_init(&dummy->l_debug_list);

View File

@@ -200,8 +200,10 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
mode = mode_strip_sgid(&init_user_ns, dir, mode); mode = mode_strip_sgid(&init_user_ns, dir, mode);
inode_init_owner(&init_user_ns, inode, dir, mode); inode_init_owner(&init_user_ns, inode, dir, mode);
status = dquot_initialize(inode); status = dquot_initialize(inode);
if (status) if (status) {
iput(inode);
return ERR_PTR(status); return ERR_PTR(status);
}
return inode; return inode;
} }

View File

@@ -6370,6 +6370,10 @@ int smb2_read(struct ksmbd_work *work)
} }
offset = le64_to_cpu(req->Offset); offset = le64_to_cpu(req->Offset);
if (offset < 0) {
err = -EINVAL;
goto out;
}
length = le32_to_cpu(req->Length); length = le32_to_cpu(req->Length);
mincount = le32_to_cpu(req->MinimumCount); mincount = le32_to_cpu(req->MinimumCount);
@@ -6583,6 +6587,8 @@ int smb2_write(struct ksmbd_work *work)
} }
offset = le64_to_cpu(req->Offset); offset = le64_to_cpu(req->Offset);
if (offset < 0)
return -EINVAL;
length = le32_to_cpu(req->Length); length = le32_to_cpu(req->Length);
if (req->Channel == SMB2_CHANNEL_RDMA_V1 || if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||

View File

@@ -694,6 +694,13 @@ struct drm_dp_mst_topology_mgr {
*/ */
bool payload_id_table_cleared : 1; bool payload_id_table_cleared : 1;
/**
* @reset_rx_state: The down request's reply and up request message
* receiver state must be reset, after the topology manager got
* removed. Protected by @lock.
*/
bool reset_rx_state : 1;
/** /**
* @payload_count: The number of currently active payloads in hardware. This value is only * @payload_count: The number of currently active payloads in hardware. This value is only
* intended to be used internally by MST helpers for payload tracking, and is only safe to * intended to be used internally by MST helpers for payload tracking, and is only safe to

View File

@@ -42,7 +42,7 @@ static inline void eventpoll_release(struct file *file)
* because the file in on the way to be removed and nobody ( but * because the file in on the way to be removed and nobody ( but
* eventpoll ) has still a reference to this file. * eventpoll ) has still a reference to this file.
*/ */
if (likely(!file->f_ep)) if (likely(!READ_ONCE(file->f_ep)))
return; return;
/* /*

View File

@@ -53,8 +53,10 @@ struct fwnode_handle {
* fwnode link flags * fwnode link flags
* *
* CYCLE: The fwnode link is part of a cycle. Don't defer probe. * CYCLE: The fwnode link is part of a cycle. Don't defer probe.
* IGNORE: Completely ignore this link, even during cycle detection.
*/ */
#define FWLINK_FLAG_CYCLE BIT(0) #define FWLINK_FLAG_CYCLE BIT(0)
#define FWLINK_FLAG_IGNORE BIT(1)
struct fwnode_link { struct fwnode_link {
struct fwnode_handle *supplier; struct fwnode_handle *supplier;

View File

@@ -268,6 +268,20 @@ enum i3c_bus_mode {
I3C_BUS_MODE_MIXED_SLOW, I3C_BUS_MODE_MIXED_SLOW,
}; };
/**
* enum i3c_open_drain_speed - I3C open-drain speed
* @I3C_OPEN_DRAIN_SLOW_SPEED: Slow open-drain speed for sending the first
* broadcast address. The first broadcast address at this speed
* will be visible to all devices on the I3C bus. I3C devices
* working in I2C mode will turn off their spike filter when
* switching into I3C mode.
* @I3C_OPEN_DRAIN_NORMAL_SPEED: Normal open-drain speed in I3C bus mode.
*/
enum i3c_open_drain_speed {
I3C_OPEN_DRAIN_SLOW_SPEED,
I3C_OPEN_DRAIN_NORMAL_SPEED,
};
/** /**
* enum i3c_addr_slot_status - I3C address slot status * enum i3c_addr_slot_status - I3C address slot status
* @I3C_ADDR_SLOT_FREE: address is free * @I3C_ADDR_SLOT_FREE: address is free
@@ -275,7 +289,8 @@ enum i3c_bus_mode {
* @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device * @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device
* @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device * @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device
* @I3C_ADDR_SLOT_STATUS_MASK: address slot mask * @I3C_ADDR_SLOT_STATUS_MASK: address slot mask
* * @I3C_ADDR_SLOT_EXT_DESIRED: the bitmask represents addresses that are preferred by some devices,
* such as the "assigned-address" property in a device tree source.
* On an I3C bus, addresses are assigned dynamically, and we need to know which * On an I3C bus, addresses are assigned dynamically, and we need to know which
* addresses are free to use and which ones are already assigned. * addresses are free to use and which ones are already assigned.
* *
@@ -288,8 +303,12 @@ enum i3c_addr_slot_status {
I3C_ADDR_SLOT_I2C_DEV, I3C_ADDR_SLOT_I2C_DEV,
I3C_ADDR_SLOT_I3C_DEV, I3C_ADDR_SLOT_I3C_DEV,
I3C_ADDR_SLOT_STATUS_MASK = 3, I3C_ADDR_SLOT_STATUS_MASK = 3,
I3C_ADDR_SLOT_EXT_STATUS_MASK = 7,
I3C_ADDR_SLOT_EXT_DESIRED = BIT(2),
}; };
#define I3C_ADDR_SLOT_STATUS_BITS 4
/** /**
* struct i3c_bus - I3C bus object * struct i3c_bus - I3C bus object
* @cur_master: I3C master currently driving the bus. Since I3C is multi-master * @cur_master: I3C master currently driving the bus. Since I3C is multi-master
@@ -331,7 +350,7 @@ enum i3c_addr_slot_status {
struct i3c_bus { struct i3c_bus {
struct i3c_dev_desc *cur_master; struct i3c_dev_desc *cur_master;
int id; int id;
unsigned long addrslots[((I2C_MAX_ADDR + 1) * 2) / BITS_PER_LONG]; unsigned long addrslots[((I2C_MAX_ADDR + 1) * I3C_ADDR_SLOT_STATUS_BITS) / BITS_PER_LONG];
enum i3c_bus_mode mode; enum i3c_bus_mode mode;
struct { struct {
unsigned long i3c; unsigned long i3c;
@@ -425,6 +444,9 @@ struct i3c_bus {
* for a future IBI * for a future IBI
* This method is mandatory only if ->request_ibi is not * This method is mandatory only if ->request_ibi is not
* NULL. * NULL.
* @enable_hotjoin: enable hot join event detect.
* @disable_hotjoin: disable hot join event detect.
* @set_speed: adjust I3C open drain mode timing.
*/ */
struct i3c_master_controller_ops { struct i3c_master_controller_ops {
int (*bus_init)(struct i3c_master_controller *master); int (*bus_init)(struct i3c_master_controller *master);
@@ -451,6 +473,9 @@ struct i3c_master_controller_ops {
int (*disable_ibi)(struct i3c_dev_desc *dev); int (*disable_ibi)(struct i3c_dev_desc *dev);
void (*recycle_ibi_slot)(struct i3c_dev_desc *dev, void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
struct i3c_ibi_slot *slot); struct i3c_ibi_slot *slot);
int (*enable_hotjoin)(struct i3c_master_controller *master);
int (*disable_hotjoin)(struct i3c_master_controller *master);
int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed);
}; };
/** /**
@@ -464,6 +489,7 @@ struct i3c_master_controller_ops {
* @ops: master operations. See &struct i3c_master_controller_ops * @ops: master operations. See &struct i3c_master_controller_ops
* @secondary: true if the master is a secondary master * @secondary: true if the master is a secondary master
* @init_done: true when the bus initialization is done * @init_done: true when the bus initialization is done
* @hotjoin: true if the master support hotjoin
* @boardinfo.i3c: list of I3C boardinfo objects * @boardinfo.i3c: list of I3C boardinfo objects
* @boardinfo.i2c: list of I2C boardinfo objects * @boardinfo.i2c: list of I2C boardinfo objects
* @boardinfo: board-level information attached to devices connected on the bus * @boardinfo: board-level information attached to devices connected on the bus
@@ -486,6 +512,7 @@ struct i3c_master_controller {
const struct i3c_master_controller_ops *ops; const struct i3c_master_controller_ops *ops;
unsigned int secondary : 1; unsigned int secondary : 1;
unsigned int init_done : 1; unsigned int init_done : 1;
unsigned int hotjoin: 1;
struct { struct {
struct list_head i3c; struct list_head i3c;
struct list_head i2c; struct list_head i2c;
@@ -541,7 +568,9 @@ int i3c_master_register(struct i3c_master_controller *master,
struct device *parent, struct device *parent,
const struct i3c_master_controller_ops *ops, const struct i3c_master_controller_ops *ops,
bool secondary); bool secondary);
int i3c_master_unregister(struct i3c_master_controller *master); void i3c_master_unregister(struct i3c_master_controller *master);
int i3c_master_enable_hotjoin(struct i3c_master_controller *master);
int i3c_master_disable_hotjoin(struct i3c_master_controller *master);
/** /**
* i3c_dev_get_master_data() - get master private data attached to an I3C * i3c_dev_get_master_data() - get master private data attached to an I3C

View File

@@ -298,6 +298,8 @@ struct mmc_card {
#define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */
#define MMC_QUIRK_BROKEN_SD_DISCARD (1<<14) /* Disable broken SD discard support */ #define MMC_QUIRK_BROKEN_SD_DISCARD (1<<14) /* Disable broken SD discard support */
#define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */ #define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */
#define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */
#define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */
bool reenable_cmdq; /* Re-enable Command Queue */ bool reenable_cmdq; /* Re-enable Command Queue */

View File

@@ -122,6 +122,7 @@ struct pci_epc_mem {
* struct pci_epc - represents the PCI EPC device * struct pci_epc - represents the PCI EPC device
* @dev: PCI EPC device * @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device * @pci_epf: list of endpoint functions present in this EPC device
* list_lock: Mutex for protecting pci_epf list
* @ops: function pointers for performing endpoint operations * @ops: function pointers for performing endpoint operations
* @windows: array of address space of the endpoint controller * @windows: array of address space of the endpoint controller
* @mem: first window of the endpoint controller, which corresponds to * @mem: first window of the endpoint controller, which corresponds to
@@ -139,6 +140,7 @@ struct pci_epc_mem {
struct pci_epc { struct pci_epc {
struct device dev; struct device dev;
struct list_head pci_epf; struct list_head pci_epf;
struct mutex list_lock;
const struct pci_epc_ops *ops; const struct pci_epc_ops *ops;
struct pci_epc_mem **windows; struct pci_epc_mem **windows;
struct pci_epc_mem *mem; struct pci_epc_mem *mem;

View File

@@ -11,6 +11,7 @@
#define _LINUX_PROPERTY_H_ #define _LINUX_PROPERTY_H_
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/fwnode.h> #include <linux/fwnode.h>
#include <linux/types.h> #include <linux/types.h>
@@ -109,25 +110,32 @@ struct fwnode_handle *fwnode_get_next_available_child_node(
for (child = fwnode_get_next_available_child_node(fwnode, NULL); child;\ for (child = fwnode_get_next_available_child_node(fwnode, NULL); child;\
child = fwnode_get_next_available_child_node(fwnode, child)) child = fwnode_get_next_available_child_node(fwnode, child))
struct fwnode_handle *device_get_next_child_node( struct fwnode_handle *device_get_next_child_node(const struct device *dev,
struct device *dev, struct fwnode_handle *child); struct fwnode_handle *child);
#define device_for_each_child_node(dev, child) \ #define device_for_each_child_node(dev, child) \
for (child = device_get_next_child_node(dev, NULL); child; \ for (child = device_get_next_child_node(dev, NULL); child; \
child = device_get_next_child_node(dev, child)) child = device_get_next_child_node(dev, child))
struct fwnode_handle *fwnode_get_named_child_node( #define device_for_each_child_node_scoped(dev, child) \
const struct fwnode_handle *fwnode, const char *childname); for (struct fwnode_handle *child __free(fwnode_handle) = \
struct fwnode_handle *device_get_named_child_node(struct device *dev, device_get_next_child_node(dev, NULL); \
child; child = device_get_next_child_node(dev, child))
struct fwnode_handle *fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname);
struct fwnode_handle *device_get_named_child_node(const struct device *dev,
const char *childname); const char *childname);
struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode); struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode);
void fwnode_handle_put(struct fwnode_handle *fwnode); void fwnode_handle_put(struct fwnode_handle *fwnode);
DEFINE_FREE(fwnode_handle, struct fwnode_handle *, fwnode_handle_put(_T))
int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index); int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index);
int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name); int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name);
unsigned int device_get_child_node_count(struct device *dev); unsigned int device_get_child_node_count(const struct device *dev);
static inline bool device_property_read_bool(struct device *dev, static inline bool device_property_read_bool(struct device *dev,
const char *propname) const char *propname)

View File

@@ -288,7 +288,7 @@ static inline void sg_dma_mark_bus_address(struct scatterlist *sg)
} }
/** /**
* sg_unmark_bus_address - Unmark the scatterlist entry as a bus address * sg_dma_unmark_bus_address - Unmark the scatterlist entry as a bus address
* @sg: SG entry * @sg: SG entry
* *
* Description: * Description:

View File

@@ -287,7 +287,9 @@ struct ufs_pwr_mode_info {
* to allow variant specific Uni-Pro initialization. * to allow variant specific Uni-Pro initialization.
* @pwr_change_notify: called before and after a power mode change * @pwr_change_notify: called before and after a power mode change
* is carried out to allow vendor spesific capabilities * is carried out to allow vendor spesific capabilities
* to be set. * to be set. PRE_CHANGE can modify final_params based
* on desired_pwr_mode, but POST_CHANGE must not alter
* the final_params parameter
* @setup_xfer_req: called before any transfer request is issued * @setup_xfer_req: called before any transfer request is issued
* to set some things * to set some things
* @setup_task_mgmt: called before any task management request is issued * @setup_task_mgmt: called before any task management request is issued
@@ -324,9 +326,9 @@ struct ufs_hba_variant_ops {
int (*link_startup_notify)(struct ufs_hba *, int (*link_startup_notify)(struct ufs_hba *,
enum ufs_notify_change_status); enum ufs_notify_change_status);
int (*pwr_change_notify)(struct ufs_hba *, int (*pwr_change_notify)(struct ufs_hba *,
enum ufs_notify_change_status status, enum ufs_notify_change_status status,
struct ufs_pa_layer_attr *, struct ufs_pa_layer_attr *desired_pwr_mode,
struct ufs_pa_layer_attr *); struct ufs_pa_layer_attr *final_params);
void (*setup_xfer_req)(struct ufs_hba *hba, int tag, void (*setup_xfer_req)(struct ufs_hba *hba, int tag,
bool is_scsi_cmd); bool is_scsi_cmd);
void (*setup_task_mgmt)(struct ufs_hba *, int, u8); void (*setup_task_mgmt)(struct ufs_hba *, int, u8);

View File

@@ -184,7 +184,7 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
static void dev_map_free(struct bpf_map *map) static void dev_map_free(struct bpf_map *map)
{ {
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
int i; u32 i;
/* At this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0, /* At this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
* so the programs (can be more than one that used this map) were * so the programs (can be more than one that used this map) were
@@ -807,7 +807,7 @@ static int dev_map_delete_elem(struct bpf_map *map, void *key)
{ {
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
struct bpf_dtab_netdev *old_dev; struct bpf_dtab_netdev *old_dev;
int k = *(u32 *)key; u32 k = *(u32 *)key;
if (k >= map->max_entries) if (k >= map->max_entries)
return -EINVAL; return -EINVAL;
@@ -822,7 +822,7 @@ static int dev_map_hash_delete_elem(struct bpf_map *map, void *key)
{ {
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
struct bpf_dtab_netdev *old_dev; struct bpf_dtab_netdev *old_dev;
int k = *(u32 *)key; u32 k = *(u32 *)key;
unsigned long flags; unsigned long flags;
int ret = -ENOENT; int ret = -ENOENT;

View File

@@ -302,12 +302,22 @@ static struct lpm_trie_node *lpm_trie_node_alloc(const struct lpm_trie *trie,
return node; return node;
} }
static int trie_check_add_elem(struct lpm_trie *trie, u64 flags)
{
if (flags == BPF_EXIST)
return -ENOENT;
if (trie->n_entries == trie->map.max_entries)
return -ENOSPC;
trie->n_entries++;
return 0;
}
/* Called from syscall or from eBPF program */ /* Called from syscall or from eBPF program */
static int trie_update_elem(struct bpf_map *map, static int trie_update_elem(struct bpf_map *map,
void *_key, void *value, u64 flags) void *_key, void *value, u64 flags)
{ {
struct lpm_trie *trie = container_of(map, struct lpm_trie, map); struct lpm_trie *trie = container_of(map, struct lpm_trie, map);
struct lpm_trie_node *node, *im_node = NULL, *new_node = NULL; struct lpm_trie_node *node, *im_node, *new_node = NULL;
struct lpm_trie_node *free_node = NULL; struct lpm_trie_node *free_node = NULL;
struct lpm_trie_node __rcu **slot; struct lpm_trie_node __rcu **slot;
struct bpf_lpm_trie_key_u8 *key = _key; struct bpf_lpm_trie_key_u8 *key = _key;
@@ -325,20 +335,12 @@ static int trie_update_elem(struct bpf_map *map,
spin_lock_irqsave(&trie->lock, irq_flags); spin_lock_irqsave(&trie->lock, irq_flags);
/* Allocate and fill a new node */ /* Allocate and fill a new node */
if (trie->n_entries == trie->map.max_entries) {
ret = -ENOSPC;
goto out;
}
new_node = lpm_trie_node_alloc(trie, value); new_node = lpm_trie_node_alloc(trie, value);
if (!new_node) { if (!new_node) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
trie->n_entries++;
new_node->prefixlen = key->prefixlen; new_node->prefixlen = key->prefixlen;
RCU_INIT_POINTER(new_node->child[0], NULL); RCU_INIT_POINTER(new_node->child[0], NULL);
RCU_INIT_POINTER(new_node->child[1], NULL); RCU_INIT_POINTER(new_node->child[1], NULL);
@@ -368,6 +370,10 @@ static int trie_update_elem(struct bpf_map *map,
* simply assign the @new_node to that slot and be done. * simply assign the @new_node to that slot and be done.
*/ */
if (!node) { if (!node) {
ret = trie_check_add_elem(trie, flags);
if (ret)
goto out;
rcu_assign_pointer(*slot, new_node); rcu_assign_pointer(*slot, new_node);
goto out; goto out;
} }
@@ -376,18 +382,30 @@ static int trie_update_elem(struct bpf_map *map,
* which already has the correct data array set. * which already has the correct data array set.
*/ */
if (node->prefixlen == matchlen) { if (node->prefixlen == matchlen) {
if (!(node->flags & LPM_TREE_NODE_FLAG_IM)) {
if (flags == BPF_NOEXIST) {
ret = -EEXIST;
goto out;
}
} else {
ret = trie_check_add_elem(trie, flags);
if (ret)
goto out;
}
new_node->child[0] = node->child[0]; new_node->child[0] = node->child[0];
new_node->child[1] = node->child[1]; new_node->child[1] = node->child[1];
if (!(node->flags & LPM_TREE_NODE_FLAG_IM))
trie->n_entries--;
rcu_assign_pointer(*slot, new_node); rcu_assign_pointer(*slot, new_node);
free_node = node; free_node = node;
goto out; goto out;
} }
ret = trie_check_add_elem(trie, flags);
if (ret)
goto out;
/* If the new node matches the prefix completely, it must be inserted /* If the new node matches the prefix completely, it must be inserted
* as an ancestor. Simply insert it between @node and *@slot. * as an ancestor. Simply insert it between @node and *@slot.
*/ */
@@ -400,6 +418,7 @@ static int trie_update_elem(struct bpf_map *map,
im_node = lpm_trie_node_alloc(trie, NULL); im_node = lpm_trie_node_alloc(trie, NULL);
if (!im_node) { if (!im_node) {
trie->n_entries--;
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
@@ -421,14 +440,8 @@ static int trie_update_elem(struct bpf_map *map,
rcu_assign_pointer(*slot, im_node); rcu_assign_pointer(*slot, im_node);
out: out:
if (ret) { if (ret)
if (new_node)
trie->n_entries--;
kfree(new_node); kfree(new_node);
kfree(im_node);
}
spin_unlock_irqrestore(&trie->lock, irq_flags); spin_unlock_irqrestore(&trie->lock, irq_flags);
kfree_rcu(free_node, rcu); kfree_rcu(free_node, rcu);
@@ -628,7 +641,7 @@ static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
struct lpm_trie_node **node_stack = NULL; struct lpm_trie_node **node_stack = NULL;
int err = 0, stack_ptr = -1; int err = 0, stack_ptr = -1;
unsigned int next_bit; unsigned int next_bit;
size_t matchlen; size_t matchlen = 0;
/* The get_next_key follows postorder. For the 4 node example in /* The get_next_key follows postorder. For the 4 node example in
* the top of this file, the trie_get_next_key() returns the following * the top of this file, the trie_get_next_key() returns the following
@@ -667,7 +680,7 @@ static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
next_bit = extract_bit(key->data, node->prefixlen); next_bit = extract_bit(key->data, node->prefixlen);
node = rcu_dereference(node->child[next_bit]); node = rcu_dereference(node->child[next_bit]);
} }
if (!node || node->prefixlen != key->prefixlen || if (!node || node->prefixlen != matchlen ||
(node->flags & LPM_TREE_NODE_FLAG_IM)) (node->flags & LPM_TREE_NODE_FLAG_IM))
goto find_leftmost; goto find_leftmost;

View File

@@ -46,14 +46,8 @@ static struct {
int used; /* number of elements used */ int used; /* number of elements used */
bool sorted; /* if elements are sorted */ bool sorted; /* if elements are sorted */
bool whitelist; /* if list is a blacklist or whitelist */ bool whitelist; /* if list is a blacklist or whitelist */
} report_filterlist = { } report_filterlist;
.addrs = NULL, static DEFINE_RAW_SPINLOCK(report_filterlist_lock);
.size = 8, /* small initial size */
.used = 0,
.sorted = false,
.whitelist = false, /* default is blacklist */
};
static DEFINE_SPINLOCK(report_filterlist_lock);
/* /*
* The microbenchmark allows benchmarking KCSAN core runtime only. To run * The microbenchmark allows benchmarking KCSAN core runtime only. To run
@@ -110,7 +104,7 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
return false; return false;
func_addr -= offset; /* Get function start */ func_addr -= offset; /* Get function start */
spin_lock_irqsave(&report_filterlist_lock, flags); raw_spin_lock_irqsave(&report_filterlist_lock, flags);
if (report_filterlist.used == 0) if (report_filterlist.used == 0)
goto out; goto out;
@@ -127,7 +121,7 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
ret = !ret; ret = !ret;
out: out:
spin_unlock_irqrestore(&report_filterlist_lock, flags); raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
return ret; return ret;
} }
@@ -135,9 +129,9 @@ static void set_report_filterlist_whitelist(bool whitelist)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&report_filterlist_lock, flags); raw_spin_lock_irqsave(&report_filterlist_lock, flags);
report_filterlist.whitelist = whitelist; report_filterlist.whitelist = whitelist;
spin_unlock_irqrestore(&report_filterlist_lock, flags); raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
} }
/* Returns 0 on success, error-code otherwise. */ /* Returns 0 on success, error-code otherwise. */
@@ -145,6 +139,9 @@ static ssize_t insert_report_filterlist(const char *func)
{ {
unsigned long flags; unsigned long flags;
unsigned long addr = kallsyms_lookup_name(func); unsigned long addr = kallsyms_lookup_name(func);
unsigned long *delay_free = NULL;
unsigned long *new_addrs = NULL;
size_t new_size = 0;
ssize_t ret = 0; ssize_t ret = 0;
if (!addr) { if (!addr) {
@@ -152,32 +149,33 @@ static ssize_t insert_report_filterlist(const char *func)
return -ENOENT; return -ENOENT;
} }
spin_lock_irqsave(&report_filterlist_lock, flags); retry_alloc:
/*
* Check if we need an allocation, and re-validate under the lock. Since
* the report_filterlist_lock is a raw, cannot allocate under the lock.
*/
if (data_race(report_filterlist.used == report_filterlist.size)) {
new_size = (report_filterlist.size ?: 4) * 2;
delay_free = new_addrs = kmalloc_array(new_size, sizeof(unsigned long), GFP_KERNEL);
if (!new_addrs)
return -ENOMEM;
}
if (report_filterlist.addrs == NULL) { raw_spin_lock_irqsave(&report_filterlist_lock, flags);
/* initial allocation */ if (report_filterlist.used == report_filterlist.size) {
report_filterlist.addrs = /* Check we pre-allocated enough, and retry if not. */
kmalloc_array(report_filterlist.size, if (report_filterlist.used >= new_size) {
sizeof(unsigned long), GFP_ATOMIC); raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
if (report_filterlist.addrs == NULL) { kfree(new_addrs); /* kfree(NULL) is safe */
ret = -ENOMEM; delay_free = new_addrs = NULL;
goto out; goto retry_alloc;
}
} else if (report_filterlist.used == report_filterlist.size) {
/* resize filterlist */
size_t new_size = report_filterlist.size * 2;
unsigned long *new_addrs =
krealloc(report_filterlist.addrs,
new_size * sizeof(unsigned long), GFP_ATOMIC);
if (new_addrs == NULL) {
/* leave filterlist itself untouched */
ret = -ENOMEM;
goto out;
} }
if (report_filterlist.used)
memcpy(new_addrs, report_filterlist.addrs, report_filterlist.used * sizeof(unsigned long));
delay_free = report_filterlist.addrs; /* free the old list */
report_filterlist.addrs = new_addrs; /* switch to the new list */
report_filterlist.size = new_size; report_filterlist.size = new_size;
report_filterlist.addrs = new_addrs;
} }
/* Note: deduplicating should be done in userspace. */ /* Note: deduplicating should be done in userspace. */
@@ -185,9 +183,9 @@ static ssize_t insert_report_filterlist(const char *func)
kallsyms_lookup_name(func); kallsyms_lookup_name(func);
report_filterlist.sorted = false; report_filterlist.sorted = false;
out: raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
spin_unlock_irqrestore(&report_filterlist_lock, flags);
kfree(delay_free);
return ret; return ret;
} }
@@ -204,13 +202,13 @@ static int show_info(struct seq_file *file, void *v)
} }
/* show filter functions, and filter type */ /* show filter functions, and filter type */
spin_lock_irqsave(&report_filterlist_lock, flags); raw_spin_lock_irqsave(&report_filterlist_lock, flags);
seq_printf(file, "\n%s functions: %s\n", seq_printf(file, "\n%s functions: %s\n",
report_filterlist.whitelist ? "whitelisted" : "blacklisted", report_filterlist.whitelist ? "whitelisted" : "blacklisted",
report_filterlist.used == 0 ? "none" : ""); report_filterlist.used == 0 ? "none" : "");
for (i = 0; i < report_filterlist.used; ++i) for (i = 0; i < report_filterlist.used; ++i)
seq_printf(file, " %ps\n", (void *)report_filterlist.addrs[i]); seq_printf(file, " %ps\n", (void *)report_filterlist.addrs[i]);
spin_unlock_irqrestore(&report_filterlist_lock, flags); raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
return 0; return 0;
} }

View File

@@ -796,7 +796,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
NTP_SCALE_SHIFT); NTP_SCALE_SHIFT);
if (!(time_status & STA_NANO)) if (!(time_status & STA_NANO))
txc->offset = (u32)txc->offset / NSEC_PER_USEC; txc->offset = div_s64(txc->offset, NSEC_PER_USEC);
} }
result = time_state; /* mostly `TIME_OK' */ result = time_state; /* mostly `TIME_OK' */

View File

@@ -845,15 +845,11 @@ int tracing_map_init(struct tracing_map *map)
static int cmp_entries_dup(const void *A, const void *B) static int cmp_entries_dup(const void *A, const void *B)
{ {
const struct tracing_map_sort_entry *a, *b; const struct tracing_map_sort_entry *a, *b;
int ret = 0;
a = *(const struct tracing_map_sort_entry **)A; a = *(const struct tracing_map_sort_entry **)A;
b = *(const struct tracing_map_sort_entry **)B; b = *(const struct tracing_map_sort_entry **)B;
if (memcmp(a->key, b->key, a->elt->map->key_size)) return memcmp(a->key, b->key, a->elt->map->key_size);
ret = 1;
return ret;
} }
static int cmp_entries_sum(const void *A, const void *B) static int cmp_entries_sum(const void *A, const void *B)

View File

@@ -199,6 +199,7 @@ static noinline void test_ ## name (struct kunit *test) \
static noinline DO_NOTHING_TYPE_ ## which(var_type) \ static noinline DO_NOTHING_TYPE_ ## which(var_type) \
do_nothing_ ## name(var_type *ptr) \ do_nothing_ ## name(var_type *ptr) \
{ \ { \
OPTIMIZER_HIDE_VAR(ptr); \
/* Will always be true, but compiler doesn't know. */ \ /* Will always be true, but compiler doesn't know. */ \
if ((unsigned long)ptr > 0x2) \ if ((unsigned long)ptr > 0x2) \
return DO_NOTHING_RETURN_ ## which(ptr); \ return DO_NOTHING_RETURN_ ## which(ptr); \

View File

@@ -1441,12 +1441,27 @@ static __always_inline bool free_pages_prepare(struct page *page,
int bad = 0; int bad = 0;
bool skip_kasan_poison = should_skip_kasan_poison(page, fpi_flags); bool skip_kasan_poison = should_skip_kasan_poison(page, fpi_flags);
bool init = want_init_on_free(); bool init = want_init_on_free();
struct folio *folio = page_folio(page);
VM_BUG_ON_PAGE(PageTail(page), page); VM_BUG_ON_PAGE(PageTail(page), page);
trace_mm_page_free(page, order); trace_mm_page_free(page, order);
kmsan_free_page(page, order); kmsan_free_page(page, order);
/*
* In rare cases, when truncation or holepunching raced with
* munlock after VM_LOCKED was cleared, Mlocked may still be
* found set here. This does not indicate a problem, unless
* "unevictable_pgs_cleared" appears worryingly large.
*/
if (unlikely(folio_test_mlocked(folio))) {
long nr_pages = folio_nr_pages(folio);
__folio_clear_mlocked(folio);
zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
}
if (unlikely(PageHWPoison(page)) && !order) { if (unlikely(PageHWPoison(page)) && !order) {
/* /*
* Do not let hwpoison pages hit pcplists/buddy * Do not let hwpoison pages hit pcplists/buddy

View File

@@ -88,14 +88,6 @@ static void __page_cache_release(struct folio *folio)
__folio_clear_lru_flags(folio); __folio_clear_lru_flags(folio);
unlock_page_lruvec_irqrestore(lruvec, flags); unlock_page_lruvec_irqrestore(lruvec, flags);
} }
/* See comment on folio_test_mlocked in release_pages() */
if (unlikely(folio_test_mlocked(folio))) {
long nr_pages = folio_nr_pages(folio);
__folio_clear_mlocked(folio);
zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
}
} }
static void __folio_put_small(struct folio *folio) static void __folio_put_small(struct folio *folio)
@@ -1042,18 +1034,6 @@ void release_pages(struct page **pages, int nr)
__folio_clear_lru_flags(folio); __folio_clear_lru_flags(folio);
} }
/*
* In rare cases, when truncation or holepunching raced with
* munlock after VM_LOCKED was cleared, Mlocked may still be
* found set here. This does not indicate a problem, unless
* "unevictable_pgs_cleared" appears worryingly large.
*/
if (unlikely(folio_test_mlocked(folio))) {
__folio_clear_mlocked(folio);
zone_stat_sub_folio(folio, NR_MLOCK);
count_vm_event(UNEVICTABLE_PGCLEARED);
}
list_add(&folio->lru, &pages_to_free); list_add(&folio->lru, &pages_to_free);
} }
if (lruvec) if (lruvec)

View File

@@ -424,7 +424,6 @@ more_data:
cork = true; cork = true;
psock->cork = NULL; psock->cork = NULL;
} }
sk_msg_return(sk, msg, tosend);
release_sock(sk); release_sock(sk);
origsize = msg->sg.size; origsize = msg->sg.size;
@@ -436,8 +435,9 @@ more_data:
sock_put(sk_redir); sock_put(sk_redir);
lock_sock(sk); lock_sock(sk);
sk_mem_uncharge(sk, sent);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
int free = sk_msg_free_nocharge(sk, msg); int free = sk_msg_free(sk, msg);
if (!cork) if (!cork)
*copied -= free; *copied -= free;
@@ -451,7 +451,7 @@ more_data:
break; break;
case __SK_DROP: case __SK_DROP:
default: default:
sk_msg_free_partial(sk, msg, tosend); sk_msg_free(sk, msg);
sk_msg_apply_bytes(psock, tosend); sk_msg_apply_bytes(psock, tosend);
*copied -= (tosend + delta); *copied -= (tosend + delta);
return -EACCES; return -EACCES;
@@ -467,11 +467,8 @@ more_data:
} }
if (msg && if (msg &&
msg->sg.data[msg->sg.start].page_link && msg->sg.data[msg->sg.start].page_link &&
msg->sg.data[msg->sg.start].length) { msg->sg.data[msg->sg.start].length)
if (eval == __SK_REDIRECT)
sk_mem_charge(sk, tosend - sent);
goto more_data; goto more_data;
}
} }
return ret; return ret;
} }

View File

@@ -356,10 +356,9 @@ void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs)
return; return;
} }
if (!refcount_dec_and_test(&dma_map->users)) if (refcount_dec_and_test(&dma_map->users))
return; __xp_dma_unmap(dma_map, attrs);
__xp_dma_unmap(dma_map, attrs);
kvfree(pool->dma_pages); kvfree(pool->dma_pages);
pool->dma_pages_cnt = 0; pool->dma_pages_cnt = 0;
pool->dev = NULL; pool->dev = NULL;

View File

@@ -216,7 +216,7 @@ static int xsk_map_delete_elem(struct bpf_map *map, void *key)
struct xsk_map *m = container_of(map, struct xsk_map, map); struct xsk_map *m = container_of(map, struct xsk_map, map);
struct xdp_sock __rcu **map_entry; struct xdp_sock __rcu **map_entry;
struct xdp_sock *old_xs; struct xdp_sock *old_xs;
int k = *(u32 *)key; u32 k = *(u32 *)key;
if (k >= map->max_entries) if (k >= map->max_entries)
return -EINVAL; return -EINVAL;

View File

@@ -832,7 +832,7 @@ static void check_section(const char *modname, struct elf_info *elf,
".ltext", ".ltext.*" ".ltext", ".ltext.*"
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
".fixup", ".entry.text", ".exception.text", \ ".fixup", ".entry.text", ".exception.text", \
".coldtext", ".softirqentry.text" ".coldtext", ".softirqentry.text", ".irqentry.text"
#define INIT_SECTIONS ".init.*" #define INIT_SECTIONS ".init.*"
#define MEM_INIT_SECTIONS ".meminit.*" #define MEM_INIT_SECTIONS ".meminit.*"
@@ -892,7 +892,7 @@ enum mismatch {
struct sectioncheck { struct sectioncheck {
const char *fromsec[20]; const char *fromsec[20];
const char *bad_tosec[20]; const char *bad_tosec[20];
const char *good_tosec[20]; const char *good_tosec[21];
enum mismatch mismatch; enum mismatch mismatch;
void (*handler)(const char *modname, struct elf_info *elf, void (*handler)(const char *modname, struct elf_info *elf,
const struct sectioncheck* const mismatch, const struct sectioncheck* const mismatch,

View File

@@ -9766,6 +9766,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
@@ -10015,6 +10016,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),

View File

@@ -403,10 +403,15 @@ static int prepare_inbound_urb(struct snd_usb_endpoint *ep,
static void notify_xrun(struct snd_usb_endpoint *ep) static void notify_xrun(struct snd_usb_endpoint *ep)
{ {
struct snd_usb_substream *data_subs; struct snd_usb_substream *data_subs;
struct snd_pcm_substream *psubs;
data_subs = READ_ONCE(ep->data_subs); data_subs = READ_ONCE(ep->data_subs);
if (data_subs && data_subs->pcm_substream) if (!data_subs)
snd_pcm_stop_xrun(data_subs->pcm_substream); return;
psubs = data_subs->pcm_substream;
if (psubs && psubs->runtime &&
psubs->runtime->state == SNDRV_PCM_STATE_RUNNING)
snd_pcm_stop_xrun(psubs);
} }
static struct snd_usb_packet_info * static struct snd_usb_packet_info *
@@ -557,7 +562,10 @@ static void snd_complete_urb(struct urb *urb)
push_back_to_ready_list(ep, ctx); push_back_to_ready_list(ep, ctx);
clear_bit(ctx->index, &ep->active_mask); clear_bit(ctx->index, &ep->active_mask);
snd_usb_queue_pending_output_urbs(ep, false); snd_usb_queue_pending_output_urbs(ep, false);
atomic_dec(&ep->submitted_urbs); /* decrement at last */ /* decrement at last, and check xrun */
if (atomic_dec_and_test(&ep->submitted_urbs) &&
!snd_usb_endpoint_implicit_feedback_sink(ep))
notify_xrun(ep);
return; return;
} }

View File

@@ -621,6 +621,16 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x1b1c, 0x0a42), .id = USB_ID(0x1b1c, 0x0a42),
.map = corsair_virtuoso_map, .map = corsair_virtuoso_map,
}, },
{
/* Corsair HS80 RGB Wireless (wired mode) */
.id = USB_ID(0x1b1c, 0x0a6a),
.map = corsair_virtuoso_map,
},
{
/* Corsair HS80 RGB Wireless (wireless mode) */
.id = USB_ID(0x1b1c, 0x0a6b),
.map = corsair_virtuoso_map,
},
{ /* Gigabyte TRX40 Aorus Master (rear panel + front mic) */ { /* Gigabyte TRX40 Aorus Master (rear panel + front mic) */
.id = USB_ID(0x0414, 0xa001), .id = USB_ID(0x0414, 0xa001),
.map = aorus_master_alc1220vb_map, .map = aorus_master_alc1220vb_map,

View File

@@ -16,7 +16,6 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <bfd.h> #include <bfd.h>
@@ -29,14 +28,18 @@
#include "json_writer.h" #include "json_writer.h"
#include "main.h" #include "main.h"
static void get_exec_path(char *tpath, size_t size) static int get_exec_path(char *tpath, size_t size)
{ {
const char *path = "/proc/self/exe"; const char *path = "/proc/self/exe";
ssize_t len; ssize_t len;
len = readlink(path, tpath, size - 1); len = readlink(path, tpath, size - 1);
assert(len > 0); if (len <= 0)
return -1;
tpath[len] = 0; tpath[len] = 0;
return 0;
} }
static int oper_count; static int oper_count;
@@ -97,30 +100,39 @@ static int fprintf_json_styled(void *out,
return r; return r;
} }
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch, const char *disassembler_options, const char *arch, const char *disassembler_options,
const struct btf *btf, const struct btf *btf,
const struct bpf_prog_linfo *prog_linfo, const struct bpf_prog_linfo *prog_linfo,
__u64 func_ksym, unsigned int func_idx, __u64 func_ksym, unsigned int func_idx,
bool linum) bool linum)
{ {
const struct bpf_line_info *linfo = NULL; const struct bpf_line_info *linfo = NULL;
disassembler_ftype disassemble; disassembler_ftype disassemble;
int count, i, pc = 0, err = -1;
struct disassemble_info info; struct disassemble_info info;
unsigned int nr_skip = 0; unsigned int nr_skip = 0;
int count, i, pc = 0;
char tpath[PATH_MAX]; char tpath[PATH_MAX];
bfd *bfdf; bfd *bfdf;
if (!len) if (!len)
return; return -1;
memset(tpath, 0, sizeof(tpath)); memset(tpath, 0, sizeof(tpath));
get_exec_path(tpath, sizeof(tpath)); if (get_exec_path(tpath, sizeof(tpath))) {
p_err("failed to create disasembler (get_exec_path)");
return -1;
}
bfdf = bfd_openr(tpath, NULL); bfdf = bfd_openr(tpath, NULL);
assert(bfdf); if (!bfdf) {
assert(bfd_check_format(bfdf, bfd_object)); p_err("failed to create disassembler (bfd_openr)");
return -1;
}
if (!bfd_check_format(bfdf, bfd_object)) {
p_err("failed to create disassembler (bfd_check_format)");
goto exit_close;
}
if (json_output) if (json_output)
init_disassemble_info_compat(&info, stdout, init_disassemble_info_compat(&info, stdout,
@@ -139,7 +151,7 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
bfdf->arch_info = inf; bfdf->arch_info = inf;
} else { } else {
p_err("No libbfd support for %s", arch); p_err("No libbfd support for %s", arch);
return; goto exit_close;
} }
} }
@@ -160,7 +172,10 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
#else #else
disassemble = disassembler(bfdf); disassemble = disassembler(bfdf);
#endif #endif
assert(disassemble); if (!disassemble) {
p_err("failed to create disassembler");
goto exit_close;
}
if (json_output) if (json_output)
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
@@ -224,7 +239,11 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
err = 0;
exit_close:
bfd_close(bfdf); bfd_close(bfdf);
return err;
} }
int disasm_init(void) int disasm_init(void)

View File

@@ -173,22 +173,23 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
struct bpf_prog_linfo; struct bpf_prog_linfo;
#ifdef HAVE_LIBBFD_SUPPORT #ifdef HAVE_LIBBFD_SUPPORT
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch, const char *disassembler_options, const char *arch, const char *disassembler_options,
const struct btf *btf, const struct btf *btf,
const struct bpf_prog_linfo *prog_linfo, const struct bpf_prog_linfo *prog_linfo,
__u64 func_ksym, unsigned int func_idx, __u64 func_ksym, unsigned int func_idx,
bool linum); bool linum);
int disasm_init(void); int disasm_init(void);
#else #else
static inline static inline
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch, const char *disassembler_options, const char *arch, const char *disassembler_options,
const struct btf *btf, const struct btf *btf,
const struct bpf_prog_linfo *prog_linfo, const struct bpf_prog_linfo *prog_linfo,
__u64 func_ksym, unsigned int func_idx, __u64 func_ksym, unsigned int func_idx,
bool linum) bool linum)
{ {
return 0;
} }
static inline int disasm_init(void) static inline int disasm_init(void)
{ {

View File

@@ -1,7 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/err.h> #include <linux/err.h>

View File

@@ -820,10 +820,18 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
printf("%s:\n", sym_name); printf("%s:\n", sym_name);
} }
disasm_print_insn(img, lens[i], opcodes, if (ksyms) {
name, disasm_opt, btf, if (disasm_print_insn(img, lens[i], opcodes,
prog_linfo, ksyms[i], i, name, disasm_opt, btf,
linum); prog_linfo, ksyms[i], i,
linum))
goto exit_free;
} else {
if (disasm_print_insn(img, lens[i], opcodes,
name, disasm_opt, btf,
NULL, 0, 0, false))
goto exit_free;
}
img += lens[i]; img += lens[i];
@@ -836,8 +844,10 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
} else { } else {
disasm_print_insn(buf, member_len, opcodes, name, if (disasm_print_insn(buf, member_len, opcodes, name,
disasm_opt, btf, NULL, 0, 0, false); disasm_opt, btf, NULL, 0, 0,
false))
goto exit_free;
} }
} else if (visual) { } else if (visual) {
if (json_output) if (json_output)

View File

@@ -7,8 +7,8 @@ HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-e s/riscv.*/riscv/) -e s/riscv.*/riscv/)
ifndef ARCH ifeq ($(strip $(ARCH)),)
ARCH := $(HOSTARCH) override ARCH := $(HOSTARCH)
endif endif
SRCARCH := $(ARCH) SRCARCH := $(ARCH)

View File

@@ -182,6 +182,9 @@ int exec_sign_all(struct signatures *signed_vals, size_t val)
return -1; return -1;
} }
close(new_stdin[1]);
close(new_stdout[0]);
return 0; return 0;
} }