From patchwork Mon May 21 01:29:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver O'Halloran X-Patchwork-Id: 917316 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40q1SR3Lr0z9s1w for ; Mon, 21 May 2018 11:30:47 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FU4hC3qr"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40q1SR1XT4zF0bZ for ; Mon, 21 May 2018 11:30:47 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FU4hC3qr"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400e:c01::244; helo=mail-pl0-x244.google.com; envelope-from=oohall@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FU4hC3qr"; dkim-atps=neutral Received: from mail-pl0-x244.google.com (mail-pl0-x244.google.com [IPv6:2607:f8b0:400e:c01::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40q1RF59cjzF0Tj for ; Mon, 21 May 2018 11:29:45 +1000 (AEST) Received: by mail-pl0-x244.google.com with SMTP id ay10-v6so7807660plb.1 for ; Sun, 20 May 2018 18:29:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VQMRgKYPrGhkkNOjyccC93Y6zfOOTCGBJ/miEsyMin0=; b=FU4hC3qr/lupClLhhc6yw/0BLP/VUh0Poka4Cj/RfyZPkfs2xaNzv4167EOizX+35W nUi2rB/BgC7bkV8BRWK3RD90jlOJGIOlFg39KM7GhLWqBPhfXmxcV3MeK3eTyEwDuIWY pJPEiAuszjSEijsOz+bLov1NamHxP0QKK8adyeDSr85EZbghn370LWKAqG+wnzdqcR1m BkThhGSZc8SH8UNx/4qYV2cnll4sE8Obc+eiqbGd7f5OgwuUJH3Xeu1/SQaa2sMCyTK1 GAUYmlrvvmx8Tic715OFXkNYq4AfxUwyFdNf8iVea0TD/ThtyKeOUAk09xi1g/l048+q 2K1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VQMRgKYPrGhkkNOjyccC93Y6zfOOTCGBJ/miEsyMin0=; b=tyh0GjqV+ck2zlnwryJSQ0MbpDhsK1YSDLMQPInFjJJTF9+ZySNxyq66hqfbnhQmA8 YVjxiJpmd6KXIHORZtaJsZjOBHIMd6x1GUYLxlRoqB3yAyqvuCjWXRJQgKtHv/8N2pbJ RwzHmlSo3DA7/44b+csx3Lh7xSQ+TaiSq90mvwreAMAPMzQqrALLkB/jWhHFn+rDnBKR TRbWi5Nkjry1gekbTZm9/x4X92/IXX3i+PsQZjUMdzWxjq8Rj6eJTXlzR6bb2OjCpOM7 5PpEmAmhmxOkGOSqTg+J99Kz32QBp3JZdNhX0pv6qN46F2jJChaqZNcHMp5kOWdpb7FJ viJg== X-Gm-Message-State: ALKqPwcB/jB8LlculAqV4T5a/mVc82ntyOreLeuWRJugwGOYNi1bngGH 710lv3VsYIjSWiaqzOhLB9bO3g== X-Google-Smtp-Source: AB8JxZqy+QTTCCFkqSLGD5Ufux3OBz6AFCIHXzdQmOl0VHrn4FhaPX5Vh1bT6ch/5WkSGhifGEMT9A== X-Received: by 2002:a17:902:778a:: with SMTP id o10-v6mr18588278pll.214.1526866183592; Sun, 20 May 2018 18:29:43 -0700 (PDT) Received: from flat-canetoad.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id p71-v6sm28105059pfl.170.2018.05.20.18.29.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 20 May 2018 18:29:43 -0700 (PDT) From: Oliver O'Halloran To: skiboot@lists.ozlabs.org Date: Mon, 21 May 2018 11:29:26 +1000 Message-Id: <20180521012926.4365-4-oohall@gmail.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20180521012926.4365-1-oohall@gmail.com> References: <20180521012926.4365-1-oohall@gmail.com> Subject: [Skiboot] [PATCH 4/4] p8-i2c: Remove force reset X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Force reset was added as an attempt to work around some issues with TPM devices locking up their I2C bus. In that particular case the problem was that the device would hold the SCL line down permanently due to a device firmware bug. The force reset doesn't actually do anything to alleviate the situation here, it just happens to reset the internal master state enough to make the I2C driver appear to work until something tries to access the bus again. On P9 systems with secure boot enabled there is the added problem of the "diagostic mode" not being supported on I2C masters A,B,C and D. Diagnostic mode allows the SCL and SDA lines to be driven directly by software. Without this force reset is impossible to implement. This patch removes the force reset functionality entirely since: a) it doesn't do what it's supposed to, and b) it's butt ugly code Additionally, turn p8_i2c_reset_engine() into p8_i2c_reset_port(). There's no need to reset every port on a master in response to an error that occurred on a specific port. Signed-off-by: Oliver O'Halloran --- hw/p8-i2c.c | 173 +++++++++++++----------------------------------------------- 1 file changed, 38 insertions(+), 135 deletions(-) diff --git a/hw/p8-i2c.c b/hw/p8-i2c.c index 5f49f726ba91..1bcd7cc8b420 100644 --- a/hw/p8-i2c.c +++ b/hw/p8-i2c.c @@ -516,151 +516,54 @@ static void p8_i2c_translate_error(struct i2c_request *req, uint64_t status) req->result = OPAL_I2C_TIMEOUT; } -static void p8_i2c_force_reset(struct p8_i2c_master *master) +static int p8_i2c_reset_port(struct p8_i2c_master_port *p) { - struct p8_i2c_master_port *p; - uint64_t mode; - int rc; + struct p8_i2c_master *master = p->master; + int reset_loops, rc; + uint64_t status; - /* Reset the i2c engine */ - rc = xscom_write(master->chip_id, master->xscom_base + - I2C_RESET_I2C_REG, 0); - if (rc) { - log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed " - "to reset the i2c engine\n"); - return; - } - time_wait_us_nopoll(10); - /* Reset port busy */ - rc = xscom_write(master->chip_id, master->xscom_base + - I2C_PORT_BUSY_REG, 0x8000000000000000ULL); + /* FIXME: this should per per-port rather than per-master */ + master->state = state_error; + + /* + * Put the master into enhanced STOP mode when recovering the + * port. This causes the master to send additional STOP conditions + * to work around some particularly stupid I2C devices and it's + * required on secure I2C masters since they will not send a bare + * stop condition. + */ + rc = p8_i2c_prog_mode(p, true); if (rc) { - log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed " - "to reset port busy on i2c engine\n"); - return; + log_simple_error(&e_info(OPAL_RC_I2C_RESET), + "I2C: Failed to enable enhanced mode\n"); + return -1; } - time_wait_us_nopoll(10); - list_for_each(&master->ports, p, link) { - mode = 0; - mode = SETFIELD(I2C_MODE_PORT_NUM, mode, p->port_num); - mode = SETFIELD(I2C_MODE_BIT_RATE_DIV, mode, p->bit_rate_div); - mode |= I2C_MODE_DIAGNOSTIC; - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_MODE_REG, - mode); - if (rc) - prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n"); - - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_RESET_S_SCL_REG, - 0); - if (rc) - prlog(PR_ERR, "I2C: Failed to reset S_SCL\n"); - - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_SET_S_SCL_REG, - 0); - if (rc) - prlog(PR_ERR, "I2C: Failed to set S_SCL\n"); - - /* Manually reset */ - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_RESET_S_SCL_REG, - 0); - if (rc) - prlog(PR_ERR, "I2C: sendStop: fail reset S_SCL\n"); - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_RESET_S_SDA_REG, - 0); - if (rc) - prlog(PR_ERR, "I2C: sendStop: fail reset S_SDA\n"); + rc = xscom_write(master->chip_id, master->xscom_base + + I2C_CMD_REG, I2C_CMD_WITH_STOP); + if (rc) + goto err; - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_SET_S_SCL_REG, - 0); - if (rc) - prlog(PR_ERR, "I2C: sendStop: fail set S_SCL\n"); + /* Wait for COMMAND COMPLETE */ + for (reset_loops = 0; reset_loops < 10; reset_loops++) { + time_wait_ms(10); - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_SET_S_SDA_REG, - 0); + rc = xscom_read(master->chip_id, + master->xscom_base + I2C_STAT_REG, + &status); if (rc) - prlog(PR_ERR, "I2C: sendStop: fail set 2 S_SDA\n"); + goto err; - mode ^= I2C_MODE_DIAGNOSTIC; - time_wait_us_nopoll(10); - rc = xscom_write(master->chip_id, - master->xscom_base + I2C_MODE_REG, - mode); - if (rc) - prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n"); + if (status & I2C_STAT_CMD_COMP) + break; } -} - -static int p8_i2c_reset_engine(struct p8_i2c_master *master) -{ - struct p8_i2c_master_port *p; - int reset_loops; - int rc; - uint64_t status; - list_for_each(&master->ports, p, link) { - /* - * Reset each port by issuing a STOP command to slave. - * - * Reprogram the mode register with 'enhanced bit' set - */ - rc = p8_i2c_prog_mode(p, true); - if (rc) { - log_simple_error(&e_info(OPAL_RC_I2C_RESET), - "I2C: Failed to program the MODE_REG\n"); - return -1; - } - - /* Send an immediate stop */ - master->state = state_error; - rc = xscom_write(master->chip_id, master->xscom_base + - I2C_CMD_REG, I2C_CMD_WITH_STOP); - if (rc) { - log_simple_error(&e_info(OPAL_RC_I2C_RESET), - "I2C: Failed to issue immediate STOP\n"); - return -1; - } - - /* Wait for COMMAND COMPLETE */ - reset_loops = 0; - do { - rc = xscom_read(master->chip_id, - master->xscom_base + I2C_STAT_REG, - &status); - if (rc) { - log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER), - "I2C: Failed to read the STAT_REG\n"); - return -1; - } - if (! (status & I2C_STAT_CMD_COMP)) { - time_wait_ms(10); - if (reset_loops++ == 5) { - prlog(PR_WARNING, "I2C: Retrying reset, with force!\n"); - p8_i2c_force_reset(master); - continue; - } - if (reset_loops == 10) { - log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER), - "I2C: Failed to recover i2c engine\n"); - break; - } - } - } while (! (status & I2C_STAT_CMD_COMP)); - } - return 0; + if (status & I2C_STAT_CMD_COMP) + return 0; +err: + prerror("I2C: Failed to reset c%de%dp%d\n", + master->chip_id, master->engine_id, p->port_num); + return -1; } static void p8_i2c_status_error(struct p8_i2c_master_port *port, @@ -699,7 +602,7 @@ static void p8_i2c_status_error(struct p8_i2c_master_port *port, */ p8_i2c_complete_request(master, req, req->result); } else { - if (p8_i2c_reset_engine(master)) + if (p8_i2c_reset_port(port)) goto exit; /* Enable the interrupt */ p8_i2c_enable_irqs(master);