cc-ing Jin Quian, Bo Hu & Lingfeng Yang from Google Hi Alexandre, thank you for your comments, answers are inline: > > On 28/06/2017 at 17:46:55 +0200, Aleksandar Markovic wrote: > > From: Aleksandar Markovic <aleksandar.markovic@xxxxxxxxxx> > > > > Add device driver for a virtual Goldfish RTC clock. > > > > The driver can be built only if CONFIG_MIPS and CONFIG_GOLDFISH are > > set. The compatible string used by OS for binding the driver is > > defined as "google,goldfish-rtc". > > > > Is it really MIPS specific? I would expect the same driver to work on > the ARM based emulator too. This driver can be made to work for ARM/Intel emulator but it is currently used only by MIPS emulator, so I would prefer to keep it guarded with "MIPS". If ARM or Intel decide to use this driver for their emulators it can be easily enabled. > > +config RTC_DRV_GOLDFISH > > + tristate "Goldfish Real Time Clock" > > + depends on MIPS > > + depends on GOLDFISH > > This should be made buildable with COMPILE_TEST to extend coverage. It will be included in the next version. > > + help > > + Say yes here to build support for the Goldfish RTC. > > Please, don't expect anybody to actually know what is goldfish can you > add a sentence or two? It will be better documented in the next version. Thank you. > > +static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id) > > +{ > > + struct goldfish_rtc *qrtc = dev_id; > > + unsigned long events = 0; > > + void __iomem *base = qrtc->base; > > + > > + writel(1, base + TIMER_CLEAR_INTERRUPT); > > + events = RTC_IRQF | RTC_AF; > > + > > + rtc_update_irq(qrtc->rtc, 1, events); > > I'd say that events is not needed you can pass the flags directly to > rtc_update_irq It will be corrected in the next version. > > +static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm) > > +{ > > + u64 time; > > + u64 time_low; > > + u64 time_high; > > + u64 time_high_prev; > > + > > + struct goldfish_rtc *qrtc = > > + platform_get_drvdata(to_platform_device(dev)); > > + void __iomem *base = qrtc->base; > > + > > + time_high = readl(base + TIMER_TIME_HIGH); > > + do { > > + time_high_prev = time_high; > > + time_low = readl(base + TIMER_TIME_LOW); > > + time_high = readl(base + TIMER_TIME_HIGH); > > + } while (time_high != time_high_prev); > > I'm not sure why you need that loop as the comments for TIMER_TIME_LOW > and TIMER_TIME_HIGH indicate that TIMER_TIME_HIGH is latched when > TIMER_TIME_LOW is read. Note that the original driver from google > doesn't do that. This is the way how other HW drivers are doing it, so we used this approach to make it more in-line with other HW, and it also does not make any assumptions regarding TIMER_TIME_HIGH is latched or not. This is the relevant part of code on the RTC device side which emulates these reads: static uint64_t goldfish_timer_read(void *opaque, hwaddr offset, unsigned size) { struct timer_state *s = (struct timer_state *)opaque; switch(offset) { case TIMER_TIME_LOW: s->now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); return s->now_ns; case TIMER_TIME_HIGH: return s->now_ns >> 32; default: cpu_abort(current_cpu, "goldfish_timer_read: Bad offset %" HWADDR_PRIx "\n", offset); return 0; } } So theoretically speaking, we could imagine the situation that the kernel pre-empts after the first TIMER_TIME_LOW read and another request for reading the time gets processed, so the previous call would end-up having stale TIMER_TIME_LOW value. This is however very unlikely to happen, but one extra read in the loop doesn't hurt and actually makes the code less prone to error. > > + time = (time_high << 32) | time_low; > > + > > + do_div(time, NSEC_PER_SEC); > > + > > + rtc_time_to_tm(time, tm); > > + > > + return 0; > > +} > > + > > +static const struct rtc_class_ops goldfish_rtc_ops = { > > + .read_time = goldfish_rtc_read_time, > > +}; > > + > > +static int goldfish_rtc_probe(struct platform_device *pdev) > > +{ > > + struct resource *r; > > + struct goldfish_rtc *qrtc; > > + unsigned long rtc_dev_len; > > + unsigned long rtc_dev_addr; > > + int err; > > + > > + qrtc = devm_kzalloc(&pdev->dev, sizeof(*qrtc), GFP_KERNEL); > > + if (qrtc == NULL) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, qrtc); > > + > > + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + if (r == NULL) > > + return -ENODEV; > > + > > + rtc_dev_addr = r->start; > > + rtc_dev_len = resource_size(r); > > + qrtc->base = devm_ioremap(&pdev->dev, rtc_dev_addr, rtc_dev_len); > > devm_ioremap_resource ? Thanks, it will be fixed in next version to use devm_ioremap_resource(). > > + if (IS_ERR(qrtc->base)) > > + return -ENODEV; > > + > > + qrtc->irq = platform_get_irq(pdev, 0); > > + if (qrtc->irq < 0) > > + return -ENODEV; > > + > > Is the irq so important that you have to fail here even if the driver > doesn't support any alarm? Well currently it does not support alarm features, but we are considering to implement it in some other iteration. Maybe we will introduce it in the next version if not we will remove the IRQ handling. Thanks. > > + qrtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, > > + &goldfish_rtc_ops, THIS_MODULE); > > + if (IS_ERR(qrtc->rtc)) > > + return PTR_ERR(qrtc->rtc); > > + > > + err = devm_request_irq(&pdev->dev, qrtc->irq, goldfish_rtc_interrupt, > > + 0, pdev->name, qrtc); > > + if (err) > > + return err; > > Ditto. Kind regards, Miodrag ________________________________________ From: Alexandre Belloni [alexandre.belloni@xxxxxxxxxxxxxxxxxx] Sent: Wednesday, July 05, 2017 11:56 PM To: Aleksandar Markovic Cc: linux-mips@xxxxxxxxxxxxxx; Aleksandar Markovic; Miodrag Dinic; Goran Ferenc; Alessandro Zummo; David S. Miller; Douglas Leung; Greg Kroah-Hartman; James Hogan; linux-kernel@xxxxxxxxxxxxxxx; linux-rtc@xxxxxxxxxxxxxxx; Martin K. Petersen; Mauro Carvalho Chehab; Paul Burton; Petar Jovanovic; Raghu Gandham Subject: Re: [PATCH v2 02/10] MIPS: ranchu: Add Goldfish RTC driver Hi, The subject doesn't fit the subsystem style, this needs to be changed. On 28/06/2017 at 17:46:55 +0200, Aleksandar Markovic wrote: > From: Aleksandar Markovic <aleksandar.markovic@xxxxxxxxxx> > > Add device driver for a virtual Goldfish RTC clock. > > The driver can be built only if CONFIG_MIPS and CONFIG_GOLDFISH are > set. The compatible string used by OS for binding the driver is > defined as "google,goldfish-rtc". > Is it really MIPS specific? I would expect the same driver to work on the ARM based emulator too. > +config RTC_DRV_GOLDFISH > + tristate "Goldfish Real Time Clock" > + depends on MIPS > + depends on GOLDFISH This should be made buildable with COMPILE_TEST to extend coverage. > + help > + Say yes here to build support for the Goldfish RTC. Please, don't expect anybody to actually know what is goldfish can you add a sentence or two? > +static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id) > +{ > + struct goldfish_rtc *qrtc = dev_id; > + unsigned long events = 0; > + void __iomem *base = qrtc->base; > + > + writel(1, base + TIMER_CLEAR_INTERRUPT); > + events = RTC_IRQF | RTC_AF; > + > + rtc_update_irq(qrtc->rtc, 1, events); I'd say that events is not needed you can pass the flags directly to rtc_update_irq > +static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm) > +{ > + u64 time; > + u64 time_low; > + u64 time_high; > + u64 time_high_prev; > + > + struct goldfish_rtc *qrtc = > + platform_get_drvdata(to_platform_device(dev)); > + void __iomem *base = qrtc->base; > + > + time_high = readl(base + TIMER_TIME_HIGH); > + do { > + time_high_prev = time_high; > + time_low = readl(base + TIMER_TIME_LOW); > + time_high = readl(base + TIMER_TIME_HIGH); > + } while (time_high != time_high_prev); I'm not sure why you need that loop as the comments for TIMER_TIME_LOW and TIMER_TIME_HIGH indicate that TIMER_TIME_HIGH is latched when TIMER_TIME_LOW is read. Note that the original driver from google doesn't do that. > + time = (time_high << 32) | time_low; > + > + do_div(time, NSEC_PER_SEC); > + > + rtc_time_to_tm(time, tm); > + > + return 0; > +} > + > +static const struct rtc_class_ops goldfish_rtc_ops = { > + .read_time = goldfish_rtc_read_time, > +}; > + > +static int goldfish_rtc_probe(struct platform_device *pdev) > +{ > + struct resource *r; > + struct goldfish_rtc *qrtc; > + unsigned long rtc_dev_len; > + unsigned long rtc_dev_addr; > + int err; > + > + qrtc = devm_kzalloc(&pdev->dev, sizeof(*qrtc), GFP_KERNEL); > + if (qrtc == NULL) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, qrtc); > + > + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (r == NULL) > + return -ENODEV; > + > + rtc_dev_addr = r->start; > + rtc_dev_len = resource_size(r); > + qrtc->base = devm_ioremap(&pdev->dev, rtc_dev_addr, rtc_dev_len); devm_ioremap_resource ? > + if (IS_ERR(qrtc->base)) > + return -ENODEV; > + > + qrtc->irq = platform_get_irq(pdev, 0); > + if (qrtc->irq < 0) > + return -ENODEV; > + Is the irq so important that you have to fail here even if the driver doesn't support any alarm? > + qrtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, > + &goldfish_rtc_ops, THIS_MODULE); > + if (IS_ERR(qrtc->rtc)) > + return PTR_ERR(qrtc->rtc); > + > + err = devm_request_irq(&pdev->dev, qrtc->irq, goldfish_rtc_interrupt, > + 0, pdev->name, qrtc); > + if (err) > + return err; Ditto. -- Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com