diff options
Diffstat (limited to 'drivers')
33 files changed, 255 insertions, 152 deletions
| diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 8c99ceaa303b..a3a1b5c33ba3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -851,17 +851,8 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong,  	} else {  		if (!internal)  			node->local_weak_refs++; -		if (!node->has_weak_ref && list_empty(&node->work.entry)) { -			if (target_list == NULL) { -				pr_err("invalid inc weak node for %d\n", -					node->debug_id); -				return -EINVAL; -			} -			/* -			 * See comment above -			 */ +		if (!node->has_weak_ref && target_list && list_empty(&node->work.entry))  			binder_enqueue_work_ilocked(&node->work, target_list); -		}  	}  	return 0;  } @@ -2418,10 +2409,10 @@ err_fd_not_accepted:  /**   * struct binder_ptr_fixup - data to be fixed-up in target buffer - * @offset	offset in target buffer to fixup - * @skip_size	bytes to skip in copy (fixup will be written later) - * @fixup_data	data to write at fixup offset - * @node	list node + * @offset:      offset in target buffer to fixup + * @skip_size:   bytes to skip in copy (fixup will be written later) + * @fixup_data:  data to write at fixup offset + * @node:        list node   *   * This is used for the pointer fixup list (pf) which is created and consumed   * during binder_transaction() and is only accessed locally. No @@ -2438,10 +2429,10 @@ struct binder_ptr_fixup {  /**   * struct binder_sg_copy - scatter-gather data to be copied - * @offset		offset in target buffer - * @sender_uaddr	user address in source buffer - * @length		bytes to copy - * @node		list node + * @offset:        offset in target buffer + * @sender_uaddr:  user address in source buffer + * @length:        bytes to copy + * @node:          list node   *   * This is used for the sg copy list (sgc) which is created and consumed   * during binder_transaction() and is only accessed locally. No @@ -4063,14 +4054,15 @@ binder_freeze_notification_done(struct binder_proc *proc,  /**   * binder_free_buf() - free the specified buffer - * @proc:	binder proc that owns buffer - * @buffer:	buffer to be freed - * @is_failure:	failed to send transaction + * @proc:       binder proc that owns buffer + * @thread:     binder thread performing the buffer release + * @buffer:     buffer to be freed + * @is_failure: failed to send transaction   * - * If buffer for an async transaction, enqueue the next async + * If the buffer is for an async transaction, enqueue the next async   * transaction from the node.   * - * Cleanup buffer and free it. + * Cleanup the buffer and free it.   */  static void  binder_free_buf(struct binder_proc *proc, diff --git a/drivers/android/binder/freeze.rs b/drivers/android/binder/freeze.rs index e68c3c8bc55a..220de35ae85a 100644 --- a/drivers/android/binder/freeze.rs +++ b/drivers/android/binder/freeze.rs @@ -106,13 +106,22 @@ impl DeliverToRead for FreezeMessage {              return Ok(true);          }          if freeze.is_clearing { -            _removed_listener = freeze_entry.remove_node(); +            kernel::warn_on!(freeze.num_cleared_duplicates != 0); +            if freeze.num_pending_duplicates > 0 { +                // The primary freeze listener was deleted, so convert a pending duplicate back +                // into the primary one. +                freeze.num_pending_duplicates -= 1; +                freeze.is_pending = true; +                freeze.is_clearing = true; +            } else { +                _removed_listener = freeze_entry.remove_node(); +            }              drop(node_refs);              writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;              writer.write_payload(&self.cookie.0)?;              Ok(true)          } else { -            let is_frozen = freeze.node.owner.inner.lock().is_frozen; +            let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();              if freeze.last_is_frozen == Some(is_frozen) {                  return Ok(true);              } @@ -245,8 +254,9 @@ impl Process {                  );                  return Err(EINVAL);              } -            if freeze.is_clearing { -                // Immediately send another FreezeMessage for BR_CLEAR_FREEZE_NOTIFICATION_DONE. +            let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen(); +            if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) { +                // Immediately send another FreezeMessage.                  clear_msg = Some(FreezeMessage::init(alloc, cookie));              }              freeze.is_pending = false; diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index ade895ef791e..08d362deaf61 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -687,7 +687,7 @@ impl Node {              );          }          if inner.freeze_list.is_empty() { -            _unused_capacity = mem::replace(&mut inner.freeze_list, KVVec::new()); +            _unused_capacity = mem::take(&mut inner.freeze_list);          }      } diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index f13a747e784c..7607353a5e92 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -72,6 +72,33 @@ impl Mapping {  const PROC_DEFER_FLUSH: u8 = 1;  const PROC_DEFER_RELEASE: u8 = 2; +#[derive(Copy, Clone)] +pub(crate) enum IsFrozen { +    Yes, +    No, +    InProgress, +} + +impl IsFrozen { +    /// Whether incoming transactions should be rejected due to freeze. +    pub(crate) fn is_frozen(self) -> bool { +        match self { +            IsFrozen::Yes => true, +            IsFrozen::No => false, +            IsFrozen::InProgress => true, +        } +    } + +    /// Whether freeze notifications consider this process frozen. +    pub(crate) fn is_fully_frozen(self) -> bool { +        match self { +            IsFrozen::Yes => true, +            IsFrozen::No => false, +            IsFrozen::InProgress => false, +        } +    } +} +  /// The fields of `Process` protected by the spinlock.  pub(crate) struct ProcessInner {      is_manager: bool, @@ -98,7 +125,7 @@ pub(crate) struct ProcessInner {      /// are woken up.      outstanding_txns: u32,      /// Process is frozen and unable to service binder transactions. -    pub(crate) is_frozen: bool, +    pub(crate) is_frozen: IsFrozen,      /// Process received sync transactions since last frozen.      pub(crate) sync_recv: bool,      /// Process received async transactions since last frozen. @@ -124,7 +151,7 @@ impl ProcessInner {              started_thread_count: 0,              defer_work: 0,              outstanding_txns: 0, -            is_frozen: false, +            is_frozen: IsFrozen::No,              sync_recv: false,              async_recv: false,              binderfs_file: None, @@ -1260,7 +1287,7 @@ impl Process {          let is_manager = {              let mut inner = self.inner.lock();              inner.is_dead = true; -            inner.is_frozen = false; +            inner.is_frozen = IsFrozen::No;              inner.sync_recv = false;              inner.async_recv = false;              inner.is_manager @@ -1346,10 +1373,6 @@ impl Process {                  .alloc                  .take_for_each(|offset, size, debug_id, odata| {                      let ptr = offset + address; -                    pr_warn!( -                        "{}: removing orphan mapping {offset}:{size}\n", -                        self.pid_in_current_ns() -                    );                      let mut alloc =                          Allocation::new(self.clone(), debug_id, offset, size, ptr, false);                      if let Some(data) = odata { @@ -1371,7 +1394,7 @@ impl Process {                  return;              }              inner.outstanding_txns -= 1; -            inner.is_frozen && inner.outstanding_txns == 0 +            inner.is_frozen.is_frozen() && inner.outstanding_txns == 0          };          if wake { @@ -1385,7 +1408,7 @@ impl Process {              let mut inner = self.inner.lock();              inner.sync_recv = false;              inner.async_recv = false; -            inner.is_frozen = false; +            inner.is_frozen = IsFrozen::No;              drop(inner);              msgs.send_messages();              return Ok(()); @@ -1394,7 +1417,7 @@ impl Process {          let mut inner = self.inner.lock();          inner.sync_recv = false;          inner.async_recv = false; -        inner.is_frozen = true; +        inner.is_frozen = IsFrozen::InProgress;          if info.timeout_ms > 0 {              let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms); @@ -1408,7 +1431,7 @@ impl Process {                      .wait_interruptible_timeout(&mut inner, jiffies)                  {                      CondVarTimeoutResult::Signal { .. } => { -                        inner.is_frozen = false; +                        inner.is_frozen = IsFrozen::No;                          return Err(ERESTARTSYS);                      }                      CondVarTimeoutResult::Woken { jiffies: remaining } => { @@ -1422,17 +1445,18 @@ impl Process {          }          if inner.txns_pending_locked() { -            inner.is_frozen = false; +            inner.is_frozen = IsFrozen::No;              Err(EAGAIN)          } else {              drop(inner);              match self.prepare_freeze_messages() {                  Ok(batch) => { +                    self.inner.lock().is_frozen = IsFrozen::Yes;                      batch.send_messages();                      Ok(())                  }                  Err(kernel::alloc::AllocError) => { -                    self.inner.lock().is_frozen = false; +                    self.inner.lock().is_frozen = IsFrozen::No;                      Err(ENOMEM)                  }              } diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 02512175d622..4bd3c0e417eb 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -249,7 +249,7 @@ impl Transaction {          if oneway {              if let Some(target_node) = self.target_node.clone() { -                if process_inner.is_frozen { +                if process_inner.is_frozen.is_frozen() {                      process_inner.async_recv = true;                      if self.flags & TF_UPDATE_TXN != 0 {                          if let Some(t_outdated) = @@ -270,7 +270,7 @@ impl Transaction {                      }                  } -                if process_inner.is_frozen { +                if process_inner.is_frozen.is_frozen() {                      return Err(BinderError::new_frozen_oneway());                  } else {                      return Ok(()); @@ -280,7 +280,7 @@ impl Transaction {              }          } -        if process_inner.is_frozen { +        if process_inner.is_frozen.is_frozen() {              process_inner.sync_recv = true;              return Err(BinderError::new_frozen());          } diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 1037169abb45..e1eff05bea4a 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -292,7 +292,7 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)  		 * frequency (by keeping the initial capacity_freq_ref value).  		 */  		cpu_clk = of_clk_get(cpu_node, 0); -		if (!PTR_ERR_OR_ZERO(cpu_clk)) { +		if (!IS_ERR_OR_NULL(cpu_clk)) {  			per_cpu(capacity_freq_ref, cpu) =  				clk_get_rate(cpu_clk) / HZ_PER_KHZ;  			clk_put(cpu_clk); diff --git a/drivers/base/core.c b/drivers/base/core.c index 3c533dab8fa5..f69dc9c85954 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1784,7 +1784,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data)  		return 0;  	if (fw_devlink_sync_state == FW_DEVLINK_SYNC_STATE_STRICT) { -		dev_warn(sup, "sync_state() pending due to %s\n", +		dev_info(sup, "sync_state() pending due to %s\n",  			 dev_name(link->consumer));  		return 0;  	} diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 37faf6156d7c..55bdc7f5e59d 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -23,50 +23,46 @@ struct devcd_entry {  	void *data;  	size_t datalen;  	/* -	 * Here, mutex is required to serialize the calls to del_wk work between -	 * user/kernel space which happens when devcd is added with device_add() -	 * and that sends uevent to user space. User space reads the uevents, -	 * and calls to devcd_data_write() which try to modify the work which is -	 * not even initialized/queued from devcoredump. +	 * There are 2 races for which mutex is required.  	 * +	 * The first race is between device creation and userspace writing to +	 * schedule immediately destruction.  	 * +	 * This race is handled by arming the timer before device creation, but +	 * when device creation fails the timer still exists.  	 * -	 *        cpu0(X)                                 cpu1(Y) +	 * To solve this, hold the mutex during device_add(), and set +	 * init_completed on success before releasing the mutex.  	 * -	 *        dev_coredump() uevent sent to user space -	 *        device_add()  ======================> user space process Y reads the -	 *                                              uevents writes to devcd fd -	 *                                              which results into writes to +	 * That way the timer will never fire until device_add() is called, +	 * it will do nothing if init_completed is not set. The timer is also +	 * cancelled in that case.  	 * -	 *                                             devcd_data_write() -	 *                                               mod_delayed_work() -	 *                                                 try_to_grab_pending() -	 *                                                   timer_delete() -	 *                                                     debug_assert_init() -	 *       INIT_DELAYED_WORK() -	 *       schedule_delayed_work() -	 * -	 * -	 * Also, mutex alone would not be enough to avoid scheduling of -	 * del_wk work after it get flush from a call to devcd_free() -	 * mentioned as below. -	 * -	 *	disabled_store() -	 *        devcd_free() -	 *          mutex_lock()             devcd_data_write() -	 *          flush_delayed_work() -	 *          mutex_unlock() -	 *                                   mutex_lock() -	 *                                   mod_delayed_work() -	 *                                   mutex_unlock() -	 * So, delete_work flag is required. +	 * The second race involves multiple parallel invocations of devcd_free(), +	 * add a deleted flag so only 1 can call the destructor.  	 */  	struct mutex mutex; -	bool delete_work; +	bool init_completed, deleted;  	struct module *owner;  	ssize_t (*read)(char *buffer, loff_t offset, size_t count,  			void *data, size_t datalen);  	void (*free)(void *data); +	/* +	 * If nothing interferes and device_add() was returns success, +	 * del_wk will destroy the device after the timer fires. +	 * +	 * Multiple userspace processes can interfere in the working of the timer: +	 * - Writing to the coredump will reschedule the timer to run immediately, +	 *   if still armed. +	 * +	 *   This is handled by using "if (cancel_delayed_work()) { +	 *   schedule_delayed_work() }", to prevent re-arming after having +	 *   been previously fired. +	 * - Writing to /sys/class/devcoredump/disabled will destroy the +	 *   coredump synchronously. +	 *   This is handled by using disable_delayed_work_sync(), and then +	 *   checking if deleted flag is set with &devcd->mutex held. +	 */  	struct delayed_work del_wk;  	struct device *failing_dev;  }; @@ -95,14 +91,27 @@ static void devcd_dev_release(struct device *dev)  	kfree(devcd);  } +static void __devcd_del(struct devcd_entry *devcd) +{ +	devcd->deleted = true; +	device_del(&devcd->devcd_dev); +	put_device(&devcd->devcd_dev); +} +  static void devcd_del(struct work_struct *wk)  {  	struct devcd_entry *devcd; +	bool init_completed;  	devcd = container_of(wk, struct devcd_entry, del_wk.work); -	device_del(&devcd->devcd_dev); -	put_device(&devcd->devcd_dev); +	/* devcd->mutex serializes against dev_coredumpm_timeout */ +	mutex_lock(&devcd->mutex); +	init_completed = devcd->init_completed; +	mutex_unlock(&devcd->mutex); + +	if (init_completed) +		__devcd_del(devcd);  }  static ssize_t devcd_data_read(struct file *filp, struct kobject *kobj, @@ -122,12 +131,12 @@ static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj,  	struct device *dev = kobj_to_dev(kobj);  	struct devcd_entry *devcd = dev_to_devcd(dev); -	mutex_lock(&devcd->mutex); -	if (!devcd->delete_work) { -		devcd->delete_work = true; -		mod_delayed_work(system_wq, &devcd->del_wk, 0); -	} -	mutex_unlock(&devcd->mutex); +	/* +	 * Although it's tempting to use mod_delayed work here, +	 * that will cause a reschedule if the timer already fired. +	 */ +	if (cancel_delayed_work(&devcd->del_wk)) +		schedule_delayed_work(&devcd->del_wk, 0);  	return count;  } @@ -151,11 +160,21 @@ static int devcd_free(struct device *dev, void *data)  {  	struct devcd_entry *devcd = dev_to_devcd(dev); +	/* +	 * To prevent a race with devcd_data_write(), disable work and +	 * complete manually instead. +	 * +	 * We cannot rely on the return value of +	 * disable_delayed_work_sync() here, because it might be in the +	 * middle of a cancel_delayed_work + schedule_delayed_work pair. +	 * +	 * devcd->mutex here guards against multiple parallel invocations +	 * of devcd_free(). +	 */ +	disable_delayed_work_sync(&devcd->del_wk);  	mutex_lock(&devcd->mutex); -	if (!devcd->delete_work) -		devcd->delete_work = true; - -	flush_delayed_work(&devcd->del_wk); +	if (!devcd->deleted) +		__devcd_del(devcd);  	mutex_unlock(&devcd->mutex);  	return 0;  } @@ -179,12 +198,10 @@ static ssize_t disabled_show(const struct class *class, const struct class_attri   *                                                                 put_device() <- last reference   *             error = fn(dev, data)                           devcd_dev_release()   *             devcd_free(dev, data)                           kfree(devcd) - *             mutex_lock(&devcd->mutex);   *   *   * In the above diagram, it looks like disabled_store() would be racing with parallelly - * running devcd_del() and result in memory abort while acquiring devcd->mutex which - * is called after kfree of devcd memory after dropping its last reference with + * running devcd_del() and result in memory abort after dropping its last reference with   * put_device(). However, this will not happens as fn(dev, data) runs   * with its own reference to device via klist_node so it is not its last reference.   * so, above situation would not occur. @@ -374,7 +391,7 @@ void dev_coredumpm_timeout(struct device *dev, struct module *owner,  	devcd->read = read;  	devcd->free = free;  	devcd->failing_dev = get_device(dev); -	devcd->delete_work = false; +	devcd->deleted = false;  	mutex_init(&devcd->mutex);  	device_initialize(&devcd->devcd_dev); @@ -383,8 +400,14 @@ void dev_coredumpm_timeout(struct device *dev, struct module *owner,  		     atomic_inc_return(&devcd_count));  	devcd->devcd_dev.class = &devcd_class; -	mutex_lock(&devcd->mutex);  	dev_set_uevent_suppress(&devcd->devcd_dev, true); + +	/* devcd->mutex prevents devcd_del() completing until init finishes */ +	mutex_lock(&devcd->mutex); +	devcd->init_completed = false; +	INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); +	schedule_delayed_work(&devcd->del_wk, timeout); +  	if (device_add(&devcd->devcd_dev))  		goto put_device; @@ -401,13 +424,20 @@ void dev_coredumpm_timeout(struct device *dev, struct module *owner,  	dev_set_uevent_suppress(&devcd->devcd_dev, false);  	kobject_uevent(&devcd->devcd_dev.kobj, KOBJ_ADD); -	INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); -	schedule_delayed_work(&devcd->del_wk, timeout); + +	/* +	 * Safe to run devcd_del() now that we are done with devcd_dev. +	 * Alternatively we could have taken a ref on devcd_dev before +	 * dropping the lock. +	 */ +	devcd->init_completed = true;  	mutex_unlock(&devcd->mutex);  	return;   put_device: -	put_device(&devcd->devcd_dev);  	mutex_unlock(&devcd->mutex); +	cancel_delayed_work_sync(&devcd->del_wk); +	put_device(&devcd->devcd_dev); +   put_module:  	module_put(owner);   free: diff --git a/drivers/comedi/comedi_buf.c b/drivers/comedi/comedi_buf.c index 002c0e76baff..c7c262a2d8ca 100644 --- a/drivers/comedi/comedi_buf.c +++ b/drivers/comedi/comedi_buf.c @@ -317,7 +317,7 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s,  	unsigned int count = 0;  	const unsigned int num_sample_bytes = comedi_bytes_per_sample(s); -	if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { +	if (!s->munge || (async->cmd.flags & CMDF_RAWDATA) || async->cmd.chanlist_len == 0) {  		async->munge_count += num_bytes;  		return num_bytes;  	} diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig index 4aae0733d0fc..ab594908cb4a 100644 --- a/drivers/misc/amd-sbi/Kconfig +++ b/drivers/misc/amd-sbi/Kconfig @@ -2,9 +2,11 @@  config AMD_SBRMI_I2C  	tristate "AMD side band RMI support"  	depends on I2C +	depends on ARM || ARM64 || COMPILE_TEST  	select REGMAP_I2C  	help  	  Side band RMI over I2C support for AMD out of band management. +	  This driver is intended to run on the BMC, not the managed node.  	  This driver can also be built as a module. If so, the module will  	  be called sbrmi-i2c. diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 621bce7e101c..ee652ef01534 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -381,6 +381,8 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,  	}  	spin_unlock(&fl->lock); +	dma_buf_put(buf); +  	return ret;  } diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index bc40b940ae21..a4f75dc36929 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -120,6 +120,8 @@  #define MEI_DEV_ID_PTL_H      0xE370  /* Panther Lake H */  #define MEI_DEV_ID_PTL_P      0xE470  /* Panther Lake P */ +#define MEI_DEV_ID_WCL_P      0x4D70  /* Wildcat Lake P */ +  /*   * MEI HW Section   */ diff --git a/drivers/misc/mei/mei_lb.c b/drivers/misc/mei/mei_lb.c index 77686b108d3c..78717ee8ac9a 100644 --- a/drivers/misc/mei/mei_lb.c +++ b/drivers/misc/mei/mei_lb.c @@ -134,8 +134,7 @@ static bool mei_lb_check_response(const struct device *dev, ssize_t bytes,  	return true;  } -static int mei_lb_push_payload(struct device *dev, -			       enum intel_lb_type type, u32 flags, +static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags,  			       const void *payload, size_t payload_size)  {  	struct mei_cl_device *cldev; diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index b108a7c22388..b017ff29dbd1 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -127,6 +127,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {  	{MEI_PCI_DEVICE(MEI_DEV_ID_PTL_H, MEI_ME_PCH15_CFG)},  	{MEI_PCI_DEVICE(MEI_DEV_ID_PTL_P, MEI_ME_PCH15_CFG)}, +	{MEI_PCI_DEVICE(MEI_DEV_ID_WCL_P, MEI_ME_PCH15_CFG)}, +  	/* required last entry */  	{0, }  }; diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index c9eb5c5393e4..06b55a891c6b 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -109,19 +109,19 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto end;  	} +	err = mei_register(dev, &pdev->dev); +	if (err) +		goto release_irq; +  	if (mei_start(dev)) {  		dev_err(&pdev->dev, "init hw failure.\n");  		err = -ENODEV; -		goto release_irq; +		goto deregister;  	}  	pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);  	pm_runtime_use_autosuspend(&pdev->dev); -	err = mei_register(dev, &pdev->dev); -	if (err) -		goto stop; -  	pci_set_drvdata(pdev, dev);  	/* @@ -144,8 +144,8 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	return 0; -stop: -	mei_stop(dev); +deregister: +	mei_deregister(dev);  release_irq:  	mei_cancel_work(dev);  	mei_disable_interrupts(dev); diff --git a/drivers/most/most_usb.c b/drivers/most/most_usb.c index cf5be9c449a5..10064d7b7249 100644 --- a/drivers/most/most_usb.c +++ b/drivers/most/most_usb.c @@ -929,6 +929,10 @@ static void release_mdev(struct device *dev)  {  	struct most_dev *mdev = to_mdev_from_dev(dev); +	kfree(mdev->busy_urbs); +	kfree(mdev->cap); +	kfree(mdev->conf); +	kfree(mdev->ep_address);  	kfree(mdev);  }  /** @@ -1093,7 +1097,7 @@ err_free_cap:  err_free_conf:  	kfree(mdev->conf);  err_free_mdev: -	put_device(&mdev->dev); +	kfree(mdev);  	return ret;  } @@ -1121,13 +1125,6 @@ static void hdm_disconnect(struct usb_interface *interface)  	if (mdev->dci)  		device_unregister(&mdev->dci->dev);  	most_deregister_interface(&mdev->iface); - -	kfree(mdev->busy_urbs); -	kfree(mdev->cap); -	kfree(mdev->conf); -	kfree(mdev->ep_address); -	put_device(&mdev->dci->dev); -	put_device(&mdev->dev);  }  static int hdm_suspend(struct usb_interface *interface, pm_message_t message) diff --git a/drivers/nvmem/rcar-efuse.c b/drivers/nvmem/rcar-efuse.c index f24bdb9cb5a7..d9a96a1d59c8 100644 --- a/drivers/nvmem/rcar-efuse.c +++ b/drivers/nvmem/rcar-efuse.c @@ -127,6 +127,7 @@ static const struct of_device_id rcar_fuse_match[] = {  	{ .compatible = "renesas,r8a779h0-otp", .data = &rcar_fuse_v4m },  	{ /* sentinel */ }  }; +MODULE_DEVICE_TABLE(of, rcar_fuse_match);  static struct platform_driver rcar_fuse_driver = {  	.probe = rcar_fuse_probe, diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c index 94bbb3b6576d..01a5bb43cd2d 100644 --- a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c +++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c @@ -182,10 +182,12 @@ static int agilent_82350b_accel_write(struct gpib_board *board, u8 *buffer,  		return retval;  #endif -	retval = agilent_82350b_write(board, buffer, 1, 0, &num_bytes); -	*bytes_written += num_bytes; -	if (retval < 0) -		return retval; +	if (fifotransferlength > 0) { +		retval = agilent_82350b_write(board, buffer, 1, 0, &num_bytes); +		*bytes_written += num_bytes; +		if (retval < 0) +			return retval; +	}  	write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BOIE, IMR0);  	for (i = 1; i < fifotransferlength;) { @@ -217,7 +219,7 @@ static int agilent_82350b_accel_write(struct gpib_board *board, u8 *buffer,  			break;  	}  	write_byte(tms_priv, tms_priv->imr0_bits, IMR0); -	if (retval) +	if (retval < 0)  		return retval;  	if (send_eoi) { diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c index 164dcfc3c9ef..f7bfb4a8e553 100644 --- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c @@ -1517,6 +1517,11 @@ void fmh_gpib_detach(struct gpib_board *board)  					   resource_size(e_priv->gpib_iomem_res));  	}  	fmh_gpib_generic_detach(board); + +	if (board->dev) { +		put_device(board->dev); +		board->dev = NULL; +	}  }  static int fmh_gpib_pci_attach_impl(struct gpib_board *board, diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c index 4dec87d12687..1f8412de9fa3 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c @@ -327,7 +327,10 @@ static void ni_usb_soft_update_status(struct gpib_board *board, unsigned int ni_  	board->status &= ~clear_mask;  	board->status &= ~ni_usb_ibsta_mask;  	board->status |= ni_usb_ibsta & ni_usb_ibsta_mask; -	// FIXME should generate events on DTAS and DCAS +	if (ni_usb_ibsta & DCAS) +		push_gpib_event(board, EVENT_DEV_CLR); +	if (ni_usb_ibsta & DTAS) +		push_gpib_event(board, EVENT_DEV_TRG);  	spin_lock_irqsave(&board->spinlock, flags);  /* remove set status bits from monitored set why ?***/ @@ -694,8 +697,12 @@ static int ni_usb_read(struct gpib_board *board, u8 *buffer, size_t length,  		 */  		break;  	case NIUSB_ATN_STATE_ERROR: -		retval = -EIO; -		dev_err(&usb_dev->dev, "read when ATN set\n"); +		if (status.ibsta & DCAS) { +			retval = -EINTR; +		} else { +			retval = -EIO; +			dev_dbg(&usb_dev->dev, "read when ATN set stat: 0x%06x\n", status.ibsta); +		}  		break;  	case NIUSB_ADDRESSING_ERROR:  		retval = -EIO; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a53ba04d9770..710ae4d40aec 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -635,7 +635,9 @@ static int dw8250_probe(struct platform_device *pdev)  	if (IS_ERR(data->rst))  		return PTR_ERR(data->rst); -	reset_control_deassert(data->rst); +	err = reset_control_deassert(data->rst); +	if (err) +		return dev_err_probe(dev, err, "failed to deassert resets\n");  	err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst);  	if (err) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 04a0cbab02c2..b9cc0b786ca6 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -40,6 +40,8 @@  #define PCI_DEVICE_ID_ACCESSIO_COM_4SM		0x10db  #define PCI_DEVICE_ID_ACCESSIO_COM_8SM		0x10ea +#define PCI_DEVICE_ID_ADVANTECH_XR17V352	0x0018 +  #define PCI_DEVICE_ID_COMMTECH_4224PCI335	0x0002  #define PCI_DEVICE_ID_COMMTECH_4222PCI335	0x0004  #define PCI_DEVICE_ID_COMMTECH_2324PCI335	0x000a @@ -1622,6 +1624,12 @@ static const struct exar8250_board pbn_fastcom35x_8 = {  	.exit		= pci_xr17v35x_exit,  }; +static const struct exar8250_board pbn_adv_XR17V352 = { +	.num_ports	= 2, +	.setup		= pci_xr17v35x_setup, +	.exit		= pci_xr17v35x_exit, +}; +  static const struct exar8250_board pbn_exar_XR17V4358 = {  	.num_ports	= 12,  	.setup		= pci_xr17v35x_setup, @@ -1696,6 +1704,9 @@ static const struct pci_device_id exar_pci_tbl[] = {  	USR_DEVICE(XR17C152, 2980, pbn_exar_XR17C15x),  	USR_DEVICE(XR17C152, 2981, pbn_exar_XR17C15x), +	/* ADVANTECH devices */ +	EXAR_DEVICE(ADVANTECH, XR17V352, pbn_adv_XR17V352), +  	/* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */  	EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x),  	EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index b44de2ed7413..5875a7b9b4b1 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -435,6 +435,7 @@ static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)  	while  		(serial_in(up, MTK_UART_DEBUG0)); +	clk_disable_unprepare(data->uart_clk);  	clk_disable_unprepare(data->bus_clk);  	return 0; @@ -445,6 +446,7 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev)  	struct mtk8250_data *data = dev_get_drvdata(dev);  	clk_prepare_enable(data->bus_clk); +	clk_prepare_enable(data->uart_clk);  	return 0;  } @@ -475,13 +477,13 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,  	int dmacnt;  #endif -	data->uart_clk = devm_clk_get(&pdev->dev, "baud"); +	data->uart_clk = devm_clk_get_enabled(&pdev->dev, "baud");  	if (IS_ERR(data->uart_clk)) {  		/*  		 * For compatibility with older device trees try unnamed  		 * clk when no baud clk can be found.  		 */ -		data->uart_clk = devm_clk_get(&pdev->dev, NULL); +		data->uart_clk = devm_clk_get_enabled(&pdev->dev, NULL);  		if (IS_ERR(data->uart_clk)) {  			dev_warn(&pdev->dev, "Can't get uart clock\n");  			return PTR_ERR(data->uart_clk); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 1a2c4c14f6aa..c7435595dce1 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -588,13 +588,6 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)  		div /= prescaler;  	} -	/* Enable enhanced features */ -	sc16is7xx_efr_lock(port); -	sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, -			      SC16IS7XX_EFR_ENABLE_BIT, -			      SC16IS7XX_EFR_ENABLE_BIT); -	sc16is7xx_efr_unlock(port); -  	/* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */  	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,  			      SC16IS7XX_MCR_CLKSEL_BIT, diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 538b2f991609..62bb62b82cbe 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1014,16 +1014,18 @@ static int sci_handle_fifo_overrun(struct uart_port *port)  	struct sci_port *s = to_sci_port(port);  	const struct plat_sci_reg *reg;  	int copied = 0; -	u16 status; +	u32 status; -	reg = sci_getreg(port, s->params->overrun_reg); -	if (!reg->size) -		return 0; +	if (s->type != SCI_PORT_RSCI) { +		reg = sci_getreg(port, s->params->overrun_reg); +		if (!reg->size) +			return 0; +	} -	status = sci_serial_in(port, s->params->overrun_reg); +	status = s->ops->read_reg(port, s->params->overrun_reg);  	if (status & s->params->overrun_mask) {  		status &= ~s->params->overrun_mask; -		sci_serial_out(port, s->params->overrun_reg, status); +		s->ops->write_reg(port, s->params->overrun_reg, status);  		port->icount.overrun++; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f5bc53875330..47f589c4104a 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -467,6 +467,8 @@ static const struct usb_device_id usb_quirk_list[] = {  	/* Huawei 4G LTE module */  	{ USB_DEVICE(0x12d1, 0x15bb), .driver_info =  			USB_QUIRK_DISCONNECT_SUSPEND }, +	{ USB_DEVICE(0x12d1, 0x15c1), .driver_info = +			USB_QUIRK_DISCONNECT_SUSPEND },  	{ USB_DEVICE(0x12d1, 0x15c3), .driver_info =  			USB_QUIRK_DISCONNECT_SUSPEND }, diff --git a/drivers/usb/dwc3/dwc3-generic-plat.c b/drivers/usb/dwc3/dwc3-generic-plat.c index d96b20570002..f8ad79c08c4e 100644 --- a/drivers/usb/dwc3/dwc3-generic-plat.c +++ b/drivers/usb/dwc3/dwc3-generic-plat.c @@ -85,11 +85,8 @@ static int dwc3_generic_probe(struct platform_device *pdev)  static void dwc3_generic_remove(struct platform_device *pdev)  {  	struct dwc3 *dwc = platform_get_drvdata(pdev); -	struct dwc3_generic *dwc3g = to_dwc3_generic(dwc);  	dwc3_core_remove(dwc); - -	clk_bulk_disable_unprepare(dwc3g->num_clocks, dwc3g->clks);  }  static int dwc3_generic_suspend(struct device *dev) diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index 20165e1582d9..b71680c58de6 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -667,8 +667,6 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,  		return ERR_PTR(-EINVAL);  	if (!usb_raw_io_flags_valid(io->flags))  		return ERR_PTR(-EINVAL); -	if (io->length > PAGE_SIZE) -		return ERR_PTR(-EINVAL);  	if (get_from_user)  		data = memdup_user(ptr + sizeof(*io), io->length);  	else { diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 63edf2d8f245..ecda964e018a 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -892,7 +892,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)  			dev_info(dbc->dev, "DbC configured\n");  			portsc = readl(&dbc->regs->portsc);  			writel(portsc, &dbc->regs->portsc); -			return EVT_GSER; +			ret = EVT_GSER; +			break;  		}  		return EVT_DONE; @@ -954,7 +955,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)  			break;  		case TRB_TYPE(TRB_TRANSFER):  			dbc_handle_xfer_event(dbc, evt); -			ret = EVT_XFER_DONE; +			if (ret != EVT_GSER) +				ret = EVT_XFER_DONE;  			break;  		default:  			break; @@ -1390,8 +1392,15 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci)  	if (!dbc)  		return 0; -	if (dbc->state == DS_CONFIGURED) +	switch (dbc->state) { +	case DS_ENABLED: +	case DS_CONNECTED: +	case DS_CONFIGURED:  		dbc->resume_required = 1; +		break; +	default: +		break; +	}  	xhci_dbc_stop(dbc); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5c8ab519f497..f67a4d956204 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -582,6 +582,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)  	if (!usb_hcd_is_primary_hcd(hcd))  		return 0; +	xhci->allow_single_roothub = 1; +  	if (xhci->quirks & XHCI_PME_STUCK_QUIRK)  		xhci_pme_acpi_rtd3_enable(pdev); @@ -637,7 +639,6 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)  	xhci = hcd_to_xhci(hcd);  	xhci->reset = reset; -	xhci->allow_single_roothub = 1;  	if (!xhci_has_one_roothub(xhci)) {  		xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev,  							 pci_name(dev), hcd); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 09ac6f1c985f..0b56b773dbdf 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -182,6 +182,7 @@ config USB_LJCA  config USB_USBIO  	tristate "Intel USBIO Bridge support"  	depends on USB && ACPI +	depends on X86 || COMPILE_TEST  	select AUXILIARY_BUS  	help  	  This adds support for Intel USBIO drivers. diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 62e984d20e59..5de856f65f0d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -273,6 +273,7 @@ static void option_instat_callback(struct urb *urb);  #define QUECTEL_PRODUCT_EM05CN			0x0312  #define QUECTEL_PRODUCT_EM05G_GR		0x0313  #define QUECTEL_PRODUCT_EM05G_RS		0x0314 +#define QUECTEL_PRODUCT_RG255C			0x0316  #define QUECTEL_PRODUCT_EM12			0x0512  #define QUECTEL_PRODUCT_RM500Q			0x0800  #define QUECTEL_PRODUCT_RM520N			0x0801 @@ -617,6 +618,7 @@ static void option_instat_callback(struct urb *urb);  #define UNISOC_VENDOR_ID			0x1782  /* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */  #define TOZED_PRODUCT_LT70C			0x4055 +#define UNISOC_PRODUCT_UIS7720			0x4064  /* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */  #define LUAT_PRODUCT_AIR720U			0x4e00 @@ -1270,6 +1272,9 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) },  	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) },  	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },  	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, @@ -1398,10 +1403,14 @@ static const struct usb_device_id option_ids[] = {  	  .driver_info = RSVD(0) | NCTRL(3) },  	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a2, 0xff),	/* Telit FN920C04 (MBIM) */  	  .driver_info = NCTRL(4) }, +	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a3, 0xff),	/* Telit FN920C04 (ECM) */ +	  .driver_info = NCTRL(4) },  	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a4, 0xff),	/* Telit FN20C04 (rmnet) */  	  .driver_info = RSVD(0) | NCTRL(3) },  	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a7, 0xff),	/* Telit FN920C04 (MBIM) */  	  .driver_info = NCTRL(4) }, +	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a8, 0xff),	/* Telit FN920C04 (ECM) */ +	  .driver_info = NCTRL(4) },  	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a9, 0xff),	/* Telit FN20C04 (rmnet) */  	  .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) },  	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff),	/* Telit FN920C04 (MBIM) */ @@ -2466,6 +2475,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) },  	{ USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) },  	{ USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, UNISOC_PRODUCT_UIS7720, 0xff, 0, 0) },  	{ USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) },  	{ USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff),			/* TCL IK512 MBIM */  	  .driver_info = NCTRL(1) }, diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index b2a568a5bc9b..cc78770509db 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7876,9 +7876,9 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)  	port->partner_desc.identity = &port->partner_ident; -	port->role_sw = usb_role_switch_get(port->dev); +	port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode);  	if (!port->role_sw) -		port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); +		port->role_sw = usb_role_switch_get(port->dev);  	if (IS_ERR(port->role_sw)) {  		err = PTR_ERR(port->role_sw);  		goto out_destroy_wq; | 
