diff options
Diffstat (limited to 'src/usr/devtree/bld_devtree.C')
-rw-r--r-- | src/usr/devtree/bld_devtree.C | 586 |
1 files changed, 421 insertions, 165 deletions
diff --git a/src/usr/devtree/bld_devtree.C b/src/usr/devtree/bld_devtree.C index 85d2d0773..3dc7f96d6 100644 --- a/src/usr/devtree/bld_devtree.C +++ b/src/usr/devtree/bld_devtree.C @@ -53,6 +53,9 @@ namespace DEVTREE { using namespace TARGETING; +#define CHIPID_EXTRACT_NODE(i_chipid) (i_chipid >> CHIPID_NODE_SHIFT) +#define CHIPID_EXTRACT_PROC(i_chipid) (i_chipid & CHIPID_PROC_MASK) + enum BuildConstants { DEVTREE_DATA_ADDR =0xFF00000, /* 256MB - 1MB*/ @@ -60,37 +63,225 @@ enum BuildConstants XSCOM_NODE_SHIFT =38, /*Node pos is 25, so 63-25=38*/ XSCOM_CHIP_SHIFT =35, /*Chip pos is 28, so 63-28=35*/ CHIPID_NODE_SHIFT =3, /*CHIPID is NNNCCC, shift 3*/ + CHIPID_PROC_MASK =0x7, /*CHIPID is NNNCCC, shift 3*/ PHB0_MASK =0x80, - MAX_PHBs = 3, /*Max PHBs per chip is 3*/ + MAX_PHBs =3, /*Max PHBs per chip is 3*/ + THREADPERCORE =8, /*8 threads per core*/ + MHZ =1000000, + + /* The Cache unit address (and reg property) is mostly free-for-all + * as long as there is no collisions. On HDAT machines we use the + * following encoding which I encourage you to also follow to limit + * surprises: + * + * L2 : (0x20 << 24) | PIR (PIR is PIR value of thread 0 of core) + * L3 : (0x30 << 24) | PIR + * L3.5 : (0x35 << 24) | PIR */ + L2_HDR = (0x20 << 24), + L3_HDR = (0x30 << 24), }; -errlHndl_t bld_fdt_cpu(devTree * i_dt) + +uint32_t getProcChipId(const TARGETING::Target * i_pProc) +{ + uint32_t l_fabId = i_pProc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); + uint32_t l_procPos = i_pProc->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); + return ( (l_fabId << CHIPID_NODE_SHIFT) + l_procPos); +} + +uint64_t getHomerPhysAddr(const TARGETING::Target * i_pProc) +{ + //If running Sapphire need to place this at the top of memory + uint64_t homerPhysAddrBase = VMM_HOMER_REGION_START_ADDR; + if(TARGETING::is_sapphire_load()) + { + homerPhysAddrBase = TARGETING::get_top_mem_addr(); + assert (homerPhysAddrBase != 0, + "bld_devtree: Top of memory was 0!"); + homerPhysAddrBase -= VMM_ALL_HOMER_OCC_MEMORY_SIZE; + } + + uint8_t tmpPos = i_pProc->getAttr<ATTR_POSITION>(); + uint64_t tmpOffset = tmpPos*VMM_HOMER_INSTANCE_SIZE; + uint64_t targHomer = homerPhysAddrBase + tmpOffset; + + TRACFCOMP( g_trac_devtree, "proc ChipID [%X] HOMER is at %.16X", + getProcChipId(i_pProc), targHomer ); + + return targHomer; +} + + +void bld_xscom_node(devTree * i_dt, dtOffset_t & i_parentNode, + const TARGETING::Target * i_pProc, uint32_t i_chipid) { - errlHndl_t errhdl = NULL; - const char* cpuNodeName = "PowerPC,POWER8"; - const char* cpuIntrName = "interrupt-controller"; const char* xscomNodeName = "xscom"; const char* todNodeName = "chiptod"; const char* pciNodeName = "pbcq"; - const char* lpcNodeName = "lpc"; - const uint32_t THREADPERCORE = 8; - - /* Find the / node and add a cpus node under it. */ - dtOffset_t rootNode = i_dt->findNode("/"); - dtOffset_t cpusNode = i_dt->addNode(rootNode, "cpus"); // Grab a system object to work with TARGETING::Target* sys = NULL; TARGETING::targetService().getTopLevelTarget(sys); + uint64_t l_xscomBaseAddr = sys->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>(); + /**********************************************************/ + /* Xscom node */ + /**********************************************************/ + uint64_t l_xscomAddr = l_xscomBaseAddr + + (static_cast<uint64_t>(i_chipid) << XSCOM_CHIP_SHIFT); + + dtOffset_t xscomNode = i_dt->addNode(i_parentNode, xscomNodeName, + l_xscomAddr); + + i_dt->addPropertyCell32(xscomNode, "#address-cells", 1); + i_dt->addPropertyCell32(xscomNode, "#size-cells", 1); + i_dt->addProperty(xscomNode, "scom-controller"); + const char* xscom_compatStrs[] = {"ibm,xscom","ibm,power8-xscom",NULL}; + i_dt->addPropertyStrings(xscomNode, "compatible", xscom_compatStrs); + + i_dt->addPropertyCell32(xscomNode, "ibm,chip-id", i_chipid); + + uint64_t xscom_prop[2] = { l_xscomAddr, THIRTYTWO_GB}; + i_dt->addPropertyCells64(xscomNode, "reg", xscom_prop, 2); + + /*MVPD -- TODO RTC 88002 add full MVPD here*/ + //i_dt->addPropertyBytes(xscomNode, "ibm,module-vpd", ....); + + /*PSI Host Bridge*/ + uint32_t l_psiInfo = 0x2010900; /*PSI Host Bridge Scom addr*/ + dtOffset_t psiNode = i_dt->addNode(xscomNode, "psihb", l_psiInfo); + const char* psi_compatStrs[] = {"ibm,power8-psihb-x", + "ibm,psihb-x", NULL}; + i_dt->addPropertyStrings(psiNode, "compatible", psi_compatStrs); + uint32_t psi_prop[2] = { l_psiInfo, 0x20 }; //# of scoms in range + i_dt->addPropertyCells32(psiNode, "reg", psi_prop, 2); + i_dt->addPropertyString(psiNode, "status", "ok"); + + /*ChipTod*/ + uint32_t l_todInfo = 0x40000; /*Chip tod Scom addr*/ + dtOffset_t todNode = i_dt->addNode(xscomNode, todNodeName, l_todInfo); + const char* tod_compatStrs[] = {"ibm,power-chiptod", + "ibm,power8-chiptod", NULL}; + i_dt->addPropertyStrings(todNode, "compatible", tod_compatStrs); + uint32_t tod_prop[2] = { l_todInfo, 0x34 }; //# of scoms in range + i_dt->addPropertyCells32(todNode, "reg", tod_prop, 2); + + if(i_chipid == 0x0) //Master chip + { + i_dt->addProperty(todNode, "primary"); //TODO RTC 88002 + + uint32_t l_lpcInfo = 0xB0020; /*ECCB FW addr*/ + dtOffset_t lpcNode = i_dt->addNode(xscomNode,"lpc",l_lpcInfo); + i_dt->addPropertyString(lpcNode, "compatible", "ibm,power8-lpc"); + uint32_t lpc_prop[2] = { l_lpcInfo, 0x4 }; //# of scoms in range + i_dt->addPropertyCells32(lpcNode, "reg", lpc_prop, 2); + i_dt->addPropertyCell32(lpcNode, "#address-cells", 2); + i_dt->addPropertyCell32(lpcNode, "#size-cells", 1); + + } + + /*NX*/ + uint32_t l_nxInfo = 0x2010000; /*NX Scom addr*/ + dtOffset_t nxNode = i_dt->addNode(xscomNode, "nx", l_nxInfo); + const char* nx_compatStrs[] = {"ibm,power-nx", + "ibm,power8-nx", NULL}; + i_dt->addPropertyStrings(nxNode, "compatible", nx_compatStrs); + uint32_t nx_prop[2] = { l_nxInfo, 0x4000 }; //# of scoms in range + i_dt->addPropertyCells32(nxNode, "reg", nx_prop, 2); - /* Add the # address & size cell properties to /cpus. */ - i_dt->addPropertyCell32(cpusNode, "#address-cells", 1); - i_dt->addPropertyCell32(cpusNode, "#size-cells", 0); + /*PCIE*/ + uint8_t l_phbActive = + i_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_PHB_ACTIVE>(); + //TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION_type l_laneEq = + // l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION>(); + uint32_t l_laneEq[] = {0,0,0,0}; + + TRACFCOMP( g_trac_devtree, "Chip %X PHB Active mask %X", + i_chipid, l_phbActive); + + for(uint32_t l_phb =0; l_phb < MAX_PHBs; l_phb++) + { + if(!(l_phbActive & (PHB0_MASK>>l_phb))) + { + continue; + } + + TRACFCOMP( g_trac_devtree, "Adding PHB %d", l_phb); + + /*PHB is active, add to Xscom map*/ + uint32_t l_peInfo = 0x02012000 + (l_phb * 0x400); + uint32_t l_pciInfo = 0x09012000 + (l_phb * 0x400); + uint32_t l_spciInfo = 0x09013c00 + (l_phb * 0x40); + dtOffset_t pcieNode = i_dt->addNode(xscomNode,pciNodeName,l_peInfo); + const char* pcie_compatStrs[] = {"ibm,power8-pbcq", NULL}; + i_dt->addPropertyStrings(pcieNode, "compatible", pcie_compatStrs); + uint32_t pcie_prop[6] = { l_peInfo, 0x20, //# of scoms in range + l_pciInfo, 0x5, //# of scoms in range + l_spciInfo, 0x15}; //# of scoms in range + i_dt->addPropertyCells32(pcieNode, "reg", pcie_prop, 6); + i_dt->addPropertyCell32(pcieNode, "ibm,phb-index", l_phb); + i_dt->addProperty(pcieNode, "ibm,use-ab-detect"); + i_dt->addPropertyCell32(pcieNode, "ibm,lane-eq", l_laneEq[l_phb]); + } +} + +uint32_t bld_l3_node(devTree * i_dt, dtOffset_t & i_parentNode, + uint32_t i_pir) +{ + uint32_t l3Id = i_pir | L3_HDR; + + /* Build L3 Cache information */ + dtOffset_t l3Node = i_dt->addNode(i_parentNode, "l3-cache",l3Id); + i_dt->addPropertyString(l3Node, "device_type", "cache"); + i_dt->addPropertyCell32(l3Node, "reg", l3Id); + i_dt->addProperty(l3Node, "cache-unified"); + i_dt->addPropertyCell32(l3Node, "d-cache-sets", 0x8); + i_dt->addPropertyCell32(l3Node, "i-cache-sets", 0x8); + i_dt->addPropertyCell32(l3Node, "d-cache-size", 0x800000); //8MB + i_dt->addPropertyCell32(l3Node, "i-cache-size", 0x800000); //8MB + i_dt->addPropertyString(l3Node, "status", "okay"); + + return i_dt->getPhandle(l3Node); +} + +uint32_t bld_l2_node(devTree * i_dt, dtOffset_t & i_parentNode, + uint32_t i_pir, uint32_t i_nextCacheHandle) +{ + uint32_t l2Id = i_pir | L2_HDR; + + /* Build l2 Cache information */ + dtOffset_t l2Node = i_dt->addNode(i_parentNode, "l2-cache",l2Id); + i_dt->addPropertyString(l2Node, "device_type", "cache"); + i_dt->addPropertyCell32(l2Node, "reg", l2Id); + i_dt->addProperty(l2Node, "cache-unified"); + i_dt->addPropertyCell32(l2Node, "d-cache-sets", 0x8); + i_dt->addPropertyCell32(l2Node, "i-cache-sets", 0x8); + i_dt->addPropertyCell32(l2Node, "d-cache-size", 0x80000); //512KB + i_dt->addPropertyCell32(l2Node, "i-cache-size", 0x80000); //512KB + i_dt->addPropertyString(l2Node, "status", "okay"); + i_dt->addPropertyCell32(l2Node, "next-level-cache", i_nextCacheHandle); + + + return i_dt->getPhandle(l2Node); +} + +uint32_t bld_cpu_node(devTree * i_dt, dtOffset_t & i_parentNode, + const TARGETING::Target * i_ex, + INTR::PIR_t i_pir, uint32_t i_chipId, + uint32_t i_nextCacheHandle) +{ + /* + * The following node must exist for each *core* in the system. The unit + * address (number after the @) is the hexadecimal HW CPU number (PIR value) + * of thread 0 of that core. + */ + + uint32_t paFeatures[8] = { 0x6, 0x0, 0xf6, 0x3f, 0xc7, 0x0, 0x80, 0xc0 }; + uint32_t pageSizes[4] = { 0xc, 0x10, 0x18, 0x22 }; uint32_t segmentSizes[4] = { 0x1c, 0x28, 0xffffffff, 0xffffffff }; uint32_t segmentPageSizes[] = { @@ -110,87 +301,205 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt) }; - // Get all functional proc chip targets - TARGETING::TargetHandleList l_cpuTargetList; - getAllChips(l_cpuTargetList, TYPE_PROC); + dtOffset_t cpuNode = i_dt->addNode(i_parentNode, "PowerPC,POWER8", + i_pir.word); + i_dt->addPropertyString(cpuNode, "device_type", "cpu"); + i_dt->addProperty(cpuNode, "64-bit"); + i_dt->addProperty(cpuNode, "32-64-bridge"); + i_dt->addProperty(cpuNode, "graphics"); + i_dt->addProperty(cpuNode, "general-purpose"); + i_dt->addPropertyString(cpuNode, "status", "okay"); + i_dt->addPropertyCell32(cpuNode, "reg", i_pir.word); + i_dt->addPropertyCell32(cpuNode, "ibm,pir", i_pir.word); + i_dt->addPropertyCell32(cpuNode, "ibm,chip-id", i_chipId); + + uint32_t interruptServerNum[THREADPERCORE]; + for(size_t i = 0; i < THREADPERCORE ; i++) + { + i_pir.threadId = i; + interruptServerNum[i] = i_pir.word; + } + i_dt->addPropertyCells32(cpuNode, "ibm,ppc-interrupt-server#s", + interruptServerNum, THREADPERCORE); + + /* This is the "architected processor version" as defined in PAPR. Just + * stick to 0x0f000004 for P8 and things will be fine */ + i_dt->addPropertyCell32(cpuNode, "cpu-version", 0x0f000004); + + i_dt->addPropertyCells32(cpuNode, "ibm,processor-segment-sizes", + segmentSizes, + sizeof(segmentSizes) / sizeof(uint32_t)); + i_dt->addPropertyCells32(cpuNode, "ibm,processor-page-sizes", + pageSizes, + sizeof(pageSizes) / sizeof(uint32_t)); + i_dt->addPropertyCells32(cpuNode, "ibm,segment-page-sizes", + segmentPageSizes, + sizeof(segmentPageSizes)/sizeof(uint32_t)); + i_dt->addPropertyCells32(cpuNode, "ibm,pa-features", + paFeatures, + sizeof(paFeatures)/sizeof(uint32_t)); + + i_dt->addPropertyCell32(cpuNode, "ibm,slb-size", 32); + i_dt->addPropertyCell32(cpuNode, "ibm,dfp", 1); + i_dt->addPropertyCell32(cpuNode, "ibm,vmx", 2); + i_dt->addPropertyCell32(cpuNode, "ibm,purr", 1); + i_dt->addPropertyCell32(cpuNode, "ibm,spurr", 1); + + //TODO RTC88002 -- move this to nominal once HB has nominal freq + TARGETING::Target* sys = NULL; + TARGETING::targetService().getTopLevelTarget(sys); + uint64_t freq = sys->getAttr<TARGETING::ATTR_BOOT_FREQ_MHZ>(); + freq *= MHZ; - for ( size_t proc = 0; (!errhdl) && (proc < l_cpuTargetList.size()); proc++) + uint32_t ex_freq[2] = {static_cast<uint32_t>(freq >> 32), + static_cast<uint32_t>(freq & 0xFFFFFFFF)}; + if(ex_freq[0] == 0) //Only create if fits into 32 bits { - const TARGETING::Target * l_pProc = l_cpuTargetList[proc]; + i_dt->addPropertyCell32(cpuNode, "clock-frequency", ex_freq[1]); + } + i_dt->addPropertyCells32(cpuNode, "ibm,extended-clock-frequency", + ex_freq, 2); + + uint32_t timebase_freq[2] = {0, 512000000}; + i_dt->addPropertyCell32(cpuNode, "timebase-frequency", timebase_freq[1]); + i_dt->addPropertyCells32(cpuNode, "ibm,extended-timebase-frequency", + timebase_freq, 2); + + + i_dt->addPropertyCell32(cpuNode, "reservation-granule-size", 0x80); + i_dt->addPropertyCell32(cpuNode, "d-tlb-size", 0x800); + i_dt->addPropertyCell32(cpuNode, "i-tlb-size", 0x0); + i_dt->addPropertyCell32(cpuNode, "tlb-size", 0x800); + i_dt->addPropertyCell32(cpuNode, "d-tlb-sets", 0x4); + i_dt->addPropertyCell32(cpuNode, "i-tlb-sets", 0x0); + i_dt->addPropertyCell32(cpuNode, "tlb-sets", 0x4); + i_dt->addPropertyCell32(cpuNode, "d-cache-block-size", 0x80); + i_dt->addPropertyCell32(cpuNode, "i-cache-block-size", 0x80); + i_dt->addPropertyCell32(cpuNode, "d-cache-size", 0x10000); + i_dt->addPropertyCell32(cpuNode, "i-cache-size", 0x8000); + i_dt->addPropertyCell32(cpuNode, "i-cache-sets", 0x4); + i_dt->addPropertyCell32(cpuNode, "d-cache-sets", 0x8); + i_dt->addPropertyCell64(cpuNode, "performance-monitor", 0x1); + i_dt->addPropertyCell32(cpuNode, "next-level-cache", i_nextCacheHandle); + + return i_dt->getPhandle(cpuNode); +} - uint32_t l_fabId = l_pProc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); - uint32_t l_procPos = l_pProc->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); - uint32_t l_chipid = (l_fabId << CHIPID_NODE_SHIFT) + l_procPos; +uint32_t bld_intr_node(devTree * i_dt, dtOffset_t & i_parentNode, + const TARGETING::Target * i_ex, + INTR::PIR_t i_pir) - /* Find calculate the Xscom addr for this chip and add it */ - uint64_t l_xscomAddr = l_xscomBaseAddr + - (static_cast<uint64_t>(l_chipid) << XSCOM_CHIP_SHIFT); +{ + /* + * Interrupt presentation controller (ICP) nodes + * + * There is some flexibility as to how many of these are presents since + * a given node can represent multiple ICPs. When generating from HDAT we + * chose to create one per core + */ + + uint64_t l_ibase = INTR::getIntpAddr(i_ex, 0); //IBASE ADDRESS + + dtOffset_t intNode = i_dt->addNode(i_parentNode, "interrupt-controller", + l_ibase); + + const char* intr_compatStrs[] = {"ibm,ppc-xicp", "ibm,power8-xicp",NULL}; + i_dt->addPropertyStrings(intNode, "compatible", intr_compatStrs); + i_dt->addProperty(intNode,"interrupt-controller"); + i_dt->addPropertyCell32(intNode, "#address-cells", 0); + i_dt->addPropertyCell32(intNode, "#interrupt-cells", 1); + i_dt->addPropertyString(intNode, "device_type", + "PowerPC-External-Interrupt-Presentation"); + + uint32_t int_serv[2] = { i_pir.word, THREADPERCORE}; + i_dt->addPropertyCells32(intNode, "ibm,interrupt-server-ranges", + int_serv, 2); + + uint64_t intr_prop[THREADPERCORE][2]; + for(size_t i=0; i < THREADPERCORE; i++) + { + intr_prop[i][0] = INTR::getIntpAddr(i_ex, i); + intr_prop[i][1] = 0x1000; + } + i_dt->addPropertyCells64(intNode, "reg", + reinterpret_cast<uint64_t*>(intr_prop), + sizeof(intr_prop) / sizeof(uint64_t)); - dtOffset_t xscomNode = i_dt->addNode(rootNode, xscomNodeName, - l_xscomAddr); + return i_dt->getPhandle(intNode); +} - uint64_t xscom_prop[2] = { l_xscomAddr, THIRTYTWO_GB}; - i_dt->addPropertyCells64(xscomNode, "reg", xscom_prop, 2); - const char* xscom_compatStrs[] = {"ibm,xscom","ibm,power8-xscom",NULL}; - i_dt->addPropertyCell32(xscomNode, "#address-cells", 1); - i_dt->addPropertyCell32(xscomNode, "#size-cells", 1); - i_dt->addPropertyCell32(xscomNode, "ibm,chip-id", l_chipid); - i_dt->addPropertyStrings(xscomNode, "compatible", xscom_compatStrs); +void add_reserved_mem(devTree * i_dt, uint64_t i_homerAddr[], size_t i_num) +{ + /* + * The reserved-names and reserve-names properties work hand in hand. + * The first one is a list of strings providing a "name" for each entry + * in the second one using the traditional "vendor,name" format. + * + * The reserved-ranges property contains a list of ranges, each in the + * form of 2 cells of address and 2 cells of size (64-bit x2 so each + * entry is 4 cells) indicating regions of memory that are reserved + * and must not be overwritten by skiboot or subsequently by the Linux + * Kernel. + * + * Corresponding entries must also be created in the "reserved map" part + * of the flat device-tree (which is a binary list in the header of the + * fdt). + * + * Unless a component (skiboot or Linux) specifically knows about a region + * (usually based on its name) and decides to change or remove it, all + * these regions are passed as-is to Linux and to subsequent kernels + * accross kexec and are kept preserved. + */ + dtOffset_t rootNode = i_dt->findNode("/"); - /*ChipTod*/ - uint32_t l_todInfo = 0x40000; /*Chip tod Scom addr*/ - dtOffset_t todNode = i_dt->addNode(xscomNode, todNodeName, l_todInfo); - const char* tod_compatStrs[] = {"ibm,power-chiptod", - "ibm,power8-chiptod", NULL}; - i_dt->addPropertyStrings(todNode, "compatible", tod_compatStrs); - uint32_t tod_prop[2] = { l_todInfo, 0x34 }; //# of scoms in range - i_dt->addPropertyCells32(todNode, "reg", tod_prop, 2); + const char* homerStr = "ibm,slw-occ-image"; + const char* reserve_strs[i_num+1]; + uint64_t homerRanges[i_num][2]; + for(size_t i = 0; i<i_num; i++) + { + reserve_strs[i] = homerStr; + homerRanges[i][0] = i_homerAddr[i]; + homerRanges[i][1] = VMM_HOMER_INSTANCE_SIZE; + } - if(l_chipid == 0x0) //Master chip - { - i_dt->addProperty(todNode, "primary"); //TODO -- get from ATTR + reserve_strs[i_num] = NULL; - uint32_t l_lpcInfo = 0xB0020; /*ECCB FW addr*/ - dtOffset_t lpcNode = i_dt->addNode(xscomNode,lpcNodeName,l_lpcInfo); - i_dt->addPropertyString(lpcNode, "compatible", "ibm,power8-lpc"); - uint32_t lpc_prop[2] = { l_lpcInfo, 0x4 }; //# of scoms in range - i_dt->addPropertyCells32(lpcNode, "reg", lpc_prop, 2); - } + i_dt->addPropertyStrings(rootNode, "reserved-names", reserve_strs); + i_dt->addPropertyCells64(rootNode, "reserved-ranges", + reinterpret_cast<uint64_t*>(homerRanges), + sizeof(homerRanges) / sizeof(uint64_t)); +} - /*PCIE*/ - uint8_t l_phbActive = - l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_PHB_ACTIVE>(); - //TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION_type l_laneEq = - // l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION>(); - uint32_t l_laneEq[] = {0,0,0,0}; - TRACFCOMP( g_trac_devtree, "Chip %X PHB Active mask %X", - l_chipid, l_phbActive); +errlHndl_t bld_fdt_cpu(devTree * i_dt) +{ + errlHndl_t errhdl = NULL; - for(uint32_t l_phb =0; l_phb < MAX_PHBs; l_phb++) - { - if(!(l_phbActive & (PHB0_MASK>>l_phb))) - { - continue; - } + /* Find the / node and add a cpus node under it. */ + dtOffset_t rootNode = i_dt->findNode("/"); + dtOffset_t cpusNode = i_dt->addNode(rootNode, "cpus"); - TRACFCOMP( g_trac_devtree, "Adding PHB %d", l_phb); - - /*PHB is active, add to Xscom map*/ - uint32_t l_peInfo = 0x02012000 + (l_phb * 0x400); - uint32_t l_pciInfo = 0x09012000 + (l_phb * 0x400); - uint32_t l_spciInfo = 0x09013c00 + (l_phb * 0x40); - dtOffset_t pcieNode = i_dt->addNode(xscomNode,pciNodeName,l_peInfo); - const char* pcie_compatStrs[] = {"ibm,power8-pbcq", NULL}; - i_dt->addPropertyStrings(pcieNode, "compatible", pcie_compatStrs); - uint32_t pcie_prop[6] = { l_peInfo, 0x20, //# of scoms in range - l_pciInfo, 0x5, //# of scoms in range - l_spciInfo, 0x15}; //# of scoms in range - i_dt->addPropertyCells32(pcieNode, "reg", pcie_prop, 6); - i_dt->addPropertyCell32(pcieNode, "ibm,phb-index", l_phb); - i_dt->addPropertyCell32(pcieNode, "ibm,lane-eq", l_laneEq[l_phb]); - } + /* Add the # address & size cell properties to /cpus. */ + i_dt->addPropertyCell32(cpusNode, "#address-cells", 1); + i_dt->addPropertyCell32(cpusNode, "#size-cells", 0); + + // Get all functional proc chip targets + TARGETING::TargetHandleList l_cpuTargetList; + getAllChips(l_cpuTargetList, TYPE_PROC); + uint64_t l_homerAddr[l_cpuTargetList.size()]; + + for ( size_t proc = 0; (!errhdl) && (proc < l_cpuTargetList.size()); proc++) + { + const TARGETING::Target * l_pProc = l_cpuTargetList[proc]; + + uint32_t l_chipid = getProcChipId(l_pProc); + + bld_xscom_node(i_dt, rootNode, l_pProc, l_chipid); + + //Each processor will have a HOMER image that needs + //to be reserved -- save it away + l_homerAddr[proc] = getHomerPhysAddr(l_pProc); TARGETING::TargetHandleList l_exlist; getChildChiplets( l_exlist, l_pProc, TYPE_CORE ); @@ -202,12 +511,6 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt) continue; //Not functional } - /* TODO -- need to add cache info */ - - /* Add a dev node for each cpu core. The unit address is the - *interrupt server number of the first thread of the core. - */ - /* Proc ID Reg is N NNCC CPPP PTTT Where NNN is node number CCC is Chip @@ -216,76 +519,28 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt) */ uint32_t l_coreNum = l_ex->getAttr<TARGETING::ATTR_CHIP_UNIT>(); INTR::PIR_t pir(0); - pir.nodeId = l_fabId; - pir.chipId = l_procPos; + pir.nodeId = CHIPID_EXTRACT_NODE(l_chipid); + pir.chipId = CHIPID_EXTRACT_PROC(l_chipid); pir.coreId = l_coreNum; - TRACFCOMP( g_trac_devtree, "Added pir[%x] node %d proc %d core %d", - pir.word, l_fabId, l_procPos, l_coreNum ); + TRACFCOMP( g_trac_devtree, "Added pir[%x] chipid 0x%x core %d", + pir.word, l_chipid, l_coreNum ); cpusNode = i_dt->findNode("/cpus"); - dtOffset_t cpuNode = i_dt->addNode(cpusNode, cpuNodeName, - pir.word); - i_dt->addPropertyString(cpuNode, "device_type", "cpu"); - i_dt->addPropertyString(cpuNode, "status", "okay"); - i_dt->addPropertyCell32(cpuNode, "reg", pir.word); - i_dt->addPropertyCell32(cpuNode, "d-cache-size", 0x10000); - i_dt->addPropertyCell32(cpuNode, "i-cache-size", 0x8000); - i_dt->addPropertyCell32(cpuNode, "d-cache-line-size", 128); - i_dt->addPropertyCell32(cpuNode, "i-cache-line-size", 128); - i_dt->addPropertyCell32(cpuNode, "ibm,dfp", 1); - i_dt->addPropertyCell32(cpuNode, "ibm,vmx", 2); - i_dt->addPropertyCell32(cpuNode, "timebase-frequency", 512000000); - i_dt->addPropertyCell32(cpuNode, "clock-frequency", 2000000000); - i_dt->addPropertyCell32(cpuNode, "ibm,pir", pir.word); - i_dt->addPropertyCell32(cpuNode, "ibm,chip-id", l_chipid); - i_dt->addPropertyCells32(cpuNode, "ibm,processor-segment-sizes", - segmentSizes, - sizeof(segmentSizes) / sizeof(uint32_t)); - i_dt->addPropertyCells32(cpuNode, "ibm,segment-page-sizes", - segmentPageSizes, - sizeof(segmentPageSizes)/sizeof(uint32_t)); - i_dt->addPropertyCell32(cpuNode, "ibm,slb-size", 32); - - uint32_t interruptServerNum[THREADPERCORE]; - for(size_t i = 0; i < THREADPERCORE ; i++) - { - pir.threadId = i; - interruptServerNum[i] = pir.word; - } - i_dt->addPropertyCells32(cpuNode, "ibm,ppc-interrupt-server#s", - interruptServerNum, THREADPERCORE); - - //IBASE ADDRESS - uint64_t l_ibase = INTR::getIntpAddr(l_ex, 0); + uint32_t l3pHandle = bld_l3_node(i_dt, cpusNode, pir.word); + uint32_t l2pHandle = bld_l2_node(i_dt, cpusNode, pir.word, + l3pHandle); + bld_cpu_node(i_dt, cpusNode, l_ex, pir, l_chipid, l2pHandle); rootNode = i_dt->findNode("/"); - dtOffset_t intNode = i_dt->addNode(rootNode, cpuIntrName, l_ibase); - const char* intr_compatStrs[] = {"ibm,ppc-xicp", "ibm,power8-xicp", - NULL}; - i_dt->addPropertyStrings(intNode, "compatible", intr_compatStrs); - uint32_t int_serv[2] = { interruptServerNum[0], THREADPERCORE}; - i_dt->addPropertyCells32(intNode, "ibm,interrupt-server-ranges", - int_serv, 2); - i_dt->addPropertyCell32(intNode, "#address-cells", 0); - i_dt->addPropertyCell32(intNode, "#interrupt-cells", 1); - i_dt->addPropertyString(intNode, "device_type", - "PowerPC-External-Interrupt-Presentation"); - uint64_t intr_prop[THREADPERCORE][2]; - for(size_t i=0; i < THREADPERCORE; i++) - { - intr_prop[i][0] = INTR::getIntpAddr(l_ex, i); - intr_prop[i][1] = 0x1000; - } - i_dt->addPropertyCells64(intNode, "reg", - reinterpret_cast<uint64_t*>(intr_prop), - sizeof(intr_prop) / sizeof(uint64_t)); - - /* TODO add associativity*/ + bld_intr_node(i_dt, rootNode, l_ex, pir); } } + //Add in reserved memory for HOMER images + add_reserved_mem(i_dt, l_homerAddr, l_cpuTargetList.size()); + return errhdl; } @@ -294,9 +549,24 @@ errlHndl_t bld_fdt_mem(devTree * i_dt) errlHndl_t errhdl = NULL; bool rc; + /* + * The "memory" nodes represent physical memory in the system. They + * do not represent DIMMs, memory controllers or Centaurs, thus will + * be expressed separately. + * + * In order to be able to handle affinity propertly, we require that + * a memory node is created for each range of memory that has a different + * "affinity", which in practice means for each chip since we don't + * support memory interleaved accross multiple chips on P8. + * + * Additionally, it is *not* required that one chip = one memory node, + * it is perfectly acceptable to break down the memory of one chip into + * multiple memory nodes (typically skiboot does that if the two MCs + * are not interlaved). + */ + do { - /* Find the / node and add a memory node(s) under it. */ dtOffset_t rootNode = i_dt->findNode("/"); @@ -363,9 +633,10 @@ errlHndl_t bld_fdt_mem(devTree * i_dt) uint64_t propertyCells[2] = {l_bases[i],l_sizes[i]}; i_dt->addPropertyCells64(memNode, "reg", propertyCells, 2); - /*TODO -- add core affinity*/ + //Add the attached proc chip for affinity + i_dt->addPropertyCell32(memNode, "ibm,chip-id", + getProcChipId(l_pProc)); - /*TODO -- add VPD*/ } } } @@ -373,15 +644,6 @@ errlHndl_t bld_fdt_mem(devTree * i_dt) return errhdl; } -errlHndl_t bld_fdt_io(devTree * i_dt) -{ - errlHndl_t errhdl = NULL; - - - - return errhdl; -} - errlHndl_t build_flatdevtree( void ) { errlHndl_t errhdl = NULL; @@ -407,12 +669,6 @@ errlHndl_t build_flatdevtree( void ) break; } - TRACFCOMP( g_trac_devtree, "---devtree io ---" ); - errhdl = bld_fdt_io(dt); - if(errhdl) - { - break; - } }while(0); return errhdl; |