From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id AC9C4A0350 for ; Mon, 28 Feb 2022 16:30:15 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 837F3411DB; Mon, 28 Feb 2022 16:30:12 +0100 (CET) Received: from EUR01-DB5-obe.outbound.protection.outlook.com (mail-eopbgr150121.outbound.protection.outlook.com [40.107.15.121]) by mails.dpdk.org (Postfix) with ESMTP id CA55F41184; Mon, 28 Feb 2022 16:30:08 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lH3v+Krv9oqyfQrhzqno72HOrl/dSjmSYONgXTn0A/KpFAmm9R5pPOoxW8dJzOC+XF3/FzHkj/VLt31/IuPyEeR45Trlu8L/HlQKAU3ysTOi2IM9xYWo7Gmbp5EFVI9JWCKsPslYHsZf7ctpWyCxn0Awome20fcttqbHMunTdbXBEsU1dn4ZkzOVyk3hWyPAOi4mqyyYFjj14WomxUEg5AMLJwN/NrFobNV6l/IO7TLdUrNYDREQUkAtFTiI1QbIheBLwKh8tQkL7qZexHW+XR83bTjR6NoUTnxBIB/GMDxrdC5n4pdakKBG5HoWaiPTkzvZy3IGcqCV4vKkbT/yhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Ok9xVAVcyiS5oI+0yOYCh5ALx3rsV/bOXaaDCJYQLCM=; b=Jn7kH1UrfVEPIsKrstnWymjkTqjym1bojygJEymt7VqHzqyWrO04C00nlmeCt9YqBE43o1PndYmeus1XijQ/6Lhbiq7VctH/QpbhyFlbsZfetH8bE/VHw0iPhUtz4xN+6Qy7x7wvne4nlFZ1TJxFsS932DYSBFpS220JXo5HlUUzfar1RmXVPlVabCSyF/2vMPnr+JOxkMBoKBAR6qi2xYTUf1e3bKPjfSr4TNh/AXcrTjDPGeamZPADkyovPn26EA9ktjmsex5lvR9vymUNc58THTaeLnizNQ4HrxucDM8MhT7aHSj80UlXLOWPBJBxxLw973WEgWS6ciVENR0emA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=silicom-usa.com; dmarc=pass action=none header.from=silicom-usa.com; dkim=pass header.d=silicom-usa.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=SILICOMLTD.onmicrosoft.com; s=selector2-SILICOMLTD-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Ok9xVAVcyiS5oI+0yOYCh5ALx3rsV/bOXaaDCJYQLCM=; b=qLmwmmbX4uZhQYsWirp/FISgCijrmzzQUyGox+cDNw+qBUr4qTwMjiDSjg8OXdWG+jBqTlazdhk66JewyaR2sqCnXaPL5v/v9P5zrcPgd4UePGu0zh0+WYS1g2cLi8GQF86HZAV+XZWAZre8nV4c0YuqF5igaBHYAlSLwdsXb1o= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=silicom-usa.com; Received: from VI1PR0402MB3517.eurprd04.prod.outlook.com (2603:10a6:803:b::16) by VI1PR04MB5167.eurprd04.prod.outlook.com (2603:10a6:803:5b::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5017.25; Mon, 28 Feb 2022 15:30:07 +0000 Received: from VI1PR0402MB3517.eurprd04.prod.outlook.com ([fe80::ed1d:f50d:740:a182]) by VI1PR0402MB3517.eurprd04.prod.outlook.com ([fe80::ed1d:f50d:740:a182%4]) with mapi id 15.20.5017.026; Mon, 28 Feb 2022 15:30:07 +0000 From: Jeff Daly To: dev@dpdk.org Cc: stable@dpdk.org, Stephen Douthit , Haiyue Wang Subject: [PATCH v4 3/3] net/ixgbe: Fix SFP detection and linking on hotplug Date: Mon, 28 Feb 2022 10:29:37 -0500 Message-Id: <20220228152937.21247-4-jeffd@silicom-usa.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220228152937.21247-1-jeffd@silicom-usa.com> References: <20211206221922.644187-1-stephend@silicom-usa.com> <20220228152937.21247-1-jeffd@silicom-usa.com> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: BN9PR03CA0248.namprd03.prod.outlook.com (2603:10b6:408:ff::13) To VI1PR0402MB3517.eurprd04.prod.outlook.com (2603:10a6:803:b::16) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 512a62a0-cd86-4a48-9c93-08d9facf3313 X-MS-TrafficTypeDiagnostic: VI1PR04MB5167:EE_ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: EjxXuEf/QLEvPaiaRoB4MzLVwbEZqfu2hOREMlCSavbU6NAr9dyEsRWKMwudYaJm8J0XyCquQFdMnNrWWkPpgB6EVLQRuoxLa++gwo1SjHttOeHjYN+KHCIIRkPSdb8l2suEDg4C0wPBTOUd+9v9Z7Yyhxae8Fm7sAeR7aVDaKck88X3CYoCpPCf0oeIKy+IXl6yQ1Fyh0nXBaftbxwUJUm9iRu83hYFCXutdtBttPGleY8jZYInmbXdMcNz8bjxwMlx1ozQjyWNUDDz9/17izfOmAypx6gGWDZaC3hpaNuAEKFnLaTlQ+qpguxP0eFl3TV7Qvu5cbFnb4WNLNKpyYcBzMjvpYwrRIV5DXH/gfikdUWL+ddx6E6NhXzgUkRDfuZgt28t9EsRGnr6xaUY04ZOphhNgky1o8tWo2Tf0Ys8GlLqXxjiwQ8chsnicIcuD1PW7H6MfcE72sjCJmJK6mdQTU7IwC+sK/Ytf0CqXCgZfuDR0r4dnNMVRz0vhS5L/iIZwGaH+6pHBqcOHkG05FMb16v7GjI8h8p/hWxEiS97usqAIITtV7ZAkVd0kKnul4LNgSC/O3vLj+4YpmTJXrDN7gL4DwDV8NYJmT901bqQ+Km/qChMR1Beq++9kt27o+b0VhvEMEVIa+sFdJBpL3qNmdfYtLPAGpGymwkbm79Isl4O7bZtqmOryUUCAadbY4TO5TSXv1+9qk2qN8/zUw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI1PR0402MB3517.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230001)(4636009)(366004)(6512007)(66556008)(8676002)(66476007)(6506007)(66946007)(52116002)(4326008)(86362001)(26005)(186003)(2906002)(83380400001)(38100700002)(8936002)(1076003)(38350700002)(2616005)(5660300002)(54906003)(30864003)(6916009)(6666004)(36756003)(508600001)(6486002)(316002); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?ENDHmkavWuBs1iTZeBdq00UC47WhDEDsDjsv2YeYyhcIOM16LlSmXNixBUJG?= =?us-ascii?Q?zdH1RY9eo8E8KcC2lFi6218ZV8qxjW8XNsjTHGbZbuETN0u07FbN9lpQml1m?= =?us-ascii?Q?JxxD/81nM/2kscovB30lJvDuaQWrRao8CvGqhnaJFsw5Gl1yeDt/QQp6OJdg?= =?us-ascii?Q?YW5MlyL0lwz3wCuVy3ZKeOLMuu9AFYzfo0YS78airdBvHMs5nYzWKkB96YHh?= =?us-ascii?Q?p1o1cbLwl03sk5hn6ym7cP5ftJlRk2WOG6j9nNts/9KTZIlPmITqrNppo3Tl?= =?us-ascii?Q?zLMTpCyr/KPO2s/jlGQX878PNG9Yke/v3LdsTzilYDmBhCOPR/N1Bof/9BLf?= =?us-ascii?Q?ZIc2eYsvUu4pQSfvIXVE+jPnhyIUXKjBqwc5ZVeFCSxT0OQEAjs0+ycWQKvM?= =?us-ascii?Q?d2/FYKQhajz/39wrDU03pj1YbumNuX0zTfaAzvGRr0MqO8EfuObzJdfN/xMC?= =?us-ascii?Q?t+NqOgrtWnMPcVWlpPqdNurUn/FiT3N5IwcXT4a753kTTbiS88fN1FR5udEe?= =?us-ascii?Q?/FwQogKo707ltSqceqiShCRaexCW02HlUYqQE2AI27jTV/zbvgvj25krzxwl?= =?us-ascii?Q?/4Wk8Bq1FQF0iqr2Dw2e3433+1Hs/aHlvTGDfQbvMe9im/vSu3pSGvtj+Qfn?= =?us-ascii?Q?K+BVVIrC0YDYS7IfpiQAWIMqREqeSn9wBzfSVvmcx3V+9G8ZXWuBLz3tycGA?= =?us-ascii?Q?e6i6kaV4/eh0xd30dqUu4mPt+pvOad+OLRRpdpxEqHCaURBoiFOGvfmbuGub?= =?us-ascii?Q?NYejpYWb3Pz0IupWwXqaQ4zhFNEbkCQ4G7WEF377pGpOV+SomxKe4kRZ7p0u?= =?us-ascii?Q?3QZla+6iJfDP+GeR+fWzbF5GjD0hQKfXUzamUkK9DjPyGxwsCUHLEt6srZOM?= =?us-ascii?Q?ysovApTFXqXa1adImWk2c4Kj2lXRUocpKZXeXOjLWAl4nbq6PgZ44LmlTxR4?= =?us-ascii?Q?J6XYTZSd6QVV3mwFbEO9izfTLHzFpYNR0HYlU6OULBlf7/27W7P/wtPRXaxO?= =?us-ascii?Q?Rt50kbFxZsundrUpRHCpBdWe6jv+CoLOSWS4vm6mkt8MyFp9RbwIsqhjnXl5?= =?us-ascii?Q?8eB4CnaaL1f/CV4WSurspzC8vPJZo+Nn+XjLIi4Mmxpc6CaiEZaZATVviZKd?= =?us-ascii?Q?Fejlad2xaCLd4iQN7K65uQqLZxbRQHDeZmDHBl9e5N98dHDIGo4CehrRB+bQ?= =?us-ascii?Q?Kz6WOShTLNjHlyJSsxzdCdS4BrnenrlABDLgB5IZH7+/5jQNruXwDszJgXXD?= =?us-ascii?Q?ToGOsIg5G7l3w3nXxikD32kvfiyZXFPlFeWrQPRO38qJUl5uIUo1zwJWs1Xc?= =?us-ascii?Q?Xp5VHFDD9FK47Qj9i6V5oNlp13Yb/bYZJPrL31rgKeSyMcWG4fhuLPANP5Lw?= =?us-ascii?Q?gC1NWRXT+OM24KyBckaeQw8vEesQz71a1Og/HfFOi+b69K1gkqmjIRNrwSYy?= =?us-ascii?Q?8G2PklPZuOaKe/aqPG/+WdhnpAjiAXxGXuPqxYk+aGKBEH7CTZ3AIEW5PmnR?= =?us-ascii?Q?ZtU4ZVxqdm7gpoXWvOjp777ArruS2eAbPpok8d/DXCmOOCEvWjHEt8fbbUlW?= =?us-ascii?Q?x/h4cNgDz++Bc067a0AKw8czLUJeJ2/fGfszTRV0K8AmK1pP3hJqsLyxAoiD?= =?us-ascii?Q?+wScudxh1gGMaEw7NpZcih4=3D?= X-OriginatorOrg: silicom-usa.com X-MS-Exchange-CrossTenant-Network-Message-Id: 512a62a0-cd86-4a48-9c93-08d9facf3313 X-MS-Exchange-CrossTenant-AuthSource: VI1PR0402MB3517.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Feb 2022 15:30:07.4545 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: c9e326d8-ce47-4930-8612-cc99d3c87ad1 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: fxlBYC5ySi6iqB3vYeMjydvw5/A41pns5QbZgmtwoUl1SC/OKwkWkzmbPTy4evWAi6EeBfmcfOQoD6btmkhhhg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB5167 X-BeenThere: stable@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: patches for DPDK stable branches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: stable-bounces@dpdk.org Currently the ixgbe driver does not ID any SFP except for the first one plugged in. This can lead to no-link, or incorrect speed conditions. For example: * If link is initially established with a 1G SFP, and later a 1G/10G multispeed part is later installed, then the MAC link setup functions are never called to change from 1000BASE-X to 10GBASE-R mode, and the link stays running at the slower rate. * If link is initially established with a 1G SFP, and later a 10G only module is later installed, no link is established, since we are still trasnsmitting in 1000BASE-X mode to a 10GBASE-R only partner. Refactor the SFP ID/setup, and link setup code, to more closely match the flow of the mainline kernel driver which does not have these issues. In that driver a service task runs periodically to handle these operations based on bit flags that have been set (usually via interrupt or userspace request), and then get cleared once the requested subtask has been completed. Fixes: af75078fece ("first public release") Cc: stable@dpdk.org Signed-off-by: Stephen Douthit Signed-off-by: Jeff Daly --- drivers/net/ixgbe/ixgbe_ethdev.c | 499 +++++++++++++++++++++++-------- drivers/net/ixgbe/ixgbe_ethdev.h | 14 +- 2 files changed, 392 insertions(+), 121 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c index e8f07cb405..b70985bb1d 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.c +++ b/drivers/net/ixgbe/ixgbe_ethdev.c @@ -229,9 +229,6 @@ static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev); static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev); static void ixgbe_dev_interrupt_handler(void *param); static void ixgbe_dev_interrupt_delayed_handler(void *param); -static void *ixgbe_dev_setup_link_thread_handler(void *param); -static int ixgbe_dev_wait_setup_link_complete(struct rte_eth_dev *dev, - uint32_t timeout_ms); static int ixgbe_add_rar(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr, @@ -766,6 +763,33 @@ static const struct rte_ixgbe_xstats_name_off rte_ixgbevf_stats_strings[] = { #define IXGBEVF_NB_XSTATS (sizeof(rte_ixgbevf_stats_strings) / \ sizeof(rte_ixgbevf_stats_strings[0])) +/** + * This function is the same as ixgbe_need_crosstalk_fix() in base/ixgbe_common.c + * + * ixgbe_need_crosstalk_fix - Determine if we need to do cross talk fix + * @hw: pointer to hardware structure + * + * Contains the logic to identify if we need to verify link for the + * crosstalk fix + **/ +static bool ixgbe_need_crosstalk_fix(struct ixgbe_hw *hw) +{ + /* Does FW say we need the fix */ + if (!hw->need_crosstalk_fix) + return false; + + /* Only consider SFP+ PHYs i.e. media type fiber */ + switch (ixgbe_get_media_type(hw)) { + case ixgbe_media_type_fiber: + case ixgbe_media_type_fiber_qsfp: + break; + default: + return false; + } + + return true; +} + /* * This function is the same as ixgbe_is_sfp() in base/ixgbe.h. */ @@ -1032,6 +1056,306 @@ ixgbe_swfw_lock_reset(struct ixgbe_hw *hw) ixgbe_release_swfw_semaphore(hw, mask); } +/** + * ixgbe_check_sfp_cage - Find present status of SFP module + * @hw: pointer to hardware structure + * + * Find if a SFP module is present and if this device supports SFPs + **/ +enum ixgbe_sfp_cage_status ixgbe_check_sfp_cage(struct ixgbe_hw *hw) +{ + enum ixgbe_sfp_cage_status sfp_cage_status; + + /* If we're not a fiber/fiber_qsfp, no cage to check */ + switch (hw->mac.ops.get_media_type(hw)) { + case ixgbe_media_type_fiber: + case ixgbe_media_type_fiber_qsfp: + break; + default: + return IXGBE_SFP_CAGE_NOCAGE; + } + + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + sfp_cage_status = !!(IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP2); + break; + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + /* SDP0 is the active low signal PRSNT#, so invert this */ + sfp_cage_status = !(IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP0); + break; + default: + /* Don't know how to check this device type yet */ + sfp_cage_status = IXGBE_SFP_CAGE_UNKNOWN; + DEBUGOUT("IXGBE_SFP_CAGE_UNKNOWN, unknown mac type %d\n", + hw->mac.type); + break; + } + + DEBUGOUT("sfp status %d for mac type %d\n", sfp_cage_status, hw->mac.type); + return sfp_cage_status; +} + +static s32 +ixgbe_sfp_id_and_setup(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + enum ixgbe_sfp_cage_status sfp_cage_status; + s32 err; + + /* Can't ID or setup SFP if it's not plugged in */ + sfp_cage_status = ixgbe_check_sfp_cage(hw); + if (sfp_cage_status == IXGBE_SFP_CAGE_EMPTY || + sfp_cage_status == IXGBE_SFP_CAGE_NOCAGE) + return IXGBE_ERR_SFP_NOT_PRESENT; + + /* Something's in the cage, ID it */ + hw->phy.ops.identify_sfp(hw); + + /* Unknown module type, give up */ + if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { + PMD_DRV_LOG(ERR, "unknown SFP type, giving up"); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + + /* This should be a redundant check, since we looked at the + * PRSNT# signal from the cage above, but just in case this is + * an SFP that's slow to respond to I2C pokes correctly, try it + * again later + */ + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) { + PMD_DRV_LOG(ERR, "IDed SFP as absent but cage PRSNT# active!?"); + return IXGBE_ERR_SFP_NOT_PRESENT; + } + + /* SFP is present and identified, try to set it up */ + err = hw->mac.ops.setup_sfp(hw); + if (err) + PMD_DRV_LOG(ERR, "setup_sfp() failed %d", err); + + return err; +} + +static void +ixgbe_sfp_service(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_interrupt *intr = + IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + enum ixgbe_sfp_cage_status sfp_cage_status; + s32 err; + u8 sff_id; + bool have_int = false; + + /* If there's no module cage, then there's nothing to service */ + sfp_cage_status = ixgbe_check_sfp_cage(hw); + if (sfp_cage_status == IXGBE_SFP_CAGE_NOCAGE) { + PMD_DRV_LOG(DEBUG, "No SFP to service\n"); + return; + } + + /* TODO - Even for platforms where ixgbe_check_sfp_cage() gives a clear + * status result, if there's no interrupts, or no interrupt for the SFP + * cage present pin, even if other interrupts exist, then we still need + * to poll here to set the flag. + */ +#ifndef RTE_EXEC_ENV_FREEBSD + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); + struct rte_intr_handle *intr_handle = pci_dev->intr_handle; + if (rte_intr_allow_others(intr_handle)) { + /* check if lsc interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.lsc) + have_int = true; + } +#endif /* #ifdef RTE_EXEC_ENV_FREEBSD */ + + if (!have_int && sfp_cage_status == IXGBE_SFP_CAGE_EMPTY) { + intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP; + PMD_DRV_LOG(DEBUG, "No SFP, no LSC, set NEED_SFP_SETUP\n"); + } + + /* For platforms that don't have a way to read the PRESENT# signal from + * the SFP cage, fallback to doing an I2C read and seeing if it's ACKed + * to determine if a module is present + */ + if (sfp_cage_status == IXGBE_SFP_CAGE_UNKNOWN) { + PMD_DRV_LOG(DEBUG, + "SFP present unknown (int? %d), try I2C read\n", + have_int); + + /* Rather than calling identify_sfp, which will read a lot of I2C + * registers (and in a slow processor intensive fashion due to + * bit-banging, just read the SFF ID register, which is at a + * common address across SFP/SFP+/QSFP modules and see if + * there's a NACK. This works since we only expect a NACK if no + * module is present + */ + err = ixgbe_read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &sff_id); + if (err != IXGBE_SUCCESS) { + PMD_DRV_LOG(DEBUG, "Received I2C NAK from SFP, set NEED_SFP_SETUP flag\n"); + intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP; + sfp_cage_status = IXGBE_SFP_CAGE_EMPTY; + } else { + PMD_DRV_LOG(DEBUG, "SFP ID read ACKed"); + sfp_cage_status = IXGBE_SFP_CAGE_FULL; + } + } + + if (sfp_cage_status == IXGBE_SFP_CAGE_EMPTY) { + PMD_DRV_LOG(DEBUG, "SFP absent, cage_status %d\n", sfp_cage_status); + return; + } + + /* No setup requested? Nothing to do */ + if (!(intr->flags & IXGBE_FLAG_NEED_SFP_SETUP)) + return; + + err = ixgbe_sfp_id_and_setup(dev); + if (err) { + PMD_DRV_LOG(DEBUG, "failed to ID & setup SFP %d", err); + return; + } + + /* Setup is done, clear the flag, but make sure link config runs for new SFP */ + intr->flags &= ~IXGBE_FLAG_NEED_SFP_SETUP; + intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + + /* + * Since this is a new SFP, clear the old advertised speed mask so we don't + * end up using an old slower rate + */ + hw->phy.autoneg_advertised = 0; +} + +static void +ixgbe_link_service(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_interrupt *intr = + IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + bool link_up, autoneg = false, have_int = false; + u32 speed; + s32 err; + + /* Test if we have a LSC interrupt for this platform, if not we need to + * manually check the link register since IXGBE_FLAG_NEED_LINK_CONFIG + * will never be set in the interrupt handler + */ +#ifndef RTE_EXEC_ENV_FREEBSD + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); + struct rte_intr_handle *intr_handle = pci_dev->intr_handle; + if (rte_intr_allow_others(intr_handle)) { + /* check if lsc interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.lsc) + have_int = true; + } +#endif /* #ifdef RTE_EXEC_ENV_FREEBSD */ + + /* Skip if we still need to setup an SFP, or if no link config requested + */ + if ((intr->flags & IXGBE_FLAG_NEED_SFP_SETUP) || + (!(intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG) && have_int)) + return; + + if (!have_int && !(intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG)) { + err = ixgbe_check_link(hw, &speed, &link_up, 0); + if (!err && !link_up) { + intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + PMD_DRV_LOG(DEBUG, "Link down, no LSC, set NEED_LINK_CONFIG\n"); + } else { + return; + } + } + + speed = hw->phy.autoneg_advertised; + if (!speed) + ixgbe_get_link_capabilities(hw, &speed, &autoneg); + + err = ixgbe_setup_link(hw, speed, true); + if (err) { + PMD_DRV_LOG(ERR, "ixgbe_setup_link failed %d", err); + return; + } + + intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; +} + +static void +ixgbe_link_update_service(struct rte_eth_dev *dev) +{ + /* Update internal link status, waiting for link */ + if (!ixgbe_dev_link_update(dev, 0)) { + ixgbe_dev_link_status_print(dev); + rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL); + } +} + +/* + * Service task thread to handle periodic tasks + */ +static void * +ixgbe_dev_service_thread_handler(void *param) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)param; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint64_t start, ticks, service_ms; + uint32_t speed; + s32 err; + bool link_up; + + while (1) { + ixgbe_sfp_service(dev); + ixgbe_link_service(dev); + ixgbe_link_update_service(dev); + + /* Run the service thread handler more frequently when link is + * down to reduce link up latency (every 200ms vs 1s) + * + * Use a number of smaller sleeps to decrease exit latency when + * ixgbe_dev_stop() wants this thread to join + */ + err = ixgbe_check_link(hw, &speed, &link_up, 0); + if (err == IXGBE_SUCCESS && link_up) + service_ms = 2000; + else + service_ms = 100; + + /* Call msec_delay in a loop with several smaller sleeps to + * provide periodic thread cancellation points + */ + start = rte_get_timer_cycles(); + ticks = (uint64_t)service_ms * rte_get_timer_hz() / 1E3; + while ((rte_get_timer_cycles() - start) < ticks) + msec_delay(100); + } + + /* Never return */ + return NULL; +} + +static s32 +eth_ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, + bool *link_up, bool link_up_wait_to_complete) +{ + if (ixgbe_need_crosstalk_fix(hw)) { + enum ixgbe_sfp_cage_status sfp_cage_status; + + sfp_cage_status = ixgbe_check_sfp_cage(hw); + if (sfp_cage_status != IXGBE_SFP_CAGE_FULL) { + *link_up = false; + *speed = IXGBE_LINK_SPEED_UNKNOWN; + return IXGBE_SUCCESS; + } + } + + return ixgbe_check_mac_link_generic(hw, speed, link_up, link_up_wait_to_complete); +} + /* * This function is based on code in ixgbe_attach() in base/ixgbe.c. * It returns 0 on success. @@ -1054,6 +1378,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) IXGBE_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private); struct ixgbe_bw_conf *bw_conf = IXGBE_DEV_PRIVATE_TO_BW_CONF(eth_dev->data->dev_private); + struct ixgbe_mac_info *mac = &hw->mac; uint32_t ctrl_ext; uint16_t csum; int diag, i, ret; @@ -1124,6 +1449,17 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) return -EIO; } + /* override mac_link_check to check for sfp cage full/empty */ + switch (hw->mac.type) { + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + case ixgbe_mac_82599EB: + mac->ops.check_link = eth_ixgbe_check_mac_link_generic; + break; + default: + break; + } + /* pick up the PCI bus settings for reporting later */ ixgbe_get_bus_info(hw); @@ -2558,8 +2894,11 @@ ixgbe_flow_ctrl_enable(struct rte_eth_dev *dev, struct ixgbe_hw *hw) static int ixgbe_dev_start(struct rte_eth_dev *dev) { + struct ixgbe_adapter *ad = dev->data->dev_private; struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_interrupt *intr = + IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); struct ixgbe_vf_info *vfinfo = *IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private); struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); @@ -2580,9 +2919,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - /* Stop the link setup handler before resetting the HW. */ - ixgbe_dev_wait_setup_link_complete(dev, 0); - /* disable uio/vfio intr/eventfd mapping */ rte_intr_disable(intr_handle); @@ -2815,6 +3151,20 @@ ixgbe_dev_start(struct rte_eth_dev *dev) ixgbe_l2_tunnel_conf(dev); ixgbe_filter_restore(dev); + /* Spawn service thread */ + if (ixgbe_is_sfp(hw)) { + intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP; + err = rte_ctrl_thread_create(&ad->service_thread_tid, + "ixgbe-service-thread", + NULL, + ixgbe_dev_service_thread_handler, + dev); + if (err) { + PMD_DRV_LOG(ERR, "service_thread err"); + goto error; + } + } + if (tm_conf->root && !tm_conf->committed) PMD_DRV_LOG(WARNING, "please call hierarchy_commit() " @@ -2860,13 +3210,21 @@ ixgbe_dev_stop(struct rte_eth_dev *dev) int vf; struct ixgbe_tm_conf *tm_conf = IXGBE_DEV_PRIVATE_TO_TM_CONF(dev->data->dev_private); + void *res; + s32 err; if (hw->adapter_stopped) return 0; PMD_INIT_FUNC_TRACE(); - ixgbe_dev_wait_setup_link_complete(dev, 0); + /* Cancel the service thread, and wait for it to join */ + err = pthread_cancel(adapter->service_thread_tid); + if (err) + PMD_DRV_LOG(ERR, "failed to cancel service thread %d", err); + err = pthread_join(adapter->service_thread_tid, &res); + if (err) + PMD_DRV_LOG(ERR, "failed to join service thread %d", err); /* disable interrupts */ ixgbe_disable_intr(hw); @@ -2945,7 +3303,6 @@ ixgbe_dev_set_link_up(struct rte_eth_dev *dev) } else { /* Turn on the laser */ ixgbe_enable_tx_laser(hw); - ixgbe_dev_link_update(dev, 0); } return 0; @@ -2976,7 +3333,6 @@ ixgbe_dev_set_link_down(struct rte_eth_dev *dev) } else { /* Turn off the laser */ ixgbe_disable_tx_laser(hw); - ixgbe_dev_link_update(dev, 0); } return 0; @@ -4128,57 +4484,6 @@ ixgbevf_check_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed, return ret_val; } -/* - * If @timeout_ms was 0, it means that it will not return until link complete. - * It returns 1 on complete, return 0 on timeout. - */ -static int -ixgbe_dev_wait_setup_link_complete(struct rte_eth_dev *dev, uint32_t timeout_ms) -{ -#define WARNING_TIMEOUT 9000 /* 9s in total */ - struct ixgbe_adapter *ad = dev->data->dev_private; - uint32_t timeout = timeout_ms ? timeout_ms : WARNING_TIMEOUT; - - while (rte_atomic32_read(&ad->link_thread_running)) { - msec_delay(1); - timeout--; - - if (timeout_ms) { - if (!timeout) - return 0; - } else if (!timeout) { - /* It will not return until link complete */ - timeout = WARNING_TIMEOUT; - PMD_DRV_LOG(ERR, "IXGBE link thread not complete too long time!"); - } - } - - return 1; -} - -static void * -ixgbe_dev_setup_link_thread_handler(void *param) -{ - struct rte_eth_dev *dev = (struct rte_eth_dev *)param; - struct ixgbe_adapter *ad = dev->data->dev_private; - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct ixgbe_interrupt *intr = - IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); - u32 speed; - bool autoneg = false; - - pthread_detach(pthread_self()); - speed = hw->phy.autoneg_advertised; - if (!speed) - ixgbe_get_link_capabilities(hw, &speed, &autoneg); - - ixgbe_setup_link(hw, speed, true); - - intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; - rte_atomic32_clear(&ad->link_thread_running); - return NULL; -} - /* * In freebsd environment, nic_uio drivers do not support interrupts, * rte_intr_callback_register() will fail to register interrupts. @@ -4218,11 +4523,8 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev, int wait_to_complete, int vf) { struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct ixgbe_adapter *ad = dev->data->dev_private; struct rte_eth_link link; ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN; - struct ixgbe_interrupt *intr = - IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); bool link_up; int diag; int wait = 1; @@ -4237,9 +4539,6 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev, hw->mac.get_link_status = true; - if (intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG) - return rte_eth_linkstatus_set(dev, &link); - /* check if it needs to wait to complete, if lsc interrupt is enabled */ if (wait_to_complete == 0 || dev->data->dev_conf.intr_conf.lsc != 0) wait = 0; @@ -4254,7 +4553,7 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev, else diag = ixgbe_check_link(hw, &link_speed, &link_up, wait); - if (diag != 0) { + if (diag != 0 || !link_up) { link.link_speed = RTE_ETH_SPEED_NUM_100M; link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX; return rte_eth_linkstatus_set(dev, &link); @@ -4267,32 +4566,6 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev, link_up = 0; } - if (link_up == 0) { - if (ixgbe_get_media_type(hw) == ixgbe_media_type_fiber) { - ixgbe_dev_wait_setup_link_complete(dev, 0); - if (rte_atomic32_test_and_set(&ad->link_thread_running)) { - /* To avoid race condition between threads, set - * the IXGBE_FLAG_NEED_LINK_CONFIG flag only - * when there is no link thread running. - */ - intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; - if (rte_ctrl_thread_create(&ad->link_thread_tid, - "ixgbe-link-handler", - NULL, - ixgbe_dev_setup_link_thread_handler, - dev) < 0) { - PMD_DRV_LOG(ERR, - "Create link thread failed!"); - rte_atomic32_clear(&ad->link_thread_running); - } - } else { - PMD_DRV_LOG(ERR, - "Other link thread is running now!"); - } - } - return rte_eth_linkstatus_set(dev, &link); - } - link.link_status = RTE_ETH_LINK_UP; link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX; @@ -4498,8 +4771,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev) eicr = IXGBE_READ_REG(hw, IXGBE_EICR); PMD_DRV_LOG(DEBUG, "eicr %x", eicr); - intr->flags = 0; - /* set flag for async link update */ if (eicr & IXGBE_EICR_LSC) intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -4515,6 +4786,14 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev) (eicr & IXGBE_EICR_GPI_SDP0_X550EM_x)) intr->flags |= IXGBE_FLAG_PHY_INTERRUPT; + /* Check for loss of SFP */ + /* TODO - For platforms that don't have this flag, do we need to set + * NEED_SFP_SETUP on LSC if we're a SFP platform? + */ + if (hw->mac.type == ixgbe_mac_X550EM_a && + (eicr & IXGBE_EICR_GPI_SDP0_X550EM_a)) + intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP; + return 0; } @@ -4566,11 +4845,13 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev) static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev) { + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); + struct rte_intr_handle *intr_handle = pci_dev->intr_handle; struct ixgbe_interrupt *intr = IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); - int64_t timeout; struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int64_t timeout; PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags); @@ -4605,16 +4886,14 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev) if (rte_eal_alarm_set(timeout * 1000, ixgbe_dev_interrupt_delayed_handler, (void *)dev) < 0) PMD_DRV_LOG(ERR, "Error setting alarm"); - else { - /* remember original mask */ - intr->mask_original = intr->mask; + else /* only disable lsc interrupt */ intr->mask &= ~IXGBE_EIMS_LSC; - } } PMD_DRV_LOG(DEBUG, "enable intr immediately"); ixgbe_enable_intr(dev); + rte_intr_ack(intr_handle); return 0; } @@ -4637,8 +4916,6 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param) { struct rte_eth_dev *dev = (struct rte_eth_dev *)param; - struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); - struct rte_intr_handle *intr_handle = pci_dev->intr_handle; struct ixgbe_interrupt *intr = IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); struct ixgbe_hw *hw = @@ -4668,13 +4945,10 @@ ixgbe_dev_interrupt_delayed_handler(void *param) intr->flags &= ~IXGBE_FLAG_MACSEC; } - /* restore original mask */ - intr->mask = intr->mask_original; - intr->mask_original = 0; + if (dev->data->dev_conf.intr_conf.lsc != 0) + intr->mask |= IXGBE_EICR_LSC; - PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]", eicr); ixgbe_enable_intr(dev); - rte_intr_ack(intr_handle); } /** @@ -5316,9 +5590,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - /* Stop the link setup handler before resetting the HW. */ - ixgbe_dev_wait_setup_link_complete(dev, 0); - err = hw->mac.ops.reset_hw(hw); /** @@ -5398,12 +5669,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev) /* Re-enable interrupt for VF */ ixgbevf_intr_enable(dev); - /* - * Update link status right before return, because it may - * start link configuration process in a separate thread. - */ - ixgbevf_dev_link_update(dev, 0); - hw->adapter_stopped = false; return 0; @@ -5422,8 +5687,6 @@ ixgbevf_dev_stop(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - ixgbe_dev_wait_setup_link_complete(dev, 0); - ixgbevf_intr_disable(dev); dev->data->dev_started = 0; diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h index 69e0e82a5b..d243e417e9 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.h +++ b/drivers/net/ixgbe/ixgbe_ethdev.h @@ -29,6 +29,7 @@ #define IXGBE_FLAG_PHY_INTERRUPT (uint32_t)(1 << 2) #define IXGBE_FLAG_MACSEC (uint32_t)(1 << 3) #define IXGBE_FLAG_NEED_LINK_CONFIG (uint32_t)(1 << 4) +#define IXGBE_FLAG_NEED_SFP_SETUP ((uint32_t)(1 << 5)) /* * Defines that were not part of ixgbe_type.h as they are not used by the @@ -223,8 +224,6 @@ struct ixgbe_rte_flow_rss_conf { struct ixgbe_interrupt { uint32_t flags; uint32_t mask; - /*to save original mask during delayed handler */ - uint32_t mask_original; }; struct ixgbe_stat_mapping_registers { @@ -507,7 +506,7 @@ struct ixgbe_adapter { uint8_t pflink_fullchk; uint8_t mac_ctrl_frame_fwd; rte_atomic32_t link_thread_running; - pthread_t link_thread_tid; + pthread_t service_thread_tid; }; struct ixgbe_vf_representor { @@ -670,6 +669,15 @@ int ixgbe_syn_filter_set(struct rte_eth_dev *dev, struct rte_eth_syn_filter *filter, bool add); +enum ixgbe_sfp_cage_status { + IXGBE_SFP_CAGE_EMPTY = 0, + IXGBE_SFP_CAGE_FULL, + IXGBE_SFP_CAGE_UNKNOWN = -1, + IXGBE_SFP_CAGE_NOCAGE = -2, +}; +enum ixgbe_sfp_cage_status ixgbe_check_sfp_cage(struct ixgbe_hw *hw); + + /** * l2 tunnel configuration. */ -- 2.25.1