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:
@@ -70,6 +70,7 @@ struct hda_controller {
|
|||||||
area_id regs_area;
|
area_id regs_area;
|
||||||
vuint8* regs;
|
vuint8* regs;
|
||||||
uint32 irq;
|
uint32 irq;
|
||||||
|
bool msi;
|
||||||
|
|
||||||
uint16 codec_status;
|
uint16 codec_status;
|
||||||
uint32 num_input_streams;
|
uint32 num_input_streams;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <PCI_x86.h>
|
||||||
|
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "hda_codec_defs.h"
|
#include "hda_codec_defs.h"
|
||||||
|
|
||||||
@@ -52,6 +54,8 @@ static const struct {
|
|||||||
// {B_SR_384000, MAKE_RATE(44100, ??, ??), 384000},
|
// {B_SR_384000, MAKE_RATE(44100, ??, ??), 384000},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static pci_x86_module_info* sPCIx86Module;
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
update_pci_register(hda_controller* controller, uint8 reg, uint32 mask, uint32 value, uint8 size)
|
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;
|
uint16 capabilities, stateStatus, cmd;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
/* Map MMIO registers */
|
// Map MMIO registers
|
||||||
controller->regs_area = map_physical_memory("hda_hw_regs",
|
controller->regs_area = map_physical_memory("hda_hw_regs",
|
||||||
controller->pci_info.u.h0.base_registers[0],
|
controller->pci_info.u.h0.base_registers[0],
|
||||||
controller->pci_info.u.h0.base_register_sizes[0], B_ANY_KERNEL_ADDRESS,
|
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,
|
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)) {
|
if (!(cmd & PCI_command_master)) {
|
||||||
(gPci->write_pci_config)(controller->pci_info.bus,
|
(gPci->write_pci_config)(controller->pci_info.bus,
|
||||||
controller->pci_info.device, controller->pci_info.function,
|
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");
|
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->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,
|
status = install_io_interrupt_handler(controller->irq,
|
||||||
(interrupt_handler)hda_interrupt_handler, controller, 0);
|
(interrupt_handler)hda_interrupt_handler, controller, 0);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
goto no_irq;
|
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);
|
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,
|
// Enable snooping for ATI and Nvidia, right now for all their hda-devices,
|
||||||
but only based on guessing. */
|
// but only based on guessing.
|
||||||
switch (controller->pci_info.vendor_id) {
|
switch (controller->pci_info.vendor_id) {
|
||||||
case NVIDIA_VENDORID:
|
case NVIDIA_VENDORID:
|
||||||
update_pci_register(controller, NVIDIA_HDA_TRANSREG,
|
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_output_streams = GLOBAL_CAP_OUTPUT_STREAMS(capabilities);
|
||||||
controller->num_bidir_streams = GLOBAL_CAP_BIDIR_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",
|
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_MAJOR),
|
||||||
controller->Read8(HDAC_VERSION_MINOR),
|
controller->Read8(HDAC_VERSION_MINOR),
|
||||||
@@ -863,29 +892,27 @@ hda_hw_init(hda_controller* controller)
|
|||||||
GLOBAL_CAP_NUM_SDO(capabilities),
|
GLOBAL_CAP_NUM_SDO(capabilities),
|
||||||
GLOBAL_CAP_64BIT(capabilities) ? "yes" : "no");
|
GLOBAL_CAP_64BIT(capabilities) ? "yes" : "no");
|
||||||
|
|
||||||
/* Get controller into valid state */
|
// Get controller into valid state
|
||||||
status = reset_controller(controller);
|
status = reset_controller(controller);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
dprintf("hda: reset_controller failed\n");
|
dprintf("hda: reset_controller failed\n");
|
||||||
goto reset_failed;
|
goto reset_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup CORB/RIRB/DMA POS */
|
// Setup CORB/RIRB/DMA POS
|
||||||
status = init_corb_rirb_pos(controller);
|
status = init_corb_rirb_pos(controller);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
dprintf("hda: init_corb_rirb_pos failed\n");
|
dprintf("hda: init_corb_rirb_pos failed\n");
|
||||||
goto corb_rirb_failed;
|
goto corb_rirb_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Don't enable codec state change interrupts. We don't handle
|
||||||
* Don't enable codec state change interrupts. We don't handle
|
// them, as we want to use the STATE_STATUS register to identify
|
||||||
* them, as we want to use the STATE_STATUS register to identify
|
// available codecs. We'd have to clear that register in the interrupt
|
||||||
* available codecs. We'd have to clear that register in the interrupt
|
// handler to 'ack' the codec change.
|
||||||
* handler to 'ack' the codec change.
|
|
||||||
*/
|
|
||||||
controller->Write16(HDAC_WAKE_ENABLE, 0x0);
|
controller->Write16(HDAC_WAKE_ENABLE, 0x0);
|
||||||
|
|
||||||
/* Enable controller interrupts */
|
// Enable controller interrupts
|
||||||
controller->Write32(HDAC_INTR_CONTROL, INTR_CONTROL_GLOBAL_ENABLE
|
controller->Write32(HDAC_INTR_CONTROL, INTR_CONTROL_GLOBAL_ENABLE
|
||||||
| INTR_CONTROL_CONTROLLER_ENABLE);
|
| INTR_CONTROL_CONTROLLER_ENABLE);
|
||||||
|
|
||||||
@@ -939,6 +966,11 @@ no_irq:
|
|||||||
controller->regs_area = B_ERROR;
|
controller->regs_area = B_ERROR;
|
||||||
controller->regs = NULL;
|
controller->regs = NULL;
|
||||||
|
|
||||||
|
if (sPCIx86Module != NULL) {
|
||||||
|
put_module(B_PCI_X86_MODULE_NAME);
|
||||||
|
sPCIx86Module = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
dprintf("hda: ERROR: %s(%ld)\n", strerror(status), status);
|
dprintf("hda: ERROR: %s(%ld)\n", strerror(status), status);
|
||||||
|
|
||||||
@@ -952,7 +984,7 @@ hda_hw_stop(hda_controller* controller)
|
|||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
/* Stop all audio streams */
|
// Stop all audio streams
|
||||||
for (index = 0; index < HDA_MAX_STREAMS; index++) {
|
for (index = 0; index < HDA_MAX_STREAMS; index++) {
|
||||||
if (controller->streams[index] && controller->streams[index]->running)
|
if (controller->streams[index] && controller->streams[index]->running)
|
||||||
hda_stream_stop(controller, controller->streams[index]);
|
hda_stream_stop(controller, controller->streams[index]);
|
||||||
@@ -969,7 +1001,7 @@ hda_hw_uninit(hda_controller* controller)
|
|||||||
if (controller == NULL)
|
if (controller == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* 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) {
|
||||||
@@ -979,13 +1011,24 @@ hda_hw_uninit(hda_controller* controller)
|
|||||||
|
|
||||||
reset_controller(controller);
|
reset_controller(controller);
|
||||||
|
|
||||||
/* Disable interrupts, and remove interrupt handler */
|
// Disable interrupts, and remove interrupt handler
|
||||||
controller->Write32(HDAC_INTR_CONTROL, 0);
|
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,
|
remove_io_interrupt_handler(controller->irq,
|
||||||
(interrupt_handler)hda_interrupt_handler, controller);
|
(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) {
|
if (controller->corb_rirb_pos_area >= 0) {
|
||||||
delete_area(controller->corb_rirb_pos_area);
|
delete_area(controller->corb_rirb_pos_area);
|
||||||
controller->corb_rirb_pos_area = B_ERROR;
|
controller->corb_rirb_pos_area = B_ERROR;
|
||||||
@@ -994,17 +1037,16 @@ hda_hw_uninit(hda_controller* controller)
|
|||||||
controller->stream_positions = NULL;
|
controller->stream_positions = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmap registers */
|
// Unmap registers
|
||||||
if (controller->regs_area >= 0) {
|
if (controller->regs_area >= 0) {
|
||||||
delete_area(controller->regs_area);
|
delete_area(controller->regs_area);
|
||||||
controller->regs_area = B_ERROR;
|
controller->regs_area = B_ERROR;
|
||||||
controller->regs = NULL;
|
controller->regs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now delete all codecs */
|
// Now delete all codecs
|
||||||
for (index = 0; index < HDA_MAX_CODECS; index++) {
|
for (index = 0; index < HDA_MAX_CODECS; index++) {
|
||||||
if (controller->codecs[index] != NULL)
|
if (controller->codecs[index] != NULL)
|
||||||
hda_codec_delete(controller->codecs[index]);
|
hda_codec_delete(controller->codecs[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user