From ca04455fba937eb2d85f437900cd1726166192e6 Mon Sep 17 00:00:00 2001 From: Matej Muzila Date: Sun, 28 Dec 2014 15:54:13 +0100 Subject: [PATCH 01/90] tools: hv: Makefile: Add hv_fcopy_daemon to Makefile hv_fcopy_daemon is not mentioned in Makefile so it must be built manually. Add hv_fcopy_daemon to Makefile. Signed-off-by: Matej Muzila Signed-off-by: Greg Kroah-Hartman --- tools/hv/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hv/Makefile b/tools/hv/Makefile index bd22f786a60c..99ffe61051a7 100644 --- a/tools/hv/Makefile +++ b/tools/hv/Makefile @@ -5,9 +5,9 @@ PTHREAD_LIBS = -lpthread WARNINGS = -Wall -Wextra CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -all: hv_kvp_daemon hv_vss_daemon +all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon %: %.c $(CC) $(CFLAGS) -o $@ $^ clean: - $(RM) hv_kvp_daemon hv_vss_daemon + $(RM) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon From 87712bf81dd092821c406ea3fb47a07222484a64 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sun, 14 Dec 2014 23:34:51 -0800 Subject: [PATCH 02/90] Drivers: hv: vmbus: Use get_cpu() to get the current CPU Replace calls for smp_processor_id() to get_cpu() to get the CPU ID of the current CPU. In these instances, there is no correctness issue with regards to preemption, we just need the current CPU ID. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 4 +++- drivers/hv/connection.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 2c59f030546b..1d7df2576b1c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -815,7 +815,7 @@ cleanup: struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) { struct list_head *cur, *tmp; - int cur_cpu = hv_context.vp_index[smp_processor_id()]; + int cur_cpu; struct vmbus_channel *cur_channel; struct vmbus_channel *outgoing_channel = primary; int cpu_distance, new_cpu_distance; @@ -823,6 +823,8 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) if (list_empty(&primary->sc_list)) return outgoing_channel; + cur_cpu = hv_context.vp_index[get_cpu()]; + put_cpu(); list_for_each_safe(cur, tmp, &primary->sc_list) { cur_channel = list_entry(cur, struct vmbus_channel, sc_list); if (cur_channel->state != CHANNEL_OPENED_STATE) diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index e206619b946e..a63a795300b9 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -80,8 +80,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); - if (version == VERSION_WIN8_1) - msg->target_vcpu = hv_context.vp_index[smp_processor_id()]; + if (version == VERSION_WIN8_1) { + msg->target_vcpu = hv_context.vp_index[get_cpu()]; + put_cpu(); + } /* * Add to list before we send the request since we may From 787d61822525295399f97390bca3e1bb4ce7a6b3 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 10 Dec 2014 03:33:20 -0800 Subject: [PATCH 03/90] tools: hv: kvp_daemon: make IPv6-only-injection work In the case the host only injects an IPv6 address, the dhcp_enabled flag is true (it's only for IPv4 according to Hyper-V host team), but we still need to proceed to parse the IPv6 information. Cc: K. Y. Srinivasan Signed-off-by: Dexuan Cui Reviewed-By: Vitaly Kuznetsov Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 6a6432a20a1d..4b3ee3521bde 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -1308,16 +1308,17 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) if (error) goto setval_error; + /* + * The dhcp_enabled flag is only for IPv4. In the case the host only + * injects an IPv6 address, the flag is true, but we still need to + * proceed to parse and pass the IPv6 information to the + * disto-specific script hv_set_ifconfig. + */ if (new_val->dhcp_enabled) { error = kvp_write_file(file, "BOOTPROTO", "", "dhcp"); if (error) goto setval_error; - /* - * We are done!. - */ - goto setval_done; - } else { error = kvp_write_file(file, "BOOTPROTO", "", "none"); if (error) @@ -1345,7 +1346,6 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) if (error) goto setval_error; -setval_done: fclose(file); /* From 39db74ce1aa83626a0a70ed2abf29a17598fff49 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 27 Nov 2014 14:07:28 +0200 Subject: [PATCH 04/90] 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 +++--- include/linux/mei_cl_bus.h | 4 ++-- 3 files changed, 19 insertions(+), 21 deletions(-) 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); diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 164aad1f9f12..0819d36a3a74 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -25,8 +25,8 @@ int __mei_cl_driver_register(struct mei_cl_driver *driver, void mei_cl_driver_unregister(struct mei_cl_driver *driver); -int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length); -int mei_cl_recv(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); +ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length); typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, u32 events, void *context); From 2e5df413becf6bd3854d1eb4f96542a53848bb27 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 7 Dec 2014 16:40:14 +0200 Subject: [PATCH 05/90] 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(-) 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; From 46d0d33350e9b32642d745a8b46a954910196b4d Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:45:02 +0000 Subject: [PATCH 06/90] 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(-) 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 From 4b4aa3ab982e1e6f22a3df12a368803576b73ccf Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:46:24 +0000 Subject: [PATCH 07/90] 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(-) 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; } /**********************************************************************/ From c6ec0fb4006d1d8110b3166f2cc2b04b8002d210 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:47:51 +0000 Subject: [PATCH 08/90] 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(-) 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); From 868eba8e13d592f2eb9774777c9f3d9286482154 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:48:29 +0000 Subject: [PATCH 09/90] 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(-) 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) From 0ec0cf19201da36af858a6bc052a13e88866f341 Mon Sep 17 00:00:00 2001 From: Gigi Joseph Date: Fri, 9 Jan 2015 03:49:03 +0000 Subject: [PATCH 10/90] 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(-) 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); } } - - From 769105aa740dc0428f2585ec99c457d30aaab364 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 8 Dec 2014 16:28:10 +0100 Subject: [PATCH 11/90] 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(-) 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: From 73f0718e74e25ac7381450a7a21257b8f26f43f0 Mon Sep 17 00:00:00 2001 From: Rob Ward Date: Sun, 7 Dec 2014 15:40:33 +0000 Subject: [PATCH 12/90] drivers: char: mem: Make /dev/mem an optional device Adds Kconfig option CONFIG_DEVMEM that allows the /dev/mem device to be disabled. Option defaults to /dev/mem enabled. Signed-off-by: Rob Ward Acked-by: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 9 +++++++++ drivers/char/mem.c | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index efefd12a0f7b..a4af8221751e 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,15 @@ menu "Character devices" source "drivers/tty/Kconfig" +config DEVMEM + bool "/dev/mem virtual device support" + default y + help + Say Y here if you want to support the /dev/mem device. + The /dev/mem device is used to access areas of physical + memory. + When in doubt, say "Y". + config DEVKMEM bool "/dev/kmem virtual device support" default y diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 4c58333b4257..7d6778437be0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -715,7 +715,7 @@ static int open_port(struct inode *inode, struct file *filp) #define open_mem open_port #define open_kmem open_mem -static const struct file_operations mem_fops = { +static const struct file_operations __maybe_unused mem_fops = { .llseek = memory_lseek, .read = read_mem, .write = write_mem, @@ -785,7 +785,9 @@ static const struct memdev { const struct file_operations *fops; struct backing_dev_info *dev_info; } devlist[] = { +#ifdef CONFIG_DEVMEM [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, +#endif #ifdef CONFIG_DEVKMEM [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, #endif From a8c912522b547b3512cd25ccb8d507cd75264c84 Mon Sep 17 00:00:00 2001 From: Rob Ward Date: Sun, 7 Dec 2014 15:40:34 +0000 Subject: [PATCH 13/90] drivers: char: mem: Simplify DEVKMEM configuration Simplify the use of CONFIG_DEVKMEM by making the kmem_fops so that it is __maybe_unused. This enabled the multiple #ifdef's used for this structure to be removed and brings it in line with the use of CONFIG_DEVMEM This change should introduce no functional changes. Signed-off-by: Rob Ward Acked-by: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 7d6778437be0..17b21396e7f9 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -341,7 +341,6 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) return 0; } -#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file *file, struct vm_area_struct *vma) { unsigned long pfn; @@ -362,9 +361,7 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma) vma->vm_pgoff = pfn; return mmap_mem(file, vma); } -#endif -#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -544,7 +541,6 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, *ppos = p; return virtr + wrote ? : err; } -#endif #ifdef CONFIG_DEVPORT static ssize_t read_port(struct file *file, char __user *buf, @@ -724,8 +720,7 @@ static const struct file_operations __maybe_unused mem_fops = { .get_unmapped_area = get_unmapped_area_mem, }; -#ifdef CONFIG_DEVKMEM -static const struct file_operations kmem_fops = { +static const struct file_operations __maybe_unused kmem_fops = { .llseek = memory_lseek, .read = read_kmem, .write = write_kmem, @@ -733,7 +728,6 @@ static const struct file_operations kmem_fops = { .open = open_kmem, .get_unmapped_area = get_unmapped_area_mem, }; -#endif static const struct file_operations null_fops = { .llseek = null_lseek, From 3a4bc2fb80fb1fc943b640aae87dc078ba2aad78 Mon Sep 17 00:00:00 2001 From: Rob Ward Date: Sun, 7 Dec 2014 15:40:35 +0000 Subject: [PATCH 14/90] drivers: char: mem: Simplify DEVPORT configuration Simplify the use of CONFIG_DEVPORT by making the port_fops so that it includes __maybe_unused. This enabled the multiple #ifdef's used for this structure to be removed and brings it in line with the use of CONFIG_DEVMEM This change should introduce no functional changes. Signed-off-by: Rob Ward Acked-by: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 17b21396e7f9..40c1580ecd47 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -542,7 +542,6 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, return virtr + wrote ? : err; } -#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -583,7 +582,6 @@ static ssize_t write_port(struct file *file, const char __user *buf, *ppos = i; return tmp-buf; } -#endif static ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -738,14 +736,12 @@ static const struct file_operations null_fops = { .splice_write = splice_write_null, }; -#ifdef CONFIG_DEVPORT -static const struct file_operations port_fops = { +static const struct file_operations __maybe_unused port_fops = { .llseek = memory_lseek, .read = read_port, .write = write_port, .open = open_port, }; -#endif static const struct file_operations zero_fops = { .llseek = zero_lseek, From 35b6c7e4a536f9a6110023431533b738650d6457 Mon Sep 17 00:00:00 2001 From: Rob Ward Date: Sat, 20 Dec 2014 18:28:35 +0000 Subject: [PATCH 15/90] drivers: char: mem: Replace usage of asm include Replaces the use of asm/uaccess.h with linux/uaccess.h. Signed-off-by: Rob Ward Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 40c1580ecd47..da73aeaa7008 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -28,7 +28,7 @@ #include #include -#include +#include #ifdef CONFIG_IA64 # include From 6a0061badd2e894edb5a3a5d7704095766a343fd Mon Sep 17 00:00:00 2001 From: Rob Ward Date: Sat, 20 Dec 2014 18:28:36 +0000 Subject: [PATCH 16/90] drivers: char: mem: Fix Missing blank line issues Fixes "Missing a blank line after declarations" reported by checkpatch. This patch introduces no functional changes. Signed-off-by: Rob Ward Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index da73aeaa7008..080273287c48 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -570,6 +570,7 @@ static ssize_t write_port(struct file *file, const char __user *buf, return -EFAULT; while (count-- > 0 && i < 65536) { char c; + if (__get_user(c, tmp)) { if (tmp > buf) break; @@ -625,6 +626,7 @@ static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter) while (iov_iter_count(iter)) { size_t chunk = iov_iter_count(iter), n; + if (chunk > PAGE_SIZE) chunk = PAGE_SIZE; /* Just for latency reasons */ n = iov_iter_zero(chunk, iter); From ef3522f78cf0d068e5d0bb3cdc3568d9c7aee1f0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 21 Dec 2014 20:54:37 +0100 Subject: [PATCH 17/90] MAINTAINERS: Fix up entry for Dell laptop SMM driver Mark driver as maintained. Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8d32b3..2b41cd183b4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3012,6 +3012,7 @@ F: drivers/platform/x86/dell-laptop.c DELL LAPTOP SMM DRIVER M: Guenter Roeck +S: Maintained F: drivers/char/i8k.c F: include/uapi/linux/i8k.h From 0ecb3dffb1f56f03cbce91fe8b03d52c2980c13b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 29 Dec 2014 15:32:47 +0100 Subject: [PATCH 18/90] 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(-) 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 From 1558455582623b67492f630d11b94d5e4c506e5f Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:16:26 +0530 Subject: [PATCH 19/90] 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(+) 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): From 3d494bba92c4665ab34056bf86a14e02b0e1db22 Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:17:13 +0530 Subject: [PATCH 20/90] 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(-) 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); From c076860dd86d48460562d1c2a724914b64709da8 Mon Sep 17 00:00:00 2001 From: Mohammad Jamal Date: Thu, 18 Dec 2014 07:24:11 +0530 Subject: [PATCH 21/90] 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(+) 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; From c1038307c4586403b4d393300e6e2f4a5673e722 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 7 Dec 2014 20:20:53 +0100 Subject: [PATCH 22/90] vme: fix misspelling of current function in string Replace a misspelled function name by %s and then __func__. This is the get function, not the set function, as was indicated by the string. This was done using Coccinelle, including the use of Levenshtein distance, as proposed by Rasmus Villemoes. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/vme/vme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 7516030037a1..d95fb848dd03 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -502,7 +502,7 @@ int vme_master_get(struct vme_resource *resource, int *enabled, image = list_entry(resource->entry, struct vme_master_resource, list); if (bridge->master_get == NULL) { - printk(KERN_WARNING "vme_master_set not supported\n"); + printk(KERN_WARNING "%s not supported\n", __func__); return -EINVAL; } From 5de61e7aa1ba9ac3c7edbea375da2bc8eb1a89ae Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 18 Dec 2014 14:55:53 -0800 Subject: [PATCH 23/90] stable_kernel_rules: reorganize and update submission options The current organization of Documentation/stable_kernel_rules.txt doesn't clearly differentiate the mutually exclusive options for submission to the -stable review process. As I understand it, patches are not actually required to be mailed directly to stable@vger.kernel.org, but the instructions do not make this clear. Also, there are some established processes that are not listed -- specifically, what I call Option 2 below. This patch updates and reorganizes a bit, to make things clearer. Signed-off-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- Documentation/stable_kernel_rules.txt | 44 +++++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index aee73e78c7d4..02f8331edb8b 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -32,18 +32,42 @@ Procedure for submitting patches to the -stable tree: - If the patch covers files in net/ or drivers/net please follow netdev stable submission guidelines as described in Documentation/networking/netdev-FAQ.txt - - Send the patch, after verifying that it follows the above rules, to - stable@vger.kernel.org. You must note the upstream commit ID in the - changelog of your submission, as well as the kernel version you wish - it to be applied to. - - To have the patch automatically included in the stable tree, add the tag + - Security patches should not be handled (solely) by the -stable review + process but should follow the procedures in Documentation/SecurityBugs. + +For all other submissions, choose one of the following procedures: + + --- Option 1 --- + + To have the patch automatically included in the stable tree, add the tag Cc: stable@vger.kernel.org in the sign-off area. Once the patch is merged it will be applied to the stable tree without anything else needing to be done by the author or subsystem maintainer. - - If the patch requires other patches as prerequisites which can be - cherry-picked, then this can be specified in the following format in - the sign-off area: + + --- Option 2 --- + + After the patch has been merged to Linus' tree, send an email to + stable@vger.kernel.org containing the subject of the patch, the commit ID, + why you think it should be applied, and what kernel version you wish it to + be applied to. + + --- Option 3 --- + + Send the patch, after verifying that it follows the above rules, to + stable@vger.kernel.org. You must note the upstream commit ID in the + changelog of your submission, as well as the kernel version you wish + it to be applied to. + +Option 1 is probably the easiest and most common. Options 2 and 3 are more +useful if the patch isn't deemed worthy at the time it is applied to a public +git tree (for instance, because it deserves more regression testing first). +Option 3 is especially useful if the patch needs some special handling to apply +to an older kernel (e.g., if API's have changed in the meantime). + +Additionally, some patches submitted via Option 1 may have additional patch +prerequisites which can be cherry-picked. This can be specified in the following +format in the sign-off area: Cc: # 3.3.x: a1f84a3: sched: Check for idle Cc: # 3.3.x: 1b9508f: sched: Rate-limit newidle @@ -57,13 +81,13 @@ Procedure for submitting patches to the -stable tree: git cherry-pick fd21073 git cherry-pick +Following the submission: + - The sender will receive an ACK when the patch has been accepted into the queue, or a NAK if the patch is rejected. This response might take a few days, according to the developer's schedules. - If accepted, the patch will be added to the -stable queue, for review by other developers and by the relevant subsystem maintainer. - - Security patches should not be sent to this alias, but instead to the - documented security@kernel.org address. Review cycle: From c4277e9ea70431aea0fecebb8bb9a3fbc27d074e Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 6 Dec 2014 00:28:01 +0300 Subject: [PATCH 24/90] uio/uio_pci_generic: don't return zero on failure path in probe() If uio_register_device() fails in probe(), it breaks off initialization, deallocates all resources, but returns zero. The patch adds proper error code propagation. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_pci_generic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 077ae12269ce..d0b508b68f3c 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -91,7 +91,8 @@ static int probe(struct pci_dev *pdev, gdev->info.handler = irqhandler; gdev->pdev = pdev; - if (uio_register_device(&pdev->dev, &gdev->info)) + err = uio_register_device(&pdev->dev, &gdev->info); + if (err) goto err_register; pci_set_drvdata(pdev, gdev); From a6c6193a3662f6634ad7f797597081556a9db068 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 10 Dec 2014 15:05:38 +0000 Subject: [PATCH 25/90] pcmcia: correct types We should be using resource_size_t and unsigned types correctly, otherwise we sign extend the flags on a 64bit box, which is not what we want. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/cs_internal.h | 6 +++--- drivers/pcmcia/rsrc_mgr.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7f1953f78b12..e86cd6b31773 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -80,9 +80,9 @@ struct pccard_resource_ops { * Stuff internal to module "pcmcia_rsrc": */ extern int static_init(struct pcmcia_socket *s); -extern struct resource *pcmcia_make_resource(unsigned long start, - unsigned long end, - int flags, const char *name); +extern struct resource *pcmcia_make_resource(resource_size_t start, + resource_size_t end, + unsigned long flags, const char *name); /* * Stuff internal to module "pcmcia_core": diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index aa628ed0e9f4..df2cb70aef5b 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -30,8 +30,9 @@ int static_init(struct pcmcia_socket *s) return 0; } -struct resource *pcmcia_make_resource(unsigned long start, unsigned long end, - int flags, const char *name) +struct resource *pcmcia_make_resource(resource_size_t start, + resource_size_t end, + unsigned long flags, const char *name) { struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); From b38a4bd319e615b4eb4be9d8c0d5ddc13113c768 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 10 Dec 2014 15:06:10 +0000 Subject: [PATCH 26/90] pcmcia cis: on an out of range CIS read return 0xff, don't just warn The current code displays warnings but then proceeds to try and reference the data through the PCMCIA window. Instead return 0xff. This prevents bogus CIS data sending us off into hyperspace. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/cistpl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 884a984216fe..4ff725ca2c74 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -168,9 +168,12 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, } else { u_int inc = 1, card_offset, flags; - if (addr > CISTPL_MAX_CIS_SIZE) + if (addr > CISTPL_MAX_CIS_SIZE) { dev_dbg(&s->dev, "attempt to read CIS mem at addr %#x", addr); + memset(ptr, 0xff, len); + return -1; + } flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); if (attr) { From 8402641b2dc73748dde81e3513ac61c8436be3cb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 10 Dec 2014 15:06:40 +0000 Subject: [PATCH 27/90] pcmcia: Fix requery The requery logic goes off and attempts to read the CIS of empty slots. In most cases this happens not to do any harm - but not all! Add the missing check and also a WARN() to catch any other offenders. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/cistpl.c | 2 +- drivers/pcmcia/ds.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 4ff725ca2c74..8b3b49217287 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1386,7 +1386,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) if (!s) return -EINVAL; - if (s->functions) { + if (s->functions || !(s->state & SOCKET_PRESENT)) { WARN_ON(1); return -EINVAL; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 757119b87146..d3baf0bfca9f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -667,6 +667,9 @@ static void pcmcia_requery(struct pcmcia_socket *s) { int has_pfc; + if (!(s->state & SOCKET_PRESENT)) + return; + if (s->functions == 0) { pcmcia_card_add(s); return; From 1c6c9b1d9d2530c346910329751e7fd1a02dc2bd Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 10 Dec 2014 15:07:14 +0000 Subject: [PATCH 28/90] pcmcia: handle anonymous cards by generating a fake CIS The core pcmcia code blows up all over the place if it allowed a card without a valid CIS. We need to allow such cards as the CIS stuff is not on the older flash, ROM and SRAM cards. In order to minimise the risk of misidentifying junk and feeding it to the wrong thing we only fix up apparently anonymous cards if the driver for them has been enabled. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/cistpl.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 8b3b49217287..64d0515b76bd 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1451,10 +1451,26 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) done: /* invalidate CIS cache on failure */ if (!dev_ok || !ident_ok || !count) { - mutex_lock(&s->ops_mutex); - destroy_cis_cache(s); - mutex_unlock(&s->ops_mutex); - ret = -EIO; +#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS) + /* Set up as an anonymous card. If we don't have anonymous + memory support then just error the card as there is no + point trying to second guess. + + Note: some cards have just a device entry, it may be + worth extending support to cover these in future */ + if (!dev_ok || !ident_ok) { + dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n"); + pcmcia_replace_cis(s, "\xFF", 1); + count = 1; + ret = 0; + } else +#endif + { + mutex_lock(&s->ops_mutex); + destroy_cis_cache(s); + mutex_unlock(&s->ops_mutex); + ret = -EIO; + } } if (info) From 02b03846bb2befc558bfd0665749d6bb26f4c2f1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 10 Dec 2014 15:07:36 +0000 Subject: [PATCH 29/90] pcmcia: add a new resource manager for non ISA systems On a pure PCI platform we don't actually need all the complexity of the rsrc_nonstatic manager, in fact we can just work directly with the pci allocators and avoid all the complexity (and code bloat). Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/Kconfig | 12 ++- drivers/pcmcia/Makefile | 1 + drivers/pcmcia/rsrc_pci.c | 172 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 drivers/pcmcia/rsrc_pci.c diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 910e90bf16c6..8843a678f200 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -69,7 +69,8 @@ config YENTA tristate "CardBus yenta-compatible bridge support" depends on PCI select CARDBUS if !EXPERT - select PCCARD_NONSTATIC if PCMCIA != n + select PCCARD_NONSTATIC if PCMCIA != n && ISA + select PCCARD_PCI if PCMCIA !=n && !ISA ---help--- This option enables support for CardBus host bridges. Virtually all modern PCMCIA bridges are CardBus compatible. A "bridge" is @@ -109,7 +110,8 @@ config YENTA_TOSHIBA config PD6729 tristate "Cirrus PD6729 compatible bridge support" depends on PCMCIA && PCI - select PCCARD_NONSTATIC + select PCCARD_NONSTATIC if PCMCIA != n && ISA + select PCCARD_PCI if PCMCIA !=n && !ISA help This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge device, found in some older laptops and PCMCIA card readers. @@ -117,7 +119,8 @@ config PD6729 config I82092 tristate "i82092 compatible bridge support" depends on PCMCIA && PCI - select PCCARD_NONSTATIC + select PCCARD_NONSTATIC if PCMCIA != n && ISA + select PCCARD_PCI if PCMCIA !=n && !ISA help This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device, found in some older laptops and more commonly in evaluation boards for the @@ -287,6 +290,9 @@ config ELECTRA_CF Say Y here to support the CompactFlash controller on the PA Semi Electra eval board. +config PCCARD_PCI + bool + config PCCARD_NONSTATIC bool diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 27e94b30cf96..f1a7ca04d89e 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PCMCIA) += pcmcia.o pcmcia_rsrc-y += rsrc_mgr.o pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o pcmcia_rsrc-$(CONFIG_PCCARD_IODYN) += rsrc_iodyn.o +pcmcia_rsrc-$(CONFIG_PCCARD_PCI) += rsrc_pci.o obj-$(CONFIG_PCCARD) += pcmcia_rsrc.o diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c new file mode 100644 index 000000000000..8934d3c01f80 --- /dev/null +++ b/drivers/pcmcia/rsrc_pci.c @@ -0,0 +1,172 @@ +#include +#include +#include + +#include +#include +#include "cs_internal.h" + + +struct pcmcia_align_data { + unsigned long mask; + unsigned long offset; +}; + +static resource_size_t pcmcia_align(void *align_data, + const struct resource *res, + resource_size_t size, resource_size_t align) +{ + struct pcmcia_align_data *data = align_data; + resource_size_t start; + + start = (res->start & ~data->mask) + data->offset; + if (start < res->start) + start += data->mask + 1; + return start; +} + +static struct resource *find_io_region(struct pcmcia_socket *s, + unsigned long base, int num, + unsigned long align) +{ + struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, + dev_name(&s->dev)); + struct pcmcia_align_data data; + int ret; + + data.mask = align - 1; + data.offset = base & data.mask; + + ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, + base, 0, pcmcia_align, &data); + if (ret != 0) { + kfree(res); + res = NULL; + } + return res; +} + +static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr, + unsigned int *base, unsigned int num, + unsigned int align, struct resource **parent) +{ + int i, ret = 0; + + /* Check for an already-allocated window that must conflict with + * what was asked for. It is a hack because it does not catch all + * potential conflicts, just the most obvious ones. + */ + for (i = 0; i < MAX_IO_WIN; i++) { + if (!s->io[i].res) + continue; + + if (!*base) + continue; + + if ((s->io[i].res->start & (align-1)) == *base) + return -EBUSY; + } + + for (i = 0; i < MAX_IO_WIN; i++) { + struct resource *res = s->io[i].res; + unsigned int try; + + if (res && (res->flags & IORESOURCE_BITS) != + (attr & IORESOURCE_BITS)) + continue; + + if (!res) { + if (align == 0) + align = 0x10000; + + res = s->io[i].res = find_io_region(s, *base, num, + align); + if (!res) + return -EINVAL; + + *base = res->start; + s->io[i].res->flags = + ((res->flags & ~IORESOURCE_BITS) | + (attr & IORESOURCE_BITS)); + s->io[i].InUse = num; + *parent = res; + return 0; + } + + /* Try to extend top of window */ + try = res->end + 1; + if ((*base == 0) || (*base == try)) { + ret = adjust_resource(s->io[i].res, res->start, + resource_size(res) + num); + if (ret) + continue; + *base = try; + s->io[i].InUse += num; + *parent = res; + return 0; + } + + /* Try to extend bottom of window */ + try = res->start - num; + if ((*base == 0) || (*base == try)) { + ret = adjust_resource(s->io[i].res, + res->start - num, + resource_size(res) + num); + if (ret) + continue; + *base = try; + s->io[i].InUse += num; + *parent = res; + return 0; + } + } + return -EINVAL; +} + +static struct resource *res_pci_find_mem(u_long base, u_long num, + u_long align, int low, struct pcmcia_socket *s) +{ + struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM, + dev_name(&s->dev)); + struct pcmcia_align_data data; + unsigned long min; + int ret; + + if (align < 0x20000) + align = 0x20000; + data.mask = align - 1; + data.offset = base & data.mask; + + min = 0; + if (!low) + min = 0x100000UL; + + ret = pci_bus_alloc_resource(s->cb_dev->bus, + res, num, 1, min, 0, + pcmcia_align, &data); + + if (ret != 0) { + kfree(res); + res = NULL; + } + return res; +} + + +static int res_pci_init(struct pcmcia_socket *s) +{ + if (!s->cb_dev || (!s->features & SS_CAP_PAGE_REGS)) { + dev_err(&s->dev, "not supported by res_pci\n"); + return -EOPNOTSUPP; + } + return 0; +} + +struct pccard_resource_ops pccard_nonstatic_ops = { + .validate_mem = NULL, + .find_io = res_pci_find_io, + .find_mem = res_pci_find_mem, + .init = res_pci_init, + .exit = NULL, +}; +EXPORT_SYMBOL(pccard_nonstatic_ops); From fbc4a8a85777e065f7a195ddc58b3245808f1e87 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Tue, 9 Dec 2014 17:43:10 +0100 Subject: [PATCH 30/90] uio: uio_fsl_elbc_gpcm: new driver This driver provides UIO access to memory of a peripheral connected to the Freescale enhanced local bus controller (eLBC) interface using the general purpose chip-select mode (GPCM). Signed-off-by: John Ogness Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/powerpc/fsl/lbc.txt | 18 +- arch/powerpc/include/asm/fsl_lbc.h | 3 + drivers/uio/Kconfig | 20 + drivers/uio/Makefile | 1 + drivers/uio/uio_fsl_elbc_gpcm.c | 499 ++++++++++++++++++ 5 files changed, 536 insertions(+), 5 deletions(-) create mode 100644 drivers/uio/uio_fsl_elbc_gpcm.c diff --git a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt index 3300fec501c5..1c80fcedebb5 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt @@ -16,20 +16,28 @@ Example: "fsl,pq2-localbus"; #address-cells = <2>; #size-cells = <1>; - reg = ; + reg = <0xf0010100 0x40>; - ranges = <0 0 fe000000 02000000 - 1 0 f4500000 00008000>; + ranges = <0x0 0x0 0xfe000000 0x02000000 + 0x1 0x0 0xf4500000 0x00008000 + 0x2 0x0 0xfd810000 0x00010000>; flash@0,0 { compatible = "jedec-flash"; - reg = <0 0 2000000>; + reg = <0x0 0x0 0x2000000>; bank-width = <4>; device-width = <1>; }; board-control@1,0 { - reg = <1 0 20>; + reg = <0x1 0x0 0x20>; compatible = "fsl,mpc8272ads-bcsr"; }; + + simple-periph@2,0 { + compatible = "fsl,elbc-gpcm-uio"; + reg = <0x2 0x0 0x10000>; + elbc-gpcm-br = <0xfd810800>; + elbc-gpcm-or = <0xffff09f7>; + }; }; diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h index 067fb0dca549..c7240a024b96 100644 --- a/arch/powerpc/include/asm/fsl_lbc.h +++ b/arch/powerpc/include/asm/fsl_lbc.h @@ -95,6 +95,9 @@ struct fsl_lbc_bank { #define OR_FCM_TRLX_SHIFT 2 #define OR_FCM_EHTR 0x00000002 #define OR_FCM_EHTR_SHIFT 1 + +#define OR_GPCM_AM 0xFFFF8000 +#define OR_GPCM_AM_SHIFT 15 }; struct fsl_lbc_regs { diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 5a90914d856d..8a15c323c030 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -104,6 +104,26 @@ config UIO_NETX To compile this driver as a module, choose M here; the module will be called uio_netx. +config UIO_FSL_ELBC_GPCM + tristate "eLBC/GPCM driver" + depends on FSL_LBC + help + Generic driver for accessing a peripheral connected to an eLBC port + that is running in GPCM mode. GPCM is an interface for simple lower + performance memories and memory-mapped devices. For devices using + FCM or UPM eLBC modes, other device-specific drivers are available. + +config UIO_FSL_ELBC_GPCM_NETX5152 + bool "eLBC/GPCM netX 51/52 support" + depends on UIO_FSL_ELBC_GPCM + help + This will add support for netX 51/52 devices connected via eLBC/GPCM. + In particular, it implements interrupt handling. This can be used + together with the userspace netX stack from Hilscher. + + Information about this hardware can be found at: + http://www.hilscher.com/netx + config UIO_PRUSS tristate "Texas Instruments PRUSS driver" depends on ARCH_DAVINCI_DA850 diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index d3218bde3aeb..8560dad52d0f 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o obj-$(CONFIG_UIO_NETX) += uio_netx.o obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o +obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c new file mode 100644 index 000000000000..b6cac91c2ced --- /dev/null +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -0,0 +1,499 @@ +/* uio_fsl_elbc_gpcm: UIO driver for eLBC/GPCM peripherals + + Copyright (C) 2014 Linutronix GmbH + Author: John Ogness + + This driver provides UIO access to memory of a peripheral connected + to the Freescale enhanced local bus controller (eLBC) interface + using the general purpose chip-select mode (GPCM). + + Here is an example of the device tree entries: + + localbus@ffe05000 { + ranges = <0x2 0x0 0x0 0xff810000 0x10000>; + + dpm@2,0 { + compatible = "fsl,elbc-gpcm-uio"; + reg = <0x2 0x0 0x10000>; + elbc-gpcm-br = <0xff810800>; + elbc-gpcm-or = <0xffff09f7>; + interrupt-parent = <&mpic>; + interrupts = <4 1>; + device_type = "netx5152"; + uio_name = "netx_custom"; + netx5152,init-win0-offset = <0x0>; + }; + }; + + Only the entries reg (to identify bank) and elbc-gpcm-* (initial BR/OR + values) are required. The entries interrupt*, device_type, and uio_name + are optional (as well as any type-specific options such as + netx5152,init-win0-offset). As long as no interrupt handler is needed, + this driver can be used without any type-specific implementation. + + The netx5152 type has been tested to work with the netX 51/52 hardware + from Hilscher using the Hilscher userspace netX stack. + + The netx5152 type should serve as a model to add new type-specific + devices as needed. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX_BANKS 8 + +struct fsl_elbc_gpcm { + struct device *dev; + struct fsl_lbc_regs __iomem *lbc; + u32 bank; + const char *name; + + void (*init)(struct uio_info *info); + void (*shutdown)(struct uio_info *info, bool init_err); + irqreturn_t (*irq_handler)(int irq, struct uio_info *info); +}; + +static ssize_t reg_show(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +DEVICE_ATTR(reg_br, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store); +DEVICE_ATTR(reg_or, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store); + +static ssize_t reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct uio_info *info = platform_get_drvdata(pdev); + struct fsl_elbc_gpcm *priv = info->priv; + struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank]; + + if (attr == &dev_attr_reg_br) { + return scnprintf(buf, PAGE_SIZE, "0x%08x\n", + in_be32(&bank->br)); + + } else if (attr == &dev_attr_reg_or) { + return scnprintf(buf, PAGE_SIZE, "0x%08x\n", + in_be32(&bank->or)); + } + + return 0; +} + +static ssize_t reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct uio_info *info = platform_get_drvdata(pdev); + struct fsl_elbc_gpcm *priv = info->priv; + struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank]; + unsigned long val; + u32 reg_br_cur; + u32 reg_or_cur; + u32 reg_new; + + /* parse use input */ + if (kstrtoul(buf, 0, &val) != 0) + return -EINVAL; + reg_new = (u32)val; + + /* read current values */ + reg_br_cur = in_be32(&bank->br); + reg_or_cur = in_be32(&bank->or); + + if (attr == &dev_attr_reg_br) { + /* not allowed to change effective base address */ + if ((reg_br_cur & reg_or_cur & BR_BA) != + (reg_new & reg_or_cur & BR_BA)) { + return -EINVAL; + } + + /* not allowed to change mode */ + if ((reg_new & BR_MSEL) != BR_MS_GPCM) + return -EINVAL; + + /* write new value (force valid) */ + out_be32(&bank->br, reg_new | BR_V); + + } else if (attr == &dev_attr_reg_or) { + /* not allowed to change access mask */ + if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM)) + return -EINVAL; + + /* write new value */ + out_be32(&bank->or, reg_new); + + } else { + return -EINVAL; + } + + return count; +} + +#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152 +#define DPM_HOST_WIN0_OFFSET 0xff00 +#define DPM_HOST_INT_STAT0 0xe0 +#define DPM_HOST_INT_EN0 0xf0 +#define DPM_HOST_INT_MASK 0xe600ffff +#define DPM_HOST_INT_GLOBAL_EN 0x80000000 + +static irqreturn_t netx5152_irq_handler(int irq, struct uio_info *info) +{ + void __iomem *reg_int_en = info->mem[0].internal_addr + + DPM_HOST_WIN0_OFFSET + + DPM_HOST_INT_EN0; + void __iomem *reg_int_stat = info->mem[0].internal_addr + + DPM_HOST_WIN0_OFFSET + + DPM_HOST_INT_STAT0; + + /* check if an interrupt is enabled and active */ + if ((ioread32(reg_int_en) & ioread32(reg_int_stat) & + DPM_HOST_INT_MASK) == 0) { + return IRQ_NONE; + } + + /* disable interrupts */ + iowrite32(ioread32(reg_int_en) & ~DPM_HOST_INT_GLOBAL_EN, reg_int_en); + + return IRQ_HANDLED; +} + +static void netx5152_init(struct uio_info *info) +{ + unsigned long win0_offset = DPM_HOST_WIN0_OFFSET; + struct fsl_elbc_gpcm *priv = info->priv; + const void *prop; + + /* get an optional initial win0 offset */ + prop = of_get_property(priv->dev->of_node, + "netx5152,init-win0-offset", NULL); + if (prop) + win0_offset = of_read_ulong(prop, 1); + + /* disable interrupts */ + iowrite32(0, info->mem[0].internal_addr + win0_offset + + DPM_HOST_INT_EN0); +} + +static void netx5152_shutdown(struct uio_info *info, bool init_err) +{ + if (init_err) + return; + + /* disable interrupts */ + iowrite32(0, info->mem[0].internal_addr + DPM_HOST_WIN0_OFFSET + + DPM_HOST_INT_EN0); +} +#endif + +static void setup_periph(struct fsl_elbc_gpcm *priv, + const char *type) +{ +#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152 + if (strcmp(type, "netx5152") == 0) { + priv->irq_handler = netx5152_irq_handler; + priv->init = netx5152_init; + priv->shutdown = netx5152_shutdown; + priv->name = "netX 51/52"; + return; + } +#endif +} + +static int check_of_data(struct fsl_elbc_gpcm *priv, + struct resource *res, + u32 reg_br, u32 reg_or) +{ + /* check specified bank */ + if (priv->bank >= MAX_BANKS) { + dev_err(priv->dev, "invalid bank\n"); + return -ENODEV; + } + + /* check specified mode (BR_MS_GPCM is 0) */ + if ((reg_br & BR_MSEL) != BR_MS_GPCM) { + dev_err(priv->dev, "unsupported mode\n"); + return -ENODEV; + } + + /* check specified mask vs. resource size */ + if ((~(reg_or & OR_GPCM_AM) + 1) != resource_size(res)) { + dev_err(priv->dev, "address mask / size mismatch\n"); + return -ENODEV; + } + + /* check specified address */ + if ((reg_br & reg_or & BR_BA) != fsl_lbc_addr(res->start)) { + dev_err(priv->dev, "base address mismatch\n"); + return -ENODEV; + } + + return 0; +} + +static int get_of_data(struct fsl_elbc_gpcm *priv, struct device_node *node, + struct resource *res, u32 *reg_br, + u32 *reg_or, unsigned int *irq, char **name) +{ + const char *dt_name; + const char *type; + int ret; + + /* get the memory resource */ + ret = of_address_to_resource(node, 0, res); + if (ret) { + dev_err(priv->dev, "failed to get resource\n"); + return ret; + } + + /* get the bank number */ + ret = of_property_read_u32(node, "reg", &priv->bank); + if (ret) { + dev_err(priv->dev, "failed to get bank number\n"); + return ret; + } + + /* get BR value to set */ + ret = of_property_read_u32(node, "elbc-gpcm-br", reg_br); + if (ret) { + dev_err(priv->dev, "missing elbc-gpcm-br value\n"); + return ret; + } + + /* get OR value to set */ + ret = of_property_read_u32(node, "elbc-gpcm-or", reg_or); + if (ret) { + dev_err(priv->dev, "missing elbc-gpcm-or value\n"); + return ret; + } + + /* get optional peripheral type */ + priv->name = "generic"; + if (of_property_read_string(node, "device_type", &type) == 0) + setup_periph(priv, type); + + /* get optional irq value */ + *irq = irq_of_parse_and_map(node, 0); + + /* sanity check device tree data */ + ret = check_of_data(priv, res, *reg_br, *reg_or); + if (ret) + return ret; + + /* get optional uio name */ + if (of_property_read_string(node, "uio_name", &dt_name) != 0) + dt_name = "eLBC_GPCM"; + *name = kstrdup(dt_name, GFP_KERNEL); + if (!*name) + return -ENOMEM; + + return 0; +} + +static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct fsl_elbc_gpcm *priv; + struct uio_info *info; + char *uio_name = NULL; + struct resource res; + unsigned int irq; + u32 reg_br_cur; + u32 reg_or_cur; + u32 reg_br_new; + u32 reg_or_new; + int ret; + + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) + return -ENODEV; + + /* allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = &pdev->dev; + priv->lbc = fsl_lbc_ctrl_dev->regs; + + /* get device tree data */ + ret = get_of_data(priv, node, &res, ®_br_new, ®_or_new, + &irq, &uio_name); + if (ret) + goto out_err0; + + /* allocate UIO structure */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto out_err0; + } + + /* get current BR/OR values */ + reg_br_cur = in_be32(&priv->lbc->bank[priv->bank].br); + reg_or_cur = in_be32(&priv->lbc->bank[priv->bank].or); + + /* if bank already configured, make sure it matches */ + if ((reg_br_cur & BR_V)) { + if ((reg_br_cur & BR_MSEL) != BR_MS_GPCM || + (reg_br_cur & reg_or_cur & BR_BA) + != fsl_lbc_addr(res.start)) { + dev_err(priv->dev, + "bank in use by another peripheral\n"); + ret = -ENODEV; + goto out_err1; + } + + /* warn if behavior settings changing */ + if ((reg_br_cur & ~(BR_BA | BR_V)) != + (reg_br_new & ~(BR_BA | BR_V))) { + dev_warn(priv->dev, + "modifying BR settings: 0x%08x -> 0x%08x", + reg_br_cur, reg_br_new); + } + if ((reg_or_cur & ~OR_GPCM_AM) != (reg_or_new & ~OR_GPCM_AM)) { + dev_warn(priv->dev, + "modifying OR settings: 0x%08x -> 0x%08x", + reg_or_cur, reg_or_new); + } + } + + /* configure the bank (force base address and GPCM) */ + reg_br_new &= ~(BR_BA | BR_MSEL); + reg_br_new |= fsl_lbc_addr(res.start) | BR_MS_GPCM | BR_V; + out_be32(&priv->lbc->bank[priv->bank].or, reg_or_new); + out_be32(&priv->lbc->bank[priv->bank].br, reg_br_new); + + /* map the memory resource */ + info->mem[0].internal_addr = ioremap(res.start, resource_size(&res)); + if (!info->mem[0].internal_addr) { + dev_err(priv->dev, "failed to map chip region\n"); + ret = -ENODEV; + goto out_err1; + } + + /* set all UIO data */ + if (node->name) + info->mem[0].name = kstrdup(node->name, GFP_KERNEL); + info->mem[0].addr = res.start; + info->mem[0].size = resource_size(&res); + info->mem[0].memtype = UIO_MEM_PHYS; + info->priv = priv; + info->name = uio_name; + info->version = "0.0.1"; + if (irq != NO_IRQ) { + if (priv->irq_handler) { + info->irq = irq; + info->irq_flags = IRQF_SHARED; + info->handler = priv->irq_handler; + } else { + irq = NO_IRQ; + dev_warn(priv->dev, "ignoring irq, no handler\n"); + } + } + + if (priv->init) + priv->init(info); + + /* register UIO device */ + if (uio_register_device(priv->dev, info) != 0) { + dev_err(priv->dev, "UIO registration failed\n"); + ret = -ENODEV; + goto out_err2; + } + + /* store private data */ + platform_set_drvdata(pdev, info); + + /* create sysfs files */ + ret = device_create_file(priv->dev, &dev_attr_reg_br); + if (ret) + goto out_err3; + ret = device_create_file(priv->dev, &dev_attr_reg_or); + if (ret) + goto out_err4; + + dev_info(priv->dev, + "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n", + priv->name, (unsigned long long)res.start, priv->bank, + irq != NO_IRQ ? irq : -1); + + return 0; +out_err4: + device_remove_file(priv->dev, &dev_attr_reg_br); +out_err3: + platform_set_drvdata(pdev, NULL); + uio_unregister_device(info); +out_err2: + if (priv->shutdown) + priv->shutdown(info, true); + iounmap(info->mem[0].internal_addr); +out_err1: + kfree(info->mem[0].name); + kfree(info); +out_err0: + kfree(uio_name); + kfree(priv); + return ret; +} + +static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev) +{ + struct uio_info *info = platform_get_drvdata(pdev); + struct fsl_elbc_gpcm *priv = info->priv; + + device_remove_file(priv->dev, &dev_attr_reg_or); + device_remove_file(priv->dev, &dev_attr_reg_br); + platform_set_drvdata(pdev, NULL); + uio_unregister_device(info); + if (priv->shutdown) + priv->shutdown(info, false); + iounmap(info->mem[0].internal_addr); + kfree(info->mem[0].name); + kfree(info->name); + kfree(info); + kfree(priv); + + return 0; + +} + +static const struct of_device_id uio_fsl_elbc_gpcm_match[] = { + { .compatible = "fsl,elbc-gpcm-uio", }, + {} +}; + +static struct platform_driver uio_fsl_elbc_gpcm_driver = { + .driver = { + .name = "fsl,elbc-gpcm-uio", + .owner = THIS_MODULE, + .of_match_table = uio_fsl_elbc_gpcm_match, + }, + .probe = uio_fsl_elbc_gpcm_probe, + .remove = uio_fsl_elbc_gpcm_remove, +}; + +static int __init uio_fsl_elbc_gpcm_init(void) +{ + return platform_driver_register(&uio_fsl_elbc_gpcm_driver); +} + +static void __exit uio_fsl_elbc_gpcm_exit(void) +{ + platform_driver_unregister(&uio_fsl_elbc_gpcm_driver); +} + +module_init(uio_fsl_elbc_gpcm_init); +module_exit(uio_fsl_elbc_gpcm_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Ogness "); +MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller GPCM driver"); From 6ad1095990328e7e4b3a0e260825ad4b6406785a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 9 Jan 2015 16:57:12 -0700 Subject: [PATCH 31/90] coresight-etm: unlock on error paths in mode_store() There are some missing unlocks on the error paths. Fixes: a939fc5a71ad ('coresight-etm: add CoreSight ETM/PTM driver') Signed-off-by: Dan Carpenter Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-etm3x.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/coresight/coresight-etm3x.c b/drivers/coresight/coresight-etm3x.c index d9e3ed6aa857..369cac00afaa 100644 --- a/drivers/coresight/coresight-etm3x.c +++ b/drivers/coresight/coresight-etm3x.c @@ -573,7 +573,8 @@ static ssize_t mode_store(struct device *dev, if (drvdata->mode & ETM_MODE_STALL) { if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) { dev_warn(drvdata->dev, "stall mode not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto err_unlock; } drvdata->ctrl |= ETMCR_STALL_MODE; } else @@ -582,7 +583,8 @@ static ssize_t mode_store(struct device *dev, if (drvdata->mode & ETM_MODE_TIMESTAMP) { if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) { dev_warn(drvdata->dev, "timestamp not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto err_unlock; } drvdata->ctrl |= ETMCR_TIMESTAMP_EN; } else @@ -595,6 +597,10 @@ static ssize_t mode_store(struct device *dev, spin_unlock(&drvdata->spinlock); return size; + +err_unlock: + spin_unlock(&drvdata->spinlock); + return ret; } static DEVICE_ATTR_RW(mode); From 52d6bbb9b06cac67ec3c016bc9758a1815022b2b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 9 Jan 2015 16:57:13 -0700 Subject: [PATCH 32/90] coresight-etb: use module_amba_driver to simplify the code module_amba_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Wei Yongjun Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-etb10.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/coresight/coresight-etb10.c b/drivers/coresight/coresight-etb10.c index c922d4aded8a..a1da7020201b 100644 --- a/drivers/coresight/coresight-etb10.c +++ b/drivers/coresight/coresight-etb10.c @@ -521,17 +521,7 @@ static struct amba_driver etb_driver = { .id_table = etb_ids, }; -static int __init etb_init(void) -{ - return amba_driver_register(&etb_driver); -} -module_init(etb_init); - -static void __exit etb_exit(void) -{ - amba_driver_unregister(&etb_driver); -} -module_exit(etb_exit); +module_amba_driver(etb_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver"); From a48f52e185f7f6da2c53f8dd4efda963c32b73f1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 9 Jan 2015 16:57:14 -0700 Subject: [PATCH 33/90] coresight-funnel: use module_amba_driver to simplify the code module_amba_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Wei Yongjun Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-funnel.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c index 2108edffe1f4..3db36f70b666 100644 --- a/drivers/coresight/coresight-funnel.c +++ b/drivers/coresight/coresight-funnel.c @@ -252,17 +252,7 @@ static struct amba_driver funnel_driver = { .id_table = funnel_ids, }; -static int __init funnel_init(void) -{ - return amba_driver_register(&funnel_driver); -} -module_init(funnel_init); - -static void __exit funnel_exit(void) -{ - amba_driver_unregister(&funnel_driver); -} -module_exit(funnel_exit); +module_amba_driver(funnel_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CoreSight Funnel driver"); From d2e580c272d19afff768b56dd0f5d2095cb5a07c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 9 Jan 2015 16:57:15 -0700 Subject: [PATCH 34/90] coresight-tmc: use module_amba_driver to simplify the code module_amba_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Wei Yongjun Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-tmc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c index ce2c293f1707..3ff232f9ddf7 100644 --- a/drivers/coresight/coresight-tmc.c +++ b/drivers/coresight/coresight-tmc.c @@ -760,17 +760,7 @@ static struct amba_driver tmc_driver = { .id_table = tmc_ids, }; -static int __init tmc_init(void) -{ - return amba_driver_register(&tmc_driver); -} -module_init(tmc_init); - -static void __exit tmc_exit(void) -{ - amba_driver_unregister(&tmc_driver); -} -module_exit(tmc_exit); +module_amba_driver(tmc_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver"); From 3ff7ca051a43bf2dfd1eebdd6c771c4b7a276d8e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 9 Jan 2015 16:57:16 -0700 Subject: [PATCH 35/90] coresight-tpiu: use module_amba_driver to simplify the code module_amba_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Wei Yongjun Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-tpiu.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c index ae101082791a..3b33af2416bb 100644 --- a/drivers/coresight/coresight-tpiu.c +++ b/drivers/coresight/coresight-tpiu.c @@ -201,17 +201,7 @@ static struct amba_driver tpiu_driver = { .id_table = tpiu_ids, }; -static int __init tpiu_init(void) -{ - return amba_driver_register(&tpiu_driver); -} -module_init(tpiu_init); - -static void __exit tpiu_exit(void) -{ - amba_driver_unregister(&tpiu_driver); -} -module_exit(tpiu_exit); +module_amba_driver(tpiu_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver"); From b2c09284bbfe36f9ba0e3e8bec8bb3c4789b3911 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 9 Jan 2015 16:57:17 -0700 Subject: [PATCH 36/90] coresight-etm: Fix initial trace ID value The coresight TRM specify that a component's trace ID should be other than 0. Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-etm3x.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/coresight/coresight-etm3x.c b/drivers/coresight/coresight-etm3x.c index 369cac00afaa..73c36696f1b6 100644 --- a/drivers/coresight/coresight-etm3x.c +++ b/drivers/coresight/coresight-etm3x.c @@ -1749,7 +1749,11 @@ static void etm_init_arch_data(void *info) static void etm_init_default_data(struct etm_drvdata *drvdata) { - static int etm3x_traceid; + /* + * A trace ID of value 0 is invalid, so let's start at some + * random value that fits in 7 bits and will be just as good. + */ + static int etm3x_traceid = 0x10; u32 flags = (1 << 0 | /* instruction execute*/ 3 << 3 | /* ARM instruction */ From f379984f849d729bd2eb076b633200b1c040611e Mon Sep 17 00:00:00 2001 From: Xia Kaixu Date: Fri, 9 Jan 2015 16:57:18 -0700 Subject: [PATCH 37/90] coresight: remove the unused macro CORESIGHT_DEBUGFS_ENTRY Debugfs isn't used for coresight configuration, so the macro CORESIGHT_DEBUGFS_ENTRY is unnecessary, just remove it. Signed-off-by: Xia Kaixu Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- include/linux/coresight.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 5d3c54311f7a..7cbfecbfa643 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -179,15 +179,6 @@ struct coresight_device { #define sink_ops(csdev) csdev->ops->sink_ops #define link_ops(csdev) csdev->ops->link_ops -#define CORESIGHT_DEBUGFS_ENTRY(__name, __entry_name, \ - __mode, __get, __set, __fmt) \ -DEFINE_SIMPLE_ATTRIBUTE(__name ## _ops, __get, __set, __fmt); \ -static const struct coresight_ops_entry __name ## _entry = { \ - .name = __entry_name, \ - .mode = __mode, \ - .ops = &__name ## _ops \ -} - /** * struct coresight_ops_sink - basic operations for a sink * Operations available for sinks From ff1e33b0c16ba422e3bf3fa8cc7e89b2c958e193 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Fri, 9 Jan 2015 16:57:19 -0700 Subject: [PATCH 38/90] coresight: fix typo in comment in of_coresight.c Debugfs isn't used for coresight configuration, so the corresponding comments should be changed. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/of_coresight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c index 5030c0734508..8bd524e49518 100644 --- a/drivers/coresight/of_coresight.c +++ b/drivers/coresight/of_coresight.c @@ -126,7 +126,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( if (!pdata) return ERR_PTR(-ENOMEM); - /* Use device name as debugfs handle */ + /* Use device name as sysfs handle */ pdata->name = dev_name(dev); /* Get the number of input and output port for this component */ From c61c4b5dd2c6b5dbf0f7e299db1e8411ef590f5c Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Fri, 9 Jan 2015 16:57:20 -0700 Subject: [PATCH 39/90] coresight: Fixing wrong #ifdef/#endif placement Fixing problem reported by: https://lkml.org/lkml/2015/1/6/86 The #ifdef/#endif is wrong and prevents the stub of function of_get_coresight_platform_data() from being visible when CONFIG_OF is not defined. Moving CONFIG_OF condition out of CONFIG_CORESIGHT, making them both independent. Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- include/linux/coresight.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 7cbfecbfa643..cd6d4c384ca3 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -230,10 +230,6 @@ extern void coresight_disable(struct coresight_device *csdev); extern int coresight_is_bit_set(u32 val, int position, int value); extern int coresight_timeout(void __iomem *addr, u32 offset, int position, int value); -#ifdef CONFIG_OF -extern struct coresight_platform_data *of_get_coresight_platform_data( - struct device *dev, struct device_node *node); -#endif #else static inline struct coresight_device * coresight_register(struct coresight_desc *desc) { return NULL; } @@ -245,10 +241,14 @@ static inline int coresight_is_bit_set(u32 val, int position, int value) { return 0; } static inline int coresight_timeout(void __iomem *addr, u32 offset, int position, int value) { return 1; } +#endif + #ifdef CONFIG_OF +extern struct coresight_platform_data *of_get_coresight_platform_data( + struct device *dev, struct device_node *node); +#else static inline struct coresight_platform_data *of_get_coresight_platform_data( struct device *dev, struct device_node *node) { return NULL; } #endif -#endif #endif From f7c55298f17f0bf9d257ea7f2f15cf920248db5b Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Fri, 9 Jan 2015 16:57:21 -0700 Subject: [PATCH 40/90] coresight: fix comment in of_coresight.c Outports is a member of the struct pdata and should be a better choice. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/of_coresight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c index 8bd524e49518..89ebbe29ac97 100644 --- a/drivers/coresight/of_coresight.c +++ b/drivers/coresight/of_coresight.c @@ -93,7 +93,7 @@ static int of_coresight_alloc_memory(struct device *dev, if (!pdata->outports) return -ENOMEM; - /* Children connected to this component via @outport */ + /* Children connected to this component via @outports */ pdata->child_names = devm_kzalloc(dev, pdata->nr_outport * sizeof(*pdata->child_names), GFP_KERNEL); From 2ccffaf92e7b7cc9dfa6c3458fc9cb151621680a Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Fri, 9 Jan 2015 16:57:22 -0700 Subject: [PATCH 41/90] coresight: fixing validity check on remote device A validity check should be made on the remote device, i.e rdev, rather than the current device. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/of_coresight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c index 89ebbe29ac97..9a5ff56f34d9 100644 --- a/drivers/coresight/of_coresight.c +++ b/drivers/coresight/of_coresight.c @@ -174,7 +174,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( continue; rdev = of_coresight_get_endpoint_device(rparent); - if (!dev) + if (!rdev) continue; pdata->child_names[i] = dev_name(rdev); From d885d4f3728f386034bb2f7a61b7f2054c49b2d4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Jan 2015 15:11:55 +0100 Subject: [PATCH 42/90] pcmcia: add missing include for new pci resource handler The recently added rsrc_pci.c file calls pci_bus_alloc_resource without including the header file that declares it, and that sometimes causes a build warning on ARM: drivers/pcmcia/rsrc_pci.c: In function 'find_io_region': drivers/pcmcia/rsrc_pci.c:40:2: error: implicit declaration of function 'pci_bus_alloc_resource' [-Werror=implicit-function-declaration] This adds the missing include statement. Signed-off-by: Arnd Bergmann Fixes: 02b03846bb2be ("pcmcia: add a new resource manager for non ISA systems") Acked-by: Alan Cox Reported-by: Jim Davis Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/rsrc_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c index 8934d3c01f80..21c3683b1a53 100644 --- a/drivers/pcmcia/rsrc_pci.c +++ b/drivers/pcmcia/rsrc_pci.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include From 79563db9ddd37908343103debf20da716ccc5ce4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Jan 2015 00:07:16 +0200 Subject: [PATCH 43/90] 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 | 19 +++-- drivers/misc/mei/debugfs.c | 30 +++++--- 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(-) 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" -struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, - const uuid_le *cuuid); -struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id); +/* + * 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 *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) { + list_for_each_entry_safe(me_cl, n, &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); + 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); From 79af73079d753b2d04e46f7445716d3b5f914dbd Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 21 Jan 2015 10:54:10 -0500 Subject: [PATCH 44/90] Add security hooks to binder and implement the hooks for SELinux. Add security hooks to the binder and implement the hooks for SELinux. The security hooks enable security modules such as SELinux to implement controls over binder IPC. The security hooks include support for controlling what process can become the binder context manager (binder_set_context_mgr), controlling the ability of a process to invoke a binder transaction/IPC to another process (binder_transaction), controlling the ability of a process to transfer a binder reference to another process (binder_transfer_binder), and controlling the ability of a process to transfer an open file to another process (binder_transfer_file). These hooks have been included in the Android kernel trees since Android 4.3. (Updated to reflect upstream relocation and changes to the binder driver, changes to the LSM audit data structures, coding style cleanups, and to add inline documentation for the hooks). Signed-off-by: Stephen Smalley Acked-by: Nick Kralevich Acked-by: Jeffrey Vander Stoep Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 26 ++++++++++ include/linux/security.h | 58 +++++++++++++++++++++++ security/capability.c | 27 +++++++++++ security/security.c | 23 +++++++++ security/selinux/hooks.c | 73 +++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 2 + 6 files changed, 209 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 8c43521d3f11..33b09b6568a4 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT #define BINDER_IPC_32BIT 1 @@ -1400,6 +1401,11 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_DEAD_REPLY; goto err_dead_binder; } + if (security_binder_transaction(proc->tsk, + target_proc->tsk) < 0) { + return_error = BR_FAILED_REPLY; + goto err_invalid_target_handle; + } if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; @@ -1551,6 +1557,11 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } + if (security_binder_transfer_binder(proc->tsk, + target_proc->tsk)) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_for_node_failed; + } ref = binder_get_ref_for_node(target_proc, node); if (ref == NULL) { return_error = BR_FAILED_REPLY; @@ -1581,6 +1592,11 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_binder_get_ref_failed; } + if (security_binder_transfer_binder(proc->tsk, + target_proc->tsk)) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_failed; + } if (ref->node->proc == target_proc) { if (fp->type == BINDER_TYPE_HANDLE) fp->type = BINDER_TYPE_BINDER; @@ -1638,6 +1654,13 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_fget_failed; } + if (security_binder_transfer_file(proc->tsk, + target_proc->tsk, + file) < 0) { + fput(file); + return_error = BR_FAILED_REPLY; + goto err_get_unused_fd_failed; + } target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); if (target_fd < 0) { fput(file); @@ -2675,6 +2698,9 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) ret = -EBUSY; goto out; } + ret = security_binder_set_context_mgr(proc->tsk); + if (ret < 0) + goto out; if (uid_valid(binder_context_mgr_uid)) { if (!uid_eq(binder_context_mgr_uid, curr_euid)) { pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n", diff --git a/include/linux/security.h b/include/linux/security.h index ba96471c11ba..a1b7dbd127ff 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1281,6 +1281,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @alter contains the flag indicating whether changes are to be made. * Return 0 if permission is granted. * + * @binder_set_context_mgr + * Check whether @mgr is allowed to be the binder context manager. + * @mgr contains the task_struct for the task being registered. + * Return 0 if permission is granted. + * @binder_transaction + * Check whether @from is allowed to invoke a binder transaction call + * to @to. + * @from contains the task_struct for the sending task. + * @to contains the task_struct for the receiving task. + * @binder_transfer_binder + * Check whether @from is allowed to transfer a binder reference to @to. + * @from contains the task_struct for the sending task. + * @to contains the task_struct for the receiving task. + * @binder_transfer_file + * Check whether @from is allowed to transfer @file to @to. + * @from contains the task_struct for the sending task. + * @file contains the struct file being transferred. + * @to contains the task_struct for the receiving task. + * * @ptrace_access_check: * Check permission before allowing the current process to trace the * @child process. @@ -1441,6 +1460,14 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) struct security_operations { char name[SECURITY_NAME_MAX + 1]; + int (*binder_set_context_mgr) (struct task_struct *mgr); + int (*binder_transaction) (struct task_struct *from, + struct task_struct *to); + int (*binder_transfer_binder) (struct task_struct *from, + struct task_struct *to); + int (*binder_transfer_file) (struct task_struct *from, + struct task_struct *to, struct file *file); + int (*ptrace_access_check) (struct task_struct *child, unsigned int mode); int (*ptrace_traceme) (struct task_struct *parent); int (*capget) (struct task_struct *target, @@ -1739,6 +1766,13 @@ extern void __init security_fixup_ops(struct security_operations *ops); /* Security operations */ +int security_binder_set_context_mgr(struct task_struct *mgr); +int security_binder_transaction(struct task_struct *from, + struct task_struct *to); +int security_binder_transfer_binder(struct task_struct *from, + struct task_struct *to); +int security_binder_transfer_file(struct task_struct *from, + struct task_struct *to, struct file *file); int security_ptrace_access_check(struct task_struct *child, unsigned int mode); int security_ptrace_traceme(struct task_struct *parent); int security_capget(struct task_struct *target, @@ -1927,6 +1961,30 @@ static inline int security_init(void) return 0; } +static inline int security_binder_set_context_mgr(struct task_struct *mgr) +{ + return 0; +} + +static inline int security_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static inline int security_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static inline int security_binder_transfer_file(struct task_struct *from, + struct task_struct *to, + struct file *file) +{ + return 0; +} + static inline int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { diff --git a/security/capability.c b/security/capability.c index d68c57a62bcf..070dd46f62f4 100644 --- a/security/capability.c +++ b/security/capability.c @@ -12,6 +12,29 @@ #include +static int cap_binder_set_context_mgr(struct task_struct *mgr) +{ + return 0; +} + +static int cap_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_file(struct task_struct *from, + struct task_struct *to, struct file *file) +{ + return 0; +} + static int cap_syslog(int type) { return 0; @@ -930,6 +953,10 @@ static void cap_audit_rule_free(void *lsmrule) void __init security_fixup_ops(struct security_operations *ops) { + set_to_cap_if_null(ops, binder_set_context_mgr); + set_to_cap_if_null(ops, binder_transaction); + set_to_cap_if_null(ops, binder_transfer_binder); + set_to_cap_if_null(ops, binder_transfer_file); set_to_cap_if_null(ops, ptrace_access_check); set_to_cap_if_null(ops, ptrace_traceme); set_to_cap_if_null(ops, capget); diff --git a/security/security.c b/security/security.c index 18b35c63fc0c..b196de34b19f 100644 --- a/security/security.c +++ b/security/security.c @@ -135,6 +135,29 @@ int __init register_security(struct security_operations *ops) /* Security operations */ +int security_binder_set_context_mgr(struct task_struct *mgr) +{ + return security_ops->binder_set_context_mgr(mgr); +} + +int security_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + return security_ops->binder_transaction(from, to); +} + +int security_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + return security_ops->binder_transfer_binder(from, to); +} + +int security_binder_transfer_file(struct task_struct *from, + struct task_struct *to, struct file *file) +{ + return security_ops->binder_transfer_file(from, to, file); +} + int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { #ifdef CONFIG_SECURITY_YAMA_STACKED diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6da7532893a1..9d984bfb978b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1933,6 +1933,74 @@ static inline u32 open_file_to_av(struct file *file) /* Hook functions begin here. */ +static int selinux_binder_set_context_mgr(struct task_struct *mgr) +{ + u32 mysid = current_sid(); + u32 mgrsid = task_sid(mgr); + + return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, + BINDER__SET_CONTEXT_MGR, NULL); +} + +static int selinux_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + u32 mysid = current_sid(); + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + int rc; + + if (mysid != fromsid) { + rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, + BINDER__IMPERSONATE, NULL); + if (rc) + return rc; + } + + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, + NULL); +} + +static int selinux_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, + NULL); +} + +static int selinux_binder_transfer_file(struct task_struct *from, + struct task_struct *to, + struct file *file) +{ + u32 sid = task_sid(to); + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file->f_path.dentry->d_inode; + struct inode_security_struct *isec = inode->i_security; + struct common_audit_data ad; + int rc; + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + return rc; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), + &ad); +} + static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { @@ -5810,6 +5878,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) static struct security_operations selinux_ops = { .name = "selinux", + .binder_set_context_mgr = selinux_binder_set_context_mgr, + .binder_transaction = selinux_binder_transaction, + .binder_transfer_binder = selinux_binder_transfer_binder, + .binder_transfer_file = selinux_binder_transfer_file, + .ptrace_access_check = selinux_ptrace_access_check, .ptrace_traceme = selinux_ptrace_traceme, .capget = selinux_capget, diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index be491a74c1ed..eccd61b3de8a 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -151,5 +151,7 @@ struct security_class_mapping secclass_map[] = { { "kernel_service", { "use_as_override", "create_files_as", NULL } }, { "tun_socket", { COMMON_SOCK_PERMS, "attach_queue", NULL } }, + { "binder", { "impersonate", "call", "set_context_mgr", "transfer", + NULL } }, { NULL } }; From 77ce247a8dbc587564dbfcb16fc6d09f6f85b31b Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 9 Jan 2015 22:18:52 -0800 Subject: [PATCH 45/90] Tools: hv: remove unused bytes_written from kvp_update_file() fwrite() does not actually return the number of bytes written and this value is being ignored anyway and ferror() is being called to check for an error. As we assign to this variable and never use it we get the following compile-time warning: hv_kvp_daemon.c:149:9: warning: variable .bytes_written. set but not used [-Wunused-but-set-variable] Remove bytes_written completely. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 4b3ee3521bde..fe790090f328 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -147,7 +147,6 @@ static void kvp_release_lock(int pool) static void kvp_update_file(int pool) { FILE *filep; - size_t bytes_written; /* * We are going to write our in-memory registry out to @@ -163,8 +162,7 @@ static void kvp_update_file(int pool) exit(EXIT_FAILURE); } - bytes_written = fwrite(kvp_file_info[pool].records, - sizeof(struct kvp_record), + fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record), kvp_file_info[pool].num_records, filep); if (ferror(filep) || fclose(filep)) { From 69258c058d0a7e0a6433dae7e336c316d28129fc Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 9 Jan 2015 22:18:53 -0800 Subject: [PATCH 46/90] Tools: hv: address compiler warnings for hv_kvp_daemon.c This patch addresses two types of compiler warnings: ... warning: comparison between signed and unsigned integer expressions [-Wsign-compare] and ... warning: pointer targets in passing argument N of .kvp_.... differ in signedness [-Wpointer-sign] Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index fe790090f328..408bb076a234 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -308,7 +308,7 @@ static int kvp_file_init(void) return 0; } -static int kvp_key_delete(int pool, const char *key, int key_size) +static int kvp_key_delete(int pool, const __u8 *key, int key_size) { int i; int j, k; @@ -351,8 +351,8 @@ static int kvp_key_delete(int pool, const char *key, int key_size) return 1; } -static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value, - int value_size) +static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size, + const __u8 *value, int value_size) { int i; int num_records; @@ -405,7 +405,7 @@ static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const return 0; } -static int kvp_get_value(int pool, const char *key, int key_size, char *value, +static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value, int value_size) { int i; @@ -437,8 +437,8 @@ static int kvp_get_value(int pool, const char *key, int key_size, char *value, return 1; } -static int kvp_pool_enumerate(int pool, int index, char *key, int key_size, - char *value, int value_size) +static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, + __u8 *value, int value_size) { struct kvp_record *record; @@ -659,7 +659,7 @@ static char *kvp_if_name_to_mac(char *if_name) char *p, *x; char buf[256]; char addr_file[256]; - int i; + unsigned int i; char *mac_addr = NULL; snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/", @@ -698,7 +698,7 @@ static char *kvp_mac_to_if_name(char *mac) char buf[256]; char *kvp_net_dir = "/sys/class/net/"; char dev_id[256]; - int i; + unsigned int i; dir = opendir(kvp_net_dir); if (dir == NULL) @@ -748,7 +748,7 @@ static char *kvp_mac_to_if_name(char *mac) static void kvp_process_ipconfig_file(char *cmd, - char *config_buf, int len, + char *config_buf, unsigned int len, int element_size, int offset) { char buf[256]; @@ -766,7 +766,7 @@ static void kvp_process_ipconfig_file(char *cmd, if (offset == 0) memset(config_buf, 0, len); while ((p = fgets(buf, sizeof(buf), file)) != NULL) { - if ((len - strlen(config_buf)) < (element_size + 1)) + if (len < strlen(config_buf) + element_size + 1) break; x = strchr(p, '\n'); @@ -914,7 +914,7 @@ static int kvp_process_ip_address(void *addrp, static int kvp_get_ip_info(int family, char *if_name, int op, - void *out_buffer, int length) + void *out_buffer, unsigned int length) { struct ifaddrs *ifap; struct ifaddrs *curp; @@ -1017,8 +1017,7 @@ kvp_get_ip_info(int family, char *if_name, int op, weight += hweight32(&w[i]); sprintf(cidr_mask, "/%d", weight); - if ((length - sn_offset) < - (strlen(cidr_mask) + 1)) + if (length < sn_offset + strlen(cidr_mask) + 1) goto gather_ipaddr; if (sn_offset == 0) From aba474b8185d60ca8cdbf3049fe6d655aa761e23 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 9 Jan 2015 22:18:54 -0800 Subject: [PATCH 47/90] Tools: hv: address compiler warnings for hv_fcopy_daemon.c This patch addresses two types of compiler warnings: ... warning: unused variable .fd. [-Wunused-variable] and ... warning: format .%s. expects argument of type .char *., but argument 5 has type .__u16 *. [-Wformat=] Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_fcopy_daemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index f437d739f37d..1a238726dda6 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -51,7 +51,7 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg) p = (char *)smsg->path_name; snprintf(target_fname, sizeof(target_fname), "%s/%s", - (char *)smsg->path_name, smsg->file_name); + (char *)smsg->path_name, (char *)smsg->file_name); syslog(LOG_INFO, "Target file name: %s", target_fname); /* @@ -137,7 +137,7 @@ void print_usage(char *argv[]) int main(int argc, char *argv[]) { - int fd, fcopy_fd, len; + int fcopy_fd, len; int error; int daemonize = 1, long_index = 0, opt; int version = FCOPY_CURRENT_VERSION; From c1136da62170465920eea1ae9ba9ce2234091f77 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 9 Jan 2015 22:18:55 -0800 Subject: [PATCH 48/90] Tools: hv: do not add redundant '/' in hv_start_fcopy() We don't need to add additional '/' to smsg->path_name as snprintf("%s/%s") does the right thing. Without the patch we get doubled '//' in the log message. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_fcopy_daemon.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index 1a238726dda6..9445d8f264a4 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -43,12 +43,6 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg) int error = HV_E_FAIL; char *q, *p; - /* - * If possile append a path seperator to the path. - */ - if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2)) - strcat((char *)smsg->path_name, "/"); - p = (char *)smsg->path_name; snprintf(target_fname, sizeof(target_fname), "%s/%s", (char *)smsg->path_name, (char *)smsg->file_name); From 79208c57da5311860f165b613c89b3f647e357cd Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:29 -0800 Subject: [PATCH 49/90] Drivers: hv: hv_balloon: Make adjustments in computing the floor Make adjustments in computing the balloon floor. The current computation of the balloon floor was not appropriate for virtual machines with more than 10 GB of assigned memory - we would get into situations where the host would agressively balloon down the guest and leave the guest in an unusable state. This patch fixes the issue by raising the floor. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_balloon.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index b958ded8ac7e..9cbbb831778a 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -928,9 +928,8 @@ static unsigned long compute_balloon_floor(void) * 128 72 (1/2) * 512 168 (1/4) * 2048 360 (1/8) - * 8192 552 (1/32) - * 32768 1320 - * 131072 4392 + * 8192 768 (1/16) + * 32768 1536 (1/32) */ if (totalram_pages < MB2PAGES(128)) min_pages = MB2PAGES(8) + (totalram_pages >> 1); @@ -938,8 +937,10 @@ static unsigned long compute_balloon_floor(void) min_pages = MB2PAGES(40) + (totalram_pages >> 2); else if (totalram_pages < MB2PAGES(2048)) min_pages = MB2PAGES(104) + (totalram_pages >> 3); + else if (totalram_pages < MB2PAGES(8192)) + min_pages = MB2PAGES(256) + (totalram_pages >> 4); else - min_pages = MB2PAGES(296) + (totalram_pages >> 5); + min_pages = MB2PAGES(512) + (totalram_pages >> 5); #undef MB2PAGES return min_pages; } From 22f88475b62ac826acae2f77c3e1bd9543e87b2a Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:30 -0800 Subject: [PATCH 50/90] Drivers: hv: hv_balloon: Fix a locking bug in the balloon driver We support memory hot-add in the Hyper-V balloon driver by hot adding an appropriately sized and aligned region and controlling the on-lining of pages within that region based on the pages that the host wants us to online. We do this because the granularity and alignment requirements in Linux are different from what Windows expects. The state to manage the onlining of pages needs to be correctly protected. Fix this bug. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_balloon.c | 68 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 9cbbb831778a..8e30415b0eb7 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -533,6 +533,9 @@ struct hv_dynmem_device { */ struct task_struct *thread; + struct mutex ha_region_mutex; + struct completion waiter_event; + /* * A list of hot-add regions. */ @@ -549,7 +552,59 @@ struct hv_dynmem_device { static struct hv_dynmem_device dm_device; static void post_status(struct hv_dynmem_device *dm); + #ifdef CONFIG_MEMORY_HOTPLUG +static void acquire_region_mutex(bool trylock) +{ + if (trylock) { + reinit_completion(&dm_device.waiter_event); + while (!mutex_trylock(&dm_device.ha_region_mutex)) + wait_for_completion(&dm_device.waiter_event); + } else { + mutex_lock(&dm_device.ha_region_mutex); + } +} + +static void release_region_mutex(bool trylock) +{ + if (trylock) { + mutex_unlock(&dm_device.ha_region_mutex); + } else { + mutex_unlock(&dm_device.ha_region_mutex); + complete(&dm_device.waiter_event); + } +} + +static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, + void *v) +{ + switch (val) { + case MEM_GOING_ONLINE: + acquire_region_mutex(true); + break; + + case MEM_ONLINE: + case MEM_CANCEL_ONLINE: + release_region_mutex(true); + if (dm_device.ha_waiting) { + dm_device.ha_waiting = false; + complete(&dm_device.ol_waitevent); + } + break; + + case MEM_GOING_OFFLINE: + case MEM_OFFLINE: + case MEM_CANCEL_OFFLINE: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block hv_memory_nb = { + .notifier_call = hv_memory_notifier, + .priority = 0 +}; + static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size) { @@ -591,6 +646,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, init_completion(&dm_device.ol_waitevent); dm_device.ha_waiting = true; + release_region_mutex(false); nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn)); ret = add_memory(nid, PFN_PHYS((start_pfn)), (HA_CHUNK << PAGE_SHIFT)); @@ -619,6 +675,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, * have not been "onlined" within the allowed time. */ wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ); + acquire_region_mutex(false); post_status(&dm_device); } @@ -632,11 +689,6 @@ static void hv_online_page(struct page *pg) unsigned long cur_start_pgp; unsigned long cur_end_pgp; - if (dm_device.ha_waiting) { - dm_device.ha_waiting = false; - complete(&dm_device.ol_waitevent); - } - list_for_each(cur, &dm_device.ha_region_list) { has = list_entry(cur, struct hv_hotadd_state, list); cur_start_pgp = (unsigned long) @@ -834,6 +886,7 @@ static void hot_add_req(struct work_struct *dummy) resp.hdr.size = sizeof(struct dm_hot_add_response); #ifdef CONFIG_MEMORY_HOTPLUG + acquire_region_mutex(false); pg_start = dm->ha_wrk.ha_page_range.finfo.start_page; pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt; @@ -865,6 +918,7 @@ static void hot_add_req(struct work_struct *dummy) if (do_hot_add) resp.page_count = process_hot_add(pg_start, pfn_cnt, rg_start, rg_sz); + release_region_mutex(false); #endif /* * The result field of the response structure has the @@ -1388,7 +1442,9 @@ static int balloon_probe(struct hv_device *dev, dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7; init_completion(&dm_device.host_event); init_completion(&dm_device.config_event); + init_completion(&dm_device.waiter_event); INIT_LIST_HEAD(&dm_device.ha_region_list); + mutex_init(&dm_device.ha_region_mutex); INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up); INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req); dm_device.host_specified_ha_region = false; @@ -1402,6 +1458,7 @@ static int balloon_probe(struct hv_device *dev, #ifdef CONFIG_MEMORY_HOTPLUG set_online_page_callback(&hv_online_page); + register_memory_notifier(&hv_memory_nb); #endif hv_set_drvdata(dev, &dm_device); @@ -1520,6 +1577,7 @@ static int balloon_remove(struct hv_device *dev) kfree(send_buffer); #ifdef CONFIG_MEMORY_HOTPLUG restore_online_page_callback(&hv_online_page); + unregister_memory_notifier(&hv_memory_nb); #endif list_for_each_safe(cur, tmp, &dm->ha_region_list) { has = list_entry(cur, struct hv_hotadd_state, list); From ab3de22bb4a3d4bda2d0ec8bebcb76a40f1cbf9b Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:31 -0800 Subject: [PATCH 51/90] Drivers: hv: hv_balloon: Don't post pressure status from interrupt context We currently release memory (balloon down) in the interrupt context and we also post memory status while releasing memory. Rather than posting the status in the interrupt context, wakeup the status posting thread to post the status. This will address the inconsistent lock state that Sitsofe Wheeler reported: http://lkml.iu.edu/hypermail/linux/kernel/1411.1/00075.html Signed-off-by: K. Y. Srinivasan Reported-by: Sitsofe Wheeler Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_balloon.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 8e30415b0eb7..ff169386b2c7 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1226,7 +1226,7 @@ static void balloon_down(struct hv_dynmem_device *dm, for (i = 0; i < range_count; i++) { free_balloon_pages(dm, &range_array[i]); - post_status(&dm_device); + complete(&dm_device.config_event); } if (req->more_pages == 1) @@ -1250,19 +1250,16 @@ static void balloon_onchannelcallback(void *context); static int dm_thread_func(void *dm_dev) { struct hv_dynmem_device *dm = dm_dev; - int t; while (!kthread_should_stop()) { - t = wait_for_completion_interruptible_timeout( + wait_for_completion_interruptible_timeout( &dm_device.config_event, 1*HZ); /* * The host expects us to post information on the memory * pressure every second. */ - - if (t == 0) - post_status(dm); - + reinit_completion(&dm_device.config_event); + post_status(dm); } return 0; From 4061ed9e2aaac31daef44f06e9b83143c78b24b2 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:32 -0800 Subject: [PATCH 52/90] Drivers: hv: vmbus: Implement a clockevent device Implement a clockevent device based on the timer support available on Hyper-V. In this version of the patch I have addressed Jason's review comments. Signed-off-by: K. Y. Srinivasan Reviewed-by: Jason Wang Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/uapi/asm/hyperv.h | 11 +++++ drivers/hv/hv.c | 78 ++++++++++++++++++++++++++++++ drivers/hv/hyperv_vmbus.h | 21 ++++++++ drivers/hv/vmbus_drv.c | 37 +++++++++++++- 4 files changed, 145 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 462efe746d77..90c458e66e13 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -187,6 +187,17 @@ #define HV_X64_MSR_SINT14 0x4000009E #define HV_X64_MSR_SINT15 0x4000009F +/* + * Synthetic Timer MSRs. Four timers per vcpu. + */ +#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0 +#define HV_X64_MSR_STIMER0_COUNT 0x400000B1 +#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2 +#define HV_X64_MSR_STIMER1_COUNT 0x400000B3 +#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4 +#define HV_X64_MSR_STIMER2_COUNT 0x400000B5 +#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 +#define HV_X64_MSR_STIMER3_COUNT 0x400000B7 #define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12 diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 3e4235c7a47f..50e51a51ff8b 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include #include "hyperv_vmbus.h" /* The one and only */ @@ -37,6 +39,10 @@ struct hv_context hv_context = { .hypercall_page = NULL, }; +#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */ +#define HV_MAX_MAX_DELTA_TICKS 0xffffffff +#define HV_MIN_DELTA_TICKS 1 + /* * query_hypervisor_info - Get version info of the windows hypervisor */ @@ -144,6 +150,8 @@ int hv_init(void) sizeof(int) * NR_CPUS); memset(hv_context.event_dpc, 0, sizeof(void *) * NR_CPUS); + memset(hv_context.clk_evt, 0, + sizeof(void *) * NR_CPUS); max_leaf = query_hypervisor_info(); @@ -258,10 +266,63 @@ u16 hv_signal_event(void *con_id) return status; } +static int hv_ce_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + cycle_t current_tick; + + WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT); + + rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); + current_tick += delta; + wrmsrl(HV_X64_MSR_STIMER0_COUNT, current_tick); + return 0; +} + +static void hv_ce_setmode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + union hv_timer_config timer_cfg; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* unsupported */ + break; + + case CLOCK_EVT_MODE_ONESHOT: + timer_cfg.enable = 1; + timer_cfg.auto_enable = 1; + timer_cfg.sintx = VMBUS_MESSAGE_SINT; + wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0); + wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0); + break; + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu) +{ + dev->name = "Hyper-V clockevent"; + dev->features = CLOCK_EVT_FEAT_ONESHOT; + dev->cpumask = cpumask_of(cpu); + dev->rating = 1000; + dev->owner = THIS_MODULE; + + dev->set_mode = hv_ce_setmode; + dev->set_next_event = hv_ce_set_next_event; +} + int hv_synic_alloc(void) { size_t size = sizeof(struct tasklet_struct); + size_t ced_size = sizeof(struct clock_event_device); int cpu; for_each_online_cpu(cpu) { @@ -272,6 +333,13 @@ int hv_synic_alloc(void) } tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu); + hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC); + if (hv_context.clk_evt[cpu] == NULL) { + pr_err("Unable to allocate clock event device\n"); + goto err; + } + hv_init_clockevent_device(hv_context.clk_evt[cpu], cpu); + hv_context.synic_message_page[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); @@ -305,6 +373,7 @@ err: static void hv_synic_free_cpu(int cpu) { kfree(hv_context.event_dpc[cpu]); + kfree(hv_context.clk_evt[cpu]); if (hv_context.synic_event_page[cpu]) free_page((unsigned long)hv_context.synic_event_page[cpu]); if (hv_context.synic_message_page[cpu]) @@ -388,6 +457,15 @@ void hv_synic_init(void *arg) hv_context.vp_index[cpu] = (u32)vp_index; INIT_LIST_HEAD(&hv_context.percpu_list[cpu]); + + /* + * Register the per-cpu clockevent source. + */ + if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE) + clockevents_config_and_register(hv_context.clk_evt[cpu], + HV_TIMER_FREQUENCY, + HV_MIN_DELTA_TICKS, + HV_MAX_MAX_DELTA_TICKS); return; } diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index c386d8dc7223..44b1c9424712 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -178,6 +178,23 @@ struct hv_message_header { }; }; +/* + * Timer configuration register. + */ +union hv_timer_config { + u64 as_uint64; + struct { + u64 enable:1; + u64 periodic:1; + u64 lazy:1; + u64 auto_enable:1; + u64 reserved_z0:12; + u64 sintx:4; + u64 reserved_z1:44; + }; +}; + + /* Define timer message payload structure. */ struct hv_timer_message_payload { u32 timer_index; @@ -519,6 +536,10 @@ struct hv_context { * buffer to post messages to the host. */ void *post_msg_page[NR_CPUS]; + /* + * Support PV clockevent device. + */ + struct clock_event_device *clk_evt[NR_CPUS]; }; extern struct hv_context hv_context; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4d6b26979fbd..7488111ec057 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -578,6 +579,34 @@ static void vmbus_onmessage_work(struct work_struct *work) kfree(ctx); } +void hv_process_timer_expiration(struct hv_message *msg, int cpu) +{ + struct clock_event_device *dev = hv_context.clk_evt[cpu]; + + if (dev->event_handler) + dev->event_handler(dev); + + msg->header.message_type = HVMSG_NONE; + + /* + * Make sure the write to MessageType (ie set to + * HVMSG_NONE) happens before we read the + * MessagePending and EOMing. Otherwise, the EOMing + * will not deliver any more messages since there is + * no empty slot + */ + mb(); + + if (msg->header.message_flags.msg_pending) { + /* + * This will cause message queue rescan to + * possibly deliver another msg from the + * hypervisor + */ + wrmsrl(HV_X64_MSR_EOM, 0); + } +} + static void vmbus_on_msg_dpc(unsigned long data) { int cpu = smp_processor_id(); @@ -667,8 +696,12 @@ static void vmbus_isr(void) msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; /* Check if there are actual msgs to be processed */ - if (msg->header.message_type != HVMSG_NONE) - tasklet_schedule(&msg_dpc); + if (msg->header.message_type != HVMSG_NONE) { + if (msg->header.message_type == HVMSG_TIMER_EXPIRED) + hv_process_timer_expiration(msg, cpu); + else + tasklet_schedule(&msg_dpc); + } } /* From 9f52a1630922bcdab75fc72e59ed58db8e164314 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:33 -0800 Subject: [PATCH 53/90] Drivers: hv: vmbus: Fix a bug in vmbus_establish_gpadl() Correctly compute the local (gpadl) handle. I would like to thank Michael Brown for seeing this bug. Signed-off-by: K. Y. Srinivasan Reported-by: Michael Brown Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 433f72a1c006..c76ffbe59f65 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -366,8 +366,8 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, unsigned long flags; int ret = 0; - next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle); - atomic_inc(&vmbus_connection.next_gpadl_handle); + next_gpadl_handle = + (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount); if (ret) From d61031ee8df6214d58371a1cc36a0591e242fba0 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 9 Jan 2015 23:54:34 -0800 Subject: [PATCH 54/90] Drivers: hv: vmbus: Support a vmbus API for efficiently sending page arrays Currently, the API for sending a multi-page buffer over VMBUS is limited to a maximum pfn array of MAX_MULTIPAGE_BUFFER_COUNT. This limitation is not imposed by the host and unnecessarily limits the maximum payload that can be sent. Implement an API that does not have this restriction. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 44 ++++++++++++++++++++++++++++++++++++++++++ include/linux/hyperv.h | 31 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index c76ffbe59f65..18c4f23dacf1 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -683,6 +683,50 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, } EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); +/* + * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet + * using a GPADL Direct packet type. + * The buffer includes the vmbus descriptor. + */ +int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *desc, + u32 desc_size, + void *buffer, u32 bufferlen, u64 requestid) +{ + int ret; + u32 packetlen; + u32 packetlen_aligned; + struct kvec bufferlist[3]; + u64 aligned_data = 0; + bool signal = false; + + packetlen = desc_size + bufferlen; + packetlen_aligned = ALIGN(packetlen, sizeof(u64)); + + /* Setup the descriptor */ + desc->type = VM_PKT_DATA_USING_GPA_DIRECT; + desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; + desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */ + desc->length8 = (u16)(packetlen_aligned >> 3); + desc->transactionid = requestid; + desc->rangecount = 1; + + bufferlist[0].iov_base = desc; + bufferlist[0].iov_len = desc_size; + bufferlist[1].iov_base = buffer; + bufferlist[1].iov_len = bufferlen; + bufferlist[2].iov_base = &aligned_data; + bufferlist[2].iov_len = (packetlen_aligned - packetlen); + + ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); + + if (ret == 0 && signal) + vmbus_setevent(channel); + + return ret; +} +EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc); + /* * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet * using a GPADL Direct packet type. diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 476c685ca6f9..259023a34bec 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -57,6 +57,18 @@ struct hv_multipage_buffer { u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT]; }; +/* + * Multiple-page buffer array; the pfn array is variable size: + * The number of entries in the PFN array is determined by + * "len" and "offset". + */ +struct hv_mpb_array { + /* Length and Offset determines the # of pfns in the array */ + u32 len; + u32 offset; + u64 pfn_array[]; +}; + /* 0x18 includes the proprietary packet header */ #define MAX_PAGE_BUFFER_PACKET (0x18 + \ (sizeof(struct hv_page_buffer) * \ @@ -814,6 +826,18 @@ struct vmbus_channel_packet_multipage_buffer { struct hv_multipage_buffer range; } __packed; +/* The format must be the same as struct vmdata_gpa_direct */ +struct vmbus_packet_mpb_array { + u16 type; + u16 dataoffset8; + u16 length8; + u16 flags; + u64 transactionid; + u32 reserved; + u32 rangecount; /* Always 1 in this case */ + struct hv_mpb_array range; +} __packed; + extern int vmbus_open(struct vmbus_channel *channel, u32 send_ringbuffersize, @@ -845,6 +869,13 @@ extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, u32 bufferlen, u64 requestid); +extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, + struct vmbus_packet_mpb_array *mpb, + u32 desc_size, + void *buffer, + u32 bufferlen, + u64 requestid); + extern int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, u32 size, From d9b1652947c695d247b5e4603a16213ec55661ed Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 14 Jan 2015 01:55:10 -0800 Subject: [PATCH 55/90] hv: hv_fcopy: drop the obsolete message on transfer failure In the case the user-space daemon crashes, hangs or is killed, we need to down the semaphore, otherwise, after the daemon starts next time, the obsolete data in fcopy_transaction.message or fcopy_transaction.fcopy_msg will be used immediately. Cc: Jason Wang Cc: Vitaly Kuznetsov Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_fcopy.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index 23b2ce294c4c..cd453e4b2a07 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -86,6 +86,18 @@ static void fcopy_work_func(struct work_struct *dummy) * process the pending transaction. */ fcopy_respond_to_host(HV_E_FAIL); + + /* In the case the user-space daemon crashes, hangs or is killed, we + * need to down the semaphore, otherwise, after the daemon starts next + * time, the obsolete data in fcopy_transaction.message or + * fcopy_transaction.fcopy_msg will be used immediately. + * + * NOTE: fcopy_read() happens to get the semaphore (very rare)? We're + * still OK, because we've reported the failure to the host. + */ + if (down_trylock(&fcopy_transaction.read_sema)) + ; + } static int fcopy_handle_handshake(u32 version) @@ -344,6 +356,14 @@ static int fcopy_open(struct inode *inode, struct file *f) return 0; } +/* XXX: there are still some tricky corner cases, e.g., + * 1) In a SMP guest, when fcopy_release() runs between + * schedule_delayed_work() and fcopy_send_data(), there is + * still a chance an obsolete message will be queued. + * + * 2) When the fcopy daemon is running, if we unload the driver, + * we'll notice a kernel oops when we kill the daemon later. + */ static int fcopy_release(struct inode *inode, struct file *f) { /* @@ -351,6 +371,13 @@ static int fcopy_release(struct inode *inode, struct file *f) */ in_hand_shake = true; opened = false; + + if (cancel_delayed_work_sync(&fcopy_work)) { + /* We haven't up()-ed the semaphore(very rare)? */ + if (down_trylock(&fcopy_transaction.read_sema)) + ; + fcopy_respond_to_host(HV_E_FAIL); + } return 0; } From 5114b474cbb464e7a5da4ba5cdc551e798395151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:31:57 +0100 Subject: [PATCH 56/90] i8k: Add support for temperature sensor labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds labels for temperature sensors if SMM function with EAX register 0x11a3 reports it. This information was taken from DOS binary NBSVC.MDM. Signed-off-by: Pali Rohár Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Tested-by: Pali Rohár Tested-by: Steven Honeyman Tested-by: Gabriele Mazzotta Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 76 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index e34a019eb930..663868b2adc4 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -42,6 +42,7 @@ #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 #define I8K_SMM_GET_TEMP 0x10a3 +#define I8K_SMM_GET_TEMP_TYPE 0x11a3 #define I8K_SMM_GET_DELL_SIG1 0xfea3 #define I8K_SMM_GET_DELL_SIG2 0xffa3 @@ -288,6 +289,14 @@ static int i8k_set_fan(int fan, int speed) return i8k_smm(®s) ? : i8k_get_fan_status(fan); } +static int i8k_get_temp_type(int sensor) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, }; + + regs.ebx = sensor & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; +} + /* * Read the cpu temperature. */ @@ -493,6 +502,29 @@ static int i8k_open_fs(struct inode *inode, struct file *file) * Hwmon interface */ +static ssize_t i8k_hwmon_show_temp_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + static const char * const labels[] = { + "CPU", + "GPU", + "SODIMM", + "Other", + "Ambient", + "Other", + }; + int index = to_sensor_dev_attr(devattr)->index; + int type; + + type = i8k_get_temp_type(index); + if (type < 0) + return type; + if (type >= ARRAY_SIZE(labels)) + type = ARRAY_SIZE(labels) - 1; + return sprintf(buf, "%s\n", labels[type]); +} + static ssize_t i8k_hwmon_show_temp(struct device *dev, struct device_attribute *devattr, char *buf) @@ -555,9 +587,17 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev, } static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 2); static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 3); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, I8K_FAN_LEFT); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, @@ -569,31 +609,39 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ - &sensor_dev_attr_temp2_input.dev_attr.attr, /* 1 */ - &sensor_dev_attr_temp3_input.dev_attr.attr, /* 2 */ - &sensor_dev_attr_temp4_input.dev_attr.attr, /* 3 */ - &sensor_dev_attr_fan1_input.dev_attr.attr, /* 4 */ - &sensor_dev_attr_pwm1.dev_attr.attr, /* 5 */ - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 6 */ - &sensor_dev_attr_pwm2.dev_attr.attr, /* 7 */ + &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ + &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ + &sensor_dev_attr_temp2_label.dev_attr.attr, /* 3 */ + &sensor_dev_attr_temp3_input.dev_attr.attr, /* 4 */ + &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */ + &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ + &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ + &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ + &sensor_dev_attr_pwm1.dev_attr.attr, /* 9 */ + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 10 */ + &sensor_dev_attr_pwm2.dev_attr.attr, /* 11 */ NULL }; static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) + if (index >= 0 && index <= 1 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) return 0; - if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) - return 0; - if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) - return 0; - if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) + if (index >= 2 && index <= 3 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) return 0; if (index >= 4 && index <= 5 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) return 0; if (index >= 6 && index <= 7 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) + return 0; + if (index >= 8 && index <= 9 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) + return 0; + if (index >= 10 && index <= 11 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) return 0; From 672af223305791c3a814ec8c4fb841dc75277f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:31:58 +0100 Subject: [PATCH 57/90] i8k: Register only temperature sensors which have labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect presense of sensor by calling type function instead trying to read temperature value. Type function is working also for sensors which are temporary turned off (e.g on GPU which is turned off). Dell DOS binary NBSVC.MDM is doing similar checks, so we should do that too. Signed-off-by: Pali Rohár Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 663868b2adc4..afcc9fe084dc 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -660,19 +660,19 @@ static int __init i8k_init_hwmon(void) i8k_hwmon_flags = 0; - /* CPU temperature attributes, if temperature reading is OK */ - err = i8k_get_temp(0); - if (err >= 0 || err == -ERANGE) + /* CPU temperature attributes, if temperature type is OK */ + err = i8k_get_temp_type(0); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1; /* check for additional temperature sensors */ - err = i8k_get_temp(1); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(1); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; - err = i8k_get_temp(2); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(2); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; - err = i8k_get_temp(3); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(3); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; /* Left fan attributes, if left fan is present */ From 83d514d76278e85cc74c472dd51687c8eb4faff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:31:59 +0100 Subject: [PATCH 58/90] i8k: Return -ENODATA for invalid temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guenter Roeck suggested to return -ENODATA instead -ERANGE or -EINVAL when BIOS reports invalid temperature value. Signed-off-by: Pali Rohár Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index afcc9fe084dc..1854faba8ae6 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -331,7 +331,7 @@ static int i8k_get_temp(int sensor) prev[sensor] = temp; } if (temp > I8K_MAX_TEMP) - return -ERANGE; + return -ENODATA; #endif return temp; @@ -533,8 +533,6 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev, int temp; temp = i8k_get_temp(index); - if (temp == -ERANGE) - return -EINVAL; if (temp < 0) return temp; return sprintf(buf, "%d\n", temp * 1000); From 564132d9d62b3151dc6573da794378b5bf0cea17 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 Jan 2015 14:32:00 +0100 Subject: [PATCH 59/90] i8k: Rework error retries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of returning a previous value if the SMM code returns an error when trying to read a temperature, retry once. If that fails again, return -ENODATA. Also return -ENODATA if an attempt is made to read the GPU temperature but the GPU is currently turned off. Drop the I8K_TEMPERATURE_BUG definition and handle the related bug unconditionally. Signed-off-by: Guenter Roeck Tested-by: Pali Rohár Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 49 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 1854faba8ae6..0e332fcd8fc3 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -5,7 +5,7 @@ * * Hwmon integration: * Copyright (C) 2011 Jean Delvare - * Copyright (C) 2013 Guenter Roeck + * Copyright (C) 2013, 2014 Guenter Roeck * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,6 +20,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -59,8 +60,6 @@ #define I8K_POWER_AC 0x05 #define I8K_POWER_BATTERY 0x01 -#define I8K_TEMPERATURE_BUG 1 - static DEFINE_MUTEX(i8k_mutex); static char bios_version[4]; static struct device *i8k_hwmon_dev; @@ -300,39 +299,41 @@ static int i8k_get_temp_type(int sensor) /* * Read the cpu temperature. */ +static int _i8k_get_temp(int sensor) +{ + struct smm_regs regs = { + .eax = I8K_SMM_GET_TEMP, + .ebx = sensor & 0xff, + }; + + return i8k_smm(®s) ? : regs.eax & 0xff; +} + static int i8k_get_temp(int sensor) { - struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; - int rc; - int temp; + int temp = _i8k_get_temp(sensor); -#ifdef I8K_TEMPERATURE_BUG - static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 }; -#endif - regs.ebx = sensor & 0xff; - rc = i8k_smm(®s); - if (rc < 0) - return rc; - - temp = regs.eax & 0xff; - -#ifdef I8K_TEMPERATURE_BUG /* * Sometimes the temperature sensor returns 0x99, which is out of range. - * In this case we return (once) the previous cached value. For example: + * In this case we retry (once) before returning an error. # 1003655137 00000058 00005a4b # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees # 1003655139 00000054 00005c52 */ - if (temp > I8K_MAX_TEMP) { - temp = prev[sensor]; - prev[sensor] = I8K_MAX_TEMP+1; - } else { - prev[sensor] = temp; + if (temp == 0x99) { + msleep(100); + temp = _i8k_get_temp(sensor); } + /* + * Return -ENODATA for all invalid temperatures. + * + * Known instances are the 0x99 value as seen above as well as + * 0xc1 (193), which may be returned when trying to read the GPU + * temperature if the system supports a GPU and it is currently + * turned off. + */ if (temp > I8K_MAX_TEMP) return -ENODATA; -#endif return temp; } From 34ae40f6c91c2267af1dd3c0495082e8b9f9969e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 12 Jan 2015 14:32:01 +0100 Subject: [PATCH 60/90] i8k: Add support for Dell XPS 13 XPS 13 does not support turbo speed, so its initialization data matches that of XPS M140. Make XPS initialization data generic, and add support for XPS 13. Signed-off-by: Guenter Roeck Reviewed-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 0e332fcd8fc3..8ec4c371dc50 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -705,7 +705,7 @@ enum i8k_configs { DELL_LATITUDE_E6540, DELL_PRECISION_490, DELL_STUDIO, - DELL_XPS_M140, + DELL_XPS, }; static const struct i8k_config_data i8k_config_data[] = { @@ -725,7 +725,7 @@ static const struct i8k_config_data i8k_config_data[] = { .fan_mult = 1, .fan_max = I8K_FAN_HIGH, }, - [DELL_XPS_M140] = { + [DELL_XPS] = { .fan_mult = 1, .fan_max = I8K_FAN_HIGH, }, @@ -836,13 +836,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { }, .driver_data = (void *)&i8k_config_data[DELL_STUDIO], }, + { + .ident = "Dell XPS 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"), + }, + .driver_data = (void *)&i8k_config_data[DELL_XPS], + }, { .ident = "Dell XPS M140", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), }, - .driver_data = (void *)&i8k_config_data[DELL_XPS_M140], + .driver_data = (void *)&i8k_config_data[DELL_XPS], }, { } }; From 7f69fb033b38022554fc43f991aef030021b2d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:32:02 +0100 Subject: [PATCH 61/90] i8k: Make fan module parameters an unsigned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting negative fan multiplier or maximal fan speed does make any sense and can cause problems. So ensure that negative values will not be accepted. Signed-off-by: Pali Rohár Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 8ec4c371dc50..d6e8a267d3a6 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -64,9 +64,9 @@ static DEFINE_MUTEX(i8k_mutex); static char bios_version[4]; static struct device *i8k_hwmon_dev; static u32 i8k_hwmon_flags; -static int i8k_fan_mult; -static int i8k_pwm_mult; -static int i8k_fan_max = I8K_FAN_HIGH; +static uint i8k_fan_mult; +static uint i8k_pwm_mult; +static uint i8k_fan_max = I8K_FAN_HIGH; #define I8K_HWMON_HAVE_TEMP1 (1 << 0) #define I8K_HWMON_HAVE_TEMP2 (1 << 1) @@ -95,12 +95,12 @@ static bool power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static int fan_mult = I8K_FAN_MULT; -module_param(fan_mult, int, 0); +static uint fan_mult = I8K_FAN_MULT; +module_param(fan_mult, uint, 0); MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); -static int fan_max = I8K_FAN_HIGH; -module_param(fan_max, int, 0); +static uint fan_max = I8K_FAN_HIGH; +module_param(fan_max, uint, 0); MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); static int i8k_open_fs(struct inode *inode, struct file *file); @@ -696,8 +696,8 @@ static int __init i8k_init_hwmon(void) } struct i8k_config_data { - int fan_mult; - int fan_max; + uint fan_mult; + uint fan_max; }; enum i8k_configs { From 8f21d8e939b8be096d6f8b6f4386a1f616e307a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:32:03 +0100 Subject: [PATCH 62/90] i8k: Autodetect fan RPM multiplier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds new function i8k_get_fan_nominal_speed() for doing SMM call which will return nominal fan RPM for specified fan speed. It returns nominal RPM value at which fan operate when speed (0, 1, 2, 3) is set. It looks like RPM value is not accurate, but still provides very useful information. New function i8k_get_fan_nominal_speed() is used for determinate if fan multiplier is 1 or 30. If function for maximal fan value success and returned RPM value too high (above 30000) then fan multiplier is set to 1. Otherwise multiplier is not changed and default value 30 is used. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Tested-by: Gabriele Mazzotta Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index d6e8a267d3a6..6ad087240cef 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -6,6 +6,7 @@ * Hwmon integration: * Copyright (C) 2011 Jean Delvare * Copyright (C) 2013, 2014 Guenter Roeck + * Copyright (C) 2014 Pali Rohár * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -42,12 +43,14 @@ #define I8K_SMM_SET_FAN 0x01a3 #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 +#define I8K_SMM_GET_NOM_SPEED 0x04a3 #define I8K_SMM_GET_TEMP 0x10a3 #define I8K_SMM_GET_TEMP_TYPE 0x11a3 #define I8K_SMM_GET_DELL_SIG1 0xfea3 #define I8K_SMM_GET_DELL_SIG2 0xffa3 #define I8K_FAN_MULT 30 +#define I8K_FAN_MAX_RPM 30000 #define I8K_MAX_TEMP 127 #define I8K_FN_NONE 0x00 @@ -64,7 +67,7 @@ static DEFINE_MUTEX(i8k_mutex); static char bios_version[4]; static struct device *i8k_hwmon_dev; static u32 i8k_hwmon_flags; -static uint i8k_fan_mult; +static uint i8k_fan_mult = I8K_FAN_MULT; static uint i8k_pwm_mult; static uint i8k_fan_max = I8K_FAN_HIGH; @@ -95,13 +98,13 @@ static bool power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static uint fan_mult = I8K_FAN_MULT; +static uint fan_mult; module_param(fan_mult, uint, 0); -MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); +MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)"); -static uint fan_max = I8K_FAN_HIGH; +static uint fan_max; module_param(fan_max, uint, 0); -MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); +MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)"); static int i8k_open_fs(struct inode *inode, struct file *file); static long i8k_ioctl(struct file *, unsigned int, unsigned long); @@ -275,6 +278,17 @@ static int i8k_get_fan_speed(int fan) return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; } +/* + * Read the fan nominal rpm for specific fan speed. + */ +static int i8k_get_fan_nominal_speed(int fan, int speed) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; + + regs.ebx = (fan & 0xff) | (speed << 8); + return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; +} + /* * Set the fan speed (off, low, high). Returns the new fan status. */ @@ -863,6 +877,7 @@ MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); static int __init i8k_probe(void) { const struct dmi_system_id *id; + int fan, ret; /* * Get DMI information @@ -891,19 +906,40 @@ static int __init i8k_probe(void) return -ENODEV; } - i8k_fan_mult = fan_mult; - i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ + /* + * Set fan multiplier and maximal fan speed from dmi config + * Values specified in module parameters override values from dmi + */ id = dmi_first_match(i8k_dmi_table); if (id && id->driver_data) { const struct i8k_config_data *conf = id->driver_data; - - if (fan_mult == I8K_FAN_MULT && conf->fan_mult) - i8k_fan_mult = conf->fan_mult; - if (fan_max == I8K_FAN_HIGH && conf->fan_max) - i8k_fan_max = conf->fan_max; + if (!fan_mult && conf->fan_mult) + fan_mult = conf->fan_mult; + if (!fan_max && conf->fan_max) + fan_max = conf->fan_max; } + + i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); + if (!fan_mult) { + /* + * Autodetect fan multiplier based on nominal rpm + * If fan reports rpm value too high then set multiplier to 1 + */ + for (fan = 0; fan < 2; ++fan) { + ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max); + if (ret < 0) + continue; + if (ret > I8K_FAN_MAX_RPM) + i8k_fan_mult = 1; + break; + } + } else { + /* Fan multiplier was specified in module param or in dmi */ + i8k_fan_mult = fan_mult; + } + return 0; } From 1a131ca1de7a84cf3827c418ee5971b493c6f23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:32:04 +0100 Subject: [PATCH 63/90] i8k: Remove DMI config data for Latitude E6440 and E6540 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both Dell Latitude machines were tested with new fan autodetection code and they are working fine. We already have DMI_MATCH data for generic Latitude machines which match also E6440 and E6540 models. So we do not need to maintain DMI data for those specific machines anymore. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Tested-by: Steven Honeyman Acked-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 6ad087240cef..09ebe06764e3 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -716,7 +716,6 @@ struct i8k_config_data { enum i8k_configs { DELL_LATITUDE_D520, - DELL_LATITUDE_E6540, DELL_PRECISION_490, DELL_STUDIO, DELL_XPS, @@ -727,10 +726,6 @@ static const struct i8k_config_data i8k_config_data[] = { .fan_mult = 1, .fan_max = I8K_FAN_TURBO, }, - [DELL_LATITUDE_E6540] = { - .fan_mult = 1, - .fan_max = I8K_FAN_HIGH, - }, [DELL_PRECISION_490] = { .fan_mult = 1, .fan_max = I8K_FAN_TURBO, @@ -775,22 +770,6 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { }, .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], }, - { - .ident = "Dell Latitude E6440", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"), - }, - .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540], - }, - { - .ident = "Dell Latitude E6540", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"), - }, - .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540], - }, { .ident = "Dell Latitude 2", .matches = { From f989e55452c74b4f7b22c889b8ec9f1192aaeec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 12 Jan 2015 14:32:05 +0100 Subject: [PATCH 64/90] i8k: Add support for fan labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds labels support for fans if SMM function with EAX register 0x03a3 reports it. This information was taken from DOS binary NBSVC.MDM. Additionally this patch change detection of fan presece. Instead reading fan status now detection is based on new label SMM function. Dell DOS binary NBSVC.MDM is doing similar checks, so we should do that too. This patch also remove I8K_FAN_LEFT and I8K_FAN_RIGHT usage from hwmon driver part because that names does not make sense anymore. So numeric constants are used instead. Original /proc/i8k ioctl part was not changed for compatibility reasons. Signed-off-by: Pali Rohár Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/char/i8k.c | 76 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 09ebe06764e3..24cc4ed9a780 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -43,6 +43,7 @@ #define I8K_SMM_SET_FAN 0x01a3 #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 +#define I8K_SMM_GET_FAN_TYPE 0x03a3 #define I8K_SMM_GET_NOM_SPEED 0x04a3 #define I8K_SMM_GET_TEMP 0x10a3 #define I8K_SMM_GET_TEMP_TYPE 0x11a3 @@ -278,6 +279,17 @@ static int i8k_get_fan_speed(int fan) return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; } +/* + * Read the fan type. + */ +static int i8k_get_fan_type(int fan) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; + + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; +} + /* * Read the fan nominal rpm for specific fan speed. */ @@ -553,6 +565,37 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev, return sprintf(buf, "%d\n", temp * 1000); } +static ssize_t i8k_hwmon_show_fan_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + static const char * const labels[] = { + "Processor Fan", + "Motherboard Fan", + "Video Fan", + "Power Supply Fan", + "Chipset Fan", + "Other Fan", + }; + int index = to_sensor_dev_attr(devattr)->index; + bool dock = false; + int type; + + type = i8k_get_fan_type(index); + if (type < 0) + return type; + + if (type & 0x10) { + dock = true; + type &= 0x0F; + } + + if (type >= ARRAY_SIZE(labels)) + type = (ARRAY_SIZE(labels) - 1); + + return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]); +} + static ssize_t i8k_hwmon_show_fan(struct device *dev, struct device_attribute *devattr, char *buf) @@ -611,14 +654,17 @@ static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, 3); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, - I8K_FAN_LEFT); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, + 0); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, - i8k_hwmon_set_pwm, I8K_FAN_LEFT); + i8k_hwmon_set_pwm, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, - I8K_FAN_RIGHT); + 1); +static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, + 1); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, - i8k_hwmon_set_pwm, I8K_FAN_RIGHT); + i8k_hwmon_set_pwm, 1); static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ @@ -630,9 +676,11 @@ static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ - &sensor_dev_attr_pwm1.dev_attr.attr, /* 9 */ - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 10 */ - &sensor_dev_attr_pwm2.dev_attr.attr, /* 11 */ + &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ + &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ + &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ + &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ NULL }; @@ -651,10 +699,10 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, if (index >= 6 && index <= 7 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) return 0; - if (index >= 8 && index <= 9 && + if (index >= 8 && index <= 10 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) return 0; - if (index >= 10 && index <= 11 && + if (index >= 11 && index <= 13 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) return 0; @@ -688,13 +736,13 @@ static int __init i8k_init_hwmon(void) if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; - /* Left fan attributes, if left fan is present */ - err = i8k_get_fan_status(I8K_FAN_LEFT); + /* First fan attributes, if fan type is OK */ + err = i8k_get_fan_type(0); if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; - /* Right fan attributes, if right fan is present */ - err = i8k_get_fan_status(I8K_FAN_RIGHT); + /* Second fan attributes, if fan type is OK */ + err = i8k_get_fan_type(1); if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; From 625505b509b38b3a389cb3f4fd6520a46763bf45 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 20 Jan 2015 12:54:50 +0000 Subject: [PATCH 65/90] pnpbios: bail out on strange errors A small number of systems respond to PnP dock queries with bogus values. This causes us to keep logging an error every 2 seconds. Instead of trying again just assume the BIOS is crapware and doesn't actually have dock functionality. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/pnpbios/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 074569e77d22..facd43b8516c 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -181,7 +181,8 @@ static int pnp_dock_thread(void *unused) break; default: pnpbios_print_status("pnp_dock_thread", status); - continue; + printk(KERN_WARNING "PnPBIOS: disabling dock monitoring.\n"); + complete_and_exit(&unload_sem, 0); } if (d != docked) { if (pnp_dock_event(d, &now) == 0) { From 3f46d81ae1cf8f20f25c39ae1ab3f1b064698361 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Tue, 20 Jan 2015 06:27:45 +0100 Subject: [PATCH 66/90] 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(-) 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; From a1d88436d53a75e950db15834b3d2f8c0c358fdc Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Wed, 14 Jan 2015 11:10:19 -0800 Subject: [PATCH 67/90] 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(-) 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; From c3762b248faf9db2b00b36c0535f79758942069e Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 14 Jan 2015 18:46:26 +0000 Subject: [PATCH 68/90] pcmcia: fix incorrect bracketing on a test Reported by wonderful 0-Day Test infrastructure. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/rsrc_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c index 21c3683b1a53..1f67b3ba70fb 100644 --- a/drivers/pcmcia/rsrc_pci.c +++ b/drivers/pcmcia/rsrc_pci.c @@ -156,7 +156,7 @@ static struct resource *res_pci_find_mem(u_long base, u_long num, static int res_pci_init(struct pcmcia_socket *s) { - if (!s->cb_dev || (!s->features & SS_CAP_PAGE_REGS)) { + if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) { dev_err(&s->dev, "not supported by res_pci\n"); return -EOPNOTSUPP; } From 9c3a6f7e476fc4961297fc66b1177f9f8c8dd238 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 20 Jan 2015 16:45:04 +0100 Subject: [PATCH 69/90] Drivers: hv: check vmbus_device_create() return value in vmbus_process_offer() vmbus_device_create() result is not being checked in vmbus_process_offer() and it can fail if kzalloc() fails. Add the check and do minor cleanup to avoid additional duplication of "free_channel(); return;" block. Reported-by: Jason Wang Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Acked-by: Jason Wang Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 1d7df2576b1c..704c0e00f8d2 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -341,11 +341,10 @@ static void vmbus_process_offer(struct work_struct *work) if (channel->sc_creation_callback != NULL) channel->sc_creation_callback(newchannel); - return; + goto out; } - free_channel(newchannel); - return; + goto err_free_chan; } /* @@ -364,6 +363,8 @@ static void vmbus_process_offer(struct work_struct *work) &newchannel->offermsg.offer.if_type, &newchannel->offermsg.offer.if_instance, newchannel); + if (!newchannel->device_obj) + goto err_free_chan; /* * Add the new device to the bus. This will kick off device-driver @@ -379,9 +380,12 @@ static void vmbus_process_offer(struct work_struct *work) list_del(&newchannel->listentry); spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); kfree(newchannel->device_obj); - - free_channel(newchannel); + goto err_free_chan; } +out: + return; +err_free_chan: + free_channel(newchannel); } enum { From 67fae053bfc6e84144150e4c6c62670abb215c33 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 20 Jan 2015 16:45:05 +0100 Subject: [PATCH 70/90] Drivers: hv: rename sc_lock to the more generic lock sc_lock spinlock in struct vmbus_channel is being used to not only protect the sc_list field, e.g. vmbus_open() function uses it to implement test-and-set access to the state field. Rename it to the more generic 'lock' and add the description. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Acked-by: Jason Wang Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 6 +++--- drivers/hv/channel_mgmt.c | 10 +++++----- include/linux/hyperv.h | 7 ++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 18c4f23dacf1..2978f5ee8d2a 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -73,14 +73,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, unsigned long flags; int ret, t, err = 0; - spin_lock_irqsave(&newchannel->sc_lock, flags); + spin_lock_irqsave(&newchannel->lock, flags); if (newchannel->state == CHANNEL_OPEN_STATE) { newchannel->state = CHANNEL_OPENING_STATE; } else { - spin_unlock_irqrestore(&newchannel->sc_lock, flags); + spin_unlock_irqrestore(&newchannel->lock, flags); return -EINVAL; } - spin_unlock_irqrestore(&newchannel->sc_lock, flags); + spin_unlock_irqrestore(&newchannel->lock, flags); newchannel->onchannel_callback = onchannelcallback; newchannel->channel_callback_context = context; diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 704c0e00f8d2..1e0b996ed643 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -146,7 +146,7 @@ static struct vmbus_channel *alloc_channel(void) return NULL; spin_lock_init(&channel->inbound_lock); - spin_lock_init(&channel->sc_lock); + spin_lock_init(&channel->lock); INIT_LIST_HEAD(&channel->sc_list); INIT_LIST_HEAD(&channel->percpu_list); @@ -246,9 +246,9 @@ static void vmbus_process_rescind_offer(struct work_struct *work) spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); } else { primary_channel = channel->primary_channel; - spin_lock_irqsave(&primary_channel->sc_lock, flags); + spin_lock_irqsave(&primary_channel->lock, flags); list_del(&channel->sc_list); - spin_unlock_irqrestore(&primary_channel->sc_lock, flags); + spin_unlock_irqrestore(&primary_channel->lock, flags); } free_channel(channel); } @@ -323,9 +323,9 @@ static void vmbus_process_offer(struct work_struct *work) * Process the sub-channel. */ newchannel->primary_channel = channel; - spin_lock_irqsave(&channel->sc_lock, flags); + spin_lock_irqsave(&channel->lock, flags); list_add_tail(&newchannel->sc_list, &channel->sc_list); - spin_unlock_irqrestore(&channel->sc_lock, flags); + spin_unlock_irqrestore(&channel->lock, flags); if (newchannel->target_cpu != get_cpu()) { put_cpu(); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 259023a34bec..5a2ba674795e 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -734,7 +734,12 @@ struct vmbus_channel { */ void (*sc_creation_callback)(struct vmbus_channel *new_sc); - spinlock_t sc_lock; + /* + * The spinlock to protect the structure. It is being used to protect + * test-and-set access to various attributes of the structure as well + * as all sc_list operations. + */ + spinlock_t lock; /* * All Sub-channels of a primary channel are linked here. */ From d7f2fbafb4f84306436277664cf28042beaf252a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 20 Jan 2015 16:45:06 +0100 Subject: [PATCH 71/90] Drivers: hv: vmbus: serialize Offer and Rescind offer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 4b2f9abea52a ("staging: hv: convert channel_mgmt.c to not call osd_schedule_callback")' was written under an assumption that we never receive Rescind offer while we're still processing the initial Offer request. However, the issue we fixed in 04a258c162a8 could be caused by this assumption not always being true. In particular, we need to protect against the following: 1) Receiving a Rescind offer after we do queue_work() for processing an Offer request and before we actually enter vmbus_process_offer(). work.func points to vmbus_process_offer() at this moment and in vmbus_onoffer_rescind() we do another queue_work() without a check so we'll enter vmbus_process_offer() twice. 2) Receiving a Rescind offer after we enter vmbus_process_offer() and especially after we set >state = CHANNEL_OPEN_STATE. Many things can go wrong in that case, e.g. we can call free_channel() while we're still using it. Implement the required protection by changing work->func at the very end of vmbus_process_offer() and checking work->func in vmbus_onoffer_rescind(). In case we receive rescind offer during or before vmbus_process_offer() is done we set rescind flag to true and we check it at the end of vmbus_process_offer() so such offer will not get lost. Suggested-by: Radim Krčmář Signed-off-by: Vitaly Kuznetsov Acked-by: Jason Wang Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 1e0b996ed643..3736f71bdec5 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -279,9 +279,6 @@ static void vmbus_process_offer(struct work_struct *work) int ret; unsigned long flags; - /* The next possible work is rescind handling */ - INIT_WORK(&newchannel->work, vmbus_process_rescind_offer); - /* Make sure this is a new offer */ spin_lock_irqsave(&vmbus_connection.channel_lock, flags); @@ -341,7 +338,7 @@ static void vmbus_process_offer(struct work_struct *work) if (channel->sc_creation_callback != NULL) channel->sc_creation_callback(newchannel); - goto out; + goto done_init_rescind; } goto err_free_chan; @@ -382,7 +379,14 @@ static void vmbus_process_offer(struct work_struct *work) kfree(newchannel->device_obj); goto err_free_chan; } -out: +done_init_rescind: + spin_lock_irqsave(&newchannel->lock, flags); + /* The next possible work is rescind handling */ + INIT_WORK(&newchannel->work, vmbus_process_rescind_offer); + /* Check if rescind offer was already received */ + if (newchannel->rescind) + queue_work(newchannel->controlwq, &newchannel->work); + spin_unlock_irqrestore(&newchannel->lock, flags); return; err_free_chan: free_channel(newchannel); @@ -520,6 +524,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) { struct vmbus_channel_rescind_offer *rescind; struct vmbus_channel *channel; + unsigned long flags; rescind = (struct vmbus_channel_rescind_offer *)hdr; channel = relid2channel(rescind->child_relid); @@ -528,11 +533,20 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) /* Just return here, no channel found */ return; + spin_lock_irqsave(&channel->lock, flags); channel->rescind = true; + /* + * channel->work.func != vmbus_process_rescind_offer means we are still + * processing offer request and the rescind offer processing should be + * postponed. It will be done at the very end of vmbus_process_offer() + * as rescind flag is being checked there. + */ + if (channel->work.func == vmbus_process_rescind_offer) + /* work is initialized for vmbus_process_rescind_offer() from + * vmbus_process_offer() where the channel got created */ + queue_work(channel->controlwq, &channel->work); - /* work is initialized for vmbus_process_rescind_offer() from - * vmbus_process_offer() where the channel got created */ - queue_work(channel->controlwq, &channel->work); + spin_unlock_irqrestore(&channel->lock, flags); } /* From d8a60e000c951f845d9a5fb3e67853e0e63a5659 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 26 Jan 2015 01:17:54 +0800 Subject: [PATCH 72/90] Drivers: hv: vmbus: hv_process_timer_expiration() can be static drivers/hv/vmbus_drv.c:582:6: sparse: symbol 'hv_process_timer_expiration' was not declared. Should it be static? Signed-off-by: Fengguang Wu Cc: Vitaly Kuznetsov Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 7488111ec057..35e3f422ad7b 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -579,7 +579,7 @@ static void vmbus_onmessage_work(struct work_struct *work) kfree(ctx); } -void hv_process_timer_expiration(struct hv_message *msg, int cpu) +static void hv_process_timer_expiration(struct hv_message *msg, int cpu) { struct clock_event_device *dev = hv_context.clk_evt[cpu]; From 25c0f4e42b1d6d19cb20a98ae59fbee57de1d268 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Dec 2014 09:08:39 +0800 Subject: [PATCH 73/90] extcon: Remove duplicated include from extcon-class.c Remove duplicated "of.h" header file. Signed-off-by: Wei Yongjun Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-class.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c index 043dcd9946c9..8319f25b7145 100644 --- a/drivers/extcon/extcon-class.c +++ b/drivers/extcon/extcon-class.c @@ -32,7 +32,6 @@ #include #include #include -#include /* * extcon_cable_name suggests the standard cable names for commonly used From 5a696d9760fe99bd96dfc6ac336b7e2dc9b21c98 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 17 Dec 2014 17:59:27 +0200 Subject: [PATCH 74/90] extcon: adc-jack: Release IIO channel on driver remove Release IIO channel acquired during driver probe. Signed-off-by: Ivan T. Ivanov Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 5d7ab577fba9..2bb82e55065a 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -173,6 +173,7 @@ static int adc_jack_remove(struct platform_device *pdev) free_irq(data->irq, data); cancel_work_sync(&data->handler.work); + iio_channel_release(data->chan); return 0; } From 6594890020d505ddfab24a2dcd0b68b84628ed1e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2015 09:57:27 +0100 Subject: [PATCH 75/90] extcon: max77693: Constify struct regmap_config The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77693.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 740a14d35072..af165fd0c6f5 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1033,7 +1033,7 @@ static irqreturn_t max77693_muic_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static struct regmap_config max77693_muic_regmap_config = { +static const struct regmap_config max77693_muic_regmap_config = { .reg_bits = 8, .val_bits = 8, }; From 1ab1e79b9fd4b01331490bbe2e630a0fc0b25449 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 25 Jan 2015 23:45:27 +0200 Subject: [PATCH 76/90] 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(-) 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); } From 663b7ee9517eec6deea9a48c7a1392a9a34f7809 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 25 Jan 2015 23:45:28 +0200 Subject: [PATCH 77/90] 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(-) 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 { From 63e144c9d6ffa791c1402f4ee4551c1b9f5a336a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 15 Jan 2015 14:42:27 +0300 Subject: [PATCH 78/90] 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(-) 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 *); From d909f4315b99e5743041eeb01a2552fcbb125c89 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 13 Jan 2015 16:43:18 +0200 Subject: [PATCH 79/90] virtio/console: verify device has config space Some devices might not implement config space access (e.g. remoteproc used not to - before 3.9). virtio/console needs config space access so make it fail gracefully if not there. Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index de03df9dd7c9..26afb56a8073 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1986,6 +1986,12 @@ static int virtcons_probe(struct virtio_device *vdev) bool multiport; bool early = early_put_chars != NULL; + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + /* Ensure to read early_put_chars now */ barrier(); From a48742bce1011d2109f6d6cbda00445aee049fd4 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 12 Jan 2015 16:26:32 +0100 Subject: [PATCH 80/90] mcb: Fix error path of mcb_pci_probe If a MCB PCI Carrier device is IO mapped insted of memory-mapped (which is currently unsupported by the upstream driver) the probe function bails out with -ENOTSUPP. In this case the memory of the PCI device was not unmapped. Also rename error label to reflect what will happen at the destination (suggested by Julia Lawall . Signed-off-by: Johannes Thumshirn Reported-by: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-pci.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index 5e1bd5db02c8..0af7361e377f 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c @@ -51,7 +51,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) priv->mapbase = pci_resource_start(pdev, 0); if (!priv->mapbase) { dev_err(&pdev->dev, "No PCI resource\n"); - goto err_start; + goto out_disable; } res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE, @@ -59,14 +59,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (IS_ERR(res)) { dev_err(&pdev->dev, "Failed to request PCI memory\n"); ret = PTR_ERR(res); - goto err_start; + goto out_disable; } priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE); if (!priv->base) { dev_err(&pdev->dev, "Cannot ioremap\n"); ret = -ENOMEM; - goto err_ioremap; + goto out_release; } flags = pci_resource_flags(pdev, 0); @@ -74,7 +74,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = -ENOTSUPP; dev_err(&pdev->dev, "IO mapped PCI devices are not supported\n"); - goto err_ioremap; + goto out_release; } pci_set_drvdata(pdev, priv); @@ -82,14 +82,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) priv->bus = mcb_alloc_bus(&pdev->dev); if (IS_ERR(priv->bus)) { ret = PTR_ERR(priv->bus); - goto err_drvdata; + goto out_iounmap; } priv->bus->get_irq = mcb_pci_get_irq; ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base); if (ret < 0) - goto err_drvdata; + goto out_iounmap; num_cells = ret; dev_dbg(&pdev->dev, "Found %d cells\n", num_cells); @@ -98,11 +98,11 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; -err_drvdata: +out_iounmap: iounmap(priv->base); -err_ioremap: +out_release: pci_release_region(pdev, 0); -err_start: +out_disable: pci_disable_device(pdev); return ret; } From 9e4129bfc0ae25bfbd9dd6545d6da9bdf72d6977 Mon Sep 17 00:00:00 2001 From: Sharon Dvir Date: Tue, 27 Jan 2015 22:59:54 +0200 Subject: [PATCH 81/90] pdfdocs: Fix 'make pdfdocs' failure for 'uio-howto.tmpl' 'make pdfdocs' failed for uio-howto.tmpl and reported errors of the form: 'document type does not allow element "varname" here; missing one of "remark", "synopsis", "fieldsynopsis", "literallayout", "programlisting", "screen", "para", "simpara", "bridgehead" start-tag' and similar. Fixed by adding '' and '' tags to a location that made sense, fixed the errors and the pdf looks OK in relevant ereas. Signed-off-by: Sharon Dvir Signed-off-by: Greg Kroah-Hartman --- Documentation/DocBook/uio-howto.tmpl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 1fdc246e4256..cd0e452dfed5 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -719,7 +719,7 @@ framework to set up sysfs files for this region. Simply leave it alone. - + Using uio_dmem_genirq for platform devices In addition to statically allocated memory ranges, they may also be @@ -746,16 +746,16 @@ framework to set up sysfs files for this region. Simply leave it alone. following elements: - struct uio_info uioinfo: The same + struct uio_info uioinfo: The same structure used as the uio_pdrv_genirq platform - data - unsigned int *dynamic_region_sizes: + data + unsigned int *dynamic_region_sizes: Pointer to list of sizes of dynamic memory regions to be mapped into user space. - - unsigned int num_dynamic_regions: + + unsigned int num_dynamic_regions: Number of elements in dynamic_region_sizes array. - + The dynamic regions defined in the platform data will be appended to From 410d841a599683408a77f42f110cd17298682520 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:17 -0700 Subject: [PATCH 82/90] coresight: fix the replicator subtype value According to the classification, the type of replicator is link, so the subtype should also be link_subtype. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-replicator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c index a2dfcf903551..cdf05537d574 100644 --- a/drivers/coresight/coresight-replicator.c +++ b/drivers/coresight/coresight-replicator.c @@ -87,7 +87,7 @@ static int replicator_probe(struct platform_device *pdev) return -ENOMEM; desc->type = CORESIGHT_DEV_TYPE_LINK; - desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; + desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; desc->ops = &replicator_cs_ops; desc->pdata = pdev->dev.platform_data; desc->dev = &pdev->dev; From 603101708c9c9ad2bc5a183d6d10b115738098c7 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:18 -0700 Subject: [PATCH 83/90] coresight: remove the unnecessary replicator property Now we use the device name to identify replicator instead of a unique number, so just remove it. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/coresight.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index d790f49066f3..a3089359aaa6 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -38,8 +38,6 @@ its hardware characteristcs. AMBA markee): - "arm,coresight-replicator" - * id: a unique number that will identify this replicator. - * port or ports: same as above. * Optional properties for ETM/PTMs: @@ -94,8 +92,6 @@ Example: * AMBA bus. As such no need to add "arm,primecell". */ compatible = "arm,coresight-replicator"; - /* this will show up in debugfs as "0.replicator" */ - id = <0>; ports { #address-cells = <1>; From 22394bc58543639e5135f19eee2b03d14e4a9b66 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:19 -0700 Subject: [PATCH 84/90] coresight: fix the link between orphan connection and newly added device When founding a component that has orphan connections, we should validate if it match the newly added device. If it does not match, only then should the @still_orphan flag should be set. The tested result as follows. pre: /sys/bus/coresight/devices # echo 1 > e3c42000.etb/enable_sink /sys/bus/coresight/devices # echo 1 > e3c7c000.ptm/enable_source [ 15.527692] Unable to handle kernel NULL pointer dereference at virtual address 00000124 [ 15.555142] pgd = c2294000 [ 15.564226] [00000124] *pgd=3d393831, *pte=00000000, *ppte=00000000 [ 15.585391] Internal error: Oops: 817 [#1] PREEMPT SMP ARM [ 15.603807] CPU: 0 PID: 144 Comm: sh Not tainted 3.17.0-rc1-12634-g1222fe0-dirty #3 [ 15.629490] task: ed3803c0 ti: c213a000 task.ti: c213a000 [ 15.647627] PC is at coresight_build_paths+0x1c/0x314 [ 15.664579] LR is at coresight_build_paths+0x6c/0x314 [ 15.681526] pc : [] lr : [] psr: 20000013 [ 15.681526] sp : c213be88 ip : c02da800 fp : 00000000 [ 15.720023] r10: 00000002 r9 : ed13250c r8 : 00000001 [ 15.737549] r7 : c213bee8 r6 : ffffffea r5 : 00000000 r4 : 00000124 [ 15.759446] r3 : ed216f24 r2 : 00000001 r1 : c213bee8 r0 : 00000000 [ 15.781346] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user post: /sys/bus/coresight/devices # echo 1 > e3c42000.etb/enable_sink /sys/bus/coresight/devices # echo 1 > e3c7c000.ptm/enable_source [ 59.934255] coresight-etb10 e3c42000.etb: ETB enabled [ 59.951317] coresight-replicator replicator0: REPLICATOR enabled [ 59.971581] coresight-funnel e3c41000.funnel: FUNNEL inport 0 enabled [ 59.993334] coresight-etm3x e3c7c000.ptm: ETM tracing enabled Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c index 6e0181f84425..d6052e2cd6a7 100644 --- a/drivers/coresight/coresight.c +++ b/drivers/coresight/coresight.c @@ -504,11 +504,12 @@ static int coresight_orphan_match(struct device *dev, void *data) /* We have found at least one orphan connection */ if (conn->child_dev == NULL) { /* Does it match this newly added device? */ - if (!strcmp(dev_name(&csdev->dev), conn->child_name)) + if (!strcmp(dev_name(&csdev->dev), conn->child_name)) { conn->child_dev = csdev; - } else { - /* Too bad, this component still has an orphan */ - still_orphan = true; + } else { + /* This component still has an orphan */ + still_orphan = true; + } } } From d786a47de97fd194d6cf4f9087543119b9b330c3 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:20 -0700 Subject: [PATCH 85/90] coresight: remove the extra spaces There are some extra spaces, so just remove them from these lines. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-etb10.c | 2 +- drivers/coresight/coresight.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/coresight/coresight-etb10.c b/drivers/coresight/coresight-etb10.c index a1da7020201b..c9acd406f0d0 100644 --- a/drivers/coresight/coresight-etb10.c +++ b/drivers/coresight/coresight-etb10.c @@ -454,7 +454,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) if (ret) return ret; - drvdata->buffer_depth = etb_get_buffer_depth(drvdata); + drvdata->buffer_depth = etb_get_buffer_depth(drvdata); clk_disable_unprepare(drvdata->clk); if (drvdata->buffer_depth < 0) diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c index d6052e2cd6a7..c5def9382357 100644 --- a/drivers/coresight/coresight.c +++ b/drivers/coresight/coresight.c @@ -498,7 +498,7 @@ static int coresight_orphan_match(struct device *dev, void *data) * Circle throuch all the connection of that component. If we find * an orphan connection whose name matches @csdev, link it. */ - for (i = 0; i < i_csdev->nr_outport; i++) { + for (i = 0; i < i_csdev->nr_outport; i++) { conn = &i_csdev->conns[i]; /* We have found at least one orphan connection */ From 7af8792b4d3ad94774fb40f422fa245ab3755bb4 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:21 -0700 Subject: [PATCH 86/90] coresight: fix the debug AMBA bus name The right debug AMBA bus name should be APB(Advanced Peripheral Bus), so just fix it. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/coresight.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt index bba7dbfc49ed..02361552a3ea 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -46,7 +46,7 @@ At typical coresight system would look like this: | | . | ! | | . | ! | ! . | | SWD/ | | . | ! | | . | ! | ! . | | JTAG *****************************************************************<-| - *************************** AMBA Debug ABP ************************ + *************************** AMBA Debug APB ************************ ***************************************************************** | . ! . ! ! . | | . * . * * . | @@ -79,7 +79,7 @@ At typical coresight system would look like this: To trace port TPIU= Trace Port Interface Unit SWD = Serial Wire Debug -While on target configuration of the components is done via the ABP bus, +While on target configuration of the components is done via the APB bus, all trace data are carried out-of-band on the ATB bus. The CTM provides a way to aggregate and distribute signals between CoreSight components. From c4546f246636ccf4cda092bcfcafcb5f5f752ec7 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:22 -0700 Subject: [PATCH 87/90] coresight: remove the unnecessary function coresight_is_bit_set() This function coresight_is_bit_set() isn't called, so we should remove it. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- include/linux/coresight.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index cd6d4c384ca3..3486b9082adb 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -227,7 +227,6 @@ coresight_register(struct coresight_desc *desc); extern void coresight_unregister(struct coresight_device *csdev); extern int coresight_enable(struct coresight_device *csdev); extern void coresight_disable(struct coresight_device *csdev); -extern int coresight_is_bit_set(u32 val, int position, int value); extern int coresight_timeout(void __iomem *addr, u32 offset, int position, int value); #else @@ -237,8 +236,6 @@ static inline void coresight_unregister(struct coresight_device *csdev) {} static inline int coresight_enable(struct coresight_device *csdev) { return -ENOSYS; } static inline void coresight_disable(struct coresight_device *csdev) {} -static inline int coresight_is_bit_set(u32 val, int position, int value) - { return 0; } static inline int coresight_timeout(void __iomem *addr, u32 offset, int position, int value) { return 1; } #endif From 34a03c1d30f04ca7439c685c0ea9b7d79c353705 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 26 Jan 2015 09:22:23 -0700 Subject: [PATCH 88/90] coresight: fixing CPU hwid lookup in device tree Some DT specification will represent CPU nodes with address cells greater than one, making the current code fail. Using the proper retrieval helper function ensure the correct hwid for CPUs is read properly with different address cell size. Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/of_coresight.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c index 9a5ff56f34d9..c3efa418a86d 100644 --- a/drivers/coresight/of_coresight.c +++ b/drivers/coresight/of_coresight.c @@ -117,7 +117,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( struct coresight_platform_data *pdata; struct of_endpoint endpoint, rendpoint; struct device *rdev; - struct device_node *cpu; + struct device_node *dn; struct device_node *ep = NULL; struct device_node *rparent = NULL; struct device_node *rport = NULL; @@ -186,14 +186,16 @@ struct coresight_platform_data *of_get_coresight_platform_data( /* Affinity defaults to CPU0 */ pdata->cpu = 0; - cpu = of_parse_phandle(node, "cpu", 0); - if (cpu) { - const u32 *mpidr; + dn = of_parse_phandle(node, "cpu", 0); + if (dn) { + const u32 *cell; int len, index; + u64 hwid; - mpidr = of_get_property(cpu, "reg", &len); - if (mpidr && len == 4) { - index = get_logical_index(be32_to_cpup(mpidr)); + cell = of_get_property(dn, "reg", &len); + if (cell) { + hwid = of_read_number(cell, of_n_addr_cells(dn)); + index = get_logical_index(hwid); if (index != -EINVAL) pdata->cpu = index; } From 406b9f659fbc966ab47a1fe8f5c1a2e8110483ad Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 26 Jan 2015 09:22:24 -0700 Subject: [PATCH 89/90] coresight-etm: remove check for unknown Kconfig macro The CoreSight ETM/PTM driver contains a check for a CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE macro. But there's no related Kconfig symbol CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE. Remove that check and the single line of code it hides. Signed-off-by: Paul Bolle Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-etm3x.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/coresight/coresight-etm3x.c b/drivers/coresight/coresight-etm3x.c index 73c36696f1b6..c965f5724abd 100644 --- a/drivers/coresight/coresight-etm3x.c +++ b/drivers/coresight/coresight-etm3x.c @@ -34,14 +34,8 @@ #include "coresight-etm.h" -#ifdef CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE -static int boot_enable = 1; -#else static int boot_enable; -#endif -module_param_named( - boot_enable, boot_enable, int, S_IRUGO -); +module_param_named(boot_enable, boot_enable, int, S_IRUGO); /* The number of ETM/PTM currently registered */ static int etm_count; From 5fb31cd839c21130c0b2524ceb9244e98dfe10e3 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Mon, 26 Jan 2015 09:22:25 -0700 Subject: [PATCH 90/90] coresight: fix function etm_writel_cp14() parameter order Function etm_writel_cp14() takes an offset and a value rather than the other way around, something this patch is correcting. The semantic remains the same since it is only a function stub. Signed-off-by: Kaixu Xia Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/coresight/coresight-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h index 7b3372fca4f6..62fcd98cc7cf 100644 --- a/drivers/coresight/coresight-priv.h +++ b/drivers/coresight/coresight-priv.h @@ -57,7 +57,7 @@ extern int etm_readl_cp14(u32 off, unsigned int *val); extern int etm_writel_cp14(u32 off, u32 val); #else static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } -static inline int etm_writel_cp14(u32 val, u32 off) { return 0; } +static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif #endif