| /* | |
| * | |
| Copyright (c) Eicon Networks, 2002. | |
| * | |
| This source file is supplied for the use with | |
| Eicon Networks range of DIVA Server Adapters. | |
| * | |
| Eicon File Revision : 2.1 | |
| * | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| * | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY | |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| See the GNU General Public License for more details. | |
| * | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include "platform.h" | |
| #include "di_defs.h" | |
| #include "pc.h" | |
| #include "pr_pc.h" | |
| #include "divasync.h" | |
| #define MIPS_SCOM | |
| #include "pkmaint.h" /* pc_main.h, packed in os-dependent fashion */ | |
| #include "di.h" | |
| #include "mi_pc.h" | |
| #include "io.h" | |
| extern ADAPTER *adapter[MAX_ADAPTER]; | |
| extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; | |
| void request(PISDN_ADAPTER, ENTITY *); | |
| static void pcm_req(PISDN_ADAPTER, ENTITY *); | |
| /* -------------------------------------------------------------------------- | |
| local functions | |
| -------------------------------------------------------------------------- */ | |
| #define ReqFunc(N) \ | |
| static void Request##N(ENTITY *e) \ | |
| { if (IoAdapters[N]) (*IoAdapters[N]->DIRequest)(IoAdapters[N], e); } | |
| ReqFunc(0) | |
| ReqFunc(1) | |
| ReqFunc(2) | |
| ReqFunc(3) | |
| ReqFunc(4) | |
| ReqFunc(5) | |
| ReqFunc(6) | |
| ReqFunc(7) | |
| ReqFunc(8) | |
| ReqFunc(9) | |
| ReqFunc(10) | |
| ReqFunc(11) | |
| ReqFunc(12) | |
| ReqFunc(13) | |
| ReqFunc(14) | |
| ReqFunc(15) | |
| IDI_CALL Requests[MAX_ADAPTER] = | |
| { &Request0, &Request1, &Request2, &Request3, | |
| &Request4, &Request5, &Request6, &Request7, | |
| &Request8, &Request9, &Request10, &Request11, | |
| &Request12, &Request13, &Request14, &Request15 | |
| }; | |
| /*****************************************************************************/ | |
| /* | |
| This array should indicate all new services, that this version of XDI | |
| is able to provide to his clients | |
| */ | |
| static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ + 1] = { | |
| (DIVA_XDI_EXTENDED_FEATURES_VALID | | |
| DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR | | |
| DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS | | |
| #if defined(DIVA_IDI_RX_DMA) | |
| DIVA_XDI_EXTENDED_FEATURE_CMA | | |
| DIVA_XDI_EXTENDED_FEATURE_RX_DMA | | |
| DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA | | |
| #endif | |
| DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC), | |
| 0 | |
| }; | |
| /*****************************************************************************/ | |
| void | |
| dump_xlog_buffer(PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) | |
| { | |
| dword logLen; | |
| word *Xlog = xlogDesc->buf; | |
| word logCnt = xlogDesc->cnt; | |
| word logOut = xlogDesc->out / sizeof(*Xlog); | |
| DBG_FTL(("%s: ************* XLOG recovery (%d) *************", | |
| &IoAdapter->Name[0], (int)logCnt)) | |
| DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0])) | |
| for (; logCnt > 0; --logCnt) | |
| { | |
| if (!GET_WORD(&Xlog[logOut])) | |
| { | |
| if (--logCnt == 0) | |
| break; | |
| logOut = 0; | |
| } | |
| if (GET_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog))) | |
| { | |
| if (logCnt > 2) | |
| { | |
| DBG_FTL(("Possibly corrupted XLOG: %d entries left", | |
| (int)logCnt)) | |
| } | |
| break; | |
| } | |
| logLen = (dword)(GET_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))); | |
| DBG_FTL_MXLOG(((char *)&Xlog[logOut + 1], (dword)(logLen - 2))) | |
| logOut = (GET_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog); | |
| } | |
| DBG_FTL(("%s: ***************** end of XLOG *****************", | |
| &IoAdapter->Name[0])) | |
| } | |
| /*****************************************************************************/ | |
| #if defined(XDI_USE_XLOG) | |
| static char *(ExceptionCauseTable[]) = | |
| { | |
| "Interrupt", | |
| "TLB mod /IBOUND", | |
| "TLB load /DBOUND", | |
| "TLB store", | |
| "Address error load", | |
| "Address error store", | |
| "Instruction load bus error", | |
| "Data load/store bus error", | |
| "Syscall", | |
| "Breakpoint", | |
| "Reverd instruction", | |
| "Coprocessor unusable", | |
| "Overflow", | |
| "TRAP", | |
| "VCEI", | |
| "Floating Point Exception", | |
| "CP2", | |
| "Reserved 17", | |
| "Reserved 18", | |
| "Reserved 19", | |
| "Reserved 20", | |
| "Reserved 21", | |
| "Reserved 22", | |
| "WATCH", | |
| "Reserved 24", | |
| "Reserved 25", | |
| "Reserved 26", | |
| "Reserved 27", | |
| "Reserved 28", | |
| "Reserved 29", | |
| "Reserved 30", | |
| "VCED" | |
| }; | |
| #endif | |
| void | |
| dump_trap_frame(PISDN_ADAPTER IoAdapter, byte __iomem *exceptionFrame) | |
| { | |
| MP_XCPTC __iomem *xcept = (MP_XCPTC __iomem *)exceptionFrame; | |
| dword __iomem *regs; | |
| regs = &xcept->regs[0]; | |
| DBG_FTL(("%s: ***************** CPU TRAPPED *****************", | |
| &IoAdapter->Name[0])) | |
| DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0])) | |
| DBG_FTL(("Cause: %s", | |
| ExceptionCauseTable[(READ_DWORD(&xcept->cr) & 0x0000007c) >> 2])) | |
| DBG_FTL(("sr 0x%08x cr 0x%08x epc 0x%08x vaddr 0x%08x", | |
| READ_DWORD(&xcept->sr), READ_DWORD(&xcept->cr), | |
| READ_DWORD(&xcept->epc), READ_DWORD(&xcept->vaddr))) | |
| DBG_FTL(("zero 0x%08x at 0x%08x v0 0x%08x v1 0x%08x", | |
| READ_DWORD(®s[0]), READ_DWORD(®s[1]), | |
| READ_DWORD(®s[2]), READ_DWORD(®s[3]))) | |
| DBG_FTL(("a0 0x%08x a1 0x%08x a2 0x%08x a3 0x%08x", | |
| READ_DWORD(®s[4]), READ_DWORD(®s[5]), | |
| READ_DWORD(®s[6]), READ_DWORD(®s[7]))) | |
| DBG_FTL(("t0 0x%08x t1 0x%08x t2 0x%08x t3 0x%08x", | |
| READ_DWORD(®s[8]), READ_DWORD(®s[9]), | |
| READ_DWORD(®s[10]), READ_DWORD(®s[11]))) | |
| DBG_FTL(("t4 0x%08x t5 0x%08x t6 0x%08x t7 0x%08x", | |
| READ_DWORD(®s[12]), READ_DWORD(®s[13]), | |
| READ_DWORD(®s[14]), READ_DWORD(®s[15]))) | |
| DBG_FTL(("s0 0x%08x s1 0x%08x s2 0x%08x s3 0x%08x", | |
| READ_DWORD(®s[16]), READ_DWORD(®s[17]), | |
| READ_DWORD(®s[18]), READ_DWORD(®s[19]))) | |
| DBG_FTL(("s4 0x%08x s5 0x%08x s6 0x%08x s7 0x%08x", | |
| READ_DWORD(®s[20]), READ_DWORD(®s[21]), | |
| READ_DWORD(®s[22]), READ_DWORD(®s[23]))) | |
| DBG_FTL(("t8 0x%08x t9 0x%08x k0 0x%08x k1 0x%08x", | |
| READ_DWORD(®s[24]), READ_DWORD(®s[25]), | |
| READ_DWORD(®s[26]), READ_DWORD(®s[27]))) | |
| DBG_FTL(("gp 0x%08x sp 0x%08x s8 0x%08x ra 0x%08x", | |
| READ_DWORD(®s[28]), READ_DWORD(®s[29]), | |
| READ_DWORD(®s[30]), READ_DWORD(®s[31]))) | |
| DBG_FTL(("md 0x%08x|%08x resvd 0x%08x class 0x%08x", | |
| READ_DWORD(&xcept->mdhi), READ_DWORD(&xcept->mdlo), | |
| READ_DWORD(&xcept->reseverd), READ_DWORD(&xcept->xclass))) | |
| } | |
| /* -------------------------------------------------------------------------- | |
| Real XDI Request function | |
| -------------------------------------------------------------------------- */ | |
| void request(PISDN_ADAPTER IoAdapter, ENTITY *e) | |
| { | |
| byte i; | |
| diva_os_spin_lock_magic_t irql; | |
| /* | |
| * if the Req field in the entity structure is 0, | |
| * we treat this request as a special function call | |
| */ | |
| if (!e->Req) | |
| { | |
| IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e; | |
| switch (e->Rc) | |
| { | |
| #if defined(DIVA_IDI_RX_DMA) | |
| case IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION: { | |
| diva_xdi_dma_descriptor_operation_t *pI = \ | |
| &syncReq->xdi_dma_descriptor_operation.info; | |
| if (!IoAdapter->dma_map) { | |
| pI->operation = -1; | |
| pI->descriptor_number = -1; | |
| return; | |
| } | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "dma_op"); | |
| if (pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC) { | |
| pI->descriptor_number = diva_alloc_dma_map_entry(\ | |
| (struct _diva_dma_map_entry *)IoAdapter->dma_map); | |
| if (pI->descriptor_number >= 0) { | |
| dword dma_magic; | |
| void *local_addr; | |
| diva_get_dma_map_entry(\ | |
| (struct _diva_dma_map_entry *)IoAdapter->dma_map, | |
| pI->descriptor_number, | |
| &local_addr, &dma_magic); | |
| pI->descriptor_address = local_addr; | |
| pI->descriptor_magic = dma_magic; | |
| pI->operation = 0; | |
| } else { | |
| pI->operation = -1; | |
| } | |
| } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) && | |
| (pI->descriptor_number >= 0)) { | |
| diva_free_dma_map_entry((struct _diva_dma_map_entry *)IoAdapter->dma_map, | |
| pI->descriptor_number); | |
| pI->descriptor_number = -1; | |
| pI->operation = 0; | |
| } else { | |
| pI->descriptor_number = -1; | |
| pI->operation = -1; | |
| } | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "dma_op"); | |
| } return; | |
| #endif | |
| case IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER: { | |
| diva_xdi_get_logical_adapter_number_s_t *pI = \ | |
| &syncReq->xdi_logical_adapter_number.info; | |
| pI->logical_adapter_number = IoAdapter->ANum; | |
| pI->controller = IoAdapter->ControllerNumber; | |
| pI->total_controllers = IoAdapter->Properties.Adapters; | |
| } return; | |
| case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: { | |
| diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info; | |
| memset(&prms, 0x00, sizeof(prms)); | |
| prms.structure_length = min_t(size_t, sizeof(prms), pI->structure_length); | |
| memset(pI, 0x00, pI->structure_length); | |
| prms.flag_dynamic_l1_down = (IoAdapter->capi_cfg.cfg_1 & \ | |
| DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0; | |
| prms.group_optimization_enabled = (IoAdapter->capi_cfg.cfg_1 & \ | |
| DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? 1 : 0; | |
| memcpy(pI, &prms, prms.structure_length); | |
| } return; | |
| case IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR: | |
| syncReq->xdi_sdram_bar.info.bar = IoAdapter->sdram_bar; | |
| return; | |
| case IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES: { | |
| dword i; | |
| diva_xdi_get_extended_xdi_features_t *pI =\ | |
| &syncReq->xdi_extended_features.info; | |
| pI->buffer_length_in_bytes &= ~0x80000000; | |
| if (pI->buffer_length_in_bytes && pI->features) { | |
| memset(pI->features, 0x00, pI->buffer_length_in_bytes); | |
| } | |
| for (i = 0; ((pI->features) && (i < pI->buffer_length_in_bytes) && | |
| (i < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ)); i++) { | |
| pI->features[i] = extended_xdi_features[i]; | |
| } | |
| if ((pI->buffer_length_in_bytes < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ) || | |
| (!pI->features)) { | |
| pI->buffer_length_in_bytes =\ | |
| (0x80000000 | DIVA_XDI_EXTENDED_FEATURES_MAX_SZ); | |
| } | |
| } return; | |
| case IDI_SYNC_REQ_XDI_GET_STREAM: | |
| if (IoAdapter) { | |
| diva_xdi_provide_istream_info(&IoAdapter->a, | |
| &syncReq->xdi_stream_info.info); | |
| } else { | |
| syncReq->xdi_stream_info.info.provided_service = 0; | |
| } | |
| return; | |
| case IDI_SYNC_REQ_GET_NAME: | |
| if (IoAdapter) | |
| { | |
| strcpy(&syncReq->GetName.name[0], IoAdapter->Name); | |
| DBG_TRC(("xdi: Adapter %d / Name '%s'", | |
| IoAdapter->ANum, IoAdapter->Name)) | |
| return; | |
| } | |
| syncReq->GetName.name[0] = '\0'; | |
| break; | |
| case IDI_SYNC_REQ_GET_SERIAL: | |
| if (IoAdapter) | |
| { | |
| syncReq->GetSerial.serial = IoAdapter->serialNo; | |
| DBG_TRC(("xdi: Adapter %d / SerialNo %ld", | |
| IoAdapter->ANum, IoAdapter->serialNo)) | |
| return; | |
| } | |
| syncReq->GetSerial.serial = 0; | |
| break; | |
| case IDI_SYNC_REQ_GET_CARDTYPE: | |
| if (IoAdapter) | |
| { | |
| syncReq->GetCardType.cardtype = IoAdapter->cardType; | |
| DBG_TRC(("xdi: Adapter %d / CardType %ld", | |
| IoAdapter->ANum, IoAdapter->cardType)) | |
| return; | |
| } | |
| syncReq->GetCardType.cardtype = 0; | |
| break; | |
| case IDI_SYNC_REQ_GET_XLOG: | |
| if (IoAdapter) | |
| { | |
| pcm_req(IoAdapter, e); | |
| return; | |
| } | |
| e->Ind = 0; | |
| break; | |
| case IDI_SYNC_REQ_GET_DBG_XLOG: | |
| if (IoAdapter) | |
| { | |
| pcm_req(IoAdapter, e); | |
| return; | |
| } | |
| e->Ind = 0; | |
| break; | |
| case IDI_SYNC_REQ_GET_FEATURES: | |
| if (IoAdapter) | |
| { | |
| syncReq->GetFeatures.features = | |
| (unsigned short)IoAdapter->features; | |
| return; | |
| } | |
| syncReq->GetFeatures.features = 0; | |
| break; | |
| case IDI_SYNC_REQ_PORTDRV_HOOK: | |
| if (IoAdapter) | |
| { | |
| DBG_TRC(("Xdi:IDI_SYNC_REQ_PORTDRV_HOOK - ignored")) | |
| return; | |
| } | |
| break; | |
| } | |
| if (IoAdapter) | |
| { | |
| return; | |
| } | |
| } | |
| DBG_TRC(("xdi: Id 0x%x / Req 0x%x / Rc 0x%x", e->Id, e->Req, e->Rc)) | |
| if (!IoAdapter) | |
| { | |
| DBG_FTL(("xdi: uninitialized Adapter used - ignore request")) | |
| return; | |
| } | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req"); | |
| /* | |
| * assign an entity | |
| */ | |
| if (!(e->Id & 0x1f)) | |
| { | |
| if (IoAdapter->e_count >= IoAdapter->e_max) | |
| { | |
| DBG_FTL(("xdi: all Ids in use (max=%d) --> Req ignored", | |
| IoAdapter->e_max)) | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req"); | |
| return; | |
| } | |
| /* | |
| * find a new free id | |
| */ | |
| for (i = 1; IoAdapter->e_tbl[i].e; ++i); | |
| IoAdapter->e_tbl[i].e = e; | |
| IoAdapter->e_count++; | |
| e->No = (byte)i; | |
| e->More = 0; | |
| e->RCurrent = 0xff; | |
| } | |
| else | |
| { | |
| i = e->No; | |
| } | |
| /* | |
| * if the entity is still busy, ignore the request call | |
| */ | |
| if (e->More & XBUSY) | |
| { | |
| DBG_FTL(("xdi: Id 0x%x busy --> Req 0x%x ignored", e->Id, e->Req)) | |
| if (!IoAdapter->trapped && IoAdapter->trapFnc) | |
| { | |
| IoAdapter->trapFnc(IoAdapter); | |
| /* | |
| Firs trap, also notify user if supported | |
| */ | |
| if (IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) { | |
| (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum); | |
| } | |
| } | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req"); | |
| return; | |
| } | |
| /* | |
| * initialize transmit status variables | |
| */ | |
| e->More |= XBUSY; | |
| e->More &= ~XMOREF; | |
| e->XCurrent = 0; | |
| e->XOffset = 0; | |
| /* | |
| * queue this entity in the adapter request queue | |
| */ | |
| IoAdapter->e_tbl[i].next = 0; | |
| if (IoAdapter->head) | |
| { | |
| IoAdapter->e_tbl[IoAdapter->tail].next = i; | |
| IoAdapter->tail = i; | |
| } | |
| else | |
| { | |
| IoAdapter->head = i; | |
| IoAdapter->tail = i; | |
| } | |
| /* | |
| * queue the DPC to process the request | |
| */ | |
| diva_os_schedule_soft_isr(&IoAdapter->req_soft_isr); | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req"); | |
| } | |
| /* --------------------------------------------------------------------- | |
| Main DPC routine | |
| --------------------------------------------------------------------- */ | |
| void DIDpcRoutine(struct _diva_os_soft_isr *psoft_isr, void *Context) { | |
| PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)Context; | |
| ADAPTER *a = &IoAdapter->a; | |
| diva_os_atomic_t *pin_dpc = &IoAdapter->in_dpc; | |
| if (diva_os_atomic_increment(pin_dpc) == 1) { | |
| do { | |
| if (IoAdapter->tst_irq(a)) | |
| { | |
| if (!IoAdapter->Unavailable) | |
| IoAdapter->dpc(a); | |
| IoAdapter->clr_irq(a); | |
| } | |
| IoAdapter->out(a); | |
| } while (diva_os_atomic_decrement(pin_dpc) > 0); | |
| /* ---------------------------------------------------------------- | |
| Look for XLOG request (cards with indirect addressing) | |
| ---------------------------------------------------------------- */ | |
| if (IoAdapter->pcm_pending) { | |
| struct pc_maint *pcm; | |
| diva_os_spin_lock_magic_t OldIrql; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_dpc"); | |
| pcm = (struct pc_maint *)IoAdapter->pcm_data; | |
| switch (IoAdapter->pcm_pending) { | |
| case 1: /* ask card for XLOG */ | |
| a->ram_out(a, &IoAdapter->pcm->rc, 0); | |
| a->ram_out(a, &IoAdapter->pcm->req, pcm->req); | |
| IoAdapter->pcm_pending = 2; | |
| break; | |
| case 2: /* Try to get XLOG from the card */ | |
| if ((int)(a->ram_in(a, &IoAdapter->pcm->rc))) { | |
| a->ram_in_buffer(a, IoAdapter->pcm, pcm, sizeof(*pcm)); | |
| IoAdapter->pcm_pending = 3; | |
| } | |
| break; | |
| case 3: /* let XDI recovery XLOG */ | |
| break; | |
| } | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_dpc"); | |
| } | |
| /* ---------------------------------------------------------------- */ | |
| } | |
| } | |
| /* -------------------------------------------------------------------------- | |
| XLOG interface | |
| -------------------------------------------------------------------------- */ | |
| static void | |
| pcm_req(PISDN_ADAPTER IoAdapter, ENTITY *e) | |
| { | |
| diva_os_spin_lock_magic_t OldIrql; | |
| int i, rc; | |
| ADAPTER *a = &IoAdapter->a; | |
| struct pc_maint *pcm = (struct pc_maint *)&e->Ind; | |
| /* | |
| * special handling of I/O based card interface | |
| * the memory access isn't an atomic operation ! | |
| */ | |
| if (IoAdapter->Properties.Card == CARD_MAE) | |
| { | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_1"); | |
| IoAdapter->pcm_data = (void *)pcm; | |
| IoAdapter->pcm_pending = 1; | |
| diva_os_schedule_soft_isr(&IoAdapter->req_soft_isr); | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_1"); | |
| for (rc = 0, i = (IoAdapter->trapped ? 3000 : 250); !rc && (i > 0); --i) | |
| { | |
| diva_os_sleep(1); | |
| if (IoAdapter->pcm_pending == 3) { | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_3"); | |
| IoAdapter->pcm_pending = 0; | |
| IoAdapter->pcm_data = NULL; | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_3"); | |
| return; | |
| } | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_2"); | |
| diva_os_schedule_soft_isr(&IoAdapter->req_soft_isr); | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_2"); | |
| } | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_4"); | |
| IoAdapter->pcm_pending = 0; | |
| IoAdapter->pcm_data = NULL; | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &OldIrql, | |
| "data_pcm_4"); | |
| goto Trapped; | |
| } | |
| /* | |
| * memory based shared ram is accessible from different | |
| * processors without disturbing concurrent processes. | |
| */ | |
| a->ram_out(a, &IoAdapter->pcm->rc, 0); | |
| a->ram_out(a, &IoAdapter->pcm->req, pcm->req); | |
| for (i = (IoAdapter->trapped ? 3000 : 250); --i > 0;) | |
| { | |
| diva_os_sleep(1); | |
| rc = (int)(a->ram_in(a, &IoAdapter->pcm->rc)); | |
| if (rc) | |
| { | |
| a->ram_in_buffer(a, IoAdapter->pcm, pcm, sizeof(*pcm)); | |
| return; | |
| } | |
| } | |
| Trapped: | |
| if (IoAdapter->trapFnc) | |
| { | |
| int trapped = IoAdapter->trapped; | |
| IoAdapter->trapFnc(IoAdapter); | |
| /* | |
| Firs trap, also notify user if supported | |
| */ | |
| if (!trapped && IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) { | |
| (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum); | |
| } | |
| } | |
| } | |
| /*------------------------------------------------------------------*/ | |
| /* ram access functions for memory mapped cards */ | |
| /*------------------------------------------------------------------*/ | |
| byte mem_in(ADAPTER *a, void *addr) | |
| { | |
| byte val; | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| val = READ_BYTE(Base + (unsigned long)addr); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| return (val); | |
| } | |
| word mem_inw(ADAPTER *a, void *addr) | |
| { | |
| word val; | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| val = READ_WORD((Base + (unsigned long)addr)); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| return (val); | |
| } | |
| void mem_in_dw(ADAPTER *a, void *addr, dword *data, int dwords) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| while (dwords--) { | |
| *data++ = READ_DWORD((Base + (unsigned long)addr)); | |
| addr += 4; | |
| } | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_in_buffer(ADAPTER *a, void *addr, void *buffer, word length) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| memcpy_fromio(buffer, (Base + (unsigned long)addr), length); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) | |
| { | |
| PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io; | |
| IoAdapter->RBuffer.length = mem_inw(a, &RBuffer->length); | |
| mem_in_buffer(a, RBuffer->P, IoAdapter->RBuffer.P, | |
| IoAdapter->RBuffer.length); | |
| e->RBuffer = (DBUFFER *)&IoAdapter->RBuffer; | |
| } | |
| void mem_out(ADAPTER *a, void *addr, byte data) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| WRITE_BYTE(Base + (unsigned long)addr, data); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_outw(ADAPTER *a, void *addr, word data) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| WRITE_WORD((Base + (unsigned long)addr), data); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_out_dw(ADAPTER *a, void *addr, const dword *data, int dwords) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| while (dwords--) { | |
| WRITE_DWORD((Base + (unsigned long)addr), *data); | |
| addr += 4; | |
| data++; | |
| } | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_out_buffer(ADAPTER *a, void *addr, void *buffer, word length) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| memcpy_toio((Base + (unsigned long)addr), buffer, length); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| void mem_inc(ADAPTER *a, void *addr) | |
| { | |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); | |
| byte x = READ_BYTE(Base + (unsigned long)addr); | |
| WRITE_BYTE(Base + (unsigned long)addr, x + 1); | |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); | |
| } | |
| /*------------------------------------------------------------------*/ | |
| /* ram access functions for io-mapped cards */ | |
| /*------------------------------------------------------------------*/ | |
| byte io_in(ADAPTER *a, void *adr) | |
| { | |
| byte val; | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| val = inpp(Port); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| return (val); | |
| } | |
| word io_inw(ADAPTER *a, void *adr) | |
| { | |
| word val; | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| val = inppw(Port); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| return (val); | |
| } | |
| void io_in_buffer(ADAPTER *a, void *adr, void *buffer, word len) | |
| { | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| byte *P = (byte *)buffer; | |
| if ((long)adr & 1) { | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| *P = inpp(Port); | |
| P++; | |
| adr = ((byte *) adr) + 1; | |
| len--; | |
| if (!len) { | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| return; | |
| } | |
| } | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| inppw_buffer(Port, P, len + 1); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) | |
| { | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)RBuffer); | |
| ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(Port); | |
| inppw_buffer(Port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1); | |
| e->RBuffer = (DBUFFER *) &(((PISDN_ADAPTER)a->io)->RBuffer); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| void io_out(ADAPTER *a, void *adr, byte data) | |
| { | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| outpp(Port, data); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| void io_outw(ADAPTER *a, void *adr, word data) | |
| { | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| outppw(Port, data); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| void io_out_buffer(ADAPTER *a, void *adr, void *buffer, word len) | |
| { | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| byte *P = (byte *)buffer; | |
| if ((long)adr & 1) { | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| outpp(Port, *P); | |
| P++; | |
| adr = ((byte *) adr) + 1; | |
| len--; | |
| if (!len) { | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| return; | |
| } | |
| } | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| outppw_buffer(Port, P, len + 1); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| void io_inc(ADAPTER *a, void *adr) | |
| { | |
| byte x; | |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| x = inpp(Port); | |
| outppw(Port + 4, (word)(unsigned long)adr); | |
| outpp(Port, x + 1); | |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); | |
| } | |
| /*------------------------------------------------------------------*/ | |
| /* OS specific functions related to queuing of entities */ | |
| /*------------------------------------------------------------------*/ | |
| void free_entity(ADAPTER *a, byte e_no) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| diva_os_spin_lock_magic_t irql; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_free"); | |
| IoAdapter->e_tbl[e_no].e = NULL; | |
| IoAdapter->e_count--; | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_free"); | |
| } | |
| void assign_queue(ADAPTER *a, byte e_no, word ref) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| diva_os_spin_lock_magic_t irql; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_assign"); | |
| IoAdapter->e_tbl[e_no].assign_ref = ref; | |
| IoAdapter->e_tbl[e_no].next = (byte)IoAdapter->assign; | |
| IoAdapter->assign = e_no; | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_assign"); | |
| } | |
| byte get_assign(ADAPTER *a, word ref) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| diva_os_spin_lock_magic_t irql; | |
| byte e_no; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, | |
| &irql, | |
| "data_assign_get"); | |
| for (e_no = (byte)IoAdapter->assign; | |
| e_no && IoAdapter->e_tbl[e_no].assign_ref != ref; | |
| e_no = IoAdapter->e_tbl[e_no].next); | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, | |
| &irql, | |
| "data_assign_get"); | |
| return e_no; | |
| } | |
| void req_queue(ADAPTER *a, byte e_no) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| diva_os_spin_lock_magic_t irql; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req_q"); | |
| IoAdapter->e_tbl[e_no].next = 0; | |
| if (IoAdapter->head) { | |
| IoAdapter->e_tbl[IoAdapter->tail].next = e_no; | |
| IoAdapter->tail = e_no; | |
| } | |
| else { | |
| IoAdapter->head = e_no; | |
| IoAdapter->tail = e_no; | |
| } | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req_q"); | |
| } | |
| byte look_req(ADAPTER *a) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| return ((byte)IoAdapter->head); | |
| } | |
| void next_req(ADAPTER *a) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| diva_os_spin_lock_magic_t irql; | |
| IoAdapter = (PISDN_ADAPTER) a->io; | |
| diva_os_enter_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req_next"); | |
| IoAdapter->head = IoAdapter->e_tbl[IoAdapter->head].next; | |
| if (!IoAdapter->head) IoAdapter->tail = 0; | |
| diva_os_leave_spin_lock(&IoAdapter->data_spin_lock, &irql, "data_req_next"); | |
| } | |
| /*------------------------------------------------------------------*/ | |
| /* memory map functions */ | |
| /*------------------------------------------------------------------*/ | |
| ENTITY *entity_ptr(ADAPTER *a, byte e_no) | |
| { | |
| PISDN_ADAPTER IoAdapter; | |
| IoAdapter = (PISDN_ADAPTER)a->io; | |
| return (IoAdapter->e_tbl[e_no].e); | |
| } | |
| void *PTR_X(ADAPTER *a, ENTITY *e) | |
| { | |
| return ((void *) e->X); | |
| } | |
| void *PTR_R(ADAPTER *a, ENTITY *e) | |
| { | |
| return ((void *) e->R); | |
| } | |
| void *PTR_P(ADAPTER *a, ENTITY *e, void *P) | |
| { | |
| return P; | |
| } | |
| void CALLBACK(ADAPTER *a, ENTITY *e) | |
| { | |
| if (e && e->callback) | |
| e->callback(e); | |
| } |