OSDN Git Service

mei: add support to GSC extended header
authorTomas Winkler <tomas.winkler@intel.com>
Wed, 28 Sep 2022 00:41:31 +0000 (17:41 -0700)
committerDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Mon, 3 Oct 2022 18:29:07 +0000 (11:29 -0700)
GSC extend header is of variable size and data
is provided in a sgl list inside the header
and not in the data buffers, need to enable the path.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Vitaly Lubart <vitaly.lubart@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-2-daniele.ceraolospurio@intel.com
drivers/misc/mei/client.c
drivers/misc/mei/hbm.c
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw.h
drivers/misc/mei/interrupt.c
drivers/misc/mei/mei_dev.h

index 0b2fbe1..6c8b71a 100644 (file)
@@ -322,6 +322,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
 
        list_del(&cb->list);
        kfree(cb->buf.data);
+       kfree(cb->ext_hdr);
        kfree(cb);
 }
 
@@ -401,6 +402,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
        cb->buf_idx = 0;
        cb->fop_type = type;
        cb->vtag = 0;
+       cb->ext_hdr = NULL;
 
        return cb;
 }
@@ -1740,6 +1742,17 @@ static inline u8 mei_ext_hdr_set_vtag(void *ext, u8 vtag)
        return vtag_hdr->hdr.length;
 }
 
+static inline bool mei_ext_hdr_is_gsc(struct mei_ext_hdr *ext)
+{
+       return ext && ext->type == MEI_EXT_HDR_GSC;
+}
+
+static inline u8 mei_ext_hdr_set_gsc(struct mei_ext_hdr *ext, struct mei_ext_hdr *gsc_hdr)
+{
+       memcpy(ext, gsc_hdr, mei_ext_hdr_len(gsc_hdr));
+       return ext->length;
+}
+
 /**
  * mei_msg_hdr_init - allocate and initialize mei message header
  *
@@ -1752,14 +1765,17 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
        size_t hdr_len;
        struct mei_ext_meta_hdr *meta;
        struct mei_msg_hdr *mei_hdr;
-       bool is_ext, is_vtag;
+       bool is_ext, is_hbm, is_gsc, is_vtag;
+       struct mei_ext_hdr *next_ext;
 
        if (!cb)
                return ERR_PTR(-EINVAL);
 
        /* Extended header for vtag is attached only on the first fragment */
        is_vtag = (cb->vtag && cb->buf_idx == 0);
-       is_ext = is_vtag;
+       is_hbm = cb->cl->me_cl->client_id == 0;
+       is_gsc = ((!is_hbm) && cb->cl->dev->hbm_f_gsc_supported && mei_ext_hdr_is_gsc(cb->ext_hdr));
+       is_ext = is_vtag || is_gsc;
 
        /* Compute extended header size */
        hdr_len = sizeof(*mei_hdr);
@@ -1771,6 +1787,9 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
        if (is_vtag)
                hdr_len += sizeof(struct mei_ext_hdr_vtag);
 
+       if (is_gsc)
+               hdr_len += mei_ext_hdr_len(cb->ext_hdr);
+
 setup_hdr:
        mei_hdr = kzalloc(hdr_len, GFP_KERNEL);
        if (!mei_hdr)
@@ -1785,10 +1804,20 @@ setup_hdr:
                goto out;
 
        meta = (struct mei_ext_meta_hdr *)mei_hdr->extension;
+       meta->size = 0;
+       next_ext = (struct mei_ext_hdr *)meta->hdrs;
        if (is_vtag) {
                meta->count++;
-               meta->size += mei_ext_hdr_set_vtag(meta->hdrs, cb->vtag);
+               meta->size += mei_ext_hdr_set_vtag(next_ext, cb->vtag);
+               next_ext = mei_ext_next(next_ext);
+       }
+
+       if (is_gsc) {
+               meta->count++;
+               meta->size += mei_ext_hdr_set_gsc(next_ext, cb->ext_hdr);
+               next_ext = mei_ext_next(next_ext);
        }
+
 out:
        mei_hdr->length = hdr_len - sizeof(*mei_hdr);
        return mei_hdr;
@@ -1812,14 +1841,14 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
        struct mei_msg_hdr *mei_hdr = NULL;
        size_t hdr_len;
        size_t hbuf_len, dr_len;
