summaryrefslogtreecommitdiff
path: root/drivers/isdn/hardware/eicon/os_4bri.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hardware/eicon/os_4bri.c')
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c1131
1 files changed, 1131 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
new file mode 100644
index 00000000..18912468
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -0,0 +1,1131 @@
+/* $Id: os_4bri.c,v 1.28.4.4 2005/02/11 19:40:25 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_4bri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "dsrv4bri.h"
+#include "helpers.h"
+
+static void *diva_xdiLoadFileFile = NULL;
+static dword diva_xdiLoadFileLength = 0;
+
+/*
+** IMPORTS
+*/
+extern void prepare_qBri_functions(PISDN_ADAPTER IoAdapter);
+extern void prepare_qBri2_functions(PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features(int card);
+extern void diva_add_slave_adapter(diva_os_xdi_adapter_t *a);
+
+extern int qBri_FPGA_download(PISDN_ADAPTER IoAdapter);
+extern void start_qBri_hardware(PISDN_ADAPTER IoAdapter);
+
+extern int diva_card_read_xlog(diva_os_xdi_adapter_t *a);
+
+/*
+** LOCALS
+*/
+static unsigned long _4bri_bar_length[4] = {
+ 0x100,
+ 0x100, /* I/O */
+ MQ_MEMORY_SIZE,
+ 0x2000
+};
+static unsigned long _4bri_v2_bar_length[4] = {
+ 0x100,
+ 0x100, /* I/O */
+ MQ2_MEMORY_SIZE,
+ 0x10000
+};
+static unsigned long _4bri_v2_bri_bar_length[4] = {
+ 0x100,
+ 0x100, /* I/O */
+ BRI2_MEMORY_SIZE,
+ 0x10000
+};
+
+
+static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t *a);
+static int _4bri_get_serial_number(diva_os_xdi_adapter_t *a);
+static int diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+ diva_xdi_um_cfg_cmd_t *cmd,
+ int length);
+static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t *a);
+static int diva_4bri_write_fpga_image(diva_os_xdi_adapter_t *a,
+ byte *data, dword length);
+static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter);
+static int diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+ dword address,
+ const byte *data,
+ dword length, dword limit);
+static int diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
+ dword start_address, dword features);
+static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter);
+static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t *a);
+
+static int _4bri_is_rev_2_card(int card_ordinal)
+{
+ switch (card_ordinal) {
+ case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
+ case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
+ case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+ case CARDTYPE_DIVASRV_B_2F_PCI:
+ case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+ return (1);
+ }
+ return (0);
+}
+
+static int _4bri_is_rev_2_bri_card(int card_ordinal)
+{
+ switch (card_ordinal) {
+ case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+ case CARDTYPE_DIVASRV_B_2F_PCI:
+ case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+ return (1);
+ }
+ return (0);
+}
+
+static void diva_4bri_set_addresses(diva_os_xdi_adapter_t *a)
+{
+ dword offset = a->resources.pci.qoffset;
+ dword c_offset = offset * a->xdi_adapter.ControllerNumber;
+
+ a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 2;
+ a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
+ a->resources.pci.mem_type_id[MEM_TYPE_CONTROL] = 2;
+ a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 0;
+ a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 3;
+ a->resources.pci.mem_type_id[MEM_TYPE_PROM] = 0;
+
+ /*
+ Set up hardware related pointers
+ */
+ a->xdi_adapter.Address = a->resources.pci.addr[2]; /* BAR2 SDRAM */
+ a->xdi_adapter.Address += c_offset;
+
+ a->xdi_adapter.Control = a->resources.pci.addr[2]; /* BAR2 SDRAM */
+
+ a->xdi_adapter.ram = a->resources.pci.addr[2]; /* BAR2 SDRAM */
+ a->xdi_adapter.ram += c_offset + (offset - MQ_SHARED_RAM_SIZE);
+
+ a->xdi_adapter.reset = a->resources.pci.addr[0]; /* BAR0 CONFIG */
+ /*
+ ctlReg contains the register address for the MIPS CPU reset control
+ */
+ a->xdi_adapter.ctlReg = a->resources.pci.addr[3]; /* BAR3 CNTRL */
+ /*
+ prom contains the register address for FPGA and EEPROM programming
+ */
+ a->xdi_adapter.prom = &a->xdi_adapter.reset[0x6E];
+}
+
+/*
+** BAR0 - MEM - 0x100 - CONFIG MEM
+** BAR1 - I/O - 0x100 - UNUSED
+** BAR2 - MEM - MQ_MEMORY_SIZE (MQ2_MEMORY_SIZE on Rev.2) - SDRAM
+** BAR3 - MEM - 0x2000 (0x10000 on Rev.2) - CNTRL
+**
+** Called by master adapter, that will initialize and add slave adapters
+*/
+int diva_4bri_init_card(diva_os_xdi_adapter_t *a)
+{
+ int bar, i;
+ byte __iomem *p;
+ PADAPTER_LIST_ENTRY quadro_list;
+ diva_os_xdi_adapter_t *diva_current;
+ diva_os_xdi_adapter_t *adapter_list[4];
+ PISDN_ADAPTER Slave;
+ unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)];
+ int v2 = _4bri_is_rev_2_card(a->CardOrdinal);
+ int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
+ int factor = (tasks == 1) ? 1 : 2;
+
+ if (v2) {
+ if (_4bri_is_rev_2_bri_card(a->CardOrdinal)) {
+ memcpy(bar_length, _4bri_v2_bri_bar_length,
+ sizeof(bar_length));
+ } else {
+ memcpy(bar_length, _4bri_v2_bar_length,
+ sizeof(bar_length));
+ }
+ } else {
+ memcpy(bar_length, _4bri_bar_length, sizeof(bar_length));
+ }
+ DBG_TRC(("SDRAM_LENGTH=%08x, tasks=%d, factor=%d",
+ bar_length[2], tasks, factor))
+
+ /*
+ Get Serial Number
+ The serial number of 4BRI is accessible in accordance with PCI spec
+ via command register located in configuration space, also we do not
+ have to map any BAR before we can access it
+ */
+ if (!_4bri_get_serial_number(a)) {
+ DBG_ERR(("A: 4BRI can't get Serial Number"))
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+
+ /*
+ Set properties
+ */
+ a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+ DBG_LOG(("Load %s, SN:%ld, bus:%02x, func:%02x",
+ a->xdi_adapter.Properties.Name,
+ a->xdi_adapter.serialNo,
+ a->resources.pci.bus, a->resources.pci.func))
+
+ /*
+ First initialization step: get and check hardware resoures.
+ Do not map resources and do not access card at this step
+ */
+ for (bar = 0; bar < 4; bar++) {
+ a->resources.pci.bar[bar] =
+ divasa_get_pci_bar(a->resources.pci.bus,
+ a->resources.pci.func, bar,
+ a->resources.pci.hdev);
+ if (!a->resources.pci.bar[bar]
+ || (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
+ DBG_ERR(
+ ("A: invalid bar[%d]=%08x", bar,
+ a->resources.pci.bar[bar]))
+ return (-1);
+ }
+ }
+ a->resources.pci.irq =
+ (byte) divasa_get_pci_irq(a->resources.pci.bus,
+ a->resources.pci.func,
+ a->resources.pci.hdev);
+ if (!a->resources.pci.irq) {
+ DBG_ERR(("A: invalid irq"));
+ return (-1);
+ }
+
+ a->xdi_adapter.sdram_bar = a->resources.pci.bar[2];
+
+ /*
+ Map all MEMORY BAR's
+ */
+ for (bar = 0; bar < 4; bar++) {
+ if (bar != 1) { /* ignore I/O */
+ a->resources.pci.addr[bar] =
+ divasa_remap_pci_bar(a, bar, a->resources.pci.bar[bar],
+ bar_length[bar]);
+ if (!a->resources.pci.addr[bar]) {
+ DBG_ERR(("A: 4BRI: can't map bar[%d]", bar))
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+ }
+ }
+
+ /*
+ Register I/O port
+ */
+ sprintf(&a->port_name[0], "DIVA 4BRI %ld", (long) a->xdi_adapter.serialNo);
+
+ if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
+ bar_length[1], &a->port_name[0], 1)) {
+ DBG_ERR(("A: 4BRI: can't register bar[1]"))
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+
+ a->resources.pci.addr[1] =
+ (void *) (unsigned long) a->resources.pci.bar[1];
+
+ /*
+ Set cleanup pointer for base adapter only, so slave adapter
+ will be unable to get cleanup
+ */
+ a->interface.cleanup_adapter_proc = diva_4bri_cleanup_adapter;
+
+ /*
+ Create slave adapters
+ */
+ if (tasks > 1) {
+ if (!(a->slave_adapters[0] =
+ (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+ {
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+ if (!(a->slave_adapters[1] =
+ (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+ {
+ diva_os_free(0, a->slave_adapters[0]);
+ a->slave_adapters[0] = NULL;
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+ if (!(a->slave_adapters[2] =
+ (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+ {
+ diva_os_free(0, a->slave_adapters[0]);
+ diva_os_free(0, a->slave_adapters[1]);
+ a->slave_adapters[0] = NULL;
+ a->slave_adapters[1] = NULL;
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+ memset(a->slave_adapters[0], 0x00, sizeof(*a));
+ memset(a->slave_adapters[1], 0x00, sizeof(*a));
+ memset(a->slave_adapters[2], 0x00, sizeof(*a));
+ }
+
+ adapter_list[0] = a;
+ adapter_list[1] = a->slave_adapters[0];
+ adapter_list[2] = a->slave_adapters[1];
+ adapter_list[3] = a->slave_adapters[2];
+
+ /*
+ Allocate slave list
+ */
+ quadro_list =
+ (PADAPTER_LIST_ENTRY) diva_os_malloc(0, sizeof(*quadro_list));
+ if (!(a->slave_list = quadro_list)) {
+ for (i = 0; i < (tasks - 1); i++) {
+ diva_os_free(0, a->slave_adapters[i]);
+ a->slave_adapters[i] = NULL;
+ }
+ diva_4bri_cleanup_adapter(a);
+ return (-1);
+ }
+ memset(quadro_list, 0x00, sizeof(*quadro_list));
+
+ /*
+ Set interfaces
+ */
+ a->xdi_adapter.QuadroList = quadro_list;
+ for (i = 0; i < tasks; i++) {
+ adapter_list[i]->xdi_adapter.ControllerNumber = i;
+ adapter_list[i]->xdi_adapter.tasks = tasks;
+ quadro_list->QuadroAdapter[i] =
+ &adapter_list[i]->xdi_adapter;
+ }
+
+ for (i = 0; i < tasks; i++) {
+ diva_current = adapter_list[i];
+
+ diva_current->dsp_mask = 0x00000003;
+
+ diva_current->xdi_adapter.a.io =
+ &diva_current->xdi_adapter;
+ diva_current->xdi_adapter.DIRequest = request;
+ diva_current->interface.cmd_proc = diva_4bri_cmd_card_proc;
+ diva_current->xdi_adapter.Properties =
+ CardProperties[a->CardOrdinal];
+ diva_current->CardOrdinal = a->CardOrdinal;
+
+ diva_current->xdi_adapter.Channels =
+ CardProperties[a->CardOrdinal].Channels;
+ diva_current->xdi_adapter.e_max =
+ CardProperties[a->CardOrdinal].E_info;
+ diva_current->xdi_adapter.e_tbl =
+ diva_os_malloc(0,
+ diva_current->xdi_adapter.e_max *
+ sizeof(E_INFO));
+
+ if (!diva_current->xdi_adapter.e_tbl) {
+ diva_4bri_cleanup_slave_adapters(a);
+ diva_4bri_cleanup_adapter(a);
+ for (i = 1; i < (tasks - 1); i++) {
+ diva_os_free(0, adapter_list[i]);
+ }
+ return (-1);
+ }
+ memset(diva_current->xdi_adapter.e_tbl, 0x00,
+ diva_current->xdi_adapter.e_max * sizeof(E_INFO));
+
+ if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.isr_spin_lock, "isr")) {
+ diva_4bri_cleanup_slave_adapters(a);
+ diva_4bri_cleanup_adapter(a);
+ for (i = 1; i < (tasks - 1); i++) {
+ diva_os_free(0, adapter_list[i]);
+ }
+ return (-1);
+ }
+ if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.data_spin_lock, "data")) {
+ diva_4bri_cleanup_slave_adapters(a);
+ diva_4bri_cleanup_adapter(a);
+ for (i = 1; i < (tasks - 1); i++) {
+ diva_os_free(0, adapter_list[i]);
+ }
+ return (-1);
+ }
+
+ strcpy(diva_current->xdi_adapter.req_soft_isr. dpc_thread_name, "kdivas4brid");
+
+ if (diva_os_initialize_soft_isr(&diva_current->xdi_adapter.req_soft_isr, DIDpcRoutine,
+ &diva_current->xdi_adapter)) {
+ diva_4bri_cleanup_slave_adapters(a);
+ diva_4bri_cleanup_adapter(a);
+ for (i = 1; i < (tasks - 1); i++) {
+ diva_os_free(0, adapter_list[i]);
+ }
+ return (-1);
+ }
+
+ /*
+ Do not initialize second DPC - only one thread will be created
+ */
+ diva_current->xdi_adapter.isr_soft_isr.object =
+ diva_current->xdi_adapter.req_soft_isr.object;
+ }
+
+ if (v2) {
+ prepare_qBri2_functions(&a->xdi_adapter);
+ } else {
+ prepare_qBri_functions(&a->xdi_adapter);
+ }
+
+ for (i = 0; i < tasks; i++) {
+ diva_current = adapter_list[i];
+ if (i)
+ memcpy(&diva_current->resources, &a->resources, sizeof(divas_card_resources_t));
+ diva_current->resources.pci.qoffset = (a->xdi_adapter.MemorySize >> factor);
+ }
+
+ /*
+ Set up hardware related pointers
+ */
+ a->xdi_adapter.cfg = (void *) (unsigned long) a->resources.pci.bar[0]; /* BAR0 CONFIG */
+ a->xdi_adapter.port = (void *) (unsigned long) a->resources.pci.bar[1]; /* BAR1 */
+ a->xdi_adapter.ctlReg = (void *) (unsigned long) a->resources.pci.bar[3]; /* BAR3 CNTRL */
+
+ for (i = 0; i < tasks; i++) {
+ diva_current = adapter_list[i];
+ diva_4bri_set_addresses(diva_current);
+ Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
+ Slave->MultiMaster = &a->xdi_adapter;
+ Slave->sdram_bar = a->xdi_adapter.sdram_bar;
+ if (i) {
+ Slave->serialNo = ((dword) (Slave->ControllerNumber << 24)) |
+ a->xdi_adapter.serialNo;
+ Slave->cardType = a->xdi_adapter.cardType;
+ }
+ }
+
+ /*
+ reset contains the base address for the PLX 9054 register set
+ */
+ p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
+ WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
+ DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
+
+ /*
+ Set IRQ handler
+ */
+ a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+ sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA 4BRI %ld",
+ (long) a->xdi_adapter.serialNo);
+
+ if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
+ a->xdi_adapter.irq_info.irq_name)) {
+ diva_4bri_cleanup_slave_adapters(a);
+ diva_4bri_cleanup_adapter(a);
+ for (i = 1; i < (tasks - 1); i++) {
+ diva_os_free(0, adapter_list[i]);
+ }
+ return (-1);
+ }
+
+ a->xdi_adapter.irq_info.registered = 1;
+
+ /*
+ Add three slave adapters
+ */
+ if (tasks > 1) {
+ diva_add_slave_adapter(adapter_list[1]);
+ diva_add_slave_adapter(adapter_list[2]);
+ diva_add_slave_adapter(adapter_list[3]);
+ }
+
+ diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+ a->resources.pci.irq, a->xdi_adapter.serialNo);
+
+ return (0);
+}
+
+/*
+** Cleanup function will be called for master adapter only
+** this is guaranteed by design: cleanup callback is set
+** by master adapter only
+*/
+static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t *a)
+{
+ int bar;
+
+ /*
+ Stop adapter if running
+ */
+ if (a->xdi_adapter.Initialized) {
+ diva_4bri_stop_adapter(a);
+ }
+
+ /*
+ Remove IRQ handler
+ */
+ if (a->xdi_adapter.irq_info.registered) {
+ diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
+ }
+ a->xdi_adapter.irq_info.registered = 0;
+
+ /*
+ Free DPC's and spin locks on all adapters
+ */
+ diva_4bri_cleanup_slave_adapters(a);
+
+ /*
+ Unmap all BARS
+ */
+ for (bar = 0; bar < 4; bar++) {
+ if (bar != 1) {
+ if (a->resources.pci.bar[bar]
+ && a->resources.pci.addr[bar]) {
+ divasa_unmap_pci_bar(a->resources.pci.addr[bar]);
+ a->resources.pci.bar[bar] = 0;
+ a->resources.pci.addr[bar] = NULL;
+ }
+ }
+ }
+
+ /*
+ Unregister I/O
+ */
+ if (a->resources.pci.bar[1] && a->resources.pci.addr[1]) {
+ diva_os_register_io_port(a, 0, a->resources.pci.bar[1],
+ _4bri_is_rev_2_card(a->
+ CardOrdinal) ?
+ _4bri_v2_bar_length[1] :
+ _4bri_bar_length[1],
+ &a->port_name[0], 1);
+ a->resources.pci.bar[1] = 0;
+ a->resources.pci.addr[1] = NULL;
+ }
+
+ if (a->slave_list) {
+ diva_os_free(0, a->slave_list);
+ a->slave_list = NULL;
+ }
+
+ return (0);
+}
+
+static int _4bri_get_serial_number(diva_os_xdi_adapter_t *a)
+{
+ dword data[64];
+ dword serNo;
+ word addr, status, i, j;
+ byte Bus, Slot;
+ void *hdev;
+
+ Bus = a->resources.pci.bus;
+ Slot = a->resources.pci.func;
+ hdev = a->resources.pci.hdev;
+
+ for (i = 0; i < 64; ++i) {
+ addr = i * 4;
+ for (j = 0; j < 5; ++j) {
+ PCIwrite(Bus, Slot, 0x4E, &addr, sizeof(addr),
+ hdev);
+ diva_os_wait(1);
+ PCIread(Bus, Slot, 0x4E, &status, sizeof(status),
+ hdev);
+ if (status & 0x8000)
+ break;
+ }
+ if (j >= 5) {
+ DBG_ERR(("EEPROM[%d] read failed (0x%x)", i * 4, addr))
+ return (0);
+ }
+ PCIread(Bus, Slot, 0x50, &data[i], sizeof(data[i]), hdev);
+ }
+ DBG_BLK(((char *) &data[0], sizeof(data)))
+
+ serNo = data[32];
+ if (serNo == 0 || serNo == 0xffffffff)
+ serNo = data[63];
+
+ if (!serNo) {
+ DBG_LOG(("W: Serial Number == 0, create one serial number"));
+ serNo = a->resources.pci.bar[1] & 0xffff0000;
+ serNo |= a->resources.pci.bus << 8;
+ serNo |= a->resources.pci.func;
+ }
+
+ a->xdi_adapter.serialNo = serNo;
+
+ DBG_REG(("Serial No. : %ld", a->xdi_adapter.serialNo))
+
+ return (serNo);
+}
+
+/*
+** Release resources of slave adapters
+*/
+static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t *a)
+{
+ diva_os_xdi_adapter_t *adapter_list[4];
+ diva_os_xdi_adapter_t *diva_current;
+ int i;
+
+ adapter_list[0] = a;
+ adapter_list[1] = a->slave_adapters[0];
+ adapter_list[2] = a->slave_adapters[1];
+ adapter_list[3] = a->slave_adapters[2];
+
+ for (i = 0; i < a->xdi_adapter.tasks; i++) {
+ diva_current = adapter_list[i];
+ if (diva_current) {
+ diva_os_destroy_spin_lock(&diva_current->
+ xdi_adapter.
+ isr_spin_lock, "unload");
+ diva_os_destroy_spin_lock(&diva_current->
+ xdi_adapter.
+ data_spin_lock,
+ "unload");
+
+ diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
+ req_soft_isr);
+ diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
+ isr_soft_isr);
+
+ diva_os_remove_soft_isr(&diva_current->xdi_adapter.
+ req_soft_isr);
+ diva_current->xdi_adapter.isr_soft_isr.object = NULL;
+
+ if (diva_current->xdi_adapter.e_tbl) {
+ diva_os_free(0,
+ diva_current->xdi_adapter.
+ e_tbl);
+ }
+ diva_current->xdi_adapter.e_tbl = NULL;
+ diva_current->xdi_adapter.e_max = 0;
+ diva_current->xdi_adapter.e_count = 0;
+ }
+ }
+
+ return (0);
+}
+
+static int
+diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+ diva_xdi_um_cfg_cmd_t *cmd, int length)
+{
+ int ret = -1;
+
+ if (cmd->adapter != a->controller) {
+ DBG_ERR(("A: 4bri_cmd, invalid controller=%d != %d",
+ cmd->adapter, a->controller))
+ return (-1);
+ }
+
+ switch (cmd->command) {
+ case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+ a->xdi_mbox.data_length = sizeof(dword);
+ a->xdi_mbox.data =
+ diva_os_malloc(0, a->xdi_mbox.data_length);
+ if (a->xdi_mbox.data) {
+ *(dword *) a->xdi_mbox.data =
+ (dword) a->CardOrdinal;
+ a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+ ret = 0;
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+ a->xdi_mbox.data_length = sizeof(dword);
+ a->xdi_mbox.data =
+ diva_os_malloc(0, a->xdi_mbox.data_length);
+ if (a->xdi_mbox.data) {
+ *(dword *) a->xdi_mbox.data =
+ (dword) a->xdi_adapter.serialNo;
+ a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+ ret = 0;
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+ if (!a->xdi_adapter.ControllerNumber) {
+ /*
+ Only master adapter can access hardware config
+ */
+ a->xdi_mbox.data_length = sizeof(dword) * 9;
+ a->xdi_mbox.data =
+ diva_os_malloc(0, a->xdi_mbox.data_length);
+ if (a->xdi_mbox.data) {
+ int i;
+ dword *data = (dword *) a->xdi_mbox.data;
+
+ for (i = 0; i < 8; i++) {
+ *data++ = a->resources.pci.bar[i];
+ }
+ *data++ = (dword) a->resources.pci.irq;
+ a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+ ret = 0;
+ }
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+ if (!a->xdi_adapter.ControllerNumber) {
+ a->xdi_mbox.data_length = sizeof(dword);
+ a->xdi_mbox.data =
+ diva_os_malloc(0, a->xdi_mbox.data_length);
+ if (a->xdi_mbox.data) {
+ dword *data = (dword *) a->xdi_mbox.data;
+ if (!a->xdi_adapter.ram
+ || !a->xdi_adapter.reset
+ || !a->xdi_adapter.cfg) {
+ *data = 3;
+ } else if (a->xdi_adapter.trapped) {
+ *data = 2;
+ } else if (a->xdi_adapter.Initialized) {
+ *data = 1;
+ } else {
+ *data = 0;
+ }
+ a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+ ret = 0;
+ }
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_WRITE_FPGA:
+ if (!a->xdi_adapter.ControllerNumber) {
+ ret =
+ diva_4bri_write_fpga_image(a,
+ (byte *)&cmd[1],
+ cmd->command_data.
+ write_fpga.
+ image_length);
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+ if (!a->xdi_adapter.ControllerNumber) {
+ ret = diva_4bri_reset_adapter(&a->xdi_adapter);
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+ if (!a->xdi_adapter.ControllerNumber) {
+ ret = diva_4bri_write_sdram_block(&a->xdi_adapter,
+ cmd->
+ command_data.
+ write_sdram.
+ offset,
+ (byte *) &
+ cmd[1],
+ cmd->
+ command_data.
+ write_sdram.
+ length,
+ a->xdi_adapter.
+ MemorySize);
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_START_ADAPTER:
+ if (!a->xdi_adapter.ControllerNumber) {
+ ret = diva_4bri_start_adapter(&a->xdi_adapter,
+ cmd->command_data.
+ start.offset,
+ cmd->command_data.
+ start.features);
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+ if (!a->xdi_adapter.ControllerNumber) {
+ a->xdi_adapter.features =
+ cmd->command_data.features.features;
+ a->xdi_adapter.a.protocol_capabilities =
+ a->xdi_adapter.features;
+ DBG_TRC(("Set raw protocol features (%08x)",
+ a->xdi_adapter.features))
+ ret = 0;
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+ if (!a->xdi_adapter.ControllerNumber) {
+ ret = diva_4bri_stop_adapter(a);
+ }
+ break;
+
+ case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+ ret = diva_card_read_xlog(a);
+ break;
+
+ case DIVA_XDI_UM_CMD_READ_SDRAM:
+ if (!a->xdi_adapter.ControllerNumber
+ && a->xdi_adapter.Address) {
+ if (
+ (a->xdi_mbox.data_length =
+ cmd->command_data.read_sdram.length)) {
+ if (
+ (a->xdi_mbox.data_length +
+ cmd->command_data.read_sdram.offset) <
+ a->xdi_adapter.MemorySize) {
+ a->xdi_mbox.data =
+ diva_os_malloc(0,
+ a->xdi_mbox.
+ data_length);
+ if (a->xdi_mbox.data) {
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(&a->xdi_adapter);
+ byte __iomem *src = p;
+ byte *dst = a->xdi_mbox.data;
+ dword len = a->xdi_mbox.data_length;
+
+ src += cmd->command_data.read_sdram.offset;
+
+ while (len--) {
+ *dst++ = READ_BYTE(src++);
+ }
+ DIVA_OS_MEM_DETACH_ADDRESS(&a->xdi_adapter, p);
+ a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+ ret = 0;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller,
+ cmd->command))
+ }
+
+ return (ret);
+}
+
+void *xdiLoadFile(char *FileName, dword *FileLength,
+ unsigned long lim)
+{
+ void *ret = diva_xdiLoadFileFile;
+
+ if (FileLength) {
+ *FileLength = diva_xdiLoadFileLength;
+ }
+ diva_xdiLoadFileFile = NULL;
+ diva_xdiLoadFileLength = 0;
+
+ return (ret);
+}
+
+void diva_os_set_qBri_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+void diva_os_set_qBri2_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+static int
+diva_4bri_write_fpga_image(diva_os_xdi_adapter_t *a, byte *data,
+ dword length)
+{
+ int ret;
+
+ diva_xdiLoadFileFile = data;
+ diva_xdiLoadFileLength = length;
+
+ ret = qBri_FPGA_download(&a->xdi_adapter);
+
+ diva_xdiLoadFileFile = NULL;
+ diva_xdiLoadFileLength = 0;
+
+ return (ret ? 0 : -1);
+}
+
+static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter)
+{
+ PISDN_ADAPTER Slave;
+ int i;
+
+ if (!IoAdapter->Address || !IoAdapter->reset) {
+ return (-1);
+ }
+ if (IoAdapter->Initialized) {
+ DBG_ERR(("A: A(%d) can't reset 4BRI adapter - please stop first",
+ IoAdapter->ANum))
+ return (-1);
+ }
+
+ /*
+ Forget all entities on all adapters
+ */
+ for (i = 0; ((i < IoAdapter->tasks) && IoAdapter->QuadroList); i++) {
+ Slave = IoAdapter->QuadroList->QuadroAdapter[i];
+ Slave->e_count = 0;
+ if (Slave->e_tbl) {
+ memset(Slave->e_tbl, 0x00,
+ Slave->e_max * sizeof(E_INFO));
+ }
+ Slave->head = 0;
+ Slave->tail = 0;
+ Slave->assign = 0;
+ Slave->trapped = 0;
+
+ memset(&Slave->a.IdTable[0], 0x00,
+ sizeof(Slave->a.IdTable));
+ memset(&Slave->a.IdTypeTable[0], 0x00,
+ sizeof(Slave->a.IdTypeTable));
+ memset(&Slave->a.FlowControlIdTable[0], 0x00,
+ sizeof(Slave->a.FlowControlIdTable));
+ memset(&Slave->a.FlowControlSkipTable[0], 0x00,
+ sizeof(Slave->a.FlowControlSkipTable));
+ memset(&Slave->a.misc_flags_table[0], 0x00,
+ sizeof(Slave->a.misc_flags_table));
+ memset(&Slave->a.rx_stream[0], 0x00,
+ sizeof(Slave->a.rx_stream));
+ memset(&Slave->a.tx_stream[0], 0x00,
+ sizeof(Slave->a.tx_stream));
+ memset(&Slave->a.tx_pos[0], 0x00, sizeof(Slave->a.tx_pos));
+ memset(&Slave->a.rx_pos[0], 0x00, sizeof(Slave->a.rx_pos));
+ }
+
+ return (0);
+}
+
+
+static int
+diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+ dword address,
+ const byte *data, dword length, dword limit)
+{
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+ byte __iomem *mem = p;
+
+ if (((address + length) >= limit) || !mem) {
+ DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+ DBG_ERR(("A: A(%d) write 4BRI address=0x%08lx",
+ IoAdapter->ANum, address + length))
+ return (-1);
+ }
+ mem += address;
+
+ while (length--) {
+ WRITE_BYTE(mem++, *data++);
+ }
+
+ DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+ return (0);
+}
+
+static int
+diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
+ dword start_address, dword features)
+{
+ volatile word __iomem *signature;
+ int started = 0;
+ int i;
+ byte __iomem *p;
+
+ /*
+ start adapter
+ */
+ start_qBri_hardware(IoAdapter);
+
+ p = DIVA_OS_MEM_ATTACH_RAM(IoAdapter);
+ /*
+ wait for signature in shared memory (max. 3 seconds)
+ */
+ signature = (volatile word __iomem *) (&p[0x1E]);
+
+ for (i = 0; i < 300; ++i) {
+ diva_os_wait(10);
+ if (READ_WORD(&signature[0]) == 0x4447) {
+ DBG_TRC(("Protocol startup time %d.%02d seconds",
+ (i / 100), (i % 100)))
+ started = 1;
+ break;
+ }
+ }
+
+ for (i = 1; i < IoAdapter->tasks; i++) {
+ IoAdapter->QuadroList->QuadroAdapter[i]->features =
+ IoAdapter->features;
+ IoAdapter->QuadroList->QuadroAdapter[i]->a.
+ protocol_capabilities = IoAdapter->features;
+ }
+
+ if (!started) {
+ DBG_FTL(("%s: Adapter selftest failed, signature=%04x",
+ IoAdapter->Properties.Name,
+ READ_WORD(&signature[0])))
+ DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
+ (*(IoAdapter->trapFnc)) (IoAdapter);
+ IoAdapter->stop(IoAdapter);
+ return (-1);
+ }
+ DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
+
+ for (i = 0; i < IoAdapter->tasks; i++) {
+ IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 1;
+ IoAdapter->QuadroList->QuadroAdapter[i]->IrqCount = 0;
+ }
+
+ if (check_qBri_interrupt(IoAdapter)) {
+ DBG_ERR(("A: A(%d) interrupt test failed",
+ IoAdapter->ANum))
+ for (i = 0; i < IoAdapter->tasks; i++) {
+ IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+ }
+ IoAdapter->stop(IoAdapter);
+ return (-1);
+ }
+
+ IoAdapter->Properties.Features = (word) features;
+ diva_xdi_display_adapter_features(IoAdapter->ANum);
+
+ for (i = 0; i < IoAdapter->tasks; i++) {
+ DBG_LOG(("A(%d) %s adapter successfully started",
+ IoAdapter->QuadroList->QuadroAdapter[i]->ANum,
+ (IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI"))
+ diva_xdi_didd_register_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+ IoAdapter->QuadroList->QuadroAdapter[i]->Properties.Features = (word) features;
+ }
+
+ return (0);
+}
+
+static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter)
+{
+#ifdef SUPPORT_INTERRUPT_TEST_ON_4BRI
+ int i;
+ ADAPTER *a = &IoAdapter->a;
+ byte __iomem *p;
+
+ IoAdapter->IrqCount = 0;
+
+ if (IoAdapter->ControllerNumber > 0)
+ return (-1);
+
+ p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+ /*
+ interrupt test
+ */
+ a->ReadyInt = 1;
+ a->ram_out(a, &PR_RAM->ReadyInt, 1);
+
+ for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait(10));
+
+ return ((IoAdapter->IrqCount > 0) ? 0 : -1);
+#else
+ dword volatile __iomem *qBriIrq;
+ byte __iomem *p;
+ /*
+ Reset on-board interrupt register
+ */
+ IoAdapter->IrqCount = 0;
+ p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ qBriIrq = (dword volatile __iomem *) (&p[_4bri_is_rev_2_card
+ (IoAdapter->
+ cardType) ? (MQ2_BREG_IRQ_TEST)
+ : (MQ_BREG_IRQ_TEST)]);
+
+ WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
+ DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+
+ p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+
+ diva_os_wait(100);
+
+ return (0);
+#endif /* SUPPORT_INTERRUPT_TEST_ON_4BRI */
+}
+
+static void diva_4bri_clear_interrupts(diva_os_xdi_adapter_t *a)
+{
+ PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+ /*
+ clear any pending interrupt
+ */
+ IoAdapter->disIrq(IoAdapter);
+
+ IoAdapter->tst_irq(&IoAdapter->a);
+ IoAdapter->clr_irq(&IoAdapter->a);
+ IoAdapter->tst_irq(&IoAdapter->a);
+
+ /*
+ kill pending dpcs
+ */
+ diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
+ diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
+}
+
+static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t *a)
+{
+ PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+ int i;
+
+ if (!IoAdapter->ram) {
+ return (-1);
+ }
+
+ if (!IoAdapter->Initialized) {
+ DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
+ IoAdapter->ANum))
+ return (-1); /* nothing to stop */
+ }
+
+ for (i = 0; i < IoAdapter->tasks; i++) {
+ IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+ }
+
+ /*
+ Disconnect Adapters from DIDD
+ */
+ for (i = 0; i < IoAdapter->tasks; i++) {
+ diva_xdi_didd_remove_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+ }
+
+ i = 100;
+
+ /*
+ Stop interrupts
+ */
+ a->clear_interrupts_proc = diva_4bri_clear_interrupts;
+ IoAdapter->a.ReadyInt = 1;
+ IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
+ do {
+ diva_os_sleep(10);
+ } while (i-- && a->clear_interrupts_proc);
+
+ if (a->clear_interrupts_proc) {
+ diva_4bri_clear_interrupts(a);
+ a->clear_interrupts_proc = NULL;
+ DBG_ERR(("A: A(%d) no final interrupt from 4BRI adapter",
+ IoAdapter->ANum))
+ }
+ IoAdapter->a.ReadyInt = 0;
+
+ /*
+ Stop and reset adapter
+ */
+ IoAdapter->stop(IoAdapter);
+
+ return (0);
+}