[linux-yocto] [PATCH 3/5] misc: lsi-ncr: Locking Mechanism Update

Daniel Dragomir daniel.dragomir at windriver.com
Mon Feb 9 09:42:25 PST 2015


From: Gary McGee <gary.mcgee at lsi.com>

Allow for other drivers to share the locking mechanisms for
lsi-ncr h/w - provide unlocked methods for read/write - provide
consistent way of detecting/reporting lsi-ncr errors

Signed-off-by: Gary McGee <gary.mcgee at lsi.com>
---
 drivers/misc/lsi-ncr.c | 308 ++++++++++++++++++++++++++++++-------------------
 drivers/misc/lsi-ncr.h |   2 +
 2 files changed, 189 insertions(+), 121 deletions(-)

diff --git a/drivers/misc/lsi-ncr.c b/drivers/misc/lsi-ncr.c
index 20101ef..16b1907 100644
--- a/drivers/misc/lsi-ncr.c
+++ b/drivers/misc/lsi-ncr.c
@@ -42,7 +42,10 @@ static void __iomem *apb2ser0_address;
 #define WFC_TIMEOUT (400000)
 
 static DEFINE_RAW_SPINLOCK(ncr_spin_lock);
-static unsigned long flags;
+static DEFINE_RAW_SPINLOCK(nca_access_lock);
+EXPORT_SYMBOL(nca_access_lock);
+static unsigned long ncr_spin_flags, axi_access_flags;
+
 
 #define LOCK_DOMAIN 0
 
@@ -93,6 +96,10 @@ typedef union {
 	} __packed bits;
 } __packed command_data_register_2_t;
 
+int
+ncr_read_nolock(unsigned long region, unsigned long address, int number,
+void *buffer);
+
 #ifdef CONFIG_ARM
 
 /*
@@ -165,6 +172,42 @@ ncr_register_write(const unsigned value, unsigned *address)
 #endif
 
 /*
+  ----------------------------------------------------------------------
+  nca_register_read
+*/
+
+inline unsigned long
+nca_register_read(unsigned *address)
+{
+	unsigned long value;
+
+	raw_spin_lock_irqsave(&nca_access_lock,
+		axi_access_flags);
+	value = ncr_register_read(address);
+	raw_spin_unlock_irqrestore(&nca_access_lock,
+		axi_access_flags);
+
+	return value;
+}
+
+/*
+  ----------------------------------------------------------------------
+  nca_register_write
+*/
+
+void
+inline nca_register_write(const unsigned value, unsigned *address)
+{
+	raw_spin_lock_irqsave(&nca_access_lock,
+		axi_access_flags);
+	ncr_register_write(value, address);
+	raw_spin_unlock_irqrestore(&nca_access_lock,
+		axi_access_flags);
+
+	return;
+}
+
+/*
   ------------------------------------------------------------------------------
   ncr_lock
 */
@@ -175,42 +218,21 @@ ncr_lock(int domain)
 	unsigned long offset;
 	unsigned long value;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-	command_data_register_0_t cdr0;
 
-	raw_spin_lock_irqsave(&ncr_spin_lock, flags);
+	raw_spin_lock_irqsave(&ncr_spin_lock, ncr_spin_flags);
 	offset = (0xff80 + (domain * 4));
 
 	do {
-		value = ncr_register_read((unsigned *)(nca_address + offset));
+		value = nca_register_read((unsigned *)(nca_address + offset));
 	} while ((0 != value) && (time_before(jiffies, timeout)));
 
 	if (!(time_before(jiffies, timeout))) {
-		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
+		raw_spin_unlock_irqrestore(&ncr_spin_lock, ncr_spin_flags);
 		pr_err("ncr_lock() Timeout!\n");
 		BUG();
 
 		return -1;
 	}
