aboutsummaryrefslogtreecommitdiff
path: root/hw/lpc.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-08-09 16:38:15 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-08-11 19:54:22 +1000
commitbf4d12f4a93cb3c8ea083586d42afa59a04ec5fc (patch)
tree0abf8606ea2b5f1720896b41b055fccf838d9ce0 /hw/lpc.c
parentd0a3ec6aea455d8b564f62679ff6f69f91ea7896 (diff)
downloadskiboot-bf4d12f4a93cb3c8ea083586d42afa59a04ec5fc.zip
skiboot-bf4d12f4a93cb3c8ea083586d42afa59a04ec5fc.tar.gz
skiboot-bf4d12f4a93cb3c8ea083586d42afa59a04ec5fc.tar.bz2
lpc: Move LPC instance variables to a private structure
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@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/lpc.c')
-rw-r--r--hw/lpc.c408
1 files changed, 235 insertions, 173 deletions
diff --git a/hw/lpc.c b/hw/lpc.c
index 8def775..ab458b0 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -110,6 +110,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;
@@ -130,33 +141,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:
@@ -173,7 +184,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);
@@ -183,7 +194,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);
@@ -191,7 +202,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",
@@ -212,32 +224,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("Invalid data size %d\n", sz);
@@ -247,7 +259,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);
@@ -255,7 +267,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",
@@ -288,39 +301,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("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("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:
@@ -341,17 +354,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("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)
@@ -398,12 +411,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;
}
@@ -414,41 +427,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);
}
/*
@@ -459,12 +473,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++;
@@ -473,41 +492,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);
}
/*
@@ -518,15 +538,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));
@@ -541,7 +566,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;
@@ -551,10 +576,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("Failed to update irq mask\n");
return;
@@ -562,19 +587,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("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");
}
@@ -582,13 +607,13 @@ static void lpc_setup_serirq(struct proc_chip *chip)
prerror("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("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("Failed to readback ctrl");
@@ -597,13 +622,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) {
@@ -614,47 +637,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("Failed to init interrutps\n");
- return;
+ prerror("LPC: Failed to init interrutps\n");
+ 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("Failed to set interrupt mask\n");
- return;
+ prerror("LPC: Failed to set interrupt mask\n");
+ 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:
@@ -663,17 +680,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;
@@ -684,63 +712,64 @@ static void lpc_dispatch_reset(struct proc_chip *chip)
* on/off rather than just reset
*/
- prerror("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("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 address: Unknown\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 "
- "Error address: 0x%08x\n",
- sync_err, err_addr);
+ log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "LPC[%03x]: %s "
+ "Error address reg: 0x%08x\n",
+ 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;
@@ -750,14 +779,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);
}
}
@@ -767,7 +796,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("Failed to clear SerIRQ latches !\n");
}
@@ -775,21 +804,23 @@ 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("Failed to read OPB IRQ state\n");
- unlock(&chip->lpc_lock);
+ unlock(&lpc->lpc_lock);
return;
}
@@ -802,7 +833,7 @@ void lpc_interrupt(uint32_t chip_id)
}
/* 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("Failed to read LPC IRQ state\n");
goto bail;
@@ -812,32 +843,34 @@ 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:
/* Ack it at the OPB level */
- 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);
- 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;
@@ -847,89 +880,110 @@ 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]: Initialized, access via XSCOM @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",
- gcid, chip->lpc_mbase);
+ printf("LPC[%03x]: Initialized, access via MMIO @%p\n",
+ gcid, lpc->lpc_mbase);
+
+ chip->lpc = lpc;
}
void lpc_init(void)
@@ -946,8 +1000,7 @@ void lpc_init(void)
has_lpc = true;
}
if (lpc_default_chip_id >= 0)
- prlog(PR_NOTICE, "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);
@@ -962,9 +1015,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);
+ }
}
}
@@ -977,7 +1033,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,
@@ -985,18 +1043,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);
}