From patchwork Fri Mar 18 14:36:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1607068 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=tlyHqW7j; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KKmmb2m04z9s3q for ; Sat, 19 Mar 2022 01:36:47 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KKmmb1xYGz30Bm for ; Sat, 19 Mar 2022 01:36:47 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=tlyHqW7j; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=tlyHqW7j; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KKmmC4Ptsz30FC for ; Sat, 19 Mar 2022 01:36:27 +1100 (AEDT) Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22ICnqKA030081 for ; Fri, 18 Mar 2022 14:36:24 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : content-transfer-encoding : mime-version; s=pp1; bh=j46ZNC6jhNTqBb59ZzZTjgdJU3zBfjavVNRFH/5dKJw=; b=tlyHqW7jlDA5BFxClBX0m9hEA5Pl2uvG7wZACV5J5SxDREwowYhY0IzP/BSyQy4ht5dl T6ybeEFKFqA29lL1A5Id0D0u9Npn6gxCA+wfXMC+Od4Jz+qH7phYhtt0T0bk8akVNvtt GjUX10l6NCQRpVjYgJb1eSnGJweEmKKjmdCAI60QOSJfP2q3nNZrXOyUYCHmuAf3c1ur YLKAg5XOcSVyI0G2Ad42K4jq7fC8piG0uQa64xR2dqWhy72HOvYPTPzVW7ZpNOFO8KYG sz0xFzxbDUcBt6QWCi0+KRa+TsKwiRejuReaOLROKKn0cIx1TD9lpbepvk6nATVedtYj JQ== Received: from ppma05fra.de.ibm.com (6c.4a.5195.ip4.static.sl-reverse.com [149.81.74.108]) by mx0b-001b2d01.pphosted.com with ESMTP id 3evpuu63wk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 18 Mar 2022 14:36:24 +0000 Received: from pps.filterd (ppma05fra.de.ibm.com [127.0.0.1]) by ppma05fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22IEIc6v003607 for ; Fri, 18 Mar 2022 14:36:22 GMT Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by ppma05fra.de.ibm.com with ESMTP id 3erk58uqd0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 18 Mar 2022 14:36:22 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22IEaKWU52363718 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 18 Mar 2022 14:36:20 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 56F6911C04C for ; Fri, 18 Mar 2022 14:36:20 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2700C11C04A for ; Fri, 18 Mar 2022 14:36:20 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.63.232]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Fri, 18 Mar 2022 14:36:20 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Fri, 18 Mar 2022 15:36:00 +0100 Message-Id: <20220318143619.83489-3-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220318143619.83489-1-clombard@linux.vnet.ibm.com> References: <20220318143619.83489-1-clombard@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-GUID: BjYX26kh6M74np4aM1N890_bqD9shEgE X-Proofpoint-ORIG-GUID: BjYX26kh6M74np4aM1N890_bqD9shEgE X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-18_10,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 suspectscore=0 clxscore=1015 impostorscore=0 mlxlogscore=999 malwarescore=0 spamscore=0 priorityscore=1501 bulkscore=0 phishscore=0 mlxscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203180080 Subject: [Skiboot] [PATCH V3 02/21] hw/ast-bmc: Initialize ast lpc mctp binding X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" The Management Component Transport Protocol (MCTP) defines a communication model intended to facilitate communication. This patch initialize MCTP binding over LPC Bus interface. Several steps must be performed: - Initialize the MCTP core (mctp_init()). - Initialize a hardware binding as AST LPC mode host (mctp_astlpc_init()). - Register the hardware binding with the core (mctp_register_bus()), using a predefined EID (Host default is 9). To transmit a MCTP message, mctp_message_tx() is used. To receive a MCTP message, a callback need to be provided and registered through mctp_set_rx_all(). For the transfer of MCTP messages, two basics components are used: - A window of the LPC FW address space, where reads and writes are forwarded to BMC memory. - An interrupt mechanism using the KCS interface. hw/ast-bmc/ast-mctp.c is compilated if the compiler flag CONFIG_PLDM is set. Signed-off-by: Christophe Lombard --- hw/ast-bmc/Makefile.inc | 7 + hw/ast-bmc/ast-mctp.c | 347 ++++++++++++++++++++++++++++++++++++++++ include/ast.h | 7 + 3 files changed, 361 insertions(+) create mode 100644 hw/ast-bmc/ast-mctp.c diff --git a/hw/ast-bmc/Makefile.inc b/hw/ast-bmc/Makefile.inc index e7ded0e8..ca7de379 100644 --- a/hw/ast-bmc/Makefile.inc +++ b/hw/ast-bmc/Makefile.inc @@ -2,5 +2,12 @@ SUBDIRS += hw/ast-bmc AST_BMC_OBJS = ast-io.o ast-sf-ctrl.o + +ifeq ($(CONFIG_PLDM),1) +CPPFLAGS += -I$(SRC)/libmctp/ +#CFLAGS += -DASTLPC_DEBUG +AST_BMC_OBJS += ast-mctp.o +endif + AST_BMC = hw/ast-bmc/built-in.a $(AST_BMC): $(AST_BMC_OBJS:%=hw/ast-bmc/%) diff --git a/hw/ast-bmc/ast-mctp.c b/hw/ast-bmc/ast-mctp.c new file mode 100644 index 00000000..9274d77f --- /dev/null +++ b/hw/ast-bmc/ast-mctp.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +// Copyright 2022 IBM Corp. + +#define pr_fmt(fmt) "AST-MCTP: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * For the EIDs: the valid range is 8-254. + * host default = 9 + */ +uint8_t HOST_EID = 9; + +static struct mctp *mctp; + +/* binding specific */ +struct astlpc_ops_data { + + uint16_t kcs_data_addr; /* LPC IO space offset for the data register */ + uint16_t kcs_stat_addr; + + /* address of the packet exchange buffer in FW space */ + uint32_t lpc_fw_addr; +}; + +/* + * The AST binding is described here: + * + * https://github.com/openbmc/libmctp/blob/master/docs/bindings/vendor-astlpc.md + * + * Most of the binding is implemented in libmctp, but we need to provide + * accessors for the LPC FW space (for the packet buffer) and for the KCS + * peripheral (for the interrupt mechanism). + */ + +static int ast_kcs_reg_read(void *binding_data, + enum mctp_binding_astlpc_kcs_reg reg, + uint8_t *val) +{ + struct astlpc_ops_data *ops_data = binding_data; + uint32_t addr, tmp; + int rc; + + if (reg == MCTP_ASTLPC_KCS_REG_STATUS) + addr = ops_data->kcs_stat_addr; + else if (reg == MCTP_ASTLPC_KCS_REG_DATA) + addr = ops_data->kcs_data_addr; + else + return OPAL_PARAMETER; + + rc = lpc_read(OPAL_LPC_IO, addr, &tmp, 1); + if (!rc) + *val = tmp & 0xff; + else + *val = 0xff; + + mctp_prdebug("%s 0x%hhx from %s (%d)", + __func__, *val, reg ? "status" : "data", rc); + + return rc; +} + +static int ast_kcs_reg_write(void *binding_data, + enum mctp_binding_astlpc_kcs_reg reg, + uint8_t val) +{ + struct astlpc_ops_data *ops_data = binding_data; + uint32_t addr; + + mctp_prdebug("%s 0x%hhx to %s", + __func__, val, reg ? "status" : "data"); + + if (reg == MCTP_ASTLPC_KCS_REG_STATUS) + addr = ops_data->kcs_stat_addr; + else if (reg == MCTP_ASTLPC_KCS_REG_DATA) + addr = ops_data->kcs_data_addr; + else + return OPAL_PARAMETER; + + return lpc_write(OPAL_LPC_IO, addr, val, 1); +} + +static int ast_lpc_read(void *binding_data, void *buf, long offset, + size_t len) +{ + struct astlpc_ops_data *ops_data = binding_data; + + mctp_prdebug("%s %zu bytes from 0x%lx (lpc: 0x%lx)", + __func__, len, offset, + ops_data->lpc_fw_addr + offset); + return lpc_fw_read(ops_data->lpc_fw_addr + offset, buf, len); +} + +static int ast_lpc_write(void *binding_data, const void *buf, + long offset, size_t len) +{ + struct astlpc_ops_data *ops_data = binding_data; + + mctp_prdebug("%s %zu bytes to offset 0x%lx (lpc: 0x%lx)", + __func__, len, offset, + ops_data->lpc_fw_addr + offset); + return lpc_fw_write(ops_data->lpc_fw_addr + offset, buf, len); +} + +static const struct mctp_binding_astlpc_ops astlpc_ops = { + .kcs_read = ast_kcs_reg_read, + .kcs_write = ast_kcs_reg_write, + .lpc_read = ast_lpc_read, + .lpc_write = ast_lpc_write, +}; + +static struct mctp_binding_astlpc *ast_binding; +static struct astlpc_ops_data *ops_data; + +/* Keyboard Controller Style (KCS) data register address */ +#define KCS_DATA_REG 0xca2 + +/* Keyboard Controller Style (KCS) status register address */ +#define KCS_STATUS_REG 0xca3 + +/* Serial IRQ number for KCS interface */ +#define KCS_SERIAL_IRQ 11 + +bool irq_active; +struct timer mctp_boot_timer; + +/* we need a poller to crank the mctp state machine during boot */ +static void ast_mctp_poller(struct timer *t __unused, + void *data __unused, uint64_t now __unused) +{ + mctp_astlpc_poll(ast_binding); + + /* once booted we can rely on the KCS interrupt */ + if ((opal_booting() && !irq_active)) + schedule_timer(&mctp_boot_timer, msecs_to_tb(5)); +} + +/* at runtime the interrupt should handle it */ +static void ast_mctp_interrupt(uint32_t chip_id __unused, + uint32_t irq_msk __unused) +{ + if (!irq_active) { + mctp_prerr("IRQ Active! Disabling boot poller..."); + irq_active = true; + } + + mctp_astlpc_poll(ast_binding); +} + +static struct lpc_client kcs_lpc_client = { + .reset = NULL, + .interrupt = ast_mctp_interrupt, + .interrupts = LPC_IRQ(KCS_SERIAL_IRQ), +}; + +static bool ast_mctp_supported(void) +{ + uint32_t tmp; + + /* + * Probe for MCTP support by reading the STAT register of KCS#4 + */ + tmp = 0; + return true; + + if (lpc_probe_read(OPAL_LPC_IO, KCS_STATUS_REG, &tmp, 1)) { + mctp_prdebug("KCS4 probe failed, skipping MCTP init"); + return false; + } + + return !!(tmp & 0x80); /* high bit indicates BMC is listening */ +} + +#define DESIRED_MTU 32768 + +static struct mctp_binding_astlpc *ast_mctp_binding(void) +{ + struct mctp_binding_astlpc *ast_binding; + + ops_data = zalloc(sizeof(struct astlpc_ops_data)); + if (!ops_data) + return NULL; + + /* + * Current OpenBMC systems put the MCTP buffer 1MB down from + * the end of the LPC FW range. + * + * The size of the FW range is: 0x1000_0000 so the window be at: + * + * 0x1000_0000 - 2**20 == 0xff00000 + */ + ops_data->lpc_fw_addr = 0xff00000; + + /* values chosen by the OpenBMC driver */ + ops_data->kcs_data_addr = KCS_DATA_REG; + ops_data->kcs_stat_addr = KCS_STATUS_REG; + + /* Initialise the binding */ + ast_binding = mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, + DESIRED_MTU, + NULL, + &astlpc_ops, + ops_data); + if (!ast_binding) { + mctp_prerr("binding init failed"); + goto err; + } + + /* register an lpc client so we get an interrupt */ + lpc_register_client(0, &kcs_lpc_client, IRQ_ATTR_TARGET_OPAL); + + init_timer(&mctp_boot_timer, ast_mctp_poller, ast_binding); + schedule_timer(&mctp_boot_timer, msecs_to_tb(5)); + + return ast_binding; + +err: + mctp_astlpc_destroy(ast_binding); + free(ops_data); + return NULL; +} + +static void *mctp_malloc(size_t size) { return malloc(size); } +static void mctp_free(void *ptr) { return free(ptr); } +static void *mctp_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +#ifdef ASTLPC_DEBUG +char buffer[320]; +static void mctp_log(int log_lvl, const char *fmt, va_list va) +{ + snprintf(buffer, sizeof(buffer), "%s\n", fmt); + vprlog(log_lvl, buffer, va); +} +#endif + +int ast_mctp_message_tx(uint8_t eid, uint8_t *msg, int len) +{ + uint8_t tag = 0; + + return mctp_message_tx(mctp, eid, MCTP_MESSAGE_TO_DST, tag, msg, len); +} + +void ast_mctp_stop_polling(void) +{ + irq_active = true; +} + +#define HOST_MAX_INCOMING_MESSAGE_ALLOCATION 131072 + +/* + * Initialize mctp binding for hbrt and provide interfaces for sending + * and receiving mctp messages. + */ +int ast_mctp_init(void (*fn)(uint8_t src_eid, bool tag_owner, + uint8_t msg_tag, void *data, void *msg, + size_t len)) +{ + uint64_t start; + + if (!ast_mctp_supported()) + return OPAL_HARDWARE; + + /* skiboot's malloc/free/realloc are macros so they need + * wrappers + */ + mctp_set_alloc_ops(mctp_malloc, mctp_free, mctp_realloc); + + /* + * /-----\ /---------\ + * | bmc | (eid: 8) <- lpc/kcs -> (eid: 9) | skiboot | + * \-----/ \---------/ + * astlpc kcs binding + */ + mctp = mctp_init(); + if (!mctp) { + mctp_prerr("mctp init failed"); + return OPAL_HARDWARE; + } + +#ifdef ASTLPC_DEBUG + /* Setup the trace hook */ + mctp_set_log_custom(mctp_log); +#endif + + mctp_prinfo("libmctp initialized"); + + /* Set the max message size to be large enough */ + mctp_set_max_message_size(mctp, HOST_MAX_INCOMING_MESSAGE_ALLOCATION); + + /* Setup the message rx callback */ + mctp_set_rx_all(mctp, fn, NULL); + + /* Initialise the binding */ + ast_binding = ast_mctp_binding(); + if (!ast_binding) + goto err; + + /* Register the binding to the LPC bus we are using for this + * MCTP configuration. + */ + if (mctp_register_bus(mctp, + mctp_binding_astlpc_core(ast_binding), + HOST_EID)) { + mctp_prerr("failed to register bus"); + goto err; + } + + /* Initializing the channel requires running the poll function + * a few times to handle the initial setup since we need the + * BMC to reply. + * + * Unfortuntately there's no good way to determine if this + * worked or not so poll for a bit with a timeout. :( + * + * We have to check (bus->state == mctp_bus_state_constructed) + * otherwise mctp_message_tx() will reject the message. + * astlpc: host: Version negotiation got: 3 + */ + start = mftb(); + while (tb_compare(mftb(), start + msecs_to_tb(250)) == TB_ABEFOREB) + time_wait_ms(10); + + mctp_prwarn("%s - The mctp bus state should be correct now !!!", + __func__); + + return OPAL_SUCCESS; + +err: + mctp_prerr("Unable to initialize MCTP"); + mctp_destroy(mctp); + mctp = NULL; + + return OPAL_HARDWARE; +} diff --git a/include/ast.h b/include/ast.h index 5e932398..e21774be 100644 --- a/include/ast.h +++ b/include/ast.h @@ -91,6 +91,13 @@ void ast_setup_ibt(uint16_t io_base, uint8_t irq); /* MBOX configuration */ void ast_setup_sio_mbox(uint16_t io_base, uint8_t irq); +/* AST MCTP configuration */ +int ast_mctp_init(void (*fn)(uint8_t src_eid, bool tag_owner, + uint8_t msg_tag, void *data, void *msg, + size_t len)); +void ast_mctp_stop_polling(void); +int ast_mctp_message_tx(uint8_t eid, uint8_t *msg, int len); + #endif /* __SKIBOOT__ */ /*