mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
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:
@@ -1342,7 +1342,7 @@ static int tagged_addr_ctrl_get(struct task_struct *target,
|
||||
{
|
||||
long ctrl = get_tagged_addr_ctrl(target);
|
||||
|
||||
if (IS_ERR_VALUE(ctrl))
|
||||
if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl)))
|
||||
return 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;
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -32,9 +32,9 @@ static unsigned long nr_pinned_asids;
|
||||
static unsigned long *pinned_asid_map;
|
||||
|
||||
#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 asid2ctxid(asid, genid) ((asid) | (genid))
|
||||
|
||||
|
||||
@@ -29,6 +29,16 @@ static inline int prepare_hugepage_range(struct file *file,
|
||||
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
|
||||
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
|
||||
unsigned long addr, pte_t *ptep)
|
||||
|
||||
@@ -10,23 +10,11 @@ obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o not
|
||||
|
||||
ifneq ($(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
|
||||
# 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
|
||||
# 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
|
||||
|
||||
# Build rules
|
||||
@@ -47,14 +35,33 @@ KCOV_INSTRUMENT := n
|
||||
UBSAN_SANITIZE := n
|
||||
KASAN_SANITIZE := n
|
||||
|
||||
ccflags-y := -shared -fno-common -fno-builtin -nostdlib -Wl,--hash-style=both
|
||||
ccflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld)
|
||||
ccflags-y := -fno-common -fno-builtin
|
||||
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
|
||||
AS32FLAGS := -D__VDSO32__ -s
|
||||
CC32FLAGS := -m32
|
||||
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
|
||||
AS64FLAGS := -D__VDSO64__ -s
|
||||
LD64FLAGS := -Wl,-soname=linux-vdso64.so.1
|
||||
AS64FLAGS := -D__VDSO64__
|
||||
|
||||
targets += vdso32.lds
|
||||
CPPFLAGS_vdso32.lds += -P -C -Upowerpc
|
||||
@@ -92,13 +99,15 @@ include/generated/vdso64-offsets.h: $(obj)/vdso64.so.dbg FORCE
|
||||
|
||||
# actual build commands
|
||||
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 $@
|
||||
cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $<
|
||||
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 $@
|
||||
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 $@
|
||||
cmd_vdso64as = $(VDSOCC) $(a_flags) $(CC64FLAGS) $(AS64FLAGS) -c -o $@ $<
|
||||
cmd_vdso64as = $(VDSOCC) $(a_flags) $(AS64FLAGS) -c -o $@ $<
|
||||
|
||||
OBJECT_FILES_NON_STANDARD := y
|
||||
|
||||
@@ -1896,7 +1896,9 @@ static void cpumsf_pmu_stop(struct perf_event *event, int flags)
|
||||
event->hw.state |= PERF_HES_STOPPED;
|
||||
|
||||
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;
|
||||
}
|
||||
perf_pmu_enable(event->pmu);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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 hw_perf_event *hwc;
|
||||
struct perf_event *event;
|
||||
int handled = 0, idx;
|
||||
u64 reserved, status, mask;
|
||||
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
|
||||
* 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 */
|
||||
amd_pmu_ack_global_status(~status);
|
||||
|
||||
@@ -137,7 +137,7 @@ static void __fwnode_link_del(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->flags |= FWLINK_FLAG_CYCLE;
|
||||
}
|
||||
@@ -1082,7 +1082,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
|
||||
return NULL;
|
||||
|
||||
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 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.
|
||||
*/
|
||||
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 device *sup_dev = NULL, *par_dev = NULL;
|
||||
struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL;
|
||||
struct fwnode_link *link;
|
||||
struct device_link *dev_link;
|
||||
bool ret = false;
|
||||
@@ -1952,27 +1953,31 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
|
||||
sup_handle->flags |= FWNODE_FLAG_VISITED;
|
||||
|
||||
sup_dev = get_dev_from_fwnode(sup_handle);
|
||||
|
||||
/* Termination condition. */
|
||||
if (sup_dev == con) {
|
||||
if (sup_handle == con_handle) {
|
||||
pr_debug("----- cycle: start -----\n");
|
||||
ret = true;
|
||||
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
|
||||
* driver, sup_dev can't be a consumer of @con. So, no need to check
|
||||
* further.
|
||||
*/
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = true;
|
||||
}
|
||||
@@ -1987,8 +1992,11 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
if (!sup_dev)
|
||||
goto out;
|
||||
@@ -2002,8 +2010,10 @@ static bool __fw_devlink_relax_cycles(struct device *con,
|
||||
!(dev_link->flags & DL_FLAG_CYCLE))
|
||||
continue;
|
||||
|
||||
if (__fw_devlink_relax_cycles(con,
|
||||
if (__fw_devlink_relax_cycles(con_handle,
|
||||
dev_link->supplier->fwnode)) {
|
||||
pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
|
||||
dev_link->supplier->fwnode);
|
||||
fw_devlink_relax_link(dev_link);
|
||||
dev_link->flags |= DL_FLAG_CYCLE;
|
||||
ret = true;
|
||||
@@ -2045,10 +2055,8 @@ static int fw_devlink_create_devlink(struct device *con,
|
||||
int ret = 0;
|
||||
u32 flags;
|
||||
|
||||
if (con->fwnode == link->consumer)
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
else
|
||||
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
|
||||
if (link->flags & FWLINK_FLAG_IGNORE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* SYNC_STATE_ONLY device links don't block probing and supports cycles.
|
||||
* So, one might expect that cycle detection isn't necessary for them.
|
||||
* However, if the device link was marked as SYNC_STATE_ONLY because
|
||||
* 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.
|
||||
* Don't try to optimize by not calling the cycle detection logic under
|
||||
* certain conditions. There's always some corner case that won't get
|
||||
* detected.
|
||||
*/
|
||||
if (!device_link_flag_is_sync_state_only(flags) ||
|
||||
flags & DL_FLAG_CYCLE) {
|
||||
device_links_write_lock();
|
||||
if (__fw_devlink_relax_cycles(con, sup_handle)) {
|
||||
__fwnode_link_cycle(link);
|
||||
flags = fw_devlink_get_flags(link->flags);
|
||||
dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
|
||||
sup_handle);
|
||||
}
|
||||
device_links_write_unlock();
|
||||
device_links_write_lock();
|
||||
if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) {
|
||||
__fwnode_link_cycle(link);
|
||||
pr_debug("----- cycle: end -----\n");
|
||||
pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n",
|
||||
link->consumer, sup_handle);
|
||||
}
|
||||
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)
|
||||
sup_dev = fwnode_get_next_parent_dev(sup_handle);
|
||||
|
||||
@@ -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
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
unsigned int count = 0;
|
||||
|
||||
@@ -652,6 +652,17 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
|
||||
}
|
||||
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,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
@@ -1502,6 +1513,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
|
||||
{
|
||||
int ret;
|
||||
|
||||
regmap_detach_dev(map->dev, map);
|
||||
regcache_exit(map);
|
||||
regmap_debugfs_exit(map);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/dma-fence-chain.h>
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
/* Internal helper to start new array iteration, don't use directly */
|
||||
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);
|
||||
|
||||
|
||||
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 */
|
||||
struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_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 *tmp, **array;
|
||||
ktime_t timestamp;
|
||||
unsigned int i;
|
||||
size_t count;
|
||||
int i, j, count;
|
||||
|
||||
count = 0;
|
||||
timestamp = ns_to_ktime(0);
|
||||
@@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
|
||||
if (!array)
|
||||
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;
|
||||
do {
|
||||
unsigned int sel;
|
||||
|
||||
restart:
|
||||
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;
|
||||
for (i = 0; i < num_fences; ++i) {
|
||||
dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
|
||||
if (!dma_fence_is_signaled(tmp)) {
|
||||
array[count++] = dma_fence_get(tmp);
|
||||
} else {
|
||||
fences[sel] = dma_fence_unwrap_next(&iter[sel]);
|
||||
goto restart;
|
||||
ktime_t t = dma_fence_timestamp(tmp);
|
||||
|
||||
if (ktime_after(t, timestamp))
|
||||
timestamp = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp) {
|
||||
array[count++] = dma_fence_get(tmp);
|
||||
fences[sel] = dma_fence_unwrap_next(&iter[sel]);
|
||||
if (count == 0 || count == 1)
|
||||
goto return_fastpath;
|
||||
|
||||
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);
|
||||
|
||||
if (count == 0) {
|
||||
tmp = dma_fence_allocate_private_stub(ktime_get());
|
||||
goto return_tmp;
|
||||
return &result->base;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
return_fastpath:
|
||||
if (count == 0)
|
||||
tmp = dma_fence_allocate_private_stub(timestamp);
|
||||
else
|
||||
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:
|
||||
kfree(array);
|
||||
|
||||
@@ -31,13 +31,15 @@
|
||||
static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev,
|
||||
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,
|
||||
0);
|
||||
else
|
||||
RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2);
|
||||
} else {
|
||||
amdgpu_ring_emit_wreg(ring,
|
||||
(adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev,
|
||||
|
||||
@@ -2560,10 +2560,10 @@ static int it6505_poweron(struct it6505 *it6505)
|
||||
/* time interval between OVDD and SYSRSTN at least be 10ms */
|
||||
if (pdata->gpiod_reset) {
|
||||
usleep_range(10000, 20000);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
|
||||
usleep_range(1000, 2000);
|
||||
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;
|
||||
@@ -2589,7 +2589,7 @@ static int it6505_poweroff(struct it6505 *it6505)
|
||||
}
|
||||
|
||||
if (pdata->gpiod_reset)
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
|
||||
gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
|
||||
|
||||
if (pdata->pwr18) {
|
||||
err = regulator_disable(pdata->pwr18);
|
||||
@@ -3050,7 +3050,7 @@ static int it6505_init_pdata(struct it6505 *it6505)
|
||||
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)) {
|
||||
dev_err(dev, "gpiod_reset gpio not found");
|
||||
return PTR_ERR(pdata->gpiod_reset);
|
||||
|
||||
@@ -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->path_msg = (buf[idx] >> 6) & 0x1;
|
||||
hdr->msg_len = buf[idx] & 0x3f;
|
||||
if (hdr->msg_len < 1) /* min space for body CRC */
|
||||
return false;
|
||||
|
||||
idx++;
|
||||
hdr->somt = (buf[idx] >> 7) & 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;
|
||||
mgr->payload_id_table_cleared = false;
|
||||
|
||||
memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv));
|
||||
memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv));
|
||||
mgr->reset_rx_state = true;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
@@ -3781,6 +3783,11 @@ out_fail:
|
||||
}
|
||||
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
|
||||
drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (!verify_rx_request_type(mgr, txmsg, msg))
|
||||
goto out_clear_reply;
|
||||
|
||||
drm_dp_sideband_parse_reply(mgr, msg, &txmsg->reply);
|
||||
|
||||
if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
|
||||
@@ -4063,6 +4101,17 @@ out:
|
||||
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
|
||||
* @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;
|
||||
}
|
||||
|
||||
update_msg_rx_state(mgr);
|
||||
|
||||
if (esi[1] & DP_DOWN_REP_MSG_RDY) {
|
||||
ret = drm_dp_mst_handle_down_rep(mgr);
|
||||
*handled = true;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_EN, 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_V4_PCTR_0_EN, mask);
|
||||
|
||||
v3d->active_perfmon = perfmon;
|
||||
}
|
||||
|
||||
@@ -2234,7 +2234,8 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
|
||||
if (hid_is_usb(wacom->hdev)) {
|
||||
struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
|
||||
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) {
|
||||
|
||||
@@ -341,10 +341,10 @@ struct bus_type i3c_bus_type = {
|
||||
};
|
||||
|
||||
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;
|
||||
int bitpos = addr * 2;
|
||||
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
|
||||
|
||||
if (addr > I2C_MAX_ADDR)
|
||||
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 >>= 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,
|
||||
enum i3c_addr_slot_status status)
|
||||
static enum i3c_addr_slot_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;
|
||||
|
||||
if (addr > I2C_MAX_ADDR)
|
||||
return;
|
||||
|
||||
ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
|
||||
*ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
|
||||
(bitpos % BITS_PER_LONG));
|
||||
*ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
|
||||
*ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
|
||||
*ptr |= ((unsigned long)status & mask) << (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)
|
||||
@@ -379,13 +390,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
|
||||
return status == I3C_ADDR_SLOT_FREE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ┌────┬─────────────┬───┬─────────┬───┐
|
||||
* │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐
|
||||
* └────┴─────────────┴───┴─────────┴───┘ │
|
||||
* ┌─────────────────────────────────────────┘
|
||||
* │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐
|
||||
* └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ 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)
|
||||
{
|
||||
enum i3c_addr_slot_status status;
|
||||
u8 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)
|
||||
return addr;
|
||||
}
|
||||
@@ -514,6 +556,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
|
||||
}
|
||||
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[] = {
|
||||
&dev_attr_mode.attr,
|
||||
&dev_attr_current_master.attr,
|
||||
@@ -524,6 +648,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
|
||||
&dev_attr_pid.attr,
|
||||
&dev_attr_dynamic_address.attr,
|
||||
&dev_attr_hdrcap.attr,
|
||||
&dev_attr_hotjoin.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(i3c_masterdev);
|
||||
@@ -1366,16 +1491,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
|
||||
u8 old_dyn_addr)
|
||||
{
|
||||
struct i3c_master_controller *master = i3c_dev_get_master(dev);
|
||||
enum i3c_addr_slot_status status;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
if (dev->info.dyn_addr != old_dyn_addr) {
|
||||
i3c_bus_set_addr_slot_status(&master->bus,
|
||||
dev->info.dyn_addr,
|
||||
I3C_ADDR_SLOT_I3C_DEV);
|
||||
@@ -1727,6 +1845,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
|
||||
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
|
||||
* (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)
|
||||
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. */
|
||||
ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
|
||||
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;
|
||||
}
|
||||
|
||||
i3c_bus_set_addr_slot_status(&master->bus,
|
||||
i3cboardinfo->init_dyn_addr,
|
||||
I3C_ADDR_SLOT_I3C_DEV);
|
||||
/* Do not mark as occupied until real device exist in bus */
|
||||
i3c_bus_set_addr_slot_status_mask(&master->bus,
|
||||
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
|
||||
@@ -1930,7 +2062,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
|
||||
else
|
||||
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
|
||||
* 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
|
||||
*
|
||||
* 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_unregister_i3c_devs(master);
|
||||
i3c_master_bus_cleanup(master);
|
||||
device_unregister(&master->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_master_unregister);
|
||||
|
||||
|
||||
@@ -1184,11 +1184,8 @@ err_disable_core_clk:
|
||||
static int dw_i3c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i3c_master *master = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = i3c_master_unregister(&master->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
i3c_master_unregister(&master->base);
|
||||
|
||||
reset_control_assert(master->core_rst);
|
||||
|
||||
|
||||
@@ -1666,11 +1666,8 @@ err_disable_pclk:
|
||||
static int cdns_i3c_master_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_i3c_master *master = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = i3c_master_unregister(&master->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
i3c_master_unregister(&master->base);
|
||||
|
||||
clk_disable_unprepare(master->sysclk);
|
||||
clk_disable_unprepare(master->pclk);
|
||||
|
||||
@@ -769,7 +769,9 @@ static int i3c_hci_remove(struct platform_device *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[] = {
|
||||
|
||||
@@ -128,6 +128,9 @@
|
||||
/* This parameter depends on the implementation and may be tuned */
|
||||
#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 {
|
||||
u8 addr;
|
||||
bool rnw;
|
||||
@@ -171,6 +174,8 @@ struct svc_i3c_xfer {
|
||||
* @ibi.tbq_slot: To be queued IBI slot
|
||||
* @ibi.lock: IBI lock
|
||||
* @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 i3c_master_controller base;
|
||||
@@ -199,6 +204,8 @@ struct svc_i3c_master {
|
||||
spinlock_t lock;
|
||||
} ibi;
|
||||
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;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
u32 mstatus, merrwarn;
|
||||
@@ -432,13 +444,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
||||
switch (ibitype) {
|
||||
case SVC_I3C_MSTATUS_IBITYPE_IBI:
|
||||
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);
|
||||
else
|
||||
svc_i3c_master_handle_ibi(master, dev);
|
||||
break;
|
||||
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;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
|
||||
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);
|
||||
break;
|
||||
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;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
|
||||
default:
|
||||
@@ -506,6 +523,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
writel(reg, master->regs + SVC_I3C_MCONFIG);
|
||||
|
||||
master->mctrl_config = reg;
|
||||
/* Master core's registration */
|
||||
ret = i3c_master_get_free_addr(m, 0);
|
||||
if (ret < 0)
|
||||
@@ -1475,6 +1541,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
master->enabled_events++;
|
||||
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -1496,6 +1565,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
|
||||
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,
|
||||
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,
|
||||
.enable_ibi = svc_i3c_master_enable_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)
|
||||
@@ -1651,11 +1756,8 @@ err_disable_clks:
|
||||
static int svc_i3c_master_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct svc_i3c_master *master = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = i3c_master_unregister(&master->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
i3c_master_unregister(&master->base);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
@@ -372,6 +372,7 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y
|
||||
u8 data[8];
|
||||
u16 xy1y2[3];
|
||||
s32 h[3], s[3];
|
||||
int half_range = BIT(13);
|
||||
int i, ret;
|
||||
|
||||
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 */
|
||||
if (yas5xx->version == YAS537_VERSION_1) {
|
||||
for (i = 0; i < 3; i++)
|
||||
s[i] = xy1y2[i] - BIT(13);
|
||||
h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13);
|
||||
h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13);
|
||||
h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13);
|
||||
s[i] = xy1y2[i] - half_range;
|
||||
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])) / half_range;
|
||||
h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / half_range;
|
||||
for (i = 0; i < 3; i++) {
|
||||
clamp_val(h[i], -BIT(13), BIT(13) - 1);
|
||||
xy1y2[i] = h[i] + BIT(13);
|
||||
h[i] = clamp(h[i], -half_range, half_range - 1);
|
||||
xy1y2[i] = h[i] + half_range;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1363,6 +1363,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
|
||||
goto out_free;
|
||||
} else if (fwspec && fwspec->ops == &arm_smmu_ops) {
|
||||
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 {
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
@@ -797,7 +797,6 @@ static void mt6360_v4l2_flash_release(struct mt6360_priv *priv)
|
||||
static int mt6360_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mt6360_priv *priv;
|
||||
struct fwnode_handle *child;
|
||||
size_t count;
|
||||
int i = 0, ret;
|
||||
|
||||
@@ -824,7 +823,7 @@ static int mt6360_led_probe(struct platform_device *pdev)
|
||||
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 led_init_data init_data = { .fwnode = child, };
|
||||
u32 reg, led_color;
|
||||
|
||||
@@ -1726,7 +1726,7 @@ static void cache_set_flush(struct closure *cl)
|
||||
if (!IS_ERR_OR_NULL(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);
|
||||
|
||||
/*
|
||||
|
||||
@@ -994,6 +994,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
struct usb_device_id cx231xx_id_table[] = {
|
||||
{USB_DEVICE(0x1D19, 0x6108),
|
||||
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
|
||||
{USB_DEVICE(0x1D19, 0x6109),
|
||||
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
|
||||
{USB_DEVICE(0x0572, 0x5A3C),
|
||||
|
||||
@@ -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
|
||||
* VENDOR_SPEC because they don't announce themselves as UVC devices, even
|
||||
* though they are compliant.
|
||||
*
|
||||
* Sort these by vendor/product ID.
|
||||
*/
|
||||
static const struct usb_device_id uvc_ids[] = {
|
||||
/* Quanta USB2.0 HD UVC Webcam */
|
||||
@@ -2983,6 +2985,15 @@ static const struct usb_device_id uvc_ids[] = {
|
||||
.bInterfaceProtocol = 0,
|
||||
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
|
||||
| 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 */
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
||||
| USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
|
||||
@@ -149,6 +149,8 @@ static void mmc_bus_shutdown(struct device *dev)
|
||||
if (dev->driver && drv->shutdown)
|
||||
drv->shutdown(card);
|
||||
|
||||
__mmc_stop_host(host);
|
||||
|
||||
if (host->bus_ops->shutdown) {
|
||||
ret = host->bus_ops->shutdown(host);
|
||||
if (ret)
|
||||
|
||||
@@ -82,6 +82,7 @@ struct mmc_fixup {
|
||||
#define CID_MANFID_SANDISK_SD 0x3
|
||||
#define CID_MANFID_ATP 0x9
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_GIGASTONE 0x12
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
#define CID_MANFID_SAMSUNG 0x15
|
||||
#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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -2297,6 +2297,9 @@ void mmc_start_host(struct mmc_host *host)
|
||||
|
||||
void __mmc_stop_host(struct mmc_host *host)
|
||||
{
|
||||
if (host->rescan_disable)
|
||||
return;
|
||||
|
||||
if (host->slot.cd_irq >= 0) {
|
||||
mmc_gpio_set_cd_wake(host, false);
|
||||
disable_irq(host->slot.cd_irq);
|
||||
|
||||
@@ -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,
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Power Sustenance support at bit 5. */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_qos.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),
|
||||
};
|
||||
|
||||
/* 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 = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.resume = byt_resume,
|
||||
@@ -1257,6 +1281,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||
.add_host = byt_add_host,
|
||||
.remove_slot = byt_remove_slot,
|
||||
.ops = &sdhci_intel_byt_ops,
|
||||
.cd_gpio_override = sdhci_intel_byt_cd_gpio_override,
|
||||
.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(
|
||||
struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
|
||||
int slotno)
|
||||
@@ -2111,8 +2172,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
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,
|
||||
slot->cd_override_level, 0);
|
||||
|
||||
sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table);
|
||||
|
||||
if (ret && ret != -EPROBE_DEFER)
|
||||
ret = mmc_gpiod_request_cd(host->mmc, NULL,
|
||||
slot->cd_idx,
|
||||
|
||||
@@ -151,6 +151,7 @@ struct sdhci_pci_fixes {
|
||||
#endif
|
||||
|
||||
const struct sdhci_ops *ops;
|
||||
const struct dmi_system_id *cd_gpio_override;
|
||||
size_t priv_size;
|
||||
};
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@ static int can_set_termination(struct net_device *ndev, u16 term)
|
||||
else
|
||||
set = 0;
|
||||
|
||||
gpiod_set_value(priv->termination_gpio, set);
|
||||
gpiod_set_value_cansleep(priv->termination_gpio, set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta)
|
||||
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
|
||||
mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
|
||||
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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
|
||||
if (type == SECONDARY_INTERFACE && epf->sec_epc)
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&epc->lock);
|
||||
mutex_lock(&epc->list_lock);
|
||||
func_no = find_first_zero_bit(&epc->function_num_map,
|
||||
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);
|
||||
ret:
|
||||
mutex_unlock(&epc->lock);
|
||||
mutex_unlock(&epc->list_lock);
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
mutex_lock(&epc->list_lock);
|
||||
if (type == PRIMARY_INTERFACE) {
|
||||
func_no = epf->func_no;
|
||||
list = &epf->list;
|
||||
epf->epc = NULL;
|
||||
} else {
|
||||
func_no = epf->sec_epc_func_no;
|
||||
list = &epf->sec_epc_list;
|
||||
epf->sec_epc = NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&epc->lock);
|
||||
clear_bit(func_no, &epc->function_num_map);
|
||||
list_del(list);
|
||||
epf->epc = NULL;
|
||||
mutex_unlock(&epc->lock);
|
||||
mutex_unlock(&epc->list_lock);
|
||||
}
|
||||
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->list_lock);
|
||||
INIT_LIST_HEAD(&epc->pci_epf);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);
|
||||
|
||||
|
||||
@@ -3312,6 +3312,7 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
|
||||
.show_host_node_name = 1,
|
||||
.show_host_port_name = 1,
|
||||
.show_host_supported_classes = 1,
|
||||
.show_host_supported_speeds = 1,
|
||||
|
||||
.get_host_port_id = qla2x00_get_host_port_id,
|
||||
.show_host_port_id = 1,
|
||||
|
||||
@@ -24,6 +24,7 @@ void qla2x00_bsg_job_done(srb_t *sp, int res)
|
||||
{
|
||||
struct bsg_job *bsg_job = sp->u.bsg_job;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct completion *comp = sp->comp;
|
||||
|
||||
ql_dbg(ql_dbg_user, sp->vha, 0x7009,
|
||||
"%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_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
if (comp)
|
||||
complete(comp);
|
||||
}
|
||||
|
||||
void qla2x00_bsg_sp_free(srb_t *sp)
|
||||
@@ -490,16 +494,6 @@ qla2x00_process_ct(struct bsg_job *bsg_job)
|
||||
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) {
|
||||
ql_log(ql_log_warn, vha, 0x7012,
|
||||
"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)
|
||||
{
|
||||
bool found = false;
|
||||
bool found, do_bsg_done;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
|
||||
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;
|
||||
unsigned long flags;
|
||||
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);
|
||||
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_NOLOGIN) &&
|
||||
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;
|
||||
goto done;
|
||||
sp->comp = ∁
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||
|
||||
done:
|
||||
return found;
|
||||
if (!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
|
||||
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));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int i;
|
||||
struct qla_qpair *qpair;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n",
|
||||
__func__, bsg_job);
|
||||
ql_log(ql_log_info, vha, 0x708b,
|
||||
"%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)) {
|
||||
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");
|
||||
bsg_reply->result = -ENXIO;
|
||||
|
||||
done:
|
||||
return 0;
|
||||
|
||||
@@ -515,6 +515,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
vha->irq_offset = QLA_BASE_VECTORS;
|
||||
host = vha->host;
|
||||
fc_vport->dd_data = vha;
|
||||
/* New host info */
|
||||
|
||||
@@ -6883,12 +6883,15 @@ qla2x00_do_dpc(void *data)
|
||||
set_user_nice(current, MIN_NICE);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (!kthread_should_stop()) {
|
||||
while (1) {
|
||||
ql_dbg(ql_dbg_dpc, base_vha, 0x4000,
|
||||
"DPC handler sleeping.\n");
|
||||
|
||||
schedule();
|
||||
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags))
|
||||
qla_pci_set_eeh_busy(base_vha);
|
||||
|
||||
@@ -6901,15 +6904,16 @@ qla2x00_do_dpc(void *data)
|
||||
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;
|
||||
|
||||
ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001,
|
||||
"DPC handler waking up, dpc_flags=0x%lx.\n",
|
||||
base_vha->dpc_flags);
|
||||
|
||||
if (test_bit(UNLOADING, &base_vha->dpc_flags))
|
||||
break;
|
||||
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
if (IS_QLA8044(ha)) {
|
||||
if (test_and_clear_bit(ISP_UNRECOVERABLE,
|
||||
@@ -7227,9 +7231,6 @@ end_loop:
|
||||
*/
|
||||
ha->dpc_active = 0;
|
||||
|
||||
/* Cleanup any residual CTX SRBs. */
|
||||
qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5673,7 +5673,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
|
||||
if (sdebug_host_max_queue)
|
||||
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();
|
||||
|
||||
/* one of the resp_*() response functions is called here */
|
||||
|
||||
@@ -519,6 +519,7 @@ static int mpc52xx_spi_remove(struct platform_device *op)
|
||||
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&ms->work);
|
||||
free_irq(ms->irq0, ms);
|
||||
free_irq(ms->irq1, ms);
|
||||
|
||||
|
||||
@@ -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_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]),
|
||||
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_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]),
|
||||
m->nr_req[WRITE]));
|
||||
}
|
||||
|
||||
@@ -4633,9 +4633,6 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
|
||||
dev_err(hba->dev,
|
||||
"%s: power mode change failed %d\n", __func__, ret);
|
||||
} else {
|
||||
ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
|
||||
pwr_mode);
|
||||
|
||||
memcpy(&hba->pwr_info, pwr_mode,
|
||||
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);
|
||||
|
||||
if (!ret)
|
||||
ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
|
||||
&final_params);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
#define MAX_HW_ERROR 250
|
||||
|
||||
static int heartbeat = DEFAULT_HEARTBEAT;
|
||||
static int heartbeat;
|
||||
|
||||
/*
|
||||
* 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->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
|
||||
wdt->freq * 1000;
|
||||
wdd->timeout = DEFAULT_HEARTBEAT;
|
||||
wdd->parent = dev;
|
||||
|
||||
watchdog_set_drvdata(wdd, wdt);
|
||||
|
||||
@@ -671,6 +671,42 @@ u8 *btrfs_sb_fsid_ptr(struct btrfs_super_block *sb)
|
||||
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
|
||||
* 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,
|
||||
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.
|
||||
* 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);
|
||||
|
||||
if (seeding_dev) {
|
||||
btrfs_clear_sb_rdonly(sb);
|
||||
|
||||
/* GFP_KERNEL allocation must not be under device_list_mutex */
|
||||
seed_devices = btrfs_init_sprout(fs_info);
|
||||
if (IS_ERR(seed_devices)) {
|
||||
@@ -2875,8 +2909,6 @@ error_sysfs:
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||
error_trans:
|
||||
if (seeding_dev)
|
||||
btrfs_set_sb_rdonly(sb);
|
||||
if (trans)
|
||||
btrfs_end_transaction(trans);
|
||||
error_free_zone:
|
||||
|
||||
@@ -743,7 +743,8 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
to_free = NULL;
|
||||
head = file->f_ep;
|
||||
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)) {
|
||||
struct epitems_head *v;
|
||||
v = container_of(head, struct epitems_head, epitems);
|
||||
@@ -1513,7 +1514,8 @@ allocate:
|
||||
spin_unlock(&file->f_lock);
|
||||
goto allocate;
|
||||
}
|
||||
file->f_ep = head;
|
||||
/* See eventpoll_release() for details. */
|
||||
WRITE_ONCE(file->f_ep, head);
|
||||
to_free = NULL;
|
||||
}
|
||||
hlist_add_head_rcu(&epi->fllink, file->f_ep);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
unsigned int last_byte = inode->i_size;
|
||||
u64 last_byte = inode->i_size;
|
||||
|
||||
last_byte -= page_nr << PAGE_SHIFT;
|
||||
if (last_byte > PAGE_SIZE)
|
||||
|
||||
@@ -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 *dummy = &priv->p_iter_res;
|
||||
|
||||
(*pos)++;
|
||||
spin_lock(&ocfs2_dlm_tracking_lock);
|
||||
iter = ocfs2_dlm_next_res(iter, priv);
|
||||
list_del_init(&dummy->l_debug_list);
|
||||
|
||||
@@ -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);
|
||||
inode_init_owner(&init_user_ns, inode, dir, mode);
|
||||
status = dquot_initialize(inode);
|
||||
if (status)
|
||||
if (status) {
|
||||
iput(inode);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
@@ -6370,6 +6370,10 @@ int smb2_read(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
offset = le64_to_cpu(req->Offset);
|
||||
if (offset < 0) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
length = le32_to_cpu(req->Length);
|
||||
mincount = le32_to_cpu(req->MinimumCount);
|
||||
|
||||
@@ -6583,6 +6587,8 @@ int smb2_write(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
offset = le64_to_cpu(req->Offset);
|
||||
if (offset < 0)
|
||||
return -EINVAL;
|
||||
length = le32_to_cpu(req->Length);
|
||||
|
||||
if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||
|
||||
|
||||
@@ -694,6 +694,13 @@ struct drm_dp_mst_topology_mgr {
|
||||
*/
|
||||
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
|
||||
* intended to be used internally by MST helpers for payload tracking, and is only safe to
|
||||
|
||||
@@ -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
|
||||
* eventpoll ) has still a reference to this file.
|
||||
*/
|
||||
if (likely(!file->f_ep))
|
||||
if (likely(!READ_ONCE(file->f_ep)))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
||||
@@ -53,8 +53,10 @@ struct fwnode_handle {
|
||||
* fwnode link flags
|
||||
*
|
||||
* 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_IGNORE BIT(1)
|
||||
|
||||
struct fwnode_link {
|
||||
struct fwnode_handle *supplier;
|
||||
|
||||
@@ -268,6 +268,20 @@ enum i3c_bus_mode {
|
||||
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
|
||||
* @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_I3C_DEV: address is assigned to an I3C device
|
||||
* @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
|
||||
* 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_I3C_DEV,
|
||||
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
|
||||
* @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_dev_desc *cur_master;
|
||||
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;
|
||||
struct {
|
||||
unsigned long i3c;
|
||||
@@ -425,6 +444,9 @@ struct i3c_bus {
|
||||
* for a future IBI
|
||||
* This method is mandatory only if ->request_ibi is not
|
||||
* 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 {
|
||||
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);
|
||||
void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
|
||||
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
|
||||
* @secondary: true if the master is a secondary master
|
||||
* @init_done: true when the bus initialization is done
|
||||
* @hotjoin: true if the master support hotjoin
|
||||
* @boardinfo.i3c: list of I3C boardinfo objects
|
||||
* @boardinfo.i2c: list of I2C boardinfo objects
|
||||
* @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;
|
||||
unsigned int secondary : 1;
|
||||
unsigned int init_done : 1;
|
||||
unsigned int hotjoin: 1;
|
||||
struct {
|
||||
struct list_head i3c;
|
||||
struct list_head i2c;
|
||||
@@ -541,7 +568,9 @@ int i3c_master_register(struct i3c_master_controller *master,
|
||||
struct device *parent,
|
||||
const struct i3c_master_controller_ops *ops,
|
||||
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
|
||||
|
||||
@@ -298,6 +298,8 @@ struct mmc_card {
|
||||
#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_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 */
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ struct pci_epc_mem {
|
||||
* struct pci_epc - represents the PCI EPC device
|
||||
* @dev: PCI 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
|
||||
* @windows: array of address space of the endpoint controller
|
||||
* @mem: first window of the endpoint controller, which corresponds to
|
||||
@@ -139,6 +140,7 @@ struct pci_epc_mem {
|
||||
struct pci_epc {
|
||||
struct device dev;
|
||||
struct list_head pci_epf;
|
||||
struct mutex list_lock;
|
||||
const struct pci_epc_ops *ops;
|
||||
struct pci_epc_mem **windows;
|
||||
struct pci_epc_mem *mem;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define _LINUX_PROPERTY_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/fwnode.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;\
|
||||
child = fwnode_get_next_available_child_node(fwnode, child))
|
||||
|
||||
struct fwnode_handle *device_get_next_child_node(
|
||||
struct device *dev, struct fwnode_handle *child);
|
||||
struct fwnode_handle *device_get_next_child_node(const struct device *dev,
|
||||
struct fwnode_handle *child);
|
||||
|
||||
#define device_for_each_child_node(dev, child) \
|
||||
for (child = 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(struct device *dev,
|
||||
#define device_for_each_child_node_scoped(dev, child) \
|
||||
for (struct fwnode_handle *child __free(fwnode_handle) = \
|
||||
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);
|
||||
|
||||
struct fwnode_handle *fwnode_handle_get(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_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,
|
||||
const char *propname)
|
||||
|
||||
@@ -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
|
||||
*
|
||||
* Description:
|
||||
|
||||
@@ -287,7 +287,9 @@ struct ufs_pwr_mode_info {
|
||||
* to allow variant specific Uni-Pro initialization.
|
||||
* @pwr_change_notify: called before and after a power mode change
|
||||
* 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
|
||||
* to set some things
|
||||
* @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 *,
|
||||
enum ufs_notify_change_status);
|
||||
int (*pwr_change_notify)(struct ufs_hba *,
|
||||
enum ufs_notify_change_status status,
|
||||
struct ufs_pa_layer_attr *,
|
||||
struct ufs_pa_layer_attr *);
|
||||
enum ufs_notify_change_status status,
|
||||
struct ufs_pa_layer_attr *desired_pwr_mode,
|
||||
struct ufs_pa_layer_attr *final_params);
|
||||
void (*setup_xfer_req)(struct ufs_hba *hba, int tag,
|
||||
bool is_scsi_cmd);
|
||||
void (*setup_task_mgmt)(struct ufs_hba *, int, u8);
|
||||
|
||||
@@ -184,7 +184,7 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
|
||||
static void dev_map_free(struct bpf_map *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,
|
||||
* 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_netdev *old_dev;
|
||||
int k = *(u32 *)key;
|
||||
u32 k = *(u32 *)key;
|
||||
|
||||
if (k >= map->max_entries)
|
||||
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_netdev *old_dev;
|
||||
int k = *(u32 *)key;
|
||||
u32 k = *(u32 *)key;
|
||||
unsigned long flags;
|
||||
int ret = -ENOENT;
|
||||
|
||||
|
||||
@@ -302,12 +302,22 @@ static struct lpm_trie_node *lpm_trie_node_alloc(const struct lpm_trie *trie,
|
||||
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 */
|
||||
static int trie_update_elem(struct bpf_map *map,
|
||||
void *_key, void *value, u64 flags)
|
||||
{
|
||||
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 __rcu **slot;
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
if (!new_node) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
trie->n_entries++;
|
||||
|
||||
new_node->prefixlen = key->prefixlen;
|
||||
RCU_INIT_POINTER(new_node->child[0], 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.
|
||||
*/
|
||||
if (!node) {
|
||||
ret = trie_check_add_elem(trie, flags);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
rcu_assign_pointer(*slot, new_node);
|
||||
goto out;
|
||||
}
|
||||
@@ -376,18 +382,30 @@ static int trie_update_elem(struct bpf_map *map,
|
||||
* which already has the correct data array set.
|
||||
*/
|
||||
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[1] = node->child[1];
|
||||
|
||||
if (!(node->flags & LPM_TREE_NODE_FLAG_IM))
|
||||
trie->n_entries--;
|
||||
|
||||
rcu_assign_pointer(*slot, new_node);
|
||||
free_node = node;
|
||||
|
||||
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
|
||||
* 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);
|
||||
if (!im_node) {
|
||||
trie->n_entries--;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@@ -421,14 +440,8 @@ static int trie_update_elem(struct bpf_map *map,
|
||||
rcu_assign_pointer(*slot, im_node);
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
if (new_node)
|
||||
trie->n_entries--;
|
||||
|
||||
if (ret)
|
||||
kfree(new_node);
|
||||
kfree(im_node);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&trie->lock, irq_flags);
|
||||
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;
|
||||
int err = 0, stack_ptr = -1;
|
||||
unsigned int next_bit;
|
||||
size_t matchlen;
|
||||
size_t matchlen = 0;
|
||||
|
||||
/* 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
|
||||
@@ -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);
|
||||
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))
|
||||
goto find_leftmost;
|
||||
|
||||
|
||||
@@ -46,14 +46,8 @@ static struct {
|
||||
int used; /* number of elements used */
|
||||
bool sorted; /* if elements are sorted */
|
||||
bool whitelist; /* if list is a blacklist or whitelist */
|
||||
} report_filterlist = {
|
||||
.addrs = NULL,
|
||||
.size = 8, /* small initial size */
|
||||
.used = 0,
|
||||
.sorted = false,
|
||||
.whitelist = false, /* default is blacklist */
|
||||
};
|
||||
static DEFINE_SPINLOCK(report_filterlist_lock);
|
||||
} report_filterlist;
|
||||
static DEFINE_RAW_SPINLOCK(report_filterlist_lock);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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)
|
||||
goto out;
|
||||
|
||||
@@ -127,7 +121,7 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
|
||||
ret = !ret;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&report_filterlist_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -135,9 +129,9 @@ static void set_report_filterlist_whitelist(bool whitelist)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&report_filterlist_lock, flags);
|
||||
raw_spin_lock_irqsave(&report_filterlist_lock, flags);
|
||||
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. */
|
||||
@@ -145,6 +139,9 @@ static ssize_t insert_report_filterlist(const char *func)
|
||||
{
|
||||
unsigned long flags;
|
||||
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;
|
||||
|
||||
if (!addr) {
|
||||
@@ -152,32 +149,33 @@ static ssize_t insert_report_filterlist(const char *func)
|
||||
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) {
|
||||
/* initial allocation */
|
||||
report_filterlist.addrs =
|
||||
kmalloc_array(report_filterlist.size,
|
||||
sizeof(unsigned long), GFP_ATOMIC);
|
||||
if (report_filterlist.addrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
} 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;
|
||||
raw_spin_lock_irqsave(&report_filterlist_lock, flags);
|
||||
if (report_filterlist.used == report_filterlist.size) {
|
||||
/* Check we pre-allocated enough, and retry if not. */
|
||||
if (report_filterlist.used >= new_size) {
|
||||
raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
|
||||
kfree(new_addrs); /* kfree(NULL) is safe */
|
||||
delay_free = new_addrs = NULL;
|
||||
goto retry_alloc;
|
||||
}
|
||||
|
||||
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.addrs = new_addrs;
|
||||
}
|
||||
|
||||
/* Note: deduplicating should be done in userspace. */
|
||||
@@ -185,9 +183,9 @@ static ssize_t insert_report_filterlist(const char *func)
|
||||
kallsyms_lookup_name(func);
|
||||
report_filterlist.sorted = false;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&report_filterlist_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
|
||||
|
||||
kfree(delay_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -204,13 +202,13 @@ static int show_info(struct seq_file *file, void *v)
|
||||
}
|
||||
|
||||
/* 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",
|
||||
report_filterlist.whitelist ? "whitelisted" : "blacklisted",
|
||||
report_filterlist.used == 0 ? "none" : "");
|
||||
for (i = 0; i < report_filterlist.used; ++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;
|
||||
}
|
||||
|
||||
@@ -796,7 +796,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
|
||||
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
|
||||
NTP_SCALE_SHIFT);
|
||||
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' */
|
||||
|
||||
@@ -845,15 +845,11 @@ int tracing_map_init(struct tracing_map *map)
|
||||
static int cmp_entries_dup(const void *A, const void *B)
|
||||
{
|
||||
const struct tracing_map_sort_entry *a, *b;
|
||||
int ret = 0;
|
||||
|
||||
a = *(const struct tracing_map_sort_entry **)A;
|
||||
b = *(const struct tracing_map_sort_entry **)B;
|
||||
|
||||
if (memcmp(a->key, b->key, a->elt->map->key_size))
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
return memcmp(a->key, b->key, a->elt->map->key_size);
|
||||
}
|
||||
|
||||
static int cmp_entries_sum(const void *A, const void *B)
|
||||
|
||||
@@ -199,6 +199,7 @@ static noinline void test_ ## name (struct kunit *test) \
|
||||
static noinline DO_NOTHING_TYPE_ ## which(var_type) \
|
||||
do_nothing_ ## name(var_type *ptr) \
|
||||
{ \
|
||||
OPTIMIZER_HIDE_VAR(ptr); \
|
||||
/* Will always be true, but compiler doesn't know. */ \
|
||||
if ((unsigned long)ptr > 0x2) \
|
||||
return DO_NOTHING_RETURN_ ## which(ptr); \
|
||||
|
||||
@@ -1441,12 +1441,27 @@ static __always_inline bool free_pages_prepare(struct page *page,
|
||||
int bad = 0;
|
||||
bool skip_kasan_poison = should_skip_kasan_poison(page, fpi_flags);
|
||||
bool init = want_init_on_free();
|
||||
struct folio *folio = page_folio(page);
|
||||
|
||||
VM_BUG_ON_PAGE(PageTail(page), page);
|
||||
|
||||
trace_mm_page_free(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) {
|
||||
/*
|
||||
* Do not let hwpoison pages hit pcplists/buddy
|
||||
|
||||
20
mm/swap.c
20
mm/swap.c
@@ -88,14 +88,6 @@ static void __page_cache_release(struct folio *folio)
|
||||
__folio_clear_lru_flags(folio);
|
||||
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)
|
||||
@@ -1042,18 +1034,6 @@ void release_pages(struct page **pages, int nr)
|
||||
__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);
|
||||
}
|
||||
if (lruvec)
|
||||
|
||||
@@ -424,7 +424,6 @@ more_data:
|
||||
cork = true;
|
||||
psock->cork = NULL;
|
||||
}
|
||||
sk_msg_return(sk, msg, tosend);
|
||||
release_sock(sk);
|
||||
|
||||
origsize = msg->sg.size;
|
||||
@@ -436,8 +435,9 @@ more_data:
|
||||
sock_put(sk_redir);
|
||||
|
||||
lock_sock(sk);
|
||||
sk_mem_uncharge(sk, sent);
|
||||
if (unlikely(ret < 0)) {
|
||||
int free = sk_msg_free_nocharge(sk, msg);
|
||||
int free = sk_msg_free(sk, msg);
|
||||
|
||||
if (!cork)
|
||||
*copied -= free;
|
||||
@@ -451,7 +451,7 @@ more_data:
|
||||
break;
|
||||
case __SK_DROP:
|
||||
default:
|
||||
sk_msg_free_partial(sk, msg, tosend);
|
||||
sk_msg_free(sk, msg);
|
||||
sk_msg_apply_bytes(psock, tosend);
|
||||
*copied -= (tosend + delta);
|
||||
return -EACCES;
|
||||
@@ -467,11 +467,8 @@ more_data:
|
||||
}
|
||||
if (msg &&
|
||||
msg->sg.data[msg->sg.start].page_link &&
|
||||
msg->sg.data[msg->sg.start].length) {
|
||||
if (eval == __SK_REDIRECT)
|
||||
sk_mem_charge(sk, tosend - sent);
|
||||
msg->sg.data[msg->sg.start].length)
|
||||
goto more_data;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -356,10 +356,9 @@ void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!refcount_dec_and_test(&dma_map->users))
|
||||
return;
|
||||
if (refcount_dec_and_test(&dma_map->users))
|
||||
__xp_dma_unmap(dma_map, attrs);
|
||||
|
||||
__xp_dma_unmap(dma_map, attrs);
|
||||
kvfree(pool->dma_pages);
|
||||
pool->dma_pages_cnt = 0;
|
||||
pool->dev = NULL;
|
||||
|
||||
@@ -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 xdp_sock __rcu **map_entry;
|
||||
struct xdp_sock *old_xs;
|
||||
int k = *(u32 *)key;
|
||||
u32 k = *(u32 *)key;
|
||||
|
||||
if (k >= map->max_entries)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -832,7 +832,7 @@ static void check_section(const char *modname, struct elf_info *elf,
|
||||
".ltext", ".ltext.*"
|
||||
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
|
||||
".fixup", ".entry.text", ".exception.text", \
|
||||
".coldtext", ".softirqentry.text"
|
||||
".coldtext", ".softirqentry.text", ".irqentry.text"
|
||||
|
||||
#define INIT_SECTIONS ".init.*"
|
||||
#define MEM_INIT_SECTIONS ".meminit.*"
|
||||
@@ -892,7 +892,7 @@ enum mismatch {
|
||||
struct sectioncheck {
|
||||
const char *fromsec[20];
|
||||
const char *bad_tosec[20];
|
||||
const char *good_tosec[20];
|
||||
const char *good_tosec[21];
|
||||
enum mismatch mismatch;
|
||||
void (*handler)(const char *modname, struct elf_info *elf,
|
||||
const struct sectioncheck* const mismatch,
|
||||
|
||||
@@ -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, 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, 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, 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),
|
||||
@@ -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, 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, 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(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
|
||||
|
||||
@@ -403,10 +403,15 @@ static int prepare_inbound_urb(struct snd_usb_endpoint *ep,
|
||||
static void notify_xrun(struct snd_usb_endpoint *ep)
|
||||
{
|
||||
struct snd_usb_substream *data_subs;
|
||||
struct snd_pcm_substream *psubs;
|
||||
|
||||
data_subs = READ_ONCE(ep->data_subs);
|
||||
if (data_subs && data_subs->pcm_substream)
|
||||
snd_pcm_stop_xrun(data_subs->pcm_substream);
|
||||
if (!data_subs)
|
||||
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 *
|
||||
@@ -557,7 +562,10 @@ static void snd_complete_urb(struct urb *urb)
|
||||
push_back_to_ready_list(ep, ctx);
|
||||
clear_bit(ctx->index, &ep->active_mask);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -621,6 +621,16 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
.id = USB_ID(0x1b1c, 0x0a42),
|
||||
.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) */
|
||||
.id = USB_ID(0x0414, 0xa001),
|
||||
.map = aorus_master_alc1220vb_map,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <bfd.h>
|
||||
@@ -29,14 +28,18 @@
|
||||
#include "json_writer.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";
|
||||
ssize_t len;
|
||||
|
||||
len = readlink(path, tpath, size - 1);
|
||||
assert(len > 0);
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
tpath[len] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oper_count;
|
||||
@@ -97,30 +100,39 @@ static int fprintf_json_styled(void *out,
|
||||
return r;
|
||||
}
|
||||
|
||||
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum)
|
||||
int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum)
|
||||
{
|
||||
const struct bpf_line_info *linfo = NULL;
|
||||
disassembler_ftype disassemble;
|
||||
int count, i, pc = 0, err = -1;
|
||||
struct disassemble_info info;
|
||||
unsigned int nr_skip = 0;
|
||||
int count, i, pc = 0;
|
||||
char tpath[PATH_MAX];
|
||||
bfd *bfdf;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
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);
|
||||
assert(bfdf);
|
||||
assert(bfd_check_format(bfdf, bfd_object));
|
||||
if (!bfdf) {
|
||||
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)
|
||||
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;
|
||||
} else {
|
||||
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
|
||||
disassemble = disassembler(bfdf);
|
||||
#endif
|
||||
assert(disassemble);
|
||||
if (!disassemble) {
|
||||
p_err("failed to create disassembler");
|
||||
goto exit_close;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_start_array(json_wtr);
|
||||
@@ -224,7 +239,11 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
if (json_output)
|
||||
jsonw_end_array(json_wtr);
|
||||
|
||||
err = 0;
|
||||
|
||||
exit_close:
|
||||
bfd_close(bfdf);
|
||||
return err;
|
||||
}
|
||||
|
||||
int disasm_init(void)
|
||||
|
||||
@@ -173,22 +173,23 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
|
||||
|
||||
struct bpf_prog_linfo;
|
||||
#ifdef HAVE_LIBBFD_SUPPORT
|
||||
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum);
|
||||
int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum);
|
||||
int disasm_init(void);
|
||||
#else
|
||||
static inline
|
||||
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum)
|
||||
int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
||||
const char *arch, const char *disassembler_options,
|
||||
const struct btf *btf,
|
||||
const struct bpf_prog_linfo *prog_linfo,
|
||||
__u64 func_ksym, unsigned int func_idx,
|
||||
bool linum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int disasm_init(void)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
@@ -820,10 +820,18 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
|
||||
printf("%s:\n", sym_name);
|
||||
}
|
||||
|
||||
disasm_print_insn(img, lens[i], opcodes,
|
||||
name, disasm_opt, btf,
|
||||
prog_linfo, ksyms[i], i,
|
||||
linum);
|
||||
if (ksyms) {
|
||||
if (disasm_print_insn(img, lens[i], opcodes,
|
||||
name, disasm_opt, btf,
|
||||
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];
|
||||
|
||||
@@ -836,8 +844,10 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
|
||||
if (json_output)
|
||||
jsonw_end_array(json_wtr);
|
||||
} else {
|
||||
disasm_print_insn(buf, member_len, opcodes, name,
|
||||
disasm_opt, btf, NULL, 0, 0, false);
|
||||
if (disasm_print_insn(buf, member_len, opcodes, name,
|
||||
disasm_opt, btf, NULL, 0, 0,
|
||||
false))
|
||||
goto exit_free;
|
||||
}
|
||||
} else if (visual) {
|
||||
if (json_output)
|
||||
|
||||
@@ -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/riscv.*/riscv/)
|
||||
|
||||
ifndef ARCH
|
||||
ARCH := $(HOSTARCH)
|
||||
ifeq ($(strip $(ARCH)),)
|
||||
override ARCH := $(HOSTARCH)
|
||||
endif
|
||||
|
||||
SRCARCH := $(ARCH)
|
||||
|
||||
@@ -182,6 +182,9 @@ int exec_sign_all(struct signatures *signed_vals, size_t val)
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(new_stdin[1]);
|
||||
close(new_stdout[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user