Commit 4c257ec3 authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 39272dde ed6dc538
...@@ -13,3 +13,63 @@ Optional properties: ...@@ -13,3 +13,63 @@ Optional properties:
ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR
If this node is not mentioned or if the value is unknown, then If this node is not mentioned or if the value is unknown, then
headphone detection mode is set to HPDETL. headphone detection mode is set to HPDETL.
- wlf,use-jd2 : Use the additional JD input along with JD1 for dual pin jack
detection.
- wlf,use-jd2-nopull : Internal pull on JD2 is disabled when used for
jack detection.
- wlf,jd-invert : Invert the polarity of the jack detection switch
- wlf,micd-software-compare : Use a software comparison to determine mic
presence
- wlf,micd-detect-debounce : Additional software microphone detection
debounce specified in milliseconds.
- wlf,micd-pol-gpio : GPIO specifier for the GPIO controlling the headset
polarity if one exists.
- wlf,micd-bias-start-time : Time allowed for MICBIAS to startup prior to
performing microphone detection, specified as per the ARIZONA_MICD_TIME_XXX
defines.
- wlf,micd-rate : Delay between successive microphone detection measurements,
specified as per the ARIZONA_MICD_TIME_XXX defines.
- wlf,micd-dbtime : Microphone detection hardware debounces specified as the
number of measurements to take, valid values being 2 and 4.
- wlf,micd-timeout-ms : Timeout for microphone detection, specified in
milliseconds.
- wlf,micd-force-micbias : Force MICBIAS continuously on during microphone
detection.
- wlf,micd-configs : Headset polarity configurations (generally used for
detection of CTIA / OMTP headsets), the field can be of variable length
but should always be a multiple of 3 cells long, each three cell group
represents one polarity configuration.
The first cell defines the accessory detection pin, zero will use MICDET1
and all other values will use MICDET2.
The second cell represents the MICBIAS to be used.
The third cell represents the value of the micd-pol-gpio pin.
- wlf,gpsw : Settings for the general purpose switch
Example:
codec: wm8280@0 {
compatible = "wlf,wm8280";
reg = <0>;
...
wlf,use-jd2;
wlf,use-jd2-nopull;
wlf,jd-invert;
wlf,micd-software-compare;
wlf,micd-detect-debounce = <0>;
wlf,micd-pol-gpio = <&codec 2 0>;
wlf,micd-rate = <ARIZONA_MICD_TIME_8MS>;
wlf,micd-dbtime = <4>;
wlf,micd-timeout-ms = <100>;
wlf,micd-force-micbias;
wlf,micd-configs = <
0 1 0 /* MICDET1 MICBIAS1 GPIO=low */
1 2 1 /* MICDET2 MICBIAS2 GPIO=high */
>;
wlf,gpsw = <0>;
};
Maxim Integrated MAX3355 USB OTG chip
-------------------------------------
MAX3355 integrates a charge pump and comparators to enable a system with an
integrated USB OTG dual-role transceiver to function as a USB OTG dual-role
device.
Required properties:
- compatible: should be "maxim,max3355";
- maxim,shdn-gpios: should contain a phandle and GPIO specifier for the GPIO pin
connected to the MAX3355's SHDN# pin;
- id-gpios: should contain a phandle and GPIO specifier for the GPIO pin
connected to the MAX3355's ID_OUT pin.
Example:
usb-otg {
compatible = "maxim,max3355";
maxim,shdn-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
id-gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
};
...@@ -52,6 +52,15 @@ config EXTCON_MAX14577 ...@@ -52,6 +52,15 @@ config EXTCON_MAX14577
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch. 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 config EXTCON_MAX77693
tristate "Maxim MAX77693 EXTCON Support" tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT depends on MFD_MAX77693 && INPUT
......
...@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o ...@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.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_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
......
...@@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index, ...@@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level); 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; struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val = ARIZONA_ACCDET_MODE_HPL; unsigned int val = ARIZONA_ACCDET_MODE_HPL;
int ret;
device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val); device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
switch (val) { switch (val) {
...@@ -1230,12 +1278,29 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) ...@@ -1230,12 +1278,29 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona)
device_property_read_u32(arizona->dev, "wlf,micd-dbtime", device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
&pdata->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_timeout);
pdata->micd_force_micbias = device_property_read_bool(arizona->dev, pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
"wlf,micd-force-micbias"); "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; return 0;
} }
...@@ -1257,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1257,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
if (!dev_get_platdata(arizona->dev)) 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"); info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) { if (IS_ERR(info->micvdd)) {
......
...@@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev) ...@@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
/* Support irq domain for max14577 MUIC device */ /* Support irq domain for max14577 MUIC device */
for (i = 0; i < info->muic_irqs_num; i++) { for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[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); virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
if (virq <= 0) if (virq <= 0)
......
/*
* 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");
...@@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
/* Support irq domain for MAX77693 MUIC device */ /* Support irq domain for MAX77693 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max77693_muic_irq *muic_irq = &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, virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq); muic_irq->irq);
if (!virq) if (virq <= 0)
return -EINVAL; return -EINVAL;
muic_irq->virq = virq; muic_irq->virq = virq;
......
...@@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev) ...@@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) { for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
struct max77843_muic_irq *muic_irq = &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, virq = regmap_irq_get_virq(max77843->irq_data_muic,
muic_irq->irq); muic_irq->irq);
......
...@@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c, ...@@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
ret = devm_request_threaded_irq(info->dev, virq, NULL, ret = devm_request_threaded_irq(info->dev, virq, NULL,
rt8973a_muic_irq_handler, rt8973a_muic_irq_handler,
IRQF_NO_SUSPEND, IRQF_NO_SUSPEND | IRQF_ONESHOT,
muic_irq->name, info); muic_irq->name, info);
if (ret) { if (ret) {
dev_err(info->dev, dev_err(info->dev,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/interrupt.h>
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
...@@ -496,8 +497,33 @@ static void reset_channel_cb(void *arg) ...@@ -496,8 +497,33 @@ static void reset_channel_cb(void *arg)
static int vmbus_close_internal(struct vmbus_channel *channel) static int vmbus_close_internal(struct vmbus_channel *channel)
{ {
struct vmbus_channel_close_channel *msg; struct vmbus_channel_close_channel *msg;
struct tasklet_struct *tasklet;
int ret; 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->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL; channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */ /* Stop callback and cancel the timer asap */
...@@ -525,7 +551,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) ...@@ -525,7 +551,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to post the close msg, * If we failed to post the close msg,
* it is perhaps better to leak memory. * it is perhaps better to leak memory.
*/ */
return ret; goto out;
} }
/* Tear down the gpadl for the channel's ring buffer */ /* Tear down the gpadl for the channel's ring buffer */
...@@ -538,7 +564,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) ...@@ -538,7 +564,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to teardown gpadl, * If we failed to teardown gpadl,
* it is perhaps better to leak memory. * it is perhaps better to leak memory.
*/ */
return ret; goto out;
} }
} }
...@@ -549,12 +575,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel) ...@@ -549,12 +575,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages, free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
/* out:
* If the channel has been rescinded; process device removal. tasklet_enable(tasklet);
*/
if (channel->rescind)
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
return ret; return ret;
} }
...@@ -630,10 +653,19 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, ...@@ -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 * on the ring. We will not signal if more data is
* to be placed. * 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 * If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare * even if we may not have written anything. This is a rare
* enough condition that it should not matter. * enough condition that it should not matter.
*/ */
if (channel->signal_policy)
signal = true;
else
kick_q = true;
if (((ret == 0) && kick_q && signal) || (ret)) if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel); vmbus_setevent(channel);
...@@ -733,10 +765,19 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *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 * on the ring. We will not signal if more data is
* to be placed. * 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 * If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare * even if we may not have written anything. This is a rare
* enough condition that it should not matter. * enough condition that it should not matter.
*/ */
if (channel->signal_policy)
signal = true;
else
kick_q = true;
if (((ret == 0) && kick_q && signal) || (ret)) if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel); vmbus_setevent(channel);
...@@ -881,46 +922,29 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer); ...@@ -881,46 +922,29 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
* *
* Mainly used by Hyper-V drivers. * Mainly used by Hyper-V drivers.
*/ */
int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, static inline int
u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) __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; int ret;
bool signal = false; bool signal = false;
*buffer_actual_len = 0; ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
*requestid = 0; buffer_actual_len, requestid, &signal, raw);
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);
if (signal) if (signal)
vmbus_setevent(channel); 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); EXPORT_SYMBOL(vmbus_recvpacket);
...@@ -931,37 +955,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, ...@@ -931,37 +955,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u32 *buffer_actual_len, u32 bufferlen, u32 *buffer_actual_len,
u64 *requestid) u64 *requestid)
{ {
struct vmpacket_descriptor desc; return __vmbus_recvpacket(channel, buffer, bufferlen,
u32 packetlen; buffer_actual_len, requestid, true);
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;
} }
EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
...@@ -177,19 +177,24 @@ static void percpu_channel_deq(void *arg) ...@@ -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; struct vmbus_channel_relid_released msg;
unsigned long flags;
struct vmbus_channel *primary_channel;
memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = relid; msg.child_relid = relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED; msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
}
if (channel == NULL) void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
return; {
unsigned long flags;
struct vmbus_channel *primary_channel;
vmbus_release_relid(relid);
BUG_ON(!channel->rescind);
if (channel->target_cpu != get_cpu()) { if (channel->target_cpu != get_cpu()) {
put_cpu(); put_cpu();
...@@ -201,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) ...@@ -201,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
} }
if (channel->primary_channel == NULL) { if (channel->primary_channel == NULL) {
spin_lock_irqsave(&vmbus_connection.channel_lock, flags); mutex_lock(&vmbus_connection.channel_mutex);
list_del(&channel->listentry); list_del(&channel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); mutex_unlock(&vmbus_connection.channel_mutex);
primary_channel = channel; primary_channel = channel;
} else { } else {
...@@ -230,9 +235,7 @@ void vmbus_free_channels(void) ...@@ -230,9 +235,7 @@ void vmbus_free_channels(void)
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list, list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) { listentry) {
/* if we don't set rescind to true, vmbus_close_internal() /* hv_process_channel_removal() needs this */
* won't invoke hv_process_channel_removal().
*/
channel->rescind = true; channel->rescind = true;
vmbus_device_unregister(channel->device_obj); vmbus_device_unregister(channel->device_obj);
...@@ -250,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -250,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
unsigned long flags; unsigned long flags;
/* Make sure this is a new offer */ /* 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) { list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (!uuid_le_cmp(channel->offermsg.offer.if_type, if (!uuid_le_cmp(channel->offermsg.offer.if_type,
...@@ -266,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -266,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_add_tail(&newchannel->listentry, list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list); &vmbus_connection.chn_list);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); mutex_unlock(&vmbus_connection.channel_mutex);
if (!fnew) { if (!fnew) {
/* /*
...@@ -336,9 +339,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -336,9 +339,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
return; return;
err_deq_chan: 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); list_del(&newchannel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); mutex_unlock(&vmbus_connection.channel_mutex);
if (newchannel->target_cpu != get_cpu()) { if (newchannel->target_cpu != get_cpu()) {
put_cpu(); put_cpu();
...@@ -356,8 +361,10 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -356,8 +361,10 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
enum { enum {
IDE = 0, IDE = 0,
SCSI, SCSI,
FC,
NIC, NIC,
ND_NIC, ND_NIC,
PCIE,
MAX_PERF_CHN, MAX_PERF_CHN,
}; };
...@@ -371,10 +378,14 @@ static const struct hv_vmbus_device_id hp_devs[] = { ...@@ -371,10 +378,14 @@ static const struct hv_vmbus_device_id hp_devs[] = {
{ HV_IDE_GUID, }, { HV_IDE_GUID, },
/* Storage - SCSI */ /* Storage - SCSI */
{ HV_SCSI_GUID, }, { HV_SCSI_GUID, },
/* Storage - FC */
{ HV_SYNTHFC_GUID, },
/* Network */ /* Network */
{ HV_NIC_GUID, }, { HV_NIC_GUID, },
/* NetworkDirect Guest RDMA */ /* NetworkDirect Guest RDMA */
{ HV_ND_GUID, }, { 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 ...@@ -405,8 +416,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
struct cpumask *alloced_mask; struct cpumask *alloced_mask;
for (i = IDE; i < MAX_PERF_CHN; i++) { for (i = IDE; i < MAX_PERF_CHN; i++) {
if (!memcmp(type_guid->b, hp_devs[i].guid, if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) {
sizeof(uuid_le))) {
perf_chn = true; perf_chn = true;
break; break;
} }
...@@ -585,7 +595,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) ...@@ -585,7 +595,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
channel = relid2channel(rescind->child_relid); channel = relid2channel(rescind->child_relid);
if (channel == NULL) { 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; return;
} }
......
...@@ -83,10 +83,13 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, ...@@ -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->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); 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()]; * We want all channel messages to be delivered on CPU 0.
put_cpu(); * 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 * Add to list before we send the request since we may
...@@ -146,7 +149,7 @@ int vmbus_connect(void) ...@@ -146,7 +149,7 @@ int vmbus_connect(void)
spin_lock_init(&vmbus_connection.channelmsg_lock); spin_lock_init(&vmbus_connection.channelmsg_lock);
INIT_LIST_HEAD(&vmbus_connection.chn_list); 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 * Setup the vmbus event connection for channel interrupt
...@@ -282,11 +285,10 @@ struct vmbus_channel *relid2channel(u32 relid) ...@@ -282,11 +285,10 @@ struct vmbus_channel *relid2channel(u32 relid)
{ {
struct vmbus_channel *channel; struct vmbus_channel *channel;
struct vmbus_channel *found_channel = NULL; struct vmbus_channel *found_channel = NULL;
unsigned long flags;
struct list_head *cur, *tmp; struct list_head *cur, *tmp;
struct vmbus_channel *cur_sc; 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) { list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) { if (channel->offermsg.child_relid == relid) {
found_channel = channel; found_channel = channel;
...@@ -305,7 +307,7 @@ struct vmbus_channel *relid2channel(u32 relid) ...@@ -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; return found_channel;
} }
......
...@@ -89,9 +89,9 @@ static int query_hypervisor_info(void) ...@@ -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 input_address = (input) ? virt_to_phys(input) : 0;
u64 output_address = (output) ? virt_to_phys(output) : 0; u64 output_address = (output) ? virt_to_phys(output) : 0;
...@@ -132,6 +132,7 @@ static u64 do_hypercall(u64 control, void *input, void *output) ...@@ -132,6 +132,7 @@ static u64 do_hypercall(u64 control, void *input, void *output)
return hv_status_lo | ((u64)hv_status_hi << 32); return hv_status_lo | ((u64)hv_status_hi << 32);
#endif /* !x86_64 */ #endif /* !x86_64 */
} }
EXPORT_SYMBOL_GPL(hv_do_hypercall);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
static cycle_t read_hv_clock_tsc(struct clocksource *arg) static cycle_t read_hv_clock_tsc(struct clocksource *arg)
...@@ -139,7 +140,7 @@ 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; cycle_t current_tick;
struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page; 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. * Use the tsc page to compute the value.
*/ */
...@@ -161,7 +162,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg) ...@@ -161,7 +162,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg)
if (tsc_pg->tsc_sequence == sequence) if (tsc_pg->tsc_sequence == sequence)
return current_tick; return current_tick;
if (tsc_pg->tsc_sequence != -1) if (tsc_pg->tsc_sequence != 0)
continue; continue;
/* /*
* Fallback using MSR method. * Fallback using MSR method.
...@@ -192,9 +193,7 @@ int hv_init(void) ...@@ -192,9 +193,7 @@ int hv_init(void)
{ {
int max_leaf; int max_leaf;
union hv_x64_msr_hypercall_contents hypercall_msr; union hv_x64_msr_hypercall_contents hypercall_msr;
union hv_x64_msr_hypercall_contents tsc_msr;
void *virtaddr = NULL; void *virtaddr = NULL;
void *va_tsc = NULL;
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0, memset(hv_context.synic_message_page, 0,
...@@ -240,6 +239,9 @@ int hv_init(void) ...@@ -240,6 +239,9 @@ int hv_init(void)
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) { 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); va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!va_tsc) if (!va_tsc)
goto cleanup; goto cleanup;
...@@ -315,7 +317,7 @@ int hv_post_message(union hv_connection_id connection_id, ...@@ -315,7 +317,7 @@ int hv_post_message(union hv_connection_id connection_id,
{ {
struct hv_input_post_message *aligned_msg; struct hv_input_post_message *aligned_msg;
u16 status; u64 status;
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -EMSGSIZE; return -EMSGSIZE;
...@@ -329,11 +331,10 @@ int hv_post_message(union hv_connection_id connection_id, ...@@ -329,11 +331,10 @@ int hv_post_message(union hv_connection_id connection_id,
aligned_msg->payload_size = payload_size; aligned_msg->payload_size = payload_size;
memcpy((void *)aligned_msg->payload, payload, payload_size); memcpy((void *)aligned_msg->payload, payload, payload_size);
status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL);
& 0xFFFF;
put_cpu(); put_cpu();
return status; return status & 0xFFFF;
} }
...@@ -343,13 +344,13 @@ int hv_post_message(union hv_connection_id connection_id, ...@@ -343,13 +344,13 @@ int hv_post_message(union hv_connection_id connection_id,
* *
* This involves a hypercall. * 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, static int hv_ce_set_next_event(unsigned long delta,
......
...@@ -51,7 +51,6 @@ static struct { ...@@ -51,7 +51,6 @@ static struct {
struct hv_fcopy_hdr *fcopy_msg; /* current message */ struct hv_fcopy_hdr *fcopy_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */ struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */ u64 recv_req_id; /* request ID. */
void *fcopy_context; /* for the channel callback */
} fcopy_transaction; } fcopy_transaction;
static void fcopy_respond_to_host(int error); static void fcopy_respond_to_host(int error);
...@@ -67,6 +66,13 @@ static struct hvutil_transport *hvt; ...@@ -67,6 +66,13 @@ static struct hvutil_transport *hvt;
*/ */
static int dm_reg_value; static int dm_reg_value;
static void fcopy_poll_wrapper(void *channel)
{
/* Transaction is finished, reset the state here to avoid races. */
fcopy_transaction.state = HVUTIL_READY;
hv_fcopy_onchannelcallback(channel);
}
static void fcopy_timeout_func(struct work_struct *dummy) static void fcopy_timeout_func(struct work_struct *dummy)
{ {
/* /*
...@@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy) ...@@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy)
* process the pending transaction. * process the pending transaction.
*/ */
fcopy_respond_to_host(HV_E_FAIL); fcopy_respond_to_host(HV_E_FAIL);
hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
/* Transaction is finished, reset the state. */
if (fcopy_transaction.state > HVUTIL_READY)
fcopy_transaction.state = HVUTIL_READY;
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
} }
static int fcopy_handle_handshake(u32 version) static int fcopy_handle_handshake(u32 version)
...@@ -108,9 +108,7 @@ static int fcopy_handle_handshake(u32 version) ...@@ -108,9 +108,7 @@ static int fcopy_handle_handshake(u32 version)
return -EINVAL; return -EINVAL;
} }
pr_debug("FCP: userspace daemon ver. %d registered\n", version); pr_debug("FCP: userspace daemon ver. %d registered\n", version);
fcopy_transaction.state = HVUTIL_READY; hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
return 0; return 0;
} }
...@@ -227,15 +225,8 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -227,15 +225,8 @@ void hv_fcopy_onchannelcallback(void *context)
int util_fw_version; int util_fw_version;
int fcopy_srv_version; int fcopy_srv_version;
if (fcopy_transaction.state > HVUTIL_READY) { if (fcopy_transaction.state > HVUTIL_READY)
/*
* We will defer processing this callback once
* the current transaction is complete.
*/
fcopy_transaction.fcopy_context = context;
return; return;
}
fcopy_transaction.fcopy_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid); &requestid);
...@@ -275,7 +266,8 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -275,7 +266,8 @@ void hv_fcopy_onchannelcallback(void *context)
* Send the information to the user-level daemon. * Send the information to the user-level daemon.
*/ */
schedule_work(&fcopy_send_work); schedule_work(&fcopy_send_work);
schedule_delayed_work(&fcopy_timeout_work, 5*HZ); schedule_delayed_work(&fcopy_timeout_work,
HV_UTIL_TIMEOUT * HZ);
return; return;
} }
icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
...@@ -304,9 +296,8 @@ static int fcopy_on_msg(void *msg, int len) ...@@ -304,9 +296,8 @@ static int fcopy_on_msg(void *msg, int len)
if (cancel_delayed_work_sync(&fcopy_timeout_work)) { if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
fcopy_transaction.state = HVUTIL_USERSPACE_RECV; fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
fcopy_respond_to_host(*val); fcopy_respond_to_host(*val);
fcopy_transaction.state = HVUTIL_READY; hv_poll_channel(fcopy_transaction.recv_channel,
hv_poll_channel(fcopy_transaction.fcopy_context, fcopy_poll_wrapper);
hv_fcopy_onchannelcallback);
} }
return 0; return 0;
......
...@@ -66,7 +66,6 @@ static struct { ...@@ -66,7 +66,6 @@ static struct {
struct hv_kvp_msg *kvp_msg; /* current message */ struct hv_kvp_msg *kvp_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */ struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */ u64 recv_req_id; /* request ID. */
void *kvp_context; /* for the channel callback */
} kvp_transaction; } kvp_transaction;
/* /*
...@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt; ...@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt;
*/ */
#define HV_DRV_VERSION "3.1" #define HV_DRV_VERSION "3.1"
static void kvp_poll_wrapper(void *channel)
{
/* Transaction is finished, reset the state here to avoid races. */
kvp_transaction.state = HVUTIL_READY;
hv_kvp_onchannelcallback(channel);
}
static void static void
kvp_register(int reg_value) kvp_register(int reg_value)
{ {
...@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy) ...@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
*/ */
kvp_respond_to_host(NULL, HV_E_FAIL); kvp_respond_to_host(NULL, HV_E_FAIL);
/* Transaction is finished, reset the state. */ hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
if (kvp_transaction.state > HVUTIL_READY)
kvp_transaction.state = HVUTIL_READY;
hv_poll_channel(kvp_transaction.kvp_context,
hv_kvp_onchannelcallback);
} }
static int kvp_handle_handshake(struct hv_kvp_msg *msg) static int kvp_handle_handshake(struct hv_kvp_msg *msg)
...@@ -153,7 +154,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) ...@@ -153,7 +154,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
pr_debug("KVP: userspace daemon ver. %d registered\n", pr_debug("KVP: userspace daemon ver. %d registered\n",
KVP_OP_REGISTER); KVP_OP_REGISTER);
kvp_register(dm_reg_value); kvp_register(dm_reg_value);
kvp_transaction.state = HVUTIL_READY; hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
return 0; return 0;
} }
...@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len) ...@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len)
*/ */
if (cancel_delayed_work_sync(&kvp_timeout_work)) { if (cancel_delayed_work_sync(&kvp_timeout_work)) {
kvp_respond_to_host(message, error); kvp_respond_to_host(message, error);
kvp_transaction.state = HVUTIL_READY; hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
hv_poll_channel(kvp_transaction.kvp_context,
hv_kvp_onchannelcallback);
} }
return 0; return 0;
...@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context)
int util_fw_version; int util_fw_version;
int kvp_srv_version; int kvp_srv_version;
if (kvp_transaction.state > HVUTIL_READY) { if (kvp_transaction.state > HVUTIL_READY)
/*
* We will defer processing this callback once
* the current transaction is complete.
*/
kvp_transaction.kvp_context = context;
return; return;
}
kvp_transaction.kvp_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen, vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
&requestid); &requestid);
...@@ -668,7 +660,8 @@ void hv_kvp_onchannelcallback(void *context) ...@@ -668,7 +660,8 @@ void hv_kvp_onchannelcallback(void *context)
* user-mode not responding. * user-mode not responding.
*/ */
schedule_work(&kvp_sendkey_work); schedule_work(&kvp_sendkey_work);
schedule_delayed_work(&kvp_timeout_work, 5*HZ); schedule_delayed_work(&kvp_timeout_work,
HV_UTIL_TIMEOUT * HZ);
return; return;
......
...@@ -53,7 +53,6 @@ static struct { ...@@ -53,7 +53,6 @@ static struct {
struct vmbus_channel *recv_channel; /* chn we got the request */ struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */ u64 recv_req_id; /* request ID. */
struct hv_vss_msg *msg; /* current message */ struct hv_vss_msg *msg; /* current message */
void *vss_context; /* for the channel callback */
} vss_transaction; } vss_transaction;
...@@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy); ...@@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func); static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
static DECLARE_WORK(vss_send_op_work, vss_send_op); static DECLARE_WORK(vss_send_op_work, vss_send_op);
static void vss_poll_wrapper(void *channel)
{
/* Transaction is finished, reset the state here to avoid races. */
vss_transaction.state = HVUTIL_READY;
hv_vss_onchannelcallback(channel);
}
/* /*
* Callback when data is received from user mode. * Callback when data is received from user mode.
*/ */
...@@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy) ...@@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy)
pr_warn("VSS: timeout waiting for daemon to reply\n"); pr_warn("VSS: timeout waiting for daemon to reply\n");
vss_respond_to_host(HV_E_FAIL); vss_respond_to_host(HV_E_FAIL);
/* Transaction is finished, reset the state. */ hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
if (vss_transaction.state > HVUTIL_READY)
vss_transaction.state = HVUTIL_READY;
hv_poll_channel(vss_transaction.vss_context,
hv_vss_onchannelcallback);
} }
static int vss_handle_handshake(struct hv_vss_msg *vss_msg) static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
...@@ -112,7 +113,7 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg) ...@@ -112,7 +113,7 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
default: default:
return -EINVAL; return -EINVAL;
} }
vss_transaction.state = HVUTIL_READY; hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value); pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
return 0; return 0;
} }
...@@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len) ...@@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len)
if (cancel_delayed_work_sync(&vss_timeout_work)) { if (cancel_delayed_work_sync(&vss_timeout_work)) {
vss_respond_to_host(vss_msg->error); vss_respond_to_host(vss_msg->error);
/* Transaction is finished, reset the state. */ /* Transaction is finished, reset the state. */
vss_transaction.state = HVUTIL_READY; hv_poll_channel(vss_transaction.recv_channel,
hv_poll_channel(vss_transaction.vss_context, vss_poll_wrapper);
hv_vss_onchannelcallback);
} }
} else { } else {
/* This is a spurious call! */ /* This is a spurious call! */
...@@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context) ...@@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp; struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL; struct icmsg_negotiate *negop = NULL;
if (vss_transaction.state > HVUTIL_READY) { if (vss_transaction.state > HVUTIL_READY)
/*
* We will defer processing this callback once
* the current transaction is complete.
*/
vss_transaction.vss_context = context;
return; return;
}
vss_transaction.vss_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid); &requestid);
...@@ -338,6 +331,11 @@ static void vss_on_reset(void) ...@@ -338,6 +331,11 @@ static void vss_on_reset(void)
int int
hv_vss_init(struct hv_util_service *srv) hv_vss_init(struct hv_util_service *srv)
{ {
if (vmbus_proto_version < VERSION_WIN8_1) {
pr_warn("Integration service 'Backup (volume snapshot)'"
" not supported on this host version.\n");
return -ENOTSUPP;
}
recv_buffer = srv->recv_buffer; recv_buffer = srv->recv_buffer;
/* /*
......
...@@ -27,11 +27,9 @@ static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list); ...@@ -27,11 +27,9 @@ static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list);
static void hvt_reset(struct hvutil_transport *hvt) static void hvt_reset(struct hvutil_transport *hvt)
{ {
mutex_lock(&hvt->outmsg_lock);
kfree(hvt->outmsg); kfree(hvt->outmsg);
hvt->outmsg = NULL; hvt->outmsg = NULL;
hvt->outmsg_len = 0; hvt->outmsg_len = 0;
mutex_unlock(&hvt->outmsg_lock);
if (hvt->on_reset) if (hvt->on_reset)
hvt->on_reset(); hvt->on_reset();
} }
...@@ -44,10 +42,17 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, ...@@ -44,10 +42,17 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
hvt = container_of(file->f_op, struct hvutil_transport, fops); hvt = container_of(file->f_op, struct hvutil_transport, fops);
if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0)) if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0 ||
hvt->mode != HVUTIL_TRANSPORT_CHARDEV))
return -EINTR; return -EINTR;
mutex_lock(&hvt->outmsg_lock); mutex_lock(&hvt->lock);
if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
ret = -EBADF;
goto out_unlock;
}
if (!hvt->outmsg) { if (!hvt->outmsg) {
ret = -EAGAIN; ret = -EAGAIN;
goto out_unlock; goto out_unlock;
...@@ -68,7 +73,7 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, ...@@ -68,7 +73,7 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
hvt->outmsg_len = 0; hvt->outmsg_len = 0;
out_unlock: out_unlock:
mutex_unlock(&hvt->outmsg_lock); mutex_unlock(&hvt->lock);
return ret; return ret;
} }
...@@ -77,19 +82,22 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf, ...@@ -77,19 +82,22 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf,
{ {
struct hvutil_transport *hvt; struct hvutil_transport *hvt;
u8 *inmsg; u8 *inmsg;
int ret;
hvt = container_of(file->f_op, struct hvutil_transport, fops); hvt = container_of(file->f_op, struct hvutil_transport, fops);
inmsg = kzalloc(count, GFP_KERNEL); inmsg = memdup_user(buf, count);
if (copy_from_user(inmsg, buf, count)) { if (IS_ERR(inmsg))
kfree(inmsg); return PTR_ERR(inmsg);
return -EFAULT;
} if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
if (hvt->on_msg(inmsg, count)) ret = -EBADF;
return -EFAULT; else
ret = hvt->on_msg(inmsg, count);
kfree(inmsg); kfree(inmsg);
return count; return ret ? ret : count;
} }
static unsigned int hvt_op_poll(struct file *file, poll_table *wait) static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
...@@ -99,6 +107,10 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait) ...@@ -99,6 +107,10 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
hvt = container_of(file->f_op, struct hvutil_transport, fops); hvt = container_of(file->f_op, struct hvutil_transport, fops);
poll_wait(file, &hvt->outmsg_q, wait); poll_wait(file, &hvt->outmsg_q, wait);
if (hvt->mode == HVUTIL_TRANSPORT_DESTROY)
return POLLERR | POLLHUP;
if (hvt->outmsg_len > 0) if (hvt->outmsg_len > 0)
return POLLIN | POLLRDNORM; return POLLIN | POLLRDNORM;
...@@ -108,40 +120,68 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait) ...@@ -108,40 +120,68 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
static int hvt_op_open(struct inode *inode, struct file *file) static int hvt_op_open(struct inode *inode, struct file *file)
{ {
struct hvutil_transport *hvt; struct hvutil_transport *hvt;
int ret = 0;
bool issue_reset = false;
hvt = container_of(file->f_op, struct hvutil_transport, fops); hvt = container_of(file->f_op, struct hvutil_transport, fops);
/* mutex_lock(&hvt->lock);
* Switching to CHARDEV mode. We switch bach to INIT when device
* gets released. if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
*/ ret = -EBADF;
if (hvt->mode == HVUTIL_TRANSPORT_INIT) } else if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
/*
* Switching to CHARDEV mode. We switch bach to INIT when
* device gets released.
*/
hvt->mode = HVUTIL_TRANSPORT_CHARDEV; hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
}
else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
/* /*
* We're switching from netlink communication to using char * We're switching from netlink communication to using char
* device. Issue the reset first. * device. Issue the reset first.
*/ */
hvt_reset(hvt); issue_reset = true;
hvt->mode = HVUTIL_TRANSPORT_CHARDEV; hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
} else } else {
return -EBUSY; ret = -EBUSY;
}
return 0; if (issue_reset)
hvt_reset(hvt);
mutex_unlock(&hvt->lock);
return ret;
}
static void hvt_transport_free(struct hvutil_transport *hvt)
{
misc_deregister(&hvt->mdev);
kfree(hvt->outmsg);
kfree(hvt);
} }
static int hvt_op_release(struct inode *inode, struct file *file) static int hvt_op_release(struct inode *inode, struct file *file)
{ {
struct hvutil_transport *hvt; struct hvutil_transport *hvt;
int mode_old;
hvt = container_of(file->f_op, struct hvutil_transport, fops); hvt = container_of(file->f_op, struct hvutil_transport, fops);
hvt->mode = HVUTIL_TRANSPORT_INIT; mutex_lock(&hvt->lock);
mode_old = hvt->mode;
if (hvt->mode != HVUTIL_TRANSPORT_DESTROY)
hvt->mode = HVUTIL_TRANSPORT_INIT;
/* /*
* Cleanup message buffers to avoid spurious messages when the daemon * Cleanup message buffers to avoid spurious messages when the daemon
* connects back. * connects back.
*/ */
hvt_reset(hvt); hvt_reset(hvt);
mutex_unlock(&hvt->lock);
if (mode_old == HVUTIL_TRANSPORT_DESTROY)
hvt_transport_free(hvt);
return 0; return 0;
} }
...@@ -168,6 +208,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) ...@@ -168,6 +208,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
* Switching to NETLINK mode. Switching to CHARDEV happens when someone * Switching to NETLINK mode. Switching to CHARDEV happens when someone
* opens the device. * opens the device.
*/ */
mutex_lock(&hvt->lock);
if (hvt->mode == HVUTIL_TRANSPORT_INIT) if (hvt->mode == HVUTIL_TRANSPORT_INIT)
hvt->mode = HVUTIL_TRANSPORT_NETLINK; hvt->mode = HVUTIL_TRANSPORT_NETLINK;
...@@ -175,6 +216,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) ...@@ -175,6 +216,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
hvt_found->on_msg(msg->data, msg->len); hvt_found->on_msg(msg->data, msg->len);
else else
pr_warn("hvt_cn_callback: unexpected netlink message!\n"); pr_warn("hvt_cn_callback: unexpected netlink message!\n");
mutex_unlock(&hvt->lock);
} }
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
...@@ -182,7 +224,8 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) ...@@ -182,7 +224,8 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
struct cn_msg *cn_msg; struct cn_msg *cn_msg;
int ret = 0; int ret = 0;
if (hvt->mode == HVUTIL_TRANSPORT_INIT) { if (hvt->mode == HVUTIL_TRANSPORT_INIT ||
hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
return -EINVAL; return -EINVAL;
} else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { } else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC); cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC);
...@@ -197,18 +240,26 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) ...@@ -197,18 +240,26 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
return ret; return ret;
} }
/* HVUTIL_TRANSPORT_CHARDEV */ /* HVUTIL_TRANSPORT_CHARDEV */
mutex_lock(&hvt->outmsg_lock); mutex_lock(&hvt->lock);
if (hvt->mode != HVUTIL_TRANSPORT_CHARDEV) {
ret = -EINVAL;
goto out_unlock;
}
if (hvt->outmsg) { if (hvt->outmsg) {
/* Previous message wasn't received */ /* Previous message wasn't received */
ret = -EFAULT; ret = -EFAULT;
goto out_unlock; goto out_unlock;
} }
hvt->outmsg = kzalloc(len, GFP_KERNEL); hvt->outmsg = kzalloc(len, GFP_KERNEL);
memcpy(hvt->outmsg, msg, len); if (hvt->outmsg) {
hvt->outmsg_len = len; memcpy(hvt->outmsg, msg, len);
wake_up_interruptible(&hvt->outmsg_q); hvt->outmsg_len = len;
wake_up_interruptible(&hvt->outmsg_q);
} else
ret = -ENOMEM;
out_unlock: out_unlock:
mutex_unlock(&hvt->outmsg_lock); mutex_unlock(&hvt->lock);
return ret; return ret;
} }
...@@ -239,7 +290,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name, ...@@ -239,7 +290,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
hvt->mdev.fops = &hvt->fops; hvt->mdev.fops = &hvt->fops;
init_waitqueue_head(&hvt->outmsg_q); init_waitqueue_head(&hvt->outmsg_q);
mutex_init(&hvt->outmsg_lock); mutex_init(&hvt->lock);
spin_lock(&hvt_list_lock); spin_lock(&hvt_list_lock);
list_add(&hvt->list, &hvt_list); list_add(&hvt->list, &hvt_list);
...@@ -265,12 +316,25 @@ struct hvutil_transport *hvutil_transport_init(const char *name, ...@@ -265,12 +316,25 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
void hvutil_transport_destroy(struct hvutil_transport *hvt) void hvutil_transport_destroy(struct hvutil_transport *hvt)
{ {
int mode_old;
mutex_lock(&hvt->lock);
mode_old = hvt->mode;
hvt->mode = HVUTIL_TRANSPORT_DESTROY;
wake_up_interruptible(&hvt->outmsg_q);
mutex_unlock(&hvt->lock);
/*
* In case we were in 'chardev' mode we still have an open fd so we
* have to defer freeing the device. Netlink interface can be freed
* now.
*/
spin_lock(&hvt_list_lock); spin_lock(&hvt_list_lock);
list_del(&hvt->list); list_del(&hvt->list);
spin_unlock(&hvt_list_lock); spin_unlock(&hvt_list_lock);
if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0)
cn_del_callback(&hvt->cn_id); cn_del_callback(&hvt->cn_id);
misc_deregister(&hvt->mdev);
kfree(hvt->outmsg); if (mode_old != HVUTIL_TRANSPORT_CHARDEV)
kfree(hvt); hvt_transport_free(hvt);
} }
...@@ -25,6 +25,7 @@ enum hvutil_transport_mode { ...@@ -25,6 +25,7 @@ enum hvutil_transport_mode {
HVUTIL_TRANSPORT_INIT = 0, HVUTIL_TRANSPORT_INIT = 0,
HVUTIL_TRANSPORT_NETLINK, HVUTIL_TRANSPORT_NETLINK,
HVUTIL_TRANSPORT_CHARDEV, HVUTIL_TRANSPORT_CHARDEV,
HVUTIL_TRANSPORT_DESTROY,
}; };
struct hvutil_transport { struct hvutil_transport {
...@@ -38,7 +39,7 @@ struct hvutil_transport { ...@@ -38,7 +39,7 @@ struct hvutil_transport {
u8 *outmsg; /* message to the userspace */ u8 *outmsg; /* message to the userspace */
int outmsg_len; /* its length */ int outmsg_len; /* its length */
wait_queue_head_t outmsg_q; /* poll/read wait queue */ wait_queue_head_t outmsg_q; /* poll/read wait queue */
struct mutex outmsg_lock; /* protects outmsg */ struct mutex lock; /* protects struct members */
}; };
struct hvutil_transport *hvutil_transport_init(const char *name, struct hvutil_transport *hvutil_transport_init(const char *name,
......
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
/*
* Timeout for services such as KVP and fcopy.
*/
#define HV_UTIL_TIMEOUT 30
/* /*
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
* is set by CPUID(HVCPUID_VERSION_FEATURES). * is set by CPUID(HVCPUID_VERSION_FEATURES).
...@@ -496,7 +501,7 @@ extern int hv_post_message(union hv_connection_id connection_id, ...@@ -496,7 +501,7 @@ extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type, enum hv_message_type message_type,
void *payload, size_t payload_size); void *payload, size_t payload_size);
extern u16 hv_signal_event(void *con_id); extern int hv_signal_event(void *con_id);
extern int hv_synic_alloc(void); extern int hv_synic_alloc(void);
...@@ -528,14 +533,9 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, ...@@ -528,14 +533,9 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct kvec *kv_list, struct kvec *kv_list,
u32 kv_count, bool *signal); u32 kv_count, bool *signal);
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer, int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
u32 buflen); void *buffer, u32 buflen, u32 *buffer_actual_len,
u64 *requestid, bool *signal, bool raw);
int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
void *buffer,
u32 buflen,
u32 offset, bool *signal);
void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info); struct hv_ring_buffer_debug_info *debug_info);
...@@ -592,7 +592,7 @@ struct vmbus_connection { ...@@ -592,7 +592,7 @@ struct vmbus_connection {
/* List of channels */ /* List of channels */
struct list_head chn_list; struct list_head chn_list;
spinlock_t channel_lock; struct mutex channel_mutex;
struct workqueue_struct *work_queue; struct workqueue_struct *work_queue;
}; };
...@@ -673,11 +673,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel, ...@@ -673,11 +673,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
if (!channel) if (!channel)
return; return;
if (channel->target_cpu != smp_processor_id()) smp_call_function_single(channel->target_cpu, cb, channel, true);
smp_call_function_single(channel->target_cpu,
cb, channel, true);
else
cb(channel);
} }
enum hvutil_device_state { enum hvutil_device_state {
......
...@@ -112,9 +112,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz, ...@@ -112,9 +112,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz,
u32 read_loc = rbi->ring_buffer->read_index; u32 read_loc = rbi->ring_buffer->read_index;
u32 pending_sz = rbi->ring_buffer->pending_send_sz; u32 pending_sz = rbi->ring_buffer->pending_send_sz;
/* /* If the other end is not blocked on write don't bother. */
* If the other end is not blocked on write don't bother.
*/
if (pending_sz == 0) if (pending_sz == 0)
return false; return false;
...@@ -128,12 +126,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz, ...@@ -128,12 +126,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz,
return false; return false;
} }
/* /* Get the next write location for the specified ring buffer. */
* hv_get_next_write_location()
*
* Get the next write location for the specified ring buffer
*
*/
static inline u32 static inline u32
hv_get_next_write_location(struct hv_ring_buffer_info *ring_info) hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
{ {
...@@ -142,12 +135,7 @@ hv_get_next_write_location(struct hv_ring_buffer_info *ring_info) ...@@ -142,12 +135,7 @@ hv_get_next_write_location(struct hv_ring_buffer_info *ring_info)
return next; return next;
} }
/* /* Set the next write location for the specified ring buffer. */
* hv_set_next_write_location()
*
* Set the next write location for the specified ring buffer
*
*/
static inline void static inline void
hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
u32 next_write_location) u32 next_write_location)
...@@ -155,11 +143,7 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, ...@@ -155,11 +143,7 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->write_index = next_write_location; ring_info->ring_buffer->write_index = next_write_location;
} }
/* /* Get the next read location for the specified ring buffer. */
* hv_get_next_read_location()
*
* Get the next read location for the specified ring buffer
*/
static inline u32 static inline u32
hv_get_next_read_location(struct hv_ring_buffer_info *ring_info) hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
{ {
...@@ -169,10 +153,8 @@ hv_get_next_read_location(struct hv_ring_buffer_info *ring_info) ...@@ -169,10 +153,8 @@ hv_get_next_read_location(struct hv_ring_buffer_info *ring_info)
} }
/* /*
* hv_get_next_readlocation_withoffset()
*
* Get the next read location + offset for the specified ring buffer. * Get the next read location + offset for the specified ring buffer.
* This allows the caller to skip * This allows the caller to skip.
*/ */
static inline u32 static inline u32
hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
...@@ -186,13 +168,7 @@ hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, ...@@ -186,13 +168,7 @@ hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
return next; return next;
} }
/* /* Set the next read location for the specified ring buffer. */
*
* hv_set_next_read_location()
*
* Set the next read location for the specified ring buffer
*
*/
static inline void static inline void
hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
u32 next_read_location) u32 next_read_location)
...@@ -201,12 +177,7 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, ...@@ -201,12 +177,7 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
} }
/* /* Get the start of the ring buffer. */
*
* hv_get_ring_buffer()
*
* Get the start of the ring buffer
*/
static inline void * static inline void *
hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info) hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
{ {
...@@ -214,25 +185,14 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info) ...@@ -214,25 +185,14 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
} }
/* /* Get the size of the ring buffer. */
*
* hv_get_ring_buffersize()
*
* Get the size of the ring buffer
*/
static inline u32 static inline u32
hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info) hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
{ {
return ring_info->ring_datasize; return ring_info->ring_datasize;
} }
/* /* Get the read and write indices as u64 of the specified ring buffer. */
*
* hv_get_ring_bufferindices()
*
* Get the read and write indices as u64 of the specified ring buffer
*
*/
static inline u64 static inline u64
hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
{ {
...@@ -240,12 +200,8 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) ...@@ -240,12 +200,8 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
} }
/* /*
*
* hv_copyfrom_ringbuffer()
*
* Helper routine to copy to source from ring buffer. * Helper routine to copy to source from ring buffer.
* Assume there is enough room. Handles wrap-around in src case only!! * Assume there is enough room. Handles wrap-around in src case only!!
*
*/ */
static u32 hv_copyfrom_ringbuffer( static u32 hv_copyfrom_ringbuffer(
struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_info *ring_info,
...@@ -277,12 +233,8 @@ static u32 hv_copyfrom_ringbuffer( ...@@ -277,12 +233,8 @@ static u32 hv_copyfrom_ringbuffer(
/* /*
*
* hv_copyto_ringbuffer()
*
* Helper routine to copy from source to ring buffer. * Helper routine to copy from source to ring buffer.
* Assume there is enough room. Handles wrap-around in dest case only!! * Assume there is enough room. Handles wrap-around in dest case only!!
*
*/ */
static u32 hv_copyto_ringbuffer( static u32 hv_copyto_ringbuffer(
struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_info *ring_info,
...@@ -308,13 +260,7 @@ static u32 hv_copyto_ringbuffer( ...@@ -308,13 +260,7 @@ static u32 hv_copyto_ringbuffer(
return start_write_offset; return start_write_offset;
} }
/* /* Get various debug metrics for the specified ring buffer. */
*
* hv_ringbuffer_get_debuginfo()
*
* Get various debug metrics for the specified ring buffer
*
*/
void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info) struct hv_ring_buffer_debug_info *debug_info)
{ {
...@@ -337,13 +283,7 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, ...@@ -337,13 +283,7 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
} }
} }
/* /* Initialize the ring buffer. */
*
* hv_ringbuffer_init()
*
*Initialize the ring buffer
*
*/
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
void *buffer, u32 buflen) void *buffer, u32 buflen)
{ {
...@@ -356,9 +296,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -356,9 +296,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->read_index = ring_info->ring_buffer->read_index =
ring_info->ring_buffer->write_index = 0; ring_info->ring_buffer->write_index = 0;
/* /* Set the feature bit for enabling flow control. */
* Set the feature bit for enabling flow control.
*/
ring_info->ring_buffer->feature_bits.value = 1; ring_info->ring_buffer->feature_bits.value = 1;
ring_info->ring_size = buflen; ring_info->ring_size = buflen;
...@@ -369,24 +307,12 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -369,24 +307,12 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
return 0; return 0;
} }
/* /* Cleanup the ring buffer. */
*
* hv_ringbuffer_cleanup()
*
* Cleanup the ring buffer
*
*/
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{ {
} }
/* /* Write to the ring buffer. */
*
* hv_ringbuffer_write()
*
* Write to the ring buffer
*
*/
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct kvec *kv_list, u32 kv_count, bool *signal) struct kvec *kv_list, u32 kv_count, bool *signal)
{ {
...@@ -411,10 +337,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, ...@@ -411,10 +337,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
&bytes_avail_toread, &bytes_avail_toread,
&bytes_avail_towrite); &bytes_avail_towrite);
/*
/* If there is only room for the packet, assume it is full. */ * If there is only room for the packet, assume it is full.
/* Otherwise, the next time around, we think the ring buffer */ * Otherwise, the next time around, we think the ring buffer
/* is empty since the read index == write index */ * is empty since the read index == write index.
*/
if (bytes_avail_towrite <= totalbytes_towrite) { if (bytes_avail_towrite <= totalbytes_towrite) {
spin_unlock_irqrestore(&outring_info->ring_lock, flags); spin_unlock_irqrestore(&outring_info->ring_lock, flags);
return -EAGAIN; return -EAGAIN;
...@@ -453,80 +380,59 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, ...@@ -453,80 +380,59 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
return 0; return 0;
} }
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
/* void *buffer, u32 buflen, u32 *buffer_actual_len,
* u64 *requestid, bool *signal, bool raw)
* hv_ringbuffer_peek()
*
* Read without advancing the read index
*
*/
int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
void *Buffer, u32 buflen)
{
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 next_read_location = 0;
unsigned long flags;
spin_lock_irqsave(&Inring_info->ring_lock, flags);
hv_get_ringbuffer_availbytes(Inring_info,
&bytes_avail_toread,
&bytes_avail_towrite);
/* Make sure there is something to read */
if (bytes_avail_toread < buflen) {
spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
return -EAGAIN;
}
/* Convert to byte offset */
next_read_location = hv_get_next_read_location(Inring_info);
next_read_location = hv_copyfrom_ringbuffer(Inring_info,
Buffer,
buflen,
next_read_location);
spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
return 0;
}
/*
*
* hv_ringbuffer_read()
*
* Read and advance the read index
*
*/
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
u32 buflen, u32 offset, bool *signal)
{ {
u32 bytes_avail_towrite; u32 bytes_avail_towrite;
u32 bytes_avail_toread; u32 bytes_avail_toread;
u32 next_read_location = 0; u32 next_read_location = 0;
u64 prev_indices = 0; u64 prev_indices = 0;
unsigned long flags; unsigned long flags;
struct vmpacket_descriptor desc;
u32 offset;
u32 packetlen;
int ret = 0;
if (buflen <= 0) if (buflen <= 0)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&inring_info->ring_lock, flags); spin_lock_irqsave(&inring_info->ring_lock, flags);
*buffer_actual_len = 0;
*requestid = 0;
hv_get_ringbuffer_availbytes(inring_info, hv_get_ringbuffer_availbytes(inring_info,
&bytes_avail_toread, &bytes_avail_toread,
&bytes_avail_towrite); &bytes_avail_towrite);
/* Make sure there is something to read */ /* Make sure there is something to read */
if (bytes_avail_toread < buflen) { if (bytes_avail_toread < sizeof(desc)) {
spin_unlock_irqrestore(&inring_info->ring_lock, flags); /*
* No error is set when there is even no header, drivers are
* supposed to analyze buffer_actual_len.
*/
goto out_unlock;
}
return -EAGAIN; next_read_location = hv_get_next_read_location(inring_info);
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
sizeof(desc),
next_read_location);
offset = raw ? 0 : (desc.offset8 << 3);
packetlen = (desc.len8 << 3) - offset;
*buffer_actual_len = packetlen;
*requestid = desc.trans_id;
if (bytes_avail_toread < packetlen + offset) {
ret = -EAGAIN;
goto out_unlock;
}
if (packetlen > buflen) {
ret = -ENOBUFS;
goto out_unlock;
} }
next_read_location = next_read_location =
...@@ -534,7 +440,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, ...@@ -534,7 +440,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
next_read_location = hv_copyfrom_ringbuffer(inring_info, next_read_location = hv_copyfrom_ringbuffer(inring_info,
buffer, buffer,
buflen, packetlen,
next_read_location); next_read_location);
next_read_location = hv_copyfrom_ringbuffer(inring_info, next_read_location = hv_copyfrom_ringbuffer(inring_info,
...@@ -542,17 +448,19 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, ...@@ -542,17 +448,19 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
sizeof(u64), sizeof(u64),
next_read_location); next_read_location);
/* Make sure all reads are done before we update the read index since */ /*
/* the writer may start writing to the read area once the read index */ * Make sure all reads are done before we update the read index since
/*is updated */ * the writer may start writing to the read area once the read index
* is updated.
*/
mb(); mb();
/* Update the read index */ /* Update the read index */
hv_set_next_read_location(inring_info, next_read_location); hv_set_next_read_location(inring_info, next_read_location);
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
*signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info); *signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info);
return 0; out_unlock:
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
return ret;
} }
...@@ -47,7 +47,6 @@ static struct acpi_device *hv_acpi_dev; ...@@ -47,7 +47,6 @@ static struct acpi_device *hv_acpi_dev;
static struct tasklet_struct msg_dpc; static struct tasklet_struct msg_dpc;
static struct completion probe_event; static struct completion probe_event;
static int irq;
static void hyperv_report_panic(struct pt_regs *regs) static void hyperv_report_panic(struct pt_regs *regs)
...@@ -531,9 +530,9 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) ...@@ -531,9 +530,9 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
static const uuid_le null_guid; static const uuid_le null_guid;
static inline bool is_null_guid(const __u8 *guid) static inline bool is_null_guid(const uuid_le *guid)
{ {
if (memcmp(guid, &null_guid, sizeof(uuid_le))) if (uuid_le_cmp(*guid, null_guid))
return false; return false;
return true; return true;
} }
...@@ -544,10 +543,10 @@ static inline bool is_null_guid(const __u8 *guid) ...@@ -544,10 +543,10 @@ static inline bool is_null_guid(const __u8 *guid)
*/ */
static const struct hv_vmbus_device_id *hv_vmbus_get_id( static const struct hv_vmbus_device_id *hv_vmbus_get_id(
const struct hv_vmbus_device_id *id, const struct hv_vmbus_device_id *id,
const __u8 *guid) const uuid_le *guid)
{ {
for (; !is_null_guid(id->guid); id++) for (; !is_null_guid(&id->guid); id++)
if (!memcmp(&id->guid, guid, sizeof(uuid_le))) if (!uuid_le_cmp(id->guid, *guid))
return id; return id;
return NULL; return NULL;
...@@ -563,7 +562,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver) ...@@ -563,7 +562,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct hv_driver *drv = drv_to_hv_drv(driver); struct hv_driver *drv = drv_to_hv_drv(driver);
struct hv_device *hv_dev = device_to_hv_device(device); struct hv_device *hv_dev = device_to_hv_device(device);
if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b)) if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
return 1; return 1;
return 0; return 0;
...@@ -580,7 +579,7 @@ static int vmbus_probe(struct device *child_device) ...@@ -580,7 +579,7 @@ static int vmbus_probe(struct device *child_device)
struct hv_device *dev = device_to_hv_device(child_device); struct hv_device *dev = device_to_hv_device(child_device);
const struct hv_vmbus_device_id *dev_id; const struct hv_vmbus_device_id *dev_id;
dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b); dev_id = hv_vmbus_get_id(drv->id_table, &dev->dev_type);
if (drv->probe) { if (drv->probe) {
ret = drv->probe(dev, dev_id); ret = drv->probe(dev, dev_id);
if (ret != 0) if (ret != 0)
...@@ -602,23 +601,11 @@ static int vmbus_remove(struct device *child_device) ...@@ -602,23 +601,11 @@ static int vmbus_remove(struct device *child_device)
{ {
struct hv_driver *drv; struct hv_driver *drv;
struct hv_device *dev = device_to_hv_device(child_device); struct hv_device *dev = device_to_hv_device(child_device);
u32 relid = dev->channel->offermsg.child_relid;
if (child_device->driver) { if (child_device->driver) {
drv = drv_to_hv_drv(child_device->driver); drv = drv_to_hv_drv(child_device->driver);
if (drv->remove) if (drv->remove)
drv->remove(dev); drv->remove(dev);
else {
hv_process_channel_removal(dev->channel, relid);
pr_err("remove not set for driver %s\n",
dev_name(child_device));
}
} else {
/*
* We don't have a driver for this device; deal with the
* rescind message by removing the channel.
*/
hv_process_channel_removal(dev->channel, relid);
} }
return 0; return 0;
...@@ -653,7 +640,10 @@ static void vmbus_shutdown(struct device *child_device) ...@@ -653,7 +640,10 @@ static void vmbus_shutdown(struct device *child_device)
static void vmbus_device_release(struct device *device) static void vmbus_device_release(struct device *device)
{ {
struct hv_device *hv_dev = device_to_hv_device(device); struct hv_device *hv_dev = device_to_hv_device(device);
struct vmbus_channel *channel = hv_dev->channel;
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
kfree(hv_dev); kfree(hv_dev);
} }
...@@ -835,10 +825,9 @@ static void vmbus_isr(void) ...@@ -835,10 +825,9 @@ static void vmbus_isr(void)
* Here, we * Here, we
* - initialize the vmbus driver context * - initialize the vmbus driver context
* - invoke the vmbus hv main init routine * - invoke the vmbus hv main init routine
* - get the irq resource
* - retrieve the channel offers * - retrieve the channel offers
*/ */
static int vmbus_bus_init(int irq) static int vmbus_bus_init(void)
{ {
int ret; int ret;
...@@ -867,7 +856,7 @@ static int vmbus_bus_init(int irq) ...@@ -867,7 +856,7 @@ static int vmbus_bus_init(int irq)
on_each_cpu(hv_synic_init, NULL, 1); on_each_cpu(hv_synic_init, NULL, 1);
ret = vmbus_connect(); ret = vmbus_connect();
if (ret) if (ret)
goto err_alloc; goto err_connect;
if (vmbus_proto_version > VERSION_WIN7) if (vmbus_proto_version > VERSION_WIN7)
cpu_hotplug_disable(); cpu_hotplug_disable();
...@@ -885,6 +874,8 @@ static int vmbus_bus_init(int irq) ...@@ -885,6 +874,8 @@ static int vmbus_bus_init(int irq)
return 0; return 0;
err_connect:
on_each_cpu(hv_synic_cleanup, NULL, 1);
err_alloc: err_alloc:
hv_synic_free(); hv_synic_free();
hv_remove_vmbus_irq(); hv_remove_vmbus_irq();
...@@ -1031,9 +1022,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) ...@@ -1031,9 +1022,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
struct resource **prev_res = NULL; struct resource **prev_res = NULL;
switch (res->type) { switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
irq = res->data.irq.interrupts[0];
return AE_OK;
/* /*
* "Address" descriptors are for bus windows. Ignore * "Address" descriptors are for bus windows. Ignore
...@@ -1075,12 +1063,28 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) ...@@ -1075,12 +1063,28 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
new_res->start = start; new_res->start = start;
new_res->end = end; new_res->end = end;
/*
* Stick ranges from higher in address space at the front of the list.
* If two ranges are adjacent, merge them.
*/
do { do {
if (!*old_res) { if (!*old_res) {
*old_res = new_res; *old_res = new_res;
break; break;
} }
if (((*old_res)->end + 1) == new_res->start) {
(*old_res)->end = new_res->end;
kfree(new_res);
break;
}
if ((*old_res)->start == new_res->end + 1) {
(*old_res)->start = new_res->start;
kfree(new_res);
break;
}
if ((*old_res)->end < new_res->start) { if ((*old_res)->end < new_res->start) {
new_res->sibling = *old_res; new_res->sibling = *old_res;
if (prev_res) if (prev_res)
...@@ -1191,6 +1195,23 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -1191,6 +1195,23 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
} }
EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
/**
* vmbus_cpu_number_to_vp_number() - Map CPU to VP.
* @cpu_number: CPU number in Linux terms
*
* This function returns the mapping between the Linux processor
* number and the hypervisor's virtual processor number, useful
* in making hypercalls and such that talk about specific
* processors.
*
* Return: Virtual processor number in Hyper-V terms
*/
int vmbus_cpu_number_to_vp_number(int cpu_number)
{
return hv_context.vp_index[cpu_number];
}
EXPORT_SYMBOL_GPL(vmbus_cpu_number_to_vp_number);
static int vmbus_acpi_add(struct acpi_device *device) static int vmbus_acpi_add(struct acpi_device *device)
{ {
acpi_status result; acpi_status result;
...@@ -1275,7 +1296,7 @@ static int __init hv_acpi_init(void) ...@@ -1275,7 +1296,7 @@ static int __init hv_acpi_init(void)
init_completion(&probe_event); init_completion(&probe_event);
/* /*
* Get irq resources first. * Get ACPI resources first.
*/ */
ret = acpi_bus_register_driver(&vmbus_acpi_driver); ret = acpi_bus_register_driver(&vmbus_acpi_driver);
...@@ -1288,12 +1309,7 @@ static int __init hv_acpi_init(void) ...@@ -1288,12 +1309,7 @@ static int __init hv_acpi_init(void)
goto cleanup; goto cleanup;
} }
if (irq <= 0) { ret = vmbus_bus_init();
ret = -ENODEV;
goto cleanup;
}
ret = vmbus_bus_init(irq);
if (ret) if (ret)
goto cleanup; goto cleanup;
......
...@@ -8,7 +8,7 @@ menuconfig CORESIGHT ...@@ -8,7 +8,7 @@ menuconfig CORESIGHT
This framework provides a kernel interface for the CoreSight debug This framework provides a kernel interface for the CoreSight debug
and trace drivers to register themselves with. It's intended to build and trace drivers to register themselves with. It's intended to build
a topological view of the CoreSight components based on a DT a topological view of the CoreSight components based on a DT
specification and configure the right serie of components when a specification and configure the right series of components when a
trace source gets enabled. trace source gets enabled.
if CORESIGHT if CORESIGHT
......
...@@ -548,7 +548,7 @@ static int coresight_name_match(struct device *dev, void *data) ...@@ -548,7 +548,7 @@ static int coresight_name_match(struct device *dev, void *data)
to_match = data; to_match = data;
i_csdev = to_coresight_device(dev); i_csdev = to_coresight_device(dev);
if (!strcmp(to_match, dev_name(&i_csdev->dev))) if (to_match && !strcmp(to_match, dev_name(&i_csdev->dev)))
return 1; return 1;
return 0; return 0;
......
...@@ -412,16 +412,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev) ...@@ -412,16 +412,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
return 0; return 0;
} }
/*
* Keyboard GUID
* {f912ad6d-2b17-48ea-bd65-f927a61c7684}
*/
#define HV_KBD_GUID \
.guid = { \
0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \
0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \
}
static const struct hv_vmbus_device_id id_table[] = { static const struct hv_vmbus_device_id id_table[] = {
/* Keyboard guid */ /* Keyboard guid */
{ HV_KBD_GUID, }, { HV_KBD_GUID, },
......
...@@ -657,7 +657,9 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) ...@@ -657,7 +657,9 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
* @file: pointer to file structure * @file: pointer to file structure
* @band: band bitmap * @band: band bitmap
* *
* Return: poll mask * Return: negative on error,
* 0 if it did no changes,
* and positive a process was added or deleted
*/ */
static int mei_fasync(int fd, struct file *file, int band) static int mei_fasync(int fd, struct file *file, int band)
{ {
...@@ -665,7 +667,7 @@ static int mei_fasync(int fd, struct file *file, int band) ...@@ -665,7 +667,7 @@ static int mei_fasync(int fd, struct file *file, int band)
struct mei_cl *cl = file->private_data; struct mei_cl *cl = file->private_data;
if (!mei_cl_is_connected(cl)) if (!mei_cl_is_connected(cl))
return POLLERR; return -ENODEV;
return fasync_helper(fd, file, band, &cl->ev_async); return fasync_helper(fd, file, band, &cl->ev_async);
} }
......
This diff is collapsed.
...@@ -141,8 +141,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, ...@@ -141,8 +141,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
{ {
u32 read_loc, write_loc, dsize; u32 read_loc, write_loc, dsize;
smp_read_barrier_depends();
/* Capture the read/write indices before they changed */ /* Capture the read/write indices before they changed */
read_loc = rbi->ring_buffer->read_index; read_loc = rbi->ring_buffer->read_index;
write_loc = rbi->ring_buffer->write_index; write_loc = rbi->ring_buffer->write_index;
...@@ -630,6 +628,11 @@ struct hv_input_signal_event_buffer { ...@@ -630,6 +628,11 @@ struct hv_input_signal_event_buffer {
struct hv_input_signal_event event; struct hv_input_signal_event event;
}; };
enum hv_signal_policy {
HV_SIGNAL_POLICY_DEFAULT = 0,
HV_SIGNAL_POLICY_EXPLICIT,
};
struct vmbus_channel { struct vmbus_channel {
/* Unique channel id */ /* Unique channel id */
int id; int id;
...@@ -757,8 +760,21 @@ struct vmbus_channel { ...@@ -757,8 +760,21 @@ struct vmbus_channel {
* link up channels based on their CPU affinity. * link up channels based on their CPU affinity.
*/ */
struct list_head percpu_list; struct list_head percpu_list;
/*
* Host signaling policy: The default policy will be
* based on the ring buffer state. We will also support
* a policy where the client driver can have explicit
* signaling control.
*/
enum hv_signal_policy signal_policy;
}; };
static inline void set_channel_signal_state(struct vmbus_channel *c,
enum hv_signal_policy policy)
{
c->signal_policy = policy;
}
static inline void set_channel_read_state(struct vmbus_channel *c, bool state) static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
{ {
c->batched_reading = state; c->batched_reading = state;
...@@ -983,16 +999,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -983,16 +999,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
resource_size_t size, resource_size_t align, resource_size_t size, resource_size_t align,
bool fb_overlap_ok); bool fb_overlap_ok);
/** int vmbus_cpu_number_to_vp_number(int cpu_number);
* VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device u64 hv_do_hypercall(u64 control, void *input, void *output);
*
* This macro is used to create a struct hv_vmbus_device_id that matches a
* specific device.
*/
#define VMBUS_DEVICE(g0, g1, g2, g3, g4, g5, g6, g7, \
g8, g9, ga, gb, gc, gd, ge, gf) \
.guid = { g0, g1, g2, g3, g4, g5, g6, g7, \
g8, g9, ga, gb, gc, gd, ge, gf },
/* /*
* GUID definitions of various offer types - services offered to the guest. * GUID definitions of various offer types - services offered to the guest.
...@@ -1003,118 +1011,102 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -1003,118 +1011,102 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
* {f8615163-df3e-46c5-913f-f2d2f965ed0e} * {f8615163-df3e-46c5-913f-f2d2f965ed0e}
*/ */
#define HV_NIC_GUID \ #define HV_NIC_GUID \
.guid = { \ .guid = UUID_LE(0xf8615163, 0xdf3e, 0x46c5, 0x91, 0x3f, \
0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, \ 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e)
0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e \
}
/* /*
* IDE GUID * IDE GUID
* {32412632-86cb-44a2-9b5c-50d1417354f5} * {32412632-86cb-44a2-9b5c-50d1417354f5}
*/ */
#define HV_IDE_GUID \ #define HV_IDE_GUID \
.guid = { \ .guid = UUID_LE(0x32412632, 0x86cb, 0x44a2, 0x9b, 0x5c, \
0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \ 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5)
0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 \
}
/* /*
* SCSI GUID * SCSI GUID
* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} * {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
*/ */
#define HV_SCSI_GUID \ #define HV_SCSI_GUID \
.guid = { \ .guid = UUID_LE(0xba6163d9, 0x04a1, 0x4d29, 0xb6, 0x05, \
0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \ 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f)
0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f \
}
/* /*
* Shutdown GUID * Shutdown GUID
* {0e0b6031-5213-4934-818b-38d90ced39db} * {0e0b6031-5213-4934-818b-38d90ced39db}
*/ */
#define HV_SHUTDOWN_GUID \ #define HV_SHUTDOWN_GUID \
.guid = { \ .guid = UUID_LE(0x0e0b6031, 0x5213, 0x4934, 0x81, 0x8b, \
0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, \ 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb)
0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb \
}
/* /*
* Time Synch GUID * Time Synch GUID
* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} * {9527E630-D0AE-497b-ADCE-E80AB0175CAF}
*/ */
#define HV_TS_GUID \ #define HV_TS_GUID \
.guid = { \ .guid = UUID_LE(0x9527e630, 0xd0ae, 0x497b, 0xad, 0xce, \
0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, \ 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf \
}
/* /*
* Heartbeat GUID * Heartbeat GUID
* {57164f39-9115-4e78-ab55-382f3bd5422d} * {57164f39-9115-4e78-ab55-382f3bd5422d}
*/ */
#define HV_HEART_BEAT_GUID \ #define HV_HEART_BEAT_GUID \
.guid = { \ .guid = UUID_LE(0x57164f39, 0x9115, 0x4e78, 0xab, 0x55, \
0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, \ 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d \
}
/* /*
* KVP GUID * KVP GUID
* {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6} * {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}
*/ */
#define HV_KVP_GUID \ #define HV_KVP_GUID \
.guid = { \ .guid = UUID_LE(0xa9a0f4e7, 0x5a45, 0x4d96, 0xb8, 0x27, \
0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, \ 0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6)
0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6 \
}
/* /*
* Dynamic memory GUID * Dynamic memory GUID
* {525074dc-8985-46e2-8057-a307dc18a502} * {525074dc-8985-46e2-8057-a307dc18a502}
*/ */
#define HV_DM_GUID \ #define HV_DM_GUID \
.guid = { \ .guid = UUID_LE(0x525074dc, 0x8985, 0x46e2, 0x80, 0x57, \
0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, \ 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02)
0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02 \
}
/* /*
* Mouse GUID * Mouse GUID
* {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a} * {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}
*/ */
#define HV_MOUSE_GUID \ #define HV_MOUSE_GUID \
.guid = { \ .guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \
0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c, \ 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a)
0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a \
} /*
* Keyboard GUID
* {f912ad6d-2b17-48ea-bd65-f927a61c7684}
*/
#define HV_KBD_GUID \
.guid = UUID_LE(0xf912ad6d, 0x2b17, 0x48ea, 0xbd, 0x65, \
0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84)
/* /*
* VSS (Backup/Restore) GUID * VSS (Backup/Restore) GUID
*/ */
#define HV_VSS_GUID \ #define HV_VSS_GUID \
.guid = { \ .guid = UUID_LE(0x35fa2e29, 0xea23, 0x4236, 0x96, 0xae, \
0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \ 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40)
0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40 \
}
/* /*
* Synthetic Video GUID * Synthetic Video GUID
* {DA0A7802-E377-4aac-8E77-0558EB1073F8} * {DA0A7802-E377-4aac-8E77-0558EB1073F8}
*/ */
#define HV_SYNTHVID_GUID \ #define HV_SYNTHVID_GUID \
.guid = { \ .guid = UUID_LE(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \
0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \ 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8)
0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
}
/* /*
* Synthetic FC GUID * Synthetic FC GUID
* {2f9bcc4a-0069-4af3-b76b-6fd0be528cda} * {2f9bcc4a-0069-4af3-b76b-6fd0be528cda}
*/ */
#define HV_SYNTHFC_GUID \ #define HV_SYNTHFC_GUID \
.guid = { \ .guid = UUID_LE(0x2f9bcc4a, 0x0069, 0x4af3, 0xb7, 0x6b, \
0x4A, 0xCC, 0x9B, 0x2F, 0x69, 0x00, 0xF3, 0x4A, \ 0x6f, 0xd0, 0xbe, 0x52, 0x8c, 0xda)
0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \
}
/* /*
* Guest File Copy Service * Guest File Copy Service
...@@ -1122,20 +1114,25 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, ...@@ -1122,20 +1114,25 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
*/ */
#define HV_FCOPY_GUID \ #define HV_FCOPY_GUID \
.guid = { \ .guid = UUID_LE(0x34d14be3, 0xdee4, 0x41c8, 0x9a, 0xe7, \
0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \ 0x6b, 0x17, 0x49, 0x77, 0xc1, 0x92)
0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
}
/* /*
* NetworkDirect. This is the guest RDMA service. * NetworkDirect. This is the guest RDMA service.
* {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501} * {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}
*/ */
#define HV_ND_GUID \ #define HV_ND_GUID \
.guid = { \ .guid = UUID_LE(0x8c2eaf3d, 0x32a7, 0x4b09, 0xab, 0x99, \
0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \ 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01)
0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \
} /*
* PCI Express Pass Through
* {44C4F61D-4444-4400-9D52-802E27EDE19F}
*/
#define HV_PCIE_GUID \
.guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \
0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
/* /*
* Common header for Hyper-V ICs * Common header for Hyper-V ICs
......
...@@ -404,7 +404,7 @@ struct virtio_device_id { ...@@ -404,7 +404,7 @@ struct virtio_device_id {
* For Hyper-V devices we use the device guid as the id. * For Hyper-V devices we use the device guid as the id.
*/ */
struct hv_vmbus_device_id { struct hv_vmbus_device_id {
__u8 guid[16]; uuid_le guid;
kernel_ulong_t driver_data; /* Data private to the driver */ kernel_ulong_t driver_data; /* Data private to the driver */
}; };
......
...@@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool { ...@@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool {
#define HV_INVALIDARG 0x80070057 #define HV_INVALIDARG 0x80070057
#define HV_GUID_NOTFOUND 0x80041002 #define HV_GUID_NOTFOUND 0x80041002
#define HV_ERROR_ALREADY_EXISTS 0x80070050 #define HV_ERROR_ALREADY_EXISTS 0x80070050
#define HV_ERROR_DISK_FULL 0x80070070
#define ADDR_FAMILY_NONE 0x00 #define ADDR_FAMILY_NONE 0x00
#define ADDR_FAMILY_IPV4 0x01 #define ADDR_FAMILY_IPV4 0x01
......
This diff is collapsed.
...@@ -917,7 +917,7 @@ static int do_vmbus_entry(const char *filename, void *symval, ...@@ -917,7 +917,7 @@ static int do_vmbus_entry(const char *filename, void *symval,
char guid_name[(sizeof(*guid) + 1) * 2]; char guid_name[(sizeof(*guid) + 1) * 2];
for (i = 0; i < (sizeof(*guid) * 2); i += 2) for (i = 0; i < (sizeof(*guid) * 2); i += 2)
sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));
strcpy(alias, "vmbus:"); strcpy(alias, "vmbus:");
strcat(alias, guid_name); strcat(alias, guid_name);
......
...@@ -37,12 +37,14 @@ ...@@ -37,12 +37,14 @@
static int target_fd; static int target_fd;
static char target_fname[W_MAX_PATH]; static char target_fname[W_MAX_PATH];
static unsigned long long filesize;
static int hv_start_fcopy(struct hv_start_fcopy *smsg) static int hv_start_fcopy(struct hv_start_fcopy *smsg)
{ {
int error = HV_E_FAIL; int error = HV_E_FAIL;
char *q, *p; char *q, *p;
filesize = 0;
p = (char *)smsg->path_name; p = (char *)smsg->path_name;
snprintf(target_fname, sizeof(target_fname), "%s/%s", snprintf(target_fname, sizeof(target_fname), "%s/%s",
(char *)smsg->path_name, (char *)smsg->file_name); (char *)smsg->path_name, (char *)smsg->file_name);
...@@ -98,14 +100,26 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg) ...@@ -98,14 +100,26 @@ static int hv_start_fcopy(struct hv_start_fcopy *smsg)
static int hv_copy_data(struct hv_do_fcopy *cpmsg) static int hv_copy_data(struct hv_do_fcopy *cpmsg)
{ {
ssize_t bytes_written; ssize_t bytes_written;
int ret = 0;
bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
cpmsg->offset); cpmsg->offset);
if (bytes_written != cpmsg->size) filesize += cpmsg->size;
return HV_E_FAIL; if (bytes_written != cpmsg->size) {
switch (errno) {
case ENOSPC:
ret = HV_ERROR_DISK_FULL;
break;
default:
ret = HV_E_FAIL;
break;
}
syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
filesize, (long)bytes_written, strerror(errno));
}
return 0; return ret;
} }
static int hv_copy_finished(void) static int hv_copy_finished(void)
...@@ -165,7 +179,7 @@ int main(int argc, char *argv[]) ...@@ -165,7 +179,7 @@ int main(int argc, char *argv[])
} }
openlog("HV_FCOPY", 0, LOG_USER); openlog("HV_FCOPY", 0, LOG_USER);
syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); syslog(LOG_INFO, "starting; pid is:%d", getpid());
fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
...@@ -201,7 +215,7 @@ int main(int argc, char *argv[]) ...@@ -201,7 +215,7 @@ int main(int argc, char *argv[])
} }
kernel_modver = *(__u32 *)buffer; kernel_modver = *(__u32 *)buffer;
in_handshake = 0; in_handshake = 0;
syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d", syslog(LOG_INFO, "kernel module version: %d",
kernel_modver); kernel_modver);
continue; continue;
} }
......
...@@ -254,7 +254,7 @@ int main(int argc, char *argv[]) ...@@ -254,7 +254,7 @@ int main(int argc, char *argv[])
syslog(LOG_ERR, "Illegal op:%d\n", op); syslog(LOG_ERR, "Illegal op:%d\n", op);
} }
vss_msg->error = error; vss_msg->error = error;
len = write(vss_fd, &error, sizeof(struct hv_vss_msg)); len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
if (len != sizeof(struct hv_vss_msg)) { if (len != sizeof(struct hv_vss_msg)) {
syslog(LOG_ERR, "write failed; error: %d %s", errno, syslog(LOG_ERR, "write failed; error: %d %s", errno,
strerror(errno)); strerror(errno));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment