aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/client.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-15 13:48:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-15 13:48:44 -0500
commit4ba63072b998cc31515cc6305c25f3b808b50c01 (patch)
tree779863511765c70bfd232f676b885f940ba88722 /drivers/misc/mei/client.c
parente29876723f7cb7728f0d6a674d23f92673e9f112 (diff)
parent5fb31cd839c21130c0b2524ceb9244e98dfe10e3 (diff)
Merge tag 'char-misc-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc patches from Greg KH: "Here's the big char/misc driver update for 3.20-rc1. Lots of little things in here, all described in the changelog. Nothing major or unusual, except maybe the binder selinux stuff, which was all acked by the proper selinux people and they thought it best to come through this tree. All of this has been in linux-next with no reported issues for a while" * tag 'char-misc-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (90 commits) coresight: fix function etm_writel_cp14() parameter order coresight-etm: remove check for unknown Kconfig macro coresight: fixing CPU hwid lookup in device tree coresight: remove the unnecessary function coresight_is_bit_set() coresight: fix the debug AMBA bus name coresight: remove the extra spaces coresight: fix the link between orphan connection and newly added device coresight: remove the unnecessary replicator property coresight: fix the replicator subtype value pdfdocs: Fix 'make pdfdocs' failure for 'uio-howto.tmpl' mcb: Fix error path of mcb_pci_probe virtio/console: verify device has config space ti-st: clean up data types (fix harmless memory corruption) mei: me: release hw from reset only during the reset flow mei: mask interrupt set bit on clean reset bit extcon: max77693: Constify struct regmap_config extcon: adc-jack: Release IIO channel on driver remove extcon: Remove duplicated include from extcon-class.c Drivers: hv: vmbus: hv_process_timer_expiration() can be static Drivers: hv: vmbus: serialize Offer and Rescind offer ...
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r--drivers/misc/mei/client.c156
1 files changed, 131 insertions, 25 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1382d551d7ed..dfbddfe1c7a0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -27,7 +27,63 @@
27#include "client.h" 27#include "client.h"
28 28
29/** 29/**
30 * mei_me_cl_init - initialize me client
31 *
32 * @me_cl: me client
33 */
34void mei_me_cl_init(struct mei_me_client *me_cl)
35{
36 INIT_LIST_HEAD(&me_cl->list);
37 kref_init(&me_cl->refcnt);
38}
39
40/**
41 * mei_me_cl_get - increases me client refcount
42 *
43 * @me_cl: me client
44 *
45 * Locking: called under "dev->device_lock" lock
46 *
47 * Return: me client or NULL
48 */
49struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
50{
51 if (me_cl)
52 kref_get(&me_cl->refcnt);
53
54 return me_cl;
55}
56
57/**
58 * mei_me_cl_release - unlink and free me client
59 *
60 * Locking: called under "dev->device_lock" lock
61 *
62 * @ref: me_client refcount
63 */
64static void mei_me_cl_release(struct kref *ref)
65{
66 struct mei_me_client *me_cl =
67 container_of(ref, struct mei_me_client, refcnt);
68 list_del(&me_cl->list);
69 kfree(me_cl);
70}
71/**
72 * mei_me_cl_put - decrease me client refcount and free client if necessary
73 *
74 * Locking: called under "dev->device_lock" lock
75 *
76 * @me_cl: me client
77 */
78void mei_me_cl_put(struct mei_me_client *me_cl)
79{
80 if (me_cl)
81 kref_put(&me_cl->refcnt, mei_me_cl_release);
82}
83
84/**
30 * mei_me_cl_by_uuid - locate me client by uuid 85 * mei_me_cl_by_uuid - locate me client by uuid
86 * increases ref count
31 * 87 *
32 * @dev: mei device 88 * @dev: mei device
33 * @uuid: me client uuid 89 * @uuid: me client uuid
@@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
43 99
44 list_for_each_entry(me_cl, &dev->me_clients, list) 100 list_for_each_entry(me_cl, &dev->me_clients, list)
45 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) 101 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
46 return me_cl; 102 return mei_me_cl_get(me_cl);
47 103
48 return NULL; 104 return NULL;
49} 105}
50 106
51/** 107/**
52 * mei_me_cl_by_id - locate me client by client id 108 * mei_me_cl_by_id - locate me client by client id
109 * increases ref count
53 * 110 *
54 * @dev: the device structure 111 * @dev: the device structure
55 * @client_id: me client id 112 * @client_id: me client id
@@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
65 122
66 list_for_each_entry(me_cl, &dev->me_clients, list) 123 list_for_each_entry(me_cl, &dev->me_clients, list)
67 if (me_cl->client_id == client_id) 124 if (me_cl->client_id == client_id)
68 return me_cl; 125 return mei_me_cl_get(me_cl);
126
69 return NULL; 127 return NULL;
70} 128}
71 129
72/** 130/**
73 * mei_me_cl_by_uuid_id - locate me client by client id and uuid 131 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
132 * increases ref count
74 * 133 *
75 * @dev: the device structure 134 * @dev: the device structure
76 * @uuid: me client uuid 135 * @uuid: me client uuid
@@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
88 list_for_each_entry(me_cl, &dev->me_clients, list) 147 list_for_each_entry(me_cl, &dev->me_clients, list)
89 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && 148 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
90 me_cl->client_id == client_id) 149 me_cl->client_id == client_id)
91 return me_cl; 150 return mei_me_cl_get(me_cl);
151
92 return NULL; 152 return NULL;
93} 153}
94 154
95/** 155/**
96 * mei_me_cl_remove - remove me client matching uuid and client_id 156 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
97 * 157 *
98 * @dev: the device structure 158 * @dev: the device structure
99 * @uuid: me client uuid 159 * @uuid: me client uuid
100 * @client_id: me client address 160 *
161 * Locking: called under "dev->device_lock" lock
101 */ 162 */
102void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id) 163void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
103{ 164{
104 struct mei_me_client *me_cl, *next; 165 struct mei_me_client *me_cl, *next;
105 166
167 dev_dbg(dev->dev, "remove %pUl\n", uuid);
168 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
169 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
170 mei_me_cl_put(me_cl);
171}
172
173/**
174 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
175 *
176 * @dev: the device structure
177 * @uuid: me client uuid
178 * @id: me client id
179 *
180 * Locking: called under "dev->device_lock" lock
181 */
182void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
183{
184 struct mei_me_client *me_cl, *next;
185 const uuid_le *pn;
186
187 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
106 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { 188 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
107 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && 189 pn = &me_cl->props.protocol_name;
108 me_cl->client_id == client_id) { 190 if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
109 list_del(&me_cl->list); 191 mei_me_cl_put(me_cl);
110 kfree(me_cl);
111 break;
112 }
113 } 192 }
114} 193}
115 194
195/**
196 * mei_me_cl_rm_all - remove all me clients
197 *
198 * @dev: the device structure
199 *
200 * Locking: called under "dev->device_lock" lock
201 */
202void mei_me_cl_rm_all(struct mei_device *dev)
203{
204 struct mei_me_client *me_cl, *next;
205
206 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
207 mei_me_cl_put(me_cl);
208}
209
210
116 211
117/** 212/**
118 * mei_cl_cmp_id - tells if the clients are the same 213 * mei_cl_cmp_id - tells if the clients are the same
@@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
695{ 790{
696 struct mei_device *dev; 791 struct mei_device *dev;
697 struct mei_me_client *me_cl; 792 struct mei_me_client *me_cl;
793 int rets = 0;
698 794
699 if (WARN_ON(!cl || !cl->dev)) 795 if (WARN_ON(!cl || !cl->dev))
700 return -EINVAL; 796 return -EINVAL;
@@ -704,18 +800,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
704 if (cl->mei_flow_ctrl_creds > 0) 800 if (cl->mei_flow_ctrl_creds > 0)
705 return 1; 801 return 1;
706 802
707 me_cl = mei_me_cl_by_id(dev, cl->me_client_id); 803 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
708 if (!me_cl) { 804 if (!me_cl) {
709 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 805 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
710 return -ENOENT; 806 return -ENOENT;
711 } 807 }
712 808
713 if (me_cl->mei_flow_ctrl_creds) { 809 if (me_cl->mei_flow_ctrl_creds > 0) {
810 rets = 1;
714 if (WARN_ON(me_cl->props.single_recv_buf == 0)) 811 if (WARN_ON(me_cl->props.single_recv_buf == 0))
715 return -EINVAL; 812 rets = -EINVAL;
716 return 1;
717 } 813 }
718 return 0; 814 mei_me_cl_put(me_cl);
815 return rets;
719} 816}
720 817
721/** 818/**
@@ -732,28 +829,36 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
732{ 829{
733 struct mei_device *dev; 830 struct mei_device *dev;
734 struct mei_me_client *me_cl; 831 struct mei_me_client *me_cl;
832 int rets;
735 833
736 if (WARN_ON(!cl || !cl->dev)) 834 if (WARN_ON(!cl || !cl->dev))
737 return -EINVAL; 835 return -EINVAL;
738 836
739 dev = cl->dev; 837 dev = cl->dev;
740 838
741 me_cl = mei_me_cl_by_id(dev, cl->me_client_id); 839 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
742 if (!me_cl) { 840 if (!me_cl) {
743 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 841 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
744 return -ENOENT; 842 return -ENOENT;
745 } 843 }
746 844
747 if (me_cl->props.single_recv_buf) { 845 if (me_cl->props.single_recv_buf) {
748 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) 846 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
749 return -EINVAL; 847 rets = -EINVAL;
848 goto out;
849 }
750 me_cl->mei_flow_ctrl_creds--; 850 me_cl->mei_flow_ctrl_creds--;
751 } else { 851 } else {
752 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) 852 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
753 return -EINVAL; 853 rets = -EINVAL;
854 goto out;
855 }
754 cl->mei_flow_ctrl_creds--; 856 cl->mei_flow_ctrl_creds--;
755 } 857 }
756 return 0; 858 rets = 0;
859out:
860 mei_me_cl_put(me_cl);
861 return rets;
757} 862}
758 863
759/** 864/**
@@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
788 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 893 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
789 return -ENOTTY; 894 return -ENOTTY;
790 } 895 }
896 /* always allocate at least client max message */
897 length = max_t(size_t, length, me_cl->props.max_msg_length);
898 mei_me_cl_put(me_cl);
791 899
792 rets = pm_runtime_get(dev->dev); 900 rets = pm_runtime_get(dev->dev);
793 if (rets < 0 && rets != -EINPROGRESS) { 901 if (rets < 0 && rets != -EINPROGRESS) {
@@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
802 goto out; 910 goto out;
803 } 911 }
804 912
805 /* always allocate at least client max message */
806 length = max_t(size_t, length, me_cl->props.max_msg_length);
807 rets = mei_io_cb_alloc_resp_buf(cb, length); 913 rets = mei_io_cb_alloc_resp_buf(cb, length);
808 if (rets) 914 if (rets)
809 goto out; 915 goto out;