--- dahdi-linux-complete-2.7.0.1+2.7.0.1/linux/drivers/dahdi/dahdi-base.c 2013-08-22 02:36:34.000000000 +0700 +++ dahdi-linux-complete/linux/drivers/dahdi/dahdi-base.c 2013-11-07 22:04:15.605488557 +0700 @@ -173,7 +173,7 @@ static sumtype *conf_sums; static sumtype *conf_sums_prev; -static struct dahdi_span *master; +static struct dahdi_span *master = NULL; struct file_operations *dahdi_transcode_fops = NULL; @@ -241,10 +241,13 @@ static int dahdi_chan_ioctl(struct file *file, unsigned int cmd, unsigned long data); #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) -#if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_I386) +#if (defined(CONFIG_X86) || defined(CONFIG_X86_64)) +#include /* in_atomic */ +#ifndef X86_CR0_TS +# define X86_CR0_TS 0x00000008 /* Task Switched */ +#endif struct fpu_save_buf { unsigned long cr0; - unsigned long fpu_buf[128]; }; static DEFINE_PER_CPU(struct fpu_save_buf, fpu_buf); @@ -260,14 +263,18 @@ * inside a spinlock. Otherwise the context might be restored to the * wrong process. * - * Current implementation is x86/ia32-specific and will not even build on - * x86_64) + * This code is x86/x86_64-specific. * */ static inline void dahdi_kernel_fpu_begin(void) { struct fpu_save_buf *buf = &__get_cpu_var(fpu_buf); - __asm__ __volatile__ ("movl %%cr0,%0; clts" : "=r" (buf->cr0)); - __asm__ __volatile__ ("fnsave %0" : "=m" (buf->fpu_buf)); + + buf->cr0 = 0; /* irq_ts_save */ + if (in_atomic() && (read_cr0() & X86_CR0_TS)) { + clts(); + buf->cr0 = 1; + } /* endof irq_ts_save */ + kernel_fpu_begin(); } /** dahdi_kernel_fpu_end() - restore floating point context @@ -278,20 +285,16 @@ static inline void dahdi_kernel_fpu_end(void) { struct fpu_save_buf *buf = &__get_cpu_var(fpu_buf); - __asm__ __volatile__ ("frstor %0" : "=m" (buf->fpu_buf)); - __asm__ __volatile__ ("movl %0,%%cr0" : : "r" (buf->cr0)); + kernel_fpu_end(); + if (buf->cr0) + stts(); } -#else /* We haven't fixed FP context saving/restoring yet */ -/* Very strange things can happen when the context is not properly - * restored. OTOH, some people do report success with this. Hence we - * so far just issue a warning */ -#warning CONFIG_DAHDI_MMX may behave randomly on this platform -#define dahdi_kernel_fpu_begin kernel_fpu_begin -#define dahdi_kernel_fpu_end kernel_fpu_end +#else +#error CONFIG_DAHDI_MMX | ECHO_CAN_FP is x86/x86_64-specific. #endif -#endif +#endif /* defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) */ struct dahdi_timer { spinlock_t lock; @@ -3835,31 +3838,28 @@ static void __dahdi_find_master_span(void) { - struct dahdi_span *s; + struct dahdi_span *s, *old_master, *new_master = NULL; unsigned long flags; - struct dahdi_span *old_master; spin_lock_irqsave(&chan_lock, flags); old_master = master; - list_for_each_entry(s, &span_list, spans_node) { - if (s->alarms && old_master) + /* Searching for the FIRST reliable sync source with reverse for. */ + list_for_each_entry_reverse(s, &span_list, spans_node) { + if (!can_provide_timing(s) || s->alarms) continue; if (dahdi_is_digital_span(s) && - !test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags) && - old_master) + !test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags)) continue; - if (!can_provide_timing(s)) - continue; - if (master == s) - continue; - - master = s; - break; + if ((0 == s->channels) && !new_master) /* dummy is better than nothing (coretimer). */ + new_master = s; + new_master = s; /* But real span is better than dummy. */ } + master = new_master; spin_unlock_irqrestore(&chan_lock, flags); if ((debug & DEBUG_MAIN) && (old_master != master)) - module_printk(KERN_NOTICE, "Master changed to %s\n", s->name); + module_printk(KERN_NOTICE, "Master changed to '%s'\n", + master ? master->name : "no master (core timer)"); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) @@ -7437,7 +7437,6 @@ { int res; int x; - struct dahdi_span *new_master, *s; unsigned long flags; if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) { @@ -7472,25 +7471,7 @@ for (x=0;xchannels;x++) dahdi_chan_unreg(span->chans[x]); - new_master = master; /* FIXME: locking */ - if (master == span) - new_master = NULL; - - spin_lock_irqsave(&chan_lock, flags); - list_for_each_entry(s, &span_list, spans_node) { - if ((s == new_master) || !can_provide_timing(s)) - continue; - new_master = s; - break; - } - spin_unlock_irqrestore(&chan_lock, flags); - if (master != new_master) { - if (debug & DEBUG_MAIN) { - module_printk(KERN_NOTICE, "%s: Span ('%s') is new master\n", __FUNCTION__, - (new_master)? new_master->name: "no master"); - } - } - master = new_master; + __dahdi_find_master_span(); return 0; }