[Skiboot] [PATCH 4/8] lpc: Move LPC instance variables to a private structure

Benjamin Herrenschmidt benh at kernel.crashing.org
Sun Jul 3 10:50:14 AEST 2016


Take them out of struct proc_chip and into a private struct lpcm
that's local to lpc.c

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 core/chip.c    |   1 -
 hw/lpc.c       | 398 +++++++++++++++++++++++++++++++++------------------------
 include/chip.h |   8 +-
 include/lpc.h  |   3 -
 4 files changed, 233 insertions(+), 177 deletions(-)

diff --git a/core/chip.c b/core/chip.c
index b39a0f0..5ac5d62 100644
--- a/core/chip.c
+++ b/core/chip.c
@@ -123,6 +123,5 @@ void init_chips(void)
 			chip->occ_functional = false;
 
 		list_head_init(&chip->i2cms);
-		list_head_init(&chip->lpc_clients);
 	};
 }
diff --git a/hw/lpc.c b/hw/lpc.c
index 2c8e4f5..be755f8 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -108,6 +108,17 @@ DEFINE_LOG_ENTRY(OPAL_RC_LPC_SYNC, OPAL_PLATFORM_ERR_EVT, OPAL_LPC,
 	LPC_HC_IRQ_BM_TAR_ERR)
 #define LPC_HC_ERROR_ADDRESS	0x40
 
+struct lpcm {
+	uint32_t		chip_id;
+	uint32_t		lpc_xbase;
+	void			*lpc_mbase;
+	struct lock		lpc_lock;
+	uint8_t			lpc_fw_idsel;
+	uint8_t			lpc_fw_rdsz;
+	struct list_head	lpc_clients;
+	bool			has_serirq;
+};
+
 struct lpc_client_entry {
 	struct list_node node;
 	const struct lpc_client *clt;
@@ -128,33 +139,33 @@ static uint32_t lpc_fw_opb_base 	= 0xf0000000;
 static uint32_t lpc_reg_opb_base 	= 0xc0012000;
 static uint32_t opb_master_reg_base 	= 0xc0010000;
 
-static int64_t opb_mmio_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
+static int64_t opb_mmio_write(struct lpcm *lpc, uint32_t addr, uint32_t data,
 			      uint32_t sz)
 {
 	switch (sz) {
 	case 1:
-		out_8(chip->lpc_mbase + addr, data);
+		out_8(lpc->lpc_mbase + addr, data);
 		return OPAL_SUCCESS;
 	case 2:
-		out_be16(chip->lpc_mbase + addr, data);
+		out_be16(lpc->lpc_mbase + addr, data);
 		return OPAL_SUCCESS;
 	case 4:
-		out_be32(chip->lpc_mbase + addr, data);
+		out_be32(lpc->lpc_mbase + addr, data);
 		return OPAL_SUCCESS;
 	}
 	prerror("LPC: Invalid data size %d\n", sz);
 	return OPAL_PARAMETER;
 }
 
-static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
+static int64_t opb_write(struct lpcm *lpc, uint32_t addr, uint32_t data,
 			 uint32_t sz)
 {
 	uint64_t ctl = ECCB_CTL_MAGIC, stat;
 	int64_t rc, tout;
 	uint64_t data_reg;
 
-	if (chip->lpc_mbase)
-		return opb_mmio_write(chip, addr, data, sz);
+	if (lpc->lpc_mbase)
+		return opb_mmio_write(lpc, addr, data, sz);
 
 	switch(sz) {
 	case 1:
@@ -171,7 +182,7 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 		return OPAL_PARAMETER;
 	}
 
-	rc = xscom_write(chip->id, chip->lpc_xbase + ECCB_DATA, data_reg);
+	rc = xscom_write(lpc->chip_id, lpc->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);
@@ -181,7 +192,7 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 	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);
+	rc = xscom_write(lpc->chip_id, lpc->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);
@@ -189,7 +200,8 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 	}
 
 	for (tout = 0; tout < ECCB_TIMEOUT; tout++) {
-		rc = xscom_read(chip->id, chip->lpc_xbase + ECCB_STAT, &stat);
+		rc = xscom_read(lpc->chip_id, lpc->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",
@@ -210,32 +222,32 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
 	return OPAL_HARDWARE;
 }
 
-static int64_t opb_mmio_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
+static int64_t opb_mmio_read(struct lpcm *lpc, uint32_t addr, uint32_t *data,
 			     uint32_t sz)
 {
 	switch (sz) {
 	case 1:
-		*data = in_8(chip->lpc_mbase + addr);
+		*data = in_8(lpc->lpc_mbase + addr);
 		return OPAL_SUCCESS;
 	case 2:
-		*data = in_be16(chip->lpc_mbase + addr);
+		*data = in_be16(lpc->lpc_mbase + addr);
 		return OPAL_SUCCESS;
 	case 4:
-		*data = in_be32(chip->lpc_mbase + addr);
+		*data = in_be32(lpc->lpc_mbase + addr);
 		return OPAL_SUCCESS;
 	}
 	prerror("LPC: Invalid data size %d\n", sz);
 	return OPAL_PARAMETER;
 }
 
-static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
+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 (chip->lpc_mbase)
-		return opb_mmio_read(chip, addr, data, sz);
+	if (lpc->lpc_mbase)
+		return opb_mmio_read(lpc, addr, data, sz);
 
 	if (sz != 1 && sz != 2 && sz != 4) {
 		prerror("LPC: Invalid data size %d\n", sz);
@@ -245,7 +257,7 @@ static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
 	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);
+	rc = xscom_write(lpc->chip_id, lpc->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);
@@ -253,7 +265,8 @@ static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
 	}
 
 	for (tout = 0; tout < ECCB_TIMEOUT; tout++) {
-		rc = xscom_read(chip->id, chip->lpc_xbase + ECCB_STAT, &stat);
+		rc = xscom_read(lpc->chip_id, lpc->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",
@@ -286,39 +299,39 @@ static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
 	return OPAL_HARDWARE;
 }
 
-static int64_t lpc_set_fw_idsel(struct proc_chip *chip, uint8_t idsel)
+static int64_t lpc_set_fw_idsel(struct lpcm *lpc, uint8_t idsel)
 {
 	uint32_t val;
 	int64_t rc;
 
-	if (idsel == chip->lpc_fw_idsel)
+	if (idsel == lpc->lpc_fw_idsel)
 		return OPAL_SUCCESS;
 	if (idsel > 0xf)
 		return OPAL_PARAMETER;
 
-	rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
+	rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
 		      &val, 4);
 	if (rc) {
 		prerror("LPC: Failed to read HC_FW_SEG_IDSEL register !\n");
 		return rc;
 	}
 	val = (val & 0xfffffff0) | idsel;
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
 		       val, 4);
 	if (rc) {
 		prerror("LPC: Failed to write HC_FW_SEG_IDSEL register !\n");
 		return rc;
 	}
