preempt-rt amd uClibc

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi everybody!

I downloaded the newest uClinux dist a while ago and compiled it with 2.6.33 kernel and the 2.6.33.7.2-rt30 patch applied.
Then i by hand implemeted an old patch for arm lpc22xx machine (ARMv4T), since i am running a lpc2478 board from embedded artists.
I had to implement a clockevent/source timer to add hrtimer support. I compiled it all with uClibc since it as a NOMMU system.

Now i have some questions:
Is it possible to run the preempt-rt patch with the uClinux distribution and uClibc?
I read a few times that if doesnt support PI mutexes, but arent those RT mutexes part of the kernel?

I have the problem that my clockevent subsystem runs with a 72MHz timer, which is also the CPU clock speed.
I calculated my .shift and .mult with \"clockevents_calc_mult_shift\" and my /proc/timer_list tells me it shift =32
and mult = 309237645 (i have no idea what these values are good for):


cat timer_list
Timer List Version: v0.5
HRTIMER_MAX_CLOCK_BASES: 2
now at 1282856491072 nsecs

cpu: 0
 clock 0:
  .base:       a02e63fc
  .index:      0
  .resolution: 1 nsecs
  .get_time:   ktime_get_real
  .offset:     17704160842103256530 nsecs
active timers:
 clock 1:
  .base:       a02e6430
  .index:      1
  .resolution: 1 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: per_cpu__tick_cpu_sched, tick_sched_timer, S:01, hrtimer_start_range_ns, sirq-timer/0/4
 # expires at 1282860000000-1282860000000 nsecs [in 3508928 to 3508928 nsecs]
 #1: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
 # expires at 1283000000000-1283000000000 nsecs [in 143508928 to 143508928 nsecs]
 #2: , hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
 # expires at 1283031816781-1283032816699 nsecs [in 175325709 to 176325627 nsecs]
  .expires_next   : 1282870000000 nsecs
  .hres_active    : 1
  .nr_events      : 129341
  .nr_retries     : 1
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 0 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 0 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 98286


Tick Device: mode:     1
Per CPU device: 0
Clock Event Device: pit
 max_delta_ns:   59652323587
 min_delta_ns:   50000
 mult:           309237645
 shift:          32
 mode:           3
 next_event:     1282870000000 nsecs
 set_next_event: lpc22xx_next_event
 set_mode:       pit_clkevt_mode
 event_handler:  hrtimer_interrupt


However when i run \"cyclictest -t1 -p 80 -n -i 10000 -l 1000\"
i get following results
T: 0 (  254) P:80 I:10000 C:   1000 Min:    464 Act:  712 Avg:  568 Max:     881

for the interval timers (cyclictest -t1 -p 80 -i 10000 -l 1000) i am getting totally different horrible results,
which seem to widely defere from run to run (sleep_nanoseconds seem to be more or less constant) :
T: 0 (  257) P:80 I:10000 C:   1000 Min:   3658 Act: 3784 Avg: 4460 Max:   55211

and for multiple threads i can see no ordering after the priorities (cyclictest -t5 -p 80 -i 10000 -l 1000):
policy: fifo: loadavg: 0.18 0.06 0.01 1/48 270          0 Avg:  955 Max:    3747
T: 2 (  268) P:78 I:11000 C:    885 Min:    483 Act:  652 Avg:  838 Max:    2941
T: 0 (  266) P:80 I:10000 C:    985 Min:    473 Act:  525 Avg:  619 Max:    1549
T: 3 (  269) P:77 I:11500 C:    846 Min:    483 Act: 1176 Avg:  907 Max:    3079
T: 1 (  267) P:79 I:10500 C:    938 Min:    484 Act:  555 Avg:  746 Max:    2153

Anyone has an idea if it is due to a wrong clockevent/source implementation or has something to do with PI mutexes or my processor is two weak?
Please, any suggestions would be highly appreciated.

Kind Regards
Johannes Bauer

Heres my clocksource/event implementation:

/*
 *  linux/arch/arm/mach-lpc22xx/time.c
 *
 *  Copyright (C) 2004 Philips Semiconductors
 */

#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
//#include
#include
#include


extern void    lpc22xx_unmask_irq(unsigned int);

/*
 * TODO: We should be using the clk.h interface instead.
 */

static unsigned int lpc2xxx_fcclk = 0;
static unsigned int lpc2xxx_fpclk = 0;

unsigned int lpc_get_fcclk(void)
{
    return lpc2xxx_fcclk;
}
EXPORT_SYMBOL(lpc_get_fcclk);

unsigned int lpc_get_fpclk(void)
{
    return lpc2xxx_fpclk;
}
EXPORT_SYMBOL(lpc_get_fpclk);

static int lpc22xx_next_event(unsigned long delta,
                    struct clock_event_device *dev)
{
   
    BUG_ON(delta == 0);

    T0TCR = 0;    //disabel timer0
    T0TCR = 0x02;    //reset timer0
    T0IR = 0x01;    //clear interrupt flag
    T0TCR = 0x01;    //enable timer0
    T0MR0 = delta;    //set match register to delta
   
    return 0;
}

static cycle_t read_pit_clk(struct clocksource *cs)
{
    unsigned long elapsed;
    unsigned long flags;

    elapsed = T1TC;            // return timer1 counter value

    return (cycle_t) elapsed;    // returns the actual timer count
}

static struct clocksource pit_clk = {
    .name        = \"pit\",
    .rating        = 175,
    .read        = read_pit_clk,
    .shift        = 28,    //is changed by init code
    .flags        = CLOCK_SOURCE_IS_CONTINUOUS,
};

static void
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
    switch (mode) {
    case CLOCK_EVT_MODE_PERIODIC:
        /* update clocksource counter */
        printk(\"periodic\\n\");
        T0TCR = 0;        //disable timer0       
        T0TCR = 0x02;        //reset timer0
        T0MCR = 0x03;        //interrupt on compare match and counter reset on compare match
        T0PR = 0;        //no prescaler (72MHz)
        T0MR0 = 720000;        //fire interrupt after 10ms (100Hz)
        T0TCR = 1;        //enable timer
       
        break;
    case CLOCK_EVT_MODE_ONESHOT:
        printk(\"oneshot\\n\");
        T0TCR = 0;        //disabel timer0
        T0TCR = 0x02;        //reset timer0
        T0MCR = 0x03;        //interrupt on compare match and counter reset on compare match
        T0PR = 0;        //no prescaler (72MHz)
        T0MR0 = 0xFFFFFFFF;    //fire interrupts some time in the future (set_next_event should do it before)

        break;
        /* FALLTHROUGH */
    case CLOCK_EVT_MODE_SHUTDOWN:
        printk(\"shutdown\\n\");
        T0TCR &= ~0x01;        // disable timer
        break;
    case CLOCK_EVT_MODE_UNUSED:
        printk(\"unused\\n\");
        /* disable irq, leaving the clocksource active */
        T0MCR &= ~0x01;        //disable interrupt
        break;
    case CLOCK_EVT_MODE_RESUME:
        printk(\"resume\\n\");
        break;
    }
}

static struct clock_event_device pit_clkevt = {
    .name        = \"pit\",
    .features    = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
    .shift        = 20,    //is changed by init function
    .rating        = 100,    //dont know yet
    .set_mode    = pit_clkevt_mode,
    .set_next_event = lpc22xx_next_event,
};


static irqreturn_t
lpc2xxx_timer_interrupt(int irq, void *dev_id)
{

    pit_clkevt.event_handler(&pit_clkevt);    //handle_event   
    T0IR |= 0x01;    /* reset MR0 interrupt */
   
    return IRQ_HANDLED;
}

static struct irqaction lpc2xxx_timer_irq = {
        .name           = \"lpc2xxx-tick\",
    .flags        = IRQF_DISABLED | IRQF_TIMER,
        .handler        = lpc2xxx_timer_interrupt
};

/*
 * Set up timer interrupt, and return the current time in seconds.
 */
/*
 Timer0 used as periodic or oneshot clockevent
 Timer1 used as clocksource for reading continous time
*/
void __init  lpc2xxx_time_init (void)
{
    unsigned char clkSel = 0;
    unsigned long stat = PLLSTAT;
    unsigned long M = stat & 0x7FFFF;
    unsigned long N = (stat>>16) & 0xFF;
    unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
    unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
    lpc2xxx_fcclk = Fcclk;
    lpc2xxx_fpclk = Fcclk;

    /*
       * Here we assume that the clock is the same for all peripherals
      * which of course doesn\'t have to be the case.
     * We should be using the clk.h interface instead.
     */
   
    clkSel = (unsigned char)(PCLKSEL0 & 0xff);
    if (clkSel == 0x00)
        lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
    else if (clkSel == 0x55)
        lpc2xxx_fpclk = lpc2xxx_fcclk;
    else if (clkSel == 0xAA)
        lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
    else if (clkSel == 0xFF)
        lpc2xxx_fpclk = lpc2xxx_fcclk / 8;

    printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
        CONFIG_LPC22xx_Fosc,
        Fcco,
        M,
        N);
    PCLKSEL0 &= ~(3 < <2);
    PCLKSEL0 |=  (1 < <2);
    PCLKSEL0 |=  (1 < <4);
    printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
        Fcclk, PCLKSEL0, PCLKSEL1);
    /*
     * disable and clear timer 0, set to
     */
    T1TCR &= ~0x01;    //disable timer1
    T0TCR &= ~0x01;    //disable timer1
    /* initialize the timer period and prescaler */

    T0PR = 0;    //no prescaler (72Mhz)
    T1PR = 0;    //no prescaler (72Mhz)
    T1MCR = 0x0;    //no interrupt for timer1

    lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;

    /* set up the interrupt vevtor for timer 0 match */
    setup_irq(LPC2xxx_INTERRUPT_TIMER0, &lpc2xxx_timer_irq);
   
    /* enable the timer IRQ */
    lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);

    clocksource_calc_mult_shift(&pit_clk,Fcclk,4);    // minsecvalue = 4 no idea why (seen in other codes)

    pit_clk.mask = CLOCKSOURCE_MASK(32);                // mask is 32 bit so the clk subsystem knows where it overruns
    clocksource_register(&pit_clk);

    clockevents_calc_mult_shift(&pit_clkevt,(Fcclk),4);    // minsecvalue = 4 no idea why (seen in other codes)
    pit_clkevt.max_delta_ns =
        clockevent_delta2ns((u32)0xfffffffe, &pit_clkevt);    //close to max (maybe not necessary
    printk(\"Max Delta: %llu\\n\",clockevent_delta2ns((u32)0xfffffffe, &pit_clkevt));   
    pit_clkevt.min_delta_ns =
        clockevent_delta2ns(0xE10, &pit_clkevt);        // min delta is 50us (i dont know what should be taken here???!!)
    printk(\"Min Delta: %llu\\n\",clockevent_delta2ns(0xE10, &pit_clkevt));    //50us?
    pit_clkevt.cpumask = cpumask_of(0);        // uniprocessro system
    clockevents_register_device(&pit_clkevt);

    T0MR0 = 720000;                   
    T1MR0 = 0xFFFFFFFF;               
    /* let timer 0 run... */
    T1IR = 0x01; /* reset MR0 interrupt*/
    T1TCR = 0x02;    /* Reset timer count and prescale counter */
    T1TCR = 0x01;    /* enable timer counter and prescale counter */
        /* let timer 0 run... */
    T0IR = 0x01; /* reset MR0 interrupt*/
    T0TCR = 0x02;    /* Reset timer count and prescale counter */
    T0TCR = 0x01;    /* enable timer counter and prescale counter */
}

struct sys_timer lpc22xx_timer = {
    .init        = lpc2xxx_time_init,
};



--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux