From owner-svn-src-stable@FreeBSD.ORG Wed Feb 27 21:03:10 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id A5025469; Wed, 27 Feb 2013 21:03:10 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 7DE92F2A; Wed, 27 Feb 2013 21:03:10 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1RL3AY2003814; Wed, 27 Feb 2013 21:03:10 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1RL3Atr003813; Wed, 27 Feb 2013 21:03:10 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201302272103.r1RL3Atr003813@svn.freebsd.org> From: John Baldwin Date: Wed, 27 Feb 2013 21:03:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r247420 - stable/9/sys/dev/amr X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Feb 2013 21:03:10 -0000 Author: jhb Date: Wed Feb 27 21:03:09 2013 New Revision: 247420 URL: http://svnweb.freebsd.org/changeset/base/247420 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/9/sys/dev/amr/amr.c Directory Properties: stable/9/sys/ (props changed) stable/9/sys/dev/ (props changed) Modified: stable/9/sys/dev/amr/amr.c ============================================================================== --- stable/9/sys/dev/amr/amr.c Wed Feb 27 20:54:45 2013 (r247419) +++ stable/9/sys/dev/amr/amr.c Wed Feb 27 21:03:09 2013 (r247420) @@ -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: