summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuma copybara merger <zuma-automerger@google.com>2023-06-16 15:40:50 +0800
committerCopybara-Service <copybara-worker@google.com>2023-06-22 21:45:18 -0700
commit8b9e35adca98df7cf86c2295a1a2e383bb4de502 (patch)
tree978224ac671ecb6052f50ac1670f352942784647
parentb136a231d24aa456d94e87fda93f4ba8c02d1a8d (diff)
downloadrio-8b9e35adca98df7cf86c2295a1a2e383bb4de502.tar.gz
[Copybara Auto Merge] Merge branch zuma into android14-gs-pixel-5.15-udc-d1
edgetpu: Acquire PM lock before PM count check during suspend There might be a race between edgetpu_pm_suspend and gcip_pm_put that when gcip_pm_put already decreases the PM count to zero, but hasn't shut the block down, a suspend request is received and edgetpu_pm_suspend returns 0. This race might allow the parent devices (e.g., sysmmu) to suspend while the TPU is still on. Add gcip_pm_trylock in edgetpu_pm_suspend to avoid it. Bug: 277256378 Test: echo mem > /sys/power/state (cherry picked from commit 3f948d35cb78e8bc7001b8de944cb0d6b1d8ebbf) edgetpu: replace group member check macro that modifies control flow LOCK_RETURN_IF_NO_GROUP macro modifies control flow, contraindicated by Linux kernel coding standards. Replace with an inline call and explicit function return by callers. Remove unnecessary update of client group parameter and refer to the original value of the client's group pointer instead. Bug: 286406228 (cherry picked from commit 8f5061cc6598a23d6b5232447174ac555ef8a3f6) (cherry picked from commit c887d310d4196efd25092d0369a6c7c26d07481d) edgetpu: kci replace use of macro that modifies control flow Macro that returns from function on errors violates kernel coding standards, replace with explicit control logic. Bug: 286406228 (repeat) (cherry picked from commit 8e1fc53e20cca260abefa980fe19d86e76823e93) (cherry picked from commit 828e937d891eaabc2059e296ee0db802603de414) Signed-off-by: Zuma copybara merger <zuma-automerger@google.com> GitOrigin-RevId: 38c11dab698ec20d07c314f17c187115963d5bc2 Change-Id: I7c7394fadfc2ca566a67df3ad1deae72c645e7e8
-rw-r--r--drivers/edgetpu/edgetpu-fs.c68
-rw-r--r--drivers/edgetpu/edgetpu-kci.c31
-rw-r--r--drivers/edgetpu/edgetpu-pm.c19
3 files changed, 66 insertions, 52 deletions
diff --git a/drivers/edgetpu/edgetpu-fs.c b/drivers/edgetpu/edgetpu-fs.c
index 18bcd17..02ffa38 100644
--- a/drivers/edgetpu/edgetpu-fs.c
+++ b/drivers/edgetpu/edgetpu-fs.c
@@ -58,18 +58,19 @@ static struct dentry *edgetpu_debugfs_dir;
#define LOCK(client) mutex_lock(&client->group_lock)
#define UNLOCK(client) mutex_unlock(&client->group_lock)
/*
- * Locks @client->group_lock and assigns @client->group to @grp.
- * Returns -EINVAL if @client is not in a group.
+ * Locks @client->group_lock and checks whether @client is in a group.
+ * If @client is not in a group, unlocks group_lock and returns false.
+ * If @client is in a group, returns true with group_lock held.
*/
-#define LOCK_RETURN_IF_NO_GROUP(client, grp) \
- do { \
- LOCK(client); \
- grp = client->group; \
- if (!grp) { \
- UNLOCK(client); \
- return -EINVAL; \
- } \
- } while (0)
+static inline bool lock_check_group_member(struct edgetpu_client *client)
+{
+ LOCK(client);
+ if (!client->group) {
+ UNLOCK(client);
+ return false;
+ }
+ return true;
+}
int edgetpu_open(struct edgetpu_dev_iface *etiface, struct file *file)
{
@@ -130,16 +131,14 @@ static int edgetpu_fs_release(struct inode *inode, struct file *file)
static int edgetpu_ioctl_set_eventfd(struct edgetpu_client *client,
struct edgetpu_event_register __user *argp)
{
- struct edgetpu_device_group *group;
int ret;
struct edgetpu_event_register eventreg;
if (copy_from_user(&eventreg, argp, sizeof(eventreg)))
return -EFAULT;
-
- LOCK_RETURN_IF_NO_GROUP(client, group);
- ret = edgetpu_group_set_eventfd(group, eventreg.event_id,
- eventreg.eventfd);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
+ ret = edgetpu_group_set_eventfd(client->group, eventreg.event_id, eventreg.eventfd);
UNLOCK(client);
return ret;
}
@@ -147,10 +146,9 @@ static int edgetpu_ioctl_set_eventfd(struct edgetpu_client *client,
static int edgetpu_ioctl_unset_eventfd(struct edgetpu_client *client,
uint event_id)
{
- struct edgetpu_device_group *group;
-
- LOCK_RETURN_IF_NO_GROUP(client, group);
- edgetpu_group_unset_eventfd(group, event_id);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
+ edgetpu_group_unset_eventfd(client->group, event_id);
UNLOCK(client);
return 0;
}
@@ -261,9 +259,10 @@ static int edgetpu_ioctl_map_buffer(struct edgetpu_client *client,
trace_edgetpu_map_buffer_start(&ibuf);
- LOCK_RETURN_IF_NO_GROUP(client, group);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
/* to prevent group being released when we perform map/unmap later */
- group = edgetpu_device_group_get(group);
+ group = edgetpu_device_group_get(client->group);
/*
* Don't hold @client->group_lock on purpose since
* 1. We don't care whether @client still belongs to @group.
@@ -292,15 +291,13 @@ static int edgetpu_ioctl_unmap_buffer(struct edgetpu_client *client,
struct edgetpu_map_ioctl __user *argp)
{
struct edgetpu_map_ioctl ibuf;
- struct edgetpu_device_group *group;
int ret;
if (copy_from_user(&ibuf, argp, sizeof(ibuf)))
return -EFAULT;
-
- LOCK_RETURN_IF_NO_GROUP(client, group);
- ret = edgetpu_device_group_unmap(group, ibuf.device_address,
- ibuf.flags);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
+ ret = edgetpu_device_group_unmap(client->group, ibuf.device_address, ibuf.flags);
UNLOCK(client);
return ret;
}
@@ -314,14 +311,14 @@ edgetpu_ioctl_allocate_device_buffer(struct edgetpu_client *client, u64 size)
static int edgetpu_ioctl_sync_buffer(struct edgetpu_client *client,
struct edgetpu_sync_ioctl __user *argp)
{
- struct edgetpu_device_group *group;
int ret;
struct edgetpu_sync_ioctl ibuf;
if (copy_from_user(&ibuf, argp, sizeof(ibuf)))
return -EFAULT;
- LOCK_RETURN_IF_NO_GROUP(client, group);
- ret = edgetpu_device_group_sync_buffer(group, &ibuf);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
+ ret = edgetpu_device_group_sync_buffer(client->group, &ibuf);
UNLOCK(client);
return ret;
}
@@ -339,9 +336,10 @@ edgetpu_ioctl_map_dmabuf(struct edgetpu_client *client,
trace_edgetpu_map_dmabuf_start(&ibuf);
- LOCK_RETURN_IF_NO_GROUP(client, group);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
/* to prevent group being released when we perform unmap on fault */
- group = edgetpu_device_group_get(group);
+ group = edgetpu_device_group_get(client->group);
ret = edgetpu_map_dmabuf(group, &ibuf);
UNLOCK(client);
if (ret)
@@ -363,14 +361,14 @@ static int
edgetpu_ioctl_unmap_dmabuf(struct edgetpu_client *client,
struct edgetpu_map_dmabuf_ioctl __user *argp)
{
- struct edgetpu_device_group *group;
int ret;
struct edgetpu_map_dmabuf_ioctl ibuf;
if (copy_from_user(&ibuf, argp, sizeof(ibuf)))
return -EFAULT;
- LOCK_RETURN_IF_NO_GROUP(client, group);
- ret = edgetpu_unmap_dmabuf(group, ibuf.device_address);
+ if (!lock_check_group_member(client))
+ return -EINVAL;
+ ret = edgetpu_unmap_dmabuf(client->group, ibuf.device_address);
UNLOCK(client);
return ret;
}
diff --git a/drivers/edgetpu/edgetpu-kci.c b/drivers/edgetpu/edgetpu-kci.c
index 27d0a3f..dea5ecd 100644
--- a/drivers/edgetpu/edgetpu-kci.c
+++ b/drivers/edgetpu/edgetpu-kci.c
@@ -48,17 +48,15 @@
#define KCI_TIMEOUT (1000)
#endif
-/* A macro for KCIs to leave early when the device state is known to be bad. */
-#define RETURN_ERRNO_IF_ETDEV_NOT_GOOD(etkci, opstring) \
- do { \
- struct edgetpu_mailbox *mailbox = etkci->mailbox; \
- int ret = edgetpu_get_state_errno_locked(mailbox->etdev); \
- if (ret) { \
- etdev_err(mailbox->etdev, "%s failed: device state %u (%d)", \
- opstring, mailbox->etdev->state, ret); \
- return ret; \
- } \
- } while (0)
+static inline int check_etdev_state(struct edgetpu_kci *etkci, char *opstring)
+{
+ int ret = edgetpu_get_state_errno_locked(etkci->mailbox->etdev);
+
+ if (ret)
+ etdev_err(etkci->mailbox->etdev, "%s failed: device state %u (%d)",
+ opstring, etkci->mailbox->etdev->state, ret);
+ return ret;
+}
static int edgetpu_kci_alloc_queue(struct edgetpu_dev *etdev, struct edgetpu_mailbox *mailbox,
enum gcip_mailbox_queue_type type,
@@ -597,8 +595,11 @@ int edgetpu_kci_open_device(struct edgetpu_kci *etkci, u32 mailbox_map, u32 clie
.flags = mailbox_map,
},
};
+ int ret;
- RETURN_ERRNO_IF_ETDEV_NOT_GOOD(etkci, "open device");
+ ret = check_etdev_state(etkci, "open device");
+ if (ret)
+ return ret;
if (vcid < 0)
return gcip_kci_send_cmd(etkci->kci, &cmd);
@@ -613,9 +614,11 @@ int edgetpu_kci_close_device(struct edgetpu_kci *etkci, u32 mailbox_map)
.flags = mailbox_map,
},
};
+ int ret;
- RETURN_ERRNO_IF_ETDEV_NOT_GOOD(etkci, "close device");
-
+ ret = check_etdev_state(etkci, "close device");
+ if (ret)
+ return ret;
return gcip_kci_send_cmd(etkci->kci, &cmd);
}
diff --git a/drivers/edgetpu/edgetpu-pm.c b/drivers/edgetpu/edgetpu-pm.c
index bb19a42..a65e14b 100644
--- a/drivers/edgetpu/edgetpu-pm.c
+++ b/drivers/edgetpu/edgetpu-pm.c
@@ -52,12 +52,25 @@ static int __maybe_unused edgetpu_pm_suspend(struct device *dev)
struct edgetpu_dev *etdev = dev_get_drvdata(dev);
struct gcip_pm *pm = etdev->pm;
struct edgetpu_list_device_client *lc;
+ int count;
- if (!pm || !gcip_pm_is_powered(pm))
+ if (unlikely(!pm))
return 0;
- etdev_warn_ratelimited(etdev, "cannot suspend with power up count = %d\n",
- gcip_pm_get_count(pm));
+ if (!gcip_pm_trylock(pm)) {
+ etdev_warn_ratelimited(etdev, "cannot suspend during power state transition\n");
+ return -EAGAIN;
+ }
+
+ count = gcip_pm_get_count(pm);
+ gcip_pm_unlock(etdev->pm);
+
+ if (!count) {
+ etdev_info_ratelimited(etdev, "suspended\n");
+ return 0;
+ }
+
+ etdev_warn_ratelimited(etdev, "cannot suspend with power up count = %d\n", count);
if (!mutex_trylock(&etdev->clients_lock))
return -EAGAIN;