summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 10:23:36 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 10:23:36 -0800
commit4c257ec37bc365614933c7f0a7fe9b0688dfd1e7 (patch)
tree37df4c3e0e963df9b87729c19f7c337e2f53008e /drivers
parent39272dde8ffcfd1322209e05f3f8fa4d14f796de (diff)
parented6dc538e5a36a331b6256d54f435c80f6715460 (diff)
Merge tag 'char-misc-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc updates from Greg KH: "Here's the big set of char/misc patches for 4.5-rc1. Nothing major, lots of different driver subsystem updates, full details in the shortlog. All of these have been in linux-next for a while" * tag 'char-misc-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (71 commits) mei: fix fasync return value on error parport: avoid assignment in if parport: remove unneeded space parport: change style of NULL comparison parport: remove unnecessary out of memory message parport: remove braces parport: quoted strings should not be split parport: code indent should use tabs parport: fix coding style parport: EXPORT_SYMBOL should follow function parport: remove trailing white space parport: fix a trivial typo coresight: Fix a typo in Kconfig coresight: checking for NULL string in coresight_name_match() Drivers: hv: vmbus: Treat Fibre Channel devices as performance critical Drivers: hv: utils: fix hvt_op_poll() return value on transport destroy Drivers: hv: vmbus: fix the building warning with hyperv-keyboard extcon: add Maxim MAX3355 driver Drivers: hv: ring_buffer: eliminate hv_ringbuffer_peek() Drivers: hv: remove code duplication between vmbus_recvpacket()/vmbus_recvpacket_raw() ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/extcon/Kconfig9
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-arizona.c71
-rw-r--r--drivers/extcon/extcon-max14577.c2
-rw-r--r--drivers/extcon/extcon-max3355.c146
-rw-r--r--drivers/extcon/extcon-max77693.c4
-rw-r--r--drivers/extcon/extcon-max77843.c2
-rw-r--r--drivers/extcon/extcon-rt8973a.c2
-rw-r--r--drivers/hv/channel.c138
-rw-r--r--drivers/hv/channel_mgmt.c48
-rw-r--r--drivers/hv/connection.c18
-rw-r--r--drivers/hv/hv.c29
-rw-r--r--drivers/hv/hv_fcopy.c37
-rw-r--r--drivers/hv/hv_kvp.c33
-rw-r--r--drivers/hv/hv_snapshot.c36
-rw-r--r--drivers/hv/hv_utils_transport.c130
-rw-r--r--drivers/hv/hv_utils_transport.h3
-rw-r--r--drivers/hv/hyperv_vmbus.h26
-rw-r--r--drivers/hv/ring_buffer.c218
-rw-r--r--drivers/hv/vmbus_drv.c82
-rw-r--r--drivers/hwtracing/coresight/Kconfig2
-rw-r--r--drivers/hwtracing/coresight/coresight.c2
-rw-r--r--drivers/input/serio/hyperv-keyboard.c10
-rw-r--r--drivers/misc/mei/main.c6
-rw-r--r--drivers/parport/share.c246
25 files changed, 749 insertions, 552 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 0cebbf668886..3d89e60a3e71 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -52,6 +52,15 @@ config EXTCON_MAX14577
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch.
+config EXTCON_MAX3355
+ tristate "Maxim MAX3355 USB OTG EXTCON Support"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ If you say yes here you get support for the USB OTG role detection by
+ MAX3355. The MAX3355 chip integrates a charge pump and comparators to
+ enable a system with an integrated USB OTG dual-role transceiver to
+ function as an USB OTG dual-role device.
+
config EXTCON_MAX77693
tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index ba787d04295b..2a0e4f45d5b2 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
+obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e4890dd4fefd..c121d01a5cd6 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level);
}
-static int arizona_extcon_device_get_pdata(struct arizona *arizona)
+static int arizona_extcon_get_micd_configs(struct device *dev,
+ struct arizona *arizona)
+{
+ const char * const prop = "wlf,micd-configs";
+ const int entries_per_config = 3;
+ struct arizona_micd_config *micd_configs;
+ int nconfs, ret;
+ int i, j;
+ u32 *vals;
+
+ nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
+ if (nconfs <= 0)
+ return 0;
+
+ vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
+ if (ret < 0)
+ goto out;
+
+ nconfs /= entries_per_config;
+
+ micd_configs = devm_kzalloc(dev,
+ nconfs * sizeof(struct arizona_micd_range),
+ GFP_KERNEL);
+ if (!micd_configs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, j = 0; i < nconfs; ++i) {
+ micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
+ micd_configs[i].bias = vals[j++];
+ micd_configs[i].gpio = vals[j++];
+ }
+
+ arizona->pdata.micd_configs = micd_configs;
+ arizona->pdata.num_micd_configs = nconfs;
+
+out:
+ kfree(vals);
+ return ret;
+}
+
+static int arizona_extcon_device_get_pdata(struct device *dev,
+ struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+ int ret;
device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
switch (val) {
@@ -1230,12 +1278,29 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona)
device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
&pdata->micd_dbtime);
- device_property_read_u32(arizona->dev, "wlf,micd-timeout",
+ device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
&pdata->micd_timeout);
pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
"wlf,micd-force-micbias");
+ pdata->micd_software_compare = device_property_read_bool(arizona->dev,
+ "wlf,micd-software-compare");
+
+ pdata->jd_invert = device_property_read_bool(arizona->dev,
+ "wlf,jd-invert");
+
+ device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
+
+ pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2");
+ pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2-nopull");
+
+ ret = arizona_extcon_get_micd_configs(dev, arizona);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
+
return 0;
}
@@ -1257,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
return -ENOMEM;
if (!dev_get_platdata(arizona->dev))
- arizona_extcon_device_get_pdata(arizona);
+ arizona_extcon_device_get_pdata(&pdev->dev, arizona);
info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) {
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 601dbd996487..b30ab97ce75f 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
/* Support irq domain for max14577 MUIC device */
for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
if (virq <= 0)
diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
new file mode 100644
index 000000000000..c24abec5d06c
--- /dev/null
+++ b/drivers/extcon/extcon-max3355.c
@@ -0,0 +1,146 @@
+/*
+ * Maxim Integrated MAX3355 USB OTG chip extcon driver
+ *
+ * Copyright (C) 2014-2015 Cogent Embedded, Inc.
+ * Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+
+#include <linux/extcon.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct max3355_data {
+ struct extcon_dev *edev;
+ struct gpio_desc *id_gpiod;
+ struct gpio_desc *shdn_gpiod;
+};
+
+static const unsigned int max3355_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+static irqreturn_t max3355_id_irq(int irq, void *dev_id)
+{
+ struct max3355_data *data = dev_id;
+ int id = gpiod_get_value_cansleep(data->id_gpiod);
+
+ if (id) {
+ /*
+ * ID = 1 means USB HOST cable detached.
+ * As we don't have event for USB peripheral cable attached,
+ * we simulate USB peripheral attach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB, true);
+ } else {
+ /*
+ * ID = 0 means USB HOST cable attached.
+ * As we don't have event for USB peripheral cable detached,
+ * we simulate USB peripheral detach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int max3355_probe(struct platform_device *pdev)
+{
+ struct max3355_data *data;
+ struct gpio_desc *gpiod;
+ int irq, err;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->id_gpiod = gpiod;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get SHDN# GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->shdn_gpiod = gpiod;
+
+ data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable);
+ if (IS_ERR(data->edev)) {
+ dev_err(&pdev->dev, "failed to allocate extcon device\n");
+ return PTR_ERR(data->edev);
+ }
+
+ err = devm_extcon_dev_register(&pdev->dev, data->edev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return err;
+ }
+
+ irq = gpiod_to_irq(data->id_gpiod);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n");
+ return irq;
+ }
+
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND |
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ pdev->name, data);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ /* Perform initial detection */
+ max3355_id_irq(irq, data);
+
+ return 0;
+}
+
+static int max3355_remove(struct platform_device *pdev)
+{
+ struct max3355_data *data = platform_get_drvdata(pdev);
+
+ gpiod_set_value_cansleep(data->shdn_gpiod, 0);
+
+ return 0;
+}
+
+static const struct of_device_id max3355_match_table[] = {
+ { .compatible = "maxim,max3355", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max3355_match_table);
+
+static struct platform_driver max3355_driver = {
+ .probe = max3355_probe,
+ .remove = max3355_remove,
+ .driver = {
+ .name = "extcon-max3355",
+ .of_match_table = max3355_match_table,
+ },
+};
+
+module_platform_driver(max3355_driver);
+
+MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
+MODULE_DESCRIPTION("Maxim MAX3355 extcon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 44c499e1beee..fdf8f5d4d4e9 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
/* Support irq domain for MAX77693 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max77693_muic_irq *muic_irq = &muic_irqs[i];
- unsigned int virq = 0;
+ int virq;
virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq);
- if (!virq)
+ if (virq <= 0)
return -EINVAL;
muic_irq->virq = virq;
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 9f9ea334399c..74dfb7f4f277 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max77843->irq_data_muic,
muic_irq->irq);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 36bf1d63791c..e1bb82809bef 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
ret = devm_request_threaded_irq(info->dev, virq, NULL,
rt8973a_muic_irq_handler,
- IRQF_NO_SUSPEND,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
muic_irq->name, info);
if (ret) {
dev_err(info->dev,
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index c4dcab048cb8..1161d68a1863 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/hyperv.h>
#include <linux/uio.h>
+#include <linux/interrupt.h>
#include "hyperv_vmbus.h"
@@ -496,8 +497,33 @@ static void reset_channel_cb(void *arg)
static int vmbus_close_internal(struct vmbus_channel *channel)
{
struct vmbus_channel_close_channel *msg;
+ struct tasklet_struct *tasklet;
int ret;
+ /*
+ * process_chn_event(), running in the tasklet, can race
+ * with vmbus_close_internal() in the case of SMP guest, e.g., when
+ * the former is accessing channel->inbound.ring_buffer, the latter
+ * could be freeing the ring_buffer pages.
+ *
+ * To resolve the race, we can serialize them by disabling the
+ * tasklet when the latter is running here.
+ */
+ tasklet = hv_context.event_dpc[channel->target_cpu];
+ tasklet_disable(tasklet);
+
+ /*
+ * In case a device driver's probe() fails (e.g.,
+ * util_probe() -> vmbus_open() returns -ENOMEM) and the device is
+ * rescinded later (e.g., we dynamically disble an Integrated Service
+ * in Hyper-V Manager), the driver's remove() invokes vmbus_close():
+ * here we should skip most of the below cleanup work.
+ */
+ if (channel->state != CHANNEL_OPENED_STATE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
@@ -525,7 +551,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to post the close msg,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}
/* Tear down the gpadl for the channel's ring buffer */
@@ -538,7 +564,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to teardown gpadl,
* it is perhaps better to leak memory.
*/
- return ret;
+ goto out;
}
}
@@ -549,12 +575,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
- /*
- * If the channel has been rescinded; process device removal.
- */
- if (channel->rescind)
- hv_process_channel_removal(channel,
- channel->offermsg.child_relid);
+out:
+ tasklet_enable(tasklet);
+
return ret;
}
@@ -630,10 +653,19 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
* on the ring. We will not signal if more data is
* to be placed.
*
+ * Based on the channel signal state, we will decide
+ * which signaling policy will be applied.
+ *
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
*/
+
+ if (channel->signal_policy)
+ signal = true;
+ else
+ kick_q = true;
+
if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel);
@@ -733,10 +765,19 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
* on the ring. We will not signal if more data is
* to be placed.
*
+ * Based on the channel signal state, we will decide
+ * which signaling policy will be applied.
+ *
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
*/
+
+ if (channel->signal_policy)
+ signal = true;
+ else
+ kick_q = true;
+
if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel);
@@ -881,46 +922,29 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
*
* Mainly used by Hyper-V drivers.
*/
-int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
- u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
+static inline int
+__vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
+ bool raw)
{
- struct vmpacket_descriptor desc;
- u32 packetlen;
- u32 userlen;
int ret;
bool signal = false;
- *buffer_actual_len = 0;
- *requestid = 0;
-
-
- ret = hv_ringbuffer_peek(&channel->inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0)
- return 0;
-
- packetlen = desc.len8 << 3;
- userlen = packetlen - (desc.offset8 << 3);
-
- *buffer_actual_len = userlen;
-
- if (userlen > bufferlen) {
-
- pr_err("Buffer too small - got %d needs %d\n",
- bufferlen, userlen);
- return -ETOOSMALL;
- }
-
- *requestid = desc.trans_id;
-
- /* Copy over the packet to the user buffer */
- ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
- (desc.offset8 << 3), &signal);
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
+ buffer_actual_len, requestid, &signal, raw);
if (signal)
vmbus_setevent(channel);
- return 0;
+ return ret;
+}
+
+int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len,
+ u64 *requestid)
+{
+ return __vmbus_recvpacket(channel, buffer, bufferlen,
+ buffer_actual_len, requestid, false);
}
EXPORT_SYMBOL(vmbus_recvpacket);
@@ -931,37 +955,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u32 *buffer_actual_len,
u64 *requestid)
{
- struct vmpacket_descriptor desc;
- u32 packetlen;
- int ret;
- bool signal = false;
-
- *buffer_actual_len = 0;
- *requestid = 0;
-
-
- ret = hv_ringbuffer_peek(&channel->inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0)
- return 0;
-
-
- packetlen = desc.len8 << 3;
-
- *buffer_actual_len = packetlen;
-
- if (packetlen > bufferlen)
- return -ENOBUFS;
-
- *requestid = desc.trans_id;
-
- /* Copy over the entire packet to the user buffer */
- ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0,
- &signal);
-
- if (signal)
- vmbus_setevent(channel);
-
- return ret;
+ return __vmbus_recvpacket(channel, buffer, bufferlen,
+ buffer_actual_len, requestid, true);
}
EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 652afd11a9ef..1c1ad47042c5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -177,19 +177,24 @@ static void percpu_channel_deq(void *arg)
}
-void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+static void vmbus_release_relid(u32 relid)
{
struct vmbus_channel_relid_released msg;
- unsigned long flags;
- struct vmbus_channel *primary_channel;
memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+}
- if (channel == NULL)
- return;
+void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
+{
+ unsigned long flags;
+ struct vmbus_channel *primary_channel;
+
+ vmbus_release_relid(relid);
+
+ BUG_ON(!channel->rescind);
if (channel->target_cpu != get_cpu()) {
put_cpu();
@@ -201,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
}
if (channel->primary_channel == NULL) {
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&channel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
primary_channel = channel;
} else {
@@ -230,9 +235,7 @@ void vmbus_free_channels(void)
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
- /* if we don't set rescind to true, vmbus_close_internal()
- * won't invoke hv_process_channel_removal().
- */
+ /* hv_process_channel_removal() needs this */
channel->rescind = true;
vmbus_device_unregister(channel->device_obj);
@@ -250,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
unsigned long flags;
/* Make sure this is a new offer */
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (!uuid_le_cmp(channel->offermsg.offer.if_type,
@@ -266,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
if (!fnew) {
/*
@@ -336,9 +339,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
return;
err_deq_chan:
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ vmbus_release_relid(newchannel->offermsg.child_relid);
+
+ mutex_lock(&vmbus_connection.channel_mutex);
list_del(&newchannel->listentry);
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
@@ -356,8 +361,10 @@ err_free_chan:
enum {
IDE = 0,
SCSI,
+ FC,
NIC,
ND_NIC,
+ PCIE,
MAX_PERF_CHN,
};
@@ -371,10 +378,14 @@ static const struct hv_vmbus_device_id hp_devs[] = {
{ HV_IDE_GUID, },
/* Storage - SCSI */
{ HV_SCSI_GUID, },
+ /* Storage - FC */
+ { HV_SYNTHFC_GUID, },
/* Network */
{ HV_NIC_GUID, },
/* NetworkDirect Guest RDMA */
{ HV_ND_GUID, },
+ /* PCI Express Pass Through */
+ { HV_PCIE_GUID, },
};
@@ -405,8 +416,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
struct cpumask *alloced_mask;
for (i = IDE; i < MAX_PERF_CHN; i++) {
- if (!memcmp(type_guid->b, hp_devs[i].guid,
- sizeof(uuid_le))) {
+ if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) {
perf_chn = true;
break;
}
@@ -585,7 +595,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
channel = relid2channel(rescind->child_relid);
if (channel == NULL) {
- hv_process_channel_removal(NULL, rescind->child_relid);
+ /*
+ * This is very impossible, because in
+ * vmbus_process_offer(), we have already invoked
+ * vmbus_release_relid() on error.
+ */
return;
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 4fc2e8836e60..3dc5a9c7fad6 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -83,10 +83,13 @@ 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[get_cpu()];
- put_cpu();
- }
+ /*
+ * We want all channel messages to be delivered on CPU 0.
+ * This has been the behavior pre-win8. This is not
+ * perf issue and having all channel messages delivered on CPU 0
+ * would be ok.
+ */
+ msg->target_vcpu = 0;
/*
* Add to list before we send the request since we may
@@ -146,7 +149,7 @@ int vmbus_connect(void)
spin_lock_init(&vmbus_connection.channelmsg_lock);
INIT_LIST_HEAD(&vmbus_connection.chn_list);
- spin_lock_init(&vmbus_connection.channel_lock);
+ mutex_init(&vmbus_connection.channel_mutex);
/*
* Setup the vmbus event connection for channel interrupt
@@ -282,11 +285,10 @@ struct vmbus_channel *relid2channel(u32 relid)
{
struct vmbus_channel *channel;
struct vmbus_channel *found_channel = NULL;
- unsigned long flags;
struct list_head *cur, *tmp;
struct vmbus_channel *cur_sc;
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) {
found_channel = channel;
@@ -305,7 +307,7 @@ struct vmbus_channel *relid2channel(u32 relid)
}
}
}
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ mutex_unlock(&vmbus_connection.channel_mutex);
return found_channel;
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 6341be8739ae..11bca51ef5ff 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -89,9 +89,9 @@ static int query_hypervisor_info(void)
}
/*
- * do_hypercall- Invoke the specified hypercall
+ * hv_do_hypercall- Invoke the specified hypercall
*/
-static u64 do_hypercall(u64 control, void *input, void *output)
+u64 hv_do_hypercall(u64 control, void *input, void *output)
{
u64 input_address = (input) ? virt_to_phys(input) : 0;
u64 output_address = (output) ? virt_to_phys(output) : 0;
@@ -132,6 +132,7 @@ static u64 do_hypercall(u64 control, void *input, void *output)
return hv_status_lo | ((u64)hv_status_hi << 32);
#endif /* !x86_64 */
}
+EXPORT_SYMBOL_GPL(hv_do_hypercall);
#ifdef CONFIG_X86_64
static cycle_t read_hv_clock_tsc(struct clocksource *arg)
@@ -139,7 +140,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg)
cycle_t current_tick;
struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page;
- if (tsc_pg->tsc_sequence != -1) {
+ if (tsc_pg->tsc_sequence != 0) {
/*
* Use the tsc page to compute the value.
*/
@@ -161,7 +162,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg)
if (tsc_pg->tsc_sequence == sequence)
return current_tick;
- if (tsc_pg->tsc_sequence != -1)
+ if (tsc_pg->tsc_sequence != 0)
continue;
/*
* Fallback using MSR method.
@@ -192,9 +193,7 @@ int hv_init(void)
{
int max_leaf;
union hv_x64_msr_hypercall_contents hypercall_msr;
- union hv_x64_msr_hypercall_contents tsc_msr;
void *virtaddr = NULL;
- void *va_tsc = NULL;
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
@@ -240,6 +239,9 @@ int hv_init(void)
#ifdef CONFIG_X86_64
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
+ union hv_x64_msr_hypercall_contents tsc_msr;
+ void *va_tsc;
+
va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!va_tsc)
goto cleanup;
@@ -315,7 +317,7 @@ int hv_post_message(union hv_connection_id connection_id,
{
struct hv_input_post_message *aligned_msg;
- u16 status;
+ u64 status;
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -EMSGSIZE;
@@ -329,11 +331,10 @@ int hv_post_message(union hv_connection_id connection_id,
aligned_msg->payload_size = payload_size;
memcpy((void *)aligned_msg->payload, payload, payload_size);
- status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
- & 0xFFFF;
+ status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL);
put_cpu();
- return status;
+ return status & 0xFFFF;
}
@@ -343,13 +344,13 @@ int hv_post_message(union hv_connection_id connection_id,
*
* This involves a hypercall.
*/
-u16 hv_signal_event(void *con_id)
+int hv_signal_event(void *con_id)
{
- u16 status;
+ u64 status;
- status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF);
+ status = hv_do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL);
- return status;
+ return status & 0xFFFF;
}
static int hv_ce_set_next_event(unsigned long delta,
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index db4b887b889d..c37a71e13de0 100644
--- a/