From owner-p4-projects@FreeBSD.ORG Tue Apr 1 21:02:46 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 15E771065671; Tue, 1 Apr 2008 21:02:46 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C961D1065675 for ; Tue, 1 Apr 2008 21:02:45 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id B84158FC18 for ; Tue, 1 Apr 2008 21:02:45 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m31L2jA7010488 for ; Tue, 1 Apr 2008 21:02:45 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m31L2jkw010486 for perforce@freebsd.org; Tue, 1 Apr 2008 21:02:45 GMT (envelope-from hselasky@FreeBSD.org) Date: Tue, 1 Apr 2008 21:02:45 GMT Message-Id: <200804012102.m31L2jkw010486@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 139164 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Apr 2008 21:02:46 -0000 http://perforce.freebsd.org/chv.cgi?CH=139164 Change 139164 by hselasky@hselasky_laptop001 on 2008/04/01 21:02:19 To solve the following three problems I have to make a set of BUS-DMA related changes. Commit 2/3 P1) I should pass a valid lock function to "bus_dma_tag_create". P2) Currently the error code EINPROGRESS is not handled at all, when returned by "bus_dmamap_load". I have created a new condition variable that will be used to wait for the done callback. P3) Ensure that all USB page caches on an USB transfer are loaded in serial, mostly in case of page bouncing. Changes in "usb_subr.c" from the top: 1) Create new function that solves P1. 2) Some changes in "usbd_pc_common_mem_cb" to separate the two different use cases: 2a) We are loaded kernel virtual memory into DMA through "usbd_pc_load_mem". 2b) We are loading a BUS-DMA buffer into DMA through "usbd_pc_alloc_mem". 3) "usbd_dma_tag_setup" has changed name to "usbd_dma_tag_find" and now take 3 arguments instead of 5. Functionality is the same. 4) Some changes here and there because some function parameters have moved into new structures. 5) Handle the "EINPROGRESS" case when returned by "bus_dmamap_load()" (P2). 6) "usbd_pc_load_mem()" now calls the done callback in case "size == 0", hence we removed the direct "dma_refcount" increment to make the function more generally available to non-USB drivers. 7) The NetBSD BUS-DMA implementation has not been completly updated and is probably a bit broken. 8) New function "usbd_dma_tag_setup". Affected files ... .. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#102 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/usb_subr.c#102 (text+ko) ==== @@ -88,12 +88,15 @@ static void usbd_suspend_resume_sub(struct usbd_device *udev, device_t dev, uint8_t do_suspend); #ifdef __FreeBSD__ +static void usbd_dma_lock_cb(void *arg, bus_dma_lock_op_t op); static int32_t usbd_m_copy_in_cb(void *arg, void *src, uint32_t count); static void usbd_pc_alloc_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error); +static void usbd_pc_load_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error); +static void usbd_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error, uint8_t isload); #else static int32_t usbd_m_copy_in_cb(void *arg, caddr_t src, uint32_t count); -static void usbd_pc_alloc_mem_cb(struct usbd_page_cache *pc, bus_dma_segment_t *segs, int nseg, int error); +static void usbd_pc_common_mem_cb(struct usbd_page_cache *pc, bus_dma_segment_t *segs, int nseg, int error, uint8_t isload); #endif static void usbd_config_td_thread(void *arg);; @@ -2519,19 +2522,29 @@ #ifdef __FreeBSD__ /*------------------------------------------------------------------------* + * usbd_dma_lock_cb - dummy callback + *------------------------------------------------------------------------*/ +static void +usbd_dma_lock_cb(void *arg, bus_dma_lock_op_t op) +{ + /* we use "mtx_owned()" instead of this function */ + return; +} + +/*------------------------------------------------------------------------* * usbd_dma_tag_create - allocate a DMA tag * * NOTE: If the "align" parameter has a value of 1 the DMA-tag will * allow multi-segment mappings. Else all mappings are single-segment. *------------------------------------------------------------------------*/ void -usbd_dma_tag_create(bus_dma_tag_t tag_parent, struct usbd_dma_tag *udt, +usbd_dma_tag_create(struct usbd_dma_tag *udt, uint32_t size, uint32_t align) { bus_dma_tag_t tag; if (bus_dma_tag_create - ( /* parent */ tag_parent, + ( /* parent */ udt->tag_parent->tag, /* alignment */ align, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, @@ -2544,8 +2557,8 @@ /* maxsegsz */ (align == 1) ? USB_PAGE_SIZE : size, /* flags */ 0, - /* lock */ NULL, - /* */ NULL, + /* lockfn */ &usbd_dma_lock_cb, + /* lockarg */ NULL, &tag)) { tag = NULL; } @@ -2570,7 +2583,29 @@ usbd_pc_alloc_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct usbd_xfer *xfer; + usbd_pc_common_mem_cb(arg, segs, nseg, error, 0); + return; +} + +/*------------------------------------------------------------------------* + * usbd_pc_load_mem_cb - BUS-DMA callback function + *------------------------------------------------------------------------*/ +static void +usbd_pc_load_mem_cb(void *arg, bus_dma_segment_t *segs, + int nseg, int error) +{ + usbd_pc_common_mem_cb(arg, segs, nseg, error, 1); + return; +} + +/*------------------------------------------------------------------------* + * usbd_pc_common_mem_cb - BUS-DMA callback function + *------------------------------------------------------------------------*/ +static void +usbd_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs, + int nseg, int error, uint8_t isload) +{ + struct usbd_dma_parent_tag *uptag; struct usbd_page_cache *pc; struct usbd_page *pg; uint32_t rem; @@ -2578,7 +2613,7 @@ uint8_t ext_seg; /* extend last segment */ pc = arg; - xfer = pc->xfer; + uptag = pc->tag_parent; /* * XXX There is sometimes recursive locking here. @@ -2588,16 +2623,7 @@ */ if (error) { - if (xfer) { - owned = mtx_owned(xfer->priv_mtx); - if (!owned) - mtx_lock(xfer->priv_mtx); - xfer->usb_root->dma_error = 1; - usbd_bdma_done_event(xfer->usb_root); - if (!owned) - mtx_unlock(xfer->priv_mtx); - } - return; + goto done; } pg = pc->page_start; pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1); @@ -2627,14 +2653,19 @@ if (ext_seg && pc->ismultiseg) { (pg + 1)->physaddr = pg->physaddr + USB_PAGE_SIZE; } - if (xfer) { - owned = mtx_owned(xfer->priv_mtx); - if (!owned) - mtx_lock(xfer->priv_mtx); - usbd_bdma_done_event(xfer->usb_root); - if (!owned) - mtx_unlock(xfer->priv_mtx); +done: + owned = mtx_owned(uptag->mtx); + if (!owned) + mtx_lock(uptag->mtx); + + uptag->dma_error = (error ? 1 : 0); + if (isload) { + (uptag->func) (uptag); + } else { + cv_broadcast(uptag->cv); } + if (!owned) + mtx_unlock(uptag->mtx); return; } @@ -2646,13 +2677,16 @@ * Else: Failure *------------------------------------------------------------------------*/ uint8_t -usbd_pc_alloc_mem(bus_dma_tag_t parent_tag, struct usbd_dma_tag *utag, - struct usbd_page_cache *pc, struct usbd_page *pg, uint32_t size, - uint32_t align, uint8_t utag_max) +usbd_pc_alloc_mem(struct usbd_page_cache *pc, struct usbd_page *pg, + uint32_t size, uint32_t align) { - bus_dma_tag_t tag; + struct usbd_dma_parent_tag *uptag; + struct usbd_dma_tag *utag; bus_dmamap_t map; void *ptr; + int err; + + uptag = pc->tag_parent; if (align != 1) { /* @@ -2689,16 +2723,13 @@ #endif } /* get the correct DMA tag */ - utag = usbd_dma_tag_setup(parent_tag, utag, size, align, utag_max); + utag = usbd_dma_tag_find(uptag, size, align); if (utag == NULL) { goto error; } - /* get the DMA tag */ - tag = utag->tag; - /* allocate memory */ - if (bus_dmamem_alloc - (tag, &ptr, (BUS_DMA_WAITOK | BUS_DMA_COHERENT), &map)) { + if (bus_dmamem_alloc( + utag->tag, &ptr, (BUS_DMA_WAITOK | BUS_DMA_COHERENT), &map)) { goto error; } /* setup page cache */ @@ -2707,14 +2738,24 @@ pc->page_offset_buf = 0; pc->page_offset_end = size; pc->map = map; - pc->tag = tag; + pc->tag = utag->tag; pc->ismultiseg = (align == 1); + mtx_lock(uptag->mtx); + /* load memory into DMA */ - if (bus_dmamap_load - (tag, map, ptr, size, &usbd_pc_alloc_mem_cb, - pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT))) { - bus_dmamem_free(tag, ptr, map); + err = bus_dmamap_load( + utag->tag, map, ptr, size, &usbd_pc_alloc_mem_cb, + pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT)); + + if (err == EINPROGRESS) { + cv_wait(uptag->cv, uptag->mtx); + err = 0; + } + mtx_unlock(uptag->mtx); + + if (err || uptag->dma_error) { + bus_dmamem_free(utag->tag, ptr, map); goto error; } bzero(ptr, size); @@ -2759,25 +2800,31 @@ void usbd_pc_load_mem(struct usbd_page_cache *pc, uint32_t size) { - /* sanity check */ - if (pc->xfer == NULL) { - panic("This page cache is not loadable!\n"); - return; - } /* setup page cache */ pc->page_offset_buf = 0; pc->page_offset_end = size; pc->ismultiseg = 1; + mtx_assert(pc->tag_parent->mtx, MA_OWNED); + if (size > 0) { - pc->xfer->usb_root->dma_refcount++; - - /* try to load memory into DMA */ + /* + * Try to load memory into DMA and wait for the callback to + * be called in all cases: + */ if (bus_dmamap_load( pc->tag, pc->map, pc->buffer, size, - &usbd_pc_alloc_mem_cb, pc, 0)) { + &usbd_pc_load_mem_cb, pc, BUS_DMA_WAITOK)) { } + } else { + + /* + * Call callback so that refcount is decremented + * properly: + */ + pc->tag_parent->dma_error = 0; + (pc->tag_parent->func) (pc->tag_parent); } return; } @@ -2816,28 +2863,23 @@ { struct usbd_memory_info *info; struct usbd_dma_tag *utag; - bus_dma_tag_t tag; + + /* get info */ + info = pc->tag_parent->info; /* sanity check */ - if (pc->xfer == NULL) { + if (info == NULL) { goto error; } - info = pc->xfer->usb_root; - tag = pc->xfer->udev->bus->dma_tag_parent; - - utag = usbd_dma_tag_setup(tag, info->dma_tag_p, - size, 1, info->dma_tag_max); + utag = usbd_dma_tag_find(pc->tag_parent, size, 1); if (utag == NULL) { goto error; } - /* get the DMA tag */ - tag = utag->tag; - /* create DMA map */ - if (bus_dmamap_create(tag, 0, &(pc->map))) { + if (bus_dmamap_create(utag->tag, 0, &(pc->map))) { goto error; } - pc->tag = tag; + pc->tag = utag->tag; return 0; /* success */ error: @@ -2873,7 +2915,7 @@ * allow multi-segment mappings. Else all mappings are single-segment. *------------------------------------------------------------------------*/ void -usbd_dma_tag_create(bus_dma_tag_t tag_parent, struct usbd_dma_tag *udt, +usbd_dma_tag_create(struct usbd_dma_tag *udt, uint32_t size, uint32_t align) { uint32_t nseg; @@ -2890,7 +2932,7 @@ if (udt->p_seg == NULL) { return; } - udt->tag = tag_parent; + udt->tag = udt->tag_parent->tag; udt->n_seg = nseg; return; } @@ -2906,19 +2948,20 @@ } /*------------------------------------------------------------------------* - * usbd_pc_alloc_mem_cb - BUS-DMA callback function + * usbd_pc_common_mem_cb - BUS-DMA callback function *------------------------------------------------------------------------*/ static void -usbd_pc_alloc_mem_cb(struct usbd_page_cache *pc, bus_dma_segment_t *segs, - int nseg, int error) +usbd_pc_common_mem_cb(struct usbd_page_cache *pc, bus_dma_segment_t *segs, + int nseg, int error, uint8_t isload) { + struct usbd_dma_parent_tag *uptag; struct usbd_xfer *xfer; struct usbd_page *pg; uint32_t rem; uint8_t owned; uint8_t ext_seg; /* extend last segment */ - xfer = pc->xfer; + uptag = pc->tag_parent; /* * XXX There is sometimes recursive locking here. @@ -2928,16 +2971,7 @@ */ if (error) { - if (xfer) { - owned = mtx_owned(xfer->priv_mtx); - if (!owned) - mtx_lock(xfer->priv_mtx); - xfer->usb_root->dma_error = 1; - usbd_bdma_done_event(xfer->usb_root); - if (!owned) - mtx_unlock(xfer->priv_mtx); - } - return; + goto done; } pg = pc->page_start; pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1); @@ -2967,14 +3001,19 @@ if (ext_seg && pc->ismultiseg) { (pg + 1)->physaddr = pg->physaddr + USB_PAGE_SIZE; } - if (xfer) { - owned = mtx_owned(xfer->priv_mtx); - if (!owned) - mtx_lock(xfer->priv_mtx); - usbd_bdma_done_event(xfer->usb_root); - if (!owned) - mtx_unlock(xfer->priv_mtx); +done: + owned = mtx_owned(uptag->mtx); + if (!owned) + mtx_lock(uptag->mtx); + + uptag->dma_error = (error ? 1 : 0); + if (isload) { + (uptag->func) (uptag); + } else { + cv_broadcast(uptag->cv); } + if (!owned) + mtx_unlock(uptag->mtx); return; } @@ -2986,15 +3025,16 @@ * Else: Failure *------------------------------------------------------------------------*/ uint8_t -usbd_pc_alloc_mem(bus_dma_tag_t parent_tag, struct usbd_dma_tag *utag, - struct usbd_page_cache *pc, struct usbd_page *pg, uint32_t size, - uint32_t align, uint8_t utag_max) +usbd_pc_alloc_mem(struct usbd_page_cache *pc, struct usbd_page *pg, + uint32_t size, uint32_t align) { + struct usbd_dma_parent_tag *uptag; caddr_t ptr = NULL; - bus_dma_tag_t tag; bus_dmamap_t map; int seg_count; + uptag = pc->tag_parent; + if (align != 1) { /* * The alignment must be greater or equal to the @@ -3009,26 +3049,23 @@ } } /* get the correct DMA tag */ - utag = usbd_dma_tag_setup(parent_tag, utag, size, align, utag_max); + utag = usbd_dma_tag_find(pc->tag_parent, size, align); if (utag == NULL) { goto done_5; } - /* get the DMA tag */ - tag = utag->tag; - - if (bus_dmamem_alloc(tag, size, align, 0, utag->p_seg, + if (bus_dmamem_alloc(utag->tag, size, align, 0, utag->p_seg, utag->n_seg, &seg_count, BUS_DMA_WAITOK)) { goto done_4; } - if (bus_dmamem_map(tag, utag->p_seg, seg_count, size, + if (bus_dmamem_map(utag->tag, utag->p_seg, seg_count, size, &ptr, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) { goto done_3; } - if (bus_dmamap_create(tag, size, utag->n_seg, (align == 1) ? + if (bus_dmamap_create(utag->tag, size, utag->n_seg, (align == 1) ? USB_PAGE_SIZE : size, 0, BUS_DMA_WAITOK, &map)) { goto done_2; } - if (bus_dmamap_load(tag, map, ptr, size, NULL, + if (bus_dmamap_load(utag->tag, map, ptr, size, NULL, BUS_DMA_WAITOK)) { goto done_1; } @@ -3050,10 +3087,10 @@ pc->page_offset_buf = 0; pc->page_offset_end = size; pc->map = map; - pc->tag = tag; + pc->tag = utag->tag; pc->ismultiseg = (align == 1); - usbd_pc_alloc_mem_cb(pc, utag->p_seg, seg_count, 0); + usbd_pc_common_mem_cb(pc, utag->p_seg, seg_count, 0, 0); bzero(ptr, size); @@ -3112,11 +3149,6 @@ { int error; - /* sanity check */ - if (pc->xfer == NULL) { - panic("This page cache is not loadable!\n"); - return; - } /* setup page cache */ pc->page_offset_buf = 0; pc->page_offset_end = size; @@ -3124,9 +3156,7 @@ if (size > 0) { - pc->xfer->usb_root->dma_refcount++; - - /* try to load memory into DMA */ + /* try to load memory into DMA using using no wait option */ if (bus_dmamap_load(pc->tag, pc->map, pc->buffer, size, NULL, BUS_DMA_NOWAIT)) { error = ENOMEM; @@ -3134,8 +3164,15 @@ error = 0; } - usbd_pc_alloc_mem_cb(pc, pc->map->dm_segs, - pc->map->dm_nsegs, error); + usbd_pc_common_mem_cb(pc, pc->map->dm_segs, + pc->map->dm_nsegs, error, 1); + } else { + /* + * Call callback so that refcount is decremented + * properly: + */ + pc->tag_parent->dma_error = 0; + (pc->tag_parent->func) (pc->tag_parent); } return; } @@ -3182,17 +3219,15 @@ { struct usbd_memory_info *info; struct usbd_dma_tag *utag; - bus_dma_tag_t tag; + + /* get info */ + info = pc->tag_parent->info; /* sanity check */ - if (pc->xfer == NULL) { + if (info == NULL) { goto error; } - info = pc->xfer->usb_root; - tag = pc->xfer->udev->bus->dma_tag_parent; - - utag = usbd_dma_tag_setup(tag, info->dma_tag_p, - size, 1, info->dma_tag_max); + utag = usbd_dma_tag_find(pc->tag_parent, size, 1); if (utag == NULL) { goto error; } @@ -3759,19 +3794,25 @@ } /*------------------------------------------------------------------------* - * usbd_bus_tag_setup - factored out code + * usbd_dma_tag_find - factored out code *------------------------------------------------------------------------*/ struct usbd_dma_tag * -usbd_dma_tag_setup(bus_dma_tag_t tag_parent, struct usbd_dma_tag *udt, - uint32_t size, uint32_t align, uint8_t nudt) +usbd_dma_tag_find(struct usbd_dma_parent_tag *udpt, + uint32_t size, uint32_t align) { + struct usbd_dma_tag *udt; + uint8_t nudt; + __KASSERT(align > 0, ("Invalid parameter align = 0!\n")); __KASSERT(size > 0, ("Invalid parameter size = 0!\n")); + udt = udpt->utag_first; + nudt = udpt->utag_max; + while (nudt--) { if (udt->align == 0) { - usbd_dma_tag_create(tag_parent, udt, size, align); + usbd_dma_tag_create(udt, size, align); if (udt->tag == NULL) { return (NULL); } @@ -3788,19 +3829,70 @@ } /*------------------------------------------------------------------------* + * usbd_dma_tag_setup - initialise USB DMA tags + *------------------------------------------------------------------------*/ +void +usbd_dma_tag_setup(struct usbd_dma_parent_tag *udpt, + struct usbd_dma_tag *udt, bus_dma_tag_t dmat, + struct mtx *mtx, usbd_dma_callback_t *func, + struct usbd_memory_info *info, uint8_t ndmabits, + uint8_t nudt) +{ + bzero(udpt, sizeof(*udpt)); + + /* sanity checking */ + if ((nudt == 0) || + (ndmabits == 0) || + (mtx == NULL)) { + /* something is corrupt */ + return; + } + /* initialise condition variable */ + cv_init(udpt->cv, "USB DMA CV"); + + /* store some information */ + udpt->mtx = mtx; + udpt->info = info; + udpt->func = func; + udpt->tag = dmat; + udpt->utag_first = udt; + udpt->utag_max = nudt; + udpt->dma_bits = ndmabits; + + while (nudt--) { + bzero(udt, sizeof(*udt)); + udt->tag_parent = udpt; + udt++; + } + return; +} + +/*------------------------------------------------------------------------* * usbd_bus_tag_unsetup - factored out code *------------------------------------------------------------------------*/ void -usbd_dma_tag_unsetup(struct usbd_dma_tag *udt, uint8_t nudt) +usbd_dma_tag_unsetup(struct usbd_dma_parent_tag *udpt) { + struct usbd_dma_tag *udt; + uint8_t nudt; + + udt = udpt->utag_first; + nudt = udpt->utag_max; + while (nudt--) { if (udt->align) { + /* destroy the USB DMA tag */ usbd_dma_tag_destroy(udt); udt->align = 0; } udt++; } + + if (udpt->utag_max) { + /* destroy the condition variable */ + cv_destroy(udpt->cv); + } return; } @@ -3834,9 +3926,10 @@ usbd_bus_mem_alloc_all_cb(struct usbd_bus *bus, struct usbd_page_cache *pc, struct usbd_page *pg, uint32_t size, uint32_t align) { - if (usbd_pc_alloc_mem(bus->dma_tag_parent, - bus->dma_tags, pc, pg, size, align, - USB_BUS_DMA_TAG_MAX)) { + /* need to initialize the page cache */ + pc->tag_parent = bus->dma_parent_tag; + + if (usbd_pc_alloc_mem(pc, pg, size, align)) { bus->alloc_failed = 1; } return; @@ -3850,7 +3943,8 @@ * Else: Failure *------------------------------------------------------------------------*/ uint8_t -usbd_bus_mem_alloc_all(struct usbd_bus *bus, usbd_bus_mem_cb_t *cb) +usbd_bus_mem_alloc_all(struct usbd_bus *bus, bus_dma_tag_t dmat, + usbd_bus_mem_cb_t *cb) { bus->alloc_failed = 0; @@ -3859,6 +3953,9 @@ LIST_INIT(&(bus->intr_list_head)); + usbd_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, + dmat, &(bus->mtx), NULL, NULL, 32, USB_BUS_DMA_TAG_MAX); + if (cb) { cb(bus, &usbd_bus_mem_alloc_all_cb); } @@ -3888,7 +3985,7 @@ if (cb) { cb(bus, &usbd_bus_mem_free_all_cb); } - usbd_dma_tag_unsetup(bus->dma_tags, USB_BUS_DMA_TAG_MAX); + usbd_dma_tag_unsetup(bus->dma_parent_tag); mtx_destroy(&(bus->mtx)); @@ -3921,10 +4018,12 @@ parm->dma_page_cache_ptr++; return (0); } - if (usbd_pc_alloc_mem(parm->udev->bus->dma_tag_parent, - parm->dma_tag_p, parm->dma_page_cache_ptr, - parm->dma_page_ptr, size, align, - parm->dma_tag_max)) { + /* need to initialize the page cache */ + parm->dma_page_cache_ptr->tag_parent = + &(parm->curr_xfer->usb_root->dma_parent_tag); + + if (usbd_pc_alloc_mem(parm->dma_page_cache_ptr, + parm->dma_page_ptr, size, align)) { return (1); /* failure */ } if (info) {