From patchwork Thu Nov 3 13:30:26 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Lendacky X-Patchwork-Id: 690831 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 3t8m7L0nkkz9vDZ for ; Fri, 4 Nov 2016 00:30:38 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=amdcloud.onmicrosoft.com header.i=@amdcloud.onmicrosoft.com header.b=k23HOi8D; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754333AbcKCNag (ORCPT ); Thu, 3 Nov 2016 09:30:36 -0400 Received: from mail-by2nam01on0087.outbound.protection.outlook.com ([104.47.34.87]:32328 "EHLO NAM01-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754162AbcKCNad (ORCPT ); Thu, 3 Nov 2016 09:30:33 -0400 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=ITtKA3UcbXlN++XLKqrjaK2wIp1IqC1uGu9SIT1OJ0M=; b=k23HOi8DI7wekeBo25MnFX1FbTtu50kBOuDCNlom+JTbZBRlcDTO/jspxX0qBikclYGlRu5uoPjNXQKVnjoaDgaiRPDgC4yAwrvOF7kh4W/nLsQnhelxoF2KEvKVW7NOc0HyYRcx23gKpQGg3Y0DhlL18MCN5YB8DS4Hzm6JwDI= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Thomas.Lendacky@amd.com; Received: from tlendack-t1.amdoffice.net (165.204.77.1) by MWHPR12MB1152.namprd12.prod.outlook.com (10.169.204.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.693.12; Thu, 3 Nov 2016 13:30:30 +0000 From: Tom Lendacky Subject: [PATCH net-next v1 16/21] amd-xgbe: Add ECC status support for the device memory To: CC: Florian Fainelli , David Miller Date: Thu, 3 Nov 2016 08:30:26 -0500 Message-ID: <20161103133026.3437.61559.stgit@tlendack-t1.amdoffice.net> In-Reply-To: <20161103132744.3437.27332.stgit@tlendack-t1.amdoffice.net> References: <20161103132744.3437.27332.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: BY2PR11CA0024.namprd11.prod.outlook.com (10.163.150.34) To MWHPR12MB1152.namprd12.prod.outlook.com (10.169.204.16) X-MS-Office365-Filtering-Correlation-Id: 66944a92-2e74-4b65-8900-08d403ed9527 X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1152; 2:iQdoyGa8+fW7w7im0qGDd0197qAfr6s9e+EWSlGAWdlMb1B0znOoKvUHyQD2TgIW+3B3o3nH1tqegBZAYemOB7VvVd9ld5qOoyeW7ldABWEwG2Mcld17Gp98OtBnk+sE5Ewjm2Ms1JTxXPhmJiorAjJBbcf32/9GUSXZJBer0/64B7ikE5TULisH7hyOUcAysbyQLEUkxGfos7uekYrrYg==; 3:3HCQzd26mmZqOHgtUGcJBu3dESbKqlPwhnGw0DfWQsxPXF3e9NF4E085/QRrKLEIUud03lNyiQ8Nrw459FX+bCfvxEJp/7JjJTBsdTjU12qSCFlWJI5Eyj/pNAXNL4GOzCO7bQH4RFsbFuQTXSPmAQ==; 25:cxhh0bjS7IET8ntAGz13hhn+Niyob/PSv86mgbv4IXUrt38bzNX/b8vaBy8jAkRJzGQ/t7jRB9gt0f3nfFU8mLdT+cIRA6e47UBg5UAIFG8pGgL7AqIgvZSSZjNe+71PqWxBpi1+jqndbvXrYGPYtI9QRTEM1RmF9iOg9D2AhVgzairc0XfhOBYfXuY0D+h5lDCzDZfDpG1ss5GyruJlauKYhaJwDMSt9jtSxhyk1jwUfGtiyjtuxtt7H/0XuM2MBZfIripkiK4JBdJnsAMWziWSSHsavl52M8p+73KE+wDdy2XnB3VkR0LpfB7hME/lnNqs9LdmO0PtbdwfAHJXv/HmIVCMVG9Cu6RaOrHNSuVhQMGJjpHrCpmvLUmgMx1s5uNkhpmLmt4Q2hGZOYMMPYvAx/1tD+j0AKAF2NtRtkW0a1uZyS0lwFT5eYLpNQSV X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:MWHPR12MB1152; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1152; 31:fSsk46rSLZMc1Fy0/S1HON5UwxTXm+ie0cs7wV19N+MbOzZhkDyU3PVq0lOCQ0a3cQ0EpRS2Hz4wl9hnk/JJBgiSCGMLvuHD7/mhoxXAAO0JK5DPQHEegcEsargCtsACvSHoQzHcrw1fm4xXY+iFoyELCVv4VXPcRi6yASaEBGvYfTAbvjCSxKtsvotOtsmlV7WvHuKbymbd/4BcGjqFEtiq1zwWRLz12uk92B7Bp91Ps3MbwbHxZmrDV2r//Fk9aWOzdGvhwchTBgOiE3ygag==; 20:LG3Os35AssrTRAdNI0oljLg3rgWqrDreHjQ+erShcSXzFPSCPnIvM6eH2w0E91mcylYX8wobWgflVxNs2SlvHknbK9o+OUyuTjEIxK9bxwSYhdHnllpC8eveF/OmJahrpnGxW3Xavq1tmDG1TH3TrLWXMS8eOVhypbs2AlRob0p5zXwMGYjDQudHJlcsErGAe1Pyt1eewNuEkrTGHexoaikudR5VAUfGcNaTfQ2KQVIuuOELcYsP9cU6moCi7WIXADaFo1RqiB4w3iOSmQKDklVTASlQptW70zg4A878ALmUDuh9Xp6sPH7VrRYcfs7HhfdYw39tTRh5m5PEHAIpwDZYpyHtr7o0xxTUN1rhtEeVJnNFLghbQ5eX6cvpcZNIjxDclbTGTB3xiwQUe0Eze50BOIGF8L7FyybM10rdjyoZbbwNtJ0FbmlLAsjcNk1r0Vkg3Ptil392dEgQDo1/z3lX/Z0+vDUXLTxB2fC22ut8HlfJVFV66yzcddqtpYoW X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110)(211171220733660); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6055026); SRVR:MWHPR12MB1152; BCL:0; PCL:0; RULEID:; SRVR:MWHPR12MB1152; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1152; 4:u15hM6NhTq51CCjyQPjoJ3BYU34T23iL5rbTHqNyi6HhxN8SSx3H7UB779/oaFwwTnbHc/HuvYSgRiU6fXIWpdqktDOZlHO67C1mrQ7uGK3a+mAkEMdNpPrhTPU3jm2Cwr8WGloyqXYloM8rZsJ6EyY+5YclM/cPNU0hNXcvNEVa7Hyh4tDAqQZO2BSzWdQbJKptleYBH35TuMEEP/qS2fmzw0JQX6F2ekr4a1n5eB5RD5jv/dgGZ7fYEU6NFQqkD7EyQGK8TH2t8svCnVrgc12JpCqkJX2pm5rW6nq0u+tzADY1c7WvIr3zzaaLhK3ixIpIPdukxsRpP9E1XhIBNbBL4CzKEge5zFg5BLpVWoZcHz5pqDWX7zx5fVyiOqg8qbRmZ5thzXEN1imcqDm47bqIo1WiUUwhmzZPMFr1mqkBmIhTSpp7TGFQI0TRW3sTYRMfGHx+a3tPJ+rJy/Ez+eTHYSP3QZsWzw040bgCZpm3wAkTnMT7rXXuNMqqH+ce X-Forefront-PRVS: 011579F31F X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(7916002)(199003)(189002)(6916009)(50466002)(5660300001)(110136003)(305945005)(7736002)(7846002)(2950100002)(101416001)(103116003)(97746001)(6666003)(92566002)(77096005)(8676002)(81166006)(97736004)(4001350100001)(81156014)(83506001)(189998001)(4326007)(230700001)(33646002)(68736007)(9686002)(23676002)(66066001)(86362001)(586003)(6116002)(3846002)(1076002)(42186005)(19580405001)(19580395003)(47776003)(76176999)(50986999)(69596002)(2906002)(106356001)(54356999)(105586002)(53416004)(2351001)(229853001)(71626007); DIR:OUT; SFP:1101; SCL:1; SRVR:MWHPR12MB1152; H:tlendack-t1.amdoffice.net; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtNV0hQUjEyTUIxMTUyOzIzOmUxTWpZM0FaZmdYRjlUUWp2d3RkVGJOWGFH?= =?utf-8?B?ZERSdlM0bE1nTHFxanpxOUY4LzA5OFZNSzVlZ0ZiRktDZmJvMmFBYWZqUURN?= =?utf-8?B?TytIaUlrYjdJMEY0OU9idWtPaHJjdmREZmM2MDlqRWNFakxvWWhiaDFQakwy?= =?utf-8?B?YldNSS9CSFdKMXdQaWRmbXowVzFuTG1KOFpFUktYMDJMeEV6WXltT0VVYzln?= =?utf-8?B?eXhkZE02SkMxUDJ3Z3FEZDJOSktERWhyZlJaWGIrZmxFekRJY1gwWkcwdkJl?= =?utf-8?B?cXVqM0xtTzByYmt1a3dEU0JjajN6OE9GUDg0TmlJQnpzMWdBTEJib3dHUXJi?= =?utf-8?B?YXBWSG5VeVZFQnh1cHpKamNPYXVkOFVoV0VlTGcwOVpMRk9MV2UzaXF0L1g2?= =?utf-8?B?ZHBXU2d4UTBrNytvKzN5QXJraWVHTG14emxVblJ1bGt4dGk2M2tJTXhwa2xl?= =?utf-8?B?OGNweG40UWlDUXlMQThHeVI0WnlpN1ZpQ0RpNnZZSFBkSVYyNStzZzNyenVm?= =?utf-8?B?c2hvbnA0UTYrb25MV0dYSklvK3NLNnJzWXA4VUpQWmR5aUlvSklWVEtiUW0r?= =?utf-8?B?ZjFQZjhHaXVERG1nOWZ0OFJFSmZ4L2kwQUZwRDBTZkg0YVBQY1BVZ09ROVcv?= =?utf-8?B?VG4rV0FUR2pNTk5FcVVBbDJvSE1BdG94MEZzWTRITjRMRldjbjdHaVZRb1R5?= =?utf-8?B?RTZyTWFxT25rWmRTaHM0SC9MOXpxK0thOFI4UUQ3UUdLczdYYXY2MWJUbHNZ?= =?utf-8?B?QUJDZitHdndVdXVva0NxUUJHd1ZQNEtkSkpiUEdNUmlvTmc0WW93dHpGcTRw?= =?utf-8?B?R0FJNER0b2prd2laSlk4VG1kc1FndlErYTNOZ01Xc1FvWW05TkduV2FYMXhP?= =?utf-8?B?dWV2NkluR2MvRnhUci9WaXkySm5XMDk2RXIweEN2LzJNL1hKZk5aNkFmanZM?= =?utf-8?B?TkxObDhnYWZjcHkwdmtlREhuTWhlTXJvdGNUbmlETUxnV3JabjFHN3JEYm5v?= =?utf-8?B?eGY4eFEyTUc0T1I0NTArOU52Q3VNejYwbVB6bzM3MTZXcFd2WEhxdWx4NFhs?= =?utf-8?B?ZGFFcEQ2U1hBaGlGeVRKcXhnZUJWUGVUS2NWUk96NHNDdXNkbGVTOTZIN25E?= =?utf-8?B?Z1ROUXhKSmh5UW1LbmN0eWd5R3NOdEZGbmx4bmU3bWtwVjJHYWxFbzRtWTdk?= =?utf-8?B?Qi8rVGdFaEp1dTBGUkxkb25yc0dCVXJhd214d0c2N2I2dHcwQ3Y4RFA3RlV0?= =?utf-8?B?RVR6ZklqbVNCZmx6MGhSSU51cTVVZ0wxMjZra3FZNlR4ZHBvdDgvTVF1M2p3?= =?utf-8?B?TE5BalUxamNiU2F4VGtsc1NjeWlsU2U0a1F5eTB2UVBEQndPUk9ieDV6RjYy?= =?utf-8?B?MEpiZ1l6WHlWRFFXS2U4aUxMVDYzRWZWbSswMUtWMmtTNG80OWY5UFExc3BP?= =?utf-8?B?N3ZyUHg5UGlaQWlyczVFcWF2cnp6VHQ2Vm9WTjlIa2VNVks3cGJDZ2JoTkFh?= =?utf-8?B?SzYyczliSXZyOFBSRFJuQjRLampFdmlYSUtLQXBsM203c21ndDFFVGpLd1Fh?= =?utf-8?B?RHYybTBRUTIzVXpZRkQ1SzFqK1M2cXRqbVZFOFE1MFpKT2wwUVV0MUJSWitX?= =?utf-8?B?b1NTSjF2T2E4L3ptdG9NZEkvRGF1cklNQzJaY210MGMvbjh6dFVXd0hsUlRl?= =?utf-8?B?djVhSDczMmV6STJkL1dEd3d6YnZYakZvc1JVV09hK1E4Rzl0Y21VY3RrRDBF?= =?utf-8?B?UEFBaDh3ZWp6SnBQOEp1QT09?= X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1152; 6:TN75/Ga7S+TeH+i3tU7psDJwj8jBg11rjUjwYQjkOwmOQxWZtCAZBJqKN3X4biUvQov45m1w+OUEFu4erzibuhZ88CGFUgrcPKZznHYrguUJ7uRBzCCRV/feOK5FqyRB0iKd8nOBTPoYynO/S/t5p2E6Zf2jVgSXciFycGGbjmSrQK5OaLqW8EYI2beFWMh4cv1jSKBMeXZXcZkWHcO2/HARtCGiC5oZtHMwSV63sgPSVNSuPO1FUXQ+Qw26XPoRInPU4lfuyeQ8itK+GZd7UG4EWVMJnhwMqIXtSq4Mza0ZPGYEJ1ydsSbHX9TZiTAOPeFf7b2XEc+lpj76wsaMO+e8UggvOhtYDxNq0rdJtE0=; 5:O1vI2X8SFTCzNOVeS6298pQrD5yeaa0SZWxjCX3/RPRZJVg8K5vMcq6pMIVHImEpiwktFE0Ubi10PPku0KSSHNoQgYyRIKkkRH/Y3by6DgA29HduZd8jGs3+yy89rgEPwlzm/tHFeUXYi5Qujt3Jk9JGjJsI/S/UM+DfPHiH1bI=; 24:2cpefoDi8OZJDcgiPctUrMkcV60sV3N3UNI5+As9+6lnFMJNgj7cZKu/zTSfDluPtu5iNw/pdJvdCn18aycyB4UbLNfPeq48y1ZU8Rmk8Ow= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1152; 7:Ld6IbUBtCO9RPsmf8+HXD5h1DQ4IwRLa4OoqQQif3N9FFTUf8jYBDgnoZ0K69uJCjFmCCBBRURuRZi+uZqmddnjUUWcE7BpbRmcir94TaOXPD60bnwI79ot7T2AZGdBcH3nwJsiH6OjKc3oUlOG6tlPoiCe+05tengE8mzDiu63l9eF/wMkfPVVURUKY+7LKBoCPKSk8JfyIZszOFaLQYdVhnV73XogiiiXl4fPQ6HGU4wpTF46Ya46JAkGfo7nsMeiVliKPu9Ihbs1akDD1IdYEZGYeLj8IywJqzJGl7Gy3jgOYyHySK7POamdMRtsjduxTJ3vHTzS39VLFHICWXO82EW83bzMMFXT8Rh0wtQo=; 20:iNTVfRmDPJlk/G1htBYQVtiOeugkr5aDaoyNBzS8j3TArGN7SsFq7/md1LA8B9swexDXAS381R8DhU5D9C2ebtDdYttkhqgQmCxqbDQdnYJW4MOnZxmlSThEg9qVLL4ZBA0r99GPwLKnhY2nSPFolEPUs95tQoGv5PrySNVfrOFxBi17iFclGOzrxtgC77PytlVhz11TR7flEvduyAE4RAAA2nHTXn/D4k3Mgy1EeWCI6zbq1B+/NAp5/ZfaPIc9 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Nov 2016 13:30:30.5667 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: MWHPR12MB1152 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Some versions of the amd-xgbe device are capable of reporting ECC error information back to the driver. Add support to process, track and report on this information. Signed-off-by: Tom Lendacky --- drivers/net/ethernet/amd/Kconfig | 5 + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 40 ++++++ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 64 +++++++++ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 182 +++++++++++++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 13 ++ drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 12 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 37 +++++ 7 files changed, 344 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 9255ce4..930636c 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -178,6 +178,7 @@ config AMD_XGBE select BITREVERSE select CRC32 select PTP_1588_CLOCK + select AMD_XGBE_HAVE_ECC if X86 ---help--- This driver supports the AMD 10GbE Ethernet device found on an AMD SoC. @@ -195,4 +196,8 @@ config AMD_XGBE_DCB If unsure, say N. +config AMD_XGBE_HAVE_ECC + bool + default n + endif # NET_VENDOR_AMD diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 516345c..f7527cd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -920,6 +920,10 @@ #define XP_PROP_5 0x0014 #define XP_MAC_ADDR_LO 0x0020 #define XP_MAC_ADDR_HI 0x0024 +#define XP_ECC_ISR 0x0030 +#define XP_ECC_IER 0x0034 +#define XP_ECC_CNT0 0x003c +#define XP_ECC_CNT1 0x0040 #define XP_DRIVER_INT_REQ 0x0060 #define XP_DRIVER_INT_RO 0x0064 #define XP_DRIVER_SCRATCH_0 0x0068 @@ -935,6 +939,42 @@ #define XP_DRIVER_SCRATCH_0_COMMAND_WIDTH 8 #define XP_DRIVER_SCRATCH_0_SUB_COMMAND_INDEX 8 #define XP_DRIVER_SCRATCH_0_SUB_COMMAND_WIDTH 8 +#define XP_ECC_CNT0_RX_DED_INDEX 24 +#define XP_ECC_CNT0_RX_DED_WIDTH 8 +#define XP_ECC_CNT0_RX_SEC_INDEX 16 +#define XP_ECC_CNT0_RX_SEC_WIDTH 8 +#define XP_ECC_CNT0_TX_DED_INDEX 8 +#define XP_ECC_CNT0_TX_DED_WIDTH 8 +#define XP_ECC_CNT0_TX_SEC_INDEX 0 +#define XP_ECC_CNT0_TX_SEC_WIDTH 8 +#define XP_ECC_CNT1_DESC_DED_INDEX 8 +#define XP_ECC_CNT1_DESC_DED_WIDTH 8 +#define XP_ECC_CNT1_DESC_SEC_INDEX 0 +#define XP_ECC_CNT1_DESC_SEC_WIDTH 8 +#define XP_ECC_IER_DESC_DED_INDEX 0 +#define XP_ECC_IER_DESC_DED_WIDTH 1 +#define XP_ECC_IER_DESC_SEC_INDEX 1 +#define XP_ECC_IER_DESC_SEC_WIDTH 1 +#define XP_ECC_IER_RX_DED_INDEX 2 +#define XP_ECC_IER_RX_DED_WIDTH 1 +#define XP_ECC_IER_RX_SEC_INDEX 3 +#define XP_ECC_IER_RX_SEC_WIDTH 1 +#define XP_ECC_IER_TX_DED_INDEX 4 +#define XP_ECC_IER_TX_DED_WIDTH 1 +#define XP_ECC_IER_TX_SEC_INDEX 5 +#define XP_ECC_IER_TX_SEC_WIDTH 1 +#define XP_ECC_ISR_DESC_DED_INDEX 0 +#define XP_ECC_ISR_DESC_DED_WIDTH 1 +#define XP_ECC_ISR_DESC_SEC_INDEX 1 +#define XP_ECC_ISR_DESC_SEC_WIDTH 1 +#define XP_ECC_ISR_RX_DED_INDEX 2 +#define XP_ECC_ISR_RX_DED_WIDTH 1 +#define XP_ECC_ISR_RX_SEC_INDEX 3 +#define XP_ECC_ISR_RX_SEC_WIDTH 1 +#define XP_ECC_ISR_TX_DED_INDEX 4 +#define XP_ECC_ISR_TX_DED_WIDTH 1 +#define XP_ECC_ISR_TX_SEC_INDEX 5 +#define XP_ECC_ISR_TX_SEC_WIDTH 1 #define XP_MAC_ADDR_HI_VALID_INDEX 31 #define XP_MAC_ADDR_HI_VALID_WIDTH 1 #define XP_PROP_0_CONN_TYPE_INDEX 28 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 67bb40d..2997053 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -724,6 +724,61 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff); } +static void xgbe_enable_ecc_interrupts(struct xgbe_prv_data *pdata) +{ + unsigned int ecc_ier = 0; + + if (!pdata->vdata->ecc_support) + return; + + /* Enable ECC interrupts */ + XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_DED, 1); + XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_SEC, 1); + XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_DED, 1); + XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_SEC, 1); + XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_DED, 1); + XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_SEC, 1); + + XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier); +} + +static void xgbe_disable_ecc_ded(struct xgbe_prv_data *pdata) +{ + unsigned int ecc_ier; + + ecc_ier = XP_IOREAD(pdata, XP_ECC_IER); + + /* Disable ECC DED interrupts */ + XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_DED, 0); + XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_DED, 0); + XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_DED, 0); + + XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier); +} + +static void xgbe_disable_ecc_sec(struct xgbe_prv_data *pdata, + enum xgbe_ecc_sec sec) +{ + unsigned int ecc_ier; + + ecc_ier = XP_IOREAD(pdata, XP_ECC_IER); + + /* Disable ECC SEC interrupt */ + switch (sec) { + case XGBE_ECC_SEC_TX: + XP_SET_BITS(ecc_ier, XP_ECC_IER, TX_SEC, 0); + break; + case XGBE_ECC_SEC_RX: + XP_SET_BITS(ecc_ier, XP_ECC_IER, RX_SEC, 0); + break; + case XGBE_ECC_SEC_DESC: + XP_SET_BITS(ecc_ier, XP_ECC_IER, DESC_SEC, 0); + break; + } + + XP_IOWRITE(pdata, XP_ECC_IER, ecc_ier); +} + static int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed) { unsigned int ss; @@ -3296,6 +3351,11 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_mmc(pdata); xgbe_enable_mac_interrupts(pdata); + /* + * Initialize ECC related features + */ + xgbe_enable_ecc_interrupts(pdata); + DBGPR("<--xgbe_init\n"); return 0; @@ -3401,5 +3461,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->set_rss_hash_key = xgbe_set_rss_hash_key; hw_if->set_rss_lookup_table = xgbe_set_rss_lookup_table; + /* For ECC */ + hw_if->disable_ecc_ded = xgbe_disable_ecc_ded; + hw_if->disable_ecc_sec = xgbe_disable_ecc_sec; + DBGPR("<--xgbe_init_function_ptrs\n"); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 490fdb5..15627f4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -114,6 +114,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -126,8 +127,35 @@ #include "xgbe.h" #include "xgbe-common.h" +static unsigned int ecc_sec_info_threshold = 10; +static unsigned int ecc_sec_warn_threshold = 10000; +static unsigned int ecc_sec_period = 600; +static unsigned int ecc_ded_threshold = 2; +static unsigned int ecc_ded_period = 600; + +#ifdef CONFIG_AMD_XGBE_HAVE_ECC +/* Only expose the ECC parameters if supported */ +module_param(ecc_sec_info_threshold, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(ecc_sec_info_threshold, + " ECC corrected error informational threshold setting"); + +module_param(ecc_sec_warn_threshold, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(ecc_sec_warn_threshold, + " ECC corrected error warning threshold setting"); + +module_param(ecc_sec_period, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(ecc_sec_period, " ECC corrected error period (in seconds)"); + +module_param(ecc_ded_threshold, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(ecc_ded_threshold, " ECC detected error threshold setting"); + +module_param(ecc_ded_period, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(ecc_ded_period, " ECC detected error period (in seconds)"); +#endif + static int xgbe_one_poll(struct napi_struct *, int); static int xgbe_all_poll(struct napi_struct *, int); +static void xgbe_stop(struct xgbe_prv_data *); static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) { @@ -308,6 +336,109 @@ static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) xgbe_disable_rx_tx_int(pdata, channel); } +static bool xgbe_ecc_sec(struct xgbe_prv_data *pdata, unsigned long *period, + unsigned int *count, const char *area) +{ + bool ret = false; + + if (time_before(jiffies, *period)) { + (*count)++; + } else { + *period = jiffies + (ecc_sec_period * HZ); + *count = 1; + } + + if (*count > ecc_sec_info_threshold) + dev_warn_once(pdata->dev, + "%s ECC corrected errors exceed information threshold\n", + area); + + if (*count > ecc_sec_warn_threshold) { + dev_warn_once(pdata->dev, + "%s ECC corrected errors exceed warning threshold\n", + area); + ret = true; + } + + return ret; +} + +static bool xgbe_ecc_ded(struct xgbe_prv_data *pdata, unsigned long *period, + unsigned int *count, const char *area) +{ + if (time_before(jiffies, *period)) { + (*count)++; + } else { + *period = jiffies + (ecc_ded_period * HZ); + *count = 1; + } + + if (*count > ecc_ded_threshold) { + netdev_alert(pdata->netdev, + "%s ECC detected errors exceed threshold\n", + area); + return true; + } + + return false; +} + +static irqreturn_t xgbe_ecc_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = data; + unsigned int ecc_isr; + bool stop = false; + + /* Mask status with only the interrupts we care about */ + ecc_isr = XP_IOREAD(pdata, XP_ECC_ISR); + ecc_isr &= XP_IOREAD(pdata, XP_ECC_IER); + netif_dbg(pdata, intr, pdata->netdev, "ECC_ISR=%#010x\n", ecc_isr); + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, TX_DED)) { + stop |= xgbe_ecc_ded(pdata, &pdata->tx_ded_period, + &pdata->tx_ded_count, "TX fifo"); + } + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, RX_DED)) { + stop |= xgbe_ecc_ded(pdata, &pdata->rx_ded_period, + &pdata->rx_ded_count, "RX fifo"); + } + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, DESC_DED)) { + stop |= xgbe_ecc_ded(pdata, &pdata->desc_ded_period, + &pdata->desc_ded_count, + "descriptor cache"); + } + + if (stop) { + pdata->hw_if.disable_ecc_ded(pdata); + schedule_work(&pdata->stopdev_work); + goto out; + } + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, TX_SEC)) { + if (xgbe_ecc_sec(pdata, &pdata->tx_sec_period, + &pdata->tx_sec_count, "TX fifo")) + pdata->hw_if.disable_ecc_sec(pdata, XGBE_ECC_SEC_TX); + } + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, RX_SEC)) + if (xgbe_ecc_sec(pdata, &pdata->rx_sec_period, + &pdata->rx_sec_count, "RX fifo")) + pdata->hw_if.disable_ecc_sec(pdata, XGBE_ECC_SEC_RX); + + if (XP_GET_BITS(ecc_isr, XP_ECC_ISR, DESC_SEC)) + if (xgbe_ecc_sec(pdata, &pdata->desc_sec_period, + &pdata->desc_sec_count, "descriptor cache")) + pdata->hw_if.disable_ecc_sec(pdata, XGBE_ECC_SEC_DESC); + +out: + /* Clear all ECC interrupts */ + XP_IOWRITE(pdata, XP_ECC_ISR, ecc_isr); + + return IRQ_HANDLED; +} + static irqreturn_t xgbe_isr(int irq, void *data) { struct xgbe_prv_data *pdata = data; @@ -397,6 +528,10 @@ static irqreturn_t xgbe_isr(int irq, void *data) if (pdata->dev_irq == pdata->an_irq) pdata->phy_if.an_isr(irq, pdata); + /* If there is not a separate SMU irq, handle it here */ + if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq)) + xgbe_ecc_isr(irq, pdata); + isr_done: return IRQ_HANDLED; } @@ -679,6 +814,16 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) return ret; } + if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) { + ret = devm_request_irq(pdata->dev, pdata->ecc_irq, xgbe_ecc_isr, + 0, pdata->ecc_name, pdata); + if (ret) { + netdev_alert(netdev, "error requesting ecc irq %d\n", + pdata->ecc_irq); + goto err_dev_irq; + } + } + if (!pdata->per_channel_irq) return 0; @@ -695,17 +840,21 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) if (ret) { netdev_alert(netdev, "error requesting irq %d\n", channel->dma_irq); - goto err_irq; + goto err_dma_irq; } } return 0; -err_irq: +err_dma_irq: /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ for (i--, channel--; i < pdata->channel_count; i--, channel--) devm_free_irq(pdata->dev, channel->dma_irq, channel); + if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) + devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); + +err_dev_irq: devm_free_irq(pdata->dev, pdata->dev_irq, pdata); return ret; @@ -718,6 +867,9 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) + devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); + if (!pdata->per_channel_irq) return; @@ -919,6 +1071,8 @@ static int xgbe_start(struct xgbe_prv_data *pdata) xgbe_start_timers(pdata); queue_work(pdata->dev_workqueue, &pdata->service_work); + clear_bit(XGBE_STOPPED, &pdata->dev_state); + DBGPR("<--xgbe_start\n"); return 0; @@ -945,6 +1099,9 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_stop\n"); + if (test_bit(XGBE_STOPPED, &pdata->dev_state)) + return; + netif_tx_stop_all_queues(netdev); xgbe_stop_timers(pdata); @@ -970,9 +1127,29 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) netdev_tx_reset_queue(txq); } + set_bit(XGBE_STOPPED, &pdata->dev_state); + DBGPR("<--xgbe_stop\n"); } +static void xgbe_stopdev(struct work_struct *work) +{ + struct xgbe_prv_data *pdata = container_of(work, + struct xgbe_prv_data, + stopdev_work); + + rtnl_lock(); + + xgbe_stop(pdata); + + xgbe_free_tx_data(pdata); + xgbe_free_rx_data(pdata); + + rtnl_unlock(); + + netdev_alert(pdata->netdev, "device stopped\n"); +} + static void xgbe_restart_dev(struct xgbe_prv_data *pdata) { DBGPR("-->xgbe_restart_dev\n"); @@ -1355,6 +1532,7 @@ static int xgbe_open(struct net_device *netdev) INIT_WORK(&pdata->service_work, xgbe_service); INIT_WORK(&pdata->restart_work, xgbe_restart); + INIT_WORK(&pdata->stopdev_work, xgbe_stopdev); INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); xgbe_init_timers(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 7655753..9c88f8f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -190,6 +190,7 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev) pdata->msg_enable = netif_msg_init(debug, default_msg_level); set_bit(XGBE_DOWN, &pdata->dev_state); + set_bit(XGBE_STOPPED, &pdata->dev_state); return pdata; } @@ -263,6 +264,14 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) netdev->base_addr = (unsigned long)pdata->xgmac_regs; memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); + /* Initialize ECC timestamps */ + pdata->tx_sec_period = jiffies; + pdata->tx_ded_period = jiffies; + pdata->rx_sec_period = jiffies; + pdata->rx_ded_period = jiffies; + pdata->desc_sec_period = jiffies; + pdata->desc_ded_period = jiffies; + /* Issue software reset to device */ pdata->hw_if.exit(pdata); @@ -384,6 +393,10 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs", netdev_name(netdev)); + /* Create the SMU name based on netdev name */ + snprintf(pdata->ecc_name, sizeof(pdata->ecc_name) - 1, "%s-ecc", + netdev_name(netdev)); + /* Create workqueues */ pdata->dev_workqueue = create_singlethread_workqueue(netdev_name(netdev)); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 8bc4e4e..12d95eb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -152,7 +152,7 @@ static int xgbe_config_msi(struct xgbe_prv_data *pdata) pdata->dev_irq = pdata->pcidev->irq; if (msi_count > 1) { - pdata->smu_irq = pdata->pcidev->irq + 1; + pdata->ecc_irq = pdata->pcidev->irq + 1; pdata->i2c_irq = pdata->pcidev->irq + 2; pdata->an_irq = pdata->pcidev->irq + 3; @@ -165,7 +165,7 @@ static int xgbe_config_msi(struct xgbe_prv_data *pdata) pdata->per_channel_irq = 1; pdata->channel_irq_mode = XGBE_IRQ_MODE_LEVEL; } else { - pdata->smu_irq = pdata->pcidev->irq; + pdata->ecc_irq = pdata->pcidev->irq; pdata->i2c_irq = pdata->pcidev->irq; pdata->an_irq = pdata->pcidev->irq; } @@ -207,7 +207,7 @@ static int xgbe_config_msix(struct xgbe_prv_data *pdata) pdata->irq_count = ret; pdata->dev_irq = pdata->msix_entries[0].vector; - pdata->smu_irq = pdata->msix_entries[1].vector; + pdata->ecc_irq = pdata->msix_entries[1].vector; pdata->i2c_irq = pdata->msix_entries[2].vector; pdata->an_irq = pdata->msix_entries[3].vector; @@ -240,7 +240,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata) pdata->irq_shared = 1; pdata->dev_irq = pdata->pcidev->irq; - pdata->smu_irq = pdata->pcidev->irq; + pdata->ecc_irq = pdata->pcidev->irq; pdata->i2c_irq = pdata->pcidev->irq; pdata->an_irq = pdata->pcidev->irq; @@ -249,7 +249,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata) unsigned int i; dev_dbg(pdata->dev, " dev irq=%d\n", pdata->dev_irq); - dev_dbg(pdata->dev, " smu irq=%d\n", pdata->smu_irq); + dev_dbg(pdata->dev, " ecc irq=%d\n", pdata->ecc_irq); dev_dbg(pdata->dev, " i2c irq=%d\n", pdata->i2c_irq); dev_dbg(pdata->dev, " an irq=%d\n", pdata->an_irq); for (i = 0; i < pdata->channel_irq_count; i++) @@ -460,6 +460,7 @@ static int xgbe_pci_resume(struct pci_dev *pdev) .tx_max_fifo_size = 229376, .rx_max_fifo_size = 229376, .tx_tstamp_workaround = 1, + .ecc_support = 1, }; static const struct xgbe_version_data xgbe_v2b = { @@ -469,6 +470,7 @@ static int xgbe_pci_resume(struct pci_dev *pdev) .tx_max_fifo_size = 65536, .rx_max_fifo_size = 65536, .tx_tstamp_workaround = 1, + .ecc_support = 1, }; static const struct pci_device_id xgbe_pci_table[] = { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 4047bc0..e6d69d1 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -285,6 +285,9 @@ #define XGBE_SGMII_AN_LINK_SPEED_1000 0x08 #define XGBE_SGMII_AN_LINK_DUPLEX BIT(4) +/* ECC correctable error notification window (seconds) */ +#define XGBE_ECC_LIMIT 60 + struct xgbe_prv_data; struct xgbe_packet_data { @@ -461,6 +464,7 @@ enum xgbe_state { XGBE_DOWN, XGBE_LINK_INIT, XGBE_LINK_ERR, + XGBE_STOPPED, }; enum xgbe_int { @@ -480,6 +484,12 @@ enum xgbe_int_state { XGMAC_INT_STATE_RESTORE, }; +enum xgbe_ecc_sec { + XGBE_ECC_SEC_TX, + XGBE_ECC_SEC_RX, + XGBE_ECC_SEC_DESC, +}; + enum xgbe_speed { XGBE_SPEED_1000 = 0, XGBE_SPEED_2500, @@ -694,6 +704,10 @@ struct xgbe_hw_if { int (*disable_rss)(struct xgbe_prv_data *); int (*set_rss_hash_key)(struct xgbe_prv_data *, const u8 *); int (*set_rss_lookup_table)(struct xgbe_prv_data *, const u32 *); + + /* For ECC */ + void (*disable_ecc_ded)(struct xgbe_prv_data *); + void (*disable_ecc_sec)(struct xgbe_prv_data *, enum xgbe_ecc_sec); }; /* This structure represents implementation specific routines for an @@ -827,6 +841,7 @@ struct xgbe_version_data { unsigned int tx_max_fifo_size; unsigned int rx_max_fifo_size; unsigned int tx_tstamp_workaround; + unsigned int ecc_support; }; struct xgbe_prv_data { @@ -868,9 +883,24 @@ struct xgbe_prv_data { /* Flags representing xgbe_state */ unsigned long dev_state; + /* ECC support */ + unsigned long tx_sec_period; + unsigned long tx_ded_period; + unsigned long rx_sec_period; + unsigned long rx_ded_period; + unsigned long desc_sec_period; + unsigned long desc_ded_period; + + unsigned int tx_sec_count; + unsigned int tx_ded_count; + unsigned int rx_sec_count; + unsigned int rx_ded_count; + unsigned int desc_ded_count; + unsigned int desc_sec_count; + struct msix_entry *msix_entries; int dev_irq; - int smu_irq; + int ecc_irq; int i2c_irq; int channel_irq[XGBE_MAX_DMA_CHANNELS]; @@ -880,6 +910,8 @@ struct xgbe_prv_data { unsigned int channel_irq_count; unsigned int channel_irq_mode; + char ecc_name[IFNAMSIZ + 32]; + struct xgbe_hw_if hw_if; struct xgbe_phy_if phy_if; struct xgbe_desc_if desc_if; @@ -990,8 +1022,9 @@ struct xgbe_prv_data { /* Hardware features of the device */ struct xgbe_hw_features hw_feat; - /* Device restart work structure */ + /* Device work structures */ struct work_struct restart_work; + struct work_struct stopdev_work; /* Keeps track of power mode */ unsigned int power_down;