Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
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
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
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
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
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
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
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
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
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
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
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
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); /*