Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-12 Thread Finn Thain

On Mon, 12 Dec 2011, Benjamin Herrenschmidt wrote:

 Any chance you can test this patch ? I would not be surprised if it 
 broke m68k since I had to do some of the changes in there blind, so 
 let me know... with this, I can again suspend/resume properly on a Pismo 
 while using the internal modem among other things.

The patch works on a PowerBook 520 given a few changes (below). This 
PowerBook only has one serial port that I can test (the internal modem is 
not supported on 68k Macs). Can you test a machine with two ports? The 
rest of my Mac hardware is in storage since I moved house last week.

Finn


Index: linux-git/drivers/tty/serial/pmac_zilog.c
===
--- linux-git.orig/drivers/tty/serial/pmac_zilog.c  2011-12-13 
00:18:02.0 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.c   2011-12-13 00:23:55.0 
+1100
@@ -1705,8 +1705,8 @@ static int __init pmz_init_port(struct u
struct resource *r_ports;
int irq;
 
-   r_ports = platform_get_resource(uap-node, IORESOURCE_MEM, 0);
-   irq = platform_get_irq(uap-node, 0);
+   r_ports = platform_get_resource(uap-pdev, IORESOURCE_MEM, 0);
+   irq = platform_get_irq(uap-pdev, 0);
if (!r_ports || !irq)
return -ENODEV;
 
@@ -1763,8 +1763,10 @@ static void pmz_dispose_port(struct uart
 
 static int __init pmz_attach(struct platform_device *pdev)
 {
+   struct uart_pmac_port *uap;
int i;
 
+   /* Iterate the pmz_ports array to find a matching entry */
for (i = 0; i  pmz_ports_count; i++)
if (pmz_ports[i].pdev == pdev)
break;
@@ -1773,15 +1775,23 @@ static int __init pmz_attach(struct plat
 
uap = pmz_ports[i];
uap-port.dev = pdev-dev;
-   dev_set_drvdata(mdev-ofdev.dev, uap);
+   platform_set_drvdata(pdev, uap);
 
-   return uart_add_one_port(pmz_uart_reg,
-pmz_ports[i]-port);
+   return uart_add_one_port(pmz_uart_reg, uap-port);
 }
 
 static int __exit pmz_detach(struct platform_device *pdev)
 {
+   struct uart_pmac_port *uap = platform_get_drvdata(pdev);
+
+   if (!uap)
+   return -ENODEV;
+
uart_remove_one_port(pmz_uart_reg, uap-port);
+
+   platform_set_drvdata(pdev, NULL);
+   uap-port.dev = NULL;
+
return 0;
 }
 
@@ -1918,8 +1928,13 @@ static void __exit exit_pmz(void)
 
for (i = 0; i  pmz_ports_count; i++) {
struct uart_pmac_port *uport = pmz_ports[i];
+#ifdef CONFIG_PPC_PMAC
if (uport-node != NULL)
pmz_dispose_port(uport);
+#else
+   if (uport-pdev != NULL)
+   pmz_dispose_port(uport);
+#endif
}
/* Unregister UART driver */
uart_unregister_driver(pmz_uart_reg);
@@ -1993,6 +2008,9 @@ static int __init pmz_console_setup(stru
 #ifdef CONFIG_PPC_PMAC
if (uap-node == NULL)
return -ENODEV;
+#else
+   if (uap-pdev == NULL)
+   return -ENODEV;
 #endif
port = uap-port;
 
Index: linux-git/drivers/tty/serial/pmac_zilog.h
===
--- linux-git.orig/drivers/tty/serial/pmac_zilog.h  2011-12-13 
00:18:02.0 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.h   2011-12-13 00:23:55.0 
+1100
@@ -1,18 +1,9 @@
 #ifndef __PMAC_ZILOG_H__
 #define __PMAC_ZILOG_H__
 
-#ifdef CONFIG_PPC_PMAC
-/* We cannot use dev_* because this can be called early, way before
- * we are matched with a device (when using it as a kernel console)
- */
 #define pmz_debug(fmt, arg...) pr_debug(ttyPZ%d:  fmt, uap-port.line, ## 
arg)
 #define pmz_error(fmt, arg...) pr_err(ttyPZ%d:  fmt, uap-port.line, ## arg)
 #define pmz_info(fmt, arg...)  pr_info(ttyPZ%d:  fmt, uap-port.line, ## arg)
-#else
-#define pmz_debug(fmt, arg...) dev_dbg(uap-node-dev, fmt, ## arg)
-#define pmz_error(fmt, arg...) dev_err(uap-node-dev, fmt, ## arg)
-#define pmz_info(fmt, arg...)  dev_info(uap-node-dev, fmt, ## arg)
-#endif
 
 /*
  * At most 2 ESCCs with 2 ports each
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-12 Thread Benjamin Herrenschmidt
On Tue, 2011-12-13 at 00:34 +1100, Finn Thain wrote:
 On Mon, 12 Dec 2011, Benjamin Herrenschmidt wrote:
 
  Any chance you can test this patch ? I would not be surprised if it 
  broke m68k since I had to do some of the changes in there blind, so 
  let me know... with this, I can again suspend/resume properly on a Pismo 
  while using the internal modem among other things.
 
 The patch works on a PowerBook 520 given a few changes (below). This 
 PowerBook only has one serial port that I can test (the internal modem is 
 not supported on 68k Macs).

Interesting. The modem is a soft-modem geoport or a hw serial modem ?
In the later case it's probably just a matter of finding the right GPIO
bit in Apple ASIC to turn the power on :-)

  Can you test a machine with two ports? The 
 rest of my Mac hardware is in storage since I moved house last week.

I tried on 2 port powermacs, but I only have one adapter, so I've
basically been running with one serial port open and shooting irda frame
on the other (with nothing to check wether I got the frames on the other
hand), oh well ...

I'll apply your patch and commit via my tree.

Cheers,
Ben.

 Finn
 
 
 Index: linux-git/drivers/tty/serial/pmac_zilog.c
 ===
 --- linux-git.orig/drivers/tty/serial/pmac_zilog.c2011-12-13 
 00:18:02.0 +1100
 +++ linux-git/drivers/tty/serial/pmac_zilog.c 2011-12-13 00:23:55.0 
 +1100
 @@ -1705,8 +1705,8 @@ static int __init pmz_init_port(struct u
   struct resource *r_ports;
   int irq;
  
 - r_ports = platform_get_resource(uap-node, IORESOURCE_MEM, 0);
 - irq = platform_get_irq(uap-node, 0);
 + r_ports = platform_get_resource(uap-pdev, IORESOURCE_MEM, 0);
 + irq = platform_get_irq(uap-pdev, 0);
   if (!r_ports || !irq)
   return -ENODEV;
  
 @@ -1763,8 +1763,10 @@ static void pmz_dispose_port(struct uart
  
  static int __init pmz_attach(struct platform_device *pdev)
  {
 + struct uart_pmac_port *uap;
   int i;
  
 + /* Iterate the pmz_ports array to find a matching entry */
   for (i = 0; i  pmz_ports_count; i++)
   if (pmz_ports[i].pdev == pdev)
   break;
 @@ -1773,15 +1775,23 @@ static int __init pmz_attach(struct plat
  
   uap = pmz_ports[i];
   uap-port.dev = pdev-dev;
 - dev_set_drvdata(mdev-ofdev.dev, uap);
 + platform_set_drvdata(pdev, uap);
  
 - return uart_add_one_port(pmz_uart_reg,
 -  pmz_ports[i]-port);
 + return uart_add_one_port(pmz_uart_reg, uap-port);
  }
  
  static int __exit pmz_detach(struct platform_device *pdev)
  {
 + struct uart_pmac_port *uap = platform_get_drvdata(pdev);
 +
 + if (!uap)
 + return -ENODEV;
 +
   uart_remove_one_port(pmz_uart_reg, uap-port);
 +
 + platform_set_drvdata(pdev, NULL);
 + uap-port.dev = NULL;
 +
   return 0;
  }
  
 @@ -1918,8 +1928,13 @@ static void __exit exit_pmz(void)
  
   for (i = 0; i  pmz_ports_count; i++) {
   struct uart_pmac_port *uport = pmz_ports[i];
 +#ifdef CONFIG_PPC_PMAC
   if (uport-node != NULL)
   pmz_dispose_port(uport);
 +#else
 + if (uport-pdev != NULL)
 + pmz_dispose_port(uport);
 +#endif
   }
   /* Unregister UART driver */
   uart_unregister_driver(pmz_uart_reg);
 @@ -1993,6 +2008,9 @@ static int __init pmz_console_setup(stru
  #ifdef CONFIG_PPC_PMAC
   if (uap-node == NULL)
   return -ENODEV;
 +#else
 + if (uap-pdev == NULL)
 + return -ENODEV;
  #endif
   port = uap-port;
  
 Index: linux-git/drivers/tty/serial/pmac_zilog.h
 ===
 --- linux-git.orig/drivers/tty/serial/pmac_zilog.h2011-12-13 
 00:18:02.0 +1100
 +++ linux-git/drivers/tty/serial/pmac_zilog.h 2011-12-13 00:23:55.0 
 +1100
 @@ -1,18 +1,9 @@
  #ifndef __PMAC_ZILOG_H__
  #define __PMAC_ZILOG_H__
  
 -#ifdef CONFIG_PPC_PMAC
 -/* We cannot use dev_* because this can be called early, way before
 - * we are matched with a device (when using it as a kernel console)
 - */
  #define pmz_debug(fmt, arg...)   pr_debug(ttyPZ%d:  fmt, 
 uap-port.line, ## arg)
  #define pmz_error(fmt, arg...)   pr_err(ttyPZ%d:  fmt, uap-port.line, 
 ## arg)
  #define pmz_info(fmt, arg...)pr_info(ttyPZ%d:  fmt, 
 uap-port.line, ## arg)
 -#else
 -#define pmz_debug(fmt, arg...)   dev_dbg(uap-node-dev, fmt, ## arg)
 -#define pmz_error(fmt, arg...)   dev_err(uap-node-dev, fmt, ## arg)
 -#define pmz_info(fmt, arg...)dev_info(uap-node-dev, fmt, ## arg)
 -#endif
  
  /*
   * At most 2 ESCCs with 2 ports each


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-12 Thread Finn Thain

On Tue, 13 Dec 2011, Benjamin Herrenschmidt wrote:

 On Tue, 2011-12-13 at 00:34 +1100, Finn Thain wrote:
  On Mon, 12 Dec 2011, Benjamin Herrenschmidt wrote:
  
   Any chance you can test this patch ? I would not be surprised if it 
   broke m68k since I had to do some of the changes in there blind, 
   so let me know... with this, I can again suspend/resume properly on 
   a Pismo while using the internal modem among other things.
  
  The patch works on a PowerBook 520 given a few changes (below). This 
  PowerBook only has one serial port that I can test (the internal modem 
  is not supported on 68k Macs).
 
 Interesting. The modem is a soft-modem geoport or a hw serial modem ? 

It's the latter.

 In the later case it's probably just a matter of finding the right GPIO 
 bit in Apple ASIC to turn the power on :-)

Surely feasible, but not high on the list of missing hardware support.

 
   Can you test a machine with two ports? The rest of my Mac hardware is 
  in storage since I moved house last week.
 
 I tried on 2 port powermacs, but I only have one adapter, so I've 
 basically been running with one serial port open and shooting irda frame 
 on the other (with nothing to check wether I got the frames on the other 
 hand), oh well ...
 
 I'll apply your patch and commit via my tree.

I forgot to include this fix for your logging change.

Finn

Index: linux-git/drivers/tty/serial/pmac_zilog.c
===
--- linux-git.orig/drivers/tty/serial/pmac_zilog.c  2011-12-13 
12:12:05.0 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.c   2011-12-13 12:13:29.0 
+1100
@@ -99,6 +99,10 @@ MODULE_LICENSE(GPL);
 #define PMACZILOG_NAME ttyPZ
 #endif
 
+#define pmz_debug(fmt, arg...) pr_debug(PMACZILOG_NAME %d:  fmt, 
uap-port.line, ## arg)
+#define pmz_error(fmt, arg...) pr_err(PMACZILOG_NAME %d:  fmt, 
uap-port.line, ## arg)
+#define pmz_info(fmt, arg...)  pr_info(PMACZILOG_NAME %d:  fmt, 
uap-port.line, ## arg)
+
 
 /*
  * For the sake of early serial console, we can do a pre-probe
Index: linux-git/drivers/tty/serial/pmac_zilog.h
===
--- linux-git.orig/drivers/tty/serial/pmac_zilog.h  2011-12-13 
12:12:05.0 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.h   2011-12-13 12:12:28.0 
+1100
@@ -1,10 +1,6 @@
 #ifndef __PMAC_ZILOG_H__
 #define __PMAC_ZILOG_H__
 
-#define pmz_debug(fmt, arg...) pr_debug(ttyPZ%d:  fmt, uap-port.line, ## 
arg)
-#define pmz_error(fmt, arg...) pr_err(ttyPZ%d:  fmt, uap-port.line, ## arg)
-#define pmz_info(fmt, arg...)  pr_info(ttyPZ%d:  fmt, uap-port.line, ## arg)
-
 /*
  * At most 2 ESCCs with 2 ports each
  */
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-11 Thread Benjamin Herrenschmidt
Any chance you can test this patch ? I would not be surprised if it
broke m68k since I had to do some of the changes in there blind,
so let me know... with this, I can again suspend/resume properly on
a Pismo while using the internal modem among other things.

From c2dbe7117bb94c59a4b2a215fc87fe7eabb7658d Mon Sep 17 00:00:00 2001
From: Benjamin Herrenschmidt b...@kernel.crashing.org
Date: Mon, 12 Dec 2011 10:44:08 +1100
Subject: [PATCH 2/2] tty/serial/pmac_zilog: Fix suspend  resume

This patch reworks  simplifies pmac_zilog handling of suspend/resume,
essentially removing all the specific code in there and using the
generic uart helpers.

This required properly registering the tty as a child of the macio (or platform)
device, so I had to delay the registration a bit (we used to register the ports
very very early). We still register the kernel console early though.

I removed a couple of unused or useless flags as well, relying on the
core to not call us when asleep. I also removed the essentially useless
interrupt mutex, simplifying the locking a bit.

I removed some code for handling unexpected interrupt which should never
be hit and could potentially be harmful (causing us to access a register
on a powered off SCC). We diable port interrupts on close always so there
should be no need to drain data on a closed port.

Signed-off-by: Benjamin Herrenschmidt b...@kernel.crashing.org
---
 drivers/tty/serial/pmac_zilog.c |  350 ++-
 drivers/tty/serial/pmac_zilog.h |   18 +-
 2 files changed, 99 insertions(+), 269 deletions(-)

diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 51941f0..46cb39b 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -106,7 +106,6 @@ MODULE_LICENSE(GPL);
  */
 static struct uart_pmac_port   pmz_ports[MAX_ZS_PORTS];
 static int pmz_ports_count;
-static DEFINE_MUTEX(pmz_irq_mutex);
 
 static struct uart_driver pmz_uart_reg = {
.owner  =   THIS_MODULE,
@@ -126,9 +125,6 @@ static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 
*regs)
 {
int i;
 
-   if (ZS_IS_ASLEEP(uap))
-   return;
-
/* Let pending transmits finish.  */
for (i = 0; i  1000; i++) {
unsigned char stat = read_zsreg(uap, R1);
@@ -234,26 +230,6 @@ static struct tty_struct *pmz_receive_chars(struct 
uart_pmac_port *uap)
unsigned char ch, r1, drop, error, flag;
int loops = 0;
 
-   /* The interrupt can be enabled when the port isn't open, typically
-* that happens when using one port is open and the other closed (stale
-* interrupt) or when one port is used as a console.
-*/
-   if (!ZS_IS_OPEN(uap)) {
-   pmz_debug(pmz: draining input\n);
-   /* Port is closed, drain input data */
-   for (;;) {
-   if ((++loops)  1000)
-   goto flood;
-   (void)read_zsreg(uap, R1);
-   write_zsreg(uap, R0, ERR_RES);
-   (void)read_zsdata(uap);
-   ch = read_zsreg(uap, R0);
-   if (!(ch  Rx_CH_AV))
-   break;
-   }
-   return NULL;
-   }
-
/* Sanity check, make sure the old bug is no longer happening */
if (uap-port.state == NULL || uap-port.state-port.tty == NULL) {
WARN_ON(1);
@@ -393,8 +369,6 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
 {
struct circ_buf *xmit;
 
-   if (ZS_IS_ASLEEP(uap))
-   return;
if (ZS_IS_CONS(uap)) {
unsigned char status = read_zsreg(uap, R0);
 
@@ -485,12 +459,16 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
spin_lock(uap_a-port.lock);
r3 = read_zsreg(uap_a, R3);
 
-#ifdef DEBUG_HARD
+#ifde DEBUG_HARD
pmz_debug(irq, r3: %x\n, r3);
 #endif
/* Channel A */
tty = NULL;
if (r3  (CHAEXT | CHATxIP | CHARxIP)) {
+   if (!ZS_IS_OPEN(uap_a)) {
+   pmz_debug(ChanA interrupt while open !\n);
+   goto skip_a;
+   }
write_zsreg(uap_a, R0, RES_H_IUS);
zssync(uap_a);  
if (r3  CHAEXT)
@@ -501,16 +479,21 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
pmz_transmit_chars(uap_a);
rc = IRQ_HANDLED;
}
+ skip_a:
spin_unlock(uap_a-port.lock);
if (tty != NULL)
tty_flip_buffer_push(tty);
 
-   if (uap_b-node == NULL)
+   if (!uap_b)
goto out;
 
spin_lock(uap_b-port.lock);
tty = NULL;
if (r3  (CHBEXT | CHBTxIP | CHBRxIP)) {
+   if (!ZS_IS_OPEN(uap_a)) {
+   pmz_debug(ChanB interrupt while open !\n);
+

Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-11 Thread Benjamin Herrenschmidt
On Mon, 2011-12-12 at 10:48 +1100, Benjamin Herrenschmidt wrote:
 Any chance you can test this patch ? I would not be surprised if it
 broke m68k since I had to do some of the changes in there blind,
 so let me know... with this, I can again suspend/resume properly on
 a Pismo while using the internal modem among other things.

 /

Forgot to commit a fix before sending, but it's a trivial one:

 -#ifdef DEBUG_HARD
 +#ifde DEBUG_HARD
   pmz_debug(irq, r3: %x\n, r3);
  #endif

Remove that hunk :-)

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-08 Thread Finn Thain

On Thu, 8 Dec 2011, Benjamin Herrenschmidt wrote:

 On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:
 
  So basic operations seem to work, I've applied the patch to 
  powerpc-next.

Then I guess Geert should not push this for 3.3 -- or does it make no 
difference?

  However, the internal modem on my Pismo powerbook doesn't appear to 
  survive suspend/resume. I'll dig into that and merge a fixup patch 
  asap.
 
 BTW. I applied anyway because suspend/resume was already broken (you 
 spotted that we don't clear the suspended flag for example).
 
 Fixing the flag alone helps a bit. We can't use the modem if we 
 suspend/resume with the open port,

If the SCC IRQ counters change across suspend/resume, perhaps the modem 
itself is not powering up...

 but closing and re-opening works.

Maybe the modem wants a transition on DTR or similar, but it hasn't had 
time to initialise when that happens during SCC resumption.

If so, calling pmz_shutdown() then pmz_startup() from the tail of 
pmz_resume() without delay should probably fail to revive it...

 
 Lockdep also picked-up a A-B B-A between the port mutex and the pmz 
 irq mutex on suspend.
 
 I'll try to fix all these, and will let you know (I may not have time 
 today).

Thanks.

Finn

 
 Cheers,
 Ben.
 
 
 --
 To unsubscribe from this list: send the line unsubscribe linux-m68k in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
 
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-08 Thread Geert Uytterhoeven
Hi Finn,

On Thu, Dec 8, 2011 at 12:26, Finn Thain fth...@telegraphics.com.au wrote:
 On Thu, 8 Dec 2011, Benjamin Herrenschmidt wrote:
 On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:
  So basic operations seem to work, I've applied the patch to
  powerpc-next.

 Then I guess Geert should not push this for 3.3 -- or does it make no
 difference?

I do not plan to push it myself, that's why it's not in my for-next branch.
The for-3.3 is just indicative.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say programmer or something like that.
                                -- Linus Torvalds
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-08 Thread Benjamin Herrenschmidt
On Thu, 2011-12-08 at 22:26 +1100, Finn Thain wrote:
 
 Maybe the modem wants a transition on DTR or similar, but it hasn't had 
 time to initialise when that happens during SCC resumption.
 
 If so, calling pmz_shutdown() then pmz_startup() from the tail of 
 pmz_resume() without delay should probably fail to revive it... 

Well, we power the modem down and back up... but it's possible that we
fail to re-enable something, I'll check. That used to work (at least
with macserial, maybe I never tried this specific torture with pmz...).
I'll figure it out eventually.

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-07 Thread Benjamin Herrenschmidt
On Wed, 2011-12-07 at 14:49 +1100, Finn Thain wrote:
 On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be 
 masked. This can be a problem when pmac_zilog starts up.

Thanks. I'll test it on a powermac or two and will merge it via the
powerpc -next tree if it works out allright.

Cheers,
Ben.
 

 For example, the serial debugging code in arch/m68k/kernel/head.S may be 
 used beforehand. It disables the SCC interrupts at the chip but doesn't 
 ack them. Then when a pmac_zilog port is used, the machine locks up with 
 unexpected interrupt.
 
 This can happen in pmz_shutdown() since the irq is freed before the 
 channel interrupts are disabled.
 
 Fix this by clearing interrupt enable bits before the handler is 
 uninstalled. Also move the interrupt control bit flipping into a separate 
 pmz_interrupt_control() routine. Replace all instances of these operations 
 with calls to this routine. Omit the zssync() calls that seem to serve no 
 purpose.
 
 Signed-off-by: Finn Thain fth...@telegraphics.com.au
 Acked-by: Alan Cox a...@linux.intel.com
 
 ---

 Re-implemented as v2 using a simpler approach that avoids messing with the 
 Master Interrupt Enable bit. As well as the ifdef problem, it turns out 
 that v1 was not sufficient to entirely fix the problem.
 
 v3 avoids needless changes to the logic and locking in the suspend and 
 shutdown code and tries to keep register writes closer to their original 
 sequence.
 
 This patch has been tested on a PowerBook 520 but no PowerMacs yet.
 
 
 Index: linux-git/drivers/tty/serial/pmac_zilog.c
 ===
 --- linux-git.orig/drivers/tty/serial/pmac_zilog.c2011-12-07 
 12:36:32.0 +1100
 +++ linux-git/drivers/tty/serial/pmac_zilog.c 2011-12-07 14:29:21.0 
 +1100
 @@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct
   }
  }
  
 +static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
 +{
 + if (enable) {
 + uap-curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
 + if (!ZS_IS_EXTCLK(uap))
 + uap-curregs[1] |= EXT_INT_ENAB;
 + } else {
 + uap-curregs[1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
 + }
 + write_zsreg(uap, R1, uap-curregs[1]);
 +}
 +
  static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
  {
   struct tty_struct *tty = NULL;
 @@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_ch
  
   return tty;
   flood:
 - uap-curregs[R1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
 - write_zsreg(uap, R1, uap-curregs[R1]);
 - zssync(uap);
 + pmz_interrupt_control(uap, 0);
   pmz_error(pmz: rx irq flood !\n);
   return tty;
  }
 @@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port
   if (ZS_IS_IRDA(uap))
   pmz_irda_reset(uap);
  
 - /* Enable interrupts emission from the chip */
 + /* Enable interrupt requests for the channel */
   spin_lock_irqsave(port-lock, flags);
 - uap-curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
 - if (!ZS_IS_EXTCLK(uap))
 - uap-curregs[R1] |= EXT_INT_ENAB;
 - write_zsreg(uap, R1, uap-curregs[R1]);
 + pmz_interrupt_control(uap, 1);
   spin_unlock_irqrestore(port-lock, flags);
  
   pmz_debug(pmz: startup() done.\n);
 @@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_por
  
   mutex_lock(pmz_irq_mutex);
  
 + spin_lock_irqsave(port-lock, flags);
 +
 + if (!ZS_IS_ASLEEP(uap)) {
 + /* Disable interrupt requests for the channel */
 + pmz_interrupt_control(uap, 0);
 +
 + if (!ZS_IS_CONS(uap)) {
 + /* Disable receiver and transmitter */
 + uap-curregs[R3] = ~RxENABLE;
 + uap-curregs[R5] = ~TxENABLE;
 +
 + /* Disable break assertion */
 + uap-curregs[R5] = ~SND_BRK;
 + pmz_maybe_update_regs(uap);
 + }
 + }
 +
 + spin_unlock_irqrestore(port-lock, flags);
 +
   /* Release interrupt handler */
   free_irq(uap-port.irq, uap);
  
 @@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_por
   if (!ZS_IS_OPEN(uap-mate))
   pmz_get_port_A(uap)-flags = ~PMACZILOG_FLAG_IS_IRQ_ON;
  
 - /* Disable interrupts */
 - if (!ZS_IS_ASLEEP(uap)) {
 - uap-curregs[R1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
 - write_zsreg(uap, R1, uap-curregs[R1]);
 - zssync(uap);
 - }
 -
 - if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
 - spin_unlock_irqrestore(port-lock, flags);
 - mutex_unlock(pmz_irq_mutex);
 - return;
 - }
 -
 - /* Disable receiver and transmitter.  */
 - uap-curregs[R3] = ~RxENABLE;
 - uap-curregs[R5] = ~TxENABLE;
 -
 - /* Disable all interrupts and BRK assertion.  */
 - uap-curregs[R5] = ~SND_BRK;
 - 

Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-07 Thread Benjamin Herrenschmidt
On Wed, 2011-12-07 at 14:49 +1100, Finn Thain wrote:
 On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be 
 masked. This can be a problem when pmac_zilog starts up.
 
 For example, the serial debugging code in arch/m68k/kernel/head.S may be 
 used beforehand. It disables the SCC interrupts at the chip but doesn't 
 ack them. Then when a pmac_zilog port is used, the machine locks up with 
 unexpected interrupt.
 
 This can happen in pmz_shutdown() since the irq is freed before the 
 channel interrupts are disabled.
 
 Fix this by clearing interrupt enable bits before the handler is 
 uninstalled. Also move the interrupt control bit flipping into a separate 
 pmz_interrupt_control() routine. Replace all instances of these operations 
 with calls to this routine. Omit the zssync() calls that seem to serve no 
 purpose.
 
 Signed-off-by: Finn Thain fth...@telegraphics.com.au
 Acked-by: Alan Cox a...@linux.intel.com
 
 ---

So basic operations seem to work, I've applied the patch to
powerpc-next.

However, the internal modem on my Pismo powerbook doesn't appear to
survive suspend/resume. I'll dig into that and merge a fixup patch asap.

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-07 Thread Benjamin Herrenschmidt
On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:

 So basic operations seem to work, I've applied the patch to
 powerpc-next.
 
 However, the internal modem on my Pismo powerbook doesn't appear to
 survive suspend/resume. I'll dig into that and merge a fixup patch asap.

BTW. I applied anyway because suspend/resume was already broken (you
spotted that we don't clear the suspended flag for example).

Fixing the flag alone helps a bit. We can't use the modem if we
suspend/resume with the open port, but closing and re-opening works.

Lockdep also picked-up a A-B B-A between the port mutex and the pmz
irq mutex on suspend.

I'll try to fix all these, and will let you know (I may not have time
today).

Cheers,
Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


[PATCH 01/16 v3] pmac_zilog: fix unexpected irq

2011-12-06 Thread Finn Thain

On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be 
masked. This can be a problem when pmac_zilog starts up.

For example, the serial debugging code in arch/m68k/kernel/head.S may be 
used beforehand. It disables the SCC interrupts at the chip but doesn't 
ack them. Then when a pmac_zilog port is used, the machine locks up with 
unexpected interrupt.

This can happen in pmz_shutdown() since the irq is freed before the 
channel interrupts are disabled.

Fix this by clearing interrupt enable bits before the handler is 
uninstalled. Also move the interrupt control bit flipping into a separate 
pmz_interrupt_control() routine. Replace all instances of these operations 
with calls to this routine. Omit the zssync() calls that seem to serve no 
purpose.

Signed-off-by: Finn Thain fth...@telegraphics.com.au
Acked-by: Alan Cox a...@linux.intel.com

---
   
Re-implemented as v2 using a simpler approach that avoids messing with the 
Master Interrupt Enable bit. As well as the ifdef problem, it turns out 
that v1 was not sufficient to entirely fix the problem.

v3 avoids needless changes to the logic and locking in the suspend and 
shutdown code and tries to keep register writes closer to their original 
sequence.

This patch has been tested on a PowerBook 520 but no PowerMacs yet.


Index: linux-git/drivers/tty/serial/pmac_zilog.c
===
--- linux-git.orig/drivers/tty/serial/pmac_zilog.c  2011-12-07 
12:36:32.0 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.c   2011-12-07 14:29:21.0 
+1100
@@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct
}
 }
 
+static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
+{
+   if (enable) {
+   uap-curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
+   if (!ZS_IS_EXTCLK(uap))
+   uap-curregs[1] |= EXT_INT_ENAB;
+   } else {
+   uap-curregs[1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+   }
+   write_zsreg(uap, R1, uap-curregs[1]);
+}
+
 static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
 {
struct tty_struct *tty = NULL;
@@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_ch
 
return tty;
  flood:
-   uap-curregs[R1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-   write_zsreg(uap, R1, uap-curregs[R1]);
-   zssync(uap);
+   pmz_interrupt_control(uap, 0);
pmz_error(pmz: rx irq flood !\n);
return tty;
 }
@@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port
if (ZS_IS_IRDA(uap))
pmz_irda_reset(uap);
 
-   /* Enable interrupts emission from the chip */
+   /* Enable interrupt requests for the channel */
spin_lock_irqsave(port-lock, flags);
-   uap-curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
-   if (!ZS_IS_EXTCLK(uap))
-   uap-curregs[R1] |= EXT_INT_ENAB;
-   write_zsreg(uap, R1, uap-curregs[R1]);
+   pmz_interrupt_control(uap, 1);
spin_unlock_irqrestore(port-lock, flags);
 
pmz_debug(pmz: startup() done.\n);
@@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_por
 
mutex_lock(pmz_irq_mutex);
 
+   spin_lock_irqsave(port-lock, flags);
+
+   if (!ZS_IS_ASLEEP(uap)) {
+   /* Disable interrupt requests for the channel */
+   pmz_interrupt_control(uap, 0);
+
+   if (!ZS_IS_CONS(uap)) {
+   /* Disable receiver and transmitter */
+   uap-curregs[R3] = ~RxENABLE;
+   uap-curregs[R5] = ~TxENABLE;
+
+   /* Disable break assertion */
+   uap-curregs[R5] = ~SND_BRK;
+   pmz_maybe_update_regs(uap);
+   }
+   }
+
+   spin_unlock_irqrestore(port-lock, flags);
+
/* Release interrupt handler */
free_irq(uap-port.irq, uap);
 
@@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_por
if (!ZS_IS_OPEN(uap-mate))
pmz_get_port_A(uap)-flags = ~PMACZILOG_FLAG_IS_IRQ_ON;
 
-   /* Disable interrupts */
-   if (!ZS_IS_ASLEEP(uap)) {
-   uap-curregs[R1] = ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
-   write_zsreg(uap, R1, uap-curregs[R1]);
-   zssync(uap);
-   }
-
-   if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
-   spin_unlock_irqrestore(port-lock, flags);
-   mutex_unlock(pmz_irq_mutex);
-   return;
-   }
-
-   /* Disable receiver and transmitter.  */
-   uap-curregs[R3] = ~RxENABLE;
-   uap-curregs[R5] = ~TxENABLE;
-
-   /* Disable all interrupts and BRK assertion.  */
-   uap-curregs[R5] = ~SND_BRK;
-   pmz_maybe_update_regs(uap);
-
-   /* Shut the chip down */
-   pmz_set_scc_power(uap, 0);
+   if (!ZS_IS_ASLEEP(uap)  !ZS_IS_CONS(uap))
+   pmz_set_scc_power(uap, 0);  /*