From 39db74ce1aa83626a0a70ed2abf29a17598fff49 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 27 Nov 2014 14:07:28 +0200 Subject: mei: bus: use ssize_t as the return type for send and receive Mei bus receive and send function may return either number of transmitted bytes or errno. It is better to use ssize_t type for that purpose that mixing size_t with int. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 30 ++++++++++++++---------------- drivers/misc/mei/mei_dev.h | 6 +++--- 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index b3a72bca5242..31164dd14bd0 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -224,13 +224,13 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver) } EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); -static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, +static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking) { struct mei_device *dev; struct mei_me_client *me_cl; struct mei_cl_cb *cb; - int rets; + ssize_t rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; @@ -271,12 +271,12 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, return rets; } -int __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) { struct mei_device *dev; struct mei_cl_cb *cb; size_t r_length; - int err; + ssize_t rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; @@ -286,11 +286,9 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) mutex_lock(&dev->device_lock); if (!cl->read_cb) { - err = mei_cl_read_start(cl, length); - if (err < 0) { - mutex_unlock(&dev->device_lock); - return err; - } + rets = mei_cl_read_start(cl, length); + if (rets < 0) + goto out; } if (cl->reading_state != MEI_READ_COMPLETE && @@ -313,13 +311,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) cb = cl->read_cb; if (cl->reading_state != MEI_READ_COMPLETE) { - r_length = 0; + rets = 0; goto out; } r_length = min_t(size_t, length, cb->buf_idx); - memcpy(buf, cb->response_buffer.data, r_length); + rets = r_length; mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; @@ -328,20 +326,20 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) out: mutex_unlock(&dev->device_lock); - return r_length; + return rets; } -inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) +inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) { return ___mei_cl_send(cl, buf, length, 0); } -inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) +inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) { return ___mei_cl_send(cl, buf, length, 1); } -int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) { struct mei_cl *cl = device->cl; @@ -355,7 +353,7 @@ int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) } EXPORT_SYMBOL_GPL(mei_cl_send); -int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) { struct mei_cl *cl = device->cl; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 3dad74a8d496..7f350af2ee10 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -345,9 +345,9 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, struct mei_cl_ops *ops); void mei_cl_remove_device(struct mei_cl_device *device); -int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); -int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); -int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *dev); int mei_cl_bus_init(void); -- cgit v1.2.3 From 2e5df413becf6bd3854d1eb4f96542a53848bb27 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 7 Dec 2014 16:40:14 +0200 Subject: mei: use uuid, me_addr tuple addressing also for flow control credits Add uuid, me_addr addressing also for flow control credits. The only exception in cases for single buffer clients for which the host address in flow credits response is always 0 To in order to deal with add/remove race between fw and driver clients addressing we need to use [uuid, me_addr] tuple to address the clients Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 1382d551d7ed..3be18b7951e5 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -704,7 +704,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl) if (cl->mei_flow_ctrl_creds > 0) return 1; - me_cl = mei_me_cl_by_id(dev, cl->me_client_id); + me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); if (!me_cl) { cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOENT; @@ -738,7 +738,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) dev = cl->dev; - me_cl = mei_me_cl_by_id(dev, cl->me_client_id); + me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); if (!me_cl) { cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOENT; -- cgit v1.2.3 From 46d0d33350e9b32642d745a8b46a954910196b4d Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:45:02 +0000 Subject: ti-st: add device tree support When using device tree, driver configuration data need to be read from device node. Add support for getting the platform data information from the device tree information stored in the .dtb file in case it exists. Signed-off-by: Eyal Reizer Signed-off-by: bvijay Diff rendering mode:inlineside by side Signed-off-by: Gigi Joseph Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 97 ++++++++++++++++++++++++++++++++++++++++---- drivers/misc/ti-st/st_ll.c | 17 +++++++- include/linux/ti_wilink_st.h | 1 + 3 files changed, 105 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index e4b7ee4f57b8..68a0b582d81a 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -36,7 +36,8 @@ #include #include #include - +#include +#include #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; @@ -44,6 +45,9 @@ static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; /**********************************************************************/ /* internal functions */ +struct ti_st_plat_data *dt_pdata; +static struct ti_st_plat_data *get_platform_data(struct device *dev); + /** * st_get_plat_device - * function which returns the reference to the platform device @@ -462,7 +466,12 @@ long st_kim_start(void *kim_data) struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; pr_info(" %s", __func__); - pdata = kim_gdata->kim_pdev->dev.platform_data; + if (kim_gdata->kim_pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = kim_gdata->kim_pdev->dev.platform_data; + } do { /* platform specific enabling code here */ @@ -522,12 +531,18 @@ long st_kim_stop(void *kim_data) { long err = 0; struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; - struct ti_st_plat_data *pdata = - kim_gdata->kim_pdev->dev.platform_data; + struct ti_st_plat_data *pdata; struct tty_struct *tty = kim_gdata->core_data->tty; reinit_completion(&kim_gdata->ldisc_installed); + if (kim_gdata->kim_pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else + pdata = kim_gdata->kim_pdev->dev.platform_data; + + if (tty) { /* can be called before ldisc is installed */ /* Flush any pending characters in the driver and discipline. */ tty_ldisc_flush(tty); @@ -715,13 +730,53 @@ static const struct file_operations list_debugfs_fops = { * board-*.c file */ +static const struct of_device_id kim_of_match[] = { +{ + .compatible = "kim", + }, + {} +}; +MODULE_DEVICE_TABLE(of, kim_of_match); + +static struct ti_st_plat_data *get_platform_data(struct device *dev) +{ + struct device_node *np = dev->of_node; + const u32 *dt_property; + int len; + + dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL); + + if (!dt_pdata) + pr_err("Can't allocate device_tree platform data\n"); + + dt_property = of_get_property(np, "dev_name", &len); + if (dt_property) + memcpy(&dt_pdata->dev_name, dt_property, len); + of_property_read_u32(np, "nshutdown_gpio", + (u32 *)&dt_pdata->nshutdown_gpio); + of_property_read_u32(np, "flow_cntrl", (u32 *)&dt_pdata->flow_cntrl); + of_property_read_u32(np, "baud_rate", (u32 *)&dt_pdata->baud_rate); + + return dt_pdata; +} + static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { struct kim_data_s *kim_gdata; - struct ti_st_plat_data *pdata = pdev->dev.platform_data; + struct ti_st_plat_data *pdata; int err; + if (pdev->dev.of_node) + pdata = get_platform_data(&pdev->dev); + else + pdata = pdev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform Data is missing\n"); + return -ENXIO; + } + if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { /* multiple devices could exist */ st_kim_devices[pdev->id] = pdev; @@ -806,9 +861,16 @@ err_core_init: static int kim_remove(struct platform_device *pdev) { /* free the GPIOs requested */ - struct ti_st_plat_data *pdata = pdev->dev.platform_data; + struct ti_st_plat_data *pdata; struct kim_data_s *kim_gdata; + if (pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = pdev->dev.platform_data; + } + kim_gdata = platform_get_drvdata(pdev); /* Free the Bluetooth/FM/GPIO @@ -826,12 +888,22 @@ static int kim_remove(struct platform_device *pdev) kfree(kim_gdata); kim_gdata = NULL; + kfree(dt_pdata); + dt_pdata = NULL; + return 0; } static int kim_suspend(struct platform_device *pdev, pm_message_t state) { - struct ti_st_plat_data *pdata = pdev->dev.platform_data; + struct ti_st_plat_data *pdata; + + if (pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = pdev->dev.platform_data; + } if (pdata->suspend) return pdata->suspend(pdev, state); @@ -841,7 +913,14 @@ static int kim_suspend(struct platform_device *pdev, pm_message_t state) static int kim_resume(struct platform_device *pdev) { - struct ti_st_plat_data *pdata = pdev->dev.platform_data; + struct ti_st_plat_data *pdata; + + if (pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = pdev->dev.platform_data; + } if (pdata->resume) return pdata->resume(pdev); @@ -858,6 +937,8 @@ static struct platform_driver kim_platform_driver = { .resume = kim_resume, .driver = { .name = "kim", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(kim_of_match), }, }; diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c index 93b4d67cc4a3..518e1b7f2f95 100644 --- a/drivers/misc/ti-st/st_ll.c +++ b/drivers/misc/ti-st/st_ll.c @@ -26,6 +26,7 @@ #include /**********************************************************************/ + /* internal functions */ static void send_ll_cmd(struct st_data_s *st_data, unsigned char cmd) @@ -53,7 +54,13 @@ static void ll_device_want_to_sleep(struct st_data_s *st_data) /* communicate to platform about chip asleep */ kim_data = st_data->kim_data; - pdata = kim_data->kim_pdev->dev.platform_data; + if (kim_data->kim_pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = kim_data->kim_pdev->dev.platform_data; + } + if (pdata->chip_asleep) pdata->chip_asleep(NULL); } @@ -86,7 +93,13 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data) /* communicate to platform about chip wakeup */ kim_data = st_data->kim_data; - pdata = kim_data->kim_pdev->dev.platform_data; + if (kim_data->kim_pdev->dev.of_node) { + pr_debug("use device tree data"); + pdata = dt_pdata; + } else { + pdata = kim_data->kim_pdev->dev.platform_data; + } + if (pdata->chip_awake) pdata->chip_awake(NULL); } diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index 884d6263e962..9072d9f95cff 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -86,6 +86,7 @@ struct st_proto_s { extern long st_register(struct st_proto_s *); extern long st_unregister(struct st_proto_s *); +extern struct ti_st_plat_data *dt_pdata; /* * header information used by st_core.c -- cgit v1.2.3 From 4b4aa3ab982e1e6f22a3df12a368803576b73ccf Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:46:24 +0000 Subject: st_kim: allow suspend if callback is not registered Suspend/resume was failing if callbacks were not registered. As it is ok not to do anything when suspending fix this so it soen't return an error and allow the system to suspend. Signed-off-by: Eyal Reizer Signed-off-by: Gigi Joseph Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 68a0b582d81a..f2c1071e54c9 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -908,7 +908,7 @@ static int kim_suspend(struct platform_device *pdev, pm_message_t state) if (pdata->suspend) return pdata->suspend(pdev, state); - return -EOPNOTSUPP; + return 0; } static int kim_resume(struct platform_device *pdev) @@ -925,7 +925,7 @@ static int kim_resume(struct platform_device *pdev) if (pdata->resume) return pdata->resume(pdev); - return -EOPNOTSUPP; + return 0; } /**********************************************************************/ -- cgit v1.2.3 From c6ec0fb4006d1d8110b3166f2cc2b04b8002d210 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:47:51 +0000 Subject: drivers: misc: ti-st: fix debugfs creation error handling In case the debugfs creation fails the whole init process was failing. There is no need to do this as the shared transport can work without it. Fix it so it just reports the failure and continue. Signed-off-by: Eyal Reizer Signed-off-by: Gigi Joseph Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index f2c1071e54c9..878956a7f897 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -836,8 +836,7 @@ static int kim_probe(struct platform_device *pdev) kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); if (!kim_debugfs_dir) { pr_err(" debugfs entries creation failed "); - err = -EIO; - goto err_debugfs_dir; + return 0; } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, @@ -846,9 +845,6 @@ static int kim_probe(struct platform_device *pdev) kim_gdata, &list_debugfs_fops); return 0; -err_debugfs_dir: - sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); - err_sysfs_group: st_core_exit(kim_gdata->core_data); -- cgit v1.2.3 From 868eba8e13d592f2eb9774777c9f3d9286482154 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:48:29 +0000 Subject: drivers: misc: ti-st: fix null pointer exception in st_kim_ref() st_kim_ref() does not take care of the fact that platform_get_drvdata() might return NULL. On AM437x EVM, this causes the platform to stop booting as soon as the module is inserted. This patch fixes the issue by checking for NULL return value. Oops log follows. I have not tested BT functionality after this patch. But at least the platform boots now. [ 12.675697] Unable to handle kernel NULL pointer dereference at virtual address 0000005c [ 12.684310] pgd = c0004000 [ 12.687157] [0000005c] *pgd=00000000 [ 12.690927] Internal error: Oops: 17 [#1] SMP ARM [ 12.695873] Modules linked in: btwilink bluetooth ti_vpfe dwc3(+) ov2659 videobuf2_core v4l2_common videodev ti_am335x_adc 6lowpan_iphc matrix_keypad panel_dpi kfifo_buf pixcir_i2c_ts media industrialio videobuf2_dma_contig c_can_platform videobuf2_memops dwc3_omap c_can can_dev [ 12.721969] CPU: 0 PID: 1235 Comm: kworker/u3:0 Not tainted 3.14.25-02445-g9036ac6daed6 #128 [ 12.730937] Workqueue: hci0 hci_power_on [bluetooth] [ 12.736165] task: ebd93b40 ti: ecd7c000 task.ti: ecd7c000 [ 12.741856] PC is at st_kim_ref+0x30/0x40 [ 12.746071] LR is at st_kim_ref+0x30/0x40 [ 12.750289] pc : [] lr : [] psr: a0000013 [ 12.750289] sp : ecd7de08 ip : ecd7de08 fp : ecd7de1c [ 12.762365] r10: bf1e710c r9 : bf1e70ec r8 : bf1e7964 [ 12.767858] r7 : ebd2fd50 r6 : bf1e7964 r5 : 00000000 r4 : ecd7de24 [ 12.774723] r3 : c0957208 r2 : 00000000 r1 : c0957208 r0 : 00000000 [ 12.781589] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 12.789274] Control: 10c5387d Table: abde4059 DAC: 00000015 [ 12.795315] Process kworker/u3:0 (pid: 1235, stack limit = 0xecd7c248) Signed-off-by: Sekhar Nori Signed-off-by: Gigi Joseph Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 878956a7f897..7109d28518d3 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -691,12 +691,16 @@ void st_kim_ref(struct st_data_s **core_data, int id) struct kim_data_s *kim_gdata; /* get kim_gdata reference from platform device */ pdev = st_get_plat_device(id); - if (!pdev) { - *core_data = NULL; - return; - } + if (!pdev) + goto err; kim_gdata = platform_get_drvdata(pdev); + if (!kim_gdata) + goto err; + *core_data = kim_gdata->core_data; + return; +err: + *core_data = NULL; } static int kim_version_open(struct inode *i, struct file *f) -- cgit v1.2.3 From 0ec0cf19201da36af858a6bc052a13e88866f341 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:49:03 +0000 Subject: drivers:misc:ti-st: protect against bad packets We encounter situations where we got bad packet type from the UART (probably due to platform problem or UART driver issues) which caused us out of boundary array access, which eventually led to kernel panic. Signed-off-by: Amir Ayun Signed-off-by: Pavan Savoy Signed-off-by: Leonid Iziumtsev Signed-off-by: Gigi Joseph Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_core.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 54be83d3efdd..c8c6a363069c 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -343,12 +343,26 @@ void st_int_recv(void *disc_data, /* Unknow packet? */ default: type = *ptr; - if (st_gdata->list[type] == NULL) { - pr_err("chip/interface misbehavior dropping" - " frame starting with 0x%02x", type); - goto done; + /* Default case means non-HCILL packets, + * possibilities are packets for: + * (a) valid protocol - Supported Protocols within + * the ST_MAX_CHANNELS. + * (b) registered protocol - Checked by + * "st_gdata->list[type] == NULL)" are supported + * protocols only. + * Rules out any invalid protocol and + * unregistered protocols with channel ID < 16. + */ + + if ((type >= ST_MAX_CHANNELS) || + (st_gdata->list[type] == NULL)) { + pr_err("chip/interface misbehavior: " + "dropping frame starting " + "with 0x%02x\n", type); + goto done; } + st_gdata->rx_skb = alloc_skb( st_gdata->list[type]->max_frame_size, GFP_ATOMIC); @@ -893,5 +907,3 @@ void st_core_exit(struct st_data_s *st_gdata) kfree(st_gdata); } } - - -- cgit v1.2.3 From 769105aa740dc0428f2585ec99c457d30aaab364 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 8 Dec 2014 16:28:10 +0100 Subject: misc: ioc4: simplify wave period measurement in clock_calibrate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The loop for measuring the square wave periods over some cycles is refactored to be more easily readable. This includes avoiding a "by-hand-implemented" for loop with a "real" one and adding some comments. Furthermore the following compiler warning is avoided by this patch: drivers/misc/ioc4.c: In function ‘ioc4_probe’: drivers/misc/ioc4.c:194:16: warning: ‘start’ may be used uninitialized in this function [-Wmaybe-uninitialized] period = (end - start) / ^ drivers/misc/ioc4.c:148:11: note: ‘start’ was declared here uint64_t start, end, period; ^ Signed-off-by: Richard Leitner Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ioc4.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 3336ddca45ac..8758d033db23 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -144,9 +144,9 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) { union ioc4_int_out int_out; union ioc4_gpcr gpcr; - unsigned int state, last_state = 1; + unsigned int state, last_state; uint64_t start, end, period; - unsigned int count = 0; + unsigned int count; /* Enable output */ gpcr.raw = 0; @@ -167,19 +167,20 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) mmiowb(); /* Check square wave period averaged over some number of cycles */ - do { - int_out.raw = readl(&idd->idd_misc_regs->int_out.raw); - state = int_out.fields.int_out; - if (!last_state && state) { - count++; - if (count == IOC4_CALIBRATE_END) { - end = ktime_get_ns(); - break; - } else if (count == IOC4_CALIBRATE_DISCARD) - start = ktime_get_ns(); - } - last_state = state; - } while (1); + start = ktime_get_ns(); + state = 1; /* make sure the first read isn't a rising edge */ + for (count = 0; count <= IOC4_CALIBRATE_END; count++) { + do { /* wait for a rising edge */ + last_state = state; + int_out.raw = readl(&idd->idd_misc_regs->int_out.raw); + state = int_out.fields.int_out; + } while (last_state || !state); + + /* discard the first few cycles */ + if (count == IOC4_CALIBRATE_DISCARD) + start = ktime_get_ns(); + } + end = ktime_get_ns(); /* Calculation rearranged to preserve intermediate precision. * Logically: -- cgit v1.2.3 From 0ecb3dffb1f56f03cbce91fe8b03d52c2980c13b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 29 Dec 2014 15:32:47 +0100 Subject: GenWQE: remove unnecessary version.h inclusion Based on versioncheck. Signed-off-by: Fabian Frederick Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_base.h | 1 - drivers/misc/genwqe/card_sysfs.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index c64d7cad1085..e7353449874b 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c index 2c33fbca9225..6ab31eff0536 100644 --- a/drivers/misc/genwqe/card_sysfs.c +++ b/drivers/misc/genwqe/card_sysfs.c @@ -24,7 +24,6 @@ * debugging, please also see the debugfs interfaces of this driver. */ -#include #include #include #include -- cgit v1.2.3 From 1558455582623b67492f630d11b94d5e4c506e5f Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:16:26 +0530 Subject: ad525x_dpot: Add a blank line after declaration Added a blank line after declaration to fix the warning of checkpatch.pl Signed-off-by: Mohammad Jamal Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index a43053daad0e..32f907245409 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -176,6 +176,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) { int value; unsigned ctrl = 0; + switch (dpot->uid) { case DPOT_UID(AD5246_ID): case DPOT_UID(AD5247_ID): -- cgit v1.2.3 From 3d494bba92c4665ab34056bf86a14e02b0e1db22 Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:17:13 +0530 Subject: ad525x_dpot:Remove break after return This patch removes the break statements present after return Signed-off-by: Mohammad Jamal Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 32f907245409..15e88078ba1e 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -334,7 +334,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) case DPOT_UID(AD5246_ID): case DPOT_UID(AD5247_ID): return dpot_write_d8(dpot, value); - break; case DPOT_UID(AD5245_ID): case DPOT_UID(AD5241_ID): @@ -346,7 +345,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? 0 : DPOT_AD5282_RDAC_AB; return dpot_write_r8d8(dpot, ctrl, value); - break; case DPOT_UID(AD5171_ID): case DPOT_UID(AD5273_ID): if (reg & DPOT_ADDR_OTP) { @@ -356,7 +354,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) ctrl = DPOT_AD5273_FUSE; } return dpot_write_r8d8(dpot, ctrl, value); - break; case DPOT_UID(AD5172_ID): case DPOT_UID(AD5173_ID): ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? @@ -368,7 +365,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) ctrl |= DPOT_AD5170_2_3_FUSE; } return dpot_write_r8d8(dpot, ctrl, value); - break; case DPOT_UID(AD5170_ID): if (reg & DPOT_ADDR_OTP) { tmp = dpot_read_r8d16(dpot, tmp); @@ -377,7 +373,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) ctrl = DPOT_AD5170_2_3_FUSE; } return dpot_write_r8d8(dpot, ctrl, value); - break; case DPOT_UID(AD5272_ID): case DPOT_UID(AD5274_ID): dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2, @@ -392,7 +387,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) | (value >> 8), value & 0xFF); - break; default: if (reg & DPOT_ADDR_CMD) return dpot_write_d8(dpot, reg); -- cgit v1.2.3 From c076860dd86d48460562d1c2a724914b64709da8 Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:24:11 +0530 Subject: ad525x_dpot-spi: Added Blank lines after declarations This patch solves the blank line warning of checkpatch.pl Signed-off-by: Mohammad Jamal Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot-spi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index 9da04ede04f3..f4c82eafa8e5 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -15,18 +15,21 @@ static int write8(void *client, u8 val) { u8 data = val; + return spi_write(client, &data, 1); } static int write16(void *client, u8 reg, u8 val) { u8 data[2] = {reg, val}; + return spi_write(client, data, 2); } static int write24(void *client, u8 reg, u16 val) { u8 data[3] = {reg, val >> 8, val}; + return spi_write(client, data, 3); } @@ -34,6 +37,7 @@ static int read8(void *client) { int ret; u8 data; + ret = spi_read(client, &data, 1); if (ret < 0) return ret; -- cgit v1.2.3 From 79563db9ddd37908343103debf20da716ccc5ce4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Jan 2015 00:07:16 +0200 Subject: mei: add reference counting for me clients To support dynamic addition and removal of me clients we add reference counter. Update kdoc with locking requirements. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 14 +++-- drivers/misc/mei/bus.c | 39 +++++++----- drivers/misc/mei/client.c | 152 ++++++++++++++++++++++++++++++++++++++------- drivers/misc/mei/client.h | 17 +++-- drivers/misc/mei/debugfs.c | 32 ++++++---- drivers/misc/mei/hbm.c | 34 +++++----- drivers/misc/mei/main.c | 22 +++---- drivers/misc/mei/mei_dev.h | 2 + drivers/misc/mei/nfc.c | 2 + drivers/misc/mei/wd.c | 1 + 10 files changed, 221 insertions(+), 94 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 79f53941779d..c4cb9a984a5f 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -97,23 +97,25 @@ int mei_amthif_host_init(struct mei_device *dev) /* allocate storage for ME message buffer */ msg_buf = kcalloc(dev->iamthif_mtu, sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) - return -ENOMEM; + if (!msg_buf) { + ret = -ENOMEM; + goto out; + } dev->iamthif_msg_buf = msg_buf; ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); - if (ret < 0) { - dev_err(dev->dev, - "amthif: failed link client %d\n", ret); - return ret; + dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); + goto out; } ret = mei_cl_connect(cl, NULL); dev->iamthif_state = MEI_IAMTHIF_IDLE; +out: + mei_me_cl_put(me_cl); return ret; } diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 31164dd14bd0..be767f4db26a 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -228,8 +228,8 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking) { struct mei_device *dev; - struct mei_me_client *me_cl; - struct mei_cl_cb *cb; + struct mei_me_client *me_cl = NULL; + struct mei_cl_cb *cb = NULL; ssize_t rets; if (WARN_ON(!cl || !cl->dev)) @@ -237,33 +237,40 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, dev = cl->dev; - if (cl->state != MEI_FILE_CONNECTED) - return -ENODEV; + mutex_lock(&dev->device_lock); + if (cl->state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + goto out; + } /* Check if we have an ME client device */ me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); - if (!me_cl) - return -ENOTTY; + if (!me_cl) { + rets = -ENOTTY; + goto out; + } - if (length > me_cl->props.max_msg_length) - return -EFBIG; + if (length > me_cl->props.max_msg_length) { + rets = -EFBIG; + goto out; + } cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; + if (!cb) { + rets = -ENOMEM; + goto out; + } rets = mei_io_cb_alloc_req_buf(cb, length); - if (rets < 0) { - mei_io_cb_free(cb); - return rets; - } + if (rets < 0) + goto out; memcpy(cb->request_buffer.data, buf, length); - mutex_lock(&dev->device_lock); - rets = mei_cl_write(cl, cb, blocking); +out: + mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); if (rets < 0) mei_io_cb_free(cb); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 3be18b7951e5..dfbddfe1c7a0 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -26,8 +26,64 @@ #include "hbm.h" #include "client.h" +/** + * mei_me_cl_init - initialize me client + * + * @me_cl: me client + */ +void mei_me_cl_init(struct mei_me_client *me_cl) +{ + INIT_LIST_HEAD(&me_cl->list); + kref_init(&me_cl->refcnt); +} + +/** + * mei_me_cl_get - increases me client refcount + * + * @me_cl: me client + * + * Locking: called under "dev->device_lock" lock + * + * Return: me client or NULL + */ +struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl) +{ + if (me_cl) + kref_get(&me_cl->refcnt); + + return me_cl; +} + +/** + * mei_me_cl_release - unlink and free me client + * + * Locking: called under "dev->device_lock" lock + * + * @ref: me_client refcount + */ +static void mei_me_cl_release(struct kref *ref) +{ + struct mei_me_client *me_cl = + container_of(ref, struct mei_me_client, refcnt); + list_del(&me_cl->list); + kfree(me_cl); +} +/** + * mei_me_cl_put - decrease me client refcount and free client if necessary + * + * Locking: called under "dev->device_lock" lock + * + * @me_cl: me client + */ +void mei_me_cl_put(struct mei_me_client *me_cl) +{ + if (me_cl) + kref_put(&me_cl->refcnt, mei_me_cl_release); +} + /** * mei_me_cl_by_uuid - locate me client by uuid + * increases ref count * * @dev: mei device * @uuid: me client uuid @@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, list_for_each_entry(me_cl, &dev->me_clients, list) if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) - return me_cl; + return mei_me_cl_get(me_cl); return NULL; } /** * mei_me_cl_by_id - locate me client by client id + * increases ref count * * @dev: the device structure * @client_id: me client id @@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id) list_for_each_entry(me_cl, &dev->me_clients, list) if (me_cl->client_id == client_id) - return me_cl; + return mei_me_cl_get(me_cl); + return NULL; } /** * mei_me_cl_by_uuid_id - locate me client by client id and uuid + * increases ref count * * @dev: the device structure * @uuid: me client uuid @@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, list_for_each_entry(me_cl, &dev->me_clients, list) if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && me_cl->client_id == client_id) - return me_cl; + return mei_me_cl_get(me_cl); + return NULL; } /** - * mei_me_cl_remove - remove me client matching uuid and client_id + * mei_me_cl_rm_by_uuid - remove all me clients matching uuid * * @dev: the device structure * @uuid: me client uuid - * @client_id: me client address + * + * Locking: called under "dev->device_lock" lock */ -void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id) +void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid) { struct mei_me_client *me_cl, *next; + dev_dbg(dev->dev, "remove %pUl\n", uuid); + list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) + if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) + mei_me_cl_put(me_cl); +} + +/** + * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id + * + * @dev: the device structure + * @uuid: me client uuid + * @id: me client id + * + * Locking: called under "dev->device_lock" lock + */ +void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id) +{ + struct mei_me_client *me_cl, *next; + const uuid_le *pn; + + dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id); list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { - if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && - me_cl->client_id == client_id) { - list_del(&me_cl->list); - kfree(me_cl); - break; - } + pn = &me_cl->props.protocol_name; + if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0) + mei_me_cl_put(me_cl); } } +/** + * mei_me_cl_rm_all - remove all me clients + * + * @dev: the device structure + * + * Locking: called under "dev->device_lock" lock + */ +void mei_me_cl_rm_all(struct mei_device *dev) +{ + struct mei_me_client *me_cl, *next; + + list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) + mei_me_cl_put(me_cl); +} + + /** * mei_cl_cmp_id - tells if the clients are the same @@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl) { struct mei_device *dev; struct mei_me_client *me_cl; + int rets = 0; if (WARN_ON(!cl || !cl->dev)) return -EINVAL; @@ -710,12 +806,13 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl) return -ENOENT; } - if (me_cl->mei_flow_ctrl_creds) { + if (me_cl->mei_flow_ctrl_creds > 0) { + rets = 1; if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; - return 1; + rets = -EINVAL; } - return 0; + mei_me_cl_put(me_cl); + return rets; } /** @@ -732,6 +829,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) { struct mei_device *dev; struct mei_me_client *me_cl; + int rets; if (WARN_ON(!cl || !cl->dev)) return -EINVAL; @@ -745,15 +843,22 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) } if (me_cl->props.single_recv_buf) { - if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; + if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) { + rets = -EINVAL; + goto out; + } me_cl->mei_flow_ctrl_creds--; } else { - if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; + if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) { + rets = -EINVAL; + goto out; + } cl->mei_flow_ctrl_creds--; } - return 0; + rets = 0; +out: + mei_me_cl_put(me_cl); + return rets; } /** @@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOTTY; } + /* always allocate at least client max message */ + length = max_t(size_t, length, me_cl->props.max_msg_length); + mei_me_cl_put(me_cl); rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { @@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) goto out; } - /* always allocate at least client max message */ - length = max_t(size_t, length, me_cl->props.max_msg_length); rets = mei_io_cb_alloc_resp_buf(cb, length); if (rets) goto out; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index d9d0c1525259..cfcde8e97fc4 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -24,15 +24,22 @@ #include "mei_dev.h" +/* + * reference counting base function + */ +void mei_me_cl_init(struct mei_me_client *me_cl); +void mei_me_cl_put(struct mei_me_client *me_cl); +struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl); + struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, - const uuid_le *cuuid); + const uuid_le *uuid); struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id); - struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 client_id); - -void mei_me_cl_remove(struct mei_device *dev, - const uuid_le *uuid, u8 client_id); +void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid); +void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, + const uuid_le *uuid, u8 id); +void mei_me_cl_rm_all(struct mei_device *dev); /* * MEI IO Functions diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index b60b4263cf0f..b125380ee871 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -21,20 +21,22 @@ #include #include "mei_dev.h" +#include "client.h" #include "hw.h" static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct mei_device *dev = fp->private_data; - struct mei_me_client *me_cl; + struct mei_me_client *me_cl, *n; size_t bufsz = 1; char *buf; int i = 0; int pos = 0; int ret; -#define HDR " |id|fix| UUID |con|msg len|sb|\n" +#define HDR \ +" |id|fix| UUID |con|msg len|sb|refc|\n" mutex_lock(&dev->device_lock); @@ -54,16 +56,22 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, if (dev->dev_state != MEI_DEV_ENABLED) goto out; - list_for_each_entry(me_cl, &dev->me_clients, list) { - - pos += scnprintf(buf + pos, bufsz - pos, - "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n", - i++, me_cl->client_id, - me_cl->props.fixed_address, - &me_cl->props.protocol_name, - me_cl->props.max_number_of_connections, - me_cl->props.max_msg_length, - me_cl->props.single_recv_buf); + list_for_each_entry_safe(me_cl, n, &dev->me_clients, list) { + + me_cl = mei_me_cl_get(me_cl); + if (me_cl) { + pos += scnprintf(buf + pos, bufsz - pos, + "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n", + i++, me_cl->client_id, + me_cl->props.fixed_address, + &me_cl->props.protocol_name, + me_cl->props.max_number_of_connections, + me_cl->props.max_msg_length, + me_cl->props.single_recv_buf, + atomic_read(&me_cl->refcnt.refcount)); + } + + mei_me_cl_put(me_cl); } out: mutex_unlock(&dev->device_lock); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 239d7f5d6a92..c8412d41e4f1 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -104,21 +104,6 @@ void mei_hbm_idle(struct mei_device *dev) dev->hbm_state = MEI_HBM_IDLE; } -/** - * mei_me_cl_remove_all - remove all me clients - * - * @dev: the device structure - */ -static void mei_me_cl_remove_all(struct mei_device *dev) -{ - struct mei_me_client *me_cl, *next; - - list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { - list_del(&me_cl->list); - kfree(me_cl); - } -} - /** * mei_hbm_reset - reset hbm counters and book keeping data structurs * @@ -128,7 +113,7 @@ void mei_hbm_reset(struct mei_device *dev) { dev->me_client_index = 0; - mei_me_cl_remove_all(dev); + mei_me_cl_rm_all(dev); mei_hbm_idle(dev); } @@ -339,11 +324,16 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, struct hbm_props_response *res) { struct mei_me_client *me_cl; + const uuid_le *uuid = &res->client_properties.protocol_name; + + mei_me_cl_rm_by_uuid(dev, uuid); me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL); if (!me_cl) return -ENOMEM; + mei_me_cl_init(me_cl); + me_cl->props = res->client_properties; me_cl->client_id = res->me_addr; me_cl->mei_flow_ctrl_creds = 0; @@ -484,6 +474,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev, struct hbm_flow_control *flow) { struct mei_me_client *me_cl; + int rets; me_cl = mei_me_cl_by_id(dev, flow->me_addr); if (!me_cl) { @@ -492,14 +483,19 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev, return -ENOENT; } - if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; + if (WARN_ON(me_cl->props.single_recv_buf == 0)) { + rets = -EINVAL; + goto out; + } me_cl->mei_flow_ctrl_creds++; dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", flow->me_addr, me_cl->mei_flow_ctrl_creds); - return 0; + rets = 0; +out: + mei_me_cl_put(me_cl); + return rets; } /** diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ae56ba6ca0e3..3c019c0e60eb 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -303,7 +303,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, size_t length, loff_t *offset) { struct mei_cl *cl = file->private_data; - struct mei_me_client *me_cl; + struct mei_me_client *me_cl = NULL; struct mei_cl_cb *write_cb = NULL; struct mei_device *dev; unsigned long timeout = 0; @@ -399,12 +399,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, "amthif write failed with status = %d\n", rets); goto out; } + mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); return length; } rets = mei_cl_write(cl, write_cb, false); out: + mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); if (rets < 0) mei_io_cb_free(write_cb); @@ -433,24 +435,19 @@ static int mei_ioctl_connect_client(struct file *file, cl = file->private_data; dev = cl->dev; - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto end; - } + if (dev->dev_state != MEI_DEV_ENABLED) + return -ENODEV; if (cl->state != MEI_FILE_INITIALIZING && - cl->state != MEI_FILE_DISCONNECTED) { - rets = -EBUSY; - goto end; - } + cl->state != MEI_FILE_DISCONNECTED) + return -EBUSY; /* find ME client we're trying to connect to */ me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid); if (!me_cl || me_cl->props.fixed_address) { dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n", &data->in_client_uuid); - rets = -ENOTTY; - goto end; + return -ENOTTY; } cl->me_client_id = me_cl->client_id; @@ -487,17 +484,16 @@ static int mei_ioctl_connect_client(struct file *file, goto end; } - /* prepare the output buffer */ client = &data->out_client_properties; client->max_msg_length = me_cl->props.max_msg_length; client->protocol_version = me_cl->props.protocol_version; dev_dbg(dev->dev, "Can connect?\n"); - rets = mei_cl_connect(cl, file); end: + mei_me_cl_put(me_cl); return rets; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 7f350af2ee10..6c6ce9381535 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -172,12 +172,14 @@ struct mei_fw_status { * struct mei_me_client - representation of me (fw) client * * @list: link in me client list + * @refcnt: struct reference count * @props: client properties * @client_id: me client id * @mei_flow_ctrl_creds: flow control credits */ struct mei_me_client { struct list_head list; + struct kref refcnt; struct mei_client_properties props; u8 client_id; u8 mei_flow_ctrl_creds; diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 60ca9240368e..bb61a119b8bb 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -521,6 +521,7 @@ int mei_nfc_host_init(struct mei_device *dev) cl_info->me_client_id = me_cl->client_id; cl_info->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY); if (ret) @@ -539,6 +540,7 @@ int mei_nfc_host_init(struct mei_device *dev) cl->me_client_id = me_cl->client_id; cl->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); if (ret) diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index b1d892cea94d..475f1dea45bf 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -76,6 +76,7 @@ int mei_wd_host_init(struct mei_device *dev) cl->me_client_id = me_cl->client_id; cl->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); -- cgit v1.2.3 From 3f46d81ae1cf8f20f25c39ae1ab3f1b064698361 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 20 Jan 2015 06:27:45 +0100 Subject: misc: ti-st: add handling of the signal case if(!wait_for_completion_interruptible_timeout(...)) only handles the timeout case - this patch adds handling the signal case the same as timeout. Only the timeout case was being handled, the signal case (-ERESTARTSYS) was treated just like the case of successful completion, which is most likely not reasonable. read_local_version() is called from download_firmware() where it checks for !=0 return, so the error handling logic should be preserved correctly. download_firmware() is called from st_kim_start() which is checking for !=0 return, so the error handling logic should be preserved correctly Signed-off-by: Nicholas Mc Guire Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 7109d28518d3..8fb116f8a152 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -219,6 +219,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) { unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; + long timeout; pr_debug("%s", __func__); @@ -228,10 +229,11 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) return -EIO; } - if (!wait_for_completion_interruptible_timeout( - &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) { - pr_err(" waiting for ver info- timed out "); - return -ETIMEDOUT; + timeout = wait_for_completion_interruptible_timeout( + &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME)); + if (timeout <= 0) { + pr_err(" waiting for ver info- timed out or received signal"); + return timeout ? -ERESTARTSYS : -ETIMEDOUT; } reinit_completion(&kim_gdata->kim_rcvd); /* the positions 12 & 13 in the response buffer provide with the @@ -395,13 +397,14 @@ static long download_firmware(struct kim_data_s *kim_gdata) break; case ACTION_WAIT_EVENT: /* wait */ pr_debug("W"); - if (!wait_for_completion_interruptible_timeout( + err = wait_for_completion_interruptible_timeout( &kim_gdata->kim_rcvd, - msecs_to_jiffies(CMD_RESP_TIME))) { - pr_err("response timeout during fw download "); + msecs_to_jiffies(CMD_RESP_TIME)); + if (err <= 0) { + pr_err("response timeout/signaled during fw download "); /* timed out */ release_firmware(kim_gdata->fw_entry); - return -ETIMEDOUT; + return err ? -ERESTARTSYS : -ETIMEDOUT; } reinit_completion(&kim_gdata->kim_rcvd); break; -- cgit v1.2.3 From a1d88436d53a75e950db15834b3d2f8c0c358fdc Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Wed, 14 Jan 2015 11:10:19 -0800 Subject: VMCI: Fix two UVA mapping bugs (this is a resend of this patch. Originally sent last year, but post appears to have been lost) This change fixes two bugs in the VMCI host driver related to mapping the notify boolean from user space into kernel space: - the actual UVA was rounded up to the next page boundary - resulting in memory corruption in the calling process whenever notifications would be signalled. This has been fixed by just removing the PAGE_ALIGN part, since get_user_pages_fast can figure this out on its own - the mapped page wasn't stored anywhere, so it wasn't unmapped and put back when a VMCI context was destroyed. Fixed this by remembering the page. Acked-by: Andy King Acked-by: Darius Davis Signed-off-by: Jorgen Hansen Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_driver.c | 2 +- drivers/misc/vmw_vmci/vmci_host.c | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c index 3dee7ae123e7..032d35cf93ca 100644 --- a/drivers/misc/vmw_vmci/vmci_driver.c +++ b/drivers/misc/vmw_vmci/vmci_driver.c @@ -113,5 +113,5 @@ module_exit(vmci_drv_exit); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); -MODULE_VERSION("1.1.0.0-k"); +MODULE_VERSION("1.1.1.0-k"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 1723a6e4f2e8..66fc9921fc85 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -218,13 +218,12 @@ static int drv_cp_harray_to_user(void __user *user_buf_uva, } /* - * Sets up a given context for notify to work. Calls drv_map_bool_ptr() - * which maps the notify boolean in user VA in kernel space. + * Sets up a given context for notify to work. Maps the notify + * boolean in user VA into kernel space. */ static int vmci_host_setup_notify(struct vmci_ctx *context, unsigned long uva) { - struct page *page; int retval; if (context->notify_page) { @@ -243,14 +242,16 @@ static int vmci_host_setup_notify(struct vmci_ctx *context, /* * Lock physical page backing a given user VA. */ - retval = get_user_pages_fast(PAGE_ALIGN(uva), 1, 1, &page); - if (retval != 1) + retval = get_user_pages_fast(uva, 1, 1, &context->notify_page); + if (retval != 1) { + context->notify_page = NULL; return VMCI_ERROR_GENERIC; + } /* * Map the locked page and set up notify pointer. */ - context->notify = kmap(page) + (uva & (PAGE_SIZE - 1)); + context->notify = kmap(context->notify_page) + (uva & (PAGE_SIZE - 1)); vmci_ctx_check_signal_notify(context); return VMCI_SUCCESS; -- cgit v1.2.3 From 1ab1e79b9fd4b01331490bbe2e630a0fc0b25449 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 25 Jan 2015 23:45:27 +0200 Subject: mei: mask interrupt set bit on clean reset bit We should mask interrupt set bit when writing back hcsr value in reset bit clean-up. This is refinement for mei: clean reset bit before reset commit b13a65ef190e488e2761d65bdd2e1fe8a3a125f5 Cc: #3.10+ Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 06ff0a2ec960..ccc1b405ca21 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -242,7 +242,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) if ((hcsr & H_RST) == H_RST) { dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); hcsr &= ~H_RST; - mei_me_reg_write(hw, H_CSR, hcsr); + mei_hcsr_set(hw, hcsr); hcsr = mei_hcsr_read(hw); } -- cgit v1.2.3 From 663b7ee9517eec6deea9a48c7a1392a9a34f7809 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 25 Jan 2015 23:45:28 +0200 Subject: mei: me: release hw from reset only during the reset flow We might enter the interrupt handler with hw_ready already set, but prior we actually started the reset flow. To soleve this we move the reset release from the interrupt handler to the HW start wait function which is part of the reset sequence. Cc: #3.10+ Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index ccc1b405ca21..f8fd503dfbd6 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -335,6 +335,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) return -ETIME; } + mei_me_hw_reset_release(dev); dev->recvd_hw_ready = false; return 0; } @@ -731,9 +732,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if we need to start the dev */ if (!mei_host_is_ready(dev)) { if (mei_hw_is_ready(dev)) { - mei_me_hw_reset_release(dev); dev_dbg(dev->dev, "we need to start the dev.\n"); - dev->recvd_hw_ready = true; wake_up(&dev->wait_hw_ready); } else { -- cgit v1.2.3 From 63e144c9d6ffa791c1402f4ee4551c1b9f5a336a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 15 Jan 2015 14:42:27 +0300 Subject: ti-st: clean up data types (fix harmless memory corruption) The big issue here is: of_property_read_u32(np, "flow_cntrl", (u32 *)&dt_pdata->flow_cntrl); "->flow_cntrl" is a char so when we write a 32 bit number to it then it corrupts past the end of the char. It's probably hard to notice because the struct has padding so the code works on little endian systems. But on a big endian system the code would fail and on a 64 bit, big endian systems then "nshutdown_gpio" and "baud_rate" would be buggy as well. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 12 ++++++------ include/linux/ti_wilink_st.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 8fb116f8a152..18e7a03985d4 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -638,7 +638,7 @@ static ssize_t show_baud_rate(struct device *dev, struct device_attribute *attr, char *buf) { struct kim_data_s *kim_data = dev_get_drvdata(dev); - return sprintf(buf, "%ld\n", kim_data->baud_rate); + return sprintf(buf, "%d\n", kim_data->baud_rate); } static ssize_t show_flow_cntrl(struct device *dev, @@ -760,9 +760,9 @@ static struct ti_st_plat_data *get_platform_data(struct device *dev) if (dt_property) memcpy(&dt_pdata->dev_name, dt_property, len); of_property_read_u32(np, "nshutdown_gpio", - (u32 *)&dt_pdata->nshutdown_gpio); - of_property_read_u32(np, "flow_cntrl", (u32 *)&dt_pdata->flow_cntrl); - of_property_read_u32(np, "baud_rate", (u32 *)&dt_pdata->baud_rate); + &dt_pdata->nshutdown_gpio); + of_property_read_u32(np, "flow_cntrl", &dt_pdata->flow_cntrl); + of_property_read_u32(np, "baud_rate", &dt_pdata->baud_rate); return dt_pdata; } @@ -812,14 +812,14 @@ static int kim_probe(struct platform_device *pdev) kim_gdata->nshutdown = pdata->nshutdown_gpio; err = gpio_request(kim_gdata->nshutdown, "kim"); if (unlikely(err)) { - pr_err(" gpio %ld request failed ", kim_gdata->nshutdown); + pr_err(" gpio %d request failed ", kim_gdata->nshutdown); return err; } /* Configure nShutdown GPIO as output=0 */ err = gpio_direction_output(kim_gdata->nshutdown, 0); if (unlikely(err)) { - pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown); + pr_err(" unable to configure gpio %d", kim_gdata->nshutdown); return err; } /* get reference of pdev for request_firmware diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index 9072d9f95cff..c78dcfeaf25f 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -262,7 +262,7 @@ struct kim_data_s { struct completion kim_rcvd, ldisc_installed; char resp_buffer[30]; const struct firmware *fw_entry; - long nshutdown; + unsigned nshutdown; unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; @@ -270,8 +270,8 @@ struct kim_data_s { struct chip_version version; unsigned char ldisc_install; unsigned char dev_name[UART_DEV_NAME_LEN + 1]; - unsigned char flow_cntrl; - unsigned long baud_rate; + unsigned flow_cntrl; + unsigned baud_rate; }; /** @@ -437,10 +437,10 @@ struct gps_event_hdr { * */ struct ti_st_plat_data { - long nshutdown_gpio; + u32 nshutdown_gpio; unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */ - unsigned char flow_cntrl; /* flow control flag */ - unsigned long baud_rate; + u32 flow_cntrl; /* flow control flag */ + u32 baud_rate; int (*suspend)(struct platform_device *, pm_message_t); int (*resume)(struct platform_device *); int (*chip_enable) (struct kim_data_s *); -- cgit v1.2.3