[PATCH v4 4/8] hv: add vRTC reg_b and reg_c support


Zhao, Yuanyuan
 

On 5/6/2022 9:24 AM, Junjie Mao wrote:
Yuanyuan Zhao <yuanyuan.zhao@...> writes:

Support bit 7 of reg_b. When it set to 0, time will be updated. And
when it's set to 1, rtc will keep the second it was set.

Support alarm interrupt flag update. Current driver sets alarm interrupt
when get RTC time. So if alarm interrupt is enabled (bit 5, reg_b set to 1),
interrupt flag register will be set (bit 7 & bit 5 of reg_c) at
appropriate time.

These regisers are involved in RTC time getting and setting.
Passive voices are typically not a good choice for justification as they
hide the subject for no reason. Be explicit and precise where and when
you see those bits being used.
During setting RTC time, driver will halt RTC update. So support bit 7 of reg_b. When it set to 0, time will be updated. And
when it's set to 1, rtc will keep the second it was set.

In the process of getting RTC time, driver sets alarm interrupt, waits 1s, and get alarm interrupt flag. So support alarm interrupt flag update. If alarm interrupt is enabled (bit 5, reg_b set to 1),
interrupt flag register will be set (bit 7 & bit 5 of reg_c) at
appropriate time.




Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 70 +++++++++++++++++++++++++++--
hypervisor/include/dm/mc146818rtc.h | 5 +++
2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 8d42db44d..d167432c6 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -422,6 +422,41 @@ static uint8_t cmos_get_reg_val(uint8_t addr)
return reg;
}
+#define TRIGGER_ALARM (RTCIR_ALARM | RTCIR_INT)
+#define RTC_DELTA 1 /* For RTC and system time may out of sync for no more than 1s */
+static inline bool rtc_halted(struct acrn_vrtc *rtc)
+{
+ return ((rtc->rtcdev.reg_b & RTCSB_HALT) != 0U);
+}
+
+static uint8_t vrtc_get_reg_c(struct acrn_vrtc *vrtc)
+{
+ uint8_t ret = vrtc->rtcdev.reg_c;
+ struct rtcdev *rtc = &vrtc->rtcdev;
+ time_t current, alarm;
+
+ if ((rtc->reg_b & RTCSB_AINTR) != 0U) {
+ current = rtc->hour * 3600 + rtc->min * 60 + rtc->sec;
+ alarm = rtc->alarm_hour * 3600 + rtc->alarm_min * 60 + rtc->alarm_sec;
+
+ if (current >= alarm - RTC_DELTA && current <= alarm + RTC_DELTA) {
+ /*
+ * If alarm interrut is enabled and rtc time is in alarm time scale,
+ * set the interrupt flag as alarm triggered.
It is highly recommended to describe the background of this operation,
as the alarm mechanism is generally not supported. Such information
shall be present in both the commit messages and comments.


Junjie Mao
 

Yuanyuan Zhao <yuanyuan.zhao@...> writes:

Support bit 7 of reg_b. When it set to 0, time will be updated. And
when it's set to 1, rtc will keep the second it was set.

Support alarm interrupt flag update. Current driver sets alarm interrupt
when get RTC time. So if alarm interrupt is enabled (bit 5, reg_b set to 1),
interrupt flag register will be set (bit 7 & bit 5 of reg_c) at
appropriate time.

These regisers are involved in RTC time getting and setting.
Passive voices are typically not a good choice for justification as they
hide the subject for no reason. Be explicit and precise where and when
you see those bits being used.


Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 70 +++++++++++++++++++++++++++--
hypervisor/include/dm/mc146818rtc.h | 5 +++
2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 8d42db44d..d167432c6 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -422,6 +422,41 @@ static uint8_t cmos_get_reg_val(uint8_t addr)
return reg;
}

+#define TRIGGER_ALARM (RTCIR_ALARM | RTCIR_INT)
+#define RTC_DELTA 1 /* For RTC and system time may out of sync for no more than 1s */
+static inline bool rtc_halted(struct acrn_vrtc *rtc)
+{
+ return ((rtc->rtcdev.reg_b & RTCSB_HALT) != 0U);
+}
+
+static uint8_t vrtc_get_reg_c(struct acrn_vrtc *vrtc)
+{
+ uint8_t ret = vrtc->rtcdev.reg_c;
+ struct rtcdev *rtc = &vrtc->rtcdev;
+ time_t current, alarm;
+
+ if ((rtc->reg_b & RTCSB_AINTR) != 0U) {
+ current = rtc->hour * 3600 + rtc->min * 60 + rtc->sec;
+ alarm = rtc->alarm_hour * 3600 + rtc->alarm_min * 60 + rtc->alarm_sec;
+
+ if (current >= alarm - RTC_DELTA && current <= alarm + RTC_DELTA) {
+ /*
+ * If alarm interrut is enabled and rtc time is in alarm time scale,
+ * set the interrupt flag as alarm triggered.
It is highly recommended to describe the background of this operation,
as the alarm mechanism is generally not supported. Such information
shall be present in both the commit messages and comments.

--
Best Regards
Junjie Mao

+ */
+ ret |= TRIGGER_ALARM;
+ }
+ }
+
+ vrtc->rtcdev.reg_c = 0;
+ return ret;
+}
+
+static void vrtc_set_reg_b(struct acrn_vrtc *vrtc, uint8_t newval)
+{
+ vrtc->rtcdev.reg_b = newval;
+}
+
/**
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
@@ -435,7 +470,7 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
struct acrn_vm *vm = vcpu->vm;
bool ret = true;

- offset = vm->vrtc.addr;
+ offset = vrtc->addr;

if (addr == CMOS_ADDR_PORT) {
pio_req->value = offset;
@@ -447,7 +482,11 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
current = vrtc_get_current_time(vrtc);
secs_to_rtc(current, vrtc);

- pio_req->value = *((uint8_t *)&vm->vrtc.rtcdev + offset);
+ if(offset == 0xCU) {
+ pio_req->value = vrtc_get_reg_c(vrtc);
+ } else {
+ pio_req->value = *((uint8_t *)&vrtc->rtcdev + offset);
+ }
RTC_DEBUG("read 0x%x, 0x%x", offset, pio_req->value);
} else {
RTC_ERR("vrtc read invalid addr 0x%x", offset);
@@ -466,8 +505,33 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
uint32_t value)
{
+ struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;
+
if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
- vcpu->vm->vrtc.addr = (uint8_t)value & 0x7FU;
+ vrtc->addr = (uint8_t)(value & 0x7FU);
+ } else {
+ if (!is_service_vm(vcpu->vm)) {
+ switch (vrtc->addr) {
+ case RTC_STATUSA:
+ case RTC_INTR:
+ case RTC_STATUSD:
+ RTC_DEBUG("RTC reg_%x set to %#x (ignored)\n", vrtc->addr, value);
+ break;
+ case RTC_STATUSB:
+ vrtc_set_reg_b(vrtc, value);
+ RTC_DEBUG("RTC reg_b set to %#x\n", value);
+ break;
+ case RTC_SECALRM:
+ case RTC_MINALRM:
+ /* FALLTHRU */
+ case RTC_HRSALRM:
+ *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU);
+ RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value);
+ break;
+ default:
+ break;
+ }
+ }
}

