summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJeffrey Ladouceur <Jeffrey.Ladouceur@freescale.com>2014-02-28 00:15:48 (GMT)
committerJose Rivera <German.Rivera@freescale.com>2014-04-09 01:01:09 (GMT)
commit563e96070a46ad41e172992dd408d2279facac6f (patch)
tree52ba11ce50de9e451c2b2ab3822d196c893b6834 /drivers
parenta1a36c47104a2c104368bcb90f808579809e6720 (diff)
downloadlinux-fsl-qoriq-563e96070a46ad41e172992dd408d2279facac6f.tar.xz
fsl_pme: Support for power management
Change the pme error interrupt handler to be per-CPU to avoid a warning ("Cannot set affinity for irq") when entering suspend-to-ram state. Added IRQF_PERCPU flag. While sending frames to the PME device, this device can return a serious error. Added logic to properly handle this scenario. If this happens while reading the pme database, upon resume the resulting database will not be restored. The size of the confidence table was incorrect for a specific version of pme. Signed-off-by: Jeffrey Ladouceur <Jeffrey.Ladouceur@freescale.com> Change-Id: Ic8cbc048c7a0e4cd8389298267ec9b4876055568 Reviewed-on: http://git.am.freescale.net:8181/9267 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Geoff Thorpe <Geoff.Thorpe@freescale.com> Reviewed-by: Jose Rivera <German.Rivera@freescale.com> (cherry picked from commit f13d881f9e464079b62dba71f96dd73be4ad83a0) Reviewed-on: http://git.am.freescale.net:8181/10777
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/fsl_pme2/pme2_ctrl.c23
-rw-r--r--drivers/staging/fsl_pme2/pme2_private.h1
-rw-r--r--drivers/staging/fsl_pme2/pme2_suspend.c117
3 files changed, 79 insertions, 62 deletions
diff --git a/drivers/staging/fsl_pme2/pme2_ctrl.c b/drivers/staging/fsl_pme2/pme2_ctrl.c
index 9901fe6..016648c 100644
--- a/drivers/staging/fsl_pme2/pme2_ctrl.c
+++ b/drivers/staging/fsl_pme2/pme2_ctrl.c
@@ -340,8 +340,8 @@ static int of_fsl_pme_probe(struct platform_device *ofdev)
if (likely(pme_err_irq != NO_IRQ)) {
/* Register the pme ISR handler */
- err = request_irq(pme_err_irq, pme_isr, IRQF_SHARED, "pme-err",
- dev);
+ err = request_irq(pme_err_irq, pme_isr,
+ IRQF_SHARED | IRQF_PERCPU, "pme-err", dev);
if (err) {
dev_err(dev, "request_irq() failed\n");
goto out_unmap_ctrl_region;
@@ -473,14 +473,31 @@ void restore_all_ccsr(struct ccsr_backup_info *save_ccsr,
{
int i;
int num_regs = sizeof(save_ccsr->regdb)/sizeof(uint32_t);
-
uint32_t *pme_reg = &save_ccsr->regdb.pmfa.isr;
+#ifdef CONFIG_PM_DEBUG
+ int diff_count = 0;
+#endif
for (i = 0; i < num_regs; i++) {
+#ifdef CONFIG_PM_DEBUG
+ /* skip enable register */
+ if ((pme_reg + i) != (&save_ccsr->regdb.pmfa.faconf)) {
+ uint32_t pme_reg_val;
+ pme_reg_val = in_be32(regs + i);
+ if (pme_reg_val != *(pme_reg + i))
+ diff_count++;
+ out_be32(regs + i, *(pme_reg + i));
+ }
+#else
/* skip enable register */
if ((pme_reg + i) != (&save_ccsr->regdb.pmfa.faconf))
out_be32(regs + i, *(pme_reg + i));
+#endif
}
+
+#ifdef CONFIG_PM_DEBUG
+ pr_info("pme ccsr restore: %d registers were different\n", diff_count);
+#endif
}
void save_all_ccsr(struct ccsr_backup_info *save_ccsr, uint32_t __iomem *regs)
diff --git a/drivers/staging/fsl_pme2/pme2_private.h b/drivers/staging/fsl_pme2/pme2_private.h
index e1ea3e8..4bd92c2 100644
--- a/drivers/staging/fsl_pme2/pme2_private.h
+++ b/drivers/staging/fsl_pme2/pme2_private.h
@@ -238,6 +238,7 @@ struct portal_backup_info {
struct pmtcc_raw_db db;
struct pme_pwrmgmt_ctx *ctx;
struct platform_device *pdev;
+ int backup_failed;
};
#endif /* CONFIG_PM */
diff --git a/drivers/staging/fsl_pme2/pme2_suspend.c b/drivers/staging/fsl_pme2/pme2_suspend.c
index 4de830b..e2ef2af 100644
--- a/drivers/staging/fsl_pme2/pme2_suspend.c
+++ b/drivers/staging/fsl_pme2/pme2_suspend.c
@@ -40,49 +40,6 @@ static dma_addr_t pme_suspend_map(struct platform_device *pdev, void *ptr)
return dma_map_single(&pdev->dev, ptr, 1, DMA_BIDIRECTIONAL);
}
-#ifdef PME_SUSPEND_DEBUG
-
-static inline void __hexdump(unsigned long start, unsigned long end,
- unsigned long p, size_t sz, const unsigned char *c)
-{
- while (start < end) {
- unsigned int pos = 0;
- char buf[64];
- int nl = 0;
- pos += sprintf(buf + pos, "%08lx: ", start);
- do {
- if ((start < p) || (start >= (p + sz)))
- pos += sprintf(buf + pos, "..");
- else
- pos += sprintf(buf + pos, "%02x", *(c++));
- if (!(++start & 15)) {
- buf[pos++] = '\n';
- nl = 1;
- } else {
- nl = 0;
- if (!(start & 1))
- buf[pos++] = ' ';
- if (!(start & 3))
- buf[pos++] = ' ';
- }
- } while (start & 15);
- if (!nl)
- buf[pos++] = '\n';
- buf[pos] = '\0';
- pr_info("%s", buf);
- }
-}
-
-static inline void hexdump(const void *ptr, size_t sz)
-{
- unsigned long p = (unsigned long)ptr;
- unsigned long start = p & ~(unsigned long)15;
- unsigned long end = (p + sz + 15) & ~(unsigned long)15;
- const unsigned char *c = ptr;
- __hexdump(start, end, p, sz, c);
-}
-#endif
-
/*
* The following SRAM tables need to be saved
* 1-byte trigger table
@@ -197,6 +154,8 @@ struct pme_pmtcc_write_request_msg_t {
#define PME_SPECIAL_CONFIDENCE_ENTRY_NUM 64
#define PME_ONE_BYTE_CONFIDENCE_ENTRY_NUM 64
+#define PME_SPECIAL_CONFIDENCE_ENTRY_NUM_V2_2 32
+
#define PME_CONFIDENCE_ENTRY_NUM_V1 \
((PME_TWO_BYTE_TRIGGER_ENTRY_NUM_V1 + \
PME_VARIABLE_TRIGGER_ENTRY_NUM_V1 + \
@@ -222,7 +181,7 @@ struct pme_pmtcc_write_request_msg_t {
((PME_TWO_BYTE_TRIGGER_ENTRY_NUM_V2_2 + \
PME_VARIABLE_TRIGGER_ENTRY_NUM_V2_2 + \
PME_ONE_BYTE_CONFIDENCE_ENTRY_NUM + \
- PME_SPECIAL_CONFIDENCE_ENTRY_NUM) * \
+ PME_SPECIAL_CONFIDENCE_ENTRY_NUM_V2_2) * \
PME_CONFIDENCE_ENTRY_NUM_PER_TRIGGER_ENTRY)
#define PME_EQUIVALENCE_ENTRY_NUM 1
@@ -351,13 +310,11 @@ static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *portal,
struct pme_pwrmgmt_ctx *ctx = (struct pme_pwrmgmt_ctx *)fq;
if (unlikely(flags & PME_STATUS_UNRELIABLE))
- pr_err("pme error %d\n", __LINE__);
+ pr_err("pme status error 0x%x\n", (u32)flags);
else if (unlikely((serious_error_vec[status])))
- pr_err("pme error %d\n", __LINE__);
- else {
- memcpy(&ctx->result_fd, &dq->fd, sizeof(*&dq->fd));
- complete(&ctx->done);
- }
+ pr_err("pme error status 0x%x\n", (u32)status);
+ memcpy(&ctx->result_fd, &dq->fd, sizeof(*&dq->fd));
+ complete(&ctx->done);
return qman_cb_dqrr_consume;
}
@@ -830,12 +787,16 @@ static int save_all_tables(struct portal_backup_info *save_db,
if (status) {
ret = -EINVAL;
pr_err("PMTCC read status failed %d\n", status);
+ save_db->backup_failed = 1;
+ break;
}
if (pme_fd_res_flags(&save_db->ctx->result_fd) &
PME_STATUS_UNRELIABLE) {
pr_err("pme %x\n", pme_fd_res_flags(
&save_db->ctx->result_fd));
ret = -EINVAL;
+ save_db->backup_failed = 1;
+ break;
}
/* copy the response */
if (tbl_id == PME_UDG_TBL ||
@@ -859,8 +820,11 @@ static int save_all_tables(struct portal_backup_info *save_db,
kfree(output_data);
kfree(input_data);
kfree(sg_table);
+ /* if failed, stop saving database */
+ if (ret)
+ break;
}
- return 0;
+ return ret;
}
/* don't need to write zero to PME sram since POR is all zero */
@@ -938,20 +902,25 @@ static int restore_all_tables(struct portal_backup_info *save_db,
if (status) {
ret = -EINVAL;
pr_err("PMTCC write status fail %d\n", status);
+ break;
}
if (pme_fd_res_flags(&save_db->ctx->result_fd) &
PME_STATUS_UNRELIABLE) {
pr_err("pme %x\n", pme_fd_res_flags(
&save_db->ctx->result_fd));
ret = -EINVAL;
+ break;
}
}
current_tbl += num_write_entries * write_entry_size;
/* Free input and output frame data */
kfree(input_data);
+ /* if failed, stop restoring database */
+ if (ret)
+ break;
}
- return 0;
+ return ret;
}
int fsl_pme_save_db(struct pme2_private_data *priv_data)
@@ -980,6 +949,11 @@ static int is_pme_active(void)
return val;
}
+static void reset_db_saved_state(struct portal_backup_info *db_info)
+{
+ db_info->backup_failed = 0;
+}
+
/**
* pme_suspend - power management suspend function
*
@@ -997,6 +971,8 @@ int pme_suspend(struct pme2_private_data *priv_data)
ccsr_info = &priv_data->save_ccsr;
db_info = &priv_data->save_db;
+ reset_db_saved_state(db_info);
+
pme_attr_get(pme_attr_faconf_en, &ccsr_info->save_faconf_en);
pme_attr_get(pme_attr_cdcr, &ccsr_info->save_cdcr);
@@ -1045,13 +1021,18 @@ int pme_suspend(struct pme2_private_data *priv_data)
pr_info("PME is quiescent\n");
#endif
-#ifdef PME_SUSPEND_DEBUG
- /* set the PME reset bit */
- pme_attr_set(pme_attr_faconf_rst, 1);
- /* clear the PME reset bit */
- pme_attr_set(pme_attr_faconf_rst, 0);
-#endif
-
+ /* if saving db failed, reset internal state explicitly */
+ if (db_info->backup_failed) {
+ /* set the PME reset bit */
+ pme_attr_set(pme_attr_faconf_rst, 1);
+ /* clear the PME reset bit */
+ pme_attr_set(pme_attr_faconf_rst, 0);
+ /* wait until device is not active */
+ while (is_pme_active()) {
+ cpu_relax();
+ /* TODO: sanity check */
+ }
+ }
return 0;
}
@@ -1068,6 +1049,7 @@ int pme_resume(struct pme2_private_data *priv_data)
int ret;
struct ccsr_backup_info *ccsr_info;
struct portal_backup_info *db_info;
+ int db_restore_failed = 0;
ccsr_info = &priv_data->save_ccsr;
db_info = &priv_data->save_db;
@@ -1082,6 +1064,9 @@ int pme_resume(struct pme2_private_data *priv_data)
/* restore caching state */
pme_attr_set(pme_attr_cdcr, ccsr_info->save_cdcr);
+ /* Don't restore database if it wasn't saved properly */
+ if (db_info->backup_failed)
+ goto skip_db_restore;
/* set private exclusive mode before enabling pme */
/* save sram, must first configure the new exclusive fq before
* enabling pme */
@@ -1093,6 +1078,8 @@ int pme_resume(struct pme2_private_data *priv_data)
pme_attr_set(pme_attr_faconf_en, 1);
ret = restore_all_tables(db_info, priv_data->pme_rev1);
+ if (ret)
+ db_restore_failed = 1;
/* disable pme */
pme_attr_set(pme_attr_faconf_en, 0);
@@ -1101,10 +1088,22 @@ int pme_resume(struct pme2_private_data *priv_data)
cpu_relax();
/* TODO: sanity check */
}
+ if (db_restore_failed) {
+ /* set the PME reset bit */
+ pme_attr_set(pme_attr_faconf_rst, 1);
+ /* clear the PME reset bit */
+ pme_attr_set(pme_attr_faconf_rst, 0);
+ /* when PME was saved, it was disabled. Therefore it will
+ * remain disabled */
+ restore_all_ccsr(ccsr_info, priv_data->regs);
+ /* restore caching state */
+ pme_attr_set(pme_attr_cdcr, ccsr_info->save_cdcr);
+ }
/* restore EFQC register */
pme_attr_set(pme_attr_efqc, ccsr_info->regdb.pmfa.efqc);
+skip_db_restore:
/* restore pme enable state */
pme_attr_set(pme_attr_faconf_en, ccsr_info->save_faconf_en);