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);
if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
ret = -EBADF;
} else if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
/* /*
* Switching to CHARDEV mode. We switch bach to INIT when device * Switching to CHARDEV mode. We switch bach to INIT when
* gets released. * device gets released.
*/ */
if (hvt->mode == HVUTIL_TRANSPORT_INIT)
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);
mutex_lock(&hvt->lock);
mode_old = hvt->mode;
if (hvt->mode != HVUTIL_TRANSPORT_DESTROY)
hvt->mode = HVUTIL_TRANSPORT_INIT; 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);
if (hvt->outmsg) {
memcpy(hvt->outmsg, msg, len); memcpy(hvt->outmsg, msg, len);
hvt->outmsg_len = len; hvt->outmsg_len = len;
wake_up_interruptible(&hvt->outmsg_q); 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);
} }
......
...@@ -54,16 +54,16 @@ static LIST_HEAD(drivers); ...@@ -54,16 +54,16 @@ static LIST_HEAD(drivers);
static DEFINE_MUTEX(registration_lock); static DEFINE_MUTEX(registration_lock);
/* What you can do to a port that's gone away.. */ /* What you can do to a port that's gone away.. */
static void dead_write_lines (struct parport *p, unsigned char b){} static void dead_write_lines(struct parport *p, unsigned char b){}
static unsigned char dead_read_lines (struct parport *p) { return 0; } static unsigned char dead_read_lines(struct parport *p) { return 0; }
static unsigned char dead_frob_lines (struct parport *p, unsigned char b, static unsigned char dead_frob_lines(struct parport *p, unsigned char b,
unsigned char c) { return 0; } unsigned char c) { return 0; }
static void dead_onearg (struct parport *p){} static void dead_onearg(struct parport *p){}
static void dead_initstate (struct pardevice *d, struct parport_state *s) { } static void dead_initstate(struct pardevice *d, struct parport_state *s) { }
static void dead_state (struct parport *p, struct parport_state *s) { } static void dead_state(struct parport *p, struct parport_state *s) { }
static size_t dead_write (struct parport *p, const void *b, size_t l, int f) static size_t dead_write(struct parport *p, const void *b, size_t l, int f)
{ return 0; } { return 0; }
static size_t dead_read (struct parport *p, void *b, size_t l, int f) static size_t dead_read(struct parport *p, void *b, size_t l, int f)
{ return 0; } { return 0; }
static struct parport_operations dead_ops = { static struct parport_operations dead_ops = {
.write_data = dead_write_lines, /* data */ .write_data = dead_write_lines, /* data */
...@@ -148,7 +148,7 @@ void parport_bus_exit(void) ...@@ -148,7 +148,7 @@ void parport_bus_exit(void)
/* /*
* iterates through all the drivers registered with the bus and sends the port * iterates through all the drivers registered with the bus and sends the port
* details to the match_port callback of the driver, so that the driver can * details to the match_port callback of the driver, so that the driver can
* know about the new port that just regsitered with the bus and decide if it * know about the new port that just registered with the bus and decide if it
* wants to use this new port. * wants to use this new port.
*/ */
static int driver_check(struct device_driver *dev_drv, void *_port) static int driver_check(struct device_driver *dev_drv, void *_port)
...@@ -194,7 +194,7 @@ static void detach_driver_chain(struct parport *port) ...@@ -194,7 +194,7 @@ static void detach_driver_chain(struct parport *port)
struct parport_driver *drv; struct parport_driver *drv;
/* caller has exclusive registration_lock */ /* caller has exclusive registration_lock */
list_for_each_entry(drv, &drivers, list) list_for_each_entry(drv, &drivers, list)
drv->detach (port); drv->detach(port);
/* /*
* call the detach function of the drivers registered in * call the detach function of the drivers registered in
...@@ -205,11 +205,13 @@ static void detach_driver_chain(struct parport *port) ...@@ -205,11 +205,13 @@ static void detach_driver_chain(struct parport *port)
} }
/* Ask kmod for some lowlevel drivers. */ /* Ask kmod for some lowlevel drivers. */
static void get_lowlevel_driver (void) static void get_lowlevel_driver(void)
{ {
/* There is no actual module called this: you should set /*
* up an alias for modutils. */ * There is no actual module called this: you should set
request_module ("parport_lowlevel"); * up an alias for modutils.
*/
request_module("parport_lowlevel");
} }
/* /*
...@@ -265,7 +267,7 @@ int __parport_register_driver(struct parport_driver *drv, struct module *owner, ...@@ -265,7 +267,7 @@ int __parport_register_driver(struct parport_driver *drv, struct module *owner,
const char *mod_name) const char *mod_name)
{ {
if (list_empty(&portlist)) if (list_empty(&portlist))
get_lowlevel_driver (); get_lowlevel_driver();
if (drv->devmodel) { if (drv->devmodel) {
/* using device model */ /* using device model */
...@@ -328,7 +330,7 @@ static int port_detach(struct device *dev, void *_drv) ...@@ -328,7 +330,7 @@ static int port_detach(struct device *dev, void *_drv)
* finished by the time this function returns. * finished by the time this function returns.
**/ **/
void parport_unregister_driver (struct parport_driver *drv) void parport_unregister_driver(struct parport_driver *drv)
{ {
struct parport *port; struct parport *port;
...@@ -343,6 +345,7 @@ void parport_unregister_driver (struct parport_driver *drv) ...@@ -343,6 +345,7 @@ void parport_unregister_driver (struct parport_driver *drv)
} }
mutex_unlock(&registration_lock); mutex_unlock(&registration_lock);
} }
EXPORT_SYMBOL(parport_unregister_driver);
static void free_port(struct device *dev) static void free_port(struct device *dev)
{ {
...@@ -372,12 +375,13 @@ static void free_port(struct device *dev) ...@@ -372,12 +375,13 @@ static void free_port(struct device *dev)
* until the matching parport_put_port() call. * until the matching parport_put_port() call.
**/ **/
struct parport *parport_get_port (struct parport *port) struct parport *parport_get_port(struct parport *port)
{ {
struct device *dev = get_device(&port->bus_dev); struct device *dev = get_device(&port->bus_dev);
return to_parport_dev(dev); return to_parport_dev(dev);
} }
EXPORT_SYMBOL(parport_get_port);
void parport_del_port(struct parport *port) void parport_del_port(struct parport *port)
{ {
...@@ -394,10 +398,11 @@ EXPORT_SYMBOL(parport_del_port); ...@@ -394,10 +398,11 @@ EXPORT_SYMBOL(parport_del_port);
* zero (port is no longer used), free_port is called. * zero (port is no longer used), free_port is called.
**/ **/
void parport_put_port (struct parport *port) void parport_put_port(struct parport *port)
{ {
put_device(&port->bus_dev); put_device(&port->bus_dev);
} }
EXPORT_SYMBOL(parport_put_port);
/** /**
* parport_register_port - register a parallel port * parport_register_port - register a parallel port
...@@ -439,10 +444,8 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, ...@@ -439,10 +444,8 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
int ret; int ret;
tmp = kzalloc(sizeof(struct parport), GFP_KERNEL); tmp = kzalloc(sizeof(struct parport), GFP_KERNEL);
if (!tmp) { if (!tmp)
printk(KERN_WARNING "parport: memory squeeze\n");
return NULL; return NULL;
}
/* Init our structure */ /* Init our structure */
tmp->base = base; tmp->base = base;
...@@ -455,7 +458,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, ...@@ -455,7 +458,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->flags = 0; tmp->flags = 0;
tmp->ops = ops; tmp->ops = ops;
tmp->physport = tmp; tmp->physport = tmp;
memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info)); memset(tmp->probe_info, 0, 5 * sizeof(struct parport_device_info));
rwlock_init(&tmp->cad_lock); rwlock_init(&tmp->cad_lock);
spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->waitlist_lock);
spin_lock_init(&tmp->pardevice_lock); spin_lock_init(&tmp->pardevice_lock);
...@@ -463,12 +466,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, ...@@ -463,12 +466,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
sema_init(&tmp->ieee1284.irq, 0); sema_init(&tmp->ieee1284.irq, 0);
tmp->spintime = parport_default_spintime; tmp->spintime = parport_default_spintime;
atomic_set (&tmp->ref_count, 1); atomic_set(&tmp->ref_count, 1);
INIT_LIST_HEAD(&tmp->full_list); INIT_LIST_HEAD(&tmp->full_list);
name = kmalloc(15, GFP_KERNEL); name = kmalloc(15, GFP_KERNEL);
if (!name) { if (!name) {
printk(KERN_ERR "parport: memory squeeze\n");
kfree(tmp); kfree(tmp);
return NULL; return NULL;
} }
...@@ -508,6 +510,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, ...@@ -508,6 +510,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
return tmp; return tmp;
} }
EXPORT_SYMBOL(parport_register_port);
/** /**
* parport_announce_port - tell device drivers about a parallel port * parport_announce_port - tell device drivers about a parallel port
...@@ -521,7 +524,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, ...@@ -521,7 +524,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
* functions will be called, with @port as the parameter. * functions will be called, with @port as the parameter.
**/ **/
void parport_announce_port (struct parport *port) void parport_announce_port(struct parport *port)
{ {
int i; int i;
...@@ -531,8 +534,7 @@ void parport_announce_port (struct parport *port) ...@@ -531,8 +534,7 @@ void parport_announce_port (struct parport *port)
#endif #endif
if (!port->dev) if (!port->dev)
printk(KERN_WARNING "%s: fix this legacy " printk(KERN_WARNING "%s: fix this legacy no-device port driver!\n",
"no-device port driver!\n",
port->name); port->name);
parport_proc_register(port); parport_proc_register(port);
...@@ -547,7 +549,7 @@ void parport_announce_port (struct parport *port) ...@@ -547,7 +549,7 @@ void parport_announce_port (struct parport *port)
spin_unlock_irq(&parportlist_lock); spin_unlock_irq(&parportlist_lock);
/* Let drivers know that new port(s) has arrived. */ /* Let drivers know that new port(s) has arrived. */
attach_driver_chain (port); attach_driver_chain(port);
for (i = 1; i < 3; i++) { for (i = 1; i < 3; i++) {
struct parport *slave = port->slaves[i-1]; struct parport *slave = port->slaves[i-1];
if (slave) if (slave)
...@@ -555,6 +557,7 @@ void parport_announce_port (struct parport *port) ...@@ -555,6 +557,7 @@ void parport_announce_port (struct parport *port)
} }
mutex_unlock(&registration_lock); mutex_unlock(&registration_lock);
} }
EXPORT_SYMBOL(parport_announce_port);
/** /**
* parport_remove_port - deregister a parallel port * parport_remove_port - deregister a parallel port
...@@ -582,7 +585,7 @@ void parport_remove_port(struct parport *port) ...@@ -582,7 +585,7 @@ void parport_remove_port(struct parport *port)
mutex_lock(&registration_lock); mutex_lock(&registration_lock);
/* Spread the word. */ /* Spread the word. */
detach_driver_chain (port); detach_driver_chain(port);
#ifdef CONFIG_PARPORT_1284 #ifdef CONFIG_PARPORT_1284
/* Forget the IEEE1284.3 topology of the port. */ /* Forget the IEEE1284.3 topology of the port. */
...@@ -616,6 +619,7 @@ void parport_remove_port(struct parport *port) ...@@ -616,6 +619,7 @@ void parport_remove_port(struct parport *port)
parport_put_port(slave); parport_put_port(slave);
} }
} }
EXPORT_SYMBOL(parport_remove_port);
/** /**
* parport_register_device - register a device on a parallel port * parport_register_device - register a device on a parallel port
...@@ -696,7 +700,7 @@ parport_register_device(struct parport *port, const char *name, ...@@ -696,7 +700,7 @@ parport_register_device(struct parport *port, const char *name,
if (port->physport->flags & PARPORT_FLAG_EXCL) { if (port->physport->flags & PARPORT_FLAG_EXCL) {
/* An exclusive device is registered. */ /* An exclusive device is registered. */
printk (KERN_DEBUG "%s: no more devices allowed\n", printk(KERN_DEBUG "%s: no more devices allowed\n",
port->name); port->name);
return NULL; return NULL;
} }
...@@ -722,28 +726,24 @@ parport_register_device(struct parport *port, const char *name, ...@@ -722,28 +726,24 @@ parport_register_device(struct parport *port, const char *name,
} }
} }
/* We up our own module reference count, and that of the port /*
on which a device is to be registered, to ensure that * We up our own module reference count, and that of the port
neither of us gets unloaded while we sleep in (e.g.) * on which a device is to be registered, to ensure that
kmalloc. * neither of us gets unloaded while we sleep in (e.g.)
* kmalloc.
*/ */
if (!try_module_get(port->ops->owner)) { if (!try_module_get(port->ops->owner))
return NULL; return NULL;
}
parport_get_port (port); parport_get_port(port);
tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
if (tmp == NULL) { if (!tmp)
printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
goto out; goto out;
}
tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
if (tmp->state == NULL) { if (!tmp->state)
printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
goto out_free_pardevice; goto out_free_pardevice;
}
tmp->name = name; tmp->name = name;
tmp->port = port; tmp->port = port;
...@@ -767,19 +767,21 @@ parport_register_device(struct parport *port, const char *name, ...@@ -767,19 +767,21 @@ parport_register_device(struct parport *port, const char *name,
if (flags & PARPORT_DEV_EXCL) { if (flags & PARPORT_DEV_EXCL) {
if (port->physport->devices) { if (port->physport->devices) {
spin_unlock (&port->physport->pardevice_lock); spin_unlock(&port->physport->pardevice_lock);
printk (KERN_DEBUG printk(KERN_DEBUG
"%s: cannot grant exclusive access for " "%s: cannot grant exclusive access for device %s\n",
"device %s\n", port->name, name); port->name, name);
goto out_free_all; goto out_free_all;
} }
port->flags |= PARPORT_FLAG_EXCL; port->flags |= PARPORT_FLAG_EXCL;
} }
tmp->next = port->physport->devices; tmp->next = port->physport->devices;
wmb(); /* Make sure that tmp->next is written before it's wmb(); /*
added to the list; see comments marked 'no locking * Make sure that tmp->next is written before it's
required' */ * added to the list; see comments marked 'no locking
* required'
*/
if (port->physport->devices) if (port->physport->devices)
port->physport->devices->prev = tmp; port->physport->devices->prev = tmp;
port->physport->devices = tmp; port->physport->devices = tmp;
...@@ -805,11 +807,12 @@ parport_register_device(struct parport *port, const char *name, ...@@ -805,11 +807,12 @@ parport_register_device(struct parport *port, const char *name,
out_free_pardevice: out_free_pardevice:
kfree(tmp); kfree(tmp);
out: out:
parport_put_port (port); parport_put_port(port);
module_put(port->ops->owner); module_put(port->ops->owner);
return NULL; return NULL;
} }
EXPORT_SYMBOL(parport_register_device);
static void free_pardevice(struct device *dev) static void free_pardevice(struct device *dev)
{ {
...@@ -968,7 +971,7 @@ void parport_unregister_device(struct pardevice *dev) ...@@ -968,7 +971,7 @@ void parport_unregister_device(struct pardevice *dev)
struct parport *port; struct parport *port;
#ifdef PARPORT_PARANOID #ifdef PARPORT_PARANOID
if (dev == NULL) { if (!dev) {
printk(KERN_ERR "parport_unregister_device: passed NULL\n"); printk(KERN_ERR "parport_unregister_device: passed NULL\n");
return; return;
} }
...@@ -985,7 +988,7 @@ void parport_unregister_device(struct pardevice *dev) ...@@ -985,7 +988,7 @@ void parport_unregister_device(struct pardevice *dev)
if (port->cad == dev) { if (port->cad == dev) {
printk(KERN_DEBUG "%s: %s forgot to release port\n", printk(KERN_DEBUG "%s: %s forgot to release port\n",
port->name, dev->name); port->name, dev->name);
parport_release (dev); parport_release(dev);
} }
spin_lock(&port->pardevice_lock); spin_lock(&port->pardevice_lock);
...@@ -1001,8 +1004,10 @@ void parport_unregister_device(struct pardevice *dev) ...@@ -1001,8 +1004,10 @@ void parport_unregister_device(struct pardevice *dev)
spin_unlock(&port->pardevice_lock); spin_unlock(&port->pardevice_lock);
/* Make sure we haven't left any pointers around in the wait /*
* list. */ * Make sure we haven't left any pointers around in the wait
* list.
*/
spin_lock_irq(&port->waitlist_lock); spin_lock_irq(&port->waitlist_lock);
if (dev->waitprev || dev->waitnext || port->waithead == dev) { if (dev->waitprev || dev->waitnext || port->waithead == dev) {
if (dev->waitprev) if (dev->waitprev)
...@@ -1023,8 +1028,9 @@ void parport_unregister_device(struct pardevice *dev) ...@@ -1023,8 +1028,9 @@ void parport_unregister_device(struct pardevice *dev)
kfree(dev); kfree(dev);
module_put(port->ops->owner); module_put(port->ops->owner);
parport_put_port (port); parport_put_port(port);
} }
EXPORT_SYMBOL(parport_unregister_device);
/** /**
* parport_find_number - find a parallel port by number * parport_find_number - find a parallel port by number
...@@ -1038,23 +1044,24 @@ void parport_unregister_device(struct pardevice *dev) ...@@ -1038,23 +1044,24 @@ void parport_unregister_device(struct pardevice *dev)
* gives you, use parport_put_port(). * gives you, use parport_put_port().
*/ */
struct parport *parport_find_number (int number) struct parport *parport_find_number(int number)
{ {
struct parport *port, *result = NULL; struct parport *port, *result = NULL;
if (list_empty(&portlist)) if (list_empty(&portlist))
get_lowlevel_driver (); get_lowlevel_driver();
spin_lock (&parportlist_lock); spin_lock(&parportlist_lock);
list_for_each_entry(port, &portlist, list) { list_for_each_entry(port, &portlist, list) {
if (port->number == number) { if (port->number == number) {
result = parport_get_port (port); result = parport_get_port(port);
break; break;
} }
} }
spin_unlock (&parportlist_lock); spin_unlock(&parportlist_lock);
return result; return result;
} }
EXPORT_SYMBOL(parport_find_number);
/** /**
* parport_find_base - find a parallel port by base address * parport_find_base - find a parallel port by base address
...@@ -1068,23 +1075,24 @@ struct parport *parport_find_number (int number) ...@@ -1068,23 +1075,24 @@ struct parport *parport_find_number (int number)
* gives you, use parport_put_port(). * gives you, use parport_put_port().
*/ */
struct parport *parport_find_base (unsigned long base) struct parport *parport_find_base(unsigned long base)
{ {
struct parport *port, *result = NULL; struct parport *port, *result = NULL;
if (list_empty(&portlist)) if (list_empty(&portlist))
get_lowlevel_driver (); get_lowlevel_driver();
spin_lock (&parportlist_lock); spin_lock(&parportlist_lock);
list_for_each_entry(port, &portlist, list) { list_for_each_entry(port, &portlist, list) {
if (port->base == base) { if (port->base == base) {
result = parport_get_port (port); result = parport_get_port(port);
break; break;
} }
} }
spin_unlock (&parportlist_lock); spin_unlock(&parportlist_lock);
return result; return result;
} }
EXPORT_SYMBOL(parport_find_base);
/** /**
* parport_claim - claim access to a parallel port device * parport_claim - claim access to a parallel port device
...@@ -1111,8 +1119,9 @@ int parport_claim(struct pardevice *dev) ...@@ -1111,8 +1119,9 @@ int parport_claim(struct pardevice *dev)
} }
/* Preempt any current device */ /* Preempt any current device */
write_lock_irqsave (&port->cad_lock, flags); write_lock_irqsave(&port->cad_lock, flags);
if ((oldcad = port->cad) != NULL) { oldcad = port->cad;
if (oldcad) {
if (oldcad->preempt) { if (oldcad->preempt) {
if (oldcad->preempt(oldcad->private)) if (oldcad->preempt(oldcad->private))
goto blocked; goto blocked;
...@@ -1121,8 +1130,10 @@ int parport_claim(struct pardevice *dev) ...@@ -1121,8 +1130,10 @@ int parport_claim(struct pardevice *dev)
goto blocked; goto blocked;
if (port->cad != oldcad) { if (port->cad != oldcad) {
/* I think we'll actually deadlock rather than /*
get here, but just in case.. */ * I think we'll actually deadlock rather than
* get here, but just in case..
*/
printk(KERN_WARNING printk(KERN_WARNING
"%s: %s released port when preempted!\n", "%s: %s released port when preempted!\n",
port->name, oldcad->name); port->name, oldcad->name);
...@@ -1136,7 +1147,7 @@ int parport_claim(struct pardevice *dev) ...@@ -1136,7 +1147,7 @@ int parport_claim(struct pardevice *dev)
dev->waiting = 0; dev->waiting = 0;
/* Take ourselves out of the wait list again. */ /* Take ourselves out of the wait list again. */
spin_lock_irq (&port->waitlist_lock); spin_lock_irq(&port->waitlist_lock);
if (dev->waitprev) if (dev->waitprev)
dev->waitprev->waitnext = dev->waitnext; dev->waitprev->waitnext = dev->waitnext;
else else
...@@ -1145,7 +1156,7 @@ int parport_claim(struct pardevice *dev) ...@@ -1145,7 +1156,7 @@ int parport_claim(struct pardevice *dev)
dev->waitnext->waitprev = dev->waitprev; dev->waitnext->waitprev = dev->waitprev;
else else
port->waittail = dev->waitprev; port->waittail = dev->waitprev;
spin_unlock_irq (&port->waitlist_lock); spin_unlock_irq(&port->waitlist_lock);
dev->waitprev = dev->waitnext = NULL; dev->waitprev = dev->waitnext = NULL;
} }
...@@ -1162,7 +1173,7 @@ int parport_claim(struct pardevice *dev) ...@@ -1162,7 +1173,7 @@ int parport_claim(struct pardevice *dev)
/* If it's a daisy chain device, select it. */ /* If it's a daisy chain device, select it. */
if (dev->daisy >= 0) { if (dev->daisy >= 0) {
/* This could be lazier. */ /* This could be lazier. */
if (!parport_daisy_select (port, dev->daisy, if (!parport_daisy_select(port, dev->daisy,
IEEE1284_MODE_COMPAT)) IEEE1284_MODE_COMPAT))
port->daisy = dev->daisy; port->daisy = dev->daisy;
} }
...@@ -1175,13 +1186,15 @@ int parport_claim(struct pardevice *dev) ...@@ -1175,13 +1186,15 @@ int parport_claim(struct pardevice *dev)
return 0; return 0;
blocked: blocked:
/* If this is the first time we tried to claim the port, register an /*
interest. This is only allowed for devices sleeping in * If this is the first time we tried to claim the port, register an
parport_claim_or_block(), or those with a wakeup function. */ * interest. This is only allowed for devices sleeping in
* parport_claim_or_block(), or those with a wakeup function.
*/
/* The cad_lock is still held for writing here */ /* The cad_lock is still held for writing here */
if (dev->waiting & 2 || dev->wakeup) { if (dev->waiting & 2 || dev->wakeup) {
spin_lock (&port->waitlist_lock); spin_lock(&port->waitlist_lock);
if (test_and_set_bit(0, &dev->waiting) == 0) { if (test_and_set_bit(0, &dev->waiting) == 0) {
/* First add ourselves to the end of the wait list. */ /* First add ourselves to the end of the wait list. */
dev->waitnext = NULL; dev->waitnext = NULL;
...@@ -1192,11 +1205,12 @@ int parport_claim(struct pardevice *dev) ...@@ -1192,11 +1205,12 @@ int parport_claim(struct pardevice *dev)
} else } else
port->waithead = port->waittail = dev; port->waithead = port->waittail = dev;
} }
spin_unlock (&port->waitlist_lock); spin_unlock(&port->waitlist_lock);
} }
write_unlock_irqrestore (&port->cad_lock, flags); write_unlock_irqrestore(&port->cad_lock, flags);
return -EAGAIN; return -EAGAIN;
} }
EXPORT_SYMBOL(parport_claim);
/** /**
* parport_claim_or_block - claim access to a parallel port device * parport_claim_or_block - claim access to a parallel port device
...@@ -1212,8 +1226,10 @@ int parport_claim_or_block(struct pardevice *dev) ...@@ -1212,8 +1226,10 @@ int parport_claim_or_block(struct pardevice *dev)
{ {
int r; int r;
/* Signal to parport_claim() that we can wait even without a /*
wakeup function. */ * Signal to parport_claim() that we can wait even without a
* wakeup function.
*/
dev->waiting = 2; dev->waiting = 2;
/* Try to claim the port. If this fails, we need to sleep. */ /* Try to claim the port. If this fails, we need to sleep. */
...@@ -1231,14 +1247,15 @@ int parport_claim_or_block(struct pardevice *dev) ...@@ -1231,14 +1247,15 @@ int parport_claim_or_block(struct pardevice *dev)
* See also parport_release() * See also parport_release()
*/ */
/* If dev->waiting is clear now, an interrupt /*
gave us the port and we would deadlock if we slept. */ * If dev->waiting is clear now, an interrupt
* gave us the port and we would deadlock if we slept.
*/
if (dev->waiting) { if (dev->waiting) {
wait_event_interruptible(dev->wait_q, wait_event_interruptible(dev->wait_q,
!dev->waiting); !dev->waiting);
if (signal_pending (current)) { if (signal_pending(current))
return -EINTR; return -EINTR;
}
r = 1; r = 1;
} else { } else {
r = 0; r = 0;
...@@ -1250,15 +1267,15 @@ int parport_claim_or_block(struct pardevice *dev) ...@@ -1250,15 +1267,15 @@ int parport_claim_or_block(struct pardevice *dev)
#ifdef PARPORT_DEBUG_SHARING #ifdef PARPORT_DEBUG_SHARING
if (dev->port->physport->cad != dev) if (dev->port->physport->cad != dev)
printk(KERN_DEBUG "%s: exiting parport_claim_or_block " printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n",
"but %s owns port!\n", dev->name, dev->name, dev->port->physport->cad ?
dev->port->physport->cad ?
dev->port->physport->cad->name:"nobody"); dev->port->physport->cad->name:"nobody");
#endif #endif
} }
dev->waiting = 0; dev->waiting = 0;
return r; return r;
} }
EXPORT_SYMBOL(parport_claim_or_block);
/** /**
* parport_release - give up access to a parallel port device * parport_release - give up access to a parallel port device
...@@ -1278,9 +1295,9 @@ void parport_release(struct pardevice *dev) ...@@ -1278,9 +1295,9 @@ void parport_release(struct pardevice *dev)
/* Make sure that dev is the current device */ /* Make sure that dev is the current device */
write_lock_irqsave(&port->cad_lock, flags); write_lock_irqsave(&port->cad_lock, flags);
if (port->cad != dev) { if (port->cad != dev) {
write_unlock_irqrestore (&port->cad_lock, flags); write_unlock_irqrestore(&port->cad_lock, flags);
printk(KERN_WARNING "%s: %s tried to release parport " printk(KERN_WARNING "%s: %s tried to release parport when not owner\n",
"when not owner\n", port->name, dev->name); port->name, dev->name);
return; return;
} }
...@@ -1293,7 +1310,7 @@ void parport_release(struct pardevice *dev) ...@@ -1293,7 +1310,7 @@ void parport_release(struct pardevice *dev)
/* If this is a daisy device, deselect it. */ /* If this is a daisy device, deselect it. */
if (dev->daisy >= 0) { if (dev->daisy >= 0) {
parport_daisy_deselect_all (port); parport_daisy_deselect_all(port);
port->daisy = -1; port->daisy = -1;
} }
#endif #endif
...@@ -1304,8 +1321,10 @@ void parport_release(struct pardevice *dev) ...@@ -1304,8 +1321,10 @@ void parport_release(struct pardevice *dev)
/* Save control registers */ /* Save control registers */
port->ops->save_state(port, dev->state); port->ops->save_state(port, dev->state);
/* If anybody is waiting, find out who's been there longest and /*
then wake them up. (Note: no locking required) */ * If anybody is waiting, find out who's been there longest and
* then wake them up. (Note: no locking required)
*/
/* !!! LOCKING IS NEEDED HERE */ /* !!! LOCKING IS NEEDED HERE */
for (pd = port->waithead; pd; pd = pd->waitnext) { for (pd = port->waithead; pd; pd = pd->waitnext) {
if (pd->waiting & 2) { /* sleeping in claim_or_block */ if (pd->waiting & 2) { /* sleeping in claim_or_block */
...@@ -1322,14 +1341,17 @@ void parport_release(struct pardevice *dev) ...@@ -1322,14 +1341,17 @@ void parport_release(struct pardevice *dev)
} }
} }
/* Nobody was waiting, so walk the list to see if anyone is /*
interested in being woken up. (Note: no locking required) */ * Nobody was waiting, so walk the list to see if anyone is
* interested in being woken up. (Note: no locking required)
*/
/* !!! LOCKING IS NEEDED HERE */ /* !!! LOCKING IS NEEDED HERE */
for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { for (pd = port->devices; !port->cad && pd; pd = pd->next) {
if (pd->wakeup && pd != dev) if (pd->wakeup && pd != dev)
pd->wakeup(pd->private); pd->wakeup(pd->private);
} }
} }
EXPORT_SYMBOL(parport_release);
irqreturn_t parport_irq_handler(int irq, void *dev_id) irqreturn_t parport_irq_handler(int irq, void *dev_id)
{ {
...@@ -1339,22 +1361,6 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id) ...@@ -1339,22 +1361,6 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* Exported symbols for modules. */
EXPORT_SYMBOL(parport_claim);
EXPORT_SYMBOL(parport_claim_or_block);
EXPORT_SYMBOL(parport_release);
EXPORT_SYMBOL(parport_register_port);
EXPORT_SYMBOL(parport_announce_port);
EXPORT_SYMBOL(parport_remove_port);
EXPORT_SYMBOL(parport_unregister_driver);
EXPORT_SYMBOL(parport_register_device);
EXPORT_SYMBOL(parport_unregister_device);
EXPORT_SYMBOL(parport_get_port);
EXPORT_SYMBOL(parport_put_port);
EXPORT_SYMBOL(parport_find_number);
EXPORT_SYMBOL(parport_find_base);
EXPORT_SYMBOL(parport_irq_handler); EXPORT_SYMBOL(parport_irq_handler);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -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
......
...@@ -8,11 +8,14 @@ ...@@ -8,11 +8,14 @@
# Licensed under the terms of the GNU GPL License version 2 # Licensed under the terms of the GNU GPL License version 2
import difflib
import os import os
import re import re
import signal
import sys import sys
from subprocess import Popen, PIPE, STDOUT from multiprocessing import Pool, cpu_count
from optparse import OptionParser from optparse import OptionParser
from subprocess import Popen, PIPE, STDOUT
# regex expressions # regex expressions
...@@ -26,7 +29,7 @@ SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")" ...@@ -26,7 +29,7 @@ SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
# regex objects # regex objects
REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
REGEX_FEATURE = re.compile(r'(?!\B"[^"]*)' + FEATURE + r'(?![^"]*"\B)') REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)')
REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE) REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
REGEX_KCONFIG_DEF = re.compile(DEF) REGEX_KCONFIG_DEF = re.compile(DEF)
REGEX_KCONFIG_EXPR = re.compile(EXPR) REGEX_KCONFIG_EXPR = re.compile(EXPR)
...@@ -34,6 +37,7 @@ REGEX_KCONFIG_STMT = re.compile(STMT) ...@@ -34,6 +37,7 @@ REGEX_KCONFIG_STMT = re.compile(STMT)
REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$") REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$")
REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+") REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+")
REGEX_QUOTES = re.compile("(\"(.*?)\")")
def parse_options(): def parse_options():
...@@ -71,6 +75,9 @@ def parse_options(): ...@@ -71,6 +75,9 @@ def parse_options():
"the pattern needs to be a Python regex. To " "the pattern needs to be a Python regex. To "
"ignore defconfigs, specify -i '.*defconfig'.") "ignore defconfigs, specify -i '.*defconfig'.")
parser.add_option('-s', '--sim', dest='sim', action='store', default="",
help="Print a list of maximum 10 string-similar symbols.")
parser.add_option('', '--force', dest='force', action='store_true', parser.add_option('', '--force', dest='force', action='store_true',
default=False, default=False,
help="Reset current Git tree even when it's dirty.") help="Reset current Git tree even when it's dirty.")
...@@ -109,6 +116,18 @@ def main(): ...@@ -109,6 +116,18 @@ def main():
"""Main function of this module.""" """Main function of this module."""
opts = parse_options() opts = parse_options()
if opts.sim and not opts.commit and not opts.diff:
sims = find_sims(opts.sim, opts.ignore)
if sims:
print "%s: %s" % (yel("Similar symbols"), ', '.join(sims))
else:
print "%s: no similar symbols found" % yel("Similar symbols")
sys.exit(0)
# dictionary of (un)defined symbols
defined = {}
undefined = {}
if opts.commit or opts.diff: if opts.commit or opts.diff:
head = get_head() head = get_head()
...@@ -127,40 +146,56 @@ def main(): ...@@ -127,40 +146,56 @@ def main():
# get undefined items before the commit # get undefined items before the commit
execute("git reset --hard %s" % commit_a) execute("git reset --hard %s" % commit_a)
undefined_a = check_symbols(opts.ignore) undefined_a, _ = check_symbols(opts.ignore)
# get undefined items for the commit # get undefined items for the commit
execute("git reset --hard %s" % commit_b) execute("git reset --hard %s" % commit_b)
undefined_b = check_symbols(opts.ignore) undefined_b, defined = check_symbols(opts.ignore)
# report cases that are present for the commit but not before # report cases that are present for the commit but not before
for feature in sorted(undefined_b): for feature in sorted(undefined_b):
# feature has not been undefined before # feature has not been undefined before
if not feature in undefined_a: if not feature in undefined_a:
files = sorted(undefined_b.get(feature)) files = sorted(undefined_b.get(feature))
print "%s\t%s" % (yel(feature), ", ".join(files)) undefined[feature] = files
if opts.find:
commits = find_commits(feature, opts.diff)
print red(commits)
# check if there are new files that reference the undefined feature # check if there are new files that reference the undefined feature
else: else:
files = sorted(undefined_b.get(feature) - files = sorted(undefined_b.get(feature) -
undefined_a.get(feature)) undefined_a.get(feature))
if files: if files:
print "%s\t%s" % (yel(feature), ", ".join(files)) undefined[feature] = files
if opts.find:
commits = find_commits(feature, opts.diff)
print red(commits)
# reset to head # reset to head
execute("git reset --hard %s" % head) execute("git reset --hard %s" % head)
# default to check the entire tree # default to check the entire tree
else: else:
undefined = check_symbols(opts.ignore) undefined, defined = check_symbols(opts.ignore)
# now print the output
for feature in sorted(undefined): for feature in sorted(undefined):
print red(feature)
files = sorted(undefined.get(feature)) files = sorted(undefined.get(feature))
print "%s\t%s" % (yel(feature), ", ".join(files)) print "%s: %s" % (yel("Referencing files"), ", ".join(files))
sims = find_sims(feature, opts.ignore, defined)
sims_out = yel("Similar symbols")
if sims:
print "%s: %s" % (sims_out, ', '.join(sims))
else:
print "%s: %s" % (sims_out, "no similar symbols found")
if opts.find:
print "%s:" % yel("Commits changing symbol")
commits = find_commits(feature, opts.diff)
if commits:
for commit in commits:
commit = commit.split(" ", 1)
print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1])
else:
print "\t- no commit found"
print # new line
def yel(string): def yel(string):
...@@ -190,7 +225,7 @@ def find_commits(symbol, diff): ...@@ -190,7 +225,7 @@ def find_commits(symbol, diff):
"""Find commits changing %symbol in the given range of %diff.""" """Find commits changing %symbol in the given range of %diff."""
commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s"
% (symbol, diff)) % (symbol, diff))
return commits return [x for x in commits.split("\n") if x]
def tree_is_dirty(): def tree_is_dirty():
...@@ -209,43 +244,107 @@ def get_head(): ...@@ -209,43 +244,107 @@ def get_head():
return stdout.strip('\n') return stdout.strip('\n')
def check_symbols(ignore): def partition(lst, size):
"""Find undefined Kconfig symbols and return a dict with the symbol as key """Partition list @lst into eveni-sized lists of size @size."""
and a list of referencing files as value. Files matching %ignore are not return [lst[i::size] for i in xrange(size)]
checked for undefined symbols."""
source_files = []
kconfig_files = [] def init_worker():
defined_features = set() """Set signal handler to ignore SIGINT."""
referenced_features = dict() # {feature: [files]} signal.signal(signal.SIGINT, signal.SIG_IGN)
def find_sims(symbol, ignore, defined = []):
"""Return a list of max. ten Kconfig symbols that are string-similar to
@symbol."""
if defined:
return sorted(difflib.get_close_matches(symbol, set(defined), 10))
pool = Pool(cpu_count(), init_worker)
kfiles = []
for gitfile in get_files():
if REGEX_FILE_KCONFIG.match(gitfile):
kfiles.append(gitfile)
arglist = []
for part in partition(kfiles, cpu_count()):
arglist.append((part, ignore))
for res in pool.map(parse_kconfig_files, arglist):
defined.extend(res[0])
return sorted(difflib.get_close_matches(symbol, set(defined), 10))
def get_files():
"""Return a list of all files in the current git directory."""
# use 'git ls-files' to get the worklist # use 'git ls-files' to get the worklist
stdout = execute("git ls-files") stdout = execute("git ls-files")
if len(stdout) > 0 and stdout[-1] == "\n": if len(stdout) > 0 and stdout[-1] == "\n":
stdout = stdout[:-1] stdout = stdout[:-1]
files = []
for gitfile in stdout.rsplit("\n"): for gitfile in stdout.rsplit("\n"):
if ".git" in gitfile or "ChangeLog" in gitfile or \ if ".git" in gitfile or "ChangeLog" in gitfile or \
".log" in gitfile or os.path.isdir(gitfile) or \ ".log" in gitfile or os.path.isdir(gitfile) or \
gitfile.startswith("tools/"): gitfile.startswith("tools/"):
continue continue
files.append(gitfile)
return files
def check_symbols(ignore):
"""Find undefined Kconfig symbols and return a dict with the symbol as key
and a list of referencing files as value. Files matching %ignore are not
checked for undefined symbols."""
pool = Pool(cpu_count(), init_worker)
try:
return check_symbols_helper(pool, ignore)
except KeyboardInterrupt:
pool.terminate()
pool.join()
sys.exit(1)
def check_symbols_helper(pool, ignore):
"""Helper method for check_symbols(). Used to catch keyboard interrupts in
check_symbols() in order to properly terminate running worker processes."""
source_files = []
kconfig_files = []
defined_features = []
referenced_features = dict() # {file: [features]}
for gitfile in get_files():
if REGEX_FILE_KCONFIG.match(gitfile): if REGEX_FILE_KCONFIG.match(gitfile):
kconfig_files.append(gitfile) kconfig_files.append(gitfile)
else: else:
# all non-Kconfig files are checked for consistency if ignore and not re.match(ignore, gitfile):
continue
# add source files that do not match the ignore pattern
source_files.append(gitfile) source_files.append(gitfile)
for sfile in source_files: # parse source files
if ignore and re.match(ignore, sfile): arglist = partition(source_files, cpu_count())
# do not check files matching %ignore for res in pool.map(parse_source_files, arglist):
continue referenced_features.update(res)
parse_source_file(sfile, referenced_features)
for kfile in kconfig_files:
if ignore and re.match(ignore, kfile): # parse kconfig files
# do not collect references for files matching %ignore arglist = []
parse_kconfig_file(kfile, defined_features, dict()) for part in partition(kconfig_files, cpu_count()):
else: arglist.append((part, ignore))
parse_kconfig_file(kfile, defined_features, referenced_features) for res in pool.map(parse_kconfig_files, arglist):
defined_features.extend(res[0])
referenced_features.update(res[1])
defined_features = set(defined_features)
# inverse mapping of referenced_features to dict(feature: [files])
inv_map = dict()
for _file, features in referenced_features.iteritems():
for feature in features:
inv_map[feature] = inv_map.get(feature, set())
inv_map[feature].add(_file)
referenced_features = inv_map
undefined = {} # {feature: [files]} undefined = {} # {feature: [files]}
for feature in sorted(referenced_features): for feature in sorted(referenced_features):
...@@ -259,12 +358,26 @@ def check_symbols(ignore): ...@@ -259,12 +358,26 @@ def check_symbols(ignore):
if feature[:-len("_MODULE")] in defined_features: if feature[:-len("_MODULE")] in defined_features:
continue continue
undefined[feature] = referenced_features.get(feature) undefined[feature] = referenced_features.get(feature)
return undefined return undefined, defined_features
def parse_source_file(sfile, referenced_features): def parse_source_files(source_files):
"""Parse @sfile for referenced Kconfig features.""" """Parse each source file in @source_files and return dictionary with source
files as keys and lists of references Kconfig symbols as values."""
referenced_features = dict()
for sfile in source_files:
referenced_features[sfile] = parse_source_file(sfile)
return referenced_features
def parse_source_file(sfile):
"""Parse @sfile and return a list of referenced Kconfig features."""
lines = [] lines = []
references = []
if not os.path.exists(sfile):
return references
with open(sfile, "r") as stream: with open(sfile, "r") as stream:
lines = stream.readlines() lines = stream.readlines()
...@@ -275,9 +388,9 @@ def parse_source_file(sfile, referenced_features): ...@@ -275,9 +388,9 @@ def parse_source_file(sfile, referenced_features):
for feature in features: for feature in features:
if not REGEX_FILTER_FEATURES.search(feature): if not REGEX_FILTER_FEATURES.search(feature):
continue continue
sfiles = referenced_features.get(feature, set()) references.append(feature)
sfiles.add(sfile)
referenced_features[feature] = sfiles return references
def get_features_in_line(line): def get_features_in_line(line):
...@@ -285,11 +398,35 @@ def get_features_in_line(line): ...@@ -285,11 +398,35 @@ def get_features_in_line(line):
return REGEX_FEATURE.findall(line) return REGEX_FEATURE.findall(line)
def parse_kconfig_file(kfile, defined_features, referenced_features): def parse_kconfig_files(args):
"""Parse kconfig files and return tuple of defined and references Kconfig
symbols. Note, @args is a tuple of a list of files and the @ignore
pattern."""
kconfig_files = args[0]
ignore = args[1]
defined_features = []
referenced_features = dict()
for kfile in kconfig_files:
defined, references = parse_kconfig_file(kfile)
defined_features.extend(defined)
if ignore and re.match(ignore, kfile):
# do not collect references for files that match the ignore pattern
continue
referenced_features[kfile] = references
return (defined_features, referenced_features)
def parse_kconfig_file(kfile):
"""Parse @kfile and update feature definitions and references.""" """Parse @kfile and update feature definitions and references."""
lines = [] lines = []
defined = []
references = []
skip = False skip = False
if not os.path.exists(kfile):
return defined, references
with open(kfile, "r") as stream: with open(kfile, "r") as stream:
lines = stream.readlines() lines = stream.readlines()
...@@ -300,7 +437,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): ...@@ -300,7 +437,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
if REGEX_KCONFIG_DEF.match(line): if REGEX_KCONFIG_DEF.match(line):
feature_def = REGEX_KCONFIG_DEF.findall(line) feature_def = REGEX_KCONFIG_DEF.findall(line)
defined_features.add(feature_def[0]) defined.append(feature_def[0])
skip = False skip = False
elif REGEX_KCONFIG_HELP.match(line): elif REGEX_KCONFIG_HELP.match(line):
skip = True skip = True
...@@ -308,6 +445,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): ...@@ -308,6 +445,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
# ignore content of help messages # ignore content of help messages
pass pass
elif REGEX_KCONFIG_STMT.match(line): elif REGEX_KCONFIG_STMT.match(line):
line = REGEX_QUOTES.sub("", line)
features = get_features_in_line(line) features = get_features_in_line(line)
# multi-line statements # multi-line statements
while line.endswith("\\"): while line.endswith("\\"):
...@@ -319,9 +457,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): ...@@ -319,9 +457,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features):
if REGEX_NUMERIC.match(feature): if REGEX_NUMERIC.match(feature):
# ignore numeric values # ignore numeric values
continue continue
paths = referenced_features.get(feature, set()) references.append(feature)
paths.add(kfile)
referenced_features[feature] = paths return defined, references
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -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