implemented channel init and uninit
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18797 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -59,12 +59,16 @@ static const struct {
|
|||||||
#define SI_MASK_2PORT ((1 << 22) | (1 << 23))
|
#define SI_MASK_2PORT ((1 << 22) | (1 << 23))
|
||||||
#define SI_MASK_4PORT ((1 << 22) | (1 << 23) | (1 << 24) | (1 << 25))
|
#define SI_MASK_4PORT ((1 << 22) | (1 << 23) | (1 << 24) | (1 << 25))
|
||||||
|
|
||||||
|
struct channel_data;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct controller_data {
|
||||||
pci_device_module_info *pci;
|
pci_device_module_info *pci;
|
||||||
pci_device device;
|
pci_device device;
|
||||||
|
|
||||||
device_node_handle node;
|
device_node_handle node;
|
||||||
|
|
||||||
|
struct channel_data *channel[4]; // XXX only for interrupt workaround
|
||||||
|
int channel_count; // XXX only for interrupt workaround
|
||||||
|
|
||||||
uint32 asic_index;
|
uint32 asic_index;
|
||||||
uint32 int_num;
|
uint32 int_num;
|
||||||
@@ -77,11 +81,12 @@ typedef struct {
|
|||||||
} controller_data;
|
} controller_data;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct channel_data {
|
||||||
|
|
||||||
pci_device_module_info *pci;
|
pci_device_module_info *pci;
|
||||||
device_node_handle node;
|
device_node_handle node;
|
||||||
pci_device device;
|
pci_device device;
|
||||||
|
ide_channel ide_channel;
|
||||||
|
|
||||||
volatile uint8 * task_file;
|
volatile uint8 * task_file;
|
||||||
volatile uint8 * control_block;
|
volatile uint8 * control_block;
|
||||||
@@ -104,6 +109,7 @@ static ide_for_controller_interface * ide;
|
|||||||
static ide_adapter_interface * ide_adapter;
|
static ide_adapter_interface * ide_adapter;
|
||||||
static device_manager_info * dm;
|
static device_manager_info * dm;
|
||||||
|
|
||||||
|
static status_t device_control_write(void *channel_cookie, uint8 val);
|
||||||
static int32 handle_interrupt(void *arg);
|
static int32 handle_interrupt(void *arg);
|
||||||
|
|
||||||
|
|
||||||
@@ -275,6 +281,8 @@ controller_init(device_node_handle node, void *user_cookie, void **controller_co
|
|||||||
if (!controller)
|
if (!controller)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
FLOW("controller %p\n", controller);
|
||||||
|
|
||||||
mmio_area = map_physical_memory("Silicon Image SATA regs", (void *)mmio_base,
|
mmio_area = map_physical_memory("Silicon Image SATA regs", (void *)mmio_base,
|
||||||
asic_data[asic_index].mmio_bar_size,
|
asic_data[asic_index].mmio_bar_size,
|
||||||
B_ANY_KERNEL_ADDRESS, 0, (void **)&mmio_addr);
|
B_ANY_KERNEL_ADDRESS, 0, (void **)&mmio_addr);
|
||||||
@@ -305,6 +313,10 @@ controller_init(device_node_handle node, void *user_cookie, void **controller_co
|
|||||||
controller->mmio_addr = mmio_addr;
|
controller->mmio_addr = mmio_addr;
|
||||||
controller->lost = 0;
|
controller->lost = 0;
|
||||||
|
|
||||||
|
controller->channel_count = asic_data[asic_index].channel_count;
|
||||||
|
for (i = 0; i < asic_data[asic_index].channel_count; i++)
|
||||||
|
controller->channel[i] = 0;
|
||||||
|
|
||||||
if (asic_index == ASIC_SI3114) {
|
if (asic_index == ASIC_SI3114) {
|
||||||
// I put a magic spell on you
|
// I put a magic spell on you
|
||||||
temp = *(volatile uint32 *)mmio_addr + SI_BMDMA2;
|
temp = *(volatile uint32 *)mmio_addr + SI_BMDMA2;
|
||||||
@@ -374,37 +386,76 @@ static status_t
|
|||||||
channel_init(device_node_handle node, void *user_cookie, void **channel_cookie)
|
channel_init(device_node_handle node, void *user_cookie, void **channel_cookie)
|
||||||
{
|
{
|
||||||
ide_channel ide_channel = user_cookie;
|
ide_channel ide_channel = user_cookie;
|
||||||
|
controller_data *controller;
|
||||||
channel_data *channel;
|
channel_data *channel;
|
||||||
|
physical_entry pe[1];
|
||||||
|
size_t prdt_size;
|
||||||
|
uint32 chan_index;
|
||||||
|
|
||||||
|
TRACE("channel_init enter\n");
|
||||||
|
|
||||||
channel = malloc(sizeof(channel_data));
|
channel = malloc(sizeof(channel_data));
|
||||||
if (!channel)
|
if (!channel)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
TRACE("channel %p\n", channel);
|
||||||
|
|
||||||
|
if (dm->get_attr_uint32(node, "silicon_image_3112/chan_index", &chan_index, false) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
TRACE("channel_index %ld", chan_index);
|
||||||
|
TRACE("channel name: %s\n", controller_channel_data[chan_index].name);
|
||||||
|
|
||||||
|
if (dm->init_driver(dm->get_parent(node), NULL, NULL, (void **)&controller) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
TRACE("controller %p\n", controller);
|
||||||
|
TRACE("mmio_addr %p\n", (void *)controller->mmio_addr);
|
||||||
|
|
||||||
|
// PRDT must be contiguous, dword-aligned and must not cross 64K boundary
|
||||||
|
prdt_size = (IDE_ADAPTER_MAX_SG_COUNT * sizeof(prd_entry) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
|
||||||
|
channel->prd_area = create_area("prd", (void **)&channel->prdt, B_ANY_KERNEL_ADDRESS, prdt_size, B_FULL_LOCK | B_CONTIGUOUS, 0);
|
||||||
|
if (channel->prd_area < B_OK) {
|
||||||
|
TRACE("creating prd_area failed\n");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_memory_map(channel->prdt, prdt_size, pe, 1);
|
||||||
|
channel->prdt_phys = (void *)(uint32)pe[0].address;
|
||||||
|
|
||||||
|
channel->pci = controller->pci;
|
||||||
|
channel->device = controller->device;
|
||||||
|
channel->node = node;
|
||||||
|
channel->ide_channel = ide_channel;
|
||||||
|
|
||||||
|
channel->task_file = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].cmd + 1);
|
||||||
|
channel->control_block = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].ctl);
|
||||||
|
channel->command_block = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].cmd);
|
||||||
|
channel->dev_ctrl = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].ctl);
|
||||||
|
channel->bm_prdt_address = (volatile uint32 *)(controller->mmio_addr + controller_channel_data[chan_index].bmdma + ide_bm_prdt_address);
|
||||||
|
channel->bm_status_reg = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].bmdma + ide_bm_status_reg);
|
||||||
|
channel->bm_command_reg = (volatile uint8 *)(controller->mmio_addr + controller_channel_data[chan_index].bmdma + ide_bm_command_reg);
|
||||||
|
|
||||||
|
channel->lost = 0;
|
||||||
|
channel->dma_active = 0;
|
||||||
|
|
||||||
/*
|
controller->channel[chan_index] = channel;
|
||||||
channel->
|
|
||||||
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
device_node_handle node;
|
|
||||||
pci_device device;
|
|
||||||
|
|
||||||
volatile uint8 *task_file (volatile uint8 *)(channel->mmio_addr + channel->command_block_base + 1);
|
// enable interrupts so the channel is ready to run
|
||||||
volatile uint8 *control_block (volatile uint8 *)(channel->mmio_addr + channel->control_block_base);
|
device_control_write(channel, ide_devctrl_bit3);
|
||||||
volatile uint8 *command_block
|
|
||||||
volatile uint8 *dev_ctrl
|
|
||||||
volatile uint32 * bm_prdt_address = (volatile uint32 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_prdt_address);
|
|
||||||
volatile uint8 * bm_status_reg = (volatile uint8 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_status_reg);
|
|
||||||
volatile uint8 * bm_command_reg = (volatile uint8 *)(channel->mmio_addr + channel->bus_master_base + ata_bm_command_reg);
|
|
||||||
|
|
||||||
uint32 lost;
|
|
||||||
|
|
||||||
prd_entry *prdt;
|
|
||||||
area_id prd_area;
|
|
||||||
prd_entry *prdt;
|
|
||||||
uint32 dma_active;
|
|
||||||
*/
|
|
||||||
|
|
||||||
*channel_cookie = channel;
|
*channel_cookie = channel;
|
||||||
|
|
||||||
|
TRACE("channel_init leave\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
|
err3:
|
||||||
|
delete_area(channel->prd_area);
|
||||||
|
err2:
|
||||||
|
dm->uninit_driver(dm->get_parent(node));
|
||||||
|
err:
|
||||||
|
free(channel);
|
||||||
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -412,7 +463,20 @@ static status_t
|
|||||||
channel_uninit(void *channel_cookie)
|
channel_uninit(void *channel_cookie)
|
||||||
{
|
{
|
||||||
channel_data *channel = channel_cookie;
|
channel_data *channel = channel_cookie;
|
||||||
return B_ERROR;
|
|
||||||
|
// disable IRQs
|
||||||
|
device_control_write(channel, ide_devctrl_bit3 | ide_devctrl_nien);
|
||||||
|
|
||||||
|
// catch spurious interrupt
|
||||||
|
// (some controllers generate an IRQ when you _disable_ interrupts,
|
||||||
|
// they are delayed by less then 40 µs, so 1 ms is safe)
|
||||||
|
snooze(1000);
|
||||||
|
|
||||||
|
dm->uninit_driver(dm->get_parent(channel->node));
|
||||||
|
|
||||||
|
delete_area(channel->prd_area);
|
||||||
|
free(channel);
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -420,6 +484,7 @@ static void
|
|||||||
channel_removed(device_node_handle node, void *channel_cookie)
|
channel_removed(device_node_handle node, void *channel_cookie)
|
||||||
{
|
{
|
||||||
channel_data *channel = channel_cookie;
|
channel_data *channel = channel_cookie;
|
||||||
|
channel->lost = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -689,32 +754,30 @@ static int32
|
|||||||
handle_interrupt(void *arg)
|
handle_interrupt(void *arg)
|
||||||
{
|
{
|
||||||
controller_data *controller = arg;
|
controller_data *controller = arg;
|
||||||
pci_device_module_info *pci = controller->pci;
|
|
||||||
pci_device device = controller->device;
|
|
||||||
ide_bm_status bm_status;
|
ide_bm_status bm_status;
|
||||||
uint8 status;
|
uint8 status;
|
||||||
|
int i;
|
||||||
|
|
||||||
FLOW("handle_interrupt\n");
|
FLOW("handle_interrupt\n");
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
/*
|
|
||||||
if (channel->lost)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
// add test whether this is really our IRQ
|
|
||||||
if (channel->dma_active) {
|
|
||||||
// in DMA mode, there is a safe test
|
|
||||||
// in PIO mode, this doesn't work
|
|
||||||
*(uint8 *)&bm_status = *channel->bm_status_reg;
|
|
||||||
|
|
||||||
if (!bm_status.interrupt)
|
// XXX This is bogus
|
||||||
return B_UNHANDLED_INTERRUPT;
|
for (i = 0; i < controller->channel_count; i++) {
|
||||||
|
channel_data *channel = controller->channel[i];
|
||||||
|
if (!channel || channel->lost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (channel->dma_active) {
|
||||||
|
*(uint8 *)&bm_status = *channel->bm_status_reg;
|
||||||
|
if (!bm_status.interrupt)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// acknowledge IRQ
|
||||||
|
status = *(channel->command_block + 7);
|
||||||
|
return ide->irq_handler(channel->ide_channel, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// acknowledge IRQ
|
return B_UNHANDLED_INTERRUPT;
|
||||||
status = *(channel->command_block + 7);
|
|
||||||
|
|
||||||
return channel->ata->irq_handler(channel->ata_bus, status);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user