[svn-commits] kpfleming: linux/trunk r6791 - /linux/trunk/drivers/dahdi/dahdi-base.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jun 29 15:05:48 CDT 2009


Author: kpfleming
Date: Mon Jun 29 15:05:43 2009
New Revision: 6791

URL: http://svn.asterisk.org/svn-view/dahdi?view=rev&rev=6791
Log:
Improve MMX safety for DAHDI echo cancellers on 32-bit x86 systems.

Replaces the standard kernel FPU save/restore operations with custom written
versions for 32-bit x86 CPUs, which have been tested to be reliable and safe
to use.

(closes issue #13500)
Reported by: tzafrir
Patches:
      dahdi_mmx_fix.diff uploaded by tzafrir (license 46)


Modified:
    linux/trunk/drivers/dahdi/dahdi-base.c

Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svn.asterisk.org/svn-view/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=6791&r1=6790&r2=6791
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Mon Jun 29 15:05:43 2009
@@ -289,7 +289,56 @@
 static int dahdi_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit);
 
 #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP)
+#if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_I386)
+struct fpu_save_buf {
+	unsigned long cr0;
+	unsigned long fpu_buf[128];
+};
+
+static DEFINE_PER_CPU(struct fpu_save_buf, fpu_buf);
+
+/** dahdi_kernel_fpu_begin() - Save floating point registers
+ *
+ * This function is similar to kernel_fpu_begin() . However it is
+ * designed to work in an interrupt context. Restoring must be done with
+ * dahdi_kernel_fpu_end().
+ *
+ * Furthermore, the whole code between the call to
+ * dahdi_kernel_fpu_begin() and dahdi_kernel_fpu_end() must reside
+ * 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)
+ * */
+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));
+}
+
+/** dahdi_kernel_fpu_end() - restore floating point context
+ *
+ * Must be used with context saved by dahdi_kernel_fpu_begin(). See its
+ * documentation for further information.
+ */
+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));
+}
+
+#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
+#endif
+
 #endif
 
 struct dahdi_timer {
@@ -6659,7 +6708,7 @@
 
 		}
 #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP)
-		kernel_fpu_end();
+		dahdi_kernel_fpu_end();
 #endif
 	}
 	spin_unlock_irqrestore(&ss->lock, flags);
@@ -6991,6 +7040,7 @@
 	int abort=0;
 	int res;
 	int left, x;
+
 
 	while(bytes) {
 #if defined(CONFIG_DAHDI_NET)  || defined(CONFIG_DAHDI_PPP)
@@ -7553,7 +7603,7 @@
 #endif
 		__dahdi_process_getaudio_chunk(chan, buf);
 #ifdef CONFIG_DAHDI_MMX
-		kernel_fpu_end();
+		dahdi_kernel_fpu_end();
 #endif
 	}
 }
@@ -7638,7 +7688,7 @@
 #endif
 		__dahdi_process_putaudio_chunk(chan, buf);
 #ifdef CONFIG_DAHDI_MMX
-		kernel_fpu_end();
+		dahdi_kernel_fpu_end();
 #endif
 	}
 	__dahdi_putbuf_chunk(chan, buf);
@@ -7860,7 +7910,7 @@
 				}
 			}
 #ifdef CONFIG_DAHDI_MMX
-			kernel_fpu_end();
+			dahdi_kernel_fpu_end();
 #endif
 		}
 		/* do all the pseudo/conferenced channel transmits (putbuf's) */




More information about the svn-commits mailing list