summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-30 17:15:31 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-30 17:15:31 +0100
commitc2101d01826480755f2bd9f3dd5e36757be61e23 (patch)
tree3f1d29969a98cc78b84335dc185e2806cd025282 /drivers
parentMerge tag 'pm-4.20-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ra... (diff)
parentACPI / PMIC: xpower: Add depends on IOSF_MBI to Kconfig entry (diff)
downloadlinux-c2101d01826480755f2bd9f3dd5e36757be61e23.tar.xz
linux-c2101d01826480755f2bd9f3dd5e36757be61e23.zip
Merge tag 'acpi-4.20-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more ACPI updates from Rafael Wysocki: "Rework the handling of the P-unit semaphore on Intel Baytrail and Cherrytrail systems to avoid race conditions and excessive overhead related to it (Hans de Goede)" * tag 'acpi-4.20-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / PMIC: xpower: Add depends on IOSF_MBI to Kconfig entry i2c: designware: Cleanup bus lock handling ACPI / PMIC: xpower: Block P-Unit I2C access during read-modify-write x86: baytrail/cherrytrail: Rework and move P-Unit PMIC bus semaphore code
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c21
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c139
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c4
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h9
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c2
6 files changed, 22 insertions, 155 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 365e6c1a729e..8f3a444c6ea9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -512,7 +512,7 @@ config CRC_PMIC_OPREGION
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"
- depends on MFD_AXP20X_I2C
+ depends on MFD_AXP20X_I2C && IOSF_MBI
help
This config adds ACPI operation region support for XPower AXP288 PMIC.
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
index aadc86db804c..2579675b7082 100644
--- a/drivers/acpi/pmic/intel_pmic_xpower.c
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -8,8 +8,9 @@
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/mfd/axp20x.h>
-#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <asm/iosf_mbi.h>
#include "intel_pmic.h"
#define XPOWER_GPADC_LOW 0x5b
@@ -172,15 +173,21 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
int bit, bool on)
{
- int data;
+ int data, ret;
/* GPIO1 LDO regulator needs special handling */
if (reg == XPOWER_GPI1_CTRL)
return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
on ? GPI1_LDO_ON : GPI1_LDO_OFF);
- if (regmap_read(regmap, reg, &data))
- return -EIO;
+ ret = iosf_mbi_block_punit_i2c_access();
+ if (ret)
+ return ret;
+
+ if (regmap_read(regmap, reg, &data)) {
+ ret = -EIO;
+ goto out;
+ }
if (on)
data |= BIT(bit);
@@ -188,9 +195,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
data &= ~BIT(bit);
if (regmap_write(regmap, reg, data))
- return -EIO;
+ ret = -EIO;
+out:
+ iosf_mbi_unblock_punit_i2c_access();
- return 0;
+ return ret;
}
/**
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
index 9ca1feaba98f..33da07d64494 100644
--- a/drivers/i2c/busses/i2c-designware-baytrail.c
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -3,141 +3,15 @@
* Intel BayTrail PMIC I2C bus semaphore implementaion
* Copyright (c) 2014, Intel Corporation.
*/
-#include <linux/delay.h>
#include <linux/device.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
#include <asm/iosf_mbi.h>
#include "i2c-designware-core.h"
-#define SEMAPHORE_TIMEOUT 500
-#define PUNIT_SEMAPHORE 0x7
-#define PUNIT_SEMAPHORE_CHT 0x10e
-#define PUNIT_SEMAPHORE_BIT BIT(0)
-#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
-
-static unsigned long acquired;
-
-static u32 get_sem_addr(struct dw_i2c_dev *dev)
-{
- if (dev->flags & MODEL_CHERRYTRAIL)
- return PUNIT_SEMAPHORE_CHT;
- else
- return PUNIT_SEMAPHORE;
-}
-
-static int get_sem(struct dw_i2c_dev *dev, u32 *sem)
-{
- u32 addr = get_sem_addr(dev);
- u32 data;
- int ret;
-
- ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &data);
- if (ret) {
- dev_err(dev->dev, "iosf failed to read punit semaphore\n");
- return ret;
- }
-
- *sem = data & PUNIT_SEMAPHORE_BIT;
-
- return 0;
-}
-
-static void reset_semaphore(struct dw_i2c_dev *dev)
-{
- if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, get_sem_addr(dev),
- 0, PUNIT_SEMAPHORE_BIT))
- dev_err(dev->dev, "iosf failed to reset punit semaphore during write\n");
-
- pm_qos_update_request(&dev->pm_qos, PM_QOS_DEFAULT_VALUE);
-
- iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_END,
- NULL);
- iosf_mbi_punit_release();
-}
-
-static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
-{
- u32 addr;
- u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
- int ret;
- unsigned long start, end;
-
- might_sleep();
-
- if (!dev || !dev->dev)
- return -ENODEV;
-
- if (!dev->release_lock)
- return 0;
-
- iosf_mbi_punit_acquire();
- iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_BEGIN,
- NULL);
-
- /*
- * Disallow the CPU to enter C6 or C7 state, entering these states
- * requires the punit to talk to the pmic and if this happens while
- * we're holding the semaphore, the SoC hangs.
- */
- pm_qos_update_request(&dev->pm_qos, 0);
-
- addr = get_sem_addr(dev);
-
- /* host driver writes to side band semaphore register */
- ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
- if (ret) {
- dev_err(dev->dev, "iosf punit semaphore request failed\n");
- goto out;
- }
-
- /* host driver waits for bit 0 to be set in semaphore register */
- start = jiffies;
- end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
- do {
- ret = get_sem(dev, &sem);
- if (!ret && sem) {
- acquired = jiffies;
- dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
- jiffies_to_msecs(jiffies - start));
- return 0;
- }
-
- usleep_range(1000, 2000);
- } while (time_before(jiffies, end));
-
- dev_err(dev->dev, "punit semaphore timed out, resetting\n");
-out:
- reset_semaphore(dev);
-
- ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &sem);
- if (ret)
- dev_err(dev->dev, "iosf failed to read punit semaphore\n");
- else
- dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
-
- WARN_ON(1);
-
- return -ETIMEDOUT;
-}
-
-static void baytrail_i2c_release(struct dw_i2c_dev *dev)
-{
- if (!dev || !dev->dev)
- return;
-
- if (!dev->acquire_lock)
- return;
-
- reset_semaphore(dev);
- dev_dbg(dev->dev, "punit semaphore held for %ums\n",
- jiffies_to_msecs(jiffies - acquired));
-}
-
int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
{
acpi_status status;
@@ -162,18 +36,9 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return -EPROBE_DEFER;
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
- dev->acquire_lock = baytrail_i2c_acquire;
- dev->release_lock = baytrail_i2c_release;
+ dev->acquire_lock = iosf_mbi_block_punit_i2c_access;
+ dev->release_lock = iosf_mbi_unblock_punit_i2c_access;
dev->shared_with_punit = true;
- pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
return 0;
}
-
-void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
-{
- if (dev->acquire_lock)
- pm_qos_remove_request(&dev->pm_qos);
-}
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 36271cd75342..a4730111d290 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -269,7 +269,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
if (!dev->acquire_lock)
return 0;
- ret = dev->acquire_lock(dev);
+ ret = dev->acquire_lock();
if (!ret)
return 0;
@@ -281,7 +281,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
void i2c_dw_release_lock(struct dw_i2c_dev *dev)
{
if (dev->release_lock)
- dev->release_lock(dev);
+ dev->release_lock();
}
/*
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9ec8394f4787..b4a0b2b99a78 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -10,7 +10,6 @@
*/
#include <linux/i2c.h>
-#include <linux/pm_qos.h>
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
@@ -209,7 +208,6 @@
* @fp_lcnt: fast plus LCNT value
* @hs_hcnt: high speed HCNT value
* @hs_lcnt: high speed LCNT value
- * @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @shared_with_punit: true if this bus is shared with the SoCs PUNIT
@@ -263,9 +261,8 @@ struct dw_i2c_dev {
u16 fp_lcnt;
u16 hs_hcnt;
u16 hs_lcnt;
- struct pm_qos_request pm_qos;
- int (*acquire_lock)(struct dw_i2c_dev *dev);
- void (*release_lock)(struct dw_i2c_dev *dev);
+ int (*acquire_lock)(void);
+ void (*release_lock)(void);
bool shared_with_punit;
void (*disable)(struct dw_i2c_dev *dev);
void (*disable_int)(struct dw_i2c_dev *dev);
@@ -322,8 +319,6 @@ static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev);
-extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev);
#else
static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; }
-static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {}
#endif
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 997bbb3d925f..9eaac3be1f63 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -418,8 +418,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
- i2c_dw_remove_lock_support(dev);
-
return 0;
}