svn commit: r247421 - stable/8/sys/dev/amr

John Baldwin jhb at FreeBSD.org
Wed Feb 27 21:03:20 UTC 2013


Author: jhb
Date: Wed Feb 27 21:03:19 2013
New Revision: 247421
URL: http://svnweb.freebsd.org/changeset/base/247421

Log:
  MFC 240692,241228:
  Adjust the ioctl workaround from r234501:
  - Ensure the native ioctl path always allocates a 4kb buffer if a request
    uses a buffer size of 0.
  - Rounding all small requests up to 32k swamped the controller causing
    firmware hangs.  Instead, round requests smaller than 64k up to the next
    power of 2 as a general rule.  To handle the one known special case of a
    command that accepts a 12k buffer returning a 24k-ish reply, round
    requests between 8k and 16k up to 32k rather than 16k.  The result is
    that commands less than 8k should now be rounded up to a smaller size
    (either 4k or 8k) rather than 32k.

Modified:
  stable/8/sys/dev/amr/amr.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/amr/   (props changed)

Modified: stable/8/sys/dev/amr/amr.c
==============================================================================
--- stable/8/sys/dev/amr/amr.c	Wed Feb 27 21:03:09 2013	(r247420)
+++ stable/8/sys/dev/amr/amr.c	Wed Feb 27 21:03:19 2013	(r247421)
@@ -546,13 +546,19 @@ shutdown_out:
  * The amr(4) firmware relies on this feature.  In fact, it assumes
  * the buffer is always a power of 2 up to a max of 64k.  There is
  * also at least one case where it assumes a buffer less than 16k is
- * greater than 16k.  Force a minimum buffer size of 32k and round
- * sizes between 32k and 64k up to 64k as a workaround.
+ * greater than 16k.  However, forcing all buffers to a size of 32k
+ * causes stalls in the firmware.  Force each command smaller than
+ * 64k up to the next power of two except that commands between 8k
+ * and 16k are rounded up to 32k instead of 16k.
  */
 static unsigned long
 amr_ioctl_buffer_length(unsigned long len)
 {
 
+    if (len <= 4 * 1024)
+	return (4 * 1024);
+    if (len <= 8 * 1024)
+	return (8 * 1024);
     if (len <= 32 * 1024)
 	return (32 * 1024);
     if (len <= 64 * 1024)
@@ -859,11 +865,8 @@ amr_ioctl(struct cdev *dev, u_long cmd, 
 
     /* handle inbound data buffer */
     real_length = amr_ioctl_buffer_length(au_length);
+    dp = malloc(real_length, M_AMR, M_WAITOK|M_ZERO);
     if (au_length != 0 && au_cmd[0] != 0x06) {
-	if ((dp = malloc(real_length, M_AMR, M_WAITOK|M_ZERO)) == NULL) {
-	    error = ENOMEM;
-	    goto out;
-	}
 	if ((error = copyin(au_buffer, dp, au_length)) != 0) {
 	    free(dp, M_AMR);
 	    return (error);
@@ -933,8 +936,7 @@ amr_ioctl(struct cdev *dev, u_long cmd, 
 	error = copyout(dp, au_buffer, au_length);
     }
     debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
-    if (dp != NULL)
-	debug(2, "%p status 0x%x", dp, ac->ac_status);
+    debug(2, "%p status 0x%x", dp, ac->ac_status);
     *au_statusp = ac->ac_status;
 
 out:


More information about the svn-src-all mailing list