Message ID | 1486717462-5016-5-git-send-email-clombard@linux.vnet.ibm.com |
---|---|
State | Superseded |
Headers | show |
Le 10/02/2017 à 10:04, Christophe Lombard a écrit : > 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@linux.vnet.ibm.com> > --- > core/init.c | 2 +- > hw/Makefile.inc | 2 +- > hw/capp.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/phb3.c | 212 ++++-------------------------------------------- > hw/phb4.c | 15 ++++ > include/capp.h | 18 ++++- > include/skiboot.h | 3 +- > 7 files changed, 283 insertions(+), 204 deletions(-) > create mode 100644 hw/capp.c > > diff --git a/core/init.c b/core/init.c > index 7bcb680..795746c 100644 > --- a/core/init.c > +++ b/core/init.c > @@ -918,7 +918,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) > op_display(OP_LOG, OP_MOD_INIT, 0x0002); > > phb3_preload_vpd(); > - phb3_preload_capp_ucode(); > + preload_capp_ucode(); > start_preload_kernel(); > > /* NX init */ > diff --git a/hw/Makefile.inc b/hw/Makefile.inc > index f2dc328..5a3fd39 100644 > --- a/hw/Makefile.inc > +++ b/hw/Makefile.inc > @@ -6,7 +6,7 @@ HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o > HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o > HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o > HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o > -HW_OBJS += fake-nvram.o > +HW_OBJS += fake-nvram.o capp.o > HW=hw/built-in.o > > # FIXME hack this for now > diff --git a/hw/capp.c b/hw/capp.c > new file mode 100644 > index 0000000..c7c359d > --- /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"); > + 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, > + 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 > + */ > + 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)) { This is old code and we got lucky, but it should be: be64_to_cpu(ucode->version) != 1 (I was running the same code on my laptop to check the p9 microcode, and of course, it was failing) Fred > + 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); >
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@linux.vnet.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@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); >
Le 23/02/2017 à 17:36, Frederic Barrat a écrit : > Le 10/02/2017 à 10:04, Christophe Lombard a écrit : >> 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@linux.vnet.ibm.com> >> --- >> core/init.c | 2 +- >> hw/Makefile.inc | 2 +- >> hw/capp.c | 235 >> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> hw/phb3.c | 212 >> ++++-------------------------------------------- >> hw/phb4.c | 15 ++++ >> include/capp.h | 18 ++++- >> include/skiboot.h | 3 +- >> 7 files changed, 283 insertions(+), 204 deletions(-) >> create mode 100644 hw/capp.c >> >> diff --git a/core/init.c b/core/init.c >> index 7bcb680..795746c 100644 >> --- a/core/init.c >> +++ b/core/init.c >> @@ -918,7 +918,7 @@ void __noreturn __nomcount main_cpu_entry(const >> void *fdt) >> op_display(OP_LOG, OP_MOD_INIT, 0x0002); >> >> phb3_preload_vpd(); >> - phb3_preload_capp_ucode(); >> + preload_capp_ucode(); >> start_preload_kernel(); >> >> /* NX init */ >> diff --git a/hw/Makefile.inc b/hw/Makefile.inc >> index f2dc328..5a3fd39 100644 >> --- a/hw/Makefile.inc >> +++ b/hw/Makefile.inc >> @@ -6,7 +6,7 @@ HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o >> HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o >> HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o >> HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o >> -HW_OBJS += fake-nvram.o >> +HW_OBJS += fake-nvram.o capp.o >> HW=hw/built-in.o >> >> # FIXME hack this for now >> diff --git a/hw/capp.c b/hw/capp.c >> new file mode 100644 >> index 0000000..c7c359d >> --- /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"); >> + 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, >> + 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 >> + */ >> + 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)) { > > > This is old code and we got lucky, but it should be: > be64_to_cpu(ucode->version) != 1 > > (I was running the same code on my laptop to check the p9 microcode, > and of course, it was failing) > > Fred > ok. > >> + 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); >>
Le 02/03/2017 à 06:44, Andrew Donnellan a écrit : > 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@linux.vnet.ibm.com> > > Reviewed-by: Andrew Donnellan <andrew.donnellan@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 > will do. >> + 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. > yep, you are right. >> + 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); >> >
diff --git a/core/init.c b/core/init.c index 7bcb680..795746c 100644 --- a/core/init.c +++ b/core/init.c @@ -918,7 +918,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) op_display(OP_LOG, OP_MOD_INIT, 0x0002); phb3_preload_vpd(); - phb3_preload_capp_ucode(); + preload_capp_ucode(); start_preload_kernel(); /* NX init */ diff --git a/hw/Makefile.inc b/hw/Makefile.inc index f2dc328..5a3fd39 100644 --- a/hw/Makefile.inc +++ b/hw/Makefile.inc @@ -6,7 +6,7 @@ HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o -HW_OBJS += fake-nvram.o +HW_OBJS += fake-nvram.o capp.o HW=hw/built-in.o # FIXME hack this for now diff --git a/hw/capp.c b/hw/capp.c new file mode 100644 index 0000000..c7c359d --- /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"); + 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, + 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 + */ + 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);
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@linux.vnet.ibm.com> --- core/init.c | 2 +- hw/Makefile.inc | 2 +- hw/capp.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/phb3.c | 212 ++++-------------------------------------------- hw/phb4.c | 15 ++++ include/capp.h | 18 ++++- include/skiboot.h | 3 +- 7 files changed, 283 insertions(+), 204 deletions(-) create mode 100644 hw/capp.c