return true;
diff --git a/hypervisor/include/dm/mc146818rtc.h b/hypervisor/include/dm/mc146818rtc.h
index b23f90d34..1681cc960 100644
--- a/hypervisor/include/dm/mc146818rtc.h
+++ b/hypervisor/include/dm/mc146818rtc.h
@@ -60,8 +60,13 @@
#define RTC_STATUSB 0x0b /* status register B */
#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */
+#define RTCSB_AINTR 0x20 /* 1 = enable alarm interrupt */
+#define RTCSB_HALT 0x80 /* stop clock updates */

#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */

#endif /* _MC146818_RTC_H_ */


Zhao, Yuanyuan
 

Support bit 7 of reg_b. When it set to 0, time will be updated. And
when it's set to 1, rtc will keep the second it was set.

Support alarm interrupt flag update. Current driver sets alarm interrupt
when get RTC time. So if alarm interrupt is enabled (bit 5, reg_b set to 1),
interrupt flag register will be set (bit 7 & bit 5 of reg_c) at
appropriate time.

These regisers are involved in RTC time getting and setting.

Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 70 +++++++++++++++++++++++++++--
hypervisor/include/dm/mc146818rtc.h | 5 +++
2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 8d42db44d..d167432c6 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -422,6 +422,41 @@ static uint8_t cmos_get_reg_val(uint8_t addr)
return reg;
}

