summaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r--drivers/misc/mei/interrupt.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 5a661cbdf2ae..055c2d89b310 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -75,6 +75,8 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
*/
static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
{
+ if (hdr->dma_ring)
+ mei_dma_ring_read(dev, NULL, hdr->extension[0]);
/*
* no need to check for size as it is guarantied
* that length fits into rd_msg_buf
@@ -100,6 +102,7 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
size_t buf_sz;
+ u32 length;
cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
if (!cb) {
@@ -119,25 +122,31 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
goto discard;
}
- buf_sz = mei_hdr->length + cb->buf_idx;
+ length = mei_hdr->dma_ring ? mei_hdr->extension[0] : mei_hdr->length;
+
+ buf_sz = length + cb->buf_idx;
/* catch for integer overflow */
if (buf_sz < cb->buf_idx) {
cl_err(dev, cl, "message is too big len %d idx %zu\n",
- mei_hdr->length, cb->buf_idx);
+ length, cb->buf_idx);
cb->status = -EMSGSIZE;
goto discard;
}
if (cb->buf.size < buf_sz) {
cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",
- cb->buf.size, mei_hdr->length, cb->buf_idx);
+ cb->buf.size, length, cb->buf_idx);
cb->status = -EMSGSIZE;
goto discard;
}
+ if (mei_hdr->dma_ring)
+ mei_dma_ring_read(dev, cb->buf.data + cb->buf_idx, length);
+
+ /* for DMA read 0 length to generate an interrupt to the device */
mei_read_slots(dev, cb->buf.data + cb->buf_idx, mei_hdr->length);
- cb->buf_idx += mei_hdr->length;
+ cb->buf_idx += length;
if (mei_hdr->msg_complete) {
cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx);
@@ -247,6 +256,9 @@ static inline int hdr_is_valid(u32 msg_hdr)
if (!msg_hdr || mei_hdr->reserved)
return -EBADMSG;
+ if (mei_hdr->dma_ring && mei_hdr->length != MEI_SLOT_SIZE)
+ return -EBADMSG;
+
return 0;
}
@@ -267,20 +279,20 @@ int mei_irq_read_handler(struct mei_device *dev,
struct mei_cl *cl;
int ret;
- if (!dev->rd_msg_hdr) {
- dev->rd_msg_hdr = mei_read_hdr(dev);
+ if (!dev->rd_msg_hdr[0]) {
+ dev->rd_msg_hdr[0] = mei_read_hdr(dev);
(*slots)--;
dev_dbg(dev->dev, "slots =%08x.\n", *slots);
- ret = hdr_is_valid(dev->rd_msg_hdr);
+ ret = hdr_is_valid(dev->rd_msg_hdr[0]);
if (ret) {
dev_err(dev->dev, "corrupted message header 0x%08X\n",
- dev->rd_msg_hdr);
+ dev->rd_msg_hdr[0]);
goto end;
}
}
- mei_hdr = (struct mei_msg_hdr *)&dev->rd_msg_hdr;
+ mei_hdr = (struct mei_msg_hdr *)dev->rd_msg_hdr;
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
if (mei_slots2data(*slots) < mei_hdr->length) {
@@ -291,6 +303,12 @@ int mei_irq_read_handler(struct mei_device *dev,
goto end;
}
+ if (mei_hdr->dma_ring) {
+ dev->rd_msg_hdr[1] = mei_read_hdr(dev);
+ (*slots)--;
+ mei_hdr->length = 0;
+ }
+
/* HBM message */
if (hdr_is_hbm(mei_hdr)) {
ret = mei_hbm_dispatch(dev, mei_hdr);
@@ -324,7 +342,7 @@ int mei_irq_read_handler(struct mei_device *dev,
goto reset_slots;
}
dev_err(dev->dev, "no destination client found 0x%08X\n",
- dev->rd_msg_hdr);
+ dev->rd_msg_hdr[0]);
ret = -EBADMSG;
goto end;
}
@@ -334,9 +352,8 @@ int mei_irq_read_handler(struct mei_device *dev,
reset_slots:
/* reset the number of slots and header */
+ memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));
*slots = mei_count_full_read_slots(dev);
- dev->rd_msg_hdr = 0;
-
if (*slots == -EOVERFLOW) {
/* overflow - reset */
dev_err(dev->dev, "resetting due to slots overflow.\n");
OpenPOWER on IntegriCloud