Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp1483796pxb; Sat, 30 Oct 2021 14:53:02 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxdz1qfAjvkk9O4IRsLBgIimDUJ2RPHhiPIiFtREAGef/9+XbHHGqgMiC23Xnn6ovLSRbmL X-Received: by 2002:a17:907:2d20:: with SMTP id gs32mr24886168ejc.472.1635630782766; Sat, 30 Oct 2021 14:53:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1635630782; cv=none; d=google.com; s=arc-20160816; b=if4YxmAw+8aeTzI6I4GJdTneAI7Rk6SdjTyJYQd1hlnVvyq47NozNvI03/ORMmpm2t AcVQeBOWbWBGRhZMmTLgm8WWOXVor7ummq9rnZzG0LuUMwst5T3UoIJPN51GX/KVq7eO B3LusilCDzWw7+E6va7NSZRLzyBW3EPZZX+FKGVxPNQBA31WFfSDCLilAb19KSYttEKm UNptF8cjth9us69/vGKNw42fzH5Jr1gxsH/72ytmZhCSw2LCm5MQ5iPLziTnVK3Ptn3r cyxw8jS/mT5tOzYxc82jI+A7fl+xhw0szRz+QpAfigSgsV4qtoKS+iWWoZrpSQn9YOs7 wfEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=IiNlBYkDnR36ib1JK88p2ItCAvyOlEF11DbUtE/R2wY=; b=0GV2yMWr/t6G9pP5kuOWP7v8EJiSnfiXPhb/nLLXobisWveWG4MV51HLyhWWi25+th 9E5j+xdQiK+EKe6nxoXHt5tkDiMUaA8lDvS6GFBf+GaVl8FhzvcILElvnAVKjUcV6VhU 7/56er6DJRYyf951yrH/llDRWhm0GHVJuNERnjs9DIEy0E9pwK2Ntt8VDWMYqoheK2Kv aIJkty85CtWNBMfd1g3rrmxeJhXX/E8Wk118QGPQc0NjAYJEOh37dg2Jv72s7ac60xlk 6+lRvcZ8PprvgT0I+n9bRrORcL2LK95WOxkml37zAYqLZVm1bireslMkh7ZjASlczRll qxcA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass (test mode) header.i=@o2.pl header.s=1024a header.b=dPcuRjUD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=o2.pl Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y1si18219535eda.279.2021.10.30.14.52.27; Sat, 30 Oct 2021 14:53:02 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass (test mode) header.i=@o2.pl header.s=1024a header.b=dPcuRjUD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=o2.pl Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232110AbhJ3Vu2 (ORCPT + 99 others); Sat, 30 Oct 2021 17:50:28 -0400 Received: from mx-out.tlen.pl ([193.222.135.142]:4430 "EHLO mx-out.tlen.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232084AbhJ3VuR (ORCPT ); Sat, 30 Oct 2021 17:50:17 -0400 Received: (wp-smtpd smtp.tlen.pl 26339 invoked from network); 30 Oct 2021 23:47:42 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=o2.pl; s=1024a; t=1635630462; bh=IiNlBYkDnR36ib1JK88p2ItCAvyOlEF11DbUtE/R2wY=; h=From:To:Cc:Subject; b=dPcuRjUDBbVJZG5cuSJ7Z7pLof+3oTqFWqglWfl4/YNbx/56OoXMnMIi9MtovWWt1 LQcuO2d2+9M6Or5zh+IgLluaeAzsCaRY3UGQ9O0Hmu29ThoJEbi8CuG7yRsEAZW9F6 UqEO/Nl3yS8Y57u77zXFkGEwdnyhEfemLAl8fpxg= Received: from ablz112.neoplus.adsl.tpnet.pl (HELO localhost.localdomain) (mat.jonczyk@o2.pl@[83.7.219.112]) (envelope-sender ) by smtp.tlen.pl (WP-SMTPD) with SMTP for ; 30 Oct 2021 23:47:42 +0200 From: =?UTF-8?q?Mateusz=20Jo=C5=84czyk?= To: linux-rtc@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Mateusz=20Jo=C5=84czyk?= , Alessandro Zummo , Alexandre Belloni Subject: [PATCH v3 7/7] rtc-cmos: avoid UIP when writing alarm time Date: Sat, 30 Oct 2021 23:46:35 +0200 Message-Id: <20211030214636.49602-8-mat.jonczyk@o2.pl> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211030214636.49602-1-mat.jonczyk@o2.pl> References: <20211030214636.49602-1-mat.jonczyk@o2.pl> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-WP-MailID: 741571f4e22b8dd52dc380a525b2820d X-WP-AV: skaner antywirusowy Poczty o2 X-WP-SPAM: NO 0000000 [wVP0] Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some Intel chipsets disconnect the time and date RTC registers when the clock update is in progress: during this time reads may return bogus values and writes fail silently. This includes the RTC alarm registers. [1] cmos_set_alarm() did not take account for that, fix it. [1] 7th Generation Intel ® Processor Family I/O for U/Y Platforms [...] Datasheet, Volume 1 of 2 (Intel's Document Number: 334658-006) Page 208 https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/7th-and-8th-gen-core-family-mobile-u-y-processor-lines-i-o-datasheet-vol-1.pdf "If a RAM read from the ten time and date bytes is attempted during an update cycle, the value read do not necessarily represent the true contents of those locations. Any RAM writes under the same conditions are ignored." Signed-off-by: Mateusz Jończyk Cc: Alessandro Zummo Cc: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 108 +++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 2def331e88b6..b6d7dd3cf066 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -463,10 +463,58 @@ static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } +struct cmos_set_alarm_callback_param { + struct cmos_rtc *cmos; + unsigned char mon, mday, hrs, min, sec; + struct rtc_wkalrm *t; +}; + +/* Note: this function may be executed by mc146818_do_avoiding_UIP() more then + * once + */ +static void cmos_set_alarm_callback(unsigned char __always_unused seconds, + void *param_in) +{ + struct cmos_set_alarm_callback_param *p = + (struct cmos_set_alarm_callback_param *) param_in; + + /* next rtc irq must not be from previous alarm setting */ + cmos_irq_disable(p->cmos, RTC_AIE); + + /* update alarm */ + CMOS_WRITE(p->hrs, RTC_HOURS_ALARM); + CMOS_WRITE(p->min, RTC_MINUTES_ALARM); + CMOS_WRITE(p->sec, RTC_SECONDS_ALARM); + + /* the system may support an "enhanced" alarm */ + if (p->cmos->day_alrm) { + CMOS_WRITE(p->mday, p->cmos->day_alrm); + if (p->cmos->mon_alrm) + CMOS_WRITE(p->mon, p->cmos->mon_alrm); + } + + if (use_hpet_alarm()) { + /* + * FIXME the HPET alarm glue currently ignores day_alrm + * and mon_alrm ... + */ + hpet_set_alarm_time(p->t->time.tm_hour, p->t->time.tm_min, + p->t->time.tm_sec); + } + + if (p->t->enabled) + cmos_irq_enable(p->cmos, RTC_AIE); + +} + static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned char mon, mday, hrs, min, sec, rtc_control; + struct cmos_set_alarm_callback_param p = { + .cmos = cmos, + .t = t + }; + unsigned char rtc_control; int ret; /* This not only a rtc_op, but also called directly */ @@ -477,11 +525,11 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (ret < 0) return ret; - mon = t->time.tm_mon + 1; - mday = t->time.tm_mday; - hrs = t->time.tm_hour; - min = t->time.tm_min; - sec = t->time.tm_sec; + p.mon = t->time.tm_mon + 1; + p.mday = t->time.tm_mday; + p.hrs = t->time.tm_hour; + p.min = t->time.tm_min; + p.sec = t->time.tm_sec; spin_lock_irq(&rtc_lock); rtc_control = CMOS_READ(RTC_CONTROL); @@ -489,43 +537,21 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { /* Writing 0xff means "don't care" or "match all". */ - mon = (mon <= 12) ? bin2bcd(mon) : 0xff; - mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; - hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; - min = (min < 60) ? bin2bcd(min) : 0xff; - sec = (sec < 60) ? bin2bcd(sec) : 0xff; + p.mon = (p.mon <= 12) ? bin2bcd(p.mon) : 0xff; + p.mday = (p.mday >= 1 && p.mday <= 31) ? bin2bcd(p.mday) : 0xff; + p.hrs = (p.hrs < 24) ? bin2bcd(p.hrs) : 0xff; + p.min = (p.min < 60) ? bin2bcd(p.min) : 0xff; + p.sec = (p.sec < 60) ? bin2bcd(p.sec) : 0xff; } - spin_lock_irq(&rtc_lock); - - /* next rtc irq must not be from previous alarm setting */ - cmos_irq_disable(cmos, RTC_AIE); - - /* update alarm */ - CMOS_WRITE(hrs, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - - /* the system may support an "enhanced" alarm */ - if (cmos->day_alrm) { - CMOS_WRITE(mday, cmos->day_alrm); - if (cmos->mon_alrm) - CMOS_WRITE(mon, cmos->mon_alrm); - } - - if (use_hpet_alarm()) { - /* - * FIXME the HPET alarm glue currently ignores day_alrm - * and mon_alrm ... - */ - hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, - t->time.tm_sec); - } - - if (t->enabled) - cmos_irq_enable(cmos, RTC_AIE); - - spin_unlock_irq(&rtc_lock); + /* + * Some Intel chipsets disconnect the alarm registers when the clock + * update is in progress - during this time writes fail silently. + * + * Use mc146818_do_avoiding_UIP() to avoid this. + */ + if (!mc146818_do_avoiding_UIP(cmos_set_alarm_callback, &p)) + return -EIO; cmos->alarm_expires = rtc_tm_to_time64(&t->time); -- 2.25.1