* OMAP1 realtime patch
@ 2007-02-05 19:29 Dirk Behme
2007-02-07 21:00 ` Kevin Hilman
0 siblings, 1 reply; 8+ messages in thread
From: Dirk Behme @ 2007-02-05 19:29 UTC (permalink / raw)
To: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 880 bytes --]
For everybody interested please find in attachment my OMAP1
realtime patch.
It's tested on OSK and boots with both, MPU and 32KHz timer
and plays mp3 via NFS. It's against recent OMAP 2.6.20 git
tree and should be applied on top of patch-2.6.20-rt2 [1].
Note that with our OMAP git, patch-2.6.20-rt2 will not apply
cleanly due to differences between mainline and our git.
Ignore the resulting patch-2.6.20-rt2 rejects, using e.g.
quilt you have to use push -f to force apply.
Order to use:
1) OMAP 2.6.20 git [2]
2) patch-2.6.20-rt2 [1]
(The -rtX patches are frequently updated. > -rt2 patches
should work as well unless major changes)
3) patch-2.6.20-rt2-omap1 in attachment
For more info see [3].
Enjoy,
Dirk
[1] http://people.redhat.com/mingo/realtime-preempt/
[2]
http://source.mvista.com/git/gitweb.cgi?p=linux-omap-2.6.git;a=log
[3] http://rt.wiki.kernel.org/
[-- Attachment #2: patch-2.6.20-rt2-omap1 --]
[-- Type: text/plain, Size: 19523 bytes --]
Index: linux-osk/arch/arm/mach-omap2/gpmc.c
===================================================================
--- linux-osk.orig/arch/arm/mach-omap2/gpmc.c
+++ linux-osk/arch/arm/mach-omap2/gpmc.c
@@ -61,7 +61,7 @@
static struct resource gpmc_mem_root;
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
-static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED;
+static raw_spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED;
static unsigned gpmc_cs_map;
static void __iomem *gpmc_base =
Index: linux-osk/arch/arm/plat-omap/debug-leds.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/debug-leds.c
+++ linux-osk/arch/arm/plat-omap/debug-leds.c
@@ -34,7 +34,7 @@
* one, or both.
*/
-static spinlock_t lock;
+static raw_spinlock_t lock;
static struct h2p2_dbg_fpga __iomem *fpga;
static u16 led_state, hw_led_state;
Index: linux-osk/arch/arm/plat-omap/dma.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dma.c
+++ linux-osk/arch/arm/plat-omap/dma.c
@@ -62,7 +62,7 @@ struct omap_dma_lch {
static int dma_chan_count;
-static spinlock_t dma_chan_lock;
+static raw_spinlock_t dma_chan_lock;
static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT];
static const u8 omap1_dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = {
Index: linux-osk/arch/arm/plat-omap/dmtimer.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dmtimer.c
+++ linux-osk/arch/arm/plat-omap/dmtimer.c
@@ -129,7 +129,7 @@ static struct clk *dm_source_clocks[3];
#endif
static const int dm_timer_count = ARRAY_SIZE(dm_timers);
-static spinlock_t dm_timer_lock;
+static raw_spinlock_t dm_timer_lock;
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
{
Index: linux-osk/arch/arm/plat-omap/dsp/fifo.h
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dsp/fifo.h
+++ linux-osk/arch/arm/plat-omap/dsp/fifo.h
@@ -22,7 +22,7 @@
*/
struct fifo_struct {
- spinlock_t lock;
+ raw_spinlock_t lock;
char *buf;
size_t sz;
size_t cnt;
Index: linux-osk/arch/arm/plat-omap/dsp/ipbuf.h
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dsp/ipbuf.h
+++ linux-osk/arch/arm/plat-omap/dsp/ipbuf.h
@@ -79,15 +79,15 @@ extern struct ipbuf_sys *ipbuf_sys_da, *
#define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base)
struct ipblink {
- spinlock_t lock;
+ raw_spinlock_t lock;
u16 top;
u16 tail;
};
-#define IPBLINK_INIT { \
- .lock = SPIN_LOCK_UNLOCKED, \
- .top = BID_NULL, \
- .tail = BID_NULL, \
+#define IPBLINK_INIT { \
+ .lock = RAW_SPIN_LOCK_UNLOCKED(ipb_free.lock), \
+ .top = BID_NULL, \
+ .tail = BID_NULL, \
}
#define INIT_IPBLINK(link) \
Index: linux-osk/arch/arm/plat-omap/dsp/mblog.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dsp/mblog.c
+++ linux-osk/arch/arm/plat-omap/dsp/mblog.c
@@ -117,12 +117,12 @@ struct mblogent {
};
static struct {
- spinlock_t lock;
+ raw_spinlock_t lock;
int wp;
unsigned long cnt, cnt_ad, cnt_da;
struct mblogent ent[MBLOG_DEPTH];
} mblog = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = RAW_SPIN_LOCK_UNLOCKED(mblog.lock),
};
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
Index: linux-osk/arch/arm/plat-omap/dsp/proclist.h
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dsp/proclist.h
+++ linux-osk/arch/arm/plat-omap/dsp/proclist.h
@@ -27,8 +27,10 @@ struct proc_list {
struct file *file;
};
-static __inline__ void proc_list_add(spinlock_t *lock, struct list_head *list,
- struct task_struct *tsk, struct file *file)
+static __inline__ void proc_list_add(raw_spinlock_t *lock,
+ struct list_head *list,
+ struct task_struct *tsk,
+ struct file *file)
{
struct proc_list *new;
@@ -40,8 +42,10 @@ static __inline__ void proc_list_add(spi
spin_unlock(lock);
}
-static __inline__ void proc_list_del(spinlock_t *lock, struct list_head *list,
- struct task_struct *tsk, struct file *file)
+static __inline__ void proc_list_del(raw_spinlock_t *lock,
+ struct list_head *list,
+ struct task_struct *tsk,
+ struct file *file)
{
struct proc_list *pl;
@@ -64,7 +68,8 @@ static __inline__ void proc_list_del(spi
spin_unlock(lock);
}
-static __inline__ void proc_list_flush(spinlock_t *lock, struct list_head *list)
+static __inline__ void proc_list_flush(raw_spinlock_t *lock,
+ struct list_head *list)
{
struct proc_list *pl;
Index: linux-osk/arch/arm/plat-omap/dsp/task.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/dsp/task.c
+++ linux-osk/arch/arm/plat-omap/dsp/task.c
@@ -117,7 +117,7 @@ struct taskdev {
unsigned int usecount;
char name[TNM_LEN];
struct file_operations fops;
- spinlock_t proc_list_lock;
+ raw_spinlock_t proc_list_lock;
struct list_head proc_list;
struct dsptask *task;
@@ -132,7 +132,7 @@ struct taskdev {
/* write stuff */
wait_queue_head_t write_wait_q;
struct mutex write_mutex;
- spinlock_t wsz_lock;
+ raw_spinlock_t wsz_lock;
size_t wsz;
/* tctl stuff */
Index: linux-osk/arch/arm/plat-omap/mcbsp.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/mcbsp.c
+++ linux-osk/arch/arm/plat-omap/mcbsp.c
@@ -61,7 +61,7 @@ struct omap_mcbsp {
struct completion tx_dma_completion;
struct completion rx_dma_completion;
- spinlock_t lock;
+ raw_spinlock_t lock;
};
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
Index: linux-osk/drivers/input/touchscreen/ads7846.c
===================================================================
--- linux-osk.orig/drivers/input/touchscreen/ads7846.c
+++ linux-osk/drivers/input/touchscreen/ads7846.c
@@ -100,7 +100,7 @@ struct ads7846 {
u16 debounce_tol;
u16 debounce_rep;
- spinlock_t lock;
+ raw_spinlock_t lock;
struct hrtimer timer;
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
@@ -454,7 +454,7 @@ static void ads7846_rx(void *ads)
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
return;
}
@@ -473,7 +473,8 @@ static void ads7846_rx(void *ads)
ads7846_sync_events(ts);
}
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
static int ads7846_debounce(void *ads, int data_idx, int *val)
@@ -558,7 +559,7 @@ static void ads7846_rx_val(void *ads)
status);
}
-static int ads7846_timer(struct hrtimer *handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
@@ -609,7 +610,7 @@ static irqreturn_t ads7846_irq(int irq,
disable_irq(ts->spi->irq);
ts->pending = 1;
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -747,7 +748,7 @@ static int __devinit ads7846_probe(struc
ts->input = input_dev;
ts->hwmon = hwmon;
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
Index: linux-osk/sound/arm/omap/omap-alsa-dma.c
===================================================================
--- linux-osk.orig/sound/arm/omap/omap-alsa-dma.c
+++ linux-osk/sound/arm/omap/omap-alsa-dma.c
@@ -56,6 +56,7 @@
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/spinlock_types.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -114,7 +115,7 @@
/**************************** DATA STRUCTURES *****************************************/
-static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
+static raw_spinlock_t dma_list_lock = RAW_SPIN_LOCK_UNLOCKED(dma_list_lock);
static char nr_linked_channels = 1;
Index: linux-osk/include/asm-arm/arch-omap/mailbox.h
===================================================================
--- linux-osk.orig/include/asm-arm/arch-omap/mailbox.h
+++ linux-osk/include/asm-arm/arch-omap/mailbox.h
@@ -37,7 +37,7 @@ struct omap_mbox_ops {
struct omap_mbox {
char *name;
- spinlock_t lock;
+ raw_spinlock_t lock;
unsigned int irq;
struct omap_mbox_ops *ops;
Index: linux-osk/include/asm-arm/arch-omap/omap-alsa.h
===================================================================
--- linux-osk.orig/include/asm-arm/arch-omap/omap-alsa.h
+++ linux-osk/include/asm-arm/arch-omap/omap-alsa.h
@@ -83,7 +83,7 @@ struct audio_stream {
int active:1; /* we are using this stream for transfer now */
int period; /* current transfer period */
int periods; /* current count of periods registerd in the DMA engine */
- spinlock_t dma_lock; /* for locking in DMA operations */
+ raw_spinlock_t dma_lock; /* for locking in DMA operations */
snd_pcm_substream_t *stream; /* the pcm stream */
unsigned linked:1; /* dma channels linked */
int offset; /* store start position of the last period in the alsa buffer */
Index: linux-osk/arch/arm/plat-omap/gpio.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/gpio.c
+++ linux-osk/arch/arm/plat-omap/gpio.c
@@ -137,7 +137,7 @@ struct gpio_bank {
u32 saved_fallingdetect;
u32 saved_risingdetect;
#endif
- spinlock_t lock;
+ raw_spinlock_t lock;
};
#define METHOD_MPUIO 0
Index: linux-osk/arch/arm/plat-omap/timer32k.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/timer32k.c
+++ linux-osk/arch/arm/plat-omap/timer32k.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -202,106 +203,16 @@ unsigned long long sched_clock(void)
return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
}
-/*
- * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
- * function is also called from other interrupts to remove latency
- * issues with dynamic tick. In the dynamic tick case, we need to lock
- * with irqsave.
- */
-static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
+static inline irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long now;
-
- omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
-
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
+ struct clock_event_device *evt = &clockevent_32k_timer;
+ omap_32k_timer_ack_irq();
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
-static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
-{
- unsigned long flags;
-
- write_seqlock_irqsave(&xtime_lock, flags);
- _omap_32k_timer_interrupt(irq, dev_id);
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-/*
- * Programs the next timer interrupt needed. Called when dynamic tick is
- * enabled, and to reprogram the ticks to skip from pm_idle. Note that
- * we can keep the timer continuous, and don't need to set it to run in
- * one-shot mode. This is because the timer will get reprogrammed again
- * after next interrupt.
- */
-void omap_32k_timer_reprogram(unsigned long next_tick)
-{
- unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1;
- unsigned long now = omap_32k_sync_timer_read();
- unsigned long idled = now - omap_32k_last_tick;
-
- if (idled + 1 < ticks)
- ticks -= idled;
- else
- ticks = 1;
- omap_32k_timer_start(ticks);
-}
-
-static struct irqaction omap_32k_timer_irq;
-extern struct timer_update_handler timer_update;
-
-static int omap_32k_timer_enable_dyn_tick(void)
-{
- /* No need to reprogram timer, just use the next interrupt */
- return 0;
-}
-
-static int omap_32k_timer_disable_dyn_tick(void)
-{
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
- return 0;
-}
-
-static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
-{
- unsigned long now;
-
- now = omap_32k_sync_timer_read();
-
- /* Don't bother reprogramming timer if last tick was before next
- * jiffie. We will get another interrupt when previously programmed
- * timer expires. This cuts down interrupt load quite a bit.
- */
- if (now - omap_32k_last_tick < OMAP_32K_TICKS_PER_HZ)
- return IRQ_HANDLED;
-
- return _omap_32k_timer_interrupt(irq, dev_id);
-}
-
-static struct dyn_tick_timer omap_dyn_tick_timer = {
- .enable = omap_32k_timer_enable_dyn_tick,
- .disable = omap_32k_timer_disable_dyn_tick,
- .reprogram = omap_32k_timer_reprogram,
- .handler = omap_32k_timer_handler,
-};
-#endif /* CONFIG_NO_IDLE_HZ */
-
static struct irqaction omap_32k_timer_irq = {
.name = "32KHz timer",
.flags = IRQF_DISABLED | IRQF_TIMER,
@@ -310,10 +221,6 @@ static struct irqaction omap_32k_timer_i
static __init void omap_init_32k_timer(void)
{
-#ifdef CONFIG_NO_IDLE_HZ
- omap_timer.dyn_tick = &omap_dyn_tick_timer;
-#endif
-
if (cpu_class_is_omap1())
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
omap_32k_last_tick = omap_32k_sync_timer_read();
Index: linux-osk/arch/arm/mach-omap1/time.c
===================================================================
--- linux-osk.orig/arch/arm/mach-omap1/time.c
+++ linux-osk/arch/arm/mach-omap1/time.c
@@ -42,6 +42,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -102,15 +103,33 @@ static inline unsigned long omap_mpu_tim
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
+
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
/*
@@ -118,12 +137,42 @@ static inline void omap_mpu_timer_start(
* MPU timer 1 ... count down to zero, interrupt, reload
* ---------------------------------------------------------------------------
*/
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
+
static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
- /* NOTE: no lost-tick detection/handling! */
- timer_tick();
- write_sequnlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -139,7 +188,17 @@ static __init void omap_init_mpu_timer(u
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- omap_mpu_timer_start(0, (rate / HZ) - 1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
/*
@@ -173,7 +232,7 @@ static struct clocksource clocksource_mp
.read = mpu_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init omap_init_clocksource(unsigned long rate)
@@ -185,7 +244,7 @@ static void __init omap_init_clocksource
= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
- omap_mpu_timer_start(1, ~0);
+ omap_mpu_timer_start(1, ~0, 1);
if (clocksource_register(&clocksource_mpu))
printk(err, clocksource_mpu.name);
Index: linux-osk/arch/arm/plat-omap/common.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/common.c
+++ linux-osk/arch/arm/plat-omap/common.c
@@ -212,7 +212,7 @@ static struct clocksource clocksource_32
.read = omap_32k_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init omap_init_clocksource_32k(void)
Index: linux-osk/kernel/irq/manage.c
===================================================================
--- linux-osk.orig/kernel/irq/manage.c
+++ linux-osk/kernel/irq/manage.c
@@ -593,6 +593,7 @@ static void thread_simple_irq(irq_desc_t
unsigned int irq = desc - irq_desc;
irqreturn_t action_ret;
+ restart:
if (action && !desc->depth) {
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
@@ -601,6 +602,19 @@ static void thread_simple_irq(irq_desc_t
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
}
+
+ /*
+ * Some boards will disable an interrupt when it
+ * sets IRQ_PENDING . So we have to remove the flag
+ * and re-enable to handle it.
+ */
+ if (desc->status & IRQ_PENDING) {
+ desc->status &= ~IRQ_PENDING;
+ if (desc->chip)
+ desc->chip->enable(irq);
+ goto restart;
+ }
+
desc->status &= ~IRQ_INPROGRESS;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-05 19:29 OMAP1 realtime patch Dirk Behme
@ 2007-02-07 21:00 ` Kevin Hilman
2007-02-08 15:01 ` Dirk Behme
2007-02-08 18:09 ` Dirk Behme
0 siblings, 2 replies; 8+ messages in thread
From: Kevin Hilman @ 2007-02-07 21:00 UTC (permalink / raw)
To: Dirk Behme; +Cc: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 547 bytes --]
On Mon, 2007-02-05 at 20:29 +0100, Dirk Behme wrote:
> For everybody interested please find in attachment my OMAP1
> realtime patch.
Dirk,
Was there a reason for the raw_spinlock conversions? Did you run into
specific issues for converting those? At first glance, I don't think
any of those are needed.
Here is a patch which leaves out the raw_spinlock conversions. It goes
on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
all the raw_spinlock conversions. This has been tested on an
OMAP1623/H2 platform.
Kevin
[-- Attachment #2: patch-2.6.20-rt5-omap1-fixups --]
[-- Type: text/x-patch, Size: 6758 bytes --]
Index: dev/arch/arm/mach-omap1/time.c
===================================================================
--- dev.orig/arch/arm/mach-omap1/time.c
+++ dev/arch/arm/mach-omap1/time.c
@@ -42,6 +42,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -102,15 +103,33 @@ static inline unsigned long omap_mpu_tim
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
+
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
/*
@@ -118,12 +137,42 @@ static inline void omap_mpu_timer_start(
* MPU timer 1 ... count down to zero, interrupt, reload
* ---------------------------------------------------------------------------
*/
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
+
static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
- /* NOTE: no lost-tick detection/handling! */
- timer_tick();
- write_sequnlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -139,7 +188,17 @@ static __init void omap_init_mpu_timer(u
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- omap_mpu_timer_start(0, (rate / HZ) - 1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
/*
@@ -173,7 +232,7 @@ static struct clocksource clocksource_mp
.read = mpu_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init omap_init_clocksource(unsigned long rate)
@@ -185,7 +244,7 @@ static void __init omap_init_clocksource
= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
- omap_mpu_timer_start(1, ~0);
+ omap_mpu_timer_start(1, ~0, 1);
if (clocksource_register(&clocksource_mpu))
printk(err, clocksource_mpu.name);
Index: dev/arch/arm/plat-omap/timer32k.c
===================================================================
--- dev.orig/arch/arm/plat-omap/timer32k.c
+++ dev/arch/arm/plat-omap/timer32k.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -210,23 +211,10 @@ unsigned long long sched_clock(void)
*/
static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long now;
-
+ struct clock_event_device *evt = &clockevent_32k_timer;
omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
Index: dev/kernel/printk.c
===================================================================
--- dev.orig/kernel/printk.c
+++ dev/kernel/printk.c
@@ -464,6 +464,7 @@ static void zap_locks(void)
spin_lock_init(&logbuf_lock);
/* And make sure that we print immediately */
init_MUTEX(&console_sem);
+ zap_rt_locks();
}
static int printk_time = 0;
Index: dev/arch/arm/plat-omap/common.c
===================================================================
--- dev.orig/arch/arm/plat-omap/common.c
+++ dev/arch/arm/plat-omap/common.c
@@ -212,7 +212,7 @@ static struct clocksource clocksource_32
.read = omap_32k_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init omap_init_clocksource_32k(void)
Index: dev/kernel/irq/manage.c
===================================================================
--- dev.orig/kernel/irq/manage.c
+++ dev/kernel/irq/manage.c
@@ -593,6 +593,7 @@ static void thread_simple_irq(irq_desc_t
unsigned int irq = desc - irq_desc;
irqreturn_t action_ret;
+ restart:
if (action && !desc->depth) {
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
@@ -601,6 +602,19 @@ static void thread_simple_irq(irq_desc_t
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
}
+
+ /*
+ * Some boards will disable an interrupt when it
+ * sets IRQ_PENDING . So we have to remove the flag
+ * and re-enable to handle it.
+ */
+ if (desc->status & IRQ_PENDING) {
+ desc->status &= ~IRQ_PENDING;
+ if (desc->chip)
+ desc->chip->enable(irq);
+ goto restart;
+ }
+
desc->status &= ~IRQ_INPROGRESS;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-07 21:00 ` Kevin Hilman
@ 2007-02-08 15:01 ` Dirk Behme
2007-02-08 18:09 ` Dirk Behme
1 sibling, 0 replies; 8+ messages in thread
From: Dirk Behme @ 2007-02-08 15:01 UTC (permalink / raw)
To: Kevin Hilman; +Cc: linux-omap-open-source
Kevin Hilman wrote:
> On Mon, 2007-02-05 at 20:29 +0100, Dirk Behme wrote:
>
>>For everybody interested please find in attachment my OMAP1
>>realtime patch.
>
> Was there a reason for the raw_spinlock conversions?
Not really ;)
> Did you run into
> specific issues for converting those?
There was this ethernet/irq/gpio issue we fixed with
workaround in kernel/irq/manage.c. Until we had this the
root cause was unclear so a lot of raw_spinlock to be on the
safe side for debugging. Then, I posted my patch to have a
starting point people can try and improve, as you did :)
> Here is a patch which leaves out the raw_spinlock conversions. It goes
> on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
> all the raw_spinlock conversions. This has been tested on an
> OMAP1623/H2 platform.
Many thanks for the update!
> Index: dev/kernel/printk.c
> ===================================================================
> --- dev.orig/kernel/printk.c
> +++ dev/kernel/printk.c
> @@ -464,6 +464,7 @@ static void zap_locks(void)
> spin_lock_init(&logbuf_lock);
> /* And make sure that we print immediately */
> init_MUTEX(&console_sem);
> + zap_rt_locks();
> }
What's this?
Btw: You removed the HRTIMER_MODE_REL and enum
hrtimer_restart changes in
drivers/input/touchscreen/ads7846.c as well?
Cheers
Dirk
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-07 21:00 ` Kevin Hilman
2007-02-08 15:01 ` Dirk Behme
@ 2007-02-08 18:09 ` Dirk Behme
2007-02-11 17:01 ` Dirk Behme
1 sibling, 1 reply; 8+ messages in thread
From: Dirk Behme @ 2007-02-08 18:09 UTC (permalink / raw)
To: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 4663 bytes --]
Kevin Hilman wrote:
> Here is a patch which leaves out the raw_spinlock conversions. It goes
> on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
> all the raw_spinlock conversions. This has been tested on an
> OMAP1623/H2 platform.
Update of Kevins update. Tested on OSK.
Changes:
- Remove kernel/printk.c "+ zap_rt_locks();". It's
already in -rt5.
- Re-add HRTIMER conversion to ads7846.c
With this patch I get Oops below after playing mp3 via NFS.
Add raw_spinlock_t to sound/arm/omap/omap-alsa-dma.c like in
my original patch doesn't seem to help.
Dirk
10337 frames decoded (0:04:30.0), +1.3 dB peak amplitude,
295 clipped samples
kernel BUG at kernel/rtmutex.c:650!
Unable to handle kernel NULL pointer dereference at virtual
address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 817 [#1]
Modules linked in: ppp_async ppp_generic slhc crc_ccitt
rfcomm l2cap hci_usb blueti
CPU: 0
PC is at __bug+0x20/0x2c
LR is at 0xc02350f0
pc : [<c0028aa8>] lr : [<c02350f0>] Not tainted
sp : c032fe04 ip : 60000093 fp : c032fe10
r10: 00000000 r9 : 00000013 r8 : 00000000
r7 : 00000000 r6 : c1979d14 r5 : c032e000 r4 : a0000013
r3 : 00000000 r2 : 00000001 r1 : c032e000 r0 : 00000027
Flags: nzcv IRQs off FIQs on Mode SVC_32 Segment kernel
Control: 5317F
Table: 11F90000 DAC: 00000017
Process IRQ-19 (pid: 30, stack limit = 0xc032e250)
Stack: (0xc032fe04 to 0xc0330000)
fe00: c032fe68 c032fe14 c01bcc58 c0028a98 c035d160
c032fe4c c032fe28
fe20: c00467f0 c0045fac 00000007 c02482a4 c035d160 00000000
00000001 00000000
fe40: c032fe74 c1979cec 00000000 c1979d14 00000000 00000000
00000000 c032fe78
fe60: c032fe6c c01bd04c c01bcbc8 c032fe94 c032fe7c bf0b92b0
c01bd01c bf0b6e6c
fe80: c1e20e00 00000001 c032fea4 c032fe98 bf0a7978 bf0b9250
c032fec4 c032fea8
fea0: bf0a77c8 bf0a7934 c1c13c00 00b5bffe c1e20e00 c1c13c00
c032fed4 c032fec8
fec0: bf0a799c bf0a7798 c032fef4 c032fed8 bf0ade9c bf0a7990
c1979cec c1979d14
fee0: 00000000 00000013 c032ff0c c032fef8 bf0b94ac bf0adcdc
0000ff7f c024677c
ff00: c032ff20 c032ff10 bf0b9bc0 bf0b9494 00000020 c032ff3c
c032ff24 c0036b8c
ff20: bf0b9b68 00000000 00000000 c032e000 c032ff54 c032ff40
c0036bc4 c0036ae4
ff40: c02c2d20 00000000 c032ff80 c032ff58 c006fef8 c0036bb8
c0224740 c032e000
ff60: c0224740 00000013 c02c2d20 00000000 00000000 c032ffa4
c032ff84 c0070590
ff80: c006fe9c c0224740 c032e000 c007099c 00000013 60000013
c032ffcc c032ffa8
ffa0: c0070a90 c0070534 00000032 c0224740 c032e000 c007099c
c02cbe88 00000000
ffc0: c032fff4 c032ffd0 c0060e24 c00709ac ffffffff ffffffff
00000000 00000000
ffe0: 00000000 00000000 00000000 c032fff8 c004e1f4 c0060d4c
00000000 00000000
Backtrace:
[<c0028a88>] (__bug+0x0/0x2c) from [<c01bcc58>]
(rt_spin_lock_slowlock+0xa0/0x204)
[<c01bcbb8>] (rt_spin_lock_slowlock+0x0/0x204) from
[<c01bd04c>] (rt_spin_lock+0x4)
[<c01bd00c>] (rt_spin_lock+0x0/0x44) from [<bf0b92b0>]
(snd_omap_alsa_trigger+0x70)
[<bf0b9240>] (snd_omap_alsa_trigger+0x0/0xac
[snd_omap_alsa_aic23]) from [<bf0a797)
r6 = 00000001 r5 = C1E20E00 r4 = BF0B6E6C
[<bf0a7924>] (snd_pcm_do_stop+0x0/0x5c [snd_pcm]) from
[<bf0a77c8>] (snd_pcm_actio)
[<bf0a7788>] (snd_pcm_action_single+0x0/0x7c [snd_pcm]) from
[<bf0a799c>] (snd_pcm)
r7 = C1C13C00 r6 = C1E20E00 r5 = 00B5BFFE r4 = C1C13C00
[<bf0a7980>] (snd_pcm_drain_done+0x0/0x24 [snd_pcm]) from
[<bf0ade9c>] (snd_pcm_pe)
[<bf0adccc>] (snd_pcm_period_elapsed+0x0/0x278 [snd_pcm])
from [<bf0b94ac>] (callb)
r7 = 00000013 r6 = 00000000 r5 = C1979D14 r4 = C1979CEC
[<bf0b9484>] (callback_omap_alsa_sound_dma+0x0/0x54
[snd_omap_alsa_aic23]) from [<)
r5 = C024677C r4 = 0000FF7F
[<bf0b9b58>] (sound_dma_irq_handler+0x0/0x80
[snd_omap_alsa_aic23]) from [<c0036b8)
r4 = 00000020
[<c0036ad4>] (omap1_dma_handle_ch+0x0/0xd4) from
[<c0036bc4>] (omap1_dma_irq_handl)
r6 = C032E000 r5 = 00000000 r4 = 00000000
[<c0036ba8>] (omap1_dma_irq_handler+0x0/0x34) from
[<c006fef8>] (handle_IRQ_event+)
r5 = 00000000 r4 = C02C2D20
[<c006fe8c>] (handle_IRQ_event+0x0/0xf8) from [<c0070590>]
(thread_simple_irq+0x6c)
[<c0070524>] (thread_simple_irq+0x0/0xf4) from [<c0070a90>]
(do_irqd+0xf4/0x398)
r8 = 60000013 r7 = 00000013 r6 = C007099C r5 = C032E000
r4 = C0224740
[<c007099c>] (do_irqd+0x0/0x398) from [<c0060e24>]
(kthread+0xe8/0x128)
r8 = 00000000 r7 = C02CBE88 r6 = C007099C r5 = C032E000
r4 = C0224740
[<c0060d3c>] (kthread+0x0/0x128) from [<c004e1f4>]
(do_exit+0x0/0x860)
r7 = 00000000 r6 = 00000000 r5 = 00000000 r4 = 00000000
Code: e1a01000 e59f000c eb008bf1 e3a03000 (e5833000)
<6>note: IRQ-19[30] exited with preempt_count 1
[-- Attachment #2: patch-2.6.20-rt5-omap1 --]
[-- Type: text/plain, Size: 8104 bytes --]
Index: linux-osk/arch/arm/mach-omap1/time.c
===================================================================
--- linux-osk.orig/arch/arm/mach-omap1/time.c
+++ linux-osk/arch/arm/mach-omap1/time.c
@@ -42,6 +42,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -102,15 +103,33 @@ static inline unsigned long omap_mpu_tim
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
+
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
/*
@@ -118,12 +137,42 @@ static inline void omap_mpu_timer_start(
* MPU timer 1 ... count down to zero, interrupt, reload
* ---------------------------------------------------------------------------
*/
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
+
static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
- /* NOTE: no lost-tick detection/handling! */
- timer_tick();
- write_sequnlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -139,7 +188,17 @@ static __init void omap_init_mpu_timer(u
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- omap_mpu_timer_start(0, (rate / HZ) - 1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
/*
@@ -173,7 +232,7 @@ static struct clocksource clocksource_mp
.read = mpu_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init omap_init_clocksource(unsigned long rate)
@@ -185,7 +244,7 @@ static void __init omap_init_clocksource
= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
- omap_mpu_timer_start(1, ~0);
+ omap_mpu_timer_start(1, ~0, 1);
if (clocksource_register(&clocksource_mpu))
printk(err, clocksource_mpu.name);
Index: linux-osk/arch/arm/plat-omap/timer32k.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/timer32k.c
+++ linux-osk/arch/arm/plat-omap/timer32k.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -210,23 +211,10 @@ unsigned long long sched_clock(void)
*/
static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long now;
-
+ struct clock_event_device *evt = &clockevent_32k_timer;
omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
Index: linux-osk/arch/arm/plat-omap/common.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/common.c
+++ linux-osk/arch/arm/plat-omap/common.c
@@ -212,7 +212,7 @@ static struct clocksource clocksource_32
.read = omap_32k_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init omap_init_clocksource_32k(void)
Index: linux-osk/kernel/irq/manage.c
===================================================================
--- linux-osk.orig/kernel/irq/manage.c
+++ linux-osk/kernel/irq/manage.c
@@ -593,6 +593,7 @@ static void thread_simple_irq(irq_desc_t
unsigned int irq = desc - irq_desc;
irqreturn_t action_ret;
+ restart:
if (action && !desc->depth) {
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
@@ -601,6 +602,19 @@ static void thread_simple_irq(irq_desc_t
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
}
+
+ /*
+ * Some boards will disable an interrupt when it
+ * sets IRQ_PENDING . So we have to remove the flag
+ * and re-enable to handle it.
+ */
+ if (desc->status & IRQ_PENDING) {
+ desc->status &= ~IRQ_PENDING;
+ if (desc->chip)
+ desc->chip->enable(irq);
+ goto restart;
+ }
+
desc->status &= ~IRQ_INPROGRESS;
}
Index: linux-osk/drivers/input/touchscreen/ads7846.c
===================================================================
--- linux-osk.orig/drivers/input/touchscreen/ads7846.c
+++ linux-osk/drivers/input/touchscreen/ads7846.c
@@ -454,7 +454,7 @@ static void ads7846_rx(void *ads)
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
return;
}
@@ -473,7 +473,8 @@ static void ads7846_rx(void *ads)
ads7846_sync_events(ts);
}
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
static int ads7846_debounce(void *ads, int data_idx, int *val)
@@ -558,7 +559,7 @@ static void ads7846_rx_val(void *ads)
status);
}
-static int ads7846_timer(struct hrtimer *handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
@@ -609,7 +610,7 @@ static irqreturn_t ads7846_irq(int irq,
disable_irq(ts->spi->irq);
ts->pending = 1;
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -747,7 +748,7 @@ static int __devinit ads7846_probe(struc
ts->input = input_dev;
ts->hwmon = hwmon;
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-08 18:09 ` Dirk Behme
@ 2007-02-11 17:01 ` Dirk Behme
2007-02-12 19:24 ` Kevin Hilman
0 siblings, 1 reply; 8+ messages in thread
From: Dirk Behme @ 2007-02-11 17:01 UTC (permalink / raw)
To: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 859 bytes --]
Dirk Behme wrote:
> Kevin Hilman wrote:
>
>> Here is a patch which leaves out the raw_spinlock conversions. It goes
>> on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
>> all the raw_spinlock conversions. This has been tested on an
>> OMAP1623/H2 platform.
>
> Update of Kevins update. Tested on OSK.
>
> Changes:
>
> - Remove kernel/printk.c "+ zap_rt_locks();". It's already in -rt5.
>
> - Re-add HRTIMER conversion to ads7846.c
>
> With this patch I get Oops below after playing mp3 via NFS. Add
> raw_spinlock_t to sound/arm/omap/omap-alsa-dma.c like in my original
> patch doesn't seem to help.
Re-adding raw_spinlock_t to omap-alsa.h helps against this Oops.
Updated patch-2.6.20-rt5-omap2 in attachment.
Dirk
P.S.: As with Tony patches, omap2 stands here for "second
-rt5 omap patch" and not for OMAP2 chips.
[-- Attachment #2: patch-2.6.20-rt5-omap2 --]
[-- Type: text/plain, Size: 8862 bytes --]
Index: linux-osk/arch/arm/mach-omap1/time.c
===================================================================
--- linux-osk.orig/arch/arm/mach-omap1/time.c
+++ linux-osk/arch/arm/mach-omap1/time.c
@@ -42,6 +42,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -102,15 +103,33 @@ static inline unsigned long omap_mpu_tim
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
+
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
/*
@@ -118,12 +137,42 @@ static inline void omap_mpu_timer_start(
* MPU timer 1 ... count down to zero, interrupt, reload
* ---------------------------------------------------------------------------
*/
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
+
static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
- /* NOTE: no lost-tick detection/handling! */
- timer_tick();
- write_sequnlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -139,7 +188,17 @@ static __init void omap_init_mpu_timer(u
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- omap_mpu_timer_start(0, (rate / HZ) - 1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
/*
@@ -173,7 +232,7 @@ static struct clocksource clocksource_mp
.read = mpu_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init omap_init_clocksource(unsigned long rate)
@@ -185,7 +244,7 @@ static void __init omap_init_clocksource
= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
- omap_mpu_timer_start(1, ~0);
+ omap_mpu_timer_start(1, ~0, 1);
if (clocksource_register(&clocksource_mpu))
printk(err, clocksource_mpu.name);
Index: linux-osk/arch/arm/plat-omap/timer32k.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/timer32k.c
+++ linux-osk/arch/arm/plat-omap/timer32k.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -210,23 +211,10 @@ unsigned long long sched_clock(void)
*/
static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long now;
-
+ struct clock_event_device *evt = &clockevent_32k_timer;
omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
Index: linux-osk/arch/arm/plat-omap/common.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/common.c
+++ linux-osk/arch/arm/plat-omap/common.c
@@ -212,7 +212,7 @@ static struct clocksource clocksource_32
.read = omap_32k_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init omap_init_clocksource_32k(void)
Index: linux-osk/kernel/irq/manage.c
===================================================================
--- linux-osk.orig/kernel/irq/manage.c
+++ linux-osk/kernel/irq/manage.c
@@ -593,6 +593,7 @@ static void thread_simple_irq(irq_desc_t
unsigned int irq = desc - irq_desc;
irqreturn_t action_ret;
+ restart:
if (action && !desc->depth) {
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
@@ -601,6 +602,19 @@ static void thread_simple_irq(irq_desc_t
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
}
+
+ /*
+ * Some boards will disable an interrupt when it
+ * sets IRQ_PENDING . So we have to remove the flag
+ * and re-enable to handle it.
+ */
+ if (desc->status & IRQ_PENDING) {
+ desc->status &= ~IRQ_PENDING;
+ if (desc->chip)
+ desc->chip->enable(irq);
+ goto restart;
+ }
+
desc->status &= ~IRQ_INPROGRESS;
}
Index: linux-osk/drivers/input/touchscreen/ads7846.c
===================================================================
--- linux-osk.orig/drivers/input/touchscreen/ads7846.c
+++ linux-osk/drivers/input/touchscreen/ads7846.c
@@ -454,7 +454,7 @@ static void ads7846_rx(void *ads)
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
return;
}
@@ -473,7 +473,8 @@ static void ads7846_rx(void *ads)
ads7846_sync_events(ts);
}
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
static int ads7846_debounce(void *ads, int data_idx, int *val)
@@ -558,7 +559,7 @@ static void ads7846_rx_val(void *ads)
status);
}
-static int ads7846_timer(struct hrtimer *handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
@@ -609,7 +610,7 @@ static irqreturn_t ads7846_irq(int irq,
disable_irq(ts->spi->irq);
ts->pending = 1;
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -747,7 +748,7 @@ static int __devinit ads7846_probe(struc
ts->input = input_dev;
ts->hwmon = hwmon;
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
Index: linux-osk/include/asm-arm/arch-omap/omap-alsa.h
===================================================================
--- linux-osk.orig/include/asm-arm/arch-omap/omap-alsa.h
+++ linux-osk/include/asm-arm/arch-omap/omap-alsa.h
@@ -83,7 +83,7 @@ struct audio_stream {
int active:1; /* we are using this stream for transfer now */
int period; /* current transfer period */
int periods; /* current count of periods registerd in the DMA engine */
- spinlock_t dma_lock; /* for locking in DMA operations */
+ raw_spinlock_t dma_lock; /* for locking in DMA operations */
snd_pcm_substream_t *stream; /* the pcm stream */
unsigned linked:1; /* dma channels linked */
int offset; /* store start position of the last period in the alsa buffer */
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-11 17:01 ` Dirk Behme
@ 2007-02-12 19:24 ` Kevin Hilman
2007-02-12 19:32 ` Kevin Hilman
2007-02-12 20:34 ` Dirk Behme
0 siblings, 2 replies; 8+ messages in thread
From: Kevin Hilman @ 2007-02-12 19:24 UTC (permalink / raw)
To: Dirk Behme; +Cc: linux-omap-open-source
On Sun, 2007-02-11 at 18:01 +0100, Dirk Behme wrote:
> Dirk Behme wrote:
> > Kevin Hilman wrote:
> >
> >> Here is a patch which leaves out the raw_spinlock conversions. It goes
> >> on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
> >> all the raw_spinlock conversions. This has been tested on an
> >> OMAP1623/H2 platform.
> >
> > Update of Kevins update. Tested on OSK.
> >
> > Changes:
> >
> > - Remove kernel/printk.c "+ zap_rt_locks();". It's already in -rt5.
> >
> > - Re-add HRTIMER conversion to ads7846.c
> >
> > With this patch I get Oops below after playing mp3 via NFS. Add
> > raw_spinlock_t to sound/arm/omap/omap-alsa-dma.c like in my original
> > patch doesn't seem to help.
>
> Re-adding raw_spinlock_t to omap-alsa.h helps against this Oops.
My guess the oops you sent is that you saw this crash when doing a
Ctrl-C or otherwise stopping the playback, correct?
This oops is triggered by the same thread trying to take the same
spinlock (now an rt_mutex under PREEMPT_RT.) The following patch
fixes the nested spinlocks, and removes the raw_spinlock. It applies
on top of your latest patch.
On my OSK, I do notice however that using -rt (with and without this
fix) mp3 playback has some audible noise under PREEMPT_RT. Do you hear
this too?
Kevin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-12 19:24 ` Kevin Hilman
@ 2007-02-12 19:32 ` Kevin Hilman
2007-02-12 20:34 ` Dirk Behme
1 sibling, 0 replies; 8+ messages in thread
From: Kevin Hilman @ 2007-02-12 19:32 UTC (permalink / raw)
To: Dirk Behme; +Cc: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 1680 bytes --]
On Mon, 2007-02-12 at 11:24 -0800, Kevin Hilman wrote:
> On Sun, 2007-02-11 at 18:01 +0100, Dirk Behme wrote:
> > Dirk Behme wrote:
> > > Kevin Hilman wrote:
> > >
> > >> Here is a patch which leaves out the raw_spinlock conversions. It goes
> > >> on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
> > >> all the raw_spinlock conversions. This has been tested on an
> > >> OMAP1623/H2 platform.
> > >
> > > Update of Kevins update. Tested on OSK.
> > >
> > > Changes:
> > >
> > > - Remove kernel/printk.c "+ zap_rt_locks();". It's already in -rt5.
> > >
> > > - Re-add HRTIMER conversion to ads7846.c
> > >
> > > With this patch I get Oops below after playing mp3 via NFS. Add
> > > raw_spinlock_t to sound/arm/omap/omap-alsa-dma.c like in my original
> > > patch doesn't seem to help.
> >
> > Re-adding raw_spinlock_t to omap-alsa.h helps against this Oops.
>
> My guess the oops you sent is that you saw this crash when doing a
> Ctrl-C or otherwise stopping the playback, correct?
>
> This oops is triggered by the same thread trying to take the same
> spinlock (now an rt_mutex under PREEMPT_RT.) The following patch
> fixes the nested spinlocks, and removes the raw_spinlock. It applies
> on top of your latest patch.
>
> On my OSK, I do notice however that using -rt (with and without this
> fix) mp3 playback has some audible noise under PREEMPT_RT. Do you hear
> this too?
This time with the patch.
Another data point... I only hear the noise when using mpg123 to play
an .mp3 file. If I use aplay to play a .wav file, I'm not hearing any
noise. I can even ping flood the target and audio plays without
problems.
Kevin
[-- Attachment #2: omap-alsa-rt.patch --]
[-- Type: text/x-patch, Size: 1331 bytes --]
Index: dev/include/asm-arm/arch-omap/omap-alsa.h
===================================================================
--- dev.orig/include/asm-arm/arch-omap/omap-alsa.h
+++ dev/include/asm-arm/arch-omap/omap-alsa.h
@@ -83,7 +83,7 @@ struct audio_stream {
int active:1; /* we are using this stream for transfer now */
int period; /* current transfer period */
int periods; /* current count of periods registerd in the DMA engine */
- raw_spinlock_t dma_lock; /* for locking in DMA operations */
+ spinlock_t dma_lock; /* for locking in DMA operations */
snd_pcm_substream_t *stream; /* the pcm stream */
unsigned linked:1; /* dma channels linked */
int offset; /* store start position of the last period in the alsa buffer */
Index: dev/sound/arm/omap/omap-alsa.c
===================================================================
--- dev.orig/sound/arm/omap/omap-alsa.c
+++ dev/sound/arm/omap/omap-alsa.c
@@ -167,7 +167,6 @@ static void audio_stop_dma(struct audio_
unsigned long flags;
ADEBUG();
- spin_lock_irqsave(&s->dma_lock, flags);
s->active = 0;
s->period = 0;
s->periods = 0;
@@ -176,8 +175,6 @@ static void audio_stop_dma(struct audio_
omap_stop_alsa_sound_dma(s);
omap_clear_alsa_sound_dma(s);
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
}
/*
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP1 realtime patch
2007-02-12 19:24 ` Kevin Hilman
2007-02-12 19:32 ` Kevin Hilman
@ 2007-02-12 20:34 ` Dirk Behme
1 sibling, 0 replies; 8+ messages in thread
From: Dirk Behme @ 2007-02-12 20:34 UTC (permalink / raw)
To: Kevin Hilman; +Cc: linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 2307 bytes --]
Kevin Hilman wrote:
> On Sun, 2007-02-11 at 18:01 +0100, Dirk Behme wrote:
>
>>Dirk Behme wrote:
>>
>>>Kevin Hilman wrote:
>>>
>>>
>>>>Here is a patch which leaves out the raw_spinlock conversions. It goes
>>>>on the OMAP git tree on top of -rt5 (ignoring conflicts.) I've left out
>>>>all the raw_spinlock conversions. This has been tested on an
>>>>OMAP1623/H2 platform.
>>>
>>>Update of Kevins update. Tested on OSK.
>>>
>>>Changes:
>>>
>>>- Remove kernel/printk.c "+ zap_rt_locks();". It's already in -rt5.
>>>
>>>- Re-add HRTIMER conversion to ads7846.c
>>>
>>>With this patch I get Oops below after playing mp3 via NFS. Add
>>>raw_spinlock_t to sound/arm/omap/omap-alsa-dma.c like in my original
>>>patch doesn't seem to help.
>>
>>Re-adding raw_spinlock_t to omap-alsa.h helps against this Oops.
>
>
> My guess the oops you sent is that you saw this crash when doing a
> Ctrl-C or otherwise stopping the playback, correct?
Nearly ;)
Even without Ctrl-C this Oops happened. Simply waiting for
mp3 to finish and coming back to prompt triggered it.
Your patch fixes this.
> This oops is triggered by the same thread trying to take the same
> spinlock (now an rt_mutex under PREEMPT_RT.) The following patch
> fixes the nested spinlocks, and removes the raw_spinlock. It applies
> on top of your latest patch.
Update to patch-2.6.20-rt5-omap3 in attachment.
Changes:
- Add Kevins fix for nested omap-alsa.c spinlocks and remove
raw_spinlock workaround.
Thanks!
> On my OSK, I do notice however that using -rt (with and without this
> fix) mp3 playback has some audible noise under PREEMPT_RT. Do you hear
> this too?
> Another data point... I only hear the noise when using
mpg123 to play
> an .mp3 file. If I use aplay to play a .wav file, I'm
not hearing any
> noise. I can even ping flood the target and audio plays
without
> problems.
I use madplay
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004
Robert Leslie et al.
to play mp3. I explicitly checked it again and don't think
there is any noise. Maybe a mpg123 related issue?
Far from it, I have the feeling that mp3 playback improves
with -rt. In the past I had some random noise with my mp3
test song (nobody else seemed to have ;) ). With -rt I have
the impression that it's better.
Dirk
[-- Attachment #2: patch-2.6.20-rt5-omap3 --]
[-- Type: text/plain, Size: 8679 bytes --]
Index: linux-osk/arch/arm/mach-omap1/time.c
===================================================================
--- linux-osk.orig/arch/arm/mach-omap1/time.c
+++ linux-osk/arch/arm/mach-omap1/time.c
@@ -42,6 +42,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -102,15 +103,33 @@ static inline unsigned long omap_mpu_tim
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
+
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
/*
@@ -118,12 +137,42 @@ static inline void omap_mpu_timer_start(
* MPU timer 1 ... count down to zero, interrupt, reload
* ---------------------------------------------------------------------------
*/
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
+
static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
- /* NOTE: no lost-tick detection/handling! */
- timer_tick();
- write_sequnlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -139,7 +188,17 @@ static __init void omap_init_mpu_timer(u
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- omap_mpu_timer_start(0, (rate / HZ) - 1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
/*
@@ -173,7 +232,7 @@ static struct clocksource clocksource_mp
.read = mpu_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 24,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init omap_init_clocksource(unsigned long rate)
@@ -185,7 +244,7 @@ static void __init omap_init_clocksource
= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
- omap_mpu_timer_start(1, ~0);
+ omap_mpu_timer_start(1, ~0, 1);
if (clocksource_register(&clocksource_mpu))
printk(err, clocksource_mpu.name);
Index: linux-osk/arch/arm/plat-omap/timer32k.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/timer32k.c
+++ linux-osk/arch/arm/plat-omap/timer32k.c
@@ -43,6 +43,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -210,23 +211,10 @@ unsigned long long sched_clock(void)
*/
static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long now;
-
+ struct clock_event_device *evt = &clockevent_32k_timer;
omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
Index: linux-osk/arch/arm/plat-omap/common.c
===================================================================
--- linux-osk.orig/arch/arm/plat-omap/common.c
+++ linux-osk/arch/arm/plat-omap/common.c
@@ -212,7 +212,7 @@ static struct clocksource clocksource_32
.read = omap_32k_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init omap_init_clocksource_32k(void)
Index: linux-osk/kernel/irq/manage.c
===================================================================
--- linux-osk.orig/kernel/irq/manage.c
+++ linux-osk/kernel/irq/manage.c
@@ -593,6 +593,7 @@ static void thread_simple_irq(irq_desc_t
unsigned int irq = desc - irq_desc;
irqreturn_t action_ret;
+ restart:
if (action && !desc->depth) {
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);
@@ -601,6 +602,19 @@ static void thread_simple_irq(irq_desc_t
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
}
+
+ /*
+ * Some boards will disable an interrupt when it
+ * sets IRQ_PENDING . So we have to remove the flag
+ * and re-enable to handle it.
+ */
+ if (desc->status & IRQ_PENDING) {
+ desc->status &= ~IRQ_PENDING;
+ if (desc->chip)
+ desc->chip->enable(irq);
+ goto restart;
+ }
+
desc->status &= ~IRQ_INPROGRESS;
}
Index: linux-osk/drivers/input/touchscreen/ads7846.c
===================================================================
--- linux-osk.orig/drivers/input/touchscreen/ads7846.c
+++ linux-osk/drivers/input/touchscreen/ads7846.c
@@ -454,7 +454,7 @@ static void ads7846_rx(void *ads)
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
return;
}
@@ -473,7 +473,8 @@ static void ads7846_rx(void *ads)
ads7846_sync_events(ts);
}
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
static int ads7846_debounce(void *ads, int data_idx, int *val)
@@ -558,7 +559,7 @@ static void ads7846_rx_val(void *ads)
status);
}
-static int ads7846_timer(struct hrtimer *handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
@@ -609,7 +610,7 @@ static irqreturn_t ads7846_irq(int irq,
disable_irq(ts->spi->irq);
ts->pending = 1;
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_REL);
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -747,7 +748,7 @@ static int __devinit ads7846_probe(struc
ts->input = input_dev;
ts->hwmon = hwmon;
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
Index: linux-osk/sound/arm/omap/omap-alsa.c
===================================================================
--- linux-osk.orig/sound/arm/omap/omap-alsa.c
+++ linux-osk/sound/arm/omap/omap-alsa.c
@@ -167,7 +167,6 @@ static void audio_stop_dma(struct audio_
unsigned long flags;
ADEBUG();
- spin_lock_irqsave(&s->dma_lock, flags);
s->active = 0;
s->period = 0;
s->periods = 0;
@@ -176,8 +175,6 @@ static void audio_stop_dma(struct audio_
omap_stop_alsa_sound_dma(s);
omap_clear_alsa_sound_dma(s);
-
- spin_unlock_irqrestore(&s->dma_lock, flags);
}
/*
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-02-12 20:34 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-05 19:29 OMAP1 realtime patch Dirk Behme
2007-02-07 21:00 ` Kevin Hilman
2007-02-08 15:01 ` Dirk Behme
2007-02-08 18:09 ` Dirk Behme
2007-02-11 17:01 ` Dirk Behme
2007-02-12 19:24 ` Kevin Hilman
2007-02-12 19:32 ` Kevin Hilman
2007-02-12 20:34 ` Dirk Behme
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.