summaryrefslogtreecommitdiffstats
path: root/src/usr/devtree/bld_devtree.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/devtree/bld_devtree.C')
-rw-r--r--src/usr/devtree/bld_devtree.C586
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;
OpenPOWER on IntegriCloud