12336Snarayan /* 22336Snarayan * CDDL HEADER START 32336Snarayan * 42336Snarayan * The contents of this file are subject to the terms of the 52336Snarayan * Common Development and Distribution License (the "License"). 62336Snarayan * You may not use this file except in compliance with the License. 72336Snarayan * 82336Snarayan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92336Snarayan * or http://www.opensolaris.org/os/licensing. 102336Snarayan * See the License for the specific language governing permissions 112336Snarayan * and limitations under the License. 122336Snarayan * 132336Snarayan * When distributing Covered Code, include this CDDL HEADER in each 142336Snarayan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152336Snarayan * If applicable, add the following below this CDDL HEADER, with the 162336Snarayan * fields enclosed by brackets "[]" replaced with your own identifying 172336Snarayan * information: Portions Copyright [yyyy] [name of copyright owner] 182336Snarayan * 192336Snarayan * CDDL HEADER END 202336Snarayan */ 212336Snarayan 222336Snarayan /* 232336Snarayan * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 242336Snarayan * Use is subject to license terms. 252336Snarayan */ 262336Snarayan 272336Snarayan #pragma ident "%Z%%M% %I% %E% SMI" 282336Snarayan 292336Snarayan #include <sys/types.h> 302336Snarayan #include <sys/sysmacros.h> 312336Snarayan #include <sys/cmn_err.h> 322336Snarayan #include <sys/errno.h> 332336Snarayan #include <sys/kmem.h> 342336Snarayan #include <sys/ksynch.h> 352336Snarayan #include <sys/stream.h> 362336Snarayan #include <sys/ddi.h> 372336Snarayan #include <sys/sunddi.h> 382336Snarayan #include <sys/vio_util.h> 392336Snarayan 402336Snarayan /* 412336Snarayan * Create a pool of mblks from which future vio_allocb() requests 422336Snarayan * will be serviced. 432336Snarayan * 442336Snarayan * NOTE: num_mblks has to non-zero and a power-of-2 452336Snarayan * 462336Snarayan * Returns 0 on success or EINVAL if num_mblks is zero or not 472336Snarayan * a power of 2. 482336Snarayan */ 492336Snarayan int 502336Snarayan vio_create_mblks(uint64_t num_mblks, size_t mblk_size, vio_mblk_pool_t **poolp) 512336Snarayan { 522336Snarayan vio_mblk_pool_t *vmplp; 532336Snarayan vio_mblk_t *vmp; 542336Snarayan uint8_t *datap; 552336Snarayan int i; 562336Snarayan 572336Snarayan if (!(num_mblks) || (!ISP2(num_mblks))) { 582336Snarayan *poolp = 0; 592336Snarayan return (EINVAL); 602336Snarayan } 612336Snarayan 622336Snarayan vmplp = kmem_zalloc(sizeof (*vmplp), KM_SLEEP); 632336Snarayan vmplp->quelen = num_mblks; 642336Snarayan vmplp->quemask = num_mblks - 1; /* expects quelen is power-of-2 */ 652336Snarayan vmplp->mblk_size = mblk_size; 662336Snarayan 672336Snarayan mutex_init(&vmplp->hlock, NULL, MUTEX_DRIVER, 682336Snarayan DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); 692336Snarayan mutex_init(&vmplp->tlock, NULL, MUTEX_DRIVER, 702336Snarayan DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); 712336Snarayan 722336Snarayan vmplp->basep = kmem_zalloc(num_mblks * sizeof (vio_mblk_t), KM_SLEEP); 732336Snarayan vmplp->datap = kmem_zalloc(num_mblks * mblk_size, KM_SLEEP); 742336Snarayan vmplp->nextp = NULL; 752336Snarayan 762336Snarayan /* create a queue of pointers to free vio_mblk_t's */ 772336Snarayan vmplp->quep = kmem_zalloc(vmplp->quelen * sizeof (vio_mblk_t *), 782336Snarayan KM_SLEEP); 792336Snarayan vmplp->head = 0; 802336Snarayan vmplp->tail = 0; 812336Snarayan 822336Snarayan for (i = 0, datap = vmplp->datap; i < num_mblks; i++) { 832336Snarayan 842336Snarayan vmp = &(vmplp->basep[i]); 852336Snarayan vmp->vmplp = vmplp; 862336Snarayan vmp->datap = datap; 872336Snarayan vmp->reclaim.free_func = vio_freeb; 882336Snarayan vmp->reclaim.free_arg = (caddr_t)vmp; 892336Snarayan vmp->mp = desballoc(vmp->datap, mblk_size, BPRI_MED, 902336Snarayan &vmp->reclaim); 912336Snarayan 922336Snarayan if (vmp->mp == NULL) 932336Snarayan continue; 942336Snarayan 952336Snarayan /* put this vmp on the free stack */ 962336Snarayan vmplp->quep[vmplp->tail] = vmp; 972336Snarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask; 982336Snarayan 992336Snarayan datap += mblk_size; 1002336Snarayan } 1012336Snarayan 1022336Snarayan *poolp = vmplp; 1032336Snarayan return (0); 1042336Snarayan } 1052336Snarayan 1062336Snarayan /* 1072336Snarayan * Destroy the pool of mblks. This can only succeed when 1082336Snarayan * all allocated mblks have been returned to the pool. 1092336Snarayan * 1102336Snarayan * It is up to the caller to ensure that no further mblks are 1112336Snarayan * requested from the pool after destroy has been invoked. 1122336Snarayan * 1132336Snarayan * Returns 0 on success, EINVAL if handle is invalid, or 1142336Snarayan * EBUSY if not all mblks reclaimed yet. 1152336Snarayan */ 1162336Snarayan int 1172336Snarayan vio_destroy_mblks(vio_mblk_pool_t *vmplp) 1182336Snarayan { 119*2793Slm66018 uint64_t i; 120*2793Slm66018 uint64_t num_mblks; 121*2793Slm66018 vio_mblk_t *vmp; 122*2793Slm66018 1232336Snarayan if (vmplp == NULL) 1242336Snarayan return (EINVAL); 1252336Snarayan 1262336Snarayan /* 1272336Snarayan * We can only destroy the pool once all the mblks have 1282336Snarayan * been reclaimed. 1292336Snarayan */ 1302336Snarayan if (vmplp->head != vmplp->tail) { 1312336Snarayan /* some mblks still in use */ 1322336Snarayan return (EBUSY); 1332336Snarayan } 1342336Snarayan 135*2793Slm66018 num_mblks = vmplp->quelen; 136*2793Slm66018 137*2793Slm66018 /* 138*2793Slm66018 * Set pool flag to tell vio_freeb() which is invoked from freeb(), 139*2793Slm66018 * that it is being called in the context of vio_destroy_mblks(). 140*2793Slm66018 * This results in freeing only mblk_t and dblk_t structures for 141*2793Slm66018 * each mp. The associated data buffers are freed below as one big 142*2793Slm66018 * chunk through kmem_free(vmplp->datap). 143*2793Slm66018 */ 144*2793Slm66018 vmplp->flag |= VMPL_FLAG_DESTROYING; 145*2793Slm66018 for (i = 0; i < num_mblks; i++) { 146*2793Slm66018 vmp = &(vmplp->basep[i]); 147*2793Slm66018 if (vmp->mp) 148*2793Slm66018 freeb(vmp->mp); 149*2793Slm66018 } 150*2793Slm66018 vmplp->flag &= ~(VMPL_FLAG_DESTROYING); 151*2793Slm66018 152*2793Slm66018 kmem_free(vmplp->basep, num_mblks * sizeof (vio_mblk_t)); 153*2793Slm66018 kmem_free(vmplp->datap, num_mblks * vmplp->mblk_size); 154*2793Slm66018 kmem_free(vmplp->quep, num_mblks * sizeof (vio_mblk_t *)); 1552336Snarayan 1562336Snarayan mutex_destroy(&vmplp->hlock); 1572336Snarayan mutex_destroy(&vmplp->tlock); 1582336Snarayan 1592336Snarayan kmem_free(vmplp, sizeof (*vmplp)); 1602336Snarayan 1612336Snarayan return (0); 1622336Snarayan } 1632336Snarayan 1642336Snarayan /* 1652336Snarayan * Allocate a mblk from the free pool if one is available. 1662336Snarayan * Otherwise returns NULL. 1672336Snarayan */ 1682336Snarayan mblk_t * 1692336Snarayan vio_allocb(vio_mblk_pool_t *vmplp) 1702336Snarayan { 1712336Snarayan vio_mblk_t *vmp = NULL; 1722336Snarayan mblk_t *mp = NULL; 1732336Snarayan uint32_t head; 1742336Snarayan 1752336Snarayan mutex_enter(&vmplp->hlock); 1762336Snarayan head = (vmplp->head + 1) & vmplp->quemask; 1772336Snarayan if (head != vmplp->tail) { 1782336Snarayan /* we have free mblks */ 1792336Snarayan vmp = vmplp->quep[vmplp->head]; 1802336Snarayan mp = vmp->mp; 1812336Snarayan vmplp->head = head; 1822336Snarayan } 1832336Snarayan mutex_exit(&vmplp->hlock); 1842336Snarayan 1852336Snarayan return (mp); 1862336Snarayan } 1872336Snarayan 1882336Snarayan /* 1892336Snarayan * Return a mblk to the free pool. Invoked when the upper IP 1902336Snarayan * layers do freemsg() etc on the mblk they were passed. 1912336Snarayan */ 1922336Snarayan void 1932336Snarayan vio_freeb(void *arg) 1942336Snarayan { 1952336Snarayan vio_mblk_t *vmp = (vio_mblk_t *)arg; 1962336Snarayan vio_mblk_pool_t *vmplp = vmp->vmplp; 1972336Snarayan 198*2793Slm66018 if (vmplp->flag & VMPL_FLAG_DESTROYING) { 199*2793Slm66018 /* 200*2793Slm66018 * This flag indicates that freeb() is being called from 201*2793Slm66018 * vio_destroy_mblks(). 202*2793Slm66018 * We don't need to alloc a new mblk_t/dblk_t pair for 203*2793Slm66018 * this data buffer, return from here and the data buffer 204*2793Slm66018 * itself will be freed in vio_destroy_mblks(). 205*2793Slm66018 */ 206*2793Slm66018 return; 207*2793Slm66018 } 208*2793Slm66018 2092336Snarayan vmp->mp = desballoc(vmp->datap, vmplp->mblk_size, 2102336Snarayan BPRI_MED, &vmp->reclaim); 2112336Snarayan 2122336Snarayan mutex_enter(&vmplp->tlock); 2132336Snarayan vmplp->quep[vmplp->tail] = vmp; 2142336Snarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask; 2152336Snarayan mutex_exit(&vmplp->tlock); 2162336Snarayan } 217