/** * @brief Get the Virtual Address of the XSCOM space for the processor * associated with this thread (the source chip) * * @param[out] o_mmioAddr Physical mmio address that was mapped in * @return uint64_t* virtualAddress */ uint64_t* getCpuIdVirtualAddress( XSComBase_t& o_mmioAddr ) { uint64_t* o_virtAddr = 0; // Read the MMIO setup by the SBE o_mmioAddr = g_BlToHbDataManager.getXscomBAR(); // Target's virtual address o_virtAddr = static_cast<uint64_t*> (mmio_dev_map(reinterpret_cast<void*>(o_mmioAddr), THIRTYTWO_GB)); TRACDCOMP(g_trac_xscom, "getCpuIdVirtualAddress: o_Virtual Address = 0x%llX\n",o_virtAddr); return o_virtAddr; }
/** * @brief Get the Virtual Address of the XSCOM space for the processor * associated with this thread (the source chip) * * @return uint64_t* virtualAddress */ uint64_t* getCpuIdVirtualAddress() { uint64_t* o_virtAddr = 0; // Get the CPU core this thread is running on uint32_t cpuid = task_getcpuid(); //NNNCCCPPPPTTT format fot the cpuid.. // N = node, C = chip, P = proc, T = thread uint32_t chipId = (cpuid & 0x0380)>>7; uint32_t nodeId = (cpuid & 0x1C00)>>10; // Can change the above hardcoded values to either a macro or use // the info below to do the masking and shifting. // uint64_t max_threads = cpu_thread_count(); // for the number of Chips - use g_xscomMaxChipsPerNode instead.. // For the number of Procs.. MAX_PROCS_RSV = P8_MAX_PROCS*2 // P8_MAX_PROCS = 8 -- space left for 2* that. XSComBase_t l_systemBaseAddr = MASTER_PROC_XSCOM_BASE_ADDR; // Target's XSCOM Base address XSComBase_t l_XSComBaseAddr = l_systemBaseAddr + ( ( (g_xscomMaxChipsPerNode * nodeId) + chipId ) * THIRTYTWO_GB); // Target's virtual address o_virtAddr = static_cast<uint64_t*> (mmio_dev_map(reinterpret_cast<void*>(l_XSComBaseAddr), THIRTYTWO_GB)); TRACDCOMP(g_trac_xscom, "getCpuIdVirtualAddress: o_Virtual Address = 0x%llX\n",o_virtAddr); return o_virtAddr; }
/** * @brief Get the virtual address of the input target * for an XSCOM access. * * Logic: * * If sentinel: * If never XSCOM to sentinel * Calculate virtual addr for sentinel * Save it to g_masterProcVirtAddr for future XSCOM to sentinel * Else * Use virtual addr stored in g_masterProcVirtAddr * End if * Else (not sentinel) * If never XSCOM to this chip: * If this is a master processor object * Use virtual addr stored for sentinel (g_masterProcVirtAddr) * Else * Call mmio_dev_map() to get virtual addr for this slave proc * End if * Save virtual addr used to this chip's attribute * Else * Use virtual address stored in this chip's attributes. * End if * End if * * @param[in] i_target XSCom target * @param[out] o_virtAddr Target's virtual address * * @return errlHndl_t */ errlHndl_t getTargetVirtualAddress(TARGETING::Target* i_target, uint64_t*& o_virtAddr) { errlHndl_t l_err = NULL; o_virtAddr = NULL; XSComBase_t l_XSComBaseAddr = 0; do { // Find out if the target pointer is the master processor chip bool l_isMasterProcChip = false; if (i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) { // Sentinel pointer representing the master processor chip l_isMasterProcChip = true; } else { TARGETING::Target* l_pMasterProcChip = NULL; TARGETING::targetService(). masterProcChipTargetHandle(l_pMasterProcChip); if (i_target == l_pMasterProcChip) { // Target Service reports that this is the master processor chip l_isMasterProcChip = true; } } // If the target is the master processor chip sentinel if (l_isMasterProcChip) { // This is the master processor chip. The virtual address is // g_masterProcVirtAddr. If this is NULL then initialize it // Use atomic update instructions here to avoid // race condition between different threads. // Keep in mind that the mutex used in XSCOM is hardware mutex, // not a mutex for the whole XSCOM logic. if (__sync_bool_compare_and_swap(&g_masterProcVirtAddr, NULL, NULL)) { // Note: can't call TARGETING code prior to PNOR being // brought up. uint64_t* l_tempVirtAddr = getCpuIdVirtualAddress(); if (!__sync_bool_compare_and_swap(&g_masterProcVirtAddr, NULL, l_tempVirtAddr)) { // If g_masterProcVirtAddr has already been updated by // another thread, we need to unmap the dev_map we just // called above. int rc = 0; rc = mmio_dev_unmap(reinterpret_cast<void*> (l_tempVirtAddr)); if (rc != 0) { /*@ * @errortype * @moduleid XSCOM_GET_TARGET_VIRT_ADDR * @reasoncode XSCOM_MMIO_UNMAP_ERR * @userdata1 Return Code * @userdata2 Unmap address * @devdesc mmio_dev_unmap() returns error * @custdesc A problem occurred during the IPL * of the system. */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, XSCOM_GET_TARGET_VIRT_ADDR, XSCOM_MMIO_UNMAP_ERR, rc, reinterpret_cast<uint64_t>(l_tempVirtAddr), true /*Add HB Software Callout*/); break; } } } // Set virtual address to sentinel's value o_virtAddr = g_masterProcVirtAddr; } else // This is not the master sentinel { // Get the virtual addr value of the chip from the virtual address // attribute o_virtAddr = reinterpret_cast<uint64_t*>( i_target->getAttr<TARGETING::ATTR_XSCOM_VIRTUAL_ADDR>()); // If the virtual address equals NULL(default) then this is the // first XSCOM to this target so we need to calculate // the virtual address and save it in the xscom address attribute. if (o_virtAddr == NULL) { uint64_t xscomNodeId = 0; uint64_t xscomChipId = 0; // Get the target Node Id xscomNodeId = i_target->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); // Get the target Chip Id xscomChipId = i_target->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); // Get system XSCOM base address TARGETING::TargetService& l_targetService = TARGETING::targetService(); TARGETING::Target* l_pTopLevel = NULL; (void) l_targetService.getTopLevelTarget(l_pTopLevel); assert(l_pTopLevel != NULL); XSComBase_t l_systemBaseAddr = l_pTopLevel->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>(); // Target's XSCOM Base address l_XSComBaseAddr = l_systemBaseAddr + ( ( (g_xscomMaxChipsPerNode * xscomNodeId) + xscomChipId ) * THIRTYTWO_GB); TRACFCOMP(g_trac_xscom, "Target %.8X :: Node:%d Chip:%d :: XscomBase:0x%llX", TARGETING::get_huid(i_target), xscomNodeId, xscomChipId, l_XSComBaseAddr); // Target's virtual address o_virtAddr = static_cast<uint64_t*> (mmio_dev_map(reinterpret_cast<void*>(l_XSComBaseAddr), THIRTYTWO_GB)); TRACDCOMP(g_trac_xscom, "xscomPerformOp: o_Virtual Address = 0x%llX\n",o_virtAddr); // Implemented the virtual address attribute.. // Leaving the comments as a discussion point... // Technically there is a race condition here. The mutex is // a per-hardware thread mutex, not a mutex for the whole XSCOM // logic. So there is possibility that this same thread is running // on another thread at the exact same time. We can use atomic // update instructions here. // Comment for Nick: This is a good candidate for having a way // to return a reference to the attribute instead of requiring // to call setAttr. We currently have no way to SMP-safely update // this attribute, where as if we had a reference to it we could use // the atomic update functions (_sync_bool_compare_and_swap in // this case. // Save the virtual address attribute. i_target->setAttr<TARGETING::ATTR_XSCOM_VIRTUAL_ADDR>( reinterpret_cast<uint64_t>(o_virtAddr)); } } } while (0); return l_err; }