aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2011-07-19 01:19:38 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2011-07-19 01:19:38 -0400
commit87e774db58f9e4432fd5f8db0358f0432047a31c (patch)
treec957443fcd032c14901d950a3fcf26f289f640b3
parentbb2489f0bede32ee6cce9e21508adfadb7e18f5e (diff)
downloadlibrambutan-87e774db58f9e4432fd5f8db0358f0432047a31c.tar.gz
librambutan-87e774db58f9e4432fd5f8db0358f0432047a31c.zip
timer.c: Fix dispatch_irq() and dispatch_cc_irqs().
Modify them to check whether the relevant interrupts are enabled before attempting to handle them.
-rw-r--r--libmaple/timer.c70
1 files changed, 46 insertions, 24 deletions
diff --git a/libmaple/timer.c b/libmaple/timer.c
index 367e1f4..377bab7 100644
--- a/libmaple/timer.c
+++ b/libmaple/timer.c
@@ -309,20 +309,22 @@ void __irq_tim8_cc(void) {
}
#endif
-static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit);
+static inline void dispatch_irq(timer_dev *dev,
+ timer_interrupt_id iid,
+ uint32 irq_mask);
static inline void dispatch_cc_irqs(timer_dev *dev);
static inline void dispatch_adv_brk(timer_dev *dev) {
- dispatch_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF_BIT);
+ dispatch_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF);
}
static inline void dispatch_adv_up(timer_dev *dev) {
- dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
}
static inline void dispatch_adv_trg_com(timer_dev *dev) {
- dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT);
- dispatch_irq(dev, TIMER_COM_INTERRUPT, TIMER_SR_COMIF_BIT);
+ dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF);
+ dispatch_irq(dev, TIMER_COM_INTERRUPT, TIMER_SR_COMIF);
}
static inline void dispatch_adv_cc(timer_dev *dev) {
@@ -330,42 +332,62 @@ static inline void dispatch_adv_cc(timer_dev *dev) {
}
static inline void dispatch_general(timer_dev *dev) {
- dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT);
+ dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF);
dispatch_cc_irqs(dev);
- dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
}
static inline void dispatch_basic(timer_dev *dev) {
- dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
-}
-
-static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit) {
- __io uint32 *sr = &(dev->regs).bas->SR;
- if (bb_peri_get_bit(sr, sr_bit)) {
- if (dev->handlers[iid])
- (dev->handlers[iid])();
- bb_peri_set_bit(sr, sr_bit, 0);
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+/* Note: The following dispatch routines play some tricks that depend
+ * on the positions of the relevant interrupt-related bits in TIMx_SR
+ * and TIMx_DIER. */
+
+/* TODO (optimization): since the callers all know the timer
+ * statically, it may be possible to speed these dispatch routines up
+ * by skipping the timer_dev and accessing timer_reg_map/handlers
+ * directly */
+
+static inline void dispatch_irq(timer_dev *dev,
+ timer_interrupt_id iid,
+ uint32 irq_mask) {
+ timer_bas_reg_map *regs = (dev->regs).bas;
+ void (*handler)(void) = dev->handlers[iid];
+ if ((regs->DIER & irq_mask) && (regs->SR & irq_mask) && handler) {
+ handler();
+ regs->SR &= ~irq_mask;
}
}
+#define DIER_CCS (TIMER_DIER_CC4IE | \
+ TIMER_DIER_CC3IE | \
+ TIMER_DIER_CC2IE | \
+ TIMER_DIER_CC1IE)
+
static inline void dispatch_cc_irqs(timer_dev *dev) {
- uint32 sr = (dev->regs).gen->SR;
- uint32 sr_clear = 0;
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dier = regs->DIER;
+ uint32 sr;
+ uint32 sr_clear; /* cuts down on writes to a volatile register */
uint32 b;
- ASSERT_FAULT(sr & (TIMER_SR_CC1IF | TIMER_SR_CC2IF |
- TIMER_SR_CC3IF | TIMER_SR_CC4IF));
+ if (!(dier & DIER_CCS)) {
+ return;
+ }
+ sr = regs->SR;
+ sr_clear = 0;
for (b = TIMER_SR_CC1IF_BIT; b <= TIMER_SR_CC4IF_BIT; b++) {
uint32 mask = BIT(b);
- if (sr & mask) {
- if (dev->handlers[b])
- (dev->handlers[b])();
+ if ((dier & mask) && (sr & mask) && dev->handlers[b]) {
+ (dev->handlers[b])();
sr_clear |= mask;
}
}
- (dev->regs).gen->SR &= ~sr_clear;
+ regs->SR &= ~sr_clear;
}
/*