clear-pkgs-linux-iot-lts2018/0150-mei-add-extended-heade...

369 lines
10 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tomas Winkler <tomas.winkler@intel.com>
Date: Mon, 18 Jun 2018 18:11:40 +0300
Subject: [PATCH] mei: add extended header
Extend header, beyond existing 4 bytes mei message header,
currently containing 8bit vtag (virtual tag).
Change-Id: I125b0bade2d600f4f96dd4dcbf8fb3e81fbc7e95
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
drivers/misc/mei/client.c | 76 ++++++++++++++++++++++--------------
drivers/misc/mei/hbm.c | 14 +++----
drivers/misc/mei/hw.h | 17 +++++++-
drivers/misc/mei/interrupt.c | 20 +++++++++-
drivers/misc/mei/mei_dev.h | 7 +++-
5 files changed, 89 insertions(+), 45 deletions(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1fc8ea0..42f2e30 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -386,6 +386,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
cb->cl = cl;
cb->buf_idx = 0;
cb->fop_type = type;
+ cb->vtag = 0;
return cb;
}
@@ -1528,16 +1529,29 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
*
* @mei_hdr: mei message header
* @cb: message callback structure
+ *
+ * Return: header length in bytes
*/
-static void mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *cb)
+static size_t mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr,
+ struct mei_cl_cb *cb)
{
+ size_t hdr_len = sizeof(*mei_hdr);
+ struct mei_msg_extd_hdr *ext_hdr;
+
+ memset(mei_hdr, 0, sizeof(*mei_hdr));
mei_hdr->host_addr = mei_cl_host_addr(cb->cl);
mei_hdr->me_addr = mei_cl_me_id(cb->cl);
- mei_hdr->length = 0;
- mei_hdr->reserved = 0;
- mei_hdr->msg_complete = 0;
- mei_hdr->dma_ring = 0;
mei_hdr->internal = cb->internal;
+
+ if (cb->vtag && cb->buf_idx == 0) {
+ ext_hdr = (struct mei_msg_extd_hdr *)mei_hdr->extension;
+ memset(ext_hdr, 0, sizeof(*ext_hdr));
+ mei_hdr->extended = 1;
+ ext_hdr->vtag = cb->vtag;
+ hdr_len += sizeof(*ext_hdr);
+ }
+
+ return hdr_len;
}
/**
@@ -1555,8 +1569,9 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
{
struct mei_device *dev;
struct mei_msg_data *buf;
- struct mei_msg_hdr mei_hdr;
- size_t hdr_len = sizeof(mei_hdr);
+ u32 __hdr[MEI_MSG_HDR_MAX];
+ struct mei_msg_hdr *mei_hdr = (void *)__hdr;
+ size_t hdr_len;
size_t len;
size_t hbuf_len, dr_len;
int hbuf_slots;
@@ -1596,36 +1611,36 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
dr_slots = mei_dma_ring_empty_slots(dev);
dr_len = mei_slots2data(dr_slots);
- mei_msg_hdr_init(&mei_hdr, cb);
+ hdr_len = mei_msg_hdr_init(mei_hdr, cb);
/**
* Split the message only if we can write the whole host buffer
* otherwise wait for next time the host buffer is empty.
*/
if (len + hdr_len <= hbuf_len) {
- mei_hdr.length = len;
- mei_hdr.msg_complete = 1;
+ mei_hdr->length = len;
+ mei_hdr->msg_complete = 1;
} else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) {
- mei_hdr.dma_ring = 1;
+ mei_hdr->dma_ring = 1;
if (len > dr_len)
len = dr_len;
else
- mei_hdr.msg_complete = 1;
+ mei_hdr->msg_complete = 1;
- mei_hdr.length = sizeof(dma_len);
+ mei_hdr->length = sizeof(dma_len);
dma_len = len;
data = &dma_len;
} else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) {
len = hbuf_len - hdr_len;
- mei_hdr.length = len;
+ mei_hdr->length = len;
} else {
return 0;
}
- if (mei_hdr.dma_ring)
+ if (mei_hdr->dma_ring)
mei_dma_ring_write(dev, buf->data + cb->buf_idx, len);
- rets = mei_write_message(dev, &mei_hdr, hdr_len, data, mei_hdr.length);
+ rets = mei_write_message(dev, mei_hdr, hdr_len, data, mei_hdr->length);
if (rets)
goto err;
@@ -1640,7 +1655,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
}
}
- if (mei_hdr.msg_complete)
+ if (mei_hdr->msg_complete)
list_move_tail(&cb->list, &dev->write_waiting_list);
return 0;
@@ -1664,8 +1679,9 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
{
struct mei_device *dev;
struct mei_msg_data *buf;
- struct mei_msg_hdr mei_hdr;
- size_t hdr_len = sizeof(mei_hdr);
+ u32 __hdr[MEI_MSG_HDR_MAX];
+ struct mei_msg_hdr *mei_hdr = (void *)__hdr;
+ size_t hdr_len;
size_t len, hbuf_len, dr_len;
int hbuf_slots;
u32 dr_slots;
@@ -1705,7 +1721,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
if (rets < 0)
goto err;
- mei_msg_hdr_init(&mei_hdr, cb);
+ hdr_len = mei_msg_hdr_init(mei_hdr, cb);
if (rets == 0) {
cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
@@ -1730,28 +1746,28 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
dr_len = mei_slots2data(dr_slots);
if (len + hdr_len <= hbuf_len) {
- mei_hdr.length = len;
- mei_hdr.msg_complete = 1;
+ mei_hdr->length = len;
+ mei_hdr->msg_complete = 1;
} else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) {
- mei_hdr.dma_ring = 1;
+ mei_hdr->dma_ring = 1;
if (len > dr_len)
len = dr_len;
else
- mei_hdr.msg_complete = 1;
+ mei_hdr->msg_complete = 1;
- mei_hdr.length = sizeof(dma_len);
+ mei_hdr->length = sizeof(dma_len);
dma_len = len;
data = &dma_len;
} else {
len = hbuf_len - hdr_len;
- mei_hdr.length = len;
+ mei_hdr->length = len;
}
- if (mei_hdr.dma_ring)
+ if (mei_hdr->dma_ring)
mei_dma_ring_write(dev, buf->data, len);
- rets = mei_write_message(dev, &mei_hdr, hdr_len,
- data, mei_hdr.length);
+ rets = mei_write_message(dev, mei_hdr, hdr_len,
+ data, mei_hdr->length);
if (rets)
goto err;
@@ -1765,7 +1781,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
len = buf->size;
out:
- if (mei_hdr.msg_complete)
+ if (mei_hdr->msg_complete)
mei_tx_cb_enqueue(cb, &dev->write_waiting_list);
else
mei_tx_cb_enqueue(cb, &dev->write_list);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 06d6da2..d635f65 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -136,19 +136,15 @@ void mei_hbm_reset(struct mei_device *dev)
/**
* mei_hbm_hdr - construct hbm header
*
- * @hdr: hbm header
+ * @mei_hdr: hbm header
* @length: payload length
*/
-static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
+static inline void mei_hbm_hdr(struct mei_msg_hdr *mei_hdr, size_t length)
{
- hdr->host_addr = 0;
- hdr->me_addr = 0;
- hdr->length = length;
- hdr->msg_complete = 1;
- hdr->dma_ring = 0;
- hdr->reserved = 0;
- hdr->internal = 0;
+ memset(mei_hdr, 0, sizeof(*mei_hdr));
+ mei_hdr->length = length;
+ mei_hdr->msg_complete = 1;
}
/**
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 46843bc..b4e0002 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -211,6 +211,17 @@ enum mei_cl_disconnect_status {
MEI_CL_DISCONN_SUCCESS = MEI_HBMS_SUCCESS
};
+/**
+ * struct mei_msg_extd_hdr - mei extended header
+ *
+ * @vtag: virtual tag.
+ * @reserved: reserved.
+ */
+struct mei_msg_extd_hdr {
+ u8 vtag;
+ u8 reserved[3];
+} __packed;
+
/**
* struct mei_msg_hdr - MEI BUS Interface Section
*
@@ -218,6 +229,7 @@ enum mei_cl_disconnect_status {
* @host_addr: host address
* @length: message length
* @reserved: reserved
+ * @extended: message has extended header
* @dma_ring: message is on dma ring
* @internal: message is internal
* @msg_complete: last packet of the message
@@ -227,14 +239,15 @@ struct mei_msg_hdr {
u32 me_addr:8;
u32 host_addr:8;
u32 length:9;
- u32 reserved:4;
+ u32 reserved:3;
+ u32 extended:1;
u32 dma_ring:1;
u32 internal:1;
u32 msg_complete:1;
u32 extension[0];
} __packed;
-#define MEI_MSG_HDR_MAX 2
+#define MEI_MSG_HDR_MAX 3
struct mei_bus_message {
u8 hbm_cmd;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 055c2d8..6531e03 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -101,6 +101,7 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
{
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
+ struct mei_msg_extd_hdr *ext_hdr = (void *)mei_hdr->extension;
size_t buf_sz;
u32 length;
@@ -116,13 +117,24 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
list_add_tail(&cb->list, &cl->rd_pending);
}
+ if (mei_hdr->extended) {
+ cl_dbg(dev, cl, "vtag: %d\n", ext_hdr->vtag);
+ if (cb->vtag && cb->vtag != ext_hdr->vtag) {
+ cl_err(dev, cl, "mismatched tag: %d != %d\n",
+ cb->vtag, ext_hdr->vtag);
+ cb->status = -EPROTO;
+ goto discard;
+ }
+ cb->vtag = ext_hdr->vtag;
+ }
+
if (!mei_cl_is_connected(cl)) {
cl_dbg(dev, cl, "not connected\n");
cb->status = -ENODEV;
goto discard;
}
- length = mei_hdr->dma_ring ? mei_hdr->extension[0] : mei_hdr->length;
+ length = mei_hdr->dma_ring ? mei_hdr->extension[1] : mei_hdr->length;
buf_sz = length + cb->buf_idx;
/* catch for integer overflow */
@@ -303,9 +315,13 @@ int mei_irq_read_handler(struct mei_device *dev,
goto end;
}
- if (mei_hdr->dma_ring) {
+ if (mei_hdr->extended) {
dev->rd_msg_hdr[1] = mei_read_hdr(dev);
(*slots)--;
+ }
+ if (mei_hdr->dma_ring) {
+ dev->rd_msg_hdr[2] = mei_read_hdr(dev);
+ (*slots)--;
mei_hdr->length = 0;
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 6a815a1..5f033b7 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -184,6 +184,7 @@ struct mei_cl;
* @fop_type: file operation type
* @buf: buffer for data associated with the callback
* @buf_idx: last read index
+ * @vtag: vm tag
* @fp: pointer to file structure
* @status: io status of the cb
* @internal: communication between driver and FW flag
@@ -195,6 +196,7 @@ struct mei_cl_cb {
enum mei_cb_file_ops fop_type;
struct mei_msg_data buf;
size_t buf_idx;
+ u8 vtag;
const struct file *fp;
int status;
u32 internal:1;
@@ -744,10 +746,11 @@ static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
int mei_register(struct mei_device *dev, struct device *parent);
void mei_deregister(struct mei_device *dev);
-#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d dma=%1d internal=%1d comp=%1d"
+#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d dma=%1d ext=%1d internal=%1d comp=%1d"
#define MEI_HDR_PRM(hdr) \
(hdr)->host_addr, (hdr)->me_addr, \
- (hdr)->length, (hdr)->dma_ring, (hdr)->internal, (hdr)->msg_complete
+ (hdr)->length, (hdr)->dma_ring, (hdr)->extended, \
+ (hdr)->internal, (hdr)->msg_complete
ssize_t mei_fw_status2str(struct mei_fw_status *fw_sts, char *buf, size_t len);
/**
--
https://clearlinux.org