[Skiboot] [PATCH 4/4] capi: Load capp microcode for phb4
Andrew Donnellan
andrew.donnellan at au1.ibm.com
Thu Mar 2 16:44:37 AEDT 2017
On 10/02/17 20:04, Christophe Lombard wrote:
> CAPP microcode flash download and CAPP upload for PHB4.
> A new file 'capp.c' is created to receive common capp code for PHB3 and
> PHB4.
>
> Signed-off-by: Christophe Lombard <clombard at linux.vnet.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan at au1.ibm.com>
Comments below
> --- /dev/null
> +++ b/hw/capp.c
> @@ -0,0 +1,235 @@
> +/* Copyright 2013-2017 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 <io.h>
> +#include <opal.h>
> +#include <chip.h>
> +#include <xscom.h>
> +#include <capp.h>
> +
> +#define PHBERR(opal_id, chip_id, index, fmt, a...) \
> + prlog(PR_ERR, "PHB#%04x[%d:%d]: " fmt, \
> + opal_id, chip_id, \
> + index, ## a)
> +
> +static struct {
> + uint32_t ec_level;
> + struct capp_lid_hdr *lid;
> + size_t size;
> + int load_result;
> +} capp_ucode_info = { 0, NULL, 0, false };
> +
> +#define CAPP_UCODE_MAX_SIZE 0x20000
> +
> +bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index)
> +{
> + return (chip->capp_ucode_loaded & (1 << index));
> +}
> +
> +int preload_capp_ucode(void)
> +{
> + struct dt_node *p;
> + struct proc_chip *chip;
> + uint32_t index;
> + uint64_t rc;
> + int ret;
> +
> + p = dt_find_compatible_node(dt_root, NULL, "ibm,power8-pbcq");
> +
> + if (!p) {
> + p = dt_find_compatible_node(dt_root, NULL, "ibm,power9-pbcq");
> + if (!p) {
> + printf("CAPI: WARNING: no compat thing found\n");
Could take this opportunity to move away from printf to an appropriate
pr* macro? Also the message has always been a bit dumb... though that
could be a separate patch I guess
> + return OPAL_SUCCESS;
> + }
> + }
> +
> + chip = get_chip(dt_get_chip_id(p));
> +
> + rc = xscom_read_cfam_chipid(chip->id, &index);
> + if (rc) {
> + prerror("CAPP: Error reading cfam chip-id\n");
> + ret = OPAL_HARDWARE;
> + return ret;
> + }
> + /* Keep ChipID and Major/Minor EC. Mask out the Location Code. */
> + index = index & 0xf0fff;
> +
> + /* Assert that we're preloading */
> + assert(capp_ucode_info.lid == NULL);
> + capp_ucode_info.load_result = OPAL_EMPTY;
> +
> + capp_ucode_info.ec_level = index;
> +
> + /* Is the ucode preloaded like for BML? */
> + if (dt_has_node_property(p, "ibm,capp-ucode", NULL)) {
> + capp_ucode_info.lid = (struct capp_lid_hdr *)(u64)
> + dt_prop_get_u32(p, "ibm,capp-ucode");
> + ret = OPAL_SUCCESS;
> + goto end;
> + }
> + /* If we successfully download the ucode, we leave it around forever */
> + capp_ucode_info.size = CAPP_UCODE_MAX_SIZE;
> + capp_ucode_info.lid = malloc(CAPP_UCODE_MAX_SIZE);
> + if (!capp_ucode_info.lid) {
> + prerror("CAPP: Can't allocate space for ucode lid\n");
> + ret = OPAL_NO_MEM;
> + goto end;
> + }
> +
> + printf("CAPI: Preloading ucode %x\n", capp_ucode_info.ec_level);
> +
> + ret = start_preload_resource(RESOURCE_ID_CAPP, index,
> + capp_ucode_info.lid,
> + &capp_ucode_info.size);
> +
> + if (ret != OPAL_SUCCESS)
> + prerror("CAPI: Failed to preload resource %d\n", ret);
> +
> +end:
> + return ret;
> +}
> +
> +static int64_t capp_lid_download(void)
> +{
> + int64_t ret;
> +
> + if (capp_ucode_info.load_result != OPAL_EMPTY)
> + return capp_ucode_info.load_result;
> +
> + capp_ucode_info.load_result = wait_for_resource_loaded(
> + RESOURCE_ID_CAPP,
> + capp_ucode_info.ec_level);
> +
> + if (capp_ucode_info.load_result != OPAL_SUCCESS) {
> + prerror("CAPP: Error loading ucode lid. index=%x\n",
> + capp_ucode_info.ec_level);
> + ret = OPAL_RESOURCE;
> + free(capp_ucode_info.lid);
> + capp_ucode_info.lid = NULL;
> + goto end;
> + }
> +
> + ret = OPAL_SUCCESS;
> +end:
> + return ret;
> +}
> +
> +int64_t capp_load_ucode(unsigned int index, unsigned int chip_id,
> + unsigned int max_phb_index, u64 lidec,
It took me a while to figure out that lidec == "lid eyecatcher", perhaps
the name could be better.
> + uint32_t reg_offset, uint32_t opal_id,
> + uint64_t apc_master_addr, uint64_t apc_master_write,
> + uint64_t snp_array_addr, uint64_t snp_array_write)
> +{
> + struct proc_chip *chip = get_chip(chip_id);
> + struct capp_ucode_lid *ucode;
> + struct capp_ucode_data *data;
> + struct capp_lid_hdr *lid;
> + uint64_t rc, val, addr;
> + uint32_t chunk_count, offset;
> + int i;
> +
> + if (capp_ucode_loaded(chip, index))
> + return OPAL_SUCCESS;
> +
> + /* Return if PHB not attached to a CAPP unit */
> + if (index > max_phb_index)
> + return OPAL_HARDWARE;
> +
> + rc = capp_lid_download();
> + if (rc)
> + return rc;
> +
> + prlog(PR_INFO, "CHIP%i: CAPP ucode lid loaded at %p\n",
> + chip_id, capp_ucode_info.lid);
> +
> + lid = capp_ucode_info.lid;
> + /*
> + * If lid header is present (on FSP machines), it'll tell us where to
> + * find the ucode. Otherwise this is the ucode.
> + */
> + ucode = (struct capp_ucode_lid *)lid;
> + /* PHB3: 'CAPPLIDH' in ASCII
> + * PHB4: 'CAPPPSLL' in ASCII
> + */
This comment is pretty far removed from where the lidec value is
actually passed.
> + if (be64_to_cpu(lid->eyecatcher) == lidec) {
> + if (be64_to_cpu(lid->version) != 0x1) {
> + PHBERR(opal_id, chip_id, index,
> + "capi ucode lid header invalid\n");
> + return OPAL_HARDWARE;
> + }
> + ucode = (struct capp_ucode_lid *)
> + ((char *)ucode + be64_to_cpu(lid->ucode_offset));
> + }
> +
> + /* 'CAPPULID' in ASCII */
> + if ((be64_to_cpu(ucode->eyecatcher) != 0x43415050554C4944) ||
> + (ucode->version != 1)) {
> + PHBERR(opal_id, chip_id, index,
> + "CAPP: ucode header invalid\n");
> + return OPAL_HARDWARE;
> + }
> +
> + offset = 0;
> + while (offset < be64_to_cpu(ucode->data_size)) {
> + data = (struct capp_ucode_data *)
> + ((char *)&ucode->data + offset);
> + chunk_count = be32_to_cpu(data->hdr.chunk_count);
> + offset += sizeof(struct capp_ucode_data_hdr) + chunk_count * 8;
> +
> + /* 'CAPPUCOD' in ASCII */
> + if (be64_to_cpu(data->hdr.eyecatcher) != 0x4341505055434F44) {
> + PHBERR(opal_id, chip_id, index,
> + "CAPP: ucode data header invalid:%i\n",
> + offset);
> + return OPAL_HARDWARE;
> + }
> +
> + switch (data->hdr.reg) {
> + case apc_master_cresp:
> + xscom_write(chip_id, apc_master_addr + reg_offset,
> + 0);
> + addr = apc_master_write;
> + break;
> + case apc_master_uop_table:
> + xscom_write(chip_id, apc_master_addr + reg_offset,
> + 0x180ULL << 52);
> + addr = apc_master_write;
> + break;
> + case snp_ttype:
> + xscom_write(chip_id, snp_array_addr + reg_offset,
> + 0x5000ULL << 48);
> + addr = snp_array_write;
> + break;
> + case snp_uop_table:
> + xscom_write(chip_id, snp_array_addr + reg_offset,
> + 0x4000ULL << 48);
> + addr = snp_array_write;
> + break;
> + default:
> + continue;
> + }
> +
> + for (i = 0; i < chunk_count; i++) {
> + val = be64_to_cpu(data->data[i]);
> + xscom_write(chip_id, addr + reg_offset, val);
> + }
> + }
> +
> + chip->capp_ucode_loaded |= (1 << index);
> +
> + return OPAL_SUCCESS;
> +}
> diff --git a/hw/phb3.c b/hw/phb3.c
> index f0e957c..0af20a6 100644
> --- a/hw/phb3.c
> +++ b/hw/phb3.c
> @@ -2417,139 +2417,6 @@ static int64_t phb3_freset(struct pci_slot *slot)
> }
>
> struct lock capi_lock = LOCK_UNLOCKED;
> -static struct {
> - uint32_t ec_level;
> - struct capp_lid_hdr *lid;
> - size_t size;
> - int load_result;
> -} capp_ucode_info = { 0, NULL, 0, false };
> -
> -#define CAPP_UCODE_MAX_SIZE 0x20000
> -
> -#define CAPP_UCODE_LOADED(chip, p) \
> - ((chip)->capp_ucode_loaded & (1 << (p)->index))
> -
> -static int64_t capp_lid_download(void)
> -{
> - int64_t ret;
> -
> - if (capp_ucode_info.load_result != OPAL_EMPTY)
> - return capp_ucode_info.load_result;
> -
> - capp_ucode_info.load_result = wait_for_resource_loaded(
> - RESOURCE_ID_CAPP,
> - capp_ucode_info.ec_level);
> -
> - if (capp_ucode_info.load_result != OPAL_SUCCESS) {
> - prerror("CAPP: Error loading ucode lid. index=%x\n",
> - capp_ucode_info.ec_level);
> - ret = OPAL_RESOURCE;
> - free(capp_ucode_info.lid);
> - capp_ucode_info.lid = NULL;
> - goto end;
> - }
> -
> - ret = OPAL_SUCCESS;
> -end:
> - return ret;
> -}
> -
> -static int64_t capp_load_ucode(struct phb3 *p)
> -{
> - struct proc_chip *chip = get_chip(p->chip_id);
> - struct capp_ucode_lid *ucode;
> - struct capp_ucode_data *data;
> - struct capp_lid_hdr *lid;
> - uint64_t rc, val, addr;
> - uint32_t chunk_count, offset, reg_offset;
> - int i;
> -
> - if (CAPP_UCODE_LOADED(chip, p))
> - return OPAL_SUCCESS;
> -
> - /* Return if PHB not attached to a CAPP unit */
> - if (p->index > PHB3_CAPP_MAX_PHB_INDEX(p))
> - return OPAL_HARDWARE;
> -
> - rc = capp_lid_download();
> - if (rc)
> - return rc;
> -
> - prlog(PR_INFO, "CHIP%i: CAPP ucode lid loaded at %p\n",
> - p->chip_id, capp_ucode_info.lid);
> - lid = capp_ucode_info.lid;
> - /*
> - * If lid header is present (on FSP machines), it'll tell us where to
> - * find the ucode. Otherwise this is the ucode.
> - */
> - ucode = (struct capp_ucode_lid *)lid;
> - if (be64_to_cpu(lid->eyecatcher) == 0x434150504c494448) {
> - if (be64_to_cpu(lid->version) != 0x1) {
> - PHBERR(p, "capi ucode lid header invalid\n");
> - return OPAL_HARDWARE;
> - }
> - ucode = (struct capp_ucode_lid *)
> - ((char *)ucode + be64_to_cpu(lid->ucode_offset));
> - }
> -
> - if ((be64_to_cpu(ucode->eyecatcher) != 0x43415050554C4944) ||
> - (ucode->version != 1)) {
> - PHBERR(p, "CAPP: ucode header invalid\n");
> - return OPAL_HARDWARE;
> - }
> -
> - reg_offset = PHB3_CAPP_REG_OFFSET(p);
> - offset = 0;
> - while (offset < be64_to_cpu(ucode->data_size)) {
> - data = (struct capp_ucode_data *)
> - ((char *)&ucode->data + offset);
> - chunk_count = be32_to_cpu(data->hdr.chunk_count);
> - offset += sizeof(struct capp_ucode_data_hdr) + chunk_count * 8;
> -
> - if (be64_to_cpu(data->hdr.eyecatcher) != 0x4341505055434F44) {
> - PHBERR(p, "CAPP: ucode data header invalid:%i\n",
> - offset);
> - return OPAL_HARDWARE;
> - }
> -
> - switch (data->hdr.reg) {
> - case apc_master_cresp:
> - xscom_write(p->chip_id,
> - CAPP_APC_MASTER_ARRAY_ADDR_REG + reg_offset,
> - 0);
> - addr = CAPP_APC_MASTER_ARRAY_WRITE_REG;
> - break;
> - case apc_master_uop_table:
> - xscom_write(p->chip_id,
> - CAPP_APC_MASTER_ARRAY_ADDR_REG + reg_offset,
> - 0x180ULL << 52);
> - addr = CAPP_APC_MASTER_ARRAY_WRITE_REG;
> - break;
> - case snp_ttype:
> - xscom_write(p->chip_id,
> - CAPP_SNP_ARRAY_ADDR_REG + reg_offset,
> - 0x5000ULL << 48);
> - addr = CAPP_SNP_ARRAY_WRITE_REG;
> - break;
> - case snp_uop_table:
> - xscom_write(p->chip_id,
> - CAPP_SNP_ARRAY_ADDR_REG + reg_offset,
> - 0x4000ULL << 48);
> - addr = CAPP_SNP_ARRAY_WRITE_REG;
> - break;
> - default:
> - continue;
> - }
> -
> - for (i = 0; i < chunk_count; i++) {
> - val = be64_to_cpu(data->data[i]);
> - xscom_write(p->chip_id, addr + reg_offset, val);
> - }
> - }
> -
> - chip->capp_ucode_loaded |= (1 << p->index);
> - return OPAL_SUCCESS;
> -}
>
> static void do_capp_recovery_scoms(struct phb3 *p)
> {
> @@ -2561,7 +2428,13 @@ static void do_capp_recovery_scoms(struct phb3 *p)
> offset = PHB3_CAPP_REG_OFFSET(p);
> /* disable snoops */
> xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, 0);
> - capp_load_ucode(p);
> + capp_load_ucode(p->index, p->chip_id, PHB3_CAPP_MAX_PHB_INDEX(p),
> + 0x434150504c494448, PHB3_CAPP_REG_OFFSET(p),
> + p->phb.opal_id,
> + CAPP_APC_MASTER_ARRAY_ADDR_REG,
> + CAPP_APC_MASTER_ARRAY_WRITE_REG,
> + CAPP_SNP_ARRAY_ADDR_REG,
> + CAPP_SNP_ARRAY_WRITE_REG);
> /* clear err rpt reg*/
> xscom_write(p->chip_id, CAPP_ERR_RPT_CLR + offset, 0);
> /* clear capp fir */
> @@ -3596,7 +3469,7 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
> uint32_t offset;
> u8 mask;
>
> - if (!CAPP_UCODE_LOADED(chip, p)) {
> + if (!capp_ucode_loaded(chip, p->index)) {
> PHBERR(p, "CAPP: ucode not loaded\n");
> return OPAL_RESOURCE;
> }
> @@ -4624,7 +4497,13 @@ static void phb3_create(struct dt_node *np)
> phb3_init_hw(p, true);
>
> /* Load capp microcode into capp unit */
> - capp_load_ucode(p);
> + capp_load_ucode(p->index, p->chip_id, PHB3_CAPP_MAX_PHB_INDEX(p),
> + 0x434150504c494448, PHB3_CAPP_REG_OFFSET(p),
> + p->phb.opal_id,
> + CAPP_APC_MASTER_ARRAY_ADDR_REG,
> + CAPP_APC_MASTER_ARRAY_WRITE_REG,
> + CAPP_SNP_ARRAY_ADDR_REG,
> + CAPP_SNP_ARRAY_WRITE_REG);
>
> /* Platform additional setup */
> if (platform.pci_setup_phb)
> @@ -4817,67 +4696,6 @@ static void phb3_probe_pbcq(struct dt_node *pbcq)
> add_chip_dev_associativity(np);
> }
>
> -int phb3_preload_capp_ucode(void)
> -{
> - struct dt_node *p;
> - struct proc_chip *chip;
> - uint32_t index;
> - uint64_t rc;
> - int ret;
> -
> - p = dt_find_compatible_node(dt_root, NULL, "ibm,power8-pbcq");
> -
> - if (!p) {
> - printf("CAPI: WARNING: no compat thing found\n");
> - return OPAL_SUCCESS;
> - }
> -
> - chip = get_chip(dt_get_chip_id(p));
> -
> - rc = xscom_read_cfam_chipid(chip->id, &index);
> - if (rc) {
> - prerror("CAPP: Error reading cfam chip-id\n");
> - ret = OPAL_HARDWARE;
> - return ret;
> - }
> - /* Keep ChipID and Major/Minor EC. Mask out the Location Code. */
> - index = index & 0xf0fff;
> -
> - /* Assert that we're preloading */
> - assert(capp_ucode_info.lid == NULL);
> - capp_ucode_info.load_result = OPAL_EMPTY;
> -
> - capp_ucode_info.ec_level = index;
> -
> - /* Is the ucode preloaded like for BML? */
> - if (dt_has_node_property(p, "ibm,capp-ucode", NULL)) {
> - capp_ucode_info.lid = (struct capp_lid_hdr *)(u64)
> - dt_prop_get_u32(p, "ibm,capp-ucode");
> - ret = OPAL_SUCCESS;
> - goto end;
> - }
> - /* If we successfully download the ucode, we leave it around forever */
> - capp_ucode_info.size = CAPP_UCODE_MAX_SIZE;
> - capp_ucode_info.lid = malloc(CAPP_UCODE_MAX_SIZE);
> - if (!capp_ucode_info.lid) {
> - prerror("CAPP: Can't allocate space for ucode lid\n");
> - ret = OPAL_NO_MEM;
> - goto end;
> - }
> -
> - printf("CAPI: Preloading ucode %x\n", capp_ucode_info.ec_level);
> -
> - ret = start_preload_resource(RESOURCE_ID_CAPP, index,
> - capp_ucode_info.lid,
> - &capp_ucode_info.size);
> -
> - if (ret != OPAL_SUCCESS)
> - prerror("CAPI: Failed to preload resource %d\n", ret);
> -
> -end:
> - return ret;
> -}
> -
> void phb3_preload_vpd(void)
> {
> const struct dt_property *prop;
> diff --git a/hw/phb4.c b/hw/phb4.c
> index 9858ad8..8b07590 100644
> --- a/hw/phb4.c
> +++ b/hw/phb4.c
> @@ -49,6 +49,7 @@
> #include <phb4.h>
> #include <phb4-regs.h>
> #include <phb4-capp.h>
> +#include <capp.h>
> #include <fsp.h>
> #include <chip.h>
> #include <chiptod.h>
> @@ -2592,6 +2593,11 @@ static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode,
> uint64_t reg;
> uint32_t offset;
>
> + if (!capp_ucode_loaded(chip, p->index)) {
> + PHBERR(p, "CAPP: ucode not loaded\n");
> + return OPAL_RESOURCE;
> + }
> +
> lock(&capi_lock);
> /* Only PHB0 and PHB3 have the PHB/CAPP I/F so CAPI Adapters can
> * be connected to whether PEC0 or PEC2. Single port CAPI adapter
> @@ -3505,6 +3511,15 @@ static void phb4_create(struct dt_node *np)
> /* Get the HW up and running */
> phb4_init_hw(p, true);
>
> + /* Load capp microcode into capp unit */
> + capp_load_ucode(p->index, p->chip_id, PHB4_CAPP_MAX_PHB_INDEX,
> + 0x4341505050534C4C, PHB4_CAPP_REG_OFFSET(p),
> + p->phb.opal_id,
> + CAPP_APC_MASTER_ARRAY_ADDR_REG,
> + CAPP_APC_MASTER_ARRAY_WRITE_REG,
> + CAPP_SNP_ARRAY_ADDR_REG,
> + CAPP_SNP_ARRAY_WRITE_REG);
> +
> /* Register all interrupt sources with XIVE */
> xive_register_hw_source(p->base_msi, p->num_irqs - 8, 16,
> p->int_mmio, XIVE_SRC_SHIFT_BUG,
> diff --git a/include/capp.h b/include/capp.h
> index d0c28c9..82b08f2 100644
> --- a/include/capp.h
> +++ b/include/capp.h
> @@ -17,8 +17,12 @@
> #ifndef __CAPP_H
> #define __CAPP_H
>
> +/*
> + * eyecatcher PHB3: 'CAPPLIDH' in ASCII
> + * eyecatcher PHB4: 'CAPPPSLL' in ASCII
> + */
> struct capp_lid_hdr {
> - be64 eyecatcher; /* 'CAPPLIDH' in ASCII */
> + be64 eyecatcher;
> be64 version;
> be64 lid_no;
> be64 pad;
> @@ -27,7 +31,7 @@ struct capp_lid_hdr {
> };
>
> struct capp_ucode_data_hdr {
> - be64 eyecatcher; /* 'CAPPUCOD' in ASCII */
> + be64 eyecatcher; /* 'CAPPUCOD' in ASCII */
> u8 version;
> u8 reg;
> u8 reserved[2];
> @@ -47,7 +51,6 @@ struct capp_ucode_lid {
> struct capp_ucode_data data; /* This repeats */
> };
>
> -
> enum capp_reg {
> apc_master_cresp = 0x1,
> apc_master_uop_table = 0x2,
> @@ -62,4 +65,13 @@ enum capp_reg {
> apc_master_powerbus_ctrl = 0xB
> };
>
> +struct proc_chip;
> +extern bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index);
> +
> +extern int64_t capp_load_ucode(unsigned int index, unsigned int chip_id,
> + unsigned int max_phb_index, u64 lidec,
> + uint32_t reg_offset, uint32_t opal_id,
> + uint64_t apc_master_addr, uint64_t apc_master_write,
> + uint64_t snp_array_addr, uint64_t snp_array_write);
> +
> #endif /* __CAPP_H */
> diff --git a/include/skiboot.h b/include/skiboot.h
> index 33447a4..30b8ade 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -210,9 +210,8 @@ extern void setup_reset_vector(void);
> extern void probe_p7ioc(void);
> extern void probe_phb3(void);
> extern void probe_phb4(void);
> -extern int phb3_preload_capp_ucode(void);
> extern void phb3_preload_vpd(void);
> -extern int phb4_preload_capp_ucode(void);
> +extern int preload_capp_ucode(void);
> extern void phb4_preload_vpd(void);
> extern void probe_npu(void);
> extern void uart_init(void);
>
--
Andrew Donnellan OzLabs, ADL Canberra
andrew.donnellan at au1.ibm.com IBM Australia Limited
More information about the Skiboot
mailing list