patch-2.4.20 linux-2.4.20/arch/mips/sibyte/sb1250/irq.c
Next file: linux-2.4.20/arch/mips/sibyte/sb1250/irq_handler.S
Previous file: linux-2.4.20/arch/mips/sibyte/sb1250/bcm1250_tbprof.h
Back to the patch index
Back to the overall index
- Lines: 203
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/mips/sibyte/sb1250/irq.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/mips/sibyte/sb1250/irq.c linux-2.4.20/arch/mips/sibyte/sb1250/irq.c
@@ -10,7 +10,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -23,21 +23,24 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/slab.h>
+
#include <asm/errno.h>
#include <asm/signal.h>
#include <asm/system.h>
#include <asm/ptrace.h>
+
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_uart.h>
#include <asm/sibyte/sb1250_scd.h>
#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/64bit.h>
/*
- * These are the routines that handle all the low level interrupt stuff.
+ * These are the routines that handle all the low level interrupt stuff.
* Actions handled here are: initialization of the interrupt map, requesting of
* interrupt lines by handlers, dispatching if interrupts to handlers, probing
- * for interrupt lines
+ * for interrupt lines
*/
@@ -50,6 +53,15 @@
#ifdef CONFIG_REMOTE_DEBUG
extern void breakpoint(void);
+extern void set_debug_traps(void);
+
+/* kgdb is on when configured. Pass "nokgdb" kernel arg to turn it off */
+static int kgdb_flag = 1;
+static int __init nokgdb(char *str)
+{
+ kgdb_flag = 0;
+}
+__setup("nokgdb", nokgdb);
#endif
#define NR_IRQS 64
@@ -155,11 +167,44 @@
}
+static void sb1250_dummy_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static struct irqaction sb1250_dummy_action = {
+ handler: sb1250_dummy_handler,
+ flags: 0,
+ mask: 0,
+ name: "sb1250-private",
+ next: NULL,
+ dev_id: 0
+};
+
+int sb1250_steal_irq(int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+ int retval = 0;
+
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&desc->lock,flags);
+ /* Don't allow sharing at all for these */
+ if (desc->action != NULL)
+ retval = -EBUSY;
+ else {
+ desc->action = &sb1250_dummy_action;
+ desc->depth = 0;
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+}
+
/*
* init_IRQ is called early in the boot sequence from init/main.c. It
* is responsible for setting up the interrupt mapper and installing the
* handler that will be responsible for dispatching interrupts to the
- * "right" place.
+ * "right" place.
*/
/*
* For now, map all interrupts to IP[2]. We could save
@@ -167,10 +212,10 @@
* IP lines, but keep it simple for bringup. We'll also direct
* all interrupts to a single CPU; we should probably route
* PCI and LDT to one cpu and everything else to the other
- * to balance the load a bit.
- *
+ * to balance the load a bit.
+ *
* On the second cpu, everything is set to IP5, which is
- * ignored, EXCEPT the mailbox interrupt. That one is
+ * ignored, EXCEPT the mailbox interrupt. That one is
* set to IP[2] so it is handled. This is needed so we
* can do cross-cpu function calls, as requred by SMP
*/
@@ -178,12 +223,16 @@
#define IMR_IP2_VAL K_INT_MAP_I0
#define IMR_IP3_VAL K_INT_MAP_I1
#define IMR_IP4_VAL K_INT_MAP_I2
+#define IMR_IP5_VAL K_INT_MAP_I3
+#define IMR_IP6_VAL K_INT_MAP_I4
void __init init_IRQ(void)
{
unsigned int i;
u64 tmp;
+ unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
+ STATUSF_IP1 | STATUSF_IP0;
/* Default everything to IP2 */
for (i = 0; i < NR_IRQS; i++) { /* was I0 */
@@ -220,26 +269,60 @@
out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
out64(tmp, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK));
+ sb1250_steal_irq(K_INT_MBOX_0);
+
/*
- * Note that the timer interrupts are also mapped, but this is
+ * Note that the timer interrupts are also mapped, but this is
* done in sb1250_time_init()
*/
-#ifdef CONFIG_SIBYTE_SB1250_PROF
- /* Enable IP[7,4:0], disable the rest */
- clear_cp0_status(0x6000);
- set_cp0_status(0x9f00);
-#else
- /* Enable IP[4:0], disable the rest */
- clear_cp0_status(0xe000);
- set_cp0_status(0x1f00);
+#ifdef CONFIG_BCM1250_PROF
+ imask |= STATUSF_IP7;
+#endif
+#ifdef CONFIG_REMOTE_DEBUG
+ imask |= STATUSF_IP6;
#endif
+ /* Enable necessary IPs, disable the rest */
+ change_cp0_status(ST0_IM, imask);
set_except_vector(0, sb1250_irq_handler);
#ifdef CONFIG_REMOTE_DEBUG
- /* If local serial I/O used for debug port, enter kgdb at once */
-// puts("Waiting for kgdb to connect...");
- set_debug_traps();
- breakpoint();
+ if (kgdb_flag) {
+ /* Setup uart 1 settings, mapper */
+ out64(M_DUART_IMR_BRK, KSEG1 + A_DUART + R_DUART_IMR_B);
+
+ out64(IMR_IP6_VAL,
+ KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_UART_1<<3));
+ tmp = in64(KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
+ tmp &= ~(1<<K_INT_UART_1);
+ out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));
+
+ set_debug_traps();
+ breakpoint();
+ }
#endif
}
+
+#ifdef CONFIG_REMOTE_DEBUG
+
+#include <linux/delay.h>
+
+extern void set_async_breakpoint(unsigned int epc);
+
+#define duart_out(reg, val) out64(val, KSEG1 + A_DUART_CHANREG(1,reg))
+#define duart_in(reg) in64(KSEG1 + A_DUART_CHANREG(1,reg))
+
+void sb1250_kgdb_interrupt(struct pt_regs *regs)
+{
+ /*
+ * Clear break-change status (allow some time for the remote
+ * host to stop the break, since we would see another
+ * interrupt on the end-of-break too)
+ */
+ mdelay(500);
+ duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
+ M_DUART_RX_EN | M_DUART_TX_EN);
+ if (!user_mode(regs))
+ set_async_breakpoint(regs->cp0_epc);
+}
+#endif /* CONFIG_REMOTE_DEBUG */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)