From patchwork Fri Mar 16 18:12:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Trent Piepho X-Patchwork-Id: 887090 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-rtc-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=impinj.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=impinj.onmicrosoft.com header.i=@impinj.onmicrosoft.com header.b="OWbOh8mO"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 402tpt33jbz9sRL for ; Sat, 17 Mar 2018 05:12:38 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752949AbeCPSMh (ORCPT ); Fri, 16 Mar 2018 14:12:37 -0400 Received: from mail-by2nam03on0119.outbound.protection.outlook.com ([104.47.42.119]:61856 "EHLO NAM03-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752896AbeCPSMf (ORCPT ); Fri, 16 Mar 2018 14:12:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=impinj.onmicrosoft.com; s=selector1-impinj-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=FHtuaV3Cr/GvAxYJXjrthsh+DyF6yV0qynsBfUJVz5w=; b=OWbOh8mOQOhTE074TLcFYXbGFWIs6s5VjU8kcparqeD6PHRknOiX/jx7RK3+ft7PNEDXbQuYUh3TZZE/YIRopeikNto42qN9oG2kF3TGtDxjaWFFrxLIo4dUAUgcI6H1hkftaOapcRE8XOXnvR9WafvnlZ+4/+gb41I1umITXT0= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=tpiepho@impinj.com; Received: from impinj.com (216.207.205.253) by SN4PR0601MB3758.namprd06.prod.outlook.com (2603:10b6:803:4c::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.588.14; Fri, 16 Mar 2018 18:12:32 +0000 From: Trent Piepho Cc: Trent Piepho , Alessandro Zummo , Alexandre Belloni , linux-rtc@vger.kernel.org, Shawn Guo , Sascha Hauer , Fabio Estevam Subject: [PATCH] rtc-snvs: Add timeouts to avoid kernel lockups Date: Fri, 16 Mar 2018 11:12:02 -0700 Message-Id: <20180316181202.14896-1-tpiepho@impinj.com> X-Mailer: git-send-email 2.14.3 MIME-Version: 1.0 X-Originating-IP: [216.207.205.253] X-ClientProxiedBy: DM5PR1601CA0009.namprd16.prod.outlook.com (2603:10b6:4:5e::22) To SN4PR0601MB3758.namprd06.prod.outlook.com (2603:10b6:803:4c::20) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ab7506e0-c99c-4c25-6263-08d58b697d6e X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(5600026)(4604075)(2017052603328)(7153060)(7193020); SRVR:SN4PR0601MB3758; X-Microsoft-Exchange-Diagnostics: 1; SN4PR0601MB3758; 3:tJAdHu1w6xH17x31bY6E1NhnEESU3gS/YNwJfuvuFVJsc/Pn0HZWLAHK6RINkh5NAkuNOo8RxRjpiyXkSvJjcXP9qDAyaSp84it+/SFF3w2XBMEB1mA80MpJjhVPQBvPth/aBW9E4ToXJw/0Z+Sfgvd/QfLfcR9jh0I1OwSbsG7qNVrWoxsb3aJB5LE4eerI1joI4rbj+yId22X/T3y1gtG7Qo8LDmu0+5t9TMMtFEtIZsqIikdxBkEp6CVZY1GP; 25:aakLj8zN7gO9y2jvdn5jaANTZwMtGksiTtite0ns2Wo0IujqNI4PaKCaUWMjhgXTUJyDJjvf0MDlP0xEjLja9NRvhx88qjPOXJkjuULeR41GyrMynN2zyV9NUA2y/FwoweODXuks6IKAMSRdBEwBjMeEAT4Tqiog6wB26o1FB6HQK11WXfbtZ8yZoleKWhW/I3XUzklqQl446l5Ewo/AOgKZcaQL4Wuu/4vfouTEzhFjrViOzTIh4tR4TEVlgcNd03OrYA4wLJo8syGh9OOKQbqTGxr+i3THi6eSPldBMwQiO9Y8kUtg/ZUqSKxJz5wngL2PgaBA476o+5OkyiVxkQ==; 31:tKwp4JohPWU4ju1DYezc69u0nr0OaefDQNuq1V2Y76H+DP4itfSC7P5dvr7l+yfD5N8BncYyWxfuBhOr9CjnRfPTW01Hp6dQpfeuCnCKuLnKaw5x52PGH6kUd12PUZJdyl3kg86ExrzaPbzB9lAyVDyGAdYpWZwfK0FT58vo1K1TDZ7blq0kGy8vTH8BuorqVQIeRb6G3g7B7shSyhYNv9+UGdHpMPFkLN1u1ev2RiA= X-MS-TrafficTypeDiagnostic: SN4PR0601MB3758: X-Microsoft-Exchange-Diagnostics: 1; SN4PR0601MB3758; 20:WoPS0NEjuJD/2McgHnvBLbC8tSrc7aUZqGro5Pvb8nR1beJd9JGlKjBXS+3tbTbH277D7/1140fEid+HaVB7/C9AzWC7LXQUW4D9UEptsO4u8FiHEmnlbUYTJGbJefgqEMHSBx2dPjFtutrgSnAeBGm28E5CFJPKWaLb3+JZqZsHvC6eH9oU3g6JjO6EIgD3Va9a3wWO9V9rGIk7HYmjwk7yc/2j2ZjpcLF3lA4xSrJLFe26qNpBiUiL3O515w4iBgXCnI1QZDCJzmsk+rI1I7/6i72+wScZ1/DMbG4tzc0N+qZbZrJtvDmv6i2sU4qmpxHZuQJnvbWQDIH8fq3Q0nALgpX0h6Q5yRDpUHSHqdqGk24Ah0b6I7ZkQoOgthAkJzwWwM2KbR3QTJREKL8hlYym/yC5swFmY+3wRjXX6BuzXnG/I1xUgbVxu+Fnm/O5jNyU2XC+MoXLDlXqqnwJCECP/1OlFW7jM8LWLEjhjt8mTbM8KqVlvpPCIDf7ib38; 4:zZT3/yR83EQxuPSSMi0o1EQMHfuTieRiBTEzPKJEyjeo5QFJQsfOo30RZxIIb+l62ZUtp1Hg1CkvGtsuQVEswd2aSeCKGuKtngcS4GUZxyqSQsiOWOXPcTzlelD9+Pkk0idKVXVOrAriCKGUoAESd4ih6qHdw5XKKARxEUv3wWbEwvh0kXHy6yxdawhPXGopRwhqVzMi7vlTwvpg9jtyA7LsRpss3M86YyHXCkiunq94O4suy5y+YD8tx1CRGYuk5vqr1b7moLNXgKKSO46F3DXiobNHcsNwLd3dBiPJf9StaDI7G0HvrNZNyOA7gK3gUa64KfnYICUVqAoiNOQJ6YNBases8/0FVaoXekTs68epBsj7zR5rsv3+dxCUz2Ga X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055)(185117386973197)(58145275503218); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(93006095)(93001095)(3231221)(944501244)(52105095)(3002001)(10201501046)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123560045)(20161123558120)(20161123564045)(20161123562045)(6072148)(201708071742011); SRVR:SN4PR0601MB3758; BCL:0; PCL:0; RULEID:; SRVR:SN4PR0601MB3758; X-Forefront-PRVS: 0613912E23 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(39380400002)(376002)(366004)(346002)(39850400004)(396003)(189003)(199004)(4326008)(1076002)(3846002)(6116002)(68736007)(50226002)(55016002)(53936002)(6666003)(109986005)(8936002)(23676004)(86362001)(21086003)(54906003)(59450400001)(8656006)(52116002)(7696005)(2870700001)(5660300001)(36756003)(1857600001)(478600001)(386003)(16526019)(106356001)(97736004)(66066001)(47776003)(105586002)(2906002)(305945005)(316002)(7736002)(25786009)(81166006)(81156014)(8676002)(69596002)(1671002)(26005)(50466002)(266003); DIR:OUT; SFP:1102; SCL:1; SRVR:SN4PR0601MB3758; H:impinj.com; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: impinj.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?utf-8?q?1=3BSN4PR0601MB3758=3B23=3AMR?= =?utf-8?q?7L4aFsE4/nHJBxBOfLI9JCZoWjZg4KoEiMoiEZw9QXyCKwA/3qLPaxFD?= =?utf-8?q?WxBf4mvdev4U82MYx4RSZ+EsbEzwE5garFgGHIrIfTqTcgvvt1QSk7Dv?= =?utf-8?q?inqaZRqtV1PGGl2pVgAjAjprw3um64OEAiEqbWVus2eAAoM5EYg5EQzH?= =?utf-8?q?ThZqZmV4Yrz/3BDPdVcu8ZM2TlsO5eloMq/XCpDmQNVpOfO+rS0elZfG?= =?utf-8?q?XPd5KREIYa76eNRDWunouGCJSwRM5mD2PkRXzzo7A9KkwwQ54Sfy0p4z?= =?utf-8?q?53GkZZ+PDZGVSEJ04gR90qanPf28b0r163fqqyuoFeyAbmJDls1RvbvM?= =?utf-8?q?qtz8WLSQW58pe+NDk9Yxl2x0r2Z4XEFjXwhcem3KJGNiwGTyd7+mOW3D?= =?utf-8?q?7nkfjSRNYHSkJ5Mw+y2zsKeNd81v2Uq+DGUkEEgv/lKSXywrwjJ8WZ8i?= =?utf-8?q?jZ38UApha9h4zHVui7NjSuIys6e45opXxbM3bLoi6ONqJxqje7abzUpR?= =?utf-8?q?+njrm+tyh3+B8zRGaQ896kgCmeh1dgEQf4JQG1kCPxTMS9lhPUYp/N1j?= =?utf-8?q?UkDTYgxj7tmbxx0V7gGJR/FRaIqhdwoCd65dZLUehIdbeVjWi9wE74sN?= =?utf-8?q?YWTAJphxobl+VMo9yQ9YBNZPHid66kduq3EW23WPBsFVHZskdThWReg/?= =?utf-8?q?pH4pyXCW61BihG/m9YDNwN6pgR3sQot+euRR/IjcImSnRw/S0eje0Jnq?= =?utf-8?q?FpgSvSjFl/BRBkLcpLNhuMA3F3qfgBsDGIUSLba9IiskO/vru/R1Znh5?= =?utf-8?q?xrmx6aitH1gzBio2GanNwB8Dso0Jexd3NeM+UlR6wGqa6ekvuO/LyTxw?= =?utf-8?q?kMm4bw9KPFoo7bVTuAGKoAMkpWierIsNjSrDA+RL7kIKNqsNlGgrt5sD?= =?utf-8?q?0CIe+44QdhZeoffOZ+blUTAsgQ2YIiZYaFcOBqN2vn90E4Os76nHv3bY?= =?utf-8?q?TXX8u7NTh1WG8tctgx4nfFyJ+6UPDNdU1VhbQdNgdIWqey0xoZY/XNv2?= =?utf-8?q?o1kyVGhw/wiaXsaegyIuF3iB2/Qq8TZxyG5RNhXr6dBTISlmSlT/t+vy?= =?utf-8?q?OZNWYN9xIcNXgVFhawSRVszUMElfm9+8WX0tR0fZtmZkbQjK04OG4f0o?= =?utf-8?q?iF4p/oU8vZJ0OR7tK1gcY0bZH3zbRpmu0tQsh1aX/H/y3uj9hIusnXK3?= =?utf-8?q?hCoovH1hh05uO/Lj71GpbNJEjppt+yueP/VeLj?= X-Microsoft-Antispam-Message-Info: XTaF4/cNGdFDPOLxRmZ30Ta/65q3llxBfZh3QKYPpF9RWuZnGtac5VjcNmpQqUzwjiDgK7RPhvx+ElQVJLKdLcm1U+YmuPBf2wRCoWkggs0TkSdASXcBfPAzhFNy17OPny4G3HkGUx4DiWrhbEUZvyaIWfHeA9s0Xpo2MTEJ0+ccJf0Hlqgp3DAKdWppIM1c X-Microsoft-Exchange-Diagnostics: 1; SN4PR0601MB3758; 6:m+YeDiSGtXSd/nVHBrmlRfwDlvEZ7qZs6ZfplEsIL4uGZFCOpbxLOcoo+a/0Fsb9j6kmEExjQU+4NuT03tkdeo/1XPoct9m7JHJFeGzGpvZFuwqbUBN9TYPEobdmqVHlAqbdcgeQfkjnoJGaSG+b0rC9LEXQOlYtB+NM+cWbX60hP+Qh/Go+mIk6dzUd0kORTiq5Ax1sc+zHOTwrfy6+QPODov/yuUrfvc7yc04pamgpot3OXm+3nc4oqMRR80V4XZDK6zU2vcuq+dJEFNh+qckg7QK0OLnrDgIZyeLL8CzPRWAj9dNeSlbvnIStquzIoHjTnoDBMOyNPAa+wo1JD6j9E/OiFLRnkEB21Nlxa2A=; 5:h7rxg03g/9fDdKy8oR5EhtutmVr6FQujSJEa9NZRSflCKVAyYhamVmvX1voMKLC/Zk/1WKG0n40V48H9XJydN+llkydMb5rkCYLBt6ZM/igwNvR6PHSz5KHAQIcfIgQlhPbXsWdftylzD+L4vutRz5EFr1O5D8YL9X9NpqmsVWk=; 24:maMz+CAms4LrcekjR533hMu7Y3XuSvhnEMaftIAk0JIRq7LpqcL5Wj1TQipnacXk1KKxQX/wc91Z6UM8Pe9fYd4d1o2TEvIxDl0WIJC0Lxw=; 7:goIFDkrc8Gzr+ljcgyLcJWnxyaR5u+NTBye6QikfoavNPxoKeV+JJRNPFF/HK8f1iU3Oxwigpks4ejety7zx/poDELEuNNCd/ONsvi6lYKpJlOjIHnsXpM0/pSWaSc3KLHYaAb6nAwc4ttm1og6jj1DF5nzSYFBexjSGx0G8S2RQSo4FObizOHdhm20SgzMM6OXIysxA5gU6TdndF0xRbSkZAwc3jx20Ojq65krRsRkINOXDHVTBhWUFY4oblSQN SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: impinj.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Mar 2018 18:12:32.8130 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ab7506e0-c99c-4c25-6263-08d58b697d6e X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 6de70f0f-7357-4529-a415-d8cbb7e93e5e X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN4PR0601MB3758 To: unlisted-recipients:; (no To-header on input) Sender: linux-rtc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rtc@vger.kernel.org In order to read correctly from asynchronously updated RTC registers, it's necessary to read repeatedly until their values do not change from read to read. There is no timeout in this code and it could possibly loop forever. It's also necessary to wait for three RTC clock ticks for certain operations to take effect and the driver might wait forever for this to happen. To avoid kernel hangs, put in timeouts. These hangs will happen when running under qemu, which doesn't emulate the SNVS RTC. It could also happen if the RTC block where somehow placed into reset or the slow speed clock that drives the RTC counter (but not the CPU) were to stop. The symptoms are a work queue hang on rtc_timer_do_work(), which eventually blocks a systemd fsnotify operation that triggers a work queue flush, causing systemd to hang and thus causing all services that should be started by systemd, like a console getty, to fail to start or stop. Also optimize the wait code to wait less. It only needs to wait for the clock to advance three ticks, not to see it change three times. Signed-off-by: Trent Piepho Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: linux-rtc@vger.kernel.org Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam --- drivers/rtc/rtc-snvs.c | 105 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index d8ef9e052c4f..0e7564b9d6f2 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -47,49 +47,83 @@ struct snvs_rtc_data { struct clk *clk; }; +/* Read 64 bit timer register, which could be in inconsistent state */ +static u64 rtc_read_lpsrt(struct snvs_rtc_data *data) +{ + u32 msb, lsb; + + regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb); + return (u64)msb << 32 | lsb; +} + +/* Read the secure real time counter, taking care to deal with the cases of the + * counter updating while being read. + */ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) { u64 read1, read2; - u32 val; + unsigned int timeout = 100; + /* As expected, the registers might update between the read of the LSB + * reg and the MSB reg. It's also possible that one register might be + * in partially modified state as well. + */ + read1 = rtc_read_lpsrt(data); do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read1 = val; - read1 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read1 |= val; - - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read2 = val; - read2 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read2 |= val; - } while (read1 != read2); + read2 = read1; + read1 = rtc_read_lpsrt(data); + } while (read1 != read2 && --timeout); + if (!timeout) + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); /* Convert 47-bit counter to 32-bit raw second count */ return (u32) (read1 >> CNTR_TO_SECS_SH); } -static void rtc_write_sync_lp(struct snvs_rtc_data *data) +/* Just read the lsb from the counter, dealing with inconsistent state */ +static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) { - u32 count1, count2, count3; - int i; - - /* Wait for 3 CKIL cycles */ - for (i = 0; i < 3; i++) { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - } while (count1 != count2); - - /* Now wait until counter value changes */ - do { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3); - } while (count2 != count3); - } while (count3 == count1); + u32 count1, count2; + unsigned int timeout = 100; + + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + do { + count2 = count1; + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + } while (count1 != count2 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); + return -ETIMEDOUT; } + + *lsb = count1; + return 0; +} + +static int rtc_write_sync_lp(struct snvs_rtc_data *data) +{ + u32 count1, count2; + u32 elapsed; + unsigned int timeout = 1000; + int ret; + + ret = rtc_read_lp_counter_lsb(data, &count1); + if (ret) + return ret; + + /* Wait for 3 CKIL cycles, about 61.0-91.5 µs */ + do { + ret = rtc_read_lp_counter_lsb(data, &count2); + if (ret) + return ret; + elapsed = count2 - count1; /* wrap around _is_ handled! */ + } while (elapsed < 3 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n"); + return -ETIMEDOUT; + } + return 0; } static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) @@ -170,9 +204,7 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); - rtc_write_sync_lp(data); - - return 0; + return rtc_write_sync_lp(data); } static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -180,11 +212,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct snvs_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alrm_tm = &alrm->time; unsigned long time; + int ret; rtc_tm_to_time(alrm_tm, &time); regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); - rtc_write_sync_lp(data); + ret = rtc_write_sync_lp(data); + if (ret) + return ret; regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); /* Clear alarm interrupt status bit */