diff options
author | Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> | 2017-10-07 18:19:51 -0400 |
---|---|---|
committer | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2017-10-23 13:16:36 -0400 |
commit | 6687aeb9cd3d40904d1f9e884d2145603c23adfa (patch) | |
tree | 22ff9a06a7b2be7f928cbeade5a25910350d3739 /drivers/platform/x86/intel_pmc_ipc.c | |
parent | 83beee5c88a6c71ded70e2eef5ca7406a02605cc (diff) |
platform/x86: intel_pmc_ipc: Use spin_lock to protect GCR updates
Currently, update_no_reboot_bit() function implemented in this driver
uses mutex_lock() to protect its register updates. But this function is
called with in atomic context in iTCO_wdt_start() and iTCO_wdt_stop()
functions in iTCO_wdt.c driver, which in turn causes "sleeping into
atomic context" issue. This patch fixes this issue by replacing the
mutex_lock() with spin_lock() to protect the GCR read/write/update APIs.
Fixes: 9d855d4 ("platform/x86: intel_pmc_ipc: Fix iTCO_wdt GCS memory mapping failure")
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kupuswamy@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to 'drivers/platform/x86/intel_pmc_ipc.c')
-rw-r--r-- | drivers/platform/x86/intel_pmc_ipc.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 751b1212d01c..e03fa31446ca 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/suspend.h> | 33 | #include <linux/suspend.h> |
34 | #include <linux/acpi.h> | 34 | #include <linux/acpi.h> |
35 | #include <linux/io-64-nonatomic-lo-hi.h> | 35 | #include <linux/io-64-nonatomic-lo-hi.h> |
36 | #include <linux/spinlock.h> | ||
36 | 37 | ||
37 | #include <asm/intel_pmc_ipc.h> | 38 | #include <asm/intel_pmc_ipc.h> |
38 | 39 | ||
@@ -131,6 +132,7 @@ static struct intel_pmc_ipc_dev { | |||
131 | /* gcr */ | 132 | /* gcr */ |
132 | void __iomem *gcr_mem_base; | 133 | void __iomem *gcr_mem_base; |
133 | bool has_gcr_regs; | 134 | bool has_gcr_regs; |
135 | spinlock_t gcr_lock; | ||
134 | 136 | ||
135 | /* punit */ | 137 | /* punit */ |
136 | struct platform_device *punit_dev; | 138 | struct platform_device *punit_dev; |
@@ -225,17 +227,17 @@ int intel_pmc_gcr_read(u32 offset, u32 *data) | |||
225 | { | 227 | { |
226 | int ret; | 228 | int ret; |
227 | 229 | ||
228 | mutex_lock(&ipclock); | 230 | spin_lock(&ipcdev.gcr_lock); |
229 | 231 | ||
230 | ret = is_gcr_valid(offset); | 232 | ret = is_gcr_valid(offset); |
231 | if (ret < 0) { | 233 | if (ret < 0) { |
232 | mutex_unlock(&ipclock); | 234 | spin_unlock(&ipcdev.gcr_lock); |
233 | return ret; | 235 | return ret; |
234 | } | 236 | } |
235 | 237 | ||
236 | *data = readl(ipcdev.gcr_mem_base + offset); | 238 | *data = readl(ipcdev.gcr_mem_base + offset); |
237 | 239 | ||
238 | mutex_unlock(&ipclock); | 240 | spin_unlock(&ipcdev.gcr_lock); |
239 | 241 | ||
240 | return 0; | 242 | return 0; |
241 | } | 243 | } |
@@ -255,17 +257,17 @@ int intel_pmc_gcr_write(u32 offset, u32 data) | |||
255 | { | 257 | { |
256 | int ret; | 258 | int ret; |
257 | 259 | ||
258 | mutex_lock(&ipclock); | 260 | spin_lock(&ipcdev.gcr_lock); |
259 | 261 | ||
260 | ret = is_gcr_valid(offset); | 262 | ret = is_gcr_valid(offset); |
261 | if (ret < 0) { | 263 | if (ret < 0) { |
262 | mutex_unlock(&ipclock); | 264 | spin_unlock(&ipcdev.gcr_lock); |
263 | return ret; | 265 | return ret; |
264 | } | 266 | } |
265 | 267 | ||
266 | writel(data, ipcdev.gcr_mem_base + offset); | 268 | writel(data, ipcdev.gcr_mem_base + offset); |
267 | 269 | ||
268 | mutex_unlock(&ipclock); | 270 | spin_unlock(&ipcdev.gcr_lock); |
269 | 271 | ||
270 | return 0; | 272 | return 0; |
271 | } | 273 | } |
@@ -287,7 +289,7 @@ int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val) | |||
287 | u32 new_val; | 289 | u32 new_val; |
288 | int ret = 0; | 290 | int ret = 0; |
289 | 291 | ||
290 | mutex_lock(&ipclock); | 292 | spin_lock(&ipcdev.gcr_lock); |
291 | 293 | ||
292 | ret = is_gcr_valid(offset); | 294 | ret = is_gcr_valid(offset); |
293 | if (ret < 0) | 295 | if (ret < 0) |
@@ -309,7 +311,7 @@ int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val) | |||
309 | } | 311 | } |
310 | 312 | ||
311 | gcr_ipc_unlock: | 313 | gcr_ipc_unlock: |
312 | mutex_unlock(&ipclock); | 314 | spin_unlock(&ipcdev.gcr_lock); |
313 | return ret; | 315 | return ret; |
314 | } | 316 | } |
315 | EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); | 317 | EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); |
@@ -489,6 +491,8 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
489 | 491 | ||
490 | pmc->irq_mode = IPC_TRIGGER_MODE_IRQ; | 492 | pmc->irq_mode = IPC_TRIGGER_MODE_IRQ; |
491 | 493 | ||
494 | spin_lock_init(&ipcdev.gcr_lock); | ||
495 | |||
492 | ret = pcim_enable_device(pdev); | 496 | ret = pcim_enable_device(pdev); |
493 | if (ret) | 497 | if (ret) |
494 | return ret; | 498 | return ret; |
@@ -903,6 +907,7 @@ static int ipc_plat_probe(struct platform_device *pdev) | |||
903 | ipcdev.dev = &pdev->dev; | 907 | ipcdev.dev = &pdev->dev; |
904 | ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; | 908 | ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; |
905 | init_completion(&ipcdev.cmd_complete); | 909 | init_completion(&ipcdev.cmd_complete); |
910 | spin_lock_init(&ipcdev.gcr_lock); | ||
906 | 911 | ||
907 | ipcdev.irq = platform_get_irq(pdev, 0); | 912 | ipcdev.irq = platform_get_irq(pdev, 0); |
908 | if (ipcdev.irq < 0) { | 913 | if (ipcdev.irq < 0) { |