summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 12:55:41 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 12:55:41 +0200
commitef0625b70dac9405ac9d9928cf767108041a9e51 (patch)
tree9b2a0ea588e23e477868f593f8f7397eedb71c2c /drivers
parentMerge tag 'compress-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff)
parentmei: mei_txe_fw_sts can be static (diff)
downloadlinux-ef0625b70dac9405ac9d9928cf767108041a9e51.tar.xz
linux-ef0625b70dac9405ac9d9928cf767108041a9e51.zip
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 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/i8k.c13
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c1
-rw-r--r--drivers/extcon/Kconfig13
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-gpio.c10
-rw-r--r--drivers/extcon/extcon-max77693.c37
-rw-r--r--drivers/extcon/extcon-rt8973a.c740
-rw-r--r--drivers/extcon/extcon-rt8973a.h203
-rw-r--r--drivers/extcon/extcon-sm5502.c20
-rw-r--r--drivers/extcon/extcon-sm5502.h282
-rw-r--r--drivers/hv/channel.c56
-rw-r--r--drivers/hv/channel_mgmt.c21
-rw-r--r--drivers/hv/connection.c17
-rw-r--r--drivers/hv/hv.c27
-rw-r--r--drivers/hv/hyperv_vmbus.h4
-rw-r--r--drivers/hv/ring_buffer.c5
-rw-r--r--drivers/ipack/carriers/tpci200.c3
-rw-r--r--drivers/ipack/devices/ipoctal.c69
-rw-r--r--drivers/ipack/devices/ipoctal.h2
-rw-r--r--drivers/ipack/ipack.c4
-rw-r--r--drivers/misc/eeprom/eeprom.c23
-rw-r--r--drivers/misc/genwqe/card_base.c38
-rw-r--r--drivers/misc/genwqe/card_base.h21
-rw-r--r--drivers/misc/genwqe/card_ddcb.c77
-rw-r--r--drivers/misc/genwqe/card_ddcb.h2
-rw-r--r--drivers/misc/genwqe/card_debugfs.c10
-rw-r--r--drivers/misc/genwqe/card_dev.c21
-rw-r--r--drivers/misc/genwqe/card_sysfs.c11
-rw-r--r--drivers/misc/genwqe/card_utils.c7
-rw-r--r--drivers/misc/genwqe/genwqe_driver.h4
-rw-r--r--drivers/misc/lattice-ecp3-config.c1
-rw-r--r--drivers/misc/mei/amthif.c167
-rw-r--r--drivers/misc/mei/bus.c25
-rw-r--r--drivers/misc/mei/client.c237
-rw-r--r--drivers/misc/mei/client.h17
-rw-r--r--drivers/misc/mei/debugfs.c70
-rw-r--r--drivers/misc/mei/hbm.c567
-rw-r--r--drivers/misc/mei/hbm.h17
-rw-r--r--drivers/misc/mei/hw-me.c194
-rw-r--r--drivers/misc/mei/hw-me.h32
-rw-r--r--drivers/misc/mei/hw-txe.c252
-rw-r--r--drivers/misc/mei/hw-txe.h6
-rw-r--r--drivers/misc/mei/hw.h74
-rw-r--r--drivers/misc/mei/init.c107
-rw-r--r--drivers/misc/mei/interrupt.c96
-rw-r--r--drivers/misc/mei/main.c143
-rw-r--r--drivers/misc/mei/mei_dev.h279
-rw-r--r--drivers/misc/mei/nfc.c77
-rw-r--r--drivers/misc/mei/pci-me.c14
-rw-r--r--drivers/misc/mei/pci-txe.c13
-rw-r--r--drivers/misc/mei/wd.c59
-rw-r--r--drivers/misc/spear13xx_pcie_gadget.c98
-rw-r--r--drivers/misc/ti-st/st_core.c11
-rw-r--r--drivers/misc/vmw_vmci/vmci_datagram.c3
-rw-r--r--drivers/parport/parport_pc.c54
55 files changed, 3020 insertions, 1335 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 65525c7e903c..34174d01462e 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -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,
@@ -706,6 +711,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 = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 9b1a5ac4881d..c07dfe5c4da3 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -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,
},
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 6f2f4727de2c..6a1f7de6fa54 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -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
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index b38546eb522a..0370b42e5a27 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -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
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 5b7ec274cb63..72f19a37fd01 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -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;
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 77460f2c1ca1..490e27475bac 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -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);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
new file mode 100644
index 000000000000..a784b2d5ee72
--- /dev/null
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -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");
diff --git a/drivers/extcon/extcon-rt8973a.h b/drivers/extcon/extcon-rt8973a.h
new file mode 100644
index 000000000000..9dc3e0227eb7
--- /dev/null
+++ b/drivers/extcon/extcon-rt8973a.h
@@ -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 */
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index 560d7dccec7b..b0f7bd82af90 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -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;
}
}
diff --git a/drivers/extcon/extcon-sm5502.h b/drivers/extcon/extcon-sm5502.h
new file mode 100644
index 000000000000..974b53222f56
--- /dev/null
+++ b/drivers/extcon/extcon-sm5502.h
@@ -0,0 +1,282 @@
+/*
+ * sm5502.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_SM5502_H
+#define __LINUX_EXTCON_SM5502_H
+
+enum sm5502_types {
+ TYPE_SM5502,
+};
+
+/* SM5502 registers */
+enum sm5502_reg {
+ SM5502_REG_DEVICE_ID = 0x01,
+ SM5502_REG_CONTROL,
+ SM5502_REG_INT1,
+ SM5502_REG_INT2,
+ SM5502_REG_INTMASK1,
+ SM5502_REG_INTMASK2,
+ SM5502_REG_ADC,
+ SM5502_REG_TIMING_SET1,
+ SM5502_REG_TIMING_SET2,
+ SM5502_REG_DEV_TYPE1,
+ SM5502_REG_DEV_TYPE2,
+ SM5502_REG_BUTTON1,
+ SM5502_REG_BUTTON2,
+ SM5502_REG_CAR_KIT_STATUS,
+ SM5502_REG_RSVD1,
+ SM5502_REG_RSVD2,
+ SM5502_REG_RSVD3,
+ SM5502_REG_RSVD4,
+ SM5502_REG_MANUAL_SW1,
+ SM5502_REG_MANUAL_SW2,
+ SM5502_REG_DEV_TYPE3,
+ SM5502_REG_RSVD5,
+ SM5502_REG_RSVD6,
+ SM5502_REG_RSVD7,
+ SM5502_REG_RSVD8,
+ SM5502_REG_RSVD9,
+ SM5502_REG_RESET,
+ SM5502_REG_RSVD10,
+ SM5502_REG_RESERVED_ID1,
+ SM5502_REG_RSVD11,
+ SM5502_REG_RSVD12,
+ SM5502_REG_RESERVED_ID2,
+ SM5502_REG_RSVD13,
+ SM5502_REG_OCP,
+ SM5502_REG_RSVD14,
+ SM5502_REG_RSVD15,
+ SM5502_REG_RSVD16,
+ SM5502_REG_RSVD17,
+ SM5502_REG_RSVD18,
+ SM5502_REG_RSVD19,
+ SM5502_REG_RSVD20,
+ SM5502_REG_RSVD21,
+ SM5502_REG_RSVD22,
+ SM5502_REG_RSVD23,
+ SM5502_REG_RSVD24,
+ SM5502_REG_RSVD25,
+ SM5502_REG_RSVD26,
+ SM5502_REG_RSVD27,
+ SM5502_REG_RSVD28,
+ SM5502_REG_RSVD29,
+ SM5502_REG_RSVD30,
+ SM5502_REG_RSVD31,
+ SM5502_REG_RSVD32,
+ SM5502_REG_RSVD33,
+ SM5502_REG_RSVD34,
+ SM5502_REG_RSVD35,
+ SM5502_REG_RSVD36,
+ SM5502_REG_RESERVED_ID3,
+
+ SM5502_REG_END,
+};
+
+/* Define SM5502 MASK/SHIFT constant */
+#define SM5502_REG_DEVICE_ID_VENDOR_SHIFT 0
+#define SM5502_REG_DEVICE_ID_VERSION_SHIFT 3
+#define SM5502_REG_DEVICE_ID_VENDOR_MASK (0x3 << SM5502_REG_DEVICE_ID_VENDOR_SHIFT)
+#define SM5502_REG_DEVICE_ID_VERSION_MASK (0x1f << SM5502_REG_DEVICE_ID_VERSION_SHIFT)
+
+#define SM5502_REG_CONTROL_MASK_INT_SHIFT 0
+#define SM5502_REG_CONTROL_WAIT_SHIFT 1
+#define SM5502_REG_CONTROL_MANUAL_SW_SHIFT 2
+#define SM5502_REG_CONTROL_RAW_DATA_SHIFT 3
+#define SM5502_REG_CONTROL_SW_OPEN_SHIFT 4
+#define SM5502_REG_CONTROL_MASK_INT_MASK (0x1 << SM5502_REG_CONTROL_MASK_INT_SHIFT)
+#define SM5502_REG_CONTROL_WAIT_MASK (0x1 << SM5502_REG_CONTROL_WAIT_SHIFT)
+#define SM5502_REG_CONTROL_MANUAL_SW_MASK (0x1 << SM5502_REG_CONTROL_MANUAL_SW_SHIFT)
+#define SM5502_REG_CONTROL_RAW_DATA_MASK (0x1 << SM5502_REG_CONTROL_RAW_DATA_SHIFT)
+#define SM5502_REG_CONTROL_SW_OPEN_MASK (0x1 << SM5502_REG_CONTROL_SW_OPEN_SHIFT)
+
+#define SM5502_REG_INTM1_ATTACH_SHIFT 0
+#define SM5502_REG_INTM1_DETACH_SHIFT 1
+#define SM5502_REG_INTM1_KP_SHIFT 2
+#define SM5502_REG_INTM1_LKP_SHIFT 3
+#define SM5502_REG_INTM1_LKR_SHIFT 4
+#define SM5502_REG_INTM1_OVP_EVENT_SHIFT 5
+#define SM5502_REG_INTM1_OCP_EVENT_SHIFT 6
+#define SM5502_REG_INTM1_OVP_OCP_DIS_SHIFT 7
+#define SM5502_REG_INTM1_ATTACH_MASK (0x1 << SM5502_REG_INTM1_ATTACH_SHIFT)
+#define SM5502_REG_INTM1_DETACH_MASK (0x1 << SM5502_REG_INTM1_DETACH_SHIFT)
+#define SM5502_REG_INTM1_KP_MASK (0x1 << SM5502_REG_INTM1_KP_SHIFT)
+#define SM5502_REG_INTM1_LKP_MASK (0x1 << SM5502_REG_INTM1_LKP_SHIFT)
+#define SM5502_REG_INTM1_LKR_MASK (0x1 << SM5502_REG_INTM1_LKR_SHIFT)
+#define SM5502_REG_INTM1_OVP_EVENT_MASK (0x1 << SM5502_REG_INTM1_OVP_EVENT_SHIFT)
+#define SM5502_REG_INTM1_OCP_EVENT_MASK (0x1 << SM5502_REG_INTM1_OCP_EVENT_SHIFT)
+#define SM5502_REG_INTM1_OVP_OCP_DIS_MASK (0x1 << SM5502_REG_INTM1_OVP_OCP_DIS_SHIFT)
+
+#define SM5502_REG_INTM2_VBUS_DET_SHIFT 0
+#define SM5502_REG_INTM2_REV_ACCE_SHIFT 1
+#define SM5502_REG_INTM2_ADC_CHG_SHIFT 2
+#define SM5502_REG_INTM2_STUCK_KEY_SHIFT 3
+#define SM5502_REG_INTM2_STUCK_KEY_RCV_SHIFT 4
+#define SM5502_REG_INTM2_MHL_SHIFT 5
+#define SM5502_REG_INTM2_VBUS_DET_MASK (0x1 << SM5502_REG_INTM2_VBUS_DET_SHIFT)
+#define SM5502_REG_INTM2_REV_ACCE_MASK (0x1 << SM5502_REG_INTM2_REV_ACCE_SHIFT)
+#define SM5502_REG_INTM2_ADC_CHG_MASK (0x1 << SM5502_REG_INTM2_ADC_CHG_SHIFT)
+#define SM5502_REG_INTM2_STUCK_KEY_MASK (0x1 << SM5502_REG_INTM2_STUCK_KEY_SHIFT)
+#define SM5502_REG_INTM2_STUCK_KEY_RCV_MASK (0x1 << SM5502_REG_INTM2_STUCK_KEY_RCV_SHIFT)
+#define SM5502_REG_INTM2_MHL_MASK (0x1 << SM5502_REG_INTM2_MHL_SHIFT)
+
+#define SM5502_REG_ADC_SHIFT 0
+#define SM5502_REG_ADC_MASK (0x1f << SM5502_REG_ADC_SHIFT)
+
+#define SM5502_REG_TIMING_SET1_KEY_PRESS_SHIFT 4
+#define SM5502_REG_TIMING_SET1_KEY_PRESS_MASK (0xf << SM5502_REG_TIMING_SET1_KEY_PRESS_SHIFT)
+#define TIMING_KEY_PRESS_100MS 0x0
+#define TIMING_KEY_PRESS_200MS 0x1
+#define TIMING_KEY_PRESS_300MS 0x2
+#define TIMING_KEY_PRESS_400MS 0x3
+#define TIMING_KEY_PRESS_500MS 0x4
+#define TIMING_KEY_PRESS_600MS 0x5
+#define TIMING_KEY_PRESS_700MS 0x6
+#define TIMING_KEY_PRESS_800MS 0x7
+#define TIMING_KEY_PRESS_900MS 0x8
+#define TIMING_KEY_PRESS_1000MS 0x9
+#define SM5502_REG_TIMING_SET1_ADC_DET_SHIFT 0
+#define SM5502_REG_TIMING_SET1_ADC_DET_MASK (0xf << SM5502_REG_TIMING_SET1_ADC_DET_SHIFT)
+#define TIMING_ADC_DET_50MS 0x0
+#define TIMING_ADC_DET_100MS 0x1
+#define TIMING_ADC_DET_150MS 0x2
+#define TIMING_ADC_DET_200MS 0x3
+#define TIMING_ADC_DET_300MS 0x4
+#define TIMING_ADC_DET_400MS 0x5
+#define TIMING_ADC_DET_500MS 0x6
+#define TIMING_ADC_DET_600MS 0x7
+#define TIMING_ADC_DET_700MS 0x8
+#define TIMING_ADC_DET_800MS 0x9
+#define TIMING_ADC_DET_900MS 0xA
+#define TIMING_ADC_DET_1000MS 0xB
+
+#define SM5502_REG_TIMING_SET2_SW_WAIT_SHIFT 4
+#define SM5502_REG_TIMING_SET2_SW_WAIT_MASK (0xf << SM5502_REG_TIMING_SET2_SW_WAIT_SHIFT)
+#define TIMING_SW_WAIT_10MS 0x0
+#define TIMING_SW_WAIT_30MS 0x1
+#define TIMING_SW_WAIT_50MS 0x2
+#define TIMING_SW_WAIT_70MS 0x3
+#define TIMING_SW_WAIT_90MS 0x4
+#define TIMING_SW_WAIT_110MS 0x5
+#define TIMING_SW_WAIT_130MS 0x6
+#define TIMING_SW_WAIT_150MS 0x7
+#define TIMING_SW_WAIT_170MS 0x8
+#define TIMING_SW_WAIT_190MS 0x9
+#define TIMING_SW_WAIT_210MS 0xA
+#define SM5502_REG_TIMING_SET2_LONG_KEY_SHIFT 0
+#define SM5502_REG_TIMING_SET2_LONG_KEY_MASK (0xf << SM5502_REG_TIMING_SET2_LONG_KEY_SHIFT)
+#define TIMING_LONG_KEY_300MS 0x0
+#define TIMING_LONG_KEY_400MS 0x1
+#define TIMING_LONG_KEY_500MS 0x2
+#define TIMING_LONG_KEY_600MS 0x3
+#define TIMING_LONG_KEY_700MS 0x4
+#define TIMING_LONG_KEY_800MS 0x5
+#define TIMING_LONG_KEY_900MS 0x6
+#define TIMING_LONG_KEY_1000MS 0x7
+#define TIMING_LONG_KEY_1100MS 0x8
+#define TIMING_LONG_KEY_1200MS 0x9
+#define TIMING_LONG_KEY_1300MS 0xA
+#define TIMING_LONG_KEY_1400MS 0xB
+#define TIMING_LONG_KEY_1500MS 0xC
+
+#define SM5502_REG_DEV_TYPE1_AUDIO_TYPE1_SHIFT 0
+#define SM5502_REG_DEV_TYPE1_AUDIO_TYPE2_SHIFT 1
+#define SM5502_REG_DEV_TYPE1_USB_SDP_SHIFT 2
+#define SM5502_REG_DEV_TYPE1_UART_SHIFT 3
+#define SM5502_REG_DEV_TYPE1_CAR_KIT_CHARGER_SHIFT 4
+#define SM5502_REG_DEV_TYPE1_USB_CHG_SHIFT 5
+#define SM5502_REG_DEV_TYPE1_DEDICATED_CHG_SHIFT 6
+#define SM5502_REG_DEV_TYPE1_USB_OTG_SHIFT 7
+#define SM5502_REG_DEV_TYPE1_AUDIO_TYPE1_MASK (0x1 << SM5502_REG_DEV_TYPE1_AUDIO_TYPE1_SHIFT)
+#define SM5502_REG_DEV_TYPE1_AUDIO_TYPE1__MASK (0x1 << SM5502_REG_DEV_TYPE1_AUDIO_TYPE2_SHIFT)
+#define SM5502_REG_DEV_TYPE1_USB_SDP_MASK (0x1 << SM5502_REG_DEV_TYPE1_USB_SDP_SHIFT)
+#define SM5502_REG_DEV_TYPE1_UART_MASK (0x1 << SM5502_REG_DEV_TYPE1_UART_SHIFT)
+#define SM5502_REG_DEV_TYPE1_CAR_KIT_CHARGER_MASK (0x1 << SM5502_REG_DEV_TYPE1_CAR_KIT_CHARGER_SHIFT)
+#define SM5502_REG_DEV_TYPE1_USB_CHG_MASK (0x1 << SM5502_REG_DEV_TYPE1_USB_CHG_SHIFT)
+#define SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK (0x1 << SM5502_REG_DEV_TYPE1_DEDICATED_CHG_SHIFT)
+#define SM5502_REG_DEV_TYPE1_USB_OTG_MASK (0x1 << SM5502_REG_DEV_TYPE1_USB_OTG_SHIFT)
+
+#define SM5502_REG_DEV_TYPE2_JIG_USB_ON_SHIFT 0
+#define SM5502_REG_DEV_TYPE2_JIG_USB_OFF_SHIFT 1
+#define SM5502_REG_DEV_TYPE2_JIG_UART_ON_SHIFT 2
+#define SM5502_REG_DEV_TYPE2_JIG_UART_OFF_SHIFT 3
+#define SM5502_REG_DEV_TYPE2_PPD_SHIFT 4
+#define SM5502_REG_DEV_TYPE2_TTY_SHIFT 5
+#define SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT 6
+#define SM5502_REG_DEV_TYPE2_JIG_USB_ON_MASK (0x1 << SM5502_REG_DEV_TYPE2_JIG_USB_ON_SHIFT)
+#define SM5502_REG_DEV_TYPE2_JIG_USB_OFF_MASK (0x1 << SM5502_REG_DEV_TYPE2_JIG_USB_OFF_SHIFT)
+#define SM5502_REG_DEV_TYPE2_JIG_UART_ON_MASK (0x1 << SM5502_REG_DEV_TYPE2_JIG_UART_ON_SHIFT)
+#define SM5502_REG_DEV_TYPE2_JIG_UART_OFF_MASK (0x1 << SM5502_REG_DEV_TYPE2_JIG_UART_OFF_SHIFT)
+#define SM5502_REG_DEV_TYPE2_PPD_MASK (0x1 << SM5502_REG_DEV_TYPE2_PPD_SHIFT)
+#define SM5502_REG_DEV_TYPE2_TTY_MASK (0x1 << SM5502_REG_DEV_TYPE2_TTY_SHIFT)
+#define SM5502_REG_DEV_TYPE2_AV_CABLE_MASK (0x1 << SM5502_REG_DEV_TYPE2_AV_CABLE_SHIFT)
+
+#define SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT 0
+#define SM5502_REG_MANUAL_SW1_DP_SHIFT 2
+#define SM5502_REG_MANUAL_SW1_DM_SHIFT 5
+#define SM5502_REG_MANUAL_SW1_VBUSIN_MASK (0x3 << SM5502_REG_MANUAL_SW1_VBUSIN_SHIFT)
+#define SM5502_REG_MANUAL_SW1_DP_MASK (0x7 << SM5502_REG_MANUAL_SW1_DP_SHIFT)
+#define SM5502_REG_MANUAL_SW1_DM_MASK (0x7 << SM5502_REG_MANUAL_SW1_DM_SHIFT)
+#define VBUSIN_SWITCH_OPEN 0x0
+#define VBUSIN_SWITCH_VBUSOUT 0x1
+#define VBUSIN_SWITCH_MIC 0x2
+#define VBUSIN_SWITCH_VBUSOUT_WITH_USB 0x3
+#define DM_DP_CON_SWITCH_OPEN 0x0
+#define DM_DP_CON_SWITCH_USB 0x1
+#define DM_DP_CON_SWITCH_AUDIO 0x2
+#define DM_DP_CON_SWITCH_UART 0x3
+#define DM_DP_SWITCH_OPEN ((DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
+ | (DM_DP_CON_SWITCH_OPEN <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
+#define DM_DP_SWITCH_USB ((DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
+ | (DM_DP_CON_SWITCH_USB <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
+#define DM_DP_SWITCH_AUDIO ((DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
+ | (DM_DP_CON_SWITCH_AUDIO <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
+#define DM_DP_SWITCH_UART ((DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DP_SHIFT) \
+ | (DM_DP_CON_SWITCH_UART <<SM5502_REG_MANUAL_SW1_DM_SHIFT))
+
+/* SM5502 Interrupts */
+enum sm5502_irq {
+ /* INT1 */
+ SM5502_IRQ_INT1_ATTACH,
+ SM5502_IRQ_INT1_DETACH,
+ SM5502_IRQ_INT1_KP,
+ SM5502_IRQ_INT1_LKP,
+ SM5502_IRQ_INT1_LKR,
+ SM5502_IRQ_INT1_OVP_EVENT,
+ SM5502_IRQ_INT1_OCP_EVENT,
+ SM5502_IRQ_INT1_OVP_OCP_DIS,
+
+ /* INT2 */
+ SM5502_IRQ_INT2_VBUS_DET,
+ SM5502_IRQ_INT2_REV_ACCE,
+ SM5502_IRQ_INT2_ADC_CHG,
+ SM5502_IRQ_INT2_STUCK_KEY,
+ SM5502_IRQ_INT2_STUCK_KEY_RCV,
+ SM5502_IRQ_INT2_MHL,
+
+ SM5502_IRQ_NUM,
+};
+
+#define SM5502_IRQ_INT1_ATTACH_MASK BIT(0)
+#define SM5502_IRQ_INT1_DETACH_MASK BIT(1)
+#define SM5502_IRQ_INT1_KP_MASK BIT(2)
+#define SM5502_IRQ_INT1_LKP_MASK BIT(3)
+#define SM5502_IRQ_INT1_LKR_MASK BIT(4)
+#define SM5502_IRQ_INT1_OVP_EVENT_MASK BIT(5)
+#define SM5502_IRQ_INT1_OCP_EVENT_MASK BIT(6)
+#define SM5502_IRQ_INT1_OVP_OCP_DIS_MASK BIT(7)
+#define SM5502_IRQ_INT2_VBUS_DET_MASK BIT(0)
+#define SM5502_IRQ_INT2_REV_ACCE_MASK BIT(1)
+#define SM5502_IRQ_INT2_ADC_CHG_MASK BIT(2)
+#define SM5502_IRQ_INT2_STUCK_KEY_MASK BIT(3)
+#define SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK BIT(4)
+#define SM5502_IRQ_INT2_MHL_MASK BIT(5)
+
+#endif /* __LINUX_EXTCON_SM5502_H */
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 531a593912ec..433f72a1c006 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -165,8 +165,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
ret = vmbus_post_msg(open_msg,
sizeof(struct vmbus_channel_open_channel));
- if (ret != 0)
+ if (ret != 0) {
+ err = ret;
goto error1;
+ }
t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
if (t == 0) {
@@ -363,7 +365,6 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
u32 next_gpadl_handle;
unsigned long flags;
int ret = 0;
- int t;
next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
atomic_inc(&vmbus_connection.next_gpadl_handle);
@@ -410,9 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
}
}
- t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
- BUG_ON(t == 0);
-
+ wait_for_completion(&msginfo->waitevent);
/* At this point, we received the gpadl created msg */
*gpadl_handle = gpadlmsg->gpadl;
@@ -435,7 +434,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
struct vmbus_channel_gpadl_teardown *msg;
struct vmbus_channel_msginfo *info;
unsigned long flags;
- int ret, t;
+ int ret;
info = kmalloc(sizeof(*info) +
sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
@@ -457,11 +456,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_gpadl_teardown));
- BUG_ON(ret != 0);
- t = wait_for_completion_timeout(&info->waitevent, 5*HZ);
- BUG_ON(t == 0);
+ if (ret)
+ goto post_msg_err;
+
+ wait_for_completion(&info->waitevent);
- /* Received a torndown response */
+post_msg_err:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
@@ -478,7 +478,7 @@ static void reset_channel_cb(void *arg)
channel->onchannel_callback = NULL;
}
-static void vmbus_close_internal(struct vmbus_channel *channel)
+static int vmbus_close_internal(struct vmbus_channel *channel)
{
struct vmbus_channel_close_channel *msg;
int ret;
@@ -486,11 +486,14 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
- if (channel->target_cpu != smp_processor_id())
+ if (channel->target_cpu != get_cpu()) {
+ put_cpu();
smp_call_function_single(channel->target_cpu, reset_channel_cb,
channel, true);
- else
+ } else {
reset_channel_cb(channel);
+ put_cpu();
+ }
/* Send a closing message */
@@ -501,11 +504,28 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
- BUG_ON(ret != 0);
+ if (ret) {
+ pr_err("Close failed: close post msg return is %d\n", ret);
+ /*
+ * If we failed to post the close msg,
+ * it is perhaps better to leak memory.
+ */
+ return ret;
+ }
+
/* Tear down the gpadl for the channel's ring buffer */
- if (channel->ringbuffer_gpadlhandle)
- vmbus_teardown_gpadl(channel,
- channel->ringbuffer_gpadlhandle);
+ if (channel->ringbuffer_gpadlhandle) {
+ ret = vmbus_teardown_gpadl(channel,
+ channel->ringbuffer_gpadlhandle);
+ if (ret) {
+ pr_err("Close failed: teardown gpadl return %d\n", ret);
+ /*
+ * If we failed to teardown gpadl,
+ * it is perhaps better to leak memory.
+ */
+ return ret;
+ }
+ }
/* Cleanup the ring buffers for this channel */
hv_ringbuffer_cleanup(&channel->outbound);
@@ -514,7 +534,7 @@ static void vmbus_close_internal(struct vmbus_channel *channel)
free_pages((unsigned long)channel->ringbuffer_pages,
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
-
+ return ret;
}
/*
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index ed9350d42764..a2d1a9612c86 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -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)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index ae22e3c1fc4c..e206619b946e 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -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);
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index edfc8488cb03..3e4235c7a47f 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -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)
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 22b750749a39..c386d8dc7223 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -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;
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 15db66b74141..6361d124f67d 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -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);
diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c
index de5e32151a1e..9b23843dcad4 100644
--- a/drivers/ipack/carriers/tpci200.c
+++ b/drivers/ipack/carriers/tpci200.c
@@ -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");
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index e41bef048c23..035d5449227e 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -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)
diff --git a/drivers/ipack/devices/ipoctal.h b/drivers/ipack/devices/ipoctal.h
index 28f1c4233154..7fede0eb6a0c 100644
--- a/drivers/ipack/devices/ipoctal.h
+++ b/drivers/ipack/devices/ipoctal.h
@@ -12,7 +12,7 @@
* Software Foundation; version 2 of the License.
*/
-#ifndef _IPOCTAL_H
+#ifndef _IPOCTAL_H_
#define _IPOCTAL_H_
#define NR_CHANNELS 8
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c
index d0016ba469ed..c0e7b624ce54 100644
--- a/drivers/ipack/ipack.c
+++ b/drivers/ipack/ipack.c
@@ -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);
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index 33f8673d23a6..b432873def96 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -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;
}
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index 43bbabc96b6c..4cf8f82cfca2 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -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) {
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index 67abd8cb2247..c64d7cad1085 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -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);
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c
index dc9851a5540e..6d51e5f08664 100644
--- a/drivers/misc/genwqe/card_ddcb.c
+++ b/drivers/misc/genwqe/card_ddcb.c
@@ -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
diff --git a/drivers/misc/genwqe/card_ddcb.h b/drivers/misc/genwqe/card_ddcb.h
index c4f26720753e..0361a68d79a6 100644
--- a/drivers/misc/genwqe/card_ddcb.h
+++ b/drivers/misc/genwqe/card_ddcb.h
@@ -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
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c
index c9b4d6d0eb99..c715534e7fe7 100644
--- a/drivers/misc/genwqe/card_debugfs.c
+++ b/drivers/misc/genwqe/card_debugfs.c
@@ -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,
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index aae42555e2ca..5918586f2f76 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -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. */
diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c
index 7232e40a3ad9..2c33fbca9225 100644
--- a/drivers/misc/genwqe/card_sysfs.c
+++ b/drivers/misc/genwqe/card_sysfs.c
@@ -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,
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
index a6400f09229c..7cb3b7e41739 100644
--- a/drivers/misc/genwqe/card_utils.c
+++ b/drivers/misc/genwqe/card_utils.c
@@ -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);
}
diff --git a/drivers/misc/genwqe/genwqe_driver.h b/drivers/misc/genwqe/genwqe_driver.h
index a506e9aa2d57..15355350e076 100644
--- a/drivers/misc/genwqe/genwqe_driver.h
+++ b/drivers/misc/genwqe/genwqe_driver.h
@@ -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
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index 7e1efd5f58f0..c544f1f50f52 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -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);
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 0d6234db00fa..6cdce8477f57 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
-#include <linux/pci.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
@@ -29,6 +28,7 @@
#include <linux/uuid.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
+#include <linux/slab.h>
#include <linux/mei.h>
@@ -64,31 +64,32 @@ void mei_amthif_reset_params(struct mei_device *dev)
*
* @dev: the device structure
*
+ * Return: 0 on success, <0 on failure.
*/
int mei_amthif_host_init(struct mei_device *dev)
{
struct mei_cl *cl = &dev->iamthif_cl;
+ struct mei_me_client *me_cl;
unsigned char *msg_buf;
- int ret, i;
+ int ret;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_cl_init(cl, dev);
- i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
- if (i < 0) {
- dev_info(&dev->pdev->dev,
- "amthif: failed to find the client %d\n", i);
+ me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
+ if (!me_cl) {
+ dev_info(dev->dev, "amthif: failed to find the client");
return -ENOTTY;
}
- cl->me_client_id = dev->me_clients[i].client_id;
+ cl->me_client_id = me_cl->client_id;
+ cl->cl_uuid = me_cl->props.protocol_name;
/* Assign iamthif_mtu to the value received from ME */
- dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
- dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
- dev->me_clients[i].props.max_msg_length);
+ dev->iamthif_mtu = me_cl->props.max_msg_length;
+ dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
kfree(dev->iamthif_msg_buf);
dev->iamthif_msg_buf = NULL;
@@ -96,17 +97,15 @@ int mei_amthif_host_init(struct mei_device *dev)
/* allocate storage for ME message buffer */
msg_buf = kcalloc(dev->iamthif_mtu,
sizeof(unsigned char), GFP_KERNEL);
- if (!msg_buf) {
- dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
+ if (!msg_buf)
return -ENOMEM;
- }
dev->iamthif_msg_buf = msg_buf;
ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
if (ret < 0) {
- dev_err(&dev->pdev->dev,
+ dev_err(dev->dev,
"amthif: failed link client %d\n", ret);
return ret;
}
@@ -124,18 +123,16 @@ int mei_amthif_host_init(struct mei_device *dev)
* @dev: the device structure
* @file: pointer to file object
*
- * returns returned a list entry on success, NULL on failure.
+ * Return: returned a list entry on success, NULL on failure.
*/
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
struct file *file)
{
struct mei_cl_cb *cb;
- list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
- if (cb->cl && cb->cl == &dev->iamthif_cl &&
- cb->file_object == file)
+ list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
+ if (cb->file_object == file)
return cb;
- }
return NULL;
}
@@ -144,15 +141,14 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
* mei_amthif_read - read data from AMTHIF client
*
* @dev: the device structure
- * @if_num: minor number
* @file: pointer to file object
- * @*ubuf: pointer to user data in user space
+ * @ubuf: pointer to user data in user space
* @length: data length to read
* @offset: data read offset
*
* Locking: called under "dev->device_lock" lock
*
- * returns
+ * Return:
* returned data length on success,
* zero if no data to read,
* negative on failure.
@@ -160,25 +156,19 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
int mei_amthif_read(struct mei_device *dev, struct file *file,
char __user *ubuf, size_t length, loff_t *offset)
{
- int rets;
- int wait_ret;
- struct mei_cl_cb *cb = NULL;
struct mei_cl *cl = file->private_data;
+ struct mei_cl_cb *cb;
unsigned long timeout;
- int i;
+ int rets;
+ int wait_ret;
/* Only possible if we are in timeout */
- if (!cl || cl != &dev->iamthif_cl) {
- dev_dbg(&dev->pdev->dev, "bad file ext.\n");
+ if (!cl) {
+ dev_err(dev->dev, "bad file ext.\n");
return -ETIME;
}
- i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
- if (i < 0) {
- dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
- return -ENOTTY;
- }
- dev_dbg(&dev->pdev->dev, "checking amthif data\n");
+ dev_dbg(dev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
/* Check for if we can block or not*/
@@ -186,7 +176,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
return -EAGAIN;
- dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
+ dev_dbg(dev->dev, "waiting for amthif data\n");
while (cb == NULL) {
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
@@ -200,21 +190,21 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
if (wait_ret)
return -ERESTARTSYS;
- dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
+ dev_dbg(dev->dev, "woke up from sleep\n");
}
- dev_dbg(&dev->pdev->dev, "Got amthif data\n");
+ dev_dbg(dev->dev, "Got amthif data\n");
dev->iamthif_timer = 0;
if (cb) {
timeout = cb->read_time +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
- dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
+ dev_dbg(dev->dev, "amthif timeout = %lud\n",
timeout);
if (time_after(jiffies, timeout)) {
- dev_dbg(&dev->pdev->dev, "amthif Time out\n");
+ dev_dbg(dev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
rets = -ETIME;
@@ -234,16 +224,16 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* remove message from deletion list
*/
- dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
+ dev_dbg(dev->dev, "amthif cb->response_buffer size - %d\n",
cb->response_buffer.size);
- dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
+ dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
/* length is being truncated to PAGE_SIZE, however,
* the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset));
if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
- dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
+ dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
} else {
rets = length;
@@ -253,7 +243,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
}
free:
- dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
+ dev_dbg(dev->dev, "free amthif cb memory.\n");
*offset = 0;
mei_io_cb_free(cb);
out:
@@ -266,7 +256,7 @@ 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");
-
- list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
- list_del(&pos->list);
+ dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
- if (pos->cl && pos->cl == &dev->iamthif_cl) {
- status = mei_amthif_send_cmd(dev, pos);
- if (status) {
- dev_dbg(&dev->pdev->dev,
- "amthif write failed status = %d\n",
+ list_for_each_entry_safe(cb, next, &dev->amthif_cmd_list.list, list) {
+ list_del(&cb->list);
+ if (!cb->cl)
+ continue;
+ status = mei_amthif_send_cmd(dev, cb);
+ if (status)
+ dev_warn(dev->dev, "amthif write failed status = %d\n",
status);
- return;
- }
- break;
- }
+ break;
}
}
@@ -421,7 +405,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
dev->iamthif_file_object == file) {
mask |= (POLLIN | POLLRDNORM);
- dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
+ dev_dbg(dev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
mutex_unlock(&dev->device_lock);
@@ -434,12 +418,11 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
* mei_amthif_irq_write - write iamthif command in irq thread context.
*
- * @dev: the device structure.
- * @cb_pos: callback block.
* @cl: private data of the file object.
+ * @cb: callback block.
* @cmpl_list: complete list.
*
- * returns 0, OK; otherwise, error.
+ * Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct mei_cl_cb *cmpl_list)
@@ -481,7 +464,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
- dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
+ dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
rets = mei_write_message(dev, &mei_hdr,
dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
@@ -514,14 +497,14 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
}
/**
- * mei_amthif_irq_read_message - read routine after ISR to
+ * mei_amthif_irq_read_msg - read routine after ISR to
* handle the read amthif message
*
* @dev: the device structure
* @mei_hdr: header of amthif message
* @complete_list: An instance of our list structure
*
- * returns 0 on success, <0 on failure.
+ * Return: 0 on success, <0 on failure.
*/
int mei_amthif_irq_read_msg(struct mei_device *dev,
struct mei_msg_hdr *mei_hdr,
@@ -543,10 +526,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
if (!mei_hdr->msg_complete)
return 0;
- dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
+ dev_dbg(dev->dev, "amthif_message_buffer_index =%d\n",
mei_hdr->length);
- dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
+ dev_dbg(dev->dev, "completed amthif read.\n ");
if (!dev->iamthif_current_cb)
return -ENODEV;
@@ -559,10 +542,10 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
dev->iamthif_stall_timer = 0;
cb->buf_idx = dev->iamthif_msg_buf_index;
cb->read_time = jiffies;
- if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
+ if (dev->iamthif_ioctl) {
/* found the iamthif cb */
- dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
- dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
+ dev_dbg(dev->dev, "complete the amthif read cb.\n ");
+ dev_dbg(dev->dev, "add the amthif read cb to complete.\n ");
list_add_tail(&cb->list, &complete_list->list);
}
return 0;
@@ -574,7 +557,7 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
* @dev: the device structure.
* @slots: free slots.
*
- * returns 0, OK; otherwise, error.
+ * Return: 0, OK; otherwise, error.
*/
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
@@ -586,11 +569,11 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
*slots -= msg_slots;
if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
- dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
+ dev_dbg(dev->dev, "iamthif flow control failed\n");
return -EIO;
}
- dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
+ dev_dbg(dev->dev, "iamthif flow control success\n");
dev->iamthif_state = MEI_IAMTHIF_READING;
dev->iamthif_flow_control_pending = false;
dev->iamthif_msg_buf_index = 0;
@@ -604,7 +587,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
* mei_amthif_complete - complete amthif callback.
*
* @dev: the device structure.
- * @cb_pos: callback block.
+ * @cb: callback block.
*/
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
{
@@ -615,15 +598,15 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_msg_buf,
dev->iamthif_msg_buf_index);
list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
- dev_dbg(&dev->pdev->dev, "amthif read completed\n");
+ dev_dbg(dev->dev, "amthif read completed\n");
dev->iamthif_timer = jiffies;
- dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
+ dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
} else {
mei_amthif_run_next_cmd(dev);
}
- dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
+ dev_dbg(dev->dev, "completing amthif call back.\n");
wake_up_interruptible(&dev->iamthif_cl.wait);
}
@@ -638,7 +621,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
* mei_clear_list is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
- * returns true if callback removed from the list, false otherwise
+ * Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_list(struct mei_device *dev,
const struct file *file, struct list_head *mei_cb_list)
@@ -678,7 +661,7 @@ static bool mei_clear_list(struct mei_device *dev,
* mei_clear_lists is called to clear resources associated with file
* when application calls close function or Ctrl-C was pressed
*
- * returns true if callback removed from the list, false otherwise
+ * Return: true if callback removed from the list, false otherwise
*/
static bool mei_clear_lists(struct mei_device *dev, struct file *file)
{
@@ -719,7 +702,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file)
* @dev: device structure
* @file: pointer to file structure
*
-* returns 0 on success, <0 on error
+* Return: 0 on success, <0 on error
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
@@ -729,11 +712,11 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
if (dev->iamthif_file_object == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
- dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
+ dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
dev->iamthif_state);
dev->iamthif_canceled = true;
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
- dev_dbg(&dev->pdev->dev, "run next amthif iamthif cb\n");
+ dev_dbg(dev->dev, "run next amthif iamthif cb\n");
mei_amthif_run_next_cmd(dev);
}
}
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 0e993ef28b94..4d20d60ca38d 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -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;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 2da05c0e113d..bc9ba5359bc6 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -14,10 +14,10 @@
*
*/
-#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
@@ -27,47 +27,90 @@
#include "client.h"
/**
- * mei_me_cl_by_uuid - locate index of me client
+ * mei_me_cl_by_uuid - locate me client by uuid
*
* @dev: mei device
+ * @uuid: me client uuid
*
* Locking: called under "dev->device_lock" lock
*
- * returns me client index or -ENOENT if not found
+ * Return: me client or NULL if not found
*/
-int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
+struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
+ const uuid_le *uuid)
{
- int i;
+ struct mei_me_client *me_cl;
- for (i = 0; i < dev->me_clients_num; ++i)
- if (uuid_le_cmp(*uuid,
- dev->me_clients[i].props.protocol_name) == 0)
- return i;
+ list_for_each_entry(me_cl, &dev->me_clients, list)
+ if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
+ return me_cl;
- return -ENOENT;
+ return NULL;
}
-
/**
- * mei_me_cl_by_id return index to me_clients for client_id
+ * mei_me_cl_by_id - locate me client by client id
*
* @dev: the device structure
* @client_id: me client id
*
* Locking: called under "dev->device_lock" lock
*
- * returns index on success, -ENOENT on failure.
+ * Return: me client or NULL if not found
*/
+struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
+{
+
+ struct mei_me_client *me_cl;
-int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
+ list_for_each_entry(me_cl, &dev->me_clients, list)
+ if (me_cl->client_id == client_id)
+ return me_cl;
+ return NULL;
+}
+
+/**
+ * mei_me_cl_by_uuid_id - locate me client by client id and uuid
+ *
+ * @dev: the device structure
+ * @uuid: me client uuid
+ * @client_id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: me client or NULL if not found
+ */
+struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
+ const uuid_le *uuid, u8 client_id)
{
- int i;
+ struct mei_me_client *me_cl;
- for (i = 0; i < dev->me_clients_num; i++)
- if (dev->me_clients[i].client_id == client_id)
- return i;
+ list_for_each_entry(me_cl, &dev->me_clients, list)
+ if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
+ me_cl->client_id == client_id)
+ return me_cl;
+ return NULL;
+}
- return -ENOENT;
+/**
+ * mei_me_cl_remove - remove me client matching uuid and client_id
+ *
+ * @dev: the device structure
+ * @uuid: me client uuid
+ * @client_id: me client address
+ */
+void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
+{
+ struct mei_me_client *me_cl, *next;
+
+ list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
+ if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
+ me_cl->client_id == client_id) {
+ list_del(&me_cl->list);
+ kfree(me_cl);
+ break;
+ }
+ }
}
@@ -77,7 +120,7 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
* @cl1: host client 1
* @cl2: host client 2
*
- * returns true - if the clients has same host and me ids
+ * Return: true - if the clients has same host and me ids
* false - otherwise
*/
static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
@@ -117,7 +160,7 @@ static void __mei_io_list_flush(struct mei_cl_cb *list,
* @list: An instance of our list structure
* @cl: host client
*/
-static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
{
__mei_io_list_flush(list, cl, false);
}
@@ -152,10 +195,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
/**
* mei_io_cb_init - allocate and initialize io callback
*
- * @cl - mei client
+ * @cl: mei client
* @fp: pointer to file structure
*
- * returns mei_cl_cb pointer or NULL;
+ * Return: mei_cl_cb pointer or NULL;
*/
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
{
@@ -179,7 +222,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
* @cb: io callback structure
* @length: size of the buffer
*
- * returns 0 on success
+ * Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
@@ -203,7 +246,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
* @cb: io callback structure
* @length: size of the buffer
*
- * returns 0 on success
+ * Return: 0 on success
* -EINVAL if cb is NULL
* -ENOMEM if allocation failed
*/
@@ -228,6 +271,8 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
* mei_cl_flush_queues - flushes queue lists belonging to cl.
*
* @cl: host client
+ *
+ * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
*/
int mei_cl_flush_queues(struct mei_cl *cl)
{
@@ -273,7 +318,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
* mei_cl_allocate - allocates cl structure and sets it up.
*
* @dev: mei device
- * returns The allocated file or NULL on failure
+ * Return: The allocated file or NULL on failure
*/
struct mei_cl *mei_cl_allocate(struct mei_device *dev)
{
@@ -293,7 +338,7 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
*
* @cl: host client
*
- * returns cb on success, NULL on error
+ * Return: cb on success, NULL on error
*/
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
@@ -311,7 +356,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
* @cl - host client
* @id - fixed host id or -1 for generic one
*
- * returns 0 on success
+ * Return: 0 on success
* -EINVAL on incorrect values
* -ENONET if client not found
*/
@@ -331,13 +376,13 @@ int mei_cl_link(struct mei_cl *cl, int id)
MEI_CLIENTS_MAX);
if (id >= MEI_CLIENTS_MAX) {
- dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
+ dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
return -EMFILE;
}
open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
- dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
+ dev_err(dev->dev, "open_handle_count exceeded %d",
MEI_MAX_OPEN_HANDLE_COUNT);
return -EMFILE;
}
@@ -359,6 +404,8 @@ int mei_cl_link(struct mei_cl *cl, int id)
* mei_cl_unlink - remove me_cl from the list
*
* @cl: host client
+ *
+ * Return: always 0
*/
int mei_cl_unlink(struct mei_cl *cl)
{
@@ -395,19 +442,19 @@ void mei_host_client_init(struct work_struct *work)
{
struct mei_device *dev = container_of(work,
struct mei_device, init_work);
- struct mei_client_properties *client_props;
- int i;
+ struct mei_me_client *me_cl;
+ struct mei_client_properties *props;
mutex_lock(&dev->device_lock);
- for (i = 0; i < dev->me_clients_num; i++) {
- client_props = &dev->me_clients[i].props;
+ list_for_each_entry(me_cl, &dev->me_clients, list) {
+ props = &me_cl->props;
- if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
+ if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
mei_amthif_host_init(dev);
- else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
+ else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
- else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+ else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
mei_nfc_host_init(dev);
}
@@ -417,27 +464,27 @@ void mei_host_client_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
- pm_runtime_mark_last_busy(&dev->pdev->dev);
- dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
- pm_runtime_autosuspend(&dev->pdev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ dev_dbg(dev->dev, "rpm: autosuspend\n");
+ pm_runtime_autosuspend(dev->dev);
}
/**
- * mei_hbuf_acquire: try to acquire host buffer
+ * mei_hbuf_acquire - try to acquire host buffer
*
* @dev: the device structure
- * returns true if host buffer was acquired
+ * Return: true if host buffer was acquired
*/
bool mei_hbuf_acquire(struct mei_device *dev)
{
if (mei_pg_state(dev) == MEI_PG_ON ||
dev->pg_event == MEI_PG_EVENT_WAIT) {
- dev_dbg(&dev->pdev->dev, "device is in pg\n");
+ dev_dbg(dev->dev, "device is in pg\n");
return false;
}
if (!dev->hbuf_is_ready) {
- dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+ dev_dbg(dev->dev, "hbuf is not ready\n");
return false;
}
@@ -453,7 +500,7 @@ bool mei_hbuf_acquire(struct mei_device *dev)
*
* Locking: called under "dev->device_lock" lock
*
- * returns 0 on success, <0 on failure.
+ * Return: 0 on success, <0 on failure.
*/
int mei_cl_disconnect(struct mei_cl *cl)
{
@@ -471,9 +518,9 @@ int mei_cl_disconnect(struct mei_cl *cl)
if (cl->state != MEI_FILE_DISCONNECTING)
return 0;
- rets = pm_runtime_get(&dev->pdev->dev);
+ rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
- pm_runtime_put_noidle(&dev->pdev->dev);
+ pm_runtime_put_noidle(dev->dev);
cl_err(dev, cl, "rpm: get failed %d\n", rets);
return rets;
}
@@ -484,7 +531,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
goto free;
}
- cb->fop_type = MEI_FOP_CLOSE;
+ cb->fop_type = MEI_FOP_DISCONNECT;
+
if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
@@ -501,7 +549,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
}
mutex_unlock(&dev->device_lock);
- wait_event_timeout(dev->wait_recvd_msg,
+ wait_event_timeout(cl->wait,
MEI_FILE_DISCONNECTED == cl->state,
mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
@@ -519,8 +567,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
cl_dbg(dev, cl, "rpm: autosuspend\n");
- pm_runtime_mark_last_busy(&dev->pdev->dev);
- pm_runtime_put_autosuspend(&dev->pdev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
mei_io_cb_free(cb);
return rets;
@@ -533,7 +581,7 @@ 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)
{
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 96d5de0389f9..d9d0c1525259 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -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_ */
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index ced5b777c70f..ce1566715f80 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -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;
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 804106209d76..49a2653d91a5 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -15,16 +15,34 @@
*/
#include <linux/export.h>
-#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
-#include <linux/mei.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <linux/mei.h>
#include "mei_dev.h"
#include "hbm.h"
#include "client.h"
+static const char *mei_hbm_status_str(enum mei_hbm_status status)
+{
+#define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status
+ switch (status) {
+ MEI_HBM_STATUS(SUCCESS);
+ MEI_HBM_STATUS(CLIENT_NOT_FOUND);
+ MEI_HBM_STATUS(ALREADY_EXISTS);
+ MEI_HBM_STATUS(REJECTED);
+ MEI_HBM_STATUS(INVALID_PARAMETER);
+ MEI_HBM_STATUS(NOT_ALLOWED);
+ MEI_HBM_STATUS(ALREADY_STARTED);
+ MEI_HBM_STATUS(NOT_STARTED);
+ default: return "unknown";
+ }
+#undef MEI_HBM_STATUS
+};
+
static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
{
#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
@@ -39,13 +57,29 @@ static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
#undef MEI_CL_CCS
}
+const char *mei_hbm_state_str(enum mei_hbm_state state)
+{
+#define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state
+ switch (state) {
+ MEI_HBM_STATE(IDLE);
+ MEI_HBM_STATE(STARTING);
+ MEI_HBM_STATE(STARTED);
+ MEI_HBM_STATE(ENUM_CLIENTS);
+ MEI_HBM_STATE(CLIENT_PROPERTIES);
+ MEI_HBM_STATE(STOPPED);
+ default:
+ return "unknown";
+ }
+#undef MEI_HBM_STATE
+}
+
/**
* mei_cl_conn_status_to_errno - convert client connect response
* status to error code
*
* @status: client connect response status
*
- * returns corresponding error code
+ * Return: corresponding error code
*/
static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
{
@@ -71,60 +105,54 @@ void mei_hbm_idle(struct mei_device *dev)
}
/**
- * mei_hbm_reset - reset hbm counters and book keeping data structurs
+ * mei_me_cl_remove_all - remove all me clients
*
* @dev: the device structure
*/
-void mei_hbm_reset(struct mei_device *dev)
+static void mei_me_cl_remove_all(struct mei_device *dev)
{
- dev->me_clients_num = 0;
- dev->me_client_presentation_num = 0;
- dev->me_client_index = 0;
-
- kfree(dev->me_clients);
- dev->me_clients = NULL;
+ struct mei_me_client *me_cl, *next;
- mei_hbm_idle(dev);
+ list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
+ list_del(&me_cl->list);
+ kfree(me_cl);
+ }
}
/**
- * mei_hbm_me_cl_allocate - allocates storage for me clients
+ * mei_hbm_reset - reset hbm counters and book keeping data structurs
*
* @dev: the device structure
- *
- * returns 0 on success -ENOMEM on allocation failure
*/
-static int mei_hbm_me_cl_allocate(struct mei_device *dev)
+void mei_hbm_reset(struct mei_device *dev)
{
- struct mei_me_client *clients;
- int b;
+ dev->me_client_index = 0;
- mei_hbm_reset(dev);
+ mei_me_cl_remove_all(dev);
- /* count how many ME clients we have */
- for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
- dev->me_clients_num++;
+ mei_hbm_idle(dev);
+}
- if (dev->me_clients_num == 0)
- return 0;
+/**
+ * mei_hbm_hdr - construct hbm header
+ *
+ * @hdr: hbm header
+ * @length: payload length
+ */
- dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n",
- dev->me_clients_num * sizeof(struct mei_me_client));
- /* allocate storage for ME clients representation */
- clients = kcalloc(dev->me_clients_num,
- sizeof(struct mei_me_client), GFP_KERNEL);
- if (!clients) {
- dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
- return -ENOMEM;
- }
- dev->me_clients = clients;
- return 0;
+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;
}
/**
* mei_hbm_cl_hdr - construct client hbm header
*
- * @cl: - client
+ * @cl: client
* @hbm_cmd: host bus message command
* @buf: buffer for cl header
* @len: buffer length
@@ -142,38 +170,87 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
}
/**
- * mei_hbm_cl_addr_equal - tells if they have the same address
+ * mei_hbm_cl_write - write simple hbm client message
*
- * @cl: - client
- * @buf: buffer with cl header
+ * @dev: the device structure
+ * @cl: client
+ * @hbm_cmd: host bus message command
+ * @len: buffer length
*
- * returns true if addresses are the same
+ * Return: 0 on success, <0 on failure.
*/
static inline
-bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
+int mei_hbm_cl_write(struct mei_device *dev,
+ struct mei_cl *cl, u8 hbm_cmd, size_t len)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, hbm_cmd, dev->wr_msg.data, len);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
+ * mei_hbm_cl_addr_equal - check if the client's and
+ * the message address match
+ *
+ * @cl: client
+ * @cmd: hbm client message
+ *
+ * Return: true if addresses are the same
+ */
+static inline
+bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
{
- struct mei_hbm_cl_cmd *cmd = buf;
return cl->host_client_id == cmd->host_addr &&
cl->me_client_id == cmd->me_addr;
}
+/**
+ * mei_hbm_cl_find_by_cmd - find recipient client
+ *
+ * @dev: the device structure
+ * @buf: a buffer with hbm cl command
+ *
+ * Return: the recipient client or NULL if not found
+ */
+static inline
+struct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf)
+{
+ struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf;
+ struct mei_cl *cl;
+
+ list_for_each_entry(cl, &dev->file_list, link)
+ if (mei_hbm_cl_addr_equal(cl, cmd))
+ return cl;
+ return NULL;
+}
+
+/**
+ * mei_hbm_start_wait - wait for start response message.
+ *
+ * @dev: the device structure
+ *
+ * Return: 0 on success and < 0 on failure
+ */
int mei_hbm_start_wait(struct mei_device *dev)
{
int ret;
- if (dev->hbm_state > MEI_HBM_START)
+
+ if (dev->hbm_state > MEI_HBM_STARTING)
return 0;
mutex_unlock(&dev->device_lock);
- ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
- dev->hbm_state == MEI_HBM_IDLE ||
- dev->hbm_state >= MEI_HBM_STARTED,
+ ret = wait_event_timeout(dev->wait_hbm_start,
+ dev->hbm_state != MEI_HBM_STARTING,
mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
mutex_lock(&dev->device_lock);
- if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
+ if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {
dev->hbm_state = MEI_HBM_IDLE;
- dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
+ dev_err(dev->dev, "waiting for mei start failed\n");
return -ETIME;
}
return 0;
@@ -184,7 +261,7 @@ int mei_hbm_start_wait(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns 0 on success and < 0 on failure
+ * Return: 0 on success and < 0 on failure
*/
int mei_hbm_start_req(struct mei_device *dev)
{
@@ -193,6 +270,8 @@ int mei_hbm_start_req(struct mei_device *dev)
const size_t len = sizeof(struct hbm_host_version_request);
int ret;
+ mei_hbm_reset(dev);
+
mei_hbm_hdr(mei_hdr, len);
/* host start message */
@@ -205,12 +284,12 @@ int mei_hbm_start_req(struct mei_device *dev)
dev->hbm_state = MEI_HBM_IDLE;
ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
if (ret) {
- dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
+ dev_err(dev->dev, "version message write failed: ret = %d\n",
ret);
return ret;
}
- dev->hbm_state = MEI_HBM_START;
+ dev->hbm_state = MEI_HBM_STARTING;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return 0;
}
@@ -220,7 +299,7 @@ int mei_hbm_start_req(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns 0 on success and < 0 on failure
+ * Return: 0 on success and < 0 on failure
*/
static int mei_hbm_enum_clients_req(struct mei_device *dev)
{
@@ -238,7 +317,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
if (ret) {
- dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
+ dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
ret);
return ret;
}
@@ -247,12 +326,38 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
return 0;
}
+/*
+ * mei_hbm_me_cl_add - add new me client to the list
+ *
+ * @dev: the device structure
+ * @res: hbm property response
+ *
+ * Return: 0 on success and -ENOMEM on allocation failure
+ */
+
+static int mei_hbm_me_cl_add(struct mei_device *dev,
+ struct hbm_props_response *res)
+{
+ struct mei_me_client *me_cl;
+
+ me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
+ if (!me_cl)
+ return -ENOMEM;
+
+ me_cl->props = res->client_properties;
+ me_cl->client_id = res->me_addr;
+ me_cl->mei_flow_ctrl_creds = 0;
+
+ list_add(&me_cl->list, &dev->me_clients);
+ return 0;
+}
+
/**
* mei_hbm_prop_req - request property for a single client
*
* @dev: the device structure
*
- * returns 0 on success and < 0 on failure
+ * Return: 0 on success and < 0 on failure
*/
static int mei_hbm_prop_req(struct mei_device *dev)
@@ -262,11 +367,8 @@ static int mei_hbm_prop_req(struct mei_device *dev)
struct hbm_props_request *prop_req;
const size_t len = sizeof(struct hbm_props_request);
unsigned long next_client_index;
- unsigned long client_num;
int ret;
- client_num = dev->me_client_presentation_num;
-
next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
dev->me_client_index);
@@ -278,21 +380,17 @@ static int mei_hbm_prop_req(struct mei_device *dev)
return 0;
}
- dev->me_clients[client_num].client_id = next_client_index;
- dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
-
mei_hbm_hdr(mei_hdr, len);
prop_req = (struct hbm_props_request *)dev->wr_msg.data;
memset(prop_req, 0, sizeof(struct hbm_props_request));
-
prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
- prop_req->address = next_client_index;
+ prop_req->me_addr = next_client_index;
ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
if (ret) {
- dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
+ dev_err(dev->dev, "properties request write failed: ret = %d\n",
ret);
return ret;
}
@@ -309,7 +407,8 @@ static int mei_hbm_prop_req(struct mei_device *dev)
* @dev: the device structure
* @pg_cmd: the pg command code
*
- * This function returns -EIO on write failure
+ * Return: -EIO on write failure
+ * -EOPNOTSUPP if the operation is not supported by the protocol
*/
int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
{
@@ -318,6 +417,9 @@ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
const size_t len = sizeof(struct hbm_power_gate);
int ret;
+ if (!dev->hbm_f_pg_supported)
+ return -EOPNOTSUPP;
+
mei_hbm_hdr(mei_hdr, len);
req = (struct hbm_power_gate *)dev->wr_msg.data;
@@ -326,7 +428,7 @@ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
if (ret)
- dev_err(&dev->pdev->dev, "power gate command write failed.\n");
+ dev_err(dev->dev, "power gate command write failed.\n");
return ret;
}
EXPORT_SYMBOL_GPL(mei_hbm_pg);
@@ -334,10 +436,9 @@ EXPORT_SYMBOL_GPL(mei_hbm_pg);
/**
* mei_hbm_stop_req - send stop request message
*
- * @dev - mei device
- * @cl: client info
+ * @dev: mei device
*
- * This function returns -EIO on write failure
+ * Return: -EIO on write failure
*/
static int mei_hbm_stop_req(struct mei_device *dev)
{
@@ -361,19 +462,14 @@ static int mei_hbm_stop_req(struct mei_device *dev)
* @dev: the device structure
* @cl: client info
*
- * This function returns -EIO on write failure
+ * Return: -EIO on write failure
*/
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
{
- struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
const size_t len = sizeof(struct hbm_flow_control);
- mei_hbm_hdr(mei_hdr, len);
- mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
-
cl_dbg(dev, cl, "sending flow control\n");
-
- return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+ return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, len);
}
/**
@@ -382,31 +478,26 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
* @dev: the device structure
* @flow: flow control.
*
- * return 0 on success, < 0 otherwise
+ * Return: 0 on success, < 0 otherwise
*/
static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
struct hbm_flow_control *flow)
{
struct mei_me_client *me_cl;
- int id;
- id = mei_me_cl_by_id(dev, flow->me_addr);
- if (id < 0) {
- dev_err(&dev->pdev->dev, "no such me client %d\n",
+ me_cl = mei_me_cl_by_id(dev, flow->me_addr);
+ if (!me_cl) {
+ dev_err(dev->dev, "no such me client %d\n",
flow->me_addr);
- return id;
+ return -ENOENT;
}
- me_cl = &dev->me_clients[id];
- if (me_cl->props.single_recv_buf) {
- me_cl->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
- flow->me_addr);
- dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
- me_cl->mei_flow_ctrl_creds);
- } else {
- BUG(); /* error in flow control */
- }
+ if (WARN_ON(me_cl->props.single_recv_buf == 0))
+ return -EINVAL;
+
+ me_cl->mei_flow_ctrl_creds++;
+ dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
+ flow->me_addr, me_cl->mei_flow_ctrl_creds);
return 0;
}
@@ -418,7 +509,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
* @flow_control: flow control response bus message
*/
static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
- struct hbm_flow_control *flow_control)
+ struct hbm_flow_control *flow_control)
{
struct mei_cl *cl;
@@ -428,16 +519,11 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
return;
}
- /* normal connection */
- list_for_each_entry(cl, &dev->file_list, link) {
- if (mei_hbm_cl_addr_equal(cl, flow_control)) {
- cl->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
- flow_control->host_addr, flow_control->me_addr);
- dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
- cl->mei_flow_ctrl_creds);
- break;
- }
+ cl = mei_hbm_cl_find_by_cmd(dev, flow_control);
+ if (cl) {
+ cl->mei_flow_ctrl_creds++;
+ cl_dbg(dev, cl, "flow control creds = %d.\n",
+ cl->mei_flow_ctrl_creds);
}
}
@@ -448,17 +534,13 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
* @dev: the device structure
* @cl: a client to disconnect from
*
- * This function returns -EIO on write failure
+ * Return: -EIO on write failure
*/
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
{
- struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
const size_t len = sizeof(struct hbm_client_connect_request);
- mei_hbm_hdr(mei_hdr, len);
- mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
-
- return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+ return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, len);
}
/**
@@ -467,53 +549,34 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
* @dev: the device structure
* @cl: a client to disconnect from
*
- * This function returns -EIO on write failure
+ * Return: -EIO on write failure
*/
int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
{
- struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
const size_t len = sizeof(struct hbm_client_connect_response);
- mei_hbm_hdr(mei_hdr, len);
- mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, dev->wr_msg.data, len);
-
- return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+ return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, len);
}
/**
- * mei_hbm_cl_disconnect_res - disconnect response from ME
+ * mei_hbm_cl_disconnect_res - update the client state according
+ * disconnect response
*
- * @dev: the device structure
- * @rs: disconnect response bus message
+ * @cl: mei host client
+ * @cmd: disconnect client response host bus message
*/
-static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
- struct hbm_client_connect_response *rs)
+static void mei_hbm_cl_disconnect_res(struct mei_cl *cl,
+ struct mei_hbm_cl_cmd *cmd)
{
- struct mei_cl *cl;
- struct mei_cl_cb *cb, *next;
+ struct hbm_client_connect_response *rs =
+ (struct hbm_client_connect_response *)cmd;
- dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
+ dev_dbg(cl->dev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
rs->me_addr, rs->host_addr, rs->status);
- list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
- cl = cb->cl;
-
- /* this should not happen */
- if (WARN_ON(!cl)) {
- list_del(&cb->list);
- return;
- }
-
- if (mei_hbm_cl_addr_equal(cl, rs)) {
- list_del(&cb->list);
- if (rs->status == MEI_CL_DISCONN_SUCCESS)
- cl->state = MEI_FILE_DISCONNECTED;
-
- cl->status = 0;
- cl->timer_count = 0;
- break;
- }
- }
+ if (rs->status == MEI_CL_DISCONN_SUCCESS)
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = 0;
}
/**
@@ -522,38 +585,55 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
* @dev: the device structure
* @cl: a client to connect to
*
- * returns -EIO on write failure
+ * Return: -EIO on write failure
*/
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
{
- struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
const size_t len = sizeof(struct hbm_client_connect_request);
- mei_hbm_hdr(mei_hdr, len);
- mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
+ return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, len);
+}
- return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+/**
+ * mei_hbm_cl_connect_res - update the client state according
+ * connection response
+ *
+ * @cl: mei host client
+ * @cmd: connect client response host bus message
+ */
+static void mei_hbm_cl_connect_res(struct mei_cl *cl,
+ struct mei_hbm_cl_cmd *cmd)
+{
+ struct hbm_client_connect_response *rs =
+ (struct hbm_client_connect_response *)cmd;
+
+ dev_dbg(cl->dev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
+ rs->me_addr, rs->host_addr,
+ mei_cl_conn_status_str(rs->status));
+
+ if (rs->status == MEI_CL_CONN_SUCCESS)
+ cl->state = MEI_FILE_CONNECTED;
+ else
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = mei_cl_conn_status_to_errno(rs->status);
}
/**
- * mei_hbm_cl_connect_res - connect response from the ME
+ * mei_hbm_cl_res - process hbm response received on behalf
+ * an client
*
* @dev: the device structure
- * @rs: connect response bus message
+ * @rs: hbm client message
+ * @fop_type: file operation type
*/
-static void mei_hbm_cl_connect_res(struct mei_device *dev,
- struct hbm_client_connect_response *rs)
+static void mei_hbm_cl_res(struct mei_device *dev,
+ struct mei_hbm_cl_cmd *rs,
+ enum mei_cb_file_ops fop_type)
{
-
struct mei_cl *cl;
struct mei_cl_cb *cb, *next;
- dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
- rs->me_addr, rs->host_addr,
- mei_cl_conn_status_str(rs->status));
-
cl = NULL;
-
list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
cl = cb->cl;
@@ -563,7 +643,7 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
continue;
}
- if (cb->fop_type != MEI_FOP_CONNECT)
+ if (cb->fop_type != fop_type)
continue;
if (mei_hbm_cl_addr_equal(cl, rs)) {
@@ -575,12 +655,19 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
if (!cl)
return;
+ switch (fop_type) {
+ case MEI_FOP_CONNECT:
+ mei_hbm_cl_connect_res(cl, rs);
+ break;
+ case MEI_FOP_DISCONNECT:
+ mei_hbm_cl_disconnect_res(cl, rs);
+ break;
+ default:
+ return;
+ }
+
cl->timer_count = 0;
- if (rs->status == MEI_CL_CONN_SUCCESS)
- cl->state = MEI_FILE_CONNECTED;
- else
- cl->state = MEI_FILE_DISCONNECTED;
- cl->status = mei_cl_conn_status_to_errno(rs->status);
+ wake_up(&cl->wait);
}
@@ -591,7 +678,7 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
* @dev: the device structure.
* @disconnect_req: disconnect request bus message from the me
*
- * returns -ENOMEM on allocation failure
+ * Return: -ENOMEM on allocation failure
*/
static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
struct hbm_client_connect_request *disconnect_req)
@@ -599,34 +686,46 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
struct mei_cl *cl;
struct mei_cl_cb *cb;
- list_for_each_entry(cl, &dev->file_list, link) {
- if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
- dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
- disconnect_req->host_addr,
- disconnect_req->me_addr);
- cl->state = MEI_FILE_DISCONNECTED;
- cl->timer_count = 0;
-
- cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
- cb->fop_type = MEI_FOP_DISCONNECT_RSP;
- cl_dbg(dev, cl, "add disconnect response as first\n");
- list_add(&cb->list, &dev->ctrl_wr_list.list);
+ cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
+ if (cl) {
+ cl_dbg(dev, cl, "disconnect request received\n");
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->timer_count = 0;
- break;
- }
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+ cb->fop_type = MEI_FOP_DISCONNECT_RSP;
+ cl_dbg(dev, cl, "add disconnect response as first\n");
+ list_add(&cb->list, &dev->ctrl_wr_list.list);
}
return 0;
}
+/**
+ * mei_hbm_config_features - check what hbm features and commands
+ * are supported by the fw
+ *
+ * @dev: the device structure
+ */
+static void mei_hbm_config_features(struct mei_device *dev)
+{
+ /* Power Gating Isolation Support */
+ dev->hbm_f_pg_supported = 0;
+ if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)
+ dev->hbm_f_pg_supported = 1;
+
+ if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
+ dev->version.minor_version >= HBM_MINOR_VERSION_PGI)
+ dev->hbm_f_pg_supported = 1;
+}
/**
* mei_hbm_version_is_supported - checks whether the driver can
* support the hbm version of the device
*
* @dev: the device structure
- * returns true if driver can support hbm version of the device
+ * Return: true if driver can support hbm version of the device
*/
bool mei_hbm_version_is_supported(struct mei_device *dev)
{
@@ -640,44 +739,44 @@ bool mei_hbm_version_is_supported(struct mei_device *dev)
* handle the read bus message cmd processing.
*
* @dev: the device structure
- * @mei_hdr: header of bus message
+ * @hdr: header of bus message
*
- * returns 0 on success and < 0 on failure
+ * Return: 0 on success and < 0 on failure
*/
int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
{
struct mei_bus_message *mei_msg;
- struct mei_me_client *me_client;
struct hbm_host_version_response *version_res;
- struct hbm_client_connect_response *connect_res;
- struct hbm_client_connect_response *disconnect_res;
- struct hbm_client_connect_request *disconnect_req;
- struct hbm_flow_control *flow_control;
struct hbm_props_response *props_res;
struct hbm_host_enum_response *enum_res;
+ struct mei_hbm_cl_cmd *cl_cmd;
+ struct hbm_client_connect_request *disconnect_req;
+ struct hbm_flow_control *flow_control;
+
/* read the message to our buffer */
BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
+ cl_cmd = (struct mei_hbm_cl_cmd *)mei_msg;
/* ignore spurious message and prevent reset nesting
* hbm is put to idle during system reset
*/
if (dev->hbm_state == MEI_HBM_IDLE) {
- dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n");
+ dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n");
return 0;
}
switch (mei_msg->hbm_cmd) {
case HOST_START_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
+ dev_dbg(dev->dev, "hbm: start: response message received.\n");
dev->init_clients_timer = 0;
version_res = (struct hbm_host_version_response *)mei_msg;
- dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
+ dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
version_res->me_max_version.major_version,
version_res->me_max_version.minor_version);
@@ -693,19 +792,21 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
}
if (!mei_hbm_version_is_supported(dev)) {
- dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
+ dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");
dev->hbm_state = MEI_HBM_STOPPED;
if (mei_hbm_stop_req(dev)) {
- dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
+ dev_err(dev->dev, "hbm: start: failed to send stop request\n");
return -EIO;
}
break;
}
+ mei_hbm_config_features(dev);
+
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
- dev->hbm_state != MEI_HBM_START) {
- dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
+ dev->hbm_state != MEI_HBM_STARTING) {
+ dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state);
return -EPROTO;
}
@@ -713,45 +814,39 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev->hbm_state = MEI_HBM_STARTED;
if (mei_hbm_enum_clients_req(dev)) {
- dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
+ dev_err(dev->dev, "hbm: start: failed to send enumeration request\n");
return -EIO;
}
- wake_up_interruptible(&dev->wait_recvd_msg);
+ wake_up(&dev->wait_hbm_start);
break;
case CLIENT_CONNECT_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
-
- connect_res = (struct hbm_client_connect_response *) mei_msg;
- mei_hbm_cl_connect_res(dev, connect_res);
- wake_up(&dev->wait_recvd_msg);
+ dev_dbg(dev->dev, "hbm: client connect response: message received.\n");
+ mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT);
break;
case CLIENT_DISCONNECT_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
-
- disconnect_res = (struct hbm_client_connect_response *) mei_msg;
- mei_hbm_cl_disconnect_res(dev, disconnect_res);
- wake_up(&dev->wait_recvd_msg);
+ dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n");
+ mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT);
break;
case MEI_FLOW_CONTROL_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
+ dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
flow_control = (struct hbm_flow_control *) mei_msg;
mei_hbm_cl_flow_control_res(dev, flow_control);
break;
case MEI_PG_ISOLATION_ENTRY_RES_CMD:
- dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n");
+ dev_dbg(dev->dev, "power gate isolation entry response received\n");
dev->pg_event = MEI_PG_EVENT_RECEIVED;
if (waitqueue_active(&dev->wait_pg))
wake_up(&dev->wait_pg);
break;
case MEI_PG_ISOLATION_EXIT_REQ_CMD:
- dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n");
+ dev_dbg(dev->dev, "power gate isolation exit request received\n");
dev->pg_event = MEI_PG_EVENT_RECEIVED;
if (waitqueue_active(&dev->wait_pg))
wake_up(&dev->wait_pg);
@@ -761,44 +856,33 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
* this is HW initiated exit from PG.
* Start runtime pm resume sequence to exit from PG.
*/
- pm_request_resume(&dev->pdev->dev);
+ pm_request_resume(dev->dev);
break;
case HOST_CLIENT_PROPERTIES_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
+ dev_dbg(dev->dev, "hbm: properties response: message received.\n");
dev->init_clients_timer = 0;
- if (dev->me_clients == NULL) {
- dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n");
+ if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
+ dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
+ dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
+ dev->dev_state, dev->hbm_state);
return -EPROTO;
}
props_res = (struct hbm_props_response *)mei_msg;
- me_client = &dev->me_clients[dev->me_client_presentation_num];
if (props_res->status) {
- dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
- props_res->status);
+ dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",
+ props_res->status,
+ mei_hbm_status_str(props_res->status));
return -EPROTO;
}
- if (me_client->client_id != props_res->address) {
- dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n",
- me_client->client_id, props_res->address);
- return -EPROTO;
- }
+ mei_hbm_me_cl_add(dev, props_res);
- if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
- dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
- dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
- dev->dev_state, dev->hbm_state);
- return -EPROTO;
- }
-
- me_client->props = props_res->client_properties;
dev->me_client_index++;
- dev->me_client_presentation_num++;
/* request property for the next client */
if (mei_hbm_prop_req(dev))
@@ -807,7 +891,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
break;
case HOST_ENUM_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
+ dev_dbg(dev->dev, "hbm: enumeration response: message received\n");
dev->init_clients_timer = 0;
@@ -815,20 +899,15 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
BUILD_BUG_ON(sizeof(dev->me_clients_map)
< sizeof(enum_res->valid_addresses));
memcpy(dev->me_clients_map, enum_res->valid_addresses,
- sizeof(enum_res->valid_addresses));
+ sizeof(enum_res->valid_addresses));
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
- dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
+ dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state);
return -EPROTO;
}
- if (mei_hbm_me_cl_allocate(dev)) {
- dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n");
- return -ENOMEM;
- }
-
dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
/* first property request */
@@ -838,34 +917,34 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
break;
case HOST_STOP_RES_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
+ dev_dbg(dev->dev, "hbm: stop response: message received\n");
dev->init_clients_timer = 0;
if (dev->hbm_state != MEI_HBM_STOPPED) {
- dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
+ dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
dev->dev_state, dev->hbm_state);
return -EPROTO;
}
dev->dev_state = MEI_DEV_POWER_DOWN;
- dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
+ dev_info(dev->dev, "hbm: stop response: resetting.\n");
/* force the reset */
return -EPROTO;
break;
case CLIENT_DISCONNECT_REQ_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
+ dev_dbg(dev->dev, "hbm: disconnect request: message received\n");
disconnect_req = (struct hbm_client_connect_request *)mei_msg;
mei_hbm_fw_disconnect_req(dev, disconnect_req);
break;
case ME_STOP_REQ_CMD:
- dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
+ dev_dbg(dev->dev, "hbm: stop request: message received\n");
dev->hbm_state = MEI_HBM_STOPPED;
if (mei_hbm_stop_req(dev)) {
- dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
+ dev_err(dev->dev, "hbm: stop request: failed to send stop request\n");
return -EIO;
}
break;
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index 683eb2835cec..b7cd3d857fd5 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -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);
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index a9a0d08f758e..4f2fd6fc1e23 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -28,10 +28,10 @@
/**
* mei_me_reg_read - Reads 32bit data from the mei device
*
- * @dev: the device structure
+ * @hw: the me hardware structure
* @offset: offset from which to read the data
*
- * returns register value (u32)
+ * Return: register value (u32)
*/
static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
@@ -43,7 +43,7 @@ static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
/**
* mei_me_reg_write - Writes 32bit data to the mei device
*
- * @dev: the device structure
+ * @hw: the me hardware structure
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
@@ -59,7 +59,7 @@ static inline void mei_me_reg_write(const struct mei_me_hw *hw,
*
* @dev: the device structure
*
- * returns ME_CB_RW register value (u32)
+ * Return: ME_CB_RW register value (u32)
*/
static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
@@ -68,9 +68,9 @@ static u32 mei_me_mecbrw_read(const struct mei_device *dev)
/**
* mei_me_mecsr_read - Reads 32bit data from the ME CSR
*
- * @dev: the device structure
+ * @hw: the me hardware structure
*
- * returns ME_CSR_HA register value (u32)
+ * Return: ME_CSR_HA register value (u32)
*/
static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
{
@@ -80,9 +80,9 @@ static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
/**
* mei_hcsr_read - Reads 32bit data from the host CSR
*
- * @dev: the device structure
+ * @hw: the me hardware structure
*
- * returns H_CSR register value (u32)
+ * Return: H_CSR register value (u32)
*/
static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
@@ -93,7 +93,8 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
* mei_hcsr_set - writes H_CSR register to the mei device,
* and ignores the H_IS bit for it is write-one-to-zero.
*
- * @dev: the device structure
+ * @hw: the me hardware structure
+ * @hcsr: new register value
*/
static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
@@ -101,6 +102,36 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
mei_me_reg_write(hw, H_CSR, hcsr);
}
+/**
+ * mei_me_fw_status - read fw status register from pci config space
+ *
+ * @dev: mei device
+ * @fw_status: fw status register values
+ *
+ * Return: 0 on success, error otherwise
+ */
+static int mei_me_fw_status(struct mei_device *dev,
+ struct mei_fw_status *fw_status)
+{
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ const struct mei_fw_status *fw_src = &hw->cfg->fw_status;
+ int ret;
+ int i;
+
+ if (!fw_status)
+ return -EINVAL;
+
+ fw_status->count = fw_src->count;
+ for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
+ ret = pci_read_config_dword(pdev,
+ fw_src->status[i], &fw_status->status[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
/**
* mei_me_hw_config - configure hw dependent settings
@@ -121,17 +152,19 @@ static void mei_me_hw_config(struct mei_device *dev)
* mei_me_pg_state - translate internal pg state
* to the mei power gating state
*
- * @hw - me hardware
- * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
+ * @dev: mei device
+ *
+ * Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+
return hw->pg_state;
}
/**
- * mei_clear_interrupts - clear and stop interrupts
+ * mei_me_intr_clear - clear and stop interrupts
*
* @dev: the device structure
*/
@@ -139,6 +172,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
+
if ((hcsr & H_IS) == H_IS)
mei_me_reg_write(hw, H_CSR, hcsr);
}
@@ -151,12 +185,13 @@ static void mei_me_intr_enable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
+
hcsr |= H_IE;
mei_hcsr_set(hw, hcsr);
}
/**
- * mei_disable_interrupts - disables mei device interrupts
+ * mei_me_intr_disable - disables mei device interrupts
*
* @dev: the device structure
*/
@@ -164,6 +199,7 @@ static void mei_me_intr_disable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
+
hcsr &= ~H_IE;
mei_hcsr_set(hw, hcsr);
}
@@ -190,6 +226,8 @@ static void mei_me_hw_reset_release(struct mei_device *dev)
*
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
+ *
+ * Return: always 0
*/
static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
{
@@ -213,10 +251,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
hcsr = mei_hcsr_read(hw);
if ((hcsr & H_RST) == 0)
- dev_warn(&dev->pdev->dev, "H_RST is not set = 0x%08X", hcsr);
+ dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr);
if ((hcsr & H_RDY) == H_RDY)
- dev_warn(&dev->pdev->dev, "H_RDY is not cleared 0x%08X", hcsr);
+ dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr);
if (intr_enable == false)
mei_me_hw_reset_release(dev);
@@ -227,26 +265,27 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
/**
* mei_me_host_set_ready - enable device
*
- * @dev - mei device
- * returns bool
+ * @dev: mei device
*/
-
static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+
hw->host_hw_state = mei_hcsr_read(hw);
hw->host_hw_state |= H_IE | H_IG | H_RDY;
mei_hcsr_set(hw, hw->host_hw_state);
}
+
/**
* mei_me_host_is_ready - check whether the host has turned ready
*
- * @dev - mei device
- * returns bool
+ * @dev: mei device
+ * Return: bool
*/
static bool mei_me_host_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+
hw->host_hw_state = mei_hcsr_read(hw);
return (hw->host_hw_state & H_RDY) == H_RDY;
}
@@ -254,43 +293,53 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
/**
* mei_me_hw_is_ready - check whether the me(hw) has turned ready
*
- * @dev - mei device
- * returns bool
+ * @dev: mei device
+ * Return: bool
*/
static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+
hw->me_hw_state = mei_me_mecsr_read(hw);
return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
+/**
+ * mei_me_hw_ready_wait - wait until the me(hw) has turned ready
+ * or timeout is reached
+ *
+ * @dev: mei device
+ * Return: 0 on success, error otherwise
+ */
static int mei_me_hw_ready_wait(struct mei_device *dev)
{
- int err;
-
mutex_unlock(&dev->device_lock);
- err = wait_event_interruptible_timeout(dev->wait_hw_ready,
+ wait_event_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
- if (!err && !dev->recvd_hw_ready) {
- if (!err)
- err = -ETIME;
- dev_err(&dev->pdev->dev,
- "wait hw ready failed. status = %d\n", err);
- return err;
+ if (!dev->recvd_hw_ready) {
+ dev_err(dev->dev, "wait hw ready failed\n");
+ return -ETIME;
}
dev->recvd_hw_ready = false;
return 0;
}
+/**
+ * mei_me_hw_start - hw start routine
+ *
+ * @dev: mei device
+ * Return: 0 on success, error otherwise
+ */
static int mei_me_hw_start(struct mei_device *dev)
{
int ret = mei_me_hw_ready_wait(dev);
+
if (ret)
return ret;
- dev_dbg(&dev->pdev->dev, "hw is ready\n");
+ dev_dbg(dev->dev, "hw is ready\n");
mei_me_host_set_ready(dev);
return ret;
@@ -302,7 +351,7 @@ static int mei_me_hw_start(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns number of filled slots
+ * Return: number of filled slots
*/
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
{
@@ -322,7 +371,7 @@ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns true if empty, false - otherwise.
+ * Return: true if empty, false - otherwise.
*/
static bool mei_me_hbuf_is_empty(struct mei_device *dev)
{
@@ -334,7 +383,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns -EOVERFLOW if overflow, otherwise empty slots count
+ * Return: -EOVERFLOW if overflow, otherwise empty slots count
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
@@ -350,6 +399,13 @@ static int mei_me_hbuf_empty_slots(struct mei_device *dev)
return empty_slots;
}
+/**
+ * mei_me_hbuf_max_len - returns size of hw buffer.
+ *
+ * @dev: the device structure
+ *
+ * Return: size of hw buffer in bytes
+ */
static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
{
return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
@@ -363,7 +419,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
* @header: mei HECI header of message
* @buf: message payload will be written
*
- * This function returns -EIO if write has failed
+ * Return: -EIO if write has failed
*/
static int mei_me_write_message(struct mei_device *dev,
struct mei_msg_hdr *header,
@@ -378,10 +434,10 @@ static int mei_me_write_message(struct mei_device *dev,
int i;
int empty_slots;
- dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+ dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
empty_slots = mei_hbuf_empty_slots(dev);
- dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
+ dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots);
dw_cnt = mei_data2slots(length);
if (empty_slots < 0 || dw_cnt > empty_slots)
@@ -395,6 +451,7 @@ static int mei_me_write_message(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
+
memcpy(&reg, &buf[length - rem], rem);
mei_me_reg_write(hw, H_CB_WW, reg);
}
@@ -412,7 +469,7 @@ static int mei_me_write_message(struct mei_device *dev,
*
* @dev: the device structure
*
- * returns -EOVERFLOW if overflow, otherwise filled slots count
+ * Return: -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
@@ -430,7 +487,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
if (filled_slots > buffer_depth)
return -EOVERFLOW;
- dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
+ dev_dbg(dev->dev, "filled_slots =%08x\n", filled_slots);
return (int)filled_slots;
}
@@ -440,6 +497,8 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
* @dev: the device structure
* @buffer: message buffer will be written
* @buffer_length: message size will be read
+ *
+ * Return: always 0
*/
static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned long buffer_length)
@@ -453,6 +512,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
if (buffer_length > 0) {
u32 reg = mei_me_mecbrw_read(dev);
+
memcpy(reg_buf, &reg, buffer_length);
}
@@ -462,7 +522,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
}
/**
- * mei_me_pg_enter - write pg enter register to mei device.
+ * mei_me_pg_enter - write pg enter register
*
* @dev: the device structure
*/
@@ -470,12 +530,13 @@ static void mei_me_pg_enter(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 reg = mei_me_reg_read(hw, H_HPG_CSR);
+
reg |= H_HPG_CSR_PGI;
mei_me_reg_write(hw, H_HPG_CSR, reg);
}
/**
- * mei_me_pg_enter - write pg enter register to mei device.
+ * mei_me_pg_exit - write pg exit register
*
* @dev: the device structure
*/
@@ -495,7 +556,7 @@ static void mei_me_pg_exit(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns 0 on success an error code otherwise
+ * Return: 0 on success an error code otherwise
*/
int mei_me_pg_set_sync(struct mei_device *dev)
{
@@ -532,7 +593,7 @@ int mei_me_pg_set_sync(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns 0 on success an error code otherwise
+ * Return: 0 on success an error code otherwise
*/
int mei_me_pg_unset_sync(struct mei_device *dev)
{
@@ -569,7 +630,7 @@ reply:
*
* @dev: the device structure
*
- * returns: true is pg supported, false otherwise
+ * Return: true is pg supported, false otherwise
*/
static bool mei_me_pg_is_enabled(struct mei_device *dev)
{
@@ -579,17 +640,13 @@ static bool mei_me_pg_is_enabled(struct mei_device *dev)
if ((reg & ME_PGIC_HRA) == 0)
goto notsupported;
- if (dev->version.major_version < HBM_MAJOR_VERSION_PGI)
- goto notsupported;
-
- if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
- dev->version.minor_version < HBM_MINOR_VERSION_PGI)
+ if (!dev->hbm_f_pg_supported)
goto notsupported;
return true;
notsupported:
- dev_dbg(&dev->pdev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
+ dev_dbg(dev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n",
!!(reg & ME_PGIC_HRA),
dev->version.major_version,
dev->version.minor_version,
@@ -605,7 +662,7 @@ notsupported:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
- * returns irqreturn_t
+ * Return: irqreturn_t
*/
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
@@ -630,7 +687,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
- * returns irqreturn_t
+ * Return: irqreturn_t
*
*/
irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
@@ -640,19 +697,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
- dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
+ dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
/* Ack the interrupt here
* In case of MSI we don't go through the quick handler */
- if (pci_dev_msi_enabled(dev->pdev))
+ if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_clear_interrupts(dev);
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
- dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
+ dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
}
@@ -661,19 +718,19 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
mei_me_hw_reset_release(dev);
- dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+ dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
- wake_up_interruptible(&dev->wait_hw_ready);
+ wake_up(&dev->wait_hw_ready);
} else {
- dev_dbg(&dev->pdev->dev, "Spurious Interrupt\n");
+ dev_dbg(dev->dev, "Spurious Interrupt\n");
}
goto end;
}
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
- dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
+ dev_dbg(dev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
/* There is a race between ME write and interrupt delivery:
* Not all data is always available immediately after the
@@ -683,7 +740,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
break;
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
- dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
+ dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n",
rets);
schedule_work(&dev->reset_work);
goto end;
@@ -705,13 +762,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
- dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
+ dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
static const struct mei_hw_ops mei_me_hw_ops = {
+ .fw_status = mei_me_fw_status,
.pg_state = mei_me_pg_state,
.host_is_ready = mei_me_host_is_ready,
@@ -741,6 +799,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
static bool mei_me_fw_type_nm(struct pci_dev *pdev)
{
u32 reg;
+
pci_read_config_dword(pdev, PCI_CFG_HFS_2, &reg);
/* make sure that bit 9 (NM) is up and bit 10 (DM) is down */
return (reg & 0x600) == 0x200;
@@ -809,23 +868,22 @@ const struct mei_cfg mei_me_lpt_cfg = {
* @pdev: The pci device structure
* @cfg: per device generation config
*
- * returns The mei_device_device pointer on success, NULL on failure.
+ * Return: The mei_device_device pointer on success, NULL on failure.
*/
struct mei_device *mei_me_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg)
{
struct mei_device *dev;
+ struct mei_me_hw *hw;
dev = kzalloc(sizeof(struct mei_device) +
sizeof(struct mei_me_hw), GFP_KERNEL);
if (!dev)
return NULL;
+ hw = to_me_hw(dev);
- mei_device_init(dev, cfg);
-
- dev->ops = &mei_me_hw_ops;
-
- dev->pdev = pdev;
+ mei_device_init(dev, &pdev->dev, &mei_me_hw_ops);
+ hw->cfg = cfg;
return dev;
}
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 12b0f4bbe1f1..e6a59a62573a 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -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)
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index f1cd166094f2..c5e1902e493f 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -28,11 +28,12 @@
#include "hbm.h"
/**
- * mei_txe_reg_read - Reads 32bit data from the device
+ * mei_txe_reg_read - Reads 32bit data from the txe device
*
* @base_addr: registers base address
* @offset: register offset
*
+ * Return: register value
*/
static inline u32 mei_txe_reg_read(void __iomem *base_addr,
unsigned long offset)
@@ -41,7 +42,7 @@ static inline u32 mei_txe_reg_read(void __iomem *base_addr,
}
/**
- * mei_txe_reg_write - Writes 32bit data to the device
+ * mei_txe_reg_write - Writes 32bit data to the txe device
*
* @base_addr: registers base address
* @offset: register offset
@@ -56,10 +57,12 @@ static inline void mei_txe_reg_write(void __iomem *base_addr,
/**
* mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
*
- * @dev: the device structure
+ * @hw: the txe hardware structure
* @offset: register offset
*
* Doesn't check for aliveness while Reads 32bit data from the SeC BAR
+ *
+ * Return: register value
*/
static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
unsigned long offset)
@@ -70,10 +73,12 @@ static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
*
- * @dev: the device structure
+ * @hw: the txe hardware structure
* @offset: register offset
*
* Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
+ *
+ * Return: register value
*/
static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@@ -85,7 +90,7 @@ static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
* mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
* doesn't check for aliveness
*
- * @dev: the device structure
+ * @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@@ -100,7 +105,7 @@ static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
/**
* mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
*
- * @dev: the device structure
+ * @hw: the txe hardware structure
* @offset: register offset
* @value: value to write
*
@@ -115,9 +120,10 @@ static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
*
- * @hw: the device structure
+ * @hw: the txe hardware structure
* @offset: offset from which to read the data
*
+ * Return: the byte read.
*/
static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
@@ -128,7 +134,7 @@ static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
/**
* mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
*
- * @hw: the device structure
+ * @hw: the txe hardware structure
* @offset: offset from which to write the data
* @value: the byte to write
*/
@@ -147,7 +153,10 @@ static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
* Request for aliveness change and returns true if the change is
* really needed and false if aliveness is already
* in the requested state
- * Requires device lock to be held
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: true if request was send
*/
static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
{
@@ -155,7 +164,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
struct mei_txe_hw *hw = to_txe_hw(dev);
bool do_req = hw->aliveness != req;
- dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
+ dev_dbg(dev->dev, "Aliveness current=%d request=%d\n",
hw->aliveness, req);
if (do_req) {
dev->pg_event = MEI_PG_EVENT_WAIT;
@@ -172,26 +181,31 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
* from HICR_HOST_ALIVENESS_REQ register value
+ *
+ * Return: SICR_HOST_ALIVENESS_REQ_REQUESTED bit value
*/
static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
+
reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
}
/**
* mei_txe_aliveness_get - get aliveness response register value
+ *
* @dev: the device structure
*
- * Extract HICR_HOST_ALIVENESS_RESP_ACK bit
- * from HICR_HOST_ALIVENESS_RESP register value
+ * Return: HICR_HOST_ALIVENESS_RESP_ACK bit from HICR_HOST_ALIVENESS_RESP
+ * register
*/
static u32 mei_txe_aliveness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
+
reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
return reg & HICR_HOST_ALIVENESS_RESP_ACK;
}
@@ -203,7 +217,8 @@ static u32 mei_txe_aliveness_get(struct mei_device *dev)
* @expected: expected aliveness value
*
* Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
- * returns > 0 if the expected value was received, -ETIME otherwise
+ *
+ * Return: > 0 if the expected value was received, -ETIME otherwise
*/
static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
{
@@ -214,7 +229,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
hw->aliveness = mei_txe_aliveness_get(dev);
if (hw->aliveness == expected) {
dev->pg_event = MEI_PG_EVENT_IDLE;
- dev_dbg(&dev->pdev->dev,
+ dev_dbg(dev->dev,
"aliveness settled after %d msecs\n", t);
return t;
}
@@ -225,7 +240,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
} while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
dev->pg_event = MEI_PG_EVENT_IDLE;
- dev_err(&dev->pdev->dev, "aliveness timed out\n");
+ dev_err(dev->dev, "aliveness timed out\n");
return -ETIME;
}
@@ -236,7 +251,8 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
* @expected: expected aliveness value
*
* Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
- * returns returns 0 on success and < 0 otherwise
+ *
+ * Return: 0 on success and < 0 otherwise
*/
static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
{
@@ -259,10 +275,10 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
ret = hw->aliveness == expected ? 0 : -ETIME;
if (ret)
- dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
+ dev_warn(dev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
err, hw->aliveness, dev->pg_event);
else
- dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
+ dev_dbg(dev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
jiffies_to_msecs(timeout - err),
hw->aliveness, dev->pg_event);
@@ -274,8 +290,9 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
* mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
*
* @dev: the device structure
+ * @req: requested aliveness value
*
- * returns returns 0 on success and < 0 otherwise
+ * Return: 0 on success and < 0 otherwise
*/
int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
{
@@ -289,7 +306,7 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
*
* @dev: the device structure
*
- * returns: true is pg supported, false otherwise
+ * Return: true is pg supported, false otherwise
*/
static bool mei_txe_pg_is_enabled(struct mei_device *dev)
{
@@ -302,11 +319,12 @@ static bool mei_txe_pg_is_enabled(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
+ * Return: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
*/
static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON;
}
@@ -326,9 +344,10 @@ static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
}
/**
- * mei_txe_input_doorbell_set
- * - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
- * @dev: the device structure
+ * mei_txe_input_doorbell_set - sets bit 0 in
+ * SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
+ *
+ * @hw: the txe hardware structure
*/
static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
{
@@ -340,7 +359,7 @@ static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
/**
* mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
*
- * @dev: the device structure
+ * @hw: the txe hardware structure
*/
static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
{
@@ -353,11 +372,14 @@ static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
* mei_txe_is_input_ready - check if TXE is ready for receiving data
*
* @dev: the device structure
+ *
+ * Return: true if INPUT STATUS READY bit is set
*/
static bool mei_txe_is_input_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 status;
+
status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
return !!(SEC_IPC_INPUT_STATUS_RDY & status);
}
@@ -370,6 +392,7 @@ static bool mei_txe_is_input_ready(struct mei_device *dev)
static inline void mei_txe_intr_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
SEC_IPC_HOST_INT_STATUS_PENDING);
mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
@@ -384,6 +407,7 @@ static inline void mei_txe_intr_clear(struct mei_device *dev)
static void mei_txe_intr_disable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_br_reg_write(hw, HHIER_REG, 0);
mei_txe_br_reg_write(hw, HIER_REG, 0);
}
@@ -395,6 +419,7 @@ static void mei_txe_intr_disable(struct mei_device *dev)
static void mei_txe_intr_enable(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
}
@@ -407,6 +432,8 @@ static void mei_txe_intr_enable(struct mei_device *dev)
*
* Checks if there are pending interrupts
* only Aliveness, Readiness, Input ready, and Output doorbell are relevant
+ *
+ * Return: true if there are pending interrupts
*/
static bool mei_txe_pending_interrupts(struct mei_device *dev)
{
@@ -418,7 +445,7 @@ static bool mei_txe_pending_interrupts(struct mei_device *dev)
TXE_INTR_OUT_DB));
if (ret) {
- dev_dbg(&dev->pdev->dev,
+ dev_dbg(dev->dev,
"Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
!!(hw->intr_cause & TXE_INTR_IN_READY),
!!(hw->intr_cause & TXE_INTR_READINESS),
@@ -440,6 +467,7 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
unsigned long idx, u32 value)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
(idx * sizeof(u32)), value);
}
@@ -451,12 +479,13 @@ static void mei_txe_input_payload_write(struct mei_device *dev,
* @dev: the device structure
* @idx: index in the device buffer
*
- * returns register value at index
+ * Return: register value at index
*/
static u32 mei_txe_out_data_read(const struct mei_device *dev,
unsigned long idx)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
return mei_txe_br_reg_read(hw,
BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
}
@@ -464,26 +493,28 @@ static u32 mei_txe_out_data_read(const struct mei_device *dev,
/* Readiness */
/**
- * mei_txe_readiness_set_host_rdy
+ * mei_txe_readiness_set_host_rdy - set host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_br_reg_write(hw,
SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_HOST_RDY);
}
/**
- * mei_txe_readiness_clear
+ * mei_txe_readiness_clear - clear host readiness bit
*
* @dev: the device structure
*/
static void mei_txe_readiness_clear(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
SICR_HOST_IPC_READINESS_RDY_CLR);
}
@@ -492,10 +523,13 @@ static void mei_txe_readiness_clear(struct mei_device *dev)
* the HICR_SEC_IPC_READINESS register value
*
* @dev: the device structure
+ *
+ * Return: the HICR_SEC_IPC_READINESS register value
*/
static u32 mei_txe_readiness_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
}
@@ -504,7 +538,9 @@ static u32 mei_txe_readiness_get(struct mei_device *dev)
* mei_txe_readiness_is_sec_rdy - check readiness
* for HICR_SEC_IPC_READINESS_SEC_RDY
*
- * @readiness - cached readiness state
+ * @readiness: cached readiness state
+ *
+ * Return: true if readiness bit is set
*/
static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
{
@@ -515,10 +551,13 @@ static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
* mei_txe_hw_is_ready - check if the hw is ready
*
* @dev: the device structure
+ *
+ * Return: true if sec is ready
*/
static bool mei_txe_hw_is_ready(struct mei_device *dev)
{
u32 readiness = mei_txe_readiness_get(dev);
+
return mei_txe_readiness_is_sec_rdy(readiness);
}
@@ -526,11 +565,14 @@ static bool mei_txe_hw_is_ready(struct mei_device *dev)
* mei_txe_host_is_ready - check if the host is ready
*
* @dev: the device structure
+ *
+ * Return: true if host is ready
*/
static inline bool mei_txe_host_is_ready(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+
return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
}
@@ -539,7 +581,7 @@ static inline bool mei_txe_host_is_ready(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns 0 on success and -ETIME on timeout
+ * Return: 0 on success and -ETIME on timeout
*/
static int mei_txe_readiness_wait(struct mei_device *dev)
{
@@ -551,7 +593,7 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!dev->recvd_hw_ready) {
- dev_err(&dev->pdev->dev, "wait for readiness failed\n");
+ dev_err(dev->dev, "wait for readiness failed\n");
return -ETIME;
}
@@ -559,6 +601,42 @@ static int mei_txe_readiness_wait(struct mei_device *dev)
return 0;
}
+static const struct mei_fw_status mei_txe_fw_sts = {
+ .count = 2,
+ .status[0] = PCI_CFG_TXE_FW_STS0,
+ .status[1] = PCI_CFG_TXE_FW_STS1
+};
+
+/**
+ * mei_txe_fw_status - read fw status register from pci config space
+ *
+ * @dev: mei device
+ * @fw_status: fw status register values
+ *
+ * Return: 0 on success, error otherwise
+ */
+static int mei_txe_fw_status(struct mei_device *dev,
+ struct mei_fw_status *fw_status)
+{
+ const struct mei_fw_status *fw_src = &mei_txe_fw_sts;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+ int ret;
+ int i;
+
+ if (!fw_status)
+ return -EINVAL;
+
+ fw_status->count = fw_src->count;
+ for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) {
+ ret = pci_read_config_dword(pdev,
+ fw_src->status[i], &fw_status->status[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* mei_txe_hw_config - configure hardware at the start of the devices
*
@@ -571,13 +649,14 @@ static void mei_txe_hw_config(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
/* Doesn't change in runtime */
dev->hbuf_depth = PAYLOAD_SIZE / 4;
hw->aliveness = mei_txe_aliveness_get(dev);
hw->readiness = mei_txe_readiness_get(dev);
- dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
+ dev_dbg(dev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
hw->aliveness, hw->readiness);
}
@@ -588,7 +667,8 @@ static void mei_txe_hw_config(struct mei_device *dev)
* @dev: the device structure
* @header: header of message
* @buf: message buffer will be written
- * returns 1 if success, 0 - otherwise.
+ *
+ * Return: 0 if success, <0 - otherwise.
*/
static int mei_txe_write(struct mei_device *dev,
@@ -607,7 +687,7 @@ static int mei_txe_write(struct mei_device *dev,
length = header->length;
- dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+ dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
dw_cnt = mei_data2slots(length);
if (dw_cnt > slots)
@@ -621,8 +701,9 @@ static int mei_txe_write(struct mei_device *dev,
if (!mei_txe_is_input_ready(dev)) {
struct mei_fw_status fw_status;
+
mei_fw_status(dev, &fw_status);
- dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n",
+ dev_err(dev->dev, "Input is not ready " FW_STS_FMT "\n",
FW_STS_PRM(fw_status));
return -EAGAIN;
}
@@ -635,6 +716,7 @@ static int mei_txe_write(struct mei_device *dev,
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
+
memcpy(&reg, &buf[length - rem], rem);
mei_txe_input_payload_write(dev, i + 1, reg);
}
@@ -653,7 +735,7 @@ static int mei_txe_write(struct mei_device *dev,
*
* @dev: the device structure
*
- * returns the PAYLOAD_SIZE - 4
+ * Return: the PAYLOAD_SIZE - 4
*/
static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
{
@@ -665,11 +747,12 @@ static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
*
* @dev: the device structure
*
- * returns always hbuf_depth
+ * Return: always hbuf_depth
*/
static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+
return hw->slots;
}
@@ -678,7 +761,7 @@ static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns always buffer size in dwords count
+ * Return: always buffer size in dwords count
*/
static int mei_txe_count_full_read_slots(struct mei_device *dev)
{
@@ -691,7 +774,7 @@ static int mei_txe_count_full_read_slots(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns mei message header
+ * Return: mei message header
*/
static u32 mei_txe_read_hdr(const struct mei_device *dev)
@@ -705,33 +788,35 @@ static u32 mei_txe_read_hdr(const struct mei_device *dev)
* @buf: message buffer will be written
* @len: message size will be read
*
- * returns -EINVAL on error wrong argument and 0 on success
+ * Return: -EINVAL on error wrong argument and 0 on success
*/
static int mei_txe_read(struct mei_device *dev,
unsigned char *buf, unsigned long len)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 *reg_buf, reg;
+ u32 rem;
u32 i;
- u32 *reg_buf = (u32 *)buf;
- u32 rem = len & 0x3;
if (WARN_ON(!buf || !len))
return -EINVAL;
- dev_dbg(&dev->pdev->dev,
- "buffer-length = %lu buf[0]0x%08X\n",
+ reg_buf = (u32 *)buf;
+ rem = len & 0x3;
+
+ dev_dbg(dev->dev, "buffer-length = %lu buf[0]0x%08X\n",
len, mei_txe_out_data_read(dev, 0));
for (i = 0; i < len / 4; i++) {
/* skip header: index starts from 1 */
- u32 reg = mei_txe_out_data_read(dev, i + 1);
- dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
+ reg = mei_txe_out_data_read(dev, i + 1);
+ dev_dbg(dev->dev, "buf[%d] = 0x%08X\n", i, reg);
*reg_buf++ = reg;
}
if (rem) {
- u32 reg = mei_txe_out_data_read(dev, i + 1);
+ reg = mei_txe_out_data_read(dev, i + 1);
memcpy(reg_buf, &reg, rem);
}
@@ -745,7 +830,7 @@ static int mei_txe_read(struct mei_device *dev,
* @dev: the device structure
* @intr_enable: if interrupt should be enabled after reset.
*
- * returns 0 on success and < 0 in case of error
+ * Return: 0 on success and < 0 in case of error
*/
static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
{
@@ -771,8 +856,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*/
if (aliveness_req != hw->aliveness)
if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
- dev_err(&dev->pdev->dev,
- "wait for aliveness settle failed ... bailing out\n");
+ dev_err(dev->dev, "wait for aliveness settle failed ... bailing out\n");
return -EIO;
}
@@ -782,14 +866,13 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
if (aliveness_req) {
mei_txe_aliveness_set(dev, 0);
if (mei_txe_aliveness_poll(dev, 0) < 0) {
- dev_err(&dev->pdev->dev,
- "wait for aliveness failed ... bailing out\n");
+ dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return -EIO;
}
}
/*
- * Set rediness RDY_CLR bit
+ * Set readiness RDY_CLR bit
*/
mei_txe_readiness_clear(dev);
@@ -801,7 +884,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
*
* @dev: the device structure
*
- * returns 0 on success and < 0 in case of error
+ * Return: 0 on success an error code otherwise
*/
static int mei_txe_hw_start(struct mei_device *dev)
{
@@ -815,7 +898,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_readiness_wait(dev);
if (ret < 0) {
- dev_err(&dev->pdev->dev, "wating for readiness failed\n");
+ dev_err(dev->dev, "waiting for readiness failed\n");
return ret;
}
@@ -831,7 +914,7 @@ static int mei_txe_hw_start(struct mei_device *dev)
ret = mei_txe_aliveness_set_sync(dev, 1);
if (ret < 0) {
- dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
+ dev_err(dev->dev, "wait for aliveness failed ... bailing out\n");
return ret;
}
@@ -857,6 +940,8 @@ static int mei_txe_hw_start(struct mei_device *dev)
*
* @dev: the device structure
* @do_ack: acknowledge interrupts
+ *
+ * Return: true if found interrupts to process.
*/
static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
{
@@ -912,7 +997,8 @@ out:
* @irq: The irq number
* @dev_id: pointer to the device structure
*
- * returns irqreturn_t
+ * Return: IRQ_WAKE_THREAD if interrupt is designed for the device
+ * IRQ_NONE otherwise
*/
irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
{
@@ -930,8 +1016,7 @@ irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
* @irq: The irq number
* @dev_id: pointer to the device structure
*
- * returns irqreturn_t
- *
+ * Return: IRQ_HANDLED
*/
irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
{
@@ -941,7 +1026,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
s32 slots;
int rets = 0;
- dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
+ dev_dbg(dev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
mei_txe_br_reg_read(hw, HHISR_REG),
mei_txe_br_reg_read(hw, HISR_REG),
mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
@@ -951,7 +1036,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mutex_lock(&dev->device_lock);
mei_io_list_init(&complete_list);
- if (pci_dev_msi_enabled(dev->pdev))
+ if (pci_dev_msi_enabled(to_pci_dev(dev->dev)))
mei_txe_check_and_ack_intrs(dev, true);
/* show irq events */
@@ -965,17 +1050,17 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
* or TXE driver resetting the HECI interface.
*/
if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
- dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
+ dev_dbg(dev->dev, "Readiness Interrupt was received...\n");
/* Check if SeC is going through reset */
if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
- dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+ dev_dbg(dev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
} else {
dev->recvd_hw_ready = false;
if (dev->dev_state != MEI_DEV_RESETTING) {
- dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
+ dev_warn(dev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
@@ -992,7 +1077,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
/* Clear the interrupt cause */
- dev_dbg(&dev->pdev->dev,
+ dev_dbg(dev->dev,
"Aliveness Interrupt: Status: %d\n", hw->aliveness);
dev->pg_event = MEI_PG_EVENT_RECEIVED;
if (waitqueue_active(&hw->wait_aliveness_resp))
@@ -1008,7 +1093,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
/* Read from TXE */
rets = mei_irq_read_handler(dev, &complete_list, &slots);
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
- dev_err(&dev->pdev->dev,
+ dev_err(dev->dev,
"mei_irq_read_handler ret = %d.\n", rets);
schedule_work(&dev->reset_work);
@@ -1026,7 +1111,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
rets = mei_irq_write_handler(dev, &complete_list);
if (rets && rets != -EMSGSIZE)
- dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
+ dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n",
rets);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
}
@@ -1034,7 +1119,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
mei_irq_compl_handler(dev, &complete_list);
end:
- dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
+ dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets);
mutex_unlock(&dev->device_lock);
@@ -1046,6 +1131,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.host_is_ready = mei_txe_host_is_ready,
+ .fw_status = mei_txe_fw_status,
.pg_state = mei_txe_pg_state,
.hw_is_ready = mei_txe_hw_is_ready,
@@ -1072,27 +1158,14 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
};
-#define MEI_CFG_TXE_FW_STS \
- .fw_status.count = 2, \
- .fw_status.status[0] = PCI_CFG_TXE_FW_STS0, \
- .fw_status.status[1] = PCI_CFG_TXE_FW_STS1
-
-const struct mei_cfg mei_txe_cfg = {
- MEI_CFG_TXE_FW_STS,
-};
-
-
/**
* mei_txe_dev_init - allocates and initializes txe hardware specific structure
*
- * @pdev - pci device
- * @cfg - per device generation config
- *
- * returns struct mei_device * on success or NULL;
+ * @pdev: pci device
*
+ * Return: struct mei_device * on success or NULL
*/
-struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
- const struct mei_cfg *cfg)
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
{
struct mei_device *dev;
struct mei_txe_hw *hw;
@@ -1102,15 +1175,12 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
if (!dev)
return NULL;
- mei_device_init(dev, cfg);
+ mei_device_init(dev, &pdev->dev, &mei_txe_hw_ops);
hw = to_txe_hw(dev);
init_waitqueue_head(&hw->wait_aliveness_resp);
- dev->ops = &mei_txe_hw_ops;
-
- dev->pdev = pdev;
return dev;
}
@@ -1120,6 +1190,8 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev,
* @dev: the device structure
* @addr: physical address start of the range
* @range: physical range size
+ *
+ * Return: 0 on success an error code otherwise
*/
int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
{
@@ -1151,7 +1223,7 @@ int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
- dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
+ dev_dbg(dev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
range, lo32, ctrl);
return 0;
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
index e244af79167f..ce3ed0b88b0c 100644
--- a/drivers/misc/mei/hw-txe.h
+++ b/drivers/misc/mei/hw-txe.h
@@ -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);
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index dd448e58cc87..16fef6dc4dd7 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -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;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 006929222481..7901d076c127 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -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);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 4e3cba6da3f5..20c6c511f438 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -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;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 401a3d526cd0..beedc91f03a6 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -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;
- }
-
- rets = mei_ioctl_connect_client(file, connect_data);
+ dev_dbg(dev->dev, "failed to copy data from userland\n");
+ rets = -EFAULT;
+ goto out;
+ }
- /* if all is ok, copying the data back to user. */
- if (rets)
- goto out;
+ rets = mei_ioctl_connect_client(file, &connect_data);
+ 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;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 0b0d6135543b..71744b16cc8c 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -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) \
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 5ccc23bc7690..622654323177 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -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);
}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 959c313d84a7..f3225b1643ab 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -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 */
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 74727dda51c1..bee1c6fb7e75 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -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 */
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index a84a664dfccb..b836dfffceb5 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -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;
}
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
index 2e13614d41e8..fe3ad0ca9a3e 100644
--- a/drivers/misc/spear13xx_pcie_gadget.c
+++ b/drivers/misc/spear13xx_pcie_gadget.c
@@ -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;
}
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 1972d57aadb3..54be83d3efdd 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -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 ");
diff --git a/drivers/misc/vmw_vmci/vmci_datagram.c b/drivers/misc/vmw_vmci/vmci_datagram.c
index f3cdd904fe4d..822665245588 100644
--- a/drivers/misc/vmw_vmci/vmci_datagram.c
+++ b/drivers/misc/vmw_vmci/vmci_datagram.c
@@ -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;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 76ee7750bc5e..f721299eb1ba 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -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;