Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/arch/ppc64/include/arch/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define MMIO_GROUP0_CHIP0_LPC_BASE_ADDR 0x8006030000000000
#define LPCHC_IO_SPACE 0xD0010000
#define LPC_BASE_ADDR (MMIO_GROUP0_CHIP0_LPC_BASE_ADDR + LPCHC_IO_SPACE)
#define MMIO_GROUP0_CHIP0_SCOM_BASE_ADDR 0x8006030000000000

/* Enforce In-order Execution of I/O */
static inline void eieio(void)
Expand Down
25 changes: 22 additions & 3 deletions src/cpu/power9/scom.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
#include <console/console.h>

#define XSCOM_DATA_IND_READ PPC_BIT(0)
#define XSCOM_DATA_IND_COMPLETE PPC_BIT(32)
#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)
#define XSCOM_DATA_IND_FORM1_DATA PPC_BITMASK(12,63)
#define XSCOM_IND_MAX_RETRIES 10
#define XSCOM_DATA_IND_FORM1_DATA PPC_BITMASK(12,63)
#define XSCOM_IND_MAX_RETRIES 10

#define XSCOM_RCVED_STAT_REG 0x00090018
#define XSCOM_LOG_REG 0x00090012
#define XSCOM_ERR_REG 0x00090013

/*
* WARNING:
Expand Down Expand Up @@ -157,3 +161,18 @@ uint64_t read_scom_indirect(uint64_t reg_address)

return data & XSCOM_DATA_IND_DATA;
}

/* This function should be rarely called, don't make it inlined */
void reset_scom_engine(void)
{
/*
* With cross-CPU SCOM accesses, first register should be cleared on the
* executing CPU, the other two on target CPU. In that case it may be
* necessary to do the remote writes in assembly directly to skip checking
* HMER and possibly end in a loop.
*/
write_scom_direct(XSCOM_RCVED_STAT_REG, 0);
write_scom_direct(XSCOM_LOG_REG, 0);
write_scom_direct(XSCOM_ERR_REG, 0);
eieio();
}
52 changes: 40 additions & 12 deletions src/include/cpu/power/scom.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#ifndef __ASSEMBLER__
#include <types.h>
#include <arch/io.h>
#include <cpu/power/spr.h>

// TODO: these are probably specific to POWER9
typedef enum
Expand Down Expand Up @@ -85,26 +86,53 @@ typedef enum
EC23_CHIPLET_ID = 0x37 ///< Core23 chiplet (Quad5, EX11, C1)
} chiplet_id_t;

void reset_scom_engine(void);

static uint64_t read_scom_direct(uint64_t reg_address)
{
uint64_t val;
asm volatile(
"ldcix %0, %1, %2":
"=r"(val):
"b"(0x800603FC00000000),
"r"(reg_address << 3));
eieio();
uint64_t hmer;
do {
clear_hmer();
eieio();
asm volatile(
"ldcix %0, %1, %2":
"=r"(val):
"b"(MMIO_GROUP0_CHIP0_SCOM_BASE_ADDR),
"r"(reg_address << 3));
eieio();
hmer = read_hmer();
} while ((hmer & SPR_HMER_XSCOM_STATUS) == SPR_HMER_XSCOM_OCCUPIED);

if (hmer & SPR_HMER_XSCOM_STATUS) {
reset_scom_engine();
/*
* All F's are returned in case of error, but code polls for a set bit
* after changes that can make such error appear (e.g. clock settings).
* Return 0 so caller won't have to test for all F's in that case.
*/
return 0;
}
return val;
}

static void write_scom_direct(uint64_t reg_address, uint64_t data)
{
asm volatile(
"stdcix %0, %1, %2"::
"r"(data),
"b"(0x800603FC00000000),
"r"(reg_address << 3));
eieio();
uint64_t hmer;
do {
clear_hmer();
eieio();
asm volatile(
"stdcix %0, %1, %2"::
"r"(data),
"b"(MMIO_GROUP0_CHIP0_SCOM_BASE_ADDR),
"r"(reg_address << 3));
eieio();
hmer = read_hmer();
} while ((hmer & SPR_HMER_XSCOM_STATUS) == SPR_HMER_XSCOM_OCCUPIED);

if (hmer & SPR_HMER_XSCOM_STATUS)
reset_scom_engine();
}

/*
Expand Down
36 changes: 21 additions & 15 deletions src/include/cpu/power/spr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@

#include <arch/byteorder.h> // PPC_BIT()

#define SPR_HMER 0x150
#define SPR_HMER 0x150
/* Bits in HMER/HMEER */
#define SPR_HMER_MALFUNCTION_ALERT PPC_BIT(0)
#define SPR_HMER_PROC_RECV_DONE PPC_BIT(2)
#define SPR_HMER_PROC_RECV_ERROR_MASKED PPC_BIT(3)
#define SPR_HMER_TFAC_ERROR PPC_BIT(4)
#define SPR_HMER_TFMR_PARITY_ERROR PPC_BIT(5)
#define SPR_HMER_XSCOM_FAIL PPC_BIT(8)
#define SPR_HMER_XSCOM_DONE PPC_BIT(9)
#define SPR_HMER_PROC_RECV_AGAIN PPC_BIT(11)
#define SPR_HMER_WARN_RISE PPC_BIT(14)
#define SPR_HMER_WARN_FALL PPC_BIT(15)
#define SPR_HMER_SCOM_FIR_HMI PPC_BIT(16)
#define SPR_HMER_TRIG_FIR_HMI PPC_BIT(17)
#define SPR_HMER_HYP_RESOURCE_ERR PPC_BIT(20)
#define SPR_HMER_XSCOM_STATUS PPC_BITMASK(21,23)
#define SPR_HMER_MALFUNCTION_ALERT PPC_BIT(0)
#define SPR_HMER_PROC_RECV_DONE PPC_BIT(2)
#define SPR_HMER_PROC_RECV_ERROR_MASKED PPC_BIT(3)
#define SPR_HMER_TFAC_ERROR PPC_BIT(4)
#define SPR_HMER_TFMR_PARITY_ERROR PPC_BIT(5)
#define SPR_HMER_XSCOM_FAIL PPC_BIT(8)
#define SPR_HMER_XSCOM_DONE PPC_BIT(9)
#define SPR_HMER_PROC_RECV_AGAIN PPC_BIT(11)
#define SPR_HMER_WARN_RISE PPC_BIT(14)
#define SPR_HMER_WARN_FALL PPC_BIT(15)
#define SPR_HMER_SCOM_FIR_HMI PPC_BIT(16)
#define SPR_HMER_TRIG_FIR_HMI PPC_BIT(17)
#define SPR_HMER_HYP_RESOURCE_ERR PPC_BIT(20)
#define SPR_HMER_XSCOM_STATUS PPC_BITMASK(21,23)
#define SPR_HMER_XSCOM_OCCUPIED PPC_BIT(23)

#ifndef __ASSEMBLER__
#include <types.h>
Expand All @@ -30,6 +31,11 @@ static inline uint64_t read_hmer(void)
return val;
}

static inline void clear_hmer(void)
{
asm volatile("mtspr %0, %1" :: "i"(SPR_HMER), "r"(0) : "memory");
}

static inline uint64_t read_msr(void)
{
uint64_t val;
Expand Down