* buffer_ready_sem was released with B_DO_NOT_RESCHEDULE, but without

returning B_INVOKE_SCHEDULER from the interrupt handler, causing
  latencies up to a full quantum for the multi audio output thread. This
  change improves audio clicks quite a bit on my machine. Though they still
  happen from time to time and particulary on FS activity.
* Automatic whitespace cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34633 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-11 16:16:44 +00:00
parent ed4f4fcf8b
commit 59967f764e
@@ -82,19 +82,21 @@ next_corb(hda_controller *controller)
} }
//! Called with interrupts off /*! Called with interrupts off.
static void Returns \c true, if the scheduler shall be invoked.
*/
static bool
stream_handle_interrupt(hda_controller* controller, hda_stream* stream) stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
{ {
uint8 status; uint8 status;
uint32 position, bufferSize; uint32 position, bufferSize;
if (!stream->running) if (!stream->running)
return; return false;
status = stream->Read8(HDAC_STREAM_STATUS); status = stream->Read8(HDAC_STREAM_STATUS);
if (status == 0) if (status == 0)
return; return false;
stream->Write8(HDAC_STREAM_STATUS, status); stream->Write8(HDAC_STREAM_STATUS, status);
@@ -105,11 +107,11 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
if ((status & STATUS_BUFFER_COMPLETED) == 0) { if ((status & STATUS_BUFFER_COMPLETED) == 0) {
dprintf("hda: stream buffer not completed (id:%ld)\n", stream->id); dprintf("hda: stream buffer not completed (id:%ld)\n", stream->id);
return; return false;
} }
position = stream->Read32(HDAC_STREAM_POSITION); position = stream->Read32(HDAC_STREAM_POSITION);
bufferSize = ALIGN(stream->sample_size * stream->num_channels bufferSize = ALIGN(stream->sample_size * stream->num_channels
* stream->buffer_length, 128); * stream->buffer_length, 128);
// Buffer Completed Interrupt // Buffer Completed Interrupt
@@ -122,13 +124,15 @@ stream_handle_interrupt(hda_controller* controller, hda_stream* stream)
release_spinlock(&stream->lock); release_spinlock(&stream->lock);
release_sem_etc(controller->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); release_sem_etc(controller->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
if (stream->warn_count < 20 if (stream->warn_count < 20
&& (position - stream->buffer_cycle * bufferSize) > (bufferSize >> 1)) { && (position - stream->buffer_cycle * bufferSize) > (bufferSize >> 1)) {
dprintf("hda: stream incorrect position %ld %ld %ld\n", dprintf("hda: stream incorrect position %ld %ld %ld\n",
stream->id, stream->buffer_cycle, position); stream->id, stream->buffer_cycle, position);
stream->warn_count++; stream->warn_count++;
} }
return true;
} }
@@ -167,7 +171,7 @@ hda_interrupt_handler(hda_controller* controller)
"%08lx/%08lx\n", cad, response, responseFlags); "%08lx/%08lx\n", cad, response, responseFlags);
continue; continue;
} }
if ((responseFlags & RESPONSE_FLAGS_UNSOLICITED) != 0) { if ((responseFlags & RESPONSE_FLAGS_UNSOLICITED) != 0) {
dprintf("hda: Unsolicited response: %08lx/%08lx\n", dprintf("hda: Unsolicited response: %08lx/%08lx\n",
response, responseFlags); response, responseFlags);
@@ -211,8 +215,10 @@ hda_interrupt_handler(hda_controller* controller)
for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) { for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
if ((intrStatus & (1 << index)) != 0) { if ((intrStatus & (1 << index)) != 0) {
if (controller->streams[index]) { if (controller->streams[index]) {
stream_handle_interrupt(controller, if (stream_handle_interrupt(controller,
controller->streams[index]); controller->streams[index])) {
handled = B_INVOKE_SCHEDULER;
}
} else { } else {
dprintf("hda: Stream interrupt for unconfigured stream " dprintf("hda: Stream interrupt for unconfigured stream "
"%ld!\n", index); "%ld!\n", index);
@@ -296,11 +302,11 @@ reset_controller(hda_controller* controller)
// Wait for codecs to finish their own reset (apparently needs more // Wait for codecs to finish their own reset (apparently needs more
// time than documented in the specs) // time than documented in the specs)
snooze(1000); snooze(1000);
// Enable unsolicited responses // Enable unsolicited responses
control = controller->Read32(HDAC_GLOBAL_CONTROL); control = controller->Read32(HDAC_GLOBAL_CONTROL);
controller->Write32(HDAC_GLOBAL_CONTROL, control | GLOBAL_CONTROL_UNSOLICITED); controller->Write32(HDAC_GLOBAL_CONTROL, control | GLOBAL_CONTROL_UNSOLICITED);
return B_OK; return B_OK;
} }
@@ -488,7 +494,7 @@ status_t
hda_stream_start(hda_controller* controller, hda_stream* stream) hda_stream_start(hda_controller* controller, hda_stream* stream)
{ {
dprintf("hda_stream_start() offset %lx\n", stream->offset); dprintf("hda_stream_start() offset %lx\n", stream->offset);
controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL) controller->Write32(HDAC_INTR_CONTROL, controller->Read32(HDAC_INTR_CONTROL)
| (1 << (stream->offset / HDAC_STREAM_SIZE))); | (1 << (stream->offset / HDAC_STREAM_SIZE)));
stream->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0) stream->Write8(HDAC_STREAM_CONTROL0, stream->Read8(HDAC_STREAM_CONTROL0)
@@ -577,12 +583,12 @@ hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream,
else if (stream->sample_size > 2) else if (stream->sample_size > 2)
offset = 4; offset = 4;
} else { } else {
offset = 11; offset = 11;
} }
offset *= 64; offset *= 64;
offset = ALIGN(offset, 128); offset = ALIGN(offset, 128);
} }
/* Calculate size of buffer (aligned to 128 bytes) */ /* Calculate size of buffer (aligned to 128 bytes) */
uint32 bufferSize = stream->sample_size * stream->num_channels uint32 bufferSize = stream->sample_size * stream->num_channels
* stream->buffer_length; * stream->buffer_length;
@@ -659,7 +665,7 @@ hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream,
} }
/* Setup buffer descriptor list (BDL) entries */ /* Setup buffer descriptor list (BDL) entries */
for (uint32 index = 0; index < stream->num_buffers; index++, for (uint32 index = 0; index < stream->num_buffers; index++,
bufferDescriptors++) { bufferDescriptors++) {
bufferDescriptors->lower = stream->physical_buffers[index] + offset; bufferDescriptors->lower = stream->physical_buffers[index] + offset;
bufferDescriptors->upper = 0; bufferDescriptors->upper = 0;
@@ -689,7 +695,7 @@ hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream,
stream->controller->Read32(HDAC_DMA_POSITION_BASE_LOWER) stream->controller->Read32(HDAC_DMA_POSITION_BASE_LOWER)
| DMA_POSITION_ENABLED); | DMA_POSITION_ENABLED);
dprintf("hda: stream: %ld fifo size: %d num_io_widgets: %ld\n", stream->id, dprintf("hda: stream: %ld fifo size: %d num_io_widgets: %ld\n", stream->id,
stream->Read16(HDAC_STREAM_FIFO_SIZE), stream->num_io_widgets); stream->Read16(HDAC_STREAM_FIFO_SIZE), stream->num_io_widgets);
dprintf("hda: widgets: "); dprintf("hda: widgets: ");
@@ -710,7 +716,7 @@ hda_stream_setup_buffers(hda_audio_group* audioGroup, hda_stream* stream,
dprintf("%ld ", stream->io_widgets[i]); dprintf("%ld ", stream->io_widgets[i]);
} }
dprintf("\n"); dprintf("\n");
snooze(1000); snooze(1000);
return B_OK; return B_OK;
} }
@@ -880,7 +886,7 @@ hda_hw_init(hda_controller* controller)
break; break;
} }
} }
controller->buffer_ready_sem = create_sem(0, "hda_buffer_sem"); controller->buffer_ready_sem = create_sem(0, "hda_buffer_sem");
if (controller->buffer_ready_sem < B_OK) { if (controller->buffer_ready_sem < B_OK) {
dprintf("hda: failed to create semaphore\n"); dprintf("hda: failed to create semaphore\n");
@@ -893,7 +899,7 @@ hda_hw_init(hda_controller* controller)
dprintf("hda: no active codec\n"); dprintf("hda: no active codec\n");
status = ENODEV; status = ENODEV;
delete_sem(controller->buffer_ready_sem); delete_sem(controller->buffer_ready_sem);
corb_rirb_failed: corb_rirb_failed:
@@ -940,7 +946,7 @@ hda_hw_uninit(hda_controller* controller)
/* Stop all audio streams */ /* Stop all audio streams */
hda_hw_stop(controller); hda_hw_stop(controller);
if (controller->buffer_ready_sem >= B_OK) { if (controller->buffer_ready_sem >= B_OK) {
delete_sem(controller->buffer_ready_sem); delete_sem(controller->buffer_ready_sem);
controller->buffer_ready_sem = B_ERROR; controller->buffer_ready_sem = B_ERROR;