1/*
2 * Copyright 2016, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(D61_BSD)
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <stdbool.h>
17#include <autoconf.h>
18#include <assert.h>
19#include <time.h>
20
21#include "device_timer.h"
22#include "state.h"
23#include <platsupport/timer.h>
24#include <platsupport/plat/timer.h>
25#include <refos-util/dprintf.h>
26#include <refos-util/device_io.h>
27
28/*! @file
29    @brief timer server timer device manager.
30
31    This module is responsible for managing the timer state. IT is a thin wrapper on top of the
32    timer device drivers provided by libplatsupport.
33
34    When a client wants to sleep for some amount of seconds, we use seL4_CNode_SaveCaller in order
35    to save its reply cap and reply to it when on the timer IRQ when its sleep period has expired.
36    The timer module sets up frequent periodic timer IRQs in order to do this.
37
38    This approach is relatively inefficient as it results in a lot of IRQs and wasted time
39    processing them. A better approach would be to set up one-shot IRQs at the exact time of the
40    next waking client, allowing less IRQ overhead and much better sleep accuracy. This may be
41    implemented in the near future, but for now spamming IRQs is a simple approach which works.
42*/
43
44/* ---------------------- Platform specific timer device definitions ---------------------------- */
45
46#if defined(PLAT_IMX31) || defined (PLAT_IMX6)
47
48    #define TIMER_PADDR GPT1_DEVICE_PADDR
49    #define TIMER_PERIODIC_MAX_SET false /* We don't explicitly set period for GPT. */
50    #define TIMER_PERIODIC_MAX (((1ULL << 32) / 66UL) * 1000UL)
51
52    #define TICK_TIMER_PADDR EPIT2_DEVICE_PADDR
53    #define TICK_TIMER_IRQ EPIT2_INTERRUPT
54    #define TICK_TIMER_PERIOD (2000000)
55    #define TICK_TIMER_SCALE_NS 1
56
57#elif defined(PLAT_AM335x)
58
59    #define TIMER_ID DMTIMER2
60    #define TICK_ID DMTIMER3
61    #define TIMER_PERIODIC_MAX_SET true
62    /* XXX am I doing this right? this is the largest period in nsec you can pass to the timer APIs */
63    #define TIMER_PERIODIC_MAX 178956970666  // ((((1UL << 32) / 24UL) * 1000UL) - 1)
64    #define TICK_TIMER_PERIOD (2000000)
65    #define TICK_TIMER_SCALE_NS 1
66
67#elif defined(PLAT_PC99)
68
69    /* PIT only needs IOPort operations. */
70    #define TIMER_PERIODIC_MAX_SET true
71    #define TIMER_PERIODIC_MAX 54925000
72
73    #define TICK_TIMER_PERIOD (2000000)
74    #define TICK_TIMER_SCALE_NS 1
75
76    #include <platsupport/plat/rtc.h>
77
78#else
79    #error "Unsupported platform."
80#endif
81
82/* ------------------------------------ Timer functions ----------------------------------------- */
83
84/* Forward declarations. We avoid including the whole state.h here due to errno.h definition
85   conflicts. */
86typedef void (*timeserv_irq_callback_fn_t)(void *cookie, uint32_t irq);
87int timeserv_handle_irq(uint32_t irq, timeserv_irq_callback_fn_t callback, void *cookie);
88void reply_data_write(void *rpc_userptr, int rpc___ret__);
89
90/*! @brief Look at sleeper list and reply to any sleppers that have had their time requirements
91           met.
92    @param s The timer global state structure.
93*/
94static void
95device_timer_update_sleepers(struct device_timer_state *s)
96{
97    uint64_t time = device_timer_get_time(s);
98
99    /* Loop through and find any fired waiters to reply to. */
100    int count = cvector_count(&s->waiterList);
101    for (int i = 0; i < count; i++) {
102        struct device_timer_waiter *waiter = (struct device_timer_waiter*)
103                cvector_get(&s->waiterList, i);
104        assert(waiter && waiter->magic == TIMESERV_DEVICE_TIMER_WAITER_MAGIC);
105        assert(waiter->reply && waiter->client);
106
107        if (waiter->time > time) {
108            /* Not yet. */
109            continue;
110        }
111
112        /* Reply to the waiter. */
113        waiter->client->rpcClient.skip_reply = false;
114        waiter->client->rpcClient.reply = waiter->reply;
115        reply_data_write((void*) waiter->client, sizeof(uint64_t));
116
117        /* Delete the saved reply cap, and free the structure. */
118        waiter->client->rpcClient.reply = 0;
119        csfree_delete(waiter->reply);
120        waiter->magic = 0x0;
121        free(waiter);
122
123        /* Remove the item from the waiter list. */
124        cvector_delete(&s->waiterList, i);
125        count = cvector_count(&s->waiterList);
126        i--;
127    }
128}
129
130/*! @brief Callback function to handle GPT timer IRQs.
131
132    GPT timer IRQs happen on GPT timer overflow. Note that the GPT device (used to get the actual
133    time) may actually be the excat same device as the waiting-list IRQ generator device, depending
134    on the platform.
135
136    @param cookie The global timer state (struct device_timer_state *).
137    @param irq The fired IRQ number.
138*/
139static void
140device_timer_handle_irq(void *cookie, uint32_t irq)
141{
142    struct device_timer_state *s = (struct device_timer_state *) cookie;
143    assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC);
144    assert(s->timerIRQPeriod > 0);
145    s->cumulativeTime += s->timerIRQPeriod;
146    timer_handle_irq(s->timerDev, irq);
147    device_timer_update_sleepers(s);
148}
149
150/*! @brief Callback function to handle waiter timer IRQs.
151
152    Waiter-list IRQs happen very frequently, as opposed to the GPT overflow IRQs. This is used to
153    wake up sleeping clients.
154
155    @param cookie The global timer state (struct device_timer_state *).
156    @param irq The fired IRQ number.
157*/
158static void
159device_tick_handle_irq(void *cookie, uint32_t irq)
160{
161    struct device_timer_state *s = (struct device_timer_state *) cookie;
162    assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC);
163    timer_handle_irq(s->tickDev, irq);
164    device_timer_update_sleepers(s);
165}
166
167static void
168device_timer_init_rtc(struct device_timer_state *s, dev_io_ops_t *io)
169{
170    assert(s && io);
171    s->cumulativeTime = 0;
172
173    #if defined(PLAT_PC99)
174
175    rtc_time_date_t rtcTimeDate;
176    int error = rtc_get_time_date_reg(&io->opsIO.io_port_ops, 0, &rtcTimeDate);
177    if (error) {
178        ROS_ERROR("Could not read RTC.");
179        return;
180    }
181
182    struct tm timeInfo = {0};
183    timeInfo.tm_sec = rtcTimeDate.second;
184    timeInfo.tm_min = rtcTimeDate.minute;
185    timeInfo.tm_hour = rtcTimeDate.hour;
186    timeInfo.tm_mday = rtcTimeDate.day;
187    timeInfo.tm_mon = rtcTimeDate.month - 1;
188    timeInfo.tm_year = rtcTimeDate.year - 1900;
189
190    time_t epochSeconds = mktime(&timeInfo);
191    s->cumulativeTime = (uint64_t) epochSeconds * 1000000000ULL;
192
193    #endif
194}
195
196void
197device_timer_init(struct device_timer_state *s, dev_io_ops_t *io)
198{
199    assert(s && io);
200    assert(!s->initialised);
201
202    s->magic = TIMESERV_DEVICE_TIMER_MAGIC;
203    s->io = io;
204    s->timerDev = NULL;
205
206#if defined(PLAT_IMX31) || defined (PLAT_IMX6)
207
208    /* Map the GPT (General Purpose Timer) device to use as the clock. */
209    gpt_config_t config;
210    config.vaddr = ps_io_map(&io->opsIO.io_mapper, TIMER_PADDR, 0x1000,
211                             false, PS_MEM_NORMAL);
212    config.prescaler = 0;
213    if (!config.vaddr) {
214        ROS_ERROR("Could not map timer device.");
215        assert(!"Could not map timer device.");
216        return;
217    }
218
219    /* Get timer interface from given GPT device. */
220    s->timerDev = gpt_get_timer(&config);
221
222    /* Map the EPIT device to use as the tick source. */
223    epit_config_t econfig;
224    econfig.vaddr = ps_io_map(&io->opsIO.io_mapper, TICK_TIMER_PADDR, 0x1000,
225                             false, PS_MEM_NORMAL);
226    econfig.prescaler = 0;
227    econfig.irq = TICK_TIMER_IRQ;
228    if (!econfig.vaddr) {
229        ROS_ERROR("Could not map tick timer device.");
230        assert(!"Could not map tick timer device.");
231        return;
232    }
233
234    /* Get the timer interface from EPIT device. */
235    s->tickDev = epit_get_timer(&econfig);
236
237#elif defined(PLAT_AM335x)
238
239    timer_config_t config;
240    config.vaddr = ps_io_map(&io->opsIO.io_mapper, dm_timer_paddrs[TIMER_ID],
241                             0x1000, false, PS_MEM_NORMAL);
242    config.irq = dm_timer_irqs[TIMER_ID];
243    if (!config.vaddr) {
244        ROS_ERROR("Could not map timer device.");
245        assert(!"Could not map timer device.");
246        return;
247    }
248    s->timerDev = ps_get_timer(TIMER_ID, &config);
249
250    config.vaddr = ps_io_map(&io->opsIO.io_mapper, dm_timer_paddrs[TICK_ID],
251                             0x1000, false, PS_MEM_NORMAL);
252    config.irq = dm_timer_irqs[TICK_ID];
253    if (!config.vaddr) {
254        ROS_ERROR("Could not map tick timer device.");
255        assert(!"Could not map tick timer device.");
256        return;
257    }
258    s->tickDev = ps_get_timer(TICK_ID, &config);
259
260#elif defined(PLAT_PC99)
261
262    s->timerDev = pit_get_timer(&io->opsIO.io_port_ops);
263    s->tickDev = s->timerDev;
264
265#endif
266
267    if (!s->timerDev) {
268        ROS_ERROR("Could not initialise timer.");
269        return;
270    }
271
272    /* Set up to recieve timer IRQs. */
273    for (uint32_t i = 0; i < s->timerDev->properties.irqs; i++) {
274        int irq = timer_get_nth_irq(s->timerDev, i);
275        int error = dev_handle_irq(&timeServ.irqState, irq, device_timer_handle_irq, (void*) s);
276        assert(!error);
277        (void) error;
278    }
279
280    /* Set up to recieve tick timer IRQs. */
281    if (s->tickDev != NULL && s->tickDev != s->timerDev) {
282        for (uint32_t i = 0; i < s->tickDev->properties.irqs; i++) {
283            int irq = timer_get_nth_irq(s->tickDev, i);
284            int error = dev_handle_irq(&timeServ.irqState, irq, device_tick_handle_irq, (void*) s);
285            assert(!error);
286            (void) error;
287        }
288
289        int error = timer_start(s->tickDev);
290        if (error) {
291            ROS_ERROR("Could not start tick timer.");
292            assert(!"Tick timer initialise but could not start.");
293            return;
294        }
295    }
296
297    /* Read the RTC. */
298    device_timer_init_rtc(s, io);
299
300    /* Start the timer. */
301    int error = timer_start(s->timerDev);
302    if (error) {
303        ROS_ERROR("Could not start timer.");
304        assert(!"Timer initialise but could not start.");
305        return;
306    }
307
308    #if TIMER_PERIODIC_MAX_SET
309    /* Set the timer for periodic overflow interrupts. */
310    error = timer_periodic(s->timerDev, TIMER_PERIODIC_MAX);
311    if (error) {
312        ROS_ERROR("Could not configure periodic timer.");
313        assert(!"Could not set periodic timer.");
314        return;
315    }
316    #endif
317    s->timerIRQPeriod = TIMER_PERIODIC_MAX;
318
319    /* Set the tick timer for realy fast periodic ticks. Rather crude way of implementing sleep()
320       functionality but works. In the future this should be improved
321       (see module description above).
322    */
323    if (s->tickDev != NULL) {
324        error = timer_periodic(s->tickDev, TICK_TIMER_PERIOD);
325        if (error) {
326            ROS_WARNING("Could not set periodic tick timer.");
327            assert(!"Could not set periodic tick timer.");
328        }
329        if (s->tickDev == s->timerDev) {
330            s->timerIRQPeriod = TICK_TIMER_PERIOD;
331        }
332    }
333
334    /* Initialise the sleep timer waiter list. */
335    cvector_init(&s->waiterList);
336
337    s->initialised = true;
338}
339
340uint64_t
341device_timer_get_time(struct device_timer_state *s)
342{
343    assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC);
344    uint64_t time = timer_get_time(s->timerDev);
345    if (!s->timerDev->properties.upcounter) {
346        /* This is a downcounter timer. Invert the time. */
347        assert(time <= s->timerIRQPeriod);
348        time = s->timerIRQPeriod - time;
349    }
350    time += s->cumulativeTime;
351    return time * TICK_TIMER_SCALE_NS;
352}
353
354int
355device_timer_save_caller_as_waiter(struct device_timer_state *s, struct srv_client *c,
356                                   uint64_t waitTime)
357{
358    assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC);
359    assert(c && c->magic == TIMESERV_CLIENT_MAGIC);
360    int error = EINVALID;
361
362    /* Allocate and fill out waiter structure. */
363    struct device_timer_waiter *waiter = malloc(sizeof(struct device_timer_waiter));
364    if (!waiter) {
365        ROS_ERROR("device_timer_save_caller_as_waiter failed to alloc waiter struct.");
366        return ENOMEM;
367    }
368    waiter->magic = TIMESERV_DEVICE_TIMER_WAITER_MAGIC;
369    waiter->client = c;
370    waiter->time = (waitTime / TICK_TIMER_SCALE_NS) + device_timer_get_time(s);
371
372    /* Allocate a cslot to save the reply cap into. */
373    waiter->reply = csalloc();
374    if (!waiter->reply) {
375        ROS_ERROR("device_timer_save_caller_as_waiter failed to alloc cslot.");
376        error = ENOMEM;
377        goto exit1;
378    }
379
380    /* Save current caller into the reply cap. */
381    error = seL4_CNode_SaveCaller(REFOS_CSPACE, waiter->reply, REFOS_CDEPTH);
382    if (error != seL4_NoError) {
383        ROS_ERROR("device_timer_save_caller_as_waiter failed to save caller.");
384        error = EINVALID;
385        goto exit2;
386    }
387
388    /* Add to waiter list. (Takes ownership) */
389    cvector_add(&s->waiterList, (cvector_item_t) waiter);
390
391    return ESUCCESS;
392
393    /* Exit stack. */
394exit2:
395    csfree(waiter->reply);
396exit1:
397    waiter->magic = 0;
398    free(waiter);
399    return error;
400}
401
402void
403device_timer_purge_client(struct device_timer_state *client)
404{
405    assert(!"not implemented.");
406}
407