summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorHarout Hedeshian <harouth@codeaurora.org>2014-12-04 21:38:02 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:05:29 -0700
commitd15da0c4e8ecbb054b54106332586112ccf9d0c6 (patch)
treef9c1d7df384ed1539cbc8d23ed9ca0e945be8a39 /net
parent51f33c398e0f0dd7508ad8a5a34ab2f67e0c35c7 (diff)
net: rmnet_data: consolidate VND free work-queue task on force unassociate
Previously, one new work-queue item was created and scheduled with schedule_work() for each VND getting unregistered. Since we know the exact set of VNDs which need to be cleared ahead of time, the VNDs are added to a list and freed at the same time with a single work-queue task. This saves us from having to malloc/schedule/free for each VND and provides a speed up on some low tier hardware. CRs-Fixed: 738039 Change-Id: I02d4de1308a2aed9d493f6fd58cf0984265facba Acked-by: Nagarjuna Chaganti <nchagant@qti.qualcomm.com> Signed-off-by: Harout Hedeshian <harouth@codeaurora.org> Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Diffstat (limited to 'net')
-rw-r--r--net/rmnet_data/rmnet_data_config.c59
1 files changed, 30 insertions, 29 deletions
diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c
index 6173d0bcc083..2a4f56bd9cbe 100644
--- a/net/rmnet_data/rmnet_data_config.c
+++ b/net/rmnet_data/rmnet_data_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -48,7 +48,8 @@ static struct notifier_block rmnet_dev_notifier = {
struct rmnet_free_vnd_work {
struct work_struct work;
- int vnd_id;
+ int vnd_id[RMNET_DATA_MAX_VND];
+ int count;
};
/* ***************** Init and Cleanup *************************************** */
@@ -1099,32 +1100,13 @@ int rmnet_free_vnd(int id)
static void _rmnet_free_vnd_later(struct work_struct *work)
{
+ int i;
struct rmnet_free_vnd_work *fwork;
- fwork = (struct rmnet_free_vnd_work *) work;
- rmnet_free_vnd(fwork->vnd_id);
- kfree(work);
-}
+ fwork = container_of(work, struct rmnet_free_vnd_work, work);
-/**
- * rmnet_free_vnd_later() - Schedule a work item to free virtual network device
- * @id: RmNet virtual device node id
- *
- * Schedule the VND to be freed at a later time. We need to do this if the
- * rtnl lock is already held as to prevent a deadlock.
- */
-static void rmnet_free_vnd_later(int id)
-{
- struct rmnet_free_vnd_work *work;
- LOGL("(%d);", id);
- work = (struct rmnet_free_vnd_work *)
- kmalloc(sizeof(struct rmnet_free_vnd_work), GFP_KERNEL);
- if (!work) {
- LOGH("Failed to queue removal of VND:%d", id);
- return;
- }
- INIT_WORK((struct work_struct *)work, _rmnet_free_vnd_later);
- work->vnd_id = id;
- schedule_work((struct work_struct *)work);
+ for (i = 0; i < fwork->count; i++)
+ rmnet_free_vnd(fwork->vnd_id[i]);
+ kfree(fwork);
}
/**
@@ -1136,9 +1118,10 @@ static void rmnet_free_vnd_later(int id)
*/
static void rmnet_force_unassociate_device(struct net_device *dev)
{
- int i;
+ int i, j;
struct net_device *vndev;
struct rmnet_logical_ep_conf_s *cfg;
+ struct rmnet_free_vnd_work *vnd_work;
ASSERT_RTNL();
if (!dev)
@@ -1150,8 +1133,18 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
}
trace_rmnet_unregister_cb_clear_vnds(dev);
+ vnd_work = (struct rmnet_free_vnd_work *)
+ kmalloc(sizeof(struct rmnet_free_vnd_work), GFP_KERNEL);
+ if (!vnd_work) {
+ LOGH("%s", "Out of Memory");
+ return;
+ }
+ INIT_WORK(&vnd_work->work, _rmnet_free_vnd_later);
+ vnd_work->count = 0;
+
/* Check the VNDs for offending mappings */
- for (i = 0; i < RMNET_DATA_MAX_VND; i++) {
+ for (i = 0, j = 0; i < RMNET_DATA_MAX_VND &&
+ j < RMNET_DATA_MAX_VND; i++) {
vndev = rmnet_vnd_get_by_id(i);
if (!vndev) {
LOGL("VND %d not in use; skipping", i);
@@ -1172,9 +1165,17 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
dev_close(vndev);
rmnet_unset_logical_endpoint_config(vndev,
RMNET_LOCAL_LOGICAL_ENDPOINT);
- rmnet_free_vnd_later(i);
+ vnd_work->vnd_id[j] = i;
+ j++;
}
}
+ if (j > 0) {
+ vnd_work->count = j;
+ schedule_work(&vnd_work->work);
+ } else {
+ kfree(vnd_work);
+ }
+
/* Clear the mappings on the phys ep */
trace_rmnet_unregister_cb_clear_lepcs(dev);