diff mbox

[4/4] capi: Load capp microcode for phb4

Message ID 1486717462-5016-5-git-send-email-clombard@linux.vnet.ibm.com
State Superseded
Headers show

Commit Message

Christophe Lombard Feb. 10, 2017, 9:04 a.m. UTC
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

Comments

Frederic Barrat Feb. 23, 2017, 4:36 p.m. UTC | #1
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);
>
Andrew Donnellan March 2, 2017, 5:44 a.m. UTC | #2
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);
>
Christophe Lombard March 24, 2017, 4:01 p.m. UTC | #3
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);
>>
Christophe Lombard March 24, 2017, 4:03 p.m. UTC | #4
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 mbox

Patch

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);