[Skiboot] [PATCH 4/4] capi: Load capp microcode for phb4
Christophe Lombard
clombard at linux.vnet.ibm.com
Fri Feb 10 20:04:22 AEDT 2017
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>
---
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)) {
+ 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);
--
2.7.4
More information about the Skiboot
mailing list