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:
commit
ef0625b70d
|
@ -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>;
|
||||
};
|
|
@ -150,6 +150,7 @@ winbond Winbond Electronics corp.
|
|||
wlf Wolfson Microelectronics
|
||||
wm Wondermedia Technologies, Inc.
|
||||
xes Extreme Engineering Solutions (X-ES)
|
||||
xillybus Xillybus Ltd.
|
||||
xlnx Xilinx
|
||||
zyxel ZyXEL Communications Corp.
|
||||
zarlink Zarlink Semiconductor
|
||||
|
|
|
@ -651,6 +651,7 @@ struct i8k_config_data {
|
|||
|
||||
enum i8k_configs {
|
||||
DELL_LATITUDE_D520,
|
||||
DELL_LATITUDE_E6540,
|
||||
DELL_PRECISION_490,
|
||||
DELL_STUDIO,
|
||||
DELL_XPS_M140,
|
||||
|
@ -661,6 +662,10 @@ static const struct i8k_config_data i8k_config_data[] = {
|
|||
.fan_mult = 1,
|
||||
.fan_max = I8K_FAN_TURBO,
|
||||
},
|
||||
[DELL_LATITUDE_E6540] = {
|
||||
.fan_mult = 1,
|
||||
.fan_max = I8K_FAN_HIGH,
|
||||
},
|
||||
[DELL_PRECISION_490] = {
|
||||
.fan_mult = 1,
|
||||
.fan_max = I8K_FAN_TURBO,
|
||||
|
@ -705,6 +710,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
|
|||
},
|
||||
.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
|
||||
},
|
||||
{
|
||||
.ident = "Dell Latitude E6540",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"),
|
||||
},
|
||||
.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
|
||||
},
|
||||
{
|
||||
.ident = "Dell Latitude 2",
|
||||
.matches = {
|
||||
|
|
|
@ -843,7 +843,6 @@ static struct platform_driver hwicap_platform_driver = {
|
|||
.probe = hwicap_drv_probe,
|
||||
.remove = hwicap_drv_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = hwicap_of_match,
|
||||
},
|
||||
|
|
|
@ -70,8 +70,21 @@ config EXTCON_PALMAS
|
|||
Say Y here to enable support for USB peripheral and USB host
|
||||
detection by palmas usb.
|
||||
|
||||
config EXTCON_RT8973A
|
||||
tristate "RT8973A EXTCON support"
|
||||
depends on I2C
|
||||
select IRQ_DOMAIN
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
If you say yes here you get support for the MUIC device of
|
||||
Richtek RT8973A. The RT8973A is a USB port accessory detector
|
||||
and switch that is optimized to protect low voltage system
|
||||
from abnormal high input voltage (up to 28V).
|
||||
|
||||
config EXTCON_SM5502
|
||||
tristate "SM5502 EXTCON support"
|
||||
depends on I2C
|
||||
select IRQ_DOMAIN
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
|
|
|
@ -10,4 +10,5 @@ obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
|
|||
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
|
||||
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
|
||||
obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
|
||||
obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o
|
||||
obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
|
||||
|
|
|
@ -20,16 +20,16 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/extcon/extcon-gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/extcon/extcon-gpio.h>
|
||||
|
||||
struct gpio_extcon_data {
|
||||
struct extcon_dev *edev;
|
||||
|
|
|
@ -255,10 +255,14 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
|
|||
case ADC_DEBOUNCE_TIME_10MS:
|
||||
case ADC_DEBOUNCE_TIME_25MS:
|
||||
case ADC_DEBOUNCE_TIME_38_62MS:
|
||||
ret = regmap_update_bits(info->max77693->regmap_muic,
|
||||
MAX77693_MUIC_REG_CTRL3,
|
||||
CONTROL3_ADCDBSET_MASK,
|
||||
time << CONTROL3_ADCDBSET_SHIFT);
|
||||
/*
|
||||
* Don't touch BTLDset, JIGset when you want to change adc
|
||||
* debounce time. If it writes other than 0 to BTLDset, JIGset
|
||||
* muic device will be reset and loose current state.
|
||||
*/
|
||||
ret = regmap_write(info->max77693->regmap_muic,
|
||||
MAX77693_MUIC_REG_CTRL3,
|
||||
time << CONTROL3_ADCDBSET_SHIFT);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "failed to set ADC debounce time\n");
|
||||
return ret;
|
||||
|
@ -1155,13 +1159,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
|||
|
||||
virq = regmap_irq_get_virq(max77693->irq_data_muic,
|
||||
muic_irq->irq);
|
||||
if (!virq) {
|
||||
ret = -EINVAL;
|
||||
goto err_irq;
|
||||
}
|
||||
if (!virq)
|
||||
return -EINVAL;
|
||||
muic_irq->virq = virq;
|
||||
|
||||
ret = request_threaded_irq(virq, NULL,
|
||||
ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
|
||||
max77693_muic_irq_handler,
|
||||
IRQF_NO_SUSPEND,
|
||||
muic_irq->name, info);
|
||||
|
@ -1170,7 +1172,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
|||
"failed: irq request (IRQ: %d,"
|
||||
" error :%d)\n",
|
||||
muic_irq->irq, ret);
|
||||
goto err_irq;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1179,15 +1181,14 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
|||
max77693_extcon_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_irq;
|
||||
return -ENOMEM;
|
||||
}
|
||||
info->edev->name = DEV_NAME;
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||
goto err_irq;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize MUIC register by using platform data or default data */
|
||||
|
@ -1265,7 +1266,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
|||
MAX77693_MUIC_REG_ID, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to read revision number\n");
|
||||
goto err_irq;
|
||||
return ret;
|
||||
}
|
||||
dev_info(info->dev, "device ID : 0x%x\n", id);
|
||||
|
||||
|
@ -1285,20 +1286,12 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
|||
delay_jiffies);
|
||||
|
||||
return ret;
|
||||
|
||||
err_irq:
|
||||
while (--i >= 0)
|
||||
free_irq(muic_irqs[i].virq, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77693_muic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max77693_muic_info *info = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
|
||||
free_irq(muic_irqs[i].virq, info);
|
||||
cancel_work_sync(&info->irq_work);
|
||||
input_unregister_device(info->dock);
|
||||
|
||||
|
|
|
@ -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");
|
|
@ -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 */
|
|
@ -8,16 +8,10 @@
|
|||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -26,7 +20,8 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/extcon/sm5502.h>
|
||||
|
||||
#include "extcon-sm5502.h"
|
||||
|
||||
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
|
||||
|
||||
|
@ -300,7 +295,7 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
|
|||
* If ADC is SM5502_MUIC_ADC_GROUND(0x0), external cable hasn't
|
||||
* connected with to MUIC device.
|
||||
*/
|
||||
cable_type &= SM5502_REG_ADC_MASK;
|
||||
cable_type = adc & SM5502_REG_ADC_MASK;
|
||||
if (cable_type == SM5502_MUIC_ADC_GROUND)
|
||||
return SM5502_MUIC_ADC_GROUND;
|
||||
|
||||
|
@ -395,7 +390,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
|
|||
/* Get the type of attached or detached cable */
|
||||
if (attached)
|
||||
cable_type = sm5502_muic_get_cable_type(info);
|
||||
else if (!attached)
|
||||
else
|
||||
cable_type = prev_cable_type;
|
||||
prev_cable_type = cable_type;
|
||||
|
||||
|
@ -457,8 +452,6 @@ static void sm5502_muic_irq_work(struct work_struct *work)
|
|||
dev_err(info->dev, "failed to handle MUIC interrupt\n");
|
||||
|
||||
mutex_unlock(&info->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -617,8 +610,9 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
|
|||
IRQF_NO_SUSPEND,
|
||||
muic_irq->name, info);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "failed: irq request (IRQ: %d,"
|
||||
" error :%d)\n", muic_irq->irq, ret);
|
||||
dev_err(info->dev,
|
||||
"failed: irq request (IRQ: %d, error :%d)\n",
|
||||
muic_irq->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_EXTCON_SM5502_H
|
|
@ -165,8 +165,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
|
|||
ret = vmbus_post_msg(open_msg,
|
||||
sizeof(struct vmbus_channel_open_channel));
|
||||
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
err = ret;
|
||||
goto error1;
|
||||
}
|
||||
|
||||
t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
|
||||
if (t == 0) {
|
||||
|
@ -363,7 +365,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
|
|||
u32 next_gpadl_handle;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int t;
|
||||
|
||||
next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
|
||||
atomic_inc(&vmbus_connection.next_gpadl_handle);
|
||||
|
@ -410,9 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
|
|||
|
||||
}
|
||||
}
|
||||
t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
|
||||
BUG_ON(t == 0);
|
||||
|
||||
wait_for_completion(&msginfo->waitevent);
|
||||
|
||||
/* At this point, we received the gpadl created msg */
|
||||
*gpadl_handle = gpadlmsg->gpadl;
|
||||
|
@ -435,7 +434,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
|
|||
struct vmbus_channel_gpadl_teardown *msg;
|
||||
struct vmbus_channel_msginfo *info;
|
||||
unsigned long flags;
|
||||
int ret, t;
|
||||
int ret;
|
||||
|
||||
info = kmalloc(sizeof(*info) +
|
||||
sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
|
||||
|
@ -457,11 +456,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
|
|||
ret = vmbus_post_msg(msg,
|
||||
sizeof(struct vmbus_channel_gpadl_teardown));
|
||||
|
||||
BUG_ON(ret != 0);
|
||||
t = wait_for_completion_timeout(&info->waitevent, 5*HZ);
|
||||
BUG_ON(t == 0);
|
||||
if (ret)
|
||||
goto post_msg_err;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -224,11 +224,14 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
|
|||
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
|
||||
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
|
||||
|
||||
if (channel->target_cpu != smp_processor_id())
|
||||
if (channel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(channel->target_cpu,
|
||||
percpu_channel_deq, channel, true);
|
||||
else
|
||||
} else {
|
||||
percpu_channel_deq(channel);
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
if (channel->primary_channel == NULL) {
|
||||
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
|
||||
|
@ -294,12 +297,15 @@ static void vmbus_process_offer(struct work_struct *work)
|
|||
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
|
||||
|
||||
if (enq) {
|
||||
if (newchannel->target_cpu != smp_processor_id())
|
||||
if (newchannel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(newchannel->target_cpu,
|
||||
percpu_channel_enq,
|
||||
newchannel, true);
|
||||
else
|
||||
} else {
|
||||
percpu_channel_enq(newchannel);
|
||||
put_cpu();
|
||||
}
|
||||
}
|
||||
if (!fnew) {
|
||||
/*
|
||||
|
@ -314,12 +320,15 @@ static void vmbus_process_offer(struct work_struct *work)
|
|||
list_add_tail(&newchannel->sc_list, &channel->sc_list);
|
||||
spin_unlock_irqrestore(&channel->sc_lock, flags);
|
||||
|
||||
if (newchannel->target_cpu != smp_processor_id())
|
||||
if (newchannel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(newchannel->target_cpu,
|
||||
percpu_channel_enq,
|
||||
newchannel, true);
|
||||
else
|
||||
} else {
|
||||
percpu_channel_enq(newchannel);
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
newchannel->state = CHANNEL_OPEN_STATE;
|
||||
if (channel->sc_creation_callback != NULL)
|
||||
|
|
|
@ -427,10 +427,21 @@ int vmbus_post_msg(void *buffer, size_t buflen)
|
|||
* insufficient resources. Retry the operation a couple of
|
||||
* times before giving up.
|
||||
*/
|
||||
while (retries < 3) {
|
||||
ret = hv_post_message(conn_id, 1, buffer, buflen);
|
||||
if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
|
||||
while (retries < 10) {
|
||||
ret = hv_post_message(conn_id, 1, buffer, buflen);
|
||||
|
||||
switch (ret) {
|
||||
case HV_STATUS_INSUFFICIENT_BUFFERS:
|
||||
ret = -ENOMEM;
|
||||
case -ENOMEM:
|
||||
break;
|
||||
case HV_STATUS_SUCCESS:
|
||||
return ret;
|
||||
default:
|
||||
pr_err("hv_post_msg() failed; error code:%d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retries++;
|
||||
msleep(100);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,8 @@ int hv_init(void)
|
|||
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
|
||||
memset(hv_context.synic_message_page, 0,
|
||||
sizeof(void *) * NR_CPUS);
|
||||
memset(hv_context.post_msg_page, 0,
|
||||
sizeof(void *) * NR_CPUS);
|
||||
memset(hv_context.vp_index, 0,
|
||||
sizeof(int) * NR_CPUS);
|
||||
memset(hv_context.event_dpc, 0,
|
||||
|
@ -217,26 +219,18 @@ int hv_post_message(union hv_connection_id connection_id,
|
|||
enum hv_message_type message_type,
|
||||
void *payload, size_t payload_size)
|
||||
{
|
||||
struct aligned_input {
|
||||
u64 alignment8;
|
||||
struct hv_input_post_message msg;
|
||||
};
|
||||
|
||||
struct hv_input_post_message *aligned_msg;
|
||||
u16 status;
|
||||
unsigned long addr;
|
||||
|
||||
if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
|
||||
return -EMSGSIZE;
|
||||
|
||||
addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
|
||||
aligned_msg = (struct hv_input_post_message *)
|
||||
(ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN));
|
||||
hv_context.post_msg_page[get_cpu()];
|
||||
|
||||
aligned_msg->connectionid = connection_id;
|
||||
aligned_msg->reserved = 0;
|
||||
aligned_msg->message_type = message_type;
|
||||
aligned_msg->payload_size = payload_size;
|
||||
memcpy((void *)aligned_msg->payload, payload, payload_size);
|
||||
|
@ -244,8 +238,7 @@ int hv_post_message(union hv_connection_id connection_id,
|
|||
status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
|
||||
& 0xFFFF;
|
||||
|
||||
kfree((void *)addr);
|
||||
|
||||
put_cpu();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -294,6 +287,14 @@ int hv_synic_alloc(void)
|
|||
pr_err("Unable to allocate SYNIC event page\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
hv_context.post_msg_page[cpu] =
|
||||
(void *)get_zeroed_page(GFP_ATOMIC);
|
||||
|
||||
if (hv_context.post_msg_page[cpu] == NULL) {
|
||||
pr_err("Unable to allocate post msg page\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -308,6 +309,8 @@ static void hv_synic_free_cpu(int cpu)
|
|||
free_page((unsigned long)hv_context.synic_event_page[cpu]);
|
||||
if (hv_context.synic_message_page[cpu])
|
||||
free_page((unsigned long)hv_context.synic_message_page[cpu]);
|
||||
if (hv_context.post_msg_page[cpu])
|
||||
free_page((unsigned long)hv_context.post_msg_page[cpu]);
|
||||
}
|
||||
|
||||
void hv_synic_free(void)
|
||||
|
|
|
@ -515,6 +515,10 @@ struct hv_context {
|
|||
* per-cpu list of the channels based on their CPU affinity.
|
||||
*/
|
||||
struct list_head percpu_list[NR_CPUS];
|
||||
/*
|
||||
* buffer to post messages to the host.
|
||||
*/
|
||||
void *post_msg_page[NR_CPUS];
|
||||
};
|
||||
|
||||
extern struct hv_context hv_context;
|
||||
|
|
|
@ -361,6 +361,11 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
|
|||
ring_info->ring_buffer->read_index =
|
||||
ring_info->ring_buffer->write_index = 0;
|
||||
|
||||
/*
|
||||
* Set the feature bit for enabling flow control.
|
||||
*/
|
||||
ring_info->ring_buffer->feature_bits.value = 1;
|
||||
|
||||
ring_info->ring_size = buflen;
|
||||
ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
|
||||
|
||||
|
|
|
@ -572,7 +572,8 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
|
|||
/* Register the carrier in the industry pack bus driver */
|
||||
tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
|
||||
TPCI200_NB_SLOT,
|
||||
&tpci200_bus_ops);
|
||||
&tpci200_bus_ops,
|
||||
THIS_MODULE);
|
||||
if (!tpci200->info->ipack_bus) {
|
||||
dev_err(&pdev->dev,
|
||||
"error registering the carrier on ipack driver\n");
|
||||
|
|
|
@ -55,6 +55,22 @@ struct ipoctal {
|
|||
u8 __iomem *int_space;
|
||||
};
|
||||
|
||||
static inline struct ipoctal *chan_to_ipoctal(struct ipoctal_channel *chan,
|
||||
unsigned int index)
|
||||
{
|
||||
return container_of(chan, struct ipoctal, channel[index]);
|
||||
}
|
||||
|
||||
static void ipoctal_reset_channel(struct ipoctal_channel *channel)
|
||||
{
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
|
||||
}
|
||||
|
||||
static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct ipoctal_channel *channel;
|
||||
|
@ -72,12 +88,20 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
|
||||
static int ipoctal_open(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
struct ipoctal_channel *channel;
|
||||
struct ipoctal_channel *channel = dev_get_drvdata(tty->dev);
|
||||
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
int err;
|
||||
|
||||
channel = dev_get_drvdata(tty->dev);
|
||||
tty->driver_data = channel;
|
||||
|
||||
return tty_port_open(&channel->tty_port, tty, file);
|
||||
if (!ipack_get_carrier(ipoctal->dev))
|
||||
return -EBUSY;
|
||||
|
||||
err = tty_port_open(&channel->tty_port, tty, file);
|
||||
if (err)
|
||||
ipack_put_carrier(ipoctal->dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ipoctal_reset_stats(struct ipoctal_stats *stats)
|
||||
|
@ -151,7 +175,6 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
|
|||
flag = TTY_FRAME;
|
||||
}
|
||||
if (sr & SR_RECEIVED_BREAK) {
|
||||
iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
|
||||
channel->stats.rcv_break++;
|
||||
flag = TTY_BREAK;
|
||||
}
|
||||
|
@ -196,6 +219,9 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
|
|||
isr = ioread8(&channel->block_regs->r.isr);
|
||||
sr = ioread8(&channel->regs->r.sr);
|
||||
|
||||
if (isr & (IMR_DELTA_BREAK_A | IMR_DELTA_BREAK_B))
|
||||
iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr);
|
||||
|
||||
if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
|
||||
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
/* In case of RS-485, change from TX to RX when finishing TX.
|
||||
|
@ -304,10 +330,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
|
|||
channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
|
||||
}
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
ipoctal_reset_channel(channel);
|
||||
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
|
||||
&channel->regs->w.mr); /* mr1 */
|
||||
iowrite8(0, &channel->regs->w.mr); /* mr2 */
|
||||
|
@ -467,11 +490,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
|
|||
cflag = tty->termios.c_cflag;
|
||||
|
||||
/* Disable and reset everything before change the setup */
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
|
||||
ipoctal_reset_channel(channel);
|
||||
|
||||
/* Set Bits per chars */
|
||||
switch (cflag & CSIZE) {
|
||||
|
@ -609,12 +628,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
|
|||
|
||||
tty_port_hangup(&channel->tty_port);
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
|
||||
ipoctal_reset_channel(channel);
|
||||
|
||||
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
|
||||
wake_up_interruptible(&channel->tty_port.open_wait);
|
||||
|
@ -627,15 +641,19 @@ static void ipoctal_shutdown(struct tty_struct *tty)
|
|||
if (channel == NULL)
|
||||
return;
|
||||
|
||||
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
|
||||
channel->rx_enable = 0;
|
||||
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
|
||||
iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
|
||||
ipoctal_reset_channel(channel);
|
||||
clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
|
||||
}
|
||||
|
||||
static void ipoctal_cleanup(struct tty_struct *tty)
|
||||
{
|
||||
struct ipoctal_channel *channel = tty->driver_data;
|
||||
struct ipoctal *ipoctal = chan_to_ipoctal(channel, tty->index);
|
||||
|
||||
/* release the carrier driver */
|
||||
ipack_put_carrier(ipoctal->dev);
|
||||
}
|
||||
|
||||
static const struct tty_operations ipoctal_fops = {
|
||||
.ioctl = NULL,
|
||||
.open = ipoctal_open,
|
||||
|
@ -647,6 +665,7 @@ static const struct tty_operations ipoctal_fops = {
|
|||
.get_icount = ipoctal_get_icount,
|
||||
.hangup = ipoctal_hangup,
|
||||
.shutdown = ipoctal_shutdown,
|
||||
.cleanup = ipoctal_cleanup,
|
||||
};
|
||||
|
||||
static int ipoctal_probe(struct ipack_device *dev)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#ifndef _IPOCTAL_H
|
||||
#ifndef _IPOCTAL_H_
|
||||
#define _IPOCTAL_H_
|
||||
|
||||
#define NR_CHANNELS 8
|
||||
|
|
|
@ -206,7 +206,8 @@ static struct bus_type ipack_bus_type = {
|
|||
};
|
||||
|
||||
struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
|
||||
const struct ipack_bus_ops *ops)
|
||||
const struct ipack_bus_ops *ops,
|
||||
struct module *owner)
|
||||
{
|
||||
int bus_nr;
|
||||
struct ipack_bus_device *bus;
|
||||
|
@ -225,6 +226,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
|
|||
bus->parent = parent;
|
||||
bus->slots = slots;
|
||||
bus->ops = ops;
|
||||
bus->owner = owner;
|
||||
return bus;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipack_bus_register);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -159,12 +159,11 @@ static int eeprom_probe(struct i2c_client *client,
|
|||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct eeprom_data *data;
|
||||
int err;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(data->data, 0xff, EEPROM_SIZE);
|
||||
i2c_set_clientdata(client, data);
|
||||
|
@ -190,22 +189,12 @@ static int eeprom_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
/* create the sysfs eeprom file */
|
||||
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||
if (err)
|
||||
goto exit_kfree;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||
}
|
||||
|
||||
static int eeprom_remove(struct i2c_client *client)
|
||||
{
|
||||
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -45,10 +45,10 @@
|
|||
MODULE_AUTHOR("Frank Haverkamp <haver@linux.vnet.ibm.com>");
|
||||
MODULE_AUTHOR("Michael Ruettger <michael@ibmra.de>");
|
||||
MODULE_AUTHOR("Joerg-Stephan Vogt <jsvogt@de.ibm.com>");
|
||||
MODULE_AUTHOR("Michal Jung <mijung@de.ibm.com>");
|
||||
MODULE_AUTHOR("Michael Jung <mijung@gmx.net>");
|
||||
|
||||
MODULE_DESCRIPTION("GenWQE Card");
|
||||
MODULE_VERSION(DRV_VERS_STRING);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char genwqe_driver_name[] = GENWQE_DEVNAME;
|
||||
|
@ -346,8 +346,13 @@ static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
|
|||
unsigned int vf;
|
||||
u32 T = genwqe_T_psec(cd);
|
||||
u64 x;
|
||||
int totalvfs;
|
||||
|
||||
for (vf = 0; vf < pci_sriov_get_totalvfs(pci_dev); vf++) {
|
||||
totalvfs = pci_sriov_get_totalvfs(pci_dev);
|
||||
if (totalvfs <= 0)
|
||||
return false;
|
||||
|
||||
for (vf = 0; vf < totalvfs; vf++) {
|
||||
|
||||
if (cd->vf_jobtimeout_msec[vf] == 0)
|
||||
continue;
|
||||
|
@ -383,8 +388,9 @@ static int genwqe_ffdc_buffs_alloc(struct genwqe_dev *cd)
|
|||
|
||||
/* currently support only the debug units mentioned here */
|
||||
cd->ffdc[type].entries = e;
|
||||
cd->ffdc[type].regs = kmalloc(e * sizeof(struct genwqe_reg),
|
||||
GFP_KERNEL);
|
||||
cd->ffdc[type].regs =
|
||||
kmalloc_array(e, sizeof(struct genwqe_reg),
|
||||
GFP_KERNEL);
|
||||
/*
|
||||
* regs == NULL is ok, the using code treats this as no regs,
|
||||
* Printing warning is ok in this case.
|
||||
|
@ -723,8 +729,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
|
|||
__genwqe_writeq(cd, sfir_addr, sfir);
|
||||
|
||||
dev_dbg(&pci_dev->dev,
|
||||
"[HM] Clearing 2ndary FIR 0x%08x "
|
||||
"with 0x%016llx\n", sfir_addr, sfir);
|
||||
"[HM] Clearing 2ndary FIR 0x%08x with 0x%016llx\n",
|
||||
sfir_addr, sfir);
|
||||
|
||||
/*
|
||||
* note, these cannot be error-Firs
|
||||
|
@ -740,9 +746,8 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
|
|||
__genwqe_writeq(cd, fir_clr_addr, mask);
|
||||
|
||||
dev_dbg(&pci_dev->dev,
|
||||
"[HM] Clearing primary FIR 0x%08x "
|
||||
"with 0x%016llx\n", fir_clr_addr,
|
||||
mask);
|
||||
"[HM] Clearing primary FIR 0x%08x with 0x%016llx\n",
|
||||
fir_clr_addr, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1125,6 +1130,8 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
|
|||
}
|
||||
|
||||
cd->num_vfs = pci_sriov_get_totalvfs(pci_dev);
|
||||
if (cd->num_vfs < 0)
|
||||
cd->num_vfs = 0;
|
||||
|
||||
err = genwqe_read_ids(cd);
|
||||
if (err)
|
||||
|
@ -1202,8 +1209,8 @@ static int genwqe_probe(struct pci_dev *pci_dev,
|
|||
err = genwqe_health_check_start(cd);
|
||||
if (err < 0) {
|
||||
dev_err(&pci_dev->dev,
|
||||
"err: cannot start health checking! "
|
||||
"(err=%d)\n", err);
|
||||
"err: cannot start health checking! (err=%d)\n",
|
||||
err);
|
||||
goto out_stop_services;
|
||||
}
|
||||
}
|
||||
|
@ -1313,11 +1320,14 @@ static void genwqe_err_resume(struct pci_dev *pci_dev)
|
|||
|
||||
static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
|
||||
{
|
||||
int rc;
|
||||
struct genwqe_dev *cd = dev_get_drvdata(&dev->dev);
|
||||
|
||||
if (numvfs > 0) {
|
||||
genwqe_setup_vf_jtimer(cd);
|
||||
pci_enable_sriov(dev, numvfs);
|
||||
rc = pci_enable_sriov(dev, numvfs);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return numvfs;
|
||||
}
|
||||
if (numvfs == 0) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -201,7 +201,8 @@ static inline void genwqe_mapping_init(struct dma_mapping *m,
|
|||
* @ddcb_seq: Sequence number of last DDCB
|
||||
* @ddcbs_in_flight: Currently enqueued DDCBs
|
||||
* @ddcbs_completed: Number of already completed DDCBs
|
||||
* @busy: Number of -EBUSY returns
|
||||
* @return_on_busy: Number of -EBUSY returns on full queue
|
||||
* @wait_on_busy: Number of waits on full queue
|
||||
* @ddcb_daddr: DMA address of first DDCB in the queue
|
||||
* @ddcb_vaddr: Kernel virtual address of first DDCB in the queue
|
||||
* @ddcb_req: Associated requests (one per DDCB)
|
||||
|
@ -218,7 +219,8 @@ struct ddcb_queue {
|
|||
unsigned int ddcbs_in_flight; /* number of ddcbs in processing */
|
||||
unsigned int ddcbs_completed;
|
||||
unsigned int ddcbs_max_in_flight;
|
||||
unsigned int busy; /* how many times -EBUSY? */
|
||||
unsigned int return_on_busy; /* how many times -EBUSY? */
|
||||
unsigned int wait_on_busy;
|
||||
|
||||
dma_addr_t ddcb_daddr; /* DMA address */
|
||||
struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */
|
||||
|
@ -226,7 +228,7 @@ struct ddcb_queue {
|
|||
wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */
|
||||
|
||||
spinlock_t ddcb_lock; /* exclusive access to queue */
|
||||
wait_queue_head_t ddcb_waitq; /* wait for ddcb processing */
|
||||
wait_queue_head_t busy_waitq; /* wait for ddcb processing */
|
||||
|
||||
/* registers or the respective queue to be used */
|
||||
u32 IO_QUEUE_CONFIG;
|
||||
|
@ -306,7 +308,7 @@ struct genwqe_dev {
|
|||
struct pci_dev *pci_dev; /* PCI device */
|
||||
void __iomem *mmio; /* BAR-0 MMIO start */
|
||||
unsigned long mmio_len;
|
||||
u16 num_vfs;
|
||||
int num_vfs;
|
||||
u32 vf_jobtimeout_msec[GENWQE_MAX_VFS];
|
||||
int is_privileged; /* access to all regs possible */
|
||||
|
||||
|
@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m)
|
|||
* buildup and teardown.
|
||||
*/
|
||||
int __genwqe_execute_ddcb(struct genwqe_dev *cd,
|
||||
struct genwqe_ddcb_cmd *cmd);
|
||||
struct genwqe_ddcb_cmd *cmd, unsigned int f_flags);
|
||||
|
||||
/**
|
||||
* __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation
|
||||
|
@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd,
|
|||
* modification.
|
||||
*/
|
||||
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
|
||||
struct genwqe_ddcb_cmd *cmd);
|
||||
struct genwqe_ddcb_cmd *cmd,
|
||||
unsigned int f_flags);
|
||||
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd,
|
||||
struct ddcb_requ *req,
|
||||
unsigned int f_flags);
|
||||
|
||||
int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
|
||||
int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
|
||||
int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -185,8 +185,7 @@ static void print_ddcb_info(struct genwqe_dev *cd, struct ddcb_queue *queue)
|
|||
pddcb = queue->ddcb_vaddr;
|
||||
for (i = 0; i < queue->ddcb_max; i++) {
|
||||
dev_err(&pci_dev->dev,
|
||||
" %c %-3d: RETC=%03x SEQ=%04x "
|
||||
"HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
|
||||
" %c %-3d: RETC=%03x SEQ=%04x HSI=%02X SHI=%02x PRIV=%06llx CMD=%03x\n",
|
||||
i == queue->ddcb_act ? '>' : ' ',
|
||||
i,
|
||||
be16_to_cpu(pddcb->retc_16),
|
||||
|
@ -214,6 +213,7 @@ struct genwqe_ddcb_cmd *ddcb_requ_alloc(void)
|
|||
void ddcb_requ_free(struct genwqe_ddcb_cmd *cmd)
|
||||
{
|
||||
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
|
||||
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
|
|||
|
||||
new = (old | DDCB_NEXT_BE32);
|
||||
|
||||
wmb();
|
||||
wmb(); /* need to ensure write ordering */
|
||||
icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new);
|
||||
|
||||
if (icrc_hsi_shi == old)
|
||||
|
@ -317,7 +317,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
|
|||
ddcb_mark_tapped(pddcb);
|
||||
num = (u64)ddcb_no << 8;
|
||||
|
||||
wmb();
|
||||
wmb(); /* need to ensure write ordering */
|
||||
__genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */
|
||||
|
||||
return RET_DDCB_TAPPED;
|
||||
|
@ -390,8 +390,9 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
|
|||
0x00000000)
|
||||
goto go_home; /* not completed, continue waiting */
|
||||
|
||||
/* Note: DDCB could be purged */
|
||||
wmb(); /* Add sync to decouple prev. read operations */
|
||||
|
||||
/* Note: DDCB could be purged */
|
||||
req = queue->ddcb_req[queue->ddcb_act];
|
||||
if (req == NULL) {
|
||||
/* this occurs if DDCB is purged, not an error */
|
||||
|
@ -416,9 +417,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
|
|||
status = __genwqe_readq(cd, queue->IO_QUEUE_STATUS);
|
||||
|
||||
dev_err(&pci_dev->dev,
|
||||
"[%s] SEQN=%04x HSI=%02x RETC=%03x "
|
||||
" Q_ERRCNTS=%016llx Q_STATUS=%016llx\n"
|
||||
" DDCB_DMA_ADDR=%016llx\n",
|
||||
"[%s] SEQN=%04x HSI=%02x RETC=%03x Q_ERRCNTS=%016llx Q_STATUS=%016llx DDCB_DMA_ADDR=%016llx\n",
|
||||
__func__, be16_to_cpu(pddcb->seqnum_16),
|
||||
pddcb->hsi, retc_16, errcnts, status,
|
||||
queue->ddcb_daddr + ddcb_offs);
|
||||
|
@ -439,8 +438,7 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
|
|||
vcrc_16 = be16_to_cpu(pddcb->vcrc_16);
|
||||
if (vcrc != vcrc_16) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d "
|
||||
"bytes vcrc_data=%04x is not vcrc_card=%04x\n",
|
||||
"%s %s: err: wrong VCRC pre=%02x vcrc_len=%d bytes vcrc_data=%04x is not vcrc_card=%04x\n",
|
||||
GENWQE_DEVNAME, dev_name(&pci_dev->dev),
|
||||
pddcb->pre, VCRC_LENGTH(req->cmd.asv_length),
|
||||
vcrc, vcrc_16);
|
||||
|
@ -450,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd,
|
|||
queue->ddcbs_completed++;
|
||||
queue->ddcbs_in_flight--;
|
||||
|
||||
/* wake up process waiting for this DDCB */
|
||||
/* wake up process waiting for this DDCB, and
|
||||
processes on the busy queue */
|
||||
wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]);
|
||||
wake_up_interruptible(&queue->busy_waitq);
|
||||
|
||||
pick_next_one:
|
||||
queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max;
|
||||
|
@ -717,8 +717,7 @@ 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
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -244,14 +244,16 @@ static int genwqe_ddcb_info_show(struct seq_file *s, void *unused)
|
|||
" ddcbs_in_flight: %u\n"
|
||||
" ddcbs_max_in_flight: %u\n"
|
||||
" ddcbs_completed: %u\n"
|
||||
" busy: %u\n"
|
||||
" return_on_busy: %u\n"
|
||||
" wait_on_busy: %u\n"
|
||||
" irqs_processed: %u\n",
|
||||
queue->ddcb_max, (long long)queue->ddcb_daddr,
|
||||
(long long)queue->ddcb_daddr +
|
||||
(queue->ddcb_max * DDCB_LENGTH),
|
||||
(long long)queue->ddcb_vaddr, queue->ddcbs_in_flight,
|
||||
queue->ddcbs_max_in_flight, queue->ddcbs_completed,
|
||||
queue->busy, cd->irqs_processed);
|
||||
queue->return_on_busy, queue->wait_on_busy,
|
||||
cd->irqs_processed);
|
||||
|
||||
/* Hardware State */
|
||||
seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n"
|
||||
|
@ -323,7 +325,7 @@ static int genwqe_info_show(struct seq_file *s, void *unused)
|
|||
" Base Clock : %u MHz\n"
|
||||
" Arch/SVN Release: %u/%llx\n"
|
||||
" Bitstream : %llx\n",
|
||||
GENWQE_DEVNAME, DRV_VERS_STRING, dev_name(&pci_dev->dev),
|
||||
GENWQE_DEVNAME, DRV_VERSION, dev_name(&pci_dev->dev),
|
||||
genwqe_is_privileged(cd) ?
|
||||
"Physical" : "Virtual or no SR-IOV",
|
||||
cd->card_idx, slu_id, app_id,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -213,9 +213,9 @@ static void genwqe_remove_mappings(struct genwqe_file *cfile)
|
|||
* GENWQE_MAPPING_SGL_TEMP should be removed by tidy up code.
|
||||
*/
|
||||
dev_err(&pci_dev->dev,
|
||||
"[%s] %d. cleanup mapping: u_vaddr=%p "
|
||||
"u_kaddr=%016lx dma_addr=%lx\n", __func__, i++,
|
||||
dma_map->u_vaddr, (unsigned long)dma_map->k_vaddr,
|
||||
"[%s] %d. cleanup mapping: u_vaddr=%p u_kaddr=%016lx dma_addr=%lx\n",
|
||||
__func__, i++, dma_map->u_vaddr,
|
||||
(unsigned long)dma_map->k_vaddr,
|
||||
(unsigned long)dma_map->dma_addr);
|
||||
|
||||
if (dma_map->type == GENWQE_MAPPING_RAW) {
|
||||
|
@ -346,6 +346,7 @@ static int genwqe_open(struct inode *inode, struct file *filp)
|
|||
static int genwqe_fasync(int fd, struct file *filp, int mode)
|
||||
{
|
||||
struct genwqe_file *cdev = (struct genwqe_file *)filp->private_data;
|
||||
|
||||
return fasync_helper(fd, filp, mode, &cdev->async_queue);
|
||||
}
|
||||
|
||||
|
@ -515,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile,
|
|||
u32 crc;
|
||||
u8 cmdopts;
|
||||
struct genwqe_dev *cd = cfile->cd;
|
||||
struct file *filp = cfile->filp;
|
||||
struct pci_dev *pci_dev = cd->pci_dev;
|
||||
|
||||
if ((load->size & 0x3) != 0)
|
||||
|
@ -609,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile,
|
|||
/* For Genwqe5 we get back the calculated CRC */
|
||||
*(u64 *)&req->asv[0] = 0ULL; /* 0x80 */
|
||||
|
||||
rc = __genwqe_execute_raw_ddcb(cd, req);
|
||||
rc = __genwqe_execute_raw_ddcb(cd, req, filp->f_flags);
|
||||
|
||||
load->retc = req->retc;
|
||||
load->attn = req->attn;
|
||||
|
@ -649,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile,
|
|||
u8 *xbuf;
|
||||
u8 cmdopts;
|
||||
struct genwqe_dev *cd = cfile->cd;
|
||||
struct file *filp = cfile->filp;
|
||||
struct pci_dev *pci_dev = cd->pci_dev;
|
||||
struct genwqe_ddcb_cmd *cmd;
|
||||
|
||||
|
@ -726,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile,
|
|||
/* we only get back the calculated CRC */
|
||||
*(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */
|
||||
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd);
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
|
||||
|
||||
load->retc = cmd->retc;
|
||||
load->attn = cmd->attn;
|
||||
|
@ -987,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile,
|
|||
{
|
||||
int rc;
|
||||
struct genwqe_dev *cd = cfile->cd;
|
||||
struct file *filp = cfile->filp;
|
||||
struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd);
|
||||
|
||||
rc = ddcb_cmd_fixups(cfile, req);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd);
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
|
||||
ddcb_cmd_cleanup(cfile, req);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1005,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
|
|||
struct genwqe_ddcb_cmd *cmd;
|
||||
struct ddcb_requ *req;
|
||||
struct genwqe_dev *cd = cfile->cd;
|
||||
struct file *filp = cfile->filp;
|
||||
|
||||
cmd = ddcb_requ_alloc();
|
||||
if (cmd == NULL)
|
||||
|
@ -1020,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile,
|
|||
if (!raw)
|
||||
rc = genwqe_execute_ddcb(cfile, cmd);
|
||||
else
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd);
|
||||
rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags);
|
||||
|
||||
/* Copy back only the modifed fields. Do not copy ASIV
|
||||
back since the copy got modified by the driver. */
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -91,13 +91,6 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
|||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
static ssize_t driver_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", DRV_VERS_STRING);
|
||||
}
|
||||
static DEVICE_ATTR_RO(driver);
|
||||
|
||||
static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
|
@ -256,7 +249,6 @@ static struct attribute *genwqe_attributes[] = {
|
|||
&dev_attr_next_bitstream.attr,
|
||||
&dev_attr_curr_bitstream.attr,
|
||||
&dev_attr_base_clock.attr,
|
||||
&dev_attr_driver.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_version.attr,
|
||||
&dev_attr_appid.attr,
|
||||
|
@ -268,7 +260,6 @@ static struct attribute *genwqe_attributes[] = {
|
|||
};
|
||||
|
||||
static struct attribute *genwqe_normal_attributes[] = {
|
||||
&dev_attr_driver.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_version.attr,
|
||||
&dev_attr_appid.attr,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -150,6 +150,7 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
|
|||
memset(app_name, 0, len);
|
||||
for (i = 0, j = 0; j < min(len, 4); j++) {
|
||||
char ch = (char)((app_id >> (24 - j*8)) & 0xff);
|
||||
|
||||
if (ch == ' ')
|
||||
continue;
|
||||
app_name[i++] = isprint(ch) ? ch : 'X';
|
||||
|
@ -304,8 +305,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
|
|||
sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE);
|
||||
sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE;
|
||||
|
||||
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld "
|
||||
"fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
|
||||
dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
|
||||
__func__, user_addr, user_size, sgl->nr_pages,
|
||||
sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size);
|
||||
|
||||
|
@ -662,6 +662,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m,
|
|||
u8 genwqe_card_type(struct genwqe_dev *cd)
|
||||
{
|
||||
u64 card_type = cd->slu_unitcfg;
|
||||
|
||||
return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
|
||||
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@de.ibm.com>
|
||||
* Author: Michael Jung <mijung@gmx.net>
|
||||
* Author: Michael Ruettger <michael@ibmra.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -36,7 +36,7 @@
|
|||
#include <asm/byteorder.h>
|
||||
#include <linux/genwqe/genwqe_card.h>
|
||||
|
||||
#define DRV_VERS_STRING "2.0.21"
|
||||
#define DRV_VERSION "2.0.25"
|
||||
|
||||
/*
|
||||
* Static minor number assignement, until we decide/implement
|
||||
|
|
|
@ -247,3 +247,4 @@ module_spi_driver(lattice_ecp3_driver);
|
|||
MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
|
||||
MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(FIRMWARE_NAME);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/aio.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
|
@ -29,6 +28,7 @@
|
|||
#include <linux/uuid.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mei.h>
|
||||
|
||||
|
@ -64,31 +64,32 @@ void mei_amthif_reset_params(struct mei_device *dev)
|
|||
*
|
||||
* @dev: the device structure
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
int mei_amthif_host_init(struct mei_device *dev)
|
||||
{
|
||||
struct mei_cl *cl = &dev->iamthif_cl;
|
||||
struct mei_me_client *me_cl;
|
||||
unsigned char *msg_buf;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||
|
||||
mei_cl_init(cl, dev);
|
||||
|
||||
i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
|
||||
if (i < 0) {
|
||||
dev_info(&dev->pdev->dev,
|
||||
"amthif: failed to find the client %d\n", i);
|
||||
me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
|
||||
if (!me_cl) {
|
||||
dev_info(dev->dev, "amthif: failed to find the client");
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
cl->me_client_id = dev->me_clients[i].client_id;
|
||||
cl->me_client_id = me_cl->client_id;
|
||||
cl->cl_uuid = me_cl->props.protocol_name;
|
||||
|
||||
/* Assign iamthif_mtu to the value received from ME */
|
||||
|
||||
dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
|
||||
dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
|
||||
dev->me_clients[i].props.max_msg_length);
|
||||
dev->iamthif_mtu = me_cl->props.max_msg_length;
|
||||
dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
|
||||
|
||||
kfree(dev->iamthif_msg_buf);
|
||||
dev->iamthif_msg_buf = NULL;
|
||||
|
@ -96,17 +97,15 @@ int mei_amthif_host_init(struct mei_device *dev)
|
|||
/* allocate storage for ME message buffer */
|
||||
msg_buf = kcalloc(dev->iamthif_mtu,
|
||||
sizeof(unsigned char), GFP_KERNEL);
|
||||
if (!msg_buf) {
|
||||
dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
|
||||
if (!msg_buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->iamthif_msg_buf = msg_buf;
|
||||
|
||||
ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(dev->dev,
|
||||
"amthif: failed link client %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -124,18 +123,16 @@ int mei_amthif_host_init(struct mei_device *dev)
|
|||
* @dev: the device structure
|
||||
* @file: pointer to file object
|
||||
*
|
||||
* returns returned a list entry on success, NULL on failure.
|
||||
* Return: returned a list entry on success, NULL on failure.
|
||||
*/
|
||||
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
|
||||
struct file *file)
|
||||
{
|
||||
struct mei_cl_cb *cb;
|
||||
|
||||
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
|
||||
if (cb->cl && cb->cl == &dev->iamthif_cl &&
|
||||
cb->file_object == file)
|
||||
list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
|
||||
if (cb->file_object == file)
|
||||
return cb;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -144,15 +141,14 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
|
|||
* mei_amthif_read - read data from AMTHIF client
|
||||
*
|
||||
* @dev: the device structure
|
||||
* @if_num: minor number
|
||||
* @file: pointer to file object
|
||||
* @*ubuf: pointer to user data in user space
|
||||
* @ubuf: pointer to user data in user space
|
||||
* @length: data length to read
|
||||
* @offset: data read offset
|
||||
*
|
||||
* Locking: called under "dev->device_lock" lock
|
||||
*
|
||||
* returns
|
||||
* Return:
|
||||
* returned data length on success,
|
||||
* zero if no data to read,
|
||||
* negative on failure.
|
||||
|
@ -160,25 +156,19 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
|
|||
int mei_amthif_read(struct mei_device *dev, struct file *file,
|
||||
char __user *ubuf, size_t length, loff_t *offset)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mei_cl_bus.h>
|
||||
|
||||
#include "mei_dev.h"
|
||||
|
@ -70,7 +69,7 @@ static int mei_cl_device_probe(struct device *dev)
|
|||
|
||||
dev_dbg(dev, "Device probe\n");
|
||||
|
||||
strncpy(id.name, dev_name(dev), sizeof(id.name));
|
||||
strlcpy(id.name, dev_name(dev), sizeof(id.name));
|
||||
|
||||
return driver->probe(device, &id);
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
|
|||
struct mei_cl *cl;
|
||||
|
||||
list_for_each_entry(cl, &dev->device_list, device_link) {
|
||||
if (!uuid_le_cmp(uuid, cl->device_uuid))
|
||||
if (!uuid_le_cmp(uuid, cl->cl_uuid))
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
@ -172,7 +171,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
|
|||
device->cl = cl;
|
||||
device->ops = ops;
|
||||
|
||||
device->dev.parent = &dev->pdev->dev;
|
||||
device->dev.parent = dev->dev;
|
||||
device->dev.bus = &mei_cl_bus_type;
|
||||
device->dev.type = &mei_cl_device_type;
|
||||
|
||||
|
@ -180,7 +179,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
|
|||
|
||||
status = device_register(&device->dev);
|
||||
if (status) {
|
||||
dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
|
||||
dev_err(dev->dev, "Failed to register MEI device\n");
|
||||
kfree(device);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -229,8 +228,8 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
|
|||
bool blocking)
|
||||
{
|
||||
struct mei_device *dev;
|
||||
struct mei_me_client *me_cl;
|
||||
struct mei_cl_cb *cb;
|
||||
int id;
|
||||
int rets;
|
||||
|
||||
if (WARN_ON(!cl || !cl->dev))
|
||||
|
@ -242,11 +241,11 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
|
|||
return -ENODEV;
|
||||
|
||||
/* Check if we have an ME client device */
|
||||
id = mei_me_cl_by_id(dev, cl->me_client_id);
|
||||
if (id < 0)
|
||||
return id;
|
||||
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
|
||||
if (!me_cl)
|
||||
return -ENOTTY;
|
||||
|
||||
if (length > dev->me_clients[id].props.max_msg_length)
|
||||
if (length > me_cl->props.max_msg_length)
|
||||
return -EFBIG;
|
||||
|
||||
cb = mei_io_cb_init(cl, NULL);
|
||||
|
@ -430,7 +429,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
|
|||
err = mei_cl_connect(cl, NULL);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&dev->device_lock);
|
||||
dev_err(&dev->pdev->dev, "Could not connect to the ME client");
|
||||
dev_err(dev->dev, "Could not connect to the ME client");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -462,7 +461,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
|
|||
|
||||
if (cl->state != MEI_FILE_CONNECTED) {
|
||||
mutex_unlock(&dev->device_lock);
|
||||
dev_err(&dev->pdev->dev, "Already disconnected");
|
||||
dev_err(dev->dev, "Already disconnected");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -472,7 +471,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
|
|||
err = mei_cl_disconnect(cl);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&dev->device_lock);
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(dev->dev,
|
||||
"Could not disconnect from the ME client");
|
||||
|
||||
return err;
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/mei.h>
|
||||
|
@ -27,47 +27,90 @@
|
|||
#include "client.h"
|
||||
|
||||
/**
|
||||
* mei_me_cl_by_uuid - locate index of me client
|
||||
* mei_me_cl_by_uuid - locate me client by uuid
|
||||
*
|
||||
* @dev: mei device
|
||||
* @uuid: me client uuid
|
||||
*
|
||||
* Locking: called under "dev->device_lock" lock
|
||||
*
|
||||
* returns me client index or -ENOENT if not found
|
||||
* Return: me client or NULL if not found
|
||||
*/
|
||||
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
|
||||
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
|
||||
const uuid_le *uuid)
|
||||
{
|
||||
int i;
|
||||
struct mei_me_client *me_cl;
|
||||
|
||||
for (i = 0; i < dev->me_clients_num; ++i)
|
||||
if (uuid_le_cmp(*uuid,
|
||||
dev->me_clients[i].props.protocol_name) == 0)
|
||||
return i;
|
||||
list_for_each_entry(me_cl, &dev->me_clients, list)
|
||||
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
|
||||
return me_cl;
|
||||
|
||||
return -ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mei_me_cl_by_id return index to me_clients for client_id
|
||||
* mei_me_cl_by_id - locate me client by client id
|
||||
*
|
||||
* @dev: the device structure
|
||||
* @client_id: me client id
|
||||
*
|
||||
* Locking: called under "dev->device_lock" lock
|
||||
*
|
||||
* returns index on success, -ENOENT on failure.
|
||||
* Return: me client or NULL if not found
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -24,8 +24,15 @@
|
|||
|
||||
#include "mei_dev.h"
|
||||
|
||||
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
|
||||
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
|
||||
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
|
||||
const uuid_le *cuuid);
|
||||
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
|
||||
|
||||
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
|
||||
const uuid_le *uuid, u8 client_id);
|
||||
|
||||
void mei_me_cl_remove(struct mei_device *dev,
|
||||
const uuid_le *uuid, u8 client_id);
|
||||
|
||||
/*
|
||||
* MEI IO Functions
|
||||
|
@ -45,6 +52,8 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
|
|||
{
|
||||
INIT_LIST_HEAD(&list->list);
|
||||
}
|
||||
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
|
||||
|
||||
/*
|
||||
* MEI Host Client Functions
|
||||
*/
|
||||
|
@ -101,9 +110,9 @@ void mei_cl_all_write_clear(struct mei_device *dev);
|
|||
#define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id
|
||||
|
||||
#define cl_dbg(dev, cl, format, arg...) \
|
||||
dev_dbg(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
|
||||
dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
|
||||
|
||||
#define cl_err(dev, cl, format, arg...) \
|
||||
dev_err(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
|
||||
dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
|
||||
|
||||
#endif /* _MEI_CLIENT_H_ */
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <linux/mei.h>
|
||||
|
||||
|
@ -28,39 +27,47 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
|
|||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
struct mei_device *dev = fp->private_data;
|
||||
struct mei_me_client *cl;
|
||||
const size_t bufsz = 1024;
|
||||
char *buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
int i;
|
||||
struct mei_me_client *me_cl;
|
||||
size_t bufsz = 1;
|
||||
char *buf;
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
" |id|addr| UUID |con|msg len|\n");
|
||||
#define HDR " |id|addr| UUID |con|msg len|sb|\n"
|
||||
|
||||
mutex_lock(&dev->device_lock);
|
||||
|
||||
list_for_each_entry(me_cl, &dev->me_clients, list)
|
||||
bufsz++;
|
||||
|
||||
bufsz *= sizeof(HDR) + 1;
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
mutex_unlock(&dev->device_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, HDR);
|
||||
|
||||
/* if the driver is not enabled the list won't be consistent */
|
||||
if (dev->dev_state != MEI_DEV_ENABLED)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < dev->me_clients_num; i++) {
|
||||
cl = &dev->me_clients[i];
|
||||
list_for_each_entry(me_cl, &dev->me_clients, list) {
|
||||
|
||||
/* skip me clients that cannot be connected */
|
||||
if (cl->props.max_number_of_connections == 0)
|
||||
if (me_cl->props.max_number_of_connections == 0)
|
||||
continue;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%2d|%2d|%4d|%pUl|%3d|%7d|\n",
|
||||
i, cl->client_id,
|
||||
cl->props.fixed_address,
|
||||
&cl->props.protocol_name,
|
||||
cl->props.max_number_of_connections,
|
||||
cl->props.max_msg_length);
|
||||
"%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n",
|
||||
i++, me_cl->client_id,
|
||||
me_cl->props.fixed_address,
|
||||
&me_cl->props.protocol_name,
|
||||
me_cl->props.max_number_of_connections,
|
||||
me_cl->props.max_msg_length,
|
||||
me_cl->props.single_recv_buf);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&dev->device_lock);
|
||||
|
@ -98,7 +105,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
|
|||
|
||||
mutex_lock(&dev->device_lock);
|
||||
|
||||
/* if the driver is not enabled the list won't b consitent */
|
||||
/* if the driver is not enabled the list won't be consistent */
|
||||
if (dev->dev_state != MEI_DEV_ENABLED)
|
||||
goto out;
|
||||
|
||||
|
@ -135,8 +142,13 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",
|
||||
mei_dev_state_str(dev->dev_state));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
|
||||
mei_hbm_state_str(dev->hbm_state));
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
|
||||
mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
|
||||
mei_pg_state_str(mei_pg_state(dev)));
|
||||
ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
@ -149,7 +161,8 @@ static const struct file_operations mei_dbgfs_fops_devstate = {
|
|||
|
||||
/**
|
||||
* mei_dbgfs_deregister - Remove the debugfs files and directories
|
||||
* @mei - pointer to mei device private data
|
||||
*
|
||||
* @dev: the mei device structure
|
||||
*/
|
||||
void mei_dbgfs_deregister(struct mei_device *dev)
|
||||
{
|
||||
|
@ -160,12 +173,17 @@ void mei_dbgfs_deregister(struct mei_device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* Add the debugfs files
|
||||
* mei_dbgfs_register - Add the debugfs files
|
||||
*
|
||||
* @dev: the mei device structure
|
||||
* @name: the mei device name
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
int mei_dbgfs_register(struct mei_device *dev, const char *name)
|
||||
{
|
||||
struct dentry *dir, *f;
|
||||
|
||||
dir = debugfs_create_dir(name, NULL);
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
@ -173,19 +191,19 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
|
|||
f = debugfs_create_file("meclients", S_IRUSR, dir,
|
||||
dev, &mei_dbgfs_fops_meclients);
|
||||
if (!f) {
|
||||
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
|
||||
dev_err(dev->dev, "meclients: registration failed\n");
|
||||
goto err;
|
||||
}
|
||||
f = debugfs_create_file("active", S_IRUSR, dir,
|
||||
dev, &mei_dbgfs_fops_active);
|
||||
if (!f) {
|
||||
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
|
||||
dev_err(dev->dev, "meclients: registration failed\n");
|
||||
goto err;
|
||||
}
|
||||
f = debugfs_create_file("devstate", S_IRUSR, dir,
|
||||
dev, &mei_dbgfs_fops_devstate);
|
||||
if (!f) {
|
||||
dev_err(&dev->pdev->dev, "devstate: registration failed\n");
|
||||
dev_err(dev->dev, "devstate: registration failed\n");
|
||||
goto err;
|
||||
}
|
||||
dev->dbgfs_dir = dir;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
|
|
@ -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(®, &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, ®, 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, ®);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(®, &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, ®, 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;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
* @mem_addr: SeC and BRIDGE bars
|
||||
* @aliveness: aliveness (power gating) state of the hardware
|
||||
* @readiness: readiness state of the hardware
|
||||
* @slots: number of empty slots
|
||||
* @wait_aliveness_resp: aliveness wait queue
|
||||
* @intr_cause: translated interrupt cause
|
||||
*/
|
||||
|
@ -61,10 +62,7 @@ static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
|
|||
return container_of((void *)hw, struct mei_device, hw);
|
||||
}
|
||||
|
||||
extern const struct mei_cfg mei_txe_cfg;
|
||||
|
||||
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
|
||||
const struct mei_cfg *cfg);
|
||||
struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
|
||||
|
||||
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
|
||||
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);
|
||||
|
|
|
@ -97,23 +97,52 @@ enum mei_stop_reason_types {
|
|||
SYSTEM_S5_ENTRY = 0x08
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* enum mei_hbm_status - mei host bus messages return values
|
||||
*
|
||||
* @MEI_HBMS_SUCCESS : status success
|
||||
* @MEI_HBMS_CLIENT_NOT_FOUND : client not found
|
||||
* @MEI_HBMS_ALREADY_EXISTS : connection already established
|
||||
* @MEI_HBMS_REJECTED : connection is rejected
|
||||
* @MEI_HBMS_INVALID_PARAMETER : invalid parameter
|
||||
* @MEI_HBMS_NOT_ALLOWED : operation not allowed
|
||||
* @MEI_HBMS_ALREADY_STARTED : system is already started
|
||||
* @MEI_HBMS_NOT_STARTED : system not started
|
||||
*
|
||||
* @MEI_HBMS_MAX : sentinel
|
||||
*/
|
||||
enum mei_hbm_status {
|
||||
MEI_HBMS_SUCCESS = 0,
|
||||
MEI_HBMS_CLIENT_NOT_FOUND = 1,
|
||||
MEI_HBMS_ALREADY_EXISTS = 2,
|
||||
MEI_HBMS_REJECTED = 3,
|
||||
MEI_HBMS_INVALID_PARAMETER = 4,
|
||||
MEI_HBMS_NOT_ALLOWED = 5,
|
||||
MEI_HBMS_ALREADY_STARTED = 6,
|
||||
MEI_HBMS_NOT_STARTED = 7,
|
||||
|
||||
MEI_HBMS_MAX
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Client Connect Status
|
||||
* used by hbm_client_connect_response.status
|
||||
*/
|
||||
enum mei_cl_connect_status {
|
||||
MEI_CL_CONN_SUCCESS = 0x00,
|
||||
MEI_CL_CONN_NOT_FOUND = 0x01,
|
||||
MEI_CL_CONN_ALREADY_STARTED = 0x02,
|
||||
MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
|
||||
MEI_CL_CONN_MESSAGE_SMALL = 0x04
|
||||
MEI_CL_CONN_SUCCESS = MEI_HBMS_SUCCESS,
|
||||
MEI_CL_CONN_NOT_FOUND = MEI_HBMS_CLIENT_NOT_FOUND,
|
||||
MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS,
|
||||
MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED,
|
||||
MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER,
|
||||
};
|
||||
|
||||
/*
|
||||
* Client Disconnect Status
|
||||
*/
|
||||
enum mei_cl_disconnect_status {
|
||||
MEI_CL_DISCONN_SUCCESS = 0x00
|
||||
MEI_CL_DISCONN_SUCCESS = MEI_HBMS_SUCCESS
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -138,10 +167,10 @@ struct mei_bus_message {
|
|||
* struct hbm_cl_cmd - client specific host bus command
|
||||
* CONNECT, DISCONNECT, and FlOW CONTROL
|
||||
*
|
||||
* @hbm_cmd - bus message command header
|
||||
* @me_addr - address of the client in ME
|
||||
* @host_addr - address of the client in the driver
|
||||
* @data
|
||||
* @hbm_cmd: bus message command header
|
||||
* @me_addr: address of the client in ME
|
||||
* @host_addr: address of the client in the driver
|
||||
* @data: generic data
|
||||
*/
|
||||
struct mei_hbm_cl_cmd {
|
||||
u8 hbm_cmd;
|
||||
|
@ -206,14 +235,13 @@ struct mei_client_properties {
|
|||
|
||||
struct hbm_props_request {
|
||||
u8 hbm_cmd;
|
||||
u8 address;
|
||||
u8 me_addr;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct hbm_props_response {
|
||||
u8 hbm_cmd;
|
||||
u8 address;
|
||||
u8 me_addr;
|
||||
u8 status;
|
||||
u8 reserved[1];
|
||||
struct mei_client_properties client_properties;
|
||||
|
@ -222,8 +250,8 @@ struct hbm_props_response {
|
|||
/**
|
||||
* struct hbm_power_gate - power gate request/response
|
||||
*
|
||||
* @hbm_cmd - bus message command header
|
||||
* @reserved[3]
|
||||
* @hbm_cmd: bus message command header
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct hbm_power_gate {
|
||||
u8 hbm_cmd;
|
||||
|
@ -233,10 +261,10 @@ struct hbm_power_gate {
|
|||
/**
|
||||
* struct hbm_client_connect_request - connect/disconnect request
|
||||
*
|
||||
* @hbm_cmd - bus message command header
|
||||
* @me_addr - address of the client in ME
|
||||
* @host_addr - address of the client in the driver
|
||||
* @reserved
|
||||
* @hbm_cmd: bus message command header
|
||||
* @me_addr: address of the client in ME
|
||||
* @host_addr: address of the client in the driver
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct hbm_client_connect_request {
|
||||
u8 hbm_cmd;
|
||||
|
@ -248,10 +276,10 @@ struct hbm_client_connect_request {
|
|||
/**
|
||||
* struct hbm_client_connect_response - connect/disconnect response
|
||||
*
|
||||
* @hbm_cmd - bus message command header
|
||||
* @me_addr - address of the client in ME
|
||||
* @host_addr - address of the client in the driver
|
||||
* @status - status of the request
|
||||
* @hbm_cmd: bus message command header
|
||||
* @me_addr: address of the client in ME
|
||||
* @host_addr: address of the client in the driver
|
||||
* @status: status of the request
|
||||
*/
|
||||
struct hbm_client_connect_response {
|
||||
u8 hbm_cmd;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -153,8 +153,9 @@ static void st_reg_complete(struct st_data_s *st_gdata, char err)
|
|||
(st_gdata->list[i]->priv_data, err);
|
||||
pr_info("protocol %d's cb sent %d\n", i, err);
|
||||
if (err) { /* cleanup registered protocol */
|
||||
st_gdata->protos_registered--;
|
||||
st_gdata->is_registered[i] = false;
|
||||
if (st_gdata->protos_registered)
|
||||
st_gdata->protos_registered--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -639,14 +640,12 @@ long st_unregister(struct st_proto_s *proto)
|
|||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
st_gdata->protos_registered--;
|
||||
if (st_gdata->protos_registered)
|
||||
st_gdata->protos_registered--;
|
||||
|
||||
remove_channel_from_table(st_gdata, proto);
|
||||
spin_unlock_irqrestore(&st_gdata->lock, flags);
|
||||
|
||||
/* paranoid check */
|
||||
if (st_gdata->protos_registered < ST_EMPTY)
|
||||
st_gdata->protos_registered = ST_EMPTY;
|
||||
|
||||
if ((st_gdata->protos_registered == ST_EMPTY) &&
|
||||
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
|
||||
pr_info(" all chnl_ids unregistered ");
|
||||
|
|
|
@ -328,7 +328,8 @@ int vmci_datagram_dispatch(u32 context_id,
|
|||
|
||||
BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24);
|
||||
|
||||
if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
|
||||
if (dg->payload_size > VMCI_MAX_DG_SIZE ||
|
||||
VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
|
||||
pr_devel("Payload (size=%llu bytes) too big to send\n",
|
||||
(unsigned long long)dg->payload_size);
|
||||
return VMCI_ERROR_INVALID_ARGS;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/device.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
struct mei_cl_device;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue