/* $ZEL: sis1100_irq.c,v 1.7 2004/05/27 23:10:23 wuestner Exp $ */ /* * Copyright (c) 2001-2004 * Matthias Drochner, Peter Wuestner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "sis1100_sc.h" int sis1100_enable_irq(struct sis1100_softc* sc, u_int32_t plx_mask, u_int32_t sis_mask) { DECLARE_SPINLOCKFLAGS(flags) if (plx_mask) { SPIN_LOCK_IRQSAVE(sc->lock_intcsr, flags); plxwritereg(sc, INTCSR, plxreadreg(sc, INTCSR)|plx_mask); SPIN_UNLOCK_IRQRESTORE(sc->lock_intcsr, flags); } if (sis_mask) { sis_mask&=sis1100_all_irq; sis1100writereg(sc, sr, sis_mask); /* clear pending irqs */ sis1100writereg(sc, cr, sis_mask); /* enable irqs */ } return 0; } int sis1100_disable_irq(struct sis1100_softc* sc, u_int32_t plx_mask, u_int32_t sis_mask) { DECLARE_SPINLOCKFLAGS(flags) if (plx_mask) { SPIN_LOCK_IRQSAVE(sc->lock_intcsr, flags); plxwritereg(sc, INTCSR, plxreadreg(sc, INTCSR)&~plx_mask); SPIN_UNLOCK_IRQRESTORE(sc->lock_intcsr, flags); } if (sis_mask) sis1100writereg(sc, cr, (sis_mask&sis1100_all_irq)<<16); return 0; } /* Doorbell | Local | DMA0 | DMA1 */ #define HANDLED_IRQS (plxirq_doorbell_active|plxirq_local_active|\ plxirq_dma0_active|plxirq_dma1_active) #ifdef __NetBSD__ int sis1100_intr(void* vsc) #elif __linux__ irqreturn_t sis1100_intr(int irq, void *vsc, struct pt_regs *regs) #endif { DECLARE_SPINLOCKFLAGS(flags) struct sis1100_softc* sc=(struct sis1100_softc*)vsc; u_int32_t intcsr; int local, handler_command, wakeup_handler, wakeup_local; intcsr=plxreadreg(sc, INTCSR); if (!(intcsr & HANDLED_IRQS)) return IRQ_NONE; local=0; handler_command=0; wakeup_handler=0; wakeup_local=0; if (intcsr&plxirq_doorbell_active) { /* == VME/CAMAC IRQ */ u_int32_t help=plxreadreg(sc, L2PDBELL); pINFO(sc, "doorbell irq: doorbell=0x%x", help); SPIN_LOCK_IRQSAVE(sc->lock_doorbell, flags); sc->doorbell|=help; SPIN_UNLOCK_IRQRESTORE(sc->lock_doorbell, flags); plxwritereg(sc, L2PDBELL, help); handler_command|=handlercomm_doorbell; wakeup_handler=1; } if (intcsr&plxirq_local_active) { /* local Interrupt */ local=1; } if (intcsr&plxirq_dma0_active) { /* DMA0 Interrupt */ SPIN_LOCK_IRQSAVE(sc->lock_intcsr, flags); plxwritereg(sc, INTCSR, intcsr&~plxirq_dma0); SPIN_UNLOCK_IRQRESTORE(sc->lock_intcsr, flags); sc->got_irqs|=got_dma0; wakeup_local=1; } if (intcsr&plxirq_dma1_active) { /* DMA1 Interrupt */ SPIN_LOCK_IRQSAVE(sc->lock_intcsr, flags); plxwritereg(sc, INTCSR, intcsr&~plxirq_dma1); SPIN_UNLOCK_IRQRESTORE(sc->lock_intcsr, flags); sc->got_irqs|=got_dma1; wakeup_local=1; } if (local) { u_int32_t status; status=sis1100readreg(sc, sr); if (status&irq_synch_chg) { sis1100_disable_irq(sc, 0, irq_synch_chg| irq_reset_req|irq_prot_end|irq_prot_l_err); sc->got_irqs|=got_sync; wakeup_local=1; if ((status&3)==3) { pINFO(sc, "link is UP status =0x%08x", status); } else { pINFO(sc, "link is DOWN status =0x%08x", status); sc->old_remote_hw=sc->remote_hw; sc->remote_hw=sis1100_hw_invalid; handler_command|=handlercomm_synch; wakeup_handler=1; } #ifdef __NetBSD__ callout_reset(&sc->link_up_timer, hz, sis1100_link_up_handler, sc); #elif __linux__ mod_timer(&sc->link_up_timer, jiffies+HZ); #endif } if (status&irq_inh_chg) pERROR(sc, "INH_CHG"); if (status&irq_sema_chg) pERROR(sc, "SEMA_CHG"); if (status&irq_rec_violation) pERROR(sc, "REC_VIOLATION"); if (status&irq_reset_req) pERROR(sc, "RESET_REQ"); if (status&irq_dma_eot) { sc->got_irqs|=got_eot; wakeup_local=1; } if (status&irq_mbx0) { sc->mbx0=sis1100readreg(sc, mailext[0]); /*pINFO(sc, "irq: mbx0=0x%x", sc->mbx0);*/ handler_command|=handlercomm_mbx0; wakeup_handler=1; } #ifdef NEVER if (status&irq_s_xoff) { pINFO(sc, "S_XOFF"); pINFO(sc, "status=0x%08x", status); sc->got_irqs|=got_xoff; wakeup_local=1; } #endif if (status&irq_lemo_in_chg) { /* pINFO(sc, "LEMO_IN_CHG, status=0x%08x", status); */ SPIN_LOCK_IRQSAVE(sc->lock_lemo_status, flags); sc->lemo_status|=(status<<4)&0x30000; SPIN_UNLOCK_IRQRESTORE(sc->lock_lemo_status, flags); sc->last_opt_csr=sis1100readreg(sc, opt_csr); handler_command|=handlercomm_lemo; wakeup_handler=1; } if (status&irq_prot_end) { sc->got_irqs|=got_end; wakeup_local=1; } if (status&irq_prot_l_err) { /*pINFO(sc, "PROT_L_ERR");*/ sc->got_irqs|=got_l_err; wakeup_local=1; } /* * pINFO(sc, "irq: write 0x%x to sr", status); */ sis1100writereg(sc, sr, status); } if (wakeup_local) #ifdef __NetBSD__ wakeup(&sc->local_wait); #elif __linux__ wake_up_interruptible(&sc->local_wait); #endif if (wakeup_handler) { SPIN_LOCK_IRQSAVE(sc->lock_intcsr, flags); /* XXX warum? */ sc->handlercommand.command=handler_command; SPIN_UNLOCK_IRQRESTORE(sc->lock_intcsr, flags); #ifdef __NetBSD__ wakeup(&sc->handler_wait); #elif __linux__ wake_up(&sc->handler_wait); #endif } return IRQ_HANDLED; }