summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-03 11:36:27 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-03 11:36:27 -0700
commit1d1fdd95df681f0c065d90ffaafa215a0e8825e2 (patch)
tree19016e131bb5c7eb280a4cc8dff864ba36e53be4
parentb3b49114c80e799af8b08c0c6d1ff886ea843f03 (diff)
parent3cc1f95283a125cf54ccf1e25065321d4385133b (diff)
Merge tag 'char-misc-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc patches from Greg KH: "Here is the big char/misc driver pull request for 3.12-rc1 Lots of driver updates all over the char/misc tree, full details in the shortlog" * tag 'char-misc-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (62 commits) drivers: uio: Kconfig: add MMU dependancy for UIO drivers: uio: Add driver for Humusoft MF624 DAQ PCI card drivers: uio_pdrv_genirq: use dev_get_platdata() drivers: uio_pruss: use dev_get_platdata() drivers: uio_dmem_genirq: use dev_get_platdata() drivers: parport: Kconfig: exclude h8300 for PARPORT_PC drivers: misc: ti-st: fix potential race if st_kim_start fails Drivers: hv: vmbus: Do not attempt to negoatiate a new version prematurely misc: vmw_balloon: Remove braces to fix build for clang. Drivers: hv: vmbus: Fix a bug in the handling of channel offers vme: vme_ca91cx42.c: fix to pass correct device identity to free_irq() VMCI: Add support for virtual IOMMU VMCI: Remove non-blocking/pinned queuepair support uio: uio_pruss: remove unnecessary platform_set_drvdata() parport: amiga: remove unnecessary platform_set_drvdata() vme: vme_vmivme7805.c: add missing __iomem annotation vme: vme_ca91cx42.c: add missing __iomem annotation vme: vme_tsi148.c: add missing __iomem annotation drivers/misc/hpilo: Correct panic when an AUX iLO is detected uio: drop unused vma_count member in uio_device struct ...
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-palmas.txt (renamed from Documentation/devicetree/bindings/extcon/extcon-twl.txt)6
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt5
-rw-r--r--drivers/char/pcmcia/synclink_cs.c26
-rw-r--r--drivers/extcon/Kconfig4
-rw-r--r--drivers/extcon/Makefile2
-rw-r--r--drivers/extcon/extcon-adc-jack.c3
-rw-r--r--drivers/extcon/extcon-arizona.c25
-rw-r--r--drivers/extcon/extcon-class.c3
-rw-r--r--drivers/extcon/extcon-gpio.c2
-rw-r--r--drivers/extcon/extcon-palmas.c134
-rw-r--r--drivers/extcon/of_extcon.c64
-rw-r--r--drivers/fmc/fmc-chardev.c9
-rw-r--r--drivers/fmc/fmc-write-eeprom.c4
-rw-r--r--drivers/hid/hid-hyperv.c1
-rw-r--r--drivers/hv/channel_mgmt.c89
-rw-r--r--drivers/hv/connection.c5
-rw-r--r--drivers/hv/hv_balloon.c5
-rw-r--r--drivers/hv/hv_kvp.c26
-rw-r--r--drivers/hv/hv_snapshot.c18
-rw-r--r--drivers/hv/hv_util.c22
-rw-r--r--drivers/hv/vmbus_drv.c1
-rw-r--r--drivers/misc/atmel-ssc.c8
-rw-r--r--drivers/misc/hpilo.c4
-rw-r--r--drivers/misc/lkdtm.c63
-rw-r--r--drivers/misc/mei/amthif.c14
-rw-r--r--drivers/misc/mei/bus.c4
-rw-r--r--drivers/misc/mei/client.c15
-rw-r--r--drivers/misc/mei/client.h9
-rw-r--r--drivers/misc/mei/hw-me.c9
-rw-r--r--drivers/misc/mei/init.c11
-rw-r--r--drivers/misc/mei/main.c22
-rw-r--r--drivers/misc/sram.c3
-rw-r--r--drivers/misc/ti-st/st_core.c2
-rw-r--r--drivers/misc/vmw_balloon.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.h7
-rw-r--r--drivers/misc/vmw_vmci/vmci_guest.c22
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c315
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.h18
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_amiga.c1
-rw-r--r--drivers/scsi/storvsc_drv.c1
-rw-r--r--drivers/uio/Kconfig21
-rw-r--r--drivers/uio/Makefile2
-rw-r--r--drivers/uio/uio.c40
-rw-r--r--drivers/uio/uio_dmem_genirq.c2
-rw-r--r--drivers/uio/uio_mf624.c247
-rw-r--r--drivers/uio/uio_pdrv.c113
-rw-r--r--drivers/uio/uio_pdrv_genirq.c2
-rw-r--r--drivers/uio/uio_pruss.c3
-rw-r--r--drivers/usb/dwc3/Kconfig1
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c125
-rw-r--r--drivers/video/hyperv_fb.c1
-rw-r--r--drivers/vme/boards/vme_vmivme7805.c2
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c10
-rw-r--r--drivers/vme/bridges/vme_tsi148.c4
-rw-r--r--include/linux/extcon/of_extcon.h31
-rw-r--r--include/linux/hyperv.h31
-rw-r--r--include/linux/mfd/palmas.h8
-rw-r--r--include/linux/usb/dwc3-omap.h30
-rw-r--r--mm/memory.c1
-rw-r--r--tools/hv/hv_kvp_daemon.c44
-rw-r--r--tools/hv/hv_vss_daemon.c59
64 files changed, 1093 insertions, 674 deletions
diff --git a/Documentation/devicetree/bindings/extcon/extcon-twl.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
index 58f531ab4df..7dab6a8f4a0 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-twl.txt
+++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
@@ -1,15 +1,15 @@
-EXTCON FOR TWL CHIPS
+EXTCON FOR PALMAS/TWL CHIPS
PALMAS USB COMPARATOR
Required Properties:
- compatible : Should be "ti,palmas-usb" or "ti,twl6035-usb"
- - vbus-supply : phandle to the regulator device tree node.
Optional Properties:
- ti,wakeup : To enable the wakeup comparator in probe
+ - ti,enable-id-detection: Perform ID detection.
+ - ti,enable-vbus-detection: Perform VBUS detection.
palmas-usb {
compatible = "ti,twl6035-usb", "ti,palmas-usb";
- vbus-supply = <&smps10_reg>;
ti,wakeup;
};
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index 57e71f6817d..9088ab09e20 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -53,6 +53,11 @@ OMAP DWC3 GLUE
It should be set to "1" for HW mode and "2" for SW mode.
- ranges: the child address space are mapped 1:1 onto the parent address space
+Optional Properties:
+ - extcon : phandle for the extcon device omap dwc3 uses to detect
+ connect/disconnect events.
+ - vbus-supply : phandle to the regulator device tree node if needed.
+
Sub-nodes:
The dwc3 core should be added as subnode to omap dwc3 glue.
- dwc3 :
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 5c5cc00ebb0..d39cca659a3 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1182,14 +1182,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
}
count++;
- if (gis & (BIT1 + BIT0)) {
+ if (gis & (BIT1 | BIT0)) {
isr = read_reg16(info, CHB + ISR);
if (isr & IRQ_DCD)
dcd_change(info, tty);
if (isr & IRQ_CTS)
cts_change(info, tty);
}
- if (gis & (BIT3 + BIT2))
+ if (gis & (BIT3 | BIT2))
{
isr = read_reg16(info, CHA + ISR);
if (isr & IRQ_TIMER) {
@@ -1210,7 +1210,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (isr & IRQ_RXTIME) {
issue_command(info, CHA, CMD_RXFIFO_READ);
}
- if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) {
+ if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) {
if (info->params.mode == MGSL_MODE_HDLC)
rx_ready_hdlc(info, isr & IRQ_RXEOM);
else
@@ -3031,11 +3031,11 @@ static void loopback_enable(MGSLPC_INFO *info)
unsigned char val;
/* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */
- val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0);
+ val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0);
write_reg(info, CHA + CCR1, val);
/* CCR2:04 SSEL Clock source select, 1=submode b */
- val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5);
+ val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5);
write_reg(info, CHA + CCR2, val);
/* set LinkSpeed if available, otherwise default to 2Mbps */
@@ -3125,10 +3125,10 @@ static void hdlc_mode(MGSLPC_INFO *info)
val |= BIT4;
break; // FM0
case HDLC_ENCODING_BIPHASE_MARK:
- val |= BIT4 + BIT2;
+ val |= BIT4 | BIT2;
break; // FM1
case HDLC_ENCODING_BIPHASE_LEVEL:
- val |= BIT4 + BIT3;
+ val |= BIT4 | BIT3;
break; // Manchester
}
write_reg(info, CHA + CCR0, val);
@@ -3185,7 +3185,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
*/
val = 0x00;
if (info->params.crc_type == HDLC_CRC_NONE)
- val |= BIT2 + BIT1;
+ val |= BIT2 | BIT1;
if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
val |= BIT5;
switch (info->params.preamble_length)
@@ -3197,7 +3197,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
val |= BIT6;
break;
case HDLC_PREAMBLE_LENGTH_64BITS:
- val |= BIT7 + BIT6;
+ val |= BIT7 | BIT6;
break;
}
write_reg(info, CHA + CCR3, val);
@@ -3264,8 +3264,8 @@ static void hdlc_mode(MGSLPC_INFO *info)
clear_reg_bits(info, CHA + PVR, BIT3);
irq_enable(info, CHA,
- IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT +
- IRQ_UNDERRUN + IRQ_TXFIFO);
+ IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT |
+ IRQ_UNDERRUN | IRQ_TXFIFO);
issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
wait_command_complete(info, CHA);
read_reg16(info, CHA + ISR); /* clear pending IRQs */
@@ -3582,8 +3582,8 @@ static void async_mode(MGSLPC_INFO *info)
} else
clear_reg_bits(info, CHA + PVR, BIT3);
irq_enable(info, CHA,
- IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME +
- IRQ_ALLSENT + IRQ_TXFIFO);
+ IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME |
+ IRQ_ALLSENT | IRQ_TXFIFO);
issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
wait_command_complete(info, CHA);
read_reg16(info, CHA + ISR); /* clear pending IRQs */
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 63f454e2057..f1d54a3985b 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -14,6 +14,10 @@ if EXTCON
comment "Extcon Device Drivers"
+config OF_EXTCON
+ def_tristate y
+ depends on OF
+
config EXTCON_GPIO
tristate "GPIO extcon support"
depends on GPIOLIB
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 540e2c3a443..759fdae46f9 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,6 +2,8 @@
# Makefile for external connector class (extcon) devices
#
+obj-$(CONFIG_OF_EXTCON) += of_extcon.o
+
obj-$(CONFIG_EXTCON) += extcon-class.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index d0233cd18ff..5985807e52c 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -87,7 +87,8 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data)
{
struct adc_jack_data *data = _data;
- schedule_delayed_work(&data->handler, data->handling_delay);
+ queue_delayed_work(system_power_efficient_wq,
+ &data->handler, data->handling_delay);
return IRQ_HANDLED;
}
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 7a1b4a7791b..e55713083c7 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -890,8 +890,9 @@ static void arizona_micd_detect(struct work_struct *work)
handled:
if (info->detecting)
- schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(info->micd_timeout));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
@@ -912,8 +913,9 @@ static irqreturn_t arizona_micdet(int irq, void *data)
mutex_unlock(&info->lock);
if (debounce)
- schedule_delayed_work(&info->micd_detect_work,
- msecs_to_jiffies(debounce));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_detect_work,
+ msecs_to_jiffies(debounce));
else
arizona_micd_detect(&info->micd_detect_work.work);
@@ -967,12 +969,14 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
if (val == info->last_jackdet) {
dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
if (cancelled_hp)
- schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
if (cancelled_mic)
- schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(info->micd_timeout));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
goto out;
}
@@ -994,8 +998,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
arizona_start_mic(info);
} else {
- schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
}
regmap_update_bits(arizona->regmap,
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 18ccadef43f..1446152bf2e 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -602,7 +602,8 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
edev->dev->class = extcon_class;
edev->dev->release = extcon_dev_release;
- dev_set_name(edev->dev, "%s", edev->name ? edev->name : dev_name(dev));
+ edev->name = edev->name ? edev->name : dev_name(dev);
+ dev_set_name(edev->dev, "%s", edev->name);
if (edev->max_supported) {
char buf[10];
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 02bec32adde..f874c30ddbf 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -56,7 +56,7 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
struct gpio_extcon_data *extcon_data = dev_id;
- schedule_delayed_work(&extcon_data->work,
+ queue_delayed_work(system_power_efficient_wq, &extcon_data->work,
extcon_data->debounce_jiffies);
return IRQ_HANDLED;
}
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index b752a0ad7b6..89fdd05c5fd 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -57,6 +57,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
extcon_set_cable_state(&palmas_usb->edev, "USB", true);
+ dev_info(palmas_usb->dev, "USB cable is attached\n");
} else {
dev_dbg(palmas_usb->dev,
"Spurious connect event detected\n");
@@ -65,6 +66,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(&palmas_usb->edev, "USB", false);
+ dev_info(palmas_usb->dev, "USB cable is detached\n");
} else {
dev_dbg(palmas_usb->dev,
"Spurious disconnect event detected\n");
@@ -84,28 +86,23 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_CLR,
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
+ dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_CLR,
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+ } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
+ (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
+ palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
+ extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
}
return IRQ_HANDLED;
@@ -122,13 +119,17 @@ static void palmas_enable_irq(struct palmas_usb *palmas_usb)
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+ PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
+ PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
- palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
+ if (palmas_usb->enable_vbus_detection)
+ palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
/* cold plug for host mode needs this delay */
- msleep(30);
- palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+ if (palmas_usb->enable_id_detection) {
+ msleep(30);
+ palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+ }
}
static int palmas_usb_probe(struct platform_device *pdev)
@@ -139,21 +140,25 @@ static int palmas_usb_probe(struct platform_device *pdev)
struct palmas_usb *palmas_usb;
int status;
- if (node && !pdata) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-
- if (!pdata)
- return -ENOMEM;
-
- pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
- } else if (!pdata) {
- return -EINVAL;
- }
-
palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
if (!palmas_usb)
return -ENOMEM;
+ if (node && !pdata) {
+ palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup");
+ palmas_usb->enable_id_detection = of_property_read_bool(node,
+ "ti,enable-id-detection");
+ palmas_usb->enable_vbus_detection = of_property_read_bool(node,
+ "ti,enable-vbus-detection");
+ } else {
+ palmas_usb->wakeup = true;
+ palmas_usb->enable_id_detection = true;
+ palmas_usb->enable_vbus_detection = true;
+
+ if (pdata)
+ palmas_usb->wakeup = pdata->wakeup;
+ }
+
palmas->usb = palmas_usb;
palmas_usb->palmas = palmas;
@@ -168,11 +173,10 @@ static int palmas_usb_probe(struct platform_device *pdev)
palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
PALMAS_VBUS_IRQ);
- palmas_usb_wakeup(palmas, pdata->wakeup);
+ palmas_usb_wakeup(palmas, palmas_usb->wakeup);
platform_set_drvdata(pdev, palmas_usb);
- palmas_usb->edev.name = "palmas-usb";
palmas_usb->edev.supported_cable = palmas_extcon_cable;
palmas_usb->edev.mutually_exclusive = mutually_exclusive;
@@ -182,28 +186,36 @@ static int palmas_usb_probe(struct platform_device *pdev)
return status;
}
- status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq,
- NULL, palmas_id_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "palmas_usb_id", palmas_usb);
- if (status < 0) {
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ if (palmas_usb->enable_id_detection) {
+ status = devm_request_threaded_irq(palmas_usb->dev,
+ palmas_usb->id_irq,
+ NULL, palmas_id_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas_usb_id", palmas_usb);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->id_irq, status);
- goto fail_extcon;
+ goto fail_extcon;
+ }
}
- status = devm_request_threaded_irq(palmas_usb->dev,
- palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "palmas_usb_vbus", palmas_usb);
- if (status < 0) {
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ if (palmas_usb->enable_vbus_detection) {
+ status = devm_request_threaded_irq(palmas_usb->dev,
+ palmas_usb->vbus_irq, NULL,
+ palmas_vbus_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas_usb_vbus", palmas_usb);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->vbus_irq, status);
- goto fail_extcon;
+ goto fail_extcon;
+ }
}
palmas_enable_irq(palmas_usb);
-
+ device_set_wakeup_capable(&pdev->dev, true);
return 0;
fail_extcon:
@@ -221,6 +233,39 @@ static int palmas_usb_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int palmas_usb_suspend(struct device *dev)
+{
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (palmas_usb->enable_vbus_detection)
+ enable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_id_detection)
+ enable_irq_wake(palmas_usb->id_irq);
+ }
+ return 0;
+}
+
+static int palmas_usb_resume(struct device *dev)
+{
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (palmas_usb->enable_vbus_detection)
+ disable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_id_detection)
+ disable_irq_wake(palmas_usb->id_irq);
+ }
+ return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
+ palmas_usb_resume)
+};
+
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-usb", },
{ .compatible = "ti,twl6035-usb", },
@@ -234,6 +279,7 @@ static struct platform_driver palmas_usb_driver = {
.name = "palmas-usb",
.of_match_table = of_palmas_match_tbl,
.owner = THIS_MODULE,
+ .pm = &palmas_pm_ops,
},
};
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
new file mode 100644
index 00000000000..72173ecbb31
--- /dev/null
+++ b/drivers/extcon/of_extcon.c
@@ -0,0 +1,64 @@
+/*
+ * OF helpers for External connector (extcon) framework
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ * Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/extcon/of_extcon.h>
+
+/*
+ * of_extcon_get_extcon_dev - Get the name of extcon device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of extcon_dev
+ *
+ * return the instance of extcon device
+ */
+struct extcon_dev *of_extcon_get_extcon_dev(struct device *dev, int index)
+{
+ struct device_node *node;
+ struct extcon_dev *edev;
+ struct platform_device *extcon_parent_dev;
+
+ if (!dev->of_node) {
+ dev_dbg(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, "extcon", index);
+ if (!node) {
+ dev_dbg(dev, "failed to get phandle in %s node\n",
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ extcon_parent_dev = of_find_device_by_node(node);
+ if (!extcon_parent_dev) {
+ dev_dbg(dev, "unable to find device by node\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ edev = extcon_get_extcon_dev(dev_name(&extcon_parent_dev->dev));
+ if (!edev) {
+ dev_dbg(dev, "unable to get extcon device : %s\n",
+ dev_name(&extcon_parent_dev->dev));
+ return ERR_PTR(-ENODEV);
+ }
+
+ return edev;
+}
+EXPORT_SYMBOL_GPL(of_extcon_get_extcon_dev);
diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
index cc031db2d2a..ace6ef24d15 100644
--- a/drivers/fmc/fmc-chardev.c
+++ b/drivers/fmc/fmc-chardev.c
@@ -143,18 +143,17 @@ static int fc_probe(struct fmc_device *fmc)
fc->misc.fops = &fc_fops;
fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL);
- spin_lock(&fc_lock);
ret = misc_register(&fc->misc);
if (ret < 0)
- goto err_unlock;
+ goto out;
+ spin_lock(&fc_lock);
list_add(&fc->list, &fc_devices);
spin_unlock(&fc_lock);
dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n",
fc->misc.name);
return 0;
-err_unlock:
- spin_unlock(&fc_lock);
+out:
kfree(fc->misc.name);
kfree(fc);
return ret;
@@ -174,10 +173,10 @@ static int fc_remove(struct fmc_device *fmc)
spin_lock(&fc_lock);
list_del(&fc->list);
+ spin_unlock(&fc_lock);
misc_deregister(&fc->misc);
kfree(fc->misc.name);
kfree(fc);
- spin_unlock(&fc_lock);
return 0;
}
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index 2cc680dd604..ee5b4790413 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -103,7 +103,7 @@ static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s)
* difficult to know in advance when probing the first card if others
* are there.
*/
-int fwe_probe(struct fmc_device *fmc)
+static int fwe_probe(struct fmc_device *fmc)
{
int err, index = 0;
const struct firmware *fw;
@@ -144,7 +144,7 @@ int fwe_probe(struct fmc_device *fmc)
return 0;
}
-int fwe_remove(struct fmc_device *fmc)
+static int fwe_remove(struct fmc_device *fmc)
{
return 0;
}
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 713217380b4..8fae6d1414c 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -590,6 +590,5 @@ static void __exit mousevsc_exit(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
module_init(mousevsc_init);
module_exit(mousevsc_exit);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 0df75908200..bbff5f200be 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -48,30 +48,39 @@ struct vmbus_channel_message_table_entry {
* @negop is of type &struct icmsg_negotiate.
* Set up and fill in default negotiate response message.
*
- * The max_fw_version specifies the maximum framework version that
- * we can support and max _srv_version specifies the maximum service
- * version we can support. A special value MAX_SRV_VER can be
- * specified to indicate that we can handle the maximum version
- * exposed by the host.
+ * The fw_version specifies the framework version that
+ * we can support and srv_version specifies the service
+ * version we can support.
*
* Mainly used by Hyper-V drivers.
*/
-void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
struct icmsg_negotiate *negop, u8 *buf,
- int max_fw_version, int max_srv_version)
+ int fw_version, int srv_version)
{
- int icframe_vercnt;
- int icmsg_vercnt;
+ int icframe_major, icframe_minor;
+ int icmsg_major, icmsg_minor;
+ int fw_major, fw_minor;
+ int srv_major, srv_minor;
int i;
+ bool found_match = false;
icmsghdrp->icmsgsize = 0x10;
+ fw_major = (fw_version >> 16);
+ fw_minor = (fw_version & 0xFFFF);
+
+ srv_major = (srv_version >> 16);
+ srv_minor = (srv_version & 0xFFFF);
negop = (struct icmsg_negotiate *)&buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- icframe_vercnt = negop->icframe_vercnt;
- icmsg_vercnt = negop->icmsg_vercnt;
+ icframe_major = negop->icframe_vercnt;
+ icframe_minor = 0;
+
+ icmsg_major = negop->icmsg_vercnt;
+ icmsg_minor = 0;
/*
* Select the framework version number we will
@@ -79,26 +88,48 @@ void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
*/
for (i = 0; i < negop->icframe_vercnt; i++) {
- if (negop->icversion_data[i].major <= max_fw_version)
- icframe_vercnt = negop->icversion_data[i].major;
+ if ((negop->icversion_data[i].major == fw_major) &&
+ (negop->icversion_data[i].minor == fw_minor)) {
+ icframe_major = negop->icversion_data[i].major;
+ icframe_minor = negop->icversion_data[i].minor;
+ found_match = true;
+ }
}
+ if (!found_match)
+ goto fw_error;
+
+ found_match = false;
+
for (i = negop->icframe_vercnt;
(i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
- if (negop->icversion_data[i].major <= max_srv_version)
- icmsg_vercnt = negop->icversion_data[i].major;
+ if ((negop->icversion_data[i].major == srv_major) &&
+ (negop->icversion_data[i].minor == srv_minor)) {
+ icmsg_major = negop->icversion_data[i].major;
+ icmsg_minor = negop->icversion_data[i].minor;
+ found_match = true;
+ }
}
/*
- * Respond with the maximum framework and service
+ * Respond with the framework and service
* version numbers we can support.
*/
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
- negop->icversion_data[0].major = icframe_vercnt;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = icmsg_vercnt;
- negop->icversion_data[1].minor = 0;
+
+fw_error:
+ if (!found_match) {
+ negop->icframe_vercnt = 0;
+ negop->icmsg_vercnt = 0;
+ } else {
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ }
+
+ negop->icversion_data[0].major = icframe_major;
+ negop->icversion_data[0].minor = icframe_minor;
+ negop->icversion_data[1].major = icmsg_major;
+ negop->icversion_data[1].minor = icmsg_minor;
+ return found_match;
}
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
@@ -262,6 +293,13 @@ static void vmbus_process_offer(struct work_struct *work)
}
/*
+ * This state is used to indicate a successful open
+ * so that when we do close the channel normally, we
+ * can cleanup properly
+ */
+ newchannel->state = CHANNEL_OPEN_STATE;
+
+ /*
* Start the process of binding this offer to the driver
* We need to set the DeviceObject field before calling
* vmbus_child_dev_add()
@@ -287,13 +325,6 @@ static void vmbus_process_offer(struct work_struct *work)
kfree(newchannel->device_obj);
free_channel(newchannel);
- } else {
- /*
- * This state is used to indicate a successful open
- * so that when we do close the channel normally, we
- * can cleanup properly
- */
- newchannel->state = CHANNEL_OPEN_STATE;
}
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index ec3b8cdf1e0..8f4743ab5fb 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -195,7 +195,10 @@ int vmbus_connect(void)
do {
ret = vmbus_negotiate_version(msginfo, version);
- if (ret == 0)
+ if (ret)
+ goto cleanup;
+
+ if (vmbus_connection.conn_state == CONNECTED)
break;
version = vmbus_get_next_version(version);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index deb5c25305a..7e17a5495e0 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -825,7 +825,6 @@ static void hot_add_req(struct work_struct *dummy)
memset(&resp, 0, sizeof(struct dm_hot_add_response));
resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE;
resp.hdr.size = sizeof(struct dm_hot_add_response);
- resp.hdr.trans_id = atomic_inc_return(&trans_id);
#ifdef CONFIG_MEMORY_HOTPLUG
pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
@@ -887,6 +886,7 @@ static void hot_add_req(struct work_struct *dummy)
pr_info("Memory hot add failed\n");
dm->state = DM_INITIALIZED;
+ resp.hdr.trans_id = atomic_inc_return(&trans_id);
vmbus_sendpacket(dm->dev->channel, &resp,
sizeof(struct dm_hot_add_response),
(unsigned long)NULL,
@@ -1081,7 +1081,6 @@ static void balloon_up(struct work_struct *dummy)
bl_resp = (struct dm_balloon_response *)send_buffer;
memset(send_buffer, 0, PAGE_SIZE);
bl_resp->hdr.type = DM_BALLOON_RESPONSE;
- bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
bl_resp->hdr.size = sizeof(struct dm_balloon_response);
bl_resp->more_pages = 1;
@@ -1109,6 +1108,7 @@ static void balloon_up(struct work_struct *dummy)
*/
do {
+ bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
ret = vmbus_sendpacket(dm_device.dev->channel,
bl_resp,
bl_resp->hdr.size,
@@ -1526,5 +1526,4 @@ static int __init init_balloon_drv(void)
module_init(init_balloon_drv);
MODULE_DESCRIPTION("Hyper-V Balloon");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index ed50e9e83c6..28b03325b87 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -29,6 +29,16 @@
#include <linux/hyperv.h>
+/*
+ * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
+ */
+#define WIN7_SRV_MAJOR 3
+#define WIN7_SRV_MINOR 0
+#define WIN7_SRV_MAJOR_MINOR (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
+
+#define WIN8_SRV_MAJOR 4
+#define WIN8_SRV_MINOR 0
+#define WIN8_SRV_MAJOR_MINOR (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
/*
* Global state maintained for transaction that is being processed.
@@ -76,7 +86,9 @@ static u8 *recv_buffer;
/*
* Register the kernel component with the user-level daemon.
* As part of this registration, pass the LIC version number.
+ * This number has no meaning, it satisfies the registration protocol.
*/
+#define HV_DRV_VERSION "3.1"
static void
kvp_register(int reg_value)
@@ -593,8 +605,19 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ /*
+ * We start with win8 version and if the host cannot
+ * support that we use the previous version.
+ */
+ if (vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ WIN8_SRV_MAJOR_MINOR))
+ goto done;
+
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ WIN7_SRV_MAJOR_MINOR);
+
} else {
kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
@@ -626,6 +649,7 @@ void hv_kvp_onchannelcallback(void *context)
return;
}
+done:
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 8ad5653ce44..e4572f3f283 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -24,6 +24,10 @@
#include <linux/workqueue.h>
#include <linux/hyperv.h>
+#define VSS_MAJOR 5
+#define VSS_MINOR 0
+#define VSS_MAJOR_MINOR (VSS_MAJOR << 16 | VSS_MINOR)
+
/*
@@ -186,18 +190,8 @@ void hv_vss_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
- /*
- * We currently negotiate the highest number the
- * host has presented. If this version is not
- * atleast 5.0, reject.
- */
- negop = (struct icmsg_negotiate *)&recv_buffer[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- if (negop->icversion_data[1].major < 5)
- negop->icframe_vercnt = 0;
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ VSS_MAJOR_MINOR);
} else {
vss_msg = (struct hv_vss_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 2f561c5dfe2..cb82233541b 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,6 +28,18 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
+#define SHUTDOWN_MAJOR 3
+#define SHUTDOWN_MINOR 0
+#define SHUTDOWN_MAJOR_MINOR (SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
+
+#define TIMESYNCH_MAJOR 3
+#define TIMESYNCH_MINOR 0
+#define TIMESYNCH_MAJOR_MINOR (TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR)
+
+#define HEARTBEAT_MAJOR 3
+#define HEARTBEAT_MINOR 0
+#define HEARTBEAT_MAJOR_MINOR (HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
+
static void shutdown_onchannelcallback(void *context);
static struct hv_util_service util_shutdown = {
.util_cb = shutdown_onchannelcallback,
@@ -87,7 +99,8 @@ static void shutdown_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+ shut_txf_buf, UTIL_FW_MAJOR_MINOR,
+ SHUTDOWN_MAJOR_MINOR);
} else {
shutdown_msg =
(struct shutdown_msg_data *)&shut_txf_buf[
@@ -213,7 +226,8 @@ static void timesync_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
- MAX_SRV_VER, MAX_SRV_VER);
+ UTIL_FW_MAJOR_MINOR,
+ TIMESYNCH_MAJOR_MINOR);
} else {
timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
@@ -253,7 +267,8 @@ static void heartbeat_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL,
- hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+ hbeat_txf_buf, UTIL_FW_MAJOR_MINOR,
+ HEARTBEAT_MAJOR_MINOR);
} else {
heartbeat_msg =
(struct heartbeat_msg_data *)&hbeat_txf_buf[
@@ -380,5 +395,4 @@ module_init(init_hyperv_utils);
module_exit(exit_hyperv_utils);
MODULE_DESCRIPTION("Hyper-V Utilities");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index e8e071fc1d6..f9fe46f52cf 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -816,7 +816,6 @@ static void __exit vmbus_exit(void)
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
subsys_initcall(hv_acpi_init);
module_exit(vmbus_exit);
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index e068a76a5f6..5be808406ed 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
/* Serialize access to ssc_list and user count */
static DEFINE_SPINLOCK(user_lock);
@@ -137,13 +136,6 @@ static int ssc_probe(struct platform_device *pdev)
struct resource *regs;
struct ssc_device *ssc;
const struct atmel_ssc_platform_data *plat_dat;
- struct pinctrl *pinctrl;
-
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "Failed to request pinctrl\n");
- return PTR_ERR(pinctrl);
- }
ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
if (!ssc) {
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 621c7a37339..b83e3ca12a4 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -759,7 +759,7 @@ static int ilo_probe(struct pci_dev *pdev,
/* Ignore subsystem_device = 0x1979 (set by BIOS) */
if (pdev->subsystem_device == 0x1979)
- goto out;
+ return 0;
if (max_ccb > MAX_CCB)
max_ccb = MAX_CCB;
@@ -899,7 +899,7 @@ static void __exit ilo_exit(void)
class_destroy(ilo_class);
}
-MODULE_VERSION("1.4");
+MODULE_VERSION("1.4.1");
MODULE_ALIAS(ILO_NAME);
MODULE_DESCRIPTION(ILO_NAME);
MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 08aad69c8da..2fc0586ce3b 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -43,6 +43,7 @@
#include <linux/slab.h>
#include <scsi/scsi_cmnd.h>
#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
#ifdef CONFIG_IDE
#include <linux/ide.h>
@@ -50,6 +51,7 @@
#define DEFAULT_COUNT 10
#define REC_NUM_DEFAULT 10
+#define EXEC_SIZE 64
enum cname {
CN_INVALID,
@@ -68,6 +70,7 @@ enum ctype {
CT_NONE,
CT_PANIC,
CT_BUG,
+ CT_WARNING,
CT_EXCEPTION,
CT_LOOP,
CT_OVERFLOW,
@@ -77,7 +80,12 @@ enum ctype {
CT_WRITE_AFTER_FREE,
CT_SOFTLOCKUP,
CT_HARDLOCKUP,
+ CT_SPINLOCKUP,
CT_HUNG_TASK,
+ CT_EXEC_DATA,
+ CT_EXEC_STACK,
+ CT_EXEC_KMALLOC,
+ CT_EXEC_VMALLOC,
};
static char* cp_name[] = {
@@ -95,6 +103,7 @@ static char* cp_name[] = {
static char* cp_type[] = {
"PANIC",
"BUG",
+ "WARNING",
"EXCEPTION",
"LOOP",
"OVERFLOW",
@@ -104,7 +113,12 @@ static char* cp_type[] = {
"WRITE_AFTER_FREE",
"SOFTLOCKUP",
"HARDLOCKUP",
+ "SPINLOCKUP",
"HUNG_TASK",
+ "EXEC_DATA",
+ "EXEC_STACK",
+ "EXEC_KMALLOC",
+ "EXEC_VMALLOC",
};
static struct jprobe lkdtm;
@@ -121,6 +135,9 @@ static enum cname cpoint = CN_INVALID;
static enum ctype cptype = CT_NONE;
static int count = DEFAULT_COUNT;
static DEFINE_SPINLOCK(count_lock);
+static DEFINE_SPINLOCK(lock_me_up);
+
+static u8 data_area[EXEC_SIZE];
module_param(recur_count, int, 0644);
MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
@@ -275,6 +292,19 @@ static int recursive_loop(int a)
return recursive_loop(a);
}
+static void do_nothing(void)
+{
+ return;
+}
+
+static void execute_location(void *dst)
+{
+ void (*func)(void) = dst;
+
+ memcpy(dst, do_nothing, EXEC_SIZE);
+ func();
+}
+
static void lkdtm_do_action(enum ctype which)
{
switch (which) {
@@ -284,6 +314,9 @@ static void lkdtm_do_action(enum ctype which)
case CT_BUG:
BUG();
break;
+ case CT_WARNING:
+ WARN_ON(1);
+ break;
case CT_EXCEPTION:
*((int *) 0) = 0;
break;
@@ -295,10 +328,10 @@ static void lkdtm_do_action(enum ctype which)
(void) recursive_loop(0);
break;
case CT_CORRUPT_STACK: {
- volatile u32 data[8];
- volatile u32 *p = data;
+ /* Make sure the compiler creates and uses an 8 char array. */
+ volatile char data[8];
- p[12] = 0x12345678;
+ memset((void *)data, 0, 64);
break;
}
case CT_UNALIGNED_LOAD_STORE_WRITE: {
@@ -340,10 +373,34 @@ static void lkdtm_do_action(enum ctype which)
for (;;)
cpu_relax();
break;
+ case CT_SPINLOCKUP:
+ /* Must be called twice to trigger. */
+ spin_lock(&lock_me_up);
+ break;
case CT_HUNG_TASK:
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
break;
+ case CT_EXEC_DATA:
+ execute_location(data_area);
+ break;
+ case CT_EXEC_STACK: {
+ u8 stack_area[EXEC_SIZE];
+ execute_location(stack_area);
+ break;
+ }
+ case CT_EXEC_KMALLOC: {
+ u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL);
+ execute_location(kmalloc_area);
+ kfree(kmalloc_area);
+ break;
+ }
+ case CT_EXEC_VMALLOC: {
+ u32 *vmalloc_area = vmalloc(EXEC_SIZE);
+ execute_location(vmalloc_area);
+ vfree(vmalloc_area);
+ break;
+ }
case CT_NONE:
default:
break;
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 749452f8e2f..d0fdc134068 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -418,15 +418,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
struct file *file, poll_table *wait)
{
unsigned int mask = 0;
- mutex_unlock(&dev->device_lock);
+
poll_wait(file, &dev->iamthif_cl.wait, wait);
+
mutex_lock(&dev->device_lock);
- if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
- dev->iamthif_file_object == file) {
+ if (!mei_cl_is_connected(&dev->iamthif_cl)) {
+
+ mask = POLLERR;
+
+ } else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+ dev->iamthif_file_object == file) {
+
mask |= (POLLIN | POLLRDNORM);
dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
+ mutex_unlock(&dev->device_lock);
+
return mask;
}
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 9ecd49a7be1..a150a42ed4a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -47,7 +47,7 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
id = driver->id_table;
while (id->name[0]) {
- if (!strcmp(dev_name(dev), id->name))
+ if (!strncmp(dev_name(dev), id->name, sizeof(id->name)))
return 1;
id++;
@@ -71,7 +71,7 @@ static int mei_cl_device_probe(struct device *dev)
dev_dbg(dev, "Device probe\n");
- strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+ strncpy(id.name, dev_name(dev), sizeof(id.name));
return driver->probe(device, &id);
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 21d3f5aa835..e0684b4d9a0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -635,10 +635,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
dev = cl->dev;
- if (cl->state != MEI_FILE_CONNECTED)
- return -ENODEV;
-
- if (dev->dev_state != MEI_DEV_ENABLED)
+ if (!mei_cl_is_connected(cl))
return -ENODEV;
if (cl->read_cb) {
@@ -892,18 +889,22 @@ void mei_cl_all_disconnect(struct mei_device *dev)
/**
- * mei_cl_all_read_wakeup - wake up all readings so they can be interrupted
+ * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
*
* @dev - mei device
*/
-void mei_cl_all_read_wakeup(struct mei_device *dev)
+void mei_cl_all_wakeup(struct mei_device *dev)
{
struct mei_cl *cl, *next;
list_for_each_entry_safe(cl, next, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
- dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+ dev_dbg(&dev->pdev->dev, "Waking up reading client!\n");
wake_up_interruptible(&cl->rx_wait);
}
+ if (waitqueue_active(&cl->tx_wait)) {
+ dev_dbg(&dev->pdev->dev, "Waking up writing client!\n");
+ wake_up_interruptible(&cl->tx_wait);
+ }
}
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 26b157d8bad..9eb031e9207 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -84,6 +84,13 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
/*
* MEI input output function prototype
*/
+static inline bool mei_cl_is_connected(struct mei_cl *cl)
+{
+ return (cl->dev &&
+ cl->dev->dev_state == MEI_DEV_ENABLED &&
+ cl->state == MEI_FILE_CONNECTED);
+}
+
bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl);
int mei_cl_connect(struct mei_cl *cl, struct file *file);
@@ -99,7 +106,7 @@ void mei_host_client_init(struct work_struct *work);
void mei_cl_all_disconnect(struct mei_device *dev);
-void mei_cl_all_read_wakeup(struct mei_device *dev);
+void mei_cl_all_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);
#endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index b22c7e24722..3412adcdaeb 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -176,21 +176,18 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
- dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);
-
- hcsr |= (H_RST | H_IG);
+ hcsr |= H_RST | H_IG | H_IS;
if (intr_enable)
hcsr |= H_IE;
else
- hcsr |= ~H_IE;
+ hcsr &= ~H_IE;
- mei_hcsr_set(hw, hcsr);
+ mei_me_reg_write(hw, H_CSR, hcsr);
if (dev->dev_state == MEI_DEV_POWER_DOWN)
mei_me_hw_reset_release(dev);
- dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
return 0;
}
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index e6f16f83ecd..92c73118b13 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -154,8 +154,14 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETTING;
+ /* remove all waiting requests */
+ mei_cl_all_write_clear(dev);
+
mei_cl_all_disconnect(dev);
+ /* wake up all readings so they can be interrupted */
+ mei_cl_all_wakeup(dev);
+
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
mei_cl_unlink(&dev->wd_cl);
@@ -196,11 +202,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_hbm_start_req(dev);
- /* wake up all readings so they can be interrupted */
- mei_cl_all_read_wakeup(dev);
-
- /* remove all waiting requests */
- mei_cl_all_write_clear(dev);
}
EXPORT_SYMBOL_GPL(mei_reset);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5e11b5b9b65..173ff095be0 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -625,24 +625,32 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
unsigned int mask = 0;
if (WARN_ON(!cl || !cl->dev))
- return mask;
+ return POLLERR;
dev = cl->dev;
mutex_lock(&dev->device_lock);
- if (dev->dev_state != MEI_DEV_ENABLED)
- goto out;
-
-
- if (cl == &dev->iamthif_cl) {
- mask = mei_amthif_poll(dev, file, wait);
+ if (!mei_cl_is_connected(cl)) {
+ mask = POLLERR;
goto out;
}
mutex_unlock(&dev->device_lock);
+
+
+ if (cl == &dev->iamthif_cl)
+ return mei_amthif_poll(dev, file, wait);
+
poll_wait(file, &cl->tx_wait, wait);
+
mutex_lock(&dev->device_lock);
+
+ if (!mei_cl_is_connected(cl)) {
+ mask = POLLERR;
+ goto out;
+ }
+
if (MEI_WRITE_COMPLETE == cl->writing_state)
mask |= (POLLIN | POLLRDNORM);
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index d87cc91bc01..afe66571ce0 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -68,7 +68,8 @@ static int sram_probe(struct platform_device *pdev)
ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
res->start, size, -1);
if (ret < 0) {
- gen_pool_destroy(sram->pool);
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
return ret;
}
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 0a142801635..8d64b681dd9 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -562,7 +562,9 @@ long st_register(struct st_proto_s *new_proto)
if ((st_gdata->protos_registered != ST_EMPTY) &&
(test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_err(" KIM failure complete callback ");
+ spin_lock_irqsave(&st_gdata->lock, flags);
st_reg_complete(st_gdata, err);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
clear_bit(ST_REG_PENDING, &st_gdata->st_state);
}
return -EINVAL;
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index cb56e270da1..2421835d5da 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -133,7 +133,7 @@ MODULE_LICENSE("GPL");
#define VMWARE_BALLOON_CMD(cmd, data, result) \
({ \
unsigned long __stat, __dummy1, __dummy2; \
- __asm__ __volatile__ ("inl (%%dx)" : \
+ __asm__ __volatile__ ("inl %%dx" : \
"=a"(__stat), \
"=c"(__dummy1), \
"=d"(__dummy2), \
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index 7b3fce2da6c..3dee7ae123e 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.0.0.0-k");
+MODULE_VERSION("1.1.0.0-k");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_driver.h b/drivers/misc/vmw_vmci/vmci_driver.h
index f69156a1f30..cee9e977d31 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.h
+++ b/drivers/misc/vmw_vmci/vmci_driver.h
@@ -35,6 +35,13 @@ struct vmci_obj {
enum vmci_obj_type type;
};
+/*
+ * Needed by other components of this module. It's okay to have one global
+ * instance of this because there can only ever be one VMCI device. Our
+ * virtual hardware enforces this.
+ */
+extern struct pci_dev *vmci_pdev;
+
u32 vmci_get_context_id(void);
int vmci_send_datagram(struct vmci_datagram *dg);
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
index 60c01999f48..b3a2b763ecf 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -65,9 +65,11 @@ struct vmci_guest_device {
void *data_buffer;
void *notification_bitmap;
+ dma_addr_t notification_base;
};
/* vmci_dev singleton device and supporting data*/
+struct pci_dev *vmci_pdev;
static struct vmci_guest_device *vmci_dev_g;
static DEFINE_SPINLOCK(vmci_dev_spinlock);
@@ -528,7 +530,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
* well.
*/
if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- vmci_dev->notification_bitmap = vmalloc(PAGE_SIZE);
+ vmci_dev->notification_bitmap = dma_alloc_coherent(
+ &pdev->dev, PAGE_SIZE, &vmci_dev->notification_base,
+ GFP_KERNEL);
if (!vmci_dev->notification_bitmap) {
dev_warn(&pdev->dev,
"Unable to allocate notification bitmap\n");
@@ -546,6 +550,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
/* Set up global device so that we can start sending datagrams */
spin_lock_irq(&vmci_dev_spinlock);
vmci_dev_g = vmci_dev;
+ vmci_pdev = pdev;
spin_unlock_irq(&vmci_dev_spinlock);
/*
@@ -553,9 +558,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
* used.
*/
if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- struct page *page =
- vmalloc_to_page(vmci_dev->notification_bitmap);
- unsigned long bitmap_ppn = page_to_pfn(page);
+ unsigned long bitmap_ppn =
+ vmci_dev->notification_base >> PAGE_SHIFT;
if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
dev_warn(&pdev->dev,
"VMCI device unable to register notification bitmap with PPN 0x%x\n",
@@ -665,11 +669,14 @@ err_remove_bitmap:
if (vmci_dev->notification_bitmap) {
iowrite32(VMCI_CONTROL_RESET,
vmci_dev->iobase + VMCI_CONTROL_ADDR);
- vfree(vmci_dev->notification_bitmap);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ vmci_dev->notification_bitmap,
+ vmci_dev->notification_base);
}
err_remove_vmci_dev_g:
spin_lock_irq(&vmci_dev_spinlock);
+ vmci_pdev = NULL;
vmci_dev_g = NULL;
spin_unlock_irq(&vmci_dev_spinlock);
@@ -699,6 +706,7 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
spin_lock_irq(&vmci_dev_spinlock);
vmci_dev_g = NULL;
+ vmci_pdev = NULL;
spin_unlock_irq(&vmci_dev_spinlock);
dev_dbg(&pdev->dev, "Resetting vmci device\n");
@@ -727,7 +735,9 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
* device, so we can safely free it here.
*/
- vfree(vmci_dev->notification_bitmap);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ vmci_dev->notification_bitmap,
+ vmci_dev->notification_base);
}
vfree(vmci_dev->data_buffer);
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 8ff2e5ee8fb..a0515a6d6eb 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
+#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uio.h>
@@ -146,14 +147,20 @@ typedef int vmci_memcpy_from_queue_func(void *dest, size_t dest_offset,
/* The Kernel specific component of the struct vmci_queue structure. */
struct vmci_queue_kern_if {
- struct page **page;
- struct page **header_page;
- void *va;
struct mutex __mutex; /* Protects the queue. */
struct mutex *mutex; /* Shared by producer and consumer queues. */
- bool host;
- size_t num_pages;
- bool mapped;
+ size_t num_pages; /* Number of pages incl. header. */
+ bool host; /* Host or guest? */
+ union {
+ struct {
+ dma_addr_t *pas;
+ void **vas;
+ } g; /* Used by the guest. */
+ struct {
+ struct page **page;
+ struct page **header_page;
+ } h; /* Used by the host. */
+ } u;
};
/*
@@ -265,76 +272,65 @@ static void qp_free_queue(void *q, u64 size)
struct vmci_queue *queue = q;
if (queue) {
- u64 i = DIV_ROUND_UP(size, PAGE_SIZE);
+ u64 i;
- if (queue->kernel_if->mapped) {
- vunmap(queue->kernel_if->va);
- queue->kernel_if->va = NULL;
+ /* Given size does not include header, so add in a page here. */
+ for (i = 0; i < DIV_ROUND_UP(size, PAGE_SIZE) + 1; i++) {
+ dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE,
+ queue->kernel_if->u.g.vas[i],
+ queue->kernel_if->u.g.pas[i]);
}
- while (i)
- __free_page(queue->kernel_if->page[--i]);
-
- vfree(queue->q_header);
+ vfree(queue);
}
}
/*
- * Allocates kernel VA space of specified size, plus space for the
- * queue structure/kernel interface and the queue header. Allocates
- * physical pages for the queue data pages.
- *
- * PAGE m: struct vmci_queue_header (struct vmci_queue->q_header)
- * PAGE m+1: struct vmci_queue
- * PAGE m+1+q: struct vmci_queue_kern_if (struct vmci_queue->kernel_if)
- * PAGE n-size: Data pages (struct vmci_queue->kernel_if->page[])
+ * Allocates kernel queue pages of specified size with IOMMU mappings,
+ * plus space for the queue structure/kernel interface and the queue
+ * header.
*/
static void *qp_alloc_queue(u64 size, u32 flags)
{
u64 i;
struct vmci_queue *queue;
- struct vmci_queue_header *q_header;
- const u64 num_data_pages = DIV_ROUND_UP(size, PAGE_SIZE);
- const uint queue_size =
- PAGE_SIZE +
- sizeof(*queue) + sizeof(*(queue->kernel_if)) +
- num_data_pages * sizeof(*(queue->kernel_if->page));
-
- q_header = vmalloc(queue_size);
- if (!q_header)
+ const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+ const size_t pas_size = num_pages * sizeof(*queue->kernel_if->u.g.pas);
+ const size_t vas_size = num_pages * sizeof(*queue->kernel_if->u.g.vas);
+ const size_t queue_size =
+ sizeof(*queue) + sizeof(*queue->kernel_if) +
+ pas_size + vas_size;
+
+ queue = vmalloc(queue_size);
+ if (!queue)
return NULL;
- queue = (void *)q_header + PAGE_SIZE;
- queue->q_header = q_header;
+ queue->q_header = NULL;
queue->saved_header = NULL;
queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
- queue->kernel_if->header_page = NULL; /* Unused in guest. */
- queue->kernel_if->page = (struct page **)(queue->kernel_if + 1);
+ queue->kernel_if->mutex = NULL;
+ queue->kernel_if->num_pages = num_pages;
+ queue->kernel_if->u.g.pas = (dma_addr_t *)(queue->kernel_if + 1);
+ queue->kernel_if->u.g.vas =
+ (void **)((u8 *)queue->kernel_if->u.g.pas + pas_size);
queue->kernel_if->host = false;
- queue->kernel_if->va = NULL;
- queue->kernel_if->mapped = false;
-
- for (i = 0; i < num_data_pages; i++) {
- queue->kernel_if->page[i] = alloc_pages(GFP_KERNEL, 0);
- if (!queue->kernel_if->page[i])
- goto fail;
- }
- if (vmci_qp_pinned(flags)) {
- queue->kernel_if->va =
- vmap(queue->kernel_if->page, num_data_pages, VM_MAP,
- PAGE_KERNEL);
- if (!queue->kernel_if->va)
- goto fail;
-
- queue->kernel_if->mapped = true;
+ for (i = 0; i < num_pages; i++) {
+ queue->kernel_if->u.g.vas[i] =
+ dma_alloc_coherent(&vmci_pdev->dev, PAGE_SIZE,
+ &queue->kernel_if->u.g.pas[i],
+ GFP_KERNEL);
+ if (!queue->kernel_if->u.g.vas[i]) {
+ /* Size excl. the header. */
+ qp_free_queue(queue, i * PAGE_SIZE);
+ return NULL;
+ }
}
- return (void *)queue;
+ /* Queue header is the first page. */
+ queue->q_header = queue->kernel_if->u.g.vas[0];
- fail:
- qp_free_queue(queue, i * PAGE_SIZE);
- return NULL;
+ return queue;
}
/*
@@ -353,17 +349,18 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
size_t bytes_copied = 0;
while (bytes_copied < size) {
- u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
- size_t page_offset =
+ const u64 page_index =
+ (queue_offset + bytes_copied) / PAGE_SIZE;
+ const size_t page_offset =
(queue_offset + bytes_copied) & (PAGE_SIZE - 1);
void *va;
size_t to_copy;
- if (!kernel_if->mapped)
- va = kmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ va = kmap(kernel_if->u.h.page[page_index]);
else
- va = (void *)((u8 *)kernel_if->va +
- (page_index * PAGE_SIZE));
+ va = kernel_if->u.g.vas[page_index + 1];
+ /* Skip header. */
if (size - bytes_copied > PAGE_SIZE - page_offset)
/* Enough payload to fill up from this page. */
@@ -379,7 +376,8 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
err = memcpy_fromiovec((u8 *)va + page_offset,
iov, to_copy);
if (err != 0) {
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
return VMCI_ERROR_INVALID_ARGS;
}
} else {
@@ -388,8 +386,8 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
}
bytes_copied += to_copy;
- if (!kernel_if->mapped)
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
}
return VMCI_SUCCESS;
@@ -411,17 +409,18 @@ static int __qp_memcpy_from_queue(void *dest,
size_t bytes_copied = 0;
while (bytes_copied < size) {
- u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
- size_t page_offset =
+ const u64 page_index =
+ (queue_offset + bytes_copied) / PAGE_SIZE;
+ const size_t page_offset =
(queue_offset + bytes_copied) & (PAGE_SIZE - 1);
void *va;
size_t to_copy;
- if (!kernel_if->mapped)
- va = kmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ va = kmap(kernel_if->u.h.page[page_index]);
else
- va = (void *)((u8 *)kernel_if->va +
- (page_index * PAGE_SIZE));
+ va = kernel_if->u.g.vas[page_index + 1];
+ /* Skip header. */
if (size - bytes_copied > PAGE_SIZE - page_offset)
/* Enough payload to fill up this page. */
@@ -437,7 +436,8 @@ static int __qp_memcpy_from_queue(void *dest,
err = memcpy_toiovec(iov, (u8 *)va + page_offset,
to_copy);
if (err != 0) {
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
return VMCI_ERROR_INVALID_ARGS;
}
} else {
@@ -446,8 +446,8 @@ static int __qp_memcpy_from_queue(void *dest,
}
bytes_copied += to_copy;
- if (!kernel_if->mapped)
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
}
return VMCI_SUCCESS;
@@ -489,12 +489,11 @@ static int qp_alloc_ppn_set(void *prod_q,
return VMCI_ERROR_NO_MEM;
}
- produce_ppns[0] = page_to_pfn(vmalloc_to_page(produce_q->q_header));
- for (i = 1; i < num_produce_pages; i++) {
+ for (i = 0; i < num_produce_pages; i++) {
unsigned long pfn;
produce_ppns[i] =
- page_to_pfn(produce_q->kernel_if->page[i - 1]);
+ produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = produce_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -503,12 +502,11 @@ static int qp_alloc_ppn_set(void *prod_q,
goto ppn_error;
}
- consume_ppns[0] = page_to_pfn(vmalloc_to_page(consume_q->q_header));
- for (i = 1; i < num_consume_pages; i++) {
+ for (i = 0; i < num_consume_pages; i++) {
unsigned long pfn;
consume_ppns[i] =
- page_to_pfn(consume_q->kernel_if->page[i - 1]);
+ consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = consume_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -619,23 +617,20 @@ static struct vmci_queue *qp_host_alloc_queue(u64 size)
const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
const size_t queue_page_size =
- num_pages * sizeof(*queue->kernel_if->page);
+ num_pages * sizeof(*queue->kernel_if->u.h.page);
queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
if (queue) {
queue->q_header = NULL;
queue->saved_header = NULL;
- queue->kernel_if =
- (struct vmci_queue_kern_if *)((u8 *)queue +
- sizeof(*queue));
+ queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
queue->kernel_if->host = true;
queue->kernel_if->mutex = NULL;
queue->kernel_if->num_pages = num_pages;
- queue->kernel_if->header_page =
+ queue->kernel_if->u.h.header_page =
(struct page **)((u8 *)queue + queue_size);
- queue->kernel_if->page = &queue->kernel_if->header_page[1];
- queue->kernel_if->va = NULL;
- queue->kernel_if->mapped = false;
+ queue->kernel_if->u.h.page =
+ &queue->kernel_if->u.h.header_page[1];
}
return queue;
@@ -742,11 +737,12 @@ static int qp_host_get_user_memory(u64 produce_uva,
current->mm,
(uintptr_t) produce_uva,
produce_q->kernel_if->num_pages,
- 1, 0, produce_q->kernel_if->header_page, NULL);
+ 1, 0,
+ produce_q->kernel_if->u.h.header_page, NULL);
if (retval < produce_q->kernel_if->num_pages) {
pr_warn("get_user_pages(produce) failed (retval=%d)", retval);
- qp_release_pages(produce_q->kernel_if->header_page, retval,
- false);
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
+ retval, false);
err = VMCI_ERROR_NO_MEM;
goto out;
}
@@ -755,12 +751,13 @@ static int qp_host_get_user_memory(u64 produce_uva,
current->mm,
(uintptr_t) consume_uva,
consume_q->kernel_if->num_pages,
- 1, 0, consume_q->kernel_if->header_page, NULL);
+ 1, 0,
+ consume_q->kernel_if->u.h.header_page, NULL);
if (retval < consume_q->kernel_if->num_pages) {
pr_warn("get_user_pages(consume) failed (retval=%d)", retval);
- qp_release_pages(consume_q->kernel_if->header_page, retval,
- false);
- qp_release_pages(produce_q->kernel_if->header_page,
+ qp_release_pages(consume_q->kernel_if->u.h.header_page,
+ retval, false);
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
produce_q->kernel_if->num_pages, false);
err = VMCI_ERROR_NO_MEM;
}
@@ -803,15 +800,15 @@ static int qp_host_register_user_memory(struct vmci_qp_page_store *page_store,
static void qp_host_unregister_user_memory(struct vmci_queue *produce_q,
struct vmci_queue *consume_q)
{
- qp_release_pages(produce_q->kernel_if->header_page,
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
produce_q->kernel_if->num_pages, true);
- memset(produce_q->kernel_if->header_page, 0,
- sizeof(*produce_q->kernel_if->header_page) *
+ memset(produce_q->kernel_if->u.h.header_page, 0,
+ sizeof(*produce_q->kernel_if->u.h.header_page) *
produce_q->kernel_if->num_pages);
- qp_release_pages(consume_q->kernel_if->header_page,
+ qp_release_pages(consume_q->kernel_if->u.h.header_page,
consume_q->kernel_if->num_pages, true);
- memset(consume_q->kernel_if->header_page, 0,
- sizeof(*consume_q->kernel_if->header_page) *
+ memset(consume_q->kernel_if->u.h.header_page, 0,
+ sizeof(*consume_q->kernel_if->u.h.header_page) *
consume_q->kernel_if->num_pages);
}
@@ -834,12 +831,12 @@ static int qp_host_map_queues(struct vmci_queue *produce_q,
if (produce_q->q_header != consume_q->q_header)
return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- if (produce_q->kernel_if->header_page == NULL ||
- *produce_q->kernel_if->header_page == NULL)
+ if (produce_q->kernel_if->u.h.header_page == NULL ||
+ *produce_q->kernel_if->u.h.header_page == NULL)
return VMCI_ERROR_UNAVAILABLE;
- headers[0] = *produce_q->kernel_if->header_page;
- headers[1] = *consume_q->kernel_if->header_page;
+ headers[0] = *produce_q->kernel_if->u.h.header_page;
+ headers[1] = *consume_q->kernel_if->u.h.header_page;
produce_q->q_header = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
if (produce_q->q_header != NULL) {
@@ -1720,21 +1717,6 @@ static int qp_broker_attach(struct qp_broker_entry *entry,
if (result < VMCI_SUCCESS)
return result;
- /*
- * Preemptively load in the headers if non-blocking to
- * prevent blocking later.
- */
- if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
- result = qp_host_map_queues(entry->produce_q,
- entry->consume_q);
- if (result < VMCI_SUCCESS) {
- qp_host_unregister_user_memory(
- entry->produce_q,
- entry->consume_q);
- return result;
- }
- }
-
entry->state = VMCIQPB_ATTACHED_MEM;
} else {
entry->state = VMCIQPB_ATTACHED_NO_MEM;
@@ -1749,24 +1731,6 @@ static int qp_broker_attach(struct qp_broker_entry *entry,
return VMCI_ERROR_UNAVAILABLE;
} else {
- /*
- * For non-blocking queue pairs, we cannot rely on
- * enqueue/dequeue to map in the pages on the
- * host-side, since it may block, so we make an
- * attempt here.
- */
-
- if (flags & VMCI_QPFLAG_NONBLOCK) {
- result =
- qp_host_map_queues(entry->produce_q,
- entry->consume_q);
- if (result < VMCI_SUCCESS)
- return result;
-
- entry->qp.flags |= flags &
- (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
- }
-
/* The host side has successfully attached to a queue pair. */
entry->state = VMCIQPB_ATTACHED_MEM;
}
@@ -2543,24 +2507,19 @@ void vmci_qp_guest_endpoints_exit(void)
* Since non-blocking isn't yet implemented on the host personality we
* have no reason to acquire a spin lock. So to avoid the use of an
* unnecessary lock only acquire the mutex if we can block.
- * Note: It is assumed that QPFLAG_PINNED implies QPFLAG_NONBLOCK. Therefore
- * we can use the same locking function for access to both the queue
- * and the queue headers as it is the same logic. Assert this behvior.
*/
static void qp_lock(const struct vmci_qp *qpair)
{
- if (vmci_can_block(qpair->flags))
- qp_acquire_queue_mutex(qpair->produce_q);
+ qp_acquire_queue_mutex(qpair->produce_q);
}
/*
* Helper routine that unlocks the queue pair after calling
- * qp_lock. Respects non-blocking and pinning flags.
+ * qp_lock.
*/
static void qp_unlock(const struct vmci_qp *qpair)
{
- if (vmci_can_block(qpair->flags))
- qp_release_queue_mutex(qpair->produce_q);
+ qp_release_queue_mutex(qpair->produce_q);
}
/*
@@ -2568,17 +2527,12 @@ static void qp_unlock(const struct vmci_qp *qpair)
* currently not mapped, it will be attempted to do so.
*/
static int qp_map_queue_headers(struct vmci_queue *produce_q,
- struct vmci_queue *consume_q,
- bool can_block)
+ struct vmci_queue *consume_q)
{
int result;
if (NULL == produce_q->q_header || NULL == consume_q->q_header) {
- if (can_block)
- result = qp_host_map_queues(produce_q, consume_q);
- else
- result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
-
+ result = qp_host_map_queues(produce_q, consume_q);
if (result < VMCI_SUCCESS)
return (produce_q->saved_header &&
consume_q->saved_header) ?
@@ -2601,8 +2555,7 @@ static int qp_get_queue_headers(const struct vmci_qp *qpair,
{
int result;
- result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q,
- vmci_can_block(qpair->flags));
+ result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q);
if (result == VMCI_SUCCESS) {
*produce_q_header = qpair->produce_q->q_header;
*consume_q_header = qpair->consume_q->q_header;
@@ -2645,9 +2598,6 @@ static bool qp_wait_for_ready_queue(struct vmci_qp *qpair)
{
unsigned int generation;
- if (qpair->flags & VMCI_QPFLAG_NONBLOCK)
- return false;
-
qpair->blocked++;
generation = qpair->generation;
qp_unlock(qpair);
@@ -2674,15 +2624,14 @@ static ssize_t qp_enqueue_locked(struct vmci_queue *produce_q,
const u64 produce_q_size,
const void *buf,
size_t buf_size,
- vmci_memcpy_to_queue_func memcpy_to_queue,
- bool can_block)
+ vmci_memcpy_to_queue_func memcpy_to_queue)
{
s64 free_space;
u64 tail;
size_t written;
ssize_t result;
- result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ result = qp_map_queue_headers(produce_q, consume_q);
if (unlikely(result != VMCI_SUCCESS))
return result;
@@ -2737,15 +2686,14 @@ static ssize_t qp_dequeue_locked(struct vmci_queue *produce_q,
void *buf,
size_t buf_size,
vmci_memcpy_from_queue_func memcpy_from_queue,
- bool update_consumer,
- bool can_block)
+ bool update_consumer)
{
s64 buf_ready;
u64 head;
size_t read;
ssize_t result;
- result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ result = qp_map_queue_headers(produce_q, consume_q);
if (unlikely(result != VMCI_SUCCESS))
return result;
@@ -2842,32 +2790,11 @@ int vmci_qpair_alloc(struct vmci_qp **qpair,
route = vmci_guest_code_active() ?
VMCI_ROUTE_AS_GUEST : VMCI_ROUTE_AS_HOST;
- /* If NONBLOCK or PINNED is set, we better be the guest personality. */
- if ((!vmci_can_block(flags) || vmci_qp_pinned(flags)) &&
- VMCI_ROUTE_AS_GUEST != route) {
- pr_devel("Not guest personality w/ NONBLOCK OR PINNED set");
+ if (flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED)) {
+ pr_devel("NONBLOCK OR PINNED set");
return VMCI_ERROR_INVALID_ARGS;
}
- /*
- * Limit the size of pinned QPs and check sanity.
- *
- * Pinned pages implies non-blocking mode. Mutexes aren't acquired
- * when the NONBLOCK flag is set in qpair code; and also should not be
- * acquired when the PINNED flagged is set. Since pinning pages
- * implies we want speed, it makes no sense not to have NONBLOCK
- * set if PINNED is set. Hence enforce this implication.
- */
- if (vmci_qp_pinned(flags)) {
- if (vmci_can_block(flags)) {
- pr_err("Attempted to enable pinning w/o non-blocking");
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (produce_qsize + consume_qsize > VMCI_MAX_PINNED_QP_MEMORY)
- return VMCI_ERROR_NO_RESOURCES;
- }
-
my_qpair = kzalloc(sizeof(*my_qpair), GFP_KERNEL);
if (!my_qpair)
return VMCI_ERROR_NO_MEM;
@@ -3195,8 +3122,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
qpair->consume_q,
qpair->produce_q_size,
buf, buf_size,
- qp_memcpy_to_queue,
- vmci_can_block(qpair->flags));
+ qp_memcpy_to_queue);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3237,8 +3163,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
qpair->consume_q,
qpair->consume_q_size,
buf, buf_size,
- qp_memcpy_from_queue, true,
- vmci_can_block(qpair->flags));
+ qp_memcpy_from_queue, true);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3280,8 +3205,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
qpair->consume_q,
qpair->consume_q_size,
buf, buf_size,
- qp_memcpy_from_queue, false,
- vmci_can_block(qpair->flags));
+ qp_memcpy_from_queue, false);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3323,8 +3247,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
qpair->consume_q,
qpair->produce_q_size,
iov, iov_size,
- qp_memcpy_to_queue_iov,
- vmci_can_block(qpair->flags));
+ qp_memcpy_to_queue_iov);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3367,7 +3290,7 @@ ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
qpair->consume_q_size,
iov, iov_size,
qp_memcpy_from_queue_iov,
- true, vmci_can_block(qpair->flags));
+ true);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3411,7 +3334,7 @@ ssize_t vmci_qpair_peekv(struct vmci_qp *qpair,
qpair->consume_q_size,
iov, iov_size,
qp_memcpy_from_queue_iov,
- false, vmci_can_block(qpair->flags));
+ false);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.h b/drivers/misc/vmw_vmci/vmci_queue_pair.h
index 58c6959f6b6..ed177f04ef2 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.h
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.h
@@ -146,24 +146,6 @@ VMCI_QP_PAGESTORE_IS_WELLFORMED(struct vmci_qp_page_store *page_store)
return page_store->len >= 2;
}
-/*
- * Helper function to check if the non-blocking flag
- * is set for a given queue pair.
- */
-static inline bool vmci_can_block(u32 flags)
-{
- return !(flags & VMCI_QPFLAG_NONBLOCK);
-}
-
-/*
- * Helper function to check if the queue pair is pinned
- * into memory.
- */
-static inline bool vmci_qp_pinned(u32 flags)
-{
- return flags & VMCI_QPFLAG_PINNED;
-}
-
void vmci_qp_broker_exit(void);
int vmci_qp_broker_alloc(struct vmci_handle handle, u32 peer,
u32 flags, u32 priv_flags,
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 23a0fff0df5..524f713f601 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -306,7 +306,6 @@ static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
}
@@ -529,7 +528,6 @@ static int __init netvsc_drv_init(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
module_init(netvsc_drv_init);
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index dc82ef096f3..70694ce38be 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -37,7 +37,7 @@ config PARPORT_PC
tristate "PC-style hardware"
depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
(!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \
- !XTENSA && !CRIS
+ !XTENSA && !CRIS && !H8300
---help---
You should say Y here if you have a PC-style parallel port. All
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 09503b8d12e..26ecdea84fb 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -232,7 +232,6 @@ static int __exit amiga_parallel_remove(struct platform_device *pdev)
if (port->irq != PARPORT_IRQ_NONE)
free_irq(IRQ_AMIGA_CIAA_FLG, port);
parport_put_port(port);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 83ec1aa8596..1a28f563279 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1879,7 +1879,6 @@ static void __exit storvsc_drv_exit(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
module_init(storvsc_drv_init);
module_exit(storvsc_drv_exit);
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5295be0342c..5a90914d856 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -1,5 +1,6 @@
menuconfig UIO
tristate "Userspace I/O drivers"
+ depends on MMU
help
Enable this to allow the userspace driver core code to be
built. This code allows userspace programs easy access to
@@ -23,13 +24,6 @@ config UIO_CIF
To compile this driver as a module, choose M here: the module
will be called uio_cif.
-config UIO_PDRV
- tristate "Userspace I/O platform driver"
- help
- Generic platform driver for Userspace I/O devices.
-
- If you don't know what to do here, say N.
-
config UIO_PDRV_GENIRQ
tristate "Userspace I/O platform driver with generic IRQ handling"
help
@@ -128,4 +122,17 @@ config UIO_PRUSS
To compile this driver as a module, choose M here: the module
will be called uio_pruss.
+config UIO_MF624
+ tristate "Humusoft MF624 DAQ PCI card driver"
+ depends on PCI
+ help
+ Userspace I/O interface for the Humusoft MF624 PCI card.
+ A sample userspace application using this driver is available
+ (among other MF624 related information and software components)
+ for download in a git repository:
+
+ git clone git://rtime.felk.cvut.cz/mf6xx.git
+
+ If you compile this as a module, it will be called uio_mf624.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index b354c539507..d3218bde3ae 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_UIO) += uio.o
obj-$(CONFIG_UIO_CIF) += uio_cif.o
-obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o
obj-$(CONFIG_UIO_AEC) += uio_aec.o
@@ -8,3 +7,4 @@ obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+obj-$(CONFIG_UIO_MF624) += uio_mf624.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 3b96f18593b..8abe78c0b16 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -35,7 +35,6 @@ struct uio_device {
atomic_t event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
- int vma_count;
struct uio_info *info;
struct kobject *map_dir;
struct kobject *portio_dir;
@@ -593,18 +592,6 @@ static int uio_find_mem_index(struct vm_area_struct *vma)
return -1;
}
-static void uio_vma_open(struct vm_area_struct *vma)
-{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count++;
-}
-
-static void uio_vma_close(struct vm_area_struct *vma)
-{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count--;
-}
-
static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
@@ -630,12 +617,23 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return 0;
}
-static const struct vm_operations_struct uio_vm_ops = {
- .open = uio_vma_open,
- .close = uio_vma_close,
+static const struct vm_operations_struct uio_logical_vm_ops = {
.fault = uio_vma_fault,
};
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_ops = &uio_logical_vm_ops;
+ return 0;
+}
+
+static const struct vm_operations_struct uio_physical_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys,
+#endif
+};
+
static int uio_mmap_physical(struct vm_area_struct *vma)
{
struct uio_device *idev = vma->vm_private_data;
@@ -643,6 +641,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
if (mi < 0)
return -EINVAL;
+ vma->vm_ops = &uio_physical_vm_ops;
+
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma,
@@ -652,14 +652,6 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
vma->vm_page_prot);
}
-static int uio_mmap_logical(struct vm_area_struct *vma)
-{
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_ops = &uio_vm_ops;
- uio_vma_open(vma);
- return 0;
-}
-
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uio_listener *listener = filep->private_data;
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 125d0e5a688..1270f3b2613 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -146,7 +146,7 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
static int uio_dmem_genirq_probe(struct platform_device *pdev)
{
- struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data;
+ struct uio_dmem_genirq_pdata *pdata = dev_get_platdata(&pdev->dev);
struct uio_info *uioinfo = &pdata->uioinfo;
struct uio_dmem_genirq_platdata *priv;
struct uio_mem *uiomem;
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c
new file mode 100644
index 00000000000..a1768b2f449
--- /dev/null
+++ b/drivers/uio/uio_mf624.c
@@ -0,0 +1,247 @@
+/*
+ * UIO driver fo Humusoft MF624 DAQ card.
+ * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
+ * Czech Technical University in Prague
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HUMUSOFT 0x186c
+#define PCI_DEVICE_ID_MF624 0x0624
+#define PCI_SUBVENDOR_ID_HUMUSOFT 0x186c
+#define PCI_SUBDEVICE_DEVICE 0x0624
+
+/* BAR0 Interrupt control/status register */
+#define INTCSR 0x4C
+#define INTCSR_ADINT_ENABLE (1 << 0)
+#define INTCSR_CTR4INT_ENABLE (1 << 3)
+#define INTCSR_PCIINT_ENABLE (1 << 6)
+#define INTCSR_ADINT_STATUS (1 << 2)
+#define INTCSR_CTR4INT_STATUS (1 << 5)
+
+enum mf624_interrupt_source {ADC, CTR4, ALL};
+
+void mf624_disable_interrupt(enum mf624_interrupt_source source,
+ struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ switch (source) {
+ case ADC:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+
+ case CTR4:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+
+ case ALL:
+ default:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+ | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+ }
+}
+
+void mf624_enable_interrupt(enum mf624_interrupt_source source,
+ struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ switch (source) {
+ case ADC:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+
+ case CTR4:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+
+ case ALL:
+ default:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+ | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+ }
+}
+
+static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
+ && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
+ mf624_disable_interrupt(ADC, info);
+ return IRQ_HANDLED;
+ }
+
+ if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
+ && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
+ mf624_disable_interrupt(CTR4, info);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
+{
+ if (irq_on == 0)
+ mf624_disable_interrupt(ALL, info);
+ else if (irq_on == 1)
+ mf624_enable_interrupt(ALL, info);
+
+ return 0;
+}
+
+static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct uio_info *info;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (pci_enable_device(dev))
+ goto out_free;
+
+ if (pci_request_regions(dev, "mf624"))
+ goto out_disable;
+
+ info->name = "mf624";
+ info->version = "0.0.1";
+
+ /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
+
+ /* BAR0 */
+ info->mem[0].name = "PCI chipset, interrupts, status "
+ "bits, special functions";
+ info->mem[0].addr = pci_resource_start(dev, 0);
+ if (!info->mem[0].addr)
+ goto out_release;
+ info->mem[0].size = pci_resource_len(dev, 0);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
+ if (!info->mem[0].internal_addr)
+ goto out_release;
+
+ /* BAR2 */
+ info->mem[1].name = "ADC, DAC, DIO";
+ info->mem[1].addr = pci_resource_start(dev, 2);
+ if (!info->mem[1].addr)
+ goto out_unmap0;
+ info->mem[1].size = pci_resource_len(dev, 2);
+ info->mem[1].memtype = UIO_MEM_PHYS;
+ info->mem[1].internal_addr = pci_ioremap_bar(dev, 2);
+ if (!info->mem[1].internal_addr)
+ goto out_unmap0;
+
+ /* BAR4 */
+ info->mem[2].name = "Counter/timer chip";
+ info->mem[2].addr = pci_resource_start(dev, 4);
+ if (!info->mem[2].addr)
+ goto out_unmap1;
+ info->mem[2].size = pci_resource_len(dev, 4);
+ info->mem[2].memtype = UIO_MEM_PHYS;
+ info->mem[2].internal_addr = pci_ioremap_bar(dev, 4);
+ if (!info->mem[2].internal_addr)
+ goto out_unmap1;
+
+ info->irq = dev->irq;
+ info->irq_flags = IRQF_SHARED;
+ info->handler = mf624_irq_handler;
+
+ info->irqcontrol = mf624_irqcontrol;
+
+ if (uio_register_device(&dev->dev, info))
+ goto out_unmap2;
+
+ pci_set_drvdata(dev, info);
+
+ return 0;
+
+out_unmap2:
+ iounmap(info->mem[2].internal_addr);
+out_unmap1:
+ iounmap(info->mem[1].internal_addr);
+out_unmap0:
+ iounmap(info->mem[0].internal_addr);
+
+out_release:
+ pci_release_regions(dev);
+
+out_disable:
+ pci_disable_device(dev);
+
+out_free:
+ kfree(info);
+ return -ENODEV;
+}
+
+static void mf624_pci_remove(struct pci_dev *dev)
+{
+ struct uio_info *info = pci_get_drvdata(dev);
+
+ mf624_disable_interrupt(ALL, info);
+
+ uio_unregister_device(info);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+
+ iounmap(info->mem[0].internal_addr);
+ iounmap(info->mem[1].internal_addr);
+ iounmap(info->mem[2].internal_addr);
+
+ kfree(info);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mf624_pci_id) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
+ { 0, }
+};
+
+static struct pci_driver mf624_pci_driver = {
+ .name = "mf624",
+ .id_table = mf624_pci_id,
+ .probe = mf624_pci_probe,
+ .remove = mf624_pci_remove,
+};
+MODULE_DEVICE_TABLE(pci, mf624_pci_id);
+
+module_pci_driver(mf624_pci_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c
deleted file mode 100644
index 39be9e06170..00000000000
--- a/drivers/uio/uio_pdrv.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * drivers/uio/uio_pdrv.c
- *
- * Copyright (C) 2008 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/platform_device.h>
-#include <linux/uio_driver.h>
-#include <linux/stringify.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#define DRIVER_NAME "uio_pdrv"
-
-struct uio_platdata {
- struct uio_info *uioinfo;
-};
-
-static int uio_pdrv_probe(struct platform_device *pdev)
-{
- struct uio_info *uioinfo = pdev->dev.platform_data;
- struct uio_platdata *pdata;
- struct uio_mem *uiomem;
- int ret = -ENODEV;
- int i;
-
- if (!uioinfo || !uioinfo->name || !uioinfo->version) {
- dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__);
- goto err_uioinfo;
- }
-
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__);
- goto err_alloc_pdata;
- }
-
- pdata->uioinfo = uioinfo;
-
- uiomem = &uioinfo->mem[0];
-
- for (i = 0; i < pdev->num_resources; ++i) {
- struct resource *r = &pdev->resource[i];
-
- if (r->flags != IORESOURCE_MEM)
- continue;
-
- if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
- dev_warn(&pdev->dev, "device has more than "
- __stringify(MAX_UIO_MAPS)
- " I/O memory resources.\n");
- break;
- }
-
- uiomem->memtype = UIO_MEM_PHYS;
- uiomem->addr = r->start;
- uiomem->size = resource_size(r);
- uiomem->name = r->name;
- ++uiomem;
- }
-
- while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
- uiomem->size = 0;
- ++uiomem;
- }
-
- pdata->uioinfo->priv = pdata;
-
- ret = uio_register_device(&pdev->dev, pdata->uioinfo);
-
- if (ret) {
- kfree(pdata);
-err_alloc_pdata:
-err_uioinfo:
- return ret;
- }
-
- platform_set_drvdata(pdev, pdata);
-
- return 0;
-}
-
-static int uio_pdrv_remove(struct platform_device *pdev)
-{
- struct uio_platdata *pdata = platform_get_drvdata(pdev);
-
- uio_unregister_device(pdata->uioinfo);
-
- kfree(pdata);
-
- return 0;
-}
-
-static struct platform_driver uio_pdrv = {
- .probe = uio_pdrv_probe,
- .remove = uio_pdrv_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(uio_pdrv);
-
-MODULE_AUTHOR("Uwe Kleine-Koenig");
-MODULE_DESCRIPTION("Userspace I/O platform driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 4eb8eaf71be..90ff17a0202 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -104,7 +104,7 @@ static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
static int uio_pdrv_genirq_probe(struct platform_device *pdev)
{
- struct uio_info *uioinfo = pdev->dev.platform_data;
+ struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
struct uio_pdrv_genirq_platdata *priv;
struct uio_mem *uiomem;
int ret = -EINVAL;
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index 21f7a72301e..f519da9034b 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -121,7 +121,7 @@ static int pruss_probe(struct platform_device *dev)
struct uio_pruss_dev *gdev;
struct resource *regs_prussio;
int ret = -ENODEV, cnt = 0, len;
- struct uio_pruss_pdata *pdata = dev->dev.platform_data;
+ struct uio_pruss_pdata *pdata = dev_get_platdata(&dev->dev);
gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
if (!gdev)
@@ -224,7 +224,6 @@ static int pruss_remove(struct platform_device *dev)
struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
pruss_cleanup(dev, gdev);
- platform_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 3e225d5846f..f969ea266ac 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,6 +1,7 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
+ depends on EXTCON
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index ecd99451ee9..7f7ea62e961 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -23,13 +23,15 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dwc3-omap.h>
-#include <linux/usb/dwc3-omap.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/extcon.h>
+#include <linux/extcon/of_extcon.h>
+#include <linux/regulator/consumer.h>
#include <linux/usb/otg.h>
@@ -135,9 +137,21 @@ struct dwc3_omap {
u32 revision;
u32 dma_status:1;
+
+ struct extcon_specific_cable_nb extcon_vbus_dev;
+ struct extcon_specific_cable_nb extcon_id_dev;
+ struct notifier_block vbus_nb;
+ struct notifier_block id_nb;
+
+ struct regulator *vbus_reg;
};
-static struct dwc3_omap *_omap;
+enum omap_dwc3_vbus_id_status {
+ OMAP_DWC3_ID_FLOAT,
+ OMAP_DWC3_ID_GROUND,
+ OMAP_DWC3_VBUS_OFF,
+ OMAP_DWC3_VBUS_VALID,
+};
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
@@ -201,18 +215,24 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
omap->irq0_offset, value);
}
-int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
+ enum omap_dwc3_vbus_id_status status)
{
- u32 val;
- struct dwc3_omap *omap = _omap;
-
- if (!omap)
- return -EPROBE_DEFER;
+ int ret;
+ u32 val;
switch (status) {
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
+ if (omap->vbus_reg) {
+ ret = regulator_enable(omap->vbus_reg);
+ if (ret) {
+ dev_dbg(omap->dev, "regulator enable failed\n");
+ return;
+ }
+ }
+
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
@@ -235,6 +255,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
break;
case OMAP_DWC3_ID_FLOAT:
+ if (omap->vbus_reg)
+ regulator_disable(omap->vbus_reg);
+
case OMAP_DWC3_VBUS_OFF:
dev_dbg(omap->dev, "VBUS Disconnect\n");
@@ -248,12 +271,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
break;
default:
- dev_dbg(omap->dev, "ID float\n");
+ dev_dbg(omap->dev, "invalid state\n");
}
-
- return 0;
}
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
@@ -346,6 +366,32 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
+static int dwc3_omap_id_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb);
+
+ if (event)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+ else
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+
+ return NOTIFY_DONE;
+}
+
+static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb);
+
+ if (event)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+ else
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+ return NOTIFY_DONE;
+}
+
static int dwc3_omap_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -353,6 +399,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
+ struct extcon_dev *edev;
+ struct regulator *vbus_reg = NULL;
int ret = -ENOMEM;
int irq;
@@ -393,19 +441,22 @@ static int dwc3_omap_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
+ if (of_property_read_bool(node, "vbus-supply")) {
+ vbus_reg = devm_regulator_get(dev, "vbus");
+ if (IS_ERR(vbus_reg)) {
+ dev_err(dev, "vbus init failed\n");
+ return PTR_ERR(vbus_reg);
+ }
+ }
+
spin_lock_init(&omap->lock);
omap->dev = dev;
omap->irq = irq;
omap->base = base;
+ omap->vbus_reg = vbus_reg;
dev->dma_mask = &dwc3_omap_dma_mask;
- /*
- * REVISIT if we ever have two instances of the wrapper, we will be
- * in big trouble
- */
- _omap = omap;
-
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
@@ -480,14 +531,46 @@ static int dwc3_omap_probe(struct platform_device *pdev)
dwc3_omap_enable_irqs(omap);
+ if (of_property_read_bool(node, "extcon")) {
+ edev = of_extcon_get_extcon_dev(dev, 0);
+ if (IS_ERR(edev)) {
+ dev_vdbg(dev, "couldn't get extcon device\n");
+ ret = PTR_ERR(edev);
+ goto err2;
+ }
+
+ omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
+ ret = extcon_register_interest(&omap->extcon_vbus_dev,
+ edev->name, "USB", &omap->vbus_nb);
+ if (ret < 0)
+ dev_vdbg(dev, "failed to register notifier for USB\n");
+ omap->id_nb.notifier_call = dwc3_omap_id_notifier;
+ ret = extcon_register_interest(&omap->extcon_id_dev, edev->name,
+ "USB-HOST", &omap->id_nb);
+ if (ret < 0)
+ dev_vdbg(dev,
+ "failed to register notifier for USB-HOST\n");
+
+ if (extcon_get_cable_state(edev, "USB") == true)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+ if (extcon_get_cable_state(edev, "USB-HOST") == true)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+ }
+
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(&pdev->dev, "failed to create dwc3 core\n");
- goto err2;
+ goto err3;
}
return 0;
+err3:
+ if (omap->extcon_vbus_dev.edev)
+ extcon_unregister_interest(&omap->extcon_vbus_dev);
+ if (omap->extcon_id_dev.edev)
+ extcon_unregister_interest(&omap->extcon_id_dev);
+
err2:
dwc3_omap_disable_irqs(omap);
@@ -504,6 +587,10 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
+ if (omap->extcon_vbus_dev.edev)
+ extcon_unregister_interest(&omap->extcon_vbus_dev);
+ if (omap->extcon_id_dev.edev)
+ extcon_unregister_interest(&omap->extcon_id_dev);
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
index d4d2c5fe248..8ac99b87c07 100644
--- a/drivers/video/hyperv_fb.c
+++ b/drivers/video/hyperv_fb.c
@@ -825,5 +825,4 @@ module_init(hvfb_drv_init);
module_exit(hvfb_drv_exit);
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/drivers/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
index dd22b5072e2..cf74aee2cef 100644
--- a/drivers/vme/boards/vme_vmivme7805.c
+++ b/drivers/vme/boards/vme_vmivme7805.c
@@ -23,7 +23,7 @@ static int vmic_probe(struct pci_dev *, const struct pci_device_id *);
static void vmic_remove(struct pci_dev *);
/** Base address to access FPGA register */
-static void *vmic_base;
+static void __iomem *vmic_base;
static const char driver_name[] = "vmivme_7805";
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 64bfea31442..f8448573d03 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -243,6 +243,8 @@ static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
struct pci_dev *pdev)
{
+ struct vme_bridge *ca91cx42_bridge;
+
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
@@ -251,7 +253,9 @@ static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
/* Clear Any Pending PCI Interrupts */
iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
- free_irq(pdev->irq, pdev);
+ ca91cx42_bridge = container_of((void *)bridge, struct vme_bridge,
+ driver_priv);
+ free_irq(pdev->irq, ca91cx42_bridge);
}
static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level)
@@ -856,7 +860,7 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
void *buf, size_t count, loff_t offset)
{
ssize_t retval;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
@@ -916,7 +920,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
void *buf, size_t count, loff_t offset)
{
ssize_t retval;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index 94c892f27be..9cf88337e4e 100644
--- a/drivers/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -1267,7 +1267,7 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
u32 aspace, cycle, dwidth;
struct vme_bus_error *vme_err = NULL;
struct vme_bridge *tsi148_bridge;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
@@ -1348,7 +1348,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
int retval = 0, enabled;
unsigned long long vme_base, size;
u32 aspace, cycle, dwidth;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
diff --git a/include/linux/extcon/of_extcon.h b/include/linux/extcon/of_extcon.h
new file mode 100644
index 00000000000..0ebfeff1b55
--- /dev/null
+++ b/include/linux/extcon/of_extcon.h
@@ -0,0 +1,31 @@
+/*
+ * OF helpers for External connector (extcon) framework
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ * Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_EXTCON_H
+#define __LINUX_OF_EXTCON_H
+
+#include <linux/err.h>
+
+#if IS_ENABLED(CONFIG_OF_EXTCON)
+extern struct extcon_dev
+ *of_extcon_get_extcon_dev(struct device *dev, int index);
+#else
+static inline struct extcon_dev
+ *of_extcon_get_extcon_dev(struct device *dev, int index)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_OF_EXTCON */
+#endif /* __LINUX_OF_EXTCON_H */
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index fae8bac907e..a3b8b2e2d24 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -27,6 +27,14 @@
#include <linux/types.h>
+/*
+ * Framework version for util services.
+ */
+
+#define UTIL_FW_MAJOR 3
+#define UTIL_FW_MINOR 0
+#define UTIL_FW_MAJOR_MINOR (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
/*
* Implementation of host controlled snapshot of the guest.
@@ -455,27 +463,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
*read = dsize - *write;
}
-
-/*
- * We use the same version numbering for all Hyper-V modules.
- *
- * Definition of versioning is as follows;
- *
- * Major Number Changes for these scenarios;
- * 1. When a new version of Windows Hyper-V
- * is released.
- * 2. A Major change has occurred in the
- * Linux IC's.
- * (For example the merge for the first time
- * into the kernel) Every time the Major Number
- * changes, the Revision number is reset to 0.
- * Minor Number Changes when new functionality is added
- * to the Linux IC's that is not a bug fix.
- *
- * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
- */
-#define HV_DRV_VERSION "3.1"
-
/*
* VMBUS version is 32 bit entity broken up into
* two 16 bit quantities: major_number. minor_number.
@@ -1494,7 +1481,7 @@ struct hyperv_service_callback {
};
#define MAX_SRV_VER 0x7ffffff
-extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
+extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
struct icmsg_negotiate *, u8 *, int,
int);
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index c06d78af334..e6090d88e91 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -372,17 +372,15 @@ struct palmas_usb {
struct extcon_dev edev;
- /* used to set vbus, in atomic path */
- struct work_struct set_vbus_work;
-
int id_otg_irq;
int id_irq;
int vbus_otg_irq;
int vbus_irq;
- int vbus_enable;
-
enum palmas_usb_state linkstat;
+ int wakeup;
+ bool enable_vbus_detection;
+ bool enable_id_detection;
};
#define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)
diff --git a/include/linux/usb/dwc3-omap.h b/include/linux/usb/dwc3-omap.h
deleted file mode 100644
index 5615f4d8272..00000000000
--- a/include/linux/usb/dwc3-omap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 by Texas Instruments
- *
- * The Inventra Controller Driver for Linux is free software; you
- * can redistribute it and/or modify it under the terms of the GNU
- * General Public License version 2 as published by the Free Software
- * Foundation.
- */
-
-#ifndef __DWC3_OMAP_H__
-#define __DWC3_OMAP_H__
-
-enum omap_dwc3_vbus_id_status {
- OMAP_DWC3_UNKNOWN = 0,
- OMAP_DWC3_ID_GROUND,
- OMAP_DWC3_ID_FLOAT,
- OMAP_DWC3_VBUS_VALID,
- OMAP_DWC3_VBUS_OFF,
-};
-
-#if (defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE))
-extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
-#else
-static inline int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
-{
- return -ENODEV;
-}
-#endif
-
-#endif /* __DWC3_OMAP_H__ */
diff --git a/mm/memory.c b/mm/memory.c
index af84bc0ec17..b3c6bf9a398 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4079,6 +4079,7 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
return len;
}
+EXPORT_SYMBOL_GPL(generic_access_phys);
#endif
/*
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 07819bfa7db..8fd9ec66121 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -79,8 +79,6 @@ enum {
DNS
};
-static char kvp_send_buffer[4096];
-static char kvp_recv_buffer[4096 * 2];
static struct sockaddr_nl addr;
static int in_hand_shake = 1;
@@ -1301,6 +1299,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
}
error = kvp_write_file(file, "HWADDR", "", mac_addr);
+ free(mac_addr);
if (error)
goto setval_error;
@@ -1346,7 +1345,6 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
goto setval_error;
setval_done:
- free(mac_addr);
fclose(file);
/*
@@ -1355,12 +1353,15 @@ setval_done:
*/
snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
- system(cmd);
+ if (system(cmd)) {
+ syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
+ cmd, errno, strerror(errno));
+ return HV_E_FAIL;
+ }
return 0;
setval_error:
syslog(LOG_ERR, "Failed to write config file");
- free(mac_addr);
fclose(file);
return error;
}
@@ -1391,23 +1392,18 @@ kvp_get_domain_name(char *buffer, int length)
static int
netlink_send(int fd, struct cn_msg *msg)
{
- struct nlmsghdr *nlh;
+ struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
unsigned int size;
struct msghdr message;
- char buffer[64];
struct iovec iov[2];
- size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+ size = sizeof(struct cn_msg) + msg->len;
- nlh = (struct nlmsghdr *)buffer;
- nlh->nlmsg_seq = 0;
- nlh->nlmsg_pid = getpid();
- nlh->nlmsg_type = NLMSG_DONE;
- nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
- nlh->nlmsg_flags = 0;
+ nlh.nlmsg_pid = getpid();
+ nlh.nlmsg_len = NLMSG_LENGTH(size);
- iov[0].iov_base = nlh;
- iov[0].iov_len = sizeof(*nlh);
+ iov[0].iov_base = &nlh;
+ iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = msg;
iov[1].iov_len = size;
@@ -1437,10 +1433,22 @@ int main(void)
int pool;
char *if_name;
struct hv_kvp_ipaddr_value *kvp_ip_val;
+ char *kvp_send_buffer;
+ char *kvp_recv_buffer;
+ size_t kvp_recv_buffer_len;
- daemon(1, 0);
+ if (daemon(1, 0))
+ return 1;
openlog("KVP", 0, LOG_USER);
syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
+
+ kvp_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg);
+ kvp_send_buffer = calloc(1, kvp_recv_buffer_len);
+ kvp_recv_buffer = calloc(1, kvp_recv_buffer_len);
+ if (!(kvp_send_buffer && kvp_recv_buffer)) {
+ syslog(LOG_ERR, "Failed to allocate netlink buffers");
+ exit(EXIT_FAILURE);
+ }
/*
* Retrieve OS release information.
*/
@@ -1514,7 +1522,7 @@ int main(void)
continue;
}
- len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
+ len = recvfrom(fd, kvp_recv_buffer, kvp_recv_buffer_len, 0,
addr_p, &addr_l);
if (len < 0) {
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index fea03a3edaf..8611962c672 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -38,8 +38,6 @@
#include <linux/netlink.h>
#include <syslog.h>
-static char vss_recv_buffer[4096];
-static char vss_send_buffer[4096];
static struct sockaddr_nl addr;
#ifndef SOL_NETLINK
@@ -107,23 +105,18 @@ static int vss_operate(int operation)
static int netlink_send(int fd, struct cn_msg *msg)
{
- struct nlmsghdr *nlh;
+ struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
unsigned int size;
struct msghdr message;
- char buffer[64];
struct iovec iov[2];
- size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+ size = sizeof(struct cn_msg) + msg->len;
- nlh = (struct nlmsghdr *)buffer;
- nlh->nlmsg_seq = 0;
- nlh->nlmsg_pid = getpid();
- nlh->nlmsg_type = NLMSG_DONE;
- nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
- nlh->nlmsg_flags = 0;
+ nlh.nlmsg_pid = getpid();
+ nlh.nlmsg_len = NLMSG_LENGTH(size);
- iov[0].iov_base = nlh;
- iov[0].iov_len = sizeof(*nlh);
+ iov[0].iov_base = &nlh;
+ iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = msg;
iov[1].iov_len = size;
@@ -147,6 +140,9 @@ int main(void)
struct cn_msg *incoming_cn_msg;
int op;
struct hv_vss_msg *vss_msg;
+ char *vss_send_buffer;
+ char *vss_recv_buffer;
+ size_t vss_recv_buffer_len;
if (daemon(1, 0))
return 1;
@@ -154,9 +150,18 @@ int main(void)
openlog("Hyper-V VSS", 0, LOG_USER);
syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
+ vss_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg);
+ vss_send_buffer = calloc(1, vss_recv_buffer_len);
+ vss_recv_buffer = calloc(1, vss_recv_buffer_len);
+ if (!(vss_send_buffer && vss_recv_buffer)) {
+ syslog(LOG_ERR, "Failed to allocate netlink buffers");
+ exit(EXIT_FAILURE);
+ }
+
fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd < 0) {
- syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
+ syslog(LOG_ERR, "netlink socket creation failed; error:%d %s",
+ errno, strerror(errno));
exit(EXIT_FAILURE);
}
addr.nl_family = AF_NETLINK;
@@ -167,12 +172,16 @@ int main(void)
error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (error < 0) {
- syslog(LOG_ERR, "bind failed; error:%d", error);
+ syslog(LOG_ERR, "bind failed; error:%d %s", errno, strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
nl_group = CN_VSS_IDX;
- setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
+ if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
+ syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, strerror(errno));
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
/*
* Register ourselves with the kernel.
*/
@@ -187,7 +196,7 @@ int main(void)
len = netlink_send(fd, message);
if (len < 0) {
- syslog(LOG_ERR, "netlink_send failed; error:%d", len);
+ syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
@@ -199,9 +208,18 @@ int main(void)
socklen_t addr_l = sizeof(addr);
pfd.events = POLLIN;
pfd.revents = 0;
- poll(&pfd, 1, -1);
- len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
+ if (poll(&pfd, 1, -1) < 0) {
+ syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
+ if (errno == EINVAL) {
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+ else
+ continue;
+ }
+
+ len = recvfrom(fd, vss_recv_buffer, vss_recv_buffer_len, 0,
addr_p, &addr_l);
if (len < 0) {
@@ -241,7 +259,8 @@ int main(void)
vss_msg->error = error;
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
- syslog(LOG_ERR, "net_link send failed; error:%d", len);
+ syslog(LOG_ERR, "net_link send failed; error:%d %s",
+ errno, strerror(errno));
exit(EXIT_FAILURE);
}
}