aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org> 2016-12-13 12:11:01 -0800
committerGravatar Linus Torvalds <torvalds@linux-foundation.org> 2016-12-13 12:11:01 -0800
commitb78b499a67c3f77aeb6cd0b54724bc38b141255d (patch)
tree8ebdb5303bb1552577182d9fe4086910b8648d22 /drivers/misc
parentMerge tag 'driver-core-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel... (diff)
parentuio-hv-generic: store physical addresses instead of virtual (diff)
downloadlinux-b78b499a67c3f77aeb6cd0b54724bc38b141255d.tar.gz
linux-b78b499a67c3f77aeb6cd0b54724bc38b141255d.tar.bz2
linux-b78b499a67c3f77aeb6cd0b54724bc38b141255d.zip
Merge tag 'char-misc-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here's the big char/misc driver patches for 4.10-rc1. Lots of tiny changes over lots of "minor" driver subsystems, the largest being some new FPGA drivers. Other than that, a few other new drivers, but no new driver subsystems added for this kernel cycle, a nice change. All of these have been in linux-next with no reported issues" * tag 'char-misc-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (107 commits) uio-hv-generic: store physical addresses instead of virtual Tools: hv: kvp: configurable external scripts path uio-hv-generic: new userspace i/o driver for VMBus vmbus: add support for dynamic device id's hv: change clockevents unbind tactics hv: acquire vmbus_connection.channel_mutex in vmbus_free_channels() hyperv: Fix spelling of HV_UNKOWN mei: bus: enable non-blocking RX mei: fix the back to back interrupt handling mei: synchronize irq before initiating a reset. VME: Remove shutdown entry from vme_driver auxdisplay: ht16k33: select framebuffer helper modules MAINTAINERS: add git url for fpga fpga: Clarify how write_init works streaming modes fpga zynq: Fix incorrect ISR state on bootup fpga zynq: Remove priv->dev fpga zynq: Add missing \n to messages fpga: Add COMPILE_TEST to all drivers uio: pruss: add clk_disable() char/pcmcia: add some error checking in scr24x_read() ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/genwqe/card_base.h1
-rw-r--r--drivers/misc/genwqe/card_utils.c12
-rw-r--r--drivers/misc/lkdtm_bugs.c3
-rw-r--r--drivers/misc/lkdtm_perms.c7
-rw-r--r--drivers/misc/mei/amthif.c2
-rw-r--r--drivers/misc/mei/bus-fixup.c100
-rw-r--r--drivers/misc/mei/bus.c217
-rw-r--r--drivers/misc/mei/client.c23
-rw-r--r--drivers/misc/mei/client.h2
-rw-r--r--drivers/misc/mei/hw-me-regs.h2
-rw-r--r--drivers/misc/mei/hw-me.c90
-rw-r--r--drivers/misc/mei/hw-me.h2
-rw-r--r--drivers/misc/mei/hw-txe.c18
-rw-r--r--drivers/misc/mei/init.c6
-rw-r--r--drivers/misc/mei/interrupt.c7
-rw-r--r--drivers/misc/mei/main.c45
-rw-r--r--drivers/misc/mei/mei_dev.h38
-rw-r--r--drivers/misc/mei/pci-me.c1
18 files changed, 423 insertions, 153 deletions
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index cb851c14ca4b..5813b5f25006 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -41,7 +41,6 @@
#include "genwqe_driver.h"
#define GENWQE_MSI_IRQS 4 /* Just one supported, no MSIx */
-#define GENWQE_FLAG_MSI_ENABLED (1 << 0)
#define GENWQE_MAX_VFS 15 /* maximum 15 VFs are possible */
#define GENWQE_MAX_FUNCS 16 /* 1 PF and 15 VFs */
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
index fc2794b513fa..147b83011b58 100644
--- a/drivers/misc/genwqe/card_utils.c
+++ b/drivers/misc/genwqe/card_utils.c
@@ -740,13 +740,10 @@ int genwqe_read_softreset(struct genwqe_dev *cd)
int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
{
int rc;
- struct pci_dev *pci_dev = cd->pci_dev;
- rc = pci_enable_msi_range(pci_dev, 1, count);
+ rc = pci_alloc_irq_vectors(cd->pci_dev, 1, count, PCI_IRQ_MSI);
if (rc < 0)
return rc;
-
- cd->flags |= GENWQE_FLAG_MSI_ENABLED;
return 0;
}
@@ -756,12 +753,7 @@ int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
*/
void genwqe_reset_interrupt_capability(struct genwqe_dev *cd)
{
- struct pci_dev *pci_dev = cd->pci_dev;
-
- if (cd->flags & GENWQE_FLAG_MSI_ENABLED) {
- pci_disable_msi(pci_dev);
- cd->flags &= ~GENWQE_FLAG_MSI_ENABLED;
- }
+ pci_free_irq_vectors(cd->pci_dev);
}
/**
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c
index f336206d4b1f..91edd0b55e5c 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -85,7 +85,8 @@ noinline void lkdtm_CORRUPT_STACK(void)
/* Use default char array length that triggers stack protection. */
char data[8];
- memset((void *)data, 0, 64);
+ memset((void *)data, 'a', 64);
+ pr_info("Corrupted stack with '%16s'...\n", data);
}
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c
index 45f1c0f96612..c7635a79341f 100644
--- a/drivers/misc/lkdtm_perms.c
+++ b/drivers/misc/lkdtm_perms.c
@@ -60,15 +60,18 @@ static noinline void execute_location(void *dst, bool write)
static void execute_user_location(void *dst)
{
+ int copied;
+
/* Intentionally crossing kernel/user memory boundary. */
void (*func)(void) = dst;
pr_info("attempting ok execution at %p\n", do_nothing);
do_nothing();
- if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
+ copied = access_process_vm(current, (unsigned long)dst, do_nothing,
+ EXEC_SIZE, FOLL_WRITE);
+ if (copied < EXEC_SIZE)
return;
- flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
pr_info("attempting bad execution at %p\n", func);
func();
}
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 7ae89b4a21d5..466afb2611c6 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -144,7 +144,7 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
dev->iamthif_state = MEI_IAMTHIF_WRITING;
cl->fp = cb->fp;
- ret = mei_cl_write(cl, cb, false);
+ ret = mei_cl_write(cl, cb);
if (ret < 0)
return ret;
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index 75b9d4ac8b1e..18e05ca7584f 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -38,6 +38,9 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO;
#define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
+#define MEI_UUID_MKHIF_FIX UUID_LE(0x55213584, 0x9a29, 0x4916, \
+ 0xba, 0xdf, 0xf, 0xb7, 0xed, 0x68, 0x2a, 0xeb)
+
#define MEI_UUID_ANY NULL_UUID_LE
/**
@@ -69,6 +72,97 @@ static void blacklist(struct mei_cl_device *cldev)
cldev->do_match = 0;
}
+#define OSTYPE_LINUX 2
+struct mei_os_ver {
+ __le16 build;
+ __le16 reserved1;
+ u8 os_type;
+ u8 major;
+ u8 minor;
+ u8 reserved2;
+} __packed;
+
+#define MKHI_FEATURE_PTT 0x10
+
+struct mkhi_rule_id {
+ __le16 rule_type;
+ u8 feature_id;
+ u8 reserved;
+} __packed;
+
+struct mkhi_fwcaps {
+ struct mkhi_rule_id id;
+ u8 len;
+ u8 data[0];
+} __packed;
+
+#define MKHI_FWCAPS_GROUP_ID 0x3
+#define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6
+struct mkhi_msg_hdr {
+ u8 group_id;
+ u8 command;
+ u8 reserved;
+ u8 result;
+} __packed;
+
+struct mkhi_msg {
+ struct mkhi_msg_hdr hdr;
+ u8 data[0];
+} __packed;
+
+static int mei_osver(struct mei_cl_device *cldev)
+{
+ int ret;
+ const size_t size = sizeof(struct mkhi_msg_hdr) +
+ sizeof(struct mkhi_fwcaps) +
+ sizeof(struct mei_os_ver);
+ size_t length = 8;
+ char buf[size];
+ struct mkhi_msg *req;
+ struct mkhi_fwcaps *fwcaps;
+ struct mei_os_ver *os_ver;
+ unsigned int mode = MEI_CL_IO_TX_BLOCKING | MEI_CL_IO_TX_INTERNAL;
+
+ memset(buf, 0, size);
+
+ req = (struct mkhi_msg *)buf;
+ req->hdr.group_id = MKHI_FWCAPS_GROUP_ID;
+ req->hdr.command = MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD;
+
+ fwcaps = (struct mkhi_fwcaps *)req->data;
+
+ fwcaps->id.rule_type = 0x0;
+ fwcaps->id.feature_id = MKHI_FEATURE_PTT;
+ fwcaps->len = sizeof(*os_ver);
+ os_ver = (struct mei_os_ver *)fwcaps->data;
+ os_ver->os_type = OSTYPE_LINUX;
+
+ ret = __mei_cl_send(cldev->cl, buf, size, mode);
+ if (ret < 0)
+ return ret;
+
+ ret = __mei_cl_recv(cldev->cl, buf, length, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void mei_mkhi_fix(struct mei_cl_device *cldev)
+{
+ int ret;
+
+ ret = mei_cldev_enable(cldev);
+ if (ret)
+ return;
+
+ ret = mei_osver(cldev);
+ if (ret)
+ dev_err(&cldev->dev, "OS version command failed %d\n", ret);
+
+ mei_cldev_disable(cldev);
+}
+
/**
* mei_wd - wd client on the bus, change protocol version
* as the API has changed.
@@ -162,7 +256,8 @@ static int mei_nfc_if_version(struct mei_cl *cl,
WARN_ON(mutex_is_locked(&bus->device_lock));
- ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1);
+ ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd),
+ MEI_CL_IO_TX_BLOCKING);
if (ret < 0) {
dev_err(bus->dev, "Could not send IF version cmd\n");
return ret;
@@ -177,7 +272,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
return -ENOMEM;
ret = 0;
- bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
+ bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0);
if (bytes_recv < if_version_length) {
dev_err(bus->dev, "Could not read IF version\n");
ret = -EIO;
@@ -309,6 +404,7 @@ static struct mei_fixup {
MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist),
MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc),
MEI_FIXUP(MEI_UUID_WD, mei_wd),
+ MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix),
};
/**
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 8cac7ef9ad0d..0037153c80a6 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -36,12 +36,12 @@
* @cl: host client
* @buf: buffer to send
* @length: buffer length
- * @blocking: wait for write completion
+ * @mode: sending mode
*
* Return: written size bytes or < 0 on error
*/
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
- bool blocking)
+ unsigned int mode)
{
struct mei_device *bus;
struct mei_cl_cb *cb;
@@ -80,9 +80,11 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
goto out;
}
+ cb->internal = !!(mode & MEI_CL_IO_TX_INTERNAL);
+ cb->blocking = !!(mode & MEI_CL_IO_TX_BLOCKING);
memcpy(cb->buf.data, buf, length);
- rets = mei_cl_write(cl, cb, blocking);
+ rets = mei_cl_write(cl, cb);
out:
mutex_unlock(&bus->device_lock);
@@ -96,15 +98,18 @@ out:
* @cl: host client
* @buf: buffer to receive
* @length: buffer length
+ * @mode: io mode
*
* Return: read size in bytes of < 0 on error
*/
-ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
+ unsigned int mode)
{
struct mei_device *bus;
struct mei_cl_cb *cb;
size_t r_length;
ssize_t rets;
+ bool nonblock = !!(mode & MEI_CL_IO_RX_NONBLOCK);
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -125,6 +130,11 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
if (rets && rets != -EBUSY)
goto out;
+ if (nonblock) {
+ rets = -EAGAIN;
+ goto out;
+ }
+
/* wait on event only if there is no other waiter */
/* synchronized under device mutex */
if (!waitqueue_active(&cl->rx_wait)) {
@@ -185,14 +195,30 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
{
struct mei_cl *cl = cldev->cl;
- if (cl == NULL)
- return -ENODEV;
-
- return __mei_cl_send(cl, buf, length, 1);
+ return __mei_cl_send(cl, buf, length, MEI_CL_IO_TX_BLOCKING);
}
EXPORT_SYMBOL_GPL(mei_cldev_send);
/**
+ * mei_cldev_recv_nonblock - non block client receive (read)
+ *
+ * @cldev: me client device
+ * @buf: buffer to receive
+ * @length: buffer length
+ *
+ * Return: read size in bytes of < 0 on error
+ * -EAGAIN if function will block.
+ */
+ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf,
+ size_t length)
+{
+ struct mei_cl *cl = cldev->cl;
+
+ return __mei_cl_recv(cl, buf, length, MEI_CL_IO_RX_NONBLOCK);
+}
+EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock);
+
+/**
* mei_cldev_recv - client receive (read)
*
* @cldev: me client device
@@ -205,39 +231,45 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
{
struct mei_cl *cl = cldev->cl;
- if (cl == NULL)
- return -ENODEV;
-
- return __mei_cl_recv(cl, buf, length);
+ return __mei_cl_recv(cl, buf, length, 0);
}
EXPORT_SYMBOL_GPL(mei_cldev_recv);
/**
- * mei_cl_bus_event_work - dispatch rx event for a bus device
- * and schedule new work
+ * mei_cl_bus_rx_work - dispatch rx event for a bus device
*
* @work: work
*/
-static void mei_cl_bus_event_work(struct work_struct *work)
+static void mei_cl_bus_rx_work(struct work_struct *work)
{
struct mei_cl_device *cldev;
struct mei_device *bus;
- cldev = container_of(work, struct mei_cl_device, event_work);
+ cldev = container_of(work, struct mei_cl_device, rx_work);
bus = cldev->bus;
- if (cldev->event_cb)
- cldev->event_cb(cldev, cldev->events, cldev->event_context);
+ if (cldev->rx_cb)
+ cldev->rx_cb(cldev);
+
+ mutex_lock(&bus->device_lock);
+ mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
+ mutex_unlock(&bus->device_lock);
+}
+
+/**
+ * mei_cl_bus_notif_work - dispatch FW notif event for a bus device
+ *
+ * @work: work
+ */
+static void mei_cl_bus_notif_work(struct work_struct *work)
+{
+ struct mei_cl_device *cldev;
- cldev->events = 0;
+ cldev = container_of(work, struct mei_cl_device, notif_work);
- /* Prepare for the next read */
- if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
- mutex_lock(&bus->device_lock);
- mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
- mutex_unlock(&bus->device_lock);
- }
+ if (cldev->notif_cb)
+ cldev->notif_cb(cldev);
}
/**
@@ -252,18 +284,13 @@ bool mei_cl_bus_notify_event(struct mei_cl *cl)
{
struct mei_cl_device *cldev = cl->cldev;
- if (!cldev || !cldev->event_cb)
- return false;
-
- if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)))
+ if (!cldev || !cldev->notif_cb)
return false;
if (!cl->notify_ev)
return false;
- set_bit(MEI_CL_EVENT_NOTIF, &cldev->events);
-
- schedule_work(&cldev->event_work);
+ schedule_work(&cldev->notif_work);
cl->notify_ev = false;
@@ -271,7 +298,7 @@ bool mei_cl_bus_notify_event(struct mei_cl *cl)
}
/**
- * mei_cl_bus_rx_event - schedule rx event
+ * mei_cl_bus_rx_event - schedule rx event
*
* @cl: host client
*
@@ -282,66 +309,81 @@ bool mei_cl_bus_rx_event(struct mei_cl *cl)
{
struct mei_cl_device *cldev = cl->cldev;
- if (!cldev || !cldev->event_cb)
- return false;
-
- if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX)))
+ if (!cldev || !cldev->rx_cb)
return false;
- set_bit(MEI_CL_EVENT_RX, &cldev->events);
-
- schedule_work(&cldev->event_work);
+ schedule_work(&cldev->rx_work);
return true;
}
/**
- * mei_cldev_register_event_cb - register event callback
+ * mei_cldev_register_rx_cb - register Rx event callback
*
* @cldev: me client devices
- * @event_cb: callback function
- * @events_mask: requested events bitmask
- * @context: driver context data
+ * @rx_cb: callback function
*
* Return: 0 on success
* -EALREADY if an callback is already registered
* <0 on other errors
*/
-int mei_cldev_register_event_cb(struct mei_cl_device *cldev,
- unsigned long events_mask,
- mei_cldev_event_cb_t event_cb, void *context)
+int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb)
{
struct mei_device *bus = cldev->bus;
int ret;
- if (cldev->event_cb)
+ if (!rx_cb)
+ return -EINVAL;
+ if (cldev->rx_cb)
return -EALREADY;
- cldev->events = 0;
- cldev->events_mask = events_mask;
- cldev->event_cb = event_cb;
- cldev->event_context = context;
- INIT_WORK(&cldev->event_work, mei_cl_bus_event_work);
+ cldev->rx_cb = rx_cb;
+ INIT_WORK(&cldev->rx_work, mei_cl_bus_rx_work);
- if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
- mutex_lock(&bus->device_lock);
- ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
- mutex_unlock(&bus->device_lock);
- if (ret && ret != -EBUSY)
- return ret;
- }
+ mutex_lock(&bus->device_lock);
+ ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
+ mutex_unlock(&bus->device_lock);
+ if (ret && ret != -EBUSY)
+ return ret;
- if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) {
- mutex_lock(&bus->device_lock);
- ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0);
- mutex_unlock(&bus->device_lock);
- if (ret)
- return ret;
- }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cldev_register_rx_cb);
+
+/**
+ * mei_cldev_register_notif_cb - register FW notification event callback
+ *
+ * @cldev: me client devices
+ * @notif_cb: callback function
+ *
+ * Return: 0 on success
+ * -EALREADY if an callback is already registered
+ * <0 on other errors
+ */
+int mei_cldev_register_notif_cb(struct mei_cl_device *cldev,
+ mei_cldev_cb_t notif_cb)
+{
+ struct mei_device *bus = cldev->bus;
+ int ret;
+
+ if (!notif_cb)
+ return -EINVAL;
+
+ if (cldev->notif_cb)
+ return -EALREADY;
+
+ cldev->notif_cb = notif_cb;
+ INIT_WORK(&cldev->notif_work, mei_cl_bus_notif_work);
+
+ mutex_lock(&bus->device_lock);
+ ret = mei_cl_notify_request(cldev->cl, NULL, 1);
+ mutex_unlock(&bus->device_lock);
+ if (ret)
+ return ret;
return 0;
}
-EXPORT_SYMBOL_GPL(mei_cldev_register_event_cb);
+EXPORT_SYMBOL_GPL(mei_cldev_register_notif_cb);
/**
* mei_cldev_get_drvdata - driver data getter
@@ -403,7 +445,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_ver);
*/
bool mei_cldev_enabled(struct mei_cl_device *cldev)
{
- return cldev->cl && mei_cl_is_connected(cldev->cl);
+ return mei_cl_is_connected(cldev->cl);
}
EXPORT_SYMBOL_GPL(mei_cldev_enabled);
@@ -423,14 +465,13 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
cl = cldev->cl;
- if (!cl) {
+ if (cl->state == MEI_FILE_UNINITIALIZED) {
mutex_lock(&bus->device_lock);
- cl = mei_cl_alloc_linked(bus);
+ ret = mei_cl_link(cl);
mutex_unlock(&bus->device_lock);
- if (IS_ERR(cl))
- return PTR_ERR(cl);
+ if (ret)
+ return ret;
/* update pointers */
- cldev->cl = cl;
cl->cldev = cldev;
}
@@ -471,19 +512,17 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
struct mei_cl *cl;
int err;
- if (!cldev || !cldev->cl)
+ if (!cldev)
return -ENODEV;
cl = cldev->cl;
bus = cldev->bus;
- cldev->event_cb = NULL;
-
mutex_lock(&bus->device_lock);
if (!mei_cl_is_connected(cl)) {
- dev_err(bus->dev, "Already disconnected");
+ dev_dbg(bus->dev, "Already disconnected");
err = 0;
goto out;
}
@@ -497,9 +536,6 @@ out:
mei_cl_flush_queues(cl, NULL);
mei_cl_unlink(cl);
- kfree(cl);
- cldev->cl = NULL;
-
mutex_unlock(&bus->device_lock);
return err;
}
@@ -629,9 +665,13 @@ static int mei_cl_device_remove(struct device *dev)
if (!cldev || !dev->driver)
return 0;
- if (cldev->event_cb) {
- cldev->event_cb = NULL;
- cancel_work_sync(&cldev->event_work);
+ if (cldev->rx_cb) {
+ cancel_work_sync(&cldev->rx_work);
+ cldev->rx_cb = NULL;
+ }
+ if (cldev->notif_cb) {
+ cancel_work_sync(&cldev->notif_work);
+ cldev->notif_cb = NULL;
}
cldrv = to_mei_cl_driver(dev->driver);
@@ -754,6 +794,7 @@ static void mei_cl_bus_dev_release(struct device *dev)
mei_me_cl_put(cldev->me_cl);
mei_dev_bus_put(cldev->bus);
+ kfree(cldev->cl);
kfree(cldev);
}
@@ -786,17 +827,25 @@ static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus,
struct mei_me_client *me_cl)
{
struct mei_cl_device *cldev;
+ struct mei_cl *cl;
cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
if (!cldev)
return NULL;
+ cl = mei_cl_allocate(bus);
+ if (!cl) {
+ kfree(cldev);
+ return NULL;
+ }
+
device_initialize(&cldev->dev);
cldev->dev.parent = bus->dev;
cldev->dev.bus = &mei_cl_bus_type;
cldev->dev.type = &mei_cl_device_type;
cldev->bus = mei_dev_bus_get(bus);
cldev->me_cl = mei_me_cl_get(me_cl);
+ cldev->cl = cl;
mei_cl_bus_set_name(cldev);
cldev->is_added = 0;
INIT_LIST_HEAD(&cldev->bus_list);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 6fe02350578d..391936c1aa04 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -425,7 +425,7 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
*
* @cl: host client
* @length: size of the buffer
- * @type: operation type
+ * @fop_type: operation type
* @fp: associated file pointer (might be NULL)
*
* Return: cb on success and NULL on failure
@@ -459,7 +459,7 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
*
* @cl: host client
* @length: size of the buffer
- * @type: operation type
+ * @fop_type: operation type
* @fp: associated file pointer (might be NULL)
*
* Return: cb on success and NULL on failure
@@ -571,7 +571,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
INIT_LIST_HEAD(&cl->rd_pending);
INIT_LIST_HEAD(&cl->link);
cl->writing_state = MEI_IDLE;
- cl->state = MEI_FILE_INITIALIZING;
+ cl->state = MEI_FILE_UNINITIALIZED;
cl->dev = dev;
}
@@ -672,7 +672,12 @@ int mei_cl_unlink(struct mei_cl *cl)
list_del_init(&cl->link);
- cl->state = MEI_FILE_INITIALIZING;
+ cl->state = MEI_FILE_UNINITIALIZED;
+ cl->writing_state = MEI_IDLE;
+
+ WARN_ON(!list_empty(&cl->rd_completed) ||
+ !list_empty(&cl->rd_pending) ||
+ !list_empty(&cl->link));
return 0;
}
@@ -686,7 +691,7 @@ void mei_host_client_init(struct mei_device *dev)
pm_runtime_mark_last_busy(dev->dev);
dev_dbg(dev->dev, "rpm: autosuspend\n");
- pm_runtime_autosuspend(dev->dev);
+ pm_request_autosuspend(dev->dev);
}
/**
@@ -756,7 +761,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
struct mei_device *dev = cl->dev;
if (cl->state == MEI_FILE_DISCONNECTED ||
- cl->state == MEI_FILE_INITIALIZING)
+ cl->state <= MEI_FILE_INITIALIZING)
return;
cl->state = MEI_FILE_DISCONNECTED;
@@ -1598,18 +1603,17 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
*
* @cl: host client
* @cb: write callback with filled data
- * @blocking: block until completed
*
* Return: number of bytes sent on success, <0 on failure.
*/
-int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
+int 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;
int size;
int rets;
-
+ bool blocking;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -1621,6 +1625,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
buf = &cb->buf;
size = buf->size;
+ blocking = cb->blocking;
cl_dbg(dev, cl, "size=%d\n", size);
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index d2bfabecd882..f2545af9be7b 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -219,7 +219,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
struct mei_cl_cb *cmpl_list);
-int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb);
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list);
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index 7ad15d678878..c8307e8b4c16 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -122,6 +122,8 @@
#define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */
#define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */
+#define MEI_DEV_ID_LBG 0xA1BA /* Lewisburg (SPT) */
+
#define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */
#define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 56c2101e80ad..a05375a3338a 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -246,6 +246,36 @@ static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
return hw->pg_state;
}
+static inline u32 me_intr_src(u32 hcsr)
+{
+ return hcsr & H_CSR_IS_MASK;
+}
+
+/**
+ * me_intr_disable - disables mei device interrupts
+ * using supplied hcsr register value.
+ *
+ * @dev: the device structure
+ * @hcsr: supplied hcsr register value
+ */
+static inline void me_intr_disable(struct mei_device *dev, u32 hcsr)
+{
+ hcsr &= ~H_CSR_IE_MASK;
+ mei_hcsr_set(dev, hcsr);
+}
+
+/**
+ * mei_me_intr_clear - clear and stop interrupts
+ *
+ * @dev: the device structure
+ * @hcsr: supplied hcsr register value
+ */
+static inline void me_intr_clear(struct mei_device *dev, u32 hcsr)
+{
+ if (me_intr_src(hcsr))
+ mei_hcsr_write(dev, hcsr);
+}
+
/**
* mei_me_intr_clear - clear and stop interrupts
*
@@ -255,8 +285,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
{
u32 hcsr = mei_hcsr_read(dev);
- if (hcsr & H_CSR_IS_MASK)
- mei_hcsr_write(dev, hcsr);
+ me_intr_clear(dev, hcsr);
}
/**
* mei_me_intr_enable - enables mei device interrupts
@@ -280,8 +309,19 @@ static void mei_me_intr_disable(struct mei_device *dev)
{
u32 hcsr = mei_hcsr_read(dev);
- hcsr &= ~H_CSR_IE_MASK;
- mei_hcsr_set(dev, hcsr);
+ me_intr_disable(dev, hcsr);
+}
+
+/**
+ * mei_me_synchronize_irq - wait for pending IRQ handlers
+ *
+ * @dev: the device structure
+ */
+static void mei_me_synchronize_irq(struct mei_device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ synchronize_irq(pdev->irq);
}
/**
@@ -450,7 +490,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
/**
- * mei_me_write_message - writes a message to mei device.
+ * mei_me_hbuf_write - writes a message to host hw buffer.
*
* @dev: the device structure
* @header: mei HECI header of message
@@ -458,9 +498,9 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
*
* Return: -EIO if write has failed
*/
-static int mei_me_write_message(struct mei_device *dev,
- struct mei_msg_hdr *header,
- unsigned char *buf)
+static int mei_me_hbuf_write(struct mei_device *dev,
+ struct mei_msg_hdr *header,
+ const unsigned char *buf)
{
unsigned long rem;
unsigned long length = header->length;
@@ -956,13 +996,14 @@ static void mei_me_pg_legacy_intr(struct mei_device *dev)
* mei_me_d0i3_intr - perform d0i3 processing in interrupt thread handler
*
* @dev: the device structure
+ * @intr_source: interrupt source
*/
-static void mei_me_d0i3_intr(struct mei_device *dev)
+static void mei_me_d0i3_intr(struct mei_device *dev, u32 intr_source)
{
struct mei_me_hw *hw = to_me_hw(dev);
if (dev->pg_event == MEI_PG_EVENT_INTR_WAIT &&
- (hw->intr_source & H_D0I3C_IS)) {
+ (intr_source & H_D0I3C_IS)) {
dev->pg_event = MEI_PG_EVENT_INTR_RECEIVED;
if (hw->pg_state == MEI_PG_ON) {
hw->pg_state = MEI_PG_OFF;
@@ -981,7 +1022,7 @@ static void mei_me_d0i3_intr(struct mei_device *dev)
wake_up(&dev->wait_pg);
}
- if (hw->pg_state == MEI_PG_ON && (hw->intr_source & H_IS)) {
+ if (hw->pg_state == MEI_PG_ON && (intr_source & H_IS)) {
/*
* HW sent some data and we are in D0i3, so
* we got here because of HW initiated exit from D0i3.
@@ -996,13 +1037,14 @@ static void mei_me_d0i3_intr(struct mei_device *dev)
* mei_me_pg_intr - perform pg processing in interrupt thread handler
*
* @dev: the device structure
+ * @intr_source: interrupt source
*/
-static void mei_me_pg_intr(struct mei_device *dev)
+static void mei_me_pg_intr(struct mei_device *dev, u32 intr_source)
{
struct mei_me_hw *hw = to_me_hw(dev);
if (hw->d0i3_supported)
- mei_me_d0i3_intr(dev);
+ mei_me_d0i3_intr(dev, intr_source);
else
mei_me_pg_legacy_intr(dev);
}
@@ -1121,19 +1163,16 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
{
struct mei_device *dev = (struct mei_device *)dev_id;
- struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr;
hcsr = mei_hcsr_read(dev);
- if (!(hcsr & H_CSR_IS_MASK))
+ if (!me_intr_src(hcsr))
return IRQ_NONE;
- hw->intr_source = hcsr & H_CSR_IS_MASK;
- dev_dbg(dev->dev, "interrupt source 0x%08X.\n", hw->intr_source);
-
- /* clear H_IS and H_D0I3C_IS bits in H_CSR to clear the interrupts */
- mei_hcsr_write(dev, hcsr);
+ dev_dbg(dev->dev, "interrupt source 0x%08X\n", me_intr_src(hcsr));
+ /* disable interrupts on device */
+ me_intr_disable(dev, hcsr);
return IRQ_WAKE_THREAD;
}
@@ -1152,11 +1191,16 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
struct mei_device *dev = (struct mei_device *) dev_id;
struct mei_cl_cb complete_list;
s32 slots;
+ u32 hcsr;
int rets = 0;
dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
mutex_lock(&dev->device_lock);
+
+ hcsr = mei_hcsr_read(dev);
+ me_intr_clear(dev, hcsr);
+
mei_io_list_init(&complete_list);
/* check if ME wants a reset */
@@ -1166,7 +1210,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
goto end;
}
- mei_me_pg_intr(dev);
+ mei_me_pg_intr(dev, me_intr_src(hcsr));
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
@@ -1216,6 +1260,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
end:
dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
+ mei_me_intr_enable(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
@@ -1238,12 +1283,13 @@ static const struct mei_hw_ops mei_me_hw_ops = {
.intr_clear = mei_me_intr_clear,
.intr_enable = mei_me_intr_enable,
.intr_disable = mei_me_intr_disable,
+ .synchronize_irq = mei_me_synchronize_irq,
.hbuf_free_slots = mei_me_hbuf_empty_slots,
.hbuf_is_ready = mei_me_hbuf_is_empty,
.hbuf_max_len = mei_me_hbuf_max_len,
- .write = mei_me_write_message,
+ .write = mei_me_hbuf_write,
.rdbuf_full_slots = mei_me_count_full_read_slots,
.read_hdr = mei_me_mecbrw_read,
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 2ee14dc1b2ea..cf64847a35b9 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -51,14 +51,12 @@ struct mei_cfg {
*
* @cfg: per device generation config and ops
* @mem_addr: io memory address
- * @intr_source: interrupt source
* @pg_state: power gating state
* @d0i3_supported: di03 support
*/
struct mei_me_hw {
const struct mei_cfg *cfg;
void __iomem *mem_addr;
- u32 intr_source;
enum mei_pg_state pg_state;
bool d0i3_supported;
};
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index 60415a2bfcbd..e9f8c0aeec13 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -19,7 +19,7 @@
#include <linux/ktime.h>
#include <linux/delay.h>
#include <linux/kthread.h>
-#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
@@ -441,6 +441,18 @@ static void mei_txe_intr_enable(struct mei_device *dev)
}
/**
+ * mei_txe_synchronize_irq - wait for pending IRQ handlers
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_synchronize_irq(struct mei_device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ synchronize_irq(pdev->irq);
+}
+
+/**
* mei_txe_pending_interrupts - check if there are pending interrupts
* only Aliveness, Input ready, and output doorbell are of relevance
*
@@ -691,7 +703,8 @@ static void mei_txe_hw_config(struct mei_device *dev)
*/
static int mei_txe_write(struct mei_device *dev,
- struct mei_msg_hdr *header, unsigned char *buf)
+ struct mei_msg_hdr *header,
+ const unsigned char *buf)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
unsigned long rem;
@@ -1167,6 +1180,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.intr_clear = mei_txe_intr_clear,
.intr_enable = mei_txe_intr_enable,
.intr_disable = mei_txe_intr_disable,
+ .synchronize_irq = mei_txe_synchronize_irq,
.hbuf_free_slots = mei_txe_hbuf_empty_slots,
.hbuf_is_ready = mei_txe_is_input_ready,
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 9a9c2484d107..41e5760a6886 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -122,6 +122,10 @@ int mei_reset(struct mei_device *dev)
mei_dev_state_str(state), fw_sts_str);
}
+ mei_clear_interrupts(dev);
+
+ mei_synchronize_irq(dev);
+
/* we're already in reset, cancel the init timer
* if the reset was called due the hbm protocol error
* we need to call it before hw start
@@ -273,8 +277,6 @@ int mei_restart(struct mei_device *dev)
mutex_lock(&dev->device_lock);
- mei_clear_interrupts(dev);
-
dev->dev_state = MEI_DEV_POWER_UP;
dev->reset_count = 0;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 5a4893ce9c24..b584749bcc4a 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -118,7 +118,6 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
if (!mei_cl_is_connected(cl)) {
cl_dbg(dev, cl, "not connected\n");
- list_move_tail(&cb->list, &complete_list->list);
cb->status = -ENODEV;
goto discard;
}
@@ -128,8 +127,6 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
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);
-
- list_move_tail(&cb->list, &complete_list->list);
cb->status = -EMSGSIZE;
goto discard;
}
@@ -137,8 +134,6 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
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);
-
- list_move_tail(&cb->list, &complete_list->list);
cb->status = -EMSGSIZE;
goto discard;
}
@@ -158,6 +153,8 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
return 0;
discard:
+ if (cb)
+ list_move_tail(&cb->list, &complete_list->list);
mei_irq_discard_msg(dev, mei_hdr);
return 0;
}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index fa50635512e8..e1bf54481fd6 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -322,7 +322,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
- rets = mei_cl_write(cl, cb, false);
+ rets = mei_cl_write(cl, cb);
out:
mutex_unlock(&dev->device_lock);
return rets;
@@ -653,7 +653,7 @@ static int mei_fasync(int fd, struct file *file, int band)
}
/**
- * fw_status_show - mei device attribute show method
+ * fw_status_show - mei device fw_status attribute show method
*
* @device: device pointer
* @attr: attribute pointer
@@ -684,8 +684,49 @@ static ssize_t fw_status_show(struct device *device,
}
static DEVICE_ATTR_RO(fw_status);
+/**
+ * hbm_ver_show - display HBM protocol version negotiated with FW
+ *
+ * @device: device pointer
+ * @attr: attribute pointer
+ * @buf: char out buffer
+ *
+ * Return: number of the bytes printed into buf or error
+ */
+static ssize_t hbm_ver_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct mei_device *dev = dev_get_drvdata(device);
+ struct hbm_version ver;
+
+ mutex_lock(&dev->device_lock);
+ ver = dev->version;
+ mutex_unlock(&dev->device_lock);
+
+ return sprintf(buf, "%u.%u\n", ver.major_version, ver.minor_version);
+}
+static DEVICE_ATTR_RO(hbm_ver);
+
+/**
+ * hbm_ver_drv_show - display HBM protocol version advertised by driver
+ *
+ * @device: device pointer
+ * @attr: attribute pointer
+ * @buf: char out buffer
+ *
+ * Return: number of the bytes printed into buf or error
+ */
+static ssize_t hbm_ver_drv_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u.%u\n", HBM_MAJOR_VERSION, HBM_MINOR_VERSION);
+}
+static DEVICE_ATTR_RO(hbm_ver_drv);
+
static struct attribute *mei_attrs[] = {
&dev_attr_fw_status.attr,
+ &dev_attr_hbm_ver.attr,
+ &dev_attr_hbm_ver_drv.attr,
NULL
};
ATTRIBUTE_GROUPS(mei);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 1169fd9e7d02..699693cd8c59 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -55,7 +55,8 @@ extern const uuid_le mei_amthif_guid;
/* File state */
enum file_state {
- MEI_FILE_INITIALIZING = 0,
+ MEI_FILE_UNINITIALIZED = 0,
+ MEI_FILE_INITIALIZING,
MEI_FILE_CONNECTING,
MEI_FILE_CONNECTED,
MEI_FILE_DISCONNECTING,
@@ -109,6 +110,21 @@ enum mei_cb_file_ops {
MEI_FOP_NOTIFY_STOP,
};
+/**
+ * enum mei_cl_io_mode - io mode between driver and fw
+ *
+ * @MEI_CL_IO_TX_BLOCKING: send is blocking
+ * @MEI_CL_IO_TX_INTERNAL: internal communication between driver and FW
+ *
+ * @MEI_CL_IO_RX_NONBLOCK: recv is non-blocking
+ */
+enum mei_cl_io_mode {
+ MEI_CL_IO_TX_BLOCKING = BIT(0),
+ MEI_CL_IO_TX_INTERNAL = BIT(1),
+
+ MEI_CL_IO_RX_NONBLOCK = BIT(2),
+};
+
/*
* Intel MEI message data struct
*/
@@ -169,6 +185,7 @@ struct mei_cl;
* @fp: pointer to file structure
* @status: io status of the cb
* @internal: communication between driver and FW flag
+ * @blocking: transmission blocking mode
* @completed: the transfer or reception has completed
*/
struct mei_cl_cb {
@@ -180,6 +197,7 @@ struct mei_cl_cb {
const struct file *fp;
int status;
u32 internal:1;
+ u32 blocking:1;
u32 completed:1;
};
@@ -253,6 +271,7 @@ struct mei_cl {
* @intr_clear : clear pending interrupts
* @intr_enable : enable interrupts
* @intr_disable : disable interrupts
+ * @synchronize_irq : synchronize irqs
*
* @hbuf_free_slots : query for write buffer empty slots
* @hbuf_is_ready : query if write buffer is empty
@@ -274,7 +293,6 @@ struct mei_hw_ops {
int (*hw_start)(struct mei_device *dev);
void (*hw_config)(struct mei_device *dev);
-
int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
enum mei_pg_state (*pg_state)(struct mei_device *dev);
bool (*pg_in_transition)(struct mei_device *dev);
@@ -283,14 +301,14 @@ struct mei_hw_ops {
void (*intr_clear)(struct mei_device *dev);
void (*intr_enable)(struct mei_device *dev);
void (*intr_disable)(struct mei_device *dev);
+ void (*synchronize_irq)(struct mei_device *dev);
int (*hbuf_free_slots)(struct mei_device *dev);
bool (*hbuf_is_ready)(struct mei_device *dev);
size_t (*hbuf_max_len)(const struct mei_device *dev);
-
int (*write)(struct mei_device *dev,
struct mei_msg_hdr *hdr,
- unsigned char *buf);
+ const unsigned char *buf);
int (*rdbuf_full_slots)(struct mei_device *dev);
@@ -304,8 +322,9 @@ void mei_cl_bus_rescan(struct mei_device *bus);
void mei_cl_bus_rescan_work(struct work_struct *work);
void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
- bool blocking);
-ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+ unsigned int mode);
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
+ unsigned int mode);
bool mei_cl_bus_rx_event(struct mei_cl *cl);
bool mei_cl_bus_notify_event(struct mei_cl *cl);
void mei_cl_bus_remove_devices(struct mei_device *bus);
@@ -627,6 +646,11 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
dev->ops->intr_disable(dev);
}
+static inline void mei_synchronize_irq(struct mei_device *dev)
+{
+ dev->ops->synchronize_irq(dev);
+}
+
static inline bool mei_host_is_ready(struct mei_device *dev)
{
return dev->ops->host_is_ready(dev);
@@ -652,7 +676,7 @@ static inline size_t mei_hbuf_max_len(const struct mei_device *dev)
}
static inline int mei_write_message(struct mei_device *dev,
- struct mei_msg_hdr *hdr, void *buf)
+ struct mei_msg_hdr *hdr, const void *buf)
{
return dev->ops->write(dev, hdr, buf);
}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index f3ffd883b232..f9c6ec4b98ab 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -87,6 +87,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, mei_me_pch8_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_sps_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_sps_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, mei_me_pch8_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)},