Merge dd5a440a31 ("Linux 6.9-rc7") into android-mainline
Steps on the way to v6.9 Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: Ic30d50c6a23037418a483f38695b20bd4e9fa898
This commit is contained in:
@@ -42,7 +42,7 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: maxim,max30100
|
||||
const: maxim,max30102
|
||||
then:
|
||||
properties:
|
||||
maxim,green-led-current-microamp: false
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Hurr durr I'ma ninja sloth
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -44,9 +44,8 @@
|
||||
#define PLPKS_MAX_DATA_SIZE 4000
|
||||
|
||||
// Timeouts for PLPKS operations
|
||||
#define PLPKS_MAX_TIMEOUT 5000 // msec
|
||||
#define PLPKS_FLUSH_SLEEP 10 // msec
|
||||
#define PLPKS_FLUSH_SLEEP_RANGE 400
|
||||
#define PLPKS_MAX_TIMEOUT (5 * USEC_PER_SEC)
|
||||
#define PLPKS_FLUSH_SLEEP 10000 // usec
|
||||
|
||||
struct plpks_var {
|
||||
char *component;
|
||||
|
||||
@@ -786,8 +786,16 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
|
||||
* parent bus. During reboot, there will be ibm,dma-window property to
|
||||
* define DMA window. For kdump, there will at least be default window or DDW
|
||||
* or both.
|
||||
* There is an exception to the above. In case the PE goes into frozen
|
||||
* state, firmware may not provide ibm,dma-window property at the time
|
||||
* of LPAR boot up.
|
||||
*/
|
||||
|
||||
if (!pdn) {
|
||||
pr_debug(" no ibm,dma-window property !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ppci = PCI_DN(pdn);
|
||||
|
||||
pr_debug(" parent is %pOF, iommu_table: 0x%p\n",
|
||||
|
||||
@@ -415,8 +415,7 @@ static int plpks_confirm_object_flushed(struct label *label,
|
||||
break;
|
||||
}
|
||||
|
||||
usleep_range(PLPKS_FLUSH_SLEEP,
|
||||
PLPKS_FLUSH_SLEEP + PLPKS_FLUSH_SLEEP_RANGE);
|
||||
fsleep(PLPKS_FLUSH_SLEEP);
|
||||
timeout = timeout + PLPKS_FLUSH_SLEEP;
|
||||
} while (timeout < PLPKS_MAX_TIMEOUT);
|
||||
|
||||
@@ -464,9 +463,10 @@ int plpks_signed_update_var(struct plpks_var *var, u64 flags)
|
||||
|
||||
continuetoken = retbuf[0];
|
||||
if (pseries_status_to_err(rc) == -EBUSY) {
|
||||
int delay_ms = get_longbusy_msecs(rc);
|
||||
mdelay(delay_ms);
|
||||
timeout += delay_ms;
|
||||
int delay_us = get_longbusy_msecs(rc) * 1000;
|
||||
|
||||
fsleep(delay_us);
|
||||
timeout += delay_us;
|
||||
}
|
||||
rc = pseries_status_to_err(rc);
|
||||
} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
|
||||
|
||||
@@ -98,11 +98,6 @@ static int addr_to_vsyscall_nr(unsigned long addr)
|
||||
|
||||
static bool write_ok_or_segv(unsigned long ptr, size_t size)
|
||||
{
|
||||
/*
|
||||
* XXX: if access_ok, get_user, and put_user handled
|
||||
* sig_on_uaccess_err, this could go away.
|
||||
*/
|
||||
|
||||
if (!access_ok((void __user *)ptr, size)) {
|
||||
struct thread_struct *thread = ¤t->thread;
|
||||
|
||||
@@ -120,10 +115,8 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size)
|
||||
bool emulate_vsyscall(unsigned long error_code,
|
||||
struct pt_regs *regs, unsigned long address)
|
||||
{
|
||||
struct task_struct *tsk;
|
||||
unsigned long caller;
|
||||
int vsyscall_nr, syscall_nr, tmp;
|
||||
int prev_sig_on_uaccess_err;
|
||||
long ret;
|
||||
unsigned long orig_dx;
|
||||
|
||||
@@ -172,8 +165,6 @@ bool emulate_vsyscall(unsigned long error_code,
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
tsk = current;
|
||||
|
||||
/*
|
||||
* Check for access_ok violations and find the syscall nr.
|
||||
*
|
||||
@@ -234,12 +225,8 @@ bool emulate_vsyscall(unsigned long error_code,
|
||||
goto do_ret; /* skip requested */
|
||||
|
||||
/*
|
||||
* With a real vsyscall, page faults cause SIGSEGV. We want to
|
||||
* preserve that behavior to make writing exploits harder.
|
||||
* With a real vsyscall, page faults cause SIGSEGV.
|
||||
*/
|
||||
prev_sig_on_uaccess_err = current->thread.sig_on_uaccess_err;
|
||||
current->thread.sig_on_uaccess_err = 1;
|
||||
|
||||
ret = -EFAULT;
|
||||
switch (vsyscall_nr) {
|
||||
case 0:
|
||||
@@ -262,23 +249,12 @@ bool emulate_vsyscall(unsigned long error_code,
|
||||
break;
|
||||
}
|
||||
|
||||
current->thread.sig_on_uaccess_err = prev_sig_on_uaccess_err;
|
||||
|
||||
check_fault:
|
||||
if (ret == -EFAULT) {
|
||||
/* Bad news -- userspace fed a bad pointer to a vsyscall. */
|
||||
warn_bad_vsyscall(KERN_INFO, regs,
|
||||
"vsyscall fault (exploit attempt?)");
|
||||
|
||||
/*
|
||||
* If we failed to generate a signal for any reason,
|
||||
* generate one here. (This should be impossible.)
|
||||
*/
|
||||
if (WARN_ON_ONCE(!sigismember(&tsk->pending.signal, SIGBUS) &&
|
||||
!sigismember(&tsk->pending.signal, SIGSEGV)))
|
||||
goto sigsegv;
|
||||
|
||||
return true; /* Don't emulate the ret. */
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
regs->ax = ret;
|
||||
|
||||
@@ -17,6 +17,7 @@ extern bool e820__mapped_all(u64 start, u64 end, enum e820_type type);
|
||||
extern void e820__range_add (u64 start, u64 size, enum e820_type type);
|
||||
extern u64 e820__range_update(u64 start, u64 size, enum e820_type old_type, enum e820_type new_type);
|
||||
extern u64 e820__range_remove(u64 start, u64 size, enum e820_type old_type, bool check_type);
|
||||
extern u64 e820__range_update_table(struct e820_table *t, u64 start, u64 size, enum e820_type old_type, enum e820_type new_type);
|
||||
|
||||
extern void e820__print_table(char *who);
|
||||
extern int e820__update_table(struct e820_table *table);
|
||||
|
||||
@@ -472,7 +472,6 @@ struct thread_struct {
|
||||
unsigned long iopl_emul;
|
||||
|
||||
unsigned int iopl_warn:1;
|
||||
unsigned int sig_on_uaccess_err:1;
|
||||
|
||||
/*
|
||||
* Protection Keys Register for Userspace. Loaded immediately on
|
||||
|
||||
@@ -269,6 +269,7 @@ int rmp_make_private(u64 pfn, u64 gpa, enum pg_level level, u32 asid, bool immut
|
||||
int rmp_make_shared(u64 pfn, enum pg_level level);
|
||||
void snp_leak_pages(u64 pfn, unsigned int npages);
|
||||
void kdump_sev_callback(void);
|
||||
void snp_fixup_e820_tables(void);
|
||||
#else
|
||||
static inline bool snp_probe_rmptable_info(void) { return false; }
|
||||
static inline int snp_lookup_rmpentry(u64 pfn, bool *assigned, int *level) { return -ENODEV; }
|
||||
@@ -282,6 +283,7 @@ static inline int rmp_make_private(u64 pfn, u64 gpa, enum pg_level level, u32 as
|
||||
static inline int rmp_make_shared(u64 pfn, enum pg_level level) { return -ENODEV; }
|
||||
static inline void snp_leak_pages(u64 pfn, unsigned int npages) {}
|
||||
static inline void kdump_sev_callback(void) { }
|
||||
static inline void snp_fixup_e820_tables(void) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1771,7 +1771,7 @@ void x2apic_setup(void)
|
||||
__x2apic_enable();
|
||||
}
|
||||
|
||||
static __init void apic_set_fixmap(void);
|
||||
static __init void apic_set_fixmap(bool read_apic);
|
||||
|
||||
static __init void x2apic_disable(void)
|
||||
{
|
||||
@@ -1793,7 +1793,12 @@ static __init void x2apic_disable(void)
|
||||
}
|
||||
|
||||
__x2apic_disable();
|
||||
apic_set_fixmap();
|
||||
/*
|
||||
* Don't reread the APIC ID as it was already done from
|
||||
* check_x2apic() and the APIC driver still is a x2APIC variant,
|
||||
* which fails to do the read after x2APIC was disabled.
|
||||
*/
|
||||
apic_set_fixmap(false);
|
||||
}
|
||||
|
||||
static __init void x2apic_enable(void)
|
||||
@@ -2057,13 +2062,14 @@ void __init init_apic_mappings(void)
|
||||
}
|
||||
}
|
||||
|
||||
static __init void apic_set_fixmap(void)
|
||||
static __init void apic_set_fixmap(bool read_apic)
|
||||
{
|
||||
set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
|
||||
apic_mmio_base = APIC_BASE;
|
||||
apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
|
||||
apic_mmio_base, mp_lapic_addr);
|
||||
apic_read_boot_cpu_id(false);
|
||||
if (read_apic)
|
||||
apic_read_boot_cpu_id(false);
|
||||
}
|
||||
|
||||
void __init register_lapic_address(unsigned long address)
|
||||
@@ -2073,7 +2079,7 @@ void __init register_lapic_address(unsigned long address)
|
||||
mp_lapic_addr = address;
|
||||
|
||||
if (!x2apic_mode)
|
||||
apic_set_fixmap();
|
||||
apic_set_fixmap(true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -532,9 +532,10 @@ u64 __init e820__range_update(u64 start, u64 size, enum e820_type old_type, enum
|
||||
return __e820__range_update(e820_table, start, size, old_type, new_type);
|
||||
}
|
||||
|
||||
static u64 __init e820__range_update_kexec(u64 start, u64 size, enum e820_type old_type, enum e820_type new_type)
|
||||
u64 __init e820__range_update_table(struct e820_table *t, u64 start, u64 size,
|
||||
enum e820_type old_type, enum e820_type new_type)
|
||||
{
|
||||
return __e820__range_update(e820_table_kexec, start, size, old_type, new_type);
|
||||
return __e820__range_update(t, start, size, old_type, new_type);
|
||||
}
|
||||
|
||||
/* Remove a range of memory from the E820 table: */
|
||||
@@ -806,7 +807,7 @@ u64 __init e820__memblock_alloc_reserved(u64 size, u64 align)
|
||||
|
||||
addr = memblock_phys_alloc(size, align);
|
||||
if (addr) {
|
||||
e820__range_update_kexec(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
e820__range_update_table(e820_table_kexec, addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
pr_info("update e820_table_kexec for e820__memblock_alloc_reserved()\n");
|
||||
e820__update_table_kexec();
|
||||
}
|
||||
|
||||
+1
-32
@@ -723,39 +723,8 @@ kernelmode_fixup_or_oops(struct pt_regs *regs, unsigned long error_code,
|
||||
WARN_ON_ONCE(user_mode(regs));
|
||||
|
||||
/* Are we prepared to handle this kernel fault? */
|
||||
if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) {
|
||||
/*
|
||||
* Any interrupt that takes a fault gets the fixup. This makes
|
||||
* the below recursive fault logic only apply to a faults from
|
||||
* task context.
|
||||
*/
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Per the above we're !in_interrupt(), aka. task context.
|
||||
*
|
||||
* In this case we need to make sure we're not recursively
|
||||
* faulting through the emulate_vsyscall() logic.
|
||||
*/
|
||||
if (current->thread.sig_on_uaccess_err && signal) {
|
||||
sanitize_error_code(address, &error_code);
|
||||
|
||||
set_signal_archinfo(address, error_code);
|
||||
|
||||
if (si_code == SEGV_PKUERR) {
|
||||
force_sig_pkuerr((void __user *)address, pkey);
|
||||
} else {
|
||||
/* XXX: hwpoison faults will set the wrong code. */
|
||||
force_sig_fault(signal, si_code, (void __user *)address);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Barring that, we can do the fixup and be happy.
|
||||
*/
|
||||
if (fixup_exception(regs, X86_TRAP_PF, error_code, address))
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* AMD erratum #91 manifests as a spurious page fault on a PREFETCH
|
||||
|
||||
@@ -102,6 +102,13 @@ void __init mem_encrypt_setup_arch(void)
|
||||
phys_addr_t total_mem = memblock_phys_mem_size();
|
||||
unsigned long size;
|
||||
|
||||
/*
|
||||
* Do RMP table fixups after the e820 tables have been setup by
|
||||
* e820__memory_setup().
|
||||
*/
|
||||
if (cc_platform_has(CC_ATTR_HOST_SEV_SNP))
|
||||
snp_fixup_e820_tables();
|
||||
|
||||
if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
|
||||
return;
|
||||
|
||||
|
||||
@@ -163,6 +163,42 @@ bool snp_probe_rmptable_info(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __init __snp_fixup_e820_tables(u64 pa)
|
||||
{
|
||||
if (IS_ALIGNED(pa, PMD_SIZE))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Handle cases where the RMP table placement by the BIOS is not
|
||||
* 2M aligned and the kexec kernel could try to allocate
|
||||
* from within that chunk which then causes a fatal RMP fault.
|
||||
*
|
||||
* The e820_table needs to be updated as it is converted to
|
||||
* kernel memory resources and used by KEXEC_FILE_LOAD syscall
|
||||
* to load kexec segments.
|
||||
*
|
||||
* The e820_table_firmware needs to be updated as it is exposed
|
||||
* to sysfs and used by the KEXEC_LOAD syscall to load kexec
|
||||
* segments.
|
||||
*
|
||||
* The e820_table_kexec needs to be updated as it passed to
|
||||
* the kexec-ed kernel.
|
||||
*/
|
||||
pa = ALIGN_DOWN(pa, PMD_SIZE);
|
||||
if (e820__mapped_any(pa, pa + PMD_SIZE, E820_TYPE_RAM)) {
|
||||
pr_info("Reserving start/end of RMP table on a 2MB boundary [0x%016llx]\n", pa);
|
||||
e820__range_update(pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
e820__range_update_table(e820_table_kexec, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
e820__range_update_table(e820_table_firmware, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
|
||||
}
|
||||
}
|
||||
|
||||
void __init snp_fixup_e820_tables(void)
|
||||
{
|
||||
__snp_fixup_e820_tables(probed_rmp_base);
|
||||
__snp_fixup_e820_tables(probed_rmp_base + probed_rmp_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the necessary preparations which are verified by the firmware as
|
||||
* described in the SNP_INIT_EX firmware command description in the SNP
|
||||
|
||||
@@ -425,7 +425,7 @@ static void handle_error(struct mem_ctl_info *mci, struct ecc_status *stat)
|
||||
convert_to_physical(priv, pinf), pinf.burstpos);
|
||||
|
||||
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
|
||||
priv->ce_cnt, 0, 0, 0, 0, 0, -1,
|
||||
1, 0, 0, 0, 0, 0, -1,
|
||||
priv->message, "");
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ static void handle_error(struct mem_ctl_info *mci, struct ecc_status *stat)
|
||||
convert_to_physical(priv, pinf), pinf.burstpos);
|
||||
|
||||
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
|
||||
priv->ue_cnt, 0, 0, 0, 0, 0, -1,
|
||||
1, 0, 0, 0, 0, 0, -1,
|
||||
priv->message, "");
|
||||
}
|
||||
|
||||
@@ -865,6 +865,9 @@ static ssize_t inject_data_ue_store(struct file *file, const char __user *data,
|
||||
for (i = 0; i < NUM_UE_BITPOS; i++)
|
||||
token[i] = strsep(&pbuf, ",");
|
||||
|
||||
if (!token[0] || !token[1])
|
||||
return -EFAULT;
|
||||
|
||||
ret = kstrtou8(token[0], 0, &ue0);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1135,8 +1138,7 @@ static int mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
rc = xlnx_register_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
|
||||
XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_DDRMC_NCR |
|
||||
XPM_EVENT_ERROR_MASK_NOC_CR | XPM_EVENT_ERROR_MASK_NOC_NCR,
|
||||
XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_DDRMC_NCR,
|
||||
false, err_callback, mci);
|
||||
if (rc) {
|
||||
if (rc == -EACCES)
|
||||
@@ -1173,8 +1175,6 @@ static void mc_remove(struct platform_device *pdev)
|
||||
|
||||
xlnx_unregister_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
|
||||
XPM_EVENT_ERROR_MASK_DDRMC_CR |
|
||||
XPM_EVENT_ERROR_MASK_NOC_CR |
|
||||
XPM_EVENT_ERROR_MASK_NOC_NCR |
|
||||
XPM_EVENT_ERROR_MASK_DDRMC_NCR, err_callback, mci);
|
||||
edac_mc_del_mc(&pdev->dev);
|
||||
edac_mc_free(mci);
|
||||
|
||||
@@ -78,6 +78,7 @@ static void cci_pci_free_irq(struct pci_dev *pcidev)
|
||||
#define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001
|
||||
#define PCIE_DEVICE_ID_INTEL_DFL 0xbcce
|
||||
/* PCI Subdevice ID for PCIE_DEVICE_ID_INTEL_DFL */
|
||||
#define PCIE_SUBDEVICE_ID_INTEL_D5005 0x138d
|
||||
#define PCIE_SUBDEVICE_ID_INTEL_N6000 0x1770
|
||||
#define PCIE_SUBDEVICE_ID_INTEL_N6001 0x1771
|
||||
#define PCIE_SUBDEVICE_ID_INTEL_C6100 0x17d4
|
||||
@@ -101,6 +102,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),},
|
||||
{PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL,
|
||||
PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_D5005),},
|
||||
{PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL,
|
||||
PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_N6000),},
|
||||
{PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
@@ -27,11 +28,16 @@
|
||||
#define MXC4005_REG_ZOUT_UPPER 0x07
|
||||
#define MXC4005_REG_ZOUT_LOWER 0x08
|
||||
|
||||
#define MXC4005_REG_INT_MASK0 0x0A
|
||||
|
||||
#define MXC4005_REG_INT_MASK1 0x0B
|
||||
#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01
|
||||
|
||||
#define MXC4005_REG_INT_CLR0 0x00
|
||||
|
||||
#define MXC4005_REG_INT_CLR1 0x01
|
||||
#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01
|
||||
#define MXC4005_REG_INT_CLR1_SW_RST 0x10
|
||||
|
||||
#define MXC4005_REG_CONTROL 0x0D
|
||||
#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5)
|
||||
@@ -39,6 +45,9 @@
|
||||
|
||||
#define MXC4005_REG_DEVICE_ID 0x0E
|
||||
|
||||
/* Datasheet does not specify a reset time, this is a conservative guess */
|
||||
#define MXC4005_RESET_TIME_US 2000
|
||||
|
||||
enum mxc4005_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
@@ -62,6 +71,8 @@ struct mxc4005_data {
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
bool trigger_enabled;
|
||||
unsigned int control;
|
||||
unsigned int int_mask1;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -113,7 +124,9 @@ static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg)
|
||||
static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MXC4005_REG_INT_CLR0:
|
||||
case MXC4005_REG_INT_CLR1:
|
||||
case MXC4005_REG_INT_MASK0:
|
||||
case MXC4005_REG_INT_MASK1:
|
||||
case MXC4005_REG_CONTROL:
|
||||
return true;
|
||||
@@ -330,23 +343,20 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig,
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct mxc4005_data *data = iio_priv(indio_dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (state) {
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
|
||||
MXC4005_REG_INT_MASK1_BIT_DRDYE);
|
||||
} else {
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
|
||||
~MXC4005_REG_INT_MASK1_BIT_DRDYE);
|
||||
}
|
||||
|
||||
val = state ? MXC4005_REG_INT_MASK1_BIT_DRDYE : 0;
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, val);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
dev_err(data->dev, "failed to update reg_int_mask1");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->int_mask1 = val;
|
||||
data->trigger_enabled = state;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
@@ -382,6 +392,21 @@ static int mxc4005_chip_init(struct mxc4005_data *data)
|
||||
|
||||
dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
|
||||
MXC4005_REG_INT_CLR1_SW_RST);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(data->dev, ret, "resetting chip\n");
|
||||
|
||||
fsleep(MXC4005_RESET_TIME_US);
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(data->dev, ret, "writing INT_MASK0\n");
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, 0);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(data->dev, ret, "writing INT_MASK1\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -469,6 +494,58 @@ static int mxc4005_probe(struct i2c_client *client)
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static int mxc4005_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct mxc4005_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* Save control to restore it on resume */
|
||||
ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control);
|
||||
if (ret < 0)
|
||||
dev_err(data->dev, "failed to read reg_control\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxc4005_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct mxc4005_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
|
||||
MXC4005_REG_INT_CLR1_SW_RST);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "failed to reset chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fsleep(MXC4005_RESET_TIME_US);
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "failed to restore control register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "failed to restore interrupt 0 mask\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "failed to restore interrupt 1 mask\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume);
|
||||
|
||||
static const struct acpi_device_id mxc4005_acpi_match[] = {
|
||||
{"MXC4005", 0},
|
||||
{"MXC6655", 0},
|
||||
@@ -496,6 +573,7 @@ static struct i2c_driver mxc4005_driver = {
|
||||
.name = MXC4005_DRV_NAME,
|
||||
.acpi_match_table = mxc4005_acpi_match,
|
||||
.of_match_table = mxc4005_of_match,
|
||||
.pm = pm_sleep_ptr(&mxc4005_pm_ops),
|
||||
},
|
||||
.probe = mxc4005_probe,
|
||||
.id_table = mxc4005_id,
|
||||
|
||||
@@ -1289,6 +1289,7 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
|
||||
struct device *dev = &st->adis.spi->dev;
|
||||
const struct adis16475_sync *sync;
|
||||
u32 sync_mode;
|
||||
u16 val;
|
||||
|
||||
/* default to internal clk */
|
||||
st->clk_freq = st->info->int_clk * 1000;
|
||||
@@ -1350,8 +1351,9 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
|
||||
* I'm keeping this for simplicity and avoiding extra variables
|
||||
* in chip_info.
|
||||
*/
|
||||
val = ADIS16475_SYNC_MODE(sync->sync_mode);
|
||||
ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
|
||||
ADIS16475_SYNC_MODE_MASK, sync->sync_mode);
|
||||
ADIS16475_SYNC_MODE_MASK, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -1233,6 +1233,7 @@ const struct bmp280_chip_info bmp380_chip_info = {
|
||||
.chip_id = bmp380_chip_ids,
|
||||
.num_chip_id = ARRAY_SIZE(bmp380_chip_ids),
|
||||
.regmap_config = &bmp380_regmap_config,
|
||||
.spi_read_extra_byte = true,
|
||||
.start_up_time = 2000,
|
||||
.channels = bmp380_channels,
|
||||
.num_channels = 2,
|
||||
|
||||
@@ -96,15 +96,10 @@ static int bmp280_spi_probe(struct spi_device *spi)
|
||||
|
||||
chip_info = spi_get_device_match_data(spi);
|
||||
|
||||
switch (chip_info->chip_id[0]) {
|
||||
case BMP380_CHIP_ID:
|
||||
case BMP390_CHIP_ID:
|
||||
if (chip_info->spi_read_extra_byte)
|
||||
bmp_regmap_bus = &bmp380_regmap_bus;
|
||||
break;
|
||||
default:
|
||||
else
|
||||
bmp_regmap_bus = &bmp280_regmap_bus;
|
||||
break;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init(&spi->dev,
|
||||
bmp_regmap_bus,
|
||||
@@ -127,7 +122,7 @@ static const struct of_device_id bmp280_of_spi_match[] = {
|
||||
{ .compatible = "bosch,bmp180", .data = &bmp180_chip_info },
|
||||
{ .compatible = "bosch,bmp181", .data = &bmp180_chip_info },
|
||||
{ .compatible = "bosch,bmp280", .data = &bmp280_chip_info },
|
||||
{ .compatible = "bosch,bme280", .data = &bmp280_chip_info },
|
||||
{ .compatible = "bosch,bme280", .data = &bme280_chip_info },
|
||||
{ .compatible = "bosch,bmp380", .data = &bmp380_chip_info },
|
||||
{ .compatible = "bosch,bmp580", .data = &bmp580_chip_info },
|
||||
{ },
|
||||
@@ -139,7 +134,7 @@ static const struct spi_device_id bmp280_spi_id[] = {
|
||||
{ "bmp180", (kernel_ulong_t)&bmp180_chip_info },
|
||||
{ "bmp181", (kernel_ulong_t)&bmp180_chip_info },
|
||||
{ "bmp280", (kernel_ulong_t)&bmp280_chip_info },
|
||||
{ "bme280", (kernel_ulong_t)&bmp280_chip_info },
|
||||
{ "bme280", (kernel_ulong_t)&bme280_chip_info },
|
||||
{ "bmp380", (kernel_ulong_t)&bmp380_chip_info },
|
||||
{ "bmp580", (kernel_ulong_t)&bmp580_chip_info },
|
||||
{ }
|
||||
|
||||
@@ -423,6 +423,7 @@ struct bmp280_chip_info {
|
||||
int num_chip_id;
|
||||
|
||||
const struct regmap_config *regmap_config;
|
||||
bool spi_read_extra_byte;
|
||||
|
||||
const struct iio_chan_spec *channels;
|
||||
int num_channels;
|
||||
|
||||
@@ -208,6 +208,7 @@ static const struct xpad_device {
|
||||
{ 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 },
|
||||
{ 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 },
|
||||
{ 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
|
||||
{ 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE },
|
||||
{ 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
|
||||
{ 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
|
||||
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
|
||||
@@ -487,6 +488,7 @@ static const struct usb_device_id xpad_table[] = {
|
||||
{ USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
|
||||
XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */
|
||||
XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */
|
||||
XPAD_XBOXONE_VENDOR(0x0b05), /* ASUS controllers */
|
||||
XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f Xbox 360 controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f Xbox One controllers */
|
||||
|
||||
@@ -132,7 +132,13 @@ static void __exit amimouse_remove(struct platform_device *pdev)
|
||||
input_unregister_device(dev);
|
||||
}
|
||||
|
||||
static struct platform_driver amimouse_driver = {
|
||||
/*
|
||||
* amimouse_remove() lives in .exit.text. For drivers registered via
|
||||
* module_platform_driver_probe() this is ok because they cannot get unbound at
|
||||
* runtime. So mark the driver struct with __refdata to prevent modpost
|
||||
* triggering a section mismatch warning.
|
||||
*/
|
||||
static struct platform_driver amimouse_driver __refdata = {
|
||||
.remove_new = __exit_p(amimouse_remove),
|
||||
.driver = {
|
||||
.name = "amiga-mouse",
|
||||
|
||||
@@ -115,6 +115,8 @@
|
||||
#define MEI_DEV_ID_ARL_S 0x7F68 /* Arrow Lake Point S */
|
||||
#define MEI_DEV_ID_ARL_H 0x7770 /* Arrow Lake Point H */
|
||||
|
||||
#define MEI_DEV_ID_LNL_M 0xA870 /* Lunar Lake Point M */
|
||||
|
||||
/*
|
||||
* MEI HW Section
|
||||
*/
|
||||
|
||||
@@ -122,6 +122,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_ARL_S, MEI_ME_PCH15_CFG)},
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_ARL_H, MEI_ME_PCH15_CFG)},
|
||||
|
||||
{MEI_PCI_DEVICE(MEI_DEV_ID_LNL_M, MEI_ME_PCH15_CFG)},
|
||||
|
||||
/* required last entry */
|
||||
{0, }
|
||||
};
|
||||
|
||||
@@ -236,8 +236,11 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent,
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||
|
||||
pdev->vendor != PCI_VENDOR_ID_INTEL)
|
||||
if (pdev->vendor != PCI_VENDOR_ID_INTEL)
|
||||
return 0;
|
||||
|
||||
if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
pdev->class != (PCI_CLASS_DISPLAY_OTHER << 8))
|
||||
return 0;
|
||||
|
||||
if (subcomponent != I915_COMPONENT_PXP)
|
||||
|
||||
@@ -44,8 +44,6 @@ static struct pci_driver pvpanic_pci_driver = {
|
||||
.name = "pvpanic-pci",
|
||||
.id_table = pvpanic_pci_id_tbl,
|
||||
.probe = pvpanic_pci_probe,
|
||||
.driver = {
|
||||
.dev_groups = pvpanic_dev_groups,
|
||||
},
|
||||
.dev_groups = pvpanic_dev_groups,
|
||||
};
|
||||
module_pci_driver(pvpanic_pci_driver);
|
||||
|
||||
@@ -1451,7 +1451,11 @@ static void qcom_slim_ngd_up_worker(struct work_struct *work)
|
||||
ctrl = container_of(work, struct qcom_slim_ngd_ctrl, ngd_up_work);
|
||||
|
||||
/* Make sure qmi service is up before continuing */
|
||||
wait_for_completion_interruptible(&ctrl->qmi_up);
|
||||
if (!wait_for_completion_interruptible_timeout(&ctrl->qmi_up,
|
||||
msecs_to_jiffies(MSEC_PER_SEC))) {
|
||||
dev_err(ctrl->dev, "QMI wait timeout\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ctrl->ssr_lock);
|
||||
qcom_slim_ngd_enable(ctrl, true);
|
||||
|
||||
@@ -5110,9 +5110,10 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
}
|
||||
if (usb_endpoint_maxp(&udev->ep0.desc) == i) {
|
||||
; /* Initial ep0 maxpacket guess is right */
|
||||
} else if ((udev->speed == USB_SPEED_FULL ||
|
||||
} else if (((udev->speed == USB_SPEED_FULL ||
|
||||
udev->speed == USB_SPEED_HIGH) &&
|
||||
(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
(i == 8 || i == 16 || i == 32 || i == 64)) ||
|
||||
(udev->speed >= USB_SPEED_SUPER && i > 0)) {
|
||||
/* Initial guess is wrong; use the descriptor's value */
|
||||
if (udev->speed == USB_SPEED_FULL)
|
||||
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
|
||||
@@ -51,13 +51,15 @@ static ssize_t disable_show(struct device *dev,
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
struct usb_interface *intf = to_usb_interface(hub->intfdev);
|
||||
struct usb_interface *intf = to_usb_interface(dev->parent);
|
||||
int port1 = port_dev->portnum;
|
||||
u16 portstatus, unused;
|
||||
bool disabled;
|
||||
int rc;
|
||||
struct kernfs_node *kn;
|
||||
|
||||
if (!hub)
|
||||
return -ENODEV;
|
||||
hub_get(hub);
|
||||
rc = usb_autopm_get_interface(intf);
|
||||
if (rc < 0)
|
||||
@@ -101,12 +103,14 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
struct usb_interface *intf = to_usb_interface(hub->intfdev);
|
||||
struct usb_interface *intf = to_usb_interface(dev->parent);
|
||||
int port1 = port_dev->portnum;
|
||||
bool disabled;
|
||||
int rc;
|
||||
struct kernfs_node *kn;
|
||||
|
||||
if (!hub)
|
||||
return -ENODEV;
|
||||
rc = kstrtobool(buf, &disabled);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
+38
-52
@@ -104,6 +104,27 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
if (enable && !dwc->dis_u3_susphy_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
if (enable && !dwc->dis_u2_susphy_quirk)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
||||
{
|
||||
u32 reg;
|
||||
@@ -585,11 +606,8 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
|
||||
*/
|
||||
static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned int hw_mode;
|
||||
u32 reg;
|
||||
|
||||
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
|
||||
/*
|
||||
@@ -599,21 +617,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
||||
|
||||
/*
|
||||
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
|
||||
* to '0' during coreConsultant configuration. So default value
|
||||
* will be '0' when the core is reset. Application needs to set it
|
||||
* to '1' after the core initialization is completed.
|
||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
|
||||
* So default value will be '0' when the core is reset. Application
|
||||
* needs to set it to '1' after the core initialization is completed.
|
||||
*
|
||||
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
|
||||
* cleared after power-on reset, and it can be set after core
|
||||
* initialization.
|
||||
*/
|
||||
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
/*
|
||||
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
|
||||
* power-on reset, and it can be set after core initialization, which is
|
||||
* after device soft-reset during initialization.
|
||||
*/
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
if (dwc->u2ss_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
|
||||
@@ -639,9 +652,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
if (dwc->tx_de_emphasis_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
|
||||
|
||||
if (dwc->dis_u3_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
if (dwc->dis_del_phy_power_chg_quirk)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
|
||||
|
||||
@@ -689,24 +699,15 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
}
|
||||
|
||||
/*
|
||||
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
|
||||
* '0' during coreConsultant configuration. So default value will
|
||||
* be '0' when the core is reset. Application needs to set it to
|
||||
* '1' after the core initialization is completed.
|
||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
|
||||
* So default value will be '0' when the core is reset. Application
|
||||
* needs to set it to '1' after the core initialization is completed.
|
||||
*
|
||||
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
|
||||
* after power-on reset, and it can be set after core initialization.
|
||||
*/
|
||||
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
/*
|
||||
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
|
||||
* power-on reset, and it can be set after core initialization, which is
|
||||
* after device soft-reset during initialization.
|
||||
*/
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_u2_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_enblslpm_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
|
||||
@@ -1227,21 +1228,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
|
||||
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
|
||||
if (!dwc->dis_u3_susphy_quirk) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
}
|
||||
|
||||
if (!dwc->dis_u2_susphy_quirk) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_core_setup_global_control(dwc);
|
||||
dwc3_core_num_eps(dwc);
|
||||
|
||||
|
||||
@@ -1580,6 +1580,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
|
||||
void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
|
||||
|
||||
int dwc3_core_soft_reset(struct dwc3 *dwc);
|
||||
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_host_init(struct dwc3 *dwc);
|
||||
|
||||
@@ -2924,6 +2924,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
|
||||
dwc3_ep0_out_start(dwc);
|
||||
|
||||
dwc3_gadget_enable_irq(dwc);
|
||||
dwc3_enable_susphy(dwc, true);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4690,6 +4691,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
if (!dwc->gadget)
|
||||
return;
|
||||
|
||||
dwc3_enable_susphy(dwc, false);
|
||||
usb_del_gadget(dwc->gadget);
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
usb_put_gadget(dwc->gadget);
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "../host/xhci-port.h"
|
||||
#include "../host/xhci-ext-caps.h"
|
||||
#include "../host/xhci-caps.h"
|
||||
#include "../host/xhci-plat.h"
|
||||
#include "core.h"
|
||||
|
||||
#define XHCI_HCSPARAMS1 0x4
|
||||
@@ -57,6 +60,24 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
if (!usb_hcd_is_primary_hcd(hcd))
|
||||
return;
|
||||
|
||||
pdev = to_platform_device(hcd->self.controller);
|
||||
dwc = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
dwc3_enable_susphy(dwc, true);
|
||||
}
|
||||
|
||||
static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
|
||||
.plat_start = dwc3_xhci_plat_start,
|
||||
};
|
||||
|
||||
static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
|
||||
int irq, char *name)
|
||||
{
|
||||
@@ -167,6 +188,11 @@ int dwc3_host_init(struct dwc3 *dwc)
|
||||
}
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(xhci, &dwc3_xhci_plat_quirk,
|
||||
sizeof(struct xhci_plat_priv));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add(xhci);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register xHCI device\n");
|
||||
@@ -192,6 +218,7 @@ void dwc3_host_exit(struct dwc3 *dwc)
|
||||
if (dwc->sys_wakeup)
|
||||
device_init_wakeup(&dwc->xhci->dev, false);
|
||||
|
||||
dwc3_enable_susphy(dwc, false);
|
||||
platform_device_unregister(dwc->xhci);
|
||||
dwc->xhci = NULL;
|
||||
}
|
||||
|
||||
@@ -2112,7 +2112,7 @@ unknown:
|
||||
buf[5] = 0x01;
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_DEVICE:
|
||||
if (w_index != 0x4 || (w_value >> 8))
|
||||
if (w_index != 0x4 || (w_value & 0xff))
|
||||
break;
|
||||
buf[6] = w_index;
|
||||
/* Number of ext compat interfaces */
|
||||
@@ -2128,9 +2128,9 @@ unknown:
|
||||
}
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
if (w_index != 0x5 || (w_value >> 8))
|
||||
if (w_index != 0x5 || (w_value & 0xff))
|
||||
break;
|
||||
interface = w_value & 0xFF;
|
||||
interface = w_value >> 8;
|
||||
if (interface >= MAX_CONFIG_INTERFACES ||
|
||||
!os_desc_cfg->interface[interface])
|
||||
break;
|
||||
|
||||
@@ -852,6 +852,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
||||
work);
|
||||
int ret = io_data->status;
|
||||
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
|
||||
unsigned long flags;
|
||||
|
||||
if (io_data->read && ret > 0) {
|
||||
kthread_use_mm(io_data->mm);
|
||||
@@ -864,6 +865,11 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
||||
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
|
||||
eventfd_signal(io_data->ffs->ffs_eventfd);
|
||||
|
||||
spin_lock_irqsave(&io_data->ffs->eps_lock, flags);
|
||||
usb_ep_free_request(io_data->ep, io_data->req);
|
||||
io_data->req = NULL;
|
||||
spin_unlock_irqrestore(&io_data->ffs->eps_lock, flags);
|
||||
|
||||
if (io_data->read)
|
||||
kfree(io_data->to_free);
|
||||
ffs_free_buffer(io_data);
|
||||
@@ -877,7 +883,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
|
||||
struct ffs_data *ffs = io_data->ffs;
|
||||
|
||||
io_data->status = req->status ? req->status : req->actual;
|
||||
usb_ep_free_request(_ep, req);
|
||||
|
||||
INIT_WORK(&io_data->work, ffs_user_copy_worker);
|
||||
queue_work(ffs->io_completion_wq, &io_data->work);
|
||||
@@ -3806,7 +3811,7 @@ static int ffs_func_setup(struct usb_function *f,
|
||||
__ffs_event_add(ffs, FUNCTIONFS_SETUP);
|
||||
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
|
||||
|
||||
return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
|
||||
return ffs->ev.setup.wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
|
||||
}
|
||||
|
||||
static bool ffs_func_req_match(struct usb_function *f,
|
||||
|
||||
@@ -92,10 +92,10 @@ static int __uvcg_iter_item_entries(const char *page, size_t len,
|
||||
|
||||
while (pg - page < len) {
|
||||
i = 0;
|
||||
while (i < sizeof(buf) && (pg - page < len) &&
|
||||
while (i < bufsize && (pg - page < len) &&
|
||||
*pg != '\0' && *pg != '\n')
|
||||
buf[i++] = *pg++;
|
||||
if (i == sizeof(buf)) {
|
||||
if (i == bufsize) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
@@ -888,6 +888,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
/* Check for an all 1's result which is a typical consequence
|
||||
* of dead, unclocked, or unplugged (CardBus...) devices
|
||||
*/
|
||||
again:
|
||||
if (ints == ~(u32)0) {
|
||||
ohci->rh_state = OHCI_RH_HALTED;
|
||||
ohci_dbg (ohci, "device removed!\n");
|
||||
@@ -982,6 +983,13 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
}
|
||||
spin_unlock(&ohci->lock);
|
||||
|
||||
/* repeat until all enabled interrupts are handled */
|
||||
if (ohci->rh_state != OHCI_RH_HALTED) {
|
||||
ints = ohci_readl(ohci, ®s->intrstatus);
|
||||
if (ints && (ints & ohci_readl(ohci, ®s->intrenable)))
|
||||
goto again;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#ifndef _XHCI_PLAT_H
|
||||
#define _XHCI_PLAT_H
|
||||
|
||||
#include "xhci.h" /* for hcd_to_xhci() */
|
||||
struct device;
|
||||
struct platform_device;
|
||||
struct usb_hcd;
|
||||
|
||||
struct xhci_plat_priv {
|
||||
const char *firmware_name;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/usb/rzv2m_usb3drd.h>
|
||||
#include "xhci.h"
|
||||
#include "xhci-plat.h"
|
||||
#include "xhci-rzv2m.h"
|
||||
|
||||
|
||||
@@ -104,14 +104,18 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
|
||||
|
||||
ret = tcpm->port_start(tcpm, tcpm->tcpm_port);
|
||||
if (ret)
|
||||
goto fwnode_remove;
|
||||
goto port_unregister;
|
||||
|
||||
ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port);
|
||||
if (ret)
|
||||
goto fwnode_remove;
|
||||
goto port_stop;
|
||||
|
||||
return 0;
|
||||
|
||||
port_stop:
|
||||
tcpm->port_stop(tcpm);
|
||||
port_unregister:
|
||||
tcpm_unregister_port(tcpm->tcpm_port);
|
||||
fwnode_remove:
|
||||
fwnode_remove_software_node(tcpm->tcpc.fwnode);
|
||||
|
||||
|
||||
@@ -475,10 +475,8 @@ static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdph
|
||||
|
||||
qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy);
|
||||
done:
|
||||
if (ret) {
|
||||
regulator_disable(pmic_typec_pdphy->vdd_pdphy);
|
||||
if (ret)
|
||||
dev_err(dev, "pdphy_enable fail %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -524,12 +522,17 @@ static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm,
|
||||
|
||||
ret = pmic_typec_pdphy_reset(pmic_typec_pdphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_disable_vdd_pdhy;
|
||||
|
||||
for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++)
|
||||
enable_irq(pmic_typec_pdphy->irq_data[i].irq);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_vdd_pdhy:
|
||||
regulator_disable(pmic_typec_pdphy->vdd_pdphy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm)
|
||||
|
||||
@@ -1564,8 +1564,12 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
|
||||
static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
|
||||
const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
|
||||
{
|
||||
if (port->state != SRC_READY && port->state != SNK_READY &&
|
||||
port->state != SRC_VDM_IDENTITY_REQUEST)
|
||||
return;
|
||||
|
||||
mutex_lock(&port->lock);
|
||||
tcpm_queue_vdm(port, header, data, cnt, TCPC_TX_SOP);
|
||||
tcpm_queue_vdm(port, header, data, cnt, tx_sop_type);
|
||||
mutex_unlock(&port->lock);
|
||||
}
|
||||
|
||||
@@ -1580,7 +1584,8 @@ static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt)
|
||||
port->partner_ident.cert_stat = p[VDO_INDEX_CSTAT];
|
||||
port->partner_ident.product = product;
|
||||
|
||||
typec_partner_set_identity(port->partner);
|
||||
if (port->partner)
|
||||
typec_partner_set_identity(port->partner);
|
||||
|
||||
tcpm_log(port, "Identity: %04x:%04x.%04x",
|
||||
PD_IDH_VID(vdo),
|
||||
@@ -1742,6 +1747,9 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
|
||||
struct typec_altmode *altmode;
|
||||
int i;
|
||||
|
||||
if (!port->partner)
|
||||
return;
|
||||
|
||||
for (i = 0; i < modep->altmodes; i++) {
|
||||
altmode = typec_partner_register_altmode(port->partner,
|
||||
&modep->altmode_desc[i]);
|
||||
@@ -2996,7 +3004,7 @@ static int tcpm_register_source_caps(struct tcpm_port *port)
|
||||
{
|
||||
struct usb_power_delivery_desc desc = { port->negotiated_rev };
|
||||
struct usb_power_delivery_capabilities_desc caps = { };
|
||||
struct usb_power_delivery_capabilities *cap;
|
||||
struct usb_power_delivery_capabilities *cap = port->partner_source_caps;
|
||||
|
||||
if (!port->partner_pd)
|
||||
port->partner_pd = usb_power_delivery_register(NULL, &desc);
|
||||
@@ -3006,6 +3014,9 @@ static int tcpm_register_source_caps(struct tcpm_port *port)
|
||||
memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps);
|
||||
caps.role = TYPEC_SOURCE;
|
||||
|
||||
if (cap)
|
||||
usb_power_delivery_unregister_capabilities(cap);
|
||||
|
||||
cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps);
|
||||
if (IS_ERR(cap))
|
||||
return PTR_ERR(cap);
|
||||
@@ -4231,7 +4242,10 @@ static int tcpm_init_vconn(struct tcpm_port *port)
|
||||
|
||||
static void tcpm_typec_connect(struct tcpm_port *port)
|
||||
{
|
||||
struct typec_partner *partner;
|
||||
|
||||
if (!port->connected) {
|
||||
port->connected = true;
|
||||
/* Make sure we don't report stale identity information */
|
||||
memset(&port->partner_ident, 0, sizeof(port->partner_ident));
|
||||
port->partner_desc.usb_pd = port->pd_capable;
|
||||
@@ -4241,9 +4255,13 @@ static void tcpm_typec_connect(struct tcpm_port *port)
|
||||
port->partner_desc.accessory = TYPEC_ACCESSORY_AUDIO;
|
||||
else
|
||||
port->partner_desc.accessory = TYPEC_ACCESSORY_NONE;
|
||||
port->partner = typec_register_partner(port->typec_port,
|
||||
&port->partner_desc);
|
||||
port->connected = true;
|
||||
partner = typec_register_partner(port->typec_port, &port->partner_desc);
|
||||
if (IS_ERR(partner)) {
|
||||
dev_err(port->dev, "Failed to register partner (%ld)\n", PTR_ERR(partner));
|
||||
return;
|
||||
}
|
||||
|
||||
port->partner = partner;
|
||||
typec_partner_set_usb_power_delivery(port->partner, port->partner_pd);
|
||||
}
|
||||
}
|
||||
@@ -4323,9 +4341,11 @@ static void tcpm_typec_disconnect(struct tcpm_port *port)
|
||||
port->plug_prime = NULL;
|
||||
port->cable = NULL;
|
||||
if (port->connected) {
|
||||
typec_partner_set_usb_power_delivery(port->partner, NULL);
|
||||
typec_unregister_partner(port->partner);
|
||||
port->partner = NULL;
|
||||
if (port->partner) {
|
||||
typec_partner_set_usb_power_delivery(port->partner, NULL);
|
||||
typec_unregister_partner(port->partner);
|
||||
port->partner = NULL;
|
||||
}
|
||||
port->connected = false;
|
||||
}
|
||||
}
|
||||
@@ -4549,6 +4569,9 @@ static enum typec_cc_status tcpm_pwr_opmode_to_rp(enum typec_pwr_opmode opmode)
|
||||
|
||||
static void tcpm_set_initial_svdm_version(struct tcpm_port *port)
|
||||
{
|
||||
if (!port->partner)
|
||||
return;
|
||||
|
||||
switch (port->negotiated_rev) {
|
||||
case PD_REV30:
|
||||
break;
|
||||
@@ -5605,6 +5628,7 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
break;
|
||||
case PORT_RESET:
|
||||
tcpm_reset_port(port);
|
||||
port->pd_events = 0;
|
||||
if (port->self_powered)
|
||||
tcpm_set_cc(port, TYPEC_CC_OPEN);
|
||||
else
|
||||
|
||||
+37
-1
@@ -979,6 +979,34 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ffd.file pointer may be in the process of being torn down due to
|
||||
* being closed, but we may not have finished eventpoll_release() yet.
|
||||
*
|
||||
* Normally, even with the atomic_long_inc_not_zero, the file may have
|
||||
* been free'd and then gotten re-allocated to something else (since
|
||||
* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
|
||||
*
|
||||
* But for epoll, users hold the ep->mtx mutex, and as such any file in
|
||||
* the process of being free'd will block in eventpoll_release_file()
|
||||
* and thus the underlying file allocation will not be free'd, and the
|
||||
* file re-use cannot happen.
|
||||
*
|
||||
* For the same reason we can avoid a rcu_read_lock() around the
|
||||
* operation - 'ffd.file' cannot go away even if the refcount has
|
||||
* reached zero (but we must still not call out to ->poll() functions
|
||||
* etc).
|
||||
*/
|
||||
static struct file *epi_fget(const struct epitem *epi)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
file = epi->ffd.file;
|
||||
if (!atomic_long_inc_not_zero(&file->f_count))
|
||||
file = NULL;
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Differs from ep_eventpoll_poll() in that internal callers already have
|
||||
* the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
|
||||
@@ -987,14 +1015,22 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
|
||||
static __poll_t ep_item_poll(const struct epitem *epi, poll_table *pt,
|
||||
int depth)
|
||||
{
|
||||
struct file *file = epi->ffd.file;
|
||||
struct file *file = epi_fget(epi);
|
||||
__poll_t res;
|
||||
|
||||
/*
|
||||
* We could return EPOLLERR | EPOLLHUP or something, but let's
|
||||
* treat this more as "file doesn't exist, poll didn't happen".
|
||||
*/
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
pt->_key = epi->event.events;
|
||||
if (!is_file_epoll(file))
|
||||
res = vfs_poll(file, pt);
|
||||
else
|
||||
res = __ep_eventpoll_poll(file, pt, depth);
|
||||
fput(file);
|
||||
return res & epi->event.events;
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -511,7 +511,7 @@ static inline bool lockdep_softirq_start(void) { return false; }
|
||||
static inline void lockdep_softirq_end(bool in_hardirq) { }
|
||||
#endif
|
||||
|
||||
asmlinkage __visible void __softirq_entry __do_softirq(void)
|
||||
static void handle_softirqs(bool ksirqd)
|
||||
{
|
||||
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
|
||||
unsigned long old_flags = current->flags;
|
||||
@@ -566,8 +566,7 @@ restart:
|
||||
pending >>= softirq_bit;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT_RT) &&
|
||||
__this_cpu_read(ksoftirqd) == current)
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT_RT) && ksirqd)
|
||||
rcu_softirq_qs();
|
||||
|
||||
local_irq_disable();
|
||||
@@ -587,6 +586,11 @@ restart:
|
||||
current_restore_flags(old_flags, PF_MEMALLOC);
|
||||
}
|
||||
|
||||
asmlinkage __visible void __softirq_entry __do_softirq(void)
|
||||
{
|
||||
handle_softirqs(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_enter_rcu - Enter an interrupt context with RCU watching
|
||||
*/
|
||||
@@ -924,7 +928,7 @@ static void run_ksoftirqd(unsigned int cpu)
|
||||
* We can safely run softirq on inline stack, as we are not deep
|
||||
* in the task stack here.
|
||||
*/
|
||||
__do_softirq();
|
||||
handle_softirqs(true);
|
||||
ksoftirqd_run_end();
|
||||
cond_resched();
|
||||
return;
|
||||
|
||||
@@ -1466,7 +1466,7 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
|
||||
parg->fmt = kmalloc(len, GFP_KERNEL);
|
||||
if (!parg->fmt) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto fail;
|
||||
}
|
||||
snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
|
||||
parg->count);
|
||||
|
||||
+5
-1
@@ -302,7 +302,11 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
|
||||
} else {
|
||||
for (end = buf; *end && !isspace(*end); end++)
|
||||
;
|
||||
BUG_ON(end == buf);
|
||||
if (end == buf) {
|
||||
pr_err("parse err after word:%d=%s\n", nwords,
|
||||
nwords ? words[nwords - 1] : "<none>");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* `buf' is start of word, `end' is one past its end */
|
||||
|
||||
Reference in New Issue
Block a user