-	chip->lpc_fw_idsel = idsel;
+	lpc->lpc_fw_idsel = idsel;
 	return OPAL_SUCCESS;
 }
 
-static int64_t lpc_set_fw_rdsz(struct proc_chip *chip, uint8_t rdsz)
+static int64_t lpc_set_fw_rdsz(struct lpcm *lpc, uint8_t rdsz)
 {
 	uint32_t val;
 	int64_t rc;
 
-	if (rdsz == chip->lpc_fw_rdsz)
+	if (rdsz == lpc->lpc_fw_rdsz)
 		return OPAL_SUCCESS;
 	switch(rdsz) {
 	case 1:
@@ -339,17 +352,17 @@ static int64_t lpc_set_fw_rdsz(struct proc_chip *chip, uint8_t rdsz)
 		 */
 		return OPAL_PARAMETER;
 	}
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_FW_RD_ACC_SIZE,
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_FW_RD_ACC_SIZE,
 		       val, 4);
 	if (rc) {
 		prerror("LPC: Failed to write LPC_HC_FW_RD_ACC_SIZE !\n");
 		return rc;
 	}
-	chip->lpc_fw_rdsz = rdsz;
+	lpc->lpc_fw_rdsz = rdsz;
 	return OPAL_SUCCESS;
 }
 
