diff options
-rw-r--r-- | drivers/misc/mei/bus.c | 6 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 117 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 17 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 2 |
4 files changed, 80 insertions, 62 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index be767f4db26a..025626f4467d 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -322,10 +322,16 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
322 | goto out; | 322 | goto out; |
323 | } | 323 | } |
324 | 324 | ||
325 | if (cb->status) { | ||
326 | rets = cb->status; | ||
327 | goto free; | ||
328 | } | ||
329 | |||
325 | r_length = min_t(size_t, length, cb->buf_idx); | 330 | r_length = min_t(size_t, length, cb->buf_idx); |
326 | memcpy(buf, cb->response_buffer.data, r_length); | 331 | memcpy(buf, cb->response_buffer.data, r_length); |
327 | rets = r_length; | 332 | rets = r_length; |
328 | 333 | ||
334 | free: | ||
329 | mei_io_cb_free(cb); | 335 | mei_io_cb_free(cb); |
330 | cl->reading_state = MEI_IDLE; | 336 | cl->reading_state = MEI_IDLE; |
331 | cl->read_cb = NULL; | 337 | cl->read_cb = NULL; |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 711cddfa9c99..587cb04a3cf5 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -69,85 +69,91 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl, | |||
69 | cl->me_client_id == mei_hdr->me_addr; | 69 | cl->me_client_id == mei_hdr->me_addr; |
70 | } | 70 | } |
71 | /** | 71 | /** |
72 | * mei_cl_is_reading - checks if the client | 72 | * mei_cl_is_reading - checks if the client is in reading state |
73 | * is the one to read this message | ||
74 | * | 73 | * |
75 | * @cl: mei client | 74 | * @cl: mei client |
76 | * @mei_hdr: header of mei message | ||
77 | * | 75 | * |
78 | * Return: true on match and false otherwise | 76 | * Return: true if the client is reading |
79 | */ | 77 | */ |
80 | static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr) | 78 | static bool mei_cl_is_reading(struct mei_cl *cl) |
81 | { | 79 | { |
82 | return mei_cl_hbm_equal(cl, mei_hdr) && | 80 | return cl->state == MEI_FILE_CONNECTED && |
83 | cl->state == MEI_FILE_CONNECTED && | ||
84 | cl->reading_state != MEI_READ_COMPLETE; | 81 | cl->reading_state != MEI_READ_COMPLETE; |
85 | } | 82 | } |
86 | 83 | ||
87 | /** | 84 | /** |
88 | * mei_cl_irq_read_msg - process client message | 85 | * mei_cl_irq_read_msg - process client message |
89 | * | 86 | * |
90 | * @dev: the device structure | 87 | * @cl: reading client |
91 | * @mei_hdr: header of mei client message | 88 | * @mei_hdr: header of mei client message |
92 | * @complete_list: An instance of our list structure | 89 | * @complete_list: completion list |
93 | * | 90 | * |
94 | * Return: 0 on success, <0 on failure. | 91 | * Return: always 0 |
95 | */ | 92 | */ |
96 | static int mei_cl_irq_read_msg(struct mei_device *dev, | 93 | static int mei_cl_irq_read_msg(struct mei_cl *cl, |
97 | struct mei_msg_hdr *mei_hdr, | 94 | struct mei_msg_hdr *mei_hdr, |
98 | struct mei_cl_cb *complete_list) | 95 | struct mei_cl_cb *complete_list) |
99 | { | 96 | { |
100 | struct mei_cl *cl; | 97 | struct mei_device *dev = cl->dev; |
101 | struct mei_cl_cb *cb, *next; | 98 | struct mei_cl_cb *cb; |
102 | unsigned char *buffer = NULL; | 99 | unsigned char *buffer = NULL; |
103 | 100 | ||
104 | list_for_each_entry_safe(cb, next, &dev->read_list.list, list) { | 101 | list_for_each_entry(cb, &dev->read_list.list, list) { |
105 | cl = cb->cl; | 102 | if (cl == cb->cl) |
106 | if (!mei_cl_is_reading(cl, mei_hdr)) | 103 | break; |
107 | continue; | 104 | } |
108 | 105 | ||
109 | cl->reading_state = MEI_READING; | 106 | if (&cb->list == &dev->read_list.list) { |
107 | dev_err(dev->dev, "no reader found\n"); | ||
108 | goto out; | ||
109 | } | ||
110 | 110 | ||
111 | if (cb->response_buffer.size == 0 || | 111 | if (!mei_cl_is_reading(cl)) { |
112 | cb->response_buffer.data == NULL) { | 112 | cl_err(dev, cl, "cl is not reading state=%d reading state=%d\n", |
113 | cl_err(dev, cl, "response buffer is not allocated.\n"); | 113 | cl->state, cl->reading_state); |
114 | list_del(&cb->list); | 114 | goto out; |
115 | return -ENOMEM; | 115 | } |
116 | } | ||
117 | 116 | ||
118 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { | 117 | cl->reading_state = MEI_READING; |
119 | cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", | ||
120 | cb->response_buffer.size, | ||
121 | mei_hdr->length, cb->buf_idx); | ||
122 | buffer = krealloc(cb->response_buffer.data, | ||
123 | mei_hdr->length + cb->buf_idx, | ||
124 | GFP_KERNEL); | ||
125 | |||
126 | if (!buffer) { | ||
127 | list_del(&cb->list); | ||
128 | return -ENOMEM; | ||
129 | } | ||
130 | cb->response_buffer.data = buffer; | ||
131 | cb->response_buffer.size = | ||
132 | mei_hdr->length + cb->buf_idx; | ||
133 | } | ||
134 | 118 | ||
135 | buffer = cb->response_buffer.data + cb->buf_idx; | 119 | if (cb->response_buffer.size == 0 || |
136 | mei_read_slots(dev, buffer, mei_hdr->length); | 120 | cb->response_buffer.data == NULL) { |
121 | cl_err(dev, cl, "response buffer is not allocated.\n"); | ||
122 | list_move_tail(&cb->list, &complete_list->list); | ||
123 | cb->status = -ENOMEM; | ||
124 | goto out; | ||
125 | } | ||
137 | 126 | ||
138 | cb->buf_idx += mei_hdr->length; | 127 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { |
139 | if (mei_hdr->msg_complete) { | 128 | cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", |
140 | cl->status = 0; | 129 | cb->response_buffer.size, mei_hdr->length, cb->buf_idx); |
141 | list_del(&cb->list); | 130 | buffer = krealloc(cb->response_buffer.data, |
142 | cl_dbg(dev, cl, "completed read length = %lu\n", | 131 | mei_hdr->length + cb->buf_idx, |
143 | cb->buf_idx); | 132 | GFP_KERNEL); |
144 | list_add_tail(&cb->list, &complete_list->list); | 133 | |
134 | if (!buffer) { | ||
135 | cb->status = -ENOMEM; | ||
136 | list_move_tail(&cb->list, &complete_list->list); | ||
137 | goto out; | ||
145 | } | 138 | } |
146 | break; | 139 | cb->response_buffer.data = buffer; |
140 | cb->response_buffer.size = mei_hdr->length + cb->buf_idx; | ||
147 | } | 141 | } |
148 | 142 | ||
149 | dev_dbg(dev->dev, "message read\n"); | 143 | buffer = cb->response_buffer.data + cb->buf_idx; |
144 | mei_read_slots(dev, buffer, mei_hdr->length); | ||
145 | |||
146 | cb->buf_idx += mei_hdr->length; | ||
147 | if (mei_hdr->msg_complete) { | ||
148 | cl_dbg(dev, cl, "completed read length = %lu\n", | ||
149 | cb->buf_idx); | ||
150 | list_move_tail(&cb->list, &complete_list->list); | ||
151 | } | ||
152 | |||
153 | out: | ||
150 | if (!buffer) { | 154 | if (!buffer) { |
155 | /* assume that mei_hdr->length <= MEI_RD_MSG_BUF_SIZE */ | ||
156 | BUG_ON(mei_hdr->length > MEI_RD_MSG_BUF_SIZE); | ||
151 | mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); | 157 | mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); |
152 | dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", | 158 | dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", |
153 | MEI_HDR_PRM(mei_hdr)); | 159 | MEI_HDR_PRM(mei_hdr)); |
@@ -389,14 +395,10 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
389 | goto end; | 395 | goto end; |
390 | } | 396 | } |
391 | } else { | 397 | } else { |
392 | ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); | 398 | ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); |
393 | if (ret) { | ||
394 | dev_err(dev->dev, "mei_cl_irq_read_msg failed = %d\n", | ||
395 | ret); | ||
396 | goto end; | ||
397 | } | ||
398 | } | 399 | } |
399 | 400 | ||
401 | |||
400 | reset_slots: | 402 | reset_slots: |
401 | /* reset the number of slots and header */ | 403 | /* reset the number of slots and header */ |
402 | *slots = mei_count_full_read_slots(dev); | 404 | *slots = mei_count_full_read_slots(dev); |
@@ -636,4 +638,3 @@ out: | |||
636 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | 638 | schedule_delayed_work(&dev->timer_work, 2 * HZ); |
637 | mutex_unlock(&dev->device_lock); | 639 | mutex_unlock(&dev->device_lock); |
638 | } | 640 | } |
639 | |||
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 3c019c0e60eb..cbdbf4af2bf7 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -192,8 +192,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
192 | goto out; | 192 | goto out; |
193 | } | 193 | } |
194 | 194 | ||
195 | if (cl->read_cb) { | 195 | cb = cl->read_cb; |
196 | cb = cl->read_cb; | 196 | if (cb) { |
197 | /* read what left */ | 197 | /* read what left */ |
198 | if (cb->buf_idx > *offset) | 198 | if (cb->buf_idx > *offset) |
199 | goto copy_buffer; | 199 | goto copy_buffer; |
@@ -218,7 +218,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
218 | } | 218 | } |
219 | 219 | ||
220 | if (MEI_READ_COMPLETE != cl->reading_state && | 220 | if (MEI_READ_COMPLETE != cl->reading_state && |
221 | !waitqueue_active(&cl->rx_wait)) { | 221 | !waitqueue_active(&cl->rx_wait)) { |
222 | |||
222 | if (file->f_flags & O_NONBLOCK) { | 223 | if (file->f_flags & O_NONBLOCK) { |
223 | rets = -EAGAIN; | 224 | rets = -EAGAIN; |
224 | goto out; | 225 | goto out; |
@@ -248,12 +249,20 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
248 | rets = -ENODEV; | 249 | rets = -ENODEV; |
249 | goto out; | 250 | goto out; |
250 | } | 251 | } |
252 | |||
251 | if (cl->reading_state != MEI_READ_COMPLETE) { | 253 | if (cl->reading_state != MEI_READ_COMPLETE) { |
252 | rets = 0; | 254 | rets = 0; |
253 | goto out; | 255 | goto out; |
254 | } | 256 | } |
255 | /* now copy the data to user space */ | 257 | |
256 | copy_buffer: | 258 | copy_buffer: |
259 | /* now copy the data to user space */ | ||
260 | if (cb->status) { | ||
261 | rets = cb->status; | ||
262 | dev_dbg(dev->dev, "read operation failed %d\n", rets); | ||
263 | goto free; | ||
264 | } | ||
265 | |||
257 | dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n", | 266 | dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n", |
258 | cb->response_buffer.size, cb->buf_idx); | 267 | cb->response_buffer.size, cb->buf_idx); |
259 | if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { | 268 | if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 102cc6603eba..195e426b08f0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -199,6 +199,7 @@ struct mei_cl; | |||
199 | * @buf_idx: last read index | 199 | * @buf_idx: last read index |
200 | * @read_time: last read operation time stamp (iamthif) | 200 | * @read_time: last read operation time stamp (iamthif) |
201 | * @file_object: pointer to file structure | 201 | * @file_object: pointer to file structure |
202 | * @status: io status of the cb | ||
202 | * @internal: communication between driver and FW flag | 203 | * @internal: communication between driver and FW flag |
203 | */ | 204 | */ |
204 | struct mei_cl_cb { | 205 | struct mei_cl_cb { |
@@ -210,6 +211,7 @@ struct mei_cl_cb { | |||
210 | unsigned long buf_idx; | 211 | unsigned long buf_idx; |
211 | unsigned long read_time; | 212 | unsigned long read_time; |
212 | struct file *file_object; | 213 | struct file *file_object; |
214 | int status; | ||
213 | u32 internal:1; | 215 | u32 internal:1; |
214 | }; | 216 | }; |
215 | 217 | ||