From d3e65dbba5d08931effa036eeec75a1db0f8d824 Mon Sep 17 00:00:00 2001
From: Anton Blanchard <anton@samba.org>
Date: Fri, 2 Aug 2002 14:05:00 +1000
Subject: [PATCH] ppc64: rwsem updates from ppc32 and synchronize_irq fix from
 x86

---
 arch/ppc64/kernel/i8259.c |  3 ++-
 arch/ppc64/kernel/irq.c   | 13 ++++---------
 include/asm-ppc64/rwsem.h | 40 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/arch/ppc64/kernel/i8259.c b/arch/ppc64/kernel/i8259.c
index 39e690f361a1..f6dc5c7e25db 100644
--- a/arch/ppc64/kernel/i8259.c
+++ b/arch/ppc64/kernel/i8259.c
@@ -123,7 +123,8 @@ static void i8259_unmask_irq(unsigned int irq_nr)
 
 static void i8259_end_irq(unsigned int irq)
 {
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+	    irq_desc[irq].action)
 		i8259_unmask_irq(irq);
 }
 
diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
index 9a1ea633f594..830b1c965a90 100644
--- a/arch/ppc64/kernel/irq.c
+++ b/arch/ppc64/kernel/irq.c
@@ -169,10 +169,6 @@ setup_irq(unsigned int irq, struct irqaction * new)
 
 inline void synchronize_irq(unsigned int irq)
 {
-	/* is there anything to synchronize with? */
-	if (!irq_desc[irq].action)
-		return;
-
 	while (irq_desc[irq].status & IRQ_INPROGRESS)
 		cpu_relax();
 }
@@ -502,7 +498,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
 	 * use the action we have.
 	 */
 	action = NULL;
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
 		action = desc->action;
 		if (!action || !action->handler) {
 			ppc_spurious_interrupts++;
@@ -529,10 +525,9 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
 	   a different instance of this same irq, the other processor
 	   will take care of it.
 	 */
-	if (!action)
+	if (unlikely(!action))
 		goto out;
 
-
 	/*
 	 * Edge triggered interrupts need to remember
 	 * pending events.
@@ -548,12 +543,12 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
 		handle_irq_event(irq, regs, action);
 		spin_lock(&desc->lock);
 		
-		if (!(desc->status & IRQ_PENDING))
+		if (likely(!(desc->status & IRQ_PENDING)))
 			break;
 		desc->status &= ~IRQ_PENDING;
 	}
-	desc->status &= ~IRQ_INPROGRESS;
 out:
+	desc->status &= ~IRQ_INPROGRESS;
 	/*
 	 * The ->end() handler has to deal with interrupts which got
 	 * disabled while the handler was running.
diff --git a/include/asm-ppc64/rwsem.h b/include/asm-ppc64/rwsem.h
index 2395bc8a00f2..affeaf32495d 100644
--- a/include/asm-ppc64/rwsem.h
+++ b/include/asm-ppc64/rwsem.h
@@ -57,6 +57,7 @@ struct rw_semaphore {
 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
 
 static inline void init_rwsem(struct rw_semaphore *sem)
 {
@@ -73,12 +74,26 @@ static inline void init_rwsem(struct rw_semaphore *sem)
  */
 static inline void __down_read(struct rw_semaphore *sem)
 {
-	if (atomic_inc_return((atomic_t *)(&sem->count)) >= 0)
+	if (atomic_inc_return((atomic_t *)(&sem->count)) > 0)
 		smp_wmb();
 	else
 		rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -94,6 +109,16 @@ static inline void __down_write(struct rw_semaphore *sem)
 		rwsem_down_write_failed(sem);
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
@@ -126,6 +151,19 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
 	atomic_add(delta, (atomic_t *)(&sem->count));
 }
 
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	smp_wmb();
+	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+	if (tmp < 0)
+		rwsem_downgrade_wake(sem);
+}
+
 /*
  * implement exchange and add functionality
  */
-- 
2.30.9