summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaj Rajasekaran <b10872@freescale.com>2009-09-24 14:24:25 -0500
committerRaj Rajasekaran <b10872@freescale.com>2009-10-12 13:49:07 -0500
commit503ce6aa61c66e68af47749b79673554ee1413c3 (patch)
treeef414ebf8e0b2d7eae810efa4b7dae71f7a66bf6
parent11c45f4f5858a15bf4ac13b0c8ae89a2f634b5e1 (diff)
ENGR00116798:MX51: Add support to handle potential hang on SCC HW failute.
-Added kernel error message to handle hang due to SCC HW failure. -Eliminated unwanted sleeps. -Kernel error message to handle the case when SCC key fuses are not blown. Signed-off-by: Raj Rajasekaran <b10872@freescale.com>
-rw-r--r--arch/arm/mach-mx51/devices.c167
-rw-r--r--include/linux/mxc_scc2_driver.h2
2 files changed, 132 insertions, 37 deletions
diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c
index 07cc40c2c5d4..495d1043a93f 100644
--- a/arch/arm/mach-mx51/devices.c
+++ b/arch/arm/mach-mx51/devices.c
@@ -386,12 +386,13 @@ static struct platform_device mxc_scc_device = {
.name = "mxc_scc",
.id = 0,
};
-
static void mxc_init_scc(void)
{
platform_device_register(&mxc_scc_device);
}
#else
+#define SCM_RD_DELAY 1000000 /* in nanoseconds */
+#define SEC_TO_NANOSEC 1000000000 /*Second to nanoseconds */
static inline void mxc_init_scc(void)
{
uint32_t reg_value;
@@ -404,6 +405,11 @@ static inline void mxc_init_scc(void)
void *scm_ram_base;
void *scc_base;
uint8_t iram_partitions = 16;
+ struct timespec stime;
+ struct timespec curtime;
+ long scm_rd_timeout = 0;
+ long cur_ns = 0;
+ long start_ns = 0;
if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0)
iram_partitions = 12;
@@ -419,59 +425,146 @@ static inline void mxc_init_scc(void)
return;
}
- for (partition_no = 0; partition_no < iram_partitions; partition_no++) {
- /*De-allocate a Partition*/
- reg_value = ((partition_no << SCM_ZCMD_PART_SHIFT) &
- SCM_ZCMD_PART_MASK) | ((0x03 <<
- SCM_ZCMD_CCMD_SHIFT)
- & SCM_ZCMD_CCMD_MASK);
- __raw_writel(reg_value, scc_base + SCM_ZCMD_REG);
- msleep(1);
- while ((__raw_readl(scc_base + SCM_STATUS_REG) &
- SCM_STATUS_SRS_READY) != SCM_STATUS_SRS_READY) ;
+ /* Wait for any running SCC operations to finish or fail */
+ getnstimeofday(&stime);
+ do {
+ reg_value = __raw_readl(scc_base + SCM_STATUS_REG);
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec > stime.tv_nsec)
+ scm_rd_timeout = curtime.tv_nsec - stime.tv_nsec;
+ else{
+ /*Converted second to nanosecond and add to
+ nsec when current nanosec is less than
+ start time nanosec.*/
+ cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) +
+ curtime.tv_nsec;
+ start_ns = (stime.tv_sec * SEC_TO_NANOSEC) +
+ stime.tv_nsec;
+ scm_rd_timeout = cur_ns - start_ns;
+ }
+ } while (((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY)
+ && ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_FAIL));
- /*In Supervisor mode claims a partition for it's own use
- by writing zero to SMID register.*/
- __raw_writel(0, scc_base + (SCM_SMID0_REG + 8 * partition_no));
+ /* Check for failures */
+ if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY) {
+ /* Special message for bad secret key fuses */
+ if (reg_value & SCM_STATUS_KST_BAD_KEY)
+ printk(KERN_ERR "INVALID SCC KEY FUSE PATTERN\n");
+ else
+ printk(KERN_ERR "SECURE RAM FAILURE\n");
- reg_mask |= (3 << (2 * (partition_no)));
+ iounmap(scm_ram_base);
+ iounmap(scc_base);
+ return;
}
- msleep(1);
- reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG);
+ scm_rd_timeout = 0;
+ /* Release final two partitions for SCC2 driver */
+ scc_partno = iram_partitions - (SCC_IRAM_SIZE / SZ_8K);
+ for (partition_no = scc_partno; partition_no < iram_partitions;
+ partition_no++) {
+ reg_value = (((partition_no << SCM_ZCMD_PART_SHIFT) &
+ SCM_ZCMD_PART_MASK) | ((0x03 << SCM_ZCMD_CCMD_SHIFT) &
+ SCM_ZCMD_CCMD_MASK));
+ __raw_writel(reg_value, scc_base + SCM_ZCMD_REG);
+ udelay(1);
+ /* Wait for zeroization to complete */
+ getnstimeofday(&stime);
+ do {
+ reg_value = __raw_readl(scc_base + SCM_STATUS_REG);
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec > stime.tv_nsec)
+ scm_rd_timeout = curtime.tv_nsec -
+ stime.tv_nsec;
+ else {
+ /*Converted second to nanosecond and add to
+ nsec when current nanosec is less than
+ start time nanosec.*/
+ cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) +
+ curtime.tv_nsec;
+ start_ns = (stime.tv_sec * SEC_TO_NANOSEC) +
+ stime.tv_nsec;
+ scm_rd_timeout = cur_ns - start_ns;
+ }
+ } while (((reg_value & SCM_STATUS_SRS_MASK) !=
+ SCM_STATUS_SRS_READY) && ((reg_value & SCM_STATUS_SRS_MASK) !=
+ SCM_STATUS_SRS_FAIL) && (scm_rd_timeout <= SCM_RD_DELAY));
+
+ if (scm_rd_timeout > SCM_RD_DELAY)
+ printk(KERN_ERR "SCM Status Register Read timeout"
+ "for Partition No:%d", partition_no);
+
+ if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY)
+ break;
+ }
- if ((reg_value & reg_mask) != reg_mask) {
- printk(KERN_ERR "FAILED TO ACQUIRE IRAM PARTITION\n");
+ /*Check all expected partitions released */
+ reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG);
+ if ((reg_value & reg_mask) != 0) {
+ printk(KERN_ERR "FAILED TO RELEASE IRAM PARTITION\n");
iounmap(scm_ram_base);
iounmap(scc_base);
return;
}
-
- for (partition_no = 0; partition_no < iram_partitions; partition_no++) {
+ reg_mask = 0;
+ scm_rd_timeout = 0;
+ /* Allocate remaining partitions for general use */
+ for (partition_no = 0; partition_no < scc_partno; partition_no++) {
+ /* Supervisor mode claims a partition for it's own use
+ by writing zero to SMID register.*/
+ __raw_writel(0, scc_base + (SCM_SMID0_REG + 8 * partition_no));
+
+ /* Wait for any zeroization to complete */
+ getnstimeofday(&stime);
+ do {
+ reg_value = __raw_readl(scc_base + SCM_STATUS_REG);
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec > stime.tv_nsec)
+ scm_rd_timeout = curtime.tv_nsec -
+ stime.tv_nsec;
+ else{
+ /*Converted second to nanosecond and add to
+ nsec when current nanosec is less than
+ start time nanosec.*/
+ cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) +
+ curtime.tv_nsec;
+ start_ns = (stime.tv_sec * SEC_TO_NANOSEC) +
+ stime.tv_nsec;
+ scm_rd_timeout = cur_ns - start_ns;
+ }
+ } while (((reg_value & SCM_STATUS_SRS_MASK) !=
+ SCM_STATUS_SRS_READY) && ((reg_value & SCM_STATUS_SRS_MASK) !=
+ SCM_STATUS_SRS_FAIL) && (scm_rd_timeout <= SCM_RD_DELAY));
+
+ if (scm_rd_timeout > SCM_RD_DELAY)
+ printk(KERN_ERR "SCM Status Register Read timeout"
+ "for Partition No:%d", partition_no);
+
+ if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY)
+ break;
+ /* Set UMID=0 and permissions for universal data
+ read/write access */
MAP_base = scm_ram_base + (partition_no * 0x2000);
UMID_base = (uint8_t *) MAP_base + 0x10;
-
for (i = 0; i < 16; i++)
UMID_base[i] = 0;
- MAP_base[0] = SCM_PERM_NO_ZEROIZE | SCM_PERM_HD_SUP_DISABLE |
- SCM_PERM_HD_READ | SCM_PERM_HD_WRITE | SCM_PERM_HD_EXECUTE |
- SCM_PERM_TH_READ | SCM_PERM_TH_WRITE ;
+ MAP_base[0] = (SCM_PERM_NO_ZEROIZE | SCM_PERM_HD_SUP_DISABLE |
+ SCM_PERM_HD_READ | SCM_PERM_HD_WRITE |
+ SCM_PERM_HD_EXECUTE | SCM_PERM_TH_READ |
+ SCM_PERM_TH_WRITE);
+ reg_mask |= (3 << (2 * (partition_no)));
}
- /* Freeing 2 partitions for SCC2 */
- scc_partno = iram_partitions - (SCC_IRAM_SIZE / SZ_8K);
- for (partition_no = scc_partno; partition_no < iram_partitions;
- partition_no++) {
- reg_value = ((partition_no << SCM_ZCMD_PART_SHIFT) &
- SCM_ZCMD_PART_MASK) | ((0x03 <<
- SCM_ZCMD_CCMD_SHIFT)
- & SCM_ZCMD_CCMD_MASK);
- __raw_writel(reg_value, scc_base + SCM_ZCMD_REG);
- msleep(1);
- while ((__raw_readl(scc_base + SCM_STATUS_REG) &
- SCM_STATUS_SRS_READY) != SCM_STATUS_SRS_READY) ;
+ /* Check all expected partitions allocated */
+ reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG);
+ if ((reg_value & reg_mask) != reg_mask) {
+ printk(KERN_ERR "FAILED TO ACQUIRE IRAM PARTITION\n");
+ iounmap(scm_ram_base);
+ iounmap(scc_base);
+ return;
}
+
iounmap(scm_ram_base);
iounmap(scc_base);
printk(KERN_INFO "IRAM READY\n");
diff --git a/include/linux/mxc_scc2_driver.h b/include/linux/mxc_scc2_driver.h
index f8a24f278b1c..5f84545bc0d0 100644
--- a/include/linux/mxc_scc2_driver.h
+++ b/include/linux/mxc_scc2_driver.h
@@ -737,6 +737,8 @@ scc_verify_slot_access(uint64_t owner_id, uint32_t slot, uint32_t access_len);*/
#define SCM_STATUS_SRS_ZDONE2 0x7 /**< Zeroize Done, Cipher Busy */
#define SCM_STATUS_SRS_CDONE2 0x8 /**< Cipher Done, Zeroize Busy */
#define SCM_STATUS_SRS_ADONE 0xD /**< All Done */
+#define SCM_STATUS_SRS_FAIL 0xF /**< Fail State */
+
/* Format of the SCM VERSION ID REGISTER */
#define SCM_VER_BPP_MASK 0xFF000000 /**< Bytes Per Partition Mask */