diff options
| author | Harout Hedeshian <harouth@codeaurora.org> | 2014-12-04 21:38:02 +0530 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:05:29 -0700 |
| commit | d15da0c4e8ecbb054b54106332586112ccf9d0c6 (patch) | |
| tree | f9c1d7df384ed1539cbc8d23ed9ca0e945be8a39 /net | |
| parent | 51f33c398e0f0dd7508ad8a5a34ab2f67e0c35c7 (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.c | 59 |
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); |
