blob: a0a0733eb806e8414200e60309cc579563fc8bdf [file] [log] [blame]
/* Copyright 2013-2014 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 <skiboot.h>
#include <xscom.h>
#include <io.h>
#include <cpu.h>
#include <chip.h>
#include <mem_region.h>
#include <hostservices.h>
#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,
};
u64 pba_bar0, pba_barmask0;
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();
}
}