-	/*
-	  Make sure any previous commands completed, and check for errors.
-	*/
-	timeout = jiffies + msecs_to_jiffies(1000);
-
-	do {
-		cdr0.raw =
-			ncr_register_read((unsigned *)(nca_address + 0xf0));
-	} while ((0x1 == cdr0.bits.status) &&
-		(time_before(jiffies, timeout)));
-
-	if (!(time_before(jiffies, timeout))) {
-		raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
-		pr_err("ncr_lock() Previous command didn't complete!\n");
-		BUG();
-
-		return -1;
-	}
-	if (0x2 == cdr0.bits.status)
-		pr_err("Previous ncr access failed!\n");
 
 	return 0;
 }
@@ -227,13 +249,75 @@ ncr_unlock(int domain)
 	unsigned long offset;
 
 	offset = (0xff80 + (domain * 4));
-	ncr_register_write(0, (unsigned *)(nca_address + offset));
-	raw_spin_unlock_irqrestore(&ncr_spin_lock, flags);
+	nca_register_write(0, (unsigned *)(nca_address + offset));
+	raw_spin_unlock_irqrestore(&ncr_spin_lock, ncr_spin_flags);
 
 	return;
 }
 EXPORT_SYMBOL(ncr_unlock);
 
+
+/*
+  ------------------------------------------------------------------------------
+  ncr_pio_error_dump
+*/
+
+static void
+ncr_pio_error_dump(char *str)
+{
+	unsigned long cdr0, cdr1, cdr2;
+	unsigned long stat0, stat1;
+
+	cdr0 = nca_register_read((unsigned *)(nca_address + 0xf0));
+	cdr1 = nca_register_read((unsigned *)(nca_address + 0xf4));
+	cdr2 = nca_register_read((unsigned *)(nca_address + 0xf8));
+
+	stat0 = nca_register_read((unsigned *)(nca_address + 0xe4));
+	stat1 = nca_register_read((unsigned *)(nca_address + 0xe8));
+
+	pr_err("lsi-ncr: %8s failed, error status : 0x%08lx 0x%08lx\n",
+			str, stat0, stat1);
+	pr_err("lsi-ncr:  CDR0-2: 0x%08lx 0x%08lx 0x%08lx\n",
+			cdr0, cdr1, cdr2);
+
+}
+/*
+  ------------------------------------------------------------------------------
+  ncr_check_pio_status
+*/
+
+static int
+ncr_check_pio_status(char *str)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+	command_data_register_0_t cdr0;
+
+	/*
+	  Make sure any previous commands completed, and check for errors.
+	*/
+
+	do {
+		cdr0.raw =
+			nca_register_read((unsigned *)(nca_address + 0xf0));
+	} while ((0x1 == cdr0.bits.status) &&
+		(time_before(jiffies, timeout)));
+
+	if (!(time_before(jiffies, timeout))) {
+		raw_spin_unlock_irqrestore(&ncr_spin_lock, ncr_spin_flags);
+		pr_err("ncr_check_pio_status() PIO operation timeout!\n");
+		BUG();
+
+		return -1;
+	}
+	if (0x3 != cdr0.bits.status) {
+		ncr_pio_error_dump(str);
+	/* clear CDR0 to allow subsequent commands to complete */
+		nca_register_write(0, (unsigned *) (nca_address + 0xf0));
+	}
+
+	return 0;
+}
+
 /*
   ======================================================================
   ======================================================================
@@ -248,7 +332,7 @@ EXPORT_SYMBOL(ncr_unlock);
 */
 
 int