-static int64_t lpc_opb_prepare(struct proc_chip *chip,
+static int64_t lpc_opb_prepare(struct lpcm *lpc,
 			       enum OpalLPCAddressType addr_type,
 			       uint32_t addr, uint32_t sz,
 			       uint32_t *opb_base, bool is_write)
@@ -396,12 +409,12 @@ static int64_t lpc_opb_prepare(struct proc_chip *chip,
 			return OPAL_PARAMETER;
 
 		/* Set segment */
-		rc = lpc_set_fw_idsel(chip, fw_idsel);
+		rc = lpc_set_fw_idsel(lpc, fw_idsel);
 		if (rc)
 			return rc;
 		/* Set read access size */
 		if (!is_write) {
-			rc = lpc_set_fw_rdsz(chip, sz);
+			rc = lpc_set_fw_rdsz(lpc, sz);
 			if (rc)
 				return rc;
 		}
@@ -412,41 +425,42 @@ static int64_t lpc_opb_prepare(struct proc_chip *chip,
 	return OPAL_SUCCESS;
 }
 
-static int64_t __lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
+static int64_t __lpc_write(struct lpcm *lpc, enum OpalLPCAddressType addr_type,
 			   uint32_t addr, uint32_t data, uint32_t sz)
 {
-	struct proc_chip *chip = get_chip(chip_id);
 	uint32_t opb_base;
 	int64_t rc;
 
-	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
-		return OPAL_PARAMETER;
-
-	lock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
 
 	/*
 	 * Convert to an OPB access and handle LPC HC configuration
 	 * for FW accesses (IDSEL)
 	 */
-	rc = lpc_opb_prepare(chip, addr_type, addr, sz, &opb_base, true);
+	rc = lpc_opb_prepare(lpc, addr_type, addr, sz, &opb_base, true);
 	if (rc)
 		goto bail;
 
 	/* Perform OPB access */
-	rc = opb_write(chip, opb_base + addr, data, sz);
+	rc = opb_write(lpc, opb_base + addr, data, sz);
 
 	/* XXX Add LPC error handling/recovery */
  bail:
-	unlock(&chip->lpc_lock);
+	unlock(&lpc->lpc_lock);
 	return rc;
 }
 
 int64_t lpc_write(enum OpalLPCAddressType addr_type, uint32_t addr,
 		  uint32_t data, uint32_t sz)
 {
+	struct proc_chip *chip;
+
 	if (lpc_default_chip_id < 0)
 		return OPAL_PARAMETER;
-	return __lpc_write(lpc_default_chip_id, addr_type, addr, data, sz);
+	chip = get_chip(lpc_default_chip_id);
+	if (!chip || !chip->lpc)
+		return OPAL_PARAMETER;
+	return __lpc_write(chip->lpc, addr_type, addr, data, sz);
 }
 
 /*
@@ -457,12 +471,17 @@ int64_t lpc_write(enum OpalLPCAddressType addr_type, uint32_t addr,
 static int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 			      uint32_t addr, uint32_t data, uint32_t sz)
 {
+	struct proc_chip *chip;
 	int64_t rc;
 
+	chip = get_chip(chip_id);
+	if (!chip || !chip->lpc)
+		return OPAL_PARAMETER;
+
 	if (addr_type == OPAL_LPC_FW || sz == 1)
-		return __lpc_write(chip_id, addr_type, addr, data, sz);
+		return __lpc_write(chip->lpc, addr_type, addr, data, sz);
 	while(sz--) {
-		rc = __lpc_write(chip_id, addr_type, addr, data & 0xff, 1);
+		rc = __lpc_write(chip->lpc, addr_type, addr, data & 0xff, 1);
 		if (rc)
 			return rc;
 		addr++;
@@ -471,41 +490,42 @@ static int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_typ
 	return OPAL_SUCCESS;
 }
 
-static int64_t __lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
+static int64_t __lpc_read(struct lpcm *lpc, enum OpalLPCAddressType addr_type,
 			  uint32_t addr, uint32_t *data, uint32_t sz)
 {
-	struct proc_chip *chip = get_chip(chip_id);
 	uint32_t opb_base;
 	int64_t rc;
 
-	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
-		return OPAL_PARAMETER;
-
-	lock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
 
 	/*
 	 * Convert to an OPB access and handle LPC HC configuration
 	 * for FW accesses (IDSEL and read size)
 	 */
-	rc = lpc_opb_prepare(chip, addr_type, addr, sz, &opb_base, false);
+	rc = lpc_opb_prepare(lpc, addr_type, addr, sz, &opb_base, false);
 	if (rc)
 		goto bail;
 
 	/* Perform OPB access */
-	rc = opb_read(chip, opb_base + addr, data, sz);
+	rc = opb_read(lpc, opb_base + addr, data, sz);
 
 	/* XXX Add LPC error handling/recovery */
  bail:
-	unlock(&chip->lpc_lock);
+	unlock(&lpc->lpc_lock);
 	return rc;
 }
 
 int64_t lpc_read(enum OpalLPCAddressType addr_type, uint32_t addr,
 		 uint32_t *data, uint32_t sz)
 {
+	struct proc_chip *chip;
+
 	if (lpc_default_chip_id < 0)
 		return OPAL_PARAMETER;
-	return __lpc_read(lpc_default_chip_id, addr_type, addr, data, sz);
+	chip = get_chip(lpc_default_chip_id);
+	if (!chip || !chip->lpc)
+		return OPAL_PARAMETER;
+	return __lpc_read(chip->lpc, addr_type, addr, data, sz);
 }
 
 /*
@@ -516,15 +536,20 @@ int64_t lpc_read(enum OpalLPCAddressType addr_type, uint32_t addr,
 static int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 			     uint32_t addr, uint32_t *data, uint32_t sz)
 {
+	struct proc_chip *chip;
 	int64_t rc;
 
+	chip = get_chip(chip_id);
+	if (!chip || !chip->lpc)
+		return OPAL_PARAMETER;
+
 	if (addr_type == OPAL_LPC_FW || sz == 1)
-		return __lpc_read(chip_id, addr_type, addr, data, sz);
+		return __lpc_read(chip->lpc, addr_type, addr, data, sz);
 	*data = 0;
 	while(sz--) {
 		uint32_t byte;
 
-		rc = __lpc_read(chip_id, addr_type, addr, &byte, 1);
+		rc = __lpc_read(chip->lpc, addr_type, addr, &byte, 1);
 		if (rc)
 			return rc;
 		*data = *data | (byte << (8 * sz));
@@ -539,7 +564,7 @@ bool lpc_present(void)
 }
 
 /* Called with LPC lock held */
-static void lpc_setup_serirq(struct proc_chip *chip)
+static void lpc_setup_serirq(struct lpcm *lpc)
 {
 	struct lpc_client_entry *ent;
 	uint32_t mask = LPC_HC_IRQ_BASE_IRQS;
@@ -549,10 +574,10 @@ static void lpc_setup_serirq(struct proc_chip *chip)
 		return;
 
 	/* Collect serirq enable bits */
-	list_for_each(&chip->lpc_clients, ent, node)
+	list_for_each(&lpc->lpc_clients, ent, node)
 		mask |= ent->clt->interrupts & LPC_HC_IRQ_SERIRQ_ALL;
 
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, mask, 4);
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK, mask, 4);
 	if (rc) {
 		prerror("LPC: Failed to update irq mask\n");
 		return;
@@ -560,19 +585,19 @@ static void lpc_setup_serirq(struct proc_chip *chip)
 	DBG_IRQ("LPC: IRQ mask set to 0x%08x\n", mask);
 
 	/* Enable the LPC interrupt in the OPB Master */
-	opb_write(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_POL, 0, 4);
-	rc = opb_write(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_MASK,
+	opb_write(lpc, opb_master_reg_base + OPB_MASTER_LS_IRQ_POL, 0, 4);
+	rc = opb_write(lpc, opb_master_reg_base + OPB_MASTER_LS_IRQ_MASK,
 		       OPB_MASTER_IRQ_LPC, 4);
 	if (rc)
 		prerror("LPC: Failed to enable IRQs in OPB\n");
 
 	/* Check whether we should enable serirq */
 	if (mask & LPC_HC_IRQ_SERIRQ_ALL) {
-		rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
+		rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
 			       LPC_HC_IRQSER_EN | LPC_HC_IRQSER_START_4CLK, 4);
 		DBG_IRQ("LPC: SerIRQ enabled\n");
 	} else {
-		rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
+		rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
 			       0, 4);
 		DBG_IRQ("LPC: SerIRQ disabled\n");
 	}
