/* Copyright 2013-2019 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #define P8_PBA_BAR0 0x2013f00 #define P8_PBA_BARMASK0 0x2013f04 #define P9_PBA_BAR0 0x5012B00 #define P9_PBA_BARMASK0 0x5012B04 #define PBA_MASK_ALL_BITS 0x000001FFFFF00000ULL /* Bits 23:43 */ enum P8_BAR { P8_BAR_HOMER = 0, P8_BAR_CENTAUR = 1, P8_BAR_SLW = 2, P8_BAR_OCC_COMMON = 3, }; enum P9_BAR { P9_BAR_HOMER = 0, P9_BAR_CENTAUR = 1, P9_BAR_OCC_COMMON = 2, P9_BAR_SBE = 3, }; static u64 pba_bar0, pba_barmask0; static u8 bar_homer, bar_slw, bar_occ_common; static bool read_pba_bar(struct proc_chip *chip, unsigned int bar_no, uint64_t *base, uint64_t *size) { uint64_t bar, mask; int rc; rc = xscom_read(chip->id, pba_bar0 + bar_no, &bar); if (rc) { prerror("SLW: Error %d reading PBA BAR%d on chip %d\n", rc, bar_no, chip->id); return false; } rc = xscom_read(chip->id, pba_barmask0 + bar_no, &mask); if (rc) { prerror("SLW: Error %d reading PBA BAR MASK%d on chip %d\n", rc, bar_no, chip->id); return false; } prlog(PR_DEBUG, " PBA BAR%d : 0x%016llx\n", bar_no, bar); prlog(PR_DEBUG, " PBA MASK%d: 0x%016llx\n", bar_no, mask); if (mask == PBA_MASK_ALL_BITS) { /* * This could happen if all HOMER users are not enabled during * early system bringup. Skip using the PBA BAR. */ mask = 0; bar = 0; prerror(" PBA MASK%d uninitalized skipping BAR\n", bar_no); } *base = bar & 0x0ffffffffffffffful; *size = (mask | 0xfffff) + 1; return (*base) != 0; } static void homer_init_chip(struct proc_chip *chip) { uint64_t hbase = 0, hsize = 0; uint64_t sbase, ssize, obase, osize; /* * PBA BARs assigned by HB: * * P8: * 0 : Entire HOMER * 1 : OCC to Centaur path (we don't care) * 2 : SLW image * 3 : OCC Common area * * We need to reserve the memory covered by BAR 0 and BAR 3, however * on earlier HBs, BAR0 isn't set so we need BAR 2 instead in that * case to cover SLW (OCC not running). * * P9: * 0 : Entire HOMER * 1 : OCC to Centaur path (Cumulus only) * 2 : OCC Common area * 3 : SBE communication * */ if (read_pba_bar(chip, bar_homer, &hbase, &hsize)) { prlog(PR_DEBUG, " HOMER Image at 0x%llx size %lldMB\n", hbase, hsize / 0x100000); if (!mem_range_is_reserved(hbase, hsize)) { prlog(PR_WARNING, "HOMER image is not reserved! Reserving\n"); mem_reserve_fw("ibm,homer-image", hbase, hsize); } chip->homer_base = hbase; chip->homer_size = hsize; } /* * We always read the SLW BAR since we need to grab info about the * SLW image in the struct proc_chip for use by the slw.c code */ if (proc_gen == proc_gen_p8 && read_pba_bar(chip, bar_slw, &sbase, &ssize)) { prlog(PR_DEBUG, " SLW Image at 0x%llx size %lldMB\n", sbase, ssize / 0x100000); /* * Only reserve it if we have no homer image or if it * doesn't fit in it (only check the base). */ if ((sbase < hbase || sbase > (hbase + hsize) || (hbase == 0 && sbase > 0)) && !mem_range_is_reserved(sbase, ssize)) { prlog(PR_WARNING, "SLW image is not reserved! Reserving\n"); mem_reserve_fw("ibm,slw-image", sbase, ssize); } chip->slw_base = sbase; chip->slw_bar_size = ssize; chip->slw_image_size = ssize; /* will be adjusted later */ } if (read_pba_bar(chip, bar_occ_common, &obase, &osize)) { prlog(PR_DEBUG, " OCC Common Area at 0x%llx size %lldMB\n", obase, osize / 0x100000); chip->occ_common_base = obase; chip->occ_common_size = osize; } } void homer_init(void) { struct proc_chip *chip; if (chip_quirk(QUIRK_NO_PBA)) return; switch (proc_gen) { case proc_gen_p8: pba_bar0 = P8_PBA_BAR0; pba_barmask0 = P8_PBA_BARMASK0; bar_homer = P8_BAR_HOMER; bar_slw = P8_BAR_SLW; bar_occ_common = P8_BAR_OCC_COMMON; break; case proc_gen_p9: pba_bar0 = P9_PBA_BAR0; pba_barmask0 = P9_PBA_BARMASK0; bar_homer = P9_BAR_HOMER; bar_occ_common = P9_BAR_OCC_COMMON; break; default: return; }; /* * XXX This is temporary, on P8 we look for any configured * SLW/OCC BAR and reserve the memory. Eventually, this will be * done via HostBoot using the device-tree "reserved-ranges" * or we'll load the SLW & OCC images ourselves using Host Services. */ for_each_chip(chip) { prlog(PR_DEBUG, "HOMER: Init chip %d\n", chip->id); homer_init_chip(chip); } /* * Check is PBA BARs are already loaded with HOMER and * skip host services. */ chip = next_chip(NULL); /* Both HOMER images and OCC areas are setup */ if (chip->homer_base && chip->occ_common_base) { /* Reserve OCC common area from BAR */ if (!mem_range_is_reserved(chip->occ_common_base, chip->occ_common_size)) { prlog(PR_WARNING, "OCC common area is not reserved! Reserving\n"); mem_reserve_fw("ibm,occ-common-area", chip->occ_common_base, chip->occ_common_size); } } else if (chip->homer_base) { /* * HOMER is setup but not OCC!! Do not allocate HOMER * regions. This case is possible during early system * bringup where OCC images are not yet operational. */ } else { /* Allocate memory for HOMER and OCC common area */ host_services_occ_base_setup(); } }