-       size_t buf_len;
+       size_t buf_len = 0;
        size_t data_len;
        int hbuf_slots;
        u32 dr_slots;
        u32 dma_len;
        int rets;
        bool first_chunk;
-       const void *data;
+       const void *data = NULL;
 
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
@@ -1839,8 +1868,10 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
                return 0;
        }
 
-       buf_len = buf->size - cb->buf_idx;
-       data = buf->data + cb->buf_idx;
+       if (buf->data) {
+               buf_len = buf->size - cb->buf_idx;
+               data = buf->data + cb->buf_idx;
+       }
        hbuf_slots = mei_hbuf_empty_slots(dev);
        if (hbuf_slots < 0) {
                rets = -EOVERFLOW;
@@ -1858,9 +1889,6 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
                goto err;
        }
 
-       cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",
-              mei_hdr->extended, cb->vtag);
-
        hdr_len = sizeof(*mei_hdr) + mei_hdr->length;
 
        /**
@@ -1889,7 +1917,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
        }
        mei_hdr->length += data_len;
 
-       if (mei_hdr->dma_ring)
+       if (mei_hdr->dma_ring && buf->data)
                mei_dma_ring_write(dev, buf->data + cb->buf_idx, buf_len);
        rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);
 
@@ -1983,9 +2011,6 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
                goto err;
        }
 
-       cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",
-              mei_hdr->extended, cb->vtag);
-
        hdr_len = sizeof(*mei_hdr) + mei_hdr->length;
 
        if (rets == 0) {
@@ -2030,7 +2055,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 
        mei_hdr->length += data_len;
 
-       if (mei_hdr->dma_ring)
+       if (mei_hdr->dma_ring && buf->data)
                mei_dma_ring_write(dev, buf->data, buf_len);
        rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);
 
index de712cb..12a62a9 100644 (file)
@@ -340,9 +340,13 @@ static int mei_hbm_capabilities_req(struct mei_device *dev)
        req.hbm_cmd = MEI_HBM_CAPABILITIES_REQ_CMD;
        if (dev->hbm_f_vt_supported)
                req.capability_requested[0] |= HBM_CAP_VT;
+
        if (dev->hbm_f_cd_supported)
                req.capability_requested[0] |= HBM_CAP_CD;
 
+       if (dev->hbm_f_gsc_supported)
+               req.capability_requested[0] |= HBM_CAP_GSC;
+
        ret = mei_hbm_write_message(dev, &mei_hdr, &req);
        if (ret) {
                dev_err(dev->dev,
@@ -1200,6 +1204,12 @@ static void mei_hbm_config_features(struct mei_device *dev)
             dev->version.minor_version >= HBM_MINOR_VERSION_VT))
                dev->hbm_f_vt_supported = 1;
 
+       /* GSC support */
+       if (dev->version.major_version > HBM_MAJOR_VERSION_GSC ||
+           (dev->version.major_version == HBM_MAJOR_VERSION_GSC &&
+            dev->version.minor_version >= HBM_MINOR_VERSION_GSC))
+               dev->hbm_f_gsc_supported = 1;
+
        /* Capability message Support */
        dev->hbm_f_cap_supported = 0;
        if (dev->version.major_version > HBM_MAJOR_VERSION_CAP ||
@@ -1367,6 +1377,9 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                if (!(capability_res->capability_granted[0] & HBM_CAP_CD))
                        dev->hbm_f_cd_supported = 0;
 
+               if (!(capability_res->capability_granted[0] & HBM_CAP_GSC))
+                       dev->hbm_f_gsc_supported = 0;
+
                if (dev->hbm_f_dr_supported) {
                        if (mei_dmam_ring_alloc(dev))
                                dev_info(dev->dev, "running w/o dma ring\n");
index 9e2f781..da4ef0b 100644 (file)
@@ -590,9 +590,14 @@ static int mei_me_hbuf_write(struct mei_device *dev,
        u32 dw_cnt;
        int empty_slots;
 
-       if (WARN_ON(!hdr || !data || hdr_len & 0x3))
+       if (WARN_ON(!hdr || hdr_len & 0x3))
                return -EINVAL;
 
+       if (!data && data_len) {
+               dev_err(dev->dev, "wrong parameters null data with data_len = %zu\n", data_len);
+               return -EINVAL;
+       }
+
        dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr));
 
        empty_slots = mei_hbuf_empty_slots(dev);
index e7e020d..70d405c 100644 (file)
 #define HBM_MAJOR_VERSION_VT               2
 
 /*
+ * MEI version with GSC support
+ */
+#define HBM_MINOR_VERSION_GSC              2
+#define HBM_MAJOR_VERSION_GSC              2
+
+/*
  * MEI version with capabilities message support
  */
 #define HBM_MINOR_VERSION_CAP              2
@@ -229,10 +235,12 @@ enum mei_cl_disconnect_status {
  *
  * @MEI_EXT_HDR_NONE: sentinel
  * @MEI_EXT_HDR_VTAG: vtag header
+ * @MEI_EXT_HDR_GSC: gsc header
  */
 enum mei_ext_hdr_type {
        MEI_EXT_HDR_NONE = 0,
        MEI_EXT_HDR_VTAG = 1,
+       MEI_EXT_HDR_GSC = 2,
 };
 
 /**
@@ -305,6 +313,60 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta,
        return (u8 *)ext >= (u8 *)meta + sizeof(*meta) + (meta->size * 4);
 }
 
+struct mei_gsc_sgl {
+       u32 low;
+       u32 high;
+       u32 length;
+} __packed;
+
+#define GSC_HECI_MSG_KERNEL 0
+#define GSC_HECI_MSG_USER   1
+
+#define GSC_ADDRESS_TYPE_GTT   0
+#define GSC_ADDRESS_TYPE_PPGTT 1
+#define GSC_ADDRESS_TYPE_PHYSICAL_CONTINUOUS 2 /* max of 64K */
+#define GSC_ADDRESS_TYPE_PHYSICAL_SGL 3
+
+/**
+ * struct mei_ext_hdr_gsc_h2f - extended header: gsc host to firmware interface
+ *
+ * @hdr: extended header
+ * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER
+ * @addr_type: GSC_ADDRESS_TYPE_{GTT, PPGTT, PHYSICAL_CONTINUOUS, PHYSICAL_SGL}
+ * @fence_id: synchronization marker
+ * @input_address_count: number of input sgl buffers
+ * @output_address_count: number of output sgl buffers
+ * @reserved: reserved
+ * @sgl: sg list
+ */
+struct mei_ext_hdr_gsc_h2f {
+       struct mei_ext_hdr hdr;
+       u8                 client_id;
+       u8                 addr_type;
+       u32                fence_id;
+       u8                 input_address_count;
+       u8                 output_address_count;
+       u8                 reserved[2];
+       struct mei_gsc_sgl sgl[];
+} __packed;
+
+/**
+ * struct mei_ext_hdr_gsc_f2h - gsc firmware to host interface
+ *
+ * @hdr: extended header
+ * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER
+ * @reserved: reserved
+ * @fence_id: synchronization marker
+ * @written: number of bytes written to firmware
+ */
+struct mei_ext_hdr_gsc_f2h {
+       struct mei_ext_hdr hdr;
+       u8                 client_id;
+       u8                 reserved;
+       u32                fence_id;
+       u32                written;
+} __packed;
+
 /**
  * mei_ext_next - following extended header on the TLV list
  *
@@ -321,6 +383,21 @@ static inline struct mei_ext_hdr *mei_ext_next(struct mei_ext_hdr *ext)
 }
 
 /**
+ * mei_ext_hdr_len - get ext header length in bytes
+ *
+ * @ext: extend header
+ *
+ * Return: extend header length in bytes
+ */
+static inline u32 mei_ext_hdr_len(const struct mei_ext_hdr *ext)
+{
+       if (!ext)
+               return 0;
+
+       return ext->length * sizeof(u32);
+}
+
+/**
  * struct mei_msg_hdr - MEI BUS Interface Section
  *
  * @me_addr: device address
@@ -682,6 +759,10 @@ struct hbm_dma_ring_ctrl {
 
 /* virtual tag supported */
 #define HBM_CAP_VT BIT(0)
+
+/* gsc extended header support */
+#define HBM_CAP_GSC BIT(1)
+
 /* client dma supported */
 #define HBM_CAP_CD BIT(2)
 
index 0706322..0a0e984 100644 (file)
@@ -98,9 +98,12 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
        struct mei_device *dev = cl->dev;
        struct mei_cl_cb *cb;
 
+       struct mei_ext_hdr_vtag *vtag_hdr = NULL;
+       struct mei_ext_hdr_gsc_f2h *gsc_f2h = NULL;
+
        size_t buf_sz;
        u32 length;
-       int ext_len;
+       u32 ext_len;
 
        length = mei_hdr->length;
        ext_len = 0;
@@ -122,18 +125,24 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
        }
 
        if (mei_hdr->extended) {
-               struct mei_ext_hdr *ext;
-               struct mei_ext_hdr_vtag *vtag_hdr = NULL;
-
-               ext = mei_ext_begin(meta);
+               struct mei_ext_hdr *ext = mei_ext_begin(meta);
                do {
                        switch (ext->type) {
                        case MEI_EXT_HDR_VTAG:
                                vtag_hdr = (struct mei_ext_hdr_vtag *)ext;
                                break;
+                       case MEI_EXT_HDR_GSC:
+                               gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext;
+                               cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL);
+                               if (!cb->ext_hdr) {
+                                       cb->status = -ENOMEM;
+                                       goto discard;
+                               }
+                               break;
                        case MEI_EXT_HDR_NONE:
                                fallthrough;
                        default:
+                               cl_err(dev, cl, "unknown extended header\n");
                                cb->status = -EPROTO;
                                break;
                        }
@@ -141,12 +150,14 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
                        ext = mei_ext_next(ext);
                } while (!mei_ext_last(meta, ext));
 
-               if (!vtag_hdr) {
-                       cl_dbg(dev, cl, "vtag not found in extended header.\n");
+               if (!vtag_hdr && !gsc_f2h) {
+                       cl_dbg(dev, cl, "no vtag or gsc found in extended header.\n");
                        cb->status = -EPROTO;
                        goto discard;
                }
+       }
 
+       if (vtag_hdr) {
                cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag);
                if (cb->vtag && cb->vtag != vtag_hdr->vtag) {
                        cl_err(dev, cl, "mismatched tag: %d != %d\n",
@@ -157,6 +168,28 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
                cb->vtag = vtag_hdr->vtag;
        }
 
+       if (gsc_f2h) {
+               u32 ext_hdr_len = mei_ext_hdr_len(&gsc_f2h->hdr);
+
+               if (!dev->hbm_f_gsc_supported) {
+                       cl_err(dev, cl, "gsc extended header is not supported\n");
+                       cb->status = -EPROTO;
+                       goto discard;
+               }
+
+               if (length) {
+                       cl_err(dev, cl, "no data allowed in cb with gsc\n");
+                       cb->status = -EPROTO;
+                       goto discard;
+               }
+               if (ext_hdr_len > sizeof(*gsc_f2h)) {
+                       cl_err(dev, cl, "gsc extended header is too big %u\n", ext_hdr_len);
+                       cb->status = -EPROTO;
+                       goto discard;
+               }
+               memcpy(cb->ext_hdr, gsc_f2h, ext_hdr_len);
+       }
+
        if (!mei_cl_is_connected(cl)) {
                cl_dbg(dev, cl, "not connected\n");
                cb->status = -ENODEV;
index 6bb3e1b..31784bb 100644 (file)
@@ -206,6 +206,7 @@ struct mei_cl;
  * @status: io status of the cb
  * @internal: communication between driver and FW flag
  * @blocking: transmission blocking mode
+ * @ext_hdr: extended header
  */
 struct mei_cl_cb {
        struct list_head list;
@@ -218,6 +219,7 @@ struct mei_cl_cb {
        int status;
        u32 internal:1;
        u32 blocking:1;
+       struct mei_ext_hdr *ext_hdr;
 };
 
 /**
@@ -494,6 +496,7 @@ struct mei_dev_timeouts {
  * @hbm_f_vt_supported  : hbm feature vtag supported
  * @hbm_f_cap_supported : hbm feature capabilities message supported
  * @hbm_f_cd_supported  : hbm feature client dma supported
+ * @hbm_f_gsc_supported : hbm feature gsc supported
  *
  * @fw_ver : FW versions
  *
@@ -585,6 +588,7 @@ struct mei_device {
        unsigned int hbm_f_vt_supported:1;
        unsigned int hbm_f_cap_supported:1;
        unsigned int hbm_f_cd_supported:1;
+       unsigned int hbm_f_gsc_supported:1;
 
        struct mei_fw_version fw_ver[MEI_MAX_FW_VER_BLOCKS];