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
This commit is contained in:
Axel Dörfler
2006-02-28 21:22:26 +00:00
parent 3a14d2275f
commit adbba9cd76
+185 -163
View File
@@ -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.
*/
/** Interrupt handling. Currently, none of this is used
Part of Radeon kernel driver * as I haven't got the HW spec.
*/
Interrupt handling. Currently, none of this is used
as I haven't got the HW spec.
*/
#include "radeon_driver.h"
#include <stdio.h>
#include "mmio.h" #include "mmio.h"
#include "radeon_driver.h"
#include "rbbm_regs.h" #include "rbbm_regs.h"
#include <stdio.h>
// disable all interrupts
static void /** Disable all interrupts */
Radeon_DisableIRQ( device_info *di )
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 /** Interrupt worker routine
// handles standard interrupts, i.e. VBI and DMA * handles standard interrupts, i.e. VBI and DMA
static uint32 */
Radeon_ThreadInterruptWork( vuint8 *regs, device_info *di, uint32 int_status )
static uint32
Radeon_ThreadInterruptWork(vuint8 *regs, device_info *di, uint32 int_status)
{ {
shared_info *si = di->si; shared_info *si = di->si;
uint32 handled = B_HANDLED_INTERRUPT; uint32 handled = B_HANDLED_INTERRUPT;
if( (int_status & RADEON_CRTC_VBLANK_STAT) != 0 && if ((int_status & RADEON_CRTC_VBLANK_STAT) != 0
si->crtc[0].vblank >= 0 ) && si->crtc[0].vblank >= 0) {
{
int32 blocked; int32 blocked;
++di->vbi_count[0]; ++di->vbi_count[0];
if( (get_sem_count( si->crtc[0].vblank, &blocked ) == B_OK) && (blocked < 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 ); release_sem_etc(si->crtc[0].vblank, -blocked, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER; handled = B_INVOKE_SCHEDULER;
} }
} }
if( (int_status & RADEON_CRTC2_VBLANK_STAT) != 0 && if ((int_status & RADEON_CRTC2_VBLANK_STAT) != 0
si->crtc[1].vblank >= 0 ) && si->crtc[1].vblank >= 0) {
{
int32 blocked; int32 blocked;
++di->vbi_count[1]; ++di->vbi_count[1];
if( (get_sem_count( si->crtc[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) { 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 ); release_sem_etc(si->crtc[1].vblank, -blocked, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER; handled = B_INVOKE_SCHEDULER;
} }
} }
if( (int_status & RADEON_VIDDMA_STAT ) != 0 ) { if ((int_status & RADEON_VIDDMA_STAT) != 0) {
release_sem_etc( di->dma_sem, 1, B_DO_NOT_RESCHEDULE ); release_sem_etc(di->dma_sem, 1, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER; handled = B_INVOKE_SCHEDULER;
} }
return handled; return handled;
} }
// Capture interrupt handler #if 0
/** Capture interrupt handler */
static int32 static int32
Radeon_HandleCaptureInterrupt( vuint8 *regs, device_info *di, uint32 cap_status ) Radeon_HandleCaptureInterrupt(vuint8 *regs, device_info *di, uint32 cap_status)
{ {
int32 blocked; int32 blocked;
uint32 handled = B_HANDLED_INTERRUPT; uint32 handled = B_HANDLED_INTERRUPT;
cpu_status prev_irq_state = disable_interrupts(); cpu_status prev_irq_state = disable_interrupts();
acquire_spinlock( &di->cap_spinlock ); acquire_spinlock(&di->cap_spinlock);
++di->cap_counter; ++di->cap_counter;
di->cap_int_status = cap_status; di->cap_int_status = cap_status;
di->cap_timestamp = system_time(); di->cap_timestamp = system_time();
release_spinlock( &di->cap_spinlock ); release_spinlock(&di->cap_spinlock);
restore_interrupts( prev_irq_state ); restore_interrupts(prev_irq_state);
// don't release if semaphore count is positive, i.e. notifications are piling up // 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) ) { if (get_sem_count(di->cap_sem, &blocked) == B_OK && blocked <= 0) {
release_sem_etc( di->cap_sem, 1, B_DO_NOT_RESCHEDULE ); release_sem_etc(di->cap_sem, 1, B_DO_NOT_RESCHEDULE);
handled = B_INVOKE_SCHEDULER; handled = B_INVOKE_SCHEDULER;
} }
// acknowledge IRQ // acknowledge IRQ
OUTREG( regs, RADEON_CAP_INT_STATUS, cap_status ); OUTREG(regs, RADEON_CAP_INT_STATUS, cap_status);
return handled; return handled;
} }
// Main interrupt handler
/** Main interrupt handler */
static int32 static int32
Radeon_Interrupt(void *data) Radeon_Interrupt(void *data)
{ {
@@ -105,43 +111,46 @@ Radeon_Interrupt(void *data)
int32 full_int_status, int_status; int32 full_int_status, int_status;
// read possible IRQ reasons, ignoring any masked IRQs // read possible IRQ reasons, ignoring any masked IRQs
full_int_status = INREG( regs, RADEON_GEN_INT_STATUS ); full_int_status = INREG(regs, RADEON_GEN_INT_STATUS);
int_status = full_int_status & INREG( regs, RADEON_GEN_INT_CNTL ); int_status = full_int_status & INREG(regs, RADEON_GEN_INT_CNTL);
if( int_status != 0 ) { if (int_status != 0) {
++di->interrupt_count; ++di->interrupt_count;
handled = Radeon_ThreadInterruptWork( regs, di, int_status ); handled = Radeon_ThreadInterruptWork(regs, di, int_status);
// acknowledge IRQ // 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; // capture interrupt have no mask in GEN_INT_CNTL register;
// probably, ATI wanted to make capture interrupt control independant of main control // 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; 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; int32 cap_handled;
cap_handled = Radeon_HandleCaptureInterrupt( regs, di, cap_status ); cap_handled = Radeon_HandleCaptureInterrupt(regs, di, cap_status);
if( cap_handled == B_INVOKE_SCHEDULER || handled == B_INVOKE_SCHEDULER ) if (cap_handled == B_INVOKE_SCHEDULER || 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; 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(); bigtime_t now = system_time();
/* get the pointer to the device we're handling this 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; int32 result = B_HANDLED_INTERRUPT;
/* are we suppoesed to handle interrupts still? */ /* are we suppoesed to handle interrupts still? */
if( !di->shutdown_virtual_irq ) { if (!di->shutdown_virtual_irq) {
/* reschedule with same period by default */ /* reschedule with same period by default */
bigtime_t when = si->refresh_period; bigtime_t when = si->refresh_period;
timer *to; timer *to;
/* if interrupts are "enabled", do our thing */ /* if interrupts are "enabled", do our thing */
if( si->enable_virtual_irq ) { if (si->enable_virtual_irq) {
/* insert code to sync to interrupts here */ /* insert code to sync to interrupts here */
if (!vbl_status) { if (!vbl_status) {
when -= si->blank_period - 4; when -= si->blank_period - 4;
} }
/* do the things we do when we notice a vertical retrace */ /* do the things we do when we notice a vertical retrace */
result = Radeon_ThreadInterruptWork( regs, di, result = Radeon_ThreadInterruptWork(regs, di,
RADEON_CRTC_VBLANK_STAT | RADEON_CRTC_VBLANK_STAT
(di->num_crtc > 1 ? RADEON_CRTC2_VBLANK_STAT : 0 )); | (di->num_crtc > 1 ? RADEON_CRTC2_VBLANK_STAT : 0));
} }
/* pick the "other" timer */ /* pick the "other" timer */
to = (timer *)&(di->ti_a); to = (timer *)&di->ti_a;
if (to == te) to = (timer *)&(di->ti_b); if (to == te)
to = (timer *)&di->ti_b;
/* our guess as to when we should be back */ /* our guess as to when we should be back */
((timer_info *)to)->when_target = now + when; ((timer_info *)to)->when_target = now + when;
/* reschedule the interrupt */ /* 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 */ /* remember the currently active timer */
di->current_timer = (timer_info *)to; di->current_timer = (timer_info *)to;
} }
@@ -184,142 +198,150 @@ static int32 timer_interrupt_func( timer *te )
} }
// setup IRQ handlers. /** Setup IRQ handlers.
// includes an VBI emulator via a timer (according to sample code), * Includes an VBI emulator via a timer (according to sample code),
// though this makes sense for one CRTC only * though this makes sense for one CRTC only.
*/
status_t status_t
Radeon_SetupIRQ( device_info *di, char *buffer ) Radeon_SetupIRQ(device_info *di, char *buffer)
{ {
shared_info *si = di->si; shared_info *si = di->si;
status_t result; status_t result;
thread_id thid; thread_id thid;
thread_info thinfo; 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.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function ); di->pcii.bus, di->pcii.device, di->pcii.function);
si->crtc[0].vblank = create_sem( 0, buffer ); si->crtc[0].vblank = create_sem(0, buffer);
if( si->crtc[0].vblank < 0 ) { if (si->crtc[0].vblank < 0) {
result = si->crtc[0].vblank; result = si->crtc[0].vblank;
goto err1; goto err1;
} }
si->crtc[1].vblank = 0; si->crtc[1].vblank = 0;
if( di->num_crtc > 1 ) { if (di->num_crtc > 1) {
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 2", sprintf(buffer, "%04X_%04X_%02X%02X%02X VBI 2",
di->pcii.vendor_id, di->pcii.device_id, di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function ); di->pcii.bus, di->pcii.device, di->pcii.function);
si->crtc[1].vblank = create_sem( 0, buffer ); si->crtc[1].vblank = create_sem(0, buffer);
if( si->crtc[1].vblank < 0 ) { if (si->crtc[1].vblank < 0) {
result = si->crtc[1].vblank; result = si->crtc[1].vblank;
goto err2; 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.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function ); di->pcii.bus, di->pcii.device, di->pcii.function);
di->cap_sem = create_sem( 0, buffer ); di->cap_sem = create_sem(0, buffer);
if( di->cap_sem < 0 ) { if (di->cap_sem < 0) {
result = di->cap_sem; result = di->cap_sem;
goto err3; goto err3;
} }
di->cap_spinlock = 0; 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.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function ); di->pcii.bus, di->pcii.device, di->pcii.function);
di->dma_sem = create_sem( 0, buffer ); di->dma_sem = create_sem(0, buffer);
if( di->dma_sem < 0 ) { if (di->dma_sem < 0) {
result = di->dma_sem; result = di->dma_sem;
goto err4; goto err4;
} }
/* change the owner of the semaphores to the opener's team */ /* change the owner of the semaphores to the opener's team */
/* this is required because apps can't aquire kernel semaphores */ /* this is required because apps can't aquire kernel semaphores */
thid = find_thread(NULL); thid = find_thread(NULL);
get_thread_info(thid, &thinfo); get_thread_info(thid, &thinfo);
set_sem_owner(si->crtc[0].vblank, thinfo.team); 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(si->crtc[1].vblank, thinfo.team);
//set_sem_owner(di->cap_sem, thinfo.team); //set_sem_owner(di->cap_sem, thinfo.team);
/* disable all interrupts */ /* disable all interrupts */
Radeon_DisableIRQ( di ); Radeon_DisableIRQ(di);
/* if we're faking interrupts */ /* if we're faking interrupts */
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){ if (di->pcii.u.h0.interrupt_pin == 0x00 || di->pcii.u.h0.interrupt_line == 0xff) {
SHOW_INFO0( 3, "We like to fake IRQ" ); SHOW_INFO0( 3, "We like to fake IRQ" );
/* fake some kind of interrupt with a timer */ /* fake some kind of interrupt with a timer */
di->shutdown_virtual_irq = false; di->shutdown_virtual_irq = false;
si->refresh_period = 16666; /* fake 60Hz to start */ si->refresh_period = 16666; /* fake 60Hz to start */
si->blank_period = si->refresh_period / 20; si->blank_period = si->refresh_period / 20;
di->ti_a.di = di; /* refer to ourself */ di->ti_a.di = di; /* refer to ourself */
di->ti_b.di = di; di->ti_b.di = di;
di->current_timer = &(di->ti_a); di->current_timer = &di->ti_a;
/* program the first timer interrupt, and it will handle the rest */ /* program the first timer interrupt, and it will handle the rest */
result = add_timer((timer *)(di->current_timer), timer_interrupt_func, result = add_timer((timer *)(di->current_timer), timer_interrupt_func,
si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER); si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER);
if( result != B_OK ) if (result != B_OK)
goto err5; goto err5;
} else { } else {
/* otherwise install our interrupt handler */ /* otherwise install our interrupt handler */
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, dprintf("radeon: real interrupt handling disabled\n");
Radeon_Interrupt, (void *)di, 0); #if 0
if( result != B_OK ) result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line,
goto err5; Radeon_Interrupt, (void *)di, 0);
if (result != B_OK)
goto err5;
SHOW_INFO( 3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line ); SHOW_INFO(3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line);
} #endif
}
return B_OK;
return B_OK;
err5: err5:
delete_sem( di->dma_sem ); delete_sem(di->dma_sem);
err4: err4:
delete_sem( di->cap_sem ); delete_sem(di->cap_sem);
err3: err3:
if( di->num_crtc > 1 ) if (di->num_crtc > 1)
delete_sem( si->crtc[1].vblank ); delete_sem(si->crtc[1].vblank);
err2: err2:
delete_sem( si->crtc[0].vblank ); delete_sem(si->crtc[0].vblank);
err1: err1:
return result; return result;
} }
// clean-up interrupt handling /** Clean-up interrupt handling */
void void
Radeon_CleanupIRQ( device_info *di ) Radeon_CleanupIRQ(device_info *di)
{ {
shared_info *si = di->si; 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 ); Radeon_DisableIRQ(di);
if( di->num_crtc > 1 ) #if 0
delete_sem( si->crtc[1].vblank ); /* if we were faking the interrupts */
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
delete_sem( di->cap_sem ); /* stop our interrupt faking thread */
delete_sem( di->dma_sem ); 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; di->cap_sem = si->crtc[1].vblank = si->crtc[0].vblank = 0;
} }