{"id":2221529,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2221529/?format=json","web_url":"http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260409072747.217836-1-khai.wen.tan@linux.intel.com/","project":{"id":46,"url":"http://patchwork.ozlabs.org/api/1.2/projects/46/?format=json","name":"Intel Wired Ethernet development","link_name":"intel-wired-lan","list_id":"intel-wired-lan.osuosl.org","list_email":"intel-wired-lan@osuosl.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260409072747.217836-1-khai.wen.tan@linux.intel.com>","list_archive_url":null,"date":"2026-04-09T07:27:47","name":"[iwl-next,1/1] igc: add support for forcing link speed without autonegotiation","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"f9983f69a3085d27b7fc31edbc569dc02ed49ad5","submitter":{"id":93102,"url":"http://patchwork.ozlabs.org/api/1.2/people/93102/?format=json","name":"KhaiWenTan","email":"khai.wen.tan@linux.intel.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20260409072747.217836-1-khai.wen.tan@linux.intel.com/mbox/","series":[{"id":499323,"url":"http://patchwork.ozlabs.org/api/1.2/series/499323/?format=json","web_url":"http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=499323","date":"2026-04-09T07:27:47","name":"[iwl-next,1/1] igc: add support for forcing link speed without autonegotiation","version":1,"mbox":"http://patchwork.ozlabs.org/series/499323/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2221529/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2221529/checks/","tags":{},"related":[],"headers":{"Return-Path":"<intel-wired-lan-bounces@osuosl.org>","X-Original-To":["incoming@patchwork.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256\n header.s=default header.b=ZRRT7xLO;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org\n (client-ip=140.211.166.138; helo=smtp1.osuosl.org;\n envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fs4Jd02w4z1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 01:55:12 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id A883D80D87;\n\tThu,  9 Apr 2026 15:55:10 +0000 (UTC)","from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id vKEUD9W6jjcq; Thu,  9 Apr 2026 15:55:09 +0000 (UTC)","from lists1.osuosl.org (lists1.osuosl.org [140.211.166.142])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 8E2A080D13;\n\tThu,  9 Apr 2026 15:55:09 +0000 (UTC)","from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists1.osuosl.org (Postfix) with ESMTP id 5CF2D1D6\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 07:50:14 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id 42A76605EF\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 07:50:14 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id enc2OhPS1Yrd for <intel-wired-lan@lists.osuosl.org>;\n Thu,  9 Apr 2026 07:50:13 +0000 (UTC)","from mgamail.intel.com (mgamail.intel.com [198.175.65.9])\n by smtp3.osuosl.org (Postfix) with ESMTPS id DB77B605C8\n for <intel-wired-lan@lists.osuosl.org>; Thu,  9 Apr 2026 07:50:12 +0000 (UTC)","from orviesa008.jf.intel.com ([10.64.159.148])\n by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 09 Apr 2026 00:50:10 -0700","from unknown (HELO localhost.png.intel.com) ([10.107.255.61])\n by orviesa008.jf.intel.com with ESMTP; 09 Apr 2026 00:50:05 -0700"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.166.142;\n helo=lists1.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org;\n receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp1.osuosl.org 8E2A080D13","OpenDKIM Filter v2.11.0 smtp3.osuosl.org DB77B605C8"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org;\n\ts=default; t=1775750109;\n\tbh=UroQK2T/TQuckkGfXIczSsjtta4Pf5iPKz1rgDMR1AA=;\n\th=From:To:Cc:Date:Subject:List-Id:List-Unsubscribe:List-Archive:\n\t List-Post:List-Help:List-Subscribe:From;\n\tb=ZRRT7xLOhOEhzJcdf+lx3kKC2beuzbhIgxzbcDEcEa4VIh+5lMD704f0naa1rCAXz\n\t iR792UUtQ9doB2br4Pf/NYSmIh+dQX6Sg4BfJD8Abi62KdtC2Mq+K/tMreF5YqIhWr\n\t Cxue2GCpihiOA8apJq/E77cKTJPDcOmoQBDHx6mrQzOT7RIOIJxPH/yLb8/z2LN6QT\n\t h6iuGyQ+S8Glis4RquAC5AxQdSga27dZqDOYVLxMw4DjcG6iIVMa+gUnFJ6UCGUab+\n\t OJqZ8zy+BejaMqOTuQBaB4K6f2cAOo5C0ENWHZfGMGcegWh8FNvm+t0vi9IRF0hLJF\n\t 0i1ILQr2Fif8Q==","Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=198.175.65.9;\n helo=mgamail.intel.com; envelope-from=khai.wen.tan@linux.intel.com;\n receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp3.osuosl.org DB77B605C8","X-CSE-ConnectionGUID":["4xWMn6d5SfGAwzZhmd9JlQ==","EEf733KSSPatx2WnE/RbBQ=="],"X-CSE-MsgGUID":["EdeHgKnqQ82L8WJ87uPg9A==","LKKd+yAJR++04q9/XNNC4w=="],"X-IronPort-AV":["E=McAfee;i=\"6800,10657,11753\"; a=\"99345662\"","E=Sophos;i=\"6.23,169,1770624000\"; d=\"scan'208\";a=\"99345662\"","E=Sophos;i=\"6.23,169,1770624000\"; d=\"scan'208\";a=\"228627821\""],"X-ExtLoop1":"1","From":"KhaiWenTan <khai.wen.tan@linux.intel.com>","To":"anthony.l.nguyen@intel.com, przemyslaw.kitszel@intel.com,\n andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,\n kuba@kernel.org, pabeni@redhat.com","Cc":"intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,\n linux-kernel@vger.kernel.org, faizal.abdul.rahim@intel.com,\n hector.blanco.alcaine@intel.com, hong.aun.looi@intel.com,\n khai.wen.tan@intel.com, Faizal Rahim <faizal.abdul.rahim@linux.intel.com>,\n Looi, KhaiWenTan <khai.wen.tan@linux.intel.com>","Date":"Thu,  9 Apr 2026 15:27:47 +0800","Message-ID":"<20260409072747.217836-1-khai.wen.tan@linux.intel.com>","X-Mailer":"git-send-email 2.43.0","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Mailman-Approved-At":"Thu, 09 Apr 2026 15:55:08 +0000","X-Mailman-Original-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1775721013; x=1807257013;\n h=from:to:cc:subject:date:message-id:mime-version:\n content-transfer-encoding;\n bh=xXwCqovJX3iIOUZaivpInM88vxlkHLtFkzVV9gvd0xc=;\n b=GslN6c/CmdnN7es5igOS0h7zODAH7PuU3lWY0ExLmLbSa3wjqCeVH6nI\n povDAV4KSr7u1u6KuoT/YGoAB9585U08JI9goZ3UQpWMcwRQm5CLHYf/L\n W7Jny6XUbdtCQtAvO6wH9kthCiY8m7YDHqY79jiaZVgr+ZIATN2qo1h+L\n sgprvgxE9lbYhcpMoAwRWQFhV961sjKU+NjZGgfzAsGGTdOVOTeWVYM0p\n EEVVPvHjL3guMtjcwU518eWHX+c5A4qXyOUrQX+n/ZCK4LNGTLqcC+naZ\n ebMVijAYWXXGkj6VYwrI7sBUj+nby7vb2vpHXihIlLtrgGqq+sVeBWl4k\n w==;","X-Mailman-Original-Authentication-Results":["smtp3.osuosl.org;\n dmarc=none (p=none dis=none)\n header.from=linux.intel.com","smtp3.osuosl.org;\n dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com\n header.a=rsa-sha256 header.s=Intel header.b=GslN6c/C"],"Subject":"[Intel-wired-lan] [PATCH iwl-next 1/1] igc: add support for forcing\n link speed without autonegotiation","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Intel Wired Ethernet Linux Kernel Driver Development\n <intel-wired-lan.osuosl.org>","List-Unsubscribe":"<https://lists.osuosl.org/mailman/options/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>","List-Archive":"<http://lists.osuosl.org/pipermail/intel-wired-lan/>","List-Post":"<mailto:intel-wired-lan@osuosl.org>","List-Help":"<mailto:intel-wired-lan-request@osuosl.org?subject=help>","List-Subscribe":"<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>,\n <mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"},"content":"From: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>\n\nAllow users to force 10/100 Mb/s link speed and duplex via ethtool\nwhen autonegotiation is disabled. Previously, the driver rejected\n\"ethtool -s <dev> autoneg off speed <N> duplex <half|full>\" with\n\"Force mode currently not supported.\"\n\nWhen autoneg is disabled, the driver programs both the GPY PHY and\nI225/I226 MAC control registers to bypass autonegotiation and apply\nthe requested speed and duplex. The MAC CTRL register is configured\nwith FRCSPD, FRCDPLX, and the appropriate SPEED and FD bits, while\nthe PHY STD_CTRL register has ANEN cleared and SSM/SSL/DPLX set to\nmatch. Flow control is also forced on the MAC side when autoneg is\ndisabled, consistent with the existing autoneg-failed path.\n\nForcing 1000 Mb/s and 2500 Mb/s is not supported by this change.\n\nReviewed-by: Looi, Hong Aun <hong.aun.looi@intel.com>\nSigned-off-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>\nSigned-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>\n---\n drivers/net/ethernet/intel/igc/igc_base.c    |  35 +++++-\n drivers/net/ethernet/intel/igc/igc_defines.h |   9 +-\n drivers/net/ethernet/intel/igc/igc_ethtool.c | 122 ++++++++++++++-----\n drivers/net/ethernet/intel/igc/igc_hw.h      |   9 ++\n drivers/net/ethernet/intel/igc/igc_mac.c     |   2 +-\n drivers/net/ethernet/intel/igc/igc_main.c    |   2 +-\n drivers/net/ethernet/intel/igc/igc_phy.c     |  66 +++++++++-\n drivers/net/ethernet/intel/igc/igc_phy.h     |   1 +\n 8 files changed, 201 insertions(+), 45 deletions(-)","diff":"diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c\nindex 1613b562d17c..ab9120a3127f 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.c\n+++ b/drivers/net/ethernet/intel/igc/igc_base.c\n@@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw)\n \tu32 ctrl;\n \n \tctrl = rd32(IGC_CTRL);\n-\tctrl |= IGC_CTRL_SLU;\n-\tctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);\n-\twr32(IGC_CTRL, ctrl);\n-\n-\tret_val = igc_setup_copper_link(hw);\n+\tctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX |\n+\t\t  IGC_CTRL_SPEED_MASK | IGC_CTRL_FD);\n+\n+\tif (hw->mac.autoneg_enabled) {\n+\t\tctrl |= IGC_CTRL_SLU;\n+\t\twr32(IGC_CTRL, ctrl);\n+\t\tret_val = igc_setup_copper_link(hw);\n+\t} else {\n+\t\tctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX;\n+\n+\t\tswitch (hw->mac.forced_speed_duplex) {\n+\t\tcase IGC_FORCED_10H:\n+\t\t\tctrl |= IGC_CTRL_SPEED_10;\n+\t\t\tbreak;\n+\t\tcase IGC_FORCED_10F:\n+\t\t\tctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD;\n+\t\t\tbreak;\n+\t\tcase IGC_FORCED_100H:\n+\t\t\tctrl |= IGC_CTRL_SPEED_100;\n+\t\t\tbreak;\n+\t\tcase IGC_FORCED_100F:\n+\t\t\tctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -IGC_ERR_CONFIG;\n+\t\t}\n+\t\twr32(IGC_CTRL, ctrl);\n+\t\tret_val = igc_setup_copper_link(hw);\n+\t}\n \n \treturn ret_val;\n }\n@@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = {\n \t.reset\t\t\t= igc_phy_hw_reset,\n \t.read_reg\t\t= igc_read_phy_reg_gpy,\n \t.write_reg\t\t= igc_write_phy_reg_gpy,\n+\t.force_speed_duplex\t= igc_force_speed_duplex,\n };\n \n const struct igc_info igc_base_info = {\ndiff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h\nindex 9482ab11f050..3f504751c2d9 100644\n--- a/drivers/net/ethernet/intel/igc/igc_defines.h\n+++ b/drivers/net/ethernet/intel/igc/igc_defines.h\n@@ -129,10 +129,13 @@\n #define IGC_ERR_SWFW_SYNC\t\t13\n \n /* Device Control */\n+#define IGC_CTRL_FD\t\tBIT(0)  /* Full Duplex */\n #define IGC_CTRL_RST\t\t0x04000000  /* Global reset */\n-\n #define IGC_CTRL_PHY_RST\t0x80000000  /* PHY Reset */\n #define IGC_CTRL_SLU\t\t0x00000040  /* Set link up (Force Link) */\n+#define IGC_CTRL_SPEED_MASK\tGENMASK(10, 8)\n+#define IGC_CTRL_SPEED_10\tFIELD_PREP(IGC_CTRL_SPEED_MASK, 0)\n+#define IGC_CTRL_SPEED_100\tFIELD_PREP(IGC_CTRL_SPEED_MASK, 1)\n #define IGC_CTRL_FRCSPD\t\t0x00000800  /* Force Speed */\n #define IGC_CTRL_FRCDPX\t\t0x00001000  /* Force Duplex */\n #define IGC_CTRL_VME\t\t0x40000000  /* IEEE VLAN mode enable */\n@@ -673,6 +676,10 @@\n #define IGC_GEN_POLL_TIMEOUT\t1920\n \n /* PHY Control Register */\n+#define MII_CR_SPEED_MASK\t(BIT(6) | BIT(13))\n+#define MII_CR_SPEED_10\t\t0x0000\t/* SSM=0, SSL=0: 10 Mb/s */\n+#define MII_CR_SPEED_100\tBIT(13)\t/* SSM=0, SSL=1: 100 Mb/s */\n+#define MII_CR_DUPLEX_EN\tBIT(8)\t/* 0 = Half Duplex, 1 = Full Duplex */\n #define MII_CR_RESTART_AUTO_NEG\t0x0200  /* Restart auto negotiation */\n #define MII_CR_POWER_DOWN\t0x0800  /* Power down */\n #define MII_CR_AUTO_NEG_EN\t0x1000  /* Auto Neg Enable */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c\nindex 0122009bedd0..e14771532dad 100644\n--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c\n+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c\n@@ -1930,7 +1930,12 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,\n \n \t/* set autoneg settings */\n \tethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);\n-\tethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);\n+\tif (hw->mac.autoneg_enabled) {\n+\t\tethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);\n+\t\tcmd->base.autoneg = AUTONEG_ENABLE;\n+\t} else {\n+\t\tcmd->base.autoneg = AUTONEG_DISABLE;\n+\t}\n \n \t/* Set pause flow control settings */\n \tethtool_link_ksettings_add_link_mode(cmd, supported, Pause);\n@@ -1983,7 +1988,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,\n \t\tcmd->base.duplex = DUPLEX_UNKNOWN;\n \t}\n \tcmd->base.speed = speed;\n-\tcmd->base.autoneg = AUTONEG_ENABLE;\n \n \t/* MDI-X => 2; MDI =>1; Invalid =>0 */\n \tif (hw->phy.media_type == igc_media_type_copper)\n@@ -2000,37 +2004,54 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,\n \treturn 0;\n }\n \n-static int\n-igc_ethtool_set_link_ksettings(struct net_device *netdev,\n-\t\t\t       const struct ethtool_link_ksettings *cmd)\n+/**\n+ * igc_handle_autoneg_disabled - Configure forced speed/duplex settings\n+ * @netdev: network interface device structure\n+ * @speed: requested speed\n+ * @duplex: requested duplex\n+ *\n+ * Validates and records forced speed/duplex when autoneg is disabled.\n+ * Only 10/100 Mb/s speeds are supported.\n+ *\n+ * Return: 0 on success, negative errno on failure.\n+ */\n+static int igc_handle_autoneg_disabled(struct net_device *netdev, u32 speed,\n+\t\t\t\t       u8 duplex)\n {\n \tstruct igc_adapter *adapter = netdev_priv(netdev);\n-\tstruct net_device *dev = adapter->netdev;\n-\tstruct igc_hw *hw = &adapter->hw;\n-\tu16 advertised = 0;\n+\tstruct igc_mac_info *mac = &adapter->hw.mac;\n+\tenum igc_forced_speed_duplex forced_speed_duplex;\n \n-\t/* When adapter in resetting mode, autoneg/speed/duplex\n-\t * cannot be changed\n-\t */\n-\tif (igc_check_reset_block(hw)) {\n-\t\tnetdev_err(dev, \"Cannot change link characteristics when reset is active\\n\");\n+\tswitch (speed) {\n+\tcase SPEED_10:\n+\t\tforced_speed_duplex = (duplex == DUPLEX_FULL) ? IGC_FORCED_10F : IGC_FORCED_10H;\n+\t\tbreak;\n+\tcase SPEED_100:\n+\t\tforced_speed_duplex = (duplex == DUPLEX_FULL) ? IGC_FORCED_100F : IGC_FORCED_100H;\n+\t\tbreak;\n+\tdefault:\n+\t\tnetdev_info(netdev, \"Unsupported speed for forced link\\n\");\n \t\treturn -EINVAL;\n \t}\n \n-\t/* MDI setting is only allowed when autoneg enabled because\n-\t * some hardware doesn't allow MDI setting when speed or\n-\t * duplex is forced.\n-\t */\n-\tif (cmd->base.eth_tp_mdix_ctrl) {\n-\t\tif (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&\n-\t\t    cmd->base.autoneg != AUTONEG_ENABLE) {\n-\t\t\tnetdev_err(dev, \"Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\\n\");\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t}\n+\tmac->autoneg_enabled = false;\n+\tmac->forced_speed_duplex = forced_speed_duplex;\n+\treturn 0;\n+}\n \n-\twhile (test_and_set_bit(__IGC_RESETTING, &adapter->state))\n-\t\tusleep_range(1000, 2000);\n+/**\n+ * igc_handle_autoneg_enabled - Configure autonegotiation advertisement\n+ * @adapter: private driver structure\n+ * @cmd: ethtool link ksettings from user\n+ *\n+ * Records advertised speeds and flow control settings when autoneg\n+ * is enabled.\n+ */\n+static void igc_handle_autoneg_enabled(struct igc_adapter *adapter,\n+\t\t\t\t       const struct ethtool_link_ksettings *cmd)\n+{\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tu16 advertised = 0;\n \n \tif (ethtool_link_ksettings_test_link_mode(cmd, advertising,\n \t\t\t\t\t\t  2500baseT_Full))\n@@ -2056,12 +2077,51 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,\n \t\t\t\t\t\t  10baseT_Half))\n \t\tadvertised |= ADVERTISE_10_HALF;\n \n-\tif (cmd->base.autoneg == AUTONEG_ENABLE) {\n-\t\thw->phy.autoneg_advertised = advertised;\n-\t\tif (adapter->fc_autoneg)\n-\t\t\thw->fc.requested_mode = igc_fc_default;\n+\thw->mac.autoneg_enabled = true;\n+\thw->phy.autoneg_advertised = advertised;\n+\tif (adapter->fc_autoneg)\n+\t\thw->fc.requested_mode = igc_fc_default;\n+}\n+\n+static int\n+igc_ethtool_set_link_ksettings(struct net_device *netdev,\n+\t\t\t       const struct ethtool_link_ksettings *cmd)\n+{\n+\tstruct igc_adapter *adapter = netdev_priv(netdev);\n+\tstruct net_device *dev = adapter->netdev;\n+\tstruct igc_hw *hw = &adapter->hw;\n+\n+\t/* When adapter in resetting mode, autoneg/speed/duplex\n+\t * cannot be changed\n+\t */\n+\tif (igc_check_reset_block(hw)) {\n+\t\tnetdev_err(dev, \"Cannot change link characteristics when reset is active\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* MDI setting is only allowed when autoneg enabled because\n+\t * some hardware doesn't allow MDI setting when speed or\n+\t * duplex is forced.\n+\t */\n+\tif (cmd->base.eth_tp_mdix_ctrl) {\n+\t\tif (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&\n+\t\t    cmd->base.autoneg != AUTONEG_ENABLE) {\n+\t\t\tnetdev_err(dev, \"Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\twhile (test_and_set_bit(__IGC_RESETTING, &adapter->state))\n+\t\tusleep_range(1000, 2000);\n+\n+\tif (cmd->base.autoneg == AUTONEG_DISABLE) {\n+\t\tif (igc_handle_autoneg_disabled(netdev, cmd->base.speed,\n+\t\t\t\t\t\tcmd->base.duplex)) {\n+\t\t\tclear_bit(__IGC_RESETTING, &adapter->state);\n+\t\t\treturn -EINVAL;\n+\t\t}\n \t} else {\n-\t\tnetdev_info(dev, \"Force mode currently not supported\\n\");\n+\t\tigc_handle_autoneg_enabled(adapter, cmd);\n \t}\n \n \t/* MDI-X => 2; MDI => 1; Auto => 3 */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h\nindex be8a49a86d09..0794139dbc24 100644\n--- a/drivers/net/ethernet/intel/igc/igc_hw.h\n+++ b/drivers/net/ethernet/intel/igc/igc_hw.h\n@@ -73,6 +73,13 @@ struct igc_info {\n \n extern const struct igc_info igc_base_info;\n \n+enum igc_forced_speed_duplex {\n+\tIGC_FORCED_10H,\n+\tIGC_FORCED_10F,\n+\tIGC_FORCED_100H,\n+\tIGC_FORCED_100F,\n+};\n+\n struct igc_mac_info {\n \tstruct igc_mac_operations ops;\n \n@@ -94,6 +101,8 @@ struct igc_mac_info {\n \n \tbool autoneg_failed;\n \tbool get_link_status;\n+\tbool autoneg_enabled;\n+\tenum igc_forced_speed_duplex forced_speed_duplex;\n };\n \n struct igc_nvm_operations {\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c\nindex 7ac6637f8db7..16b0f2db0689 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.c\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.c\n@@ -452,7 +452,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)\n \t * so we had to force link.  In this case, we need to force the\n \t * configuration of the MAC to match the \"fc\" parameter.\n \t */\n-\tif (mac->autoneg_failed)\n+\tif (mac->autoneg_failed || !mac->autoneg_enabled)\n \t\tret_val = igc_force_mac_fc(hw);\n \n \tif (ret_val) {\ndiff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c\nindex 72bc5128d8b8..437e1d1ef1e4 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev,\n \t/* Initialize link properties that are user-changeable */\n \tadapter->fc_autoneg = true;\n \thw->phy.autoneg_advertised = 0xaf;\n-\n+\thw->mac.autoneg_enabled = true;\n \thw->fc.requested_mode = igc_fc_default;\n \thw->fc.current_mode = igc_fc_default;\n \ndiff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c\nindex 6c4d204aecfa..51870a5c00a6 100644\n--- a/drivers/net/ethernet/intel/igc/igc_phy.c\n+++ b/drivers/net/ethernet/intel/igc/igc_phy.c\n@@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw)\n \ts32 ret_val = 0;\n \tbool link;\n \n-\t/* Setup autoneg and flow control advertisement and perform\n-\t * autonegotiation.\n-\t */\n-\tret_val = igc_copper_link_autoneg(hw);\n-\tif (ret_val)\n-\t\tgoto out;\n+\tif (hw->mac.autoneg_enabled) {\n+\t\t/* Setup autoneg and flow control advertisement and perform\n+\t\t * autonegotiation.\n+\t\t */\n+\t\tret_val = igc_copper_link_autoneg(hw);\n+\t\tif (ret_val)\n+\t\t\tgoto out;\n+\t} else {\n+\t\tret_val = hw->phy.ops.force_speed_duplex(hw);\n+\t\tif (ret_val) {\n+\t\t\thw_dbg(\"Error Forcing Speed/Duplex\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n \n \t/* Check link status. Wait up to 100 microseconds for link to become\n \t * valid.\n@@ -778,3 +786,49 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw)\n \n \treturn gphy_version;\n }\n+\n+/**\n+ * igc_force_speed_duplex - Force PHY speed and duplex settings\n+ * @hw: pointer to the HW structure\n+ *\n+ * Programs the GPY PHY control register to disable autonegotiation\n+ * and force the speed/duplex indicated by hw->mac.forced_speed_duplex.\n+ */\n+s32 igc_force_speed_duplex(struct igc_hw *hw)\n+{\n+\tenum igc_forced_speed_duplex forced_speed_duplex = hw->mac.forced_speed_duplex;\n+\tstruct igc_phy_info *phy = &hw->phy;\n+\tu16 phy_ctrl;\n+\ts32 ret_val;\n+\n+\tret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\tphy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN |\n+\t\t      MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);\n+\n+\tswitch (forced_speed_duplex) {\n+\tcase IGC_FORCED_10H:\n+\t\tphy_ctrl |= MII_CR_SPEED_10;\n+\t\tbreak;\n+\tcase IGC_FORCED_10F:\n+\t\tphy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN;\n+\t\tbreak;\n+\tcase IGC_FORCED_100H:\n+\t\tphy_ctrl |= MII_CR_SPEED_100;\n+\t\tbreak;\n+\tcase IGC_FORCED_100F:\n+\t\tphy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -IGC_ERR_CONFIG;\n+\t}\n+\n+\tret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);\n+\tif (ret_val)\n+\t\treturn ret_val;\n+\n+\thw->mac.get_link_status = true;\n+\treturn 0;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h\nindex 832a7e359f18..d37a89174826 100644\n--- a/drivers/net/ethernet/intel/igc/igc_phy.h\n+++ b/drivers/net/ethernet/intel/igc/igc_phy.h\n@@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw);\n s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);\n s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);\n u16 igc_read_phy_fw_version(struct igc_hw *hw);\n+s32 igc_force_speed_duplex(struct igc_hw *hw);\n \n #endif\n","prefixes":["iwl-next","1/1"]}