@@ -580,13 +605,13 @@ static void lpc_setup_serirq(struct proc_chip *chip)
 		prerror("LPC: Failed to configure SerIRQ\n");
 	{
 		u32 val;
-		rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, &val, 4);
+		rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK, &val, 4);
 		if (rc)
 			prerror("LPC: failed to readback mask");
 		else
 			DBG_IRQ("LPC: MASK READBACK=%x\n", val);
 
-		rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
+		rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL,
 			      &val, 4);
 		if (rc)
 			prerror("LPC: failed to readback ctrl");
@@ -595,13 +620,11 @@ static void lpc_setup_serirq(struct proc_chip *chip)
 	}
 }
 
-void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx)
+static void  __unused lpc_route_serirq(struct lpcm *lpc, uint32_t sirq, uint32_t psi_idx)
 {
-	struct proc_chip *chip = get_chip(chip_id);
 	uint32_t reg, shift, val;
 	int64_t rc;
 
-	assert(chip);
 	assert(proc_gen == proc_gen_p9);
 
 	if (sirq < 14) {
@@ -612,47 +635,41 @@ void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx)
 		shift = 8 + ((sirq - 14) << 1);
 	}
 	shift = 30-shift;
-	rc = opb_read(chip, opb_master_reg_base + reg, &val, 4);
+	rc = opb_read(lpc, opb_master_reg_base + reg, &val, 4);
 	if (rc)
 		return;
 	val = val & ~(3 << shift);
 	val |= (psi_idx & 3) << shift;
-	opb_write(chip, opb_master_reg_base + reg, val, 4);
+	opb_write(lpc, opb_master_reg_base + reg, val, 4);
 }
 
-void lpc_init_interrupts(void)
+static void lpc_init_interrupts_one(struct proc_chip *chip)
 {
-	struct proc_chip *chip;
+	struct lpcm *lpc = chip->lpc;
 	int rc;
 
-	if (lpc_default_chip_id < 0)
-		return;
-	chip = get_chip(lpc_default_chip_id);
-	if (chip == NULL)
-		return;
+	lock(&lpc->lpc_lock);
 
 	/* First mask them all */
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
 	if (rc) {
 		prerror("LPC: Failed to init interrutps\n");
-		return;
+		goto bail;
 	}
 
-	lpc_irqs_ready = true;
-
 	switch(chip->type) {
 	case PROC_CHIP_P8_MURANO:
 	case PROC_CHIP_P8_VENICE:
 		/* On Murano/Venice, there is no SerIRQ, only enable error
 		 * interrupts
 		 */
-		rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK,
+		rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK,
 			       LPC_HC_IRQ_BASE_IRQS, 4);
 		if (rc) {
 			prerror("LPC: Failed to set interrupt mask\n");
-			return;
+			goto bail;
 		}
-		opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL, 0, 4);
+		opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL, 0, 4);
 		break;
 	case PROC_CHIP_P8_NAPLES:
 	case PROC_CHIP_P9_NIMBUS:
