From adbba9cd766ae6239d8309f1e3d7037d02adf862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 28 Feb 2006 21:22:26 +0000 Subject: [PATCH] Temporarily disabled interrupt handling: this fixes a strange symptom that happen on stippi's and my laptop when connected to a power outlet (no interrupts arrive anymore but timer interrupts). Need to investigate this a bit more... git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16553 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/graphics/radeon/irq.c | 348 ++++++++++-------- 1 file changed, 185 insertions(+), 163 deletions(-) diff --git a/src/add-ons/kernel/drivers/graphics/radeon/irq.c b/src/add-ons/kernel/drivers/graphics/radeon/irq.c index fb4da4ed49..9268f69db3 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/irq.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/irq.c @@ -1,101 +1,107 @@ /* - Copyright (c) 2002-2004, Thomas Kurschel + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2002-2004, Thomas Kurschel + * + * Distributed under the terms of the MIT License. + */ - - Part of Radeon kernel driver - - Interrupt handling. Currently, none of this is used - as I haven't got the HW spec. -*/ - -#include "radeon_driver.h" -#include +/** Interrupt handling. Currently, none of this is used + * as I haven't got the HW spec. + */ #include "mmio.h" +#include "radeon_driver.h" #include "rbbm_regs.h" +#include -// disable all interrupts -static void -Radeon_DisableIRQ( device_info *di ) + +/** Disable all interrupts */ + +static void +Radeon_DisableIRQ(device_info *di) { - OUTREG( di->regs, RADEON_GEN_INT_CNTL, 0 ); + OUTREG(di->regs, RADEON_GEN_INT_CNTL, 0); } -// interrupt worker routine -// handles standard interrupts, i.e. VBI and DMA -static uint32 -Radeon_ThreadInterruptWork( vuint8 *regs, device_info *di, uint32 int_status ) +/** Interrupt worker routine + * handles standard interrupts, i.e. VBI and DMA + */ + +static uint32 +Radeon_ThreadInterruptWork(vuint8 *regs, device_info *di, uint32 int_status) { shared_info *si = di->si; uint32 handled = B_HANDLED_INTERRUPT; - if( (int_status & RADEON_CRTC_VBLANK_STAT) != 0 && - si->crtc[0].vblank >= 0 ) - { + if ((int_status & RADEON_CRTC_VBLANK_STAT) != 0 + && si->crtc[0].vblank >= 0) { int32 blocked; ++di->vbi_count[0]; - - if( (get_sem_count( si->crtc[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) { - release_sem_etc( si->crtc[0].vblank, -blocked, B_DO_NOT_RESCHEDULE ); + + if (get_sem_count(si->crtc[0].vblank, &blocked ) == B_OK && blocked < 0) { + release_sem_etc(si->crtc[0].vblank, -blocked, B_DO_NOT_RESCHEDULE); handled = B_INVOKE_SCHEDULER; } } - - if( (int_status & RADEON_CRTC2_VBLANK_STAT) != 0 && - si->crtc[1].vblank >= 0 ) - { + + if ((int_status & RADEON_CRTC2_VBLANK_STAT) != 0 + && si->crtc[1].vblank >= 0) { int32 blocked; - - ++di->vbi_count[1]; + + ++di->vbi_count[1]; - if( (get_sem_count( si->crtc[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) { - release_sem_etc( si->crtc[1].vblank, -blocked, B_DO_NOT_RESCHEDULE ); + if (get_sem_count(si->crtc[1].vblank, &blocked) == B_OK && blocked < 0) { + release_sem_etc(si->crtc[1].vblank, -blocked, B_DO_NOT_RESCHEDULE); handled = B_INVOKE_SCHEDULER; } } - - if( (int_status & RADEON_VIDDMA_STAT ) != 0 ) { - release_sem_etc( di->dma_sem, 1, B_DO_NOT_RESCHEDULE ); + + if ((int_status & RADEON_VIDDMA_STAT) != 0) { + release_sem_etc(di->dma_sem, 1, B_DO_NOT_RESCHEDULE); handled = B_INVOKE_SCHEDULER; } - + return handled; } -// Capture interrupt handler +#if 0 +/** Capture interrupt handler */ + static int32 -Radeon_HandleCaptureInterrupt( vuint8 *regs, device_info *di, uint32 cap_status ) +Radeon_HandleCaptureInterrupt(vuint8 *regs, device_info *di, uint32 cap_status) { int32 blocked; uint32 handled = B_HANDLED_INTERRUPT; cpu_status prev_irq_state = disable_interrupts(); - acquire_spinlock( &di->cap_spinlock ); - + acquire_spinlock(&di->cap_spinlock); + ++di->cap_counter; di->cap_int_status = cap_status; di->cap_timestamp = system_time(); - - release_spinlock( &di->cap_spinlock ); - restore_interrupts( prev_irq_state ); + + release_spinlock(&di->cap_spinlock); + restore_interrupts(prev_irq_state); // don't release if semaphore count is positive, i.e. notifications are piling up - if( (get_sem_count( di->cap_sem, &blocked ) == B_OK) && (blocked <= 0) ) { - release_sem_etc( di->cap_sem, 1, B_DO_NOT_RESCHEDULE ); + if (get_sem_count(di->cap_sem, &blocked) == B_OK && blocked <= 0) { + release_sem_etc(di->cap_sem, 1, B_DO_NOT_RESCHEDULE); handled = B_INVOKE_SCHEDULER; } // acknowledge IRQ - OUTREG( regs, RADEON_CAP_INT_STATUS, cap_status ); - + OUTREG(regs, RADEON_CAP_INT_STATUS, cap_status); + return handled; } -// Main interrupt handler + +/** Main interrupt handler */ + static int32 Radeon_Interrupt(void *data) { @@ -105,43 +111,46 @@ Radeon_Interrupt(void *data) int32 full_int_status, int_status; // read possible IRQ reasons, ignoring any masked IRQs - full_int_status = INREG( regs, RADEON_GEN_INT_STATUS ); - int_status = full_int_status & INREG( regs, RADEON_GEN_INT_CNTL ); + full_int_status = INREG(regs, RADEON_GEN_INT_STATUS); + int_status = full_int_status & INREG(regs, RADEON_GEN_INT_CNTL); - if( int_status != 0 ) { + if (int_status != 0) { ++di->interrupt_count; - - handled = Radeon_ThreadInterruptWork( regs, di, int_status ); - + + handled = Radeon_ThreadInterruptWork(regs, di, int_status); + // acknowledge IRQ - OUTREG( regs, RADEON_GEN_INT_STATUS, int_status ); + OUTREG(regs, RADEON_GEN_INT_STATUS, int_status); } - + // capture interrupt have no mask in GEN_INT_CNTL register; // probably, ATI wanted to make capture interrupt control independant of main control - if( (full_int_status & RADEON_CAP0_INT_ACTIVE) != 0 ) { + if ((full_int_status & RADEON_CAP0_INT_ACTIVE) != 0) { int32 cap_status; - - // same as before: only regard enabled IRQ reasons - cap_status = INREG( regs, RADEON_CAP_INT_STATUS ); - cap_status &= INREG( regs, RADEON_CAP_INT_CNTL ); - if( cap_status != 0 ) { + // same as before: only regard enabled IRQ reasons + cap_status = INREG(regs, RADEON_CAP_INT_STATUS); + cap_status &= INREG(regs, RADEON_CAP_INT_CNTL); + + if (cap_status != 0) { int32 cap_handled; - - cap_handled = Radeon_HandleCaptureInterrupt( regs, di, cap_status ); - - if( cap_handled == B_INVOKE_SCHEDULER || handled == B_INVOKE_SCHEDULER ) + + cap_handled = Radeon_HandleCaptureInterrupt(regs, di, cap_status); + + if (cap_handled == B_INVOKE_SCHEDULER || handled == B_INVOKE_SCHEDULER) handled = B_INVOKE_SCHEDULER; - else if( cap_handled == B_HANDLED_INTERRUPT ) + else if (cap_handled == B_HANDLED_INTERRUPT) handled = B_HANDLED_INTERRUPT; } } - return handled; + return handled; } +#endif -static int32 timer_interrupt_func( timer *te ) + +static int32 +timer_interrupt_func(timer *te) { bigtime_t now = system_time(); /* get the pointer to the device we're handling this time */ @@ -152,30 +161,35 @@ static int32 timer_interrupt_func( timer *te ) int32 result = B_HANDLED_INTERRUPT; /* are we suppoesed to handle interrupts still? */ - if( !di->shutdown_virtual_irq ) { + if (!di->shutdown_virtual_irq) { /* reschedule with same period by default */ bigtime_t when = si->refresh_period; timer *to; /* if interrupts are "enabled", do our thing */ - if( si->enable_virtual_irq ) { + if (si->enable_virtual_irq) { /* insert code to sync to interrupts here */ if (!vbl_status) { when -= si->blank_period - 4; } /* do the things we do when we notice a vertical retrace */ - result = Radeon_ThreadInterruptWork( regs, di, - RADEON_CRTC_VBLANK_STAT | - (di->num_crtc > 1 ? RADEON_CRTC2_VBLANK_STAT : 0 )); + result = Radeon_ThreadInterruptWork(regs, di, + RADEON_CRTC_VBLANK_STAT + | (di->num_crtc > 1 ? RADEON_CRTC2_VBLANK_STAT : 0)); } /* pick the "other" timer */ - to = (timer *)&(di->ti_a); - if (to == te) to = (timer *)&(di->ti_b); + to = (timer *)&di->ti_a; + if (to == te) + to = (timer *)&di->ti_b; + /* our guess as to when we should be back */ ((timer_info *)to)->when_target = now + when; + /* reschedule the interrupt */ - add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, B_ONE_SHOT_ABSOLUTE_TIMER); + add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, + B_ONE_SHOT_ABSOLUTE_TIMER); + /* remember the currently active timer */ di->current_timer = (timer_info *)to; } @@ -184,142 +198,150 @@ static int32 timer_interrupt_func( timer *te ) } -// setup IRQ handlers. -// includes an VBI emulator via a timer (according to sample code), -// though this makes sense for one CRTC only +/** Setup IRQ handlers. + * Includes an VBI emulator via a timer (according to sample code), + * though this makes sense for one CRTC only. + */ + status_t -Radeon_SetupIRQ( device_info *di, char *buffer ) +Radeon_SetupIRQ(device_info *di, char *buffer) { shared_info *si = di->si; status_t result; thread_id thid; thread_info thinfo; - - sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 1", + + sprintf(buffer, "%04X_%04X_%02X%02X%02X VBI 1", di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function ); - si->crtc[0].vblank = create_sem( 0, buffer ); - if( si->crtc[0].vblank < 0 ) { + di->pcii.bus, di->pcii.device, di->pcii.function); + si->crtc[0].vblank = create_sem(0, buffer); + if (si->crtc[0].vblank < 0) { result = si->crtc[0].vblank; goto err1; } si->crtc[1].vblank = 0; - - if( di->num_crtc > 1 ) { - sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 2", + + if (di->num_crtc > 1) { + sprintf(buffer, "%04X_%04X_%02X%02X%02X VBI 2", di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function ); - si->crtc[1].vblank = create_sem( 0, buffer ); - if( si->crtc[1].vblank < 0 ) { + di->pcii.bus, di->pcii.device, di->pcii.function); + si->crtc[1].vblank = create_sem(0, buffer); + if (si->crtc[1].vblank < 0) { result = si->crtc[1].vblank; goto err2; } } - - sprintf( buffer, "%04X_%04X_%02X%02X%02X Cap I", + + sprintf(buffer, "%04X_%04X_%02X%02X%02X Cap I", di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function ); - di->cap_sem = create_sem( 0, buffer ); - if( di->cap_sem < 0 ) { + di->pcii.bus, di->pcii.device, di->pcii.function); + di->cap_sem = create_sem(0, buffer); + if (di->cap_sem < 0) { result = di->cap_sem; goto err3; } - + di->cap_spinlock = 0; - - sprintf( buffer, "%04X_%04X_%02X%02X%02X DMA I", + + sprintf(buffer, "%04X_%04X_%02X%02X%02X DMA I", di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function ); - di->dma_sem = create_sem( 0, buffer ); - if( di->dma_sem < 0 ) { + di->pcii.bus, di->pcii.device, di->pcii.function); + di->dma_sem = create_sem(0, buffer); + if (di->dma_sem < 0) { result = di->dma_sem; goto err4; } - - /* change the owner of the semaphores to the opener's team */ - /* this is required because apps can't aquire kernel semaphores */ - thid = find_thread(NULL); + + /* change the owner of the semaphores to the opener's team */ + /* this is required because apps can't aquire kernel semaphores */ + thid = find_thread(NULL); get_thread_info(thid, &thinfo); set_sem_owner(si->crtc[0].vblank, thinfo.team); - if( di->num_crtc > 1 ) + if (di->num_crtc > 1) set_sem_owner(si->crtc[1].vblank, thinfo.team); //set_sem_owner(di->cap_sem, thinfo.team); - /* disable all interrupts */ - Radeon_DisableIRQ( di ); + /* disable all interrupts */ + Radeon_DisableIRQ(di); - /* if we're faking interrupts */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ + /* if we're faking interrupts */ + if (di->pcii.u.h0.interrupt_pin == 0x00 || di->pcii.u.h0.interrupt_line == 0xff) { SHOW_INFO0( 3, "We like to fake IRQ" ); - /* fake some kind of interrupt with a timer */ - di->shutdown_virtual_irq = false; - si->refresh_period = 16666; /* fake 60Hz to start */ - si->blank_period = si->refresh_period / 20; + /* fake some kind of interrupt with a timer */ + di->shutdown_virtual_irq = false; + si->refresh_period = 16666; /* fake 60Hz to start */ + si->blank_period = si->refresh_period / 20; - di->ti_a.di = di; /* refer to ourself */ - di->ti_b.di = di; - di->current_timer = &(di->ti_a); + di->ti_a.di = di; /* refer to ourself */ + di->ti_b.di = di; + di->current_timer = &di->ti_a; - /* program the first timer interrupt, and it will handle the rest */ - result = add_timer((timer *)(di->current_timer), timer_interrupt_func, - si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER); - if( result != B_OK ) - goto err5; - } else { - /* otherwise install our interrupt handler */ - result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, - Radeon_Interrupt, (void *)di, 0); - if( result != B_OK ) - goto err5; + /* program the first timer interrupt, and it will handle the rest */ + result = add_timer((timer *)(di->current_timer), timer_interrupt_func, + si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER); + if (result != B_OK) + goto err5; + } else { + /* otherwise install our interrupt handler */ + dprintf("radeon: real interrupt handling disabled\n"); +#if 0 + result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, + Radeon_Interrupt, (void *)di, 0); + if (result != B_OK) + goto err5; - SHOW_INFO( 3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line ); - } - - return B_OK; + SHOW_INFO(3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line); +#endif + } + + return B_OK; err5: - delete_sem( di->dma_sem ); + delete_sem(di->dma_sem); err4: - delete_sem( di->cap_sem ); + delete_sem(di->cap_sem); err3: - if( di->num_crtc > 1 ) - delete_sem( si->crtc[1].vblank ); + if (di->num_crtc > 1) + delete_sem(si->crtc[1].vblank); err2: - delete_sem( si->crtc[0].vblank ); + delete_sem(si->crtc[0].vblank); err1: return result; } -// clean-up interrupt handling +/** Clean-up interrupt handling */ + void -Radeon_CleanupIRQ( device_info *di ) +Radeon_CleanupIRQ(device_info *di) { shared_info *si = di->si; - - Radeon_DisableIRQ( di ); - - /* if we were faking the interrupts */ - if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ - /* stop our interrupt faking thread */ - di->shutdown_virtual_irq = true; - /* cancel the timer */ - /* we don't know which one is current, so cancel them both and ignore any error */ - cancel_timer((timer *)&(di->ti_a)); - cancel_timer((timer *)&(di->ti_b)); - } else { - /* remove interrupt handler */ - remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, Radeon_Interrupt, di); - } - delete_sem( si->crtc[0].vblank ); - - if( di->num_crtc > 1 ) - delete_sem( si->crtc[1].vblank ); - - delete_sem( di->cap_sem ); - delete_sem( di->dma_sem ); + Radeon_DisableIRQ(di); + +#if 0 + /* if we were faking the interrupts */ + if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ + /* stop our interrupt faking thread */ + di->shutdown_virtual_irq = true; + /* cancel the timer */ + /* we don't know which one is current, so cancel them both and ignore any error */ + cancel_timer((timer *)&(di->ti_a)); + cancel_timer((timer *)&(di->ti_b)); + } else { + /* remove interrupt handler */ + remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, Radeon_Interrupt, di); + } +#endif + + delete_sem(si->crtc[0].vblank); + + if (di->num_crtc > 1) + delete_sem(si->crtc[1].vblank); + + delete_sem(di->cap_sem); + delete_sem(di->dma_sem); di->cap_sem = si->crtc[1].vblank = si->crtc[0].vblank = 0; }