Implemented MSI support.

* Does not seem to change anything, though (I'm also a victim of bug
  #8949)
* Minor cleanup.
This commit is contained in:
Axel Dörfler
2012-09-21 00:22:54 +02:00
parent 8c3a938fc3
commit 45732903d0
2 changed files with 66 additions and 23 deletions
@@ -70,6 +70,7 @@ struct hda_controller {
area_id regs_area;
vuint8* regs;
uint32 irq;
bool msi;
uint16 codec_status;
uint32 num_input_streams;
@@ -12,6 +12,8 @@
#include <algorithm>
#include <PCI_x86.h>
#include "driver.h"
#include "hda_codec_defs.h"
@@ -52,6 +54,8 @@ static const struct {
// {B_SR_384000, MAKE_RATE(44100, ??, ??), 384000},
};
static pci_x86_module_info* sPCIx86Module;
static inline void
update_pci_register(hda_controller* controller, uint8 reg, uint32 mask, uint32 value, uint8 size)
@@ -797,7 +801,7 @@ hda_hw_init(hda_controller* controller)
uint16 capabilities, stateStatus, cmd;
status_t status;
/* Map MMIO registers */
// Map MMIO registers
controller->regs_area = map_physical_memory("hda_hw_regs",
controller->pci_info.u.h0.base_registers[0],
controller->pci_info.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS,
@@ -808,7 +812,8 @@ hda_hw_init(hda_controller* controller)
}
cmd = (gPci->read_pci_config)(controller->pci_info.bus,
controller->pci_info.device, controller->pci_info.function, PCI_command, 2);
controller->pci_info.device, controller->pci_info.function,
PCI_command, 2);
if (!(cmd & PCI_command_master)) {
(gPci->write_pci_config)(controller->pci_info.bus,
controller->pci_info.device, controller->pci_info.function,
@@ -816,18 +821,42 @@ hda_hw_init(hda_controller* controller)
dprintf("hda: enabling PCI bus mastering\n");
}
/* Absolute minimum hw is online; we can now install interrupt handler */
if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module)
!= B_OK)
sPCIx86Module = NULL;
// Absolute minimum hw is online; we can now install interrupt handler
controller->irq = controller->pci_info.u.h0.interrupt_line;
controller->msi = false;
if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count(
controller->pci_info.bus, controller->pci_info.device,
controller->pci_info.function) >= 1) {
// Try MSI first
uint8 vector;
if (sPCIx86Module->configure_msi(controller->pci_info.bus,
controller->pci_info.device, controller->pci_info.function,
1, &vector) == B_OK
&& sPCIx86Module->enable_msi(controller->pci_info.bus,
controller->pci_info.device, controller->pci_info.function)
== B_OK) {
dprintf("hda: using MSI vector %u\n", vector);
controller->irq = vector;
controller->msi = true;
}
}
status = install_io_interrupt_handler(controller->irq,
(interrupt_handler)hda_interrupt_handler, controller, 0);
if (status != B_OK)
goto no_irq;
/* TCSEL is reset to TC0 (clear 0-2 bits) */
// TCSEL is reset to TC0 (clear 0-2 bits)
update_pci_register(controller, PCI_HDA_TCSEL, PCI_HDA_TCSEL_MASK, 0, 1);
/* Enable snooping for ATI and Nvidia, right now for all their hda-devices,
but only based on guessing. */
// Enable snooping for ATI and Nvidia, right now for all their hda-devices,
// but only based on guessing.
switch (controller->pci_info.vendor_id) {
case NVIDIA_VENDORID:
update_pci_register(controller, NVIDIA_HDA_TRANSREG,
@@ -854,7 +883,7 @@ hda_hw_init(hda_controller* controller)
controller->num_output_streams = GLOBAL_CAP_OUTPUT_STREAMS(capabilities);
controller->num_bidir_streams = GLOBAL_CAP_BIDIR_STREAMS(capabilities);
/* show some hw features */
// show some hw features
dprintf("hda: HDA v%d.%d, O:%ld/I:%ld/B:%ld, #SDO:%d, 64bit:%s\n",
controller->Read8(HDAC_VERSION_MAJOR),
controller->Read8(HDAC_VERSION_MINOR),
@@ -863,29 +892,27 @@ hda_hw_init(hda_controller* controller)
GLOBAL_CAP_NUM_SDO(capabilities),
GLOBAL_CAP_64BIT(capabilities) ? "yes" : "no");
/* Get controller into valid state */
// Get controller into valid state
status = reset_controller(controller);
if (status != B_OK) {
dprintf("hda: reset_controller failed\n");
goto reset_failed;
}
/* Setup CORB/RIRB/DMA POS */
// Setup CORB/RIRB/DMA POS
status = init_corb_rirb_pos(controller);
if (status != B_OK) {
dprintf("hda: init_corb_rirb_pos failed\n");
goto corb_rirb_failed;
}
/*
* Don't enable codec state change interrupts. We don't handle
* them, as we want to use the STATE_STATUS register to identify
* available codecs. We'd have to clear that register in the interrupt
* handler to 'ack' the codec change.
*/
// Don't enable codec state change interrupts. We don't handle
// them, as we want to use the STATE_STATUS register to identify
// available codecs. We'd have to clear that register in the interrupt
// handler to 'ack' the codec change.
controller->Write16(HDAC_WAKE_ENABLE, 0x0);
/* Enable controller interrupts */
// Enable controller interrupts
controller->Write32(HDAC_INTR_CONTROL, INTR_CONTROL_GLOBAL_ENABLE
| INTR_CONTROL_CONTROLLER_ENABLE);
@@ -939,6 +966,11 @@ no_irq:
controller->regs_area = B_ERROR;
controller->regs = NULL;
if (sPCIx86Module != NULL) {
put_module(B_PCI_X86_MODULE_NAME);
sPCIx86Module = NULL;
}
error:
dprintf("hda: ERROR: %s(%ld)\n", strerror(status), status);
@@ -952,7 +984,7 @@ hda_hw_stop(hda_controller* controller)
{
int index;
/* Stop all audio streams */
// Stop all audio streams
for (index = 0; index < HDA_MAX_STREAMS; index++) {
if (controller->streams[index] && controller->streams[index]->running)
hda_stream_stop(controller, controller->streams[index]);
@@ -969,7 +1001,7 @@ hda_hw_uninit(hda_controller* controller)
if (controller == NULL)
return;
/* Stop all audio streams */
// Stop all audio streams
hda_hw_stop(controller);
if (controller->buffer_ready_sem >= B_OK) {
@@ -979,13 +1011,24 @@ hda_hw_uninit(hda_controller* controller)
reset_controller(controller);
/* Disable interrupts, and remove interrupt handler */
// Disable interrupts, and remove interrupt handler
controller->Write32(HDAC_INTR_CONTROL, 0);
if (controller->msi) {
// Disable MSI
sPCIx86Module->disable_msi(controller->pci_info.bus,
controller->pci_info.device, controller->pci_info.function);
}
remove_io_interrupt_handler(controller->irq,
(interrupt_handler)hda_interrupt_handler, controller);
/* Delete corb/rirb area */
if (sPCIx86Module != NULL) {
put_module(B_PCI_X86_MODULE_NAME);
sPCIx86Module = NULL;
}
// Delete corb/rirb area
if (controller->corb_rirb_pos_area >= 0) {
delete_area(controller->corb_rirb_pos_area);
controller->corb_rirb_pos_area = B_ERROR;
@@ -994,17 +1037,16 @@ hda_hw_uninit(hda_controller* controller)
controller->stream_positions = NULL;
}
/* Unmap registers */
// Unmap registers
if (controller->regs_area >= 0) {
delete_area(controller->regs_area);
controller->regs_area = B_ERROR;
controller->regs = NULL;
}
/* Now delete all codecs */
// Now delete all codecs
for (index = 0; index < HDA_MAX_CODECS; index++) {
if (controller->codecs[index] != NULL)
hda_codec_delete(controller->codecs[index]);
}
}