@@ -661,17 +678,28 @@ void lpc_init_interrupts(void)
 		 * on what clients requests. This will setup the mask and
 		 * enable processing
 		 */
-		lock(&chip->lpc_lock);
-		lpc_setup_serirq(chip);
-		unlock(&chip->lpc_lock);
-		break;
+		lpc->has_serirq = true;
+		lpc_setup_serirq(lpc); 
 	default:
-		/* We aren't getting here, are we ? */
-		return;
+		;
+	}
+ bail:
+	unlock(&lpc->lpc_lock);
+}
+
+void lpc_init_interrupts(void)
+{
+	struct proc_chip *chip;
+
+	lpc_irqs_ready = true;
+
+	for_each_chip(chip) {
+		if (chip->lpc)
+			lpc_init_interrupts_one(chip);
 	}
 }
 
-static void lpc_dispatch_reset(struct proc_chip *chip)
+static void lpc_dispatch_reset(struct lpcm *lpc)
 {
 	struct lpc_client_entry *ent;
 
@@ -682,63 +710,64 @@ static void lpc_dispatch_reset(struct proc_chip *chip)
 	 * on/off rather than just reset
 	 */
 
-	prerror("LPC: Got LPC reset !\n");
+	prerror("LPC: Got LPC reset on chip 0x%x !\n", lpc->chip_id);
 
 	/* Collect serirq enable bits */
-	list_for_each(&chip->lpc_clients, ent, node) {
+	list_for_each(&lpc->lpc_clients, ent, node) {
 		if (!ent->clt->reset)
 			continue;
-		unlock(&chip->lpc_lock);
-		ent->clt->reset(chip->id);
-		lock(&chip->lpc_lock);
+		unlock(&lpc->lpc_lock);
+		ent->clt->reset(lpc->chip_id);
+		lock(&lpc->lpc_lock);
 	}
 
 	/* Reconfigure serial interrupts */
-	if (chip->type == PROC_CHIP_P8_NAPLES)
-		lpc_setup_serirq(chip);
+	if (lpc->has_serirq)
+		lpc_setup_serirq(lpc);
 }
 
-static void lpc_dispatch_err_irqs(struct proc_chip *chip, uint32_t irqs)
+static void lpc_dispatch_err_irqs(struct lpcm *lpc, uint32_t irqs)
 {
-	int rc;
 	const char *sync_err = "Unknown LPC error";
 	uint32_t err_addr;
+	int rc;
 
 	/* Write back to clear error interrupts, we clear SerIRQ later
 	 * as they are handled as level interrupts
 	 */
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT,
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSTAT,
 		       LPC_HC_IRQ_BASE_IRQS, 4);
 	if (rc)
 		prerror("LPC: Failed to clear IRQ error latches !\n");
 
 	if (irqs & LPC_HC_IRQ_LRESET)
-		lpc_dispatch_reset(chip);
+		lpc_dispatch_reset(lpc);
 	if (irqs & LPC_HC_IRQ_SYNC_ABNORM_ERR)
-		sync_err = "LPC: Got SYNC abnormal error.";
+		sync_err = "Got SYNC abnormal error.";
 	if (irqs & LPC_HC_IRQ_SYNC_NORESP_ERR)
-		sync_err = "LPC: Got SYNC no-response error.";
+		sync_err = "Got SYNC no-response error.";
 	if (irqs & LPC_HC_IRQ_SYNC_NORM_ERR)
-		sync_err = "LPC: Got SYNC normal error.";
+		sync_err = "Got SYNC normal error.";
 	if (irqs & LPC_HC_IRQ_SYNC_TIMEOUT_ERR)
-		sync_err = "LPC: Got SYNC timeout error.";
+		sync_err = "Got SYNC timeout error.";
 	if (irqs & LPC_HC_IRQ_TARG_TAR_ERR)
-		sync_err = "LPC: Got abnormal TAR error.";
+		sync_err = "Got abnormal TAR error.";
 	if (irqs & LPC_HC_IRQ_BM_TAR_ERR)
-		sync_err = "LPC: Got bus master TAR error.";
+		sync_err = "Got bus master TAR error.";
 
-	rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_ERROR_ADDRESS,
+	rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_ERROR_ADDRESS,
 		      &err_addr, 4);
 	if (rc)
-		log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "%s "
-			"Error reading error address register\n", sync_err);
+		log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "LPC[%03x]: %s "
+				 "Error reading error address register\n",
+				 lpc->chip_id, sync_err);
 	else
