提交 ef0625b7 编写于 作者: L 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
  ...
* 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.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
xes Extreme Engineering Solutions (X-ES)
xillybus Xillybus Ltd.
xlnx Xilinx
zyxel ZyXEL Communications Corp.
zarlink Zarlink Semiconductor
......@@ -651,6 +651,7 @@ struct i8k_config_data {
enum i8k_configs {
DELL_LATITUDE_D520,
DELL_LATITUDE_E6540,
DELL_PRECISION_490,
DELL_STUDIO,
DELL_XPS_M140,
......@@ -661,6 +662,10 @@ static const struct i8k_config_data i8k_config_data[] = {
.fan_mult = 1,
.fan_max = I8K_FAN_TURBO,
},
[DELL_LATITUDE_E6540] = {
.fan_mult = 1,
.fan_max = I8K_FAN_HIGH,
},
[DELL_PRECISION_490] = {
.fan_mult = 1,
.fan_max = I8K_FAN_TURBO,
......@@ -705,6 +710,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
},
.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",
.matches = {
......
......@@ -843,7 +843,6 @@ static struct platform_driver hwicap_platform_driver = {
.probe = hwicap_drv_probe,
.remove = hwicap_drv_remove,
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
.of_match_table = hwicap_of_match,
},
......
......@@ -70,8 +70,21 @@ config EXTCON_PALMAS
Say Y here to enable support for USB peripheral and USB host
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
tristate "SM5502 EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
select REGMAP_IRQ
......
......@@ -10,4 +10,5 @@ obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o
obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
......@@ -20,16 +20,16 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/extcon.h>
#include <linux/extcon/extcon-gpio.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/extcon.h>
#include <linux/extcon/extcon-gpio.h>
struct gpio_extcon_data {
struct extcon_dev *edev;
......
......@@ -255,10 +255,14 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
case ADC_DEBOUNCE_TIME_10MS:
case ADC_DEBOUNCE_TIME_25MS:
case ADC_DEBOUNCE_TIME_38_62MS:
ret = regmap_update_bits(info->max77693->regmap_muic,
MAX77693_MUIC_REG_CTRL3,
CONTROL3_ADCDBSET_MASK,
time << CONTROL3_ADCDBSET_SHIFT);
/*
* 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,
time << CONTROL3_ADCDBSET_SHIFT);
if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
return ret;
......@@ -1155,13 +1159,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq);
if (!virq) {
ret = -EINVAL;
goto err_irq;
}
if (!virq)
return -EINVAL;
muic_irq->virq = virq;
ret = request_threaded_irq(virq, NULL,
ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
max77693_muic_irq_handler,
IRQF_NO_SUSPEND,
muic_irq->name, info);
......@@ -1170,7 +1172,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
"failed: irq request (IRQ: %d,"
" error :%d)\n",
muic_irq->irq, ret);
goto err_irq;
return ret;
}
}
......@@ -1179,15 +1181,14 @@ static int max77693_muic_probe(struct platform_device *pdev)
max77693_extcon_cable);
if (IS_ERR(info->edev)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
ret = -ENOMEM;
goto err_irq;
return -ENOMEM;
}
info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
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 */
......@@ -1265,7 +1266,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
MAX77693_MUIC_REG_ID, &id);
if (ret < 0) {
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);
......@@ -1285,20 +1286,12 @@ static int max77693_muic_probe(struct platform_device *pdev)
delay_jiffies);
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)
{
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);
input_unregister_device(info->dock);
......
此差异已折叠。
/*
* 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 @@
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
......@@ -26,7 +20,8 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/extcon.h>
#include <linux/extcon/sm5502.h>
#include "extcon-sm5502.h"
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
......@@ -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
* 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)
return SM5502_MUIC_ADC_GROUND;
......@@ -395,7 +390,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
/* Get the type of attached or detached cable */
if (attached)
cable_type = sm5502_muic_get_cable_type(info);
else if (!attached)
else
cable_type = prev_cable_type;
prev_cable_type = cable_type;
......@@ -457,8 +452,6 @@ static void sm5502_muic_irq_work(struct work_struct *work)
dev_err(info->dev, "failed to handle MUIC interrupt\n");
mutex_unlock(&info->mutex);
return;
}
/*
......@@ -617,8 +610,9 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
IRQF_NO_SUSPEND,
muic_irq->name, info);
if (ret) {
dev_err(info->dev, "failed: irq request (IRQ: %d,"
" error :%d)\n", muic_irq->irq, ret);
dev_err(info->dev,
"failed: irq request (IRQ: %d, error :%d)\n",
muic_irq->irq, ret);
return ret;
}
}
......
......@@ -7,11 +7,6 @@
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LINUX_EXTCON_SM5502_H
......
......@@ -165,8 +165,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
ret = vmbus_post_msg(open_msg,
sizeof(struct vmbus_channel_open_channel));
if (ret != 0)
if (ret != 0) {
err = ret;
goto error1;
}
t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
if (t == 0) {
......@@ -363,7 +365,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
u32 next_gpadl_handle;
unsigned long flags;
int ret = 0;
int t;
next_gpadl_handle = atomic_read(&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,
}
}
t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
BUG_ON(t == 0);
wait_for_completion(&msginfo->waitevent);
/* At this point, we received the gpadl created msg */
*gpadl_handle = gpadlmsg->gpadl;
......@@ -435,7 +434,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
struct vmbus_channel_gpadl_teardown *msg;
struct vmbus_channel_msginfo *info;
unsigned long flags;
int ret, t;
int ret;
info = kmalloc(sizeof(*info) +
sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
......@@ -457,11 +456,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_gpadl_teardown));
BUG_ON(ret != 0);
t = wait_for_completion_timeout(&info->waitevent, 5*HZ);
BUG_ON(t == 0);
if (ret)
goto post_msg_err;
wait_for_completion(&info->waitevent);
/* Received a torndown response */
post_msg_err:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
......@@ -478,7 +478,7 @@ static void reset_channel_cb(void *arg)
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;
int ret;
......@@ -486,11 +486,14 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* 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,
channel, true);
else
} else {
reset_channel_cb(channel);
put_cpu();
}
/* Send a closing message */
......@@ -501,11 +504,28 @@ static void vmbus_close_internal(struct vmbus_channel *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 */
if (channel->ringbuffer_gpadlhandle)
vmbus_teardown_gpadl(channel,
channel->ringbuffer_gpadlhandle);
if (channel->ringbuffer_gpadlhandle) {
ret = vmbus_teardown_gpadl(channel,
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 */
hv_ringbuffer_cleanup(&channel->outbound);
......@@ -514,7 +534,7 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
return ret;
}
/*
......
......@@ -224,11 +224,14 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
msg.header.msgtype = CHANNELMSG_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,
percpu_channel_deq, channel, true);
else
} else {
percpu_channel_deq(channel);
put_cpu();
}
if (channel->primary_channel == NULL) {
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
......@@ -294,12 +297,15 @@ static void vmbus_process_offer(struct work_struct *work)
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
if (enq) {
if (newchannel->target_cpu != smp_processor_id())
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq,
newchannel, true);
else
} else {
percpu_channel_enq(newchannel);
put_cpu();
}
}
if (!fnew) {
/*
......@@ -314,12 +320,15 @@ static void vmbus_process_offer(struct work_struct *work)
list_add_tail(&newchannel->sc_list, &channel->sc_list);
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,
percpu_channel_enq,
newchannel, true);
else
} else {
percpu_channel_enq(newchannel);
put_cpu();
}
newchannel->state = CHANNEL_OPEN_STATE;
if (channel->sc_creation_callback != NULL)
......
......@@ -427,10 +427,21 @@ int vmbus_post_msg(void *buffer, size_t buflen)
* insufficient resources. Retry the operation a couple of
* times before giving up.
*/
while (retries < 3) {
ret = hv_post_message(conn_id, 1, buffer, buflen);
if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
while (retries < 10) {
ret = hv_post_message(conn_id, 1, buffer, buflen);
switch (ret) {
case HV_STATUS_INSUFFICIENT_BUFFERS:
ret = -ENOMEM;
case -ENOMEM:
break;
case HV_STATUS_SUCCESS:
return ret;
default:
pr_err("hv_post_msg() failed; error code:%d\n", ret);
return -EINVAL;
}
retries++;
msleep(100);
}
......
......@@ -138,6 +138,8 @@ int hv_init(void)
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
sizeof(void *) * NR_CPUS);
memset(hv_context.post_msg_page, 0,
sizeof(void *) * NR_CPUS);
memset(hv_context.vp_index, 0,
sizeof(int) * NR_CPUS);
memset(hv_context.event_dpc, 0,
......@@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size)
{
struct aligned_input {
u64 alignment8;
struct hv_input_post_message msg;
};
struct hv_input_post_message *aligned_msg;
u16 status;
unsigned long addr;
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
return -EMSGSIZE;
addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
if (!addr)
return -ENOMEM;
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->reserved = 0;
aligned_msg->message_type = message_type;
aligned_msg->payload_size = payload_size;
memcpy((void *)aligned_msg->payload, payload, payload_size);
......@@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_id connection_id,
status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
& 0xFFFF;
kfree((void *)addr);
put_cpu();
return status;
}
......@@ -294,6 +287,14 @@ int hv_synic_alloc(void)
pr_err("Unable to allocate SYNIC event page\n");
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;
......@@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu)
free_page((unsigned long)hv_context.synic_event_page[cpu]);
if (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)
......
......@@ -515,6 +515,10 @@ struct hv_context {
* per-cpu list of the channels based on their CPU affinity.
*/
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;
......
......@@ -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->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_datasize = buflen - sizeof(struct hv_ring_buffer);
......
......@@ -572,7 +572,8 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
/* Register the carrier in the industry pack bus driver */
tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
TPCI200_NB_SLOT,
&tpci200_bus_ops);
&tpci200_bus_ops,
THIS_MODULE);
if (!tpci200->info->ipack_bus) {
dev_err(&pdev->dev,
"error registering the carrier on ipack driver\n");
......
......@@ -55,6 +55,22 @@ struct ipoctal {
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)
{
struct ipoctal_channel *channel;
......@@ -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)
{
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;
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)
......@@ -151,7 +175,6 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
flag = TTY_FRAME;
}
if (sr & SR_RECEIVED_BREAK) {
iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
channel->stats.rcv_break++;
flag = TTY_BREAK;
}
......@@ -196,6 +219,9 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
isr = ioread8(&channel->block_regs->r.isr);
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)) {
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
/* 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,
channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
}
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);
ipoctal_reset_channel(channel);
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
&channel->regs->w.mr); /* mr1 */
iowrite8(0, &channel->regs->w.mr); /* mr2 */
......@@ -467,11 +490,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
cflag = tty->termios.c_cflag;
/* Disable and reset everything before change the setup */
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
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);
ipoctal_reset_channel(channel);
/* Set Bits per chars */
switch (cflag & CSIZE) {
......@@ -609,12 +628,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
tty_port_hangup(&channel->tty_port);
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);
ipoctal_reset_channel(channel);
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
wake_up_interruptible(&channel->tty_port.open_wait);
......@@ -627,15 +641,19 @@ static void ipoctal_shutdown(struct tty_struct *tty)
if (channel == NULL)
return;
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);
ipoctal_reset_channel(channel);
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 = {
.ioctl = NULL,
.open = ipoctal_open,
......@@ -647,6 +665,7 @@ static const struct tty_operations ipoctal_fops = {
.get_icount = ipoctal_get_icount,
.hangup = ipoctal_hangup,
.shutdown = ipoctal_shutdown,
.cleanup = ipoctal_cleanup,
};
static int ipoctal_probe(struct ipack_device *dev)
......
......@@ -12,7 +12,7 @@
* Software Foundation; version 2 of the License.
*/
#ifndef _IPOCTAL_H
#ifndef _IPOCTAL_H_
#define _IPOCTAL_H_
#define NR_CHANNELS 8
......
......@@ -206,7 +206,8 @@ static struct bus_type ipack_bus_type = {
};
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;
struct ipack_bus_device *bus;
......@@ -225,6 +226,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
bus->parent = parent;
bus->slots = slots;
bus->ops = ops;
bus->owner = owner;
return bus;
}
EXPORT_SYMBOL_GPL(ipack_bus_register);
......
......@@ -18,7 +18,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
......@@ -159,12 +159,11 @@ static int eeprom_probe(struct i2c_client *client,
{
struct i2c_adapter *adapter = client->adapter;
struct eeprom_data *data;
int err;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(client, data);
......@@ -190,22 +189,12 @@ static int eeprom_probe(struct i2c_client *client,
}
/* create the sysfs eeprom file */
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
if (err)
goto exit_kfree;
return 0;
exit_kfree:
kfree(data);
exit:
return err;
return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
}
static int eeprom_remove(struct i2c_client *client)
{
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
kfree(i2c_get_clientdata(client));
return 0;
}
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* This program is free software; you can redistribute it and/or modify
......@@ -45,10 +45,10 @@
MODULE_AUTHOR("Frank Haverkamp <haver@linux.vnet.ibm.com>");
MODULE_AUTHOR("Michael Ruettger <michael@ibmra.de>");
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_VERSION(DRV_VERS_STRING);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
static char genwqe_driver_name[] = GENWQE_DEVNAME;
......@@ -346,8 +346,13 @@ static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
unsigned int vf;
u32 T = genwqe_T_psec(cd);
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)
continue;
......@@ -383,8 +388,9 @@ static int genwqe_ffdc_buffs_alloc(struct genwqe_dev *cd)
/* currently support only the debug units mentioned here */
cd->ffdc[type].entries = e;
cd->ffdc[type].regs = kmalloc(e * sizeof(struct genwqe_reg),
GFP_KERNEL);
cd->ffdc[type].regs =
kmalloc_array(e, sizeof(struct genwqe_reg),
GFP_KERNEL);
/*
* regs == NULL is ok, the using code treats this as no regs,
* Printing warning is ok in this case.
......@@ -723,8 +729,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, sfir_addr, sfir);
dev_dbg(&pci_dev->dev,
"[HM] Clearing 2ndary FIR 0x%08x "
"with 0x%016llx\n", sfir_addr, sfir);
"[HM] Clearing 2ndary FIR 0x%08x with 0x%016llx\n",
sfir_addr, sfir);
/*
* note, these cannot be error-Firs
......@@ -740,9 +746,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
__genwqe_writeq(cd, fir_clr_addr, mask);
dev_dbg(&pci_dev->dev,
"[HM] Clearing primary FIR 0x%08x "
"with 0x%016llx\n", fir_clr_addr,
mask);
"[HM] Clearing primary FIR 0x%08x with 0x%016llx\n",
fir_clr_addr, mask);
}
}
}
......@@ -1125,6 +1130,8 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
}
cd->num_vfs = pci_sriov_get_totalvfs(pci_dev);
if (cd->num_vfs < 0)
cd->num_vfs = 0;
err = genwqe_read_ids(cd);
if (err)
......@@ -1202,8 +1209,8 @@ static int genwqe_probe(struct pci_dev *pci_dev,
err = genwqe_health_check_start(cd);
if (err < 0) {
dev_err(&pci_dev->dev,
"err: cannot start health checking! "
"(err=%d)\n", err);
"err: cannot start health checking! (err=%d)\n",
err);
goto out_stop_services;
}
}
......@@ -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)
{
int rc;
struct genwqe_dev *cd = dev_get_drvdata(&dev->dev);
if (numvfs > 0) {
genwqe_setup_vf_jtimer(cd);
pci_enable_sriov(dev, numvfs);
rc = pci_enable_sriov(dev, numvfs);
if (rc < 0)
return rc;
return numvfs;
}
if (numvfs == 0) {
......
......@@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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,
* @ddcb_seq: Sequence number of last DDCB
* @ddcbs_in_flight: Currently enqueued 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_vaddr: Kernel virtual address of first DDCB in the queue
* @ddcb_req: Associated requests (one per DDCB)
......@@ -218,7 +219,8 @@ struct ddcb_queue {
unsigned int ddcbs_in_flight; /* number of ddcbs in processing */
unsigned int ddcbs_completed;
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 */
struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */
......@@ -226,7 +228,7 @@ struct ddcb_queue {
wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */
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 */
u32 IO_QUEUE_CONFIG;
......@@ -306,7 +308,7 @@ struct genwqe_dev {
struct pci_dev *pci_dev; /* PCI device */
void __iomem *mmio; /* BAR-0 MMIO start */
unsigned long mmio_len;
u16 num_vfs;
int num_vfs;
u32 vf_jobtimeout_msec[GENWQE_MAX_VFS];
int is_privileged; /* access to all regs possible */
......@@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m)
* buildup and teardown.
*/
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
......@@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd,
* modification.
*/
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_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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)
pddcb = queue->ddcb_vaddr;
for (i = 0; i < queue->ddcb_max; i++) {
dev_err(&pci_dev->dev,
" %c %-3d: RETC=%03x SEQ=%04x "
"HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
" %c %-3d: RETC=%03x SEQ=%04x HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
i == queue->ddcb_act ? '>' : ' ',
i,
be16_to_cpu(pddcb->retc_16),
......@@ -214,6 +213,7 @@ struct genwqe_ddcb_cmd *ddcb_requ_alloc(void)
void ddcb_requ_free(struct genwqe_ddcb_cmd *cmd)
{
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
kfree(req);
}
......@@ -306,7 +306,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
new = (old | DDCB_NEXT_BE32);
wmb();
wmb(); /* need to ensure write ordering */
icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new);
if (icrc_hsi_shi == old)
......@@ -317,7 +317,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
ddcb_mark_tapped(pddcb);
num = (u64)ddcb_no << 8;
wmb();
wmb(); /* need to ensure write ordering */
__genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */
return RET_DDCB_TAPPED;
......@@ -390,8 +390,9 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
0x00000000)
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];
if (req == NULL) {
/* this occurs if DDCB is purged, not an error */
......@@ -416,9 +417,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
status = __genwqe_readq(cd, queue->IO_QUEUE_STATUS);
dev_err(&pci_dev->dev,
"[%s] SEQN=%04x HSI=%02x RETC=%03x "
" Q_ERRCNTS=%016llx Q_STATUS=%016llx\n"
" DDCB_DMA_ADDR=%016llx\n",
"[%s] SEQN=%04x HSI=%02x RETC=%03x Q_ERRCNTS=%016llx Q_STATUS=%016llx DDCB_DMA_ADDR=%016llx\n",
__func__, be16_to_cpu(pddcb->seqnum_16),
pddcb->hsi, retc_16, errcnts, status,
queue->ddcb_daddr + ddcb_offs);
......@@ -439,8 +438,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
vcrc_16 = be16_to_cpu(pddcb->vcrc_16);
if (vcrc != vcrc_16) {
printk_ratelimited(KERN_ERR
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d "
"bytes vcrc_data=%04x is not vcrc_card=%04x\n",
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d bytes vcrc_data=%04x is not vcrc_card=%04x\n",
GENWQE_DEVNAME, dev_name(&pci_dev->dev),
pddcb->pre, VCRC_LENGTH(req->cmd.asv_length),
vcrc, vcrc_16);
......@@ -450,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
queue->ddcbs_completed++;
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->busy_waitq);
pick_next_one:
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)
genwqe_hexdump(pci_dev, pddcb, sizeof(*pddcb));
dev_err(&pci_dev->dev,
"[%s] err: DDCB#%d not purged and not completed "
"after %d seconds QSTAT=%016llx!!\n",
"[%s] err: DDCB#%d not purged and not completed after %d seconds QSTAT=%016llx!!\n",
__func__, req->num, genwqe_ddcb_software_timeout,
queue_status);
......@@ -740,7 +739,7 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
}
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->app_unitcfg = cd->app_unitcfg;
return 0;
......@@ -748,14 +747,16 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d)
/**
* __genwqe_enqueue_ddcb() - Enqueue a DDCB
* @cd: pointer to genwqe device descriptor
* @req: pointer to DDCB execution request
* @cd: pointer to genwqe device descriptor
* @req: pointer to DDCB execution request
* @f_flags: file mode: blocking, non-blocking
*
* Return: 0 if enqueuing succeeded
* -EIO if card is unusable/PCIe problems
* -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;
unsigned long flags;
......@@ -763,6 +764,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
struct pci_dev *pci_dev = cd->pci_dev;
u16 icrc;
retry:
if (cd->card_state != GENWQE_CARD_USED) {
printk_ratelimited(KERN_ERR
"%s %s: [%s] Card is unusable/PCIe problem Req#%d\n",
......@@ -788,9 +790,24 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */
if (pddcb == NULL) {
int rc;
spin_unlock_irqrestore(&queue->ddcb_lock, flags);
queue->busy++;
return -EBUSY;
if (f_flags & O_NONBLOCK) {
queue->return_on_busy++;
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) {
......@@ -893,9 +910,11 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
* __genwqe_execute_raw_ddcb() - Setup and execute DDCB
* @cd: pointer to genwqe device descriptor
* @req: user provided DDCB request
* @f_flags: file mode: blocking, non-blocking
*/
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;
struct pci_dev *pci_dev = cd->pci_dev;
......@@ -911,7 +930,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
__func__, cmd->asiv_length);
return -EINVAL;
}
rc = __genwqe_enqueue_ddcb(cd, req);
rc = __genwqe_enqueue_ddcb(cd, req, f_flags);
if (rc != 0)
return rc;
......@@ -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_max_in_flight = 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_max = genwqe_ddcb_max; /* module parameter */
......@@ -1057,7 +1077,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
queue->ddcb_next = 0; /* queue is empty */
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 */
__genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */
......@@ -1251,10 +1271,8 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd)
}
rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS);
if (rc) {
rc = -ENODEV;
if (rc)
goto stop_kthread;
}
/*
* 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)
for (i = 0; i < queue->ddcb_max; i++)
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
wake_up_interruptible(&queue->busy_waitq);
spin_unlock_irqrestore(&queue->ddcb_lock, flags);
return 0;
......@@ -1346,8 +1365,8 @@ int genwqe_finish_queue(struct genwqe_dev *cd)
break;
dev_dbg(&pci_dev->dev,
" DEBUG [%d/%d] waiting for queue to get empty: "
"%d requests!\n", i, waitmax, in_flight);
" DEBUG [%d/%d] waiting for queue to get empty: %d requests!\n",
i, waitmax, in_flight);
/*
* Severe severe error situation: The card itself has
......
......@@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* This program is free software; you can redistribute it and/or modify
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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)
" ddcbs_in_flight: %u\n"
" ddcbs_max_in_flight: %u\n"
" ddcbs_completed: %u\n"
" busy: %u\n"
" return_on_busy: %u\n"
" wait_on_busy: %u\n"
" irqs_processed: %u\n",
queue->ddcb_max, (long long)queue->ddcb_daddr,
(long long)queue->ddcb_daddr +
(queue->ddcb_max * DDCB_LENGTH),
(long long)queue->ddcb_vaddr, queue->ddcbs_in_flight,
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 */
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)
" Base Clock : %u MHz\n"
" Arch/SVN Release: %u/%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) ?
"Physical" : "Virtual or no SR-IOV",
cd->card_idx, slu_id, app_id,
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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)
* GENWQE_MAPPING_SGL_TEMP should be removed by tidy up code.
*/
dev_err(&pci_dev->dev,
"[%s] %d. cleanup mapping: u_vaddr=%p "
"u_kaddr=%016lx dma_addr=%lx\n", __func__, i++,
dma_map->u_vaddr, (unsigned long)dma_map->k_vaddr,
"[%s] %d. cleanup mapping: u_vaddr=%p u_kaddr=%016lx dma_addr=%lx\n",
__func__, i++, dma_map->u_vaddr,
(unsigned long)dma_map->k_vaddr,
(unsigned long)dma_map->dma_addr);
if (dma_map->type == GENWQE_MAPPING_RAW) {
......@@ -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)
{
struct genwqe_file *cdev = (struct genwqe_file *)filp->private_data;
return fasync_helper(fd, filp, mode, &cdev->async_queue);
}
......@@ -515,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile,
u32 crc;
u8 cmdopts;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev;
if ((load->size & 0x3) != 0)
......@@ -609,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile,
/* For Genwqe5 we get back the calculated CRC */
*(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->attn = req->attn;
......@@ -649,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile,
u8 *xbuf;
u8 cmdopts;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct pci_dev *pci_dev = cd->pci_dev;
struct genwqe_ddcb_cmd *cmd;
......@@ -726,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile,
/* we only get back the calculated CRC */
*(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->attn = cmd->attn;
......@@ -987,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile,
{
int rc;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
rc = ddcb_cmd_fixups(cfile, req);
if (rc != 0)
return rc;
rc = __genwqe_execute_raw_ddcb(cd, cmd);
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
ddcb_cmd_cleanup(cfile, req);
return rc;
}
......@@ -1005,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
struct genwqe_ddcb_cmd *cmd;
struct ddcb_requ *req;
struct genwqe_dev *cd = cfile->cd;
struct file *filp = cfile->filp;
cmd = ddcb_requ_alloc();
if (cmd == NULL)
......@@ -1020,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
if (!raw)
rc = genwqe_execute_ddcb(cfile, cmd);
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
back since the copy got modified by the driver. */
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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,
}
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,
char *buf)
{
......@@ -256,7 +249,6 @@ static struct attribute *genwqe_attributes[] = {
&dev_attr_next_bitstream.attr,
&dev_attr_curr_bitstream.attr,
&dev_attr_base_clock.attr,
&dev_attr_driver.attr,
&dev_attr_type.attr,
&dev_attr_version.attr,
&dev_attr_appid.attr,
......@@ -268,7 +260,6 @@ static struct attribute *genwqe_attributes[] = {
};
static struct attribute *genwqe_normal_attributes[] = {
&dev_attr_driver.attr,
&dev_attr_type.attr,
&dev_attr_version.attr,
&dev_attr_appid.attr,
......
......@@ -5,7 +5,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* 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)
memset(app_name, 0, len);
for (i = 0, j = 0; j < min(len, 4); j++) {
char ch = (char)((app_id >> (24 - j*8)) & 0xff);
if (ch == ' ')
continue;
app_name[i++] = isprint(ch) ? ch : 'X';
......@@ -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->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE;
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld "
"fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
__func__, user_addr, user_size, sgl->nr_pages,
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,
u8 genwqe_card_type(struct genwqe_dev *cd)
{
u64 card_type = cd->slu_unitcfg;
return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20);
}
......
......@@ -8,7 +8,7 @@
*
* Author: Frank Haverkamp <haver@linux.vnet.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>
*
* This program is free software; you can redistribute it and/or modify
......@@ -36,7 +36,7 @@
#include <asm/byteorder.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
......
......@@ -247,3 +247,4 @@ module_spi_driver(lattice_ecp3_driver);
MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_NAME);
......@@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
......@@ -29,6 +28,7 @@
#include <linux/uuid.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/mei.h>
......@@ -64,31 +64,32 @@ void mei_amthif_reset_params(struct mei_device *dev)
*
* @dev: the device structure
*
* Return: 0 on success, <0 on failure.
*/
int mei_amthif_host_init(struct mei_device *dev)
{
struct mei_cl *cl = &dev->iamthif_cl;
struct mei_me_client *me_cl;
unsigned char *msg_buf;
int ret, i;
int ret;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_cl_init(cl, dev);
i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (i < 0) {
dev_info(&dev->pdev->dev,
"amthif: failed to find the client %d\n", i);
me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (!me_cl) {
dev_info(dev->dev, "amthif: failed to find the client");
return -ENOTTY;
}
cl->me_client_id = dev->me_clients[i].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
/* Assign iamthif_mtu to the value received from ME */
dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
dev->me_clients[i].props.max_msg_length);
dev->iamthif_mtu = me_cl->props.max_msg_length;
dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
kfree(dev->iamthif_msg_buf);
dev->iamthif_msg_buf = NULL;
......@@ -96,17 +97,15 @@ int mei_amthif_host_init(struct mei_device *dev)
/* allocate storage for ME message buffer */
msg_buf = kcalloc(dev->iamthif_mtu,
sizeof(unsigned char), GFP_KERNEL);
if (!msg_buf) {
dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
if (!msg_buf)
return -ENOMEM;
}
dev->iamthif_msg_buf = msg_buf;
ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
if (ret < 0) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"amthif: failed link client %d\n", ret);
return ret;
}
......@@ -124,18 +123,16 @@ int mei_amthif_host_init(struct mei_device *dev)
* @dev: the device structure
* @file: pointer to file object
*
* returns returned a list entry on success, NULL on failure.
* Return: returned a list entry on success, NULL on failure.
*/
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
struct file *file)
{
struct mei_cl_cb *cb;
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
if (cb->cl && cb->cl == &dev->iamthif_cl &&
cb->file_object == file)
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
if (cb->file_object == file)
return cb;
}
return NULL;
}
......@@ -144,15 +141,14 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
* mei_amthif_read - read data from AMTHIF client
*
* @dev: the device structure
* @if_num: minor number
* @file: pointer to file object
* @*ubuf: pointer to user data in user space
* @ubuf: pointer to user data in user space
* @length: data length to read
* @offset: data read offset
*
* Locking: called under "dev->device_lock" lock
*
* returns
* Return:
* returned data length on success,
* zero if no data to read,
* negative on failure.
......@@ -160,25 +156,19 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
int mei_amthif_read(struct mei_device *dev, struct file *file,
char __user *ubuf, size_t length, loff_t *offset)
{
int rets;
int wait_ret;
struct mei_cl_cb *cb = NULL;
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *cb;
unsigned long timeout;
int i;
int rets;
int wait_ret;
/* Only possible if we are in timeout */
if (!cl || cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "bad file ext.\n");
if (!cl) {
dev_err(dev->dev, "bad file ext.\n");
return -ETIME;
}
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
if (i < 0) {
dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
return -ENOTTY;
}
dev_dbg(&dev->pdev->dev, "checking amthif data\n");
dev_dbg(dev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
/* Check for if we can block or not*/
......@@ -186,7 +176,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
return -EAGAIN;
dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
dev_dbg(dev->dev, "waiting for amthif data\n");
while (cb == NULL) {
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
......@@ -200,21 +190,21 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
if (wait_ret)
return -ERESTARTSYS;
dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
dev_dbg(dev->dev, "woke up from sleep\n");
}
dev_dbg(&dev->pdev->dev, "Got amthif data\n");
dev_dbg(dev->dev, "Got amthif data\n");
dev->iamthif_timer = 0;
if (cb) {
timeout = cb->read_time +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
dev_dbg(dev->dev, "amthif timeout = %lud\n",
timeout);
if (time_after(jiffies, timeout)) {
dev_dbg(&dev->pdev->dev, "amthif Time out\n");
dev_dbg(dev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
rets = -ETIME;
......@@ -234,16 +224,16 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* remove message from deletion list
*/
dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
dev_dbg(dev->dev, "amthif cb->response_buffer size - %d\n",
cb->response_buffer.size);
dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
/* length is being truncated to PAGE_SIZE, however,
* the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset));
if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
} else {
rets = length;
......@@ -253,7 +243,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
}
free:
dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
dev_dbg(dev->dev, "free amthif cb memory.\n");
*offset = 0;
mei_io_cb_free(cb);
out:
......@@ -266,7 +256,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* @dev: the device structure
* @cb: mei call back struct
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*
*/
static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
......@@ -277,7 +267,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (!dev || !cb)
return -ENODEV;
dev_dbg(&dev->pdev->dev, "write data to amthif client.\n");
dev_dbg(dev->dev, "write data to amthif client.\n");
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
......@@ -316,12 +306,12 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
return -EIO;
dev->iamthif_flow_control_pending = true;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n");
dev_dbg(dev->dev, "add amthif cb to write waiting list\n");
dev->iamthif_current_cb = cb;
dev->iamthif_file_object = cb->file_object;
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
dev_dbg(&dev->pdev->dev, "message does not complete, so add amthif cb to write list.\n");
dev_dbg(dev->dev, "message does not complete, so add amthif cb to write list.\n");
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
......@@ -336,7 +326,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
* @dev: the device structure
* @cb: mei call back struct
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*
*/
int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
......@@ -354,25 +344,23 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (!list_empty(&dev->amthif_cmd_list.list) ||
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"amthif state = %d\n", dev->iamthif_state);
dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n");
dev_dbg(dev->dev, "AMTHIF: add cb to the wait list\n");
list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
return 0;
}
return mei_amthif_send_cmd(dev, cb);
}
/**
* mei_amthif_run_next_cmd
* mei_amthif_run_next_cmd - send next amt command from queue
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
*/
void mei_amthif_run_next_cmd(struct mei_device *dev)
{
struct mei_cl_cb *pos = NULL;
struct mei_cl_cb *next = NULL;
struct mei_cl_cb *cb;
struct mei_cl_cb *next;
int status;
if (!dev)
......@@ -386,21 +374,17 @@ void mei_amthif_run_next_cmd(struct mei_device *dev)
dev->iamthif_timer = 0;
dev->iamthif_file_object = NULL;
dev_dbg(&dev->pdev->dev, "complete amthif cmd_list cb.\n");
list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
list_del(&pos->list);
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
if (pos->cl && pos->cl == &dev->iamthif_cl) {
status = mei_amthif_send_cmd(dev, pos);
if (status) {
dev_dbg(&dev->pdev->dev,
"amthif write failed status = %d\n",
list_for_each_entry_safe(cb, next, &dev->amthif_cmd_list.list, list) {
list_del(&cb->list);
if (!cb->cl)
continue;
status = mei_amthif_send_cmd(dev, cb);
if (status)
dev_warn(dev->dev, "amthif write failed status = %d\n",
status);
return;
}
break;
}
break;
}
}
......@@ -421,7 +405,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
dev->iamthif_file_object == file) {
mask |= (POLLIN | POLLRDNORM);
dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
dev_dbg(dev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
mutex_unlock(&dev->device_lock);
......@@ -434,12 +418,11 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
* mei_amthif_irq_write - write iamthif command in irq thread context.
*
* @dev: the device structure.
* @cb_pos: callback block.
* @cl: private data of the file object.
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
......@@ -481,7 +464,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
rets = mei_write_message(dev, &mei_hdr,
dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
......@@ -514,14 +497,14 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
}
/**
* mei_amthif_irq_read_message - read routine after ISR to
* mei_amthif_irq_read_msg - read routine after ISR to
* handle the read amthif message
*
* @dev: the device structure
* @mei_hdr: header of amthif message
* @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_amthif_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
......@@ -543,10 +526,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
if (!mei_hdr->msg_complete)
return 0;
dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
dev_dbg(dev->dev, "amthif_message_buffer_index =%d\n",
mei_hdr->length);
dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
dev_dbg(dev->dev, "completed amthif read.\n ");
if (!dev->iamthif_current_cb)
return -ENODEV;
......@@ -559,10 +542,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
dev->iamthif_stall_timer = 0;
cb->buf_idx = dev->iamthif_msg_buf_index;
cb->read_time = jiffies;
if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
if (dev->iamthif_ioctl) {
/* found the iamthif cb */
dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
dev_dbg(dev->dev, "complete the amthif read cb.\n ");
dev_dbg(dev->dev, "add the amthif read cb to complete.\n ");
list_add_tail(&cb->list, &complete_list->list);
}
return 0;
......@@ -574,7 +557,7 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
* @dev: the device structure.
* @slots: free slots.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
......@@ -586,11 +569,11 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
*slots -= msg_slots;
if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
dev_dbg(dev->dev, "iamthif flow control failed\n");
return -EIO;
}
dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
dev_dbg(dev->dev, "iamthif flow control success\n");
dev->iamthif_state = MEI_IAMTHIF_READING;
dev->iamthif_flow_control_pending = false;
dev->iamthif_msg_buf_index = 0;
......@@ -604,7 +587,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
* mei_amthif_complete - complete amthif callback.
*
* @dev: the device structure.
* @cb_pos: callback block.
* @cb: callback block.
*/
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
{
......@@ -615,15 +598,15 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_msg_buf,
dev->iamthif_msg_buf_index);
list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
dev_dbg(&dev->pdev->dev, "amthif read completed\n");
dev_dbg(dev->dev, "amthif read completed\n");
dev->iamthif_timer = jiffies;
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
} else {
mei_amthif_run_next_cmd(dev);
}
dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
dev_dbg(dev->dev, "completing amthif call back.\n");
wake_up_interruptible(&dev->iamthif_cl.wait);
}
......@@ -638,7 +621,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
* mei_clear_list is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* returns true if callback removed from the list, false otherwise
* Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_list(struct mei_device *dev,
const struct file *file, struct list_head *mei_cb_list)
......@@ -678,7 +661,7 @@ static bool mei_clear_list(struct mei_device *dev,
* mei_clear_lists is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
* returns true if callback removed from the list, false otherwise
* Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_lists(struct mei_device *dev, struct file *file)
{
......@@ -719,7 +702,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file)
* @dev: device structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
......@@ -729,11 +712,11 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
if (dev->iamthif_file_object == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
dev->iamthif_state);
dev->iamthif_canceled = true;
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
dev_dbg(&dev->pdev->dev, "run next amthif iamthif cb\n");
dev_dbg(dev->dev, "run next amthif iamthif cb\n");
mei_amthif_run_next_cmd(dev);
}
}
......
......@@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
......@@ -70,7 +69,7 @@ static int mei_cl_device_probe(struct device *dev)
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);
}
......@@ -147,7 +146,7 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
struct mei_cl *cl;
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;
}
......@@ -172,7 +171,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
device->cl = cl;
device->ops = ops;
device->dev.parent = &dev->pdev->dev;
device->dev.parent = dev->dev;
device->dev.bus = &mei_cl_bus_type;
device->dev.type = &mei_cl_device_type;
......@@ -180,7 +179,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
status = device_register(&device->dev);
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);
return NULL;
}
......@@ -229,8 +228,8 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
struct mei_cl_cb *cb;
int id;
int rets;
if (WARN_ON(!cl || !cl->dev))
......@@ -242,11 +241,11 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
return -ENODEV;
/* Check if we have an ME client device */
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0)
return id;
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl)
return -ENOTTY;
if (length > dev->me_clients[id].props.max_msg_length)
if (length > me_cl->props.max_msg_length)
return -EFBIG;
cb = mei_io_cb_init(cl, NULL);
......@@ -430,7 +429,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
err = mei_cl_connect(cl, NULL);
if (err < 0) {
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;
}
......@@ -462,7 +461,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
if (cl->state != MEI_FILE_CONNECTED) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev, "Already disconnected");
dev_err(dev->dev, "Already disconnected");
return 0;
}
......@@ -472,7 +471,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
err = mei_cl_disconnect(cl);
if (err < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"Could not disconnect from the ME client");
return err;
......
......@@ -14,10 +14,10 @@
*
*/
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
......@@ -27,47 +27,90 @@
#include "client.h"
/**
* mei_me_cl_by_uuid - locate index of me client
* mei_me_cl_by_uuid - locate me client by uuid
*
* @dev: mei device
* @uuid: me client uuid
*
* Locking: called under "dev->device_lock" lock
*
* returns me client index or -ENOENT if not found
* Return: me client or NULL if not found
*/
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
const uuid_le *uuid)
{
int i;
struct mei_me_client *me_cl;
for (i = 0; i < dev->me_clients_num; ++i)
if (uuid_le_cmp(*uuid,
dev->me_clients[i].props.protocol_name) == 0)
return i;
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
return me_cl;
return -ENOENT;
return NULL;
}
/**
* mei_me_cl_by_id return index to me_clients for client_id
* mei_me_cl_by_id - locate me client by client id
*
* @dev: the device structure
* @client_id: me client id
*
* Locking: called under "dev->device_lock" lock
*
* returns index on success, -ENOENT on failure.
* Return: me client or NULL if not found
*/
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
{
struct mei_me_client *me_cl;
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
list_for_each_entry(me_cl, &dev->me_clients, list)
if (me_cl->client_id == client_id)
return me_cl;
return NULL;
}
/**
* mei_me_cl_by_uuid_id - locate me client by client id and uuid
*
* @dev: the device structure
* @uuid: me client uuid
* @client_id: me client id
*
* Locking: called under "dev->device_lock" lock
*
* Return: me client or NULL if not found
*/
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
const uuid_le *uuid, u8 client_id)
{
int i;
struct mei_me_client *me_cl;
for (i = 0; i < dev->me_clients_num; i++)
if (dev->me_clients[i].client_id == client_id)
return i;
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
me_cl->client_id == client_id)
return me_cl;
return NULL;
}
return -ENOENT;
/**
* mei_me_cl_remove - remove me client matching uuid and client_id
*
* @dev: the device structure
* @uuid: me client uuid
* @client_id: me client address
*/
void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
{
struct mei_me_client *me_cl, *next;
list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
me_cl->client_id == client_id) {
list_del(&me_cl->list);
kfree(me_cl);
break;
}
}
}
......@@ -77,7 +120,7 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
* @cl1: host client 1
* @cl2: host client 2
*
* returns true - if the clients has same host and me ids
* Return: true - if the clients has same host and me ids
* false - otherwise
*/
static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
......@@ -117,7 +160,7 @@ static void __mei_io_list_flush(struct mei_cl_cb *list,
* @list: An instance of our list structure
* @cl: host client
*/
static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
{
__mei_io_list_flush(list, cl, false);
}
......@@ -152,10 +195,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
/**
* mei_io_cb_init - allocate and initialize io callback
*
* @cl - mei client
* @cl: mei client
* @fp: pointer to file structure
*
* returns mei_cl_cb pointer or NULL;
* Return: mei_cl_cb pointer or NULL;
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
{
......@@ -179,7 +222,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
* @cb: io callback structure
* @length: size of the buffer
*
* returns 0 on success
* Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
......@@ -203,7 +246,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
* @cb: io callback structure
* @length: size of the buffer
*
* returns 0 on success
* Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
......@@ -228,6 +271,8 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
* mei_cl_flush_queues - flushes queue lists belonging to cl.
*
* @cl: host client
*
* Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
*/
int mei_cl_flush_queues(struct mei_cl *cl)
{
......@@ -273,7 +318,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
* mei_cl_allocate - allocates cl structure and sets it up.
*
* @dev: mei device
* returns The allocated file or NULL on failure
* Return: The allocated file or NULL on failure
*/
struct mei_cl *mei_cl_allocate(struct mei_device *dev)
{
......@@ -293,7 +338,7 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
*
* @cl: host client
*
* returns cb on success, NULL on error
* Return: cb on success, NULL on error
*/
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
......@@ -311,7 +356,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
* @cl - host client
* @id - fixed host id or -1 for generic one
*
* returns 0 on success
* Return: 0 on success
* -EINVAL on incorrect values
* -ENONET if client not found
*/
......@@ -331,13 +376,13 @@ int mei_cl_link(struct mei_cl *cl, int id)
MEI_CLIENTS_MAX);
if (id >= MEI_CLIENTS_MAX) {
dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
return -EMFILE;
}
open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
dev_err(dev->dev, "open_handle_count exceeded %d",
MEI_MAX_OPEN_HANDLE_COUNT);
return -EMFILE;
}
......@@ -359,6 +404,8 @@ int mei_cl_link(struct mei_cl *cl, int id)
* mei_cl_unlink - remove me_cl from the list
*
* @cl: host client
*
* Return: always 0
*/
int mei_cl_unlink(struct mei_cl *cl)
{
......@@ -395,19 +442,19 @@ void mei_host_client_init(struct work_struct *work)
{
struct mei_device *dev = container_of(work,
struct mei_device, init_work);
struct mei_client_properties *client_props;
int i;
struct mei_me_client *me_cl;
struct mei_client_properties *props;
mutex_lock(&dev->device_lock);
for (i = 0; i < dev->me_clients_num; i++) {
client_props = &dev->me_clients[i].props;
list_for_each_entry(me_cl, &dev->me_clients, list) {
props = &me_cl->props;
if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
mei_nfc_host_init(dev);
}
......@@ -417,27 +464,27 @@ void mei_host_client_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
pm_runtime_mark_last_busy(&dev->pdev->dev);
dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
pm_runtime_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
dev_dbg(dev->dev, "rpm: autosuspend\n");
pm_runtime_autosuspend(dev->dev);
}
/**
* mei_hbuf_acquire: try to acquire host buffer
* mei_hbuf_acquire - try to acquire host buffer
*
* @dev: the device structure
* returns true if host buffer was acquired
* Return: true if host buffer was acquired
*/
bool mei_hbuf_acquire(struct mei_device *dev)
{
if (mei_pg_state(dev) == MEI_PG_ON ||
dev->pg_event == MEI_PG_EVENT_WAIT) {
dev_dbg(&dev->pdev->dev, "device is in pg\n");
dev_dbg(dev->dev, "device is in pg\n");
return false;
}
if (!dev->hbuf_is_ready) {
dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
dev_dbg(dev->dev, "hbuf is not ready\n");
return false;
}
......@@ -453,7 +500,7 @@ bool mei_hbuf_acquire(struct mei_device *dev)
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_disconnect(struct mei_cl *cl)
{
......@@ -471,9 +518,9 @@ int mei_cl_disconnect(struct mei_cl *cl)
if (cl->state != MEI_FILE_DISCONNECTING)
return 0;
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
......@@ -484,7 +531,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
goto free;
}
cb->fop_type = MEI_FOP_CLOSE;
cb->fop_type = MEI_FOP_DISCONNECT;
if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
......@@ -501,7 +549,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
}
mutex_unlock(&dev->device_lock);
wait_event_timeout(dev->wait_recvd_msg,
wait_event_timeout(cl->wait,
MEI_FILE_DISCONNECTED == cl->state,
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
......@@ -519,8 +567,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
......@@ -533,7 +581,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
*
* @cl: private data of the file object
*
* returns true if other client is connected, false - otherwise.
* Return: true if other client is connected, false - otherwise.
*/
bool mei_cl_is_other_connecting(struct mei_cl *cl)
{
......@@ -560,10 +608,11 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl)
* mei_cl_connect - connect host client to the me one
*
* @cl: host client
* @file: pointer to file structure
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_connect(struct mei_cl *cl, struct file *file)
{
......@@ -576,9 +625,9 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
dev = cl->dev;
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
......@@ -606,7 +655,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
}
mutex_unlock(&dev->device_lock);
wait_event_timeout(dev->wait_recvd_msg,
wait_event_timeout(cl->wait,
(cl->state == MEI_FILE_CONNECTED ||
cl->state == MEI_FILE_DISCONNECTED),
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
......@@ -626,8 +675,8 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
......@@ -638,7 +687,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
*
* @cl: private data of the file object
*
* returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
* Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
* -ENOENT if mei_cl is not present
* -EINVAL if single_recv_buf == 0
*/
......@@ -646,26 +695,21 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
if (!dev->me_clients_num)
return 0;
if (cl->mei_flow_ctrl_creds > 0)
return 1;
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return id;
return -ENOENT;
}
me_cl = &dev->me_clients[id];
if (me_cl->mei_flow_ctrl_creds) {
if (WARN_ON(me_cl->props.single_recv_buf == 0))
return -EINVAL;
......@@ -679,7 +723,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
*
* @cl: private data of the file object
*
* @returns
* Return:
* 0 on success
* -ENOENT when me client is not found
* -EINVAL when ctrl credits are <= 0
......@@ -688,21 +732,19 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return id;
return -ENOENT;
}
me_cl = &dev->me_clients[id];
if (me_cl->props.single_recv_buf != 0) {
if (me_cl->props.single_recv_buf) {
if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
return -EINVAL;
me_cl->mei_flow_ctrl_creds--;
......@@ -718,15 +760,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
* mei_cl_read_start - the start read client message function.
*
* @cl: host client
* @length: number of bytes to read
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_cl_read_start(struct mei_cl *cl, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
struct mei_me_client *me_cl;
int rets;
int i;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
......@@ -740,15 +783,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
cl_dbg(dev, cl, "read is pending.\n");
return -EBUSY;
}
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return -ENOTTY;
}
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
......@@ -760,7 +803,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
}
/* always allocate at least client max message */
length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
length = max_t(size_t, length, me_cl->props.max_msg_length);
rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto out;
......@@ -780,8 +823,8 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
out:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
if (rets)
mei_io_cb_free(cb);
......@@ -797,7 +840,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise error.
* Return: 0, OK; otherwise error.
*/
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
......@@ -874,12 +917,13 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_write - submit a write cb to mei device
assumes device_lock is locked
* assumes device_lock is locked
*
* @cl: host client
* @cl: write callback with filled data
* @cb: write callback with filled data
* @blocking: block until completed
*
* returns number of bytes sent on success, <0 on failure.
* Return: number of bytes sent on success, <0 on failure.
*/
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{
......@@ -900,11 +944,11 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
buf = &cb->request_buffer;
cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
cl_dbg(dev, cl, "size=%d\n", buf->size);
rets = pm_runtime_get(&dev->pdev->dev);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
pm_runtime_put_noidle(&dev->pdev->dev);
pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
......@@ -979,8 +1023,8 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
rets = buf->size;
err:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(&dev->pdev->dev);
pm_runtime_put_autosuspend(&dev->pdev->dev);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
return rets;
}
......@@ -1016,7 +1060,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
* @dev - mei device
* @dev: mei device
*/
void mei_cl_all_disconnect(struct mei_device *dev)
......@@ -1034,11 +1078,12 @@ void mei_cl_all_disconnect(struct mei_device *dev)
/**
* mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
*
* @dev - mei device
* @dev: mei device
*/
void mei_cl_all_wakeup(struct mei_device *dev)
{
struct mei_cl *cl;
list_for_each_entry(cl, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
cl_dbg(dev, cl, "Waking up reading client!\n");
......@@ -1053,8 +1098,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
/**
* mei_cl_all_write_clear - clear all pending writes
* @dev - mei device
*
* @dev: mei device
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{
......
......@@ -24,8 +24,15 @@
#include "mei_dev.h"
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
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
......@@ -45,6 +52,8 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{
INIT_LIST_HEAD(&list->list);
}
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
/*
* MEI Host Client Functions
*/
......@@ -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 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...) \
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_ */
......@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/mei.h>
......@@ -28,39 +27,47 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mei_device *dev = fp->private_data;
struct mei_me_client *cl;
const size_t bufsz = 1024;
char *buf = kzalloc(bufsz, GFP_KERNEL);
int i;
struct mei_me_client *me_cl;
size_t bufsz = 1;
char *buf;
int i = 0;
int pos = 0;
int ret;
if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos,
" |id|addr| UUID |con|msg len|\n");
#define HDR " |id|addr| UUID |con|msg len|sb|\n"
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 (dev->dev_state != MEI_DEV_ENABLED)
goto out;
for (i = 0; i < dev->me_clients_num; i++) {
cl = &dev->me_clients[i];
list_for_each_entry(me_cl, &dev->me_clients, list) {
/* 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;
pos += scnprintf(buf + pos, bufsz - pos,
"%2d|%2d|%4d|%pUl|%3d|%7d|\n",
i, cl->client_id,
cl->props.fixed_address,
&cl->props.protocol_name,
cl->props.max_number_of_connections,
cl->props.max_msg_length);
"%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n",
i++, me_cl->client_id,
me_cl->props.fixed_address,
&me_cl->props.protocol_name,
me_cl->props.max_number_of_connections,
me_cl->props.max_msg_length,
me_cl->props.single_recv_buf);
}
out:
mutex_unlock(&dev->device_lock);
......@@ -98,7 +105,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
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)
goto out;
......@@ -135,8 +142,13 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
if (!buf)
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));
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);
kfree(buf);
return ret;
......@@ -149,7 +161,8 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
/**
* 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)
{
......@@ -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)
{
struct dentry *dir, *f;
dir = debugfs_create_dir(name, NULL);
if (!dir)
return -ENOMEM;
......@@ -173,19 +191,19 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
f = debugfs_create_file("meclients", S_IRUSR, dir,
dev, &mei_dbgfs_fops_meclients);
if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
dev_err(dev->dev, "meclients: registration failed\n");
goto err;
}
f = debugfs_create_file("active", S_IRUSR, dir,
dev, &mei_dbgfs_fops_active);
if (!f) {
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
dev_err(dev->dev, "meclients: registration failed\n");
goto err;
}
f = debugfs_create_file("devstate", S_IRUSR, dir,
dev, &mei_dbgfs_fops_devstate);
if (!f) {
dev_err(&dev->pdev->dev, "devstate: registration failed\n");
dev_err(dev->dev, "devstate: registration failed\n");
goto err;
}
dev->dbgfs_dir = dir;
......
此差异已折叠。
......@@ -25,29 +25,24 @@ struct mei_cl;
* enum mei_hbm_state - host bus message protocol state
*
* @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_CLIENT_PROPERTIES : acquiring clients properties
* @MEI_HBM_STOPPED : stopping exchange
*/
enum mei_hbm_state {
MEI_HBM_IDLE = 0,
MEI_HBM_START,
MEI_HBM_STARTING,
MEI_HBM_STARTED,
MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES,
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)
{
hdr->host_addr = 0;
hdr->me_addr = 0;
hdr->length = length;
hdr->msg_complete = 1;
hdr->reserved = 0;
}
int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
void mei_hbm_idle(struct mei_device *dev);
void mei_hbm_reset(struct mei_device *dev);
......
此差异已折叠。
......@@ -19,14 +19,44 @@
#ifndef _MEI_INTERFACE_H_
#define _MEI_INTERFACE_H_
#include <linux/mei.h>
#include <linux/irqreturn.h>
#include <linux/pci.h>
#include <linux/mei.h>
#include "mei_dev.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 */
/**
* 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 {
const struct mei_cfg *cfg;
void __iomem *mem_addr;
/*
* hw states of host and fw(ME)
......
此差异已折叠。
......@@ -40,6 +40,7 @@
* @mem_addr: SeC and BRIDGE bars
* @aliveness: aliveness (power gating) state of the hardware
* @readiness: readiness state of the hardware
* @slots: number of empty slots
* @wait_aliveness_resp: aliveness wait queue
* @intr_cause: translated interrupt cause
*/
......@@ -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);
}
extern const struct mei_cfg mei_txe_cfg;
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg);
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
irqreturn_t mei_txe_irq_quick_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 {
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
* used by hbm_client_connect_response.status
*/
enum mei_cl_connect_status {
MEI_CL_CONN_SUCCESS = 0x00,
MEI_CL_CONN_NOT_FOUND = 0x01,
MEI_CL_CONN_ALREADY_STARTED = 0x02,
MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
MEI_CL_CONN_MESSAGE_SMALL = 0x04
MEI_CL_CONN_SUCCESS = MEI_HBMS_SUCCESS,
MEI_CL_CONN_NOT_FOUND = MEI_HBMS_CLIENT_NOT_FOUND,
MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS,
MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED,
MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER,
};
/*
* Client 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 {
* struct hbm_cl_cmd - client specific host bus command
* CONNECT, DISCONNECT, and FlOW CONTROL
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @data
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @data: generic data
*/
struct mei_hbm_cl_cmd {
u8 hbm_cmd;
......@@ -206,14 +235,13 @@ struct mei_client_properties {
struct hbm_props_request {
u8 hbm_cmd;
u8 address;
u8 me_addr;
u8 reserved[2];
} __packed;
struct hbm_props_response {
u8 hbm_cmd;
u8 address;
u8 me_addr;
u8 status;
u8 reserved[1];
struct mei_client_properties client_properties;
......@@ -222,8 +250,8 @@ struct hbm_props_response {
/**
* struct hbm_power_gate - power gate request/response
*
* @hbm_cmd - bus message command header
* @reserved[3]
* @hbm_cmd: bus message command header
* @reserved: reserved
*/
struct hbm_power_gate {
u8 hbm_cmd;
......@@ -233,10 +261,10 @@ struct hbm_power_gate {
/**
* struct hbm_client_connect_request - connect/disconnect request
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @reserved
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @reserved: reserved
*/
struct hbm_client_connect_request {
u8 hbm_cmd;
......@@ -248,10 +276,10 @@ struct hbm_client_connect_request {
/**
* struct hbm_client_connect_response - connect/disconnect response
*
* @hbm_cmd - bus message command header
* @me_addr - address of the client in ME
* @host_addr - address of the client in the driver
* @status - status of the request
* @hbm_cmd: bus message command header
* @me_addr: address of the client in ME
* @host_addr: address of the client in the driver
* @status: status of the request
*/
struct hbm_client_connect_response {
u8 hbm_cmd;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -98,12 +98,12 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev) {}
#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
* @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,
const struct mei_cfg *cfg)
......@@ -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
* @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)
{
......@@ -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
*
......@@ -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)
{
struct pci_dev *pdev = dev->pdev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && 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)
static inline void mei_me_unset_pm_domain(struct mei_device *dev)
{
/* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL;
dev->dev->pm_domain = NULL;
}
#endif /* CONFIG_PM_RUNTIME */
......
......@@ -36,7 +36,8 @@
#include "hw-txe.h"
static const struct pci_device_id mei_txe_pci_tbl[] = {
{MEI_PCI_DEVICE(0x0F18, mei_txe_cfg)}, /* Baytrail */
{PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */
{0, }
};
MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
......@@ -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)
{
int i;
for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
if (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)
* @pdev: PCI device structure
* @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)
{
const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data);
struct mei_device *dev;
struct mei_txe_hw *hw;
int err;
......@@ -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 */
dev = mei_txe_dev_init(pdev, cfg);
dev = mei_txe_dev_init(pdev);
if (!dev) {
err = -ENOMEM;
goto release_regions;
......@@ -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)
{
struct pci_dev *pdev = dev->pdev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pdev->dev.bus && 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)
static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
{
/* stop using pm callbacks if any */
dev->pdev->dev.pm_domain = NULL;
dev->dev->pm_domain = NULL;
}
#endif /* CONFIG_PM_RUNTIME */
......
此差异已折叠。
......@@ -153,8 +153,9 @@ static void st_reg_complete(struct st_data_s *st_gdata, char err)
(st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err);
if (err) { /* cleanup registered protocol */
st_gdata->protos_registered--;
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)
return -EPROTONOSUPPORT;
}
st_gdata->protos_registered--;
if (st_gdata->protos_registered)
st_gdata->protos_registered--;
remove_channel_from_table(st_gdata, proto);
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) &&
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_info(" all chnl_ids unregistered ");
......
......@@ -328,7 +328,8 @@ int vmci_datagram_dispatch(u32 context_id,
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",
(unsigned long long)dg->payload_size);
return VMCI_ERROR_INVALID_ARGS;
......
此差异已折叠。
......@@ -34,8 +34,10 @@
* @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
* @state_on: print_state is overriden with state_on if attached.
* 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.
* @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
* and state_off should be not NULL. If at least one of them is NULL,
......
此差异已折叠。
......@@ -3,6 +3,7 @@
#include <linux/device.h>
#include <linux/uuid.h>
#include <linux/mod_devicetable.h>
struct mei_cl_device;
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册