From patchwork Thu Nov 10 23:11:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Lendacky X-Patchwork-Id: 693505 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3tFJj40Dqbz9t2D for ; Fri, 11 Nov 2016 10:12:08 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=amdcloud.onmicrosoft.com header.i=@amdcloud.onmicrosoft.com header.b="PGO1yS4A"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965198AbcKJXMC (ORCPT ); Thu, 10 Nov 2016 18:12:02 -0500 Received: from mail-by2nam03on0058.outbound.protection.outlook.com ([104.47.42.58]:33287 "EHLO NAM03-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S965060AbcKJXLt (ORCPT ); Thu, 10 Nov 2016 18:11:49 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=/1+McDLu33kMs4pVSd3QAhvsXryKRBFPzNn5cM9g+0w=; b=PGO1yS4AaB5Adrt8oNRJSzge5urm/QSaF65cQblt5/yfneuYWPj8S8BaXh+mMmJosYEr7BhQ3oLTClIVhO7KfKIDcll0EXOAgl4PviW3VXROzcGU+2FDlUZFlBhVidSaE7tys2BEDhItBCj935IUpX56QLH5CH/mHh/cY8jN53I= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Thomas.Lendacky@amd.com; Received: from tlendack-t1.amdoffice.net (165.204.77.1) by MWHPR12MB1150.namprd12.prod.outlook.com (10.169.204.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.707.6; Thu, 10 Nov 2016 23:11:45 +0000 From: Tom Lendacky Subject: [PATCH net-next v1 11/11] amd-xgbe: Add support for a KR redriver To: CC: Florian Fainelli , David Miller Date: Thu, 10 Nov 2016 17:11:41 -0600 Message-ID: <20161110231141.20704.67246.stgit@tlendack-t1.amdoffice.net> In-Reply-To: <20161110230916.20704.34081.stgit@tlendack-t1.amdoffice.net> References: <20161110230916.20704.34081.stgit@tlendack-t1.amdoffice.net> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: MWHPR21CA0058.namprd21.prod.outlook.com (10.172.93.148) To MWHPR12MB1150.namprd12.prod.outlook.com (10.169.204.14) X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1150; 2:HSSEVz6FLqp7TSSV4vgbCUunUNldMUXTg+SOQ/KU5DLHUOkw5u3n6XNeCCluM27b5dvX0/uUx+XcD9cD4xbs19x4jqyHJpo23OUDzkgXqQaVgvYqoqA/LSZu/FRepxhcluJtcXf9L70vUquXXG7ZpR9QJTCid3zKtVwX5C9aGzk=; 3:9y6JJ6RbNshm3zJWluO/P06rGaKukyHqgLQCDsFAe050Py4wtSsvWrlhfEN1kMYNf39Vu0/9yW388lLo9ubLOuHVANA2HvhRjWQ2DVAcPCLUFF9hMLSpdPtZ8OppDGUeXmLwAQR8W/HOYv0bp+xIN1Bi8woY0EkBowB8nu1VVzc=; 25:cpQGZlI9bu/BSB5k6/r54xzBNqqKzquefhcLAE7jUvEvokrtuw78XeiGUwbvSHxn5s3UMpAo2EUydXbltzaihlIc5vPELNkhF1WByVlqjutZvFKSxJqf4d1sScA1S79SCXf1BUXZbQdAzih9mUQGeqCYtvYNre3vuVgKNFPE0pnKOTYVEBjQAqb44hhF802ElHnO+91WI6pS+/a1J2uO7rD9c5rvMCBqSzJenoDqNXj19J/qBIsn063itbA1aksEgN0QJhxt8PUewwT35g9F0GTTXaH4rMdgIIiGBgd0v3MvjZBkPDI7R3MYDLN+HtfSu+viTgesihzNgCWHvQ/L01uMB1cmIzxTjYdVDOtsC3953gQBOKiG2xi3ENIMhpOqvurZaukq5Zq5B4mEXZN4NReY7wiHjF8aMAc123OETGzWew/lQMka6ffI5FEJ2EBq X-MS-Office365-Filtering-Correlation-Id: 0f34e20f-7fe3-4f6a-c371-08d409bef132 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:MWHPR12MB1150; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1150; 31:ZtFgsOAaEW6S97mn+k6uexI/3mHF/uIxzykY7R5Ln0bR6b12Eu6u5ad02Up2N2cvTwFs3VcGacMmpM/5IUcXsTSfftL/s5ocjlb9lgn4XTKb3ZZIhDqobNYXCBL54fdSgX96CflHE66YenhYaOgQArqlkeR1Ynz8UD4/gOXcRvoQ/XFDAnGmfGDGAB+73tfbEg5HNmsejXyxACMMKZeh8MYrDIKC08YdkYEFeVysFwfxFm306zFdNg3qWIu1d5yg; 20:LPqvjsu0ge4+HJ2yzPRQa6BkWA2DTmoHliBdnthUkglcUnbbVlcQfK8ons/ZAGAqQAIVWCZDm0UIG+VJTWfF9s3wQjJe6vY9wg/HPLfm+d4GtlfviAhTuJw2PieAD+p8NKuBxsU+td0qh06qc2xRF1sXjTJw1Cpd/z80oA8are37nWCYqoKpfG2xSDJlddAK2ZSSqlb+tTYq+mbTaFJDIfomTbR/Yvyna2zxqma73W6BQPbjuLsG+NnHgBVYuKCXE+jVpfdwnGYREsN+9WeRU19/2v3s3CnFCWiEqs1CtPZA87PizuFtzBX7hGhz8kNObLPRVrhtz3MPLY2ZkINYNksXZHxk95fZf5V5c8BPevy40DVn86ImcZz64vsrcT3gWOT42N8KAPIdfTjiZYIgmbriFbYAODxFtdMtLfiPZMDquy5R7GVnbRQN+XP/G+ymJXG0kgR46o1tOn9i2e9leclgT4tTqlBHZnQ+Uqqa6hCY31bgB7Z8x6r2EbpoFERG X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6055026); SRVR:MWHPR12MB1150; BCL:0; PCL:0; RULEID:; SRVR:MWHPR12MB1150; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1150; 4:WWqI714FsNgq2GSHy7bRcaXrXM9xZkOmAEVnuPKCrh4Ol4S0iWGYemG7mwlI8/7aNOEjXrOap3zIueCjMMI3mLlpAxKOynEutwiadfQnwZquTcJBoRf8Nsuv7+qTOivJc436RCjF3NIZkS/mhOkWkKTT10BGTAqRKtZC1mrAzF/6fA+O60DhLgoFxt+HTbP5hS6BoqcJ/EG6xPBASKtW/V1LFXBBXW/vcmom8nR/6hjxFqRtz5rfY5MIBbhiIAuE1AHaIj51xDc/MxaK1/Zpayk46i5dRgX3c8YWXJOYrp2Q+xtXL5KOXroKOIrsnQtbwtL+U1/QVAvkiFkzmavABl/w9piINHlUb04Nzk7LCuqGVrGbFyluBruPS1vxUvHKphL8y8MN3Z/oBOIW3fpcFn5nSbMoJEZFWP1lXnvYZtrjDcm7d7ctVLbNq9KuOW7ivo00Y2bM1NYFSvUM6zEqiQ== X-Forefront-PRVS: 01221E3973 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(7916002)(189002)(199003)(586003)(47776003)(6666003)(54356999)(6916009)(2950100002)(50986999)(66066001)(97746001)(5890100001)(69596002)(6116002)(81156014)(4326007)(8676002)(2906002)(3846002)(23676002)(97736004)(33646002)(76176999)(81166006)(4001350100001)(230700001)(189998001)(1076002)(101416001)(77096005)(110136003)(92566002)(5660300001)(305945005)(103116003)(2351001)(68736007)(86362001)(106356001)(105586002)(53416004)(7736002)(7846002)(50466002)(42186005)(83506001)(9686002)(71626007); DIR:OUT; SFP:1101; SCL:1; SRVR:MWHPR12MB1150; H:tlendack-t1.amdoffice.net; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtNV0hQUjEyTUIxMTUwOzIzOkNlbXhUeUdoV05UR1hIQS9oZndCTWM5ZDRW?= =?utf-8?B?ZGhlQTBDZm5wU3pKdURvUkJWZnVDQlJSa1NSRGNoVytENDRQMUoyNzFraXVG?= =?utf-8?B?N1JtM2dHRXpXSmd5U3ZZbnY4TXJEM3MyQmdta21BdC94VCtBekkwUkh2U0JV?= =?utf-8?B?VnMzV0ZVM1RTNHdPZnlJaDRlczhzU0ZoMjRIVHVRU3p2Sm9LdUk3eVFYLzVS?= =?utf-8?B?emFBd2gzZ2syQkVuOERZZ1JHbFN3RmFMcjR5dmZBY1BHdTFCZXM3UVM0R0g2?= =?utf-8?B?ZXdwRXQzams4Z0dBNDVEVG9OVXVzRG9FcWsxTmJ3MzJsM3h4cHR0RVFnNHBF?= =?utf-8?B?dzNTMGdHYURoT1lycGY3QU5vMitWUzhyaDh2ampWMERhSml5RmVsbldNZ3VH?= =?utf-8?B?MTBobHowN0d6TjV6ekFXM2NOQWYzbGFoNWp0ckRoeHdQNzArN2JSVjB4VjJj?= =?utf-8?B?ZWd1a2thNWoxNTRCdEZEcy9LL3lEdVNHWCtaRXhkTGpxcWZhaWtjRFFFT1c4?= =?utf-8?B?b01XTW9GNnJlNzFSNDFZOWpGYU5IeXJhT0txa0ppeEdObWdROEEyK2gxS1Bu?= =?utf-8?B?SWtqaG9QQ3JGY1d1OFFtaGF5ZGo4WGwwaGtia2NSWG9XdXNzaU5qMTlhUjlU?= =?utf-8?B?YXlrS1VsUk4wVTl3TDlVc2lTeUdGY3ROcWROZEo4cU9qMEV6VHNsN1NkbXFW?= =?utf-8?B?UEhmU3hYNGFnY1VtT3QxWGNPTDBYeUZDQUJqckNoazZ5MS9RYmcrOHUybENY?= =?utf-8?B?NkdBQ2l4SjZHZnVGakZUdXg3M0lPb01QVUR0UVkrNHdZcnV6ZmdaRm9Qc001?= =?utf-8?B?WklMaFZrenQ5ZUxZb0tFRkxRVGpoVXU0c0dNVFJOcFI2UlN3eXlaVlNzSnVC?= =?utf-8?B?b2JReEkxa3NMTiszME93Qzg0SjRxdVBTTk9tVnpMWDE0cy9ISnNVbEdPejdE?= =?utf-8?B?TytlbzhzaGQyOVc2c2FTbWVTZ2Z6eDdLUElXRGw0elVGa0pCRGt6Ym9GUXQw?= =?utf-8?B?VUk0d1VjT3czUHBtZFNyN0c0bzBrbGMrZEN5bmo4VVRrWjFaMGlISTE2ZmhZ?= =?utf-8?B?aEtPend4Z0tTbm8zL0ZPQ0EzK3FMeE1jMkNjUUVFNU5WVXJCRlB3TFpzR0FG?= =?utf-8?B?bDU2M0tiUzFmalJrSFk3RjBYUVBhS3VBZFA4OTlPSThRLzUzbmFHQllEbGdB?= =?utf-8?B?bFJVUkt2OHJQOTVybGxCeXJYRXBUUWNvdjNmR0swUk9RWGhyYndyZE0wR0NV?= =?utf-8?B?a2RSUU1xQlkrck9sY2c5N1hkdmZhU3pnVm0vcDJ2bHZndkJTNFBYV2ZKUVJP?= =?utf-8?B?RjVuUnJONHpzYUhCejhMYUhsUW1EZTZoQUpHTXloTFpONDNKOFhRaWU4aVFU?= =?utf-8?B?L3FZODBtbWJrVTlUMkJXOGF6a0c4T0tZRGlRYjJOV1I2SnZCNmd6ZkZTaE55?= =?utf-8?B?QWhMZFJUM1hHdm9GRE5sQzBhUitIYjB1SUNpd3NnWFBDajlXZWZ1OXFWZE4w?= =?utf-8?B?SVdJUDVIVGNoTXE3dkM1cHZhUkFDMW5iZWxHYTJobDhWbXZWc1oyeXFPejZG?= =?utf-8?B?OUdjL0hKNnc3WXZWS2JNZ3JzYVF4bnU4NVZpTEhYUGFnRjNoVW5iVno0aWR6?= =?utf-8?B?SzYzbTB1YUF1RW9ZNEFjaVk5N1lwSm9qNmIrN1g4eEhmaFk0RW05K2JDajNj?= =?utf-8?Q?Y8KCY6f8M7y5cWQzq4=3D?= X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1150; 6:Fev/I2s0B9vXGvIQmk4QC8YW5kPVRhlpZyyiT36XBSUdIAgI1GsDmxzP9GiPqYLqXA4o3RRX8F1q5OWNnxwBQCF/N7T5nDnyvnyyd4Mw88a/OXbac/K6qua64Zt1Eqbgr8m0y12IBOHV/9gEfAmnvNpgxg/7dX3IGHuXVIJSlMhiuWUNeef60SBXldt0RLPBVMcxYk5AoosjZtg/OK6HhVD9BC1LNnUwQ4McjmMLVbwUUbQ6gwL64teaijwJzKylnrwXo/7bPost1vIjIQkguLRLH0CTXPKFLQJp/UJxcbNPwkDu53yNeLeEduEGnRjq5KiRQNQmxjvjzkD6mM/pNFvPT4updVs1x6Cd/es3P3M=; 5:E7a7YxAmf102kkf4PgqN5NMNX2aND1R/5LytpFgDen+E+I8SD/wKrJTOpS343YstqvtFoVXCY72MY7EKNymQXklXDF3acTNqPMgcm0ckswytZ/heKig1xW3qbzpa8ttLltJkGHh5i8yJuYDVd12Syg==; 24:Tho/Lg1EriGxHHvnrpFbDXZUhVFQK/gI4qUek//OrZfF1EbE6uC7wk0g7CO7GQjHugm36T6TK/IT433xL0upzBe+JFSyHIL6GRkP++R7d2A= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1150; 7:Eso/yn3q2zXMOaEihFISJmREYN8NvTg5p440UKL+Tdtne7rYcgWW5kgh6cILFH1zRuCHKimv2qzghDurEft1LWfUb1/I2dlyMXm/0cBSzbqQBF7+i8ZYuhJPS+idjCAf6J95/IsIveg99bWL7Sw9QpBis9UuUDGhjdJtlMcr4Gd7Txg+3M64zS5//LcA3rElyTgngpV9s9soynNdvJYjIWF7Zrh+0VJr02G3HXXXxV99J/bVUnGm4uMBtjdgeBKH8vl9BqV8JBKXu2Xy0d5zQ3b3APZCind/Cu+z/yj3vDBgan69+b6Tv+9LT4pbG1w5Uf0zJfI/vTD7ZknOxnYijPtylJuDgTW6xjeUDKfhz7E=; 20:1/8JqVI4bOTpF3y05Iw343jvq/LqGXCINoV+OJ/6TNoaDqz1AFrokS95oHm9DTnA4+1J/9dpAiCY6c7RSUvBlYVC1bxUG+fujlIj2xitWF2piA5JvhJR30+md3g9+mGxOX2ZVHqpqAoAYd4rdirpXoLHBnyS8/4AS/N9DKtKchf/CdkCMkWa7XadD5p6grEfKR6hyZlvqhAv/fXcOwARQPtnexdnh6lO43EbQfbEpaW6bhOC1hx2IIcmifsBsSJN X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Nov 2016 23:11:45.7321 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: MWHPR12MB1150 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch provides support for the presence of a KR redriver chip in between the device PCS and an external PHY. When a redriver chip is present the device must perform clause 73 auto-negotiation in order to set the redriver chip for the downstream connection. Signed-off-by: Tom Lendacky --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 10 + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 45 ++- drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c | 7 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 427 +++++++++++++++++++++++++-- drivers/net/ethernet/amd/xgbe/xgbe.h | 6 5 files changed, 458 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index ecd4f4d..5b7ba25 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -1062,6 +1062,16 @@ #define XP_PROP_4_MUX_ADDR_LO_WIDTH 3 #define XP_PROP_4_MUX_CHAN_INDEX 4 #define XP_PROP_4_MUX_CHAN_WIDTH 3 +#define XP_PROP_4_REDRV_ADDR_INDEX 16 +#define XP_PROP_4_REDRV_ADDR_WIDTH 7 +#define XP_PROP_4_REDRV_IF_INDEX 23 +#define XP_PROP_4_REDRV_IF_WIDTH 1 +#define XP_PROP_4_REDRV_LANE_INDEX 24 +#define XP_PROP_4_REDRV_LANE_WIDTH 3 +#define XP_PROP_4_REDRV_MODEL_INDEX 28 +#define XP_PROP_4_REDRV_MODEL_WIDTH 3 +#define XP_PROP_4_REDRV_PRESENT_INDEX 31 +#define XP_PROP_4_REDRV_PRESENT_WIDTH 1 /* I2C Control register offsets */ #define IC_CON 0x0000 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 622675a..0ecae70 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -179,6 +179,7 @@ static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata) { switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_enable_interrupts(pdata); break; case XGBE_AN_MODE_CL37: @@ -254,6 +255,10 @@ static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) static void xgbe_sfi_mode(struct xgbe_prv_data *pdata) { + /* If a KR re-driver is present, change to KR mode instead */ + if (pdata->kr_redrv) + return xgbe_kr_mode(pdata); + /* Disable KR training */ xgbe_an73_disable_kr_training(pdata); @@ -433,6 +438,7 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata) { switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_restart(pdata); break; case XGBE_AN_MODE_CL37: @@ -448,6 +454,7 @@ static void xgbe_an_disable(struct xgbe_prv_data *pdata) { switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_disable(pdata); break; case XGBE_AN_MODE_CL37: @@ -687,6 +694,7 @@ static irqreturn_t xgbe_an_isr(int irq, void *data) switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_isr(pdata); break; case XGBE_AN_MODE_CL37: @@ -895,6 +903,7 @@ static void xgbe_an_state_machine(struct work_struct *work) switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_state_machine(pdata); break; case XGBE_AN_MODE_CL37: @@ -910,16 +919,18 @@ static void xgbe_an_state_machine(struct work_struct *work) static void xgbe_an37_init(struct xgbe_prv_data *pdata) { - unsigned int reg; + unsigned int advertising, reg; + + advertising = pdata->phy_if.phy_impl.an_advertising(pdata); /* Set up Advertisement register */ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); - if (pdata->phy.advertising & ADVERTISED_Pause) + if (advertising & ADVERTISED_Pause) reg |= 0x100; else reg &= ~0x100; - if (pdata->phy.advertising & ADVERTISED_Asym_Pause) + if (advertising & ADVERTISED_Asym_Pause) reg |= 0x80; else reg &= ~0x80; @@ -954,11 +965,13 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata) static void xgbe_an73_init(struct xgbe_prv_data *pdata) { - unsigned int reg; + unsigned int advertising, reg; + + advertising = pdata->phy_if.phy_impl.an_advertising(pdata); /* Set up Advertisement register 3 first */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); - if (pdata->phy.advertising & ADVERTISED_10000baseR_FEC) + if (advertising & ADVERTISED_10000baseR_FEC) reg |= 0xc000; else reg &= ~0xc000; @@ -967,13 +980,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) /* Set up Advertisement register 2 next */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); - if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) + if (advertising & ADVERTISED_10000baseKR_Full) reg |= 0x80; else reg &= ~0x80; - if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) || - (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) + if ((advertising & ADVERTISED_1000baseKX_Full) || + (advertising & ADVERTISED_2500baseX_Full)) reg |= 0x20; else reg &= ~0x20; @@ -982,12 +995,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) /* Set up Advertisement register 1 last */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - if (pdata->phy.advertising & ADVERTISED_Pause) + if (advertising & ADVERTISED_Pause) reg |= 0x400; else reg &= ~0x400; - if (pdata->phy.advertising & ADVERTISED_Asym_Pause) + if (advertising & ADVERTISED_Asym_Pause) reg |= 0x800; else reg &= ~0x800; @@ -1006,6 +1019,7 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata) pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: xgbe_an73_init(pdata); break; case XGBE_AN_MODE_CL37: @@ -1149,10 +1163,15 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) if (ret) return ret; - if (pdata->phy.autoneg != AUTONEG_ENABLE) - return xgbe_phy_config_fixed(pdata); + if (pdata->phy.autoneg != AUTONEG_ENABLE) { + ret = xgbe_phy_config_fixed(pdata); + if (ret || !pdata->kr_redrv) + return ret; - netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); + netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n"); + } else { + netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); + } /* Disable auto-negotiation interrupt */ disable_irq(pdata->an_irq); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c index 6c64d11..c75edca 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c @@ -295,6 +295,11 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) return mode; } +static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) +{ + return pdata->phy.advertising; +} + static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) { /* Nothing uniquely required for an configuration */ @@ -831,6 +836,8 @@ void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if) phy_impl->an_config = xgbe_phy_an_config; + phy_impl->an_advertising = xgbe_phy_an_advertising; + phy_impl->an_outcome = xgbe_phy_an_outcome; phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 9848f74..4ba4332 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -277,6 +277,26 @@ enum xgbe_mdio_reset { XGBE_MDIO_RESET_MAX, }; +/* Re-driver related definitions */ +enum xgbe_phy_redrv_if { + XGBE_PHY_REDRV_IF_MDIO = 0, + XGBE_PHY_REDRV_IF_I2C, + XGBE_PHY_REDRV_IF_MAX, +}; + +enum xgbe_phy_redrv_model { + XGBE_PHY_REDRV_MODEL_4223 = 0, + XGBE_PHY_REDRV_MODEL_4227, + XGBE_PHY_REDRV_MODEL_MAX, +}; + +enum xgbe_phy_redrv_mode { + XGBE_PHY_REDRV_MODE_CX = 5, + XGBE_PHY_REDRV_MODE_SR = 9, +}; + +#define XGBE_PHY_REDRV_MODE_REG 0x12b0 + /* PHY related configuration information */ struct xgbe_phy_data { enum xgbe_port_mode port_mode; @@ -327,6 +347,13 @@ struct xgbe_phy_data { enum xgbe_mdio_reset mdio_reset; unsigned int mdio_reset_addr; unsigned int mdio_reset_gpio; + + /* Re-driver support */ + unsigned int redrv; + unsigned int redrv_if; + unsigned int redrv_addr; + unsigned int redrv_lane; + unsigned int redrv_model; }; /* I2C, MDIO and GPIO lines are muxed, so only one device at a time */ @@ -346,6 +373,68 @@ static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, return pdata->i2c_if.i2c_xfer(pdata, i2c_op); } +static int xgbe_phy_redrv_write(struct xgbe_prv_data *pdata, unsigned int reg, + unsigned int val) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + struct xgbe_i2c_op i2c_op; + __be16 *redrv_val; + u8 redrv_data[5], csum; + unsigned int i, retry; + int ret; + + /* High byte of register contains read/write indicator */ + redrv_data[0] = ((reg >> 8) & 0xff) << 1; + redrv_data[1] = reg & 0xff; + redrv_val = (__be16 *)&redrv_data[2]; + *redrv_val = cpu_to_be16(val); + + /* Calculate 1 byte checksum */ + csum = 0; + for (i = 0; i < 4; i++) { + csum += redrv_data[i]; + if (redrv_data[i] > csum) + csum++; + } + redrv_data[4] = ~csum; + + retry = 1; +again1: + i2c_op.cmd = XGBE_I2C_CMD_WRITE; + i2c_op.target = phy_data->redrv_addr; + i2c_op.len = sizeof(redrv_data); + i2c_op.buf = redrv_data; + ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); + if (ret) { + if ((ret == -EAGAIN) && retry--) + goto again1; + + return ret; + } + + retry = 1; +again2: + i2c_op.cmd = XGBE_I2C_CMD_READ; + i2c_op.target = phy_data->redrv_addr; + i2c_op.len = 1; + i2c_op.buf = redrv_data; + ret = xgbe_phy_i2c_xfer(pdata, &i2c_op); + if (ret) { + if ((ret == -EAGAIN) && retry--) + goto again2; + + return ret; + } + + if (redrv_data[0] != 0xff) { + netif_dbg(pdata, drv, pdata->netdev, + "Redriver write checksum error\n"); + ret = -EIO; + } + + return ret; +} + static int xgbe_phy_i2c_write(struct xgbe_prv_data *pdata, unsigned int target, void *val, unsigned int val_len) { @@ -1144,38 +1233,49 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) xgbe_phy_put_comm_ownership(pdata); } -static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) +static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - enum xgbe_mode mode; + u16 lcl_adv = 0, rmt_adv = 0; + u8 fc; - pdata->phy.lp_advertising |= ADVERTISED_Autoneg; - pdata->phy.lp_advertising |= ADVERTISED_TP; + pdata->phy.tx_pause = 0; + pdata->phy.rx_pause = 0; - if (pdata->phy.pause_autoneg && phy_data->phydev) { - /* Flow control is obtained from the attached PHY */ - u16 lcl_adv = 0, rmt_adv = 0; - u8 fc; + if (!phy_data->phydev) + return; - pdata->phy.tx_pause = 0; - pdata->phy.rx_pause = 0; + if (phy_data->phydev->advertising & ADVERTISED_Pause) + lcl_adv |= ADVERTISE_PAUSE_CAP; + if (phy_data->phydev->advertising & ADVERTISED_Asym_Pause) + lcl_adv |= ADVERTISE_PAUSE_ASYM; - if (phy_data->phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phy_data->phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; + if (phy_data->phydev->pause) { + pdata->phy.lp_advertising |= ADVERTISED_Pause; + rmt_adv |= LPA_PAUSE_CAP; + } + if (phy_data->phydev->asym_pause) { + pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; + rmt_adv |= LPA_PAUSE_ASYM; + } - if (phy_data->phydev->pause) - rmt_adv |= LPA_PAUSE_CAP; - if (phy_data->phydev->asym_pause) - rmt_adv |= LPA_PAUSE_ASYM; + fc = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); + if (fc & FLOW_CTRL_TX) + pdata->phy.tx_pause = 1; + if (fc & FLOW_CTRL_RX) + pdata->phy.rx_pause = 1; +} - fc = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); - if (fc & FLOW_CTRL_TX) - pdata->phy.tx_pause = 1; - if (fc & FLOW_CTRL_RX) - pdata->phy.rx_pause = 1; - } +static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) +{ + enum xgbe_mode mode; + + pdata->phy.lp_advertising |= ADVERTISED_Autoneg; + pdata->phy.lp_advertising |= ADVERTISED_TP; + + /* Use external PHY to determine flow control */ + if (pdata->phy.pause_autoneg) + xgbe_phy_phydev_flowctrl(pdata); switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { case XGBE_SGMII_AN_LINK_SPEED_100: @@ -1249,6 +1349,83 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) return mode; } +static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + enum xgbe_mode mode; + unsigned int ad_reg, lp_reg; + + pdata->phy.lp_advertising |= ADVERTISED_Autoneg; + pdata->phy.lp_advertising |= ADVERTISED_Backplane; + + /* Use external PHY to determine flow control */ + if (pdata->phy.pause_autoneg) + xgbe_phy_phydev_flowctrl(pdata); + + /* Compare Advertisement and Link Partner register 2 */ + ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); + lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); + if (lp_reg & 0x80) + pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; + if (lp_reg & 0x20) + pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; + + ad_reg &= lp_reg; + if (ad_reg & 0x80) { + switch (phy_data->port_mode) { + case XGBE_PORT_MODE_BACKPLANE: + mode = XGBE_MODE_KR; + break; + default: + mode = XGBE_MODE_SFI; + break; + } + } else if (ad_reg & 0x20) { + switch (phy_data->port_mode) { + case XGBE_PORT_MODE_BACKPLANE: + mode = XGBE_MODE_KX_1000; + break; + case XGBE_PORT_MODE_1000BASE_X: + mode = XGBE_MODE_X; + break; + case XGBE_PORT_MODE_SFP: + switch (phy_data->sfp_base) { + case XGBE_SFP_BASE_1000_T: + if (phy_data->phydev && + (phy_data->phydev->speed == SPEED_100)) + mode = XGBE_MODE_SGMII_100; + else + mode = XGBE_MODE_SGMII_1000; + break; + case XGBE_SFP_BASE_1000_SX: + case XGBE_SFP_BASE_1000_LX: + case XGBE_SFP_BASE_1000_CX: + default: + mode = XGBE_MODE_X; + break; + } + break; + default: + if (phy_data->phydev && + (phy_data->phydev->speed == SPEED_100)) + mode = XGBE_MODE_SGMII_100; + else + mode = XGBE_MODE_SGMII_1000; + break; + } + } else { + mode = XGBE_MODE_UNKNOWN; + } + + /* Compare Advertisement and Link Partner register 3 */ + ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); + lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); + if (lp_reg & 0xc000) + pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; + + return mode; +} + static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) { enum xgbe_mode mode; @@ -1311,6 +1488,8 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: return xgbe_phy_an73_outcome(pdata); + case XGBE_AN_MODE_CL73_REDRV: + return xgbe_phy_an73_redrv_outcome(pdata); case XGBE_AN_MODE_CL37: return xgbe_phy_an37_outcome(pdata); case XGBE_AN_MODE_CL37_SGMII: @@ -1320,6 +1499,63 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) } } +static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int advertising; + + /* Without a re-driver, just return current advertising */ + if (!phy_data->redrv) + return pdata->phy.advertising; + + /* With the KR re-driver we need to advertise a single speed */ + advertising = pdata->phy.advertising; + advertising &= ~ADVERTISED_1000baseKX_Full; + advertising &= ~ADVERTISED_10000baseKR_Full; + + switch (phy_data->port_mode) { + case XGBE_PORT_MODE_BACKPLANE: + advertising |= ADVERTISED_10000baseKR_Full; + break; + case XGBE_PORT_MODE_BACKPLANE_2500: + advertising |= ADVERTISED_1000baseKX_Full; + break; + case XGBE_PORT_MODE_1000BASE_T: + case XGBE_PORT_MODE_1000BASE_X: + case XGBE_PORT_MODE_NBASE_T: + advertising |= ADVERTISED_1000baseKX_Full; + break; + case XGBE_PORT_MODE_10GBASE_T: + if (phy_data->phydev && + (phy_data->phydev->speed == SPEED_10000)) + advertising |= ADVERTISED_10000baseKR_Full; + else + advertising |= ADVERTISED_1000baseKX_Full; + break; + case XGBE_PORT_MODE_10GBASE_R: + advertising |= ADVERTISED_10000baseKR_Full; + break; + case XGBE_PORT_MODE_SFP: + switch (phy_data->sfp_base) { + case XGBE_SFP_BASE_1000_T: + case XGBE_SFP_BASE_1000_SX: + case XGBE_SFP_BASE_1000_LX: + case XGBE_SFP_BASE_1000_CX: + advertising |= ADVERTISED_1000baseKX_Full; + break; + default: + advertising |= ADVERTISED_10000baseKR_Full; + break; + } + break; + default: + advertising |= ADVERTISED_10000baseKR_Full; + break; + } + + return advertising; +} + static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; @@ -1364,6 +1600,10 @@ static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; + /* A KR re-driver will always require CL73 AN */ + if (phy_data->redrv) + return XGBE_AN_MODE_CL73_REDRV; + switch (phy_data->port_mode) { case XGBE_PORT_MODE_BACKPLANE: return XGBE_AN_MODE_CL73; @@ -1386,6 +1626,61 @@ static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) } } +static int xgbe_phy_set_redrv_mode_mdio(struct xgbe_prv_data *pdata, + enum xgbe_phy_redrv_mode mode) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + u16 redrv_reg, redrv_val; + + redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); + redrv_val = (u16)mode; + + return pdata->hw_if.write_ext_mii_regs(pdata, phy_data->redrv_addr, + redrv_reg, redrv_val); +} + +static int xgbe_phy_set_redrv_mode_i2c(struct xgbe_prv_data *pdata, + enum xgbe_phy_redrv_mode mode) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int redrv_reg; + int ret; + + /* Calculate the register to write */ + redrv_reg = XGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); + + ret = xgbe_phy_redrv_write(pdata, redrv_reg, mode); + + return ret; +} + +static void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + enum xgbe_phy_redrv_mode mode; + int ret; + + if (!phy_data->redrv) + return; + + mode = XGBE_PHY_REDRV_MODE_CX; + if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && + (phy_data->sfp_base != XGBE_SFP_BASE_1000_CX) && + (phy_data->sfp_base != XGBE_SFP_BASE_10000_CR)) + mode = XGBE_PHY_REDRV_MODE_SR; + + ret = xgbe_phy_get_comm_ownership(pdata); + if (ret) + return; + + if (phy_data->redrv_if) + xgbe_phy_set_redrv_mode_i2c(pdata, mode); + else + xgbe_phy_set_redrv_mode_mdio(pdata, mode); + + xgbe_phy_put_comm_ownership(pdata); +} + static void xgbe_phy_start_ratechange(struct xgbe_prv_data *pdata) { if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) @@ -1457,6 +1752,8 @@ static void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 10G/SFI */ @@ -1492,6 +1789,8 @@ static void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 1G/X */ @@ -1516,6 +1815,8 @@ static void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 1G/SGMII */ @@ -1540,6 +1841,8 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 1G/SGMII */ @@ -1564,6 +1867,8 @@ static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 10G/KR */ @@ -1588,6 +1893,8 @@ static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 2.5G/KX */ @@ -1612,6 +1919,8 @@ static void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int s0; + xgbe_phy_set_redrv_mode(pdata); + xgbe_phy_start_ratechange(pdata); /* 1G/KX */ @@ -2232,6 +2541,30 @@ static int xgbe_phy_mdio_reset(struct xgbe_prv_data *pdata) return ret; } +static bool xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data) +{ + if (!phy_data->redrv) + return false; + + if (phy_data->redrv_if >= XGBE_PHY_REDRV_IF_MAX) + return true; + + switch (phy_data->redrv_model) { + case XGBE_PHY_REDRV_MODEL_4223: + if (phy_data->redrv_lane > 3) + return true; + break; + case XGBE_PHY_REDRV_MODEL_4227: + if (phy_data->redrv_lane > 1) + return true; + break; + default: + return true; + } + + return false; +} + static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; @@ -2481,6 +2814,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr); } + reg = XP_IOREAD(pdata, XP_PROP_4); + phy_data->redrv = XP_GET_BITS(reg, XP_PROP_4, REDRV_PRESENT); + phy_data->redrv_if = XP_GET_BITS(reg, XP_PROP_4, REDRV_IF); + phy_data->redrv_addr = XP_GET_BITS(reg, XP_PROP_4, REDRV_ADDR); + phy_data->redrv_lane = XP_GET_BITS(reg, XP_PROP_4, REDRV_LANE); + phy_data->redrv_model = XP_GET_BITS(reg, XP_PROP_4, REDRV_MODEL); + if (phy_data->redrv && netif_msg_probe(pdata)) { + dev_dbg(pdata->dev, "redrv present\n"); + dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if); + dev_dbg(pdata->dev, "redrv addr=%#x\n", phy_data->redrv_addr); + dev_dbg(pdata->dev, "redrv lane=%u\n", phy_data->redrv_lane); + dev_dbg(pdata->dev, "redrv model=%u\n", phy_data->redrv_model); + } + /* Validate the connection requested */ if (xgbe_phy_conn_type_mismatch(pdata)) { dev_err(pdata->dev, "phy mode/connection mismatch (%#x/%#x)\n", @@ -2499,6 +2846,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) if (ret) return ret; + /* Validate the re-driver information */ + if (xgbe_phy_redrv_error(phy_data)) { + dev_err(pdata->dev, "phy re-driver settings error\n"); + return -EINVAL; + } + pdata->kr_redrv = phy_data->redrv; + /* Indicate current mode is unknown */ phy_data->cur_mode = XGBE_MODE_UNKNOWN; @@ -2651,6 +3005,29 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) dev_dbg(pdata->dev, "phy supported=%#x\n", pdata->phy.supported); + if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) && + (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) { + ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->mdio_addr, + phy_data->phydev_mode); + if (ret) { + dev_err(pdata->dev, + "mdio port/clause not compatible (%d/%u)\n", + phy_data->mdio_addr, phy_data->phydev_mode); + return -EINVAL; + } + } + + if (phy_data->redrv && !phy_data->redrv_if) { + ret = pdata->hw_if.set_ext_mii_mode(pdata, phy_data->redrv_addr, + XGBE_MDIO_MODE_CL22); + if (ret) { + dev_err(pdata->dev, + "redriver mdio port not compatible (%u)\n", + phy_data->redrv_addr); + return -EINVAL; + } + } + /* Register for driving external PHYs */ mii = devm_mdiobus_alloc(pdata->dev); if (!mii) { @@ -2700,5 +3077,7 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) phy_impl->an_config = xgbe_phy_an_config; + phy_impl->an_advertising = xgbe_phy_an_advertising; + phy_impl->an_outcome = xgbe_phy_an_outcome; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 34db470..f52a9bd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -508,6 +508,7 @@ enum xgbe_xpcs_access { enum xgbe_an_mode { XGBE_AN_MODE_CL73 = 0, + XGBE_AN_MODE_CL73_REDRV, XGBE_AN_MODE_CL37, XGBE_AN_MODE_CL37_SGMII, XGBE_AN_MODE_NONE, @@ -807,6 +808,9 @@ struct xgbe_phy_impl_if { /* Configure auto-negotiation settings */ int (*an_config)(struct xgbe_prv_data *); + /* Set/override auto-negotiation advertisement settings */ + unsigned int (*an_advertising)(struct xgbe_prv_data *); + /* Process results of auto-negotiation */ enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); @@ -1124,6 +1128,8 @@ struct xgbe_prv_data { unsigned long link_check; struct completion mdio_complete; + unsigned int kr_redrv; + char an_name[IFNAMSIZ + 32]; struct workqueue_struct *an_workqueue;