diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2016-08-09 16:38:15 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-08-11 19:54:22 +1000 |
commit | bf4d12f4a93cb3c8ea083586d42afa59a04ec5fc (patch) | |
tree | 0abf8606ea2b5f1720896b41b055fccf838d9ce0 /hw | |
parent | d0a3ec6aea455d8b564f62679ff6f69f91ea7896 (diff) | |
download | skiboot-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')
-rw-r--r-- | hw/lpc.c | 408 |
1 files changed, 235 insertions, 173 deletions
@@ -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); } |