From patchwork Tue Apr 23 07:47:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Schiffer X-Patchwork-Id: 13639441 X-Patchwork-Delegate: kuba@kernel.org Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE84347A5D; Tue, 23 Apr 2024 07:48:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.104.207.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713858515; cv=none; b=rMWHY7lSoGu/LF+8QwWBHTwgjtJHC1DVerAkc7j1tzkebczNd+2V9oWX6wzSWpkwVnnFQPfJSS/4fA70L55TuYIt+ju+B9HMJsjtC1SC6XE3azt6YDnzrMNoTo+jJ9b0aYtGo/RvwUlQVCSKgz5bYVhvQxjFFtt77d3Aiq1lY+E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713858515; c=relaxed/simple; bh=50WUH8/gJdefZq4G72BFoplcUbcPUBwyyq+E5uJJwpw=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=RnyH+Uchd6ihNDFSQhnueNcBW21Jp8L7zRNv0i+UxNF/9wUq0h2AsgrfkhyfeLxcoMR8A/za/c2DtJV3MoxXBkNmiMfu+TtGm1puLNFXhbE/VdrZziq4Ch/+qX1q7zNeoKHLMpboRevgqo9AvH0zXTI4yvRk4uIBZodWncT0Ig0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ew.tq-group.com; spf=pass smtp.mailfrom=ew.tq-group.com; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.b=A47FWdeL; dkim=fail (0-bit key) header.d=ew.tq-group.com header.i=@ew.tq-group.com header.b=VLL3+KC+ reason="key not found in DNS"; arc=none smtp.client-ip=93.104.207.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ew.tq-group.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ew.tq-group.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.b="A47FWdeL"; dkim=fail reason="key not found in DNS" (0-bit key) header.d=ew.tq-group.com header.i=@ew.tq-group.com header.b="VLL3+KC+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1713858512; x=1745394512; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=olb7YuiDqyB6vPx9JqkzKaHx9bpQLEFyzOe5hqPoF6Y=; b=A47FWdeLjnMefa+N9ydnCq6UXYXF6gVb3h8UaXSd11h7ZtvhgYIQh3+I 3+ZndWtLjgN8dOZqxnfsRwSCElnadNZpLJ+CT1xeRdGgnBUWhVKCyAKDI Sv2zUDnD2cofOAxaETXnxShQPep2AaX+LL2hTe65r0pTxhBfoSjIETSOj eAUtT2fqInhdCGM6FWK94p7HIH45hviRfxfrl6ZZfbe92UhWLue0TjCgQ oG+JWS0T3wEpq+v6bcGSq+ymrsmveeBcG50gnhMQgkjTAJJ1YqD0f82sy sZH+y/QDpwjPRMuZNsfoMfnM0K1QdKFkIHnDrzmsIGXaNu1c6fg2rD/hr A==; X-IronPort-AV: E=Sophos;i="6.07,222,1708383600"; d="scan'208";a="36558060" Received: from vmailcow01.tq-net.de ([10.150.86.48]) by mx1.tq-group.com with ESMTP; 23 Apr 2024 09:48:28 +0200 Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 0DB0D1750DA; Tue, 23 Apr 2024 09:48:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ew.tq-group.com; s=dkim; t=1713858503; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding; bh=olb7YuiDqyB6vPx9JqkzKaHx9bpQLEFyzOe5hqPoF6Y=; b=VLL3+KC+GYUdsXj6WQoLpvHXIiz4he0woIZyf+LhtGP7xYHCuHzoppErbXlLo3cYItX/vl ZuXMtI568VBJ+D3x7V4yVIqh+j+BvQ7JbV8fo4GBrSB/uJ9X8GLE0q8A39YREKN6PHm1Iw XrcJd8S4VkKoKpRi5DavdOkSXHZRaJIM6/dhrl3sTxMFh/ZCXMsj3EhXNvSwAs5r1GgO1g znsQ11Y6jeuAGmEpNpZKjNR0rqqrwyU97hirzPdg+xlAEkY75MkPOBkfuyEErS5SQ3ZHvS Qd296WKXtS7hb/SKYcZvTJY4IoPUFzf3ewy00DmgL2g49kMgvapVNx0DAW9zSQ== From: Matthias Schiffer To: Andrew Lunn , Florian Fainelli , Vladimir Oltean Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Fabio Estevam , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux@ew.tq-group.com, Matthias Schiffer Subject: [PATCH net v2 1/2] net: dsa: mv88e6xxx: Add support for model-specific pre- and post-reset handlers Date: Tue, 23 Apr 2024 09:47:48 +0200 Message-ID: X-Mailer: git-send-email 2.43.2 Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 X-Patchwork-Delegate: kuba@kernel.org Instead of calling mv88e6xxx_g2_eeprom_wait() directly from mv88e6xxx_hardware_reset(), add configurable pre- and post-reset hard reset handlers. Initially, the handlers are set to mv88e6xxx_g2_eeprom_wait() for all families that have get/set_eeprom() to match the existing behavior. No functional change intended (except for additional error messages on failure). Fixes: 6ccf50d4d474 ("net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent") Signed-off-by: Matthias Schiffer Reviewed-by: Andrew Lunn --- v2: Moved comment back to mv88e6xxx_hardware_reset() drivers/net/dsa/mv88e6xxx/chip.c | 50 +++++++++++++++++++++++++++++--- drivers/net/dsa/mv88e6xxx/chip.h | 6 ++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 59b5dd0e2f41d..21853689f6b39 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3123,6 +3123,7 @@ static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip) static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) { struct gpio_desc *gpiod = chip->reset; + int err; /* If there is a GPIO connected to the reset pin, toggle it */ if (gpiod) { @@ -3131,17 +3132,26 @@ static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip) * mid-byte, causing the first EEPROM read after the reset * from the wrong location resulting in the switch booting * to wrong mode and inoperable. + * For this reason, switch families with EEPROM support + * generally wait for EEPROM loads to complete as their pre- + * and post-reset handlers. */ - if (chip->info->ops->get_eeprom) - mv88e6xxx_g2_eeprom_wait(chip); + if (chip->info->ops->hardware_reset_pre) { + err = chip->info->ops->hardware_reset_pre(chip); + if (err) + dev_err(chip->dev, "pre-reset error: %d\n", err); + } gpiod_set_value_cansleep(gpiod, 1); usleep_range(10000, 20000); gpiod_set_value_cansleep(gpiod, 0); usleep_range(10000, 20000); - if (chip->info->ops->get_eeprom) - mv88e6xxx_g2_eeprom_wait(chip); + if (chip->info->ops->hardware_reset_post) { + err = chip->info->ops->hardware_reset_post(chip); + if (err) + dev_err(chip->dev, "post-reset error: %d\n", err); + } } } @@ -4371,6 +4381,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4561,6 +4573,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4661,6 +4675,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4755,6 +4771,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4813,6 +4831,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4869,6 +4889,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4928,6 +4950,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -4981,6 +5005,8 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .watchdog_ops = &mv88e6250_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6250_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -5028,6 +5054,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -5087,6 +5115,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -5133,6 +5163,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -5183,6 +5215,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -5338,6 +5372,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -5400,6 +5436,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -5462,6 +5500,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, @@ -5527,6 +5567,8 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { .watchdog_ops = &mv88e6393x_watchdog_ops, .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, + .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, .atu_get_hash = mv88e6165_g1_atu_get_hash, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 85eb293381a7e..c34caf9815c5c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -487,6 +487,12 @@ struct mv88e6xxx_ops { int (*ppu_enable)(struct mv88e6xxx_chip *chip); int (*ppu_disable)(struct mv88e6xxx_chip *chip); + /* Additional handlers to run before and after hard reset, to make sure + * that the switch and EEPROM are in a good state. + */ + int (*hardware_reset_pre)(struct mv88e6xxx_chip *chip); + int (*hardware_reset_post)(struct mv88e6xxx_chip *chip); + /* Switch Software Reset */ int (*reset)(struct mv88e6xxx_chip *chip); From patchwork Tue Apr 23 07:47:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Schiffer X-Patchwork-Id: 13639442 X-Patchwork-Delegate: kuba@kernel.org Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4286C47A73; Tue, 23 Apr 2024 07:48:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.104.207.81 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713858518; cv=none; b=SPOvSxqtkzqvTPobZ61CEi/k2/LsJ9YrZe/GKzG0WrbVRvGuETE9Qtta5FGzdn4RPt3UAk9L0fDlDo2nuz701u3cFtXVVzzlCrHXYfu45eezc04S9b3nNzstqJ12MN9JW0LPUvvYbweMECoGP/We8z8U4Z3ieICcMGj8aXoHWqg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713858518; c=relaxed/simple; bh=o4u43IW73prnzZJWHI1N1Gu2LgYMBWIy7A+G8Uvr/30=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RiqPXsVzAr3eIhw+WRwigLQvGa6n+ORubzEshWAsTso2/KW65vuzmsfeOB+OSlU6A2BqCfZgP05QGi75daV5leHxXRtblAEVmwWzyGtUI4azbVuU9fB1L9YvrIIZ5bLcVU7cl6fUWlZEHq03Irl2dMD06ChsoG5aX5czrTVWPl8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ew.tq-group.com; spf=pass smtp.mailfrom=ew.tq-group.com; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.b=buAqgyeU; dkim=fail (0-bit key) header.d=ew.tq-group.com header.i=@ew.tq-group.com header.b=oYWX/pAe reason="key not found in DNS"; arc=none smtp.client-ip=93.104.207.81 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ew.tq-group.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ew.tq-group.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.b="buAqgyeU"; dkim=fail reason="key not found in DNS" (0-bit key) header.d=ew.tq-group.com header.i=@ew.tq-group.com header.b="oYWX/pAe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1713858515; x=1745394515; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JNOm6/SZulEqEYGvPyWtQk9iN1TxZjulcr5jAw4TpGw=; b=buAqgyeUxTzA8CW5zXJXgm/TCJAn5XAATyLlo821hGUGamiMI/MBiI94 RoSgYNx2ZOgTVdIke6r75NkODmzm5KCXqXylK3rhITi2vo+1s3NVnQPG1 00jWmx9djNFSj3Zb/AzZARzEDsTifMKK7L6YnKDRBtKe1ExiRHO5jtoDj jjqudYgw3KIpiCtDnCwXdQOglddfkrNfa7Y3uve4p9L5xZOe3SiMxPaPK 62OI0IP9DUs/czaoQbjOemdH1ClnYcVc2EG6gyQzdCB7/5GnaGARQ/Kgp pQwakc4oueZHUGCCo5Ui8pL1U6GaPJLWRwxDwqaxtymSl08gIcnBqaoMK A==; X-IronPort-AV: E=Sophos;i="6.07,222,1708383600"; d="scan'208";a="36558067" Received: from vmailcow01.tq-net.de ([10.150.86.48]) by mx1.tq-group.com with ESMTP; 23 Apr 2024 09:48:32 +0200 Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C3DDF1751CC; Tue, 23 Apr 2024 09:48:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ew.tq-group.com; s=dkim; t=1713858508; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=JNOm6/SZulEqEYGvPyWtQk9iN1TxZjulcr5jAw4TpGw=; b=oYWX/pAe6MWpi0kbE17bD83JvAgxwvK/JMoOkvwCMX4U1j1c9oKw2WfSp2tMtNegmRCZsg Em97nf2O7tGPDQsu5TNoOV/lSyYe5tiTw0xM2KAEkvHH5uvoRDh7LVhKV0C1+JkpA7P14N 9NbeCVVU4jEBmnKvZAnBkNVBdgjsBQlwywguSSjMNlBqMOJJhXoaFyWLxD8pZOHuVkqOvP mPgBi9TALQ8/8DtnEgu6GELh8XqP3MMLM/tLb4QhU7YoJ3j3RoxlFQpItWBjoa0URK2HEW o7qK3pMbFnQRWzqc9zKYwt+EJutnJpShcUWC0qrNrCY2fyX0zPmxgnOYSsCxCQ== From: Matthias Schiffer To: Andrew Lunn , Florian Fainelli , Vladimir Oltean Cc: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Fabio Estevam , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux@ew.tq-group.com, Matthias Schiffer Subject: [PATCH net v2 2/2] net: dsa: mv88e6xxx: Avoid EEPROM timeout without EEPROM on 88E6250-family switches Date: Tue, 23 Apr 2024 09:47:49 +0200 Message-ID: <5bcb24c64492d3e98d55fe0b905fbc955db53770.1713858017.git.matthias.schiffer@ew.tq-group.com> X-Mailer: git-send-email 2.43.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 X-Patchwork-Delegate: kuba@kernel.org 88E6250-family switches have the quirk that the EEPROM Running flag can get stuck at 1 when no EEPROM is connected, causing mv88e6xxx_g2_eeprom_wait() to time out. We still want to wait for the EEPROM however, to avoid interrupting a transfer and leaving the EEPROM in an invalid state. The condition to wait for recommended by the hardware spec is the EEInt flag, however this flag is cleared on read, so before the hardware reset, is may have been cleared already even though the EEPROM has been read successfully. For this reason, we revive the mv88e6xxx_g1_wait_eeprom_done() function that was removed in commit 6ccf50d4d474 ("net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent") in a slightly refactored form, and introduce a new mv88e6xxx_g1_wait_eeprom_done_prereset() that additionally handles this case by triggering another EEPROM reload that can be waited on. On other switch models without this quirk, mv88e6xxx_g2_eeprom_wait() is kept, as it avoids the additional reload. Fixes: 6ccf50d4d474 ("net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent") Signed-off-by: Matthias Schiffer Reviewed-by: Andrew Lunn --- v2: no changes, added Reviewed-by drivers/net/dsa/mv88e6xxx/chip.c | 4 +- drivers/net/dsa/mv88e6xxx/global1.c | 89 +++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/global1.h | 2 + 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 21853689f6b39..83511586a4de6 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5005,8 +5005,8 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .watchdog_ops = &mv88e6250_watchdog_ops, .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, - .hardware_reset_pre = mv88e6xxx_g2_eeprom_wait, - .hardware_reset_post = mv88e6xxx_g2_eeprom_wait, + .hardware_reset_pre = mv88e6250_g1_wait_eeprom_done_prereset, + .hardware_reset_post = mv88e6xxx_g1_wait_eeprom_done, .reset = mv88e6250_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 49444a72ff095..9820cd5967574 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -75,6 +75,95 @@ static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1); } +static int mv88e6250_g1_eeprom_reload(struct mv88e6xxx_chip *chip) +{ + /* MV88E6185_G1_CTL1_RELOAD_EEPROM is also valid for 88E6250 */ + int bit = __bf_shf(MV88E6185_G1_CTL1_RELOAD_EEPROM); + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); + if (err) + return err; + + val |= MV88E6185_G1_CTL1_RELOAD_EEPROM; + + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); + if (err) + return err; + + return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_CTL1, bit, 0); +} + +/* Returns 0 when done, -EBUSY when waiting, other negative codes on error */ +static int mv88e6xxx_g1_is_eeprom_done(struct mv88e6xxx_chip *chip) +{ + u16 val; + int err; + + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val); + if (err < 0) { + dev_err(chip->dev, "Error reading status"); + return err; + } + + /* If the switch is still resetting, it may not + * respond on the bus, and so MDIO read returns + * 0xffff. Differentiate between that, and waiting for + * the EEPROM to be done by bit 0 being set. + */ + if (val == 0xffff || !(val & BIT(MV88E6XXX_G1_STS_IRQ_EEPROM_DONE))) + return -EBUSY; + + return 0; +} + +/* As the EEInt (EEPROM done) flag clears on read if the status register, this + * function must be called directly after a hard reset or EEPROM ReLoad request, + * or the done condition may have been missed + */ +int mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip) +{ + const unsigned long timeout = jiffies + 1 * HZ; + int ret; + + /* Wait up to 1 second for the switch to finish reading the + * EEPROM. + */ + while (time_before(jiffies, timeout)) { + ret = mv88e6xxx_g1_is_eeprom_done(chip); + if (ret != -EBUSY) + return ret; + } + + dev_err(chip->dev, "Timeout waiting for EEPROM done"); + return -ETIMEDOUT; +} + +int mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip *chip) +{ + int ret; + + ret = mv88e6xxx_g1_is_eeprom_done(chip); + if (ret != -EBUSY) + return ret; + + /* Pre-reset, we don't know the state of the switch - when + * mv88e6xxx_g1_is_eeprom_done() returns -EBUSY, that may be because + * the switch is actually busy reading the EEPROM, or because + * MV88E6XXX_G1_STS_IRQ_EEPROM_DONE has been cleared by an unrelated + * status register read already. + * + * To account for the latter case, trigger another EEPROM reload for + * another chance at seeing the done flag. + */ + ret = mv88e6250_g1_eeprom_reload(chip); + if (ret) + return ret; + + return mv88e6xxx_g1_wait_eeprom_done(chip); +} + /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 1095261f5b490..3dbb7a1b8fe11 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -282,6 +282,8 @@ int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr); int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip); int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip); int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g1_wait_eeprom_done(struct mv88e6xxx_chip *chip); +int mv88e6250_g1_wait_eeprom_done_prereset(struct mv88e6xxx_chip *chip); int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip); int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip);