char/misc patches for 4.5-rc1
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlaV0GsACgkQMUfUDdst+ymlPgCg07GSc4SOWlUL2V36vQ0kucoO YjAAoMfeUEhsf/NJ7iaAMGQVUQKuYVqr =BlqH -----END PGP SIGNATURE----- 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() ...
This commit is contained in:
Коммит
4c257ec37b
|
@ -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>;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
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
|
||||||
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
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Maxim Integrated MAX3355 USB OTG chip extcon driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015 Cogent Embedded, Inc.
|
||||||
|
* Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/extcon.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
struct max3355_data {
|
||||||
|
struct extcon_dev *edev;
|
||||||
|
struct gpio_desc *id_gpiod;
|
||||||
|
struct gpio_desc *shdn_gpiod;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int max3355_cable[] = {
|
||||||
|
EXTCON_USB,
|
||||||
|
EXTCON_USB_HOST,
|
||||||
|
EXTCON_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static irqreturn_t max3355_id_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct max3355_data *data = dev_id;
|
||||||
|
int id = gpiod_get_value_cansleep(data->id_gpiod);
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
/*
|
||||||
|
* ID = 1 means USB HOST cable detached.
|
||||||
|
* As we don't have event for USB peripheral cable attached,
|
||||||
|
* we simulate USB peripheral attach here.
|
||||||
|
*/
|
||||||
|
extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false);
|
||||||
|
extcon_set_cable_state_(data->edev, EXTCON_USB, true);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* ID = 0 means USB HOST cable attached.
|
||||||
|
* As we don't have event for USB peripheral cable detached,
|
||||||
|
* we simulate USB peripheral detach here.
|
||||||
|
*/
|
||||||
|
extcon_set_cable_state_(data->edev, EXTCON_USB, false);
|
||||||
|
extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max3355_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct max3355_data *data;
|
||||||
|
struct gpio_desc *gpiod;
|
||||||
|
int irq, err;
|
||||||
|
|
||||||
|
data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
|
||||||
|
if (IS_ERR(gpiod)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n");
|
||||||
|
return PTR_ERR(gpiod);
|
||||||
|
}
|
||||||
|
data->id_gpiod = gpiod;
|
||||||
|
|
||||||
|
gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(gpiod)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get SHDN# GPIO\n");
|
||||||
|
return PTR_ERR(gpiod);
|
||||||
|
}
|
||||||
|
data->shdn_gpiod = gpiod;
|
||||||
|
|
||||||
|
data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable);
|
||||||
|
if (IS_ERR(data->edev)) {
|
||||||
|
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||||
|
return PTR_ERR(data->edev);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = devm_extcon_dev_register(&pdev->dev, data->edev);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = gpiod_to_irq(data->id_gpiod);
|
||||||
|
if (irq < 0) {
|
||||||
|
dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n");
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq,
|
||||||
|
IRQF_ONESHOT | IRQF_NO_SUSPEND |
|
||||||
|
IRQF_TRIGGER_RISING |
|
||||||
|
IRQF_TRIGGER_FALLING,
|
||||||
|
pdev->name, data);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
|
/* Perform initial detection */
|
||||||
|
max3355_id_irq(irq, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max3355_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct max3355_data *data = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(data->shdn_gpiod, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id max3355_match_table[] = {
|
||||||
|
{ .compatible = "maxim,max3355", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, max3355_match_table);
|
||||||
|
|
||||||
|
static struct platform_driver max3355_driver = {
|
||||||
|
.probe = max3355_probe,
|
||||||
|
.remove = max3355_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "extcon-max3355",
|
||||||
|
.of_match_table = max3355_match_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(max3355_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
|
||||||
|
MODULE_DESCRIPTION("Maxim MAX3355 extcon driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -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)
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
* 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)
|
||||||
* 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)
|
||||||
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,
|
||||||
* 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,
|
||||||
* 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);
|
||||||
*
|
*
|
||||||
* 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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ err_free_chan:
|
||||||
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[] = {
|
||||||
{ 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
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
#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,
|
||||||
{
|
{
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
*
|
*
|
||||||
* 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 {
|
||||||
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;
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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 {
|
||||||
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;
|
||||||
*/
|
*/
|
||||||
#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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
* 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 {
|
||||||
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);
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
static int hvt_op_open(struct inode *inode, struct file *file)
|
static int hvt_op_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct hvutil_transport *hvt;
|
struct hvutil_transport *hvt;
|
||||||
|
int ret = 0;
|
||||||
|
bool issue_reset = false;
|
||||||
|
|
||||||
hvt = container_of(file->f_op, struct hvutil_transport, fops);
|
hvt = container_of(file->f_op, struct hvutil_transport, fops);
|
||||||
|
|
||||||
/*
|
mutex_lock(&hvt->lock);
|
||||||
* Switching to CHARDEV mode. We switch bach to INIT when device
|
|
||||||
* gets released.
|
if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) {
|
||||||
*/
|
ret = -EBADF;
|
||||||
if (hvt->mode == HVUTIL_TRANSPORT_INIT)
|
} else if (hvt->mode == HVUTIL_TRANSPORT_INIT) {
|
||||||
|
/*
|
||||||
|
* Switching to CHARDEV mode. We switch bach to INIT when
|
||||||
|
* device gets released.
|
||||||
|
*/
|
||||||
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
|
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
|
||||||
|
}
|
||||||
else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
|
else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) {
|
||||||
/*
|
/*
|
||||||
* We're switching from netlink communication to using char
|
* We're switching from netlink communication to using char
|
||||||
* device. Issue the reset first.
|
* device. Issue the reset first.
|
||||||
*/
|
*/
|
||||||
hvt_reset(hvt);
|
issue_reset = true;
|
||||||
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
|
hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
|
||||||
} else
|
} else {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (issue_reset)
|
||||||
|
hvt_reset(hvt);
|
||||||
|
|
||||||
|
mutex_unlock(&hvt->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvt_transport_free(struct hvutil_transport *hvt)
|
||||||
|
{
|
||||||
|
misc_deregister(&hvt->mdev);
|
||||||
|
kfree(hvt->outmsg);
|
||||||
|
kfree(hvt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hvt_op_release(struct inode *inode, struct file *file)
|
static int hvt_op_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct hvutil_transport *hvt;
|
struct hvutil_transport *hvt;
|
||||||
|
int mode_old;
|
||||||
|
|
||||||
hvt = container_of(file->f_op, struct hvutil_transport, fops);
|
hvt = container_of(file->f_op, struct hvutil_transport, fops);
|
||||||
|
|
||||||
hvt->mode = HVUTIL_TRANSPORT_INIT;
|
mutex_lock(&hvt->lock);
|
||||||
|
mode_old = hvt->mode;
|
||||||
|
if (hvt->mode != HVUTIL_TRANSPORT_DESTROY)
|
||||||
|
hvt->mode = HVUTIL_TRANSPORT_INIT;
|
||||||
/*
|
/*
|
||||||
* Cleanup message buffers to avoid spurious messages when the daemon
|
* Cleanup message buffers to avoid spurious messages when the daemon
|
||||||
* connects back.
|
* connects back.
|
||||||
*/
|
*/
|
||||||
hvt_reset(hvt);
|
hvt_reset(hvt);
|
||||||
|
mutex_unlock(&hvt->lock);
|
||||||
|
|
||||||
|
if (mode_old == HVUTIL_TRANSPORT_DESTROY)
|
||||||
|
hvt_transport_free(hvt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -168,6 +208,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/* HVUTIL_TRANSPORT_CHARDEV */
|
/* HVUTIL_TRANSPORT_CHARDEV */
|
||||||
mutex_lock(&hvt->outmsg_lock);
|
mutex_lock(&hvt->lock);
|
||||||
|
if (hvt->mode != HVUTIL_TRANSPORT_CHARDEV) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
if (hvt->outmsg) {
|
if (hvt->outmsg) {
|
||||||
/* Previous message wasn't received */
|
/* Previous message wasn't received */
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
hvt->outmsg = kzalloc(len, GFP_KERNEL);
|
hvt->outmsg = kzalloc(len, GFP_KERNEL);
|
||||||
memcpy(hvt->outmsg, msg, len);
|
if (hvt->outmsg) {
|
||||||
hvt->outmsg_len = len;
|
memcpy(hvt->outmsg, msg, len);
|
||||||
wake_up_interruptible(&hvt->outmsg_q);
|
hvt->outmsg_len = len;
|
||||||
|
wake_up_interruptible(&hvt->outmsg_q);
|
||||||
|
} else
|
||||||
|
ret = -ENOMEM;
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&hvt->outmsg_lock);
|
mutex_unlock(&hvt->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +290,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
|
||||||
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 @@ err_free_hvt:
|
||||||
|
|
||||||
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 {
|
||||||
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 {
|
||||||
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 @@
|
||||||
#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,
|
||||||
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,
|
||||||
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 {
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
|
||||||
* 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(
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
|
||||||
* 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(
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
&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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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;
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
* @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)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Parallel-port resource manager code.
|
* Parallel-port resource manager code.
|
||||||
*
|
*
|
||||||
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
|
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
|
||||||
* Tim Waugh <tim@cyberelk.demon.co.uk>
|
* Tim Waugh <tim@cyberelk.demon.co.uk>
|
||||||
* Jose Renau <renau@acm.org>
|
* Jose Renau <renau@acm.org>
|
||||||
|
@ -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 */
|
||||||
|
@ -93,7 +93,7 @@ static struct parport_operations dead_ops = {
|
||||||
.ecp_write_data = dead_write, /* ecp */
|
.ecp_write_data = dead_write, /* ecp */
|
||||||
.ecp_read_data = dead_read,
|
.ecp_read_data = dead_read,
|
||||||
.ecp_write_addr = dead_write,
|
.ecp_write_addr = dead_write,
|
||||||
|
|
||||||
.compat_write_data = dead_write, /* compat */
|
.compat_write_data = dead_write, /* compat */
|
||||||
.nibble_read_data = dead_read, /* nibble */
|
.nibble_read_data = dead_read, /* nibble */
|
||||||
.byte_read_data = dead_read, /* byte */
|
.byte_read_data = dead_read, /* byte */
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
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)
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
mutex_unlock(®istration_lock);
|
mutex_unlock(®istration_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)
|
||||||
* 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);
|
||||||
* 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,
|
||||||
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;
|
||||||
|
@ -450,12 +453,12 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
|
||||||
tmp->dma = dma;
|
tmp->dma = dma;
|
||||||
tmp->muxport = tmp->daisy = tmp->muxsel = -1;
|
tmp->muxport = tmp->daisy = tmp->muxsel = -1;
|
||||||
tmp->modes = 0;
|
tmp->modes = 0;
|
||||||
INIT_LIST_HEAD(&tmp->list);
|
INIT_LIST_HEAD(&tmp->list);
|
||||||
tmp->devices = tmp->cad = NULL;
|
tmp->devices = tmp->cad = NULL;
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
* 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,9 +534,8 @@ 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);
|
||||||
mutex_lock(®istration_lock);
|
mutex_lock(®istration_lock);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
mutex_unlock(®istration_lock);
|
mutex_unlock(®istration_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)
|
||||||
mutex_lock(®istration_lock);
|
mutex_lock(®istration_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)
|
||||||
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
|
||||||
|
@ -689,14 +693,14 @@ void parport_remove_port(struct parport *port)
|
||||||
struct pardevice *
|
struct pardevice *
|
||||||
parport_register_device(struct parport *port, const char *name,
|
parport_register_device(struct parport *port, const char *name,
|
||||||
int (*pf)(void *), void (*kf)(void *),
|
int (*pf)(void *), void (*kf)(void *),
|
||||||
void (*irq_func)(void *),
|
void (*irq_func)(void *),
|
||||||
int flags, void *handle)
|
int flags, void *handle)
|
||||||
{
|
{
|
||||||
struct pardevice *tmp;
|
struct pardevice *tmp;
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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 @@ blocked:
|
||||||
} 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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
#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)
|
||||||
/* 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)
|
||||||
|
|
||||||
/* 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)
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
|
|
||||||
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,
|
||||||
{
|
{
|
||||||
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 {
|
||||||
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 {
|
||||||
* 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,
|
||||||
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,
|
||||||
* {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,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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 {
|
||||||
* 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 {
|
||||||
#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 @@
|
||||||
# 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")"
|
||||||
|
|
||||||
# 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)
|
||||||
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():
|
||||||
"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():
|
||||||
"""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():
|
||||||
|
|
||||||
# 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)
|
||||||
for feature in sorted(undefined):
|
|
||||||
files = sorted(undefined.get(feature))
|
# now print the output
|
||||||
print "%s\t%s" % (yel(feature), ", ".join(files))
|
for feature in sorted(undefined):
|
||||||
|
print red(feature)
|
||||||
|
|
||||||
|
files = sorted(undefined.get(feature))
|
||||||
|
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):
|
||||||
"""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():
|
||||||
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 = []
|
|
||||||
defined_features = set()
|
|
||||||
referenced_features = dict() # {feature: [files]}
|
|
||||||
|
|
||||||
|
|
||||||
|
def init_worker():
|
||||||
|
"""Set signal handler to ignore SIGINT."""
|
||||||
|
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):
|
||||||
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):
|
||||||
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):
|
||||||
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):
|
||||||
|
|
||||||
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):
|
||||||
# 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):
|
||||||
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,
|
||||||
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 @@
|
||||||
|
|
||||||
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 @@ done:
|
||||||
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[])
|
||||||
}
|
}
|
||||||
|
|
||||||
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[])
|
||||||
}
|
}
|
||||||
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[])
|
||||||
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));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче