diff options
Diffstat (limited to 'drivers/misc')
35 files changed, 673 insertions, 379 deletions
diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/misc/aspeed-lpc-snoop.c index cb78c98bc78d..2feb4347d67f 100644 --- a/drivers/misc/aspeed-lpc-snoop.c +++ b/drivers/misc/aspeed-lpc-snoop.c @@ -16,12 +16,15 @@ #include <linux/bitops.h> #include <linux/interrupt.h> +#include <linux/fs.h> #include <linux/kfifo.h> #include <linux/mfd/syscon.h> +#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/poll.h> #include <linux/regmap.h> #define DEVICE_NAME "aspeed-lpc-snoop" @@ -59,20 +62,70 @@ struct aspeed_lpc_snoop_model_data { unsigned int has_hicrb_ensnp; }; +struct aspeed_lpc_snoop_channel { + struct kfifo fifo; + wait_queue_head_t wq; + struct miscdevice miscdev; +}; + struct aspeed_lpc_snoop { struct regmap *regmap; int irq; - struct kfifo snoop_fifo[NUM_SNOOP_CHANNELS]; + struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; +}; + +static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file) +{ + return container_of(file->private_data, + struct aspeed_lpc_snoop_channel, + miscdev); +} + +static ssize_t snoop_file_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + unsigned int copied; + int ret = 0; + + if (kfifo_is_empty(&chan->fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(chan->wq, + !kfifo_is_empty(&chan->fifo)); + if (ret == -ERESTARTSYS) + return -EINTR; + } + ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); + + return ret ? ret : copied; +} + +static unsigned int snoop_file_poll(struct file *file, + struct poll_table_struct *pt) +{ + struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + + poll_wait(file, &chan->wq, pt); + return !kfifo_is_empty(&chan->fifo) ? POLLIN : 0; +} + +static const struct file_operations snoop_fops = { + .owner = THIS_MODULE, + .read = snoop_file_read, + .poll = snoop_file_poll, + .llseek = noop_llseek, }; /* Save a byte to a FIFO and discard the oldest byte if FIFO is full */ -static void put_fifo_with_discard(struct kfifo *fifo, u8 val) +static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val) { - if (!kfifo_initialized(fifo)) + if (!kfifo_initialized(&chan->fifo)) return; - if (kfifo_is_full(fifo)) - kfifo_skip(fifo); - kfifo_put(fifo, val); + if (kfifo_is_full(&chan->fifo)) + kfifo_skip(&chan->fifo); + kfifo_put(&chan->fifo, val); + wake_up_interruptible(&chan->wq); } static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg) @@ -97,12 +150,12 @@ static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg) if (reg & HICR6_STR_SNP0W) { u8 val = (data & SNPWDR_CH0_MASK) >> SNPWDR_CH0_SHIFT; - put_fifo_with_discard(&lpc_snoop->snoop_fifo[0], val); + put_fifo_with_discard(&lpc_snoop->chan[0], val); } if (reg & HICR6_STR_SNP1W) { u8 val = (data & SNPWDR_CH1_MASK) >> SNPWDR_CH1_SHIFT; - put_fifo_with_discard(&lpc_snoop->snoop_fifo[1], val); + put_fifo_with_discard(&lpc_snoop->chan[1], val); } return IRQ_HANDLED; @@ -139,12 +192,22 @@ static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, const struct aspeed_lpc_snoop_model_data *model_data = of_device_get_match_data(dev); + init_waitqueue_head(&lpc_snoop->chan[channel].wq); /* Create FIFO datastructure */ - rc = kfifo_alloc(&lpc_snoop->snoop_fifo[channel], + rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); if (rc) return rc; + lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR; + lpc_snoop->chan[channel].miscdev.name = + devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel); + lpc_snoop->chan[channel].miscdev.fops = &snoop_fops; + lpc_snoop->chan[channel].miscdev.parent = dev; + rc = misc_register(&lpc_snoop->chan[channel].miscdev); + if (rc) + return rc; + /* Enable LPC snoop channel at requested port */ switch (channel) { case 0: @@ -191,7 +254,8 @@ static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop, return; } - kfifo_free(&lpc_snoop->snoop_fifo[channel]); + kfifo_free(&lpc_snoop->chan[channel].fifo); + misc_deregister(&lpc_snoop->chan[channel].miscdev); } static int aspeed_lpc_snoop_probe(struct platform_device *pdev) diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index e8f1d4bb806a..da445223f4cc 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -80,7 +80,7 @@ static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr) 0xFC, 0); } -int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) +static int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) { rtsx_pci_write_register(pcr, MSGTXDATA0, MASK_8_BIT_DEF, (u8) (latency & 0xFF)); @@ -143,7 +143,7 @@ int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val) return 0; } -void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active) +static void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active) { if (pcr->ops->set_l1off_cfg_sub_d0) pcr->ops->set_l1off_cfg_sub_d0(pcr, active); @@ -162,7 +162,7 @@ static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr) rtsx_set_l1off_sub_cfg_d0(pcr, 1); } -void rtsx_pm_full_on(struct rtsx_pcr *pcr) +static void rtsx_pm_full_on(struct rtsx_pcr *pcr) { if (pcr->ops->full_on) pcr->ops->full_on(pcr); @@ -967,13 +967,13 @@ static void rtsx_pci_card_detect(struct work_struct *work) pcr->slots[RTSX_MS_CARD].p_dev); } -void rtsx_pci_process_ocp(struct rtsx_pcr *pcr) +static void rtsx_pci_process_ocp(struct rtsx_pcr *pcr) { if (pcr->ops->process_ocp) pcr->ops->process_ocp(pcr); } -int rtsx_pci_process_ocp_interrupt(struct rtsx_pcr *pcr) +static int rtsx_pci_process_ocp_interrupt(struct rtsx_pcr *pcr) { if (pcr->option.ocp_en) rtsx_pci_process_ocp(pcr); @@ -1094,7 +1094,7 @@ static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) rtsx_enable_aspm(pcr); } -void rtsx_pm_power_saving(struct rtsx_pcr *pcr) +static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) { if (pcr->ops->power_saving) pcr->ops->power_saving(pcr); diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 6a7d4a2ad514..840afb398f9e 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -94,8 +94,10 @@ static int at25_ee_read(void *priv, unsigned int offset, switch (at25->addrlen) { default: /* case 3 */ *cp++ = offset >> 16; + /* fall through */ case 2: *cp++ = offset >> 8; + /* fall through */ case 1: case 0: /* can't happen: for better codegen */ *cp++ = offset >> 0; @@ -180,8 +182,10 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) switch (at25->addrlen) { default: /* case 3 */ *cp++ = offset >> 16; + /* fall through */ case 2: *cp++ = offset >> 8; + /* fall through */ case 1: case 0: /* can't happen: for better codegen */ *cp++ = offset >> 0; diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 59dc24bb70ec..8a4659518c33 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -938,7 +938,7 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, { struct idt_89hpesx_dev *pdev = filep->private_data; char *colon_ch, *csraddr_str, *csrval_str; - int ret, csraddr_len, csrval_len; + int ret, csraddr_len; u32 csraddr, csrval; char *buf; @@ -974,12 +974,10 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, csraddr_str[csraddr_len] = '\0'; /* Register value must follow the colon */ csrval_str = colon_ch + 1; - csrval_len = strnlen(csrval_str, count - csraddr_len); } else /* if (str_colon == NULL) */ { csraddr_str = (char *)buf; /* Just to shut warning up */ csraddr_len = strnlen(csraddr_str, count); csrval_str = NULL; - csrval_len = 0; } /* Convert CSR address to u32 value */ @@ -1130,7 +1128,7 @@ static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) device_for_each_child_node(dev, fwnode) { ee_id = idt_ee_match_id(fwnode); - if (IS_ERR_OR_NULL(ee_id)) { + if (!ee_id) { dev_warn(dev, "Skip unsupported EEPROM device"); continue; } else diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c index 0e32709d1022..fc0cf9a7402e 100644 --- a/drivers/misc/eeprom/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -148,7 +148,8 @@ static int max6875_probe(struct i2c_client *client, if (client->addr & 1) return -ENODEV; - if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) + data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL); + if (!data) return -ENOMEM; /* A fake client is created on the odd address */ diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 1c3967f10f55..120738d6e58b 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -497,7 +497,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m); static inline bool dma_mapping_used(struct dma_mapping *m) { if (!m) - return 0; + return false; return m->size != 0; } diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index f921dd590271..c6b82f09b3ba 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c @@ -305,7 +305,6 @@ GENWQE_DEBUGFS_RO(ddcb_info, genwqe_ddcb_info_show); static int genwqe_info_show(struct seq_file *s, void *unused) { struct genwqe_dev *cd = s->private; - u16 val16, type; u64 app_id, slu_id, bitstream = -1; struct pci_dev *pci_dev = cd->pci_dev; @@ -315,9 +314,6 @@ static int genwqe_info_show(struct seq_file *s, void *unused) if (genwqe_is_privileged(cd)) bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM); - val16 = (u16)(slu_id & 0x0fLLU); - type = (u16)((slu_id >> 20) & 0xffLLU); - seq_printf(s, "%s driver version: %s\n" " Device Name/Type: %s %s CardIdx: %d\n" " SLU/APP Config : 0x%016llx/0x%016llx\n" diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 0dd6b5ef314a..f453ab82f0d7 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -304,14 +304,12 @@ static int genwqe_open(struct inode *inode, struct file *filp) { struct genwqe_dev *cd; struct genwqe_file *cfile; - struct pci_dev *pci_dev; cfile = kzalloc(sizeof(*cfile), GFP_KERNEL); if (cfile == NULL) return -ENOMEM; cd = container_of(inode->i_cdev, struct genwqe_dev, cdev_genwqe); - pci_dev = cd->pci_dev; cfile->cd = cd; cfile->filp = filp; cfile->client = NULL; @@ -864,7 +862,6 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) struct genwqe_dev *cd = cfile->cd; struct genwqe_ddcb_cmd *cmd = &req->cmd; struct dma_mapping *m; - const char *type = "UNKNOWN"; for (i = 0, asiv_offs = 0x00; asiv_offs <= 0x58; i++, asiv_offs += 0x08) { @@ -933,11 +930,9 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) m = genwqe_search_pin(cfile, u_addr, u_size, NULL); if (m != NULL) { - type = "PINNING"; page_offs = (u_addr - (u64)m->u_vaddr)/PAGE_SIZE; } else { - type = "MAPPING"; m = &req->dma_mappings[i]; genwqe_mapping_init(m, diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c index fb83d1375638..8f82bb9d11e2 100644 --- a/drivers/misc/ibmvmc.c +++ b/drivers/misc/ibmvmc.c @@ -273,7 +273,7 @@ static void *alloc_dma_buffer(struct vio_dev *vdev, size_t size, dma_addr_t *dma_handle) { /* allocate memory */ - void *buffer = kzalloc(size, GFP_KERNEL); + void *buffer = kzalloc(size, GFP_ATOMIC); if (!buffer) { *dma_handle = 0; diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 0208c4b027c5..a6f41f96f2a1 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -1,7 +1,7 @@ /* * * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2013, Intel Corporation. + * Copyright (c) 2003-2018, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -96,8 +96,22 @@ struct mkhi_fwcaps { u8 data[0]; } __packed; +struct mkhi_fw_ver_block { + u16 minor; + u8 major; + u8 platform; + u16 buildno; + u16 hotfix; +} __packed; + +struct mkhi_fw_ver { + struct mkhi_fw_ver_block ver[MEI_MAX_FW_VER_BLOCKS]; +} __packed; + #define MKHI_FWCAPS_GROUP_ID 0x3 #define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6 +#define MKHI_GEN_GROUP_ID 0xFF +#define MKHI_GEN_GET_FW_VERSION_CMD 0x2 struct mkhi_msg_hdr { u8 group_id; u8 command; @@ -139,21 +153,81 @@ static int mei_osver(struct mei_cl_device *cldev) return __mei_cl_send(cldev->cl, buf, size, mode); } +#define MKHI_FWVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \ + sizeof(struct mkhi_fw_ver)) +#define MKHI_FWVER_LEN(__num) (sizeof(struct mkhi_msg_hdr) + \ + sizeof(struct mkhi_fw_ver_block) * (__num)) +#define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */ +static int mei_fwver(struct mei_cl_device *cldev) +{ + char buf[MKHI_FWVER_BUF_LEN]; + struct mkhi_msg *req; + struct mkhi_fw_ver *fwver; + int bytes_recv, ret, i; + + memset(buf, 0, sizeof(buf)); + + req = (struct mkhi_msg *)buf; + req->hdr.group_id = MKHI_GEN_GROUP_ID; + req->hdr.command = MKHI_GEN_GET_FW_VERSION_CMD; + + ret = __mei_cl_send(cldev->cl, buf, sizeof(struct mkhi_msg_hdr), + MEI_CL_IO_TX_BLOCKING); + if (ret < 0) { + dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n"); + return ret; + } + + ret = 0; + bytes_recv = __mei_cl_recv(cldev->cl, buf, sizeof(buf), 0, + MKHI_RCV_TIMEOUT); + if (bytes_recv < 0 || (size_t)bytes_recv < MKHI_FWVER_LEN(1)) { + /* + * Should be at least one version block, + * error out if nothing found + */ + dev_err(&cldev->dev, "Could not read FW version\n"); + return -EIO; + } + + fwver = (struct mkhi_fw_ver *)req->data; + memset(cldev->bus->fw_ver, 0, sizeof(cldev->bus->fw_ver)); + for (i = 0; i < MEI_MAX_FW_VER_BLOCKS; i++) { + if ((size_t)bytes_recv < MKHI_FWVER_LEN(i + 1)) + break; + dev_dbg(&cldev->dev, "FW version%d %d:%d.%d.%d.%d\n", + i, fwver->ver[i].platform, + fwver->ver[i].major, fwver->ver[i].minor, + fwver->ver[i].hotfix, fwver->ver[i].buildno); + + cldev->bus->fw_ver[i].platform = fwver->ver[i].platform; + cldev->bus->fw_ver[i].major = fwver->ver[i].major; + cldev->bus->fw_ver[i].minor = fwver->ver[i].minor; + cldev->bus->fw_ver[i].hotfix = fwver->ver[i].hotfix; + cldev->bus->fw_ver[i].buildno = fwver->ver[i].buildno; + } + + return ret; +} + static void mei_mkhi_fix(struct mei_cl_device *cldev) { int ret; - if (!cldev->bus->hbm_f_os_supported) - return; - ret = mei_cldev_enable(cldev); if (ret) return; - ret = mei_osver(cldev); + ret = mei_fwver(cldev); if (ret < 0) - dev_err(&cldev->dev, "OS version command failed %d\n", ret); + dev_err(&cldev->dev, "FW version command failed %d\n", ret); + if (cldev->bus->hbm_f_os_supported) { + ret = mei_osver(cldev); + if (ret < 0) + dev_err(&cldev->dev, "OS version command failed %d\n", + ret); + } mei_cldev_disable(cldev); } @@ -266,8 +340,8 @@ 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, 0); - if (bytes_recv < if_version_length) { + bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0, 0); + if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) { dev_err(bus->dev, "Could not read IF version\n"); ret = -EIO; goto err; @@ -410,7 +484,7 @@ void mei_cl_bus_dev_fixup(struct mei_cl_device *cldev) { struct mei_fixup *f; const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - int i; + size_t i; for (i = 0; i < ARRAY_SIZE(mei_fixups); i++) { diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index b1133739fb4b..7bba62a72921 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -116,11 +116,12 @@ out: * @buf: buffer to receive * @length: buffer length * @mode: io mode + * @timeout: recv timeout, 0 for infinite timeout * * Return: read size in bytes of < 0 on error */ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, - unsigned int mode) + unsigned int mode, unsigned long timeout) { struct mei_device *bus; struct mei_cl_cb *cb; @@ -158,13 +159,28 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, mutex_unlock(&bus->device_lock); - if (wait_event_interruptible(cl->rx_wait, - (!list_empty(&cl->rd_completed)) || - (!mei_cl_is_connected(cl)))) { - - if (signal_pending(current)) - return -EINTR; - return -ERESTARTSYS; + if (timeout) { + rets = wait_event_interruptible_timeout + (cl->rx_wait, + (!list_empty(&cl->rd_completed)) || + (!mei_cl_is_connected(cl)), + msecs_to_jiffies(timeout)); + if (rets == 0) + return -ETIME; + if (rets < 0) { + if (signal_pending(current)) + return -EINTR; + return -ERESTARTSYS; + } + } else { + if (wait_event_interruptible + (cl->rx_wait, + (!list_empty(&cl->rd_completed)) || + (!mei_cl_is_connected(cl)))) { + if (signal_pending(current)) + return -EINTR; + return -ERESTARTSYS; + } } mutex_lock(&bus->device_lock); @@ -231,7 +247,7 @@ ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf, { struct mei_cl *cl = cldev->cl; - return __mei_cl_recv(cl, buf, length, MEI_CL_IO_RX_NONBLOCK); + return __mei_cl_recv(cl, buf, length, MEI_CL_IO_RX_NONBLOCK, 0); } EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock); @@ -248,7 +264,7 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) { struct mei_cl *cl = cldev->cl; - return __mei_cl_recv(cl, buf, length, 0); + return __mei_cl_recv(cl, buf, length, 0, 0); } EXPORT_SYMBOL_GPL(mei_cldev_recv); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 8d6197a88b54..4ab6251d418e 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -863,10 +863,12 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, int slots; int ret; - msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); + msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request)); slots = mei_hbuf_empty_slots(dev); + if (slots < 0) + return -EOVERFLOW; - if (slots < msg_slots) + if ((u32)slots < msg_slots) return -EMSGSIZE; ret = mei_cl_send_disconnect(cl, cb); @@ -1053,13 +1055,15 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, int slots; int rets; - msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); - slots = mei_hbuf_empty_slots(dev); - if (mei_cl_is_other_connecting(cl)) return 0; - if (slots < msg_slots) + msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request)); + slots = mei_hbuf_empty_slots(dev); + if (slots < 0) + return -EOVERFLOW; + + if ((u32)slots < msg_slots) return -EMSGSIZE; rets = mei_cl_send_connect(cl, cb); @@ -1294,10 +1298,12 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, int ret; bool request; - msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); + msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request)); slots = mei_hbuf_empty_slots(dev); + if (slots < 0) + return -EOVERFLOW; - if (slots < msg_slots) + if ((u32)slots < msg_slots) return -EMSGSIZE; request = mei_cl_notify_fop2req(cb->fop_type); @@ -1533,6 +1539,23 @@ nortpm: } /** + * mei_msg_hdr_init - initialize mei message header + * + * @mei_hdr: mei message header + * @cb: message callback structure + */ +static void mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *cb) +{ + 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; +} + +/** * mei_cl_irq_write - write a message to device * from the interrupt thread context * @@ -1548,9 +1571,10 @@ 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); size_t len; - u32 msg_slots; - int slots; + size_t hbuf_len; + int hbuf_slots; int rets; bool first_chunk; @@ -1572,40 +1596,41 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, return 0; } - slots = mei_hbuf_empty_slots(dev); len = buf->size - cb->buf_idx; - msg_slots = mei_data2slots(len); + hbuf_slots = mei_hbuf_empty_slots(dev); + if (hbuf_slots < 0) { + rets = -EOVERFLOW; + goto err; + } - mei_hdr.host_addr = mei_cl_host_addr(cl); - mei_hdr.me_addr = mei_cl_me_id(cl); - mei_hdr.reserved = 0; - mei_hdr.internal = cb->internal; + hbuf_len = mei_slots2data(hbuf_slots); - if (slots >= msg_slots) { + 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; - /* Split the message only if we can write the whole host buffer */ - } else if (slots == dev->hbuf_depth) { - msg_slots = slots; - len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr.length = len; - mei_hdr.msg_complete = 0; + } else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) { + mei_hdr.length = hbuf_len - hdr_len; } else { - /* wait for next time the host buffer is empty */ return 0; } cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n", cb->buf.size, cb->buf_idx); - rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); + rets = mei_write_message(dev, &mei_hdr, hdr_len, + buf->data + cb->buf_idx, mei_hdr.length); if (rets) goto err; cl->status = 0; cl->writing_state = MEI_WRITING; cb->buf_idx += mei_hdr.length; - cb->completed = mei_hdr.msg_complete == 1; if (first_chunk) { if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { @@ -1634,13 +1659,16 @@ err: * * Return: number of bytes sent on success, <0 on failure. */ -int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) +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; - int size; - int rets; + size_t hdr_len = sizeof(mei_hdr); + size_t len; + size_t hbuf_len; + int hbuf_slots; + ssize_t rets; bool blocking; if (WARN_ON(!cl || !cl->dev)) @@ -1652,52 +1680,57 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) dev = cl->dev; buf = &cb->buf; - size = buf->size; + len = buf->size; blocking = cb->blocking; - cl_dbg(dev, cl, "size=%d\n", size); + cl_dbg(dev, cl, "len=%zd\n", len); rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { pm_runtime_put_noidle(dev->dev); - cl_err(dev, cl, "rpm: get failed %d\n", rets); + cl_err(dev, cl, "rpm: get failed %zd\n", rets); goto free; } cb->buf_idx = 0; cl->writing_state = MEI_IDLE; - mei_hdr.host_addr = mei_cl_host_addr(cl); - mei_hdr.me_addr = mei_cl_me_id(cl); - mei_hdr.reserved = 0; - mei_hdr.msg_complete = 0; - mei_hdr.internal = cb->internal; rets = mei_cl_tx_flow_ctrl_creds(cl); if (rets < 0) goto err; + mei_msg_hdr_init(&mei_hdr, cb); + if (rets == 0) { cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); - rets = size; + rets = len; goto out; } + if (!mei_hbuf_acquire(dev)) { cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); - rets = size; + rets = len; goto out; } - /* Check for a maximum length */ - if (size > mei_hbuf_max_len(dev)) { - mei_hdr.length = mei_hbuf_max_len(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = size; + hbuf_slots = mei_hbuf_empty_slots(dev); + if (hbuf_slots < 0) { + rets = -EOVERFLOW; + goto out; + } + + hbuf_len = mei_slots2data(hbuf_slots); + + if (len + hdr_len <= hbuf_len) { + mei_hdr.length = len; mei_hdr.msg_complete = 1; + } else { + mei_hdr.length = hbuf_len - hdr_len; } - rets = mei_write_message(dev, &mei_hdr, buf->data); + rets = mei_write_message(dev, &mei_hdr, hdr_len, + buf->data, mei_hdr.length); if (rets) goto err; @@ -1707,7 +1740,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) cl->writing_state = MEI_WRITING; cb->buf_idx = mei_hdr.length; - cb->completed = mei_hdr.msg_complete == 1; out: if (mei_hdr.msg_complete) @@ -1735,7 +1767,7 @@ out: } } - rets = size; + rets = buf->size; err: cl_dbg(dev, cl, "rpm: autosuspend\n"); pm_runtime_mark_last_busy(dev->dev); diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/clie |