+#define TRIGGER_ALARM (RTCIR_ALARM | RTCIR_INT)
+#define RTC_DELTA 1 /* For RTC and system time may out of sync for no more than 1s */
+static inline bool rtc_halted(struct acrn_vrtc *rtc)
+{
+ return ((rtc->rtcdev.reg_b & RTCSB_HALT) != 0U);
+}
+
+static uint8_t vrtc_get_reg_c(struct acrn_vrtc *vrtc)
+{
+ uint8_t ret = vrtc->rtcdev.reg_c;
+ struct rtcdev *rtc = &vrtc->rtcdev;
+ time_t current, alarm;
+
+ if ((rtc->reg_b & RTCSB_AINTR) != 0U) {
+ current = rtc->hour * 3600 + rtc->min * 60 + rtc->sec;
+ alarm = rtc->alarm_hour * 3600 + rtc->alarm_min * 60 + rtc->alarm_sec;
+
+ if (current >= alarm - RTC_DELTA && current <= alarm + RTC_DELTA) {
+ /*
+ * If alarm interrut is enabled and rtc time is in alarm time scale,
+ * set the interrupt flag as alarm triggered.
+ */
+ ret |= TRIGGER_ALARM;
+ }
+ }
+
+ vrtc->rtcdev.reg_c = 0;
+ return ret;
+}
+
+static void vrtc_set_reg_b(struct acrn_vrtc *vrtc, uint8_t newval)
+{
+ vrtc->rtcdev.reg_b = newval;
+}
+
/**
* @pre vcpu != NULL
* @pre vcpu->vm != NULL
@@ -435,7 +470,7 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
struct acrn_vm *vm = vcpu->vm;
bool ret = true;

- offset = vm->vrtc.addr;
+ offset = vrtc->addr;

if (addr == CMOS_ADDR_PORT) {
pio_req->value = offset;
@@ -447,7 +482,11 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
current = vrtc_get_current_time(vrtc);
secs_to_rtc(current, vrtc);

- pio_req->value = *((uint8_t *)&vm->vrtc.rtcdev + offset);
+ if(offset == 0xCU) {
+ pio_req->value = vrtc_get_reg_c(vrtc);
+ } else {
+ pio_req->value = *((uint8_t *)&vrtc->rtcdev + offset);
+ }
RTC_DEBUG("read 0x%x, 0x%x", offset, pio_req->value);
} else {
RTC_ERR("vrtc read invalid addr 0x%x", offset);
@@ -466,8 +505,33 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
uint32_t value)
{
+ struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;
+
if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
- vcpu->vm->vrtc.addr = (uint8_t)value & 0x7FU;
+ vrtc->addr = (uint8_t)(value & 0x7FU);
+ } else {
+ if (!is_service_vm(vcpu->vm)) {
+ switch (vrtc->addr) {
+ case RTC_STATUSA:
+ case RTC_INTR:
+ case RTC_STATUSD:
+ RTC_DEBUG("RTC reg_%x set to %#x (ignored)\n", vrtc->addr, value);
+ break;
+ case RTC_STATUSB:
+ vrtc_set_reg_b(vrtc, value);
+ RTC_DEBUG("RTC reg_b set to %#x\n", value);
+ break;
+ case RTC_SECALRM:
+ case RTC_MINALRM:
+ /* FALLTHRU */
+ case RTC_HRSALRM:
+ *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU);
+ RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value);
+ break;
+ default:
+ break;
+ }
+ }
}

return true;
diff --git a/hypervisor/include/dm/mc146818rtc.h b/hypervisor/include/dm/mc146818rtc.h
index b23f90d34..1681cc960 100644
--- a/hypervisor/include/dm/mc146818rtc.h
+++ b/hypervisor/include/dm/mc146818rtc.h
@@ -60,8 +60,13 @@
#define RTC_STATUSB 0x0b /* status register B */
#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */
+#define RTCSB_AINTR 0x20 /* 1 = enable alarm interrupt */
+#define RTCSB_HALT 0x80 /* stop clock updates */

#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */

#endif /* _MC146818_RTC_H_ */
--
2.25.1