Пример #1
0
static void find_capp_checkstop_reason(int flat_chip_id,
				       struct OpalHMIEvent *hmi_evt,
				       uint64_t *out_flags)
{
	struct capp_info info;
	struct phb *phb;
	uint64_t capp_fir;
	uint64_t capp_fir_mask;
	uint64_t capp_fir_action0;
	uint64_t capp_fir_action1;
	uint64_t reg;
	int64_t rc;

	/* Find the CAPP on the chip associated with the HMI. */
	for_each_phb(phb) {
		/* get the CAPP info */
		rc = capp_get_info(flat_chip_id, phb, &info);
		if (rc == OPAL_PARAMETER)
			continue;

		if (xscom_read(flat_chip_id, info.capp_fir_reg, &capp_fir) ||
		    xscom_read(flat_chip_id, info.capp_fir_mask_reg,
			       &capp_fir_mask) ||
		    xscom_read(flat_chip_id, info.capp_fir_action0_reg,
			       &capp_fir_action0) ||
		    xscom_read(flat_chip_id, info.capp_fir_action1_reg,
			       &capp_fir_action1)) {
			prerror("CAPP: Couldn't read CAPP#%d (PHB:#%x) FIR registers by XSCOM!\n",
				info.capp_index, info.phb_index);
			continue;
		}

		if (!(capp_fir & ~capp_fir_mask))
			continue;

		prlog(PR_DEBUG, "CAPP#%d (PHB:#%x): FIR 0x%016llx mask 0x%016llx\n",
		      info.capp_index, info.phb_index, capp_fir,
		      capp_fir_mask);
		prlog(PR_DEBUG, "CAPP#%d (PHB:#%x): ACTION0 0x%016llx, ACTION1 0x%016llx\n",
		      info.capp_index, info.phb_index, capp_fir_action0,
		      capp_fir_action1);

		/*
		 * If this bit is set (=1) a Recoverable Error has been
		 * detected
		 */
		xscom_read(flat_chip_id, info.capp_err_status_ctrl_reg, &reg);
		if ((reg & PPC_BIT(0)) != 0) {
			phb_lock(phb);
			phb->ops->set_capp_recovery(phb);
			phb_unlock(phb);

			hmi_evt->severity = OpalHMI_SEV_NO_ERROR;
			hmi_evt->type = OpalHMI_ERROR_CAPP_RECOVERY;
			queue_hmi_event(hmi_evt, 1, out_flags);

			return;
		}
	}
}
Пример #2
0
static void show_all_regs(struct npu2 *npu, int brick_index)
{
	int i, stack, stack_min, stack_max;
	uint64_t fir_val, mask_val, fir_addr, mask_addr;
	struct npu2_dev *dev;
	npu2_scom_dump_t scom_reg;

	if (brick_index != -1) {
		stack_min = stack_max = NPU2_STACK_STCK_0 + brick_index / 2;
	} else {
		stack_min = NPU2_STACK_STCK_0;
		stack_max = NPU2_STACK_STCK_2;
		/* Avoid dumping unused stacks for opencapi on Lagrange */
		if (npu->total_devices == 2)
			stack_min = stack_max = NPU2_STACK_STCK_1;
	}

	/* NPU FIRs */
	for (i = 0; i < NPU2_TOTAL_FIR_REGISTERS; i++) {
		fir_addr  = NPU2_FIR_REGISTER_0 + i * NPU2_FIR_OFFSET;
		mask_addr = fir_addr + NPU2_FIR_MASK_OFFSET;
		xscom_read(npu->chip_id, fir_addr, &fir_val);
		xscom_read(npu->chip_id, mask_addr, &mask_val);
		prlog(PR_ERR, "NPU[%d] FIR%d = 0x%016llx (mask 0x%016llx => 0x%016llx)\n",
			npu->chip_id, i, fir_val, mask_val, fir_val & ~mask_val);
	}

	/* NPU global, per-stack registers */
	for (i = 0; i < ARRAY_SIZE(npu2_scom_dump_global); i++) {
		for (stack = stack_min; stack <= stack_max; stack++)
			print_one_npu_reg(npu, &npu2_scom_dump_global[i], stack);
	}

	/*
	 * NPU global registers, stack independent
	 * We have only one for now, so dump it directly
	 */
	scom_reg.name = "XTS.REG.ERR_HOLD";
	scom_reg.block = NPU2_BLOCK_XTS;
	scom_reg.offset = 0;
	print_one_npu_reg(npu, &scom_reg, NPU2_STACK_MISC);

	/* nvlink- or opencapi-specific registers */
	for (i = 0; i < npu->total_devices; i++) {
		dev = &npu->devices[i];
		if (brick_index == -1 || dev->brick_index == brick_index) {
			if (dev->type == NPU2_DEV_TYPE_NVLINK)
				show_nvlink_regs(npu, dev->brick_index);
			else if (dev->type == NPU2_DEV_TYPE_OPENCAPI)
				show_opencapi_regs(npu, dev->brick_index);
		}
	}
}
Пример #3
0
void p8_sbe_init_timer(void)
{
	struct dt_node *np;
	int64_t rc;
	uint32_t tick_us;

	np = dt_find_compatible_node(dt_root, NULL, "ibm,power8-sbe-timer");
	if (!np)
		return;

	sbe_timer_chip = dt_get_chip_id(np);
	tick_us = dt_prop_get_u32(np, "tick-time-us");
	sbe_timer_inc = usecs_to_tb(tick_us);
	sbe_timer_target = ~0ull;

	rc = xscom_read(sbe_timer_chip, 0xE0006, &sbe_last_gen);
	if (rc) {
		prerror("SLW: Error %lld reading tmr gen count\n", rc);
		return;
	}
	sbe_last_gen_stamp = mftb();

	prlog(PR_INFO, "SLW: Timer facility on chip %d, resolution %dus\n",
	      sbe_timer_chip, tick_us);
	sbe_has_timer = true;
}
Пример #4
0
static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
			 uint32_t sz)
{
	uint64_t ctl = ECCB_CTL_MAGIC, stat;
	int64_t rc, tout;
	uint64_t data_reg;

	switch(sz) {
	case 1:
		data_reg = ((uint64_t)data) << 56;
		break;
	case 2:
		data_reg = ((uint64_t)data) << 48;
		break;
	case 4:
		data_reg = ((uint64_t)data) << 32;
		break;
	default:
		prerror("LPC: Invalid data size %d\n", sz);
		return OPAL_PARAMETER;
	}

	rc = xscom_write(chip->id, chip->lpc_xbase + ECCB_DATA, data_reg);
	if (rc) {
		log_simple_error(&e_info(OPAL_RC_LPC_WRITE),
			"LPC: XSCOM write to ECCB DATA error %lld\n", rc);
		return rc;
	}

	ctl = SETFIELD(ECCB_CTL_DATASZ, ctl, sz);
	ctl = SETFIELD(ECCB_CTL_ADDRLEN, ctl, ECCB_ADDRLEN_4B);
	ctl = SETFIELD(ECCB_CTL_ADDR, ctl, addr);
	rc = xscom_write(chip->id, chip->lpc_xbase + ECCB_CTL, ctl);
	if (rc) {
		log_simple_error(&e_info(OPAL_RC_LPC_WRITE),
			"LPC: XSCOM write to ECCB CTL error %lld\n", rc);
		return rc;
	}

	for (tout = 0; tout < ECCB_TIMEOUT; tout++) {
		rc = xscom_read(chip->id, chip->lpc_xbase + ECCB_STAT, &stat);
		if (rc) {
			log_simple_error(&e_info(OPAL_RC_LPC_WRITE),
				"LPC: XSCOM read from ECCB STAT err %lld\n",
									rc);
			return rc;
		}
		if (stat & ECCB_STAT_OP_DONE) {
			if (stat & ECCB_STAT_ERR_MASK) {
				log_simple_error(&e_info(OPAL_RC_LPC_WRITE),
					"LPC: Error status: 0x%llx\n", stat);
				return OPAL_HARDWARE;
			}
			return OPAL_SUCCESS;
		}
		time_wait(100);
	}
	log_simple_error(&e_info(OPAL_RC_LPC_WRITE), "LPC: Write timeout !\n");
	return OPAL_HARDWARE;
}
Пример #5
0
static int read_core_fir(uint32_t chip_id, uint32_t core_id, uint64_t *core_fir)
{
	int rc;

	switch (proc_gen) {
	case proc_gen_p8:
		rc = xscom_read(chip_id,
			XSCOM_ADDR_P8_EX(core_id, P8_CORE_FIR), core_fir);
		break;
	case proc_gen_p9:
		rc = xscom_read(chip_id,
			XSCOM_ADDR_P9_EC(core_id, P9_CORE_FIR), core_fir);
		break;
	default:
		rc = OPAL_HARDWARE;
	}
	return rc;
}
Пример #6
0
/* same as above, but for direct access registers */
static void print_one_reg(int chip_id, int brick_index,
			uint64_t reg_addr, const char *reg_name)
{
	uint64_t val;

	xscom_read(chip_id, reg_addr, &val);
	prlog(PR_ERR, "NPU[%d] %s brick %d 0x%llx = 0x%016llx\n",
		chip_id, reg_name, brick_index, reg_addr, val);
}
Пример #7
0
static uint64_t __unused dl_read(struct npu_dev *npu_dev, uint32_t addr)
{
	uint64_t val;

	xscom_write(npu_dev->npu->chip_id,
		    npu_dev->xscom + NX_DL_REG_ADDR, addr);
	xscom_read(npu_dev->npu->chip_id,
		   npu_dev->xscom + NX_DL_REG_DATA, &val);
	return val;
}
Пример #8
0
uint64_t npu2_scom_read(uint64_t gcid, uint64_t scom_base,
			uint64_t reg, uint64_t size)
{
	uint64_t val;

	npu2_scom_set_addr(gcid, scom_base, reg, size);
	xscom_read(gcid, scom_base + NPU2_MISC_SCOM_IND_SCOM_DATA, &val);

	return val;
}
Пример #9
0
static int64_t opb_read(struct lpcm *lpc, uint32_t addr, uint32_t *data,
		        uint32_t sz)
{
	uint64_t ctl = ECCB_CTL_MAGIC | ECCB_CTL_READ, stat;
	int64_t rc, tout;

	if (lpc->mbase)
		return opb_mmio_read(lpc, addr, data, sz);

	if (sz != 1 && sz != 2 && sz != 4) {
		prerror("Invalid data size %d\n", sz);
		return OPAL_PARAMETER;
	}

	ctl = SETFIELD(ECCB_CTL_DATASZ, ctl, sz);
	ctl = SETFIELD(ECCB_CTL_ADDRLEN, ctl, ECCB_ADDRLEN_4B);
	ctl = SETFIELD(ECCB_CTL_ADDR, ctl, addr);
	rc = xscom_write(lpc->chip_id, lpc->xbase + ECCB_CTL, ctl);
	if (rc) {
		log_simple_error(&e_info(OPAL_RC_LPC_READ),
			"LPC: XSCOM write to ECCB CTL error %lld\n", rc);
		return rc;
	}

	for (tout = 0; tout < ECCB_TIMEOUT; tout++) {
		rc = xscom_read(lpc->chip_id, lpc->xbase + ECCB_STAT,
				&stat);
		if (rc) {
			log_simple_error(&e_info(OPAL_RC_LPC_READ),
				"LPC: XSCOM read from ECCB STAT err %lld\n",
									rc);
			return rc;
		}
		if (stat & ECCB_STAT_OP_DONE) {
			uint32_t rdata = GETFIELD(ECCB_STAT_RD_DATA, stat);
			if (stat & ECCB_STAT_ERR_MASK) {
				log_simple_error(&e_info(OPAL_RC_LPC_READ),
					"LPC: Error status: 0x%llx\n", stat);
				return OPAL_HARDWARE;
			}
			switch(sz) {
			case 1:
				*data = rdata >> 24;
				break;
			case 2:
				*data = rdata >> 16;
				break;
			default:
				*data = rdata;
				break;
			}
			return 0;
		}
		time_wait_nopoll(100);
	}
Пример #10
0
static uint16_t phy_read(struct npu_dev *npu_dev, uint64_t addr)
{
	uint64_t val;

	if (pl_use_scom)
		xscom_read(npu_dev->npu->chip_id, npu_dev->pl_xscom_base + addr, &val);
	else
		val = in_be16((void *) npu_dev->pl_base + PL_MMIO_ADDR(addr));

	return val & 0xffff;
}
Пример #11
0
static int read_core_wof(uint32_t chip_id, uint32_t core_id, uint64_t *core_wof)
{
	int rc;

	switch (proc_gen) {
	case proc_gen_p9:
		rc = xscom_read(chip_id,
			XSCOM_ADDR_P9_EC(core_id, P9_CORE_WOF), core_wof);
		break;
	default:
		rc = OPAL_HARDWARE;
	}
	return rc;
}
Пример #12
0
static bool read_pba_bar(struct proc_chip *chip, unsigned int bar_no,
			 uint64_t *base, uint64_t *size)
{
	uint64_t bar, mask;
	int rc;

	rc = xscom_read(chip->id, pba_bar0 + bar_no, &bar);
	if (rc) {
		prerror("SLW: Error %d reading PBA BAR%d on chip %d\n",
			rc, bar_no, chip->id);
		return false;
	}
	rc = xscom_read(chip->id, pba_barmask0 + bar_no, &mask);
	if (rc) {
		prerror("SLW: Error %d reading PBA BAR MASK%d on chip %d\n",
			rc, bar_no, chip->id);
		return false;
	}
	prlog(PR_DEBUG, "  PBA BAR%d : 0x%016llx\n", bar_no, bar);
	prlog(PR_DEBUG, "  PBA MASK%d: 0x%016llx\n", bar_no, mask);

	if (mask == PBA_MASK_ALL_BITS) {
		/*
		 * This could happen if all HOMER users are not enabled during
		 * early system bringup. Skip using the PBA BAR.
		 */
		mask = 0;
		bar = 0;
		prerror("  PBA MASK%d uninitalized skipping BAR\n", bar_no);
	}

	*base = bar & 0x0ffffffffffffffful;
	*size = (mask | 0xfffff) + 1;

	return (*base) != 0;
}
Пример #13
0
void fsi_recovery()
{
    int32_t rc = SUCCESS;

    /* Clear out OPB error */
    uint64_t scom_data = 0;
    scom_data = 0x8000000000000000; /*0=Unit Reset*/
    rc |= xscom_write( OPB_REG_RES,  scom_data );
    rc |= xscom_write( OPB_REG_STAT, scom_data );

    /* Check if we have any errors left */
    rc |= xscom_read( OPB_REG_STAT, &scom_data );

    TRACFCOMP( "PIB2OPB Status after cleanup = %08X%08X (rc=%d)",
               (uint32_t)(scom_data >> 32), (uint32_t)scom_data, rc );
}
Пример #14
0
static int __ipoll_update_mask(uint32_t proc, bool set, uint64_t bits)
{
	uint64_t mask;
	int rc;

	rc = xscom_read(proc, PRD_IPOLL_REG_MASK, &mask);
	if (rc)
		return rc;

	if (set)
		mask |= bits;
	else
		mask &= ~bits;

	return xscom_write(proc, PRD_IPOLL_REG_MASK, mask);
}
Пример #15
0
static int ipoll_record_and_mask_pending(uint32_t proc)
{
	uint64_t status;
	int rc;

	lock(&ipoll_lock);
	rc = xscom_read(proc, PRD_IPOLL_REG_STATUS, &status);
	if (!rc)
		__ipoll_update_mask(proc, true, status);
	unlock(&ipoll_lock);

	if (!rc)
		ipoll_status[proc] |= (status & PRD_IPOLL_MASK);

	return rc;
}
Пример #16
0
static void decode_malfunction(struct OpalHMIEvent *hmi_evt, uint64_t *out_flags)
{
	int i;
	uint64_t malf_alert, flags;

	flags = 0;

	if (!setup_scom_addresses()) {
		prerror("Failed to setup scom addresses\n");
		/* Send an unknown HMI event. */
		hmi_evt->u.xstop_error.xstop_type = CHECKSTOP_TYPE_UNKNOWN;
		hmi_evt->u.xstop_error.xstop_reason = 0;
		queue_hmi_event(hmi_evt, false, out_flags);
		return;
	}

	xscom_read(this_cpu()->chip_id, malf_alert_scom, &malf_alert);

	if (!malf_alert)
		return;

	for (i = 0; i < 64; i++) {
		if (malf_alert & PPC_BIT(i)) {
			xscom_write(this_cpu()->chip_id, malf_alert_scom,
								~PPC_BIT(i));
			find_capp_checkstop_reason(i, hmi_evt, &flags);
			find_nx_checkstop_reason(i, hmi_evt, &flags);
			find_npu_checkstop_reason(i, hmi_evt, &flags);
		}
	}

	find_core_checkstop_reason(hmi_evt, &flags);

	/*
	 * If we fail to find checkstop reason, send an unknown HMI event.
	 */
	if (!(flags & OPAL_HMI_FLAGS_NEW_EVENT)) {
		hmi_evt->u.xstop_error.xstop_type = CHECKSTOP_TYPE_UNKNOWN;
		hmi_evt->u.xstop_error.xstop_reason = 0;
		queue_hmi_event(hmi_evt, false, &flags);
	}
	*out_flags |= flags;
}
Пример #17
0
static void print_chip_info(uint32_t chip_id)
{
	uint64_t f000f, cfam_id;
	const char *name;
	char uname_buf[64];
	int rc;

	rc = xscom_read(chip_id, 0xf000f, &f000f);
	if (rc)
		return;

	cfam_id = f000f >> 44;

	switch(cfam_id & 0xff) {
	case 0xf9:
		name = "P7 processor";
		break;
	case 0xe8:
		name = "P7+ processor";
		break;
	case 0xef:
		name = "P8E (Murano) processor";
		break;
	case 0xea:
		name = "P8 (Venice) processor";
		break;
	case 0xd3:
		name = "P8NVL (Naples) processor";
		break;
	case 0xe9:
		name = "Centaur memory buffer";
		break;
	default:
		snprintf(uname_buf, sizeof(uname_buf), "Unknown ID 0x%02lx",
			 cfam_id & 0xff);
		name = uname_buf;
	}

	printf("%08x | DD%lx.%lx | %s\n",
	       chip_id, (cfam_id >> 16) & 0xf, (cfam_id >> 8) & 0xf, name);
	
}
Пример #18
0
static int populate_ipoll_msg(struct opal_prd_msg *msg, uint32_t proc)
{
	uint64_t ipoll_mask;
	int rc;

	lock(&ipoll_lock);
	rc = xscom_read(proc, PRD_IPOLL_REG_MASK, &ipoll_mask);
	unlock(&ipoll_lock);

	if (rc) {
		prlog(PR_ERR, "PRD: Unable to read ipoll status (chip %d)!\n",
				proc);
		return -1;
	}

	msg->attn.proc = proc;
	msg->attn.ipoll_status = ipoll_status[proc];
	msg->attn.ipoll_mask = ipoll_mask;
	return 0;
}
Пример #19
0
static int nx_cfg_umac_status_ctrl(u32 gcid, u64 xcfg)
{
	u64 uctrl;
	int rc;
#define CRB_ENABLE	1

	rc = xscom_read(gcid, xcfg, &uctrl);
	if (rc)
		return rc;

	uctrl = SETFIELD(NX_P9_UMAC_STATUS_CTRL_CRB_ENABLE, uctrl, CRB_ENABLE);
	rc = xscom_write(gcid, xcfg, uctrl);
	if (rc)
		prerror("NX%d: ERROR: Setting UMAC Status Control failure %d\n",
			gcid, rc);
	else
		prlog(PR_DEBUG, "NX%d: Setting UMAC Status Control 0x%016lx\n",
			gcid, (unsigned long)uctrl);

	return rc;
}
Пример #20
0
static void p8_sbe_dump_timer_ffdc(void)
{
	uint64_t i, val;
	int64_t rc;

	static const uint32_t dump_regs[] = {
		0xe0000, 0xe0001, 0xe0002, 0xe0003,
		0xe0004, 0xe0005, 0xe0006, 0xe0007,
		0xe0008, 0xe0009, 0xe000a, 0xe000b,
		0xe000c, 0xe000d, 0xe000e, 0xe000f,
		0xe0010, 0xe0011, 0xe0012, 0xe0013,
		0xe0014, 0xe0015, 0xe0016, 0xe0017,
		0xe0018, 0xe0019,
		0x5001c,
		0x50038, 0x50039, 0x5003a, 0x5003b
	};

	/**
	 * @fwts-label SLWRegisterDump
	 * @fwts-advice An error condition occurred in sleep/winkle
	 * engines timer state machine. Dumping debug information to
	 * root-cause. OPAL/skiboot may be stuck on some operation that
	 * requires SLW timer state machine (e.g. core powersaving)
	 */
	prlog(PR_DEBUG, "SLW: Register state:\n");

	for (i = 0; i < ARRAY_SIZE(dump_regs); i++) {
		uint32_t reg = dump_regs[i];
		rc = xscom_read(sbe_timer_chip, reg, &val);
		if (rc) {
			prlog(PR_DEBUG, "SLW: XSCOM error %lld reading"
			      " reg 0x%x\n", rc, reg);
			break;
		}
		prlog(PR_DEBUG, "SLW:  %5x = %016llx\n", reg, val);
	}
}
Пример #21
0
/**
 * @brief  Poll for completion of a FSI operation, return data on read
 */
int32_t poll_for_complete( uint32_t * o_val )
{
    int32_t rc = SUCCESS;

    enum { MAX_OPB_TIMEOUT_NS = 10*NS_PER_MSEC }; /*=10ms */

    *o_val = 0;

    uint64_t read_data = 0;
    uint64_t elapsed_time_ns = 0;
    do
    {
        rc = xscom_read( OPB_REG_STAT, &read_data );
        if ( SUCCESS != rc )
        {
            fsi_recovery(); /* Try to recover the engine. */
            return rc;
        }

        /* Check for completion. Note: not checking for FSI errors. */
        if ( (read_data & OPB_STAT_BUSY) == 0 ) break; /* Not busy */

        sleep( 10000 ); /* sleep for 10,000 ns */
        elapsed_time_ns += 10000;

    } while ( elapsed_time_ns <= MAX_OPB_TIMEOUT_NS );

    if ( MAX_OPB_TIMEOUT_NS < elapsed_time_ns )
    {
        TRAC_ERR( "[poll_for_complete] FSI request timed out." );
        return FAIL;
    }

    *o_val = (uint32_t)read_data; /* Data in the bottom half. */

    return rc;
}
Пример #22
0
int main(int argc, char *argv[])
{
	uint64_t val, addr = -1ull;
	uint32_t def_chip, chip_id = 0xffffffff;
	bool list_chips = false;
	bool no_work = false;
	int rc;

	while(1) {
		static struct option long_opts[] = {
			{"chip",	required_argument,	NULL,	'c'},
			{"list-chips",	no_argument,		NULL,	'l'},
			{"help",	no_argument,		NULL,	'h'},
			{"version",	no_argument,		NULL,	'v'},
		};
		int c, oidx = 0;

		c = getopt_long(argc, argv, "-c:hlv", long_opts, &oidx);
		if (c == EOF)
			break;
		switch(c) {
		case 1:
			addr = strtoull(optarg, NULL, 16);
			break;
		case 'c':
			chip_id = strtoul(optarg, NULL, 0);
			break;
		case 'h':
			print_usage(0);
			break;
		case 'l':
			list_chips = true;
			break;
		case 'v':
			printf("xscom utils version %s\n", version);
			exit(0);
		default:
			exit(1);
		}
	}
	
	if (addr == -1ull)
		no_work = true;
	if (no_work && !list_chips) {
		fprintf(stderr, "Invalid or missing address\n");
		print_usage(1);
	}

	def_chip = xscom_init();
	if (def_chip == 0xffffffff) {
		fprintf(stderr, "No valid XSCOM chip found\n");
		exit(1);
	}
	if (list_chips) {
		printf("Chip ID  | Rev   | Chip type\n");
		printf("---------|-------|--------\n");
		xscom_for_each_chip(print_chip_info);
	}
	if (no_work)
		return 0;
	if (chip_id == 0xffffffff)
		chip_id = def_chip;

	rc = xscom_read(chip_id, addr, &val);
	if (rc) {
		fprintf(stderr,"Error %d reading XSCOM\n", rc);
		exit(1);
	}
	printf("%016" PRIx64 "\n", val);
	return 0;
}
Пример #23
0
static void find_nx_checkstop_reason(int flat_chip_id,
				     struct OpalHMIEvent *hmi_evt,
				     uint64_t *out_flags)
{
	uint64_t nx_status;
	uint64_t nx_dma_fir;
	uint64_t nx_pbi_fir_val;
	int i;

	/* Get NX status register value. */
	if (xscom_read(flat_chip_id, nx_status_reg, &nx_status) != 0) {
		prerror("XSCOM error reading NX_STATUS_REG\n");
		return;
	}

	/* Check if NX has driven an HMI interrupt. */
	if (!(nx_status & NX_HMI_ACTIVE))
		return;

	/* Initialize HMI event */
	hmi_evt->severity = OpalHMI_SEV_FATAL;
	hmi_evt->type = OpalHMI_ERROR_MALFUNC_ALERT;
	hmi_evt->u.xstop_error.xstop_type = CHECKSTOP_TYPE_NX;
	hmi_evt->u.xstop_error.u.chip_id = flat_chip_id;

	/* Get DMA & Engine FIR data register value. */
	if (xscom_read(flat_chip_id, nx_dma_engine_fir, &nx_dma_fir) != 0) {
		prerror("XSCOM error reading NX_DMA_ENGINE_FIR\n");
		return;
	}

	/* Get PowerBus Interface FIR data register value. */
	if (xscom_read(flat_chip_id, nx_pbi_fir, &nx_pbi_fir_val) != 0) {
		prerror("XSCOM error reading NX_PBI_FIR\n");
		return;
	}

	/* Find NX checkstop reason and populate HMI event with error info. */
	for (i = 0; i < ARRAY_SIZE(nx_dma_xstop_bits); i++)
		if (nx_dma_fir & PPC_BIT(nx_dma_xstop_bits[i].bit))
			hmi_evt->u.xstop_error.xstop_reason
						|= nx_dma_xstop_bits[i].reason;

	for (i = 0; i < ARRAY_SIZE(nx_pbi_xstop_bits); i++)
		if (nx_pbi_fir_val & PPC_BIT(nx_pbi_xstop_bits[i].bit))
			hmi_evt->u.xstop_error.xstop_reason
						|= nx_pbi_xstop_bits[i].reason;

	/*
	 * Set NXDMAENGFIR[38] to signal PRD that service action is required.
	 * Without this inject, PRD will not be able to do NX unit checkstop
	 * error analysis. NXDMAENGFIR[38] is a spare bit and used to report
	 * a software initiated attention.
	 *
	 * The behavior of this bit and all FIR bits are documented in
	 * RAS spreadsheet.
	 */
	xscom_write(flat_chip_id, nx_dma_engine_fir, PPC_BIT(38));

	/* Send an HMI event. */
	queue_hmi_event(hmi_evt, 0, out_flags);
}
Пример #24
0
static void find_npu2_checkstop_reason(int flat_chip_id,
				      struct OpalHMIEvent *hmi_evt,
				      uint64_t *out_flags)
{
	struct phb *phb;
	int i;
	bool npu2_hmi_verbose = false, found = false;
	uint64_t npu2_fir;
	uint64_t npu2_fir_mask;
	uint64_t npu2_fir_action0;
	uint64_t npu2_fir_action1;
	uint64_t npu2_fir_addr;
	uint64_t npu2_fir_mask_addr;
	uint64_t npu2_fir_action0_addr;
	uint64_t npu2_fir_action1_addr;
	uint64_t fatal_errors;
	int total_errors = 0;
	const char *loc;

	/* Find the NPU on the chip associated with the HMI. */
	for_each_phb(phb) {
		/* NOTE: if a chip ever has >1 NPU this will need adjusting */
		if (phb_is_npu2(phb->dt_node) &&
		    (dt_get_chip_id(phb->dt_node) == flat_chip_id)) {
			found = true;
			break;
		}
	}

	/* If we didn't find a NPU on the chip, it's not our checkstop. */
	if (!found)
		return;

	npu2_fir_addr = NPU2_FIR_REGISTER_0;
	npu2_fir_mask_addr = NPU2_FIR_REGISTER_0 + NPU2_FIR_MASK_OFFSET;
	npu2_fir_action0_addr = NPU2_FIR_REGISTER_0 + NPU2_FIR_ACTION0_OFFSET;
	npu2_fir_action1_addr = NPU2_FIR_REGISTER_0 + NPU2_FIR_ACTION1_OFFSET;

	for (i = 0; i < NPU2_TOTAL_FIR_REGISTERS; i++) {
		/* Read all the registers necessary to find a checkstop condition. */
		if (xscom_read(flat_chip_id, npu2_fir_addr, &npu2_fir) ||
			xscom_read(flat_chip_id, npu2_fir_mask_addr, &npu2_fir_mask) ||
			xscom_read(flat_chip_id, npu2_fir_action0_addr, &npu2_fir_action0) ||
			xscom_read(flat_chip_id, npu2_fir_action1_addr, &npu2_fir_action1)) {
			prerror("HMI: Couldn't read NPU FIR register%d with XSCOM\n", i);
			continue;
		}

		fatal_errors = npu2_fir & ~npu2_fir_mask & npu2_fir_action0 & npu2_fir_action1;

		if (fatal_errors) {
			loc = chip_loc_code(flat_chip_id);
			if (!loc)
				loc = "Not Available";
			prlog(PR_ERR, "NPU: [Loc: %s] P:%d FIR#%d FIR 0x%016llx mask 0x%016llx\n",
					loc, flat_chip_id, i, npu2_fir, npu2_fir_mask);
			prlog(PR_ERR, "NPU: [Loc: %s] P:%d ACTION0 0x%016llx, ACTION1 0x%016llx\n",
					loc, flat_chip_id, npu2_fir_action0, npu2_fir_action1);
			total_errors++;
		}

		/* Can't do a fence yet, we are just logging fir information for now */
		npu2_fir_addr += NPU2_FIR_OFFSET;
		npu2_fir_mask_addr += NPU2_FIR_OFFSET;
		npu2_fir_action0_addr += NPU2_FIR_OFFSET;
		npu2_fir_action1_addr += NPU2_FIR_OFFSET;

	}

	if (!total_errors)
		return;

	npu2_hmi_verbose = nvram_query_eq_safe("npu2-hmi-verbose", "true");
	/* Force this for now until we sort out something better */
	npu2_hmi_verbose = true;

	if (npu2_hmi_verbose) {
		npu2_dump_scoms(flat_chip_id);
		prlog(PR_ERR, " _________________________ \n");
		prlog(PR_ERR, "<    It's Debug time!     >\n");
		prlog(PR_ERR, " ------------------------- \n");
		prlog(PR_ERR, "       \\   ,__,            \n");
		prlog(PR_ERR, "        \\  (oo)____        \n");
		prlog(PR_ERR, "           (__)    )\\      \n");
		prlog(PR_ERR, "              ||--|| *     \n");
	}

	/* Set up the HMI event */
	hmi_evt->severity = OpalHMI_SEV_WARNING;
	hmi_evt->type = OpalHMI_ERROR_MALFUNC_ALERT;
	hmi_evt->u.xstop_error.xstop_type = CHECKSTOP_TYPE_NPU;
	hmi_evt->u.xstop_error.u.chip_id = flat_chip_id;

	/* Marking the event as recoverable so that we don't crash */
	queue_hmi_event(hmi_evt, 1, out_flags);
}
Пример #25
0
int nx_cfg_rx_fifo(struct dt_node *node, const char *compat,
			const char *priority, u32 gcid, u32 pid, u32 tid,
			u64 umac_bar, u64 umac_notify)
{
	u64 cfg;
	int rc, size;
	uint64_t fifo;
	u32 lpid = 0xfff; /* All 1's for 12 bits in UMAC notify match reg */
#define MATCH_ENABLE    1

	fifo = (uint64_t) local_alloc(gcid, RX_FIFO_SIZE, RX_FIFO_SIZE);
	assert(fifo);

	/*
	 * When configuring the address of the Rx FIFO into the Receive FIFO
	 * BAR, we should _NOT_ shift the address into bits 8:53. Instead we
	 * should copy the address as is and VAS/NX will extract relevant bits.
	 */
	/*
	 * Section 5.21 of P9 NX Workbook Version 2.42 shows Receive FIFO BAR
	 * 54:56 represents FIFO size
	 * 000 = 1KB, 8 CRBs
	 * 001 = 2KB, 16 CRBs
	 * 010 = 4KB, 32 CRBs
	 * 011 = 8KB, 64 CRBs
	 * 100 = 16KB, 128 CRBs
	 * 101 = 32KB, 256 CRBs
	 * 110 = 111 reserved
	 */
	size = RX_FIFO_SIZE / 1024;
	cfg = SETFIELD(NX_P9_RX_FIFO_BAR_SIZE, fifo, ilog2(size));

	rc = xscom_write(gcid, umac_bar, cfg);
	if (rc) {
		prerror("NX%d: ERROR: Setting UMAC FIFO bar failure %d\n",
			gcid, rc);
		return rc;
	} else
		prlog(PR_DEBUG, "NX%d: Setting UMAC FIFO bar 0x%016lx\n",
			gcid, (unsigned long)cfg);

	rc = xscom_read(gcid, umac_notify, &cfg);
	if (rc)
		return rc;

	/*
	 * VAS issues asb_notify with the unique ID to identify the target
	 * co-processor/engine. Logical partition ID (lpid), process ID (pid),
	 * and thread ID (tid) combination is used to define the unique ID
	 * in the system. Export these values in device-tree such that the
	 * driver configure RxFIFO with VAS. Set these values in RxFIFO notify
	 * match register for each engine which compares the ID with each
	 * request.
	 * To define unique indentification, 0xfff (1's for 12 bits),
	 * co-processor type, and counter within coprocessor type are used
	 * for lpid, pid, and tid respectively.
	 */
	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_LPID, cfg, lpid);
	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_PID, cfg, pid);
	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_TID, cfg, tid);
	cfg = SETFIELD(NX_P9_RX_FIFO_NOTIFY_MATCH_MATCH_ENABLE, cfg,
			MATCH_ENABLE);

	rc = xscom_write(gcid, umac_notify, cfg);
	if (rc) {
		prerror("NX%d: ERROR: Setting UMAC notify match failure %d\n",
			gcid, rc);
		return rc;
	} else
		prlog(PR_DEBUG, "NX%d: Setting UMAC notify match 0x%016lx\n",
				gcid, (unsigned long)cfg);

	dt_add_property_string(node, "compatible", compat);
	dt_add_property_string(node, "priority", priority);
	dt_add_property_u64(node, "rx-fifo-address", fifo);
	dt_add_property_cells(node, "rx-fifo-size", RX_FIFO_SIZE);
	dt_add_property_cells(node, "lpid", lpid);
	dt_add_property_cells(node, "pid", pid);
	dt_add_property_cells(node, "tid", tid);

	return 0;
}
Пример #26
0
static void find_npu_checkstop_reason(int flat_chip_id,
				      struct OpalHMIEvent *hmi_evt,
				      uint64_t *out_flags)
{
	struct phb *phb;
	struct npu *p = NULL;

	uint64_t npu_fir;
	uint64_t npu_fir_mask;
	uint64_t npu_fir_action0;
	uint64_t npu_fir_action1;
	uint64_t fatal_errors;

	/* Only check for NPU errors if the chip has a NPU */
	if (PVR_TYPE(mfspr(SPR_PVR)) != PVR_TYPE_P8NVL)
		return find_npu2_checkstop_reason(flat_chip_id, hmi_evt, out_flags);

	/* Find the NPU on the chip associated with the HMI. */
	for_each_phb(phb) {
		/* NOTE: if a chip ever has >1 NPU this will need adjusting */
		if (dt_node_is_compatible(phb->dt_node, "ibm,power8-npu-pciex") &&
		    (dt_get_chip_id(phb->dt_node) == flat_chip_id)) {
			p = phb_to_npu(phb);
			break;
		}
	}

	/* If we didn't find a NPU on the chip, it's not our checkstop. */
	if (p == NULL)
		return;

	/* Read all the registers necessary to find a checkstop condition. */
	if (xscom_read(flat_chip_id,
		       p->at_xscom + NX_FIR, &npu_fir) ||
	    xscom_read(flat_chip_id,
		       p->at_xscom + NX_FIR_MASK, &npu_fir_mask) ||
	    xscom_read(flat_chip_id,
		       p->at_xscom + NX_FIR_ACTION0, &npu_fir_action0) ||
	    xscom_read(flat_chip_id,
		       p->at_xscom + NX_FIR_ACTION1, &npu_fir_action1)) {
		prerror("Couldn't read NPU registers with XSCOM\n");
		return;
	}

	fatal_errors = npu_fir & ~npu_fir_mask & npu_fir_action0 & npu_fir_action1;

	/* If there's no errors, we don't need to do anything. */
	if (!fatal_errors)
		return;

	prlog(PR_DEBUG, "NPU: FIR 0x%016llx mask 0x%016llx\n",
	      npu_fir, npu_fir_mask);
	prlog(PR_DEBUG, "NPU: ACTION0 0x%016llx, ACTION1 0x%016llx\n",
	      npu_fir_action0, npu_fir_action1);

	/* Set the NPU to fenced since it can't recover. */
	npu_set_fence_state(p, true);

	/* Set up the HMI event */
	hmi_evt->severity = OpalHMI_SEV_WARNING;
	hmi_evt->type = OpalHMI_ERROR_MALFUNC_ALERT;
	hmi_evt->u.xstop_error.xstop_type = CHECKSTOP_TYPE_NPU;
	hmi_evt->u.xstop_error.u.chip_id = flat_chip_id;

	/* The HMI is "recoverable" because it shouldn't crash the system */
	queue_hmi_event(hmi_evt, 1, out_flags);
}