-		log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "%s "
+		log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "LPC[%03x]: %s "
 			"Error address reg: 0x%08x\n",
-			sync_err, err_addr);
+				 lpc->chip_id, sync_err, err_addr);
 }
 
-static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
+static void lpc_dispatch_ser_irqs(struct lpcm *lpc, uint32_t irqs,
 				  bool clear_latch)
 {
 	struct lpc_client_entry *ent;
@@ -748,14 +777,14 @@ static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
 	irqs &= LPC_HC_IRQ_SERIRQ_ALL;
 
 	/* Collect serirq enable bits */
-	list_for_each(&chip->lpc_clients, ent, node) {
+	list_for_each(&lpc->lpc_clients, ent, node) {
 		if (!ent->clt->interrupt)
 			continue;
 		cirqs = ent->clt->interrupts & irqs;
 		if (cirqs) {
-			unlock(&chip->lpc_lock);
-			ent->clt->interrupt(chip->id, cirqs);
-			lock(&chip->lpc_lock);
+			unlock(&lpc->lpc_lock);
+			ent->clt->interrupt(lpc->chip_id, cirqs);
+			lock(&lpc->lpc_lock);
 		}
 	}
 
@@ -765,7 +794,7 @@ static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
 	if (!clear_latch)
 		return;
 
-	rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT, irqs, 4);
+	rc = opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQSTAT, irqs, 4);
 	if (rc)
 		prerror("LPC: Failed to clear SerIRQ latches !\n");
 }
