summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/Kconfig6
-rw-r--r--drivers/platform/chrome/Makefile5
-rw-r--r--drivers/platform/chrome/cros_ec.h2
-rw-r--r--drivers/platform/chrome/cros_ec_chardev.c6
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c6
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c6
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c6
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c2
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test.c2
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test_util.c (renamed from drivers/platform/chrome/cros_kunit_util.c)4
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test_util.h (renamed from drivers/platform/chrome/cros_kunit_util.h)0
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c6
-rw-r--r--drivers/platform/chrome/cros_ec_typec.c46
-rw-r--r--drivers/platform/chrome/cros_ec_vbc.c6
-rw-r--r--drivers/platform/chrome/cros_typec_switch.c5
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.c2
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.h2
-rw-r--r--drivers/platform/chrome/cros_usbpd_logger.c6
-rw-r--r--drivers/platform/chrome/cros_usbpd_notify.c12
-rw-r--r--drivers/platform/chrome/wilco_ec/core.c5
-rw-r--r--drivers/platform/chrome/wilco_ec/debugfs.c6
-rw-r--r--drivers/platform/chrome/wilco_ec/event.c2
-rw-r--r--drivers/platform/chrome/wilco_ec/telemetry.c6
-rw-r--r--drivers/platform/mellanox/mlxbf-bootctl.c6
-rw-r--r--drivers/platform/mellanox/mlxbf-pmc.c686
-rw-r--r--drivers/platform/mellanox/mlxbf-tmfifo.c73
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c6
-rw-r--r--drivers/platform/mellanox/mlxreg-io.c6
-rw-r--r--drivers/platform/mellanox/mlxreg-lc.c8
-rw-r--r--drivers/platform/mellanox/nvsw-sn2201.c6
-rw-r--r--drivers/platform/surface/surface3-wmi.c5
-rw-r--r--drivers/platform/surface/surface_acpi_notify.c16
-rw-r--r--drivers/platform/surface/surface_aggregator_cdev.c5
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c5
-rw-r--r--drivers/platform/surface/surface_dtx.c5
-rw-r--r--drivers/platform/surface/surface_gpe.c6
-rw-r--r--drivers/platform/surface/surface_hotplug.c6
-rw-r--r--drivers/platform/x86/Kconfig11
-rw-r--r--drivers/platform/x86/Makefile3
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/amd/hsmp.c241
-rw-r--r--drivers/platform/x86/amd/pmc/pmc.c88
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c66
-rw-r--r--drivers/platform/x86/asus-wireless.c12
-rw-r--r--drivers/platform/x86/asus-wmi.c191
-rw-r--r--drivers/platform/x86/asus-wmi.h8
-rw-r--r--drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c2
-rw-r--r--drivers/platform/x86/hp/hp-bioscfg/bioscfg.c2
-rw-r--r--drivers/platform/x86/inspur_platform_profile.c216
-rw-r--r--drivers/platform/x86/intel/bytcrc_pwrsrc.c5
-rw-r--r--drivers/platform/x86/intel/ifs/core.c15
-rw-r--r--drivers/platform/x86/intel/ifs/ifs.h64
-rw-r--r--drivers/platform/x86/intel/ifs/load.c167
-rw-r--r--drivers/platform/x86/intel/ifs/runtest.c72
-rw-r--r--drivers/platform/x86/intel/int3472/clk_and_regulator.c54
-rw-r--r--drivers/platform/x86/intel/int3472/common.h7
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c103
-rw-r--r--drivers/platform/x86/intel/int3472/led.c24
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c21
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c21
-rw-r--r--drivers/platform/x86/intel/tpmi.c81
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c18
-rw-r--r--drivers/platform/x86/intel/vbtn.c3
-rw-r--r--drivers/platform/x86/intel_ips.c30
-rw-r--r--drivers/platform/x86/mlx-platform.c31
-rw-r--r--drivers/platform/x86/msi-ec.c483
-rw-r--r--drivers/platform/x86/msi-ec.h4
-rw-r--r--drivers/platform/x86/sel3350-platform.c6
-rw-r--r--drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c6
-rw-r--r--drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c6
-rw-r--r--drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c6
-rw-r--r--drivers/platform/x86/siemens/simatic-ipc-batt.c9
-rw-r--r--drivers/platform/x86/siemens/simatic-ipc-batt.h4
-rw-r--r--drivers/platform/x86/sony-laptop.c2
-rw-r--r--drivers/platform/x86/think-lmi.c218
-rw-r--r--drivers/platform/x86/think-lmi.h16
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c106
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c39
-rw-r--r--drivers/platform/x86/wmi.c243
-rw-r--r--drivers/platform/x86/x86-android-tablets/asus.c1
-rw-r--r--drivers/platform/x86/x86-android-tablets/core.c135
-rw-r--r--drivers/platform/x86/x86-android-tablets/lenovo.c30
-rw-r--r--drivers/platform/x86/x86-android-tablets/other.c11
-rw-r--r--drivers/platform/x86/x86-android-tablets/x86-android-tablets.h8
-rw-r--r--drivers/platform/x86/xo15-ebook.c9
85 files changed, 3182 insertions, 706 deletions
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 7d82a0946e..7a83346bfa 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -299,12 +299,12 @@ config CROS_TYPEC_SWITCH
source "drivers/platform/chrome/wilco_ec/Kconfig"
# Kunit test cases
-config CROS_KUNIT
- tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS
+config CROS_KUNIT_EC_PROTO_TEST
+ tristate "Kunit tests for ChromeOS EC protocol" if !KUNIT_ALL_TESTS
depends on KUNIT && CROS_EC
default KUNIT_ALL_TESTS
select CROS_EC_PROTO
help
- ChromeOS Kunit tests.
+ Kunit tests for ChromeOS EC protocol.
endif # CHROMEOS_PLATFORMS
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 9e26e45c4a..2dcc6ccc23 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -36,6 +36,5 @@ obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
obj-$(CONFIG_WILCO_EC) += wilco_ec/
# Kunit test cases
-obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o
-cros_kunit-objs := cros_kunit_util.o
-cros_kunit-objs += cros_ec_proto_test.o
+obj-$(CONFIG_CROS_KUNIT_EC_PROTO_TEST) += cros_kunit_proto_test.o
+cros_kunit_proto_test-objs := cros_ec_proto_test_util.o cros_ec_proto_test.o
diff --git a/drivers/platform/chrome/cros_ec.h b/drivers/platform/chrome/cros_ec.h
index 566332f487..6b95f1e0ba 100644
--- a/drivers/platform/chrome/cros_ec.h
+++ b/drivers/platform/chrome/cros_ec.h
@@ -10,6 +10,8 @@
#include <linux/interrupt.h>
+struct cros_ec_device;
+
int cros_ec_register(struct cros_ec_device *ec_dev);
void cros_ec_unregister(struct cros_ec_device *ec_dev);
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index d6de5a2941..81950bb2c6 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -396,13 +396,11 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
return misc_register(&data->misc);
}
-static int cros_ec_chardev_remove(struct platform_device *pdev)
+static void cros_ec_chardev_remove(struct platform_device *pdev)
{
struct chardev_data *data = dev_get_drvdata(&pdev->dev);
misc_deregister(&data->misc);
-
- return 0;
}
static struct platform_driver cros_ec_chardev_driver = {
@@ -410,7 +408,7 @@ static struct platform_driver cros_ec_chardev_driver = {
.name = DRV_NAME,
},
.probe = cros_ec_chardev_probe,
- .remove = cros_ec_chardev_remove,
+ .remove_new = cros_ec_chardev_remove,
};
module_platform_driver(cros_ec_chardev_driver);
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index c876120e0e..091fdc154d 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -533,14 +533,12 @@ remove_debugfs:
return ret;
}
-static int cros_ec_debugfs_remove(struct platform_device *pd)
+static void cros_ec_debugfs_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent);
debugfs_remove_recursive(ec->debug_info->dir);
cros_ec_cleanup_console_log(ec->debug_info);
-
- return 0;
}
static int __maybe_unused cros_ec_debugfs_suspend(struct device *dev)
@@ -573,7 +571,7 @@ static struct platform_driver cros_ec_debugfs_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = cros_ec_debugfs_probe,
- .remove = cros_ec_debugfs_remove,
+ .remove_new = cros_ec_debugfs_remove,
};
module_platform_driver(cros_ec_debugfs_driver);
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 376425bbd8..6677cc6c49 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -560,7 +560,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd)
return ret;
}
-static int cros_ec_lightbar_remove(struct platform_device *pd)
+static void cros_ec_lightbar_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
@@ -569,8 +569,6 @@ static int cros_ec_lightbar_remove(struct platform_device *pd)
/* Let the EC take over the lightbar again. */
lb_manual_suspend_ctrl(ec_dev, 0);
-
- return 0;
}
static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
@@ -603,7 +601,7 @@ static struct platform_driver cros_ec_lightbar_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = cros_ec_lightbar_probe,
- .remove = cros_ec_lightbar_remove,
+ .remove_new = cros_ec_lightbar_remove,
};
module_platform_driver(cros_ec_lightbar_driver);
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 42e1770887..f0f3d3d561 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -460,7 +460,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
return 0;
}
-static int cros_ec_lpc_remove(struct platform_device *pdev)
+static void cros_ec_lpc_remove(struct platform_device *pdev)
{
struct cros_ec_device *ec_dev = platform_get_drvdata(pdev);
struct acpi_device *adev;
@@ -471,8 +471,6 @@ static int cros_ec_lpc_remove(struct platform_device *pdev)
cros_ec_lpc_acpi_notify);
cros_ec_unregister(ec_dev);
-
- return 0;
}
static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = {
@@ -594,7 +592,7 @@ static struct platform_driver cros_ec_lpc_driver = {
.probe_type = PROBE_FORCE_SYNCHRONOUS,
},
.probe = cros_ec_lpc_probe,
- .remove = cros_ec_lpc_remove,
+ .remove_new = cros_ec_lpc_remove,
};
static struct platform_device cros_ec_lpc_device = {
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 475a6dd72d..945b1b15a0 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -1004,7 +1004,7 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
int cros_ec_cmd(struct cros_ec_device *ec_dev,
unsigned int version,
int command,
- void *outdata,
+ const void *outdata,
size_t outsize,
void *indata,
size_t insize)
diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c
index 63e38671e9..b6169d6f24 100644
--- a/drivers/platform/chrome/cros_ec_proto_test.c
+++ b/drivers/platform/chrome/cros_ec_proto_test.c
@@ -11,7 +11,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include "cros_ec.h"
-#include "cros_kunit_util.h"
+#include "cros_ec_proto_test_util.h"
#define BUFSIZE 512
diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_ec_proto_test_util.c
index f0fda96b11..65d328bcd6 100644
--- a/drivers/platform/chrome/cros_kunit_util.c
+++ b/drivers/platform/chrome/cros_ec_proto_test_util.c
@@ -11,7 +11,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include "cros_ec.h"
-#include "cros_kunit_util.h"
+#include "cros_ec_proto_test_util.h"
int cros_kunit_ec_xfer_mock_default_result;
int cros_kunit_ec_xfer_mock_default_ret;
@@ -126,5 +126,3 @@ void cros_kunit_mock_reset(void)
cros_kunit_readmem_mock_data = NULL;
cros_kunit_readmem_mock_ret = 0;
}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_ec_proto_test_util.h
index 414002271c..414002271c 100644
--- a/drivers/platform/chrome/cros_kunit_util.h
+++ b/drivers/platform/chrome/cros_ec_proto_test_util.h
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index 09e3bf5e8e..93e67ab4af 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -340,13 +340,11 @@ static int cros_ec_sysfs_probe(struct platform_device *pd)
return ret;
}
-static int cros_ec_sysfs_remove(struct platform_device *pd)
+static void cros_ec_sysfs_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
sysfs_remove_group(&ec_dev->class_dev.kobj, &cros_ec_attr_group);
-
- return 0;
}
static struct platform_driver cros_ec_sysfs_driver = {
@@ -354,7 +352,7 @@ static struct platform_driver cros_ec_sysfs_driver = {
.name = DRV_NAME,
},
.probe = cros_ec_sysfs_probe,
- .remove = cros_ec_sysfs_remove,
+ .remove_new = cros_ec_sysfs_remove,
};
module_platform_driver(cros_ec_sysfs_driver);
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index d0b4d3fc40..2b2f14a1b7 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -80,28 +80,28 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
port->mux = fwnode_typec_mux_get(fwnode);
if (IS_ERR(port->mux)) {
ret = PTR_ERR(port->mux);
- dev_dbg(dev, "Mux handle not found: %d.\n", ret);
+ dev_err_probe(dev, ret, "Mux handle not found\n");
goto mux_err;
}
port->retimer = fwnode_typec_retimer_get(fwnode);
if (IS_ERR(port->retimer)) {
ret = PTR_ERR(port->retimer);
- dev_dbg(dev, "Retimer handle not found: %d.\n", ret);
+ dev_err_probe(dev, ret, "Retimer handle not found\n");
goto retimer_sw_err;
}
port->ori_sw = fwnode_typec_switch_get(fwnode);
if (IS_ERR(port->ori_sw)) {
ret = PTR_ERR(port->ori_sw);
- dev_dbg(dev, "Orientation switch handle not found: %d\n", ret);
+ dev_err_probe(dev, ret, "Orientation switch handle not found\n");
goto ori_sw_err;
}
port->role_sw = fwnode_usb_role_switch_get(fwnode);
if (IS_ERR(port->role_sw)) {
ret = PTR_ERR(port->role_sw);
- dev_dbg(dev, "USB role switch handle not found: %d\n", ret);
+ dev_err_probe(dev, ret, "USB role switch handle not found\n");
goto role_sw_err;
}
@@ -271,9 +271,9 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
struct typec_altmode *amode;
/* All PD capable CrOS devices are assumed to support DP altmode. */
- desc.svid = USB_TYPEC_DP_SID,
- desc.mode = USB_TYPEC_DP_MODE,
- desc.vdo = DP_PORT_VDO,
+ desc.svid = USB_TYPEC_DP_SID;
+ desc.mode = USB_TYPEC_DP_MODE;
+ desc.vdo = DP_PORT_VDO;
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
@@ -287,8 +287,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
* here for now.
*/
memset(&desc, 0, sizeof(desc));
- desc.svid = USB_TYPEC_TBT_SID,
- desc.mode = TYPEC_ANY_MODE,
+ desc.svid = USB_TYPEC_TBT_SID;
+ desc.mode = TYPEC_ANY_MODE;
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
@@ -492,6 +492,8 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
{
struct cros_typec_port *port = typec->ports[port_num];
struct typec_displayport_data dp_data;
+ u32 cable_tbt_vdo;
+ u32 cable_dp_vdo;
int ret;
if (typec->pd_ctrl_ver < 2) {
@@ -524,6 +526,32 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
port->state.data = &dp_data;
port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode));
+ /* Get cable VDO for cables with DPSID to check DPAM2.1 is supported */
+ cable_dp_vdo = cros_typec_get_cable_vdo(port, USB_TYPEC_DP_SID);
+
+ /**
+ * Get cable VDO for thunderbolt cables and cables with DPSID but does not
+ * support DPAM2.1.
+ */
+ cable_tbt_vdo = cros_typec_get_cable_vdo(port, USB_TYPEC_TBT_SID);
+
+ if (cable_dp_vdo & DP_CAP_DPAM_VERSION) {
+ dp_data.conf |= cable_dp_vdo;
+ } else if (cable_tbt_vdo) {
+ dp_data.conf |= TBT_CABLE_SPEED(cable_tbt_vdo) << DP_CONF_SIGNALLING_SHIFT;
+
+ /* Cable Type */
+ if (cable_tbt_vdo & TBT_CABLE_OPTICAL)
+ dp_data.conf |= DP_CONF_CABLE_TYPE_OPTICAL << DP_CONF_CABLE_TYPE_SHIFT;
+ else if (cable_tbt_vdo & TBT_CABLE_RETIMER)
+ dp_data.conf |= DP_CONF_CABLE_TYPE_RE_TIMER << DP_CONF_CABLE_TYPE_SHIFT;
+ else if (cable_tbt_vdo & TBT_CABLE_ACTIVE_PASSIVE)
+ dp_data.conf |= DP_CONF_CABLE_TYPE_RE_DRIVER << DP_CONF_CABLE_TYPE_SHIFT;
+ } else if (PD_IDH_PTYPE(port->c_identity.id_header) == IDH_PTYPE_PCABLE) {
+ dp_data.conf |= VDO_TYPEC_CABLE_SPEED(port->c_identity.vdo[0]) <<
+ DP_CONF_SIGNALLING_SHIFT;
+ }
+
ret = cros_typec_retimer_set(port->retimer, port->state);
if (!ret)
ret = typec_mux_set(port->mux, &port->state);
diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
index c859c862d7..2e4af10c76 100644
--- a/drivers/platform/chrome/cros_ec_vbc.c
+++ b/drivers/platform/chrome/cros_ec_vbc.c
@@ -121,14 +121,12 @@ static int cros_ec_vbc_probe(struct platform_device *pd)
return ret;
}
-static int cros_ec_vbc_remove(struct platform_device *pd)
+static void cros_ec_vbc_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
sysfs_remove_group(&ec_dev->class_dev.kobj,
&cros_ec_vbc_attr_group);
-
- return 0;
}
static struct platform_driver cros_ec_vbc_driver = {
@@ -136,7 +134,7 @@ static struct platform_driver cros_ec_vbc_driver = {
.name = DRV_NAME,
},
.probe = cros_ec_vbc_probe,
- .remove = cros_ec_vbc_remove,
+ .remove_new = cros_ec_vbc_remove,
};
module_platform_driver(cros_ec_vbc_driver);
diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
index 0eefdcf14d..07a19386dc 100644
--- a/drivers/platform/chrome/cros_typec_switch.c
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -297,12 +297,11 @@ static int cros_typec_switch_probe(struct platform_device *pdev)
return cros_typec_register_switches(sdata);
}
-static int cros_typec_switch_remove(struct platform_device *pdev)
+static void cros_typec_switch_remove(struct platform_device *pdev)
{
struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev);
cros_typec_unregister_switches(sdata);
- return 0;
}
#ifdef CONFIG_ACPI
@@ -319,7 +318,7 @@ static struct platform_driver cros_typec_switch_driver = {
.acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id),
},
.probe = cros_typec_switch_probe,
- .remove = cros_typec_switch_remove,
+ .remove_new = cros_typec_switch_remove,
};
module_platform_driver(cros_typec_switch_driver);
diff --git a/drivers/platform/chrome/cros_typec_vdm.c b/drivers/platform/chrome/cros_typec_vdm.c
index 20515ee0a2..3f632fd350 100644
--- a/drivers/platform/chrome/cros_typec_vdm.c
+++ b/drivers/platform/chrome/cros_typec_vdm.c
@@ -142,7 +142,7 @@ static int cros_typec_port_amode_vdm(struct typec_altmode *amode, const u32 hdr,
sizeof(req), NULL, 0);
}
-struct typec_altmode_ops port_amode_ops = {
+const struct typec_altmode_ops port_amode_ops = {
.enter = cros_typec_port_amode_enter,
.vdm = cros_typec_port_amode_vdm,
};
diff --git a/drivers/platform/chrome/cros_typec_vdm.h b/drivers/platform/chrome/cros_typec_vdm.h
index 95a6a75d32..631bd2ce4b 100644
--- a/drivers/platform/chrome/cros_typec_vdm.h
+++ b/drivers/platform/chrome/cros_typec_vdm.h
@@ -5,7 +5,7 @@
#include <linux/usb/typec_altmode.h>
-extern struct typec_altmode_ops port_amode_ops;
+extern const struct typec_altmode_ops port_amode_ops;
void cros_typec_handle_vdm_attention(struct cros_typec_data *typec, int port_num);
void cros_typec_handle_vdm_response(struct cros_typec_data *typec, int port_num);
diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c
index d16931203d..f618757f8b 100644
--- a/drivers/platform/chrome/cros_usbpd_logger.c
+++ b/drivers/platform/chrome/cros_usbpd_logger.c
@@ -219,14 +219,12 @@ static int cros_usbpd_logger_probe(struct platform_device *pd)
return 0;
}
-static int cros_usbpd_logger_remove(struct platform_device *pd)
+static void cros_usbpd_logger_remove(struct platform_device *pd)
{
struct logger_data *logger = platform_get_drvdata(pd);
cancel_delayed_work_sync(&logger->log_work);
destroy_workqueue(logger->log_workqueue);
-
- return 0;
}
static int __maybe_unused cros_usbpd_logger_resume(struct device *dev)
@@ -257,7 +255,7 @@ static struct platform_driver cros_usbpd_logger_driver = {
.pm = &cros_usbpd_logger_pm_ops,
},
.probe = cros_usbpd_logger_probe,
- .remove = cros_usbpd_logger_remove,
+ .remove_new = cros_usbpd_logger_remove,
};
module_platform_driver(cros_usbpd_logger_driver);
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c
index 10670b6588..aacad022f2 100644
--- a/drivers/platform/chrome/cros_usbpd_notify.c
+++ b/drivers/platform/chrome/cros_usbpd_notify.c
@@ -134,15 +134,13 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
return 0;
}
-static int cros_usbpd_notify_remove_acpi(struct platform_device *pdev)
+static void cros_usbpd_notify_remove_acpi(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(dev);
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
cros_usbpd_notify_acpi);
-
- return 0;
}
static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = {
@@ -157,7 +155,7 @@ static struct platform_driver cros_usbpd_notify_acpi_driver = {
.acpi_match_table = cros_usbpd_notify_acpi_device_ids,
},
.probe = cros_usbpd_notify_probe_acpi,
- .remove = cros_usbpd_notify_remove_acpi,
+ .remove_new = cros_usbpd_notify_remove_acpi,
};
#endif /* CONFIG_ACPI */
@@ -209,7 +207,7 @@ static int cros_usbpd_notify_probe_plat(struct platform_device *pdev)
return 0;
}
-static int cros_usbpd_notify_remove_plat(struct platform_device *pdev)
+static void cros_usbpd_notify_remove_plat(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent);
@@ -218,8 +216,6 @@ static int cros_usbpd_notify_remove_plat(struct platform_device *pdev)
blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier,
&pdnotify->nb);
-
- return 0;
}
static struct platform_driver cros_usbpd_notify_plat_driver = {
@@ -227,7 +223,7 @@ static struct platform_driver cros_usbpd_notify_plat_driver = {
.name = DRV_NAME,
},
.probe = cros_usbpd_notify_probe_plat,
- .remove = cros_usbpd_notify_remove_plat,
+ .remove_new = cros_usbpd_notify_remove_plat,
};
static int __init cros_usbpd_notify_init(void)
diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
index d6a994bdc1..9b59a1bed2 100644
--- a/drivers/platform/chrome/wilco_ec/core.c
+++ b/drivers/platform/chrome/wilco_ec/core.c
@@ -132,7 +132,7 @@ unregister_debugfs:
return ret;
}
-static int wilco_ec_remove(struct platform_device *pdev)
+static void wilco_ec_remove(struct platform_device *pdev)
{
struct wilco_ec_device *ec = platform_get_drvdata(pdev);
@@ -142,7 +142,6 @@ static int wilco_ec_remove(struct platform_device *pdev)
platform_device_unregister(ec->rtc_pdev);
if (ec->debugfs_pdev)
platform_device_unregister(ec->debugfs_pdev);
- return 0;
}
static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
@@ -157,7 +156,7 @@ static struct platform_driver wilco_ec_driver = {
.acpi_match_table = wilco_ec_acpi_device_ids,
},
.probe = wilco_ec_probe,
- .remove = wilco_ec_remove,
+ .remove_new = wilco_ec_remove,
};
module_platform_driver(wilco_ec_driver);
diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c
index 7a13f13b16..93c11f81ca 100644
--- a/drivers/platform/chrome/wilco_ec/debugfs.c
+++ b/drivers/platform/chrome/wilco_ec/debugfs.c
@@ -260,11 +260,9 @@ static int wilco_ec_debugfs_probe(struct platform_device *pdev)
return 0;
}
-static int wilco_ec_debugfs_remove(struct platform_device *pdev)
+static void wilco_ec_debugfs_remove(struct platform_device *pdev)
{
debugfs_remove_recursive(debug_info->dir);
-
- return 0;
}
static struct platform_driver wilco_ec_debugfs_driver = {
@@ -272,7 +270,7 @@ static struct platform_driver wilco_ec_debugfs_driver = {
.name = DRV_NAME,
},
.probe = wilco_ec_debugfs_probe,
- .remove = wilco_ec_debugfs_remove,
+ .remove_new = wilco_ec_debugfs_remove,
};
module_platform_driver(wilco_ec_debugfs_driver);
diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c
index a40f60bcef..f80a7c83cf 100644
--- a/drivers/platform/chrome/wilco_ec/event.c
+++ b/drivers/platform/chrome/wilco_ec/event.c
@@ -95,7 +95,7 @@ struct ec_event_queue {
int capacity;
int head;
int tail;
- struct ec_event *entries[];
+ struct ec_event *entries[] __counted_by(capacity);
};
/* Maximum number of events to store in ec_event_queue */
diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c
index 54708aa6c7..253098bace 100644
--- a/drivers/platform/chrome/wilco_ec/telemetry.c
+++ b/drivers/platform/chrome/wilco_ec/telemetry.c
@@ -400,20 +400,18 @@ static int telem_device_probe(struct platform_device *pdev)
return 0;
}
-static int telem_device_remove(struct platform_device *pdev)
+static void telem_device_remove(struct platform_device *pdev)
{
struct telem_device_data *dev_data = platform_get_drvdata(pdev);
cdev_device_del(&dev_data->cdev, &dev_data->dev);
ida_simple_remove(&telem_ida, MINOR(dev_data->dev.devt));
put_device(&dev_data->dev);
-
- return 0;
}
static struct platform_driver telem_driver = {
.probe = telem_device_probe,
- .remove = telem_device_remove,
+ .remove_new = telem_device_remove,
.driver = {
.name = DRV_NAME,
},
diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c
index e278092f88..c1aef3a8fb 100644
--- a/drivers/platform/mellanox/mlxbf-bootctl.c
+++ b/drivers/platform/mellanox/mlxbf-bootctl.c
@@ -1041,17 +1041,15 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev)
return ret;
}
-static int mlxbf_bootctl_remove(struct platform_device *pdev)
+static void mlxbf_bootctl_remove(struct platform_device *pdev)
{
sysfs_remove_bin_file(&pdev->dev.kobj,
&mlxbf_bootctl_bootfifo_sysfs_attr);
-
- return 0;
}
static struct platform_driver mlxbf_bootctl_driver = {
.probe = mlxbf_bootctl_probe,
- .remove = mlxbf_bootctl_remove,
+ .remove_new = mlxbf_bootctl_remove,
.driver = {
.name = "mlxbf-bootctl",
.dev_groups = mlxbf_bootctl_groups,
diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c
index db7a1d360c..b1995ac268 100644
--- a/drivers/platform/mellanox/mlxbf-pmc.c
+++ b/drivers/platform/mellanox/mlxbf-pmc.c
@@ -30,14 +30,16 @@
#define MLXBF_PMC_EVENT_SET_BF1 0
#define MLXBF_PMC_EVENT_SET_BF2 1
+#define MLXBF_PMC_EVENT_SET_BF3 2
#define MLXBF_PMC_EVENT_INFO_LEN 100
#define MLXBF_PMC_MAX_BLOCKS 30
-#define MLXBF_PMC_MAX_ATTRS 30
+#define MLXBF_PMC_MAX_ATTRS 70
#define MLXBF_PMC_INFO_SZ 4
#define MLXBF_PMC_REG_SIZE 8
#define MLXBF_PMC_L3C_REG_SIZE 4
+#define MLXBF_PMC_TYPE_CRSPACE 2
#define MLXBF_PMC_TYPE_COUNTER 1
#define MLXBF_PMC_TYPE_REGISTER 0
@@ -78,6 +80,16 @@
#define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0)
#define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0)
+#define MLXBF_PMC_CRSPACE_PERFMON_REG0 0x0
+#define MLXBF_PMC_CRSPACE_PERFSEL_SZ 4
+#define MLXBF_PMC_CRSPACE_PERFSEL0 GENMASK(23, 16)
+#define MLXBF_PMC_CRSPACE_PERFSEL1 GENMASK(7, 0)
+#define MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ 0x2
+#define MLXBF_PMC_CRSPACE_PERFMON_CTL(n) (n * MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ)
+#define MLXBF_PMC_CRSPACE_PERFMON_EN BIT(30)
+#define MLXBF_PMC_CRSPACE_PERFMON_CLR BIT(28)
+#define MLXBF_PMC_CRSPACE_PERFMON_VAL0(n) (MLXBF_PMC_CRSPACE_PERFMON_CTL(n) + 0xc)
+
/**
* struct mlxbf_pmc_attribute - Structure to hold attribute and block info
* for each sysfs entry
@@ -124,6 +136,9 @@ struct mlxbf_pmc_block_info {
* @pdev: The kernel structure representing the device
* @total_blocks: Total number of blocks
* @tile_count: Number of tiles in the system
+ * @llt_enable: Info on enabled LLTs
+ * @mss_enable: Info on enabled MSSs
+ * @group_num: Group number assigned to each valid block
* @hwmon_dev: Hwmon device for bfperf
* @block_name: Block name
* @block: Block info
@@ -136,6 +151,9 @@ struct mlxbf_pmc_context {
struct platform_device *pdev;
uint32_t total_blocks;
uint32_t tile_count;
+ uint8_t llt_enable;
+ uint8_t mss_enable;
+ uint32_t group_num;
struct device *hwmon_dev;
const char *block_name[MLXBF_PMC_MAX_BLOCKS];
struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS];
@@ -260,7 +278,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = {
{ 0x348, "DRAM_ECC_ERROR" },
};
-static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = {
+static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_1[] = {
{ 0x0, "DISABLE" },
{ 0xc0, "RXREQ_MSS" },
{ 0xc1, "RXDAT_MSS" },
@@ -268,6 +286,164 @@ static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = {
{ 0xc3, "TXDAT_MSS" },
};
+static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_3[] = {
+ {0, "SKYLIB_CDN_TX_FLITS"},
+ {1, "SKYLIB_DDN_TX_FLITS"},
+ {2, "SKYLIB_NDN_TX_FLITS"},
+ {3, "SKYLIB_SDN_TX_FLITS"},
+ {4, "SKYLIB_UDN_TX_FLITS"},
+ {5, "SKYLIB_CDN_RX_FLITS"},
+ {6, "SKYLIB_DDN_RX_FLITS"},
+ {7, "SKYLIB_NDN_RX_FLITS"},
+ {8, "SKYLIB_SDN_RX_FLITS"},
+ {9, "SKYLIB_UDN_RX_FLITS"},
+ {10, "SKYLIB_CDN_TX_STALL"},
+ {11, "SKYLIB_DDN_TX_STALL"},
+ {12, "SKYLIB_NDN_TX_STALL"},
+ {13, "SKYLIB_SDN_TX_STALL"},
+ {14, "SKYLIB_UDN_TX_STALL"},
+ {15, "SKYLIB_CDN_RX_STALL"},
+ {16, "SKYLIB_DDN_RX_STALL"},
+ {17, "SKYLIB_NDN_RX_STALL"},
+ {18, "SKYLIB_SDN_RX_STALL"},
+ {19, "SKYLIB_UDN_RX_STALL"},
+ {20, "SKYLIB_CHI_REQ0_TX_FLITS"},
+ {21, "SKYLIB_CHI_DATA0_TX_FLITS"},
+ {22, "SKYLIB_CHI_RESP0_TX_FLITS"},
+ {23, "SKYLIB_CHI_SNP0_TX_FLITS"},
+ {24, "SKYLIB_CHI_REQ1_TX_FLITS"},
+ {25, "SKYLIB_CHI_DATA1_TX_FLITS"},
+ {26, "SKYLIB_CHI_RESP1_TX_FLITS"},
+ {27, "SKYLIB_CHI_SNP1_TX_FLITS"},
+ {28, "SKYLIB_CHI_REQ2_TX_FLITS"},
+ {29, "SKYLIB_CHI_DATA2_TX_FLITS"},
+ {30, "SKYLIB_CHI_RESP2_TX_FLITS"},
+ {31, "SKYLIB_CHI_SNP2_TX_FLITS"},
+ {32, "SKYLIB_CHI_REQ3_TX_FLITS"},
+ {33, "SKYLIB_CHI_DATA3_TX_FLITS"},
+ {34, "SKYLIB_CHI_RESP3_TX_FLITS"},
+ {35, "SKYLIB_CHI_SNP3_TX_FLITS"},
+ {36, "SKYLIB_TLP_REQ_TX_FLITS"},
+ {37, "SKYLIB_TLP_RESP_TX_FLITS"},
+ {38, "SKYLIB_TLP_META_TX_FLITS"},
+ {39, "SKYLIB_AXIS_DATA_TX_FLITS"},
+ {40, "SKYLIB_AXIS_CRED_TX_FLITS"},
+ {41, "SKYLIB_APB_TX_FLITS"},
+ {42, "SKYLIB_VW_TX_FLITS"},
+ {43, "SKYLIB_GGA_MSN_W_TX_FLITS"},
+ {44, "SKYLIB_GGA_MSN_N_TX_FLITS"},
+ {45, "SKYLIB_CR_REQ_TX_FLITS"},
+ {46, "SKYLIB_CR_RESP_TX_FLITS"},
+ {47, "SKYLIB_MSN_PRNF_TX_FLITS"},
+ {48, "SKYLIB_DBG_DATA_TX_FLITS"},
+ {49, "SKYLIB_DBG_CRED_TX_FLITS"},
+ {50, "SKYLIB_CHI_REQ0_RX_FLITS"},
+ {51, "SKYLIB_CHI_DATA0_RX_FLITS"},
+ {52, "SKYLIB_CHI_RESP0_RX_FLITS"},
+ {53, "SKYLIB_CHI_SNP0_RX_FLITS"},
+ {54, "SKYLIB_CHI_REQ1_RX_FLITS"},
+ {55, "SKYLIB_CHI_DATA1_RX_FLITS"},
+ {56, "SKYLIB_CHI_RESP1_RX_FLITS"},
+ {57, "SKYLIB_CHI_SNP1_RX_FLITS"},
+ {58, "SKYLIB_CHI_REQ2_RX_FLITS"},
+ {59, "SKYLIB_CHI_DATA2_RX_FLITS"},
+ {60, "SKYLIB_CHI_RESP2_RX_FLITS"},
+ {61, "SKYLIB_CHI_SNP2_RX_FLITS"},
+ {62, "SKYLIB_CHI_REQ3_RX_FLITS"},
+ {63, "SKYLIB_CHI_DATA3_RX_FLITS"},
+ {64, "SKYLIB_CHI_RESP3_RX_FLITS"},
+ {65, "SKYLIB_CHI_SNP3_RX_FLITS"},
+ {66, "SKYLIB_TLP_REQ_RX_FLITS"},
+ {67, "SKYLIB_TLP_RESP_RX_FLITS"},
+ {68, "SKYLIB_TLP_META_RX_FLITS"},
+ {69, "SKYLIB_AXIS_DATA_RX_FLITS"},
+ {70, "SKYLIB_AXIS_CRED_RX_FLITS"},
+ {71, "SKYLIB_APB_RX_FLITS"},
+ {72, "SKYLIB_VW_RX_FLITS"},
+ {73, "SKYLIB_GGA_MSN_W_RX_FLITS"},
+ {74, "SKYLIB_GGA_MSN_N_RX_FLITS"},
+ {75, "SKYLIB_CR_REQ_RX_FLITS"},
+ {76, "SKYLIB_CR_RESP_RX_FLITS"},
+ {77, "SKYLIB_MSN_PRNF_RX_FLITS"},
+ {78, "SKYLIB_DBG_DATA_RX_FLITS"},
+ {79, "SKYLIB_DBG_CRED_RX_FLITS"},
+ {80, "SKYLIB_CHI_REQ0_TX_STALL"},
+ {81, "SKYLIB_CHI_DATA0_TX_STALL"},
+ {82, "SKYLIB_CHI_RESP0_TX_STALL"},
+ {83, "SKYLIB_CHI_SNP0_TX_STALL"},
+ {84, "SKYLIB_CHI_REQ1_TX_STALL"},
+ {85, "SKYLIB_CHI_DATA1_TX_STALL"},
+ {86, "SKYLIB_CHI_RESP1_TX_STALL"},
+ {87, "SKYLIB_CHI_SNP1_TX_STALL"},
+ {88, "SKYLIB_CHI_REQ2_TX_STALL"},
+ {89, "SKYLIB_CHI_DATA2_TX_STALL"},
+ {90, "SKYLIB_CHI_RESP2_TX_STALL"},
+ {91, "SKYLIB_CHI_SNP2_TX_STALL"},
+ {92, "SKYLIB_CHI_REQ3_TX_STALL"},
+ {93, "SKYLIB_CHI_DATA3_TX_STALL"},
+ {94, "SKYLIB_CHI_RESP3_TX_STALL"},
+ {95, "SKYLIB_CHI_SNP3_TX_STALL"},
+ {96, "SKYLIB_TLP_REQ_TX_STALL"},
+ {97, "SKYLIB_TLP_RESP_TX_STALL"},
+ {98, "SKYLIB_TLP_META_TX_STALL"},
+ {99, "SKYLIB_AXIS_DATA_TX_STALL"},
+ {100, "SKYLIB_AXIS_CRED_TX_STALL"},
+ {101, "SKYLIB_APB_TX_STALL"},
+ {102, "SKYLIB_VW_TX_STALL"},
+ {103, "SKYLIB_GGA_MSN_W_TX_STALL"},
+ {104, "SKYLIB_GGA_MSN_N_TX_STALL"},
+ {105, "SKYLIB_CR_REQ_TX_STALL"},
+ {106, "SKYLIB_CR_RESP_TX_STALL"},
+ {107, "SKYLIB_MSN_PRNF_TX_STALL"},
+ {108, "SKYLIB_DBG_DATA_TX_STALL"},
+ {109, "SKYLIB_DBG_CRED_TX_STALL"},
+ {110, "SKYLIB_CHI_REQ0_RX_STALL"},
+ {111, "SKYLIB_CHI_DATA0_RX_STALL"},
+ {112, "SKYLIB_CHI_RESP0_RX_STALL"},
+ {113, "SKYLIB_CHI_SNP0_RX_STALL"},
+ {114, "SKYLIB_CHI_REQ1_RX_STALL"},
+ {115, "SKYLIB_CHI_DATA1_RX_STALL"},
+ {116, "SKYLIB_CHI_RESP1_RX_STALL"},
+ {117, "SKYLIB_CHI_SNP1_RX_STALL"},
+ {118, "SKYLIB_CHI_REQ2_RX_STALL"},
+ {119, "SKYLIB_CHI_DATA2_RX_STALL"},
+ {120, "SKYLIB_CHI_RESP2_RX_STALL"},
+ {121, "SKYLIB_CHI_SNP2_RX_STALL"},
+ {122, "SKYLIB_CHI_REQ3_RX_STALL"},
+ {123, "SKYLIB_CHI_DATA3_RX_STALL"},
+ {124, "SKYLIB_CHI_RESP3_RX_STALL"},
+ {125, "SKYLIB_CHI_SNP3_RX_STALL"},
+ {126, "SKYLIB_TLP_REQ_RX_STALL"},
+ {127, "SKYLIB_TLP_RESP_RX_STALL"},
+ {128, "SKYLIB_TLP_META_RX_STALL"},
+ {129, "SKYLIB_AXIS_DATA_RX_STALL"},
+ {130, "SKYLIB_AXIS_CRED_RX_STALL"},
+ {131, "SKYLIB_APB_RX_STALL"},
+ {132, "SKYLIB_VW_RX_STALL"},
+ {133, "SKYLIB_GGA_MSN_W_RX_STALL"},
+ {134, "SKYLIB_GGA_MSN_N_RX_STALL"},
+ {135, "SKYLIB_CR_REQ_RX_STALL"},
+ {136, "SKYLIB_CR_RESP_RX_STALL"},
+ {137, "SKYLIB_MSN_PRNF_RX_STALL"},
+ {138, "SKYLIB_DBG_DATA_RX_STALL"},
+ {139, "SKYLIB_DBG_CRED_RX_STALL"},
+ {140, "SKYLIB_CDN_LOOPBACK_FLITS"},
+ {141, "SKYLIB_DDN_LOOPBACK_FLITS"},
+ {142, "SKYLIB_NDN_LOOPBACK_FLITS"},
+ {143, "SKYLIB_SDN_LOOPBACK_FLITS"},
+ {144, "SKYLIB_UDN_LOOPBACK_FLITS"},
+ {145, "HISTOGRAM_HISTOGRAM_BIN0"},
+ {146, "HISTOGRAM_HISTOGRAM_BIN1"},
+ {147, "HISTOGRAM_HISTOGRAM_BIN2"},
+ {148, "HISTOGRAM_HISTOGRAM_BIN3"},
+ {149, "HISTOGRAM_HISTOGRAM_BIN4"},
+ {150, "HISTOGRAM_HISTOGRAM_BIN5"},
+ {151, "HISTOGRAM_HISTOGRAM_BIN6"},
+ {152, "HISTOGRAM_HISTOGRAM_BIN7"},
+ {153, "HISTOGRAM_HISTOGRAM_BIN8"},
+ {154, "HISTOGRAM_HISTOGRAM_BIN9"},
+};
+
static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = {
{ 0x0, "DISABLE" },
{ 0x45, "HNF_REQUESTS" },
@@ -429,6 +605,260 @@ static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = {
{ 0x2b, "ANY_REJECT_BANK1" },
};
+static const struct mlxbf_pmc_events mlxbf_pmc_llt_events[] = {
+ {0, "HNF0_CYCLES"},
+ {1, "HNF0_REQS_RECEIVED"},
+ {2, "HNF0_REQS_PROCESSED"},
+ {3, "HNF0_DIR_HIT"},
+ {4, "HNF0_DIR_MISS"},
+ {5, "HNF0_DIR_RD_ALLOC"},
+ {6, "HNF0_DIR_WR_ALLOC"},
+ {7, "HNF0_DIR_VICTIM"},
+ {8, "HNF0_CL_HAZARD"},
+ {9, "HNF0_ALL_HAZARD"},
+ {10, "HNF0_PIPE_STALLS"},
+ {11, "HNF0_MEM_READS"},
+ {12, "HNF0_MEM_WRITES"},
+ {13, "HNF0_MEM_ACCESS"},
+ {14, "HNF0_DCL_READ"},
+ {15, "HNF0_DCL_INVAL"},
+ {16, "HNF0_CHI_RXDAT"},
+ {17, "HNF0_CHI_RXRSP"},
+ {18, "HNF0_CHI_TXDAT"},
+ {19, "HNF0_CHI_TXRSP"},
+ {20, "HNF0_CHI_TXSNP"},
+ {21, "HNF0_DCT_SNP"},
+ {22, "HNF0_SNP_FWD_DATA"},
+ {23, "HNF0_SNP_FWD_RSP"},
+ {24, "HNF0_SNP_RSP"},
+ {25, "HNF0_EXCL_FULL"},
+ {26, "HNF0_EXCL_WRITE_F"},
+ {27, "HNF0_EXCL_WRITE_S"},
+ {28, "HNF0_EXCL_WRITE"},
+ {29, "HNF0_EXCL_READ"},
+ {30, "HNF0_REQ_BUF_EMPTY"},
+ {31, "HNF0_ALL_MAFS_BUSY"},
+ {32, "HNF0_TXDAT_NO_LCRD"},
+ {33, "HNF0_TXSNP_NO_LCRD"},
+ {34, "HNF0_TXRSP_NO_LCRD"},
+ {35, "HNF0_TXREQ_NO_LCRD"},
+ {36, "HNF0_WRITE"},
+ {37, "HNF0_READ"},
+ {38, "HNF0_ACCESS"},
+ {39, "HNF0_MAF_N_BUSY"},
+ {40, "HNF0_MAF_N_REQS"},
+ {41, "HNF0_SEL_OPCODE"},
+ {42, "HNF1_CYCLES"},
+ {43, "HNF1_REQS_RECEIVED"},
+ {44, "HNF1_REQS_PROCESSED"},
+ {45, "HNF1_DIR_HIT"},
+ {46, "HNF1_DIR_MISS"},
+ {47, "HNF1_DIR_RD_ALLOC"},
+ {48, "HNF1_DIR_WR_ALLOC"},
+ {49, "HNF1_DIR_VICTIM"},
+ {50, "HNF1_CL_HAZARD"},
+ {51, "HNF1_ALL_HAZARD"},
+ {52, "HNF1_PIPE_STALLS"},
+ {53, "HNF1_MEM_READS"},
+ {54, "HNF1_MEM_WRITES"},
+ {55, "HNF1_MEM_ACCESS"},
+ {56, "HNF1_DCL_READ"},
+ {57, "HNF1_DCL_INVAL"},
+ {58, "HNF1_CHI_RXDAT"},
+ {59, "HNF1_CHI_RXRSP"},
+ {60, "HNF1_CHI_TXDAT"},
+ {61, "HNF1_CHI_TXRSP"},
+ {62, "HNF1_CHI_TXSNP"},
+ {63, "HNF1_DCT_SNP"},
+ {64, "HNF1_SNP_FWD_DATA"},
+ {65, "HNF1_SNP_FWD_RSP"},
+ {66, "HNF1_SNP_RSP"},
+ {67, "HNF1_EXCL_FULL"},
+ {68, "HNF1_EXCL_WRITE_F"},
+ {69, "HNF1_EXCL_WRITE_S"},
+ {70, "HNF1_EXCL_WRITE"},
+ {71, "HNF1_EXCL_READ"},
+ {72, "HNF1_REQ_BUF_EMPTY"},
+ {73, "HNF1_ALL_MAFS_BUSY"},
+ {74, "HNF1_TXDAT_NO_LCRD"},
+ {75, "HNF1_TXSNP_NO_LCRD"},
+ {76, "HNF1_TXRSP_NO_LCRD"},
+ {77, "HNF1_TXREQ_NO_LCRD"},
+ {78, "HNF1_WRITE"},
+ {79, "HNF1_READ"},
+ {80, "HNF1_ACCESS"},
+ {81, "HNF1_MAF_N_BUSY"},
+ {82, "HNF1_MAF_N_REQS"},
+ {83, "HNF1_SEL_OPCODE"},
+ {84, "GDC_BANK0_RD_REQ"},
+ {85, "GDC_BANK0_WR_REQ"},
+ {86, "GDC_BANK0_ALLOCATE"},
+ {87, "GDC_BANK0_HIT"},
+ {88, "GDC_BANK0_MISS"},
+ {89, "GDC_BANK0_INVALIDATE"},
+ {90, "GDC_BANK0_EVICT"},
+ {91, "GDC_BANK0_RD_RESP"},
+ {92, "GDC_BANK0_WR_ACK"},
+ {93, "GDC_BANK0_SNOOP"},
+ {94, "GDC_BANK0_SNOOP_NORMAL"},
+ {95, "GDC_BANK0_SNOOP_FWD"},
+ {96, "GDC_BANK0_SNOOP_STASH"},
+ {97, "GDC_BANK0_SNOOP_STASH_INDPND_RD"},
+ {98, "GDC_BANK0_FOLLOWER"},
+ {99, "GDC_BANK0_FW"},
+ {100, "GDC_BANK0_HIT_DCL_BOTH"},
+ {101, "GDC_BANK0_HIT_DCL_PARTIAL"},
+ {102, "GDC_BANK0_EVICT_DCL"},
+ {103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"},
+ {103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"},
+ {105, "GDC_BANK0_ARB_STRB"},
+ {106, "GDC_BANK0_ARB_WAIT"},
+ {107, "GDC_BANK0_GGA_STRB"},
+ {108, "GDC_BANK0_GGA_WAIT"},
+ {109, "GDC_BANK0_FW_STRB"},
+ {110, "GDC_BANK0_FW_WAIT"},
+ {111, "GDC_BANK0_SNP_STRB"},
+ {112, "GDC_BANK0_SNP_WAIT"},
+ {113, "GDC_BANK0_MISS_INARB_STRB"},
+ {114, "GDC_BANK0_MISS_INARB_WAIT"},
+ {115, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD0"},
+ {116, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD1"},
+ {117, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD2"},
+ {118, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD3"},
+ {119, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR0"},
+ {120, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR1"},
+ {121, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR2"},
+ {122, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR3"},
+ {123, "GDC_BANK1_RD_REQ"},
+ {124, "GDC_BANK1_WR_REQ"},
+ {125, "GDC_BANK1_ALLOCATE"},
+ {126, "GDC_BANK1_HIT"},
+ {127, "GDC_BANK1_MISS"},
+ {128, "GDC_BANK1_INVALIDATE"},
+ {129, "GDC_BANK1_EVICT"},
+ {130, "GDC_BANK1_RD_RESP"},
+ {131, "GDC_BANK1_WR_ACK"},
+ {132, "GDC_BANK1_SNOOP"},
+ {133, "GDC_BANK1_SNOOP_NORMAL"},
+ {134, "GDC_BANK1_SNOOP_FWD"},
+ {135, "GDC_BANK1_SNOOP_STASH"},
+ {136, "GDC_BANK1_SNOOP_STASH_INDPND_RD"},
+ {137, "GDC_BANK1_FOLLOWER"},
+ {138, "GDC_BANK1_FW"},
+ {139, "GDC_BANK1_HIT_DCL_BOTH"},
+ {140, "GDC_BANK1_HIT_DCL_PARTIAL"},
+ {141, "GDC_BANK1_EVICT_DCL"},
+ {142, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA0"},
+ {143, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA1"},
+ {144, "GDC_BANK1_ARB_STRB"},
+ {145, "GDC_BANK1_ARB_WAIT"},
+ {146, "GDC_BANK1_GGA_STRB"},
+ {147, "GDC_BANK1_GGA_WAIT"},
+ {148, "GDC_BANK1_FW_STRB"},
+ {149, "GDC_BANK1_FW_WAIT"},
+ {150, "GDC_BANK1_SNP_STRB"},
+ {151, "GDC_BANK1_SNP_WAIT"},
+ {152, "GDC_BANK1_MISS_INARB_STRB"},
+ {153, "GDC_BANK1_MISS_INARB_WAIT"},
+ {154, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD0"},
+ {155, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD1"},
+ {156, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD2"},
+ {157, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD3"},
+ {158, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR0"},
+ {159, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR1"},
+ {160, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR2"},
+ {161, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR3"},
+ {162, "HISTOGRAM_HISTOGRAM_BIN0"},
+ {163, "HISTOGRAM_HISTOGRAM_BIN1"},
+ {164, "HISTOGRAM_HISTOGRAM_BIN2"},
+ {165, "HISTOGRAM_HISTOGRAM_BIN3"},
+ {166, "HISTOGRAM_HISTOGRAM_BIN4"},
+ {167, "HISTOGRAM_HISTOGRAM_BIN5"},
+ {168, "HISTOGRAM_HISTOGRAM_BIN6"},
+ {169, "HISTOGRAM_HISTOGRAM_BIN7"},
+ {170, "HISTOGRAM_HISTOGRAM_BIN8"},
+ {171, "HISTOGRAM_HISTOGRAM_BIN9"},
+};
+
+static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = {
+ {0, "GDC_MISS_MACHINE_RD_REQ"},
+ {1, "GDC_MISS_MACHINE_WR_REQ"},
+ {2, "GDC_MISS_MACHINE_SNP_REQ"},
+ {3, "GDC_MISS_MACHINE_EVICT_REQ"},
+ {4, "GDC_MISS_MACHINE_FW_REQ"},
+ {5, "GDC_MISS_MACHINE_RD_RESP"},
+ {6, "GDC_MISS_MACHINE_WR_RESP"},
+ {7, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP"},
+ {8, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP_TXDAT"},
+ {9, "GDC_MISS_MACHINE_CHI_TXREQ"},
+ {10, "GDC_MISS_MACHINE_CHI_RXRSP"},
+ {11, "GDC_MISS_MACHINE_CHI_TXDAT"},
+ {12, "GDC_MISS_MACHINE_CHI_RXDAT"},
+ {13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"},
+ {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "},
+ {15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"},
+ {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "},
+ {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "},
+ {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "},
+ {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "},
+ {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "},
+ {21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"},
+ {22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"},
+ {23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"},
+ {24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"},
+ {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "},
+ {26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"},
+ {27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"},
+ {28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"},
+ {29, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_0"},
+ {30, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_1"},
+ {31, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_2"},
+ {32, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_3"},
+ {33, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_4"},
+ {34, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_5"},
+ {35, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_6"},
+ {36, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_0"},
+ {37, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_1"},
+ {38, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_0"},
+ {39, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_1"},
+ {40, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_0"},
+ {41, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_1"},
+ {42, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_0"},
+ {43, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_1"},
+ {44, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_0"},
+ {45, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_1"},
+ {46, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_2"},
+ {47, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_3"},
+ {48, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_0"},
+ {49, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_1"},
+ {50, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_0"},
+ {51, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_1"},
+ {52, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_0"},
+ {53, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_1"},
+ {54, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_0"},
+ {55, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_1"},
+ {56, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_2"},
+ {57, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_3"},
+ {58, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_0"},
+ {59, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_1"},
+ {60, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_2"},
+ {61, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_3"},
+ {62, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_4"},
+ {63, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_5"},
+ {64, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_6"},
+ {65, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_7"},
+ {66, "HISTOGRAM_HISTOGRAM_BIN0"},
+ {67, "HISTOGRAM_HISTOGRAM_BIN1"},
+ {68, "HISTOGRAM_HISTOGRAM_BIN2"},
+ {69, "HISTOGRAM_HISTOGRAM_BIN3"},
+ {70, "HISTOGRAM_HISTOGRAM_BIN4"},
+ {71, "HISTOGRAM_HISTOGRAM_BIN5"},
+ {72, "HISTOGRAM_HISTOGRAM_BIN6"},
+ {73, "HISTOGRAM_HISTOGRAM_BIN7"},
+ {74, "HISTOGRAM_HISTOGRAM_BIN8"},
+ {75, "HISTOGRAM_HISTOGRAM_BIN9"},
+};
+
static struct mlxbf_pmc_context *pmc;
/* UUID used to probe ATF service. */
@@ -569,8 +999,21 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk,
break;
}
} else if (strstr(blk, "mss")) {
- events = mlxbf_pmc_mss_events;
- *size = ARRAY_SIZE(mlxbf_pmc_mss_events);
+ switch (pmc->event_set) {
+ case MLXBF_PMC_EVENT_SET_BF1:
+ case MLXBF_PMC_EVENT_SET_BF2:
+ events = mlxbf_pmc_mss_events_1;
+ *size = ARRAY_SIZE(mlxbf_pmc_mss_events_1);
+ break;
+ case MLXBF_PMC_EVENT_SET_BF3:
+ events = mlxbf_pmc_mss_events_3;
+ *size = ARRAY_SIZE(mlxbf_pmc_mss_events_3);
+ break;
+ default:
+ events = NULL;
+ *size = 0;
+ break;
+ }
} else if (strstr(blk, "ecc")) {
events = mlxbf_pmc_ecc_events;
*size = ARRAY_SIZE(mlxbf_pmc_ecc_events);
@@ -586,6 +1029,12 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk,
} else if (strstr(blk, "smmu")) {
events = mlxbf_pmc_smgen_events;
*size = ARRAY_SIZE(mlxbf_pmc_smgen_events);
+ } else if (strstr(blk, "llt_miss")) {
+ events = mlxbf_pmc_llt_miss_events;
+ *size = ARRAY_SIZE(mlxbf_pmc_llt_miss_events);
+ } else if (strstr(blk, "llt")) {
+ events = mlxbf_pmc_llt_events;
+ *size = ARRAY_SIZE(mlxbf_pmc_llt_events);
} else {
events = NULL;
*size = 0;
@@ -712,6 +1161,43 @@ static int mlxbf_pmc_program_l3_counter(int blk_num, uint32_t cnt_num,
return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr);
}
+/* Method to handle crspace counter programming */
+static int mlxbf_pmc_program_crspace_counter(int blk_num, uint32_t cnt_num,
+ uint32_t evt)
+{
+ uint32_t word;
+ void *addr;
+ int ret;
+
+ addr = pmc->block[blk_num].mmio_base +
+ ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
+ ret = mlxbf_pmc_readl(addr, &word);
+ if (ret)
+ return ret;
+
+ if (cnt_num % 2) {
+ word &= ~MLXBF_PMC_CRSPACE_PERFSEL1;
+ word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL1, evt);
+ } else {
+ word &= ~MLXBF_PMC_CRSPACE_PERFSEL0;
+ word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL0, evt);
+ }
+
+ return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, word);
+}
+
+/* Method to clear crspace counter value */
+static int mlxbf_pmc_clear_crspace_counter(int blk_num, uint32_t cnt_num)
+{
+ void *addr;
+
+ addr = pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
+ (cnt_num * 4);
+
+ return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, 0x0);
+}
+
/* Method to program a counter to monitor an event */
static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num,
uint32_t evt, bool is_l3)
@@ -724,6 +1210,10 @@ static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num,
if (is_l3)
return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt);
+ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
+ return mlxbf_pmc_program_crspace_counter(blk_num, cnt_num,
+ evt);
+
/* Configure the counter */
perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1);
perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0);
@@ -778,7 +1268,7 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num,
{
uint32_t perfcnt_low = 0, perfcnt_high = 0;
uint64_t value;
- int status = 0;
+ int status;
status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
MLXBF_PMC_L3C_PERF_CNT_LOW +
@@ -804,6 +1294,24 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num,
return 0;
}
+/* Method to handle crspace counter reads */
+static int mlxbf_pmc_read_crspace_counter(int blk_num, uint32_t cnt_num,
+ uint64_t *result)
+{
+ uint32_t value;
+ int status = 0;
+
+ status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
+ (cnt_num * 4), &value);
+ if (status)
+ return status;
+
+ *result = value;
+
+ return 0;
+}
+
/* Method to read the counter value */
static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3,
uint64_t *result)
@@ -818,6 +1326,9 @@ static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3,
if (is_l3)
return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result);
+ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
+ return mlxbf_pmc_read_crspace_counter(blk_num, cnt_num, result);
+
perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
perfval_offset = perfcfg_offset +
pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
@@ -893,6 +1404,30 @@ static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num,
return 0;
}
+/* Method to read crspace block event */
+static int mlxbf_pmc_read_crspace_event(int blk_num, uint32_t cnt_num,
+ uint64_t *result)
+{
+ uint32_t word, evt;
+ void *addr;
+ int ret;
+
+ addr = pmc->block[blk_num].mmio_base +
+ ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
+ ret = mlxbf_pmc_readl(addr, &word);
+ if (ret)
+ return ret;
+
+ if (cnt_num % 2)
+ evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL1, word);
+ else
+ evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL0, word);
+
+ *result = evt;
+
+ return 0;
+}
+
/* Method to find the event currently being monitored by a counter */
static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3,
uint64_t *result)
@@ -906,6 +1441,9 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3,
if (is_l3)
return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result);
+ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
+ return mlxbf_pmc_read_crspace_event(blk_num, cnt_num, result);
+
perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
perfval_offset = perfcfg_offset +
pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
@@ -982,7 +1520,8 @@ static ssize_t mlxbf_pmc_counter_show(struct device *dev,
if (strstr(pmc->block_name[blk_num], "l3cache"))
is_l3 = true;
- if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) {
+ if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
+ (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) {
if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value))
return -EINVAL;
} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) {
@@ -1040,6 +1579,10 @@ static ssize_t mlxbf_pmc_counter_store(struct device *dev,
err = mlxbf_pmc_write_reg(blk_num, offset, data);
if (err)
return err;
+ } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
+ if (sscanf(attr->attr.name, "counter%d", &cnt_num) != 1)
+ return -EINVAL;
+ err = mlxbf_pmc_clear_crspace_counter(blk_num, cnt_num);
} else
return -EINVAL;
@@ -1137,28 +1680,37 @@ static ssize_t mlxbf_pmc_event_list_show(struct device *dev,
return ret;
}
-/* Show function for "enable" sysfs files - only for l3cache */
+/* Show function for "enable" sysfs files - only for l3cache & crspace */
static ssize_t mlxbf_pmc_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mlxbf_pmc_attribute *attr_enable = container_of(
attr, struct mlxbf_pmc_attribute, dev_attr);
- uint32_t perfcnt_cfg;
+ uint32_t perfcnt_cfg, word;
int blk_num, value;
blk_num = attr_enable->nr;
- if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
- MLXBF_PMC_L3C_PERF_CNT_CFG,
- &perfcnt_cfg))
- return -EINVAL;
+ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
+ if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
+ &word))
+ return -EINVAL;
- value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg);
+ value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word);
+ } else {
+ if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_L3C_PERF_CNT_CFG,
+ &perfcnt_cfg))
+ return -EINVAL;
+
+ value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg);
+ }
return sysfs_emit(buf, "%d\n", value);
}
-/* Store function for "enable" sysfs files - only for l3cache */
+/* Store function for "enable" sysfs files - only for l3cache & crspace */
static ssize_t mlxbf_pmc_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1166,6 +1718,7 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev,
struct mlxbf_pmc_attribute *attr_enable = container_of(
attr, struct mlxbf_pmc_attribute, dev_attr);
int err, en, blk_num;
+ uint32_t word;
blk_num = attr_enable->nr;
@@ -1173,19 +1726,35 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev,
if (err < 0)
return err;
- if (!en) {
- err = mlxbf_pmc_config_l3_counters(blk_num, false, false);
+ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
+ err = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
+ &word);
if (err)
- return err;
- } else if (en == 1) {
- err = mlxbf_pmc_config_l3_counters(blk_num, false, true);
- if (err)
- return err;
- err = mlxbf_pmc_config_l3_counters(blk_num, true, false);
+ return -EINVAL;
+
+ word &= ~MLXBF_PMC_CRSPACE_PERFMON_EN;
+ word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_EN, en);
+ if (en)
+ word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_CLR, 1);
+
+ mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
+ MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
+ MLXBF_PMC_WRITE_REG_32, word);
+ } else {
+ if (en && en != 1)
+ return -EINVAL;
+
+ err = mlxbf_pmc_config_l3_counters(blk_num, false, !!en);
if (err)
return err;
- } else
- return -EINVAL;
+
+ if (en == 1) {
+ err = mlxbf_pmc_config_l3_counters(blk_num, true, false);
+ if (err)
+ return err;
+ }
+ }
return count;
}
@@ -1208,7 +1777,8 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, int blk_num)
attr = NULL;
/* "enable" sysfs to start/stop the counters. Only in L3C blocks */
- if (strstr(pmc->block_name[blk_num], "l3cache")) {
+ if (strstr(pmc->block_name[blk_num], "l3cache") ||
+ ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
attr = &pmc->block[blk_num].attr_enable;
attr->dev_attr.attr.mode = 0644;
attr->dev_attr.show = mlxbf_pmc_enable_show;
@@ -1307,7 +1877,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num)
int err;
/* Populate attributes based on counter type */
- if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER)
+ if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
+ (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))
err = mlxbf_pmc_init_perftype_counter(dev, blk_num);
else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER)
err = mlxbf_pmc_init_perftype_reg(dev, blk_num);
@@ -1323,7 +1894,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num)
dev, GFP_KERNEL, pmc->block_name[blk_num]);
if (!pmc->block[blk_num].block_attr_grp.name)
return -ENOMEM;
- pmc->groups[blk_num] = &pmc->block[blk_num].block_attr_grp;
+ pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp;
+ pmc->group_num++;
return 0;
}
@@ -1346,13 +1918,52 @@ static int mlxbf_pmc_map_counters(struct device *dev)
int i, tile_num, ret;
for (i = 0; i < pmc->total_blocks; ++i) {
- if (strstr(pmc->block_name[i], "tile")) {
+ /* Create sysfs for tiles only if block number < tile_count */
+ if (strstr(pmc->block_name[i], "tilenet")) {
+ if (sscanf(pmc->block_name[i], "tilenet%d", &tile_num) != 1)
+ continue;
+
+ if (tile_num >= pmc->tile_count)
+ continue;
+ } else if (strstr(pmc->block_name[i], "tile")) {
if (sscanf(pmc->block_name[i], "tile%d", &tile_num) != 1)
- return -EINVAL;
+ continue;
if (tile_num >= pmc->tile_count)
continue;
}
+
+ /* Create sysfs only for enabled MSS blocks */
+ if (strstr(pmc->block_name[i], "mss") &&
+ pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) {
+ int mss_num;
+
+ if (sscanf(pmc->block_name[i], "mss%d", &mss_num) != 1)
+ continue;
+
+ if (!((pmc->mss_enable >> mss_num) & 0x1))
+ continue;
+ }
+
+ /* Create sysfs only for enabled LLT blocks */
+ if (strstr(pmc->block_name[i], "llt_miss")) {
+ int llt_num;
+
+ if (sscanf(pmc->block_name[i], "llt_miss%d", &llt_num) != 1)
+ continue;
+
+ if (!((pmc->llt_enable >> llt_num) & 0x1))
+ continue;
+ } else if (strstr(pmc->block_name[i], "llt")) {
+ int llt_num;
+
+ if (sscanf(pmc->block_name[i], "llt%d", &llt_num) != 1)
+ continue;
+
+ if (!((pmc->llt_enable >> llt_num) & 0x1))
+ continue;
+ }
+
ret = device_property_read_u64_array(dev, pmc->block_name[i],
info, MLXBF_PMC_INFO_SZ);
if (ret)
@@ -1429,6 +2040,8 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
pmc->event_set = MLXBF_PMC_EVENT_SET_BF1;
else if (!strcmp(hid, "MLNXBFD1"))
pmc->event_set = MLXBF_PMC_EVENT_SET_BF2;
+ else if (!strcmp(hid, "MLNXBFD2"))
+ pmc->event_set = MLXBF_PMC_EVENT_SET_BF3;
else
return -ENODEV;
@@ -1442,11 +2055,19 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
if (ret != pmc->total_blocks)
return -EFAULT;
- ret = device_property_read_u32(dev, "tile_num", &pmc->tile_count);
- if (ret)
- return ret;
+ if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) {
+ if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) {
+ dev_err(dev, "Number of tiles/LLTs undefined\n");
+ return -EINVAL;
+ }
+ if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) {
+ dev_err(dev, "Number of tiles/MSSs undefined\n");
+ return -EINVAL;
+ }
+ }
pmc->pdev = pdev;
+ pmc->group_num = 0;
ret = mlxbf_pmc_map_counters(dev);
if (ret)
@@ -1463,6 +2084,7 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 },
{ "MLNXBFD1", 0 },
+ { "MLNXBFD2", 0 },
{}, };
MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids);
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
index ab7d7a1235..f39b7b9d2b 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -47,6 +47,9 @@
/* Message with data needs at least two words (for header & data). */
#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
+/* Tx timeout in milliseconds. */
+#define TMFIFO_TX_TIMEOUT 2000
+
/* ACPI UID for BlueField-3. */
#define TMFIFO_BF3_UID 1
@@ -62,12 +65,14 @@ struct mlxbf_tmfifo;
* @drop_desc: dummy desc for packet dropping
* @cur_len: processed length of the current descriptor
* @rem_len: remaining length of the pending packet
+ * @rem_padding: remaining bytes to send as paddings
* @pkt_len: total length of the pending packet
* @next_avail: next avail descriptor id
* @num: vring size (number of descriptors)
* @align: vring alignment size
* @index: vring index
* @vdev_id: vring virtio id (VIRTIO_ID_xxx)
+ * @tx_timeout: expire time of last tx packet
* @fifo: pointer to the tmfifo structure
*/
struct mlxbf_tmfifo_vring {
@@ -79,12 +84,14 @@ struct mlxbf_tmfifo_vring {
struct vring_desc drop_desc;
int cur_len;
int rem_len;
+ int rem_padding;
u32 pkt_len;
u16 next_avail;
int num;
int align;
int index;
int vdev_id;
+ unsigned long tx_timeout;
struct mlxbf_tmfifo *fifo;
};
@@ -819,6 +826,50 @@ mlxbf_tmfifo_desc_done:
return true;
}
+static void mlxbf_tmfifo_check_tx_timeout(struct mlxbf_tmfifo_vring *vring)
+{
+ unsigned long flags;
+
+ /* Only handle Tx timeout for network vdev. */
+ if (vring->vdev_id != VIRTIO_ID_NET)
+ return;
+
+ /* Initialize the timeout or return if not expired. */
+ if (!vring->tx_timeout) {
+ /* Initialize the timeout. */
+ vring->tx_timeout = jiffies +
+ msecs_to_jiffies(TMFIFO_TX_TIMEOUT);
+ return;
+ } else if (time_before(jiffies, vring->tx_timeout)) {
+ /* Return if not timeout yet. */
+ return;
+ }
+
+ /*
+ * Drop the packet after timeout. The outstanding packet is
+ * released and the remaining bytes will be sent with padding byte 0x00
+ * as a recovery. On the peer(host) side, the padding bytes 0x00 will be
+ * either dropped directly, or appended into existing outstanding packet
+ * thus dropped as corrupted network packet.
+ */
+ vring->rem_padding = round_up(vring->rem_len, sizeof(u64));
+ mlxbf_tmfifo_release_pkt(vring);
+ vring->cur_len = 0;
+ vring->rem_len = 0;
+ vring->fifo->vring[0] = NULL;
+
+ /*
+ * Make sure the load/store are in order before
+ * returning back to virtio.
+ */
+ virtio_mb(false);
+
+ /* Notify upper layer. */
+ spin_lock_irqsave(&vring->fifo->spin_lock[0], flags);
+ vring_interrupt(0, vring->vq);
+ spin_unlock_irqrestore(&vring->fifo->spin_lock[0], flags);
+}
+
/* Rx & Tx processing of a queue. */
static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
{
@@ -841,6 +892,7 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
return;
do {
+retry:
/* Get available FIFO space. */
if (avail == 0) {
if (is_rx)
@@ -851,6 +903,17 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
break;
}
+ /* Insert paddings for discarded Tx packet. */
+ if (!is_rx) {
+ vring->tx_timeout = 0;
+ while (vring->rem_padding >= sizeof(u64)) {
+ writeq(0, vring->fifo->tx.data);
+ vring->rem_padding -= sizeof(u64);
+ if (--avail == 0)
+ goto retry;
+ }
+ }
+
/* Console output always comes from the Tx buffer. */
if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
mlxbf_tmfifo_console_tx(fifo, avail);
@@ -860,6 +923,10 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
/* Handle one descriptor. */
more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
} while (more);
+
+ /* Check Tx timeout. */
+ if (avail <= 0 && !is_rx)
+ mlxbf_tmfifo_check_tx_timeout(vring);
}
/* Handle Rx or Tx queues. */
@@ -1364,13 +1431,11 @@ fail:
}
/* Device remove function. */
-static int mlxbf_tmfifo_remove(struct platform_device *pdev)
+static void mlxbf_tmfifo_remove(struct platform_device *pdev)
{
struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev);
mlxbf_tmfifo_cleanup(fifo);
-
- return 0;
}
static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = {
@@ -1381,7 +1446,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);
static struct platform_driver mlxbf_tmfifo_driver = {
.probe = mlxbf_tmfifo_probe,
- .remove = mlxbf_tmfifo_remove,
+ .remove_new = mlxbf_tmfifo_remove,
.driver = {
.name = "bf-tmfifo",
.acpi_match_table = mlxbf_tmfifo_acpi_match,
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index eb5ad35274..5c022b258f 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -786,15 +786,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
return 0;
}
-static int mlxreg_hotplug_remove(struct platform_device *pdev)
+static void mlxreg_hotplug_remove(struct platform_device *pdev)
{
struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
/* Clean interrupts setup. */
mlxreg_hotplug_unset_irq(priv);
devm_free_irq(&pdev->dev, priv->irq, priv);
-
- return 0;
}
static struct platform_driver mlxreg_hotplug_driver = {
@@ -802,7 +800,7 @@ static struct platform_driver mlxreg_hotplug_driver = {
.name = "mlxreg-hotplug",
},
.probe = mlxreg_hotplug_probe,
- .remove = mlxreg_hotplug_remove,
+ .remove_new = mlxreg_hotplug_remove,
};
module_platform_driver(mlxreg_hotplug_driver);
diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c
index 83ba037408..ee7bd623ba 100644
--- a/drivers/platform/mellanox/mlxreg-io.c
+++ b/drivers/platform/mellanox/mlxreg-io.c
@@ -263,13 +263,11 @@ static int mlxreg_io_probe(struct platform_device *pdev)
return 0;
}
-static int mlxreg_io_remove(struct platform_device *pdev)
+static void mlxreg_io_remove(struct platform_device *pdev)
{
struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev);
mutex_destroy(&priv->io_lock);
-
- return 0;
}
static struct platform_driver mlxreg_io_driver = {
@@ -277,7 +275,7 @@ static struct platform_driver mlxreg_io_driver = {
.name = "mlxreg-io",
},
.probe = mlxreg_io_probe,
- .remove = mlxreg_io_remove,
+ .remove_new = mlxreg_io_remove,
};
module_platform_driver(mlxreg_io_driver);
diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c
index 8d833836a6..43d119e3a4 100644
--- a/drivers/platform/mellanox/mlxreg-lc.c
+++ b/drivers/platform/mellanox/mlxreg-lc.c
@@ -907,7 +907,7 @@ i2c_get_adapter_fail:
return err;
}
-static int mlxreg_lc_remove(struct platform_device *pdev)
+static void mlxreg_lc_remove(struct platform_device *pdev)
{
struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev);
@@ -921,7 +921,7 @@ static int mlxreg_lc_remove(struct platform_device *pdev)
* is nothing to remove.
*/
if (!data->notifier || !data->notifier->handle)
- return 0;
+ return;
/* Clear event notification callback and handle. */
data->notifier->user_handler = NULL;
@@ -940,13 +940,11 @@ static int mlxreg_lc_remove(struct platform_device *pdev)
i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL;
}
-
- return 0;
}
static struct platform_driver mlxreg_lc_driver = {
.probe = mlxreg_lc_probe,
- .remove = mlxreg_lc_remove,
+ .remove_new = mlxreg_lc_remove,
.driver = {
.name = "mlxreg-lc",
},
diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c
index 75b699676c..3ef6555914 100644
--- a/drivers/platform/mellanox/nvsw-sn2201.c
+++ b/drivers/platform/mellanox/nvsw-sn2201.c
@@ -1217,7 +1217,7 @@ static int nvsw_sn2201_probe(struct platform_device *pdev)
return nvsw_sn2201_config_pre_init(nvsw_sn2201);
}
-static int nvsw_sn2201_remove(struct platform_device *pdev)
+static void nvsw_sn2201_remove(struct platform_device *pdev)
{
struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev);
@@ -1239,8 +1239,6 @@ static int nvsw_sn2201_remove(struct platform_device *pdev)
/* Unregister I2C controller. */
if (nvsw_sn2201->pdev_i2c)
platform_device_unregister(nvsw_sn2201->pdev_i2c);
-
- return 0;
}
static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = {
@@ -1252,7 +1250,7 @@ MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids);
static struct platform_driver nvsw_sn2201_driver = {
.probe = nvsw_sn2201_probe,
- .remove = nvsw_sn2201_remove,
+ .remove_new = nvsw_sn2201_remove,
.driver = {
.name = "nvsw-sn2201",
.acpi_match_table = nvsw_sn2201_acpi_ids,
diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c
index ca4602bcc7..c15ed7a127 100644
--- a/drivers/platform/surface/surface3-wmi.c
+++ b/drivers/platform/surface/surface3-wmi.c
@@ -226,14 +226,13 @@ static int __init s3_wmi_probe(struct platform_device *pdev)
return error;
}
-static int s3_wmi_remove(struct platform_device *device)
+static void s3_wmi_remove(struct platform_device *device)
{
/* remove the hotplug context from the acpi device */
s3_wmi.touchscreen_adev->hp = NULL;
/* reinstall the actual PNPC0C0D LID default handle */
acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
- return 0;
}
static int __maybe_unused s3_wmi_resume(struct device *dev)
@@ -248,7 +247,7 @@ static struct platform_driver s3_wmi_driver = {
.name = "surface3-wmi",
.pm = &s3_wmi_pm,
},
- .remove = s3_wmi_remove,
+ .remove_new = s3_wmi_remove,
};
static int __init s3_wmi_init(void)
diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
index 897cdd9c3a..e4dee920da 100644
--- a/drivers/platform/surface/surface_acpi_notify.c
+++ b/drivers/platform/surface/surface_acpi_notify.c
@@ -741,6 +741,7 @@ static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle)
struct acpi_handle_list dep_devices;
acpi_handle supplier = ACPI_HANDLE(&pdev->dev);
acpi_status status;
+ bool ret = false;
int i;
if (!acpi_has_method(handle, "_DEP"))
@@ -753,11 +754,14 @@ static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle)
}
for (i = 0; i < dep_devices.count; i++) {
- if (dep_devices.handles[i] == supplier)
- return true;
+ if (dep_devices.handles[i] == supplier) {
+ ret = true;
+ break;
+ }
}
- return false;
+ acpi_handle_list_free(&dep_devices);
+ return ret;
}
static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl,
@@ -850,7 +854,7 @@ err_enable_events:
return status;
}
-static int san_remove(struct platform_device *pdev)
+static void san_remove(struct platform_device *pdev)
{
acpi_handle san = ACPI_HANDLE(&pdev->dev);
@@ -864,8 +868,6 @@ static int san_remove(struct platform_device *pdev)
* all delayed works they may have spawned are run to completion.
*/
flush_workqueue(san_wq);
-
- return 0;
}
static const struct acpi_device_id san_match[] = {
@@ -876,7 +878,7 @@ MODULE_DEVICE_TABLE(acpi, san_match);
static struct platform_driver surface_acpi_notify = {
.probe = san_probe,
- .remove = san_remove,
+ .remove_new = san_remove,
.driver = {
.name = "surface_acpi_notify",
.acpi_match_table = san_match,
diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
index 07f0ed6583..07e065b915 100644
--- a/drivers/platform/surface/surface_aggregator_cdev.c
+++ b/drivers/platform/surface/surface_aggregator_cdev.c
@@ -714,7 +714,7 @@ static int ssam_dbg_device_probe(struct platform_device *pdev)
return 0;
}
-static int ssam_dbg_device_remove(struct platform_device *pdev)
+static void ssam_dbg_device_remove(struct platform_device *pdev)
{
struct ssam_cdev *cdev = platform_get_drvdata(pdev);
struct ssam_cdev_client *client;
@@ -757,14 +757,13 @@ static int ssam_dbg_device_remove(struct platform_device *pdev)
misc_deregister(&cdev->mdev);
ssam_cdev_put(cdev);
- return 0;
}
static struct platform_device *ssam_cdev_device;
static struct platform_driver ssam_cdev_driver = {
.probe = ssam_dbg_device_probe,
- .remove = ssam_dbg_device_remove,
+ .remove_new = ssam_dbg_device_remove,
.driver = {
.name = SSAM_CDEV_DEVICE_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index 0fe5be5396..aeb3feae40 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -418,19 +418,18 @@ static int ssam_platform_hub_probe(struct platform_device *pdev)
return status;
}
-static int ssam_platform_hub_remove(struct platform_device *pdev)
+static void ssam_platform_hub_remove(struct platform_device *pdev)
{
const struct software_node **nodes = platform_get_drvdata(pdev);
ssam_remove_clients(&pdev->dev);
set_secondary_fwnode(&pdev->dev, NULL);
software_node_unregister_node_group(nodes);
- return 0;
}
static struct platform_driver ssam_platform_hub_driver = {
.probe = ssam_platform_hub_probe,
- .remove = ssam_platform_hub_remove,
+ .remove_new = ssam_platform_hub_remove,
.driver = {
.name = "surface_aggregator_platform_hub",
.acpi_match_table = ssam_platform_hub_match,
diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
index 30cbde278c..2de843b7ea 100644
--- a/drivers/platform/surface/surface_dtx.c
+++ b/drivers/platform/surface/surface_dtx.c
@@ -1168,10 +1168,9 @@ static int surface_dtx_platform_probe(struct platform_device *pdev)
return 0;
}
-static int surface_dtx_platform_remove(struct platform_device *pdev)
+static void surface_dtx_platform_remove(struct platform_device *pdev)
{
sdtx_device_destroy(platform_get_drvdata(pdev));
- return 0;
}
static const struct acpi_device_id surface_dtx_acpi_match[] = {
@@ -1182,7 +1181,7 @@ MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match);
static struct platform_driver surface_dtx_platform_driver = {
.probe = surface_dtx_platform_probe,
- .remove = surface_dtx_platform_remove,
+ .remove_new = surface_dtx_platform_remove,
.driver = {
.name = "surface_dtx_pltf",
.acpi_match_table = surface_dtx_acpi_match,
diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c
index c219b840d4..62fd4004db 100644
--- a/drivers/platform/surface/surface_gpe.c
+++ b/drivers/platform/surface/surface_gpe.c
@@ -267,20 +267,18 @@ static int surface_gpe_probe(struct platform_device *pdev)
return ret;
}
-static int surface_gpe_remove(struct platform_device *pdev)
+static void surface_gpe_remove(struct platform_device *pdev)
{
struct surface_lid_device *lid = dev_get_drvdata(&pdev->dev);
/* restore default behavior without this module */
surface_lid_enable_wakeup(&pdev->dev, false);
acpi_disable_gpe(NULL, lid->gpe_number);
-
- return 0;
}
static struct platform_driver surface_gpe_driver = {
.probe = surface_gpe_probe,
- .remove = surface_gpe_remove,
+ .remove_new = surface_gpe_remove,
.driver = {
.name = "surface_gpe",
.pm = &surface_gpe_pm,
diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c
index 7b6d887dcc..a404f26cfa 100644
--- a/drivers/platform/surface/surface_hotplug.c
+++ b/drivers/platform/surface/surface_hotplug.c
@@ -183,7 +183,7 @@ static int shps_setup_irq(struct platform_device *pdev, enum shps_irq_type type)
return 0;
}
-static int surface_hotplug_remove(struct platform_device *pdev)
+static void surface_hotplug_remove(struct platform_device *pdev)
{
struct shps_device *sdev = platform_get_drvdata(pdev);
int i;
@@ -195,8 +195,6 @@ static int surface_hotplug_remove(struct platform_device *pdev)
mutex_destroy(&sdev->lock[i]);
}
-
- return 0;
}
static int surface_hotplug_probe(struct platform_device *pdev)
@@ -261,7 +259,7 @@ MODULE_DEVICE_TABLE(acpi, surface_hotplug_acpi_match);
static struct platform_driver surface_hotplug_driver = {
.probe = surface_hotplug_probe,
- .remove = surface_hotplug_remove,
+ .remove_new = surface_hotplug_remove,
.driver = {
.name = "surface_hotplug",
.acpi_match_table = surface_hotplug_acpi_match,
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 07eea52509..c94f31a5c6 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -988,6 +988,17 @@ config TOUCHSCREEN_DMI
the OS-image for the device. This option supplies the missing info.
Enable this for x86 tablets with Silead or Chipone touchscreens.
+config INSPUR_PLATFORM_PROFILE
+ tristate "Inspur WMI platform profile driver"
+ depends on ACPI_WMI
+ select ACPI_PLATFORM_PROFILE
+ help
+ This will allow users to determine and control the platform modes
+ between low-power, balanced and performance modes.
+
+ To compile this driver as a module, choose M here: the module
+ will be called inspur-platform-profile.
+
source "drivers/platform/x86/x86-android-tablets/Kconfig"
config FW_ATTR_CLASS
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index b457de5abf..c7a18e95ad 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
# before toshiba_acpi initializes
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
+# Inspur
+obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o
+
# Laptop drivers
obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 377a0becd1..0e472aa9bf 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1922,7 +1922,6 @@ static void acer_rfkill_exit(void)
rfkill_unregister(threeg_rfkill);
rfkill_destroy(threeg_rfkill);
}
- return;
}
static void acer_wmi_notify(u32 value, void *context)
@@ -2517,7 +2516,6 @@ static void __exit acer_wmi_exit(void)
platform_driver_unregister(&acer_platform_driver);
pr_info("Acer Laptop WMI Extras unloaded\n");
- return;
}
module_init(acer_wmi_init);
diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c
index 31382ef52e..b55d80e291 100644
--- a/drivers/platform/x86/amd/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp.c
@@ -20,7 +20,7 @@
#include <linux/semaphore.h>
#define DRIVER_NAME "amd_hsmp"
-#define DRIVER_VERSION "1.0"
+#define DRIVER_VERSION "2.0"
/* HSMP Status / Error codes */
#define HSMP_STATUS_NOT_READY 0x00
@@ -47,9 +47,29 @@
#define HSMP_INDEX_REG 0xc4
#define HSMP_DATA_REG 0xc8
-static struct semaphore *hsmp_sem;
+#define HSMP_CDEV_NAME "hsmp_cdev"
+#define HSMP_DEVNODE_NAME "hsmp"
+#define HSMP_METRICS_TABLE_NAME "metrics_bin"
-static struct miscdevice hsmp_device;
+#define HSMP_ATTR_GRP_NAME_SIZE 10
+
+struct hsmp_socket {
+ struct bin_attribute hsmp_attr;
+ void __iomem *metric_tbl_addr;
+ struct semaphore hsmp_sem;
+ char name[HSMP_ATTR_GRP_NAME_SIZE];
+ u16 sock_ind;
+};
+
+struct hsmp_plat_device {
+ struct miscdevice hsmp_device;
+ struct hsmp_socket *sock;
+ struct device *dev;
+ u32 proto_ver;
+ u16 num_sockets;
+};
+
+static struct hsmp_plat_device plat_dev;
static int amd_hsmp_rdwr(struct pci_dev *root, u32 address,
u32 *value, bool write)
@@ -188,6 +208,7 @@ static int validate_message(struct hsmp_message *msg)
int hsmp_send_message(struct hsmp_message *msg)
{
+ struct hsmp_socket *sock = &plat_dev.sock[msg->sock_ind];
struct amd_northbridge *nb;
int ret;
@@ -208,14 +229,13 @@ int hsmp_send_message(struct hsmp_message *msg)
* In SMP system timeout of 100 millisecs should
* be enough for the previous thread to finish the operation
*/
- ret = down_timeout(&hsmp_sem[msg->sock_ind],
- msecs_to_jiffies(HSMP_MSG_TIMEOUT));
+ ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT));
if (ret < 0)
return ret;
ret = __hsmp_send_message(nb->root, msg);
- up(&hsmp_sem[msg->sock_ind]);
+ up(&sock->hsmp_sem);
return ret;
}
@@ -317,32 +337,198 @@ static const struct file_operations hsmp_fops = {
.compat_ioctl = hsmp_ioctl,
};
+static ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct hsmp_socket *sock = bin_attr->private;
+ struct hsmp_message msg = { 0 };
+ int ret;
+
+ /* Do not support lseek(), reads entire metric table */
+ if (count < bin_attr->size) {
+ dev_err(plat_dev.dev, "Wrong buffer size\n");
+ return -EINVAL;
+ }
+
+ if (!sock) {
+ dev_err(plat_dev.dev, "Failed to read attribute private data\n");
+ return -EINVAL;
+ }
+
+ msg.msg_id = HSMP_GET_METRIC_TABLE;
+ msg.sock_ind = sock->sock_ind;
+
+ ret = hsmp_send_message(&msg);
+ if (ret)
+ return ret;
+ memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size);
+
+ return bin_attr->size;
+}
+
+static int hsmp_get_tbl_dram_base(u16 sock_ind)
+{
+ struct hsmp_socket *sock = &plat_dev.sock[sock_ind];
+ struct hsmp_message msg = { 0 };
+ phys_addr_t dram_addr;
+ int ret;
+
+ msg.sock_ind = sock_ind;
+ msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz;
+ msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR;
+
+ ret = hsmp_send_message(&msg);
+ if (ret)
+ return ret;
+
+ /*
+ * calculate the metric table DRAM address from lower and upper 32 bits
+ * sent from SMU and ioremap it to virtual address.
+ */
+ dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32);
+ if (!dram_addr) {
+ dev_err(plat_dev.dev, "Invalid DRAM address for metric table\n");
+ return -ENOMEM;
+ }
+ sock->metric_tbl_addr = devm_ioremap(plat_dev.dev, dram_addr,
+ sizeof(struct hsmp_metric_table));
+ if (!sock->metric_tbl_addr) {
+ dev_err(plat_dev.dev, "Failed to ioremap metric table addr\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
+ struct bin_attribute *battr, int id)
+{
+ if (plat_dev.proto_ver == HSMP_PROTO_VER6)
+ return battr->attr.mode;
+ else
+ return 0;
+}
+
+static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind)
+{
+ struct bin_attribute *hattr = &plat_dev.sock[sock_ind].hsmp_attr;
+
+ sysfs_bin_attr_init(hattr);
+ hattr->attr.name = HSMP_METRICS_TABLE_NAME;
+ hattr->attr.mode = 0444;
+ hattr->read = hsmp_metric_tbl_read;
+ hattr->size = sizeof(struct hsmp_metric_table);
+ hattr->private = &plat_dev.sock[sock_ind];
+ hattrs[0] = hattr;
+
+ if (plat_dev.proto_ver == HSMP_PROTO_VER6)
+ return (hsmp_get_tbl_dram_base(sock_ind));
+ else
+ return 0;
+}
+
+/* One bin sysfs for metrics table*/
+#define NUM_HSMP_ATTRS 1
+
+static int hsmp_create_sysfs_interface(void)
+{
+ const struct attribute_group **hsmp_attr_grps;
+ struct bin_attribute **hsmp_bin_attrs;
+ struct attribute_group *attr_grp;
+ int ret;
+ u16 i;
+
+ /* String formatting is currently limited to u8 sockets */
+ if (WARN_ON(plat_dev.num_sockets > U8_MAX))
+ return -ERANGE;
+
+ hsmp_attr_grps = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group *) *
+ (plat_dev.num_sockets + 1), GFP_KERNEL);
+ if (!hsmp_attr_grps)
+ return -ENOMEM;
+
+ /* Create a sysfs directory for each socket */
+ for (i = 0; i < plat_dev.num_sockets; i++) {
+ attr_grp = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group), GFP_KERNEL);
+ if (!attr_grp)
+ return -ENOMEM;
+
+ snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i);
+ attr_grp->name = plat_dev.sock[i].name;
+
+ /* Null terminated list of attributes */
+ hsmp_bin_attrs = devm_kzalloc(plat_dev.dev, sizeof(struct bin_attribute *) *
+ (NUM_HSMP_ATTRS + 1), GFP_KERNEL);
+ if (!hsmp_bin_attrs)
+ return -ENOMEM;
+
+ attr_grp->bin_attrs = hsmp_bin_attrs;
+ attr_grp->is_bin_visible = hsmp_is_sock_attr_visible;
+ hsmp_attr_grps[i] = attr_grp;
+
+ /* Now create the leaf nodes */
+ ret = hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, i);
+ if (ret)
+ return ret;
+ }
+ return devm_device_add_groups(plat_dev.dev, hsmp_attr_grps);
+}
+
+static int hsmp_cache_proto_ver(void)
+{
+ struct hsmp_message msg = { 0 };
+ int ret;
+
+ msg.msg_id = HSMP_GET_PROTO_VER;
+ msg.sock_ind = 0;
+ msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz;
+
+ ret = hsmp_send_message(&msg);
+ if (!ret)
+ plat_dev.proto_ver = msg.args[0];
+
+ return ret;
+}
+
static int hsmp_pltdrv_probe(struct platform_device *pdev)
{
- int i;
+ int ret, i;
- hsmp_sem = devm_kzalloc(&pdev->dev,
- (amd_nb_num() * sizeof(struct semaphore)),
- GFP_KERNEL);
- if (!hsmp_sem)
+ plat_dev.sock = devm_kzalloc(&pdev->dev,
+ (plat_dev.num_sockets * sizeof(struct hsmp_socket)),
+ GFP_KERNEL);
+ if (!plat_dev.sock)
return -ENOMEM;
+ plat_dev.dev = &pdev->dev;
+
+ for (i = 0; i < plat_dev.num_sockets; i++) {
+ sema_init(&plat_dev.sock[i].hsmp_sem, 1);
+ plat_dev.sock[i].sock_ind = i;
+ }
- for (i = 0; i < amd_nb_num(); i++)
- sema_init(&hsmp_sem[i], 1);
+ plat_dev.hsmp_device.name = HSMP_CDEV_NAME;
+ plat_dev.hsmp_device.minor = MISC_DYNAMIC_MINOR;
+ plat_dev.hsmp_device.fops = &hsmp_fops;
+ plat_dev.hsmp_device.parent = &pdev->dev;
+ plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME;
+ plat_dev.hsmp_device.mode = 0644;
+
+ ret = hsmp_cache_proto_ver();
+ if (ret) {
+ dev_err(plat_dev.dev, "Failed to read HSMP protocol version\n");
+ return ret;
+ }
- hsmp_device.name = "hsmp_cdev";
- hsmp_device.minor = MISC_DYNAMIC_MINOR;
- hsmp_device.fops = &hsmp_fops;
- hsmp_device.parent = &pdev->dev;
- hsmp_device.nodename = "hsmp";
- hsmp_device.mode = 0644;
+ ret = hsmp_create_sysfs_interface();
+ if (ret)
+ dev_err(plat_dev.dev, "Failed to create HSMP sysfs interface\n");
- return misc_register(&hsmp_device);
+ return misc_register(&plat_dev.hsmp_device);
}
static void hsmp_pltdrv_remove(struct platform_device *pdev)
{
- misc_deregister(&hsmp_device);
+ misc_deregister(&plat_dev.hsmp_device);
}
static struct platform_driver amd_hsmp_driver = {
@@ -358,7 +544,6 @@ static struct platform_device *amd_hsmp_platdev;
static int __init hsmp_plt_init(void)
{
int ret = -ENODEV;
- u16 num_sockets;
int i;
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x19) {
@@ -371,18 +556,18 @@ static int __init hsmp_plt_init(void)
* amd_nb_num() returns number of SMN/DF interfaces present in the system
* if we have N SMN/DF interfaces that ideally means N sockets
*/
- num_sockets = amd_nb_num();
- if (num_sockets == 0)
+ plat_dev.num_sockets = amd_nb_num();
+ if (plat_dev.num_sockets == 0)
return ret;
/* Test the hsmp interface on each socket */
- for (i = 0; i < num_sockets; i++) {
+ for (i = 0; i < plat_dev.num_sockets; i++) {
ret = hsmp_test(i, 0xDEADBEEF);
if (ret) {
- pr_err("HSMP is not supported on Fam:%x model:%x\n",
+ pr_err("HSMP test message failed on Fam:%x model:%x\n",
boot_cpu_data.x86, boot_cpu_data.x86_model);
- pr_err("Or Is HSMP disabled in BIOS ?\n");
- return -EOPNOTSUPP;
+ pr_err("Is HSMP disabled in BIOS ?\n");
+ return ret;
}
}
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
index 96caf2221d..864c8cc2f8 100644
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -52,9 +52,13 @@
#define AMD_S2D_REGISTER_ARGUMENT 0xA88
/* STB Spill to DRAM Parameters */
-#define S2D_TELEMETRY_BYTES_MAX 0x100000
+#define S2D_TELEMETRY_BYTES_MAX 0x100000U
+#define S2D_RSVD_RAM_SPACE 0x100000
#define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000
+/* STB Spill to DRAM Message Definition */
+#define STB_FORCE_FLUSH_DATA 0xCF
+
/* Base address of SMU for mapping physical address to virtual address */
#define AMD_PMC_MAPPING_SIZE 0x01000
#define AMD_PMC_BASE_ADDR_OFFSET 0x10000
@@ -109,6 +113,11 @@ enum s2d_arg {
S2D_DRAM_SIZE,
};
+struct amd_pmc_stb_v2_data {
+ size_t size;
+ u8 data[] __counted_by(size);
+};
+
struct amd_pmc_bit_map {
const char *name;
u32 bit_mask;
@@ -147,6 +156,10 @@ static bool disable_workarounds;
module_param(disable_workarounds, bool, 0644);
MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
+static bool dump_custom_stb;
+module_param(dump_custom_stb, bool, 0644);
+MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer");
+
static struct amd_pmc_dev pmc;
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf);
@@ -223,10 +236,30 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
.release = amd_pmc_stb_debugfs_release,
};
+/* Enhanced STB Firmware Reporting Mechanism */
+static int amd_pmc_stb_handle_efr(struct file *filp)
+{
+ struct amd_pmc_dev *dev = filp->f_inode->i_private;
+ struct amd_pmc_stb_v2_data *stb_data_arr;
+ u32 fsize;
+
+ fsize = dev->dram_size - S2D_RSVD_RAM_SPACE;
+ stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
+ if (!stb_data_arr)
+ return -ENOMEM;
+
+ stb_data_arr->size = fsize;
+ memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
+ filp->private_data = stb_data_arr;
+
+ return 0;
+}
+
static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
{
struct amd_pmc_dev *dev = filp->f_inode->i_private;
- u32 *buf, fsize, num_samples, stb_rdptr_offset = 0;
+ u32 fsize, num_samples, val, stb_rdptr_offset = 0;
+ struct amd_pmc_stb_v2_data *stb_data_arr;
int ret;
/* Write dummy postcode while reading the STB buffer */
@@ -234,34 +267,55 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
if (ret)
dev_err(dev->dev, "error writing to STB: %d\n", ret);
- buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
/* Spill to DRAM num_samples uses separate SMU message port */
dev->msg_port = 1;
+ ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1);
+ if (ret)
+ dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret);
+
+ /*
+ * We have a custom stb size and the PMFW is supposed to give
+ * the enhanced dram size. Note that we land here only for the
+ * platforms that support enhanced dram size reporting.
+ */
+ if (dump_custom_stb)
+ return amd_pmc_stb_handle_efr(filp);
+
/* Get the num_samples to calculate the last push location */
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true);
/* Clear msg_port for other SMU operation */
dev->msg_port = 0;
if (ret) {
dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
- kfree(buf);
return ret;
}
- /* Start capturing data from the last push location */
+ fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX);
+ stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
+ if (!stb_data_arr)
+ return -ENOMEM;
+
+ stb_data_arr->size = fsize;
+
+ /*
+ * Start capturing data from the last push location.
+ * This is for general cases, where the stb limits
+ * are meant for standard usage.
+ */
if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
- fsize = S2D_TELEMETRY_BYTES_MAX;
- stb_rdptr_offset = num_samples - fsize;
+ /* First read oldest data starting 1 behind last write till end of ringbuffer */
+ stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX;
+ fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset;
+
+ memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize);
+ /* Second copy the newer samples from offset 0 - last write */
+ memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset);
} else {
- fsize = num_samples;
- stb_rdptr_offset = 0;
+ memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
}
- memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
- filp->private_data = buf;
+ filp->private_data = stb_data_arr;
return 0;
}
@@ -269,11 +323,9 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size,
loff_t *pos)
{
- if (!filp->private_data)
- return -EINVAL;
+ struct amd_pmc_stb_v2_data *data = filp->private_data;
- return simple_read_from_buffer(buf, size, pos, filp->private_data,
- S2D_TELEMETRY_BYTES_MAX);
+ return simple_read_from_buffer(buf, size, pos, data->data, data->size);
}
static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp)
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index af3da303e2..fceffe2082 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -16,6 +16,8 @@
#include <linux/dmi.h>
#include <linux/i8042.h>
+#include <acpi/video.h>
+
#include "asus-wmi.h"
#define ASUS_NB_WMI_FILE "asus-nb-wmi"
@@ -46,25 +48,43 @@ module_param(tablet_mode_sw, uint, 0444);
MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog");
static struct quirk_entry *quirks;
+static bool atkbd_reports_vol_keys;
-static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str,
- struct serio *port)
+static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port)
{
- static bool extended;
- bool ret = false;
+ static bool extended_e0;
+ static bool extended_e1;
if (str & I8042_STR_AUXDATA)
return false;
- if (unlikely(data == 0xe1)) {
- extended = true;
- ret = true;
- } else if (unlikely(extended)) {
- extended = false;
- ret = true;
+ if (quirks->filter_i8042_e1_extended_codes) {
+ if (data == 0xe1) {
+ extended_e1 = true;
+ return true;
+ }
+
+ if (extended_e1) {
+ extended_e1 = false;
+ return true;
+ }
+ }
+
+ if (data == 0xe0) {
+ extended_e0 = true;
+ } else if (extended_e0) {
+ extended_e0 = false;
+
+ switch (data & 0x7f) {
+ case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
+ case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
+ case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
+ atkbd_reports_vol_keys = true;
+ break;
+ }
}
- return ret;
+ return false;
}
static struct quirk_entry quirk_asus_unknown = {
@@ -73,7 +93,7 @@ static struct quirk_entry quirk_asus_unknown = {
};
static struct quirk_entry quirk_asus_q500a = {
- .i8042_filter = asus_q500a_i8042_filter,
+ .filter_i8042_e1_extended_codes = true,
.wmi_backlight_set_devstate = true,
};
@@ -595,6 +615,26 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_END, 0},
};
+static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
+ unsigned int *value, bool *autorelease)
+{
+ switch (*code) {
+ case ASUS_WMI_BRN_DOWN:
+ case ASUS_WMI_BRN_UP:
+ if (acpi_video_handles_brightness_key_presses())
+ *code = ASUS_WMI_KEY_IGNORE;
+
+ break;
+ case 0x30: /* Volume Up */
+ case 0x31: /* Volume Down */
+ case 0x32: /* Volume Mute */
+ if (atkbd_reports_vol_keys)
+ *code = ASUS_WMI_KEY_IGNORE;
+
+ break;
+ }
+}
+
static struct asus_wmi_driver asus_nb_wmi_driver = {
.name = ASUS_NB_WMI_FILE,
.owner = THIS_MODULE,
@@ -603,6 +643,8 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
.input_name = "Asus WMI hotkeys",
.input_phys = ASUS_NB_WMI_FILE "/input0",
.detect_quirks = asus_nb_wmi_quirks,
+ .key_filter = asus_nb_wmi_key_filter,
+ .i8042_filter = asus_i8042_filter,
};
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index abf01e00b7..41227bf958 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -148,16 +148,12 @@ static int asus_wireless_add(struct acpi_device *adev)
if (err)
return err;
- for (id = device_ids; id->id[0]; id++) {
- if (!strcmp((char *) id->id, acpi_device_hid(adev))) {
- data->hswc_params =
- (const struct hswc_params *)id->driver_data;
- break;
- }
- }
- if (!data->hswc_params)
+ id = acpi_match_acpi_device(device_ids, adev);
+ if (!id)
return 0;
+ data->hswc_params = (const struct hswc_params *)id->driver_data;
+
data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
if (!data->wq)
return -ENOMEM;
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 9c6321c2fc..9f7e23c5c6 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/backlight.h>
#include <linux/debugfs.h>
+#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/fb.h>
#include <linux/hwmon.h>
@@ -25,6 +26,7 @@
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/leds.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
@@ -127,6 +129,15 @@ module_param(fnlock_default, bool, 0444);
#define NVIDIA_TEMP_MIN 75
#define NVIDIA_TEMP_MAX 87
+#define ASUS_SCREENPAD_BRIGHT_MIN 20
+#define ASUS_SCREENPAD_BRIGHT_MAX 255
+#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
+
+/* Controls the power state of the USB0 hub on ROG Ally which input is on */
+#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE"
+/* 300ms so far seems to produce a reliable result on AC and battery */
+#define ASUS_USB0_PWR_EC0_CSEE_WAIT 300
+
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
static int throttle_thermal_policy_write(struct asus_wmi *);
@@ -212,6 +223,7 @@ struct asus_wmi {
struct input_dev *inputdev;
struct backlight_device *backlight_device;
+ struct backlight_device *screenpad_backlight_device;
struct platform_device *platform_device;
struct led_classdev wlan_led;
@@ -294,6 +306,9 @@ struct asus_wmi {
bool fnlock_locked;
+ /* The ROG Ally device requires the MCU USB device be disconnected before suspend */
+ bool ally_mcu_usb_switch;
+
struct asus_wmi_debug debug;
struct asus_wmi_driver *driver;
@@ -3776,6 +3791,124 @@ static int is_display_toggle(int code)
return 0;
}
+/* Screenpad backlight *******************************************************/
+
+static int read_screenpad_backlight_power(struct asus_wmi *asus)
+{
+ int ret;
+
+ ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER);
+ if (ret < 0)
+ return ret;
+ /* 1 == powered */
+ return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+}
+
+static int read_screenpad_brightness(struct backlight_device *bd)
+{
+ struct asus_wmi *asus = bl_get_data(bd);
+ u32 retval;
+ int err;
+
+ err = read_screenpad_backlight_power(asus);
+ if (err < 0)
+ return err;
+ /* The device brightness can only be read if powered, so return stored */
+ if (err == FB_BLANK_POWERDOWN)
+ return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
+
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
+ if (err < 0)
+ return err;
+
+ return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN;
+}
+
+static int update_screenpad_bl_status(struct backlight_device *bd)
+{
+ struct asus_wmi *asus = bl_get_data(bd);
+ int power, err = 0;
+ u32 ctrl_param;
+
+ power = read_screenpad_backlight_power(asus);
+ if (power < 0)
+ return power;
+
+ if (bd->props.power != power) {
+ if (power != FB_BLANK_UNBLANK) {
+ /* Only brightness > 0 can power it back on */
+ ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
+ ctrl_param, NULL);
+ } else {
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
+ }
+ } else if (power == FB_BLANK_UNBLANK) {
+ /* Only set brightness if powered on or we get invalid/unsync state */
+ ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL);
+ }
+
+ /* Ensure brightness is stored to turn back on with */
+ if (err == 0)
+ asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
+
+ return err;
+}
+
+static const struct backlight_ops asus_screenpad_bl_ops = {
+ .get_brightness = read_screenpad_brightness,
+ .update_status = update_screenpad_bl_status,
+ .options = BL_CORE_SUSPENDRESUME,
+};
+
+static int asus_screenpad_init(struct asus_wmi *asus)
+{
+ struct backlight_device *bd;
+ struct backlight_properties props;
+ int err, power;
+ int brightness = 0;
+
+ power = read_screenpad_backlight_power(asus);
+ if (power < 0)
+ return power;
+
+ if (power != FB_BLANK_POWERDOWN) {
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
+ if (err < 0)
+ return err;
+ }
+ /* default to an acceptable min brightness on boot if too low */
+ if (brightness < ASUS_SCREENPAD_BRIGHT_MIN)
+ brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */
+ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN;
+ bd = backlight_device_register("asus_screenpad",
+ &asus->platform_device->dev, asus,
+ &asus_screenpad_bl_ops, &props);
+ if (IS_ERR(bd)) {
+ pr_err("Could not register backlight device\n");
+ return PTR_ERR(bd);
+ }
+
+ asus->screenpad_backlight_device = bd;
+ asus->driver->screenpad_brightness = brightness;
+ bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN;
+ bd->props.power = power;
+ backlight_update_status(bd);
+
+ return 0;
+}
+
+static void asus_screenpad_exit(struct asus_wmi *asus)
+{
+ backlight_device_unregister(asus->screenpad_backlight_device);
+
+ asus->screenpad_backlight_device = NULL;
+}
+
/* Fn-lock ********************************************************************/
static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
@@ -4364,6 +4497,8 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
+ asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
+ && dmi_match(DMI_BOARD_NAME, "RC71L");
err = fan_boost_mode_check_present(asus);
if (err)
@@ -4424,6 +4559,12 @@ static int asus_wmi_add(struct platform_device *pdev)
} else if (asus->driver->quirks->wmi_backlight_set_devstate)
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) {
+ err = asus_screenpad_init(asus);
+ if (err && err != -ENODEV)
+ goto fail_screenpad;
+ }
+
if (asus_wmi_has_fnlock_key(asus)) {
asus->fnlock_locked = fnlock_default;
asus_wmi_fnlock_update(asus);
@@ -4437,8 +4578,8 @@ static int asus_wmi_add(struct platform_device *pdev)
goto fail_wmi_handler;
}
- if (asus->driver->quirks->i8042_filter) {
- err = i8042_install_filter(asus->driver->quirks->i8042_filter);
+ if (asus->driver->i8042_filter) {
+ err = i8042_install_filter(asus->driver->i8042_filter);
if (err)
pr_warn("Unable to install key filter - %d\n", err);
}
@@ -4453,6 +4594,8 @@ fail_wmi_handler:
asus_wmi_backlight_exit(asus);
fail_backlight:
asus_wmi_rfkill_exit(asus);
+fail_screenpad:
+ asus_screenpad_exit(asus);
fail_rfkill:
asus_wmi_led_exit(asus);
fail_leds:
@@ -4477,10 +4620,11 @@ static int asus_wmi_remove(struct platform_device *device)
struct asus_wmi *asus;
asus = platform_get_drvdata(device);
- if (asus->driver->quirks->i8042_filter)
- i8042_remove_filter(asus->driver->quirks->i8042_filter);
+ if (asus->driver->i8042_filter)
+ i8042_remove_filter(asus->driver->i8042_filter);
wmi_remove_notify_handler(asus->driver->event_guid);
asus_wmi_backlight_exit(asus);
+ asus_screenpad_exit(asus);
asus_wmi_input_exit(asus);
asus_wmi_led_exit(asus);
asus_wmi_rfkill_exit(asus);
@@ -4529,6 +4673,43 @@ static int asus_hotk_resume(struct device *device)
asus_wmi_fnlock_update(asus);
asus_wmi_tablet_mode_get_state(asus);
+
+ return 0;
+}
+
+static int asus_hotk_resume_early(struct device *device)
+{
+ struct asus_wmi *asus = dev_get_drvdata(device);
+
+ if (asus->ally_mcu_usb_switch) {
+ if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB8)))
+ dev_err(device, "ROG Ally MCU failed to connect USB dev\n");
+ else
+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT);
+ }
+ return 0;
+}
+
+static int asus_hotk_prepare(struct device *device)
+{
+ struct asus_wmi *asus = dev_get_drvdata(device);
+ int result, err;
+
+ if (asus->ally_mcu_usb_switch) {
+ /* When powersave is enabled it causes many issues with resume of USB hub */
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE);
+ if (result == 1) {
+ dev_warn(device, "MCU powersave enabled, disabling to prevent resume issues");
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, 0, &result);
+ if (err || result != 1)
+ dev_err(device, "Failed to set MCU powersave mode: %d\n", err);
+ }
+ /* sleep required to ensure USB0 is disabled before sleep continues */
+ if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB7)))
+ dev_err(device, "ROG Ally MCU failed to disconnect USB dev\n");
+ else
+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT);
+ }
return 0;
}
@@ -4576,6 +4757,8 @@ static const struct dev_pm_ops asus_pm_ops = {
.thaw = asus_hotk_thaw,
.restore = asus_hotk_restore,
.resume = asus_hotk_resume,
+ .resume_early = asus_hotk_resume_early,
+ .prepare = asus_hotk_prepare,
};
/* Registration ***************************************************************/
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index fc41d1b1bb..cc30f18538 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -39,6 +39,7 @@ struct quirk_entry {
bool wmi_backlight_set_devstate;
bool wmi_force_als_set;
bool wmi_ignore_fan;
+ bool filter_i8042_e1_extended_codes;
enum asus_wmi_tablet_switch_mode tablet_switch_mode;
int wapf;
/*
@@ -49,14 +50,12 @@ struct quirk_entry {
*/
int no_display_toggle;
u32 xusb2pr;
-
- bool (*i8042_filter)(unsigned char data, unsigned char str,
- struct serio *serio);
};
struct asus_wmi_driver {
int brightness;
int panel_power;
+ int screenpad_brightness;
int wlan_ctrl_by_user;
const char *name;
@@ -72,6 +71,9 @@ struct asus_wmi_driver {
* Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
unsigned int *value, bool *autorelease);
+ /* Optional standard i8042 filter */
+ bool (*i8042_filter)(unsigned char data, unsigned char str,
+ struct serio *serio);
int (*probe) (struct platform_device *device);
void (*detect_quirks) (struct asus_wmi_driver *driver);
diff --git a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c
index dea54f35b8..4da99cb721 100644
--- a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c
+++ b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c
@@ -19,7 +19,7 @@ struct bios_args {
u32 command;
u32 commandtype;
u32 datasize;
- u8 data[];
+ u8 data[] __counted_by(datasize);
};
/**
diff --git a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
index 6ddca857cc..8c9f4f3227 100644
--- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
+++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
@@ -588,7 +588,6 @@ static void release_attributes_data(void)
static int hp_add_other_attributes(int attr_type)
{
struct kobject *attr_name_kobj;
- union acpi_object *obj = NULL;
int ret;
char *attr_name;
@@ -648,7 +647,6 @@ err_other_attr_init:
kobject_put(attr_name_kobj);
unlock_drv_mutex:
mutex_unlock(&bioscfg_drv.mutex);
- kfree(obj);
return ret;
}
diff --git a/drivers/platform/x86/inspur_platform_profile.c b/drivers/platform/x86/inspur_platform_profile.c
new file mode 100644
index 0000000000..743705bddd
--- /dev/null
+++ b/drivers/platform/x86/inspur_platform_profile.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Inspur WMI Platform Profile
+ *
+ * Copyright (C) 2018 Ai Chao <aichao@kylinos.cn>
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_profile.h>
+#include <linux/wmi.h>
+
+#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D"
+
+enum inspur_wmi_method_ids {
+ INSPUR_WMI_GET_POWERMODE = 0x02,
+ INSPUR_WMI_SET_POWERMODE = 0x03,
+};
+
+/*
+ * Power Mode:
+ * 0x0: Balance Mode
+ * 0x1: Performance Mode
+ * 0x2: Power Saver Mode
+ */
+enum inspur_tmp_profile {
+ INSPUR_TMP_PROFILE_BALANCE = 0,
+ INSPUR_TMP_PROFILE_PERFORMANCE = 1,
+ INSPUR_TMP_PROFILE_POWERSAVE = 2,
+};
+
+struct inspur_wmi_priv {
+ struct wmi_device *wdev;
+ struct platform_profile_handler handler;
+};
+
+static int inspur_wmi_perform_query(struct wmi_device *wdev,
+ enum inspur_wmi_method_ids query_id,
+ void *buffer, size_t insize,
+ size_t outsize)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer input = { insize, buffer};
+ union acpi_object *obj;
+ acpi_status status;
+ int ret = 0;
+
+ status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&wdev->dev, "EC Powermode control failed: %s\n",
+ acpi_format_exception(status));
+ return -EIO;
+ }
+
+ obj = output.pointer;
+ if (!obj)
+ return -EINVAL;
+
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length != outsize) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ memcpy(buffer, obj->buffer.pointer, obj->buffer.length);
+
+out_free:
+ kfree(obj);
+ return ret;
+}
+
+/*
+ * Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
+ * return error
+ * Method ID: 0x3
+ * Arg: 4 Bytes
+ * Byte [0]: Power Mode:
+ * 0x0: Balance Mode
+ * 0x1: Performance Mode
+ * 0x2: Power Saver Mode
+ * Return Value: 4 Bytes
+ * Byte [0]: Return Code
+ * 0x0: No Error
+ * 0x1: Error
+ */
+static int inspur_platform_profile_set(struct platform_profile_handler *pprof,
+ enum platform_profile_option profile)
+{
+ struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv,
+ handler);
+ u8 ret_code[4] = {0, 0, 0, 0};
+ int ret;
+
+ switch (profile) {
+ case PLATFORM_PROFILE_BALANCED:
+ ret_code[0] = INSPUR_TMP_PROFILE_BALANCE;
+ break;
+ case PLATFORM_PROFILE_PERFORMANCE:
+ ret_code[0] = INSPUR_TMP_PROFILE_PERFORMANCE;
+ break;
+ case PLATFORM_PROFILE_LOW_POWER:
+ ret_code[0] = INSPUR_TMP_PROFILE_POWERSAVE;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_SET_POWERMODE,
+ ret_code, sizeof(ret_code),
+ sizeof(ret_code));
+
+ if (ret < 0)
+ return ret;
+
+ if (ret_code[0])
+ return -EBADRQC;
+
+ return 0;
+}
+
+/*
+ * Get Power Mode from EC RAM, If Power Mode value greater than 0x3,
+ * return error
+ * Method ID: 0x2
+ * Return Value: 4 Bytes
+ * Byte [0]: Return Code
+ * 0x0: No Error
+ * 0x1: Error
+ * Byte [1]: Power Mode
+ * 0x0: Balance Mode
+ * 0x1: Performance Mode
+ * 0x2: Power Saver Mode
+ */
+static int inspur_platform_profile_get(struct platform_profile_handler *pprof,
+ enum platform_profile_option *profile)
+{
+ struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv,
+ handler);
+ u8 ret_code[4] = {0, 0, 0, 0};
+ int ret;
+
+ ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_GET_POWERMODE,
+ &ret_code, sizeof(ret_code),
+ sizeof(ret_code));
+ if (ret < 0)
+ return ret;
+
+ if (ret_code[0])
+ return -EBADRQC;
+
+ switch (ret_code[1]) {
+ case INSPUR_TMP_PROFILE_BALANCE:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case INSPUR_TMP_PROFILE_PERFORMANCE:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ case INSPUR_TMP_PROFILE_POWERSAVE:
+ *profile = PLATFORM_PROFILE_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int inspur_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct inspur_wmi_priv *priv;
+
+ priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->wdev = wdev;
+ dev_set_drvdata(&wdev->dev, priv);
+
+ priv->handler.profile_get = inspur_platform_profile_get;
+ priv->handler.profile_set = inspur_platform_profile_set;
+
+ set_bit(PLATFORM_PROFILE_LOW_POWER, priv->handler.choices);
+ set_bit(PLATFORM_PROFILE_BALANCED, priv->handler.choices);
+ set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->handler.choices);
+
+ return platform_profile_register(&priv->handler);
+}
+
+static void inspur_wmi_remove(struct wmi_device *wdev)
+{
+ platform_profile_remove();
+}
+
+static const struct wmi_device_id inspur_wmi_id_table[] = {
+ { .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID },
+ { }
+};
+
+MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table);
+
+static struct wmi_driver inspur_wmi_driver = {
+ .driver = {
+ .name = "inspur-wmi-platform-profile",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = inspur_wmi_id_table,
+ .probe = inspur_wmi_probe,
+ .remove = inspur_wmi_remove,
+};
+
+module_wmi_driver(inspur_wmi_driver);
+
+MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");
+MODULE_DESCRIPTION("Platform Profile Support for Inspur");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/bytcrc_pwrsrc.c b/drivers/platform/x86/intel/bytcrc_pwrsrc.c
index 8a022b90d1..418b71af27 100644
--- a/drivers/platform/x86/intel/bytcrc_pwrsrc.c
+++ b/drivers/platform/x86/intel/bytcrc_pwrsrc.c
@@ -158,17 +158,16 @@ static int crc_pwrsrc_probe(struct platform_device *pdev)
return 0;
}
-static int crc_pwrsrc_remove(struct platform_device *pdev)
+static void crc_pwrsrc_remove(struct platform_device *pdev)
{
struct crc_pwrsrc_data *data = platform_get_drvdata(pdev);
debugfs_remove_recursive(data->debug_dentry);
- return 0;
}
static struct platform_driver crc_pwrsrc_driver = {
.probe = crc_pwrsrc_probe,
- .remove = crc_pwrsrc_remove,
+ .remove_new = crc_pwrsrc_remove,
.driver = {
.name = "crystal_cove_pwrsrc",
},
diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
index 306f886b52..7b11198d85 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2022 Intel Corporation. */
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/semaphore.h>
@@ -10,13 +11,16 @@
#include "ifs.h"
-#define X86_MATCH(model) \
+#define X86_MATCH(model, array_gen) \
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
- INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL)
+ INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen)
static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
- X86_MATCH(SAPPHIRERAPIDS_X),
- X86_MATCH(EMERALDRAPIDS_X),
+ X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0),
+ X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0),
+ X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0),
+ X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0),
+ X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1),
{}
};
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
@@ -94,6 +98,9 @@ static int __init ifs_init(void)
for (i = 0; i < IFS_NUMTESTS; i++) {
if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit)))
continue;
+ ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK,
+ msrval);
+ ifs_devices[i].rw_data.array_gen = (u32)m->driver_data;
ret = misc_register(&ifs_devices[i].misc);
if (ret)
goto err_exit;
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 9319185589..56b9f3e3cf 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -137,6 +137,10 @@
#define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5
#define MSR_ACTIVATE_SCAN 0x000002c6
#define MSR_SCAN_STATUS 0x000002c7
+#define MSR_ARRAY_TRIGGER 0x000002d6
+#define MSR_ARRAY_STATUS 0x000002d7
+#define MSR_SAF_CTRL 0x000004f0
+
#define SCAN_NOT_TESTED 0
#define SCAN_TEST_PASS 1
#define SCAN_TEST_FAIL 2
@@ -144,6 +148,9 @@
#define IFS_TYPE_SAF 0
#define IFS_TYPE_ARRAY_BIST 1
+#define ARRAY_GEN0 0
+#define ARRAY_GEN1 1
+
/* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status {
u64 data;
@@ -158,6 +165,19 @@ union ifs_scan_hashes_status {
};
};
+union ifs_scan_hashes_status_gen2 {
+ u64 data;
+ struct {
+ u16 chunk_size;
+ u16 num_chunks;
+ u32 error_code :8;
+ u32 chunks_in_stride :9;
+ u32 rsvd :2;
+ u32 max_core_limit :12;
+ u32 valid :1;
+ };
+};
+
/* MSR_CHUNKS_AUTH_STATUS bit fields */
union ifs_chunks_auth_status {
u64 data;
@@ -170,13 +190,31 @@ union ifs_chunks_auth_status {
};
};
+union ifs_chunks_auth_status_gen2 {
+ u64 data;
+ struct {
+ u16 valid_chunks;
+ u16 total_chunks;
+ u32 error_code :8;
+ u32 rsvd2 :24;
+ };
+};
+
/* MSR_ACTIVATE_SCAN bit fields */
union ifs_scan {
u64 data;
struct {
- u32 start :8;
- u32 stop :8;
- u32 rsvd :16;
+ union {
+ struct {
+ u8 start;
+ u8 stop;
+ u16 rsvd;
+ } gen0;
+ struct {
+ u16 start;
+ u16 stop;
+ } gen2;
+ };
u32 delay :31;
u32 sigmce :1;
};
@@ -186,9 +224,17 @@ union ifs_scan {
union ifs_status {
u64 data;
struct {
- u32 chunk_num :8;
- u32 chunk_stop_index :8;
- u32 rsvd1 :16;
+ union {
+ struct {
+ u8 chunk_num;
+ u8 chunk_stop_index;
+ u16 rsvd1;
+ } gen0;
+ struct {
+ u16 chunk_num;
+ u16 chunk_stop_index;
+ } gen2;
+ };
u32 error_code :8;
u32 rsvd2 :22;
u32 control_error :1;
@@ -229,6 +275,9 @@ struct ifs_test_caps {
* @status: it holds simple status pass/fail/untested
* @scan_details: opaque scan status code from h/w
* @cur_batch: number indicating the currently loaded test file
+ * @generation: IFS test generation enumerated by hardware
+ * @chunk_size: size of a test chunk
+ * @array_gen: test generation of array test
*/
struct ifs_data {
int loaded_version;
@@ -238,6 +287,9 @@ struct ifs_data {
int status;
u64 scan_details;
u32 cur_batch;
+ u32 generation;
+ u32 chunk_size;
+ u32 array_gen;
};
struct ifs_work {
diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index cefd0d886c..2cf3b4a881 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2022 Intel Corporation. */
#include <linux/firmware.h>
+#include <linux/sizes.h>
#include <asm/cpu.h>
#include <asm/microcode.h>
@@ -26,6 +27,11 @@ union meta_data {
#define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel))
#define META_TYPE_IFS 1
+#define INVALIDATE_STRIDE 0x1UL
+#define IFS_GEN_STRIDE_AWARE 2
+#define AUTH_INTERRUPTED_ERROR 5
+#define IFS_AUTH_RETRY_CT 10
+
static struct microcode_header_intel *ifs_header_ptr; /* pointer to the ifs image header */
static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */
static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */
@@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = {
static const char * const scan_authentication_status[] = {
[0] = "No error reported",
[1] = "Attempt to authenticate a chunk which is already marked as authentic",
- [2] = "Chunk authentication error. The hash of chunk did not match expected value"
+ [2] = "Chunk authentication error. The hash of chunk did not match expected value",
+ [3] = "Reserved",
+ [4] = "Chunk outside the current stride",
+ [5] = "Authentication flow interrupted",
};
#define MC_HEADER_META_TYPE_END (0)
@@ -80,6 +89,23 @@ static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_typ
return NULL;
}
+static void hashcopy_err_message(struct device *dev, u32 err_code)
+{
+ if (err_code >= ARRAY_SIZE(scan_hash_status))
+ dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
+ else
+ dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]);
+}
+
+static void auth_err_message(struct device *dev, u32 err_code)
+{
+ if (err_code >= ARRAY_SIZE(scan_authentication_status))
+ dev_err(dev, "invalid error code 0x%x for authentication\n", err_code);
+ else
+ dev_err(dev, "Chunk authentication error : %s\n",
+ scan_authentication_status[err_code]);
+}
+
/*
* To copy scan hashes and authenticate test chunks, the initiating cpu must point
* to the EDX:EAX to the test image in linear address.
@@ -109,11 +135,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
if (!hashes_status.valid) {
ifsd->loading_error = true;
- if (err_code >= ARRAY_SIZE(scan_hash_status)) {
- dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
- goto done;
- }
- dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
+ hashcopy_err_message(dev, err_code);
goto done;
}
@@ -133,13 +155,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
if (err_code) {
ifsd->loading_error = true;
- if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
- dev_err(dev,
- "invalid error code 0x%x for authentication\n", err_code);
- goto done;
- }
- dev_err(dev, "Chunk authentication error %s\n",
- scan_authentication_status[err_code]);
+ auth_err_message(dev, err_code);
goto done;
}
}
@@ -147,6 +163,102 @@ done:
complete(&ifs_done);
}
+static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status)
+{
+ return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks;
+}
+
+static bool need_copy_scan_hashes(struct ifs_data *ifsd)
+{
+ return !ifsd->loaded ||
+ ifsd->generation < IFS_GEN_STRIDE_AWARE ||
+ ifsd->loaded_version != ifs_header_ptr->rev;
+}
+
+static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
+{
+ union ifs_scan_hashes_status_gen2 hashes_status;
+ union ifs_chunks_auth_status_gen2 chunk_status;
+ u32 err_code, valid_chunks, total_chunks;
+ int i, num_chunks, chunk_size;
+ union meta_data *ifs_meta;
+ int starting_chunk_nr;
+ struct ifs_data *ifsd;
+ u64 linear_addr, base;
+ u64 chunk_table[2];
+ int retry_count;
+
+ ifsd = ifs_get_data(dev);
+
+ if (need_copy_scan_hashes(ifsd)) {
+ wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
+ rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
+
+ /* enumerate the scan image information */
+ chunk_size = hashes_status.chunk_size * SZ_1K;
+ err_code = hashes_status.error_code;
+
+ num_chunks = get_num_chunks(ifsd->generation, hashes_status);
+
+ if (!hashes_status.valid) {
+ hashcopy_err_message(dev, err_code);
+ return -EIO;
+ }
+ ifsd->loaded_version = ifs_header_ptr->rev;
+ ifsd->chunk_size = chunk_size;
+ } else {
+ num_chunks = ifsd->valid_chunks;
+ chunk_size = ifsd->chunk_size;
+ }
+
+ if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
+ wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
+ rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
+ if (chunk_status.valid_chunks != 0) {
+ dev_err(dev, "Couldn't invalidate installed stride - %d\n",
+ chunk_status.valid_chunks);
+ return -EIO;
+ }
+ }
+
+ base = ifs_test_image_ptr;
+ ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
+ starting_chunk_nr = ifs_meta->starting_chunk;
+
+ /* scan data authentication and copy chunks to secured memory */
+ for (i = 0; i < num_chunks; i++) {
+ retry_count = IFS_AUTH_RETRY_CT;
+ linear_addr = base + i * chunk_size;
+
+ chunk_table[0] = starting_chunk_nr + i;
+ chunk_table[1] = linear_addr;
+ do {
+ wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
+ rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
+ err_code = chunk_status.error_code;
+ } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
+
+ if (err_code) {
+ ifsd->loading_error = true;
+ auth_err_message(dev, err_code);
+ return -EIO;
+ }
+ }
+
+ valid_chunks = chunk_status.valid_chunks;
+ total_chunks = chunk_status.total_chunks;
+
+ if (valid_chunks != total_chunks) {
+ ifsd->loading_error = true;
+ dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n",
+ valid_chunks, total_chunks);
+ return -EIO;
+ }
+ ifsd->valid_chunks = valid_chunks;
+
+ return 0;
+}
+
static int validate_ifs_metadata(struct device *dev)
{
struct ifs_data *ifsd = ifs_get_data(dev);
@@ -179,6 +291,13 @@ static int validate_ifs_metadata(struct device *dev)
return ret;
}
+ if (ifs_meta->chunks_per_stride &&
+ (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) {
+ dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n",
+ ifs_meta->starting_chunk, ifs_meta->chunks_per_stride);
+ return ret;
+ }
+
return 0;
}
@@ -199,7 +318,9 @@ static int scan_chunks_sanity_check(struct device *dev)
return ret;
ifsd->loading_error = false;
- ifsd->loaded_version = ifs_header_ptr->rev;
+
+ if (ifsd->generation > 0)
+ return copy_hashes_authenticate_chunks_gen2(dev);
/* copy the scan hash and authenticate per package */
cpus_read_lock();
@@ -219,6 +340,7 @@ static int scan_chunks_sanity_check(struct device *dev)
ifs_pkg_auth[curr_pkg] = 1;
}
ret = 0;
+ ifsd->loaded_version = ifs_header_ptr->rev;
out:
cpus_read_unlock();
@@ -227,7 +349,7 @@ out:
static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data)
{
- struct ucode_cpu_info uci;
+ struct cpu_signature sig;
/* Provide a specific error message when loading an older/unsupported image */
if (data->hdrver != MC_HEADER_TYPE_IFS) {
@@ -240,11 +362,9 @@ static int image_sanity_check(struct device *dev, const struct microcode_header_
return -EINVAL;
}
- intel_cpu_collect_info(&uci);
+ intel_collect_cpu_info(&sig);
- if (!intel_find_matching_signature((void *)data,
- uci.cpu_sig.sig,
- uci.cpu_sig.pf)) {
+ if (!intel_find_matching_signature((void *)data, &sig)) {
dev_err(dev, "cpu signature, processor flags not matching\n");
return -EINVAL;
}
@@ -260,6 +380,7 @@ int ifs_load_firmware(struct device *dev)
{
const struct ifs_test_caps *test = ifs_get_test_caps(dev);
struct ifs_data *ifsd = ifs_get_data(dev);
+ unsigned int expected_size;
const struct firmware *fw;
char scan_path[64];
int ret = -EINVAL;
@@ -274,6 +395,14 @@ int ifs_load_firmware(struct device *dev)
goto done;
}
+ expected_size = ((struct microcode_header_intel *)fw->data)->totalsize;
+ if (fw->size != expected_size) {
+ dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n",
+ expected_size, fw->size);
+ ret = -EINVAL;
+ goto release;
+ }
+
ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data);
if (ret)
goto release;
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index 43c864add7..13ecd55c66 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -40,6 +40,8 @@ enum ifs_status_err_code {
IFS_UNASSIGNED_ERROR_CODE = 7,
IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8,
IFS_INTERRUPTED_DURING_EXECUTION = 9,
+ IFS_UNASSIGNED_ERROR_CODE_0xA = 0xA,
+ IFS_CORRUPTED_CHUNK = 0xB,
};
static const char * const scan_test_status[] = {
@@ -55,6 +57,8 @@ static const char * const scan_test_status[] = {
[IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] =
"Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently",
[IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start",
+ [IFS_UNASSIGNED_ERROR_CODE_0xA] = "Unassigned error code 0xA",
+ [IFS_CORRUPTED_CHUNK] = "Scan operation aborted due to corrupted image. Try reloading",
};
static void message_not_tested(struct device *dev, int cpu, union ifs_status status)
@@ -123,6 +127,8 @@ static bool can_restart(union ifs_status status)
case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS:
case IFS_CORE_NOT_CAPABLE_CURRENTLY:
case IFS_UNASSIGNED_ERROR_CODE:
+ case IFS_UNASSIGNED_ERROR_CODE_0xA:
+ case IFS_CORRUPTED_CHUNK:
break;
}
return false;
@@ -171,21 +177,31 @@ static void ifs_test_core(int cpu, struct device *dev)
union ifs_status status;
unsigned long timeout;
struct ifs_data *ifsd;
+ int to_start, to_stop;
+ int status_chunk;
u64 msrvals[2];
int retries;
ifsd = ifs_get_data(dev);
- activate.rsvd = 0;
+ activate.gen0.rsvd = 0;
activate.delay = IFS_THREAD_WAIT;
activate.sigmce = 0;
- activate.start = 0;
- activate.stop = ifsd->valid_chunks - 1;
+ to_start = 0;
+ to_stop = ifsd->valid_chunks - 1;
+
+ if (ifsd->generation) {
+ activate.gen2.start = to_start;
+ activate.gen2.stop = to_stop;
+ } else {
+ activate.gen0.start = to_start;
+ activate.gen0.stop = to_stop;
+ }
timeout = jiffies + HZ / 2;
retries = MAX_IFS_RETRIES;
- while (activate.start <= activate.stop) {
+ while (to_start <= to_stop) {
if (time_after(jiffies, timeout)) {
status.error_code = IFS_SW_TIMEOUT;
break;
@@ -196,13 +212,14 @@ static void ifs_test_core(int cpu, struct device *dev)
status.data = msrvals[1];
- trace_ifs_status(cpu, activate, status);
+ trace_ifs_status(cpu, to_start, to_stop, status.data);
/* Some cases can be retried, give up for others */
if (!can_restart(status))
break;
- if (status.chunk_num == activate.start) {
+ status_chunk = ifsd->generation ? status.gen2.chunk_num : status.gen0.chunk_num;
+ if (status_chunk == to_start) {
/* Check for forward progress */
if (--retries == 0) {
if (status.error_code == IFS_NO_ERROR)
@@ -211,7 +228,11 @@ static void ifs_test_core(int cpu, struct device *dev)
}
} else {
retries = MAX_IFS_RETRIES;
- activate.start = status.chunk_num;
+ if (ifsd->generation)
+ activate.gen2.start = status_chunk;
+ else
+ activate.gen0.start = status_chunk;
+ to_start = status_chunk;
}
}
@@ -308,6 +329,38 @@ static void ifs_array_test_core(int cpu, struct device *dev)
ifsd->status = SCAN_TEST_PASS;
}
+#define ARRAY_GEN1_TEST_ALL_ARRAYS 0x0ULL
+#define ARRAY_GEN1_STATUS_FAIL 0x1ULL
+
+static int do_array_test_gen1(void *status)
+{
+ int cpu = smp_processor_id();
+ int first;
+
+ first = cpumask_first(cpu_smt_mask(cpu));
+
+ if (cpu == first) {
+ wrmsrl(MSR_ARRAY_TRIGGER, ARRAY_GEN1_TEST_ALL_ARRAYS);
+ rdmsrl(MSR_ARRAY_STATUS, *((u64 *)status));
+ }
+
+ return 0;
+}
+
+static void ifs_array_test_gen1(int cpu, struct device *dev)
+{
+ struct ifs_data *ifsd = ifs_get_data(dev);
+ u64 status = 0;
+
+ stop_core_cpuslocked(cpu, do_array_test_gen1, &status);
+ ifsd->scan_details = status;
+
+ if (status & ARRAY_GEN1_STATUS_FAIL)
+ ifsd->status = SCAN_TEST_FAIL;
+ else
+ ifsd->status = SCAN_TEST_PASS;
+}
+
/*
* Initiate per core test. It wakes up work queue threads on the target cpu and
* its sibling cpu. Once all sibling threads wake up, the scan test gets executed and
@@ -336,7 +389,10 @@ int do_core_test(int cpu, struct device *dev)
ifs_test_core(cpu, dev);
break;
case IFS_TYPE_ARRAY_BIST:
- ifs_array_test_core(cpu, dev);
+ if (ifsd->array_gen == ARRAY_GEN0)
+ ifs_array_test_core(cpu, dev);
+ else
+ ifs_array_test_gen1(cpu, dev);
break;
default:
ret = -EINVAL;
diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
index ef4b3141ef..16e36ac0a7 100644
--- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c
+++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
@@ -162,9 +162,8 @@ out_free_init_name:
}
int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio, u32 polarity)
+ struct gpio_desc *gpio)
{
- char *path = agpio->resource_source.string_ptr;
struct clk_init_data init = {
.ops = &skl_int3472_clock_ops,
.flags = CLK_GET_RATE_NOCACHE,
@@ -174,26 +173,12 @@ int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
if (int3472->clock.cl)
return -EBUSY;
- int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
- "int3472,clk-enable");
- if (IS_ERR(int3472->clock.ena_gpio)) {
- ret = PTR_ERR(int3472->clock.ena_gpio);
- int3472->clock.ena_gpio = NULL;
- return dev_err_probe(int3472->dev, ret, "getting clk-enable GPIO\n");
- }
-
- if (polarity == GPIO_ACTIVE_LOW)
- gpiod_toggle_active_low(int3472->clock.ena_gpio);
-
- /* Ensure the pin is in output mode and non-active state */
- gpiod_direction_output(int3472->clock.ena_gpio, 0);
+ int3472->clock.ena_gpio = gpio;
init.name = kasprintf(GFP_KERNEL, "%s-clk",
acpi_dev_name(int3472->adev));
- if (!init.name) {
- ret = -ENOMEM;
- goto out_put_gpio;
- }
+ if (!init.name)
+ return -ENOMEM;
int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
@@ -219,8 +204,6 @@ err_unregister_clk:
clk_unregister(int3472->clock.clk);
out_free_init_name:
kfree(init.name);
-out_put_gpio:
- gpiod_put(int3472->clock.ena_gpio);
return ret;
}
@@ -232,7 +215,6 @@ void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
clkdev_drop(int3472->clock.cl);
clk_unregister(int3472->clock.clk);
- gpiod_put(int3472->clock.ena_gpio);
}
/*
@@ -273,14 +255,13 @@ static const struct dmi_system_id skl_int3472_regulator_second_sensor[] = {
};
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio)
+ struct gpio_desc *gpio)
{
- char *path = agpio->resource_source.string_ptr;
struct regulator_init_data init_data = { };
struct regulator_config cfg = { };
const char *second_sensor = NULL;
const struct dmi_system_id *id;
- int i, j, ret;
+ int i, j;
id = dmi_first_match(skl_int3472_regulator_second_sensor);
if (id)
@@ -314,16 +295,7 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
int3472->regulator.supply_name,
&int3472_gpio_regulator_ops);
- int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
- "int3472,regulator");
- if (IS_ERR(int3472->regulator.gpio)) {
- ret = PTR_ERR(int3472->regulator.gpio);
- int3472->regulator.gpio = NULL;
- return dev_err_probe(int3472->dev, ret, "getting regulator GPIO\n");
- }
-
- /* Ensure the pin is in output mode and non-active state */
- gpiod_direction_output(int3472->regulator.gpio, 0);
+ int3472->regulator.gpio = gpio;
cfg.dev = &int3472->adev->dev;
cfg.init_data = &init_data;
@@ -332,21 +304,11 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
int3472->regulator.rdev = regulator_register(int3472->dev,
&int3472->regulator.rdesc,
&cfg);
- if (IS_ERR(int3472->regulator.rdev)) {
- ret = PTR_ERR(int3472->regulator.rdev);
- goto err_free_gpio;
- }
- return 0;
-
-err_free_gpio:
- gpiod_put(int3472->regulator.gpio);
-
- return ret;
+ return PTR_ERR_OR_ZERO(int3472->regulator.rdev);
}
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472)
{
regulator_unregister(int3472->regulator.rdev);
- gpiod_put(int3472->regulator.gpio);
}
diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h
index 9f29baa138..145dec66df 100644
--- a/drivers/platform/x86/intel/int3472/common.h
+++ b/drivers/platform/x86/intel/int3472/common.h
@@ -117,16 +117,15 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
const char **name_ret);
int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio, u32 polarity);
+ struct gpio_desc *gpio);
int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472);
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio);
+ struct gpio_desc *gpio);
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
-int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio, u32 polarity);
+int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio);
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
#endif
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index e33c2d7597..07b302e093 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -52,21 +52,15 @@ static void skl_int3472_log_sensor_module_name(struct int3472_discrete_device *i
}
}
-static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio,
- const char *func, u32 polarity)
+static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
+ struct acpi_resource_gpio *agpio,
+ const char *func, u32 polarity)
{
char *path = agpio->resource_source.string_ptr;
- struct gpiod_lookup *table_entry;
struct acpi_device *adev;
acpi_handle handle;
acpi_status status;
- if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
- dev_warn(int3472->dev, "Too many GPIOs mapped\n");
- return -EINVAL;
- }
-
status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status))
return -EINVAL;
@@ -75,18 +69,62 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
if (!adev)
return -ENODEV;
- table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
table_entry->key = acpi_dev_name(adev);
table_entry->chip_hwnum = agpio->pin_table[0];
table_entry->con_id = func;
table_entry->idx = 0;
table_entry->flags = polarity;
+ return 0;
+}
+
+static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio,
+ const char *func, u32 polarity)
+{
+ int ret;
+
+ if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
+ dev_warn(int3472->dev, "Too many GPIOs mapped\n");
+ return -EINVAL;
+ }
+
+ ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
+ agpio, func, polarity);
+ if (ret)
+ return ret;
+
int3472->n_sensor_gpios++;
return 0;
}
+/* This should *really* only be used when there's no other way... */
+static struct gpio_desc *
+skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio,
+ const char *func, u32 polarity)
+{
+ struct gpio_desc *desc;
+ int ret;
+
+ struct gpiod_lookup_table *lookup __free(kfree) =
+ kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
+ if (!lookup)
+ return ERR_PTR(-ENOMEM);
+
+ lookup->dev_id = dev_name(int3472->dev);
+ ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, polarity);
+ if (ret)
+ return ERR_PTR(ret);
+
+ gpiod_add_lookup_table(lookup);
+ desc = devm_gpiod_get(int3472->dev, func, GPIOD_OUT_LOW);
+ gpiod_remove_lookup_table(lookup);
+
+ return desc;
+}
+
static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
{
switch (type) {
@@ -156,6 +194,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
struct acpi_resource_gpio *agpio;
u8 active_value, pin, type;
union acpi_object *obj;
+ struct gpio_desc *gpio;
const char *err_msg;
const char *func;
u32 polarity;
@@ -206,22 +245,38 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
- ret = skl_int3472_register_gpio_clock(int3472, agpio, polarity);
- if (ret)
- err_msg = "Failed to register clock\n";
-
- break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
- ret = skl_int3472_register_pled(int3472, agpio, polarity);
- if (ret)
- err_msg = "Failed to register LED\n";
-
- break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
- ret = skl_int3472_register_regulator(int3472, agpio);
- if (ret)
- err_msg = "Failed to map regulator to sensor\n";
-
+ gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, polarity);
+ if (IS_ERR(gpio)) {
+ ret = PTR_ERR(gpio);
+ err_msg = "Failed to get GPIO\n";
+ break;
+ }
+
+ switch (type) {
+ case INT3472_GPIO_TYPE_CLK_ENABLE:
+ ret = skl_int3472_register_gpio_clock(int3472, gpio);
+ if (ret)
+ err_msg = "Failed to register clock\n";
+
+ break;
+ case INT3472_GPIO_TYPE_PRIVACY_LED:
+ ret = skl_int3472_register_pled(int3472, gpio);
+ if (ret)
+ err_msg = "Failed to register LED\n";
+
+ break;
+ case INT3472_GPIO_TYPE_POWER_ENABLE:
+ ret = skl_int3472_register_regulator(int3472, gpio);
+ if (ret)
+ err_msg = "Failed to map regulator to sensor\n";
+
+ break;
+ default: /* Never reached */
+ ret = -EINVAL;
+ break;
+ }
break;
default:
dev_warn(int3472->dev,
diff --git a/drivers/platform/x86/intel/int3472/led.c b/drivers/platform/x86/intel/int3472/led.c
index bca1ce7d0d..9cbed694e2 100644
--- a/drivers/platform/x86/intel/int3472/led.c
+++ b/drivers/platform/x86/intel/int3472/led.c
@@ -16,26 +16,15 @@ static int int3472_pled_set(struct led_classdev *led_cdev,
return 0;
}
-int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio, u32 polarity)
+int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio)
{
- char *p, *path = agpio->resource_source.string_ptr;
+ char *p;
int ret;
if (int3472->pled.classdev.dev)
return -EBUSY;
- int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
- "int3472,privacy-led");
- if (IS_ERR(int3472->pled.gpio))
- return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio),
- "getting privacy LED GPIO\n");
-
- if (polarity == GPIO_ACTIVE_LOW)
- gpiod_toggle_active_low(int3472->pled.gpio);
-
- /* Ensure the pin is in output mode and non-active state */
- gpiod_direction_output(int3472->pled.gpio, 0);
+ int3472->pled.gpio = gpio;
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
snprintf(int3472->pled.name, sizeof(int3472->pled.name),
@@ -50,7 +39,7 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
if (ret)
- goto err_free_gpio;
+ return ret;
int3472->pled.lookup.provider = int3472->pled.name;
int3472->pled.lookup.dev_id = int3472->sensor_name;
@@ -58,10 +47,6 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
led_add_lookup(&int3472->pled.lookup);
return 0;
-
-err_free_gpio:
- gpiod_put(int3472->pled.gpio);
- return ret;
}
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
@@ -71,5 +56,4 @@ void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
led_remove_lookup(&int3472->pled.lookup);
led_classdev_unregister(&int3472->pled.classdev);
- gpiod_put(int3472->pled.gpio);
}
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c
index ff49025ec0..3f4343147d 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c
@@ -18,16 +18,17 @@
struct isst_mmio_range {
int beg;
int end;
+ int size;
};
static struct isst_mmio_range mmio_range_devid_0[] = {
- {0x04, 0x14},
- {0x20, 0xD0},
+ {0x04, 0x14, 0x18},
+ {0x20, 0xD0, 0xD4},
};
static struct isst_mmio_range mmio_range_devid_1[] = {
- {0x04, 0x14},
- {0x20, 0x11C},
+ {0x04, 0x14, 0x18},
+ {0x20, 0x11C, 0x120},
};
struct isst_if_device {
@@ -93,6 +94,7 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct isst_if_device *punit_dev;
struct isst_if_cmd_cb cb;
u32 mmio_base, pcu_base;
+ struct resource r;
u64 base_addr;
int ret;
@@ -114,13 +116,16 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pcu_base &= GENMASK(10, 0);
base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12;
- punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, 256);
- if (!punit_dev->punit_mmio)
- return -ENOMEM;
+
+ punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data;
+
+ r = DEFINE_RES_MEM(base_addr, punit_dev->mmio_range[1].size);
+ punit_dev->punit_mmio = devm_ioremap_resource(&pdev->dev, &r);
+ if (IS_ERR(punit_dev->punit_mmio))
+ return PTR_ERR(punit_dev->punit_mmio);
mutex_init(&punit_dev->mutex);
pci_set_drvdata(pdev, punit_dev);
- punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data;
memset(&cb, 0, sizeof(cb));
cb.cmd_size = sizeof(struct isst_if_io_reg);
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
index 63faa2ea83..0b6d2c8644 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
@@ -30,7 +30,8 @@
#include "isst_if_common.h"
/* Supported SST hardware version by this driver */
-#define ISST_HEADER_VERSION 1
+#define ISST_MAJOR_VERSION 0
+#define ISST_MINOR_VERSION 1
/*
* Used to indicate if value read from MMIO needs to get multiplied
@@ -352,21 +353,25 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai
pd_info->sst_header.cp_offset *= 8;
pd_info->sst_header.pp_offset *= 8;
- if (pd_info->sst_header.interface_version != ISST_HEADER_VERSION) {
- dev_err(&auxdev->dev, "SST: Unsupported version:%x\n",
- pd_info->sst_header.interface_version);
+ if (pd_info->sst_header.interface_version == TPMI_VERSION_INVALID)
+ return -ENODEV;
+
+ if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) {
+ dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n",
+ TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version));
return -ENODEV;
}
+ if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION)
+ dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n",
+ TPMI_MINOR_VERSION(pd_info->sst_header.interface_version));
+
/* Read SST CP Header */
*((u64 *)&pd_info->cp_header) = readq(pd_info->sst_base + pd_info->sst_header.cp_offset);
/* Read PP header */
*((u64 *)&pd_info->pp_header) = readq(pd_info->sst_base + pd_info->sst_header.pp_offset);
- /* Force level_en_mask level 0 */
- pd_info->pp_header.level_en_mask |= 0x01;
-
mask = 0x01;
levels = 0;
for (i = 0; i < 8; ++i) {
@@ -704,7 +709,7 @@ static int isst_if_get_perf_level(void __user *argp)
return -EINVAL;
perf_level.max_level = power_domain_info->max_level;
- perf_level.level_mask = power_domain_info->pp_header.allowed_level_mask;
+ perf_level.level_mask = power_domain_info->pp_header.level_en_mask;
perf_level.feature_rev = power_domain_info->pp_header.feature_rev;
_read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET,
SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c
index 0a95736d97..311abcac89 100644
--- a/drivers/platform/x86/intel/tpmi.c
+++ b/drivers/platform/x86/intel/tpmi.c
@@ -143,6 +143,33 @@ struct tpmi_info_header {
u64 lock:1;
} __packed;
+/**
+ * struct tpmi_feature_state - Structure to read hardware state of a feature
+ * @enabled: Enable state of a feature, 1: enabled, 0: disabled
+ * @reserved_1: Reserved for future use
+ * @write_blocked: Writes are blocked means all write operations are ignored
+ * @read_blocked: Reads are blocked means will read 0xFFs
+ * @pcs_select: Interface used by out of band software, not used in OS
+ * @reserved_2: Reserved for future use
+ * @id: TPMI ID of the feature
+ * @reserved_3: Reserved for future use
+ * @locked: When set to 1, OS can't change this register.
+ *
+ * The structure is used to read hardware state of a TPMI feature. This
+ * information is used for debug and restricting operations for this feature.
+ */
+struct tpmi_feature_state {
+ u32 enabled:1;
+ u32 reserved_1:3;
+ u32 write_blocked:1;
+ u32 read_blocked:1;
+ u32 pcs_select:1;
+ u32 reserved_2:1;
+ u32 id:8;
+ u32 reserved_3:15;
+ u32 locked:1;
+} __packed;
+
/*
* List of supported TMPI IDs.
* Some TMPI IDs are not used by Linux, so the numbers are not consecutive.
@@ -202,6 +229,7 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
#define TPMI_CONTROL_STATUS_OFFSET 0x00
#define TPMI_COMMAND_OFFSET 0x08
+#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c
/*
* Spec is calling for max 1 seconds to get ownership at the worst
@@ -230,7 +258,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
/* TPMI command data registers */
#define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0)
-#define TMPI_CONTROL_DATA_VAL GENMASK_ULL(63, 32)
#define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40)
/* Command to send via control interface */
@@ -240,9 +267,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
#define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16)
-#define TPMI_STATE_DISABLED BIT_ULL(0)
-#define TPMI_STATE_LOCKED BIT_ULL(31)
-
/* Mutex to complete get feature status without interruption */
static DEFINE_MUTEX(tpmi_dev_lock);
@@ -256,7 +280,7 @@ static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner)
}
static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id,
- int *locked, int *disabled)
+ struct tpmi_feature_state *feature_state)
{
u64 control, data;
int ret;
@@ -306,17 +330,8 @@ static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int featu
}
/* Response is ready */
- data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET);
- data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data);
-
- *disabled = 0;
- *locked = 0;
-
- if (!(data & TPMI_STATE_DISABLED))
- *disabled = 1;
-
- if (data & TPMI_STATE_LOCKED)
- *locked = 1;
+ memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET,
+ sizeof(*feature_state));
ret = 0;
@@ -335,34 +350,50 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id,
{
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent);
struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev);
+ struct tpmi_feature_state feature_state;
+ int ret;
+
+ ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state);
+ if (ret)
+ return ret;
- return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled);
+ *locked = feature_state.locked;
+ *disabled = !feature_state.enabled;
+
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI);
static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused)
{
struct intel_tpmi_info *tpmi_info = s->private;
+ int locked, disabled, read_blocked, write_blocked;
+ struct tpmi_feature_state feature_state;
struct intel_tpmi_pm_feature *pfs;
- int locked, disabled, ret, i;
+ int ret, i;
+
seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start);
- seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\n");
+ seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n");
for (i = 0; i < tpmi_info->feature_count; ++i) {
pfs = &tpmi_info->tpmi_features[i];
- ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &locked,
- &disabled);
+ ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state);
if (ret) {
locked = 'U';
disabled = 'U';
+ read_blocked = 'U';
+ write_blocked = 'U';
} else {
- disabled = disabled ? 'Y' : 'N';
- locked = locked ? 'Y' : 'N';
+ disabled = feature_state.enabled ? 'N' : 'Y';
+ locked = feature_state.locked ? 'Y' : 'N';
+ read_blocked = feature_state.read_blocked ? 'Y' : 'N';
+ write_blocked = feature_state.write_blocked ? 'Y' : 'N';
}
- seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\n",
+ seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\t\t%c\t\t%c\n",
pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries,
pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset,
- pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled);
+ pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled,
+ read_blocked, write_blocked);
}
return 0;
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
index 7d0a67f8b5..4fb790552c 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
@@ -28,7 +28,8 @@
#include "uncore-frequency-common.h"
-#define UNCORE_HEADER_VERSION 1
+#define UNCORE_MAJOR_VERSION 0
+#define UNCORE_MINOR_VERSION 1
#define UNCORE_HEADER_INDEX 0
#define UNCORE_FABRIC_CLUSTER_OFFSET 8
@@ -302,12 +303,21 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
/* Check for version and skip this resource if there is mismatch */
header = readq(pd_info->uncore_base);
pd_info->ufs_header_ver = header & UNCORE_VERSION_MASK;
- if (pd_info->ufs_header_ver != UNCORE_HEADER_VERSION) {
- dev_info(&auxdev->dev, "Uncore: Unsupported version:%d\n",
- pd_info->ufs_header_ver);
+
+ if (pd_info->ufs_header_ver == TPMI_VERSION_INVALID)
continue;
+
+ if (TPMI_MAJOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MAJOR_VERSION) {
+ dev_err(&auxdev->dev, "Uncore: Unsupported major version:%lx\n",
+ TPMI_MAJOR_VERSION(pd_info->ufs_header_ver));
+ ret = -ENODEV;
+ goto remove_clusters;
}
+ if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MINOR_VERSION)
+ dev_info(&auxdev->dev, "Uncore: Ignore: Unsupported minor version:%lx\n",
+ TPMI_MINOR_VERSION(pd_info->ufs_header_ver));
+
/* Get Cluster ID Mask */
cluster_mask = FIELD_GET(UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK, header);
if (!cluster_mask) {
diff --git a/drivers/platform/x86/intel/vbtn.c b/drivers/platform/x86/intel/vbtn.c
index 210b0a81b7..084c355c86 100644
--- a/drivers/platform/x86/intel/vbtn.c
+++ b/drivers/platform/x86/intel/vbtn.c
@@ -200,9 +200,6 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE);
sparse_keymap_report_event(input_dev, event, val, autorelease);
-
- /* Some devices need this to report further events */
- acpi_evaluate_object(handle, "VBDL", NULL, NULL);
}
/*
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 4dfdbfca68..c66808601f 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -590,6 +590,8 @@ static void ips_disable_gpu_turbo(struct ips_driver *ips)
* @ips: IPS driver struct
*
* Check whether the MCP is over its thermal or power budget.
+ *
+ * Returns: %true if the temp or power has exceeded its maximum, else %false
*/
static bool mcp_exceeded(struct ips_driver *ips)
{
@@ -619,6 +621,8 @@ static bool mcp_exceeded(struct ips_driver *ips)
* @cpu: CPU number to check
*
* Check a given CPU's average temp or power is over its limit.
+ *
+ * Returns: %true if the temp or power has exceeded its maximum, else %false
*/
static bool cpu_exceeded(struct ips_driver *ips, int cpu)
{
@@ -645,6 +649,8 @@ static bool cpu_exceeded(struct ips_driver *ips, int cpu)
* @ips: IPS driver struct
*
* Check the MCH temp & power against their maximums.
+ *
+ * Returns: %true if the temp or power has exceeded its maximum, else %false
*/
static bool mch_exceeded(struct ips_driver *ips)
{
@@ -742,12 +748,13 @@ static void update_turbo_limits(struct ips_driver *ips)
* - down (at TDP limit)
* - adjust both CPU and GPU down if possible
*
- cpu+ gpu+ cpu+gpu- cpu-gpu+ cpu-gpu-
-cpu < gpu < cpu+gpu+ cpu+ gpu+ nothing
-cpu < gpu >= cpu+gpu-(mcp<) cpu+gpu-(mcp<) gpu- gpu-
-cpu >= gpu < cpu-gpu+(mcp<) cpu- cpu-gpu+(mcp<) cpu-
-cpu >= gpu >= cpu-gpu- cpu-gpu- cpu-gpu- cpu-gpu-
+ * |cpu+ gpu+ cpu+gpu- cpu-gpu+ cpu-gpu-
+ * cpu < gpu < |cpu+gpu+ cpu+ gpu+ nothing
+ * cpu < gpu >= |cpu+gpu-(mcp<) cpu+gpu-(mcp<) gpu- gpu-
+ * cpu >= gpu < |cpu-gpu+(mcp<) cpu- cpu-gpu+(mcp<) cpu-
+ * cpu >= gpu >=|cpu-gpu- cpu-gpu- cpu-gpu- cpu-gpu-
*
+ * Returns: %0
*/
static int ips_adjust(void *data)
{
@@ -935,11 +942,13 @@ static void monitor_timeout(struct timer_list *t)
* @data: ips driver structure
*
* This is the main function for the IPS driver. It monitors power and
- * tempurature in the MCP and adjusts CPU and GPU power clams accordingly.
+ * temperature in the MCP and adjusts CPU and GPU power clamps accordingly.
*
- * We keep a 5s moving average of power consumption and tempurature. Using
+ * We keep a 5s moving average of power consumption and temperature. Using
* that data, along with CPU vs GPU preference, we adjust the power clamps
* up or down.
+ *
+ * Returns: %0 on success or -errno on error
*/
static int ips_monitor(void *data)
{
@@ -1146,6 +1155,8 @@ static void dump_thermal_info(struct ips_driver *ips)
* Handle temperature limit trigger events, generally by lowering the clamps.
* If we're at a critical limit, we clamp back to the lowest possible value
* to prevent emergency shutdown.
+ *
+ * Returns: IRQ_NONE or IRQ_HANDLED
*/
static irqreturn_t ips_irq_handler(int irq, void *arg)
{
@@ -1293,9 +1304,12 @@ static void ips_debugfs_init(struct ips_driver *ips)
/**
* ips_detect_cpu - detect whether CPU supports IPS
+ * @ips: IPS driver struct
*
* Walk our list and see if we're on a supported CPU. If we find one,
* return the limits for it.
+ *
+ * Returns: the &ips_mcp_limits struct that matches the boot CPU or %NULL
*/
static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
{
@@ -1352,6 +1366,8 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
* monitor and control graphics turbo mode. If we can find them, we can
* enable graphics turbo, otherwise we must disable it to avoid exceeding
* thermal and power limits in the MCP.
+ *
+ * Returns: %true if the required symbols are found, else %false
*/
static bool ips_get_i915_syms(struct ips_driver *ips)
{
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index a2ffe4157d..32981e2ad3 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -368,7 +368,7 @@ struct mlxplat_priv {
};
static struct platform_device *mlxplat_dev;
-static int mlxplat_i2c_main_complition_notify(void *handle, int id);
+static int mlxplat_i2c_main_completion_notify(void *handle, int id);
static void __iomem *i2c_bridge_addr, *jtag_bridge_addr;
/* Regions for LPC I2C controller and LPC base register space */
@@ -384,7 +384,7 @@ static const struct resource mlxplat_lpc_resources[] = {
/* Platform systems default i2c data */
static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = {
- .completion_notify = mlxplat_i2c_main_complition_notify,
+ .completion_notify = mlxplat_i2c_main_completion_notify,
};
/* Platform i2c next generation systems data */
@@ -409,7 +409,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = {
.mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C,
- .completion_notify = mlxplat_i2c_main_complition_notify,
+ .completion_notify = mlxplat_i2c_main_completion_notify,
};
/* Platform default channels */
@@ -6291,7 +6291,7 @@ static void mlxplat_pci_fpga_devices_exit(void)
}
static int
-mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
+mlxplat_logicdev_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
{
int err;
@@ -6302,7 +6302,7 @@ mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_reso
return err;
}
-static void mlxplat_post_exit(void)
+static void mlxplat_logicdev_exit(void)
{
if (lpc_bridge)
mlxplat_pci_fpga_devices_exit();
@@ -6310,7 +6310,7 @@ static void mlxplat_post_exit(void)
mlxplat_lpc_cpld_device_exit();
}
-static int mlxplat_post_init(struct mlxplat_priv *priv)
+static int mlxplat_platdevs_init(struct mlxplat_priv *priv)
{
int i = 0, err;
@@ -6407,7 +6407,7 @@ fail_platform_hotplug_register:
return err;
}
-static void mlxplat_pre_exit(struct mlxplat_priv *priv)
+static void mlxplat_platdevs_exit(struct mlxplat_priv *priv)
{
int i;
@@ -6429,7 +6429,7 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent,
{
struct mlxplat_priv *priv = handle;
- return mlxplat_post_init(priv);
+ return mlxplat_platdevs_init(priv);
}
static int mlxplat_i2c_mux_topology_init(struct mlxplat_priv *priv)
@@ -6471,7 +6471,7 @@ static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv)
}
}
-static int mlxplat_i2c_main_complition_notify(void *handle, int id)
+static int mlxplat_i2c_main_completion_notify(void *handle, int id)
{
struct mlxplat_priv *priv = handle;
@@ -6522,7 +6522,7 @@ fail_mlxplat_mlxcpld_verify_bus_topology:
static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv)
{
- mlxplat_pre_exit(priv);
+ mlxplat_platdevs_exit(priv);
mlxplat_i2c_mux_topology_exit(priv);
if (priv->pdev_i2c)
platform_device_unregister(priv->pdev_i2c);
@@ -6544,7 +6544,7 @@ static int mlxplat_probe(struct platform_device *pdev)
mlxplat_dev = pdev;
}
- err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size);
+ err = mlxplat_logicdev_init(&hotplug_resources, &hotplug_resources_size);
if (err)
return err;
@@ -6603,12 +6603,12 @@ fail_regcache_sync:
fail_mlxplat_i2c_main_init:
fail_regmap_write:
fail_alloc:
- mlxplat_post_exit();
+ mlxplat_logicdev_exit();
return err;
}
-static int mlxplat_remove(struct platform_device *pdev)
+static void mlxplat_remove(struct platform_device *pdev)
{
struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
@@ -6617,8 +6617,7 @@ static int mlxplat_remove(struct platform_device *pdev)
if (mlxplat_reboot_nb)
unregister_reboot_notifier(mlxplat_reboot_nb);
mlxplat_i2c_main_exit(priv);
- mlxplat_post_exit();
- return 0;
+ mlxplat_logicdev_exit();
}
static const struct acpi_device_id mlxplat_acpi_table[] = {
@@ -6634,7 +6633,7 @@ static struct platform_driver mlxplat_driver = {
.probe_type = PROBE_FORCE_SYNCHRONOUS,
},
.probe = mlxplat_probe,
- .remove = mlxplat_remove,
+ .remove_new = mlxplat_remove,
};
static int __init mlxplat_init(void)
diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c
index 492eb383ee..f19504dbf1 100644
--- a/drivers/platform/x86/msi-ec.c
+++ b/drivers/platform/x86/msi-ec.c
@@ -58,7 +58,7 @@ static struct msi_ec_conf CONF0 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xbf,
.bit = 4,
},
@@ -138,7 +138,7 @@ static struct msi_ec_conf CONF1 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xbf,
.bit = 4,
},
@@ -215,7 +215,7 @@ static struct msi_ec_conf CONF2 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xe8,
.bit = 4,
},
@@ -293,7 +293,7 @@ static struct msi_ec_conf CONF3 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xe8,
.bit = 4,
},
@@ -371,7 +371,7 @@ static struct msi_ec_conf CONF4 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown
.bit = 4,
},
@@ -450,7 +450,7 @@ static struct msi_ec_conf CONF5 __initdata = {
.block_address = 0x2f,
.bit = 1,
},
- .fn_super_swap = { // todo: reverse
+ .fn_win_swap = { // todo: reverse
.address = 0xbf,
.bit = 4,
},
@@ -528,7 +528,7 @@ static struct msi_ec_conf CONF6 __initdata = {
.block_address = MSI_EC_ADDR_UNSUPP,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xbf, // todo: reverse
.bit = 4,
},
@@ -608,7 +608,7 @@ static struct msi_ec_conf CONF7 __initdata = {
.block_address = MSI_EC_ADDR_UNSUPP,
.bit = 1,
},
- .fn_super_swap = {
+ .fn_win_swap = {
.address = 0xbf, // needs testing
.bit = 4,
},
@@ -667,6 +667,467 @@ static struct msi_ec_conf CONF7 __initdata = {
},
};
+static const char * const ALLOWED_FW_8[] __initconst = {
+ "14F1EMS1.115",
+ NULL
+};
+
+static struct msi_ec_conf CONF8 __initdata = {
+ .allowed_fw = ALLOWED_FW_8,
+ .charge_control = {
+ .address = 0xd7,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = MSI_EC_ADDR_UNSUPP,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = 0xe8,
+ .bit = 4,
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xd2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 },
+ { SM_COMFORT_NAME, 0xc1 },
+ { SM_SPORT_NAME, 0xc0 },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = 0xeb,
+ .mask = 0x0f,
+ },
+ .fan_mode = {
+ .address = 0xd4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_BASIC_NAME, 0x4d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = 0x71,
+ .rt_fan_speed_base_min = 0x19,
+ .rt_fan_speed_base_max = 0x37,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ .bs_fan_speed_base_min = 0x00,
+ .bs_fan_speed_base_max = 0x0f,
+ },
+ .gpu = {
+ .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
+ .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
+ },
+ .leds = {
+ .micmute_led_address = MSI_EC_ADDR_UNSUPP,
+ .mute_led_address = 0x2d,
+ .bit = 1,
+ },
+ .kbd_bl = {
+ .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
+ .bl_modes = { 0x00, 0x08 }, // ?
+ .max_mode = 1, // ?
+ .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
+static const char * const ALLOWED_FW_9[] __initconst = {
+ "14JKEMS1.104",
+ NULL
+};
+
+static struct msi_ec_conf CONF9 __initdata = {
+ .allowed_fw = ALLOWED_FW_9,
+ .charge_control = {
+ .address = 0xef,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = 0x2f,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = 0xbf,
+ .bit = 4,
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xf2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 },
+ { SM_COMFORT_NAME, 0xc1 },
+ { SM_SPORT_NAME, 0xc0 },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift
+ .mask = 0x0f,
+ },
+ .fan_mode = {
+ .address = 0xf4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_ADVANCED_NAME, 0x8d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = 0x71,
+ .rt_fan_speed_base_min = 0x00,
+ .rt_fan_speed_base_max = 0x96,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ .bs_fan_speed_base_min = 0x00,
+ .bs_fan_speed_base_max = 0x0f,
+ },
+ .gpu = {
+ .rt_temp_address = MSI_EC_ADDR_UNSUPP,
+ .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ },
+ .leds = {
+ .micmute_led_address = 0x2b,
+ .mute_led_address = 0x2c,
+ .bit = 2,
+ },
+ .kbd_bl = {
+ .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app
+ .bl_modes = { 0x00, 0x08 },
+ .max_mode = 1,
+ .bl_state_address = 0xf3,
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
+static const char * const ALLOWED_FW_10[] __initconst = {
+ "1582EMS1.107", // GF66 11UC
+ NULL
+};
+
+static struct msi_ec_conf CONF10 __initdata = {
+ .allowed_fw = ALLOWED_FW_10,
+ .charge_control = {
+ .address = 0xd7,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = 0x2f,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = MSI_EC_ADDR_UNSUPP,
+ .bit = 4,
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xd2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 },
+ { SM_COMFORT_NAME, 0xc1 },
+ { SM_SPORT_NAME, 0xc0 },
+ { SM_TURBO_NAME, 0xc4 },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = 0xe5,
+ .mask = 0x0f,
+ },
+ .fan_mode = {
+ .address = 0xd4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_ADVANCED_NAME, 0x8d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = 0x71, // ?
+ .rt_fan_speed_base_min = 0x19,
+ .rt_fan_speed_base_max = 0x37,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ?
+ .bs_fan_speed_base_min = 0x00,
+ .bs_fan_speed_base_max = 0x0f,
+ },
+ .gpu = {
+ .rt_temp_address = 0x80,
+ .rt_fan_speed_address = 0x89,
+ },
+ .leds = {
+ .micmute_led_address = 0x2c,
+ .mute_led_address = 0x2d,
+ .bit = 1,
+ },
+ .kbd_bl = {
+ .bl_mode_address = 0x2c,
+ .bl_modes = { 0x00, 0x08 },
+ .max_mode = 1,
+ .bl_state_address = 0xd3,
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
+static const char * const ALLOWED_FW_11[] __initconst = {
+ "16S6EMS1.111", // Prestige 15 a11scx
+ "1552EMS1.115", // Modern 15 a11m
+ NULL
+};
+
+static struct msi_ec_conf CONF11 __initdata = {
+ .allowed_fw = ALLOWED_FW_11,
+ .charge_control = {
+ .address = 0xd7,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = MSI_EC_ADDR_UNKNOWN,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = 0xe8,
+ .bit = 4,
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xd2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 },
+ { SM_COMFORT_NAME, 0xc1 },
+ { SM_SPORT_NAME, 0xc0 },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = 0xeb,
+ .mask = 0x0f,
+ },
+ .fan_mode = {
+ .address = 0xd4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_ADVANCED_NAME, 0x4d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ },
+ .gpu = {
+ .rt_temp_address = MSI_EC_ADDR_UNSUPP,
+ .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ },
+ .leds = {
+ .micmute_led_address = 0x2c,
+ .mute_led_address = 0x2d,
+ .bit = 1,
+ },
+ .kbd_bl = {
+ .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
+ .bl_modes = {}, // ?
+ .max_mode = 1, // ?
+ .bl_state_address = 0xd3,
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
+static const char * const ALLOWED_FW_12[] __initconst = {
+ "16R6EMS1.104", // GF63 Thin 11UC
+ NULL
+};
+
+static struct msi_ec_conf CONF12 __initdata = {
+ .allowed_fw = ALLOWED_FW_12,
+ .charge_control = {
+ .address = 0xd7,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = 0x2f,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = 0xe8,
+ .bit = 4,
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xd2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 },
+ { SM_COMFORT_NAME, 0xc1 },
+ { SM_SPORT_NAME, 0xc0 },
+ { SM_TURBO_NAME, 0xc4 },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = MSI_EC_ADDR_UNSUPP, // 0xeb
+ .mask = 0x0f, // 00, 0f
+ },
+ .fan_mode = {
+ .address = 0xd4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_ADVANCED_NAME, 0x8d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = 0x71,
+ .rt_fan_speed_base_min = 0x19,
+ .rt_fan_speed_base_max = 0x37,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ .bs_fan_speed_base_min = 0x00,
+ .bs_fan_speed_base_max = 0x0f,
+ },
+ .gpu = {
+ .rt_temp_address = MSI_EC_ADDR_UNSUPP,
+ .rt_fan_speed_address = 0x89,
+ },
+ .leds = {
+ .micmute_led_address = MSI_EC_ADDR_UNSUPP,
+ .mute_led_address = 0x2d,
+ .bit = 1,
+ },
+ .kbd_bl = {
+ .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
+ .bl_modes = { 0x00, 0x08 },
+ .max_mode = 1,
+ .bl_state_address = 0xd3,
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
+static const char * const ALLOWED_FW_13[] __initconst = {
+ "1594EMS1.109", // MSI Prestige 16 Studio A13VE
+ NULL
+};
+
+static struct msi_ec_conf CONF13 __initdata = {
+ .allowed_fw = ALLOWED_FW_13,
+ .charge_control = {
+ .address = 0xd7,
+ .offset_start = 0x8a,
+ .offset_end = 0x80,
+ .range_min = 0x8a,
+ .range_max = 0xe4,
+ },
+ .webcam = {
+ .address = 0x2e,
+ .block_address = 0x2f,
+ .bit = 1,
+ },
+ .fn_win_swap = {
+ .address = 0xe8,
+ .bit = 4, // 0x00-0x10
+ },
+ .cooler_boost = {
+ .address = 0x98,
+ .bit = 7,
+ },
+ .shift_mode = {
+ .address = 0xd2,
+ .modes = {
+ { SM_ECO_NAME, 0xc2 }, // super battery
+ { SM_COMFORT_NAME, 0xc1 }, // balanced
+ { SM_TURBO_NAME, 0xc4 }, // extreme
+ MSI_EC_MODE_NULL
+ },
+ },
+ .super_battery = {
+ .address = MSI_EC_ADDR_UNSUPP,
+ .mask = 0x0f, // 00, 0f
+ },
+ .fan_mode = {
+ .address = 0xd4,
+ .modes = {
+ { FM_AUTO_NAME, 0x0d },
+ { FM_SILENT_NAME, 0x1d },
+ { FM_ADVANCED_NAME, 0x8d },
+ MSI_EC_MODE_NULL
+ },
+ },
+ .cpu = {
+ .rt_temp_address = 0x68,
+ .rt_fan_speed_address = 0x71, // 0x0-0x96
+ .rt_fan_speed_base_min = 0x00,
+ .rt_fan_speed_base_max = 0x96,
+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
+ .bs_fan_speed_base_min = 0x00,
+ .bs_fan_speed_base_max = 0x0f,
+ },
+ .gpu = {
+ .rt_temp_address = 0x80,
+ .rt_fan_speed_address = 0x89,
+ },
+ .leds = {
+ .micmute_led_address = 0x2c,
+ .mute_led_address = 0x2d,
+ .bit = 1,
+ },
+ .kbd_bl = {
+ .bl_mode_address = 0x2c, // KB auto turn off
+ .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec
+ .max_mode = 1,
+ .bl_state_address = 0xd3,
+ .state_base_value = 0x80,
+ .max_state = 3,
+ },
+};
+
static struct msi_ec_conf *CONFIGS[] __initdata = {
&CONF0,
&CONF1,
@@ -676,6 +1137,12 @@ static struct msi_ec_conf *CONFIGS[] __initdata = {
&CONF5,
&CONF6,
&CONF7,
+ &CONF8,
+ &CONF9,
+ &CONF10,
+ &CONF11,
+ &CONF12,
+ &CONF13,
NULL
};
diff --git a/drivers/platform/x86/msi-ec.h b/drivers/platform/x86/msi-ec.h
index be3533dc9c..0863512175 100644
--- a/drivers/platform/x86/msi-ec.h
+++ b/drivers/platform/x86/msi-ec.h
@@ -40,7 +40,7 @@ struct msi_ec_webcam_conf {
int bit;
};
-struct msi_ec_fn_super_swap_conf {
+struct msi_ec_fn_win_swap_conf {
int address;
int bit;
};
@@ -108,7 +108,7 @@ struct msi_ec_conf {
struct msi_ec_charge_control_conf charge_control;
struct msi_ec_webcam_conf webcam;
- struct msi_ec_fn_super_swap_conf fn_super_swap;
+ struct msi_ec_fn_win_swap_conf fn_win_swap;
struct msi_ec_cooler_boost_conf cooler_boost;
struct msi_ec_shift_mode_conf shift_mode;
struct msi_ec_super_battery_conf super_battery;
diff --git a/drivers/platform/x86/sel3350-platform.c b/drivers/platform/x86/sel3350-platform.c
index fa267d0d37..d09e976e71 100644
--- a/drivers/platform/x86/sel3350-platform.c
+++ b/drivers/platform/x86/sel3350-platform.c
@@ -218,15 +218,13 @@ err_platform:
return rs;
}
-static int sel3350_remove(struct platform_device *pdev)
+static void sel3350_remove(struct platform_device *pdev)
{
struct sel3350_data *sel3350 = platform_get_drvdata(pdev);
platform_device_unregister(sel3350->leds_pdev);
gpiod_remove_lookup_table(&sel3350_gpios_table);
gpiod_remove_lookup_table(&sel3350_leds_table);
-
- return 0;
}
static const struct acpi_device_id sel3350_device_ids[] = {
@@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(acpi, sel3350_device_ids);
static struct platform_driver sel3350_platform_driver = {
.probe = sel3350_probe,
- .remove = sel3350_remove,
+ .remove_new = sel3350_remove,
.driver = {
.name = "sel3350-platform",
.acpi_match_table = sel3350_device_ids,
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c
index 8a67979d8f..31a139d87d 100644
--- a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c
+++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c
@@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = {
},
};
-static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
+static void simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
{
- return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
+ simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
}
static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
@@ -37,7 +37,7 @@ static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
static struct platform_driver simatic_ipc_batt_driver = {
.probe = simatic_ipc_batt_apollolake_probe,
- .remove = simatic_ipc_batt_apollolake_remove,
+ .remove_new = simatic_ipc_batt_apollolake_remove,
.driver = {
.name = KBUILD_MODNAME,
},
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c
index 607d033911..a7676f2240 100644
--- a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c
+++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c
@@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = {
},
};
-static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
+static void simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
{
- return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
+ simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
}
static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
@@ -37,7 +37,7 @@ static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
static struct platform_driver simatic_ipc_batt_driver = {
.probe = simatic_ipc_batt_elkhartlake_probe,
- .remove = simatic_ipc_batt_elkhartlake_remove,
+ .remove_new = simatic_ipc_batt_elkhartlake_remove,
.driver = {
.name = KBUILD_MODNAME,
},
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c
index a66107e0fe..5e77e05fdb 100644
--- a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c
+++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c
@@ -45,9 +45,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_59a = {
}
};
-static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
+static void simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
{
- return simatic_ipc_batt_remove(pdev, batt_lookup_table);
+ simatic_ipc_batt_remove(pdev, batt_lookup_table);
}
static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
@@ -73,7 +73,7 @@ static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
static struct platform_driver simatic_ipc_batt_driver = {
.probe = simatic_ipc_batt_f7188x_probe,
- .remove = simatic_ipc_batt_f7188x_remove,
+ .remove_new = simatic_ipc_batt_f7188x_remove,
.driver = {
.name = KBUILD_MODNAME,
},
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c
index ef28c806b3..c6dd263b4e 100644
--- a/drivers/platform/x86/siemens/simatic-ipc-batt.c
+++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c
@@ -146,10 +146,9 @@ static const struct hwmon_chip_info simatic_ipc_batt_chip_info = {
.info = simatic_ipc_batt_info,
};
-int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
+void simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
{
gpiod_remove_lookup_table(table);
- return 0;
}
EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove);
@@ -228,9 +227,9 @@ out:
}
EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe);
-static int simatic_ipc_batt_io_remove(struct platform_device *pdev)
+static void simatic_ipc_batt_io_remove(struct platform_device *pdev)
{
- return simatic_ipc_batt_remove(pdev, NULL);
+ simatic_ipc_batt_remove(pdev, NULL);
}
static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
@@ -240,7 +239,7 @@ static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
static struct platform_driver simatic_ipc_batt_driver = {
.probe = simatic_ipc_batt_io_probe,
- .remove = simatic_ipc_batt_io_remove,
+ .remove_new = simatic_ipc_batt_io_remove,
.driver = {
.name = KBUILD_MODNAME,
},
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.h b/drivers/platform/x86/siemens/simatic-ipc-batt.h
index 4545cd3e30..89891db26a 100644
--- a/drivers/platform/x86/siemens/simatic-ipc-batt.h
+++ b/drivers/platform/x86/siemens/simatic-ipc-batt.h
@@ -14,7 +14,7 @@
int simatic_ipc_batt_probe(struct platform_device *pdev,
struct gpiod_lookup_table *table);
-int simatic_ipc_batt_remove(struct platform_device *pdev,
- struct gpiod_lookup_table *table);
+void simatic_ipc_batt_remove(struct platform_device *pdev,
+ struct gpiod_lookup_table *table);
#endif /* _SIMATIC_IPC_BATT_H */
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 9569f11dec..40878e327a 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -4092,7 +4092,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
if (ret > 0) {
struct inode *inode = file_inode(file);
- inode->i_atime = current_time(inode);
+ inode_set_atime_to_ts(inode, current_time(inode));
}
return ret;
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index aee8697698..ce3e08815a 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -15,7 +15,7 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mutex.h>
-#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/types.h>
#include <linux/dmi.h>
#include <linux/wmi.h>
@@ -198,14 +198,6 @@ static struct think_lmi tlmi_priv;
static struct class *fw_attr_class;
static DEFINE_MUTEX(tlmi_mutex);
-/* ------ Utility functions ------------*/
-/* Strip out CR if one is present */
-static void strip_cr(char *str)
-{
- char *p = strchrnul(str, '\n');
- *p = '\0';
-}
-
/* Convert BIOS WMI error string to suitable error code */
static int tlmi_errstr_to_err(const char *errstr)
{
@@ -411,7 +403,7 @@ static ssize_t current_password_store(struct kobject *kobj,
strscpy(setting->password, buf, setting->maxlen);
/* Strip out CR if one is present, setting password won't work if it is present */
- strip_cr(setting->password);
+ strreplace(setting->password, '\n', '\0');
return count;
}
@@ -432,13 +424,11 @@ static ssize_t new_password_store(struct kobject *kobj,
if (!tlmi_priv.can_set_bios_password)
return -EOPNOTSUPP;
- new_pwd = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present, setting password won't work if it is present */
+ new_pwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!new_pwd)
return -ENOMEM;
- /* Strip out CR if one is present, setting password won't work if it is present */
- strip_cr(new_pwd);
-
/* Use lock in case multiple WMI operations needed */
mutex_lock(&tlmi_mutex);
@@ -709,13 +699,11 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
if (!setting->signature || !setting->signature[0])
return -EACCES;
- passwd = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present */
+ passwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!passwd)
return -ENOMEM;
- /* Strip out CR if one is present */
- strip_cr(passwd);
-
/* Format: 'Password,Signature' */
auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
if (!auth_str) {
@@ -765,11 +753,10 @@ static ssize_t certificate_store(struct kobject *kobj,
return ret ?: count;
}
- new_cert = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present */
+ new_cert = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!new_cert)
return -ENOMEM;
- /* Strip out CR if one is present */
- strip_cr(new_cert);
if (setting->cert_installed) {
/* Certificate is installed so this is an update */
@@ -817,13 +804,11 @@ static ssize_t signature_store(struct kobject *kobj,
if (!tlmi_priv.certificate_support)
return -EOPNOTSUPP;
- new_signature = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present */
+ new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!new_signature)
return -ENOMEM;
- /* Strip out CR if one is present */
- strip_cr(new_signature);
-
/* Free any previous signature */
kfree(setting->signature);
setting->signature = new_signature;
@@ -846,13 +831,11 @@ static ssize_t save_signature_store(struct kobject *kobj,
if (!tlmi_priv.certificate_support)
return -EOPNOTSUPP;
- new_signature = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present */
+ new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!new_signature)
return -ENOMEM;
- /* Strip out CR if one is present */
- strip_cr(new_signature);
-
/* Free any previous signature */
kfree(setting->save_signature);
setting->save_signature = new_signature;
@@ -930,7 +913,7 @@ static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *at
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
- char *item, *value, *p;
+ char *item, *value;
int ret;
ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
@@ -943,8 +926,7 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
ret = -EINVAL;
else {
/* On Workstations remove the Options part after the value */
- p = strchrnul(value, ';');
- *p = '\0';
+ strreplace(value, ';', '\0');
ret = sysfs_emit(buf, "%s\n", value + 1);
}
kfree(item);
@@ -985,12 +967,17 @@ static ssize_t current_value_store(struct kobject *kobj,
if (!tlmi_priv.can_set_bios_settings)
return -EOPNOTSUPP;
- new_setting = kstrdup(buf, GFP_KERNEL);
- if (!new_setting)
- return -ENOMEM;
+ /*
+ * If we are using bulk saves a reboot should be done once save has
+ * been called
+ */
+ if (tlmi_priv.save_mode == TLMI_SAVE_BULK && tlmi_priv.reboot_required)
+ return -EPERM;
/* Strip out CR if one is present */
- strip_cr(new_setting);
+ new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
+ if (!new_setting)
+ return -ENOMEM;
/* Use lock in case multiple WMI operations needed */
mutex_lock(&tlmi_mutex);
@@ -1011,17 +998,27 @@ static ssize_t current_value_store(struct kobject *kobj,
ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str);
if (ret)
goto out;
- ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
- tlmi_priv.pwd_admin->save_signature);
- if (ret)
- goto out;
+ if (tlmi_priv.save_mode == TLMI_SAVE_BULK)
+ tlmi_priv.save_required = true;
+ else
+ ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
+ tlmi_priv.pwd_admin->save_signature);
} else if (tlmi_priv.opcode_support) {
/*
* If opcode support is present use that interface.
* Note - this sets the variable and then the password as separate
* WMI calls. Function tlmi_save_bios_settings will error if the
* password is incorrect.
+ * Workstation's require the opcode to be set before changing the
+ * attribute.
*/
+ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+ ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
+ tlmi_priv.pwd_admin->password);
+ if (ret)
+ goto out;
+ }
+
set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name,
new_setting);
if (!set_str) {
@@ -1033,14 +1030,10 @@ static ssize_t current_value_store(struct kobject *kobj,
if (ret)
goto out;
- if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
- ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
- tlmi_priv.pwd_admin->password);
- if (ret)
- goto out;
- }
-
- ret = tlmi_save_bios_settings("");
+ if (tlmi_priv.save_mode == TLMI_SAVE_BULK)
+ tlmi_priv.save_required = true;
+ else
+ ret = tlmi_save_bios_settings("");
} else { /* old non-opcode based authentication method (deprecated) */
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
@@ -1068,10 +1061,14 @@ static ssize_t current_value_store(struct kobject *kobj,
if (ret)
goto out;
- if (auth_str)
- ret = tlmi_save_bios_settings(auth_str);
- else
- ret = tlmi_save_bios_settings("");
+ if (tlmi_priv.save_mode == TLMI_SAVE_BULK) {
+ tlmi_priv.save_required = true;
+ } else {
+ if (auth_str)
+ ret = tlmi_save_bios_settings(auth_str);
+ else
+ ret = tlmi_save_bios_settings("");
+ }
}
if (!ret && !tlmi_priv.pending_changes) {
tlmi_priv.pending_changes = true;
@@ -1152,6 +1149,107 @@ static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *
static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+static const char * const save_mode_strings[] = {
+ [TLMI_SAVE_SINGLE] = "single",
+ [TLMI_SAVE_BULK] = "bulk",
+ [TLMI_SAVE_SAVE] = "save"
+};
+
+static ssize_t save_settings_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ /* Check that setting is valid */
+ if (WARN_ON(tlmi_priv.save_mode < TLMI_SAVE_SINGLE ||
+ tlmi_priv.save_mode > TLMI_SAVE_BULK))
+ return -EIO;
+ return sysfs_emit(buf, "%s\n", save_mode_strings[tlmi_priv.save_mode]);
+}
+
+static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *auth_str = NULL;
+ int ret = 0;
+ int cmd;
+
+ cmd = sysfs_match_string(save_mode_strings, buf);
+ if (cmd < 0)
+ return cmd;
+
+ /* Use lock in case multiple WMI operations needed */
+ mutex_lock(&tlmi_mutex);
+
+ switch (cmd) {
+ case TLMI_SAVE_SINGLE:
+ case TLMI_SAVE_BULK:
+ tlmi_priv.save_mode = cmd;
+ goto out;
+ case TLMI_SAVE_SAVE:
+ /* Check if supported*/
+ if (!tlmi_priv.can_set_bios_settings ||
+ tlmi_priv.save_mode == TLMI_SAVE_SINGLE) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ /* Check there is actually something to save */
+ if (!tlmi_priv.save_required) {
+ ret = -ENOENT;
+ goto out;
+ }
+ /* Check if certificate authentication is enabled and active */
+ if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) {
+ if (!tlmi_priv.pwd_admin->signature ||
+ !tlmi_priv.pwd_admin->save_signature) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
+ tlmi_priv.pwd_admin->save_signature);
+ if (ret)
+ goto out;
+ } else if (tlmi_priv.opcode_support) {
+ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+ ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
+ tlmi_priv.pwd_admin->password);
+ if (ret)
+ goto out;
+ }
+ ret = tlmi_save_bios_settings("");
+ } else { /* old non-opcode based authentication method (deprecated) */
+ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+ auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
+ tlmi_priv.pwd_admin->password,
+ encoding_options[tlmi_priv.pwd_admin->encoding],
+ tlmi_priv.pwd_admin->kbdlang);
+ if (!auth_str) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ if (auth_str)
+ ret = tlmi_save_bios_settings(auth_str);
+ else
+ ret = tlmi_save_bios_settings("");
+ }
+ tlmi_priv.save_required = false;
+ tlmi_priv.reboot_required = true;
+
+ if (!ret && !tlmi_priv.pending_changes) {
+ tlmi_priv.pending_changes = true;
+ /* let userland know it may need to check reboot pending again */
+ kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
+ }
+ break;
+ }
+out:
+ mutex_unlock(&tlmi_mutex);
+ kfree(auth_str);
+ return ret ?: count;
+}
+
+static struct kobj_attribute save_settings = __ATTR_RW(save_settings);
+
/* ---- Debug interface--------------------------------------------------------- */
static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
@@ -1163,13 +1261,11 @@ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr
if (!tlmi_priv.can_debug_cmd)
return -EOPNOTSUPP;
- new_setting = kstrdup(buf, GFP_KERNEL);
+ /* Strip out CR if one is present */
+ new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
if (!new_setting)
return -ENOMEM;
- /* Strip out CR if one is present */
- strip_cr(new_setting);
-
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
tlmi_priv.pwd_admin->password,
@@ -1221,6 +1317,8 @@ static void tlmi_release_attr(void)
}
}
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
+ sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr);
+
if (tlmi_priv.can_debug_cmd && debug_support)
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
@@ -1318,6 +1416,10 @@ static int tlmi_sysfs_init(void)
if (ret)
goto fail_create_attr;
+ ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr);
+ if (ret)
+ goto fail_create_attr;
+
if (tlmi_priv.can_debug_cmd && debug_support) {
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
if (ret)
@@ -1447,7 +1549,6 @@ static int tlmi_analyze(void)
for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
struct tlmi_attr_setting *setting;
char *item = NULL;
- char *p;
tlmi_priv.setting[i] = NULL;
ret = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID);
@@ -1464,8 +1565,7 @@ static int tlmi_analyze(void)
strreplace(item, '/', '\\');
/* Remove the value part */
- p = strchrnul(item, ',');
- *p = '\0';
+ strreplace(item, ',', '\0');
/* Create a setting entry */
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
index 4daba6151c..e1975ffebe 100644
--- a/drivers/platform/x86/think-lmi.h
+++ b/drivers/platform/x86/think-lmi.h
@@ -27,6 +27,19 @@ enum level_option {
TLMI_LEVEL_MASTER,
};
+/*
+ * There are a limit on the number of WMI operations you can do if you use
+ * the default implementation of saving on every set. This is due to a
+ * limitation in EFI variable space used.
+ * Have a 'bulk save' mode where you can manually trigger the save, and can
+ * therefore set unlimited variables - for users that need it.
+ */
+enum save_mode {
+ TLMI_SAVE_SINGLE,
+ TLMI_SAVE_BULK,
+ TLMI_SAVE_SAVE,
+};
+
/* password configuration details */
struct tlmi_pwdcfg_core {
uint32_t password_mode;
@@ -86,6 +99,9 @@ struct think_lmi {
bool can_debug_cmd;
bool opcode_support;
bool certificate_support;
+ enum save_mode save_mode;
+ bool save_required;
+ bool reboot_required;
struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT];
struct device *class_dev;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d73cbae4aa..5ecd9d3325 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -512,10 +512,10 @@ struct tpacpi_quirk {
* Iterates over a quirks list until one is found that matches the
* ThinkPad's vendor, BIOS and EC model.
*
- * Returns 0 if nothing matches, otherwise returns the quirks field of
+ * Returns: %0 if nothing matches, otherwise returns the quirks field of
* the matching &struct tpacpi_quirk entry.
*
- * The match criteria is: vendor, ec and bios much match.
+ * The match criteria is: vendor, ec and bios must match.
*/
static unsigned long __init tpacpi_check_quirks(
const struct tpacpi_quirk *qlist,
@@ -9375,7 +9375,7 @@ static struct tpacpi_battery_driver_data battery_info;
/* ACPI helpers/functions/probes */
-/**
+/*
* This evaluates a ACPI method call specific to the battery
* ACPI extension. The specifics are that an error is marked
* in the 32rd bit of the response, so we just check that here.
@@ -10308,6 +10308,7 @@ static int convert_dytc_to_profile(int funcmode, int dytcmode,
return 0;
default:
/* Unknown function */
+ pr_debug("unknown function 0x%x\n", funcmode);
return -EOPNOTSUPP;
}
return 0;
@@ -10493,8 +10494,8 @@ static void dytc_profile_refresh(void)
return;
perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
- convert_dytc_to_profile(funcmode, perfmode, &profile);
- if (profile != dytc_current_profile) {
+ err = convert_dytc_to_profile(funcmode, perfmode, &profile);
+ if (!err && profile != dytc_current_profile) {
dytc_current_profile = profile;
platform_profile_notify();
}
@@ -10860,6 +10861,89 @@ static struct ibm_struct dprc_driver_data = {
.name = "dprc",
};
+/*
+ * Auxmac
+ *
+ * This auxiliary mac address is enabled in the bios through the
+ * MAC Address Pass-through feature. In most cases, there are three
+ * possibilities: Internal Mac, Second Mac, and disabled.
+ *
+ */
+
+#define AUXMAC_LEN 12
+#define AUXMAC_START 9
+#define AUXMAC_STRLEN 22
+#define AUXMAC_BEGIN_MARKER 8
+#define AUXMAC_END_MARKER 21
+
+static char auxmac[AUXMAC_LEN + 1];
+
+static int auxmac_init(struct ibm_init_struct *iibm)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+
+ status = acpi_evaluate_object(NULL, "\\MACA", NULL, &buffer);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ obj = buffer.pointer;
+
+ if (obj->type != ACPI_TYPE_STRING || obj->string.length != AUXMAC_STRLEN) {
+ pr_info("Invalid buffer for MAC address pass-through.\n");
+ goto auxmacinvalid;
+ }
+
+ if (obj->string.pointer[AUXMAC_BEGIN_MARKER] != '#' ||
+ obj->string.pointer[AUXMAC_END_MARKER] != '#') {
+ pr_info("Invalid header for MAC address pass-through.\n");
+ goto auxmacinvalid;
+ }
+
+ if (strncmp(obj->string.pointer + AUXMAC_START, "XXXXXXXXXXXX", AUXMAC_LEN) != 0)
+ strscpy(auxmac, obj->string.pointer + AUXMAC_START, sizeof(auxmac));
+ else
+ strscpy(auxmac, "disabled", sizeof(auxmac));
+
+free:
+ kfree(obj);
+ return 0;
+
+auxmacinvalid:
+ strscpy(auxmac, "unavailable", sizeof(auxmac));
+ goto free;
+}
+
+static struct ibm_struct auxmac_data = {
+ .name = "auxmac",
+};
+
+static ssize_t auxmac_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", auxmac);
+}
+static DEVICE_ATTR_RO(auxmac);
+
+static umode_t auxmac_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ return auxmac[0] == 0 ? 0 : attr->mode;
+}
+
+static struct attribute *auxmac_attributes[] = {
+ &dev_attr_auxmac.attr,
+ NULL
+};
+
+static const struct attribute_group auxmac_attr_group = {
+ .is_visible = auxmac_attr_is_visible,
+ .attrs = auxmac_attributes,
+};
+
/* --------------------------------------------------------------------- */
static struct attribute *tpacpi_driver_attributes[] = {
@@ -10918,6 +11002,7 @@ static const struct attribute_group *tpacpi_groups[] = {
&proxsensor_attr_group,
&kbdlang_attr_group,
&dprc_attr_group,
+ &auxmac_attr_group,
NULL,
};
@@ -11217,6 +11302,8 @@ invalid:
return '\0';
}
+#define EC_FW_STRING_LEN 18
+
static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
{
char *ec_fw_string = (char *) private;
@@ -11245,7 +11332,8 @@ static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
return;
/* fwstr is the first 8byte string */
- strncpy(ec_fw_string, dmi_data + 0x0F, 8);
+ BUILD_BUG_ON(EC_FW_STRING_LEN <= 8);
+ memcpy(ec_fw_string, dmi_data + 0x0F, 8);
}
/* returns 0 - probe ok, or < 0 - probe error.
@@ -11255,7 +11343,7 @@ static int __must_check __init get_thinkpad_model_data(
struct thinkpad_id_data *tp)
{
const struct dmi_device *dev = NULL;
- char ec_fw_string[18] = {0};
+ char ec_fw_string[EC_FW_STRING_LEN] = {0};
char const *s;
char t;
@@ -11489,6 +11577,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = tpacpi_dprc_init,
.data = &dprc_driver_data,
},
+ {
+ .init = auxmac_init,
+ .data = &auxmac_data,
+ },
};
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index 0c67337726..969477c83e 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -81,7 +81,7 @@ static const struct property_entry chuwi_hi8_air_props[] = {
};
static const struct ts_dmi_data chuwi_hi8_air_data = {
- .acpi_name = "MSSL1680:00",
+ .acpi_name = "MSSL1680",
.properties = chuwi_hi8_air_props,
};
@@ -944,6 +944,32 @@ static const struct ts_dmi_data teclast_tbook11_data = {
.properties = teclast_tbook11_props,
};
+static const struct property_entry teclast_x16_plus_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 8),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 14),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1916),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1264),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-teclast-x16-plus.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct ts_dmi_data teclast_x16_plus_data = {
+ .embedded_fw = {
+ .name = "silead/gsl3692-teclast-x16-plus.fw",
+ .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+ .length = 43560,
+ .sha256 = { 0x9d, 0xb0, 0x3d, 0xf1, 0x00, 0x3c, 0xb5, 0x25,
+ 0x62, 0x8a, 0xa0, 0x93, 0x4b, 0xe0, 0x4e, 0x75,
+ 0xd1, 0x27, 0xb1, 0x65, 0x3c, 0xba, 0xa5, 0x0f,
+ 0xcd, 0xb4, 0xbe, 0x00, 0xbb, 0xf6, 0x43, 0x29 },
+ },
+ .acpi_name = "MSSL1680:00",
+ .properties = teclast_x16_plus_props,
+};
+
static const struct property_entry teclast_x3_plus_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
@@ -1613,6 +1639,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Teclast X16 Plus */
+ .driver_data = (void *)&teclast_x16_plus_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "D3A5_A1"),
+ },
+ },
+ {
/* Teclast X3 Plus */
.driver_data = (void *)&teclast_x3_plus_data,
.matches = {
@@ -1786,7 +1821,7 @@ static void ts_dmi_add_props(struct i2c_client *client)
int error;
if (has_acpi_companion(dev) &&
- !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
+ strstarts(client->name, ts_data->acpi_name)) {
error = device_create_managed_software_node(dev, ts_data->properties, NULL);
if (error)
dev_err(dev, "failed to add properties: %d\n", error);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index d75a0ae9cd..bd017478e6 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -109,33 +109,13 @@ static const char * const allow_duplicates[] = {
NULL
};
+#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
+#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
+
/*
* GUID parsing functions
*/
-static acpi_status find_guid(const char *guid_string, struct wmi_block **out)
-{
- guid_t guid_input;
- struct wmi_block *wblock;
-
- if (!guid_string)
- return AE_BAD_PARAMETER;
-
- if (guid_parse(guid_string, &guid_input))
- return AE_BAD_PARAMETER;
-
- list_for_each_entry(wblock, &wmi_block_list, list) {
- if (guid_equal(&wblock->gblock.guid, &guid_input)) {
- if (out)
- *out = wblock;
-
- return AE_OK;
- }
- }
-
- return AE_NOT_FOUND;
-}
-
static bool guid_parse_and_compare(const char *string, const guid_t *guid)
{
guid_t guid_input;
@@ -245,6 +225,41 @@ static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_bu
return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out);
}
+static int wmidev_match_guid(struct device *dev, const void *data)
+{
+ struct wmi_block *wblock = dev_to_wblock(dev);
+ const guid_t *guid = data;
+
+ if (guid_equal(guid, &wblock->gblock.guid))
+ return 1;
+
+ return 0;
+}
+
+static struct bus_type wmi_bus_type;
+
+static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
+{
+ struct device *dev;
+ guid_t guid;
+ int ret;
+
+ ret = guid_parse(guid_string, &guid);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ return dev_to_wdev(dev);
+}
+
+static void wmi_device_put(struct wmi_device *wdev)
+{
+ put_device(&wdev->dev);
+}
+
/*
* Exported WMI functions
*/
@@ -279,18 +294,17 @@ EXPORT_SYMBOL_GPL(set_required_buffer_size);
*/
int wmi_instance_count(const char *guid_string)
{
- struct wmi_block *wblock;
- acpi_status status;
+ struct wmi_device *wdev;
+ int ret;
- status = find_guid(guid_string, &wblock);
- if (ACPI_FAILURE(status)) {
- if (status == AE_BAD_PARAMETER)
- return -EINVAL;
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
+ return PTR_ERR(wdev);
- return -ENODEV;
- }
+ ret = wmidev_instance_count(wdev);
+ wmi_device_put(wdev);
- return wmidev_instance_count(&wblock->dev);
+ return ret;
}
EXPORT_SYMBOL_GPL(wmi_instance_count);
@@ -325,15 +339,18 @@ EXPORT_SYMBOL_GPL(wmidev_instance_count);
acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id,
const struct acpi_buffer *in, struct acpi_buffer *out)
{
- struct wmi_block *wblock = NULL;
+ struct wmi_device *wdev;
acpi_status status;
- status = find_guid(guid_string, &wblock);
- if (ACPI_FAILURE(status))
- return status;
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
+ return AE_ERROR;
+
+ status = wmidev_evaluate_method(wdev, instance, method_id, in, out);
+
+ wmi_device_put(wdev);
- return wmidev_evaluate_method(&wblock->dev, instance, method_id,
- in, out);
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_evaluate_method);
@@ -472,13 +489,19 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
struct acpi_buffer *out)
{
struct wmi_block *wblock;
+ struct wmi_device *wdev;
acpi_status status;
- status = find_guid(guid_string, &wblock);
- if (ACPI_FAILURE(status))
- return status;
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
+ return AE_ERROR;
- return __query_block(wblock, instance, out);
+ wblock = container_of(wdev, struct wmi_block, dev);
+ status = __query_block(wblock, instance, out);
+
+ wmi_device_put(wdev);
+
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_query_block);
@@ -516,8 +539,9 @@ EXPORT_SYMBOL_GPL(wmidev_block_query);
acpi_status wmi_set_block(const char *guid_string, u8 instance,
const struct acpi_buffer *in)
{
- struct wmi_block *wblock = NULL;
+ struct wmi_block *wblock;
struct guid_block *block;
+ struct wmi_device *wdev;
acpi_handle handle;
struct acpi_object_list input;
union acpi_object params[2];
@@ -527,19 +551,26 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
if (!in)
return AE_BAD_DATA;
- status = find_guid(guid_string, &wblock);
- if (ACPI_FAILURE(status))
- return status;
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
+ return AE_ERROR;
+ wblock = container_of(wdev, struct wmi_block, dev);
block = &wblock->gblock;
handle = wblock->acpi_device->handle;
- if (block->instance_count <= instance)
- return AE_BAD_PARAMETER;
+ if (block->instance_count <= instance) {
+ status = AE_BAD_PARAMETER;
+
+ goto err_wdev_put;
+ }
/* Check GUID is a data block */
- if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
- return AE_ERROR;
+ if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) {
+ status = AE_ERROR;
+
+ goto err_wdev_put;
+ }
input.count = 2;
input.pointer = params;
@@ -551,7 +582,12 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
get_acpi_method_name(wblock, 'S', method);
- return acpi_evaluate_object(handle, method, &input, NULL);
+ status = acpi_evaluate_object(handle, method, &input, NULL);
+
+err_wdev_put:
+ wmi_device_put(wdev);
+
+ return status;
}
EXPORT_SYMBOL_GPL(wmi_set_block);
@@ -650,9 +686,10 @@ acpi_status wmi_install_notify_handler(const char *guid,
block->handler_data = data;
wmi_status = wmi_method_enable(block, true);
- if ((wmi_status != AE_OK) ||
- ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
- status = wmi_status;
+ if (ACPI_FAILURE(wmi_status))
+ dev_warn(&block->dev.dev, "Failed to enable device\n");
+
+ status = AE_OK;
}
}
@@ -693,12 +730,13 @@ acpi_status wmi_remove_notify_handler(const char *guid)
status = AE_OK;
} else {
wmi_status = wmi_method_enable(block, false);
+ if (ACPI_FAILURE(wmi_status))
+ dev_warn(&block->dev.dev, "Failed to disable device\n");
+
block->handler = NULL;
block->handler_data = NULL;
- if ((wmi_status != AE_OK) ||
- ((wmi_status == AE_OK) &&
- (status == AE_NOT_EXIST)))
- status = wmi_status;
+
+ status = AE_OK;
}
}
}
@@ -742,7 +780,15 @@ EXPORT_SYMBOL_GPL(wmi_get_event_data);
*/
bool wmi_has_guid(const char *guid_string)
{
- return ACPI_SUCCESS(find_guid(guid_string, NULL));
+ struct wmi_device *wdev;
+
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
+ return false;
+
+ wmi_device_put(wdev);
+
+ return true;
}
EXPORT_SYMBOL_GPL(wmi_has_guid);
@@ -756,20 +802,23 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
*/
char *wmi_get_acpi_device_uid(const char *guid_string)
{
- struct wmi_block *wblock = NULL;
- acpi_status status;
+ struct wmi_block *wblock;
+ struct wmi_device *wdev;
+ char *uid;
- status = find_guid(guid_string, &wblock);
- if (ACPI_FAILURE(status))
+ wdev = wmi_find_device_by_guid(guid_string);
+ if (IS_ERR(wdev))
return NULL;
- return acpi_device_uid(wblock->acpi_device);
+ wblock = container_of(wdev, struct wmi_block, dev);
+ uid = acpi_device_uid(wblock->acpi_device);
+
+ wmi_device_put(wdev);
+
+ return uid;
}
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
-#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
-#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
-
static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
{
return container_of(drv, struct wmi_driver, driver);
@@ -1213,17 +1262,24 @@ static int wmi_create_device(struct device *wmi_bus_dev,
return 0;
}
-static void wmi_free_devices(struct acpi_device *device)
+static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev)
{
- struct wmi_block *wblock, *next;
+ struct device_link *link;
- /* Delete devices for all the GUIDs */
- list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
- if (wblock->acpi_device == device) {
- list_del(&wblock->list);
- device_unregister(&wblock->dev.dev);
- }
- }
+ /*
+ * Many aggregate WMI drivers do not use -EPROBE_DEFER when they
+ * are unable to find a WMI device during probe, instead they require
+ * all WMI devices associated with an platform device to become available
+ * at once. This device link thus prevents WMI drivers from probing until
+ * the associated platform device has finished probing (and has registered
+ * all discovered WMI devices).
+ */
+
+ link = device_link_add(&wdev->dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
+ if (!link)
+ return -EINVAL;
+
+ return device_add(&wdev->dev);
}
static bool guid_already_parsed_for_legacy(struct acpi_device *device, const guid_t *guid)
@@ -1255,11 +1311,12 @@ static bool guid_already_parsed_for_legacy(struct acpi_device *device, const gui
/*
* Parse the _WDG method for the GUID data blocks
*/
-static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
+static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
{
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
const struct guid_block *gblock;
- struct wmi_block *wblock, *next;
+ struct wmi_block *wblock;
union acpi_object *obj;
acpi_status status;
u32 i, total;
@@ -1314,22 +1371,14 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
wblock->handler = wmi_notify_debug;
wmi_method_enable(wblock, true);
}
- }
- /*
- * Now that all of the devices are created, add them to the
- * device tree and probe subdrivers.
- */
- list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
- if (wblock->acpi_device != device)
- continue;
-
- retval = device_add(&wblock->dev.dev);
+ retval = wmi_add_device(pdev, &wblock->dev);
if (retval) {
dev_err(wmi_bus_dev, "failed to register %pUL\n",
&wblock->gblock.guid);
if (debug_event)
wmi_method_enable(wblock, false);
+
list_del(&wblock->list);
put_device(&wblock->dev.dev);
}
@@ -1432,16 +1481,28 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
event, 0);
}
+static int wmi_remove_device(struct device *dev, void *data)
+{
+ struct wmi_block *wblock = dev_to_wblock(dev);
+
+ list_del(&wblock->list);
+ device_unregister(dev);
+
+ return 0;
+}
+
static void acpi_wmi_remove(struct platform_device *device)
{
struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev);
+ struct device *wmi_bus_device = dev_get_drvdata(&device->dev);
acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY,
acpi_wmi_notify_handler);
acpi_remove_address_space_handler(acpi_device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
- wmi_free_devices(acpi_device);
- device_unregister(dev_get_drvdata(&device->dev));
+
+ device_for_each_child_reverse(wmi_bus_device, NULL, wmi_remove_device);
+ device_unregister(wmi_bus_device);
}
static int acpi_wmi_probe(struct platform_device *device)
@@ -1484,7 +1545,7 @@ static int acpi_wmi_probe(struct platform_device *device)
}
dev_set_drvdata(&device->dev, wmi_bus_dev);
- error = parse_wdg(wmi_bus_dev, acpi_device);
+ error = parse_wdg(wmi_bus_dev, device);
if (error) {
pr_err("Failed to parse WDG method\n");
goto err_remove_busdev;
diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c
index f9c4083be8..227afbb510 100644
--- a/drivers/platform/x86/x86-android-tablets/asus.c
+++ b/drivers/platform/x86/x86-android-tablets/asus.c
@@ -303,6 +303,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
.index = 28,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "atmel_mxt_ts_irq",
},
},
};
diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c
index 2fd6060a31..ac2e8caaa8 100644
--- a/drivers/platform/x86/x86-android-tablets/core.c
+++ b/drivers/platform/x86/x86-android-tablets/core.c
@@ -12,7 +12,7 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
-#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -21,33 +21,54 @@
#include <linux/string.h>
#include "x86-android-tablets.h"
-/* For gpiochip_get_desc() which is EXPORT_SYMBOL_GPL() */
-#include "../../../gpio/gpiolib.h"
-#include "../../../gpio/gpiolib-acpi.h"
-static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
-{
- return gc->label && !strcmp(gc->label, data);
-}
+static struct platform_device *x86_android_tablet_device;
-int x86_android_tablet_get_gpiod(const char *label, int pin, struct gpio_desc **desc)
+/*
+ * This helper allows getting a gpio_desc *before* the actual device consuming
+ * the GPIO has been instantiated. This function _must_ only be used to handle
+ * this special case such as e.g. :
+ *
+ * 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to
+ * i2c_client_new() to instantiate i2c_client-s; or
+ * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys
+ * platform_data which still uses old style GPIO numbers.
+ *
+ * Since the consuming device has not been instatiated yet a dynamic lookup
+ * is generated using the special x86_android_tablet dev for dev_id.
+ *
+ * For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used.
+ */
+int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
+ bool active_low, enum gpiod_flags dflags,
+ struct gpio_desc **desc)
{
+ struct gpiod_lookup_table *lookup;
struct gpio_desc *gpiod;
- struct gpio_chip *chip;
- chip = gpiochip_find((void *)label, gpiochip_find_match_label);
- if (!chip) {
- pr_err("error cannot find GPIO chip %s\n", label);
- return -ENODEV;
- }
+ lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
+ if (!lookup)
+ return -ENOMEM;
+
+ lookup->dev_id = KBUILD_MODNAME;
+ lookup->table[0].key = chip;
+ lookup->table[0].chip_hwnum = pin;
+ lookup->table[0].con_id = con_id;
+ lookup->table[0].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH;
+
+ gpiod_add_lookup_table(lookup);
+ gpiod = devm_gpiod_get(&x86_android_tablet_device->dev, con_id, dflags);
+ gpiod_remove_lookup_table(lookup);
+ kfree(lookup);
- gpiod = gpiochip_get_desc(chip, pin);
if (IS_ERR(gpiod)) {
- pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), label, pin);
+ pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), chip, pin);
return PTR_ERR(gpiod);
}
- *desc = gpiod;
+ if (desc)
+ *desc = gpiod;
+
return 0;
}
@@ -77,7 +98,8 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
return irq;
case X86_ACPI_IRQ_TYPE_GPIOINT:
/* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
- ret = x86_android_tablet_get_gpiod(data->chip, data->index, &gpiod);
+ ret = x86_android_tablet_get_gpiod(data->chip, data->index, data->con_id,
+ false, GPIOD_ASIS, &gpiod);
if (ret)
return ret;
@@ -91,6 +113,9 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq))
irq_set_irq_type(irq, irq_type);
+ if (data->free_gpio)
+ devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
+
return irq;
case X86_ACPI_IRQ_TYPE_PMIC:
status = acpi_get_handle(NULL, data->chip, &handle);
@@ -224,7 +249,7 @@ put_ctrl_adev:
return ret;
}
-static void x86_android_tablet_cleanup(void)
+static void x86_android_tablet_remove(struct platform_device *pdev)
{
int i;
@@ -255,11 +280,10 @@ static void x86_android_tablet_cleanup(void)
software_node_unregister(bat_swnode);
}
-static __init int x86_android_tablet_init(void)
+static __init int x86_android_tablet_probe(struct platform_device *pdev)
{
const struct x86_dev_info *dev_info;
const struct dmi_system_id *id;
- struct gpio_chip *chip;
int i, ret = 0;
id = dmi_first_match(x86_android_tablet_ids);
@@ -267,20 +291,8 @@ static __init int x86_android_tablet_init(void)
return -ENODEV;
dev_info = id->driver_data;
-
- /*
- * The broken DSDTs on these devices often also include broken
- * _AEI (ACPI Event Interrupt) handlers, disable these.
- */
- if (dev_info->invalid_aei_gpiochip) {
- chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
- gpiochip_find_match_label);
- if (!chip) {
- pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
- return -ENODEV;
- }
- acpi_gpiochip_free_interrupts(chip);
- }
+ /* Allow x86_android_tablet_device use before probe() exits */
+ x86_android_tablet_device = pdev;
/*
* Since this runs from module_init() it cannot use -EPROBE_DEFER,
@@ -303,7 +315,7 @@ static __init int x86_android_tablet_init(void)
if (dev_info->init) {
ret = dev_info->init();
if (ret < 0) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return ret;
}
exit_handler = dev_info->exit;
@@ -311,7 +323,7 @@ static __init int x86_android_tablet_init(void)
i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
if (!i2c_clients) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@@ -319,7 +331,7 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < i2c_client_count; i++) {
ret = x86_instantiate_i2c_client(dev_info, i);
if (ret < 0) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return ret;
}
}
@@ -327,7 +339,7 @@ static __init int x86_android_tablet_init(void)
/* + 1 to make space for (optional) gpio_keys_button pdev */
pdevs = kcalloc(dev_info->pdev_count + 1, sizeof(*pdevs), GFP_KERNEL);
if (!pdevs) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@@ -335,14 +347,14 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < pdev_count; i++) {
pdevs[i] = platform_device_register_full(&dev_info->pdev_info[i]);
if (IS_ERR(pdevs[i])) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return PTR_ERR(pdevs[i]);
}
}
serdevs = kcalloc(dev_info->serdev_count, sizeof(*serdevs), GFP_KERNEL);
if (!serdevs) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@@ -350,7 +362,7 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < serdev_count; i++) {
ret = x86_instantiate_serdev(&dev_info->serdev_info[i], i);
if (ret < 0) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return ret;
}
}
@@ -361,30 +373,34 @@ static __init int x86_android_tablet_init(void)
buttons = kcalloc(dev_info->gpio_button_count, sizeof(*buttons), GFP_KERNEL);
if (!buttons) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return -ENOMEM;
}
for (i = 0; i < dev_info->gpio_button_count; i++) {
ret = x86_android_tablet_get_gpiod(dev_info->gpio_button[i].chip,
- dev_info->gpio_button[i].pin, &gpiod);
+ dev_info->gpio_button[i].pin,
+ dev_info->gpio_button[i].button.desc,
+ false, GPIOD_IN, &gpiod);
if (ret < 0) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return ret;
}
buttons[i] = dev_info->gpio_button[i].button;
buttons[i].gpio = desc_to_gpio(gpiod);
+ /* Release gpiod so that gpio-keys can request it */
+ devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
}
pdata.buttons = buttons;
pdata.nbuttons = dev_info->gpio_button_count;
- pdevs[pdev_count] = platform_device_register_data(NULL, "gpio-keys",
+ pdevs[pdev_count] = platform_device_register_data(&pdev->dev, "gpio-keys",
PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(pdevs[pdev_count])) {
- x86_android_tablet_cleanup();
+ x86_android_tablet_remove(pdev);
return PTR_ERR(pdevs[pdev_count]);
}
pdev_count++;
@@ -393,8 +409,29 @@ static __init int x86_android_tablet_init(void)
return 0;
}
+static struct platform_driver x86_android_tablet_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+ .remove_new = x86_android_tablet_remove,
+};
+
+static int __init x86_android_tablet_init(void)
+{
+ x86_android_tablet_device = platform_create_bundle(&x86_android_tablet_driver,
+ x86_android_tablet_probe,
+ NULL, 0, NULL, 0);
+
+ return PTR_ERR_OR_ZERO(x86_android_tablet_device);
+}
module_init(x86_android_tablet_init);
-module_exit(x86_android_tablet_cleanup);
+
+static void __exit x86_android_tablet_exit(void)
+{
+ platform_device_unregister(x86_android_tablet_device);
+ platform_driver_unregister(&x86_android_tablet_driver);
+}
+module_exit(x86_android_tablet_exit);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c
index 26a4ef670a..50ac5afa00 100644
--- a/drivers/platform/x86/x86-android-tablets/lenovo.c
+++ b/drivers/platform/x86/x86-android-tablets/lenovo.c
@@ -95,6 +95,8 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 56,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "goodix_ts_irq",
+ .free_gpio = true,
},
}, {
/* Wacom Digitizer in keyboard half */
@@ -111,6 +113,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 49,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "wacom_irq",
},
}, {
/* LP8557 Backlight controller */
@@ -136,6 +139,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 77,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "hideep_ts_irq",
},
},
};
@@ -321,6 +325,7 @@ static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __init
.index = 2,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
+ .con_id = "bq24292i_irq",
},
}, {
/* BQ27541 fuel-gauge */
@@ -431,7 +436,8 @@ static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
int ret;
/* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
- ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, &gpiod);
+ ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, "yoga_bootstrap",
+ false, GPIOD_ASIS, &gpiod);
if (ret)
return ret;
@@ -560,7 +566,6 @@ static const struct software_node fg_bq25890_1_supply_node = {
/* bq25892 charger settings for the flat lipo battery behind the screen */
static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
- PROPERTY_ENTRY_STRING("linux,power-supply-name", "bq25892-second-chrg"),
PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
PROPERTY_ENTRY_BOOL("linux,skip-reset"),
/* Values taken from Android Factory Image */
@@ -615,6 +620,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
.index = 5,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "bq25892_0_irq",
},
}, {
/* bq27500 fuel-gauge for the round li-ion cells in the hinge */
@@ -640,6 +646,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
.index = 77,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "hideep_ts_irq",
},
}, {
/* LP8557 Backlight controller */
@@ -655,7 +662,6 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
static int __init lenovo_yt3_init(void)
{
- struct gpio_desc *gpiod;
int ret;
/*
@@ -665,31 +671,23 @@ static int __init lenovo_yt3_init(void)
*
* The bq25890_charger driver controls these through I2C, but this only
* works if not overridden by the pins. Set these pins here:
- * 1. Set /CE to 0 to allow charging.
+ * 1. Set /CE to 1 to allow charging.
* 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
* the main "bq25892_1" charger is used when necessary.
*/
/* /CE pin */
- ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, &gpiod);
+ ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, "bq25892_0_ce",
+ true, GPIOD_OUT_HIGH, NULL);
if (ret < 0)
return ret;
- /*
- * The gpio_desc returned by x86_android_tablet_get_gpiod() is a "raw"
- * gpio_desc, that is there is no way to pass lookup-flags like
- * GPIO_ACTIVE_LOW. Set the GPIO to 0 here to enable charging since
- * the /CE pin is active-low, but not marked as such in the gpio_desc.
- */
- gpiod_set_value(gpiod, 0);
-
/* OTG pin */
- ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, &gpiod);
+ ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, "bq25892_0_otg",
+ false, GPIOD_OUT_LOW, NULL);
if (ret < 0)
return ret;
- gpiod_set_value(gpiod, 0);
-
/* Enable the regulators used by the touchscreen */
intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff);
intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff);
diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c
index e79549c6aa..bc6bbf7ec6 100644
--- a/drivers/platform/x86/x86-android-tablets/other.c
+++ b/drivers/platform/x86/x86-android-tablets/other.c
@@ -47,6 +47,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst =
.index = 3,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "NVT-ts_irq",
},
}, {
/* BMA250E accelerometer */
@@ -62,6 +63,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst =
.index = 25,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
+ .con_id = "bma250e_irq",
},
},
};
@@ -174,6 +176,7 @@ static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
.index = 23,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
+ .con_id = "bma250e_irq",
},
},
};
@@ -312,6 +315,7 @@ static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __in
.index = 23,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
+ .con_id = "kxtj21009_irq",
},
}, {
/* goodix touchscreen */
@@ -402,6 +406,7 @@ static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst
.index = 3,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "ft5416_irq",
},
},
};
@@ -460,6 +465,7 @@ static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initcons
.index = 17,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
+ .con_id = "ft5416_irq",
},
},
};
@@ -505,11 +511,6 @@ static const struct x86_gpio_button peaq_c1010_button __initconst = {
const struct x86_dev_info peaq_c1010_info __initconst = {
.gpio_button = &peaq_c1010_button,
.gpio_button_count = 1,
- /*
- * Move the ACPI event handler used by the broken WMI interface out of
- * the way. This is the only event handler on INT33FC:00.
- */
- .invalid_aei_gpiochip = "INT33FC:00",
};
/*
diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
index e46e1128ac..136a2b359d 100644
--- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
+++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
@@ -10,6 +10,7 @@
#ifndef __PDX86_X86_ANDROID_TABLETS_H
#define __PDX86_X86_ANDROID_TABLETS_H
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/irqdomain_defs.h>
@@ -37,6 +38,8 @@ struct x86_acpi_irq_data {
int index;
int trigger; /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */
int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
+ bool free_gpio; /* Release GPIO after getting IRQ (for TYPE_GPIOINT) */
+ const char *con_id;
};
/* Structs to describe devices to instantiate */
@@ -66,7 +69,6 @@ struct x86_gpio_button {
};
struct x86_dev_info {
- char *invalid_aei_gpiochip;
const char * const *modules;
const struct software_node *bat_swnode;
struct gpiod_lookup_table * const *gpiod_lookup_tables;
@@ -82,7 +84,9 @@ struct x86_dev_info {
void (*exit)(void);
};
-int x86_android_tablet_get_gpiod(const char *label, int pin, struct gpio_desc **desc);
+int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
+ bool active_low, enum gpiod_flags dflags,
+ struct gpio_desc **desc);
int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data);
/*
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index 391f7ea443..df2bf1c585 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -81,9 +81,9 @@ static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
static int ebook_switch_add(struct acpi_device *device)
{
+ const struct acpi_device_id *id;
struct ebook_switch *button;
struct input_dev *input;
- const char *hid = acpi_device_hid(device);
char *name, *class;
int error;
@@ -102,8 +102,9 @@ static int ebook_switch_add(struct acpi_device *device)
name = acpi_device_name(device);
class = acpi_device_class(device);
- if (strcmp(hid, XO15_EBOOK_HID)) {
- pr_err("Unsupported hid [%s]\n", hid);
+ id = acpi_match_acpi_device(ebook_device_ids, device);
+ if (!id) {
+ dev_err(&device->dev, "Unsupported hid\n");
error = -ENODEV;
goto err_free_input;
}
@@ -111,7 +112,7 @@ static int ebook_switch_add(struct acpi_device *device)
strcpy(name, XO15_EBOOK_DEVICE_NAME);
sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
- snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
+ snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id);
input->name = name;
input->phys = button->phys;