-ncr_read(unsigned long region, unsigned long address, int number,
+ncr_read_nolock(unsigned long region, unsigned long address, int number,
 	void *buffer)
 {
 	command_data_register_0_t cdr0;
@@ -256,18 +340,11 @@ ncr_read(unsigned long region, unsigned long address, int number,
 	command_data_register_2_t cdr2;
 	int wfc_timeout = WFC_TIMEOUT;
 
-	if (NULL == nca_address)
-		return -1;
-
-#ifdef APB2SER_PHY_PHYS_ADDRESS
-	if (NULL == apb2ser0_address)
-		return -1;
-#endif /* APB2SER_PHY_PHYS_ADDRESS */
-
-	if (0 != ncr_lock(LOCK_DOMAIN))
-		return -1;
-
 	if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) {
+		/* make sure any previous command has completed */
+		if (0 != ncr_check_pio_status("previous"))
+			return -1;
+
 		/*
 		Set up the read command.
 		*/
@@ -275,11 +352,11 @@ ncr_read(unsigned long region, unsigned long address, int number,
 		cdr2.raw = 0;
 		cdr2.bits.target_node_id = NCP_NODE_ID(region);
 		cdr2.bits.target_id_address_upper = NCP_TARGET_ID(region);
-		ncr_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
+		nca_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
 
 		cdr1.raw = 0;
 		cdr1.bits.target_address = (address >> 2);
-		ncr_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
+		nca_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
 
 		cdr0.raw = 0;
 		cdr0.bits.start_done = 1;
@@ -290,35 +367,14 @@ ncr_read(unsigned long region, unsigned long address, int number,
 		cdr0.bits.cmd_type = 4;
 		/* TODO: Verify number... */
 		cdr0.bits.dbs = (number - 1);
-		ncr_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
+		nca_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
 		mb();
 
 		/*
 		Wait for completion.
 		*/
-
-		do {
-			--wfc_timeout;
-			cdr0.raw =
-				ncr_register_read((unsigned *)
-						  (nca_address + 0xf0));
-		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
-
-		if (0 == wfc_timeout) {
-			ncr_unlock(LOCK_DOMAIN);
-			pr_err("ncr_read() Timeout!\n");
-			BUG();
-
-			return -1;
-		}
-
-		if (0x3 != cdr0.bits.status) {
-			ncr_unlock(LOCK_DOMAIN);
-			pr_err("ncr_write() failed: 0x%x\n",
-			       cdr0.bits.status);
-
+		if (0 != ncr_check_pio_status("read"))
 			return -1;
-		}
 
 		/*
 		Copy data words to the buffer.
@@ -327,7 +383,7 @@ ncr_read(unsigned long region, unsigned long address, int number,
 		address = (unsigned long)(nca_address + 0x1000);
 		while (4 <= number) {
 			*((unsigned long *) buffer) =
-				ncr_register_read((unsigned *) address);
+				nca_register_read((unsigned *) address);
 			address += 4;
 			buffer += 4;
 			number -= 4;
@@ -335,7 +391,7 @@ ncr_read(unsigned long region, unsigned long address, int number,
 
 		if (0 < number) {
 			unsigned long temp =
-				ncr_register_read((unsigned *) address);
+				nca_register_read((unsigned *) address);
 			memcpy((void *) buffer, &temp, number);
 		}
 	} else {
@@ -356,7 +412,6 @@ ncr_read(unsigned long region, unsigned long address, int number,
 		} else {
 			void __iomem *base;
 			if (0xffff < address) {
-				ncr_unlock(LOCK_DOMAIN);
 				return -1;
 			}
 
@@ -380,7 +435,6 @@ ncr_read(unsigned long region, unsigned long address, int number,
 				base = (apb2ser0_address + 0x230);
 				break;
 			default:
-				ncr_unlock(LOCK_DOMAIN);
 				return -1;
 			}
 			if ((NCP_TARGET_ID(region) == 0x1) ||
@@ -397,7 +451,6 @@ ncr_read(unsigned long region, unsigned long address, int number,
 					&& 0 < wfc_timeout);
 
 			if (0 == wfc_timeout) {
-				ncr_unlock(LOCK_DOMAIN);
 				return -1;
 			}
 
@@ -412,15 +465,41 @@ ncr_read(unsigned long region, unsigned long address, int number,
 
 		}
 #else
-		ncr_unlock(LOCK_DOMAIN);
 		return -1;
 #endif /* APB2SER_PHY_PHYS_ADDRESS */
 	}
 
-	ncr_unlock(LOCK_DOMAIN);
 
 	return 0;
 }
+EXPORT_SYMBOL(ncr_read_nolock);
+
+
+int
+ncr_read(unsigned long region, unsigned long address, int number,
+	void *buffer)
+{
+
+	int	rc;
+
+	if (NULL == nca_address)
+		return -1;
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+	if (NULL == apb2ser0_address)
+		return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+	if (0 != ncr_lock(LOCK_DOMAIN))
+		return -1;
+
+
+	rc = ncr_read_nolock(region, address, number, buffer);
+
+	ncr_unlock(LOCK_DOMAIN);
+
+	return rc;
+}
 EXPORT_SYMBOL(ncr_read);
 
 /*
@@ -429,7 +508,7 @@ EXPORT_SYMBOL(ncr_read);
 */
 
 int
-ncr_write(unsigned long region, unsigned long address, int number,
+ncr_write_nolock(unsigned long region, unsigned long address, int number,
 	  void *buffer)
 {
 	command_data_register_0_t cdr0;
@@ -439,18 +518,11 @@ ncr_write(unsigned long region, unsigned long address, int number,
 	int dbs = (number - 1);
 	int wfc_timeout = WFC_TIMEOUT;
 
-	if (NULL == nca_address)
-		return -1;
-
-#ifdef APB2SER_PHY_PHYS_ADDRESS
-	if (NULL == apb2ser0_address)
-		return -1;
-#endif /* APB2SER_PHY_PHYS_ADDRESS */
-
-	if (0 != ncr_lock(LOCK_DOMAIN))
-		return -1;
-
 	if ((NCP_NODE_ID(region) != 0x0153) && (NCP_NODE_ID(region) != 0x115)) {
+		/* make sure any previous command has completed */
+		if (0 != ncr_check_pio_status("previous"))
+			return -1;
+
 		/*
 		  Set up the write.
 		*/
@@ -458,11 +530,11 @@ ncr_write(unsigned long region, unsigned long address, int number,
 		cdr2.raw = 0;
 		cdr2.bits.target_node_id = NCP_NODE_ID(region);
 		cdr2.bits.target_id_address_upper = NCP_TARGET_ID(region);
-		ncr_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
+		nca_register_write(cdr2.raw, (unsigned *) (nca_address + 0xf8));
 
 		cdr1.raw = 0;
 		cdr1.bits.target_address = (address >> 2);
-		ncr_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
+		nca_register_write(cdr1.raw, (unsigned *) (nca_address + 0xf4));
 
 		/*
 		  Copy from buffer to the data words.
@@ -471,7 +543,7 @@ ncr_write(unsigned long region, unsigned long address, int number,
 		data_word_base = (unsigned long)(nca_address + 0x1000);
 
 		while (4 <= number) {
-			ncr_register_write(*((unsigned long *) buffer),
+			nca_register_write(*((unsigned long *) buffer),
 					(unsigned *) data_word_base);
 			data_word_base += 4;
 			buffer += 4;
@@ -482,7 +554,7 @@ ncr_write(unsigned long region, unsigned long address, int number,
 			unsigned long temp = 0;
 
 			memcpy((void *) &temp, (void *) buffer, number);
-			ncr_register_write(temp, (unsigned *) data_word_base);
+			nca_register_write(temp, (unsigned *) data_word_base);
 			data_word_base += number;
 			buffer += number;
 			number = 0;
@@ -497,43 +569,16 @@ ncr_write(unsigned long region, unsigned long address, int number,
 		cdr0.bits.cmd_type = 5;
 		/* TODO: Verify number... */
 		cdr0.bits.dbs = dbs;
-		ncr_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
+		nca_register_write(cdr0.raw, (unsigned *) (nca_address + 0xf0));
 		mb();
 
 		/*
 		Wait for completion.
 		*/
 
-		do {
-			--wfc_timeout;
-			cdr0.raw =
-				ncr_register_read((unsigned *)
-						  (nca_address + 0xf0));
-		} while (1 == cdr0.bits.start_done && 0 < wfc_timeout);
-
-		if (0 == wfc_timeout) {
-			ncr_unlock(LOCK_DOMAIN);
-			pr_err("ncr_write() Timeout!\n");
-			BUG();
-
+		if (0 != ncr_check_pio_status("write"))
 			return -1;
-		}
-
-		/*
-		Check status.
-		*/
 
-		if ((0x3 != cdr0.bits.status) && (0x00c00000) >> 22) {
-			unsigned long status;
-
-			status = ncr_register_read((unsigned *)(nca_address +
-								0xe4));
-			ncr_unlock(LOCK_DOMAIN);
-			pr_err("ncr_write() Error: 0x%x 0x%lx\n",
-			       cdr0.bits.status, status);
-
-			return status;
-		}
 	} else {
 #ifdef APB2SER_PHY_PHYS_ADDRESS
 	if (NCP_NODE_ID(region) != 0x115) {
@@ -552,7 +597,6 @@ ncr_write(unsigned long region, unsigned long address, int number,
 	} else {
 		void __iomem *base;
 		if (0xffff < address) {
-			ncr_unlock(LOCK_DOMAIN);
 			return -1;
 		}
 
@@ -576,7 +620,6 @@ ncr_write(unsigned long region, unsigned long address, int number,
 			base = (apb2ser0_address + 0x230);
 			break;
 		default:
-			ncr_unlock(LOCK_DOMAIN);
 			return -1;
 		}
 		if ((NCP_TARGET_ID(region) == 0x1) ||
@@ -595,20 +638,43 @@ ncr_write(unsigned long region, unsigned long address, int number,
 				&& 0 < wfc_timeout);
 
 			if (0 == wfc_timeout) {
-				ncr_unlock(LOCK_DOMAIN);
 				return -1;
 			}
 		}
 #else
-		ncr_unlock(LOCK_DOMAIN);
 		return -1;
 #endif /* APB2SER_PHY_PHYS_ADDRESS */
 	}
 
+	return 0;
+}
+EXPORT_SYMBOL(ncr_write_nolock);
+
+
+int
+ncr_write(unsigned long region, unsigned long address, int number,
+	  void *buffer)
+{
+	int rc = 0;
+
+	if (NULL == nca_address)
+		return -1;
+
+#ifdef APB2SER_PHY_PHYS_ADDRESS
+	if (NULL == apb2ser0_address)
+		return -1;
+#endif /* APB2SER_PHY_PHYS_ADDRESS */
+
+	if (0 != ncr_lock(LOCK_DOMAIN))
+		return -1;
+
+	rc = ncr_write_nolock(region, address, number, buffer);
+
 	ncr_unlock(LOCK_DOMAIN);
 
-	return 0;
+	return rc;
 }
+
 EXPORT_SYMBOL(ncr_write);
 
 /*
diff --git a/drivers/misc/lsi-ncr.h b/drivers/misc/lsi-ncr.h
index cb6bebb..db54f6b 100644
--- a/drivers/misc/lsi-ncr.h
+++ b/drivers/misc/lsi-ncr.h
@@ -38,5 +38,7 @@ unsigned long ncr_register_read(unsigned *);
 void ncr_register_write(const unsigned, unsigned *);
 int ncr_read(unsigned long, unsigned long, int, void *);
 int ncr_write(unsigned long, unsigned long, int, void *);
+int ncr_read_nolock(unsigned long, unsigned long, int, void *);
+int ncr_write_nolock(unsigned long, unsigned long, int, void *);
 
 #endif /*  __DRIVERS_LSI_ACP_NCR_H */
-- 
1.8.1.4



More information about the linux-yocto mailing list