diff options
-rw-r--r-- | hw/centaur.c | 109 | ||||
-rw-r--r-- | hw/xscom.c | 12 | ||||
-rw-r--r-- | include/xscom.h | 12 |
3 files changed, 118 insertions, 15 deletions
diff --git a/hw/centaur.c b/hw/centaur.c index 3df1291..5e594c1 100644 --- a/hw/centaur.c +++ b/hw/centaur.c @@ -82,7 +82,7 @@ static int64_t centaur_fsiscom_complete(struct centaur_chip *centaur) if (stat == 0xffffffffu) { cent_log(PR_ERR, centaur, "Chip appears to be dead !\n"); centaur->valid = false; - + /* Here, hostboot grabs a pile of FFDC from the FSI layer, * we could do that too ... */ @@ -215,6 +215,103 @@ struct centaur_chip *get_centaur(uint32_t part_id) return centaur; } +/* + * Indirect XSCOM access functions. Copied from xscom.c, at a + * latter date, we should merge these properly. + */ +static void centaur_xscom_handle_ind_error(struct centaur_chip *centaur, + uint64_t data, uint64_t pcb_addr, + bool is_write) +{ + unsigned int stat = GETFIELD(XSCOM_DATA_IND_ERR, data); + bool timeout = !(data & XSCOM_DATA_IND_COMPLETE); + + /* XXX: Create error log entry ? */ + if (timeout) + cent_log(PR_ERR, centaur, + "inddirect %s timeout, pcb_addr=0x%llx stat=0x%x\n", + is_write ? "write" : "read", pcb_addr, stat); + else + cent_log(PR_ERR, centaur, + "indirect %s error, pcb_addr=0x%llx stat=0x%x\n", + is_write ? "write" : "read", pcb_addr, stat); +} + +static int centaur_xscom_ind_read(struct centaur_chip *centaur, + uint64_t pcb_addr, uint64_t *val) +{ + uint32_t addr; + uint64_t data; + int rc, retries; + + /* Write indirect address */ + addr = pcb_addr & 0x7fffffff; + data = XSCOM_DATA_IND_READ | + (pcb_addr & XSCOM_ADDR_IND_ADDR); + rc = centaur_fsiscom_write(centaur, addr, data); + if (rc) + goto bail; + + /* Wait for completion */ + for (retries = 0; retries < XSCOM_IND_MAX_RETRIES; retries++) { + rc = centaur_fsiscom_read(centaur, addr, &data); + if (rc) + goto bail; + if ((data & XSCOM_DATA_IND_COMPLETE) && + ((data & XSCOM_DATA_IND_ERR) == 0)) { + *val = data & XSCOM_DATA_IND_DATA; + break; + } + if ((data & XSCOM_DATA_IND_COMPLETE) || + (retries >= XSCOM_IND_MAX_RETRIES)) { + centaur_xscom_handle_ind_error(centaur, data, pcb_addr, + false); + rc = OPAL_HARDWARE; + goto bail; + } + } + bail: + if (rc) + *val = (uint64_t)-1; + return rc; +} + +static int centaur_xscom_ind_write(struct centaur_chip *centaur, + uint64_t pcb_addr, uint64_t val) +{ + uint32_t addr; + uint64_t data; + int rc, retries; + + /* Write indirect address & data */ + addr = pcb_addr & 0x7fffffff; + data = pcb_addr & XSCOM_ADDR_IND_ADDR; + data |= val & XSCOM_ADDR_IND_DATA; + + rc = centaur_fsiscom_write(centaur, addr, data); + if (rc) + goto bail; + + /* Wait for completion */ + for (retries = 0; retries < XSCOM_IND_MAX_RETRIES; retries++) { + rc = centaur_fsiscom_read(centaur, addr, &data); + if (rc) + goto bail; + if ((data & XSCOM_DATA_IND_COMPLETE) && + ((data & XSCOM_DATA_IND_ERR) == 0)) + break; + if ((data & XSCOM_DATA_IND_COMPLETE) || + (retries >= XSCOM_IND_MAX_RETRIES)) { + centaur_xscom_handle_ind_error(centaur, data, pcb_addr, + true); + rc = OPAL_HARDWARE; + goto bail; + } + } + bail: + return rc; +} + int64_t centaur_xscom_read(uint32_t id, uint64_t pcb_addr, uint64_t *val) { struct centaur_chip *centaur = get_centaur(id); @@ -224,7 +321,10 @@ int64_t centaur_xscom_read(uint32_t id, uint64_t pcb_addr, uint64_t *val) return OPAL_PARAMETER; lock(¢aur->lock); - rc = centaur_fsiscom_read(centaur, pcb_addr, val); + if (pcb_addr & XSCOM_ADDR_IND_FLAG) + rc = centaur_xscom_ind_read(centaur, pcb_addr, val); + else + rc = centaur_fsiscom_read(centaur, pcb_addr, val); unlock(¢aur->lock); return rc; @@ -239,7 +339,10 @@ int64_t centaur_xscom_write(uint32_t id, uint64_t pcb_addr, uint64_t val) return OPAL_PARAMETER; lock(¢aur->lock); - rc = centaur_fsiscom_write(centaur, pcb_addr, val); + if (pcb_addr & XSCOM_ADDR_IND_FLAG) + rc = centaur_xscom_ind_write(centaur, pcb_addr, val); + else + rc = centaur_fsiscom_write(centaur, pcb_addr, val); unlock(¢aur->lock); return rc; @@ -29,18 +29,6 @@ SPR_HMER_XSCOM_DONE | \ SPR_HMER_XSCOM_STATUS)) -#define XSCOM_ADDR_IND_FLAG PPC_BIT(0) -#define XSCOM_ADDR_IND_ADDR PPC_BITMASK(12,31) -#define XSCOM_ADDR_IND_DATA PPC_BITMASK(48,63) - -#define XSCOM_DATA_IND_READ PPC_BIT(0) -#define XSCOM_DATA_IND_COMPLETE PPC_BIT(32) -#define XSCOM_DATA_IND_ERR PPC_BITMASK(33,35) -#define XSCOM_DATA_IND_DATA PPC_BITMASK(48,63) - -/* HB folks say: try 10 time for now */ -#define XSCOM_IND_MAX_RETRIES 10 - DEFINE_LOG_ENTRY(OPAL_RC_XSCOM_RW, OPAL_PLATFORM_ERR_EVT, OPAL_XSCOM, OPAL_CEC_HARDWARE, OPAL_PREDICTIVE_ERR_GENERAL, OPAL_NA); diff --git a/include/xscom.h b/include/xscom.h index 6e47c0d..933af6a 100644 --- a/include/xscom.h +++ b/include/xscom.h @@ -154,6 +154,18 @@ #define EX_PM_IDLE_ST_HIST_PM_STATE_MASK PPC_BITMASK(0, 2) #define EX_PM_IDLE_ST_HIST_PM_STATE_LSH PPC_BITLSHIFT(2) +/* Definitions relating to indirect XSCOMs shared with centaur */ +#define XSCOM_ADDR_IND_FLAG PPC_BIT(0) +#define XSCOM_ADDR_IND_ADDR PPC_BITMASK(12,31) +#define XSCOM_ADDR_IND_DATA PPC_BITMASK(48,63) + +#define XSCOM_DATA_IND_READ PPC_BIT(0) +#define XSCOM_DATA_IND_COMPLETE PPC_BIT(32) +#define XSCOM_DATA_IND_ERR PPC_BITMASK(33,35) +#define XSCOM_DATA_IND_DATA PPC_BITMASK(48,63) + +/* HB folks say: try 10 time for now */ +#define XSCOM_IND_MAX_RETRIES 10 /* * Error handling: |