diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2013-04-19 15:01:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-19 16:38:38 -0400 |
commit | fcb136e1ac5774909e0d85189f721b8dfa800e0f (patch) | |
tree | ac89a706d67783063d4f752c3acddc04c5ab10e8 /drivers/misc/mei | |
parent | 6e0f180fd8b47fa0884177a142e41a86117edc23 (diff) |
mei: fix reading large reposnes
While writting to device is limitted to max_msg_length advertized
in client properites the read can be much longer delivered consequiting chunks.
We use krealloc to enlarge the buffer when needed.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/bus.c | 8 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 7 | ||||
-rw-r--r-- | drivers/misc/mei/client.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 18 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 7 |
5 files changed, 27 insertions, 15 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 834ceeb69cbf..1e935eacaa7f 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -286,7 +286,7 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
286 | mutex_lock(&dev->device_lock); | 286 | mutex_lock(&dev->device_lock); |
287 | 287 | ||
288 | if (!cl->read_cb) { | 288 | if (!cl->read_cb) { |
289 | err = mei_cl_read_start(cl); | 289 | err = mei_cl_read_start(cl, length); |
290 | if (err < 0) { | 290 | if (err < 0) { |
291 | mutex_unlock(&dev->device_lock); | 291 | mutex_unlock(&dev->device_lock); |
292 | return err; | 292 | return err; |
@@ -378,7 +378,7 @@ static void mei_bus_event_work(struct work_struct *work) | |||
378 | device->events = 0; | 378 | device->events = 0; |
379 | 379 | ||
380 | /* Prepare for the next read */ | 380 | /* Prepare for the next read */ |
381 | mei_cl_read_start(device->cl); | 381 | mei_cl_read_start(device->cl, 0); |
382 | } | 382 | } |
383 | 383 | ||
384 | int mei_cl_register_event_cb(struct mei_cl_device *device, | 384 | int mei_cl_register_event_cb(struct mei_cl_device *device, |
@@ -392,7 +392,7 @@ int mei_cl_register_event_cb(struct mei_cl_device *device, | |||
392 | device->event_context = context; | 392 | device->event_context = context; |
393 | INIT_WORK(&device->event_work, mei_bus_event_work); | 393 | INIT_WORK(&device->event_work, mei_bus_event_work); |
394 | 394 | ||
395 | mei_cl_read_start(device->cl); | 395 | mei_cl_read_start(device->cl, 0); |
396 | 396 | ||
397 | return 0; | 397 | return 0; |
398 | } | 398 | } |
@@ -436,7 +436,7 @@ int mei_cl_enable_device(struct mei_cl_device *device) | |||
436 | mutex_unlock(&dev->device_lock); | 436 | mutex_unlock(&dev->device_lock); |
437 | 437 | ||
438 | if (device->event_cb && !cl->read_cb) | 438 | if (device->event_cb && !cl->read_cb) |
439 | mei_cl_read_start(device->cl); | 439 | mei_cl_read_start(device->cl, 0); |
440 | 440 | ||
441 | if (!device->ops || !device->ops->enable) | 441 | if (!device->ops || !device->ops->enable) |
442 | return 0; | 442 | return 0; |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 9541aa90d8f7..71892745e2e8 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -624,7 +624,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) | |||
624 | * | 624 | * |
625 | * returns 0 on success, <0 on failure. | 625 | * returns 0 on success, <0 on failure. |
626 | */ | 626 | */ |
627 | int mei_cl_read_start(struct mei_cl *cl) | 627 | int mei_cl_read_start(struct mei_cl *cl, size_t length) |
628 | { | 628 | { |
629 | struct mei_device *dev; | 629 | struct mei_device *dev; |
630 | struct mei_cl_cb *cb; | 630 | struct mei_cl_cb *cb; |
@@ -657,8 +657,9 @@ int mei_cl_read_start(struct mei_cl *cl) | |||
657 | if (!cb) | 657 | if (!cb) |
658 | return -ENOMEM; | 658 | return -ENOMEM; |
659 | 659 | ||
660 | rets = mei_io_cb_alloc_resp_buf(cb, | 660 | /* always allocate at least client max message */ |
661 | dev->me_clients[i].props.max_msg_length); | 661 | length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length); |
662 | rets = mei_io_cb_alloc_resp_buf(cb, length); | ||
662 | if (rets) | 663 | if (rets) |
663 | goto err; | 664 | goto err; |
664 | 665 | ||
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index e890c8bf89d0..cfdb144526aa 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -87,7 +87,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl); | |||
87 | bool mei_cl_is_other_connecting(struct mei_cl *cl); | 87 | bool mei_cl_is_other_connecting(struct mei_cl *cl); |
88 | int mei_cl_disconnect(struct mei_cl *cl); | 88 | int mei_cl_disconnect(struct mei_cl *cl); |
89 | int mei_cl_connect(struct mei_cl *cl, struct file *file); | 89 | int mei_cl_connect(struct mei_cl *cl, struct file *file); |
90 | int mei_cl_read_start(struct mei_cl *cl); | 90 | int mei_cl_read_start(struct mei_cl *cl, size_t length); |
91 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking); | 91 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking); |
92 | 92 | ||
93 | void mei_host_client_init(struct work_struct *work); | 93 | void mei_host_client_init(struct work_struct *work); |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 9bf64c06fa39..74730713a8d3 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -145,9 +145,21 @@ static int mei_cl_irq_read_msg(struct mei_device *dev, | |||
145 | } | 145 | } |
146 | 146 | ||
147 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { | 147 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { |
148 | dev_warn(&dev->pdev->dev, "message overflow.\n"); | 148 | dev_dbg(&dev->pdev->dev, "message overflow. size %d len %d idx %ld\n", |
149 | list_del(&cb->list); | 149 | cb->response_buffer.size, |
150 | return -ENOMEM; | 150 | mei_hdr->length, cb->buf_idx); |
151 | cb->response_buffer.data = | ||
152 | krealloc(cb->response_buffer.data, | ||
153 | mei_hdr->length + cb->buf_idx, | ||
154 | GFP_KERNEL); | ||
155 | |||
156 | if (!cb->response_buffer.data) { | ||
157 | dev_err(&dev->pdev->dev, "allocation failed.\n"); | ||
158 | list_del(&cb->list); | ||
159 | return -ENOMEM; | ||
160 | } | ||
161 | cb->response_buffer.size = | ||
162 | mei_hdr->length + cb->buf_idx; | ||
151 | } | 163 | } |
152 | 164 | ||
153 | buffer = cb->response_buffer.data + cb->buf_idx; | 165 | buffer = cb->response_buffer.data + cb->buf_idx; |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 78b4da5ed96c..7c44c8dbae42 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -244,7 +244,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
244 | goto out; | 244 | goto out; |
245 | } | 245 | } |
246 | 246 | ||
247 | err = mei_cl_read_start(cl); | 247 | err = mei_cl_read_start(cl, length); |
248 | if (err && err != -EBUSY) { | 248 | if (err && err != -EBUSY) { |
249 | dev_dbg(&dev->pdev->dev, | 249 | dev_dbg(&dev->pdev->dev, |
250 | "mei start read failure with status = %d\n", err); | 250 | "mei start read failure with status = %d\n", err); |
@@ -292,9 +292,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
292 | } | 292 | } |
293 | /* now copy the data to user space */ | 293 | /* now copy the data to user space */ |
294 | copy_buffer: | 294 | copy_buffer: |
295 | dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", | 295 | dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n", |
296 | cb->response_buffer.size); | 296 | cb->response_buffer.size, cb->buf_idx); |
297 | dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx); | ||
298 | if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { | 297 | if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { |
299 | rets = -EMSGSIZE; | 298 | rets = -EMSGSIZE; |
300 | goto free; | 299 | goto free; |