diff options
Diffstat (limited to 'hdata/fsp.c')
-rw-r--r-- | hdata/fsp.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/hdata/fsp.c b/hdata/fsp.c new file mode 100644 index 0000000..cf6bc96 --- /dev/null +++ b/hdata/fsp.c @@ -0,0 +1,200 @@ +/* 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 <device.h> +#include "spira.h" +#include <cpu.h> +#include <memory.h> +#include <vpd.h> +#include <ccan/str/str.h> +#include <device_tree.h> +#include <interrupts.h> + +#include "hdata.h" + +static struct dt_node *fsp_create_node(const void *spss, int i, + struct dt_node *parent) +{ + const struct spss_sp_impl *sp_impl; + struct dt_node *node; + unsigned int mask; + + /* Find an check the SP Implementation structure */ + sp_impl = HDIF_get_idata(spss, SPSS_IDATA_SP_IMPL, NULL); + if (!CHECK_SPPTR(sp_impl)) { + prerror("FSP #%d: SPSS/SP_Implementation not found !\n", i); + return NULL; + } + + printf("FSP #%d: FSP HW version %d, SW version %d, chip DD%d.%d\n", + i, sp_impl->hw_version, sp_impl->sw_version, + sp_impl->chip_version >> 4, sp_impl->chip_version & 0xf); + mask = SPSS_SP_IMPL_FLAGS_INSTALLED | SPSS_SP_IMPL_FLAGS_FUNCTIONAL; + if ((be16_to_cpu(sp_impl->func_flags) & mask) != mask) { + prerror("FSP #%d: FSP not installed or not functional\n", i); + return NULL; + } + + node = dt_new_addr(parent, "fsp", i); + assert(node); + dt_add_property_cells(node, "reg", i); + + if (sp_impl->hw_version == 1) { + dt_add_property_strings(node, "compatible", "ibm,fsp", + "ibm,fsp1"); + /* Offset into the FSP MMIO space where the mailbox + * registers are */ + /* seen in the FSP1 spec */ + dt_add_property_cells(node, "reg-offset", 0xb0016000); + } else if (sp_impl->hw_version == 2) { + dt_add_property_strings(node, "compatible", "ibm,fsp", + "ibm,fsp2"); + dt_add_property_cells(node, "reg-offset", 0xb0011000); + } + dt_add_property_cells(node, "hw-version", sp_impl->hw_version); + dt_add_property_cells(node, "sw-version", sp_impl->sw_version); + + if (be16_to_cpu(sp_impl->func_flags) & SPSS_SP_IMPL_FLAGS_PRIMARY) + dt_add_property(node, "primary", NULL, 0); + + return node; +} + +static uint32_t fsp_create_link(const struct spss_iopath *iopath, int index, + int fsp_index) +{ + struct dt_node *node; + const char *ststr; + bool current = false; + bool working = false; + uint32_t chip_id; + + switch(iopath->psi.link_status) { + case SPSS_IO_PATH_PSI_LINK_BAD_FRU: + ststr = "Broken"; + break; + case SPSS_IO_PATH_PSI_LINK_CURRENT: + ststr = "Active"; + current = working = true; + break; + case SPSS_IO_PATH_PSI_LINK_BACKUP: + ststr = "Backup"; + working = true; + break; + default: + ststr = "Unknown"; + } + printf("FSP #%d: IO PATH %d is %s PSI Link, GXHB at %llx\n", + fsp_index, index, ststr, (long long)iopath->psi.gxhb_base); + + chip_id = pcid_to_chip_id(iopath->psi.proc_chip_id); + node = dt_find_compatible_node_on_chip(dt_root, NULL, "ibm,psihb-x", + chip_id); + if (!node) { + prerror("FSP #%d: Can't find psihb node for link %d\n", + fsp_index, index); + } else { + if (current) + dt_add_property(node, "boot-link", NULL, 0); + dt_add_property_strings(node, "status", working ? "ok" : "bad"); + } + + return chip_id; +} + +static void fsp_create_links(const void *spss, int index, + struct dt_node *fsp_node) +{ + uint32_t *links = NULL; + unsigned int i, lp, lcount = 0; + int count; + + count = HDIF_get_iarray_size(spss, SPSS_IDATA_SP_IOPATH); + if (count < 0) { + prerror("FSP #%d: Can't find IO PATH array size !\n", index); + return; + } + printf("FSP #%d: Found %d IO PATH\n", index, count); + + /* Iterate all links */ + for (i = 0; i < count; i++) { + const struct spss_iopath *iopath; + unsigned int iopath_sz; + uint32_t chip; + + iopath = HDIF_get_iarray_item(spss, SPSS_IDATA_SP_IOPATH, + i, &iopath_sz); + if (!CHECK_SPPTR(iopath)) { + prerror("FSP #%d: Can't find IO PATH %d\n", index, i); + break; + } + if (iopath->iopath_type != SPSS_IOPATH_TYPE_PSI) { + prerror("FSP #%d: Unsupported IO PATH %d type 0x%04x\n", + index, i, iopath->iopath_type); + continue; + } + + chip = fsp_create_link(iopath, i, index); + lp = lcount++; + links = realloc(links, 4 * lcount); + links[lp] = chip; + } + if (links) + dt_add_property(fsp_node, "ibm,psi-links", links, lcount * 4); +} + +void fsp_parse(void) +{ + const void *base_spss, *spss; + struct dt_node *fsp_root, *fsp_node; + int i; + + /* + * Note on DT representation of the PSI links and FSPs: + * + * We create a XSCOM node for each PSI host bridge(one per chip), + * + * This is done in spira.c + * + * We do not create the /psi MMIO variant at this stage, it will + * be added by the psi driver in skiboot. + * + * We do not put the FSP(s) as children of these. Instead, we create + * a top-level /fsps node with the FSPs as children. + * + * Each FSP then has a "links" property which is an array of chip IDs + */ + + /* Find SPSS in SPIRA */ + base_spss = get_hdif(&spira.ntuples.sp_subsys, SPSS_HDIF_SIG); + if (!base_spss) { + printf("FSP: No SPSS in SPIRA !\n"); + return; + } + + fsp_root = dt_new(dt_root, "fsps"); + assert(fsp_root); + dt_add_property_cells(fsp_root, "#address-cells", 1); + dt_add_property_cells(fsp_root, "#size-cells", 0); + + /* Iterate FSPs in SPIRA */ + for_each_ntuple_idx(&spira.ntuples.sp_subsys, spss, i, SPSS_HDIF_SIG) { + fsp_node = fsp_create_node(spss, i, fsp_root); + if (fsp_node) + fsp_create_links(spss, i, fsp_node); + } +} + |