Commit ef0625b7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver updates from Greg KH:
 "Here's the big set of driver patches for char/misc drivers.  Nothing
  major in here, the shortlog goes into the details.  All have been in
  the linux-next tree for a while with no issues"

* tag 'char-misc-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (80 commits)
  mei: mei_txe_fw_sts can be static
  mei: fix kernel-doc warnings
  mei: fix KDoc documentation formatting
  mei: drop me_client_presentation_num
  mei: trivial: fix errors in prints in comments
  mei: remove include to pci header from mei module files
  mei: push pci cfg structure me hw
  mei: remove the reference to pdev from mei_device
  mei: move fw_status back to hw ops handlers
  mei: get rid of most of the pci dependencies in mei
  mei: push all standard settings into mei_device_init
  mei: move mei_hbm_hdr function from hbm.h the hbm.c
  mei: kill error message for allocation failure
  mei: nfc: fix style warning
  mei: fix style warning: Missing a blank line after declarations
  mei: pg: fix cat and paste error in comments
  mei: debugfs: add single buffer indicator
  mei: debugfs: adjust print buffer
  mei: add hbm and pg state in devstate debugfs print
  Drivers: hv: vmbus: Enable interrupt driven flow control
  ...
parents 3fc1479c 480bd3c4
* Richtek RT8973A - Micro USB Switch device
The Richtek RT8973A is Micro USB Switch with OVP and I2C interface. The RT8973A
is a USB port accessory detector and switch that is optimized to protect low
voltage system from abnormal high input voltage (up to 28V) and supports high
speed USB operation. Also, RT8973A support 'auto-configuration' mode.
If auto-configuration mode is enabled, RT8973A would control internal h/w patch
for USB D-/D+ switching.
Required properties:
- compatible: Should be "richtek,rt8973a-muic"
- reg: Specifies the I2C slave address of the MUIC block. It should be 0x14
- interrupt-parent: Specifies the phandle of the interrupt controller to which
the interrupts from rt8973a are delivered to.
- interrupts: Interrupt specifiers for detection interrupt sources.
Example:
rt8973a@14 {
compatible = "richtek,rt8973a-muic";
interrupt-parent = <&gpx1>;
interrupts = <5 0>;
reg = <0x14>;
};
...@@ -150,6 +150,7 @@ winbond Winbond Electronics corp. ...@@ -150,6 +150,7 @@ winbond Winbond Electronics corp.
wlf Wolfson Microelectronics wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc. wm Wondermedia Technologies, Inc.
xes Extreme Engineering Solutions (X-ES) xes Extreme Engineering Solutions (X-ES)
xillybus Xillybus Ltd.
xlnx Xilinx xlnx Xilinx
zyxel ZyXEL Communications Corp. zyxel ZyXEL Communications Corp.
zarlink Zarlink Semiconductor zarlink Zarlink Semiconductor
...@@ -651,6 +651,7 @@ struct i8k_config_data { ...@@ -651,6 +651,7 @@ struct i8k_config_data {
enum i8k_configs { enum i8k_configs {
DELL_LATITUDE_D520, DELL_LATITUDE_D520,
DELL_LATITUDE_E6540,
DELL_PRECISION_490, DELL_PRECISION_490,
DELL_STUDIO, DELL_STUDIO,
DELL_XPS_M140, DELL_XPS_M140,
...@@ -661,6 +662,10 @@ static const struct i8k_config_data i8k_config_data[] = { ...@@ -661,6 +662,10 @@ static const struct i8k_config_data i8k_config_data[] = {
.fan_mult = 1, .fan_mult = 1,
.fan_max = I8K_FAN_TURBO, .fan_max = I8K_FAN_TURBO,
}, },
[DELL_LATITUDE_E6540] = {
.fan_mult = 1,
.fan_max = I8K_FAN_HIGH,
},
[DELL_PRECISION_490] = { [DELL_PRECISION_490] = {
.fan_mult = 1, .fan_mult = 1,
.fan_max = I8K_FAN_TURBO, .fan_max = I8K_FAN_TURBO,
...@@ -705,6 +710,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { ...@@ -705,6 +710,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
}, },
.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
}, },
{
.ident = "Dell Latitude E6540",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"),
},
.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
},
{ {
.ident = "Dell Latitude 2", .ident = "Dell Latitude 2",
.matches = { .matches = {
......
...@@ -843,7 +843,6 @@ static struct platform_driver hwicap_platform_driver = { ...@@ -843,7 +843,6 @@ static struct platform_driver hwicap_platform_driver = {
.probe = hwicap_drv_probe, .probe = hwicap_drv_probe,
.remove = hwicap_drv_remove, .remove = hwicap_drv_remove,
.driver = { .driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = hwicap_of_match, .of_match_table = hwicap_of_match,
}, },
......
...@@ -70,8 +70,21 @@ config EXTCON_PALMAS ...@@ -70,8 +70,21 @@ config EXTCON_PALMAS
Say Y here to enable support for USB peripheral and USB host Say Y here to enable support for USB peripheral and USB host
detection by palmas usb. detection by palmas usb.
config EXTCON_RT8973A
tristate "RT8973A EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
select REGMAP_IRQ
help
If you say yes here you get support for the MUIC device of
Richtek RT8973A. The RT8973A is a USB port accessory detector
and switch that is optimized to protect low voltage system
from abnormal high input voltage (up to 28V).
config EXTCON_SM5502 config EXTCON_SM5502
tristate "SM5502 EXTCON support" tristate "SM5502 EXTCON support"
depends on I2C
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
select REGMAP_IRQ select REGMAP_IRQ
......
...@@ -10,4 +10,5 @@ obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o ...@@ -10,4 +10,5 @@ obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o
obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
...@@ -20,16 +20,16 @@ ...@@ -20,16 +20,16 @@
* *
*/ */
#include <linux/module.h> #include <linux/extcon.h>
#include <linux/kernel.h> #include <linux/extcon/extcon-gpio.h>
#include <linux/gpio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/extcon.h>
#include <linux/extcon/extcon-gpio.h>
struct gpio_extcon_data { struct gpio_extcon_data {
struct extcon_dev *edev; struct extcon_dev *edev;
......
...@@ -255,9 +255,13 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, ...@@ -255,9 +255,13 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
case ADC_DEBOUNCE_TIME_10MS: case ADC_DEBOUNCE_TIME_10MS:
case ADC_DEBOUNCE_TIME_25MS: case ADC_DEBOUNCE_TIME_25MS:
case ADC_DEBOUNCE_TIME_38_62MS: case ADC_DEBOUNCE_TIME_38_62MS:
ret = regmap_update_bits(info->max77693->regmap_muic, /*
* Don't touch BTLDset, JIGset when you want to change adc
* debounce time. If it writes other than 0 to BTLDset, JIGset
* muic device will be reset and loose current state.
*/
ret = regmap_write(info->max77693->regmap_muic,
MAX77693_MUIC_REG_CTRL3, MAX77693_MUIC_REG_CTRL3,
CONTROL3_ADCDBSET_MASK,
time << CONTROL3_ADCDBSET_SHIFT); time << CONTROL3_ADCDBSET_SHIFT);
if (ret) { if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n"); dev_err(info->dev, "failed to set ADC debounce time\n");
...@@ -1155,13 +1159,11 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1155,13 +1159,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
virq = regmap_irq_get_virq(max77693->irq_data_muic, virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq); muic_irq->irq);
if (!virq) { if (!virq)
ret = -EINVAL; return -EINVAL;
goto err_irq;
}
muic_irq->virq = virq; muic_irq->virq = virq;
ret = request_threaded_irq(virq, NULL, ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
max77693_muic_irq_handler, max77693_muic_irq_handler,
IRQF_NO_SUSPEND, IRQF_NO_SUSPEND,
muic_irq->name, info); muic_irq->name, info);
...@@ -1170,7 +1172,7 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1170,7 +1172,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
"failed: irq request (IRQ: %d," "failed: irq request (IRQ: %d,"
" error :%d)\n", " error :%d)\n",
muic_irq->irq, ret); muic_irq->irq, ret);
goto err_irq; return ret;
} }
} }
...@@ -1179,15 +1181,14 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1179,15 +1181,14 @@ static int max77693_muic_probe(struct platform_device *pdev)
max77693_extcon_cable); max77693_extcon_cable);
if (IS_ERR(info->edev)) { if (IS_ERR(info->edev)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
ret = -ENOMEM; return -ENOMEM;
goto err_irq;
} }
info->edev->name = DEV_NAME; info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev); ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register extcon device\n"); dev_err(&pdev->dev, "failed to register extcon device\n");
goto err_irq; return ret;
} }
/* Initialize MUIC register by using platform data or default data */ /* Initialize MUIC register by using platform data or default data */
...@@ -1265,7 +1266,7 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1265,7 +1266,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
MAX77693_MUIC_REG_ID, &id); MAX77693_MUIC_REG_ID, &id);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to read revision number\n"); dev_err(&pdev->dev, "failed to read revision number\n");
goto err_irq; return ret;
} }
dev_info(info->dev, "device ID : 0x%x\n", id); dev_info(info->dev, "device ID : 0x%x\n", id);
...@@ -1285,20 +1286,12 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1285,20 +1286,12 @@ static int max77693_muic_probe(struct platform_device *pdev)
delay_jiffies); delay_jiffies);
return ret; return ret;
err_irq:
while (--i >= 0)
free_irq(muic_irqs[i].virq, info);
return ret;
} }
static int max77693_muic_remove(struct platform_device *pdev) static int max77693_muic_remove(struct platform_device *pdev)
{ {
struct max77693_muic_info *info = platform_get_drvdata(pdev); struct max77693_muic_info *info = platform_get_drvdata(pdev);
int i;
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
free_irq(muic_irqs[i].virq, info);
cancel_work_sync(&info->irq_work); cancel_work_sync(&info->irq_work);
input_unregister_device(info->dock); input_unregister_device(info->dock);
......
This diff is collapsed.
/*
* rt8973a.h
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
*
* 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_EXTCON_RT8973A_H
#define __LINUX_EXTCON_RT8973A_H
enum rt8973a_types {
TYPE_RT8973A,
};
/* RT8973A registers */
enum rt8973A_reg {
RT8973A_REG_DEVICE_ID = 0x1,
RT8973A_REG_CONTROL1,
RT8973A_REG_INT1,
RT8973A_REG_INT2,
RT8973A_REG_INTM1,
RT8973A_REG_INTM2,
RT8973A_REG_ADC,
RT8973A_REG_RSVD_1,
RT8973A_REG_RSVD_2,
RT8973A_REG_DEV1,
RT8973A_REG_DEV2,
RT8973A_REG_RSVD_3,
RT8973A_REG_RSVD_4,
RT8973A_REG_RSVD_5,
RT8973A_REG_RSVD_6,
RT8973A_REG_RSVD_7,
RT8973A_REG_RSVD_8,
RT8973A_REG_RSVD_9,
RT8973A_REG_MANUAL_SW1,
RT8973A_REG_MANUAL_SW2,
RT8973A_REG_RSVD_10,
RT8973A_REG_RSVD_11,
RT8973A_REG_RSVD_12,
RT8973A_REG_RSVD_13,
RT8973A_REG_RSVD_14,
RT8973A_REG_RSVD_15,
RT8973A_REG_RESET,
RT8973A_REG_END,
};
/* Define RT8973A MASK/SHIFT constant */
#define RT8973A_REG_DEVICE_ID_VENDOR_SHIFT 0
#define RT8973A_REG_DEVICE_ID_VERSION_SHIFT 3
#define RT8973A_REG_DEVICE_ID_VENDOR_MASK (0x7 << RT8973A_REG_DEVICE_ID_VENDOR_SHIFT)
#define RT8973A_REG_DEVICE_ID_VERSION_MASK (0x1f << RT8973A_REG_DEVICE_ID_VERSION_SHIFT)
#define RT8973A_REG_CONTROL1_INTM_SHIFT 0
#define RT8973A_REG_CONTROL1_AUTO_CONFIG_SHIFT 2
#define RT8973A_REG_CONTROL1_I2C_RST_EN_SHIFT 3
#define RT8973A_REG_CONTROL1_SWITCH_OPEN_SHIFT 4
#define RT8973A_REG_CONTROL1_CHGTYP_SHIFT 5
#define RT8973A_REG_CONTROL1_USB_CHD_EN_SHIFT 6
#define RT8973A_REG_CONTROL1_ADC_EN_SHIFT 7
#define RT8973A_REG_CONTROL1_INTM_MASK (0x1 << RT8973A_REG_CONTROL1_INTM_SHIFT)
#define RT8973A_REG_CONTROL1_AUTO_CONFIG_MASK (0x1 << RT8973A_REG_CONTROL1_AUTO_CONFIG_SHIFT)
#define RT8973A_REG_CONTROL1_I2C_RST_EN_MASK (0x1 << RT8973A_REG_CONTROL1_I2C_RST_EN_SHIFT)
#define RT8973A_REG_CONTROL1_SWITCH_OPEN_MASK (0x1 << RT8973A_REG_CONTROL1_SWITCH_OPEN_SHIFT)
#define RT8973A_REG_CONTROL1_CHGTYP_MASK (0x1 << RT8973A_REG_CONTROL1_CHGTYP_SHIFT)
#define RT8973A_REG_CONTROL1_USB_CHD_EN_MASK (0x1 << RT8973A_REG_CONTROL1_USB_CHD_EN_SHIFT)
#define RT8973A_REG_CONTROL1_ADC_EN_MASK (0x1 << RT8973A_REG_CONTROL1_ADC_EN_SHIFT)
#define RT9873A_REG_INTM1_ATTACH_SHIFT 0
#define RT9873A_REG_INTM1_DETACH_SHIFT 1
#define RT9873A_REG_INTM1_CHGDET_SHIFT 2
#define RT9873A_REG_INTM1_DCD_T_SHIFT 3
#define RT9873A_REG_INTM1_OVP_SHIFT 4
#define RT9873A_REG_INTM1_CONNECT_SHIFT 5
#define RT9873A_REG_INTM1_ADC_CHG_SHIFT 6
#define RT9873A_REG_INTM1_OTP_SHIFT 7
#define RT9873A_REG_INTM1_ATTACH_MASK (0x1 << RT9873A_REG_INTM1_ATTACH_SHIFT)
#define RT9873A_REG_INTM1_DETACH_MASK (0x1 << RT9873A_REG_INTM1_DETACH_SHIFT)
#define RT9873A_REG_INTM1_CHGDET_MASK (0x1 << RT9873A_REG_INTM1_CHGDET_SHIFT)
#define RT9873A_REG_INTM1_DCD_T_MASK (0x1 << RT9873A_REG_INTM1_DCD_T_SHIFT)
#define RT9873A_REG_INTM1_OVP_MASK (0x1 << RT9873A_REG_INTM1_OVP_SHIFT)
#define RT9873A_REG_INTM1_CONNECT_MASK (0x1 << RT9873A_REG_INTM1_CONNECT_SHIFT)
#define RT9873A_REG_INTM1_ADC_CHG_MASK (0x1 << RT9873A_REG_INTM1_ADC_CHG_SHIFT)
#define RT9873A_REG_INTM1_OTP_MASK (0x1 << RT9873A_REG_INTM1_OTP_SHIFT)
#define RT9873A_REG_INTM2_UVLO_SHIFT 1
#define RT9873A_REG_INTM2_POR_SHIFT 2
#define RT9873A_REG_INTM2_OTP_FET_SHIFT 3
#define RT9873A_REG_INTM2_OVP_FET_SHIFT 4
#define RT9873A_REG_INTM2_OCP_LATCH_SHIFT 5
#define RT9873A_REG_INTM2_OCP_SHIFT 6
#define RT9873A_REG_INTM2_OVP_OCP_SHIFT 7
#define RT9873A_REG_INTM2_UVLO_MASK (0x1 << RT9873A_REG_INTM2_UVLO_SHIFT)
#define RT9873A_REG_INTM2_POR_MASK (0x1 << RT9873A_REG_INTM2_POR_SHIFT)
#define RT9873A_REG_INTM2_OTP_FET_MASK (0x1 << RT9873A_REG_INTM2_OTP_FET_SHIFT)
#define RT9873A_REG_INTM2_OVP_FET_MASK (0x1 << RT9873A_REG_INTM2_OVP_FET_SHIFT)
#define RT9873A_REG_INTM2_OCP_LATCH_MASK (0x1 << RT9873A_REG_INTM2_OCP_LATCH_SHIFT)
#define RT9873A_REG_INTM2_OCP_MASK (0x1 << RT9873A_REG_INTM2_OCP_SHIFT)
#define RT9873A_REG_INTM2_OVP_OCP_MASK (0x1 << RT9873A_REG_INTM2_OVP_OCP_SHIFT)
#define RT8973A_REG_ADC_SHIFT 0
#define RT8973A_REG_ADC_MASK (0x1f << RT8973A_REG_ADC_SHIFT)
#define RT8973A_REG_DEV1_OTG_SHIFT 0
#define RT8973A_REG_DEV1_SDP_SHIFT 2
#define RT8973A_REG_DEV1_UART_SHIFT 3
#define RT8973A_REG_DEV1_CAR_KIT_TYPE1_SHIFT 4
#define RT8973A_REG_DEV1_CDPORT_SHIFT 5
#define RT8973A_REG_DEV1_DCPORT_SHIFT 6
#define RT8973A_REG_DEV1_OTG_MASK (0x1 << RT8973A_REG_DEV1_OTG_SHIFT)
#define RT8973A_REG_DEV1_SDP_MASK (0x1 << RT8973A_REG_DEV1_SDP_SHIFT)
#define RT8973A_REG_DEV1_UART_MASK (0x1 << RT8973A_REG_DEV1_UART_SHIFT)
#define RT8973A_REG_DEV1_CAR_KIT_TYPE1_MASK (0x1 << RT8973A_REG_DEV1_CAR_KIT_TYPE1_SHIFT)
#define RT8973A_REG_DEV1_CDPORT_MASK (0x1 << RT8973A_REG_DEV1_CDPORT_SHIFT)
#define RT8973A_REG_DEV1_DCPORT_MASK (0x1 << RT8973A_REG_DEV1_DCPORT_SHIFT)
#define RT8973A_REG_DEV1_USB_MASK (RT8973A_REG_DEV1_SDP_MASK \
| RT8973A_REG_DEV1_CDPORT_MASK)
#define RT8973A_REG_DEV2_JIG_USB_ON_SHIFT 0
#define RT8973A_REG_DEV2_JIG_USB_OFF_SHIFT 1
#define RT8973A_REG_DEV2_JIG_UART_ON_SHIFT 2
#define RT8973A_REG_DEV2_JIG_UART_OFF_SHIFT 3
#define RT8973A_REG_DEV2_JIG_USB_ON_MASK (0x1 << RT8973A_REG_DEV2_JIG_USB_ON_SHIFT)
#define RT8973A_REG_DEV2_JIG_USB_OFF_MASK (0x1 << RT8973A_REG_DEV2_JIG_USB_OFF_SHIFT)
#define RT8973A_REG_DEV2_JIG_UART_ON_MASK (0x1 << RT8973A_REG_DEV2_JIG_UART_ON_SHIFT)
#define RT8973A_REG_DEV2_JIG_UART_OFF_MASK (0x1 << RT8973A_REG_DEV2_JIG_UART_OFF_SHIFT)
#define RT8973A_REG_MANUAL_SW1_DP_SHIFT 2
#define RT8973A_REG_MANUAL_SW1_DM_SHIFT 5
#define RT8973A_REG_MANUAL_SW1_DP_MASK (0x7 << RT8973A_REG_MANUAL_SW1_DP_SHIFT)
#define RT8973A_REG_MANUAL_SW1_DM_MASK (0x7 << RT8973A_REG_MANUAL_SW1_DM_SHIFT)
#define DM_DP_CON_SWITCH_OPEN 0x0
#define DM_DP_CON_SWITCH_USB 0x1
#define DM_DP_CON_SWITCH_UART 0x3
#define DM_DP_SWITCH_OPEN ((DM_DP_CON_SWITCH_OPEN << RT8973A_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_OPEN << RT8973A_REG_MANUAL_SW1_DM_SHIFT))
#define DM_DP_SWITCH_USB ((DM_DP_CON_SWITCH_USB << RT8973A_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_USB << RT8973A_REG_MANUAL_SW1_DM_SHIFT))
#define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART << RT8973A_REG_MANUAL_SW1_DP_SHIFT) \
| (DM_DP_CON_SWITCH_UART << RT8973A_REG_MANUAL_SW1_DM_SHIFT))
#define RT8973A_REG_MANUAL_SW2_FET_ON_SHIFT 0
#define RT8973A_REG_MANUAL_SW2_JIG_ON_SHIFT 2
#define RT8973A_REG_MANUAL_SW2_BOOT_SW_SHIFT 3
#define RT8973A_REG_MANUAL_SW2_FET_ON_MASK (0x1 << RT8973A_REG_MANUAL_SW2_FET_ON_SHIFT)
#define RT8973A_REG_MANUAL_SW2_JIG_ON_MASK (0x1 << RT8973A_REG_MANUAL_SW2_JIG_ON_SHIFT)
#define RT8973A_REG_MANUAL_SW2_BOOT_SW_MASK (0x1 << RT8973A_REG_MANUAL_SW2_BOOT_SW_SHIFT)
#define RT8973A_REG_MANUAL_SW2_FET_ON 0
#define RT8973A_REG_MANUAL_SW2_FET_OFF 0x1
#define RT8973A_REG_MANUAL_SW2_JIG_OFF 0
#define RT8973A_REG_MANUAL_SW2_JIG_ON 0x1
#define RT8973A_REG_MANUAL_SW2_BOOT_SW_ON 0
#define RT8973A_REG_MANUAL_SW2_BOOT_SW_OFF 0x1
#define RT8973A_REG_RESET_SHIFT 0
#define RT8973A_REG_RESET_MASK (0x1 << RT8973A_REG_RESET_SHIFT)
#define RT8973A_REG_RESET 0x1
/* RT8973A Interrupts */
enum rt8973a_irq {
/* Interrupt1*/
RT8973A_INT1_ATTACH,
RT8973A_INT1_DETACH,
RT8973A_INT1_CHGDET,
RT8973A_INT1_DCD_T,
RT8973A_INT1_OVP,
RT8973A_INT1_CONNECT,
RT8973A_INT1_ADC_CHG,
RT8973A_INT1_OTP,
/* Interrupt2*/
RT8973A_INT2_UVLO,
RT8973A_INT2_POR,
RT8973A_INT2_OTP_FET,
RT8973A_INT2_OVP_FET,
RT8973A_INT2_OCP_LATCH,
RT8973A_INT2_OCP,
RT8973A_INT2_OVP_OCP,
RT8973A_NUM,
};
#define RT8973A_INT1_ATTACH_MASK BIT(0)
#define RT8973A_INT1_DETACH_MASK BIT(1)
#define RT8973A_INT1_CHGDET_MASK BIT(2)
#define RT8973A_INT1_DCD_T_MASK BIT(3)
#define RT8973A_INT1_OVP_MASK BIT(4)
#define RT8973A_INT1_CONNECT_MASK BIT(5)
#define RT8973A_INT1_ADC_CHG_MASK BIT(6)
#define RT8973A_INT1_OTP_MASK BIT(7)
#define RT8973A_INT2_UVLOT_MASK BIT(0)
#define RT8973A_INT2_POR_MASK BIT(1)
#define RT8973A_INT2_OTP_FET_MASK BIT(2)
#define RT8973A_INT2_OVP_FET_MASK BIT(3)
#define RT8973A_INT2_OCP_LATCH_MASK BIT(4)
#define RT8973A_INT2_OCP_MASK BIT(5)
#define RT8973A_INT2_OVP_OCP_MASK BIT(6)
#endif /* __LINUX_EXTCON_RT8973A_H */
...@@ -8,16 +8,10 @@ ...@@ -8,16 +8,10 @@
* under the terms of the GNU General Public License as published by the * 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 * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * 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.
*/ */
#include <linux/err.h> #include <linux/err.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -26,7 +20,8 @@ ...@@ -26,7 +20,8 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/extcon.h> #include <linux/extcon.h>
#include <linux/extcon/sm5502.h>
#include "extcon-sm5502.h"
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */ #define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
...@@ -300,7 +295,7 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) ...@@ -300,7 +295,7 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
* If ADC is SM5502_MUIC_ADC_GROUND(0x0), external cable hasn't * If ADC is SM5502_MUIC_ADC_GROUND(0x0), external cable hasn't
* connected with to MUIC device. * connected with to MUIC device.
*/ */
cable_type &= SM5502_REG_ADC_MASK; cable_type = adc & SM5502_REG_ADC_MASK;
if (cable_type == SM5502_MUIC_ADC_GROUND) if (cable_type == SM5502_MUIC_ADC_GROUND)
return SM5502_MUIC_ADC_GROUND; return SM5502_MUIC_ADC_GROUND;
...@@ -395,7 +390,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, ...@@ -395,7 +390,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
/* Get the type of attached or detached cable */ /* Get the type of attached or detached cable */
if (attached) if (attached)
cable_type = sm5502_muic_get_cable_type(info); cable_type = sm5502_muic_get_cable_type(info);
else if (!attached) else
cable_type = prev_cable_type; cable_type = prev_cable_type;
prev_cable_type = cable_type; prev_cable_type = cable_type;
...@@ -457,8 +452,6 @@ static void sm5502_muic_irq_work(struct work_struct *work) ...@@ -457,8 +452,6 @@ static void sm5502_muic_irq_work(struct work_struct *work)
dev_err(info->dev, "failed to handle MUIC interrupt\n"); dev_err(info->dev, "failed to handle MUIC interrupt\n");
mutex_unlock(&info->mutex); mutex_unlock(&info->mutex);
return;
} }
/* /*
...@@ -617,8 +610,9 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c, ...@@ -617,8 +610,9 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
IRQF_NO_SUSPEND, IRQF_NO_SUSPEND,
muic_irq->name, info); muic_irq->name, info);
if (ret) { if (ret) {
dev_err(info->dev, "failed: irq request (IRQ: %d," dev_err(info->dev,
" error :%d)\n", muic_irq->irq, ret); "failed: irq request (IRQ: %d, error :%d)\n",
muic_irq->irq, ret);
return ret; return ret;
} }
} }
......
...@@ -7,11 +7,6 @@ ...@@ -7,11 +7,6 @@
* under the terms of the GNU General Public License as published by the * 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 * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * 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.
*/ */
#ifndef __LINUX_EXTCON_SM5502_H #ifndef __LINUX_EXTCON_SM5502_H
......
...@@ -165,8 +165,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, ...@@ -165,8 +165,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
ret = vmbus_post_msg(open_msg, ret = vmbus_post_msg(open_msg,
sizeof(struct vmbus_channel_open_channel)); sizeof(struct vmbus_channel_open_channel));
if (ret != 0) if (ret != 0) {
err = ret;
goto error1; goto error1;
}
t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ); t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
if (t == 0) { if (t == 0) {
...@@ -363,7 +365,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, ...@@ -363,7 +365,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
u32 next_gpadl_handle; u32 next_gpadl_handle;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
int t;
next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle); next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
atomic_inc(&vmbus_connection.next_gpadl_handle); atomic_inc(&vmbus_connection.next_gpadl_handle);
...@@ -410,9 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, ...@@ -410,9 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
} }
} }
t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); wait_for_completion(&msginfo->waitevent);
BUG_ON(t == 0);
/* At this point, we received the gpadl created msg */ /* At this point, we received the gpadl created msg */
*gpadl_handle = gpadlmsg->gpadl; *gpadl_handle = gpadlmsg->gpadl;
...@@ -435,7 +434,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) ...@@ -435,7 +434,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
struct vmbus_channel_gpadl_teardown *msg; struct vmbus_channel_gpadl_teardown *msg;
struct vmbus_channel_msginfo *info; struct vmbus_channel_msginfo *info;
unsigned long flags; unsigned long flags;
int ret, t; int ret;
info = kmalloc(sizeof(*info) + info = kmalloc(sizeof(*info) +
sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL); sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
...@@ -457,11 +456,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) ...@@ -457,11 +456,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
ret = vmbus_post_msg(msg, ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_gpadl_teardown)); sizeof(struct vmbus_channel_gpadl_teardown));
BUG_ON(ret != 0); if (ret)
t = wait_for_completion_timeout(&info->waitevent, 5*HZ); goto post_msg_err;
BUG_ON(t == 0);
wait_for_completion(&info->waitevent);
/* Received a torndown response */ post_msg_err:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&info->msglistentry); list_del(&info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
...@@ -478,7 +478,7 @@ static void reset_channel_cb(void *arg) ...@@ -478,7 +478,7 @@ static void reset_channel_cb(void *arg)
channel->onchannel_callback = NULL; channel->onchannel_callback = NULL;
} }
static void vmbus_close_internal(struct vmbus_channel *channel) static int vmbus_close_internal(struct vmbus_channel *channel)
{ {
struct vmbus_channel_close_channel *msg; struct vmbus_channel_close_channel *msg;
int ret; int ret;
...@@ -486,11 +486,14 @@ static void vmbus_close_internal(struct vmbus_channel *channel) ...@@ -486,11 +486,14 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
channel->state = CHANNEL_OPEN_STATE; channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL; channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */ /* Stop callback and cancel the timer asap */
if (channel->target_cpu != smp_processor_id()) if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu, reset_channel_cb, smp_call_function_single(channel->target_cpu, reset_channel_cb,
channel, true); channel, true);
else } else {
reset_channel_cb(channel); reset_channel_cb(channel);
put_cpu();
}
/* Send a closing message */ /* Send a closing message */
...@@ -501,11 +504,28 @@ static void vmbus_close_internal(struct vmbus_channel *channel) ...@@ -501,11 +504,28 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel)); ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
BUG_ON(ret != 0); if (ret) {
pr_err("Close failed: close post msg return is %d\n", ret);
/*
* If we failed to post the close msg,
* it is perhaps better to leak memory.
*/
return ret;
}
/* Tear down the gpadl for the channel's ring buffer */ /* Tear down the gpadl for the channel's ring buffer */
if (channel->ringbuffer_gpadlhandle) if (channel->ringbuffer_gpadlhandle) {
vmbus_teardown_gpadl(channel, ret = vmbus_teardown_gpadl(channel,
channel->ringbuffer_gpadlhandle); channel->ringbuffer_gpadlhandle);
if (ret) {
pr_err("Close failed: teardown gpadl return %d\n", ret);
/*
* If we failed to teardown gpadl,
* it is perhaps better to leak memory.
*/
return ret;
}
}
/* Cleanup the ring buffers for this channel */ /* Cleanup the ring buffers for this channel */
hv_ringbuffer_cleanup(&channel->outbound); hv_ringbuffer_cleanup(&channel->outbound);
...@@ -514,7 +534,7 @@ static void vmbus_close_internal(struct vmbus_channel *channel) ...@@ -514,7 +534,7 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages, free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
return ret;
} }
/* /*
......
...@@ -224,11 +224,14 @@ static void vmbus_process_rescind_offer(struct work_struct *work) ...@@ -224,11 +224,14 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
msg.header.msgtype = CHANNELMSG_RELID_RELEASED; msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
if (channel->target_cpu != smp_processor_id()) if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu, smp_call_function_single(channel->target_cpu,
percpu_channel_deq, channel, true); percpu_channel_deq, channel, true);
else } else {
percpu_channel_deq(channel); percpu_channel_deq(channel);
put_cpu();
}
if (channel->primary_channel == NULL) { if (channel->primary_channel == NULL) {
spin_lock_irqsave(&vmbus_connection.channel_lock, flags); spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
...@@ -294,12 +297,15 @@ static void vmbus_process_offer(struct work_struct *work) ...@@ -294,12 +297,15 @@ static void vmbus_process_offer(struct work_struct *work)
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
if (enq) { if (enq) {
if (newchannel->target_cpu != smp_processor_id()) if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu, smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq, percpu_channel_enq,
newchannel, true); newchannel, true);
else } else {
percpu_channel_enq(newchannel); percpu_channel_enq(newchannel);
put_cpu();
}
} }
if (!fnew) { if (!fnew) {
/* /*
...@@ -314,12 +320,15 @@ static void vmbus_process_offer(struct work_struct *work) ...@@ -314,12 +320,15 @@ static void vmbus_process_offer(struct work_struct *work)
list_add_tail(&newchannel->sc_list, &channel->sc_list); list_add_tail(&newchannel->sc_list, &channel->sc_list);
spin_unlock_irqrestore(&channel->sc_lock, flags); spin_unlock_irqrestore(&channel->sc_lock, flags);
if (newchannel->target_cpu != smp_processor_id()) if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu, smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq, percpu_channel_enq,
newchannel, true); newchannel, true);
else } else {
percpu_channel_enq(newchannel); percpu_channel_enq(newchannel);
put_cpu();
}
newchannel->state = CHANNEL_OPEN_STATE; newchannel->state = CHANNEL_OPEN_STATE;
if (channel->sc_creation_callback != NULL) if (channel->sc_creation_callback != NULL)
......
...@@ -427,10 +427,21 @@ int vmbus_post_msg(void *buffer, size_t buflen) ...@@ -427,10 +427,21 @@ int vmbus_post_msg(void *buffer, size_t buflen)
* insufficient resources. Retry the operation a couple of * insufficient resources. Retry the operation a couple of
* times before giving up. * times before giving up.
*/ */
while (retries < 3) { while (retries < 10) {
ret = hv_post_message(conn_id, 1, buffer, buflen); ret = hv_post_message(conn_id, 1, buffer, buflen);
if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
switch (ret) {
case HV_STATUS_INSUFFICIENT_BUFFERS:
ret = -ENOMEM;
case -ENOMEM:
break;
case HV_STATUS_SUCCESS:
return ret; return ret;
default:
pr_err("hv_post_msg() failed; error code:%d\n", ret);
return -EINVAL;
}
retries++; retries++;
msleep(100); msleep(100);
} }
......
...@@ -138,6 +138,8 @@ int hv_init(void) ...@@ -138,6 +138,8 @@ int hv_init(void)
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0, memset(hv_context.synic_message_page, 0,
sizeof(void *) * NR_CPUS); sizeof(void *) * NR_CPUS);
memset(hv_context.post_msg_page, 0,
sizeof(void *) * NR_CPUS);
memset(hv_context.vp_index, 0, memset(hv_context.vp_index, 0,
sizeof(int) * NR_CPUS); sizeof(int) * NR_CPUS);
memset(hv_context.event_dpc, 0, memset(hv_context.event_dpc, 0,
...@@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_id connection_id, ...@@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type, enum hv_message_type message_type,
void *payload, size_t payload_size) void *payload, size_t payload_size)
{ {
struct aligned_input {
u64 alignment8;
struct hv_input_post_message msg;
};
struct hv_input_post_message *aligned_msg; struct hv_input_post_message *aligned_msg;
u16 status; u16 status;
unsigned long addr;
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -EMSGSIZE; return -EMSGSIZE;
addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
if (!addr)
return -ENOMEM;
aligned_msg = (struct hv_input_post_message *) aligned_msg = (struct hv_input_post_message *)
(ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN)); hv_context.post_msg_page[get_cpu()];
aligned_msg->connectionid = connection_id; aligned_msg->connectionid = connection_id;
aligned_msg->reserved = 0;
aligned_msg->message_type = message_type; aligned_msg->message_type = message_type;
aligned_msg->payload_size = payload_size; aligned_msg->payload_size = payload_size;
memcpy((void *)aligned_msg->payload, payload, payload_size); memcpy((void *)aligned_msg->payload, payload, payload_size);
...@@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_id connection_id, ...@@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_id connection_id,
status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
& 0xFFFF; & 0xFFFF;
kfree((void *)addr); put_cpu();
return status; return status;
} }
...@@ -294,6 +287,14 @@ int hv_synic_alloc(void) ...@@ -294,6 +287,14 @@ int hv_synic_alloc(void)
pr_err("Unable to allocate SYNIC event page\n"); pr_err("Unable to allocate SYNIC event page\n");
goto err; goto err;
} }
hv_context.post_msg_page[cpu] =
(void *)get_zeroed_page(GFP_ATOMIC);
if (hv_context.post_msg_page[cpu] == NULL) {
pr_err("Unable to allocate post msg page\n");
goto err;
}
} }
return 0; return 0;
...@@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu) ...@@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu)
free_page((unsigned long)hv_context.synic_event_page[cpu]); free_page((unsigned long)hv_context.synic_event_page[cpu]);
if (hv_context.synic_message_page[cpu]) if (hv_context.synic_message_page[cpu])
free_page((unsigned long)hv_context.synic_message_page[cpu]); free_page((unsigned long)hv_context.synic_message_page[cpu]);
if (hv_context.post_msg_page[cpu])
free_page((unsigned long)hv_context.post_msg_page[cpu]);
} }
void hv_synic_free(void) void hv_synic_free(void)
......
...@@ -515,6 +515,10 @@ struct hv_context { ...@@ -515,6 +515,10 @@ struct hv_context {
* per-cpu list of the channels based on their CPU affinity. * per-cpu list of the channels based on their CPU affinity.
*/ */
struct list_head percpu_list[NR_CPUS]; struct list_head percpu_list[NR_CPUS];
/*
* buffer to post messages to the host.
*/
void *post_msg_page[NR_CPUS];
}; };
extern struct hv_context hv_context; extern struct hv_context hv_context;
......
...@@ -361,6 +361,11 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -361,6 +361,11 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->read_index = ring_info->ring_buffer->read_index =
ring_info->ring_buffer->write_index = 0; ring_info->ring_buffer->write_index = 0;
/*
* Set the feature bit for enabling flow control.
*/
ring_info->ring_buffer->feature_bits.value = 1;
ring_info->ring_size = buflen; ring_info->ring_size = buflen;
ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
......
...@@ -572,7 +572,8 @@ static int tpci200_pci_probe(struct pci_dev *pdev, ...@@ -572,7 +572,8 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
/* Register the carrier in the industry pack bus driver */ /* Register the carrier in the industry pack bus driver */
tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev, tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
TPCI200_NB_SLOT, TPCI200_NB_SLOT,
&tpci200_bus_ops); &tpci200_bus_ops,
THIS_MODULE);
if (!tpci200->info->ipack_bus) { if (!tpci200->info->ipack_bus) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"error registering the carrier on ipack driver\n"); "error registering the carrier on ipack driver\n");
......
...@@ -55,6 +55,22 @@ struct ipoctal { ...@@ -55,6 +55,22 @@ struct ipoctal {
u8 __iomem *int_space; u8 __iomem *int_space;
}; };
static inline struct ipoctal *chan_to_ipoctal(struct ipoctal_channel *chan,
unsigned int index)
{
return container_of(chan, struct ipoctal, channel[index]);
}
static void ipoctal_reset_channel(struct ipoctal_channel *channel)
{
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
}
static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
{ {
struct ipoctal_channel *channel; struct ipoctal_channel *channel;
...@@ -72,12 +88,20 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) ...@@ -72,12 +88,20 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
static int ipoctal_open(struct tty_struct *tty, struct file *file) static int ipoctal_open(struct tty_struct *tty, struct file *file)
{ {
struct ipoctal_channel *channel; struct ipoctal_channel *channel = dev_get_drvdata(tty->dev);
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
int err;
channel = dev_get_drvdata(tty->dev);
tty->driver_data = channel; tty->driver_data = channel;
return tty_port_open(&channel->tty_port, tty, file); if (!ipack_get_carrier(ipoctal->dev))
return -EBUSY;
err = tty_port_open(&channel->tty_port, tty, file);
if (err)
ipack_put_carrier(ipoctal->dev);
return err;
} }
static void ipoctal_reset_stats(struct ipoctal_stats *stats) static void ipoctal_reset_stats(struct ipoctal_stats *stats)
...@@ -151,7 +175,6 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr) ...@@ -151,7 +175,6 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (sr & SR_RECEIVED_BREAK) { if (sr & SR_RECEIVED_BREAK) {
iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
channel->stats.rcv_break++; channel->stats.rcv_break++;
flag = TTY_BREAK; flag = TTY_BREAK;
} }
...@@ -196,6 +219,9 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel) ...@@ -196,6 +219,9 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
isr = ioread8(&channel->block_regs->r.isr); isr = ioread8(&channel->block_regs->r.isr);
sr = ioread8(&channel->regs->r.sr); sr = ioread8(&channel->regs->r.sr);
if (isr & (IMR_DELTA_BREAK_A | IMR_DELTA_BREAK_B))
iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) { if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
/* In case of RS-485, change from TX to RX when finishing TX. /* In case of RS-485, change from TX to RX when finishing TX.
...@@ -304,10 +330,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, ...@@ -304,10 +330,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A; channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
} }
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); ipoctal_reset_channel(channel);
channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY, iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
&channel->regs->w.mr); /* mr1 */ &channel->regs->w.mr); /* mr1 */
iowrite8(0, &channel->regs->w.mr); /* mr2 */ iowrite8(0, &channel->regs->w.mr); /* mr2 */
...@@ -467,11 +490,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, ...@@ -467,11 +490,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
cflag = tty->termios.c_cflag; cflag = tty->termios.c_cflag;
/* Disable and reset everything before change the setup */ /* Disable and reset everything before change the setup */
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); ipoctal_reset_channel(channel);
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
/* Set Bits per chars */ /* Set Bits per chars */
switch (cflag & CSIZE) { switch (cflag & CSIZE) {
...@@ -609,12 +628,7 @@ static void ipoctal_hangup(struct tty_struct *tty) ...@@ -609,12 +628,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
tty_port_hangup(&channel->tty_port); tty_port_hangup(&channel->tty_port);
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); ipoctal_reset_channel(channel);
channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
wake_up_interruptible(&channel->tty_port.open_wait); wake_up_interruptible(&channel->tty_port.open_wait);
...@@ -627,15 +641,19 @@ static void ipoctal_shutdown(struct tty_struct *tty) ...@@ -627,15 +641,19 @@ static void ipoctal_shutdown(struct tty_struct *tty)
if (channel == NULL) if (channel == NULL)
return; return;
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); ipoctal_reset_channel(channel);
channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
} }
static void ipoctal_cleanup(struct tty_struct *tty)
{
struct ipoctal_channel *channel = tty->driver_data;
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
/* release the carrier driver */
ipack_put_carrier(ipoctal->dev);
}
static const struct tty_operations ipoctal_fops = { static const struct tty_operations ipoctal_fops = {
.ioctl = NULL, .ioctl = NULL,
.open = ipoctal_open, .open = ipoctal_open,
...@@ -647,6 +665,7 @@ static const struct tty_operations ipoctal_fops = { ...@@ -647,6 +665,7 @@ static const struct tty_operations ipoctal_fops = {
.get_icount = ipoctal_get_icount, .get_icount = ipoctal_get_icount,
.hangup = ipoctal_hangup, .hangup = ipoctal_hangup,
.shutdown = ipoctal_shutdown, .shutdown = ipoctal_shutdown,
.cleanup = ipoctal_cleanup,
}; };
static int ipoctal_probe(struct ipack_device *dev) static int ipoctal_probe(struct ipack_device *dev)
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Software Foundation; version 2 of the License. * Software Foundation; version 2 of the License.
*/ */
#ifndef _IPOCTAL_H #ifndef _IPOCTAL_H_
#define _IPOCTAL_H_ #define _IPOCTAL_H_
#define NR_CHANNELS 8 #define NR_CHANNELS 8
......
...@@ -206,7 +206,8 @@ static struct bus_type ipack_bus_type = { ...@@ -206,7 +206,8 @@ static struct bus_type ipack_bus_type = {
}; };
struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
const struct ipack_bus_ops *ops) const struct ipack_bus_ops *ops,
struct module *owner)
{ {
int bus_nr; int bus_nr;
struct ipack_bus_device *bus; struct ipack_bus_device *bus;
...@@ -225,6 +226,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, ...@@ -225,6 +226,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
bus->parent = parent; bus->parent = parent;
bus->slots = slots; bus->slots = slots;
bus->ops = ops; bus->ops = ops;
bus->owner = owner;
return bus; return bus;
} }
EXPORT_SYMBOL_GPL(ipack_bus_register); EXPORT_SYMBOL_GPL(ipack_bus_register);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/device.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -159,12 +159,11 @@ static int eeprom_probe(struct i2c_client *client, ...@@ -159,12 +159,11 @@ static int eeprom_probe(struct i2c_client *client,
{ {
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
struct eeprom_data *data; struct eeprom_data *data;
int err;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data),
err = -ENOMEM; GFP_KERNEL);
goto exit; if (!data)
} return -ENOMEM;
memset(data->data, 0xff, EEPROM_SIZE); memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
...@@ -190,22 +189,12 @@ static int eeprom_probe(struct i2c_client *client, ...@@ -190,22 +189,12 @@ static int eeprom_probe(struct i2c_client *client,
} }
/* create the sysfs eeprom file */ /* create the sysfs eeprom file */
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
if (err)
goto exit_kfree;
return 0;
exit_kfree:
kfree(data);
exit:
return err;
} }
static int eeprom_remove(struct i2c_client *client) static int eeprom_remove(struct i2c_client *client)
{ {
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
kfree(i2c_get_clientdata(client));
return 0; return 0;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -45,10 +45,10 @@ ...@@ -45,10 +45,10 @@
MODULE_AUTHOR("Frank Haverkamp <haver@linux.vnet.ibm.com>"); MODULE_AUTHOR("Frank Haverkamp <haver@linux.vnet.ibm.com>");
MODULE_AUTHOR("Michael Ruettger <michael@ibmra.de>"); MODULE_AUTHOR("Michael Ruettger <michael@ibmra.de>");
MODULE_AUTHOR("Joerg-Stephan Vogt <jsvogt@de.ibm.com>"); MODULE_AUTHOR("Joerg-Stephan Vogt <jsvogt@de.ibm.com>");
MODULE_AUTHOR("Michal Jung <mijung@de.ibm.com>"); MODULE_AUTHOR("Michael Jung <mijung@gmx.net>");
MODULE_DESCRIPTION("GenWQE Card"); MODULE_DESCRIPTION("GenWQE Card");
MODULE_VERSION(DRV_VERS_STRING); MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char genwqe_driver_name[] = GENWQE_DEVNAME; static char genwqe_driver_name[] = GENWQE_DEVNAME;
...@@ -346,8 +346,13 @@ static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd) ...@@ -346,8 +346,13 @@ static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
unsigned int vf; unsigned int vf;
u32 T = genwqe_T_psec(cd); u32 T = genwqe_T_psec(cd);
u64 x; u64 x;
int totalvfs;
for (vf = 0; vf < pci_sriov_get_totalvfs(pci_dev); vf++) { totalvfs = pci_sriov_get_totalvfs(pci_dev);
if (totalvfs <= 0)
return false;
for (vf = 0; vf < totalvfs; vf++) {
if (cd->vf_jobtimeout_msec[vf] == 0) if (cd->vf_jobtimeout_msec[vf] == 0)
continue; continue;
...@@ -383,7 +388,8 @@ static int genwqe_ffdc_buffs_alloc(struct genwqe_dev *cd) ...@@ -383,7 +388,8 @@ static int genwqe_ffdc_buffs_alloc(struct genwqe_dev *cd)
/* currently support only the debug units mentioned here */ /* currently support only the debug units mentioned here */
cd->ffdc[type].entries = e; cd->ffdc[type].entries = e;
cd->ffdc[type].regs = kmalloc(e * sizeof(struct genwqe_reg), cd->ffdc[type].regs =
kmalloc_array(e, sizeof(struct genwqe_reg),
GFP_KERNEL); GFP_KERNEL);
/* /*
* regs == NULL is ok, the using code treats this as no regs, * regs == NULL is ok, the using code treats this as no regs,
...@@ -723,8 +729,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd) ...@@ -723,8 +729,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, sfir_addr, sfir); __genwqe_writeq(cd, sfir_addr, sfir);
dev_dbg(&pci_dev->dev, dev_dbg(&pci_dev->dev,
"[HM] Clearing 2ndary FIR 0x%08x " "[HM] Clearing 2ndary FIR 0x%08x with 0x%016llx\n",
"with 0x%016llx\n", sfir_addr, sfir); sfir_addr, sfir);
/* /*
* note, these cannot be error-Firs * note, these cannot be error-Firs
...@@ -740,9 +746,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd) ...@@ -740,9 +746,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, fir_clr_addr, mask); __genwqe_writeq(cd, fir_clr_addr, mask);
dev_dbg(&pci_dev->dev, dev_dbg(&pci_dev->dev,
"[HM] Clearing primary FIR 0x%08x " "[HM] Clearing primary FIR 0x%08x with 0x%016llx\n",
"with 0x%016llx\n", fir_clr_addr, fir_clr_addr, mask);
mask);
} }
} }
} }
...@@ -1125,6 +1130,8 @@ static int genwqe_pci_setup(struct genwqe_dev *cd) ...@@ -1125,6 +1130,8 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
} }
cd->num_vfs = pci_sriov_get_totalvfs(pci_dev); cd->num_vfs = pci_sriov_get_totalvfs(pci_dev);
if (cd->num_vfs < 0)
cd->num_vfs = 0;
err = genwqe_read_ids(cd); err = genwqe_read_ids(cd);
if (err) if (err)
...@@ -1202,8 +1209,8 @@ static int genwqe_probe(struct pci_dev *pci_dev, ...@@ -1202,8 +1209,8 @@ static int genwqe_probe(struct pci_dev *pci_dev,
err = genwqe_health_check_start(cd); err = genwqe_health_check_start(cd);
if (err < 0) { if (err < 0) {
dev_err(&pci_dev->dev, dev_err(&pci_dev->dev,
"err: cannot start health checking! " "err: cannot start health checking! (err=%d)\n",
"(err=%d)\n", err); err);
goto out_stop_services; goto out_stop_services;
} }
} }
...@@ -1313,11 +1320,14 @@ static void genwqe_err_resume(struct pci_dev *pci_dev) ...@@ -1313,11 +1320,14 @@ static void genwqe_err_resume(struct pci_dev *pci_dev)
static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs) static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
{ {
int rc;
struct genwqe_dev *cd = dev_get_drvdata(&dev->dev); struct genwqe_dev *cd = dev_get_drvdata(&dev->dev);
if (numvfs > 0) { if (numvfs > 0) {
genwqe_setup_vf_jtimer(cd); genwqe_setup_vf_jtimer(cd);
pci_enable_sriov(dev, numvfs); rc = pci_enable_sriov(dev, numvfs);
if (rc < 0)
return rc;
return numvfs; return numvfs;
} }
if (numvfs == 0) { if (numvfs == 0) {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -201,7 +201,8 @@ static inline void genwqe_mapping_init(struct dma_mapping *m, ...@@ -201,7 +201,8 @@ static inline void genwqe_mapping_init(struct dma_mapping *m,
* @ddcb_seq: Sequence number of last DDCB * @ddcb_seq: Sequence number of last DDCB
* @ddcbs_in_flight: Currently enqueued DDCBs * @ddcbs_in_flight: Currently enqueued DDCBs
* @ddcbs_completed: Number of already completed DDCBs * @ddcbs_completed: Number of already completed DDCBs
* @busy: Number of -EBUSY returns * @return_on_busy: Number of -EBUSY returns on full queue
* @wait_on_busy: Number of waits on full queue
* @ddcb_daddr: DMA address of first DDCB in the queue * @ddcb_daddr: DMA address of first DDCB in the queue
* @ddcb_vaddr: Kernel virtual address of first DDCB in the queue * @ddcb_vaddr: Kernel virtual address of first DDCB in the queue
* @ddcb_req: Associated requests (one per DDCB) * @ddcb_req: Associated requests (one per DDCB)
...@@ -218,7 +219,8 @@ struct ddcb_queue { ...@@ -218,7 +219,8 @@ struct ddcb_queue {
unsigned int ddcbs_in_flight; /* number of ddcbs in processing */ unsigned int ddcbs_in_flight; /* number of ddcbs in processing */
unsigned int ddcbs_completed; unsigned int ddcbs_completed;
unsigned int ddcbs_max_in_flight; unsigned int ddcbs_max_in_flight;
unsigned int busy; /* how many times -EBUSY? */ unsigned int return_on_busy; /* how many times -EBUSY? */
unsigned int wait_on_busy;
dma_addr_t ddcb_daddr; /* DMA address */ dma_addr_t ddcb_daddr; /* DMA address */
struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */ struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */
...@@ -226,7 +228,7 @@ struct ddcb_queue { ...@@ -226,7 +228,7 @@ struct ddcb_queue {
wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */ wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */
spinlock_t ddcb_lock; /* exclusive access to queue */ spinlock_t ddcb_lock; /* exclusive access to queue */
wait_queue_head_t ddcb_waitq; /* wait for ddcb processing */ wait_queue_head_t busy_waitq; /* wait for ddcb processing */
/* registers or the respective queue to be used */ /* registers or the respective queue to be used */
u32 IO_QUEUE_CONFIG; u32 IO_QUEUE_CONFIG;
...@@ -306,7 +308,7 @@ struct genwqe_dev { ...@@ -306,7 +308,7 @@ struct genwqe_dev {
struct pci_dev *pci_dev; /* PCI device */ struct pci_dev *pci_dev; /* PCI device */
void __iomem *mmio; /* BAR-0 MMIO start */ void __iomem *mmio; /* BAR-0 MMIO start */
unsigned long mmio_len; unsigned long mmio_len;
u16 num_vfs; int num_vfs;
u32 vf_jobtimeout_msec[GENWQE_MAX_VFS]; u32 vf_jobtimeout_msec[GENWQE_MAX_VFS];
int is_privileged; /* access to all regs possible */ int is_privileged; /* access to all regs possible */
...@@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m) ...@@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m)
* buildup and teardown. * buildup and teardown.
*/ */
int __genwqe_execute_ddcb(struct genwqe_dev *cd, int __genwqe_execute_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd); struct genwqe_ddcb_cmd *cmd, unsigned int f_flags);
/** /**
* __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation * __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation
...@@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd, ...@@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd,
* modification. * modification.
*/ */
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd); struct genwqe_ddcb_cmd *cmd,
unsigned int f_flags);
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd,
struct ddcb_requ *req,
unsigned int f_flags);
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -185,8 +185,7 @@ static void print_ddcb_info(struct genwqe_dev *cd, struct ddcb_queue *queue) ...@@ -185,8 +185,7 @@ static void print_ddcb_info(struct genwqe_dev *cd, struct ddcb_queue *queue)
pddcb = queue->ddcb_vaddr; pddcb = queue->ddcb_vaddr;
for (i = 0; i < queue->ddcb_max; i++) { for (i = 0; i < queue->ddcb_max; i++) {
dev_err(&pci_dev->dev, dev_err(&pci_dev->dev,
" %c %-3d: RETC=%03x SEQ=%04x " " %c %-3d: RETC=%03x SEQ=%04x HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
"HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
i == queue->ddcb_act ? '>' : ' ', i == queue->ddcb_act ? '>' : ' ',
i, i,
be16_to_cpu(pddcb->retc_16), be16_to_cpu(pddcb->retc_16),
...@@ -214,6 +213,7 @@ struct genwqe_ddcb_cmd *ddcb_requ_alloc(void) ...@@ -214,6 +213,7 @@ struct genwqe_ddcb_cmd *ddcb_requ_alloc(void)
void ddcb_requ_free(struct genwqe_ddcb_cmd *cmd) void ddcb_requ_free(struct genwqe_ddcb_cmd *cmd)
{ {
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd); struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
kfree(req); kfree(req);
} }
...@@ -306,7 +306,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, ...@@ -306,7 +306,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
new = (old | DDCB_NEXT_BE32); new = (old | DDCB_NEXT_BE32);
wmb(); wmb(); /* need to ensure write ordering */
icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new); icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new);
if (icrc_hsi_shi == old) if (icrc_hsi_shi == old)
...@@ -317,7 +317,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, ...@@ -317,7 +317,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
ddcb_mark_tapped(pddcb); ddcb_mark_tapped(pddcb);
num = (u64)ddcb_no << 8; num = (u64)ddcb_no << 8;
wmb(); wmb(); /* need to ensure write ordering */
__genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */ __genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */
return RET_DDCB_TAPPED; return RET_DDCB_TAPPED;
...@@ -390,8 +390,9 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd, ...@@ -390,8 +390,9 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
0x00000000) 0x00000000)
goto go_home; /* not completed, continue waiting */ goto go_home; /* not completed, continue waiting */
/* Note: DDCB could be purged */ wmb(); /* Add sync to decouple prev. read operations */
/* Note: DDCB could be purged */
req = queue->ddcb_req[queue->ddcb_act]; req = queue->ddcb_req[queue->ddcb_act];
if (req == NULL) { if (req == NULL) {
/* this occurs if DDCB is purged, not an error */ /* this occurs if DDCB is purged, not an error */
...@@ -416,9 +417,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd, ...@@ -416,9 +417,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
status = __genwqe_readq(cd, queue->IO_QUEUE_STATUS); status = __genwqe_readq(cd, queue->IO_QUEUE_STATUS);
dev_err(&pci_dev->dev, dev_err(&pci_dev->dev,
"[%s] SEQN=%04x HSI=%02x RETC=%03x " "[%s] SEQN=%04x HSI=%02x RETC=%03x Q_ERRCNTS=%016llx Q_STATUS=%016llx DDCB_DMA_ADDR=%016llx\n",
" Q_ERRCNTS=%016llx Q_STATUS=%016llx\n"
" DDCB_DMA_ADDR=%016llx\n",
__func__, be16_to_cpu(pddcb->seqnum_16), __func__, be16_to_cpu(pddcb->seqnum_16),
pddcb->hsi, retc_16, errcnts, status, pddcb->hsi, retc_16, errcnts, status,
queue->ddcb_daddr + ddcb_offs); queue->ddcb_daddr + ddcb_offs);
...@@ -439,8 +438,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd, ...@@ -439,8 +438,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
vcrc_16 = be16_to_cpu(pddcb->vcrc_16); vcrc_16 = be16_to_cpu(pddcb->vcrc_16);
if (vcrc != vcrc_16) { if (vcrc != vcrc_16) {
printk_ratelimited(KERN_ERR printk_ratelimited(KERN_ERR
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d " "%s %s: err: wrong VCRC pre=%02x vcrc_len=%d bytes vcrc_data=%04x is not vcrc_card=%04x\n",
"bytes vcrc_data=%04x is not vcrc_card=%04x\n",
GENWQE_DEVNAME, dev_name(&pci_dev->dev), GENWQE_DEVNAME, dev_name(&pci_dev->dev),
pddcb->pre, VCRC_LENGTH(req->cmd.asv_length), pddcb->pre, VCRC_LENGTH(req->cmd.asv_length),
vcrc, vcrc_16); vcrc, vcrc_16);
...@@ -450,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd, ...@@ -450,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
queue->ddcbs_completed++; queue->ddcbs_completed++;
queue->ddcbs_in_flight--; queue->ddcbs_in_flight--;
/* wake up process waiting for this DDCB */ /* wake up process waiting for this DDCB, and
processes on the busy queue */
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
wake_up_interruptible(&queue->busy_waitq);
pick_next_one: pick_next_one:
queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max; queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max;
...@@ -717,8 +717,7 @@ int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) ...@@ -717,8 +717,7 @@ int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
genwqe_hexdump(pci_dev, pddcb, sizeof(*pddcb)); genwqe_hexdump(pci_dev, pddcb, sizeof(*pddcb));
dev_err(&pci_dev->dev, dev_err(&pci_dev->dev,
"[%s] err: DDCB#%d not purged and not completed " "[%s] err: DDCB#%d not purged and not completed after %d seconds QSTAT=%016llx!!\n",
"after %d seconds QSTAT=%016llx!!\n",
__func__, req->num, genwqe_ddcb_software_timeout, __func__, req->num, genwqe_ddcb_software_timeout,
queue_status); queue_status);
...@@ -740,7 +739,7 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d) ...@@ -740,7 +739,7 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
} }
len = sizeof(d->driver_version); len = sizeof(d->driver_version);
snprintf(d->driver_version, len, "%s", DRV_VERS_STRING); snprintf(d->driver_version, len, "%s", DRV_VERSION);
d->slu_unitcfg = cd->slu_unitcfg; d->slu_unitcfg = cd->slu_unitcfg;
d->app_unitcfg = cd->app_unitcfg; d->app_unitcfg = cd->app_unitcfg;
return 0; return 0;
...@@ -750,12 +749,14 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d) ...@@ -750,12 +749,14 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
* __genwqe_enqueue_ddcb() - Enqueue a DDCB * __genwqe_enqueue_ddcb() - Enqueue a DDCB
* @cd: pointer to genwqe device descriptor * @cd: pointer to genwqe device descriptor
* @req: pointer to DDCB execution request * @req: pointer to DDCB execution request
* @f_flags: file mode: blocking, non-blocking
* *
* Return: 0 if enqueuing succeeded * Return: 0 if enqueuing succeeded
* -EIO if card is unusable/PCIe problems * -EIO if card is unusable/PCIe problems
* -EBUSY if enqueuing failed * -EBUSY if enqueuing failed
*/ */
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req,
unsigned int f_flags)
{ {
struct ddcb *pddcb; struct ddcb *pddcb;
unsigned long flags; unsigned long flags;
...@@ -763,6 +764,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) ...@@ -763,6 +764,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
struct pci_dev *pci_dev = cd->pci_dev; struct pci_dev *pci_dev = cd->pci_dev;
u16 icrc; u16 icrc;
retry:
if (cd->card_state != GENWQE_CARD_USED) { if (cd->card_state != GENWQE_CARD_USED) {
printk_ratelimited(KERN_ERR printk_ratelimited(KERN_ERR
"%s %s: [%s] Card is unusable/PCIe problem Req#%d\n", "%s %s: [%s] Card is unusable/PCIe problem Req#%d\n",
...@@ -788,11 +790,26 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) ...@@ -788,11 +790,26 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */ pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */
if (pddcb == NULL) { if (pddcb == NULL) {
int rc;
spin_unlock_irqrestore(&queue->ddcb_lock, flags); spin_unlock_irqrestore(&queue->ddcb_lock, flags);
queue->busy++;
if (f_flags & O_NONBLOCK) {
queue->return_on_busy++;
return -EBUSY; return -EBUSY;
} }
queue->wait_on_busy++;
rc = wait_event_interruptible(queue->busy_waitq,
queue_free_ddcbs(queue) != 0);
dev_dbg(&pci_dev->dev, "[%s] waiting for free DDCB: rc=%d\n",
__func__, rc);
if (rc == -ERESTARTSYS)
return rc; /* interrupted by a signal */
goto retry;
}
if (queue->ddcb_req[req->num] != NULL) { if (queue->ddcb_req[req->num] != NULL) {
spin_unlock_irqrestore(&queue->ddcb_lock, flags); spin_unlock_irqrestore(&queue->ddcb_lock, flags);
...@@ -893,9 +910,11 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) ...@@ -893,9 +910,11 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
* __genwqe_execute_raw_ddcb() - Setup and execute DDCB * __genwqe_execute_raw_ddcb() - Setup and execute DDCB
* @cd: pointer to genwqe device descriptor * @cd: pointer to genwqe device descriptor
* @req: user provided DDCB request * @req: user provided DDCB request
* @f_flags: file mode: blocking, non-blocking
*/ */
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
struct genwqe_ddcb_cmd *cmd) struct genwqe_ddcb_cmd *cmd,
unsigned int f_flags)
{ {
int rc = 0; int rc = 0;
struct pci_dev *pci_dev = cd->pci_dev; struct pci_dev *pci_dev = cd->pci_dev;
...@@ -911,7 +930,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, ...@@ -911,7 +930,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
__func__, cmd->asiv_length); __func__, cmd->asiv_length);
return -EINVAL; return -EINVAL;
} }
rc = __genwqe_enqueue_ddcb(cd, req); rc = __genwqe_enqueue_ddcb(cd, req, f_flags);
if (rc != 0) if (rc != 0)
return rc; return rc;
...@@ -1017,7 +1036,8 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) ...@@ -1017,7 +1036,8 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcbs_in_flight = 0; /* statistics */ queue->ddcbs_in_flight = 0; /* statistics */
queue->ddcbs_max_in_flight = 0; queue->ddcbs_max_in_flight = 0;
queue->ddcbs_completed = 0; queue->ddcbs_completed = 0;
queue->busy = 0; queue->return_on_busy = 0;
queue->wait_on_busy = 0;
queue->ddcb_seq = 0x100; /* start sequence number */ queue->ddcb_seq = 0x100; /* start sequence number */
queue->ddcb_max = genwqe_ddcb_max; /* module parameter */ queue->ddcb_max = genwqe_ddcb_max; /* module parameter */
...@@ -1057,7 +1077,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) ...@@ -1057,7 +1077,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcb_next = 0; /* queue is empty */ queue->ddcb_next = 0; /* queue is empty */
spin_lock_init(&queue->ddcb_lock); spin_lock_init(&queue->ddcb_lock);
init_waitqueue_head(&queue->ddcb_waitq); init_waitqueue_head(&queue->busy_waitq);
val64 = ((u64)(queue->ddcb_max - 1) << 8); /* lastptr */ val64 = ((u64)(queue->ddcb_max - 1) << 8); /* lastptr */
__genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */ __genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */
...@@ -1251,10 +1271,8 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd) ...@@ -1251,10 +1271,8 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd)
} }
rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS); rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS);
if (rc) { if (rc)
rc = -ENODEV;
goto stop_kthread; goto stop_kthread;
}
/* /*
* We must have all wait-queues initialized when we enable the * We must have all wait-queues initialized when we enable the
...@@ -1307,6 +1325,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd) ...@@ -1307,6 +1325,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd)
for (i = 0; i < queue->ddcb_max; i++) for (i = 0; i < queue->ddcb_max; i++)
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
wake_up_interruptible(&queue->busy_waitq);
spin_unlock_irqrestore(&queue->ddcb_lock, flags); spin_unlock_irqrestore(&queue->ddcb_lock, flags);
return 0; return 0;
...@@ -1346,8 +1365,8 @@ int genwqe_finish_queue(struct genwqe_dev *cd) ...@@ -1346,8 +1365,8 @@ int genwqe_finish_queue(struct genwqe_dev *cd)
break; break;
dev_dbg(&pci_dev->dev, dev_dbg(&pci_dev->dev,
" DEBUG [%d/%d] waiting for queue to get empty: " " DEBUG [%d/%d] waiting for queue to get empty: %d requests!\n",
"%d requests!\n", i, waitmax, in_flight); i, waitmax, in_flight);
/* /*
* Severe severe error situation: The card itself has * Severe severe error situation: The card itself has
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -244,14 +244,16 @@ static int genwqe_ddcb_info_show(struct seq_file *s, void *unused) ...@@ -244,14 +244,16 @@ static int genwqe_ddcb_info_show(struct seq_file *s, void *unused)
" ddcbs_in_flight: %u\n" " ddcbs_in_flight: %u\n"
" ddcbs_max_in_flight: %u\n" " ddcbs_max_in_flight: %u\n"
" ddcbs_completed: %u\n" " ddcbs_completed: %u\n"
" busy: %u\n" " return_on_busy: %u\n"
" wait_on_busy: %u\n"
" irqs_processed: %u\n", " irqs_processed: %u\n",
queue->ddcb_max, (long long)queue->ddcb_daddr, queue->ddcb_max, (long long)queue->ddcb_daddr,
(long long)queue->ddcb_daddr + (long long)queue->ddcb_daddr +
(queue->ddcb_max * DDCB_LENGTH), (queue->ddcb_max * DDCB_LENGTH),
(long long)queue->ddcb_vaddr, queue->ddcbs_in_flight, (long long)queue->ddcb_vaddr, queue->ddcbs_in_flight,
queue->ddcbs_max_in_flight, queue->ddcbs_completed, queue->ddcbs_max_in_flight, queue->ddcbs_completed,
queue->busy, cd->irqs_processed); queue->return_on_busy, queue->wait_on_busy,
cd->irqs_processed);
/* Hardware State */ /* Hardware State */
seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n" seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n"
...@@ -323,7 +325,7 @@ static int genwqe_info_show(struct seq_file *s, void *unused) ...@@ -323,7 +325,7 @@ static int genwqe_info_show(struct seq_file *s, void *unused)
" Base Clock : %u MHz\n" " Base Clock : %u MHz\n"
" Arch/SVN Release: %u/%llx\n" " Arch/SVN Release: %u/%llx\n"
" Bitstream : %llx\n", " Bitstream : %llx\n",
GENWQE_DEVNAME, DRV_VERS_STRING, dev_name(&pci_dev->dev), GENWQE_DEVNAME, DRV_VERSION, dev_name(&pci_dev->dev),
genwqe_is_privileged(cd) ? genwqe_is_privileged(cd) ?
"Physical" : "Virtual or no SR-IOV", "Physical" : "Virtual or no SR-IOV",
cd->card_idx, slu_id, app_id, cd->card_idx, slu_id, app_id,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -213,9 +213,9 @@ static void genwqe_remove_mappings(struct genwqe_file *cfile) ...@@ -213,9 +213,9 @@ static void genwqe_remove_mappings(struct genwqe_file *cfile)
* GENWQE_MAPPING_SGL_TEMP should be removed by tidy up code. * GENWQE_MAPPING_SGL_TEMP should be removed by tidy up code.
*/ */
dev_err(&pci_dev->dev, dev_err(&pci_dev->dev,
"[%s] %d. cleanup mapping: u_vaddr=%p " "[%s] %d. cleanup mapping: u_vaddr=%p u_kaddr=%016lx dma_addr=%lx\n",
"u_kaddr=%016lx dma_addr=%lx\n", __func__, i++, __func__, i++, dma_map->u_vaddr,
dma_map->u_vaddr, (unsigned long)dma_map->k_vaddr, (unsigned long)dma_map->k_vaddr,
(unsigned long)dma_map->dma_addr); (unsigned long)dma_map->dma_addr);
if (dma_map->type == GENWQE_MAPPING_RAW) { if (dma_map->type == GENWQE_MAPPING_RAW) {
...@@ -346,6 +346,7 @@ static int genwqe_open(struct inode *inode, struct file *filp) ...@@ -346,6 +346,7 @@ static int genwqe_open(struct inode *inode, struct file *filp)
static int genwqe_fasync(int fd, struct file *filp, int mode) static int genwqe_fasync(int fd, struct file *filp, int mode)
{ {
struct genwqe_file *cdev = (struct genwqe_file *)filp->private_data; struct genwqe_file *cdev = (struct genwqe_file *)filp->private_data;
return fasync_helper(fd, filp, mode, &cdev->async_queue); return fasync_helper(fd, filp, mode, &cdev->async_queue);
} }
...@@ -515,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile, ...@@ -515,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile,
u32 crc; u32 crc;
u8 cmdopts; u8 cmdopts;
struct genwqe_dev *cd = cfile->cd; struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev; struct pci_dev *pci_dev = cd->pci_dev;
if ((load->size & 0x3) != 0) if ((load->size & 0x3) != 0)
...@@ -609,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile, ...@@ -609,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile,
/* For Genwqe5 we get back the calculated CRC */ /* For Genwqe5 we get back the calculated CRC */
*(u64 *)&req->asv[0] = 0ULL; /* 0x80 */ *(u64 *)&req->asv[0] = 0ULL; /* 0x80 */
rc = __genwqe_execute_raw_ddcb(cd, req); rc = __genwqe_execute_raw_ddcb(cd, req, filp->f_flags);
load->retc = req->retc; load->retc = req->retc;
load->attn = req->attn; load->attn = req->attn;
...@@ -649,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile, ...@@ -649,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile,
u8 *xbuf; u8 *xbuf;
u8 cmdopts; u8 cmdopts;
struct genwqe_dev *cd = cfile->cd; struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev; struct pci_dev *pci_dev = cd->pci_dev;
struct genwqe_ddcb_cmd *cmd; struct genwqe_ddcb_cmd *cmd;
...@@ -726,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile, ...@@ -726,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile,
/* we only get back the calculated CRC */ /* we only get back the calculated CRC */
*(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */ *(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */
rc = __genwqe_execute_raw_ddcb(cd, cmd); rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
load->retc = cmd->retc; load->retc = cmd->retc;
load->attn = cmd->attn; load->attn = cmd->attn;
...@@ -987,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile, ...@@ -987,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile,
{ {
int rc; int rc;
struct genwqe_dev *cd = cfile->cd; struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd); struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
rc = ddcb_cmd_fixups(cfile, req); rc = ddcb_cmd_fixups(cfile, req);
if (rc != 0) if (rc != 0)
return rc; return rc;
rc = __genwqe_execute_raw_ddcb(cd, cmd); rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
ddcb_cmd_cleanup(cfile, req); ddcb_cmd_cleanup(cfile, req);
return rc; return rc;
} }
...@@ -1005,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile, ...@@ -1005,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
struct genwqe_ddcb_cmd *cmd; struct genwqe_ddcb_cmd *cmd;
struct ddcb_requ *req; struct ddcb_requ *req;
struct genwqe_dev *cd = cfile->cd; struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
cmd = ddcb_requ_alloc(); cmd = ddcb_requ_alloc();
if (cmd == NULL) if (cmd == NULL)
...@@ -1020,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile, ...@@ -1020,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
if (!raw) if (!raw)
rc = genwqe_execute_ddcb(cfile, cmd); rc = genwqe_execute_ddcb(cfile, cmd);
else else
rc = __genwqe_execute_raw_ddcb(cd, cmd); rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
/* Copy back only the modifed fields. Do not copy ASIV /* Copy back only the modifed fields. Do not copy ASIV
back since the copy got modified by the driver. */ back since the copy got modified by the driver. */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -91,13 +91,6 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, ...@@ -91,13 +91,6 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(type);
static ssize_t driver_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", DRV_VERS_STRING);
}
static DEVICE_ATTR_RO(driver);
static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr, static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -256,7 +249,6 @@ static struct attribute *genwqe_attributes[] = { ...@@ -256,7 +249,6 @@ static struct attribute *genwqe_attributes[] = {
&dev_attr_next_bitstream.attr, &dev_attr_next_bitstream.attr,
&dev_attr_curr_bitstream.attr, &dev_attr_curr_bitstream.attr,
&dev_attr_base_clock.attr, &dev_attr_base_clock.attr,
&dev_attr_driver.attr,
&dev_attr_type.attr, &dev_attr_type.attr,
&dev_attr_version.attr, &dev_attr_version.attr,
&dev_attr_appid.attr, &dev_attr_appid.attr,
...@@ -268,7 +260,6 @@ static struct attribute *genwqe_attributes[] = { ...@@ -268,7 +260,6 @@ static struct attribute *genwqe_attributes[] = {
}; };
static struct attribute *genwqe_normal_attributes[] = { static struct attribute *genwqe_normal_attributes[] = {
&dev_attr_driver.attr,
&dev_attr_type.attr, &dev_attr_type.attr,
&dev_attr_version.attr, &dev_attr_version.attr,
&dev_attr_appid.attr, &dev_attr_appid.attr,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -150,6 +150,7 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len) ...@@ -150,6 +150,7 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
memset(app_name, 0, len); memset(app_name, 0, len);
for (i = 0, j = 0; j < min(len, 4); j++) { for (i = 0, j = 0; j < min(len, 4); j++) {
char ch = (char)((app_id >> (24 - j*8)) & 0xff); char ch = (char)((app_id >> (24 - j*8)) & 0xff);
if (ch == ' ') if (ch == ' ')
continue; continue;
app_name[i++] = isprint(ch) ? ch : 'X'; app_name[i++] = isprint(ch) ? ch : 'X';
...@@ -304,8 +305,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, ...@@ -304,8 +305,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE); sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE);
sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE; sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE;
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld " dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
"fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
__func__, user_addr, user_size, sgl->nr_pages, __func__, user_addr, user_size, sgl->nr_pages,
sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size); sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size);
...@@ -662,6 +662,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, ...@@ -662,6 +662,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m,
u8 genwqe_card_type(struct genwqe_dev *cd) u8 genwqe_card_type(struct genwqe_dev *cd)
{ {
u64 card_type = cd->slu_unitcfg; u64 card_type = cd->slu_unitcfg;
return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20); return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com> * Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com> * Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de> * Author: Michael Ruettger <michael@ibmra.de>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/genwqe/genwqe_card.h> #include <linux/genwqe/genwqe_card.h>
#define DRV_VERS_STRING "2.0.21" #define DRV_VERSION "2.0.25"
/* /*
* Static minor number assignement, until we decide/implement * Static minor number assignement, until we decide/implement
......
...@@ -247,3 +247,4 @@ module_spi_driver(lattice_ecp3_driver); ...@@ -247,3 +247,4 @@ module_spi_driver(lattice_ecp3_driver);
MODULE_AUTHOR("Stefan Roese <sr@denx.de>"); MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI"); MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_NAME);
This diff is collapsed.
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/mei_cl_bus.h> #include <linux/mei_cl_bus.h>
#include "mei_dev.h" #include "mei_dev.h"
...@@ -70,7 +69,7 @@ static int mei_cl_device_probe(struct device *dev) ...@@ -70,7 +69,7 @@ static int mei_cl_device_probe(struct device *dev)
dev_dbg(dev, "Device probe\n"); dev_dbg(dev, "Device probe\n");
strncpy(id.name, dev_name(dev), sizeof(id.name)); strlcpy(id.name, dev_name(dev), sizeof(id.name));
return driver->probe(device, &id); return driver->probe(device, &id);
} }
...@@ -147,7 +146,7 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev, ...@@ -147,7 +146,7 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
struct mei_cl *cl; struct mei_cl *cl;
list_for_each_entry(cl, &dev->device_list, device_link) { list_for_each_entry(cl, &dev->device_list, device_link) {
if (!uuid_le_cmp(uuid, cl->device_uuid)) if (!uuid_le_cmp(uuid, cl->cl_uuid))
return cl; return cl;
} }
...@@ -172,7 +171,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, ...@@ -172,7 +171,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
device->cl = cl; device->cl = cl;
device->ops = ops; device->ops = ops;
device->dev.parent = &dev->pdev->dev; device->dev.parent = dev->dev;
device->dev.bus = &mei_cl_bus_type; device->dev.bus = &mei_cl_bus_type;
device->dev.type = &mei_cl_device_type; device->dev.type = &mei_cl_device_type;
...@@ -180,7 +179,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, ...@@ -180,7 +179,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
status = device_register(&device->dev); status = device_register(&device->dev);
if (status) { if (status) {
dev_err(&dev->pdev->dev, "Failed to register MEI device\n"); dev_err(dev->dev, "Failed to register MEI device\n");
kfree(device); kfree(device);
return NULL; return NULL;
} }
...@@ -229,8 +228,8 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -229,8 +228,8 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking) bool blocking)
{ {
struct mei_device *dev; struct mei_device *dev;
struct mei_me_client *me_cl;
struct mei_cl_cb *cb; struct mei_cl_cb *cb;
int id;
int rets; int rets;
if (WARN_ON(!cl || !cl->dev)) if (WARN_ON(!cl || !cl->dev))
...@@ -242,11 +241,11 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -242,11 +241,11 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
return -ENODEV; return -ENODEV;
/* Check if we have an ME client device */ /* Check if we have an ME client device */
id = mei_me_cl_by_id(dev, cl->me_client_id); me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (id < 0) if (!me_cl)
return id; return -ENOTTY;
if (length > dev->me_clients[id].props.max_msg_length) if (length > me_cl->props.max_msg_length)
return -EFBIG; return -EFBIG;
cb = mei_io_cb_init(cl, NULL); cb = mei_io_cb_init(cl, NULL);
...@@ -430,7 +429,7 @@ int mei_cl_enable_device(struct mei_cl_device *device) ...@@ -430,7 +429,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
err = mei_cl_connect(cl, NULL); err = mei_cl_connect(cl, NULL);
if (err < 0) { if (err < 0) {
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, "Could not connect to the ME client"); dev_err(dev->dev, "Could not connect to the ME client");
return err; return err;
} }
...@@ -462,7 +461,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) ...@@ -462,7 +461,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
if (cl->state != MEI_FILE_CONNECTED) { if (cl->state != MEI_FILE_CONNECTED) {
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, "Already disconnected"); dev_err(dev->dev, "Already disconnected");
return 0; return 0;
} }
...@@ -472,7 +471,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) ...@@ -472,7 +471,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
err = mei_cl_disconnect(cl); err = mei_cl_disconnect(cl);
if (err < 0) { if (err < 0) {
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, dev_err(dev->dev,
"Could not disconnect from the ME client"); "Could not disconnect from the ME client");
return err; return err;
......
This diff is collapsed.
...@@ -24,8 +24,15 @@ ...@@ -24,8 +24,15 @@
#include "mei_dev.h" #include "mei_dev.h"
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); const uuid_le *cuuid);
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
const uuid_le *uuid, u8 client_id);
void mei_me_cl_remove(struct mei_device *dev,
const uuid_le *uuid, u8 client_id);
/* /*
* MEI IO Functions * MEI IO Functions
...@@ -45,6 +52,8 @@ static inline void mei_io_list_init(struct mei_cl_cb *list) ...@@ -45,6 +52,8 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{ {
INIT_LIST_HEAD(&list->list); INIT_LIST_HEAD(&list->list);
} }
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
/* /*
* MEI Host Client Functions * MEI Host Client Functions
*/ */
...@@ -101,9 +110,9 @@ void mei_cl_all_write_clear(struct mei_device *dev); ...@@ -101,9 +110,9 @@ void mei_cl_all_write_clear(struct mei_device *dev);
#define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id #define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id
#define cl_dbg(dev, cl, format, arg...) \ #define cl_dbg(dev, cl, format, arg...) \
dev_dbg(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
#define cl_err(dev, cl, format, arg...) \ #define cl_err(dev, cl, format, arg...) \
dev_err(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
#endif /* _MEI_CLIENT_H_ */ #endif /* _MEI_CLIENT_H_ */
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/mei.h> #include <linux/mei.h>
...@@ -28,39 +27,47 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, ...@@ -28,39 +27,47 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos) size_t cnt, loff_t *ppos)
{ {
struct mei_device *dev = fp->private_data; struct mei_device *dev = fp->private_data;
struct mei_me_client *cl; struct mei_me_client *me_cl;
const size_t bufsz = 1024; size_t bufsz = 1;
char *buf = kzalloc(bufsz, GFP_KERNEL); char *buf;
int i; int i = 0;
int pos = 0; int pos = 0;
int ret; int ret;
if (!buf) #define HDR " |id|addr| UUID |con|msg len|sb|\n"
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos,
" |id|addr| UUID |con|msg len|\n");
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
list_for_each_entry(me_cl, &dev->me_clients, list)
bufsz++;
bufsz *= sizeof(HDR) + 1;
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
mutex_unlock(&dev->device_lock);
return -ENOMEM;
}
pos += scnprintf(buf + pos, bufsz - pos, HDR);
/* if the driver is not enabled the list won't be consistent */ /* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED) if (dev->dev_state != MEI_DEV_ENABLED)
goto out; goto out;
for (i = 0; i < dev->me_clients_num; i++) { list_for_each_entry(me_cl, &dev->me_clients, list) {
cl = &dev->me_clients[i];
/* skip me clients that cannot be connected */ /* skip me clients that cannot be connected */
if (cl->props.max_number_of_connections == 0) if (me_cl->props.max_number_of_connections == 0)
continue; continue;
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"%2d|%2d|%4d|%pUl|%3d|%7d|\n", "%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n",
i, cl->client_id, i++, me_cl->client_id,
cl->props.fixed_address, me_cl->props.fixed_address,
&cl->props.protocol_name, &me_cl->props.protocol_name,
cl->props.max_number_of_connections, me_cl->props.max_number_of_connections,
cl->props.max_msg_length); me_cl->props.max_msg_length,
me_cl->props.single_recv_buf);
} }
out: out:
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
...@@ -98,7 +105,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, ...@@ -98,7 +105,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
/* if the driver is not enabled the list won't b consitent */ /* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED) if (dev->dev_state != MEI_DEV_ENABLED)
goto out; goto out;
...@@ -135,8 +142,13 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, ...@@ -135,8 +142,13 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "%s\n", pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",
mei_dev_state_str(dev->dev_state)); mei_dev_state_str(dev->dev_state));
pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
mei_hbm_state_str(dev->hbm_state));
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
mei_pg_state_str(mei_pg_state(dev)));
ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
kfree(buf); kfree(buf);
return ret; return ret;
...@@ -149,7 +161,8 @@ static const struct file_operations mei_dbgfs_fops_devstate = { ...@@ -149,7 +161,8 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
/** /**
* mei_dbgfs_deregister - Remove the debugfs files and directories * mei_dbgfs_deregister - Remove the debugfs files and directories
* @mei - pointer to mei device private data *
* @dev: the mei device structure
*/ */
void mei_dbgfs_deregister(struct mei_device *dev) void mei_dbgfs_deregister(struct mei_device *dev)
{ {
...@@ -160,12 +173,17 @@ void mei_dbgfs_deregister(struct mei_device *dev) ...@@ -160,12 +173,17 @@ void mei_dbgfs_deregister(struct mei_device *dev)
} }
/** /**
* Add the debugfs files * mei_dbgfs_register - Add the debugfs files
* *
* @dev: the mei device structure
* @name: the mei device name
*
* Return: 0 on success, <0 on failure.
*/ */
int mei_dbgfs_register(struct mei_device *dev, const char *name) int mei_dbgfs_register(struct mei_device *dev, const char *name)
{ {
struct dentry *dir, *f; struct dentry *dir, *f;
dir = debugfs_create_dir(name, NULL); dir = debugfs_create_dir(name, NULL);
if (!dir) if (!dir)
return -ENOMEM; return -ENOMEM;
...@@ -173,19 +191,19 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name) ...@@ -173,19 +191,19 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
f = debugfs_create_file("meclients", S_IRUSR, dir, f = debugfs_create_file("meclients", S_IRUSR, dir,
dev, &mei_dbgfs_fops_meclients); dev, &mei_dbgfs_fops_meclients);
if (!f) { if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n"); dev_err(dev->dev, "meclients: registration failed\n");
goto err; goto err;
} }
f = debugfs_create_file("active", S_IRUSR, dir, f = debugfs_create_file("active", S_IRUSR, dir,
dev, &mei_dbgfs_fops_active); dev, &mei_dbgfs_fops_active);
if (!f) { if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n"); dev_err(dev->dev, "meclients: registration failed\n");
goto err; goto err;
} }
f = debugfs_create_file("devstate", S_IRUSR, dir, f = debugfs_create_file("devstate", S_IRUSR, dir,
dev, &mei_dbgfs_fops_devstate); dev, &mei_dbgfs_fops_devstate);
if (!f) { if (!f) {
dev_err(&dev->pdev->dev, "devstate: registration failed\n"); dev_err(dev->dev, "devstate: registration failed\n");
goto err; goto err;
} }
dev->dbgfs_dir = dir; dev->dbgfs_dir = dir;
......
This diff is collapsed.
...@@ -25,29 +25,24 @@ struct mei_cl; ...@@ -25,29 +25,24 @@ struct mei_cl;
* enum mei_hbm_state - host bus message protocol state * enum mei_hbm_state - host bus message protocol state
* *
* @MEI_HBM_IDLE : protocol not started * @MEI_HBM_IDLE : protocol not started
* @MEI_HBM_START : start request message was sent * @MEI_HBM_STARTING : start request message was sent
* @MEI_HBM_STARTED : start reply message was received
* @MEI_HBM_ENUM_CLIENTS : enumeration request was sent * @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
* @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties * @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
* @MEI_HBM_STOPPED : stopping exchange
*/ */
enum mei_hbm_state { enum mei_hbm_state {
MEI_HBM_IDLE = 0, MEI_HBM_IDLE = 0,
MEI_HBM_START, MEI_HBM_STARTING,
MEI_HBM_STARTED, MEI_HBM_STARTED,
MEI_HBM_ENUM_CLIENTS, MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES, MEI_HBM_CLIENT_PROPERTIES,
MEI_HBM_STOPPED, MEI_HBM_STOPPED,
}; };
int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); const char *mei_hbm_state_str(enum mei_hbm_state state);
static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
{
hdr->host_addr = 0;
hdr->me_addr = 0;
hdr->length = length;
hdr->msg_complete = 1;
hdr->reserved = 0;
}
void mei_hbm_idle(struct mei_device *dev); void mei_hbm_idle(struct mei_device *dev);
void mei_hbm_reset(struct mei_device *dev); void mei_hbm_reset(struct mei_device *dev);
......
This diff is collapsed.
...@@ -19,14 +19,44 @@ ...@@ -19,14 +19,44 @@
#ifndef _MEI_INTERFACE_H_ #ifndef _MEI_INTERFACE_H_
#define _MEI_INTERFACE_H_ #define _MEI_INTERFACE_H_
#include <linux/mei.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/pci.h>
#include <linux/mei.h>
#include "mei_dev.h" #include "mei_dev.h"
#include "client.h" #include "client.h"
/*
* mei_cfg - mei device configuration
*
* @fw_status: FW status
* @quirk_probe: device exclusion quirk
*/
struct mei_cfg {
const struct mei_fw_status fw_status;
bool (*quirk_probe)(struct pci_dev *pdev);
};
#define MEI_PCI_DEVICE(dev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
.driver_data = (kernel_ulong_t)&(cfg)
#define MEI_ME_RPM_TIMEOUT 500 /* ms */ #define MEI_ME_RPM_TIMEOUT 500 /* ms */
/**
* struct mei_me_hw - me hw specific data
*
* @cfg: per device generation config and ops
* @mem_addr: io memory address
* @host_hw_state: cached host state
* @me_hw_state: cached me (fw) state
* @pg_state: power gating state
*/
struct mei_me_hw { struct mei_me_hw {
const struct mei_cfg *cfg;
void __iomem *mem_addr; void __iomem *mem_addr;
/* /*
* hw states of host and fw(ME) * hw states of host and fw(ME)
......
This diff is collapsed.
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
* @mem_addr: SeC and BRIDGE bars * @mem_addr: SeC and BRIDGE bars
* @aliveness: aliveness (power gating) state of the hardware * @aliveness: aliveness (power gating) state of the hardware
* @readiness: readiness state of the hardware * @readiness: readiness state of the hardware
* @slots: number of empty slots
* @wait_aliveness_resp: aliveness wait queue * @wait_aliveness_resp: aliveness wait queue
* @intr_cause: translated interrupt cause * @intr_cause: translated interrupt cause
*/ */
...@@ -61,10 +62,7 @@ static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw) ...@@ -61,10 +62,7 @@ static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
return container_of((void *)hw, struct mei_device, hw); return container_of((void *)hw, struct mei_device, hw);
} }
extern const struct mei_cfg mei_txe_cfg; struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg);
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id); irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id); irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);
......
...@@ -97,23 +97,52 @@ enum mei_stop_reason_types { ...@@ -97,23 +97,52 @@ enum mei_stop_reason_types {
SYSTEM_S5_ENTRY = 0x08 SYSTEM_S5_ENTRY = 0x08
}; };
/**
* enum mei_hbm_status - mei host bus messages return values
*
* @MEI_HBMS_SUCCESS : status success
* @MEI_HBMS_CLIENT_NOT_FOUND : client not found
* @MEI_HBMS_ALREADY_EXISTS : connection already established
* @MEI_HBMS_REJECTED : connection is rejected
* @MEI_HBMS_INVALID_PARAMETER : invalid parameter
* @MEI_HBMS_NOT_ALLOWED : operation not allowed
* @MEI_HBMS_ALREADY_STARTED : system is already started
* @MEI_HBMS_NOT_STARTED : system not started
*
* @MEI_HBMS_MAX : sentinel
*/
enum mei_hbm_status {
MEI_HBMS_SUCCESS = 0,
MEI_HBMS_CLIENT_NOT_FOUND = 1,
MEI_HBMS_ALREADY_EXISTS = 2,
MEI_HBMS_REJECTED = 3,
MEI_HBMS_INVALID_PARAMETER = 4,
MEI_HBMS_NOT_ALLOWED = 5,
MEI_HBMS_ALREADY_STARTED = 6,
MEI_HBMS_NOT_STARTED = 7,
MEI_HBMS_MAX
};
/* /*
* Client Connect Status * Client Connect Status
* used by hbm_client_connect_response.status * used by hbm_client_connect_response.status
*/ */
enum mei_cl_connect_status { enum mei_cl_connect_status {
MEI_CL_CONN_SUCCESS = 0x00, MEI_CL_CONN_SUCCESS = MEI_HBMS_SUCCESS,
MEI_CL_CONN_NOT_FOUND = 0x01, MEI_CL_CONN_NOT_FOUND = MEI_HBMS_CLIENT_NOT_FOUND,
MEI_CL_CONN_ALREADY_STARTED = 0x02, MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS,
MEI_CL_CONN_OUT_OF_RESOURCES = 0x03, MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED,
MEI_CL_CONN_MESSAGE_SMALL = 0x04 MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER,
}; };
/* /*
* Client Disconnect Status * Client Disconnect Status
*/ */
enum mei_cl_disconnect_status { enum mei_cl_disconnect_status {
MEI_CL_DISCONN_SUCCESS = 0x00 MEI_CL_DISCONN_SUCCESS = MEI_HBMS_SUCCESS
}; };
/* /*
...@@ -138,10 +167,10 @@ struct mei_bus_message { ...@@ -138,10 +167,10 @@ struct mei_bus_message {
* struct hbm_cl_cmd - client specific host bus command * struct hbm_cl_cmd - client specific host bus command
* CONNECT, DISCONNECT, and FlOW CONTROL * CONNECT, DISCONNECT, and FlOW CONTROL
* *
* @hbm_cmd - bus message command header * @hbm_cmd: bus message command header
* @me_addr - address of the client in ME * @me_addr: address of the client in ME
* @host_addr - address of the client in the driver * @host_addr: address of the client in the driver
* @data * @data: generic data
*/ */
struct mei_hbm_cl_cmd { struct mei_hbm_cl_cmd {
u8 hbm_cmd; u8 hbm_cmd;
...@@ -206,14 +235,13 @@ struct mei_client_properties { ...@@ -206,14 +235,13 @@ struct mei_client_properties {
struct hbm_props_request { struct hbm_props_request {
u8 hbm_cmd; u8 hbm_cmd;
u8 address; u8 me_addr;
u8 reserved[2]; u8 reserved[2];
} __packed; } __packed;
struct hbm_props_response { struct hbm_props_response {
u8 hbm_cmd; u8 hbm_cmd;
u8 address; u8 me_addr;
u8 status; u8 status;
u8 reserved[1]; u8 reserved[1];
struct mei_client_properties client_properties; struct mei_client_properties client_properties;
...@@ -222,8 +250,8 @@ struct hbm_props_response { ...@@ -222,8 +250,8 @@ struct hbm_props_response {
/** /**
* struct hbm_power_gate - power gate request/response * struct hbm_power_gate - power gate request/response
* *
* @hbm_cmd - bus message command header * @hbm_cmd: bus message command header
* @reserved[3] * @reserved: reserved
*/ */
struct hbm_power_gate { struct hbm_power_gate {
u8 hbm_cmd; u8 hbm_cmd;
...@@ -233,10 +261,10 @@ struct hbm_power_gate { ...@@ -233,10 +261,10 @@ struct hbm_power_gate {
/** /**
* struct hbm_client_connect_request - connect/disconnect request * struct hbm_client_connect_request - connect/disconnect request
* *
* @hbm_cmd - bus message command header * @hbm_cmd: bus message command header
* @me_addr - address of the client in ME * @me_addr: address of the client in ME
* @host_addr - address of the client in the driver * @host_addr: address of the client in the driver
* @reserved * @reserved: reserved
*/ */
struct hbm_client_connect_request { struct hbm_client_connect_request {
u8 hbm_cmd; u8 hbm_cmd;
...@@ -248,10 +276,10 @@ struct hbm_client_connect_request { ...@@ -248,10 +276,10 @@ struct hbm_client_connect_request {
/** /**
* struct hbm_client_connect_response - connect/disconnect response * struct hbm_client_connect_response - connect/disconnect response
* *
* @hbm_cmd - bus message command header * @hbm_cmd: bus message command header
* @me_addr - address of the client in ME * @me_addr: address of the client in ME
* @host_addr - address of the client in the driver * @host_addr: address of the client in the driver
* @status - status of the request * @status: status of the request
*/ */
struct hbm_client_connect_response { struct hbm_client_connect_response {
u8 hbm_cmd; u8 hbm_cmd;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -98,12 +98,12 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev) {} ...@@ -98,12 +98,12 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev) {}
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
/** /**
* mei_quirk_probe - probe for devices that doesn't valid ME interface * mei_me_quirk_probe - probe for devices that doesn't valid ME interface
* *
* @pdev: PCI device structure * @pdev: PCI device structure
* @cfg: per generation config * @cfg: per generation config
* *
* returns true if ME Interface is valid, false otherwise * Return: true if ME Interface is valid, false otherwise
*/ */
static bool mei_me_quirk_probe(struct pci_dev *pdev, static bool mei_me_quirk_probe(struct pci_dev *pdev,
const struct mei_cfg *cfg) const struct mei_cfg *cfg)
...@@ -117,12 +117,12 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev, ...@@ -117,12 +117,12 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev,
} }
/** /**
* mei_probe - Device Initialization Routine * mei_me_probe - Device Initialization Routine
* *
* @pdev: PCI device structure * @pdev: PCI device structure
* @ent: entry in kcs_pci_tbl * @ent: entry in kcs_pci_tbl
* *
* returns 0 on success, <0 on failure. * Return: 0 on success, <0 on failure.
*/ */
static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
...@@ -249,7 +249,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -249,7 +249,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
/** /**
* mei_remove - Device Removal Routine * mei_me_remove - Device Removal Routine
* *
* @pdev: PCI device structure * @pdev: PCI device structure
* *
...@@ -430,7 +430,7 @@ static int mei_me_pm_runtime_resume(struct device *device) ...@@ -430,7 +430,7 @@ static int mei_me_pm_runtime_resume(struct device *device)
*/ */
static inline void mei_me_set_pm_domain(struct mei_device *dev) static inline void mei_me_set_pm_domain(struct mei_device *dev)
{ {
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && pdev->dev.bus->pm) { if (pdev->dev.bus && pdev->dev.bus->pm) {
dev->pg_domain.ops = *pdev->dev.bus->pm; dev->pg_domain.ops = *pdev->dev.bus->pm;
...@@ -451,7 +451,7 @@ static inline void mei_me_set_pm_domain(struct mei_device *dev) ...@@ -451,7 +451,7 @@ static inline void mei_me_set_pm_domain(struct mei_device *dev)
static inline void mei_me_unset_pm_domain(struct mei_device *dev) static inline void mei_me_unset_pm_domain(struct mei_device *dev)
{ {
/* stop using pm callbacks if any */ /* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL; dev->dev->pm_domain = NULL;
} }
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
#include "hw-txe.h" #include "hw-txe.h"
static const struct pci_device_id mei_txe_pci_tbl[] = { static const struct pci_device_id mei_txe_pci_tbl[] = {
{MEI_PCI_DEVICE(0x0F18, mei_txe_cfg)}, /* Baytrail */ {PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */
{0, } {0, }
}; };
MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
...@@ -52,6 +53,7 @@ static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} ...@@ -52,6 +53,7 @@ static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {}
static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
{ {
int i; int i;
for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
if (hw->mem_addr[i]) { if (hw->mem_addr[i]) {
pci_iounmap(pdev, hw->mem_addr[i]); pci_iounmap(pdev, hw->mem_addr[i]);
...@@ -65,11 +67,10 @@ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) ...@@ -65,11 +67,10 @@ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
* @pdev: PCI device structure * @pdev: PCI device structure
* @ent: entry in mei_txe_pci_tbl * @ent: entry in mei_txe_pci_tbl
* *
* returns 0 on success, <0 on failure. * Return: 0 on success, <0 on failure.
*/ */
static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data);
struct mei_device *dev; struct mei_device *dev;
struct mei_txe_hw *hw; struct mei_txe_hw *hw;
int err; int err;
...@@ -100,7 +101,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -100,7 +101,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
/* allocates and initializes the mei dev structure */ /* allocates and initializes the mei dev structure */
dev = mei_txe_dev_init(pdev, cfg); dev = mei_txe_dev_init(pdev);
if (!dev) { if (!dev) {
err = -ENOMEM; err = -ENOMEM;
goto release_regions; goto release_regions;
...@@ -377,7 +378,7 @@ static int mei_txe_pm_runtime_resume(struct device *device) ...@@ -377,7 +378,7 @@ static int mei_txe_pm_runtime_resume(struct device *device)
*/ */
static inline void mei_txe_set_pm_domain(struct mei_device *dev) static inline void mei_txe_set_pm_domain(struct mei_device *dev)
{ {
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && pdev->dev.bus->pm) { if (pdev->dev.bus && pdev->dev.bus->pm) {
dev->pg_domain.ops = *pdev->dev.bus->pm; dev->pg_domain.ops = *pdev->dev.bus->pm;
...@@ -398,7 +399,7 @@ static inline void mei_txe_set_pm_domain(struct mei_device *dev) ...@@ -398,7 +399,7 @@ static inline void mei_txe_set_pm_domain(struct mei_device *dev)
static inline void mei_txe_unset_pm_domain(struct mei_device *dev) static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
{ {
/* stop using pm callbacks if any */ /* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL; dev->dev->pm_domain = NULL;
} }
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
......
This diff is collapsed.
This diff is collapsed.
...@@ -153,8 +153,9 @@ static void st_reg_complete(struct st_data_s *st_gdata, char err) ...@@ -153,8 +153,9 @@ static void st_reg_complete(struct st_data_s *st_gdata, char err)
(st_gdata->list[i]->priv_data, err); (st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err); pr_info("protocol %d's cb sent %d\n", i, err);
if (err) { /* cleanup registered protocol */ if (err) { /* cleanup registered protocol */
st_gdata->protos_registered--;
st_gdata->is_registered[i] = false; st_gdata->is_registered[i] = false;
if (st_gdata->protos_registered)
st_gdata->protos_registered--;
} }
} }
} }
...@@ -639,14 +640,12 @@ long st_unregister(struct st_proto_s *proto) ...@@ -639,14 +640,12 @@ long st_unregister(struct st_proto_s *proto)
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
if (st_gdata->protos_registered)
st_gdata->protos_registered--; st_gdata->protos_registered--;
remove_channel_from_table(st_gdata, proto); remove_channel_from_table(st_gdata, proto);
spin_unlock_irqrestore(&st_gdata->lock, flags); spin_unlock_irqrestore(&st_gdata->lock, flags);
/* paranoid check */
if (st_gdata->protos_registered < ST_EMPTY)
st_gdata->protos_registered = ST_EMPTY;
if ((st_gdata->protos_registered == ST_EMPTY) && if ((st_gdata->protos_registered == ST_EMPTY) &&
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_info(" all chnl_ids unregistered "); pr_info(" all chnl_ids unregistered ");
......
...@@ -328,7 +328,8 @@ int vmci_datagram_dispatch(u32 context_id, ...@@ -328,7 +328,8 @@ int vmci_datagram_dispatch(u32 context_id,
BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24); BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24);
if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) { if (dg->payload_size > VMCI_MAX_DG_SIZE ||
VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
pr_devel("Payload (size=%llu bytes) too big to send\n", pr_devel("Payload (size=%llu bytes) too big to send\n",
(unsigned long long)dg->payload_size); (unsigned long long)dg->payload_size);
return VMCI_ERROR_INVALID_ARGS; return VMCI_ERROR_INVALID_ARGS;
......
This diff is collapsed.
...@@ -34,8 +34,10 @@ ...@@ -34,8 +34,10 @@
* @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW). * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
* @state_on: print_state is overriden with state_on if attached. * @state_on: print_state is overriden with state_on if attached.
* If NULL, default method of extcon class is used. * If NULL, default method of extcon class is used.
* @state_off: print_state is overriden with state_on if detached. * @state_off: print_state is overriden with state_off if detached.
* If NUll, default method of extcon class is used. * If NUll, default method of extcon class is used.
* @check_on_resume: Boolean describing whether to check the state of gpio
* while resuming from sleep.
* *
* Note that in order for state_on or state_off to be valid, both state_on * Note that in order for state_on or state_off to be valid, both state_on
* and state_off should be not NULL. If at least one of them is NULL, * and state_off should be not NULL. If at least one of them is NULL,
......
...@@ -172,6 +172,7 @@ struct ipack_bus_ops { ...@@ -172,6 +172,7 @@ struct ipack_bus_ops {
* @ops: bus operations for the mezzanine drivers * @ops: bus operations for the mezzanine drivers
*/ */
struct ipack_bus_device { struct ipack_bus_device {
struct module *owner;
struct device *parent; struct device *parent;
int slots; int slots;
int bus_nr; int bus_nr;
...@@ -189,7 +190,8 @@ struct ipack_bus_device { ...@@ -189,7 +190,8 @@ struct ipack_bus_device {
* available bus device in ipack. * available bus device in ipack.
*/ */
struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
const struct ipack_bus_ops *ops); const struct ipack_bus_ops *ops,
struct module *owner);
/** /**
* ipack_bus_unregister -- unregister an ipack bus * ipack_bus_unregister -- unregister an ipack bus
...@@ -265,3 +267,23 @@ void ipack_put_device(struct ipack_device *dev); ...@@ -265,3 +267,23 @@ void ipack_put_device(struct ipack_device *dev);
.format = (_format), \ .format = (_format), \
.vendor = (vend), \ .vendor = (vend), \
.device = (dev) .device = (dev)
/**
* ipack_get_carrier - it increase the carrier ref. counter of
* the carrier module
* @dev: mezzanine device which wants to get the carrier
*/
static inline int ipack_get_carrier(struct ipack_device *dev)
{
return try_module_get(dev->bus->owner);
}
/**
* ipack_get_carrier - it decrease the carrier ref. counter of
* the carrier module
* @dev: mezzanine device which wants to get the carrier
*/
static inline void ipack_put_carrier(struct ipack_device *dev)
{
module_put(dev->bus->owner);
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/uuid.h> #include <linux/uuid.h>
#include <linux/mod_devicetable.h>
struct mei_cl_device; struct mei_cl_device;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment