From nobody@FreeBSD.org  Tue Feb  1 09:32:29 2005
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 4F30716A4CF
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  1 Feb 2005 09:32:29 +0000 (GMT)
Received: from www.freebsd.org (www.freebsd.org [216.136.204.117])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 4139243D62
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  1 Feb 2005 09:32:27 +0000 (GMT)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id j119WQVR072721
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 1 Feb 2005 09:32:26 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id j119WQ8r072690;
	Tue, 1 Feb 2005 09:32:26 GMT
	(envelope-from nobody)
Message-Id: <200502010932.j119WQ8r072690@www.freebsd.org>
Date: Tue, 1 Feb 2005 09:32:26 GMT
From: Petr Lampa <lampa@fit.vutbr.cz>
To: freebsd-gnats-submit@FreeBSD.org
Subject: i386 bus_dmamap_create() bug
X-Send-Pr-Version: www-2.3

>Number:         76944
>Category:       i386
>Synopsis:       [busdma] [patch] i386 bus_dmamap_create() bug
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jhb
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Feb 01 09:40:10 GMT 2005
>Closed-Date:    Wed Jul 14 14:13:43 UTC 2010
>Last-Modified:  Wed Jul 14 14:50:01 UTC 2010
>Originator:     Petr Lampa
>Release:        5.3-STABLE
>Organization:
BUT FIT
>Environment:
FreeBSD 5.3-STABLE FreeBSD 5.3-STABLE #16: Fri Jan 28 14:26:
51 CET 2005     /usr/src/sys/i386/compile/VIDEO1  i386
    
>Description:
Bus_dmamap_create() fails when more then MAX_BPAGES bounce pages is already allocated. The result is panic or page fault during boot.

bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
{
..
        maxpages = MIN(MAX_BPAGES, Maxmem - atop(dmat->lowaddr));
        if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
            || (dmat->map_count > 0 && total_bpages < maxpages)) {
                int pages;
                ...
                pages = MAX(atop(dmat->maxsize), 1);

At this location maxpages=512, total_bpages=513, dmat->maxsize=131072, pages=32

                pages = MIN(maxpages - total_bpages, pages);

Here pages=-1!

                if (alloc_bounce_pages(dmat, pages) < pages)

                if (alloc_bounce_pages(dmat, pages) < pages)
                        error = ENOMEM;

Here all kernel virtual memory is lost (or something like that),
the result was spurious page fault 12 or other panic after while.

I've loooked in CVS and it seems to me, that bus_dmamap_create() was
not updated after introduction of bounce zones. The first
test that leads to alloc_bounce_pages() is wrong in any case.


>How-To-Repeat:
Insert two 3Ware 9500 controllers into machine and boot. Page fault 12 results.
>Fix:
I've tried to fixed this and my solution works for me, but it needs some inspection. The same problem probably exists in other architectures.

fix #1: change parenthesis here (I'am no sure, but the next
code only add pages when there are not sufficient pages allocated,
so it shouldn't be called if total_bpages>=maxpages at all):

        if (((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
            || dmat->map_count > 0) && total_bpages < maxpages)) {

fix #2: don't check total_bpages, but bounce zone's bz->total_bpages

        bz = dmat->bounce_zone;
        if (((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
            || dmat->map_count > 0) && bz->total_bpages < maxpages)) {

        ...
                    pages = MIN(maxpages - bz->total_bpages, pages);

The whole patch is here:

*** busdma_machdep.c    Sat Dec  4 06:55:10 2004
--- /tmp/busdma_machdep.c       Fri Jan 28 10:37:35 2005
***************
*** 393,403 ****
--- 393,405 ----

                /* Must bounce */
                int maxpages;
+               struct bounce_zone *bz;

                if (dmat->bounce_zone == NULL) {
                        if ((error = alloc_bounce_zone(dmat)) != 0)
                                return (error);
                }
+               bz = dmat->bounce_zone;

                *mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
                                             M_NOWAIT | M_ZERO);
***************
*** 415,422 ****
                 * basis up to a sane limit.
                 */
                maxpages = MIN(MAX_BPAGES, Maxmem - atop(dmat->lowaddr));
!               if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
!                || (dmat->map_count > 0 && total_bpages < maxpages)) {
                        int pages;

                        if (dmat->lowaddr > bounce_lowaddr) {
--- 417,424 ----
                 * basis up to a sane limit.
                 */
                maxpages = MIN(MAX_BPAGES, Maxmem - atop(dmat->lowaddr));
!               if (((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
!                || dmat->map_count > 0) && bz->total_bpages < maxpages) {
                        int pages;

                        if (dmat->lowaddr > bounce_lowaddr) {
***************
*** 428,434 ****
                                      "not implemented");
                        }
                        pages = MAX(atop(dmat->maxsize), 1);
!                       pages = MIN(maxpages - total_bpages, pages);
                        if (alloc_bounce_pages(dmat, pages) < pages)
                                error = ENOMEM;

--- 430,436 ----
                                      "not implemented");
                        }
                        pages = MAX(atop(dmat->maxsize), 1);
!                       pages = MIN(maxpages - bz->total_bpages, pages);
                        if (alloc_bounce_pages(dmat, pages) < pages)
                                error = ENOMEM;




  
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-i386->jhb 
Responsible-Changed-By: remko 
Responsible-Changed-When: Wed Jul 14 05:53:46 UTC 2010 
Responsible-Changed-Why:  
Hi John, you touched busdma_machdep the latest on i386 at least. Would you be so kind to see whether the patch is applicable? The code in question is still available so either this had been resolved in a different way, is not resolved yet, or is not a problem :-). 

Thanks, 

http://www.freebsd.org/cgi/query-pr.cgi?pr=76944 
State-Changed-From-To: open->closed 
State-Changed-By: scottl 
State-Changed-When: Wed Jul 14 14:13:01 UTC 2010 
State-Changed-Why:  
Bug already fixed a different way. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=76944 

From: Scott Long <scottl@samsco.org>
To: bug-followup@FreeBSD.org, lampa@fit.vutbr.cz
Cc:  
Subject: Re: i386/76944: [busdma] [patch] i386 bus_dmamap_create() bug
Date: Wed, 14 Jul 2010 08:11:47 -0600

 The underrun that was the root of this problem has been fixed a =
 different way.  Note that it was intentional for total_bpages to be a =
 global limit, so this patch is not applicable.
 
 Scott
 
>Unformatted:
