All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
To: Roberto Bielli <roberto.bielli@domain.hid>
Cc: xenomai@xenomai.org
Subject: Re: [Xenomai-core] preemptive doesn't work
Date: Tue, 10 Apr 2012 11:37:13 +0200	[thread overview]
Message-ID: <4F83FF49.90608@domain.hid> (raw)
In-Reply-To: <4F83FBAB.7040301@domain.hid>

[-- Attachment #1: Type: text/plain, Size: 246 bytes --]

On 04/10/2012 11:21 AM, Roberto Bielli wrote:
> Hi Gilles,
> 
> here is my time.c

Though you have not made all the changes I suggested. Here is the time.c
I would use.

-- 
                                                                Gilles.

[-- Attachment #2: time.c --]
[-- Type: text/x-csrc, Size: 12926 bytes --]

/*
 *  linux/arch/arm/plat-mxc/time.c
 *
 *  Copyright (C) 2000-2001 Deep Blue Solutions
 *  Copyright (C) 2002 Shane Nay (shane@domain.hid)
 *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@domain.hid)
 *  Copyright (C) 2008 Juergen Beisert (kernel@domain.hid)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>

#include <mach/hardware.h>
#include <asm/mach/time.h>
#include <mach/common.h>

/* defines common for all i.MX */
#define MXC_TCTL		0x00
#define MXC_TCTL_TEN		(1 << 0)
#define MXC_TPRER		0x04

/* MX1, MX21, MX27 */
#define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
#define MX1_2_TCTL_IRQEN	(1 << 4)
#define MX1_2_TCTL_FRR		(1 << 8)
#define MX1_2_TCMP		0x08
#define MX1_2_TCN		0x10
#define MX1_2_TSTAT		0x14

/* MX21, MX27 */
#define MX2_TSTAT_CAPT		(1 << 1)
#define MX2_TSTAT_COMP		(1 << 0)

/* MX31, MX35, MX25 */
#define MX3_TCTL_WAITEN		(1 << 3)
#define MX3_TCTL_CLK_IPG	(1 << 6)
#define MX3_TCTL_CLK_PER	(2 << 6)
#define MX3_TCTL_FRR		(1 << 9)
#define MX3_IR			0x0c
#define MX3_TSTAT		0x08
#define MX3_TSTAT_OF1		(1 << 0)
#define MX3_TCN			0x24
#define MX3_TCMP		0x10

#ifdef CONFIG_IPIPE
#ifdef CONFIG_NO_IDLE_HZ
#error "dynamic tick timer not yet supported with IPIPE"
#endif /* CONFIG_NO_IDLE_HZ */
int __ipipe_mach_timerint;
EXPORT_SYMBOL(__ipipe_mach_timerint);

int __ipipe_mach_timerstolen = 0;
EXPORT_SYMBOL(__ipipe_mach_timerstolen);

unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);

static int mxc_timer_initialized;
static unsigned mxc_min_delay;

union tsc_reg {
#ifdef __BIG_ENDIAN
	struct {
		unsigned long high;
		unsigned long low;
	};
#else /* __LITTLE_ENDIAN */
	struct {
		unsigned long low;
		unsigned long high;
	};
#endif /* __LITTLE_ENDIAN */
	unsigned long long full;
};

#ifdef CONFIG_SMP
static union tsc_reg tsc[NR_CPUS];

void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
	info->type = IPIPE_TSC_TYPE_NONE;
}

#else /* !CONFIG_SMP */
static union tsc_reg *tsc;

void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
	info->type = IPIPE_TSC_TYPE_FREERUNNING;
	if (cpu_is_mx1()) {
#ifdef CONFIG_ARCH_MX1
		info->u.fr.counter = (unsigned *) (TIM1_BASE_ADDR + MX1_2_TCN);
#endif
	} else if (cpu_is_mx2()) {
#ifdef CONFIG_ARCH_MX2
		info->u.fr.counter = (unsigned *) (GPT1_BASE_ADDR + MX1_2_TCN);
#endif
	} else if (cpu_is_mx3() || cpu_is_mx25() ) {
#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX25
		info->u.fr.counter = (unsigned *) (GPT1_BASE_ADDR + MX3_TCN);
#endif
	}
	info->u.fr.mask = 0xffffffff;
	info->u.fr.tsc = &tsc->full;
}
#endif /* !CONFIG_SMP */

static void ipipe_mach_update_tsc(void);
#endif /* CONFIG_IPIPE */

#define timer_is_v2()	(cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx5())

static struct clock_event_device clockevent_mxc;
static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;

static void __iomem *timer_base;

static inline void gpt_irq_disable(void)
{
	unsigned int tmp;

	if (timer_is_v2())
		__raw_writel(0, timer_base + MX3_IR);
	else {
		tmp = __raw_readl(timer_base + MXC_TCTL);
		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
	}
}

static inline void gpt_irq_enable(void)
{
	if (timer_is_v2())
		__raw_writel(1<<0, timer_base + MX3_IR);
	else {
		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
			timer_base + MXC_TCTL);
	}
}

static void gpt_irq_acknowledge(void)
{
	if (!timer_is_v2()) {
		if (cpu_is_mx1())
			__raw_writel(0, timer_base + MX1_2_TSTAT);
		else
			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT);
	} else
		__raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
}

static cycle_t timer_v1_get_cycles(struct clocksource *cs)
{
	return __raw_readl(timer_base + MX1_2_TCN);
}

static cycle_t timer_v2_get_cycles(struct clocksource *cs)
{
	return __raw_readl(timer_base + MX3_TCN);
}

static struct clocksource clocksource_mxc = {
	.name		= "mxc_timer1",
	.rating		= 200,
	.read		= timer_v1_get_cycles,
	.mask		= CLOCKSOURCE_MASK(32),
	.shift		= 20,
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

static int __init mxc_clocksource_init(struct clk *timer_clk)
{
	unsigned int c = clk_get_rate(timer_clk);

	if (timer_is_v2())
		clocksource_mxc.read = timer_v2_get_cycles;

#ifdef CONFIG_IPIPE
	__ipipe_mach_ticks_per_jiffy = (c + HZ/2) / HZ;
#endif /* CONFIG_IPIPE */
	clocksource_mxc.mult = clocksource_hz2mult(c,
					clocksource_mxc.shift);
	clocksource_register(&clocksource_mxc);

	return 0;
}

/* clock event */

static int timer_v1_set_next_event(unsigned long evt,
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;

	__raw_writel(tcmp, timer_base + MX1_2_TCMP);

	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
				-ETIME : 0;
}

static int timer_v2_set_next_event(unsigned long evt,
			      struct clock_event_device *unused)
{
	unsigned long tcmp;

	tcmp = __raw_readl(timer_base + MX3_TCN) + evt;

	__raw_writel(tcmp, timer_base + MX3_TCMP);

	return (int)(tcmp - __raw_readl(timer_base + MX3_TCN)) < 0 ? -ETIME : 0;
}

#ifdef DEBUG
static inline const char *clock_event_mode_label(enum clock_event_mode mode)
{
	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		return "CLOCK_EVT_MODE_PERIODIC";
	case CLOCK_EVT_MODE_ONESHOT:
		return "CLOCK_EVT_MODE_ONESHOT";
	case CLOCK_EVT_MODE_SHUTDOWN:
		return "CLOCK_EVT_MODE_SHUTDOWN";
	case CLOCK_EVT_MODE_UNUSED:
		return "CLOCK_EVT_MODE_UNUSED";
	case CLOCK_EVT_MODE_RESUME:
		return "CLOCK_EVT_MODE_RESUME";
	}
	return "UNKNOWN";
};
#endif /* DEBUG */

static void mxc_set_mode(enum clock_event_mode mode,
				struct clock_event_device *evt)
{
	unsigned long flags;

	/*
	 * The timer interrupt generation is disabled at least
	 * for enough time to call mxc_set_next_event()
	 */
	local_irq_save(flags);

	/* Disable interrupt in GPT module */
	gpt_irq_disable();

	if (mode != clockevent_mode) {
		/* Set event time into far-far future */
		if (timer_is_v2())
			__raw_writel(__raw_readl(timer_base + MX3_TCN) - 3,
					timer_base + MX3_TCMP);
		else
			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
					timer_base + MX1_2_TCMP);

		/* Clear pending interrupt */
		gpt_irq_acknowledge();
	}

#ifdef DEBUG
	printk(KERN_INFO "mxc_set_mode: changing mode from %s[%d] to %s[%d]\n",
		clock_event_mode_label(clockevent_mode), clockevent_mode,
		clock_event_mode_label(mode), mode);
#endif /* DEBUG */

	/* Remember timer mode */
	clockevent_mode = mode;
	local_irq_restore(flags);
	switch (mode)
	{
	case CLOCK_EVT_MODE_PERIODIC:
		printk(KERN_ERR "mxc_set_mode: Periodic mode is not supported for i.MX\n");
		break;
	case CLOCK_EVT_MODE_ONESHOT:
	/*
	 * Do not put overhead of interrupt enable/disable into
	 * mxc_set_next_event(), the core has about 4 minutes
	 * to call mxc_set_next_event() or shutdown clock after
	 * mode switching
	 */
		local_irq_save(flags);
		gpt_irq_enable();
		local_irq_restore(flags);
		break;
	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
	case CLOCK_EVT_MODE_RESUME:
		/* Left event sources disabled, no more interrupts appear */
		break;
	}
}

/*
 * IRQ handler for the timer
 */
static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = &clockevent_mxc;
	uint32_t tstat;
	unsigned long reg;

#ifndef CONFIG_IPIPE
	if (timer_is_v2())
		tstat = __raw_readl(timer_base + MX3_TSTAT);
	else
		tstat = __raw_readl(timer_base + MX1_2_TSTAT);

	gpt_irq_acknowledge();
#else /* !CONFIG_IPIPE */

	ipipe_mach_update_tsc();

#endif /* !CONFIG_IPIPE */

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static struct irqaction mxc_timer_irq = {
	.name		= "i.MX Timer Tick",
	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
	.handler	= mxc_timer_interrupt,
};

static struct clock_event_device clockevent_mxc = {
	.name		= "mxc_timer1",
	.features	= CLOCK_EVT_FEAT_ONESHOT,
	.shift		= 32,
	.set_mode	= mxc_set_mode,
	.set_next_event	= timer_v1_set_next_event,
	.rating		= 200,
};

static int __init mxc_clockevent_init(struct clk *timer_clk)
{
	unsigned long c = clk_get_rate(timer_clk);

	printk(KERN_DEBUG "%s: timer clk rate is %lu.%03luMHz\n", __FUNCTION__,
		c / 1000000, c / 1000 % 1000);

	if (timer_is_v2())
		clockevent_mxc.set_next_event = timer_v2_set_next_event;

	clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
					clockevent_mxc.shift);
	clockevent_mxc.max_delta_ns =
			clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
	clockevent_mxc.min_delta_ns =
			clockevent_delta2ns(0xff, &clockevent_mxc);

	clockevent_mxc.cpumask = cpumask_of(0);

	clockevents_register_device(&clockevent_mxc);

	return 0;
}

void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
{
	uint32_t tctl_val;

	clk_enable(timer_clk);

	timer_base = base;

	/*
	 * Initialise to a known state (all timers off, and timing reset)
	 */

	__raw_writel(0, timer_base + MXC_TCTL);
	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */

	if (timer_is_v2())
		tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN;
	else
		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;

	__raw_writel(tctl_val, timer_base + MXC_TCTL);

	/* init and register the timer to the framework */
	mxc_clocksource_init(timer_clk);
	mxc_clockevent_init(timer_clk);

	/* Make irqs happen */
	setup_irq(irq, &mxc_timer_irq);

#ifdef CONFIG_IPIPE
	__ipipe_mach_timerint = irq;
#ifndef CONFIG_SMP
	tsc = (union tsc_reg *) __ipipe_tsc_area;
	barrier();
#endif /* CONFIG_SMP */

	mxc_min_delay = 2 * ((ipipe_cpu_freq() + 500000) / 1000000) ?: 1;
	if (mxc_min_delay == 0)
	{
		mxc_min_delay = 1;
	}

	printk(  KERN_INFO "mxc_min_delay = %d\n", mxc_min_delay );
	mxc_timer_initialized = 1;
#endif /* CONFIG_IPIPE */
}

#ifdef CONFIG_IPIPE
int __ipipe_check_tickdev(const char *devname)
{
	return !strcmp(devname, clockevent_mxc.name);
}

void __ipipe_mach_acktimer(void)
{
	uint32_t tstat;

	if (timer_is_v2())
		tstat = __raw_readl(timer_base + MX3_TSTAT);
	else
		tstat = __raw_readl(timer_base + MX1_2_TSTAT);

	gpt_irq_acknowledge();
}

static void ipipe_mach_update_tsc(void)
{
	union tsc_reg *local_tsc;
	unsigned long stamp, flags;

	local_irq_save_hw(flags);
	local_tsc = &tsc[ipipe_processor_id()];
	if (!timer_is_v2())
		stamp = __raw_readl(timer_base + MX1_2_TCN);
	else
		stamp = __raw_readl(timer_base + MX3_TCN);
	if (unlikely(stamp < local_tsc->low))
		/* 32 bit counter wrapped, increment high word. */
		local_tsc->high++;
	local_tsc->low = stamp;
	local_irq_restore_hw(flags);
}

notrace unsigned long long __ipipe_mach_get_tsc(void)
{
	if (likely(mxc_timer_initialized)) {
		union tsc_reg *local_tsc, result;
		unsigned long stamp;

		local_tsc = &tsc[ipipe_processor_id()];

		if (!timer_is_v2())  {
			__asm__ ("ldmia %1, %M0\n"
				 : "=r"(result.full), "+&r"(local_tsc)
				 : "m"(*local_tsc));
			barrier();
			stamp = __raw_readl(timer_base + MX1_2_TCN);
		} else {
			__asm__ ("ldmia %1, %M0\n"
				 : "=r"(result.full), "+&r"(local_tsc)
				 : "m"(*local_tsc));
			barrier();
			stamp = __raw_readl(timer_base + MX3_TCN);
		}
		if (unlikely(stamp < result.low))
			/* 32 bit counter wrapped, increment high word. */
			result.high++;
		result.low = stamp;

		return result.full;
	}

	return 0;
}
EXPORT_SYMBOL(__ipipe_mach_get_tsc);

/*
 * Reprogram the timer
 */

void __ipipe_mach_set_dec(unsigned long delay)
{
	if (delay > mxc_min_delay) {
		unsigned long flags;

		local_irq_save_hw(flags);
		if (!time_is_v2())
			timer_v1_set_next_event(delay, NULL);
		else
			timer_v2_set_next_event(delay, NULL);
		local_irq_restore_hw(flags);
	} else
		ipipe_trigger_irq(__ipipe_mach_timerint);
}
EXPORT_SYMBOL(__ipipe_mach_set_dec);

void __ipipe_mach_release_timer(void)
{
	mxc_set_mode(clockevent_mxc.mode, &clockevent_mxc);
	if (clockevent_mxc.mode == CLOCK_EVT_MODE_ONESHOT)
		clockevent_mxc.set_next_event(LATCH, &clockevent_mxc);
}
EXPORT_SYMBOL(__ipipe_mach_release_timer);

unsigned long __ipipe_mach_get_dec(void)
{
	if (!time_is_v2())
		return __raw_readl(timer_base + MX1_2_TCMP)
			- __raw_readl(timer_base + MX1_2_TCN);
	else
		return __raw_readl(timer_base + MX3_TCMP)
			- __raw_readl(timer_base + MX3_TCN);
}
#endif /* CONFIG_IPIPE */

  parent reply	other threads:[~2012-04-10  9:37 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-02 10:42 [Xenomai-core] Xenomai server down Gilles Chanteperdrix
2012-03-06  7:55 ` [Xenomai-core] preemptive doesn't work Roberto Bielli
2012-03-06  9:22   ` Gilles Chanteperdrix
     [not found]     ` <4F55E390.8090706@domain.hid>
2012-03-06 12:09       ` [Xenomai-help] " Gilles Chanteperdrix
2012-03-06 13:00         ` Roberto Bielli
2012-03-06 13:04           ` Gilles Chanteperdrix
2012-03-06 15:14             ` Roberto Bielli
2012-03-06 15:20               ` Gilles Chanteperdrix
2012-03-06 15:35                 ` Roberto Bielli
2012-03-06 16:16                   ` Gilles Chanteperdrix
2012-03-07 12:59                     ` Roberto Bielli
2012-03-07 13:44                       ` Gilles Chanteperdrix
2012-03-07 18:13                         ` Roberto Bielli
2012-03-13 10:45                           ` [Xenomai-core] Fwd: " Roberto Bielli
2012-03-13 11:44                           ` [Xenomai-core] " Gilles Chanteperdrix
2012-03-13 12:10                             ` Gilles Chanteperdrix
2012-04-04  9:21                           ` Gilles Chanteperdrix
2012-04-04  9:29                             ` Roberto Bielli
2012-04-04  9:45                               ` Gilles Chanteperdrix
2012-04-06 15:35                                 ` Roberto Bielli
2012-04-06 15:40                                   ` Gilles Chanteperdrix
2012-04-06 16:59                                     ` Roberto Bielli
2012-04-07 22:17                                       ` Gilles Chanteperdrix
2012-04-10  8:18                                         ` Roberto Bielli
2012-04-10  8:22                                           ` Gilles Chanteperdrix
2012-04-10  8:43                                         ` Roberto Bielli
2012-04-10  8:45                                           ` Gilles Chanteperdrix
2012-04-10  8:58                                             ` Roberto Bielli
2012-04-10  9:00                                               ` Gilles Chanteperdrix
2012-04-10  9:06                                               ` Gilles Chanteperdrix
2012-04-10  9:11                                                 ` Gilles Chanteperdrix
2012-04-10  9:21                                                   ` Roberto Bielli
2012-04-10  9:27                                                     ` Gilles Chanteperdrix
2012-04-10  9:37                                                     ` Gilles Chanteperdrix [this message]
2012-04-10 10:39                                                       ` Roberto Bielli
2012-04-10 11:25                                                         ` Gilles Chanteperdrix
2012-04-10 12:05                                                           ` Roberto Bielli
2012-04-10 12:06                                                             ` Gilles Chanteperdrix
2012-04-10 12:11                                                               ` Roberto Bielli
2012-04-10 12:12                                                                 ` Gilles Chanteperdrix
2012-04-10 12:18                                                                   ` Roberto Bielli
2012-04-10 11:49                                                         ` Gilles Chanteperdrix
2012-04-10 12:33                                                           ` Roberto Bielli
2012-04-10 12:36                                                             ` Gilles Chanteperdrix
2012-04-10 12:58                                                               ` Roberto Bielli
2012-04-10 15:55                                                                 ` Gilles Chanteperdrix
2012-04-10 12:40                                                             ` Gilles Chanteperdrix
2012-04-11  6:59                                                               ` Roberto Bielli
2012-04-11 11:59                                                                 ` Gilles Chanteperdrix
2012-04-11 12:10                                                                 ` Gilles Chanteperdrix
2012-04-12 10:12                                                                   ` Roberto Bielli
2012-04-12 16:58                                                                     ` [Xenomai-core] porting xenomai on imx25 Roberto Bielli
2012-04-12 17:40                                                                       ` Gilles Chanteperdrix
2012-04-13  8:44                                                                         ` Roberto Bielli
2012-04-13 13:47                                                                           ` Gilles Chanteperdrix
2012-04-18  8:44                                                                             ` Roberto Bielli
2012-04-18  9:19                                                                               ` Gilles Chanteperdrix
2012-04-18 10:28                                                                                 ` Roberto Bielli
2012-04-18 11:51                                                                                   ` Gilles Chanteperdrix
2012-04-19  8:52                                                                                     ` Roberto Bielli
2012-04-19  8:54                                                                                       ` Gilles Chanteperdrix
2012-04-19  9:01                                                                                         ` Roberto Bielli
2012-04-19  9:02                                                                                           ` Gilles Chanteperdrix
2012-04-19 12:11                                                                                             ` Gilles Chanteperdrix
2012-04-12 17:32                                                                     ` [Xenomai-core] preemptive doesn't work Gilles Chanteperdrix
2012-04-10 12:52                                                             ` Gilles Chanteperdrix
2012-04-10  9:19                                                 ` Roberto Bielli
2012-04-10  9:19                                                   ` Gilles Chanteperdrix

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F83FF49.90608@domain.hid \
    --to=gilles.chanteperdrix@xenomai.org \
    --cc=roberto.bielli@domain.hid \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.