#include #include #include #include "memsize.h" #include "memMarco.h" u64 gMemDiagStartAddr; EXPORT_SYMBOL(gMemDiagStartAddr); u64 gMemDiagRegionSize; EXPORT_SYMBOL(gMemDiagRegionSize); u64 gMemDiagTOLMAddr; EXPORT_SYMBOL(gMemDiagTOLMAddr); u64 gMemDiagTOHMAddr; EXPORT_SYMBOL(gMemDiagTOHMAddr); u64 gMemDiagTSEGAddr; EXPORT_SYMBOL(gMemDiagTSEGAddr); u64 gMemDiagTSEGSize; EXPORT_SYMBOL(gMemDiagTSEGSize); #define MEM_CONFIG_MAX_CHAN 3 #define MEM_CONFIG_MAX_DIMM 3 #define MEM_CACHE_LINE_SIZE 0x40 #define MEM_CHAN_INTL_SIZE 0x1000 #define MEM_IMC_DOMAIN_ID 0x0 #define MEM_IMC_BUS_ID 0xFF #define MEM_IMC_CTL_DEVICE_ID 0x18 /* Device 3 */ #define MEM_IMC_CTL_RAS_FUNC 0x02 /* Function 2*/ #define MEM_IMC_CHAN0_DEVICE_ID 0x20 /* Device 4 */ #define MEM_IMC_CHAN1_DEVICE_ID 0x28 /* Device 5 */ #define MEM_IMC_CHAN2_DEVICE_ID 0x30 /* Device 6 */ #define MEM_IMC_CHAN_ADDR_FUNC 0x01 #define MEM_IMC_CTL_MC_CONTROL 0x48 #define MEM_IMC_CTL_MC_CHANNEL_MAPPER 0x60 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_0 0x48 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_1 0x4C #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_2 0x50 #define MEM_IMC_COR_ECC_CNT_0 0x80 #define MEM_IMC_COR_ECC_CNT_1 0x88 #define MEM_IMC_COR_ECC_CNT_2 0x90 #define MEM_DIAG_CORRECTABLE_ECC 0 #define MEM_DIAG_NONCORRECTABLE_ECC 1 #define MEM_DIAG_ECC_CYCLE 3 #define MEM_MC_CHANNEL_ADDR_MATCH 0xF0 #define MEM_MC_CHANNEL_ECC_ERROR_MASK 0xF8 #define MEM_MC_CHANNEL_ECC_ERROR_INJECT 0xFC #define MEM_MC_ENABLE_ECC_ERROR_INJECT 0x000E #define MEM_DIAG_ECC_MAX_DIMM_NUM 3 #define MEM_DIAG_ECC_DIMM_BIT_SHIFT 4 #define MEM_DIAG_ECC_THREE_DIMM_BIT_SHIFT 3 #define MEM_DIAG_ECC_RANK_BIT_SHIFT 2 #define MEM_DIAG_ECC_ADDR_MASK 0x000000E0 #define MEM_DIAG_ECC_ECC_INJECT_UPPER 0x0000000C //0x0000000A //the defined is corrected by Jay, refer to 418294 page 505 #define MEM_DIAG_ECC_ECC_INJECT_LOWER 0x0000000A //0x0000000C //the defined is corrected by Jay, refer to 418294 page 505 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_DIMMPRESENT 0x200 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_BANKMASK 0x00000180 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_BANK_SHIFT 7 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_RANKMASK 0x00000060 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_RANK_SHIFT 5 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_ROWMASK 0x0000001C #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_ROW_SHIFT 2 #define MEM_IMC_CHAN_ADDR_MC_DOD_CH_COLMASK 0x00000003 #define MEM_DATA_WIDTH_IN_BYTE 8 typedef struct memoryDimmConfiguration { int numRank; u64 sizeRank; } MEM_DIMM_CFG; typedef struct memoryChannelConfiguration { MEM_DIMM_CFG dimmCfg[MEM_CONFIG_MAX_DIMM]; bool enableChan; int totalDimm; } MEM_CHAN_CFG; typedef struct memoryAddr { int idxChan; int idxRank; int idxDimm; int totalDimm; } MEM_ADDR; /*** GLOBAL DATA ***/ MEM_CHAN_CFG sysMemConfig[MEM_CONFIG_MAX_CHAN]; u64 gMemDiagStartAddr; u64 gMemDiagRegionSize; u64 gMemDiagTOLMAddr; u64 gMemDiagTOHMAddr; u64 gMemDiagTSEGAddr; u64 gMemDiagTSEGSize; /*** LOCAL DATA ***/ const u32 imcDevFuncTrans[4] = { MEM_IMC_CHAN0_DEVICE_ID, MEM_IMC_CHAN1_DEVICE_ID, MEM_IMC_CHAN2_DEVICE_ID }; const u32 dimmOffsetTrans[4] = { MEM_IMC_CHAN_ADDR_MC_DOD_CH_0, MEM_IMC_CHAN_ADDR_MC_DOD_CH_1, MEM_IMC_CHAN_ADDR_MC_DOD_CH_2 }; const int bankTrans[4] = {4, 8, 16}; const int rankTrans[4] = {1, 2, 4}; const int rowTrans[8] = {12, 13, 14, 15, 16}; const int colTrans[4] = {10, 11, 12}; extern int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val); extern int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 val); /******************************************************************************* * PROCEDURE * * NAME: memReadIMCReg * SUMMARY: This procedure will set the starting address for memory diagnostics * SCOPE: public * * DESCRIPTION: This function will set the starting address for memory diagnostics * with user specific value or default configuration * * RETURNS: * * NOTES: * */ void memReadIMCReg(u32 idxFunc, u32 addrReg, u32 length, u32 *val) { u32 result; result = raw_pci_read(MEM_IMC_DOMAIN_ID, MEM_IMC_BUS_ID, idxFunc, addrReg, length, val); printk("Mem BUS:0x%x, Func:0x%x, addr:0x%x, length:%d, val:0x%x\n", MEM_IMC_BUS_ID, idxFunc, addrReg, length, *val); if(result) { printk("Integrated Memory Controller Control Registers read Failed\n"); //ASSERT(0); } } /******************************************************************************* * PROCEDURE * * NAME: memGetMemConfig * SUMMARY: This procedure will get memory configuration from the integrated memory controller * SCOPE: public * * DESCRIPTION: This function will read memory configuration infomation * form the pci configuration register of the integrated memory controller * * RETURNS: the total size of memory * * NOTES: * */ u64 memGetMemConfig(void) { int idxChan; int idxDimm; u32 bitmapMCControl; u32 valDimm; u64 sizeMem; u64 numRow; u64 numCol; int numBank; MEM_CHAN_CFG* pChanCfg; sizeMem = 0; memReadIMCReg(MEM_IMC_CTL_DEVICE_ID, MEM_IMC_CTL_MC_CONTROL, sizeof(u16), &bitmapMCControl); printk("bitmapMCControl 0x%x", bitmapMCControl); bitmapMCControl = bitmapMCControl >> 8; printk(">> 8 = 0x%x \n", bitmapMCControl); for(idxChan = 0; idxChan < MEM_CONFIG_MAX_CHAN; idxChan++) { pChanCfg = &sysMemConfig[idxChan]; pChanCfg->enableChan = false; pChanCfg->totalDimm = 0; //printk("chan:%d bitmapMCControl:%d \n",idxChan, (bitmapMCControl & 0x1) ); if(bitmapMCControl & 0x1) { for(idxDimm=0; idxDimm < MEM_CONFIG_MAX_DIMM; idxDimm++) { memReadIMCReg(imcDevFuncTrans[idxChan] + MEM_IMC_CHAN_ADDR_FUNC, dimmOffsetTrans[idxDimm], sizeof(u32), &valDimm); pChanCfg->dimmCfg[idxDimm].numRank = 0; pChanCfg->dimmCfg[idxDimm].sizeRank = 0; if(valDimm & MEM_IMC_CHAN_ADDR_MC_DOD_CH_DIMMPRESENT) { pChanCfg->dimmCfg[idxDimm].numRank = rankTrans[(valDimm & MEM_IMC_CHAN_ADDR_MC_DOD_CH_RANKMASK) >> MEM_IMC_CHAN_ADDR_MC_DOD_CH_RANK_SHIFT]; numBank = bankTrans[(valDimm & MEM_IMC_CHAN_ADDR_MC_DOD_CH_BANKMASK) >> MEM_IMC_CHAN_ADDR_MC_DOD_CH_BANK_SHIFT]; numRow = 1 << rowTrans[(valDimm & MEM_IMC_CHAN_ADDR_MC_DOD_CH_ROWMASK) >> MEM_IMC_CHAN_ADDR_MC_DOD_CH_ROW_SHIFT]; numCol = 1 << colTrans[valDimm & MEM_IMC_CHAN_ADDR_MC_DOD_CH_COLMASK]; pChanCfg->dimmCfg[idxDimm].sizeRank = MEM_DATA_WIDTH_IN_BYTE * numCol * numRow * numBank ; sizeMem += pChanCfg->dimmCfg[idxDimm].numRank * pChanCfg->dimmCfg[idxDimm].sizeRank; pChanCfg->totalDimm++; } } if(pChanCfg->totalDimm > 0) pChanCfg->enableChan = true; } bitmapMCControl = bitmapMCControl >> 1; } printk("sizeMem: %d \n",sizeMem ); return sizeMem; } #define UINT64_MAX (18446744073709551615ULL) #define MEM_JF_CORE_DID 0x3728 //#define MEM_JF_CORE_DID 0x3c28 #define MEM_JF_CORE_REG_TOLM_OFFSET 0xD0 // 32bit #define MEM_JF_CORE_REG_TOHM_OFFSET 0xD4 #define MEM_JF_CORE_REG_TOHML_OFFSET 0xD4 #define MEM_JF_CORE_REG_TOHMH_OFFSET 0xD8 #define MEM_JF_CORE_REG_TOM_MASK 0xFC000000 #define MEM_JF_CORE_REG_TSEGCTRL_OFFSET 0xA8 #define MEM_JF_CORE_REG_TSEG_ENABLE 0x00000001 #define MEM_JF_CORE_REG_TSEG_ADDR_MASK 0xFFF00000 #define MEM_JF_CORE_REG_TSEG_SIZE_MASK 0x0000000E #define MEM_JF_CORE_REG_TSEG_SIZE_BASE 0x00080000 void memSetDiagStartAddr(u64 start_addr) { struct pci_dev* pdev = NULL; u32 obs_val; u64 obs_val64; if(start_addr == UINT64_MAX | start_addr == 0) gMemDiagStartAddr = (u64)(num_physpages << PAGE_SHIFT); else gMemDiagStartAddr = start_addr; if (memGetMemConfig() != 0) { gMemDiagRegionSize = memGetMemConfig() - (u64)(num_physpages << PAGE_SHIFT); } else { gMemDiagRegionSize = 512 * MB - (u64)(num_physpages << PAGE_SHIFT); } printk(" = kernel size %Ld M, memory size %Ld M\n", (gMemDiagStartAddr >> 20) , (gMemDiagRegionSize >> 20)); pdev = pci_get_device(PCI_VENDOR_ID_INTEL, MEM_JF_CORE_DID, pdev); if(pdev != NULL) { pci_read_config_dword(pdev, MEM_JF_CORE_REG_TOLM_OFFSET, &obs_val); gMemDiagTOLMAddr = obs_val & MEM_JF_CORE_REG_TOM_MASK; pci_read_config_dword(pdev, MEM_JF_CORE_REG_TOHM_OFFSET, &obs_val); pci_read_config_dword(pdev, MEM_JF_CORE_REG_TOHM_OFFSET+4, &obs_val64); gMemDiagTOHMAddr = (obs_val64<<32) | (obs_val & MEM_JF_CORE_REG_TOM_MASK); printk("gMemDiagTOLMAddr: 0x%Lx, gMemDiagTOHMAddr: 0x%Lx \n",gMemDiagTOLMAddr,gMemDiagTOHMAddr); pci_read_config_dword(pdev, MEM_JF_CORE_REG_TSEGCTRL_OFFSET, &obs_val); printk(" MEM_JF_CORE_REG_TSEGCTRL_OFFSET(0x%x): 0x%Lx (%d)\n",MEM_JF_CORE_REG_TSEGCTRL_OFFSET,obs_val, (obs_val & MEM_JF_CORE_REG_TSEG_ENABLE)); if(obs_val & MEM_JF_CORE_REG_TSEG_ENABLE) { gMemDiagTSEGAddr = obs_val & MEM_JF_CORE_REG_TSEG_ADDR_MASK; if((gMemDiagTSEGAddr > gMemDiagTOLMAddr) && (gMemDiagTSEGAddr < MEM_JF_CORE_REG_TOHMH_START)) { gMemDiagTSEGAddr = 0; gMemDiagTSEGSize = 0; } else { gMemDiagTSEGSize = MEM_JF_CORE_REG_TSEG_SIZE_BASE << ((obs_val & MEM_JF_CORE_REG_TSEG_SIZE_MASK) / 2); } } printk("gMemDiagTSEGAddr: 0x%Lx, gMemDiagTSEGSize: 0x%Lx \n",gMemDiagTSEGAddr,gMemDiagTSEGSize); } printk(" + kernel size %Ld M, memory size %Ld M\n", (gMemDiagStartAddr >> 20) , (gMemDiagRegionSize >> 20)); if((gMemDiagStartAddr + gMemDiagRegionSize) > gMemDiagTOLMAddr) { gMemDiagRegionSize = gMemDiagTOLMAddr - gMemDiagStartAddr; printk(" -> kernel size %Ld M, memory size %Ld M\n", (gMemDiagStartAddr >> 20) , (gMemDiagRegionSize >> 20)); if(gMemDiagTOHMAddr > 0) { gMemDiagRegionSize += gMemDiagTOHMAddr - MEM_JF_CORE_REG_TOHMH_START; printk(" ->> kernel size %Ld M, memory size %Ld M\n", (gMemDiagStartAddr >> 20) , (gMemDiagRegionSize >> 20)); } } printk(" * kernel size %Lx, memory size %Lx\n", gMemDiagStartAddr, gMemDiagRegionSize); printk(" - kernel size %Ld M, memory size %Ld M\n", (gMemDiagStartAddr >> 20) , (gMemDiagRegionSize >> 20)); }