patch-2.4.20 linux-2.4.20/drivers/macintosh/via-cuda.c
Next file: linux-2.4.20/drivers/macintosh/via-maciisi.c
Previous file: linux-2.4.20/drivers/macintosh/macio-adb.c
Back to the patch index
Back to the overall index
- Lines: 180
- Date:
Thu Nov 28 15:53:13 2002
- Orig file:
linux-2.4.19/drivers/macintosh/via-cuda.c
- Orig date:
Fri Aug 2 17:39:44 2002
diff -urN linux-2.4.19/drivers/macintosh/via-cuda.c linux-2.4.20/drivers/macintosh/via-cuda.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/adb.h>
#include <linux/cuda.h>
+#include <linux/spinlock.h>
#ifdef CONFIG_PPC
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -31,6 +32,7 @@
#include <linux/init.h>
static volatile unsigned char *via;
+static spinlock_t cuda_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_MAC
#define CUDA_IRQ IRQ_MAC_ADB
@@ -125,7 +127,7 @@
#endif /* CONFIG_ADB */
#ifdef CONFIG_PPC
-int
+int __init
find_via_cuda(void)
{
int err;
@@ -186,12 +188,15 @@
}
#endif /* CONFIG_PPC */
-int via_cuda_start(void)
+int __init
+via_cuda_start(void)
{
if (via == NULL)
return -ENODEV;
+#ifdef CONFIG_PPC
request_OF_resource(vias, 0, NULL);
+#endif
if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
@@ -219,7 +224,7 @@
return 0;
}
-static int
+static int __init
cuda_init(void)
{
#ifdef CONFIG_PPC
@@ -382,8 +387,8 @@
req->sent = 0;
req->complete = 0;
req->reply_len = 0;
- save_flags(flags); cli();
+ spin_lock_irqsave(&cuda_lock, flags);
if (current_req != 0) {
last_req->next = req;
last_req = req;
@@ -393,15 +398,14 @@
if (cuda_state == idle)
cuda_start();
}
+ spin_unlock_irqrestore(&cuda_lock, flags);
- restore_flags(flags);
return 0;
}
static void
cuda_start()
{
- unsigned long flags;
struct adb_request *req;
/* assert cuda_state == idle */
@@ -409,41 +413,46 @@
req = current_req;
if (req == 0)
return;
- save_flags(flags); cli();
- if ((via[B] & TREQ) == 0) {
- restore_flags(flags);
+ if ((via[B] & TREQ) == 0)
return; /* a byte is coming in from the CUDA */
- }
/* set the shift register to shift out and send a byte */
via[ACR] |= SR_OUT; eieio();
via[SR] = req->data[0]; eieio();
via[B] &= ~TIP;
cuda_state = sent_first_byte;
- restore_flags(flags);
}
void
cuda_poll()
{
- unsigned long flags;
+ if (via[IFR] & SR_INT) {
+ unsigned long flags;
- save_flags(flags);
- cli();
- if (via[IFR] & SR_INT)
+ /* cuda_interrupt only takes a normal lock, we disable
+ * interrupts here to avoid re-entering and thus deadlocking.
+ * An option would be to disable only the IRQ source with
+ * disable_irq(), would that work on m68k ? --BenH
+ */
+ local_irq_save(flags);
cuda_interrupt(0, 0, 0);
- restore_flags(flags);
+ local_irq_restore(flags);
+ }
}
static void
cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
{
int x, status;
- struct adb_request *req;
-
+ struct adb_request *req = NULL;
+ unsigned char ibuf[16];
+ int ibuf_len = 0;
+ int complete = 0;
+
if ((via[IFR] & SR_INT) == 0)
return;
+ spin_lock(&cuda_lock);
status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
/* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
switch (cuda_state) {
@@ -498,8 +507,7 @@
cuda_state = awaiting_reply;
} else {
current_req = req->next;
- if (req->done)
- (*req->done)(req);
+ complete = 1;
/* not sure about this */
cuda_state = idle;
cuda_start();
@@ -542,10 +550,17 @@
}
req->complete = 1;
current_req = req->next;
- if (req->done)
- (*req->done)(req);
+ complete = 1;
} else {
- cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+ /* This is tricky. We must break the spinlock to call
+ * cuda_input. However, doing so means we might get
+ * re-entered from another CPU getting an interrupt
+ * or calling cuda_poll(). I ended up using the stack
+ * (it's only for 16 bytes) and moving the actual
+ * call to cuda_input to outside of the lock.
+ */
+ ibuf_len = reply_ptr - cuda_rbuf;
+ memcpy(ibuf, cuda_rbuf, ibuf_len);
}
if (status == TREQ) {
via[B] &= ~TIP; eieio();
@@ -561,6 +576,11 @@
default:
printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
}
+ spin_unlock(&cuda_lock);
+ if (complete && req && req->done)
+ (*req->done)(req);
+ if (ibuf_len)
+ cuda_input(ibuf, ibuf_len, regs);
}
static void
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)