mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
Merge tag 'char-misc-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc / IIO driver fixes from Greg KH: "Here are some char/misc/iio/binder fixes for 7.0-rc4. Nothing major in here, just the usual: - lots of iio driver fixes for reported issues - rust binder fixes for problems found - gpib driver binding to the wrong device fix - firmware driver fix All of these have been in linux-next with no reported issues" * tag 'char-misc-7.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (28 commits) gpib: lpvo_usb: fix unintended binding of FTDI 8U232AM devices firmware: stratix10-svc: Add Multi SVC clients support rust_binder: use lock_vma_under_rcu() in use_page_slow() rust_binder: call set_notification_done() without proc lock rust_binder: avoid reading the written value in offsets array rust_binder: check ownership before using vma rust_binder: fix oneway spam detection firmware: stratix10-rsu: Fix NULL pointer dereference when RSU is disabled iio: imu: adis: Fix NULL pointer dereference in adis_init iio: imu: inv_icm45600: fix regulator put warning when probe fails iio: buffer: Fix wait_queue not being removed iio: gyro: mpu3050-core: fix pm_runtime error handling iio: gyro: mpu3050-i2c: fix pm_runtime error handling iio: adc: ad7768-1: Fix ERR_PTR dereference in ad7768_fill_scale_tbl iio: chemical: sps30_serial: fix buffer size in sps30_serial_read_meas() iio: chemical: sps30_i2c: fix buffer size in sps30_i2c_read_meas() iio: magnetometer: tlv493d: remove erroneous shift in X-axis data iio: proximity: hx9023s: Protect against division by zero in set_samp_freq iio: proximity: hx9023s: fix assignment order for __counted_by iio: chemical: bme680: Fix measurement wait duration calculation ...
This commit is contained in:
@@ -142,6 +142,30 @@ pub(crate) struct ShrinkablePageRange {
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
// We do not define any ops. For now, used only to check identity of vmas.
|
||||
static BINDER_VM_OPS: bindings::vm_operations_struct = pin_init::zeroed();
|
||||
|
||||
// To ensure that we do not accidentally install pages into or zap pages from the wrong vma, we
|
||||
// check its vm_ops and private data before using it.
|
||||
fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> {
|
||||
// SAFETY: Just reading the vm_ops pointer of any active vma is safe.
|
||||
let vm_ops = unsafe { (*vma.as_ptr()).vm_ops };
|
||||
if !ptr::eq(vm_ops, &BINDER_VM_OPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: Reading the vm_private_data pointer of a binder-owned vma is safe.
|
||||
let vm_private_data = unsafe { (*vma.as_ptr()).vm_private_data };
|
||||
// The ShrinkablePageRange is only dropped when the Process is dropped, which only happens once
|
||||
// the file's ->release handler is invoked, which means the ShrinkablePageRange outlives any
|
||||
// VMA associated with it, so there can't be any false positives due to pointer reuse here.
|
||||
if !ptr::eq(vm_private_data, owner.cast()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
vma.as_mixedmap_vma()
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
/// Array of pages.
|
||||
///
|
||||
@@ -308,6 +332,18 @@ impl ShrinkablePageRange {
|
||||
inner.size = num_pages;
|
||||
inner.vma_addr = vma.start();
|
||||
|
||||
// This pointer is only used for comparison - it's not dereferenced.
|
||||
//
|
||||
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
|
||||
// `vm_private_data`.
|
||||
unsafe {
|
||||
(*vma.as_ptr()).vm_private_data = ptr::from_ref(self).cast_mut().cast::<c_void>()
|
||||
};
|
||||
|
||||
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
|
||||
// `vm_ops`.
|
||||
unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS };
|
||||
|
||||
Ok(num_pages)
|
||||
}
|
||||
|
||||
@@ -399,22 +435,25 @@ impl ShrinkablePageRange {
|
||||
//
|
||||
// Using `mmput_async` avoids this, because then the `mm` cleanup is instead queued to a
|
||||
// workqueue.
|
||||
MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?)
|
||||
.mmap_read_lock()
|
||||
.vma_lookup(vma_addr)
|
||||
.ok_or(ESRCH)?
|
||||
.as_mixedmap_vma()
|
||||
.ok_or(ESRCH)?
|
||||
.vm_insert_page(user_page_addr, &new_page)
|
||||
.inspect_err(|err| {
|
||||
pr_warn!(
|
||||
"Failed to vm_insert_page({}): vma_addr:{} i:{} err:{:?}",
|
||||
user_page_addr,
|
||||
vma_addr,
|
||||
i,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
let mm = MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?);
|
||||
{
|
||||
let vma_read;
|
||||
let mmap_read;
|
||||
let vma = if let Some(ret) = mm.lock_vma_under_rcu(vma_addr) {
|
||||
vma_read = ret;
|
||||
check_vma(&vma_read, self)
|
||||
} else {
|
||||
mmap_read = mm.mmap_read_lock();
|
||||
mmap_read
|
||||
.vma_lookup(vma_addr)
|
||||
.and_then(|vma| check_vma(vma, self))
|
||||
};
|
||||
|
||||
match vma {
|
||||
Some(vma) => vma.vm_insert_page(user_page_addr, &new_page)?,
|
||||
None => return Err(ESRCH),
|
||||
}
|
||||
}
|
||||
|
||||
let inner = self.lock.lock();
|
||||
|
||||
@@ -667,12 +706,15 @@ unsafe extern "C" fn rust_shrink_free_page(
|
||||
let mmap_read;
|
||||
let mm_mutex;
|
||||
let vma_addr;
|
||||
let range_ptr;
|
||||
|
||||
{
|
||||
// CAST: The `list_head` field is first in `PageInfo`.
|
||||
let info = item as *mut PageInfo;
|
||||
// SAFETY: The `range` field of `PageInfo` is immutable.
|
||||
let range = unsafe { &*((*info).range) };
|
||||
range_ptr = unsafe { (*info).range };
|
||||
// SAFETY: The `range` outlives its `PageInfo` values.
|
||||
let range = unsafe { &*range_ptr };
|
||||
|
||||
mm = match range.mm.mmget_not_zero() {
|
||||
Some(mm) => MmWithUser::into_mmput_async(mm),
|
||||
@@ -717,9 +759,11 @@ unsafe extern "C" fn rust_shrink_free_page(
|
||||
// SAFETY: The lru lock is locked when this method is called.
|
||||
unsafe { bindings::spin_unlock(&raw mut (*lru).lock) };
|
||||
|
||||
if let Some(vma) = mmap_read.vma_lookup(vma_addr) {
|
||||
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
|
||||
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
|
||||
if let Some(unchecked_vma) = mmap_read.vma_lookup(vma_addr) {
|
||||
if let Some(vma) = check_vma(unchecked_vma, range_ptr) {
|
||||
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
|
||||
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
drop(mmap_read);
|
||||
|
||||
@@ -1295,7 +1295,8 @@ impl Process {
|
||||
}
|
||||
|
||||
pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) {
|
||||
if let Some(death) = self.inner.lock().pull_delivered_death(cookie) {
|
||||
let death = self.inner.lock().pull_delivered_death(cookie);
|
||||
if let Some(death) = death {
|
||||
death.set_notification_done(thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl<T> ArrayRangeAllocator<T> {
|
||||
size: usize,
|
||||
is_oneway: bool,
|
||||
pid: Pid,
|
||||
) -> Result<usize> {
|
||||
) -> Result<(usize, bool)> {
|
||||
// Compute new value of free_oneway_space, which is set only on success.
|
||||
let new_oneway_space = if is_oneway {
|
||||
match self.free_oneway_space.checked_sub(size) {
|
||||
@@ -146,7 +146,38 @@ impl<T> ArrayRangeAllocator<T> {
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
Ok(insert_at_offset)
|
||||
// Start detecting spammers once we have less than 20%
|
||||
// of async space left (which is less than 10% of total
|
||||
// buffer size).
|
||||
//
|
||||
// (This will short-circuit, so `low_oneway_space` is
|
||||
// only called when necessary.)
|
||||
let oneway_spam_detected =
|
||||
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
|
||||
|
||||
Ok((insert_at_offset, oneway_spam_detected))
|
||||
}
|
||||
|
||||
/// Find the amount and size of buffers allocated by the current caller.
|
||||
///
|
||||
/// The idea is that once we cross the threshold, whoever is responsible
|
||||
/// for the low async space is likely to try to send another async transaction,
|
||||
/// and at some point we'll catch them in the act. This is more efficient
|
||||
/// than keeping a map per pid.
|
||||
fn low_oneway_space(&self, calling_pid: Pid) -> bool {
|
||||
let mut total_alloc_size = 0;
|
||||
let mut num_buffers = 0;
|
||||
|
||||
// Warn if this pid has more than 50 transactions, or more than 50% of
|
||||
// async space (which is 25% of total buffer size). Oneway spam is only
|
||||
// detected when the threshold is exceeded.
|
||||
for range in &self.ranges {
|
||||
if range.state.is_oneway() && range.state.pid() == calling_pid {
|
||||
total_alloc_size += range.size;
|
||||
num_buffers += 1;
|
||||
}
|
||||
}
|
||||
num_buffers > 50 || total_alloc_size > self.size / 4
|
||||
}
|
||||
|
||||
pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange> {
|
||||
|
||||
@@ -188,11 +188,11 @@ impl<T> RangeAllocator<T> {
|
||||
self.reserve_new(args)
|
||||
}
|
||||
Impl::Array(array) => {
|
||||
let offset =
|
||||
let (offset, oneway_spam_detected) =
|
||||
array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?;
|
||||
Ok(ReserveNew::Success(ReserveNewSuccess {
|
||||
offset,
|
||||
oneway_spam_detected: false,
|
||||
oneway_spam_detected,
|
||||
_empty_array_alloc: args.empty_array_alloc,
|
||||
_new_tree_alloc: args.new_tree_alloc,
|
||||
_tree_alloc: args.tree_alloc,
|
||||
|
||||
@@ -164,15 +164,6 @@ impl<T> TreeRangeAllocator<T> {
|
||||
self.free_oneway_space
|
||||
};
|
||||
|
||||
// Start detecting spammers once we have less than 20%
|
||||
// of async space left (which is less than 10% of total
|
||||
// buffer size).
|
||||
//
|
||||
// (This will short-circut, so `low_oneway_space` is
|
||||
// only called when necessary.)
|
||||
let oneway_spam_detected =
|
||||
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
|
||||
|
||||
let (found_size, found_off, tree_node, free_tree_node) = match self.find_best_match(size) {
|
||||
None => {
|
||||
pr_warn!("ENOSPC from range_alloc.reserve_new - size: {}", size);
|
||||
@@ -203,6 +194,15 @@ impl<T> TreeRangeAllocator<T> {
|
||||
self.free_tree.insert(free_tree_node);
|
||||
}
|
||||
|
||||
// Start detecting spammers once we have less than 20%
|
||||
// of async space left (which is less than 10% of total
|
||||
// buffer size).
|
||||
//
|
||||
// (This will short-circuit, so `low_oneway_space` is
|
||||
// only called when necessary.)
|
||||
let oneway_spam_detected =
|
||||
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
|
||||
|
||||
Ok((found_off, oneway_spam_detected))
|
||||
}
|
||||
|
||||
|
||||
@@ -1015,12 +1015,9 @@ impl Thread {
|
||||
|
||||
// Copy offsets if there are any.
|
||||
if offsets_size > 0 {
|
||||
{
|
||||
let mut reader =
|
||||
UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
|
||||
.reader();
|
||||
alloc.copy_into(&mut reader, aligned_data_size, offsets_size)?;
|
||||
}
|
||||
let mut offsets_reader =
|
||||
UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
|
||||
.reader();
|
||||
|
||||
let offsets_start = aligned_data_size;
|
||||
let offsets_end = aligned_data_size + offsets_size;
|
||||
@@ -1041,11 +1038,9 @@ impl Thread {
|
||||
.step_by(size_of::<u64>())
|
||||
.enumerate()
|
||||
{
|
||||
let offset: usize = view
|
||||
.alloc
|
||||
.read::<u64>(index_offset)?
|
||||
.try_into()
|
||||
.map_err(|_| EINVAL)?;
|
||||
let offset = offsets_reader.read::<u64>()?;
|
||||
view.alloc.write(index_offset, &offset)?;
|
||||
let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
|
||||
|
||||
if offset < end_of_previous_object || !is_aligned(offset, size_of::<u32>()) {
|
||||
pr_warn!("Got transaction with invalid offset.");
|
||||
|
||||
@@ -768,7 +768,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
rsu_async_status_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting RSU status %i\n", ret);
|
||||
stratix10_svc_remove_async_client(priv->chan);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get DCMF version from firmware */
|
||||
|
||||
@@ -37,15 +37,14 @@
|
||||
* service layer will return error to FPGA manager when timeout occurs,
|
||||
* timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC.
|
||||
*/
|
||||
#define SVC_NUM_DATA_IN_FIFO 32
|
||||
#define SVC_NUM_DATA_IN_FIFO 8
|
||||
#define SVC_NUM_CHANNEL 4
|
||||
#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200
|
||||
#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 2000
|
||||
#define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30
|
||||
#define BYTE_TO_WORD_SIZE 4
|
||||
|
||||
/* stratix10 service layer clients */
|
||||
#define STRATIX10_RSU "stratix10-rsu"
|
||||
#define INTEL_FCS "intel-fcs"
|
||||
|
||||
/* Maximum number of SDM client IDs. */
|
||||
#define MAX_SDM_CLIENT_IDS 16
|
||||
@@ -105,11 +104,9 @@ struct stratix10_svc_chan;
|
||||
/**
|
||||
* struct stratix10_svc - svc private data
|
||||
* @stratix10_svc_rsu: pointer to stratix10 RSU device
|
||||
* @intel_svc_fcs: pointer to the FCS device
|
||||
*/
|
||||
struct stratix10_svc {
|
||||
struct platform_device *stratix10_svc_rsu;
|
||||
struct platform_device *intel_svc_fcs;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,12 +248,10 @@ struct stratix10_async_ctrl {
|
||||
* @num_active_client: number of active service client
|
||||
* @node: list management
|
||||
* @genpool: memory pool pointing to the memory region
|
||||
* @task: pointer to the thread task which handles SMC or HVC call
|
||||
* @svc_fifo: a queue for storing service message data
|
||||
* @complete_status: state for completion
|
||||
* @svc_fifo_lock: protect access to service message data queue
|
||||
* @invoke_fn: function to issue secure monitor call or hypervisor call
|
||||
* @svc: manages the list of client svc drivers
|
||||
* @sdm_lock: only allows a single command single response to SDM
|
||||
* @actrl: async control structure
|
||||
*
|
||||
* This struct is used to create communication channels for service clients, to
|
||||
@@ -269,12 +264,10 @@ struct stratix10_svc_controller {
|
||||
int num_active_client;
|
||||
struct list_head node;
|
||||
struct gen_pool *genpool;
|
||||
struct task_struct *task;
|
||||
struct kfifo svc_fifo;
|
||||
struct completion complete_status;
|
||||
spinlock_t svc_fifo_lock;
|
||||
svc_invoke_fn *invoke_fn;
|
||||
struct stratix10_svc *svc;
|
||||
struct mutex sdm_lock;
|
||||
struct stratix10_async_ctrl actrl;
|
||||
};
|
||||
|
||||
@@ -283,6 +276,9 @@ struct stratix10_svc_controller {
|
||||
* @ctrl: pointer to service controller which is the provider of this channel
|
||||
* @scl: pointer to service client which owns the channel
|
||||
* @name: service client name associated with the channel
|
||||
* @task: pointer to the thread task which handles SMC or HVC call
|
||||
* @svc_fifo: a queue for storing service message data (separate fifo for every channel)
|
||||
* @svc_fifo_lock: protect access to service message data queue (locking pending fifo)
|
||||
* @lock: protect access to the channel
|
||||
* @async_chan: reference to asynchronous channel object for this channel
|
||||
*
|
||||
@@ -293,6 +289,9 @@ struct stratix10_svc_chan {
|
||||
struct stratix10_svc_controller *ctrl;
|
||||
struct stratix10_svc_client *scl;
|
||||
char *name;
|
||||
struct task_struct *task;
|
||||
struct kfifo svc_fifo;
|
||||
spinlock_t svc_fifo_lock;
|
||||
spinlock_t lock;
|
||||
struct stratix10_async_chan *async_chan;
|
||||
};
|
||||
@@ -527,10 +526,10 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
|
||||
*/
|
||||
static int svc_normal_to_secure_thread(void *data)
|
||||
{
|
||||
struct stratix10_svc_controller
|
||||
*ctrl = (struct stratix10_svc_controller *)data;
|
||||
struct stratix10_svc_data *pdata;
|
||||
struct stratix10_svc_cb_data *cbdata;
|
||||
struct stratix10_svc_chan *chan = (struct stratix10_svc_chan *)data;
|
||||
struct stratix10_svc_controller *ctrl = chan->ctrl;
|
||||
struct stratix10_svc_data *pdata = NULL;
|
||||
struct stratix10_svc_cb_data *cbdata = NULL;
|
||||
struct arm_smccc_res res;
|
||||
unsigned long a0, a1, a2, a3, a4, a5, a6, a7;
|
||||
int ret_fifo = 0;
|
||||
@@ -555,12 +554,12 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
a6 = 0;
|
||||
a7 = 0;
|
||||
|
||||
pr_debug("smc_hvc_shm_thread is running\n");
|
||||
pr_debug("%s: %s: Thread is running!\n", __func__, chan->name);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
ret_fifo = kfifo_out_spinlocked(&ctrl->svc_fifo,
|
||||
ret_fifo = kfifo_out_spinlocked(&chan->svc_fifo,
|
||||
pdata, sizeof(*pdata),
|
||||
&ctrl->svc_fifo_lock);
|
||||
&chan->svc_fifo_lock);
|
||||
|
||||
if (!ret_fifo)
|
||||
continue;
|
||||
@@ -569,9 +568,25 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
(unsigned int)pdata->paddr, pdata->command,
|
||||
(unsigned int)pdata->size);
|
||||
|
||||
/* SDM can only process one command at a time */
|
||||
pr_debug("%s: %s: Thread is waiting for mutex!\n",
|
||||
__func__, chan->name);
|
||||
if (mutex_lock_interruptible(&ctrl->sdm_lock)) {
|
||||
/* item already dequeued; notify client to unblock it */
|
||||
cbdata->status = BIT(SVC_STATUS_ERROR);
|
||||
cbdata->kaddr1 = NULL;
|
||||
cbdata->kaddr2 = NULL;
|
||||
cbdata->kaddr3 = NULL;
|
||||
if (pdata->chan->scl)
|
||||
pdata->chan->scl->receive_cb(pdata->chan->scl,
|
||||
cbdata);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pdata->command) {
|
||||
case COMMAND_RECONFIG_DATA_CLAIM:
|
||||
svc_thread_cmd_data_claim(ctrl, pdata, cbdata);
|
||||
mutex_unlock(&ctrl->sdm_lock);
|
||||
continue;
|
||||
case COMMAND_RECONFIG:
|
||||
a0 = INTEL_SIP_SMC_FPGA_CONFIG_START;
|
||||
@@ -700,10 +715,11 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
break;
|
||||
default:
|
||||
pr_warn("it shouldn't happen\n");
|
||||
break;
|
||||
mutex_unlock(&ctrl->sdm_lock);
|
||||
continue;
|
||||
}
|
||||
pr_debug("%s: before SMC call -- a0=0x%016x a1=0x%016x",
|
||||
__func__,
|
||||
pr_debug("%s: %s: before SMC call -- a0=0x%016x a1=0x%016x",
|
||||
__func__, chan->name,
|
||||
(unsigned int)a0,
|
||||
(unsigned int)a1);
|
||||
pr_debug(" a2=0x%016x\n", (unsigned int)a2);
|
||||
@@ -712,8 +728,8 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
pr_debug(" a5=0x%016x\n", (unsigned int)a5);
|
||||
ctrl->invoke_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
|
||||
|
||||
pr_debug("%s: after SMC call -- res.a0=0x%016x",
|
||||
__func__, (unsigned int)res.a0);
|
||||
pr_debug("%s: %s: after SMC call -- res.a0=0x%016x",
|
||||
__func__, chan->name, (unsigned int)res.a0);
|
||||
pr_debug(" res.a1=0x%016x, res.a2=0x%016x",
|
||||
(unsigned int)res.a1, (unsigned int)res.a2);
|
||||
pr_debug(" res.a3=0x%016x\n", (unsigned int)res.a3);
|
||||
@@ -728,6 +744,7 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
cbdata->kaddr2 = NULL;
|
||||
cbdata->kaddr3 = NULL;
|
||||
pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
|
||||
mutex_unlock(&ctrl->sdm_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -801,6 +818,8 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
mutex_unlock(&ctrl->sdm_lock);
|
||||
}
|
||||
|
||||
kfree(cbdata);
|
||||
@@ -1696,22 +1715,33 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
|
||||
if (!p_data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* first client will create kernel thread */
|
||||
if (!chan->ctrl->task) {
|
||||
chan->ctrl->task =
|
||||
kthread_run_on_cpu(svc_normal_to_secure_thread,
|
||||
(void *)chan->ctrl,
|
||||
cpu, "svc_smc_hvc_thread");
|
||||
if (IS_ERR(chan->ctrl->task)) {
|
||||
/* first caller creates the per-channel kthread */
|
||||
if (!chan->task) {
|
||||
struct task_struct *task;
|
||||
|
||||
task = kthread_run_on_cpu(svc_normal_to_secure_thread,
|
||||
(void *)chan,
|
||||
cpu, "svc_smc_hvc_thread");
|
||||
if (IS_ERR(task)) {
|
||||
dev_err(chan->ctrl->dev,
|
||||
"failed to create svc_smc_hvc_thread\n");
|
||||
kfree(p_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&chan->lock);
|
||||
if (chan->task) {
|
||||
/* another caller won the race; discard our thread */
|
||||
spin_unlock(&chan->lock);
|
||||
kthread_stop(task);
|
||||
} else {
|
||||
chan->task = task;
|
||||
spin_unlock(&chan->lock);
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
|
||||
p_msg->payload, p_msg->command,
|
||||
pr_debug("%s: %s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
|
||||
chan->name, p_msg->payload, p_msg->command,
|
||||
(unsigned int)p_msg->payload_length);
|
||||
|
||||
if (list_empty(&svc_data_mem)) {
|
||||
@@ -1747,12 +1777,16 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
|
||||
p_data->arg[2] = p_msg->arg[2];
|
||||
p_data->size = p_msg->payload_length;
|
||||
p_data->chan = chan;
|
||||
pr_debug("%s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n", __func__,
|
||||
(unsigned int)p_data->paddr, p_data->command,
|
||||
(unsigned int)p_data->size);
|
||||
ret = kfifo_in_spinlocked(&chan->ctrl->svc_fifo, p_data,
|
||||
pr_debug("%s: %s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n",
|
||||
__func__,
|
||||
chan->name,
|
||||
(unsigned int)p_data->paddr,
|
||||
p_data->command,
|
||||
(unsigned int)p_data->size);
|
||||
|
||||
ret = kfifo_in_spinlocked(&chan->svc_fifo, p_data,
|
||||
sizeof(*p_data),
|
||||
&chan->ctrl->svc_fifo_lock);
|
||||
&chan->svc_fifo_lock);
|
||||
|
||||
kfree(p_data);
|
||||
|
||||
@@ -1773,11 +1807,12 @@ EXPORT_SYMBOL_GPL(stratix10_svc_send);
|
||||
*/
|
||||
void stratix10_svc_done(struct stratix10_svc_chan *chan)
|
||||
{
|
||||
/* stop thread when thread is running AND only one active client */
|
||||
if (chan->ctrl->task && chan->ctrl->num_active_client <= 1) {
|
||||
pr_debug("svc_smc_hvc_shm_thread is stopped\n");
|
||||
kthread_stop(chan->ctrl->task);
|
||||
chan->ctrl->task = NULL;
|
||||
/* stop thread when thread is running */
|
||||
if (chan->task) {
|
||||
pr_debug("%s: %s: svc_smc_hvc_shm_thread is stopping\n",
|
||||
__func__, chan->name);
|
||||
kthread_stop(chan->task);
|
||||
chan->task = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stratix10_svc_done);
|
||||
@@ -1817,8 +1852,8 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
|
||||
pmem->paddr = pa;
|
||||
pmem->size = s;
|
||||
list_add_tail(&pmem->node, &svc_data_mem);
|
||||
pr_debug("%s: va=%p, pa=0x%016x\n", __func__,
|
||||
pmem->vaddr, (unsigned int)pmem->paddr);
|
||||
pr_debug("%s: %s: va=%p, pa=0x%016x\n", __func__,
|
||||
chan->name, pmem->vaddr, (unsigned int)pmem->paddr);
|
||||
|
||||
return (void *)va;
|
||||
}
|
||||
@@ -1855,6 +1890,13 @@ static const struct of_device_id stratix10_svc_drv_match[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static const char * const chan_names[SVC_NUM_CHANNEL] = {
|
||||
SVC_CLIENT_FPGA,
|
||||
SVC_CLIENT_RSU,
|
||||
SVC_CLIENT_FCS,
|
||||
SVC_CLIENT_HWMON
|
||||
};
|
||||
|
||||
static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -1862,11 +1904,11 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
struct stratix10_svc_chan *chans;
|
||||
struct gen_pool *genpool;
|
||||
struct stratix10_svc_sh_memory *sh_memory;
|
||||
struct stratix10_svc *svc;
|
||||
struct stratix10_svc *svc = NULL;
|
||||
|
||||
svc_invoke_fn *invoke_fn;
|
||||
size_t fifo_size;
|
||||
int ret;
|
||||
int ret, i = 0;
|
||||
|
||||
/* get SMC or HVC function */
|
||||
invoke_fn = get_invoke_func(dev);
|
||||
@@ -1905,8 +1947,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
controller->num_active_client = 0;
|
||||
controller->chans = chans;
|
||||
controller->genpool = genpool;
|
||||
controller->task = NULL;
|
||||
controller->invoke_fn = invoke_fn;
|
||||
INIT_LIST_HEAD(&controller->node);
|
||||
init_completion(&controller->complete_status);
|
||||
|
||||
ret = stratix10_svc_async_init(controller);
|
||||
@@ -1917,32 +1959,20 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
|
||||
ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to allocate FIFO\n");
|
||||
goto err_async_exit;
|
||||
mutex_init(&controller->sdm_lock);
|
||||
|
||||
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
|
||||
chans[i].scl = NULL;
|
||||
chans[i].ctrl = controller;
|
||||
chans[i].name = (char *)chan_names[i];
|
||||
spin_lock_init(&chans[i].lock);
|
||||
ret = kfifo_alloc(&chans[i].svc_fifo, fifo_size, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to allocate FIFO %d\n", i);
|
||||
goto err_free_fifos;
|
||||
}
|
||||
spin_lock_init(&chans[i].svc_fifo_lock);
|
||||
}
|
||||
spin_lock_init(&controller->svc_fifo_lock);
|
||||
|
||||
chans[0].scl = NULL;
|
||||
chans[0].ctrl = controller;
|
||||
chans[0].name = SVC_CLIENT_FPGA;
|
||||
spin_lock_init(&chans[0].lock);
|
||||
|
||||
chans[1].scl = NULL;
|
||||
chans[1].ctrl = controller;
|
||||
chans[1].name = SVC_CLIENT_RSU;
|
||||
spin_lock_init(&chans[1].lock);
|
||||
|
||||
chans[2].scl = NULL;
|
||||
chans[2].ctrl = controller;
|
||||
chans[2].name = SVC_CLIENT_FCS;
|
||||
spin_lock_init(&chans[2].lock);
|
||||
|
||||
chans[3].scl = NULL;
|
||||
chans[3].ctrl = controller;
|
||||
chans[3].name = SVC_CLIENT_HWMON;
|
||||
spin_lock_init(&chans[3].lock);
|
||||
|
||||
list_add_tail(&controller->node, &svc_ctrl);
|
||||
platform_set_drvdata(pdev, controller);
|
||||
@@ -1951,7 +1981,7 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
|
||||
if (!svc) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_kfifo;
|
||||
goto err_free_fifos;
|
||||
}
|
||||
controller->svc = svc;
|
||||
|
||||
@@ -1959,51 +1989,43 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
|
||||
if (!svc->stratix10_svc_rsu) {
|
||||
dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU);
|
||||
ret = -ENOMEM;
|
||||
goto err_free_kfifo;
|
||||
goto err_free_fifos;
|
||||
}
|
||||
|
||||
ret = platform_device_add(svc->stratix10_svc_rsu);
|
||||
if (ret) {
|
||||
platform_device_put(svc->stratix10_svc_rsu);
|
||||
goto err_free_kfifo;
|
||||
}
|
||||
|
||||
svc->intel_svc_fcs = platform_device_alloc(INTEL_FCS, 1);
|
||||
if (!svc->intel_svc_fcs) {
|
||||
dev_err(dev, "failed to allocate %s device\n", INTEL_FCS);
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister_rsu_dev;
|
||||
}
|
||||
|
||||
ret = platform_device_add(svc->intel_svc_fcs);
|
||||
if (ret) {
|
||||
platform_device_put(svc->intel_svc_fcs);
|
||||
goto err_unregister_rsu_dev;
|
||||
}
|
||||
if (ret)
|
||||
goto err_put_device;
|
||||
|
||||
ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
|
||||
if (ret)
|
||||
goto err_unregister_fcs_dev;
|
||||
goto err_unregister_rsu_dev;
|
||||
|
||||
pr_info("Intel Service Layer Driver Initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_fcs_dev:
|
||||
platform_device_unregister(svc->intel_svc_fcs);
|
||||
err_unregister_rsu_dev:
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
err_free_kfifo:
|
||||
kfifo_free(&controller->svc_fifo);
|
||||
err_async_exit:
|
||||
goto err_free_fifos;
|
||||
err_put_device:
|
||||
platform_device_put(svc->stratix10_svc_rsu);
|
||||
err_free_fifos:
|
||||
/* only remove from list if list_add_tail() was reached */
|
||||
if (!list_empty(&controller->node))
|
||||
list_del(&controller->node);
|
||||
/* free only the FIFOs that were successfully allocated */
|
||||
while (i--)
|
||||
kfifo_free(&chans[i].svc_fifo);
|
||||
stratix10_svc_async_exit(controller);
|
||||
err_destroy_pool:
|
||||
gen_pool_destroy(genpool);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stratix10_svc_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
|
||||
struct stratix10_svc *svc = ctrl->svc;
|
||||
|
||||
@@ -2011,14 +2033,16 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
|
||||
|
||||
of_platform_depopulate(ctrl->dev);
|
||||
|
||||
platform_device_unregister(svc->intel_svc_fcs);
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
|
||||
kfifo_free(&ctrl->svc_fifo);
|
||||
if (ctrl->task) {
|
||||
kthread_stop(ctrl->task);
|
||||
ctrl->task = NULL;
|
||||
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
|
||||
if (ctrl->chans[i].task) {
|
||||
kthread_stop(ctrl->chans[i].task);
|
||||
ctrl->chans[i].task = NULL;
|
||||
}
|
||||
kfifo_free(&ctrl->chans[i].svc_fifo);
|
||||
}
|
||||
|
||||
if (ctrl->genpool)
|
||||
gen_pool_destroy(ctrl->genpool);
|
||||
list_del(&ctrl->node);
|
||||
|
||||
@@ -38,8 +38,10 @@ MODULE_DESCRIPTION("GPIB driver for LPVO usb devices");
|
||||
/*
|
||||
* Table of devices that work with this driver.
|
||||
*
|
||||
* Currently, only one device is known to be used in the
|
||||
* lpvo_usb_gpib adapter (FTDI 0403:6001).
|
||||
* Currently, only one device is known to be used in the lpvo_usb_gpib
|
||||
* adapter (FTDI 0403:6001) but as this device id is already handled by the
|
||||
* ftdi_sio USB serial driver the LPVO driver must not bind to it by default.
|
||||
*
|
||||
* If your adapter uses a different chip, insert a line
|
||||
* in the following table with proper <Vendor-id>, <Product-id>.
|
||||
*
|
||||
@@ -50,7 +52,6 @@ MODULE_DESCRIPTION("GPIB driver for LPVO usb devices");
|
||||
*/
|
||||
|
||||
static const struct usb_device_id skel_table[] = {
|
||||
{ USB_DEVICE(0x0403, 0x6001) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, skel_table);
|
||||
|
||||
@@ -531,7 +531,7 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ad7768_fill_scale_tbl(struct iio_dev *dev)
|
||||
static int ad7768_fill_scale_tbl(struct iio_dev *dev)
|
||||
{
|
||||
struct ad7768_state *st = iio_priv(dev);
|
||||
const struct iio_scan_type *scan_type;
|
||||
@@ -541,6 +541,11 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev)
|
||||
u64 tmp2;
|
||||
|
||||
scan_type = iio_get_current_scan_type(dev, &dev->channels[0]);
|
||||
if (IS_ERR(scan_type)) {
|
||||
dev_err(&st->spi->dev, "Failed to get scan type.\n");
|
||||
return PTR_ERR(scan_type);
|
||||
}
|
||||
|
||||
if (scan_type->sign == 's')
|
||||
val2 = scan_type->realbits - 1;
|
||||
else
|
||||
@@ -565,6 +570,8 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev)
|
||||
st->scale_tbl[i][0] = tmp0; /* Integer part */
|
||||
st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
|
||||
@@ -669,7 +676,9 @@ static int ad7768_configure_dig_fil(struct iio_dev *dev,
|
||||
}
|
||||
|
||||
/* Update scale table: scale values vary according to the precision */
|
||||
ad7768_fill_scale_tbl(dev);
|
||||
ret = ad7768_fill_scale_tbl(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ad7768_fill_samp_freq_tbl(st);
|
||||
|
||||
|
||||
@@ -613,7 +613,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data)
|
||||
* + heater duration
|
||||
*/
|
||||
int wait_eoc_us = ((data->oversampling_temp + data->oversampling_press +
|
||||
data->oversampling_humid) * 1936) + (477 * 4) +
|
||||
data->oversampling_humid) * 1963) + (477 * 4) +
|
||||
(477 * 5) + 1000 + (data->heater_dur * 1000);
|
||||
|
||||
fsleep(wait_eoc_us);
|
||||
|
||||
@@ -171,7 +171,7 @@ static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t n
|
||||
if (!sps30_i2c_meas_ready(state))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num);
|
||||
return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(*meas) * num);
|
||||
}
|
||||
|
||||
static int sps30_i2c_clean_fan(struct sps30_state *state)
|
||||
|
||||
@@ -303,7 +303,7 @@ static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_
|
||||
if (msleep_interruptible(1000))
|
||||
return -EINTR;
|
||||
|
||||
ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num));
|
||||
ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(*meas));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* if measurements aren't ready sensor returns empty frame */
|
||||
|
||||
@@ -140,7 +140,7 @@ static int ds4424_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val < S8_MIN || val > S8_MAX)
|
||||
if (val <= S8_MIN || val > S8_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (val > 0) {
|
||||
|
||||
@@ -508,7 +508,7 @@ static int adf4377_soft_reset(struct adf4377_state *st)
|
||||
return ret;
|
||||
|
||||
return regmap_read_poll_timeout(st->regmap, 0x0, read_val,
|
||||
!(read_val & (ADF4377_0000_SOFT_RESET_R_MSK |
|
||||
!(read_val & (ADF4377_0000_SOFT_RESET_MSK |
|
||||
ADF4377_0000_SOFT_RESET_R_MSK)), 200, 200 * 100);
|
||||
}
|
||||
|
||||
|
||||
@@ -322,7 +322,9 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
/* Resume device */
|
||||
pm_runtime_get_sync(mpu3050->dev);
|
||||
ret = pm_runtime_resume_and_get(mpu3050->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mutex_lock(&mpu3050->lock);
|
||||
|
||||
ret = mpu3050_set_8khz_samplerate(mpu3050);
|
||||
@@ -647,14 +649,20 @@ out_trigger_unlock:
|
||||
static int mpu3050_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(mpu3050->dev);
|
||||
ret = pm_runtime_resume_and_get(mpu3050->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Unless we have OUR trigger active, run at full speed */
|
||||
if (!mpu3050->hw_irq_trigger)
|
||||
return mpu3050_set_8khz_samplerate(mpu3050);
|
||||
if (!mpu3050->hw_irq_trigger) {
|
||||
ret = mpu3050_set_8khz_samplerate(mpu3050);
|
||||
if (ret)
|
||||
pm_runtime_put_autosuspend(mpu3050->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpu3050_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
|
||||
@@ -19,8 +19,7 @@ static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
|
||||
struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
|
||||
|
||||
/* Just power up the device, that is all that is needed */
|
||||
pm_runtime_get_sync(mpu3050->dev);
|
||||
return 0;
|
||||
return pm_runtime_resume_and_get(mpu3050->dev);
|
||||
}
|
||||
|
||||
static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
|
||||
|
||||
@@ -526,7 +526,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
|
||||
|
||||
adis->spi = spi;
|
||||
adis->data = data;
|
||||
if (!adis->ops->write && !adis->ops->read && !adis->ops->reset)
|
||||
if (!adis->ops)
|
||||
adis->ops = &adis_default_ops;
|
||||
else if (!adis->ops->write || !adis->ops->read || !adis->ops->reset)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -651,6 +651,8 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
|
||||
conf.odr = inv_icm42600_accel_odr_conv[idx / 2];
|
||||
if (conf.odr == st->conf.accel.odr)
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
@@ -371,6 +371,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
|
||||
static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
|
||||
struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev);
|
||||
struct inv_sensors_timestamp *ts = &sensor_st->ts;
|
||||
struct device *dev = regmap_get_device(st->map);
|
||||
unsigned int sensor;
|
||||
unsigned int *watermark;
|
||||
@@ -392,6 +394,8 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
|
||||
|
||||
ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
@@ -358,6 +358,8 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
|
||||
conf.odr = inv_icm42600_gyro_odr_conv[idx / 2];
|
||||
if (conf.odr == st->conf.gyro.odr)
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
@@ -205,7 +205,7 @@ struct inv_icm45600_sensor_state {
|
||||
#define INV_ICM45600_SPI_SLEW_RATE_38NS 0
|
||||
|
||||
#define INV_ICM45600_REG_INT1_CONFIG2 0x0018
|
||||
#define INV_ICM45600_INT1_CONFIG2_PUSH_PULL BIT(2)
|
||||
#define INV_ICM45600_INT1_CONFIG2_OPEN_DRAIN BIT(2)
|
||||
#define INV_ICM45600_INT1_CONFIG2_LATCHED BIT(1)
|
||||
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_HIGH BIT(0)
|
||||
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_LOW 0x00
|
||||
|
||||
@@ -637,8 +637,8 @@ static int inv_icm45600_irq_init(struct inv_icm45600_state *st, int irq,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!open_drain)
|
||||
val |= INV_ICM45600_INT1_CONFIG2_PUSH_PULL;
|
||||
if (open_drain)
|
||||
val |= INV_ICM45600_INT1_CONFIG2_OPEN_DRAIN;
|
||||
|
||||
ret = regmap_write(st->map, INV_ICM45600_REG_INT1_CONFIG2, val);
|
||||
if (ret)
|
||||
@@ -744,6 +744,11 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
|
||||
*/
|
||||
fsleep(5 * USEC_PER_MSEC);
|
||||
|
||||
/* set pm_runtime active early for disable vddio resource cleanup */
|
||||
ret = pm_runtime_set_active(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = inv_icm45600_enable_regulator_vddio(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -776,7 +781,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_pm_runtime_set_active_enabled(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -1943,6 +1943,14 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
irq_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acking interrupts by status register does not work reliably
|
||||
* but seem to work when this bit is set.
|
||||
*/
|
||||
if (st->chip_type == INV_MPU9150)
|
||||
st->irq_mask |= INV_MPU6050_INT_RD_CLEAR;
|
||||
|
||||
device_set_wakeup_capable(dev, true);
|
||||
|
||||
st->vdd_supply = devm_regulator_get(dev, "vdd");
|
||||
|
||||
@@ -390,6 +390,8 @@ struct inv_mpu6050_state {
|
||||
/* enable level triggering */
|
||||
#define INV_MPU6050_LATCH_INT_EN 0x20
|
||||
#define INV_MPU6050_BIT_BYPASS_EN 0x2
|
||||
/* allow acking interrupts by any register read */
|
||||
#define INV_MPU6050_INT_RD_CLEAR 0x10
|
||||
|
||||
/* Allowed timestamp period jitter in percent */
|
||||
#define INV_MPU6050_TS_PERIOD_JITTER 4
|
||||
|
||||
@@ -248,7 +248,6 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
|
||||
switch (st->chip_type) {
|
||||
case INV_MPU6000:
|
||||
case INV_MPU6050:
|
||||
case INV_MPU9150:
|
||||
/*
|
||||
* WoM is not supported and interrupt status read seems to be broken for
|
||||
* some chips. Since data ready is the only interrupt, bypass interrupt
|
||||
@@ -257,6 +256,10 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
|
||||
wom_bits = 0;
|
||||
int_status = INV_MPU6050_BIT_RAW_DATA_RDY_INT;
|
||||
goto data_ready_interrupt;
|
||||
case INV_MPU9150:
|
||||
/* IRQ needs to be acked */
|
||||
wom_bits = 0;
|
||||
break;
|
||||
case INV_MPU6500:
|
||||
case INV_MPU6515:
|
||||
case INV_MPU6880:
|
||||
|
||||
@@ -228,8 +228,10 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
|
||||
written = 0;
|
||||
add_wait_queue(&rb->pollq, &wait);
|
||||
do {
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
if (!indio_dev->info) {
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!iio_buffer_space_available(rb)) {
|
||||
if (signal_pending(current)) {
|
||||
|
||||
@@ -109,9 +109,9 @@ static int bh1780_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_LIGHT:
|
||||
pm_runtime_get_sync(&bh1780->client->dev);
|
||||
value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
|
||||
pm_runtime_put_autosuspend(&bh1780->client->dev);
|
||||
if (value < 0)
|
||||
return value;
|
||||
pm_runtime_put_autosuspend(&bh1780->client->dev);
|
||||
*val = value;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
@@ -171,7 +171,7 @@ static s16 tlv493d_get_channel_data(u8 *b, enum tlv493d_channels ch)
|
||||
switch (ch) {
|
||||
case TLV493D_AXIS_X:
|
||||
val = FIELD_GET(TLV493D_BX_MAG_X_AXIS_MSB, b[TLV493D_RD_REG_BX]) << 4 |
|
||||
FIELD_GET(TLV493D_BX2_MAG_X_AXIS_LSB, b[TLV493D_RD_REG_BX2]) >> 4;
|
||||
FIELD_GET(TLV493D_BX2_MAG_X_AXIS_LSB, b[TLV493D_RD_REG_BX2]);
|
||||
break;
|
||||
case TLV493D_AXIS_Y:
|
||||
val = FIELD_GET(TLV493D_BY_MAG_Y_AXIS_MSB, b[TLV493D_RD_REG_BY]) << 4 |
|
||||
|
||||
@@ -221,7 +221,7 @@ static int mcp4131_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
data->buf[0] = address << MCP4131_WIPER_SHIFT;
|
||||
data->buf[0] = address;
|
||||
data->buf[0] |= MCP4131_WRITE | (val >> 8);
|
||||
data->buf[1] = val & 0xFF; /* 8 bits here */
|
||||
|
||||
|
||||
@@ -719,6 +719,9 @@ static int hx9023s_set_samp_freq(struct hx9023s_data *data, int val, int val2)
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
unsigned int i, period_ms;
|
||||
|
||||
if (!val && !val2)
|
||||
return -EINVAL;
|
||||
|
||||
period_ms = div_u64(NANO, (val * MEGA + val2));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hx9023s_samp_freq_table); i++) {
|
||||
@@ -1034,9 +1037,8 @@ static int hx9023s_send_cfg(const struct firmware *fw, struct hx9023s_data *data
|
||||
if (!bin)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(bin->data, fw->data, fw->size);
|
||||
|
||||
bin->fw_size = fw->size;
|
||||
memcpy(bin->data, fw->data, bin->fw_size);
|
||||
bin->fw_ver = bin->data[FW_VER_OFFSET];
|
||||
bin->reg_count = get_unaligned_le16(bin->data + FW_REG_CNT_OFFSET);
|
||||
|
||||
|
||||
@@ -68,12 +68,12 @@
|
||||
* timeout value used in Stratix10 FPGA manager driver.
|
||||
* timeout value used in RSU driver
|
||||
*/
|
||||
#define SVC_RECONFIG_REQUEST_TIMEOUT_MS 300
|
||||
#define SVC_RECONFIG_BUFFER_TIMEOUT_MS 720
|
||||
#define SVC_RSU_REQUEST_TIMEOUT_MS 300
|
||||
#define SVC_RECONFIG_REQUEST_TIMEOUT_MS 5000
|
||||
#define SVC_RECONFIG_BUFFER_TIMEOUT_MS 5000
|
||||
#define SVC_RSU_REQUEST_TIMEOUT_MS 2000
|
||||
#define SVC_FCS_REQUEST_TIMEOUT_MS 2000
|
||||
#define SVC_COMPLETED_TIMEOUT_MS 30000
|
||||
#define SVC_HWMON_REQUEST_TIMEOUT_MS 300
|
||||
#define SVC_HWMON_REQUEST_TIMEOUT_MS 2000
|
||||
|
||||
struct stratix10_svc_chan;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user