/* ======== dmm_create_tables ======== * Purpose: * Create table to hold the information of physical address * the buffer pages that is passed by the user, and the table * to hold the information of the virtual memory that is reserved * for DSP. */ int dmm_create_tables(struct dmm_object *dmm_mgr, u32 addr, u32 size) { struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr; int status = 0; status = dmm_delete_tables(dmm_obj); if (!status) { dyn_mem_map_beg = addr; table_size = PG_ALIGN_HIGH(size, PG_SIZE4K) / PG_SIZE4K; /* Create the free list */ virtual_mapping_table = __vmalloc(table_size * sizeof(struct map_page), GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); if (virtual_mapping_table == NULL) status = -ENOMEM; else { /* On successful allocation, * all entries are zero ('free') */ free_region = 0; free_size = table_size * PG_SIZE4K; virtual_mapping_table[0].region_size = table_size; } } if (status) pr_err("%s: failure, status 0x%x\n", __func__, status); return status; }
/* * ======== DSPNode_Allocate ======== * Purpose: * Allocate data structures for controlling and communicating * with a node on a specific DSP processor.. */ DBAPI DSPNode_Allocate(DSP_HPROCESSOR hProcessor, IN CONST struct DSP_UUID *pNodeID, IN CONST OPTIONAL struct DSP_CBDATA *pArgs, IN OPTIONAL struct DSP_NODEATTRIN *pAttrIn, OUT DSP_HNODE *phNode) { DSP_STATUS status = DSP_SOK; Trapped_Args tempStruct; struct CMM_OBJECT *hCmm; /* shared memory mngr handle */ struct CMM_INFO pInfo; /* Used for virtual space allocation */ PVOID pVirtBase; struct DSP_BUFFERATTR bufAttr; DSP_NODETYPE nodeType; struct DSP_NDBPROPS nodeProps; UINT heapSize = 0; PVOID pGPPVirtAddr = NULL; UINT uProfileID; DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Allocate:\r\n"))); if (!hProcessor) { status = DSP_EHANDLE; DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Allocate: " "hProcessor is Invalid \r\n"))); goto func_cont; } if (!(pNodeID) || !(phNode)) { status = DSP_EPOINTER; DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Allocate: " "Invalid pointer in the Input\r\n"))); goto func_cont; } /* First get the NODE properties, allocate, reserve memory for Node heap */ if (pAttrIn) { status = DSPNode_GetUUIDProps(hProcessor, pNodeID, &nodeProps); pAttrIn->pGPPVirtAddr = NULL; if (DSP_SUCCEEDED(status)) { uProfileID = pAttrIn->uProfileID; DEBUGMSG(DSPAPI_ZONE_FUNCTION, ("DSPNodeAllocate: User requested" "node heap profile \n")); if (uProfileID < nodeProps.uCountProfiles) heapSize = nodeProps.aProfiles[uProfileID].ulHeapSize; if (heapSize) { /* allocate heap memory */ /* Make heap size multiple of page size * */ heapSize = PG_ALIGN_HIGH(heapSize, PG_SIZE_4K); /* align memory on cache line boundary * */ pGPPVirtAddr = memalign(GEM_CACHE_LINE_SIZE, heapSize); DEBUGMSG(DSPAPI_ZONE_FUNCTION, ("DSPNodeAllocate: Node heap memory" "addr, size \n")); if ((pGPPVirtAddr == NULL)) status = DSP_EMEMORY; pAttrIn->uHeapSize = heapSize; pAttrIn->pGPPVirtAddr = pGPPVirtAddr; } } else { DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT( "NODE:DSPNode_Allocate: Failed to get Node " "UUID properties \r\n"))); } } if (DSP_SUCCEEDED(status)) { /* Set up the structure Call DSP Trap */ tempStruct.ARGS_NODE_ALLOCATE.hProcessor = hProcessor; tempStruct.ARGS_NODE_ALLOCATE.pNodeID = (struct DSP_UUID *)pNodeID; tempStruct.ARGS_NODE_ALLOCATE.pArgs = (struct DSP_CBDATA *)pArgs; tempStruct.ARGS_NODE_ALLOCATE.pAttrIn = (struct DSP_NODEATTRIN *)pAttrIn; tempStruct.ARGS_NODE_ALLOCATE.phNode = phNode; status = DSPTRAP_Trap(&tempStruct, CMD_NODE_ALLOCATE_OFFSET); } func_cont: /* If 1st SM segment is configured then allocate and map it to this process.*/ if (!DSP_SUCCEEDED(status)) { if (pGPPVirtAddr) free(pGPPVirtAddr); return status; } tempStruct.ARGS_CMM_GETHANDLE.hProcessor = hProcessor; tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm; status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETHANDLE_OFFSET); if (DSP_SUCCEEDED(status)) { /* Get SM segment info from CMM */ tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm; tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo; status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETINFO_OFFSET); if (DSP_FAILED(status)) { status = DSP_EFAIL; DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT( "NODE: DSPNode_Allocate: " "Failed to get SM segment\r\n"))); } else status = DSP_SOK; } else { status = DSP_EFAIL; DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT( "NODE: DSPNode_Allocate:Failed to CMM handle\r\n"))); } if (!DSP_SUCCEEDED(status)) { free(pGPPVirtAddr); return status; } GetNodeType(*phNode, &nodeType); if ((nodeType != NODE_DEVICE) && (pInfo.ulNumGPPSMSegs > 0)) { /* Messaging uses 1st segment */ if ((pInfo.segInfo[0].dwSegBasePa != 0) && (pInfo.segInfo[0].ulTotalSegSize) > 0) { pVirtBase = mmap(NULL, pInfo.segInfo[0].ulTotalSegSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, hMediaFile, pInfo.segInfo[0].dwSegBasePa); if (!pVirtBase) { DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: " "DSPNode_Allocate:Virt alloc failed\r\n"))); status = DSP_EMEMORY; /* Clean up */ tempStruct.ARGS_NODE_DELETE.hNode = *phNode; DSPTRAP_Trap(&tempStruct, CMD_NODE_DELETE_OFFSET); return status; } /* set node translator's virt addr range for seg */ bufAttr.uAlignment = 0; bufAttr.uSegment = 1 | MEMRY_SETVIRTUALSEGID; bufAttr.cbStruct = 0; status = DSPNode_AllocMsgBuf(*phNode, pInfo.segInfo[0].ulTotalSegSize, &bufAttr, (BYTE **)&pVirtBase); if (DSP_FAILED(status)) { /* If failed to set segment, unmap */ munmap(pVirtBase, pInfo.segInfo[0].ulTotalSegSize); /* Clean up */ tempStruct.ARGS_NODE_DELETE.hNode = *phNode; DSPTRAP_Trap(&tempStruct, CMD_NODE_DELETE_OFFSET); } } } return status; }
/* * ======== read_ext_dsp_data ======== * Copies DSP external memory buffers to the host side buffers. */ int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt, u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes, u32 mem_type) { int status = 0; struct bridge_dev_context *dev_context = dev_ctxt; u32 offset; u32 ul_tlb_base_virt = 0; u32 ul_shm_offset_virt = 0; u32 dw_ext_prog_virt_mem; u32 dw_base_addr = dev_context->dsp_ext_base_addr; bool trace_read = false; if (!ul_shm_base_virt) { status = dev_get_symbol(dev_context->dev_obj, SHMBASENAME, &ul_shm_base_virt); } /* Check if it is a read of Trace section */ if (!status && !ul_trace_sec_beg) { status = dev_get_symbol(dev_context->dev_obj, DSP_TRACESEC_BEG, &ul_trace_sec_beg); } if (!status && !ul_trace_sec_end) { status = dev_get_symbol(dev_context->dev_obj, DSP_TRACESEC_END, &ul_trace_sec_end); } if (!status) { if ((dsp_addr <= ul_trace_sec_end) && (dsp_addr >= ul_trace_sec_beg)) trace_read = true; } /* If reading from TRACE, force remap/unmap */ if (trace_read && dw_base_addr) { dw_base_addr = 0; dev_context->dsp_ext_base_addr = 0; } if (!dw_base_addr) { /* Initialize ul_ext_base and ul_ext_end */ ul_ext_base = 0; ul_ext_end = 0; /* Get DYNEXT_BEG, EXT_BEG and EXT_END. */ if (!status && !ul_dyn_ext_base) { status = dev_get_symbol(dev_context->dev_obj, DYNEXTBASE, &ul_dyn_ext_base); } if (!status) { status = dev_get_symbol(dev_context->dev_obj, EXTBASE, &ul_ext_base); } if (!status) { status = dev_get_symbol(dev_context->dev_obj, EXTEND, &ul_ext_end); } /* Trace buffer is right after the shm SEG0, * so set the base address to SHMBASE */ if (trace_read) { ul_ext_base = ul_shm_base_virt; ul_ext_end = ul_trace_sec_end; } if (ul_ext_end < ul_ext_base) status = -EPERM; if (!status) { ul_tlb_base_virt = dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE; dw_ext_prog_virt_mem = dev_context->atlb_entry[0].gpp_va; if (!trace_read) { ul_shm_offset_virt = ul_shm_base_virt - ul_tlb_base_virt; ul_shm_offset_virt += PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base + 1, HW_PAGE_SIZE64KB); dw_ext_prog_virt_mem -= ul_shm_offset_virt; dw_ext_prog_virt_mem += (ul_ext_base - ul_dyn_ext_base); dev_context->dsp_ext_base_addr = dw_ext_prog_virt_mem; /* * This dsp_ext_base_addr will get cleared * only when the board is stopped. */ if (!dev_context->dsp_ext_base_addr) status = -EPERM; } dw_base_addr = dw_ext_prog_virt_mem; } } if (!dw_base_addr || !ul_ext_base || !ul_ext_end) status = -EPERM; offset = dsp_addr - ul_ext_base; if (!status) memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes); return status; }
/* * ======== ReadExtDspData ======== * Copies DSP external memory buffers to the host side buffers. */ DSP_STATUS ReadExtDspData(struct WMD_DEV_CONTEXT *hDevContext, OUT u8 *pbHostBuf, u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType) { DSP_STATUS status = DSP_SOK; struct WMD_DEV_CONTEXT *pDevContext = hDevContext; u32 offset; u32 ulTLBBaseVirt = 0; u32 ulShmOffsetVirt = 0; u32 dwExtProgVirtMem; u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr; bool bTraceRead = false; if (!ulShmBaseVirt) { status = DEV_GetSymbol(pDevContext->hDevObject, SHMBASENAME, &ulShmBaseVirt); } DBC_Assert(ulShmBaseVirt != 0); /* Check if it is a read of Trace section */ if (DSP_SUCCEEDED(status) && !ulTraceSecBeg) { status = DEV_GetSymbol(pDevContext->hDevObject, DSP_TRACESEC_BEG, &ulTraceSecBeg); } DBC_Assert(ulTraceSecBeg != 0); if (DSP_SUCCEEDED(status) && !ulTraceSecEnd) { status = DEV_GetSymbol(pDevContext->hDevObject, DSP_TRACESEC_END, &ulTraceSecEnd); } DBC_Assert(ulTraceSecEnd != 0); if (DSP_SUCCEEDED(status)) { if ((dwDSPAddr <= ulTraceSecEnd) && (dwDSPAddr >= ulTraceSecBeg)) bTraceRead = true; } /* If reading from TRACE, force remap/unmap */ if (bTraceRead && dwBaseAddr) { dwBaseAddr = 0; pDevContext->dwDspExtBaseAddr = 0; } if (!dwBaseAddr) { /* Initialize ulExtBase and ulExtEnd */ ulExtBase = 0; ulExtEnd = 0; /* Get DYNEXT_BEG, EXT_BEG and EXT_END.*/ if (DSP_SUCCEEDED(status) && !ulDynExtBase) { status = DEV_GetSymbol(pDevContext->hDevObject, DYNEXTBASE, &ulDynExtBase); } DBC_Assert(ulDynExtBase != 0); if (DSP_SUCCEEDED(status)) { status = DEV_GetSymbol(pDevContext->hDevObject, EXTBASE, &ulExtBase); } DBC_Assert(ulExtBase != 0); if (DSP_SUCCEEDED(status)) { status = DEV_GetSymbol(pDevContext->hDevObject, EXTEND, &ulExtEnd); } DBC_Assert(ulExtEnd != 0); /* Trace buffer is right after the SHM SEG0, * so set the base address to SHMBASE */ if (bTraceRead) { ulExtBase = ulShmBaseVirt; ulExtEnd = ulTraceSecEnd; } DBC_Assert(ulExtEnd != 0); DBC_Assert(ulExtEnd > ulExtBase); if (ulExtEnd < ulExtBase) status = DSP_EFAIL; if (DSP_SUCCEEDED(status)) { ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa * DSPWORDSIZE; DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt); dwExtProgVirtMem = pDevContext->aTLBEntry[0].ulGppVa; if (!bTraceRead) { ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt; ulShmOffsetVirt += PG_ALIGN_HIGH(ulExtEnd - ulDynExtBase + 1, HW_PAGE_SIZE_64KB); dwExtProgVirtMem -= ulShmOffsetVirt; dwExtProgVirtMem += (ulExtBase - ulDynExtBase); pDevContext->dwDspExtBaseAddr = dwExtProgVirtMem; /* This dwDspExtBaseAddr will get cleared only when the board is * stopped. */ if (!pDevContext->dwDspExtBaseAddr) status = DSP_EFAIL; } dwBaseAddr = dwExtProgVirtMem; } } if (!dwBaseAddr || !ulExtBase || !ulExtEnd) status = DSP_EFAIL; offset = dwDSPAddr - ulExtBase; if (DSP_SUCCEEDED(status)) memcpy(pbHostBuf, (u8 *)dwBaseAddr+offset, ulNumBytes); return status; }
int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt, u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes, u32 mem_type) { int status = 0; struct bridge_dev_context *dev_context = dev_ctxt; u32 offset; u32 ul_tlb_base_virt = 0; u32 ul_shm_offset_virt = 0; u32 dw_ext_prog_virt_mem; u32 dw_base_addr = dev_context->dsp_ext_base_addr; bool trace_read = false; if (!ul_shm_base_virt) { status = dev_get_symbol(dev_context->dev_obj, SHMBASENAME, &ul_shm_base_virt); } if (!status && !ul_trace_sec_beg) { status = dev_get_symbol(dev_context->dev_obj, DSP_TRACESEC_BEG, &ul_trace_sec_beg); } if (!status && !ul_trace_sec_end) { status = dev_get_symbol(dev_context->dev_obj, DSP_TRACESEC_END, &ul_trace_sec_end); } if (!status) { if ((dsp_addr <= ul_trace_sec_end) && (dsp_addr >= ul_trace_sec_beg)) trace_read = true; } if (trace_read && dw_base_addr) { dw_base_addr = 0; dev_context->dsp_ext_base_addr = 0; } if (!dw_base_addr) { ul_ext_base = 0; ul_ext_end = 0; if (!status && !ul_dyn_ext_base) { status = dev_get_symbol(dev_context->dev_obj, DYNEXTBASE, &ul_dyn_ext_base); } if (!status) { status = dev_get_symbol(dev_context->dev_obj, EXTBASE, &ul_ext_base); } if (!status) { status = dev_get_symbol(dev_context->dev_obj, EXTEND, &ul_ext_end); } if (trace_read) { ul_ext_base = ul_shm_base_virt; ul_ext_end = ul_trace_sec_end; } if (ul_ext_end < ul_ext_base) status = -EPERM; if (!status) { ul_tlb_base_virt = dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE; dw_ext_prog_virt_mem = dev_context->atlb_entry[0].gpp_va; if (!trace_read) { ul_shm_offset_virt = ul_shm_base_virt - ul_tlb_base_virt; ul_shm_offset_virt += PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base + 1, HW_PAGE_SIZE64KB); dw_ext_prog_virt_mem -= ul_shm_offset_virt; dw_ext_prog_virt_mem += (ul_ext_base - ul_dyn_ext_base); dev_context->dsp_ext_base_addr = dw_ext_prog_virt_mem; if (!dev_context->dsp_ext_base_addr) status = -EPERM; } dw_base_addr = dw_ext_prog_virt_mem; } } if (!dw_base_addr || !ul_ext_base || !ul_ext_end) status = -EPERM; offset = dsp_addr - ul_ext_base; if (!status) memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes); return status; }