@@ -773,17 +802,19 @@ static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
 void lpc_interrupt(uint32_t chip_id)
 {
 	struct proc_chip *chip = get_chip(chip_id);
+	struct lpcm *lpc;
 	uint32_t irqs, opb_irqs;
 	int rc;
 
 	/* No initialized LPC controller on that chip */
-	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
+	if (!chip || !chip->lpc)
 		return;
+	lpc = chip->lpc;
 
-	lock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
 
 	/* Grab OPB Master LS interrupt status */
-	rc = opb_read(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_STAT,
+	rc = opb_read(lpc, opb_master_reg_base + OPB_MASTER_LS_IRQ_STAT,
 		      &opb_irqs, 4);
 	if (rc) {
 		prerror("LPC: Failed to read OPB IRQ state\n");
@@ -795,13 +826,13 @@ void lpc_interrupt(uint32_t chip_id)
 	/* Check if it's an LPC interrupt */
 	if (!(opb_irqs & OPB_MASTER_IRQ_LPC)) {
 		/* Something we don't support ? Ack it anyway... */
-		opb_write(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_STAT,
+		opb_write(lpc, opb_master_reg_base + OPB_MASTER_LS_IRQ_STAT,
 			  opb_irqs, 4);
 		goto bail;
 	}
 
 	/* Handle the lpc interrupt source (errors etc...) */
-	rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT, &irqs, 4);
+	rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_IRQSTAT, &irqs, 4);
 	if (rc) {
 		prerror("LPC: Failed to read LPC IRQ state\n");
 		goto bail;
@@ -811,30 +842,32 @@ void lpc_interrupt(uint32_t chip_id)
 
 	/* Handle error interrupts */
 	if (irqs & LPC_HC_IRQ_BASE_IRQS)
-		lpc_dispatch_err_irqs(chip, irqs);
+		lpc_dispatch_err_irqs(lpc, irqs);
 
 	/* Handle SerIRQ interrupts */
 	if (irqs & LPC_HC_IRQ_SERIRQ_ALL)
-		lpc_dispatch_ser_irqs(chip, irqs, true);
+		lpc_dispatch_ser_irqs(lpc, irqs, true);
 
  bail:
-	unlock(&chip->lpc_lock);
+	unlock(&lpc->lpc_lock);
 }
 
 void lpc_serirq(uint32_t chip_id, uint32_t index __unused)
 {
 	struct proc_chip *chip = get_chip(chip_id);
+	struct lpcm *lpc;
 	uint32_t irqs;
 	int rc;
 
 	/* No initialized LPC controller on that chip */
-	if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
+	if (!chip || !chip->lpc)
 		return;
+	lpc = chip->lpc;
 
-	lock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
 
 	/* Handle the lpc interrupt source (errors etc...) */
-	rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT, &irqs, 4);
+	rc = opb_read(lpc, lpc_reg_opb_base + LPC_HC_IRQSTAT, &irqs, 4);
 	if (rc) {
 		prerror("LPC: Failed to read LPC IRQ state\n");
 		goto bail;
@@ -844,89 +877,111 @@ void lpc_serirq(uint32_t chip_id, uint32_t index __unused)
 
 	/* Handle SerIRQ interrupts */
 	if (irqs & LPC_HC_IRQ_SERIRQ_ALL)
-		lpc_dispatch_ser_irqs(chip, irqs, true);
+		lpc_dispatch_ser_irqs(lpc, irqs, true);
 
  bail:
-	unlock(&chip->lpc_lock);
+	unlock(&lpc->lpc_lock);
 }
 
 void lpc_all_interrupts(uint32_t chip_id)
 {
 	struct proc_chip *chip = get_chip(chip_id);
+	struct lpcm *lpc;
+
+	/* No initialized LPC controller on that chip */
+	if (!chip || !chip->lpc)
+		return;
+	lpc = chip->lpc;
 
 	/* Dispatch all */
-	lock(&chip->lpc_lock);
-	lpc_dispatch_ser_irqs(chip, LPC_HC_IRQ_SERIRQ_ALL, false);
-	unlock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
+	lpc_dispatch_ser_irqs(lpc, LPC_HC_IRQ_SERIRQ_ALL, false);
+	unlock(&lpc->lpc_lock);
 }
 
 static void lpc_init_chip_p8(struct dt_node *xn)
 {
 	uint32_t gcid = dt_get_chip_id(xn);
 	struct proc_chip *chip;
+	struct lpcm *lpc;
 
 	chip = get_chip(gcid);
 	assert(chip);
 
-	chip->lpc_xbase = dt_get_address(xn, 0, NULL);
-	chip->lpc_fw_idsel = 0xff;
-	chip->lpc_fw_rdsz = 0xff;
-	init_lock(&chip->lpc_lock);
+	lpc = zalloc(sizeof(struct lpcm));
+	assert(lpc);
+	lpc->chip_id = gcid;
+	lpc->lpc_xbase = dt_get_address(xn, 0, NULL);
+	lpc->lpc_fw_idsel = 0xff;
+	lpc->lpc_fw_rdsz = 0xff;
+	list_head_init(&lpc->lpc_clients);
+	init_lock(&lpc->lpc_lock);
 
 	if (lpc_default_chip_id < 0 ||
 	    dt_has_node_property(xn, "primary", NULL)) {
-		lpc_default_chip_id = chip->id;
+		lpc_default_chip_id = gcid;
 	}
 
 	/* Mask all interrupts for now */
-	opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
+	opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
 
-	printf("LPC: Bus on chip %d, access via XSCOM, PCB_Addr=0x%x\n", chip->id, chip->lpc_xbase);
+	printf("LPC[%03x]: Initialiezd, access via XSCOM, PCB_Addr=0x%x\n",
+	       gcid, lpc->lpc_xbase);
 
 	dt_add_property(xn, "interrupt-controller", NULL, 0);
 	dt_add_property_cells(xn, "#interrupt-cells", 1);
 	assert(dt_prop_get_u32(xn, "#address-cells") == 2);
+
+	chip->lpc = lpc;
 }
 
 static void lpc_init_chip_p9(struct dt_node *opb_node)
 {
 	uint32_t gcid = dt_get_chip_id(opb_node);
 	struct proc_chip *chip;
+	struct lpcm *lpc;
 	u64 addr;
 	u32 val;
 
 	chip = get_chip(gcid);
 	assert(chip);
 
+	lpc = zalloc(sizeof(struct lpcm));
+	assert(lpc);
+	lpc->chip_id = gcid;
+
 	/* Grab OPB base address */
 	addr = dt_prop_get_cell(opb_node, "ranges", 1);
 	addr <<= 32;
 	addr |= dt_prop_get_cell(opb_node, "ranges", 2);
 
-	chip->lpc_mbase = (void *)addr;
-	chip->lpc_fw_idsel = 0xff;
-	chip->lpc_fw_rdsz = 0xff;
-	init_lock(&chip->lpc_lock);
+	lpc->lpc_mbase = (void *)addr;
+	lpc->lpc_fw_idsel = 0xff;
+	lpc->lpc_fw_rdsz = 0xff;
+	list_head_init(&lpc->lpc_clients);
+	init_lock(&lpc->lpc_lock);
 
 	if (lpc_default_chip_id < 0 ||
 	    dt_has_node_property(opb_node, "primary", NULL)) {
-		lpc_default_chip_id = chip->id;
+		lpc_default_chip_id = gcid;
 	}
 
 	/* Mask all interrupts for now */
-	opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
+	opb_write(lpc, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
 
-	/* On P9, setup routing to PSI SerIRQ 0 */
-	opb_read(chip, opb_master_reg_base + 8, &val, 4);
+	/* Default with routing to PSI SerIRQ 0 */
+	opb_read(lpc, opb_master_reg_base + 8, &val, 4);
 	val &= 0xff03ffff;
-	opb_write(chip, opb_master_reg_base + 8, val, 4);
-	opb_read(chip, opb_master_reg_base + 0xc, &val, 4);
+	opb_write(lpc, opb_master_reg_base + 8, val, 4);
+	opb_read(lpc, opb_master_reg_base + 0xc, &val, 4);
 	val &= 0xf0000000;
-	opb_write(chip, opb_master_reg_base + 0xc, val, 4);
+	opb_write(lpc, opb_master_reg_base + 0xc, val, 4);
 
-	printf("LPC: Bus on chip %d, access via MMIO @%p\n",
-	       chip->id, chip->lpc_mbase);
 
+	printf("LPC[%03x]: Initialized, access via MMIO @%p\n",
+	       gcid, lpc->lpc_mbase);
+
+	chip->lpc = lpc;
 }
 
 void lpc_init(void)
@@ -943,7 +998,7 @@ void lpc_init(void)
 		has_lpc = true;
 	}
 	if (lpc_default_chip_id >= 0)
-		printf("LPC: Default bus on chip %d\n", lpc_default_chip_id);
+		printf("LPC: Default bus on chip 0x%x\n", lpc_default_chip_id);
 
 	if (has_lpc) {
 		opal_register(OPAL_LPC_WRITE, opal_lpc_write, 5);
@@ -958,9 +1013,12 @@ void lpc_used_by_console(void)
 	xscom_used_by_console();
 
 	for_each_chip(chip) {
-		chip->lpc_lock.in_con_path = true;
-		lock(&chip->lpc_lock);
-		unlock(&chip->lpc_lock);
+		struct lpcm *lpc = chip->lpc;
+		if (lpc) {
+			lpc->lpc_lock.in_con_path = true;
+			lock(&lpc->lpc_lock);
+			unlock(&lpc->lpc_lock);
+		}
 	}
 }
 
@@ -973,7 +1031,9 @@ bool lpc_ok(void)
 	if (!xscom_ok())
 		return false;
 	chip = get_chip(lpc_default_chip_id);
-	return !lock_held_by_me(&chip->lpc_lock);
+	if (!chip->lpc)
+		return false;
+	return !lock_held_by_me(&chip->lpc->lpc_lock);
 }
 
 void lpc_register_client(uint32_t chip_id,
@@ -981,18 +1041,22 @@ void lpc_register_client(uint32_t chip_id,
 {
 	struct lpc_client_entry *ent;
 	struct proc_chip *chip;
+	struct lpcm *lpc;
 
 	chip = get_chip(chip_id);
 	assert(chip);
+	lpc = chip->lpc;
+	if (!lpc) {
+		prerror("LPC: Attempt to register client on bad chip 0x%x\n",
+			chip_id);
+		return;
+	}
 	ent = malloc(sizeof(*ent));
 	assert(ent);
 	ent->clt = clt;
-	lock(&chip->lpc_lock);
-	list_add(&chip->lpc_clients, &ent->node);
-	/* Re-evaluate ser irqs on Naples */
-	if (chip->type == PROC_CHIP_P8_NAPLES ||
-	    chip->type == PROC_CHIP_P9_NIMBUS ||
-	    chip->type == PROC_CHIP_P9_CUMULUS)
-		lpc_setup_serirq(chip);
-	unlock(&chip->lpc_lock);
+	lock(&lpc->lpc_lock);
+	list_add(&lpc->lpc_clients, &ent->node);
+	if (lpc->has_serirq)
+		lpc_setup_serirq(lpc);
+	unlock(&lpc->lpc_lock);
 }
diff --git a/include/chip.h b/include/chip.h
index f62c964..77bc5cf 100644
--- a/include/chip.h
+++ b/include/chip.h
@@ -107,6 +107,7 @@ struct dt_node;
 struct centaur_chip;
 struct mfsi;
 struct xive;
+struct lpcm;
 
 /* Chip type */
 enum proc_chip_type {
@@ -169,12 +170,7 @@ struct proc_chip {
 	uint64_t		xscom_base;
 
 	/* Used by hw/lpc.c */
-	uint32_t		lpc_xbase;
-	void			*lpc_mbase;
-	struct lock		lpc_lock;
-	uint8_t			lpc_fw_idsel;
-	uint8_t			lpc_fw_rdsz;
-	struct list_head	lpc_clients;
+	struct lpcm		*lpc;
 
 	/* Used by hw/slw.c */
 	uint64_t		slw_base;
diff --git a/include/lpc.h b/include/lpc.h
index 42c4755..f173145 100644
--- a/include/lpc.h
+++ b/include/lpc.h
@@ -104,9 +104,6 @@ extern int64_t lpc_read(enum OpalLPCAddressType addr_type, uint32_t addr,
 /* Mark LPC bus as used by console */
 extern void lpc_used_by_console(void);
 
-/* Route SerIRQs to specific PSI/LPC interrupt sources */
-void lpc_route_serirq(uint32_t chip_id, uint32_t sirq, uint32_t psi_idx);
-
 /*
  * Simplified big endian FW accessors
  */
-- 
2.7.4



More information about the Skiboot mailing list