diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-15 13:48:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-15 13:48:44 -0500 |
commit | 4ba63072b998cc31515cc6305c25f3b808b50c01 (patch) | |
tree | 779863511765c70bfd232f676b885f940ba88722 /drivers/misc/mei/client.c | |
parent | e29876723f7cb7728f0d6a674d23f92673e9f112 (diff) | |
parent | 5fb31cd839c21130c0b2524ceb9244e98dfe10e3 (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.c | 156 |
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 | */ | ||
34 | void 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 | */ | ||
49 | struct 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 | */ | ||
64 | static 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 | */ | ||
78 | void 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 | */ |
102 | void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id) | 163 | void 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 | */ | ||
182 | void 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 | */ | ||
202 | void 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; |
859 | out: | ||
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; |