[PORT FROM R2] mid_pmu: serialize access to 0xD0 and 0xD4 regs of root device (bus...
authorRamachandra Sudarshan N <sudarshan.n.ramachandra@intel.com>
Fri, 2 Dec 2011 08:38:06 +0000 (14:08 +0530)
committerbuildbot <buildbot@intel.com>
Wed, 21 Dec 2011 14:42:30 +0000 (06:42 -0800)
BZ: 6332

Apart from mid_pmu there are other drivers which read/write
0xD0 and 0xD4 registers in config space of pci root device hence
there is a potential for race condition. This patch resolves the
issue by creating an API which serializes access to the above registers.

other drivers like coretemp.c, atomisp are accessing 0xD0 and 0xD4
registers. mid_pmu uses it to map north complex PM registers, which will be
in turn used in pmu_nc_set_power_state. where as coretemp.c is using it to
read thermal sensor registers. hence used for various purpose in
different drivers

once this patch gets merged the plan is to ask individual driver
owners to use this API instead of directly accessing the above registers.

Change-Id: I57a220c79283c20ded693cf6c5c94720bf428360
Orig-Change-Id: Ib31ae2cf591749b9693dbaf16b1fee3c4120bf66
Signed-off-by: Sudarshan Ramachandra <sudarshan.n.ramachandra@intel.com>
Reviewed-on: http://android.intel.com:8080/29308
Reviewed-by: Martin, LoicX <loicx.martin@intel.com>
Reviewed-by: Mansoor, Illyas <illyas.mansoor@intel.com>
Tested-by: Martin, LoicX <loicx.martin@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/platform/mfld/pmu.c
arch/x86/platform/mfld/pmu.h
include/linux/intel_mid_pm.h

index af8c950..de1a36e 100755 (executable)
@@ -44,6 +44,8 @@ static bool pmu_initialized;
 /* mid_pmu context structure */
 static struct mid_pmu_dev *mid_pmu_cxt;
 
+static DEFINE_MUTEX(pci_root_lock);
+
 /* Accessor function for pci_devs start */
 static inline struct pci_dev *get_mid_pci_drv(int lss_index, int i)
 {
@@ -124,6 +126,58 @@ static inline void clear_d0ix_stats(void)
 /* Accessor functions for pci_devs end */
 
 /*
+ * APIs to communicate with pci root,
+ * Returns zero on sucess.
+ */
+int mfld_msg_read32(u32 cmd, u32 *data)
+{
+       struct pci_dev *pci_root;
+       int ret;
+
+       mutex_lock(&pci_root_lock);
+       pci_root = pci_get_bus_and_slot(0, 0);
+
+       ret = pci_write_config_dword(pci_root, PCI_CMD_REG, cmd);
+       if (ret)
+               goto unlock;
+       /*
+        * since we go to unlock with/without error, not
+        * checking for it here
+        */
+       pci_read_config_dword(pci_root, PCI_DATA_REG, data);
+
+unlock:
+       pci_dev_put(pci_root);
+       mutex_unlock(&pci_root_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(mfld_msg_read32);
+
+/*Returns Zero on sucess*/
+int mfld_msg_write32(u32 cmd, u32 data)
+{
+       struct pci_dev *pci_root;
+       int ret;
+
+       mutex_lock(&pci_root_lock);
+       pci_root = pci_get_bus_and_slot(0, 0);
+
+       ret = pci_write_config_dword(pci_root, PCI_DATA_REG, data);
+       if (ret)
+               goto unlock;
+
+       pci_write_config_dword(pci_root, PCI_CMD_REG, cmd);
+
+unlock:
+       pci_dev_put(pci_root);
+       mutex_unlock(&pci_root_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(mfld_msg_write32);
+
+/*
  * Locking strategy::
  *
  * Two semaphores are used to lock the global variables used in
@@ -2287,6 +2341,8 @@ static int __devinit mid_pmu_probe(struct pci_dev *dev,
 {
        int ret;
        struct mrst_pmu_reg __iomem *pmu;
+       int cmd;
+       u32 data;
 
 #ifdef CONFIG_HAS_WAKELOCK
        wake_lock_init(&mid_pmu_cxt->pmu_wake_lock,
@@ -2320,10 +2376,21 @@ static int __devinit mid_pmu_probe(struct pci_dev *dev,
        }
 
        /* Map the NC PM registers */
-       mid_pmu_cxt->apm_base =
-               MDFLD_MSG_READ32(OSPM_PUNIT_PORT, OSPM_APMBA) & 0xffff;
-       mid_pmu_cxt->ospm_base =
-               MDFLD_MSG_READ32(OSPM_PUNIT_PORT, OSPM_OSPMBA) & 0xffff;
+       cmd = (MSG_READ_CMD << 24) | (OSPM_PUNIT_PORT << 16) |
+                                               (OSPM_APMBA << 8);
+       if (mfld_msg_read32(cmd, &data)) {
+               ret = PMU_FAILED;
+               goto out_err1;
+       }
+       mid_pmu_cxt->apm_base = data & 0xffff;
+
+       cmd = (MSG_READ_CMD << 24) | (OSPM_PUNIT_PORT << 16) |
+                                                (OSPM_OSPMBA << 8);
+       if (mfld_msg_read32(cmd, &data)) {
+               ret = PMU_FAILED;
+               goto out_err1;
+       }
+       mid_pmu_cxt->ospm_base = data & 0xffff;
 
        /* Map the memory of pmu1 PMU reg base */
        pmu = pci_iomap(dev, 0, 0);
index c905d16..9cf626e 100644 (file)
 #define APM_CMD                 0x0
 #define APM_STS                 0x04
 
+#define PCI_CMD_REG            0xD0
+#define PCI_DATA_REG           0xD4
+#define MSG_READ_CMD           0x10
+#define MSG_WRITE_CMD          0x11
 
 enum cm_trigger {
        NO_TRIG,                /* No trigger is required */
@@ -825,27 +829,6 @@ struct mid_pmu_dev {
        spinlock_t nc_ready_lock;
 };
 
-/*APIs to get the APM base address */
-static inline u32 MDFLD_MSG_READ32(uint port, uint offset)
-{
-       int mcr = (0x10<<24) | (port << 16) | (offset << 8);
-       uint32_t ret_val = 0;
-       struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
-       pci_write_config_dword(pci_root, 0xD0, mcr);
-       pci_read_config_dword(pci_root, 0xD4, &ret_val);
-       pci_dev_put(pci_root);
-       return ret_val;
-}
-
-static inline void MDFLD_MSG_WRITE32(uint port, uint offset, u32 value)
-{
-       int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
-       struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
-       pci_write_config_dword(pci_root, 0xD4, value);
-       pci_write_config_dword(pci_root, 0xD0, mcr);
-       pci_dev_put(pci_root);
-}
-
 /* API used to change the platform mode */
 extern int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state);
 extern pci_power_t pmu_pci_choose_state(struct pci_dev *pdev);
index 840e6b1..ae286cb 100644 (file)
@@ -16,6 +16,8 @@
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  *
  */
+#include <linux/errno.h>
+
 #ifndef INTEL_MID_PM_H
 #define INTEL_MID_PM_H
 
@@ -107,6 +109,9 @@ extern int pmu_nc_set_power_state
        (int islands, int state_type, int reg_type);
 extern void mfld_shutdown(void);
 
+extern int mfld_msg_read32(u32 cmd, u32 *data);
+extern int mfld_msg_write32(u32 cmd, u32 data);
+
 #else
 
 /*
@@ -132,6 +137,11 @@ static inline int pmu_nc_set_power_state
 static inline void pmu_set_s0ix_complete(void) { return; }
 static inline void mfld_shutdown(void) { return; }
 static inline bool pmu_is_s0ix_in_progress(void) { return false; };
+
+/*returns function not implemented*/
+static inline  int mfld_msg_read32(u32 cmd, u32 *data) { return -ENOSYS; }
+static inline int mfld_msg_write32(u32 cmd, u32 data) { return -ENOSYS; }
+
 #endif /* #ifdef CONFIG_INTEL_MID_POWER */