diff --git a/bmc-kernel.dts.m4 b/bmc-kernel.dts.m4 index 6681d481d..e07a98d9c 100644 --- a/bmc-kernel.dts.m4 +++ b/bmc-kernel.dts.m4 @@ -14,6 +14,26 @@ define(`PIB', }; ')dnl + +dnl +dnl PIB_ODY([index], [proc], [path-index], port) +dnl +define(`PIB_ODY', +` + pib_ody@$3$4 { + #address-cells = <0x2>; + #size-cells = <0x1>; + reg = <0x0 0x$1 0x8000>; /*dummy to fix dts warning*/ + compatible = "ibm,kernel-pib-ody"; + index = <0x$1>; + proc = <0x$2>; + port = <$4>; + device-path = "/dev/scom$3$4"; + system-path = "/proc$2/ocmb$1"; + }; +')dnl + + dnl dnl SBEFIFO([index], [path-index]) dnl @@ -106,6 +126,38 @@ define(`HMFSI', }; ')dnl +//ody ocmb chips are defined in system device tree. The pdbg targets +//that captures the device path to communicate with system ody ocmb +//chips will be defined in backend device tree. + +//ody ocmb system device tree targets need to be mapped to backend +//ody pib device tree targets for communication with the ody ocmb targets. +//Mapping is done based on proc, ocmb chip index of the ody ocmb system target +//with the proc, ocmb index and port number defined in the backend kernel device +//tree + +//for get or put scom in kernel mode device path defined in PIBODY will be used +//for cfam device-path specified in HMFSIODY will be used +dnl +dnl HMFSI_ODY([index], [proc], [path-index], [port]) +dnl +define(`HMFSI_ODY', +` + hmfsi-ody@$3$4 { + #address-cells = <0x2>; + #size-cells = <0x1>; + compatible = "ibm,kernel-fsi-ody"; + device-path = "/i2cr$3$4/slave@00:00/raw"; + reg = <0x0 0x$1 0x8000>; /*dummy to fix dts warning*/ + index = <0x$1>; + proc = <0x$2>; + port = <$4>; + system-path = "/proc$2/ocmb$1/fsi"; + + PIB_ODY($1, $2, $3, $4) + /*SBE_FIFO not required in kernel mode */ + }; +')dnl /dts-v1/; @@ -141,4 +193,77 @@ define(`HMFSI', HMFSI(400000, 7, 7, 8) FSI_POST() + + HMFSI_ODY(0, 0, 1, 00) + HMFSI_ODY(1, 0, 1, 01) + HMFSI_ODY(2, 0, 1, 10) + HMFSI_ODY(3, 0, 1, 11) + HMFSI_ODY(4, 0, 1, 12) + HMFSI_ODY(5, 0, 1, 13) + HMFSI_ODY(6, 0, 1, 14) + HMFSI_ODY(7, 0, 1, 15) + + HMFSI_ODY(0, 1, 2, 02) + HMFSI_ODY(1, 1, 2, 03) + HMFSI_ODY(2, 1, 2, 10) + HMFSI_ODY(3, 1, 2, 11) + HMFSI_ODY(4, 1, 2, 14) + HMFSI_ODY(5, 1, 2, 15) + HMFSI_ODY(6, 1, 2, 16) + HMFSI_ODY(7, 1, 2, 17) + + + HMFSI_ODY(0, 2, 3, 00) + HMFSI_ODY(1, 2, 3, 01) + HMFSI_ODY(2, 2, 3, 10) + HMFSI_ODY(3, 2, 3, 11) + HMFSI_ODY(4, 2, 3, 12) + HMFSI_ODY(5, 2, 3, 13) + HMFSI_ODY(6, 2, 3, 14) + HMFSI_ODY(7, 2, 3, 15) + + HMFSI_ODY(0, 3, 4, 02) + HMFSI_ODY(1, 3, 4, 03) + HMFSI_ODY(2, 3, 4, 10) + HMFSI_ODY(3, 3, 4, 11) + HMFSI_ODY(4, 3, 4, 14) + HMFSI_ODY(5, 3, 4, 15) + HMFSI_ODY(6, 3, 4, 16) + HMFSI_ODY(7, 3, 4, 17) + + HMFSI_ODY(0, 4, 5, 00) + HMFSI_ODY(1, 4, 5, 01) + HMFSI_ODY(2, 4, 5, 10) + HMFSI_ODY(3, 4, 5, 11) + HMFSI_ODY(4, 4, 5, 12) + HMFSI_ODY(5, 4, 5, 13) + HMFSI_ODY(6, 4, 5, 14) + HMFSI_ODY(7, 4, 5, 15) + + HMFSI_ODY(0, 5, 6, 02) + HMFSI_ODY(1, 5, 6, 03) + HMFSI_ODY(2, 5, 6, 10) + HMFSI_ODY(3, 5, 6, 11) + HMFSI_ODY(4, 5, 6, 14) + HMFSI_ODY(5, 5, 6, 15) + HMFSI_ODY(6, 5, 6, 16) + HMFSI_ODY(7, 5, 6, 17) + + HMFSI_ODY(0, 6, 7, 00) + HMFSI_ODY(1, 6, 7, 01) + HMFSI_ODY(2, 6, 7, 10) + HMFSI_ODY(3, 6, 7, 11) + HMFSI_ODY(4, 6, 7, 12) + HMFSI_ODY(5, 6, 7, 13) + HMFSI_ODY(6, 6, 7, 14) + HMFSI_ODY(7, 6, 7, 15) + + HMFSI_ODY(0, 7, 8, 02) + HMFSI_ODY(1, 7, 8, 03) + HMFSI_ODY(2, 7, 8, 10) + HMFSI_ODY(3, 7, 8, 11) + HMFSI_ODY(4, 7, 8, 14) + HMFSI_ODY(5, 7, 8, 15) + HMFSI_ODY(6, 7, 8, 16) + HMFSI_ODY(7, 7, 8, 17) }; diff --git a/bmc-sbefifo.dts.m4 b/bmc-sbefifo.dts.m4 index 462a25050..1541cdfa4 100644 --- a/bmc-sbefifo.dts.m4 +++ b/bmc-sbefifo.dts.m4 @@ -81,6 +81,60 @@ define(`HMFSI', }; ')dnl +//ocmb ody ddr5 chip SBE instance will be mapped to /dev/sbefifoXYY +//device path where X is proc and YY is port. BMC need to use this +//path for get/put scom to SBE instance of the ocmb ddr5 chip. + +//ody ocmb chips will be defined in system device tree, where as how +//the sbe instances of these ody ocmb chips will be defined in this +//backend device tree + +//ody ocmb system device tree targets will be mapped to backend +//ody sbefifo device tree targets based on proc, ocmb chip index +dnl +dnl HMFSI_ODY([index], [proc], [path-index], [port]) +dnl +define(`HMFSI_ODY', +` + hmfsi-ody@$3$4 { + #address-cells = <0x2>; + #size-cells = <0x1>; + compatible = "ibm,kernel-fsi-ody"; + device-path = "/i2cr$3$4/slave@00:00/raw"; + reg = <0x0 0x$1 0x8000>; /*dummy to fix dts warning*/ + index = <0x$1>; + proc = <0x$2>; + port = <$4>; + + SBEFIFO_ODY($1, $2, $3, $4) + }; +')dnl + +dnl +dnl SBEFIFO_ODY([index], [proc], [path-index], [port] []) +dnl +define(`SBEFIFO_ODY', +` + sbefifo-ody@$3$4{ /* Bogus address */ + #address-cells = <0x2>; + #size-cells = <0x1>; + compatible = "ibm,kernel-sbefifo-ody"; + reg = <0x0 0x$1 0x8000>; /*dummy to fix dts warning*/ + index = <0x$1>; + proc = <0x$2>; + port = <$4>; + device-path = "/dev/sbefifo$3$4"; + + sbefifo-chipop-ody { + compatible = "ibm,sbefifo-chipop-ody"; + index = <0x$1>; + proc = <0x$2>; + port = <$4>; + }; + }; + +')dnl + dnl dnl BMC_I2CBUS([index]) dnl @@ -131,4 +185,77 @@ define(`BMC_I2CBUS', HMFSI(400000, 7, 7, 8) FSI_POST() + + HMFSI_ODY(0, 0, 1, 00) + HMFSI_ODY(1, 0, 1, 01) + HMFSI_ODY(2, 0, 1, 10) + HMFSI_ODY(3, 0, 1, 11) + HMFSI_ODY(4, 0, 1, 12) + HMFSI_ODY(5, 0, 1, 13) + HMFSI_ODY(6, 0, 1, 14) + HMFSI_ODY(7, 0, 1, 15) + + HMFSI_ODY(0, 1, 2, 02) + HMFSI_ODY(1, 1, 2, 03) + HMFSI_ODY(2, 1, 2, 10) + HMFSI_ODY(3, 1, 2, 11) + HMFSI_ODY(4, 1, 2, 14) + HMFSI_ODY(5, 1, 2, 15) + HMFSI_ODY(6, 1, 2, 16) + HMFSI_ODY(7, 1, 2, 17) + + + HMFSI_ODY(0, 2, 3, 00) + HMFSI_ODY(1, 2, 3, 01) + HMFSI_ODY(2, 2, 3, 10) + HMFSI_ODY(3, 2, 3, 11) + HMFSI_ODY(4, 2, 3, 12) + HMFSI_ODY(5, 2, 3, 13) + HMFSI_ODY(6, 2, 3, 14) + HMFSI_ODY(7, 2, 3, 15) + + HMFSI_ODY(0, 3, 4, 02) + HMFSI_ODY(1, 3, 4, 03) + HMFSI_ODY(2, 3, 4, 10) + HMFSI_ODY(3, 3, 4, 11) + HMFSI_ODY(4, 3, 4, 14) + HMFSI_ODY(5, 3, 4, 15) + HMFSI_ODY(6, 3, 4, 16) + HMFSI_ODY(7, 3, 4, 17) + + HMFSI_ODY(0, 4, 5, 00) + HMFSI_ODY(1, 4, 5, 01) + HMFSI_ODY(2, 4, 5, 10) + HMFSI_ODY(3, 4, 5, 11) + HMFSI_ODY(4, 4, 5, 12) + HMFSI_ODY(5, 4, 5, 13) + HMFSI_ODY(6, 4, 5, 14) + HMFSI_ODY(7, 4, 5, 15) + + HMFSI_ODY(0, 5, 6, 02) + HMFSI_ODY(1, 5, 6, 03) + HMFSI_ODY(2, 5, 6, 10) + HMFSI_ODY(3, 5, 6, 11) + HMFSI_ODY(4, 5, 6, 14) + HMFSI_ODY(5, 5, 6, 15) + HMFSI_ODY(6, 5, 6, 16) + HMFSI_ODY(7, 5, 6, 17) + + HMFSI_ODY(0, 6, 7, 00) + HMFSI_ODY(1, 6, 7, 01) + HMFSI_ODY(2, 6, 7, 10) + HMFSI_ODY(3, 6, 7, 11) + HMFSI_ODY(4, 6, 7, 12) + HMFSI_ODY(5, 6, 7, 13) + HMFSI_ODY(6, 6, 7, 14) + HMFSI_ODY(7, 6, 7, 15) + + HMFSI_ODY(0, 7, 8, 02) + HMFSI_ODY(1, 7, 8, 03) + HMFSI_ODY(2, 7, 8, 10) + HMFSI_ODY(3, 7, 8, 11) + HMFSI_ODY(4, 7, 8, 14) + HMFSI_ODY(5, 7, 8, 15) + HMFSI_ODY(6, 7, 8, 16) + HMFSI_ODY(7, 7, 8, 17) }; diff --git a/libpdbg/dtb.c b/libpdbg/dtb.c index c65d2003b..b4e2084d2 100644 --- a/libpdbg/dtb.c +++ b/libpdbg/dtb.c @@ -57,6 +57,10 @@ static enum pdbg_proc pdbg_proc = PDBG_PROC_UNKNOWN; static enum pdbg_backend pdbg_backend = PDBG_DEFAULT_BACKEND; static const char *pdbg_backend_option; + +static const uint16_t ODYSSEY_CHIP_ID = 0x60C0; +static const uint8_t ATTR_TYPE_OCMB_CHIP = 75; + static struct pdbg_dtb pdbg_dtb = { .backend = { .fd = -1, @@ -608,6 +612,21 @@ static void close_dtb(struct pdbg_mfile *mfile) } } +bool is_ody_ocmb_chip(struct pdbg_target *target) +{ + uint8_t type; + pdbg_target_get_attribute(target, "ATTR_TYPE", 1, 1, &type); + if(type != ATTR_TYPE_OCMB_CHIP) { + return false; + } + uint32_t chipId = 0; + pdbg_target_get_attribute(target, "ATTR_CHIP_ID", 4, 1, &chipId); + if(chipId == ODYSSEY_CHIP_ID) { + return true; + } + return false; +} + __attribute__((destructor)) static void pdbg_close_targets(void) { diff --git a/libpdbg/hwunit.h b/libpdbg/hwunit.h index 563b58124..c3edce938 100644 --- a/libpdbg/hwunit.h +++ b/libpdbg/hwunit.h @@ -86,6 +86,13 @@ struct chipop { }; #define target_to_chipop(x) container_of(x, struct chipop, target) +struct chipop_ody { + struct pdbg_target target; + uint32_t (*ffdc_get)(struct pdbg_target *, const uint8_t **, uint32_t *); + int (*dump)(struct chipop_ody *, uint8_t, uint8_t, uint8_t, uint8_t **, uint32_t *); +}; +#define target_to_chipop_ody(x) container_of(x, struct chipop_ody, target) + struct sbefifo { struct pdbg_target target; struct sbefifo_context *sf_ctx; diff --git a/libpdbg/kernel.c b/libpdbg/kernel.c index c239c0696..792c8354f 100644 --- a/libpdbg/kernel.c +++ b/libpdbg/kernel.c @@ -214,6 +214,20 @@ static struct fsi kernel_fsi = { }; DECLARE_HW_UNIT(kernel_fsi); +static struct fsi kernel_fsi_ody = { + .target = { + .name = "Kernel based FSI master for odyssey", + .compatible = "ibm,kernel-fsi-ody", + .class = "fsi-ody", + .probe = kernel_fsi_probe, + .release = kernel_fsi_release, + }, + .read = kernel_fsi_getcfam, + .write = kernel_fsi_putcfam, +}; +DECLARE_HW_UNIT(kernel_fsi_ody); + + static int kernel_pib_getscom(struct pib *pib, uint64_t addr, uint64_t *value) { int rc; @@ -270,9 +284,24 @@ struct pib kernel_pib = { }; DECLARE_HW_UNIT(kernel_pib); +struct pib kernel_pib_ody = { + .target = { + .name = "Kernel based FSI SCOM for odyssey", + .compatible = "ibm,kernel-pib-ody", + .class = "pib-ody", + .probe = kernel_pib_probe, + }, + .read = kernel_pib_getscom, + .write = kernel_pib_putscom, +}; +DECLARE_HW_UNIT(kernel_pib_ody); + + __attribute__((constructor)) static void register_kernel(void) { pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_fsi_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_fsi_ody_hw_unit); pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_pib_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_pib_ody_hw_unit); } diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h index b2a36b5c6..ab4525963 100644 --- a/libpdbg/libpdbg.h +++ b/libpdbg/libpdbg.h @@ -760,6 +760,24 @@ int fsi_write(struct pdbg_target *target, uint32_t addr, uint32_t val); */ int fsi_write_mask(struct pdbg_target *target, uint32_t addr, uint32_t val, uint32_t mask); +/** + * @brief Read a CFAM FSI register + * @param[in] target the pdbg_target + * @param[in] addr the CFAM address offset + * @param[out] val the read data + * @return int 0 if successful, -1 otherwise + */ +int fsi_ody_read(struct pdbg_target *target, uint32_t addr, uint32_t *val); + +/** + * @brief Write a CFAM FSI register + * @param[in] target the pdbg_target + * @param[in] addr the address offset relative to target + * @param[in] val the write data + * @return int 0 if successful, -1 otherwise + */ +int fsi_ody_write(struct pdbg_target *target, uint32_t addr, uint32_t val); + /** * @brief Read a PIB SCOM register * @param[in] target the pdbg_target @@ -778,6 +796,24 @@ int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val); */ int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val); +/** + * @brief Read a PIB odyssey ocmb SCOM register + * @param[in] target the pdbg_target + * @param[in] addr the address offset relative to target + * @param[out] val the read data + * @return int 0 if successful, -1 otherwise + */ +int pib_ody_read(struct pdbg_target *target, uint64_t addr, uint64_t *val); + +/** + * @brief Write a PIB odyssey ocmb SCOM register + * @param[in] target the pdbg_target + * @param[in] addr the address offset relative to target + * @param[out] val the write data + * @return int 0 if successful, -1 otherwise + */ +int pib_ody_write(struct pdbg_target *target, uint64_t addr, uint64_t val); + /** * @brief Write a PIB SCOM register with a mask * @param[in] target the pdbg_target @@ -798,6 +834,27 @@ int pib_write_mask(struct pdbg_target *target, uint64_t addr, uint64_t val, uint */ int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data); +/** + * @brief Get the PIB pdbg target for the matching odyssey ocmb chip target + * @param[in] target the ocmb pdbg_target + * @return pib target + */ +struct pdbg_target* get_ody_pib_target(struct pdbg_target* target); + +/** + * @brief Get the fsi pdbg target for the matching odyssey ocmb chip target + * @param[in] target ocmb pdbg_target + * @return fsi target + */ +struct pdbg_target* get_ody_fsi_target(struct pdbg_target* target); + +/** + * @brief Get the fsi pdbg target for the matching odyssey ocmb chip target + * @param[in] target ocmb pdbg_target + * @return fsi target + */ +struct pdbg_target* get_ody_chipop_target(struct pdbg_target* target); + /** * @brief Read data from i2c device * diff --git a/libpdbg/ocmb.c b/libpdbg/ocmb.c index c43672640..a341577d2 100644 --- a/libpdbg/ocmb.c +++ b/libpdbg/ocmb.c @@ -39,32 +39,44 @@ static struct sbefifo *ocmb_to_sbefifo(struct ocmb *ocmb) static int sbefifo_ocmb_getscom(struct ocmb *ocmb, uint64_t addr, uint64_t *value) { - struct sbefifo *sbefifo = ocmb_to_sbefifo(ocmb); - struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); - uint8_t instance_id; + if(is_ody_ocmb_chip(&ocmb->target)) { + struct sbefifo *sbefifo = ody_ocmb_to_sbefifo(&ocmb->target); + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + return sbefifo_scom_get(sctx, addr, value); + } else { + struct sbefifo *sbefifo = ocmb_to_sbefifo(ocmb); + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + uint8_t instance_id; - instance_id = pdbg_target_index(&ocmb->target) & 0xff; + instance_id = pdbg_target_index(&ocmb->target) & 0xff; - return sbefifo_hw_register_get(sctx, - SBEFIFO_TARGET_TYPE_OCMB, - instance_id, - addr, - value); + return sbefifo_hw_register_get(sctx, + SBEFIFO_TARGET_TYPE_OCMB, + instance_id, + addr, + value); + } } static int sbefifo_ocmb_putscom(struct ocmb *ocmb, uint64_t addr, uint64_t value) { - struct sbefifo *sbefifo = ocmb_to_sbefifo(ocmb); - struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); - uint8_t instance_id; + if(is_ody_ocmb_chip(&ocmb->target)) { + struct sbefifo *sbefifo = ody_ocmb_to_sbefifo(&ocmb->target); + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + return sbefifo_scom_put(sctx, addr, value); + } else { + struct sbefifo *sbefifo = ocmb_to_sbefifo(ocmb); + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + uint8_t instance_id; - instance_id = pdbg_target_index(&ocmb->target) & 0xff; + instance_id = pdbg_target_index(&ocmb->target) & 0xff; - return sbefifo_hw_register_put(sctx, - SBEFIFO_TARGET_TYPE_OCMB, - instance_id, - addr, - value); + return sbefifo_hw_register_put(sctx, + SBEFIFO_TARGET_TYPE_OCMB, + instance_id, + addr, + value); + } } static struct ocmb sbefifo_ocmb = { diff --git a/libpdbg/sbe_api.c b/libpdbg/sbe_api.c index ecedc4fe3..72c293a73 100644 --- a/libpdbg/sbe_api.c +++ b/libpdbg/sbe_api.c @@ -170,55 +170,101 @@ int sbe_mpipl_get_ti_info(struct pdbg_target *target, uint8_t **data, uint32_t * return 0; } -int sbe_dump(struct pdbg_target *target, uint8_t type, uint8_t clock, uint8_t fa_collect, uint8_t **data, uint32_t *data_len) +int sbe_dump(struct pdbg_target *target, uint8_t type, uint8_t clock, + uint8_t fa_collect, uint8_t **data, uint32_t *data_len) { - struct chipop *chipop; - int rc; + if(!is_ody_ocmb_chip(target)) { + struct chipop *chipop; + int rc; - chipop = pib_to_chipop(target); - if (!chipop) - return -1; + chipop = pib_to_chipop(target); + if (!chipop) + return -1; - if (!chipop->dump) { - PR_ERROR("dump() not implemented for the target\n"); - return -1; - } + if (!chipop->dump) { + PR_ERROR("dump() not implemented for the target\n"); + return -1; + } - rc = chipop->dump(chipop, type, clock, fa_collect, data, data_len); - if (rc) { - PR_ERROR("sbe dump() returned rc=%d\n", rc); - return -1; - } + rc = chipop->dump(chipop, type, clock, fa_collect, data, data_len); + if (rc) { + PR_ERROR("sbe dump() returned rc=%d\n", rc); + return -1; + } + } else { + struct chipop_ody *chipop; + int rc; + struct pdbg_target *co_target = get_ody_chipop_target(target); + chipop = target_to_chipop_ody(co_target); + if (!chipop) + return -1; + if (!chipop->dump) { + PR_ERROR("dump() not implemented for the target\n"); + return -1; + } + rc = chipop->dump(chipop, type, clock, fa_collect, data, data_len); + if (rc) { + PR_ERROR("sbe dump() returned rc=%d\n", rc); + return -1; + } + } return 0; } -int sbe_ffdc_get(struct pdbg_target *target, uint32_t *status, uint8_t **ffdc, uint32_t *ffdc_len) +int sbe_ffdc_get(struct pdbg_target *target, uint32_t *status, uint8_t **ffdc, + uint32_t *ffdc_len) { - struct chipop *chipop; - const uint8_t *data = NULL; - uint32_t len = 0; - - chipop = pib_to_chipop(target); - if (!chipop) - return -1; + if(!is_ody_ocmb_chip(target)) { + struct chipop *chipop; + const uint8_t *data = NULL; + uint32_t len = 0; - if (!chipop->ffdc_get) { - PR_ERROR("ffdc_get() not implemented for the target\n"); - return -1; - } + chipop = pib_to_chipop(target); + if (!chipop) + return -1; - *status = chipop->ffdc_get(chipop, &data, &len); - if (data && len > 0) { - *ffdc = malloc(len); - assert(*ffdc); - memcpy(*ffdc, data, len); - *ffdc_len = len; + if (!chipop->ffdc_get) { + PR_ERROR("ffdc_get() not implemented for the target\n"); + return -1; + } + + *status = chipop->ffdc_get(chipop, &data, &len); + if (data && len > 0) { + *ffdc = malloc(len); + assert(*ffdc); + memcpy(*ffdc, data, len); + *ffdc_len = len; + } else { + *ffdc = NULL; + *ffdc_len = 0; + } } else { - *ffdc = NULL; - *ffdc_len = 0; - } + struct chipop_ody *chipop; + const uint8_t *data = NULL; + uint32_t len = 0; + struct pdbg_target *co_target = get_ody_chipop_target(target); + chipop = target_to_chipop_ody(co_target); + if (!chipop) + return -1; + + if (!chipop->ffdc_get) { + PR_ERROR("ffdc_get() not implemented for the target\n"); + return -1; + } + + *status = chipop->ffdc_get(target, &data, &len); + if (data && len > 0) { + *ffdc = malloc(len); + assert(*ffdc); + memcpy(*ffdc, data, len); + *ffdc_len = len; + } else { + *ffdc = NULL; + *ffdc_len = 0; + } + } return 0; } diff --git a/libpdbg/sbefifo.c b/libpdbg/sbefifo.c index 98d46a7e4..b2d42958e 100644 --- a/libpdbg/sbefifo.c +++ b/libpdbg/sbefifo.c @@ -197,6 +197,37 @@ static uint32_t sbefifo_op_ffdc_get(struct chipop *chipop, const uint8_t **ffdc, } +static uint32_t sbefifo_op_ody_ffdc_get(struct pdbg_target *ocmb, const uint8_t **ffdc, uint32_t *ffdc_len) +{ + struct pdbg_target *fsi = get_ody_fsi_target(ocmb); + struct sbefifo *sbefifo = target_to_sbefifo(ocmb); + + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + uint32_t status, value = 0; + int rc; + + status = sbefifo_ffdc_get(sctx, ffdc, ffdc_len); + if (status) + return status; + + /* Check if async FFDC is set */ + rc = fsi_ody_read(fsi, SBE_MSG_REG, &value); + if (rc) { + PR_NOTICE("Failed to read sbe mailbox register\n"); + goto end; + } + + if ((value & SBE_MSG_ASYNC_FFDC) == SBE_MSG_ASYNC_FFDC) { + sbefifo_get_ffdc(sbefifo->sf_ctx); + return sbefifo_ffdc_get(sctx, ffdc, ffdc_len); + } + +end: + *ffdc = NULL; + *ffdc_len = 0; + return 0; + +} static int sbefifo_op_istep(struct chipop *chipop, uint32_t major, uint32_t minor) { @@ -239,6 +270,13 @@ static int sbefifo_op_dump(struct chipop *chipop, uint8_t type, uint8_t clock, u return sbefifo_get_dump(sctx, type, clock, fa_collect, data, data_len); } +static int sbefifo_op_ody_dump(struct chipop_ody *chipop, uint8_t type, uint8_t clock, uint8_t fa_collect, uint8_t **data, uint32_t *data_len) +{ + struct sbefifo *sbefifo = target_to_sbefifo(chipop->target.parent); + struct sbefifo_context *sctx = sbefifo->get_sbefifo_context(sbefifo); + + return sbefifo_get_dump(sctx, type, clock, fa_collect, data, data_len); +} static int sbefifo_op_lpc_timeout(struct chipop *chipop, uint32_t *timeout_flag) { @@ -860,6 +898,17 @@ static struct chipop sbefifo_chipop = { }; DECLARE_HW_UNIT(sbefifo_chipop); +static struct chipop_ody sbefifo_chipop_ody = { + .target = { + .name = "SBE FIFO Chip-op engine odyssey", + .compatible = "ibm,sbefifo-chipop-ody", + .class = "chipop-ody", + }, + .dump = sbefifo_op_ody_dump, + .ffdc_get = sbefifo_op_ody_ffdc_get, +}; +DECLARE_HW_UNIT(sbefifo_chipop_ody); + static struct pib sbefifo_pib = { .target = { .name = "SBE FIFO Chip-op based PIB", @@ -919,11 +968,25 @@ static struct sbefifo kernel_sbefifo = { }; DECLARE_HW_UNIT(kernel_sbefifo); +static struct sbefifo kernel_sbefifo_ody = { + .target = { + .name = "Kernel based FSI SBE FIFO", + .compatible = "ibm,kernel-sbefifo-ody", + .class = "sbefifo-ody", + .probe = sbefifo_probe, + .release = sbefifo_release, + }, + .get_sbefifo_context = sbefifo_op_get_context, +}; +DECLARE_HW_UNIT(kernel_sbefifo_ody); + __attribute__((constructor)) static void register_sbefifo(void) { pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_sbefifo_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &kernel_sbefifo_ody_hw_unit); pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &sbefifo_chipop_hw_unit); + pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &sbefifo_chipop_ody_hw_unit); pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &sbefifo_pib_hw_unit); pdbg_hwunit_register(PDBG_BACKEND_SBEFIFO, &sbefifo_thread_hw_unit); pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &sbefifo_mem_hw_unit); diff --git a/libpdbg/target.c b/libpdbg/target.c index 5b517ca56..0e8061b64 100644 --- a/libpdbg/target.c +++ b/libpdbg/target.c @@ -155,6 +155,32 @@ int pib_read(struct pdbg_target *pib_dt, uint64_t addr, uint64_t *data) return rc; } +int pib_ody_read(struct pdbg_target *pib_dt, uint64_t addr, uint64_t *data) +{ + struct pib *pib; + uint64_t target_addr = addr; + int rc; + if (pdbg_target_status(pib_dt) != PDBG_TARGET_ENABLED) + return -1; + + pib = target_to_pib(pib_dt); + + if (!pib->read) { + PR_ERROR("read() not implemented for the target\n"); + return -1; + } + + if (target_addr & PPC_BIT(0)) + rc = pib_indirect_read(pib, target_addr, data); + else + rc = pib->read(pib, target_addr, data); + + PR_DEBUG("rc = %d, addr = 0x%016" PRIx64 ", data = 0x%016" PRIx64 ", target = %s\n", + rc, target_addr, *data, pdbg_target_path(&pib->target)); + + return rc; +} + int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) { struct pib *pib; @@ -186,6 +212,35 @@ int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) return rc; } +int pib_ody_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) +{ + struct pib *pib; + uint64_t target_addr = addr; + int rc; + + if (pdbg_target_status(pib_dt) != PDBG_TARGET_ENABLED) + return -1; + + pib = target_to_pib(pib_dt); + + if (!pib->write) { + PR_ERROR("write() not implemented for the target\n"); + return -1; + } + + PR_DEBUG("addr:0x%08" PRIx64 " data:0x%016" PRIx64 "\n", + target_addr, data); + if (target_addr & PPC_BIT(0)) + rc = pib_indirect_write(pib, target_addr, data); + else + rc = pib->write(pib, target_addr, data); + + PR_DEBUG("rc = %d, addr = 0x%016" PRIx64 ", data = 0x%016" PRIx64 ", target = %s\n", + rc, target_addr, data, pdbg_target_path(&pib->target)); + + return rc; +} + int pib_write_mask(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data, uint64_t mask) { uint64_t value; @@ -310,6 +365,44 @@ int fsi_write(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t data) return rc; } +int fsi_ody_read(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t *data) +{ + struct fsi *fsi; + int rc; + uint64_t addr64 = addr; + + fsi = target_to_fsi(fsi_dt); + + if (!fsi->read) { + PR_ERROR("read() not implemented for the target\n"); + return -1; + } + + rc = fsi->read(fsi, addr64, data); + PR_DEBUG("rc = %d, addr = 0x%05" PRIx64 ", data = 0x%08" PRIx32 ", target = %s\n", + rc, addr64, *data, pdbg_target_path(&fsi->target)); + return rc; +} + +int fsi_ody_write(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t data) +{ + struct fsi *fsi; + int rc; + uint64_t addr64 = addr; + + fsi = target_to_fsi(fsi_dt); + + if (!fsi->write) { + PR_ERROR("write() not implemented for the target\n"); + return -1; + } + + rc = fsi->write(fsi, addr64, data); + PR_DEBUG("rc = %d, addr = 0x%05" PRIx64 ", data = 0x%08" PRIx32 ", target = %s\n", + rc, addr64, data, pdbg_target_path(&fsi->target)); + return rc; +} + int fsi_write_mask(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t data, uint32_t mask) { uint32_t value; @@ -492,6 +585,67 @@ struct pdbg_target_class *get_target_class(struct pdbg_target *target) return target_class; } +/*ddr5 ocmb is itself a chip but in device tree as it is kept under + perv, mc, mcc, omi so probing ocmb will probe its parent chips which + are failing, for now treating ody ocmb as special case*/ +enum pdbg_target_status pdbg_target_probe_ody_ocmb(struct pdbg_target *target) +{ + assert(is_ody_ocmb_chip(target)); + if(pdbg_get_backend() == PDBG_BACKEND_KERNEL) + { + struct pdbg_target *pibtarget = get_ody_pib_target(target); + if (pibtarget && pibtarget->probe && pibtarget->probe(pibtarget)) { + pibtarget->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + struct pdbg_target *fsitarget = get_ody_fsi_target(target); + if (fsitarget && fsitarget->probe && fsitarget->probe(fsitarget)) { + fsitarget->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + if (target && target->probe && target->probe(target)) { + target->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + target->status = PDBG_TARGET_ENABLED; + pibtarget->status = PDBG_TARGET_ENABLED; + } + else + { + struct sbefifo *sbefifo = ody_ocmb_to_sbefifo(target); + if (sbefifo && sbefifo->target.probe && sbefifo->target.probe(&sbefifo->target)) { + sbefifo->target.status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + if (target && target->probe && target->probe(target)) { + target->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + //probe the chip-op target + struct pdbg_target *co_target = get_ody_chipop_target(target); + if (co_target && co_target->probe && co_target->probe(co_target)) { + co_target->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + struct pdbg_target *fsi_target = get_ody_fsi_target(target); + if (fsi_target && fsi_target->probe && fsi_target->probe(fsi_target)) { + fsi_target->status = PDBG_TARGET_NONEXISTENT; + return PDBG_TARGET_NONEXISTENT; + } + + target->status = PDBG_TARGET_ENABLED; + sbefifo->target.status = PDBG_TARGET_ENABLED; + co_target->status = PDBG_TARGET_ENABLED; + fsi_target->status = PDBG_TARGET_ENABLED; + } + return PDBG_TARGET_ENABLED; +} + /* We walk the tree root down disabling targets which might/should * exist but don't */ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target) @@ -510,6 +664,12 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target) * it's status won't have changed */ return status; + /* odyssey ddr5 ocmb is a chip itself but in device tree it is placed + under chiplet, mc, mcc, omi so do not probe parent targets. + */ + if(is_ody_ocmb_chip(target)) + return pdbg_target_probe_ody_ocmb(target); + parent = get_parent(target, false); if (parent) { /* Recurse up the tree to probe and set parent target status */ @@ -651,3 +811,71 @@ void clear_target_classes() child = NULL; } } + +struct pdbg_target *get_backend_target(const char* class, + struct pdbg_target *ocmb) +{ + assert(is_ody_ocmb_chip(ocmb)); + + //ocmb ody ddr5 chip SBE instance will be mapped to a device path like + //dev/sbefifoXYY or /dev/scomXYY where X is proc and YY is port. + //BMC need to use this path for get/put scom to SBE instance/Kernel of + //the ody ocmb chip. + + //ody ocmb chips are defined in system device tree. The pdbg targets + //that captures the device path to communicate with system ody ocmb + //chips will be defined in backend device tree. + + //ody ocmb system device tree targets need to be mapped to backend + //ody sbefifo device tree targets for communication with the SBE instance. + //Mapping is done based on proc, ocmb chip index of the ody ocmb system target + //with the proc, ocmb index and port number defined in the backend device + //tree + + uint32_t ocmb_proc = pdbg_target_index(pdbg_target_parent("proc", + ocmb)); + uint32_t ocmb_index = pdbg_target_index(ocmb) % 0x8; + struct pdbg_target *target; + pdbg_for_each_class_target(class, target) { + uint32_t index = pdbg_target_index(target); + uint32_t proc = 0; + if(!pdbg_target_u32_property(target, "proc", &proc)) { + if(index == ocmb_index && proc == ocmb_proc) { + return target; + } + } + } + + assert(NULL); + + return NULL; +} + +struct sbefifo *ody_ocmb_to_sbefifo(struct pdbg_target *target) +{ + struct pdbg_target *sbefifo_target = get_backend_target("sbefifo-ody", target); + return target_to_sbefifo(sbefifo_target); +} + +struct chipop_ody *ody_ocmb_to_chipop(struct pdbg_target *target) +{ + struct pdbg_target *co_target = get_backend_target("sbefifo-chipop-ody", target); + return target_to_chipop_ody(co_target); +} + +struct pdbg_target* get_ody_pib_target(struct pdbg_target *target) +{ + return get_backend_target("pib-ody", target); +} + +struct pdbg_target* get_ody_fsi_target(struct pdbg_target *target) +{ + return get_backend_target("fsi-ody", target); +} + +struct pdbg_target* get_ody_chipop_target(struct pdbg_target *target) +{ + return get_backend_target("chipop-ody", target); +} + + diff --git a/libpdbg/target.h b/libpdbg/target.h index 679f0a12a..c3353275d 100644 --- a/libpdbg/target.h +++ b/libpdbg/target.h @@ -108,4 +108,27 @@ bool pdbg_context_is_short(void); */ void clear_target_classes(); +/** + * @brief Return true if given target is odyssey chip + * @param[in] target - pdbg target + * + * @return true if target is of odyssey ocmb chip + */ +bool is_ody_ocmb_chip(struct pdbg_target *target); + +/** + * @brief Return matching backend sbefifo target for ocmb target + * @param[in] target - pdbg target + * + * @return backend sbefifo odyssey target + */ +struct sbefifo *ody_ocmb_to_sbefifo(struct pdbg_target *target); + +/** + * @brief Return matching backend sbefifo chipop target for ocmb target + * @param[in] target - pdbg target + * + * @return backend sbefifo odyssey chipop target + */ +struct chipop_ody *ody_ocmb_to_chipop(struct pdbg_target *target); #endif diff --git a/libsbefifo/cmd_dump.c b/libsbefifo/cmd_dump.c index 6fdb566a4..e8920aa31 100644 --- a/libsbefifo/cmd_dump.c +++ b/libsbefifo/cmd_dump.c @@ -75,8 +75,7 @@ int sbefifo_get_dump(struct sbefifo_context *sctx, uint8_t type, uint8_t clock, rc = sbefifo_get_dump_push(type, clock, fa_collect, &msg, &msg_len); if (rc) return rc; - - rc = sbefifo_set_long_timeout(sctx); + rc = sbefifo_set_long_long_timeout(sctx); if (rc) { free(msg); return rc; diff --git a/libsbefifo/connect.c b/libsbefifo/connect.c index 27e8976cb..dc9d66cf6 100644 --- a/libsbefifo/connect.c +++ b/libsbefifo/connect.c @@ -132,6 +132,20 @@ int sbefifo_set_long_timeout(struct sbefifo_context *sctx) return rc; } +int sbefifo_set_long_long_timeout(struct sbefifo_context *sctx) +{ + unsigned int long_timeout = 120; + int rc; + + LOG("long_timeout: %u sec\n", long_timeout); + rc = ioctl(sctx->fd, FSI_SBEFIFO_READ_TIMEOUT, &long_timeout); + if (rc == -1 && errno == ENOTTY) { + /* Do not fail if kernel does not implement ioctl */ + rc = 0; + } + + return rc; +} int sbefifo_reset_timeout(struct sbefifo_context *sctx) { unsigned int timeout = 0; diff --git a/libsbefifo/sbefifo_private.h b/libsbefifo/sbefifo_private.h index a704e6e75..c660a31f6 100644 --- a/libsbefifo/sbefifo_private.h +++ b/libsbefifo/sbefifo_private.h @@ -89,6 +89,7 @@ struct sbefifo_context { }; int sbefifo_set_long_timeout(struct sbefifo_context *sctx); +int sbefifo_set_long_long_timeout(struct sbefifo_context *sctx); int sbefifo_reset_timeout(struct sbefifo_context *sctx); void sbefifo_debug(const char *fmt, ...);