Char/Misc patches for 3.12-rc1
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 below. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.21 (GNU/Linux) iEYEABECAAYFAlIlH58ACgkQMUfUDdst+ymTGwCdH1BmMdypyjUBxJEoWNDUuwXn /AQAoKt329vmB6qn41rvaTilHHYUXS7H =ovaW -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
Коммит
1d1fdd95df
|
@ -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;
|
||||
};
|
|
@ -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 :
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
@ -83,29 +85,24 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
|
|||
PALMAS_USB_ID_INT_LATCH_SET, &set);
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -261,6 +292,13 @@ static void vmbus_process_offer(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) +
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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), \
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
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;
|
||||
|
||||
q_header = vmalloc(queue_size);
|
||||
if (!q_header)
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 header is the first page. */
|
||||
queue->q_header = queue->kernel_if->u.g.vas[0];
|
||||
|
||||
queue->kernel_if->mapped = true;
|
||||
}
|
||||
|
||||
return (void *)queue;
|
||||
|
||||
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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>");
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче