Char/Misc driver patches for 3.18-rc1

Here's the big set of driver patches for char/misc drivers.  Nothing
 major in here, the shortlog below goes into the details.  All have been
 in the linux-next tree for a while with no issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlQ0ZXYACgkQMUfUDdst+ymiEgCgrKcYUluvdrbjdkhrENk332YN
 lcUAoMzgQpbkYhswrDNQet7NtAbFN9LV
 =ZPDy
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2014-10-08 06:55:41 -04:00
commit ef0625b70d
63 changed files with 2800 additions and 1351 deletions

View File

@ -0,0 +1,25 @@
* 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>;
};

View File

@ -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

View File

@ -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 = {

View File

@ -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,
},

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -0,0 +1,740 @@
/*
* extcon-rt8973a.c - Richtek RT8973A extcon driver to support USB switches
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
* Author: Chanwoo Choi <cw00.choi@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/extcon.h>
#include "extcon-rt8973a.h"
#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
struct muic_irq {
unsigned int irq;
const char *name;
unsigned int virq;
};
struct reg_data {
u8 reg;
u8 mask;
u8 val;
bool invert;
};
struct rt8973a_muic_info {
struct device *dev;
struct extcon_dev *edev;
struct i2c_client *i2c;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_data;
struct muic_irq *muic_irqs;
unsigned int num_muic_irqs;
int irq;
bool irq_attach;
bool irq_detach;
bool irq_ovp;
bool irq_otp;
struct work_struct irq_work;
struct reg_data *reg_data;
unsigned int num_reg_data;
bool auto_config;
struct mutex mutex;
/*
* Use delayed workqueue to detect cable state and then
* notify cable state to notifiee/platform through uevent.
* After completing the booting of platform, the extcon provider
* driver should notify cable state to upper layer.
*/
struct delayed_work wq_detcable;
};
/* Default value of RT8973A register to bring up MUIC device. */
static struct reg_data rt8973a_reg_data[] = {
{
.reg = RT8973A_REG_CONTROL1,
.mask = RT8973A_REG_CONTROL1_ADC_EN_MASK
| RT8973A_REG_CONTROL1_USB_CHD_EN_MASK
| RT8973A_REG_CONTROL1_CHGTYP_MASK
| RT8973A_REG_CONTROL1_SWITCH_OPEN_MASK
| RT8973A_REG_CONTROL1_AUTO_CONFIG_MASK
| RT8973A_REG_CONTROL1_INTM_MASK,
.val = RT8973A_REG_CONTROL1_ADC_EN_MASK
| RT8973A_REG_CONTROL1_USB_CHD_EN_MASK
| RT8973A_REG_CONTROL1_CHGTYP_MASK,
.invert = false,
},
{ /* sentinel */ }
};
/* List of detectable cables */
enum {
EXTCON_CABLE_USB = 0,
EXTCON_CABLE_USB_HOST,
EXTCON_CABLE_TA,
EXTCON_CABLE_JIG_OFF_USB,
EXTCON_CABLE_JIG_ON_USB,
EXTCON_CABLE_JIG_OFF_UART,
EXTCON_CABLE_JIG_ON_UART,
EXTCON_CABLE_END,
};
static const char *rt8973a_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-Host",
[EXTCON_CABLE_TA] = "TA",
[EXTCON_CABLE_JIG_OFF_USB] = "JIG-USB-OFF",
[EXTCON_CABLE_JIG_ON_USB] = "JIG-USB-ON",
[EXTCON_CABLE_JIG_OFF_UART] = "JIG-UART-OFF",
[EXTCON_CABLE_JIG_ON_UART] = "JIG-UART-ON",
NULL,
};
/* Define OVP (Over Voltage Protection), OTP (Over Temperature Protection) */
enum rt8973a_event_type {
RT8973A_EVENT_ATTACH = 1,
RT8973A_EVENT_DETACH,
RT8973A_EVENT_OVP,
RT8973A_EVENT_OTP,
};
/* Define supported accessory type */
enum rt8973a_muic_acc_type {
RT8973A_MUIC_ADC_OTG = 0x0,
RT8973A_MUIC_ADC_AUDIO_SEND_END_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S1_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S2_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S3_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S4_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S5_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S6_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S7_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S8_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S9_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S10_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S11_BUTTON,
RT8973A_MUIC_ADC_AUDIO_REMOTE_S12_BUTTON,
RT8973A_MUIC_ADC_RESERVED_ACC_1,
RT8973A_MUIC_ADC_RESERVED_ACC_2,
RT8973A_MUIC_ADC_RESERVED_ACC_3,
RT8973A_MUIC_ADC_RESERVED_ACC_4,
RT8973A_MUIC_ADC_RESERVED_ACC_5,
RT8973A_MUIC_ADC_AUDIO_TYPE2,
RT8973A_MUIC_ADC_PHONE_POWERED_DEV,
RT8973A_MUIC_ADC_UNKNOWN_ACC_1,
RT8973A_MUIC_ADC_UNKNOWN_ACC_2,
RT8973A_MUIC_ADC_TA,
RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB,
RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB,
RT8973A_MUIC_ADC_UNKNOWN_ACC_3,
RT8973A_MUIC_ADC_UNKNOWN_ACC_4,
RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART,
RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART,
RT8973A_MUIC_ADC_UNKNOWN_ACC_5,
RT8973A_MUIC_ADC_OPEN = 0x1f,
/* The below accessories has same ADC value (0x1f).
So, Device type1 is used to separate specific accessory. */
/* |---------|--ADC| */
/* | [7:5]|[4:0]| */
RT8973A_MUIC_ADC_USB = 0x3f, /* | 001|11111| */
};
/* List of supported interrupt for RT8973A */
static struct muic_irq rt8973a_muic_irqs[] = {
{ RT8973A_INT1_ATTACH, "muic-attach" },
{ RT8973A_INT1_DETACH, "muic-detach" },
{ RT8973A_INT1_CHGDET, "muic-chgdet" },
{ RT8973A_INT1_DCD_T, "muic-dcd-t" },
{ RT8973A_INT1_OVP, "muic-ovp" },
{ RT8973A_INT1_CONNECT, "muic-connect" },
{ RT8973A_INT1_ADC_CHG, "muic-adc-chg" },
{ RT8973A_INT1_OTP, "muic-otp" },
{ RT8973A_INT2_UVLO, "muic-uvlo" },
{ RT8973A_INT2_POR, "muic-por" },
{ RT8973A_INT2_OTP_FET, "muic-otp-fet" },
{ RT8973A_INT2_OVP_FET, "muic-ovp-fet" },
{ RT8973A_INT2_OCP_LATCH, "muic-ocp-latch" },
{ RT8973A_INT2_OCP, "muic-ocp" },
{ RT8973A_INT2_OVP_OCP, "muic-ovp-ocp" },
};
/* Define interrupt list of RT8973A to register regmap_irq */
static const struct regmap_irq rt8973a_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = RT8973A_INT1_ATTACH_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_DETACH_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_CHGDET_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_DCD_T_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_OVP_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_CONNECT_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_ADC_CHG_MASK, },
{ .reg_offset = 0, .mask = RT8973A_INT1_OTP_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = RT8973A_INT2_UVLOT_MASK,},
{ .reg_offset = 1, .mask = RT8973A_INT2_POR_MASK, },
{ .reg_offset = 1, .mask = RT8973A_INT2_OTP_FET_MASK, },
{ .reg_offset = 1, .mask = RT8973A_INT2_OVP_FET_MASK, },
{ .reg_offset = 1, .mask = RT8973A_INT2_OCP_LATCH_MASK, },
{ .reg_offset = 1, .mask = RT8973A_INT2_OCP_MASK, },
{ .reg_offset = 1, .mask = RT8973A_INT2_OVP_OCP_MASK, },
};
static const struct regmap_irq_chip rt8973a_muic_irq_chip = {
.name = "rt8973a",
.status_base = RT8973A_REG_INT1,
.mask_base = RT8973A_REG_INTM1,
.mask_invert = false,
.num_regs = 2,
.irqs = rt8973a_irqs,
.num_irqs = ARRAY_SIZE(rt8973a_irqs),
};
/* Define regmap configuration of RT8973A for I2C communication */
static bool rt8973a_muic_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case RT8973A_REG_INTM1:
case RT8973A_REG_INTM2:
return true;
default:
break;
}
return false;
}
static const struct regmap_config rt8973a_muic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = rt8973a_muic_volatile_reg,
.max_register = RT8973A_REG_END,
};
/* Change DM_CON/DP_CON/VBUSIN switch according to cable type */
static int rt8973a_muic_set_path(struct rt8973a_muic_info *info,
unsigned int con_sw, bool attached)
{
int ret;
/*
* Don't need to set h/w path according to cable type
* if Auto-configuration mode of CONTROL1 register is true.
*/
if (info->auto_config)
return 0;
if (!attached)
con_sw = DM_DP_SWITCH_UART;
switch (con_sw) {
case DM_DP_SWITCH_OPEN:
case DM_DP_SWITCH_USB:
case DM_DP_SWITCH_UART:
ret = regmap_update_bits(info->regmap, RT8973A_REG_MANUAL_SW1,
RT8973A_REG_MANUAL_SW1_DP_MASK |
RT8973A_REG_MANUAL_SW1_DM_MASK,
con_sw);
if (ret < 0) {
dev_err(info->dev,
"cannot update DM_CON/DP_CON switch\n");
return ret;
}
break;
default:
dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
con_sw);
return -EINVAL;
}
return 0;
}
static int rt8973a_muic_get_cable_type(struct rt8973a_muic_info *info)
{
unsigned int adc, dev1;
int ret, cable_type;
/* Read ADC value according to external cable or button */
ret = regmap_read(info->regmap, RT8973A_REG_ADC, &adc);
if (ret) {
dev_err(info->dev, "failed to read ADC register\n");
return ret;
}
cable_type = adc & RT8973A_REG_ADC_MASK;
/* Read Device 1 reigster to identify correct cable type */
ret = regmap_read(info->regmap, RT8973A_REG_DEV1, &dev1);
if (ret) {
dev_err(info->dev, "failed to read DEV1 register\n");
return ret;
}
switch (adc) {
case RT8973A_MUIC_ADC_OPEN:
if (dev1 & RT8973A_REG_DEV1_USB_MASK)
cable_type = RT8973A_MUIC_ADC_USB;
else if (dev1 & RT8973A_REG_DEV1_DCPORT_MASK)
cable_type = RT8973A_MUIC_ADC_TA;
else
cable_type = RT8973A_MUIC_ADC_OPEN;
break;
default:
break;
}
return cable_type;
}
static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
enum rt8973a_event_type event)
{
static unsigned int prev_cable_type;
const char **cable_names = info->edev->supported_cable;
unsigned int con_sw = DM_DP_SWITCH_UART;
int ret, idx = 0, cable_type;
bool attached = false;
if (!cable_names)
return 0;
switch (event) {
case RT8973A_EVENT_ATTACH:
cable_type = rt8973a_muic_get_cable_type(info);
attached = true;
break;
case RT8973A_EVENT_DETACH:
cable_type = prev_cable_type;
attached = false;
break;
case RT8973A_EVENT_OVP:
case RT8973A_EVENT_OTP:
dev_warn(info->dev,
"happen Over %s issue. Need to disconnect all cables\n",
event == RT8973A_EVENT_OVP ? "Voltage" : "Temperature");
cable_type = prev_cable_type;
attached = false;
break;
default:
dev_err(info->dev,
"Cannot handle this event (event:%d)\n", event);
return -EINVAL;
}
prev_cable_type = cable_type;
switch (cable_type) {
case RT8973A_MUIC_ADC_OTG:
idx = EXTCON_CABLE_USB_HOST;
con_sw = DM_DP_SWITCH_USB;
break;
case RT8973A_MUIC_ADC_TA:
idx = EXTCON_CABLE_TA;
con_sw = DM_DP_SWITCH_OPEN;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
idx = EXTCON_CABLE_JIG_OFF_USB;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
idx = EXTCON_CABLE_JIG_ON_USB;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
idx = EXTCON_CABLE_JIG_OFF_UART;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
idx = EXTCON_CABLE_JIG_ON_UART;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_USB:
idx = EXTCON_CABLE_USB;
con_sw = DM_DP_SWITCH_USB;
break;
case RT8973A_MUIC_ADC_OPEN:
return 0;
case RT8973A_MUIC_ADC_UNKNOWN_ACC_1:
case RT8973A_MUIC_ADC_UNKNOWN_ACC_2:
case RT8973A_MUIC_ADC_UNKNOWN_ACC_3:
case RT8973A_MUIC_ADC_UNKNOWN_ACC_4:
case RT8973A_MUIC_ADC_UNKNOWN_ACC_5:
dev_warn(info->dev,
"Unknown accessory type (adc:0x%x)\n", cable_type);
return 0;
case RT8973A_MUIC_ADC_AUDIO_SEND_END_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S1_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S2_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S3_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S4_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S5_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S6_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S7_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S8_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S9_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S10_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S11_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_REMOTE_S12_BUTTON:
case RT8973A_MUIC_ADC_AUDIO_TYPE2:
dev_warn(info->dev,
"Audio device/button type (adc:0x%x)\n", cable_type);
return 0;
case RT8973A_MUIC_ADC_RESERVED_ACC_1:
case RT8973A_MUIC_ADC_RESERVED_ACC_2:
case RT8973A_MUIC_ADC_RESERVED_ACC_3:
case RT8973A_MUIC_ADC_RESERVED_ACC_4:
case RT8973A_MUIC_ADC_RESERVED_ACC_5:
case RT8973A_MUIC_ADC_PHONE_POWERED_DEV:
return 0;
default:
dev_err(info->dev,
"Cannot handle this cable_type (adc:0x%x)\n",
cable_type);
return -EINVAL;
}
/* Change internal hardware path(DM_CON/DP_CON) */
ret = rt8973a_muic_set_path(info, con_sw, attached);
if (ret < 0)
return ret;
/* Change the state of external accessory */
extcon_set_cable_state(info->edev, cable_names[idx], attached);
return 0;
}
static void rt8973a_muic_irq_work(struct work_struct *work)
{
struct rt8973a_muic_info *info = container_of(work,
struct rt8973a_muic_info, irq_work);
int ret = 0;
if (!info->edev)
return;
mutex_lock(&info->mutex);
/* Detect attached or detached cables */
if (info->irq_attach) {
ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_ATTACH);
info->irq_attach = false;
}
if (info->irq_detach) {
ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_DETACH);
info->irq_detach = false;
}
if (info->irq_ovp) {
ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_OVP);
info->irq_ovp = false;
}
if (info->irq_otp) {
ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_OTP);
info->irq_otp = false;
}
if (ret < 0)
dev_err(info->dev, "failed to handle MUIC interrupt\n");
mutex_unlock(&info->mutex);
}
static irqreturn_t rt8973a_muic_irq_handler(int irq, void *data)
{
struct rt8973a_muic_info *info = data;
int i, irq_type = -1;
for (i = 0; i < info->num_muic_irqs; i++)
if (irq == info->muic_irqs[i].virq)
irq_type = info->muic_irqs[i].irq;
switch (irq_type) {
case RT8973A_INT1_ATTACH:
info->irq_attach = true;
break;
case RT8973A_INT1_DETACH:
info->irq_detach = true;
break;
case RT8973A_INT1_OVP:
info->irq_ovp = true;
break;
case RT8973A_INT1_OTP:
info->irq_otp = true;
break;
case RT8973A_INT1_CHGDET:
case RT8973A_INT1_DCD_T:
case RT8973A_INT1_CONNECT:
case RT8973A_INT1_ADC_CHG:
case RT8973A_INT2_UVLO:
case RT8973A_INT2_POR:
case RT8973A_INT2_OTP_FET:
case RT8973A_INT2_OVP_FET:
case RT8973A_INT2_OCP_LATCH:
case RT8973A_INT2_OCP:
case RT8973A_INT2_OVP_OCP:
default:
dev_dbg(info->dev,
"Cannot handle this interrupt (%d)\n", irq_type);
break;
}
schedule_work(&info->irq_work);
return IRQ_HANDLED;
}
static void rt8973a_muic_detect_cable_wq(struct work_struct *work)
{
struct rt8973a_muic_info *info = container_of(to_delayed_work(work),
struct rt8973a_muic_info, wq_detcable);
int ret;
/* Notify the state of connector cable or not */
ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_ATTACH);
if (ret < 0)
dev_warn(info->dev, "failed to detect cable state\n");
}
static void rt8973a_init_dev_type(struct rt8973a_muic_info *info)
{
unsigned int data, vendor_id, version_id;
int i, ret;
/* To test I2C, Print version_id and vendor_id of RT8973A */
ret = regmap_read(info->regmap, RT8973A_REG_DEVICE_ID, &data);
if (ret) {
dev_err(info->dev,
"failed to read DEVICE_ID register: %d\n", ret);
return;
}
vendor_id = ((data & RT8973A_REG_DEVICE_ID_VENDOR_MASK) >>
RT8973A_REG_DEVICE_ID_VENDOR_SHIFT);
version_id = ((data & RT8973A_REG_DEVICE_ID_VERSION_MASK) >>
RT8973A_REG_DEVICE_ID_VERSION_SHIFT);
dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
version_id, vendor_id);
/* Initiazle the register of RT8973A device to bring-up */
for (i = 0; i < info->num_reg_data; i++) {
u8 reg = info->reg_data[i].reg;
u8 mask = info->reg_data[i].mask;
u8 val = 0;
if (info->reg_data[i].invert)
val = ~info->reg_data[i].val;
else
val = info->reg_data[i].val;
regmap_update_bits(info->regmap, reg, mask, val);
}
/* Check whether RT8973A is auto swithcing mode or not */
ret = regmap_read(info->regmap, RT8973A_REG_CONTROL1, &data);
if (ret) {
dev_err(info->dev,
"failed to read CONTROL1 register: %d\n", ret);
return;
}
data &= RT8973A_REG_CONTROL1_AUTO_CONFIG_MASK;
if (data) {
info->auto_config = true;
dev_info(info->dev,
"Enable Auto-configuration for internal path\n");
}
}
static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
struct rt8973a_muic_info *info;
int i, ret, irq_flags;
if (!np)
return -EINVAL;
info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
if (!info) {
dev_err(&i2c->dev, "failed to allocate memory\n");
return -ENOMEM;
}
i2c_set_clientdata(i2c, info);
info->dev = &i2c->dev;
info->i2c = i2c;
info->irq = i2c->irq;
info->muic_irqs = rt8973a_muic_irqs;
info->num_muic_irqs = ARRAY_SIZE(rt8973a_muic_irqs);
info->reg_data = rt8973a_reg_data;
info->num_reg_data = ARRAY_SIZE(rt8973a_reg_data);
mutex_init(&info->mutex);
INIT_WORK(&info->irq_work, rt8973a_muic_irq_work);
info->regmap = devm_regmap_init_i2c(i2c, &rt8973a_muic_regmap_config);
if (IS_ERR(info->regmap)) {
ret = PTR_ERR(info->regmap);
dev_err(info->dev, "failed to allocate register map: %d\n",
ret);
return ret;
}
/* Support irq domain for RT8973A MUIC device */
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
ret = regmap_add_irq_chip(info->regmap, info->irq, irq_flags, 0,
&rt8973a_muic_irq_chip, &info->irq_data);
if (ret != 0) {
dev_err(info->dev, "failed to add irq_chip (irq:%d, err:%d)\n",
info->irq, ret);
return ret;
}
for (i = 0; i < info->num_muic_irqs; i++) {
struct muic_irq *muic_irq = &info->muic_irqs[i];
unsigned int virq = 0;
virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq);
if (virq <= 0)
return -EINVAL;
muic_irq->virq = virq;
ret = devm_request_threaded_irq(info->dev, virq, NULL,
rt8973a_muic_irq_handler,
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);
return ret;
}
}
/* Allocate extcon device */
info->edev = devm_extcon_dev_allocate(info->dev, rt8973a_extcon_cable);
if (IS_ERR(info->edev)) {
dev_err(info->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
info->edev->name = np->name;
/* Register extcon device */
ret = devm_extcon_dev_register(info->dev, info->edev);
if (ret) {
dev_err(info->dev, "failed to register extcon device\n");
return ret;
}
/*
* Detect accessory after completing the initialization of platform
*
* - Use delayed workqueue to detect cable state and then
* notify cable state to notifiee/platform through uevent.
* After completing the booting of platform, the extcon provider
* driver should notify cable state to upper layer.
*/
INIT_DELAYED_WORK(&info->wq_detcable, rt8973a_muic_detect_cable_wq);
queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
msecs_to_jiffies(DELAY_MS_DEFAULT));
/* Initialize RT8973A device and print vendor id and version id */
rt8973a_init_dev_type(info);
return 0;
}
static int rt8973a_muic_i2c_remove(struct i2c_client *i2c)
{
struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
regmap_del_irq_chip(info->irq, info->irq_data);
return 0;
}
static struct of_device_id rt8973a_dt_match[] = {
{ .compatible = "richtek,rt8973a-muic" },
{ },
};
#ifdef CONFIG_PM_SLEEP
static int rt8973a_muic_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
enable_irq_wake(info->irq);
return 0;
}
static int rt8973a_muic_resume(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
disable_irq_wake(info->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(rt8973a_muic_pm_ops,
rt8973a_muic_suspend, rt8973a_muic_resume);
static const struct i2c_device_id rt8973a_i2c_id[] = {
{ "rt8973a", TYPE_RT8973A },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt8973a_i2c_id);
static struct i2c_driver rt8973a_muic_i2c_driver = {
.driver = {
.name = "rt8973a",
.owner = THIS_MODULE,
.pm = &rt8973a_muic_pm_ops,
.of_match_table = rt8973a_dt_match,
},
.probe = rt8973a_muic_i2c_probe,
.remove = rt8973a_muic_i2c_remove,
.id_table = rt8973a_i2c_id,
};
static int __init rt8973a_muic_i2c_init(void)
{
return i2c_add_driver(&rt8973a_muic_i2c_driver);
}
subsys_initcall(rt8973a_muic_i2c_init);
MODULE_DESCRIPTION("Richtek RT8973A Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,203 @@
/*
* 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 */

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
/* Received a torndown response */
wait_for_completion(&info->waitevent);
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;
}
/*

View File

@ -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)

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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)

View File

@ -12,7 +12,7 @@
* Software Foundation; version 2 of the License.
*/
#ifndef _IPOCTAL_H
#ifndef _IPOCTAL_H_
#define _IPOCTAL_H_
#define NR_CHANNELS 8

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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 @@ go_home:
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

View File

@ -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

View File

@ -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,

View File

@ -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. */

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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)
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *cb;
unsigned long timeout;
int rets;
int wait_ret;
struct mei_cl_cb *cb = NULL;
struct mei_cl *cl = file->private_data;
unsigned long timeout;
int i;
/* 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 @@ out:
* @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");
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
list_del(&pos->list);
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);
}
}

View File

@ -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;

View File

@ -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
*/
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
{
int i;
for (i = 0; i < dev->me_clients_num; i++)
if (dev->me_clients[i].client_id == client_id)
return i;
struct mei_me_client *me_cl;
return -ENOENT;
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)
{
struct mei_me_client *me_cl;
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;
}
/**
* 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 @@ free:
*
* @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 @@ out:
*
* @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 @@ out:
* @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 @@ out:
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)
{

View File

@ -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_ */

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -28,10 +28,10 @@
/**
* mei_me_reg_read - Reads 32bit data from the mei device
*
* @dev: the device structure
* @hw: the me hardware structure
* @offset: offset from which to read the data
*
* returns register value (u32)
* Return: register value (u32)
*/
static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
@ -43,7 +43,7 @@ static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
/**
* mei_me_reg_write - Writes 32bit data to the mei device
*
* @dev: the device structure
* @hw: the me hardware structure
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
@ -59,7 +59,7 @@ static inline void mei_me_reg_write(const struct mei_me_hw *hw,
*
* @dev: the device structure
*
* returns ME_CB_RW register value (u32)
* Return: ME_CB_RW register value (u32)
*/
static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
@ -68,9 +68,9 @@ static u32 mei_me_mecbrw_read(const struct mei_device *dev)
/**
* mei_me_mecsr_read - Reads 32bit data from the ME CSR
*
* @dev: the device structure
* @hw: the me hardware structure
*
* returns ME_CSR_HA register value (u32)
* Return: ME_CSR_HA register value (u32)
*/
static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
{
@ -80,9 +80,9 @@ static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
/**
* mei_hcsr_read - Reads 32bit data from the host CSR
*
* @dev: the device structure
* @hw: the me hardware structure
*
* returns H_CSR register value (u32)
* Return: H_CSR register value (u32)
*/
static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
@ -93,7 +93,8 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
* mei_hcsr_set - writes H_CSR register to the mei device,
* and ignores the H_IS bit for it is write-one-to-zero.
*
* @dev: the device structure
* @hw: the me hardware structure
* @hcsr: new register value
*/
static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
@ -101,6 +102,36 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
mei_me_reg_write(hw, H_CSR, hcsr);
}
/**
* mei_me_fw_status - read fw status register from pci config space
*
* @dev: mei device
* @fw_status: fw status register values
*
* Return: 0 on success, error otherwise
*/
static int mei_me_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
struct mei_me_hw *hw = to_me_hw(dev);
const struct mei_fw_status *fw_src = &hw->cfg->fw_status;
int ret;
int i;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
ret = pci_read_config_dword(pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
/**
* mei_me_hw_config - configure hw dependent settings
@ -121,17 +152,19 @@ static void mei_me_hw_config(struct mei_device *dev)
* mei_me_pg_state - translate internal pg state
* to the mei power gating state
*
* @hw - me hardware
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
* @dev: mei device
*
* Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
return hw->pg_state;
}
/**
* mei_clear_interrupts - clear and stop interrupts
* mei_me_intr_clear - clear and stop interrupts
*
* @dev: the device structure
*/
@ -139,6 +172,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
if ((hcsr & H_IS) == H_IS)
mei_me_reg_write(hw, H_CSR, hcsr);
}
@ -151,12 +185,13 @@ static void mei_me_intr_enable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
hcsr |= H_IE;
mei_hcsr_set(hw, hcsr);
}
/**
* mei_disable_interrupts - disables mei device interrupts
* mei_me_intr_disable - disables mei device interrupts
*
* @dev: the device structure
*/
@ -164,6 +199,7 @@ static void mei_me_intr_disable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
hcsr &= ~H_IE;
mei_hcsr_set(hw, hcsr);
}
@ -190,6 +226,8 @@ static void mei_me_hw_reset_release(struct mei_device *dev)
*
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
*
* Return: always 0
*/
static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
{
@ -213,10 +251,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
hcsr = mei_hcsr_read(hw);
if ((hcsr & H_RST) == 0)
dev_warn(&dev->pdev->dev, "H_RST is not set = 0x%08X", hcsr);
dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr);
if ((hcsr & H_RDY) == H_RDY)
dev_warn(&dev->pdev->dev, "H_RDY is not cleared 0x%08X", hcsr);
dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr);
if (intr_enable == false)
mei_me_hw_reset_release(dev);
@ -227,26 +265,27 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
/**
* mei_me_host_set_ready - enable device
*
* @dev - mei device
* returns bool
* @dev: mei device
*/
static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state = mei_hcsr_read(hw);
hw->host_hw_state |= H_IE | H_IG | H_RDY;
mei_hcsr_set(hw, hw->host_hw_state);
}
/**
* mei_me_host_is_ready - check whether the host has turned ready
*
* @dev - mei device
* returns bool
* @dev: mei device
* Return: bool
*/
static bool mei_me_host_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state = mei_hcsr_read(hw);
return (hw->host_hw_state & H_RDY) == H_RDY;
}
@ -254,43 +293,53 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
/**
* mei_me_hw_is_ready - check whether the me(hw) has turned ready
*
* @dev - mei device
* returns bool
* @dev: mei device
* Return: bool
*/
static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->me_hw_state = mei_me_mecsr_read(hw);
return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
/**
* mei_me_hw_ready_wait - wait until the me(hw) has turned ready
* or timeout is reached
*
* @dev: mei device
* Return: 0 on success, error otherwise
*/
static int mei_me_hw_ready_wait(struct mei_device *dev)
{
int err;
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
wait_event_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
if (!err)
err = -ETIME;
dev_err(&dev->pdev->dev,
"wait hw ready failed. status = %d\n", err);
return err;
if (!dev->recvd_hw_ready) {
dev_err(dev->dev, "wait hw ready failed\n");
return -ETIME;
}
dev->recvd_hw_ready = false;
return 0;
}
/**
* mei_me_hw_start - hw start routine
*
* @dev: mei device
* Return: 0 on success, error otherwise
*/
static int mei_me_hw_start(struct mei_device *dev)
{
int ret = mei_me_hw_ready_wait(dev);
if (ret)
return ret;
dev_dbg(&dev->pdev->dev, "hw is ready\n");
dev_dbg(dev->dev, "hw is ready\n");
mei_me_host_set_ready(dev);
return ret;
@ -302,7 +351,7 @@ static int mei_me_hw_start(struct mei_device *dev)
*
* @dev: the device structure
*
* returns number of filled slots
* Return: number of filled slots
*/
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
{
@ -322,7 +371,7 @@ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns true if empty, false - otherwise.
* Return: true if empty, false - otherwise.
*/
static bool mei_me_hbuf_is_empty(struct mei_device *dev)
{
@ -334,7 +383,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*
* @dev: the device structure
*
* returns -EOVERFLOW if overflow, otherwise empty slots count
* Return: -EOVERFLOW if overflow, otherwise empty slots count
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
@ -350,6 +399,13 @@ static int mei_me_hbuf_empty_slots(struct mei_device *dev)
return empty_slots;
}
/**
* mei_me_hbuf_max_len - returns size of hw buffer.
*
* @dev: the device structure
*
* Return: size of hw buffer in bytes
*/
static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
{
return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
@ -363,7 +419,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
* @header: mei HECI header of message
* @buf: message payload will be written
*
* This function returns -EIO if write has failed
* Return: -EIO if write has failed
*/
static int mei_me_write_message(struct mei_device *dev,
struct mei_msg_hdr *header,
@ -378,10 +434,10 @@ static int mei_me_write_message(struct mei_device *dev,
int i;
int empty_slots;
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
empty_slots = mei_hbuf_empty_slots(dev);
dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots);
dw_cnt = mei_data2slots(length);
if (empty_slots < 0 || dw_cnt > empty_slots)
@ -395,6 +451,7 @@ static int mei_me_write_message(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
mei_me_reg_write(hw, H_CB_WW, reg);
}
@ -412,7 +469,7 @@ static int mei_me_write_message(struct mei_device *dev,
*
* @dev: the device structure
*
* returns -EOVERFLOW if overflow, otherwise filled slots count
* Return: -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
@ -430,7 +487,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
if (filled_slots > buffer_depth)
return -EOVERFLOW;
dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
dev_dbg(dev->dev, "filled_slots =%08x\n", filled_slots);
return (int)filled_slots;
}
@ -440,6 +497,8 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
* @dev: the device structure
* @buffer: message buffer will be written
* @buffer_length: message size will be read
*
* Return: always 0
*/
static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned long buffer_length)
@ -453,6 +512,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
if (buffer_length > 0) {
u32 reg = mei_me_mecbrw_read(dev);
memcpy(reg_buf, &reg, buffer_length);
}
@ -462,7 +522,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
}
/**
* mei_me_pg_enter - write pg enter register to mei device.
* mei_me_pg_enter - write pg enter register
*
* @dev: the device structure
*/
@ -470,12 +530,13 @@ static void mei_me_pg_enter(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 reg = mei_me_reg_read(hw, H_HPG_CSR);
reg |= H_HPG_CSR_PGI;
mei_me_reg_write(hw, H_HPG_CSR, reg);
}
/**
* mei_me_pg_enter - write pg enter register to mei device.
* mei_me_pg_exit - write pg exit register
*
* @dev: the device structure
*/
@ -495,7 +556,7 @@ static void mei_me_pg_exit(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success an error code otherwise
* Return: 0 on success an error code otherwise
*/
int mei_me_pg_set_sync(struct mei_device *dev)
{
@ -532,7 +593,7 @@ int mei_me_pg_set_sync(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success an error code otherwise
* Return: 0 on success an error code otherwise
*/
int mei_me_pg_unset_sync(struct mei_device *dev)
{
@ -569,7 +630,7 @@ reply:
*
* @dev: the device structure
*
* returns: true is pg supported, false otherwise
* Return: true is pg supported, false otherwise
*/
static bool mei_me_pg_is_enabled(struct mei_device *dev)
{
@ -579,17 +640,13 @@ static bool mei_me_pg_is_enabled(struct mei_device *dev)
if ((reg & ME_PGIC_HRA) == 0)
goto notsupported;
if (dev->version.major_version < HBM_MAJOR_VERSION_PGI)
goto notsupported;
if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
dev->version.minor_version < HBM_MINOR_VERSION_PGI)
if (!dev->hbm_f_pg_supported)
goto notsupported;
return true;
notsupported:
dev_dbg(&dev->pdev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
dev_dbg(dev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
!!(reg & ME_PGIC_HRA),
dev->version.major_version,
dev->version.minor_version,
@ -605,7 +662,7 @@ notsupported:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: irqreturn_t
*/
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
@ -630,7 +687,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: irqreturn_t
*
*/
irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
@ -640,19 +697,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
/* Ack the interrupt here
* In case of MSI we don't go through the quick handler */
if (pci_dev_msi_enabled(dev->pdev))
if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_clear_interrupts(dev);
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
}
@ -661,19 +718,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
mei_me_hw_reset_release(dev);
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
wake_up_interruptible(&dev->wait_hw_ready);
wake_up(&dev->wait_hw_ready);
} else {
dev_dbg(&dev->pdev->dev, "Spurious Interrupt\n");
dev_dbg(dev->dev, "Spurious Interrupt\n");
}
goto end;
}
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
dev_dbg(dev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
/* There is a race between ME write and interrupt delivery:
* Not all data is always available immediately after the
@ -683,7 +740,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
break;
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n",
rets);
schedule_work(&dev->reset_work);
goto end;
@ -705,13 +762,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
static const struct mei_hw_ops mei_me_hw_ops = {
.fw_status = mei_me_fw_status,
.pg_state = mei_me_pg_state,
.host_is_ready = mei_me_host_is_ready,
@ -741,6 +799,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
static bool mei_me_fw_type_nm(struct pci_dev *pdev)
{
u32 reg;
pci_read_config_dword(pdev, PCI_CFG_HFS_2, &reg);
/* make sure that bit 9 (NM) is up and bit 10 (DM) is down */
return (reg & 0x600) == 0x200;
@ -809,23 +868,22 @@ const struct mei_cfg mei_me_lpt_cfg = {
* @pdev: The pci device structure
* @cfg: per device generation config
*
* returns The mei_device_device pointer on success, NULL on failure.
* Return: The mei_device_device pointer on success, NULL on failure.
*/
struct mei_device *mei_me_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg)
{
struct mei_device *dev;
struct mei_me_hw *hw;
dev = kzalloc(sizeof(struct mei_device) +
sizeof(struct mei_me_hw), GFP_KERNEL);
if (!dev)
return NULL;
hw = to_me_hw(dev);
mei_device_init(dev, cfg);
dev->ops = &mei_me_hw_ops;
dev->pdev = pdev;
mei_device_init(dev, &pdev->dev, &mei_me_hw_ops);
hw->cfg = cfg;
return dev;
}

View File

@ -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)

View File

@ -28,11 +28,12 @@
#include "hbm.h"
/**
* mei_txe_reg_read - Reads 32bit data from the device
* mei_txe_reg_read - Reads 32bit data from the txe device
*
* @base_addr: registers base address
* @offset: register offset
*
* Return: register value
*/
static inline u32 mei_txe_reg_read(void __iomem *base_addr,
unsigned long offset)
@ -41,7 +42,7 @@ static inline u32 mei_txe_reg_read(void __iomem *base_addr,
}
/**
* mei_txe_reg_write - Writes 32bit data to the device
* mei_txe_reg_write - Writes 32bit data to the txe device
*
* @base_addr: registers base address
* @offset: register offset
@ -56,10 +57,12 @@ static inline void mei_txe_reg_write(void __iomem *base_addr,
/**
* mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
*
* Doesn't check for aliveness while Reads 32bit data from the SeC BAR
*
* Return: register value
*/
static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
unsigned long offset)
@ -70,10 +73,12 @@ static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
*
* Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
*
* Return: register value
*/
static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@ -85,7 +90,7 @@ static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
* mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
* doesn't check for aliveness
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@ -100,7 +105,7 @@ static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
*
* @dev: the device structure
* @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@ -115,9 +120,10 @@ static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
*
* @hw: the device structure
* @hw: the txe hardware structure
* @offset: offset from which to read the data
*
* Return: the byte read.
*/
static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@ -128,7 +134,7 @@ static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
*
* @hw: the device structure
* @hw: the txe hardware structure
* @offset: offset from which to write the data
* @value: the byte to write
*/
@ -147,7 +153,10 @@ static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
* Request for aliveness change and returns true if the change is
* really needed and false if aliveness is already
* in the requested state
* Requires device lock to be held
*
* Locking: called under "dev->device_lock" lock
*
* Return: true if request was send
*/
static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
{
@ -155,7 +164,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
struct mei_txe_hw *hw = to_txe_hw(dev);
bool do_req = hw->aliveness != req;
dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
dev_dbg(dev->dev, "Aliveness current=%d request=%d\n",
hw->aliveness, req);
if (do_req) {
dev->pg_event = MEI_PG_EVENT_WAIT;
@ -172,26 +181,31 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
* from HICR_HOST_ALIVENESS_REQ register value
*
* Return: SICR_HOST_ALIVENESS_REQ_REQUESTED bit value
*/
static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
}
/**
* mei_txe_aliveness_get - get aliveness response register value
*
* @dev: the device structure
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit
* from HICR_HOST_ALIVENESS_RESP register value
* Return: HICR_HOST_ALIVENESS_RESP_ACK bit from HICR_HOST_ALIVENESS_RESP
* register
*/
static u32 mei_txe_aliveness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
return reg & HICR_HOST_ALIVENESS_RESP_ACK;
}
@ -203,7 +217,8 @@ static u32 mei_txe_aliveness_get(struct mei_device *dev)
* @expected: expected aliveness value
*
* Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
* returns > 0 if the expected value was received, -ETIME otherwise
*
* Return: > 0 if the expected value was received, -ETIME otherwise
*/
static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
{
@ -214,7 +229,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
hw->aliveness = mei_txe_aliveness_get(dev);
if (hw->aliveness == expected) {
dev->pg_event = MEI_PG_EVENT_IDLE;
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"aliveness settled after %d msecs\n", t);
return t;
}
@ -225,7 +240,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
} while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
dev->pg_event = MEI_PG_EVENT_IDLE;
dev_err(&dev->pdev->dev, "aliveness timed out\n");
dev_err(dev->dev, "aliveness timed out\n");
return -ETIME;
}
@ -236,7 +251,8 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
* @expected: expected aliveness value
*
* Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
* returns returns 0 on success and < 0 otherwise
*
* Return: 0 on success and < 0 otherwise
*/
static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
{
@ -259,10 +275,10 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
ret = hw->aliveness == expected ? 0 : -ETIME;
if (ret)
dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
dev_warn(dev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
err, hw->aliveness, dev->pg_event);
else
dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
dev_dbg(dev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
jiffies_to_msecs(timeout - err),
hw->aliveness, dev->pg_event);
@ -274,8 +290,9 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
* mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
*
* @dev: the device structure
* @req: requested aliveness value
*
* returns returns 0 on success and < 0 otherwise
* Return: 0 on success and < 0 otherwise
*/
int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
{
@ -289,7 +306,7 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
*
* @dev: the device structure
*
* returns: true is pg supported, false otherwise
* Return: true is pg supported, false otherwise
*/
static bool mei_txe_pg_is_enabled(struct mei_device *dev)
{
@ -302,11 +319,12 @@ static bool mei_txe_pg_is_enabled(struct mei_device *dev)
*
* @dev: the device structure
*
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
* Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON;
}
@ -326,9 +344,10 @@ static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
}
/**
* mei_txe_input_doorbell_set
* - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
* @dev: the device structure
* mei_txe_input_doorbell_set - sets bit 0 in
* SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
*
* @hw: the txe hardware structure
*/
static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
{
@ -340,7 +359,7 @@ static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
/**
* mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
*
* @dev: the device structure
* @hw: the txe hardware structure
*/
static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
{
@ -353,11 +372,14 @@ static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
* mei_txe_is_input_ready - check if TXE is ready for receiving data
*
* @dev: the device structure
*
* Return: true if INPUT STATUS READY bit is set
*/
static bool mei_txe_is_input_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 status;
status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
return !!(SEC_IPC_INPUT_STATUS_RDY & status);
}
@ -370,6 +392,7 @@ static bool mei_txe_is_input_ready(struct mei_device *dev)
static inline void mei_txe_intr_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
SEC_IPC_HOST_INT_STATUS_PENDING);
mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
@ -384,6 +407,7 @@ static inline void mei_txe_intr_clear(struct mei_device *dev)
static void mei_txe_intr_disable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, HHIER_REG, 0);
mei_txe_br_reg_write(hw, HIER_REG, 0);
}
@ -395,6 +419,7 @@ static void mei_txe_intr_disable(struct mei_device *dev)
static void mei_txe_intr_enable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
}
@ -407,6 +432,8 @@ static void mei_txe_intr_enable(struct mei_device *dev)
*
* Checks if there are pending interrupts
* only Aliveness, Readiness, Input ready, and Output doorbell are relevant
*
* Return: true if there are pending interrupts
*/
static bool mei_txe_pending_interrupts(struct mei_device *dev)
{
@ -418,7 +445,7 @@ static bool mei_txe_pending_interrupts(struct mei_device *dev)
TXE_INTR_OUT_DB));
if (ret) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
!!(hw->intr_cause & TXE_INTR_IN_READY),
!!(hw->intr_cause & TXE_INTR_READINESS),
@ -440,6 +467,7 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
unsigned long idx, u32 value)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
(idx * sizeof(u32)), value);
}
@ -451,12 +479,13 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
* @dev: the device structure
* @idx: index in the device buffer
*
* returns register value at index
* Return: register value at index
*/
static u32 mei_txe_out_data_read(const struct mei_device *dev,
unsigned long idx)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return mei_txe_br_reg_read(hw,
BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
}
@ -464,26 +493,28 @@ static u32 mei_txe_out_data_read(const struct mei_device *dev,
/* Readiness */
/**
* mei_txe_readiness_set_host_rdy
* mei_txe_readiness_set_host_rdy - set host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw,
SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_HOST_RDY);
}
/**
* mei_txe_readiness_clear
* mei_txe_readiness_clear - clear host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_RDY_CLR);
}
@ -492,10 +523,13 @@ static void mei_txe_readiness_clear(struct mei_device *dev)
* the HICR_SEC_IPC_READINESS register value
*
* @dev: the device structure
*
* Return: the HICR_SEC_IPC_READINESS register value
*/
static u32 mei_txe_readiness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
}
@ -504,7 +538,9 @@ static u32 mei_txe_readiness_get(struct mei_device *dev)
* mei_txe_readiness_is_sec_rdy - check readiness
* for HICR_SEC_IPC_READINESS_SEC_RDY
*
* @readiness - cached readiness state
* @readiness: cached readiness state
*
* Return: true if readiness bit is set
*/
static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
{
@ -515,10 +551,13 @@ static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
* mei_txe_hw_is_ready - check if the hw is ready
*
* @dev: the device structure
*
* Return: true if sec is ready
*/
static bool mei_txe_hw_is_ready(struct mei_device *dev)
{
u32 readiness = mei_txe_readiness_get(dev);
return mei_txe_readiness_is_sec_rdy(readiness);
}
@ -526,11 +565,14 @@ static bool mei_txe_hw_is_ready(struct mei_device *dev)
* mei_txe_host_is_ready - check if the host is ready
*
* @dev: the device structure
*
* Return: true if host is ready
*/
static inline bool mei_txe_host_is_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
}
@ -539,7 +581,7 @@ static inline bool mei_txe_host_is_ready(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 on success and -ETIME on timeout
* Return: 0 on success and -ETIME on timeout
*/
static int mei_txe_readiness_wait(struct mei_device *dev)
{
@ -551,7 +593,7 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!dev->recvd_hw_ready) {
dev_err(&dev->pdev->dev, "wait for readiness failed\n");
dev_err(dev->dev, "wait for readiness failed\n");
return -ETIME;
}
@ -559,6 +601,42 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
return 0;
}
static const struct mei_fw_status mei_txe_fw_sts = {
.count = 2,
.status[0] = PCI_CFG_TXE_FW_STS0,
.status[1] = PCI_CFG_TXE_FW_STS1
};
/**
* mei_txe_fw_status - read fw status register from pci config space
*
* @dev: mei device
* @fw_status: fw status register values
*
* Return: 0 on success, error otherwise
*/
static int mei_txe_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
const struct mei_fw_status *fw_src = &mei_txe_fw_sts;
struct pci_dev *pdev = to_pci_dev(dev->dev);
int ret;
int i;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
ret = pci_read_config_dword(pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
/**
* mei_txe_hw_config - configure hardware at the start of the devices
*
@ -571,13 +649,14 @@ static void mei_txe_hw_config(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
/* Doesn't change in runtime */
dev->hbuf_depth = PAYLOAD_SIZE / 4;
hw->aliveness = mei_txe_aliveness_get(dev);
hw->readiness = mei_txe_readiness_get(dev);
dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
dev_dbg(dev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
hw->aliveness, hw->readiness);
}
@ -588,7 +667,8 @@ static void mei_txe_hw_config(struct mei_device *dev)
* @dev: the device structure
* @header: header of message
* @buf: message buffer will be written
* returns 1 if success, 0 - otherwise.
*
* Return: 0 if success, <0 - otherwise.
*/
static int mei_txe_write(struct mei_device *dev,
@ -607,7 +687,7 @@ static int mei_txe_write(struct mei_device *dev,
length = header->length;
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dw_cnt = mei_data2slots(length);
if (dw_cnt > slots)
@ -621,8 +701,9 @@ static int mei_txe_write(struct mei_device *dev,
if (!mei_txe_is_input_ready(dev)) {
struct mei_fw_status fw_status;
mei_fw_status(dev, &fw_status);
dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n",
dev_err(dev->dev, "Input is not ready " FW_STS_FMT "\n",
FW_STS_PRM(fw_status));
return -EAGAIN;
}
@ -635,6 +716,7 @@ static int mei_txe_write(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
mei_txe_input_payload_write(dev, i + 1, reg);
}
@ -653,7 +735,7 @@ static int mei_txe_write(struct mei_device *dev,
*
* @dev: the device structure
*
* returns the PAYLOAD_SIZE - 4
* Return: the PAYLOAD_SIZE - 4
*/
static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
{
@ -665,11 +747,12 @@ static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
*
* @dev: the device structure
*
* returns always hbuf_depth
* Return: always hbuf_depth
*/
static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
return hw->slots;
}
@ -678,7 +761,7 @@ static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns always buffer size in dwords count
* Return: always buffer size in dwords count
*/
static int mei_txe_count_full_read_slots(struct mei_device *dev)
{
@ -691,7 +774,7 @@ static int mei_txe_count_full_read_slots(struct mei_device *dev)
*
* @dev: the device structure
*
* returns mei message header
* Return: mei message header
*/
static u32 mei_txe_read_hdr(const struct mei_device *dev)
@ -705,33 +788,35 @@ static u32 mei_txe_read_hdr(const struct mei_device *dev)
* @buf: message buffer will be written
* @len: message size will be read
*
* returns -EINVAL on error wrong argument and 0 on success
* Return: -EINVAL on error wrong argument and 0 on success
*/
static int mei_txe_read(struct mei_device *dev,
unsigned char *buf, unsigned long len)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 *reg_buf, reg;
u32 rem;
u32 i;
u32 *reg_buf = (u32 *)buf;
u32 rem = len & 0x3;
if (WARN_ON(!buf || !len))
return -EINVAL;
dev_dbg(&dev->pdev->dev,
"buffer-length = %lu buf[0]0x%08X\n",
reg_buf = (u32 *)buf;
rem = len & 0x3;
dev_dbg(dev->dev, "buffer-length = %lu buf[0]0x%08X\n",
len, mei_txe_out_data_read(dev, 0));
for (i = 0; i < len / 4; i++) {
/* skip header: index starts from 1 */
u32 reg = mei_txe_out_data_read(dev, i + 1);
dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
reg = mei_txe_out_data_read(dev, i + 1);
dev_dbg(dev->dev, "buf[%d] = 0x%08X\n", i, reg);
*reg_buf++ = reg;
}
if (rem) {
u32 reg = mei_txe_out_data_read(dev, i + 1);
reg = mei_txe_out_data_read(dev, i + 1);
memcpy(reg_buf, &reg, rem);
}
@ -745,7 +830,7 @@ static int mei_txe_read(struct mei_device *dev,
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
*
* returns 0 on success and < 0 in case of error
* Return: 0 on success and < 0 in case of error
*/
static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
{
@ -771,8 +856,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*/
if (aliveness_req != hw->aliveness)
if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
dev_err(&dev->pdev->dev,
"wait for aliveness settle failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness settle failed ... bailing out\n");
return -EIO;
}
@ -782,14 +866,13 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
if (aliveness_req) {
mei_txe_aliveness_set(dev, 0);
if (mei_txe_aliveness_poll(dev, 0) < 0) {
dev_err(&dev->pdev->dev,
"wait for aliveness failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return -EIO;
}
}
/*
* Set rediness RDY_CLR bit
* Set readiness RDY_CLR bit
*/
mei_txe_readiness_clear(dev);
@ -801,7 +884,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*
* @dev: the device structure
*
* returns 0 on success and < 0 in case of error
* Return: 0 on success an error code otherwise
*/
static int mei_txe_hw_start(struct mei_device *dev)
{
@ -815,7 +898,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_readiness_wait(dev);
if (ret < 0) {
dev_err(&dev->pdev->dev, "wating for readiness failed\n");
dev_err(dev->dev, "waiting for readiness failed\n");
return ret;
}
@ -831,7 +914,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_aliveness_set_sync(dev, 1);
if (ret < 0) {
dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return ret;
}
@ -857,6 +940,8 @@ static int mei_txe_hw_start(struct mei_device *dev)
*
* @dev: the device structure
* @do_ack: acknowledge interrupts
*
* Return: true if found interrupts to process.
*/
static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
{
@ -912,7 +997,8 @@ out:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
* Return: IRQ_WAKE_THREAD if interrupt is designed for the device
* IRQ_NONE otherwise
*/
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
{
@ -930,8 +1016,7 @@ irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
*
* Return: IRQ_HANDLED
*/
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
{
@ -941,7 +1026,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
dev_dbg(dev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
mei_txe_br_reg_read(hw, HHISR_REG),
mei_txe_br_reg_read(hw, HISR_REG),
mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
@ -951,7 +1036,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
if (pci_dev_msi_enabled(dev->pdev))
if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_txe_check_and_ack_intrs(dev, true);
/* show irq events */
@ -965,17 +1050,17 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
* or TXE driver resetting the HECI interface.
*/
if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
dev_dbg(dev->dev, "Readiness Interrupt was received...\n");
/* Check if SeC is going through reset */
if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
} else {
dev->recvd_hw_ready = false;
if (dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
@ -992,7 +1077,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
/* Clear the interrupt cause */
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"Aliveness Interrupt: Status: %d\n", hw->aliveness);
dev->pg_event = MEI_PG_EVENT_RECEIVED;
if (waitqueue_active(&hw->wait_aliveness_resp))
@ -1008,7 +1093,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
/* Read from TXE */
rets = mei_irq_read_handler(dev, &complete_list, &slots);
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"mei_irq_read_handler ret = %d.\n", rets);
schedule_work(&dev->reset_work);
@ -1026,7 +1111,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
rets = mei_irq_write_handler(dev, &complete_list);
if (rets && rets != -EMSGSIZE)
dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n",
rets);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
}
@ -1034,7 +1119,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
@ -1046,6 +1131,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.host_is_ready = mei_txe_host_is_ready,
.fw_status = mei_txe_fw_status,
.pg_state = mei_txe_pg_state,
.hw_is_ready = mei_txe_hw_is_ready,
@ -1072,27 +1158,14 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
};
#define MEI_CFG_TXE_FW_STS \
.fw_status.count = 2, \
.fw_status.status[0] = PCI_CFG_TXE_FW_STS0, \
.fw_status.status[1] = PCI_CFG_TXE_FW_STS1
const struct mei_cfg mei_txe_cfg = {
MEI_CFG_TXE_FW_STS,
};
/**
* mei_txe_dev_init - allocates and initializes txe hardware specific structure
*
* @pdev - pci device
* @cfg - per device generation config
*
* returns struct mei_device * on success or NULL;
* @pdev: pci device
*
* Return: struct mei_device * on success or NULL
*/
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)
{
struct mei_device *dev;
struct mei_txe_hw *hw;
@ -1102,15 +1175,12 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
if (!dev)
return NULL;
mei_device_init(dev, cfg);
mei_device_init(dev, &pdev->dev, &mei_txe_hw_ops);
hw = to_txe_hw(dev);
init_waitqueue_head(&hw->wait_aliveness_resp);
dev->ops = &mei_txe_hw_ops;
dev->pdev = pdev;
return dev;
}
@ -1120,6 +1190,8 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
* @dev: the device structure
* @addr: physical address start of the range
* @range: physical range size
*
* Return: 0 on success an error code otherwise
*/
int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
{
@ -1151,7 +1223,7 @@ int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
dev_dbg(dev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
range, lo32, ctrl);
return 0;

View File

@ -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);

View File

@ -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;

View File

@ -15,7 +15,6 @@
*/
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
@ -43,13 +42,23 @@ const char *mei_dev_state_str(int state)
#undef MEI_DEV_STATE
}
const char *mei_pg_state_str(enum mei_pg_state state)
{
#define MEI_PG_STATE(state) case MEI_PG_##state: return #state
switch (state) {
MEI_PG_STATE(OFF);
MEI_PG_STATE(ON);
default:
return "unknown";
}
#undef MEI_PG_STATE
}
/**
* mei_cancel_work. Cancel mei background jobs
* mei_cancel_work - Cancel mei background jobs
*
* @dev: the device structure
*
* returns 0 on success or < 0 if the reset hasn't succeeded
*/
void mei_cancel_work(struct mei_device *dev)
{
@ -64,6 +73,8 @@ EXPORT_SYMBOL_GPL(mei_cancel_work);
* mei_reset - resets host and fw.
*
* @dev: the device structure
*
* Return: 0 on success or < 0 if the reset hasn't succeeded
*/
int mei_reset(struct mei_device *dev)
{
@ -76,8 +87,9 @@ int mei_reset(struct mei_device *dev)
state != MEI_DEV_POWER_DOWN &&
state != MEI_DEV_POWER_UP) {
struct mei_fw_status fw_status;
mei_fw_status(dev, &fw_status);
dev_warn(&dev->pdev->dev,
dev_warn(dev->dev,
"unexpected reset: dev_state = %s " FW_STS_FMT "\n",
mei_dev_state_str(state), FW_STS_PRM(fw_status));
}
@ -95,7 +107,7 @@ int mei_reset(struct mei_device *dev)
dev->reset_count++;
if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
dev->dev_state = MEI_DEV_DISABLED;
return -ENODEV;
}
@ -116,7 +128,7 @@ int mei_reset(struct mei_device *dev)
mei_cl_all_wakeup(dev);
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
dev_dbg(dev->dev, "remove iamthif and wd from the file list.\n");
mei_cl_unlink(&dev->wd_cl);
mei_cl_unlink(&dev->iamthif_cl);
mei_amthif_reset_params(dev);
@ -128,28 +140,28 @@ int mei_reset(struct mei_device *dev)
dev->wd_pending = false;
if (ret) {
dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
dev_err(dev->dev, "hw_reset failed ret = %d\n", ret);
return ret;
}
if (state == MEI_DEV_POWER_DOWN) {
dev_dbg(&dev->pdev->dev, "powering down: end of reset\n");
dev_dbg(dev->dev, "powering down: end of reset\n");
dev->dev_state = MEI_DEV_DISABLED;
return 0;
}
ret = mei_hw_start(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
dev_err(dev->dev, "hw_start failed ret = %d\n", ret);
return ret;
}
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
dev_dbg(dev->dev, "link is established start sending messages.\n");
dev->dev_state = MEI_DEV_INIT_CLIENTS;
ret = mei_hbm_start_req(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
dev_err(dev->dev, "hbm_start failed ret = %d\n", ret);
dev->dev_state = MEI_DEV_RESETTING;
return ret;
}
@ -163,11 +175,12 @@ EXPORT_SYMBOL_GPL(mei_reset);
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_start(struct mei_device *dev)
{
int ret;
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interrupts */
@ -175,7 +188,7 @@ int mei_start(struct mei_device *dev)
mei_hw_config(dev);
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
dev_dbg(dev->dev, "reset in start the mei device.\n");
dev->reset_count = 0;
do {
@ -183,43 +196,43 @@ int mei_start(struct mei_device *dev)
ret = mei_reset(dev);
if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
dev_err(dev->dev, "reset failed ret = %d", ret);
goto err;
}
} while (ret);
/* we cannot start the device w/o hbm start message completed */
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed");
dev_err(dev->dev, "reset failed");
goto err;
}
if (mei_hbm_start_wait(dev)) {
dev_err(&dev->pdev->dev, "HBM haven't started");
dev_err(dev->dev, "HBM haven't started");
goto err;
}
if (!mei_host_is_ready(dev)) {
dev_err(&dev->pdev->dev, "host is not ready.\n");
dev_err(dev->dev, "host is not ready.\n");
goto err;
}
if (!mei_hw_is_ready(dev)) {
dev_err(&dev->pdev->dev, "ME is not ready.\n");
dev_err(dev->dev, "ME is not ready.\n");
goto err;
}
if (!mei_hbm_version_is_supported(dev)) {
dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
dev_dbg(dev->dev, "MEI start failed.\n");
goto err;
}
dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
dev_dbg(dev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock);
return 0;
err:
dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
dev_err(dev->dev, "link layer initialization failed.\n");
dev->dev_state = MEI_DEV_DISABLED;
mutex_unlock(&dev->device_lock);
return -ENODEV;
@ -231,7 +244,7 @@ EXPORT_SYMBOL_GPL(mei_start);
*
* @dev: the device structure
*
* returns 0 on success or -ENODEV if the restart hasn't succeeded
* Return: 0 on success or -ENODEV if the restart hasn't succeeded
*/
int mei_restart(struct mei_device *dev)
{
@ -249,7 +262,7 @@ int mei_restart(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
dev_err(dev->dev, "device disabled = %d\n", err);
return -ENODEV;
}
@ -275,7 +288,7 @@ static void mei_reset_work(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
dev_err(dev->dev, "device disabled = %d\n", ret);
return;
}
@ -286,7 +299,7 @@ static void mei_reset_work(struct work_struct *work)
void mei_stop(struct mei_device *dev)
{
dev_dbg(&dev->pdev->dev, "stopping the device.\n");
dev_dbg(dev->dev, "stopping the device.\n");
mei_cancel_work(dev);
@ -312,7 +325,7 @@ EXPORT_SYMBOL_GPL(mei_stop);
*
* @dev: the device structure
*
* returns true of there is no pending write
* Return: true of there is no pending write
*/
bool mei_write_is_idle(struct mei_device *dev)
{
@ -320,7 +333,7 @@ bool mei_write_is_idle(struct mei_device *dev)
list_empty(&dev->ctrl_wr_list.list) &&
list_empty(&dev->write_list.list));
dev_dbg(&dev->pdev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n",
dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n",
idle,
mei_dev_state_str(dev->dev_state),
list_empty(&dev->ctrl_wr_list.list),
@ -330,36 +343,25 @@ bool mei_write_is_idle(struct mei_device *dev)
}
EXPORT_SYMBOL_GPL(mei_write_is_idle);
int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status)
{
int i;
const struct mei_fw_status *fw_src = &dev->cfg->fw_status;
if (!fw_status)
return -EINVAL;
fw_status->count = fw_src->count;
for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
int ret;
ret = pci_read_config_dword(dev->pdev,
fw_src->status[i], &fw_status->status[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(mei_fw_status);
void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg)
/**
* mei_device_init -- initialize mei_device structure
*
* @dev: the mei device
* @device: the device structure
* @hw_ops: hw operations
*/
void mei_device_init(struct mei_device *dev,
struct device *device,
const struct mei_hw_ops *hw_ops)
{
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
INIT_LIST_HEAD(&dev->device_list);
INIT_LIST_HEAD(&dev->me_clients);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_hbm_start);
init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
dev->reset_count = 0;
@ -389,7 +391,8 @@ void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg)
bitmap_set(dev->host_clients_map, 0, 1);
dev->pg_event = MEI_PG_EVENT_IDLE;
dev->cfg = cfg;
dev->ops = hw_ops;
dev->dev = device;
}
EXPORT_SYMBOL_GPL(mei_device_init);

View File

@ -16,11 +16,11 @@
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/mei.h>
@ -33,8 +33,8 @@
* mei_irq_compl_handler - dispatch complete handlers
* for the completed callbacks
*
* @dev - mei device
* @compl_list - list of completed cbs
* @dev: mei device
* @compl_list: list of completed cbs
*/
void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
{
@ -47,7 +47,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
if (!cl)
continue;
dev_dbg(&dev->pdev->dev, "completing call back.\n");
dev_dbg(dev->dev, "completing call back.\n");
if (cl == &dev->iamthif_cl)
mei_amthif_complete(dev, cb);
else
@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
* @cl: host client
* @mei_hdr: header of mei client message
*
* returns true if matches, false otherwise
* Return: true if matches, false otherwise
*/
static inline int mei_cl_hbm_equal(struct mei_cl *cl,
struct mei_msg_hdr *mei_hdr)
@ -72,12 +72,12 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
}
/**
* mei_cl_is_reading - checks if the client
is the one to read this message
* is the one to read this message
*
* @cl: mei client
* @mei_hdr: header of mei message
*
* returns true on match and false otherwise
* Return: true on match and false otherwise
*/
static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
{
@ -87,13 +87,13 @@ static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
}
/**
* mei_irq_read_client_message - process client message
* mei_cl_irq_read_msg - process client message
*
* @dev: the device structure
* @mei_hdr: header of mei client message
* @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_cl_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
@ -126,7 +126,6 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
GFP_KERNEL);
if (!buffer) {
cl_err(dev, cl, "allocation failed.\n");
list_del(&cb->list);
return -ENOMEM;
}
@ -149,10 +148,10 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
break;
}
dev_dbg(&dev->pdev->dev, "message read\n");
dev_dbg(dev->dev, "message read\n");
if (!buffer) {
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n",
MEI_HDR_PRM(mei_hdr));
}
@ -166,7 +165,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -195,16 +194,16 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_irq_close - processes close related operation from
* mei_cl_irq_disconnect - processes close related operation from
* interrupt thread context - send disconnect request
*
* @cl: client
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
static int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
@ -235,14 +234,14 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
* mei_cl_irq_close - processes client read related operation from the
* mei_cl_irq_read - processes client read related operation from the
* interrupt thread context - request for flow control credits
*
* @cl: client
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -279,7 +278,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
* @cb: callback block.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
* Return: 0, OK; otherwise, error.
*/
static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@ -322,7 +321,7 @@ static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
* @cmpl_list: An instance of our list structure
* @slots: slots to read.
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_irq_read_handler(struct mei_device *dev,
struct mei_cl_cb *cmpl_list, s32 *slots)
@ -334,20 +333,20 @@ int mei_irq_read_handler(struct mei_device *dev,
if (!dev->rd_msg_hdr) {
dev->rd_msg_hdr = mei_read_hdr(dev);
(*slots)--;
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
dev_dbg(dev->dev, "slots =%08x.\n", *slots);
}
mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
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));
if (mei_hdr->reserved || !dev->rd_msg_hdr) {
dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n",
dev_err(dev->dev, "corrupted message header 0x%08X\n",
dev->rd_msg_hdr);
ret = -EBADMSG;
goto end;
}
if (mei_slots2data(*slots) < mei_hdr->length) {
dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
dev_err(dev->dev, "less data available than length=%08x.\n",
*slots);
/* we can't read the message */
ret = -ENODATA;
@ -358,7 +357,7 @@ int mei_irq_read_handler(struct mei_device *dev,
if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
ret = mei_hbm_dispatch(dev, mei_hdr);
if (ret) {
dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n",
dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
ret);
goto end;
}
@ -375,7 +374,7 @@ int mei_irq_read_handler(struct mei_device *dev,
/* if no recipient cl was found we assume corrupted header */
if (&cl->link == &dev->file_list) {
dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n",
dev_err(dev->dev, "no destination client found 0x%08X\n",
dev->rd_msg_hdr);
ret = -EBADMSG;
goto end;
@ -387,14 +386,14 @@ int mei_irq_read_handler(struct mei_device *dev,
ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret) {
dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n",
dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n",
ret);
goto end;
}
} else {
ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret) {
dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n",
dev_err(dev->dev, "mei_cl_irq_read_msg failed = %d\n",
ret);
goto end;
}
@ -407,7 +406,7 @@ reset_slots:
if (*slots == -EOVERFLOW) {
/* overflow - reset */
dev_err(&dev->pdev->dev, "resetting due to slots overflow.\n");
dev_err(dev->dev, "resetting due to slots overflow.\n");
/* set the event since message has been read */
ret = -ERANGE;
goto end;
@ -425,7 +424,7 @@ EXPORT_SYMBOL_GPL(mei_irq_read_handler);
* @dev: the device structure
* @cmpl_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
{
@ -445,7 +444,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
return -EMSGSIZE;
/* complete all waiting for write CB */
dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
dev_dbg(dev->dev, "complete all waiting for write cb.\n");
list = &dev->write_waiting_list;
list_for_each_entry_safe(cb, next, &list->list, list) {
@ -487,7 +486,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
}
/* complete control write list CB */
dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
dev_dbg(dev->dev, "complete control write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) {
cl = cb->cl;
if (!cl) {
@ -495,9 +494,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
return -ENODEV;
}
switch (cb->fop_type) {
case MEI_FOP_CLOSE:
case MEI_FOP_DISCONNECT:
/* send disconnect message */
ret = mei_cl_irq_close(cl, cb, cmpl_list);
ret = mei_cl_irq_disconnect(cl, cb, cmpl_list);
if (ret)
return ret;
@ -528,7 +527,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
}
/* complete write list CB */
dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
dev_dbg(dev->dev, "complete write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
cl = cb->cl;
if (cl == NULL)
@ -556,8 +555,6 @@ void mei_timer(struct work_struct *work)
{
unsigned long timeout;
struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
struct mei_device *dev = container_of(work,
struct mei_device, timer_work.work);
@ -571,7 +568,7 @@ void mei_timer(struct work_struct *work)
if (dev->init_clients_timer) {
if (--dev->init_clients_timer == 0) {
dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n",
dev_err(dev->dev, "timer: init clients timeout hbm_state = %d.\n",
dev->hbm_state);
mei_reset(dev);
goto out;
@ -586,7 +583,7 @@ void mei_timer(struct work_struct *work)
list_for_each_entry(cl, &dev->file_list, link) {
if (cl->timer_count) {
if (--cl->timer_count == 0) {
dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
mei_reset(dev);
goto out;
}
@ -598,7 +595,7 @@ void mei_timer(struct work_struct *work)
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
dev_err(&dev->pdev->dev, "timer: amthif hanged.\n");
dev_err(dev->dev, "timer: amthif hanged.\n");
mei_reset(dev);
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
@ -620,27 +617,20 @@ void mei_timer(struct work_struct *work)
timeout = dev->iamthif_timer +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
dev_dbg(dev->dev, "timeout = %ld\n", timeout);
dev_dbg(dev->dev, "jiffies = %ld\n", jiffies);
if (time_after(jiffies, timeout)) {
/*
* User didn't read the AMTHI data on time (15sec)
* freeing AMTHI for other requests
*/
dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
dev_dbg(dev->dev, "freeing AMTHI for other requests\n");
list_for_each_entry_safe(cb_pos, cb_next,
&dev->amthif_rd_complete_list.list, list) {
cl = cb_pos->file_object->private_data;
/* Finding the AMTHI entry. */
if (cl == &dev->iamthif_cl)
list_del(&cb_pos->list);
}
mei_io_list_flush(&dev->amthif_rd_complete_list,
&dev->iamthif_cl);
mei_io_cb_free(dev->iamthif_current_cb);
dev->iamthif_current_cb = NULL;

View File

@ -17,12 +17,12 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioctl.h>
@ -44,7 +44,7 @@
* @inode: pointer to inode structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
static int mei_open(struct inode *inode, struct file *file)
{
@ -63,7 +63,7 @@ static int mei_open(struct inode *inode, struct file *file)
err = -ENODEV;
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
dev_dbg(dev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto err_unlock;
}
@ -96,7 +96,7 @@ err_unlock:
* @inode: pointer to inode structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
* Return: 0 on success, <0 on error
*/
static int mei_release(struct inode *inode, struct file *file)
{
@ -157,7 +157,7 @@ out:
* @length: buffer length
* @offset: data offset in buffer
*
* returns >=0 data length on success , <0 on error
* Return: >=0 data length on success , <0 on error
*/
static ssize_t mei_read(struct file *file, char __user *ubuf,
size_t length, loff_t *offset)
@ -211,7 +211,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
err = mei_cl_read_start(cl, length);
if (err && err != -EBUSY) {
dev_dbg(&dev->pdev->dev,
dev_dbg(dev->dev,
"mei start read failure with status = %d\n", err);
rets = err;
goto out;
@ -254,7 +254,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
}
/* now copy the data to user space */
copy_buffer:
dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n",
cb->response_buffer.size, cb->buf_idx);
if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
rets = -EMSGSIZE;
@ -266,7 +266,7 @@ copy_buffer:
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;
goto free;
}
@ -285,7 +285,7 @@ free:
cl->reading_state = MEI_IDLE;
cl->read_cb = NULL;
out:
dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
mutex_unlock(&dev->device_lock);
return rets;
}
@ -297,17 +297,17 @@ out:
* @length: buffer length
* @offset: data offset in buffer
*
* returns >=0 data length on success , <0 on error
* Return: >=0 data length on success , <0 on error
*/
static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
struct mei_me_client *me_cl;
struct mei_cl_cb *write_cb = NULL;
struct mei_device *dev;
unsigned long timeout = 0;
int rets;
int id;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@ -321,8 +321,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
rets = -ENOTTY;
goto out;
}
@ -332,13 +332,13 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
if (length > dev->me_clients[id].props.max_msg_length) {
if (length > me_cl->props.max_msg_length) {
rets = -EFBIG;
goto out;
}
if (cl->state != MEI_FILE_CONNECTED) {
dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d",
dev_err(dev->dev, "host client = %d, is not connected to ME client = %d",
cl->host_client_id, cl->me_client_id);
rets = -ENODEV;
goto out;
@ -377,7 +377,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
write_cb = mei_io_cb_init(cl, file);
if (!write_cb) {
dev_err(&dev->pdev->dev, "write cb allocation failed\n");
rets = -ENOMEM;
goto out;
}
@ -387,7 +386,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets) {
dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
@ -396,7 +395,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = mei_amthif_write(dev, write_cb);
if (rets) {
dev_err(&dev->pdev->dev,
dev_err(dev->dev,
"amthif write failed with status = %d\n", rets);
goto out;
}
@ -415,27 +414,23 @@ out:
/**
* mei_ioctl_connect_client - the connect to fw client IOCTL function
*
* @dev: the device structure
* @data: IOCTL connect data, input and output parameters
* @file: private data of the file object
* @data: IOCTL connect data, input and output parameters
*
* Locking: called under "dev->device_lock" lock
*
* returns 0 on success, <0 on failure.
* Return: 0 on success, <0 on failure.
*/
static int mei_ioctl_connect_client(struct file *file,
struct mei_connect_client_data *data)
{
struct mei_device *dev;
struct mei_client *client;
struct mei_me_client *me_cl;
struct mei_cl *cl;
int i;
int rets;
cl = file->private_data;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
if (dev->dev_state != MEI_DEV_ENABLED) {
@ -450,28 +445,29 @@ static int mei_ioctl_connect_client(struct file *file,
}
/* find ME client we're trying to connect to */
i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
if (i < 0 || dev->me_clients[i].props.fixed_address) {
dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
if (!me_cl || me_cl->props.fixed_address) {
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
rets = -ENOTTY;
goto end;
}
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;
dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
cl->me_client_id);
dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
dev->me_clients[i].props.protocol_version);
dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
dev->me_clients[i].props.max_msg_length);
dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
me_cl->props.protocol_version);
dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
me_cl->props.max_msg_length);
/* if we're connecting to amthif client then we will use the
* existing connection
*/
if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
dev_dbg(dev->dev, "FW Client is amthi\n");
if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
rets = -ENODEV;
goto end;
@ -484,10 +480,8 @@ static int mei_ioctl_connect_client(struct file *file,
file->private_data = &dev->iamthif_cl;
client = &data->out_client_properties;
client->max_msg_length =
dev->me_clients[i].props.max_msg_length;
client->protocol_version =
dev->me_clients[i].props.protocol_version;
client->max_msg_length = me_cl->props.max_msg_length;
client->protocol_version = me_cl->props.protocol_version;
rets = dev->iamthif_cl.status;
goto end;
@ -496,9 +490,9 @@ static int mei_ioctl_connect_client(struct file *file,
/* prepare the output buffer */
client = &data->out_client_properties;
client->max_msg_length = dev->me_clients[i].props.max_msg_length;
client->protocol_version = dev->me_clients[i].props.protocol_version;
dev_dbg(&dev->pdev->dev, "Can connect?\n");
client->max_msg_length = me_cl->props.max_msg_length;
client->protocol_version = me_cl->props.protocol_version;
dev_dbg(dev->dev, "Can connect?\n");
rets = mei_cl_connect(cl, file);
@ -507,7 +501,6 @@ end:
return rets;
}
/**
* mei_ioctl - the IOCTL function
*
@ -515,24 +508,22 @@ end:
* @cmd: ioctl command
* @data: pointer to mei message structure
*
* returns 0 on success , <0 on error
* Return: 0 on success , <0 on error
*/
static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
struct mei_device *dev;
struct mei_cl *cl = file->private_data;
struct mei_connect_client_data *connect_data = NULL;
struct mei_connect_client_data connect_data;
int rets;
if (cmd != IOCTL_MEI_CONNECT_CLIENT)
return -EINVAL;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
dev_dbg(dev->dev, "IOCTL cmd = 0x%x", cmd);
mutex_lock(&dev->device_lock);
if (dev->dev_state != MEI_DEV_ENABLED) {
@ -540,38 +531,36 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
goto out;
}
dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
connect_data = kzalloc(sizeof(struct mei_connect_client_data),
GFP_KERNEL);
if (!connect_data) {
rets = -ENOMEM;
goto out;
}
dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
if (copy_from_user(connect_data, (char __user *)data,
switch (cmd) {
case IOCTL_MEI_CONNECT_CLIENT:
dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
if (copy_from_user(&connect_data, (char __user *)data,
sizeof(struct mei_connect_client_data))) {
dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
rets = mei_ioctl_connect_client(file, connect_data);
rets = mei_ioctl_connect_client(file, &connect_data);
if (rets)
goto out;
/* if all is ok, copying the data back to user. */
if (rets)
goto out;
dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
if (copy_to_user((char __user *)data, connect_data,
/* if all is ok, copying the data back to user. */
if (copy_to_user((char __user *)data, &connect_data,
sizeof(struct mei_connect_client_data))) {
dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto out;
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto out;
}
break;
default:
dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
rets = -ENOIOCTLCMD;
}
out:
kfree(connect_data);
mutex_unlock(&dev->device_lock);
return rets;
}
@ -583,7 +572,7 @@ out:
* @cmd: ioctl command
* @data: pointer to mei message structure
*
* returns 0 on success , <0 on error
* Return: 0 on success , <0 on error
*/
#ifdef CONFIG_COMPAT
static long mei_compat_ioctl(struct file *file,
@ -600,7 +589,7 @@ static long mei_compat_ioctl(struct file *file,
* @file: pointer to file structure
* @wait: pointer to poll_table structure
*
* returns poll mask
* Return: poll mask
*/
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
@ -670,7 +659,7 @@ static DEFINE_IDR(mei_idr);
*
* @dev: device pointer
*
* returns allocated minor, or -ENOSPC if no free minor left
* Return: allocated minor, or -ENOSPC if no free minor left
*/
static int mei_minor_get(struct mei_device *dev)
{
@ -681,7 +670,7 @@ static int mei_minor_get(struct mei_device *dev)
if (ret >= 0)
dev->minor = ret;
else if (ret == -ENOSPC)
dev_err(&dev->pdev->dev, "too many mei devices\n");
dev_err(dev->dev, "too many mei devices\n");
mutex_unlock(&mei_minor_lock);
return ret;

View File

@ -129,20 +129,18 @@ enum mei_wd_states {
/**
* enum mei_cb_file_ops - file operation associated with the callback
* @MEI_FOP_READ - read
* @MEI_FOP_WRITE - write
* @MEI_FOP_CONNECT - connect
* @MEI_FOP_DISCONNECT_RSP - disconnect response
* @MEI_FOP_OPEN - open
* @MEI_FOP_CLOSE - close
* @MEI_FOP_READ: read
* @MEI_FOP_WRITE: write
* @MEI_FOP_CONNECT: connect
* @MEI_FOP_DISCONNECT: disconnect
* @MEI_FOP_DISCONNECT_RSP: disconnect response
*/
enum mei_cb_file_ops {
MEI_FOP_READ = 0,
MEI_FOP_WRITE,
MEI_FOP_CONNECT,
MEI_FOP_DISCONNECT,
MEI_FOP_DISCONNECT_RSP,
MEI_FOP_OPEN,
MEI_FOP_CLOSE
};
/*
@ -159,8 +157,8 @@ struct mei_msg_data {
/*
* struct mei_fw_status - storage of FW status data
*
* @count - number of actually available elements in array
* @status - FW status registers
* @count: number of actually available elements in array
* @status: FW status registers
*/
struct mei_fw_status {
int count;
@ -170,11 +168,13 @@ struct mei_fw_status {
/**
* struct mei_me_client - representation of me (fw) client
*
* @props - client properties
* @client_id - me client id
* @mei_flow_ctrl_creds - flow control credits
* @list: link in me client list
* @props: client properties
* @client_id: me client id
* @mei_flow_ctrl_creds: flow control credits
*/
struct mei_me_client {
struct list_head list;
struct mei_client_properties props;
u8 client_id;
u8 mei_flow_ctrl_creds;
@ -186,8 +186,15 @@ struct mei_cl;
/**
* struct mei_cl_cb - file operation callback structure
*
* @cl - file client who is running this operation
* @fop_type - file operation type
* @list: link in callback queue
* @cl: file client who is running this operation
* @fop_type: file operation type
* @request_buffer: buffer to store request data
* @response_buffer: buffer to store response data
* @buf_idx: last read index
* @read_time: last read operation time stamp (iamthif)
* @file_object: pointer to file structure
* @internal: communication between driver and FW flag
*/
struct mei_cl_cb {
struct list_head list;
@ -201,7 +208,29 @@ struct mei_cl_cb {
u32 internal:1;
};
/* MEI client instance carried as file->private_data*/
/**
* struct mei_cl - me client host representation
* carried in file->private_data
*
* @link: link in the clients list
* @dev: mei parent device
* @state: file operation state
* @tx_wait: wait queue for tx completion
* @rx_wait: wait queue for rx completion
* @wait: wait queue for management operation
* @status: connection status
* @cl_uuid: client uuid name
* @host_client_id: host id
* @me_client_id: me/fw id
* @mei_flow_ctrl_creds: transmit flow credentials
* @timer_count: watchdog timer for operation completion
* @reading_state: state of the rx
* @writing_state: state of the tx
* @read_cb: current pending reading callback
*
* @device: device on the mei client bus
* @device_link: link to bus clients
*/
struct mei_cl {
struct list_head link;
struct mei_device *dev;
@ -210,7 +239,7 @@ struct mei_cl {
wait_queue_head_t rx_wait;
wait_queue_head_t wait;
int status;
/* ID of client connected */
uuid_le cl_uuid;
u8 host_client_id;
u8 me_client_id;
u8 mei_flow_ctrl_creds;
@ -222,35 +251,35 @@ struct mei_cl {
/* MEI CL bus data */
struct mei_cl_device *device;
struct list_head device_link;
uuid_le device_uuid;
};
/** struct mei_hw_ops
*
* @host_is_ready - query for host readiness
* @host_is_ready : query for host readiness
* @hw_is_ready - query if hw is ready
* @hw_reset - reset hw
* @hw_start - start hw after reset
* @hw_config - configure hw
* @hw_is_ready : query if hw is ready
* @hw_reset : reset hw
* @hw_start : start hw after reset
* @hw_config : configure hw
* @pg_state - power gating state of the device
* @pg_is_enabled - is power gating enabled
* @fw_status : get fw status registers
* @pg_state : power gating state of the device
* @pg_is_enabled : is power gating enabled
* @intr_clear - clear pending interrupts
* @intr_enable - enable interrupts
* @intr_disable - disable interrupts
* @intr_clear : clear pending interrupts
* @intr_enable : enable interrupts
* @intr_disable : disable interrupts
* @hbuf_free_slots - query for write buffer empty slots
* @hbuf_is_ready - query if write buffer is empty
* @hbuf_max_len - query for write buffer max len
* @hbuf_free_slots : query for write buffer empty slots
* @hbuf_is_ready : query if write buffer is empty
* @hbuf_max_len : query for write buffer max len
* @write - write a message to FW
* @write : write a message to FW
* @rdbuf_full_slots - query how many slots are filled
* @rdbuf_full_slots : query how many slots are filled
* @read_hdr - get first 4 bytes (header)
* @read - read a buffer from the FW
* @read_hdr : get first 4 bytes (header)
* @read : read a buffer from the FW
*/
struct mei_hw_ops {
@ -261,6 +290,8 @@ struct mei_hw_ops {
int (*hw_start)(struct mei_device *dev);
void (*hw_config)(struct mei_device *dev);
int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
enum mei_pg_state (*pg_state)(struct mei_device *dev);
bool (*pg_is_enabled)(struct mei_device *dev);
@ -328,11 +359,12 @@ void mei_cl_bus_exit(void);
* when being probed and shall use it for doing ME bus I/O.
*
* @dev: linux driver model device pointer
* @uuid: me client uuid
* @cl: mei client
* @ops: ME transport ops
* @event_work: async work to execute event callback
* @event_cb: Drivers register this callback to get asynchronous ME
* events (e.g. Rx buffer pending) notifications.
* @event_context: event callback run context
* @events: Events bitmask sent to the driver.
* @priv_data: client private data
*/
@ -352,7 +384,7 @@ struct mei_cl_device {
};
/**
/**
* enum mei_pg_event - power gating transition events
*
* @MEI_PG_EVENT_IDLE: the driver is not in power gating transition
@ -376,67 +408,106 @@ enum mei_pg_state {
MEI_PG_ON = 1,
};
/*
* mei_cfg
*
* @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)
const char *mei_pg_state_str(enum mei_pg_state state);
/**
* struct mei_device - MEI private device struct
* @pdev - pointer to pci device struct
* @cdev - character device
* @minor - minor number allocated for device
*
* @reset_count - limits the number of consecutive resets
* @hbm_state - state of host bus message protocol
* @pg_event - power gating event
* @mem_addr - mem mapped base register address
* @hbuf_depth - depth of hardware host/write buffer is slots
* @hbuf_is_ready - query if the host host/write buffer is ready
* @wr_msg - the buffer for hbm control messages
* @cfg - per device generation config and ops
* @dev : device on a bus
* @cdev : character device
* @minor : minor number allocated for device
*
* @read_list : read completion list
* @write_list : write pending list
* @write_waiting_list : write completion list
* @ctrl_wr_list : pending control write list
* @ctrl_rd_list : pending control read list
*
* @file_list : list of opened handles
* @open_handle_count: number of opened handles
*
* @device_lock : big device lock
* @timer_work : MEI timer delayed work (timeouts)
*
* @recvd_hw_ready : hw ready message received flag
*
* @wait_hw_ready : wait queue for receive HW ready message form FW
* @wait_pg : wait queue for receive PG message from FW
* @wait_hbm_start : wait queue for receive HBM start message from FW
* @wait_stop_wd : wait queue for receive WD stop message from FW
*
* @reset_count : number of consecutive resets
* @dev_state : device state
* @hbm_state : state of host bus message protocol
* @init_clients_timer : HBM init handshake timeout
*
* @pg_event : power gating event
* @pg_domain : runtime PM domain
*
* @rd_msg_buf : control messages buffer
* @rd_msg_hdr : read message header storage
*
* @hbuf_depth : depth of hardware host/write buffer is slots
* @hbuf_is_ready : query if the host host/write buffer is ready
* @wr_msg : the buffer for hbm control messages
*
* @version : HBM protocol version in use
* @hbm_f_pg_supported : hbm feature pgi protocol
*
* @me_clients : list of FW clients
* @me_clients_map : FW clients bit map
* @host_clients_map : host clients id pool
* @me_client_index : last FW client index in enumeration
*
* @wd_cl : watchdog client
* @wd_state : watchdog client state
* @wd_pending : watchdog command is pending
* @wd_timeout : watchdog expiration timeout
* @wd_data : watchdog message buffer
*
* @amthif_cmd_list : amthif list for cmd waiting
* @amthif_rd_complete_list : amthif list for reading completed cmd data
* @iamthif_file_object : file for current amthif operation
* @iamthif_cl : amthif host client
* @iamthif_current_cb : amthif current operation callback
* @iamthif_open_count : number of opened amthif connections
* @iamthif_mtu : amthif client max message length
* @iamthif_timer : time stamp of current amthif command completion
* @iamthif_stall_timer : timer to detect amthif hang
* @iamthif_msg_buf : amthif current message buffer
* @iamthif_msg_buf_size : size of current amthif message request buffer
* @iamthif_msg_buf_index : current index in amthif message request buffer
* @iamthif_state : amthif processor state
* @iamthif_flow_control_pending: amthif waits for flow control
* @iamthif_ioctl : wait for completion if amthif control message
* @iamthif_canceled : current amthif command is canceled
*
* @init_work : work item for the device init
* @reset_work : work item for the device reset
*
* @device_list : mei client bus list
*
* @dbgfs_dir : debugfs mei root directory
*
* @ops: : hw specific operations
* @hw : hw specific data
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
struct device *dev;
struct cdev cdev;
int minor;
/*
* lists of queues
*/
/* array of pointers to aio lists */
struct mei_cl_cb read_list; /* driver read queue */
struct mei_cl_cb write_list; /* driver write queue */
struct mei_cl_cb write_waiting_list; /* write waiting queue */
struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */
struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */
struct mei_cl_cb read_list;
struct mei_cl_cb write_list;
struct mei_cl_cb write_waiting_list;
struct mei_cl_cb ctrl_wr_list;
struct mei_cl_cb ctrl_rd_list;
/*
* list of files
*/
struct list_head file_list;
long open_handle_count;
/*
* lock for the device
*/
struct mutex device_lock; /* device lock */
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
struct mutex device_lock;
struct delayed_work timer_work;
bool recvd_hw_ready;
/*
@ -444,7 +515,7 @@ struct mei_device {
*/
wait_queue_head_t wait_hw_ready;
wait_queue_head_t wait_pg;
wait_queue_head_t wait_recvd_msg;
wait_queue_head_t wait_hbm_start;
wait_queue_head_t wait_stop_wd;
/*
@ -463,7 +534,7 @@ struct mei_device {
struct dev_pm_domain pg_domain;
#endif /* CONFIG_PM_RUNTIME */
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];
u32 rd_msg_hdr;
/* write buffer */
@ -477,12 +548,11 @@ struct mei_device {
} wr_msg;
struct hbm_version version;
unsigned int hbm_f_pg_supported:1;
struct mei_me_client *me_clients; /* Note: memory has to be allocated */
struct list_head me_clients;
DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
unsigned long me_clients_num;
unsigned long me_client_presentation_num;
unsigned long me_client_index;
struct mei_cl wd_cl;
@ -523,7 +593,6 @@ struct mei_device {
const struct mei_hw_ops *ops;
const struct mei_cfg *cfg;
char hw[0] __aligned(sizeof(void *));
};
@ -535,8 +604,10 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
/**
* mei_data2slots - get slots - number of (dwords) from a message length
* + size of the mei header
* @length - size of the messages in bytes
* returns - number of slots
*
* @length: size of the messages in bytes
*
* Return: number of slots
*/
static inline u32 mei_data2slots(size_t length)
{
@ -544,9 +615,11 @@ static inline u32 mei_data2slots(size_t length)
}
/**
* mei_slots2data- get data in slots - bytes from slots
* @slots - number of available slots
* returns - number of bytes in slots
* mei_slots2data - get data in slots - bytes from slots
*
* @slots: number of available slots
*
* Return: number of bytes in slots
*/
static inline u32 mei_slots2data(int slots)
{
@ -556,7 +629,9 @@ static inline u32 mei_slots2data(int slots)
/*
* mei init function prototypes
*/
void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg);
void mei_device_init(struct mei_device *dev,
struct device *device,
const struct mei_hw_ops *hw_ops);
int mei_reset(struct mei_device *dev);
int mei_start(struct mei_device *dev);
int mei_restart(struct mei_device *dev);
@ -622,12 +697,12 @@ int mei_wd_host_init(struct mei_device *dev);
/*
* mei_watchdog_register - Registering watchdog interface
* once we got connection to the WD Client
* @dev - mei device
* @dev: mei device
*/
int mei_watchdog_register(struct mei_device *dev);
/*
* mei_watchdog_unregister - Unregistering watchdog interface
* @dev - mei device
* @dev: mei device
*/
void mei_watchdog_unregister(struct mei_device *dev);
@ -723,7 +798,11 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
return dev->ops->rdbuf_full_slots(dev);
}
int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status);
static inline int mei_fw_status(struct mei_device *dev,
struct mei_fw_status *fw_status)
{
return dev->ops->fw_status(dev, fw_status);
}
#define FW_STS_FMT "%08X %08X"
#define FW_STS_PRM(fw_status) \

View File

@ -19,7 +19,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
@ -87,14 +88,20 @@ struct mei_nfc_hci_hdr {
#define MEI_NFC_HEADER_SIZE 10
/** mei_nfc_dev - NFC mei device
/**
* struct mei_nfc_dev - NFC mei device
*
* @cl: NFC host client
* @cl_info: NFC info host client
* @init_work: perform connection to the info client
* @send_wq: send completion wait queue
* @fw_ivn: NFC Interface Version Number
* @vendor_id: NFC manufacturer ID
* @radio_type: NFC radio type
* @bus_name: bus name
*
* @req_id: message counter
* @recv_req_id: reception message counter
*/
struct mei_nfc_dev {
struct mei_cl *cl;
@ -163,7 +170,7 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
return 0;
default:
dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n",
dev_err(dev->dev, "Unknown radio type 0x%x\n",
ndev->radio_type);
return -EINVAL;
@ -175,14 +182,14 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
ndev->bus_name = "pn544";
return 0;
default:
dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n",
dev_err(dev->dev, "Unknown radio type 0x%x\n",
ndev->radio_type);
return -EINVAL;
}
default:
dev_err(&dev->pdev->dev, "Unknown vendor ID 0x%x\n",
dev_err(dev->dev, "Unknown vendor ID 0x%x\n",
ndev->vendor_id);
return -EINVAL;
@ -231,21 +238,21 @@ static int mei_nfc_connect(struct mei_nfc_dev *ndev)
ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
dev_err(dev->dev, "Could not send connect cmd\n");
goto err;
}
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
if (bytes_recv < 0) {
dev_err(&dev->pdev->dev, "Could not read connect response\n");
dev_err(dev->dev, "Could not read connect response\n");
ret = bytes_recv;
goto err;
}
dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
dev_info(dev->dev, "IVN 0x%x Vendor ID 0x%x\n",
connect_resp->fw_ivn, connect_resp->vendor_id);
dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
dev_info(dev->dev, "ME FW %d.%d.%d.%d\n",
connect_resp->me_major, connect_resp->me_minor,
connect_resp->me_hotfix, connect_resp->me_build);
@ -279,7 +286,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
dev_err(dev->dev, "Could not send IF version cmd\n");
return ret;
}
@ -293,7 +300,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
dev_err(&dev->pdev->dev, "Could not read IF version\n");
dev_err(dev->dev, "Could not read IF version\n");
ret = -EIO;
goto err;
}
@ -319,7 +326,7 @@ static int mei_nfc_enable(struct mei_cl_device *cldev)
ret = mei_nfc_connect(ndev);
if (ret < 0) {
dev_err(&dev->pdev->dev, "Could not connect to NFC");
dev_err(dev->dev, "Could not connect to NFC");
return ret;
}
@ -361,7 +368,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
if (!wait_event_interruptible_timeout(ndev->send_wq,
ndev->recv_req_id == ndev->req_id, HZ)) {
dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
dev_err(dev->dev, "NFC MEI command timeout\n");
err = -ETIME;
} else {
ndev->req_id++;
@ -418,8 +425,7 @@ static void mei_nfc_init(struct work_struct *work)
if (mei_cl_connect(cl_info, NULL) < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
"Could not connect to the NFC INFO ME client");
dev_err(dev->dev, "Could not connect to the NFC INFO ME client");
goto err;
}
@ -427,21 +433,19 @@ static void mei_nfc_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (mei_nfc_if_version(ndev) < 0) {
dev_err(&dev->pdev->dev, "Could not get the NFC interface version");
dev_err(dev->dev, "Could not get the NFC interface version");
goto err;
}
dev_info(&dev->pdev->dev,
"NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
dev_info(dev->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
mutex_lock(&dev->device_lock);
if (mei_cl_disconnect(cl_info) < 0) {
mutex_unlock(&dev->device_lock);
dev_err(&dev->pdev->dev,
"Could not disconnect the NFC INFO ME client");
dev_err(dev->dev, "Could not disconnect the NFC INFO ME client");
goto err;
}
@ -449,15 +453,13 @@ static void mei_nfc_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (mei_nfc_build_bus_name(ndev) < 0) {
dev_err(&dev->pdev->dev,
"Could not build the bus ID name\n");
dev_err(dev->dev, "Could not build the bus ID name\n");
return;
}
cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
if (!cldev) {
dev_err(&dev->pdev->dev,
"Could not add the NFC device to the MEI bus\n");
dev_err(dev->dev, "Could not add the NFC device to the MEI bus\n");
goto err;
}
@ -472,7 +474,6 @@ err:
mei_nfc_free(ndev);
mutex_unlock(&dev->device_lock);
return;
}
@ -480,7 +481,8 @@ int mei_nfc_host_init(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
struct mei_cl *cl_info, *cl = NULL;
int i, ret;
struct mei_me_client *me_cl;
int ret;
/* already initialized */
if (ndev->cl_info)
@ -498,40 +500,38 @@ int mei_nfc_host_init(struct mei_device *dev)
}
/* check for valid client id */
i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (!me_cl) {
dev_info(dev->dev, "nfc: failed to find the client\n");
ret = -ENOTTY;
goto err;
}
cl_info->me_client_id = dev->me_clients[i].client_id;
cl_info->me_client_id = me_cl->client_id;
cl_info->cl_uuid = me_cl->props.protocol_name;
ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
if (ret)
goto err;
cl_info->device_uuid = mei_nfc_info_guid;
list_add_tail(&cl_info->device_link, &dev->device_list);
/* check for valid client id */
i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (!me_cl) {
dev_info(dev->dev, "nfc: failed to find the client\n");
ret = -ENOTTY;
goto err;
}
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;
ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
if (ret)
goto err;
cl->device_uuid = mei_nfc_guid;
list_add_tail(&cl->device_link, &dev->device_list);
ndev->req_id = 1;
@ -551,6 +551,7 @@ err:
void mei_nfc_host_exit(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
cancel_work_sync(&ndev->init_work);
}

View File

@ -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 @@ end:
}
/**
* 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 */

View File

@ -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 */

View File

@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/watchdog.h>
@ -42,7 +41,7 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
{
dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout);
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
}
@ -52,14 +51,14 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
*
* @dev: the device structure
*
* returns -ENOTTY if wd client cannot be found
* Return: -ENOTTY if wd client cannot be found
* -EIO if write has failed
* 0 on success
*/
int mei_wd_host_init(struct mei_device *dev)
{
struct mei_cl *cl = &dev->wd_cl;
int id;
struct mei_me_client *me_cl;
int ret;
mei_cl_init(cl, dev);
@ -69,25 +68,26 @@ int mei_wd_host_init(struct mei_device *dev)
/* check for valid client id */
id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (id < 0) {
dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (!me_cl) {
dev_info(dev->dev, "wd: failed to find the client\n");
return -ENOTTY;
}
cl->me_client_id = dev->me_clients[id].client_id;
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
if (ret < 0) {
dev_info(&dev->pdev->dev, "wd: failed link client\n");
dev_info(dev->dev, "wd: failed link client\n");
return ret;
}
ret = mei_cl_connect(cl, NULL);
if (ret) {
dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
mei_cl_unlink(cl);
return ret;
}
@ -105,7 +105,7 @@ int mei_wd_host_init(struct mei_device *dev)
*
* @dev: the device structure
*
* returns 0 if success,
* Return: 0 if success,
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
* -ENODEV on flow control failure
@ -127,19 +127,19 @@ int mei_wd_send(struct mei_device *dev)
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
hdr.length = MEI_WD_STOP_MSG_SIZE;
else {
dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n");
return -EINVAL;
}
ret = mei_write_message(dev, &hdr, dev->wd_data);
if (ret) {
dev_err(&dev->pdev->dev, "wd: write message failed\n");
dev_err(dev->dev, "wd: write message failed\n");
return ret;
}
ret = mei_cl_flow_ctrl_reduce(cl);
if (ret) {
dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n");
return ret;
}
@ -150,9 +150,8 @@ int mei_wd_send(struct mei_device *dev)
* mei_wd_stop - sends watchdog stop message to fw.
*
* @dev: the device structure
* @preserve: indicate if to keep the timeout value
*
* returns 0 if success
* Return: 0 if success
* on error:
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
@ -192,11 +191,10 @@ int mei_wd_stop(struct mei_device *dev)
if (dev->wd_state != MEI_WD_IDLE) {
/* timeout */
ret = -ETIME;
dev_warn(&dev->pdev->dev,
"wd: stop failed to complete ret=%d.\n", ret);
dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret);
goto err;
}
dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
dev_dbg(dev->dev, "wd: stop completed after %u msec\n",
MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
return 0;
err:
@ -208,7 +206,7 @@ err:
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_start(struct watchdog_device *wd_dev)
{
@ -222,15 +220,13 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev,
"wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto end_unlock;
}
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
dev_dbg(&dev->pdev->dev,
"MEI Driver is not connected to Watchdog Client\n");
dev_dbg(dev->dev, "MEI Driver is not connected to Watchdog Client\n");
goto end_unlock;
}
@ -247,7 +243,7 @@ end_unlock:
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
{
@ -269,7 +265,7 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
*
* @wd_dev - watchdog device struct
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
@ -283,7 +279,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
dev_err(&dev->pdev->dev, "wd: not connected.\n");
dev_err(dev->dev, "wd: not connected.\n");
ret = -ENODEV;
goto end;
}
@ -296,7 +292,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
/* Check if we can send the ping to HW*/
if (ret && mei_hbuf_acquire(dev)) {
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
dev_dbg(dev->dev, "wd: sending ping\n");
ret = mei_wd_send(dev);
if (ret)
@ -317,7 +313,7 @@ end:
* @wd_dev - watchdog device struct
* @timeout - timeout value to set
*
* returns 0 if success, negative errno code for failure
* Return: 0 if success, negative errno code for failure
*/
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
unsigned int timeout)
@ -379,13 +375,12 @@ int mei_watchdog_register(struct mei_device *dev)
ret = watchdog_register_device(&amt_wd_dev);
mutex_lock(&dev->device_lock);
if (ret) {
dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n",
ret);
return ret;
}
dev_dbg(&dev->pdev->dev,
"wd: successfully register watchdog interface.\n");
dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n");
watchdog_set_drvdata(&amt_wd_dev, dev);
return 0;
}

View File

@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/delay.h>
@ -743,58 +744,33 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
struct config_item *cg_item;
struct configfs_subsystem *subsys;
/* get resource for application registers*/
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res0) {
dev_err(&pdev->dev, "no resource defined\n");
return -EBUSY;
}
if (!request_mem_region(res0->start, resource_size(res0),
pdev->name)) {
dev_err(&pdev->dev, "pcie gadget region already claimed\n");
return -EBUSY;
}
/* get resource for dbi registers*/
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res1) {
dev_err(&pdev->dev, "no resource defined\n");
goto err_rel_res0;
}
if (!request_mem_region(res1->start, resource_size(res1),
pdev->name)) {
dev_err(&pdev->dev, "pcie gadget region already claimed\n");
goto err_rel_res0;
}
target = kzalloc(sizeof(*target), GFP_KERNEL);
target = devm_kzalloc(&pdev->dev, sizeof(*target), GFP_KERNEL);
if (!target) {
dev_err(&pdev->dev, "out of memory\n");
status = -ENOMEM;
goto err_rel_res;
return -ENOMEM;
}
cg_item = &target->subsys.su_group.cg_item;
sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id);
cg_item->ci_type = &pcie_gadget_target_type;
config = &target->config;
config->va_app_base = (void __iomem *)ioremap(res0->start,
resource_size(res0));
if (!config->va_app_base) {
/* get resource for application registers*/
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
config->va_app_base = devm_ioremap_resource(&pdev->dev, res0);
if (IS_ERR(config->va_app_base)) {
dev_err(&pdev->dev, "ioremap fail\n");
status = -ENOMEM;
goto err_kzalloc;
return PTR_ERR(config->va_app_base);
}
/* get resource for dbi registers*/
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
config->base = (void __iomem *)res1->start;
config->va_dbi_base = (void __iomem *)ioremap(res1->start,
resource_size(res1));
if (!config->va_dbi_base) {
config->va_dbi_base = devm_ioremap_resource(&pdev->dev, res1);
if (IS_ERR(config->va_dbi_base)) {
dev_err(&pdev->dev, "ioremap fail\n");
status = -ENOMEM;
goto err_iounmap_app;
return PTR_ERR(config->va_dbi_base);
}
platform_set_drvdata(pdev, target);
@ -802,15 +778,15 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no update irq?\n");
status = irq;
goto err_iounmap;
return irq;
}
status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL);
status = devm_request_irq(&pdev->dev, irq, spear_pcie_gadget_irq,
0, pdev->name, NULL);
if (status) {
dev_err(&pdev->dev,
"pcie gadget interrupt IRQ%d already claimed\n", irq);
goto err_iounmap;
return status;
}
/* Register configfs hooks */
@ -819,7 +795,7 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
mutex_init(&subsys->su_mutex);
status = configfs_register_subsystem(subsys);
if (status)
goto err_irq;
return status;
/*
* init basic pcie application registers
@ -835,13 +811,12 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
clk = clk_get_sys("pcie1", NULL);
if (IS_ERR(clk)) {
pr_err("%s:couldn't get clk for pcie1\n", __func__);
status = PTR_ERR(clk);
goto err_irq;
return PTR_ERR(clk);
}
status = clk_enable(clk);
if (status) {
pr_err("%s:couldn't enable clk for pcie1\n", __func__);
goto err_irq;
return status;
}
} else if (pdev->id == 2) {
/*
@ -851,53 +826,26 @@ static int spear_pcie_gadget_probe(struct platform_device *pdev)
clk = clk_get_sys("pcie2", NULL);
if (IS_ERR(clk)) {
pr_err("%s:couldn't get clk for pcie2\n", __func__);
status = PTR_ERR(clk);
goto err_irq;
return PTR_ERR(clk);
}
status = clk_enable(clk);
if (status) {
pr_err("%s:couldn't enable clk for pcie2\n", __func__);
goto err_irq;
return status;
}
}
spear13xx_pcie_device_init(config);
return 0;
err_irq:
free_irq(irq, NULL);
err_iounmap:
iounmap(config->va_dbi_base);
err_iounmap_app:
iounmap(config->va_app_base);
err_kzalloc:
kfree(target);
err_rel_res:
release_mem_region(res1->start, resource_size(res1));
err_rel_res0:
release_mem_region(res0->start, resource_size(res0));
return status;
}
static int spear_pcie_gadget_remove(struct platform_device *pdev)
{
struct resource *res0, *res1;
static struct pcie_gadget_target *target;
struct spear_pcie_gadget_config *config;
int irq;
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(pdev, 0);
target = platform_get_drvdata(pdev);
config = &target->config;
free_irq(irq, NULL);
iounmap(config->va_dbi_base);
iounmap(config->va_app_base);
release_mem_region(res1->start, resource_size(res1));
release_mem_region(res0->start, resource_size(res0));
configfs_unregister_subsystem(&target->subsys);
kfree(target);
return 0;
}

View File

@ -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 ");

View File

@ -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;

View File

@ -1702,6 +1702,46 @@ static int parport_ECP_supported(struct parport *pb)
}
#endif
#ifdef CONFIG_X86_32
static int intel_bug_present_check_epp(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
int bug_present = 0;
if (priv->ecr) {
/* store value of ECR */
unsigned char ecr = inb(ECONTROL(pb));
unsigned char i;
for (i = 0x00; i < 0x80; i += 0x20) {
ECR_WRITE(pb, i);
if (clear_epp_timeout(pb)) {
/* Phony EPP in ECP. */
bug_present = 1;
break;
}
}
/* return ECR into the inital state */
ECR_WRITE(pb, ecr);
}
return bug_present;
}
static int intel_bug_present(struct parport *pb)
{
/* Check whether the device is legacy, not PCI or PCMCIA. Only legacy is known to be affected. */
if (pb->dev != NULL) {
return 0;
}
return intel_bug_present_check_epp(pb);
}
#else
static int intel_bug_present(struct parport *pb)
{
return 0;
}
#endif /* CONFIG_X86_32 */
static int parport_ECPPS2_supported(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
@ -1722,8 +1762,6 @@ static int parport_ECPPS2_supported(struct parport *pb)
static int parport_EPP_supported(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
/*
* Theory:
* Bit 0 of STR is the EPP timeout bit, this bit is 0
@ -1742,16 +1780,8 @@ static int parport_EPP_supported(struct parport *pb)
return 0; /* No way to clear timeout */
/* Check for Intel bug. */
if (priv->ecr) {
unsigned char i;
for (i = 0x00; i < 0x80; i += 0x20) {
ECR_WRITE(pb, i);
if (clear_epp_timeout(pb)) {
/* Phony EPP in ECP. */
return 0;
}
}
}
if (intel_bug_present(pb))
return 0;
pb->modes |= PARPORT_MODE_EPP;

View File

@ -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,

View File

@ -172,6 +172,7 @@ struct ipack_bus_ops {
* @ops: bus operations for the mezzanine drivers
*/
struct ipack_bus_device {
struct module *owner;
struct device *parent;
int slots;
int bus_nr;
@ -189,7 +190,8 @@ struct ipack_bus_device {
* available bus device in ipack.
*/
struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
const struct ipack_bus_ops *ops);
const struct ipack_bus_ops *ops,
struct module *owner);
/**
* ipack_bus_unregister -- unregister an ipack bus
@ -265,3 +267,23 @@ void ipack_put_device(struct ipack_device *dev);
.format = (_format), \
.vendor = (vend), \
.device = (dev)
/**
* ipack_get_carrier - it increase the carrier ref. counter of
* the carrier module
* @dev: mezzanine device which wants to get the carrier
*/
static inline int ipack_get_carrier(struct ipack_device *dev)
{
return try_module_get(dev->bus->owner);
}
/**
* ipack_get_carrier - it decrease the carrier ref. counter of
* the carrier module
* @dev: mezzanine device which wants to get the carrier
*/
static inline void ipack_put_carrier(struct ipack_device *dev)
{
module_put(dev->bus->owner);
}

View File

@ -3,6 +3,7 @@
#include <linux/device.h>
#include <linux/uuid.h>
#include <linux/mod_devicetable.h>
struct mei_cl_device;

View File

@ -268,7 +268,7 @@ struct kim_data_s {
struct st_data_s *core_data;
struct chip_version version;
unsigned char ldisc_install;
unsigned char dev_name[UART_DEV_NAME_LEN];
unsigned char dev_name[UART_DEV_NAME_LEN + 1];
unsigned char flow_cntrl;
unsigned long baud_rate;
};

View File

@ -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

View File

@ -137,7 +137,7 @@ struct hv_do_fcopy {
__u64 offset;
__u32 size;
__u8 data[DATA_FRAGMENT];
};
} __attribute__((packed));
/*
* An implementation of HyperV key value pair (KVP) functionality for Linux.