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 /* 239217SWentao.Yang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 242336Snarayan * Use is subject to license terms. 252336Snarayan */ 262336Snarayan 272336Snarayan #include <sys/types.h> 282336Snarayan #include <sys/sysmacros.h> 292336Snarayan #include <sys/errno.h> 302336Snarayan #include <sys/kmem.h> 312336Snarayan #include <sys/ksynch.h> 322336Snarayan #include <sys/stream.h> 332336Snarayan #include <sys/ddi.h> 342336Snarayan #include <sys/sunddi.h> 352336Snarayan #include <sys/vio_util.h> 362336Snarayan 379217SWentao.Yang@Sun.COM static int vio_pool_cleanup_retries = 10; /* Max retries to free pool */ 389217SWentao.Yang@Sun.COM static int vio_pool_cleanup_delay = 10000; /* 10ms */ 399217SWentao.Yang@Sun.COM 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 * 469217SWentao.Yang@Sun.COM * Returns 479217SWentao.Yang@Sun.COM * 0 on success 489217SWentao.Yang@Sun.COM * EINVAL if num_mblks is zero or not a power of 2. 499217SWentao.Yang@Sun.COM * ENOSPC if the pool could not be created due to alloc failures. 502336Snarayan */ 512336Snarayan int 522336Snarayan vio_create_mblks(uint64_t num_mblks, size_t mblk_size, vio_mblk_pool_t **poolp) 532336Snarayan { 542336Snarayan vio_mblk_pool_t *vmplp; 552336Snarayan vio_mblk_t *vmp; 562336Snarayan uint8_t *datap; 572336Snarayan int i; 58*9235SWentao.Yang@Sun.COM int rv; 592336Snarayan 602336Snarayan if (!(num_mblks) || (!ISP2(num_mblks))) { 612336Snarayan *poolp = 0; 622336Snarayan return (EINVAL); 632336Snarayan } 642336Snarayan 652336Snarayan vmplp = kmem_zalloc(sizeof (*vmplp), KM_SLEEP); 662336Snarayan vmplp->quelen = num_mblks; 672336Snarayan vmplp->quemask = num_mblks - 1; /* expects quelen is power-of-2 */ 682336Snarayan vmplp->mblk_size = mblk_size; 692336Snarayan 702336Snarayan mutex_init(&vmplp->hlock, NULL, MUTEX_DRIVER, 714650Sraghuram DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); 722336Snarayan mutex_init(&vmplp->tlock, NULL, MUTEX_DRIVER, 734650Sraghuram DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT)); 742336Snarayan 752336Snarayan vmplp->basep = kmem_zalloc(num_mblks * sizeof (vio_mblk_t), KM_SLEEP); 762336Snarayan vmplp->datap = kmem_zalloc(num_mblks * mblk_size, KM_SLEEP); 772336Snarayan vmplp->nextp = NULL; 782336Snarayan 792336Snarayan /* create a queue of pointers to free vio_mblk_t's */ 804647Sraghuram vmplp->quep = kmem_zalloc(vmplp->quelen * 814650Sraghuram sizeof (vio_mblk_t *), KM_SLEEP); 822336Snarayan vmplp->head = 0; 832336Snarayan vmplp->tail = 0; 842336Snarayan 852336Snarayan for (i = 0, datap = vmplp->datap; i < num_mblks; i++) { 862336Snarayan 872336Snarayan vmp = &(vmplp->basep[i]); 882336Snarayan vmp->vmplp = vmplp; 892336Snarayan vmp->datap = datap; 902336Snarayan vmp->reclaim.free_func = vio_freeb; 912336Snarayan vmp->reclaim.free_arg = (caddr_t)vmp; 922336Snarayan vmp->mp = desballoc(vmp->datap, mblk_size, BPRI_MED, 932336Snarayan &vmp->reclaim); 942336Snarayan 959217SWentao.Yang@Sun.COM if (vmp->mp == NULL) { 969217SWentao.Yang@Sun.COM /* reset tail */ 979217SWentao.Yang@Sun.COM vmplp->tail = vmplp->head; 989217SWentao.Yang@Sun.COM 999217SWentao.Yang@Sun.COM /* 1009217SWentao.Yang@Sun.COM * vio_destroy_mblks() frees mblks that have been 1019217SWentao.Yang@Sun.COM * allocated so far and then destroys the pool. 1029217SWentao.Yang@Sun.COM */ 103*9235SWentao.Yang@Sun.COM rv = vio_destroy_mblks(vmplp); 104*9235SWentao.Yang@Sun.COM ASSERT(rv == 0); 1059217SWentao.Yang@Sun.COM 1069217SWentao.Yang@Sun.COM *poolp = NULL; 1079217SWentao.Yang@Sun.COM return (ENOSPC); 1089217SWentao.Yang@Sun.COM } 1092336Snarayan 1102336Snarayan /* put this vmp on the free stack */ 1112336Snarayan vmplp->quep[vmplp->tail] = vmp; 1122336Snarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask; 1132336Snarayan 1142336Snarayan datap += mblk_size; 1152336Snarayan } 1162336Snarayan 1172336Snarayan *poolp = vmplp; 1182336Snarayan return (0); 1192336Snarayan } 1202336Snarayan 1212336Snarayan /* 1222336Snarayan * Destroy the pool of mblks. This can only succeed when 1232336Snarayan * all allocated mblks have been returned to the pool. 1242336Snarayan * 1252336Snarayan * It is up to the caller to ensure that no further mblks are 1262336Snarayan * requested from the pool after destroy has been invoked. 1272336Snarayan * 1282336Snarayan * Returns 0 on success, EINVAL if handle is invalid, or 1292336Snarayan * EBUSY if not all mblks reclaimed yet. 1302336Snarayan */ 1312336Snarayan int 1322336Snarayan vio_destroy_mblks(vio_mblk_pool_t *vmplp) 1332336Snarayan { 1349217SWentao.Yang@Sun.COM uint64_t i; 1359217SWentao.Yang@Sun.COM uint64_t num_mblks; 1369217SWentao.Yang@Sun.COM vio_mblk_t *vmp; 1379217SWentao.Yang@Sun.COM int pool_cleanup_retries = 0; 1389217SWentao.Yang@Sun.COM 1392793Slm66018 1402336Snarayan if (vmplp == NULL) 1412336Snarayan return (EINVAL); 1422336Snarayan 1432336Snarayan /* 1442336Snarayan * We can only destroy the pool once all the mblks have 1452336Snarayan * been reclaimed. 1462336Snarayan */ 1479217SWentao.Yang@Sun.COM do { 1489217SWentao.Yang@Sun.COM if (vmplp->head == vmplp->tail) { 1499217SWentao.Yang@Sun.COM break; 1509217SWentao.Yang@Sun.COM } 1519217SWentao.Yang@Sun.COM 1529217SWentao.Yang@Sun.COM /* some mblks still in use */ 1539217SWentao.Yang@Sun.COM drv_usecwait(vio_pool_cleanup_delay); 1549217SWentao.Yang@Sun.COM } while (++pool_cleanup_retries < vio_pool_cleanup_retries); 1559217SWentao.Yang@Sun.COM 1562336Snarayan if (vmplp->head != vmplp->tail) { 1572336Snarayan return (EBUSY); 1582336Snarayan } 1592336Snarayan 1602793Slm66018 num_mblks = vmplp->quelen; 1612793Slm66018 1622793Slm66018 /* 1632793Slm66018 * Set pool flag to tell vio_freeb() which is invoked from freeb(), 1642793Slm66018 * that it is being called in the context of vio_destroy_mblks(). 1652793Slm66018 * This results in freeing only mblk_t and dblk_t structures for 1662793Slm66018 * each mp. The associated data buffers are freed below as one big 1672793Slm66018 * chunk through kmem_free(vmplp->datap). 1682793Slm66018 */ 1692793Slm66018 vmplp->flag |= VMPL_FLAG_DESTROYING; 1702793Slm66018 for (i = 0; i < num_mblks; i++) { 1712793Slm66018 vmp = &(vmplp->basep[i]); 1729217SWentao.Yang@Sun.COM /* 1739217SWentao.Yang@Sun.COM * It is possible that mblks have been allocated only upto 1749217SWentao.Yang@Sun.COM * a certain index and the entire quelen has not been 1759217SWentao.Yang@Sun.COM * initialized. This might happen due to desballoc() failure 1769217SWentao.Yang@Sun.COM * while creating the pool. The below check handles this 1779217SWentao.Yang@Sun.COM * condition. 1789217SWentao.Yang@Sun.COM */ 1799217SWentao.Yang@Sun.COM if (vmp->mp != NULL) 1802793Slm66018 freeb(vmp->mp); 1812793Slm66018 } 1822793Slm66018 vmplp->flag &= ~(VMPL_FLAG_DESTROYING); 1832793Slm66018 1842793Slm66018 kmem_free(vmplp->basep, num_mblks * sizeof (vio_mblk_t)); 1852793Slm66018 kmem_free(vmplp->datap, num_mblks * vmplp->mblk_size); 1862793Slm66018 kmem_free(vmplp->quep, num_mblks * sizeof (vio_mblk_t *)); 1872336Snarayan 1882336Snarayan mutex_destroy(&vmplp->hlock); 1892336Snarayan mutex_destroy(&vmplp->tlock); 1902336Snarayan 1912336Snarayan kmem_free(vmplp, sizeof (*vmplp)); 1922336Snarayan 1932336Snarayan return (0); 1942336Snarayan } 1952336Snarayan 1962336Snarayan /* 1972336Snarayan * Allocate a mblk from the free pool if one is available. 1982336Snarayan * Otherwise returns NULL. 1992336Snarayan */ 2002336Snarayan mblk_t * 2012336Snarayan vio_allocb(vio_mblk_pool_t *vmplp) 2022336Snarayan { 2032336Snarayan vio_mblk_t *vmp = NULL; 2042336Snarayan mblk_t *mp = NULL; 2052336Snarayan uint32_t head; 2062336Snarayan 2072336Snarayan mutex_enter(&vmplp->hlock); 2082336Snarayan head = (vmplp->head + 1) & vmplp->quemask; 2092336Snarayan if (head != vmplp->tail) { 2102336Snarayan /* we have free mblks */ 2112336Snarayan vmp = vmplp->quep[vmplp->head]; 2122336Snarayan mp = vmp->mp; 2132336Snarayan vmplp->head = head; 2142336Snarayan } 2152336Snarayan mutex_exit(&vmplp->hlock); 2162336Snarayan 2172336Snarayan return (mp); 2182336Snarayan } 2192336Snarayan 2202336Snarayan /* 2212336Snarayan * Return a mblk to the free pool. Invoked when the upper IP 2222336Snarayan * layers do freemsg() etc on the mblk they were passed. 2232336Snarayan */ 2242336Snarayan void 2252336Snarayan vio_freeb(void *arg) 2262336Snarayan { 2272336Snarayan vio_mblk_t *vmp = (vio_mblk_t *)arg; 2282336Snarayan vio_mblk_pool_t *vmplp = vmp->vmplp; 2292336Snarayan 2302793Slm66018 if (vmplp->flag & VMPL_FLAG_DESTROYING) { 2312793Slm66018 /* 2322793Slm66018 * This flag indicates that freeb() is being called from 2332793Slm66018 * vio_destroy_mblks(). 2342793Slm66018 * We don't need to alloc a new mblk_t/dblk_t pair for 2352793Slm66018 * this data buffer, return from here and the data buffer 2362793Slm66018 * itself will be freed in vio_destroy_mblks(). 2372793Slm66018 */ 2382793Slm66018 return; 2392793Slm66018 } 2402793Slm66018 2412336Snarayan vmp->mp = desballoc(vmp->datap, vmplp->mblk_size, 2424650Sraghuram BPRI_MED, &vmp->reclaim); 2432336Snarayan 2442336Snarayan mutex_enter(&vmplp->tlock); 2452336Snarayan vmplp->quep[vmplp->tail] = vmp; 2462336Snarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask; 2472336Snarayan mutex_exit(&vmplp->tlock); 2482336Snarayan } 2494647Sraghuram 2504647Sraghuram /* 2514647Sraghuram * Create a multiple pools of mblks from which future vio_allocb() 2524647Sraghuram * or vio_multipool_allocb() requests will be serviced. 2534647Sraghuram * 2544647Sraghuram * Arguments: 2554647Sraghuram * vmultip -- A pointer to vio_multi_pool_t structure. 2564647Sraghuram * num_pools -- Number of the pools. 2574647Sraghuram * ... -- Variable arguments consisting a list of buffer sizes for 2584647Sraghuram * each pool and list of number of buffers for each pool. 2594647Sraghuram * 2604647Sraghuram * NOTE: The restrictions of vio_create_mblks() apply to this interface also. 2614647Sraghuram * 2624647Sraghuram * Returns 0 on success or an error returned by vio_create_mblks(). 2634647Sraghuram */ 2644647Sraghuram int 2654647Sraghuram vio_init_multipools(vio_multi_pool_t *vmultip, int num_pools, ...) 2664647Sraghuram { 2674647Sraghuram int i; 2684647Sraghuram int status; 2694647Sraghuram char *tbuf; 2704647Sraghuram va_list vap; 2714647Sraghuram vio_mblk_pool_t *fvmp = NULL; 2724647Sraghuram 2734647Sraghuram /* 2744647Sraghuram * Allocate memory for all of the following in one allocation. 2754647Sraghuram * bufsz_tbl -- sizeof (uint32_t) * num_pools 2764647Sraghuram * nbuf_tbl -- sizeof (uint32_t) * num_pools 2774647Sraghuram * vmpp -- sizeof (vio_mblk_pool_t *) * numpools 2784647Sraghuram */ 2794647Sraghuram vmultip->tbsz = (sizeof (uint32_t) * num_pools) + 2804650Sraghuram (sizeof (uint32_t) * num_pools) + 2814650Sraghuram (sizeof (vio_mblk_pool_t *) * num_pools); 2824647Sraghuram tbuf = kmem_zalloc(vmultip->tbsz, KM_SLEEP); 2834647Sraghuram vmultip->bufsz_tbl = (uint32_t *)tbuf; 2844647Sraghuram vmultip->nbuf_tbl = (uint32_t *)(tbuf + 2854650Sraghuram (sizeof (uint32_t) * num_pools)); 2864647Sraghuram vmultip->vmpp = (vio_mblk_pool_t **)(tbuf + 2874650Sraghuram (sizeof (uint32_t) * num_pools * 2)); 2884647Sraghuram vmultip->num_pools = num_pools; 2894647Sraghuram 2904647Sraghuram /* initialize the array first */ 2914647Sraghuram va_start(vap, num_pools); 2924647Sraghuram for (i = 0; i < num_pools; i++) { 2934647Sraghuram vmultip->bufsz_tbl[i] = va_arg(vap, uint32_t); 2944647Sraghuram } 2954647Sraghuram for (i = 0; i < num_pools; i++) { 2964647Sraghuram vmultip->nbuf_tbl[i] = va_arg(vap, uint32_t); 2974647Sraghuram } 2984647Sraghuram va_end(vap); 2994647Sraghuram 3004647Sraghuram for (i = 0; i < vmultip->num_pools; i++) { 3014647Sraghuram status = vio_create_mblks(vmultip->nbuf_tbl[i], 3024650Sraghuram vmultip->bufsz_tbl[i], &vmultip->vmpp[i]); 3034647Sraghuram if (status != 0) { 3044647Sraghuram vio_destroy_multipools(vmultip, &fvmp); 3054647Sraghuram /* We expect to free the pools without failure here */ 3064647Sraghuram ASSERT(fvmp == NULL); 3074647Sraghuram return (status); 3084647Sraghuram } 3094647Sraghuram } 3104647Sraghuram return (0); 3114647Sraghuram } 3124647Sraghuram 3134647Sraghuram /* 3144647Sraghuram * Destroy the multiple pools of mblks. This can only succeed when 3154647Sraghuram * all allocated mblks have been returned to the pool. 3164647Sraghuram * 3174647Sraghuram * If a pool of mblks couldn't be destroyed, then the failed vio_mblk_pool_t 3184647Sraghuram * pointers are returned via th fvmp list. Its the caller's 3194647Sraghuram * responsibility to check this list and free them later at an appropriate 3204647Sraghuram * time with vio_destroy_mblks(). 3214647Sraghuram * 3224647Sraghuram * Arguments: 3234647Sraghuram * vmultip -- A pointer to vio_multi_pool_t structure. 3244647Sraghuram * fvmp -- A list in which the pools that couldn't be destroyed are 3254647Sraghuram * returned. 3264647Sraghuram */ 3274647Sraghuram void 3284647Sraghuram vio_destroy_multipools(vio_multi_pool_t *vmultip, vio_mblk_pool_t **fvmp) 3294647Sraghuram { 3304647Sraghuram int i; 3314647Sraghuram vio_mblk_pool_t *vmp; 3324647Sraghuram 3334647Sraghuram for (i = 0; i < vmultip->num_pools; i++) { 3344647Sraghuram if ((vmp = vmultip->vmpp[i]) != NULL) { 3354647Sraghuram if (vio_destroy_mblks(vmp)) { 3364647Sraghuram /* 3374647Sraghuram * if we cannot reclaim all mblks, then 3384647Sraghuram * return the pool in the failed vmp 3394647Sraghuram * list(fvmp). 3404647Sraghuram */ 3414647Sraghuram vmp->nextp = *fvmp; 3424647Sraghuram *fvmp = vmp; 3434647Sraghuram } 3444647Sraghuram } 3454647Sraghuram } 3469217SWentao.Yang@Sun.COM if (vmultip->tbsz != 0) 3479217SWentao.Yang@Sun.COM kmem_free(vmultip->bufsz_tbl, vmultip->tbsz); 3484647Sraghuram vmultip->bufsz_tbl = NULL; 3494647Sraghuram vmultip->nbuf_tbl = NULL; 3504647Sraghuram vmultip->vmpp = NULL; 3517529SSriharsha.Basavapatna@Sun.COM vmultip->num_pools = 0; 3527529SSriharsha.Basavapatna@Sun.COM vmultip->tbsz = 0; 3534647Sraghuram } 3544647Sraghuram 3554647Sraghuram 3564647Sraghuram /* 3574647Sraghuram * Allocate an mblk from one of the free pools, but tries the pool that 3584647Sraghuram * best fits size requested first. 3594647Sraghuram */ 3604647Sraghuram mblk_t * 3614647Sraghuram vio_multipool_allocb(vio_multi_pool_t *vmultip, size_t size) 3624647Sraghuram { 3634647Sraghuram int i; 3644647Sraghuram mblk_t *mp = NULL; 3654647Sraghuram 3664647Sraghuram /* Try allocating any size that fits */ 3674647Sraghuram for (i = 0; i < vmultip->num_pools; i++) { 3684647Sraghuram if (size > vmultip->bufsz_tbl[i]) { 3694647Sraghuram continue; 3704647Sraghuram } 3714647Sraghuram mp = vio_allocb(vmultip->vmpp[i]); 3724647Sraghuram if (mp != NULL) { 3734647Sraghuram break; 3744647Sraghuram } 3754647Sraghuram } 3764647Sraghuram return (mp); 3774647Sraghuram } 3785365Slm66018 3795365Slm66018 /* 3805365Slm66018 * ----------------------------------------------------------------------------- 3815365Slm66018 * LDoms versioning functions 3825365Slm66018 * 3835365Slm66018 * Future work: the version negotiating code in the various VIO drivers 3845365Slm66018 * could be made common and placed here. 3855365Slm66018 */ 3865365Slm66018 3875365Slm66018 /* 3885365Slm66018 * Description: 3895365Slm66018 * This function checks to see if the supplied version tuple (major,minor) 3905365Slm66018 * is supported by the version 'ver', negotiated during the handshake 3915365Slm66018 * between the client and the server (ver). 3925365Slm66018 * 3935365Slm66018 * Assumption: 3945365Slm66018 * This function assumes that backward compatability is not broken in 3955365Slm66018 * newer minor versions of the protocol (e.g. v1.5 & v1.1 support v1.0) 3965365Slm66018 * 3975365Slm66018 * Return Value: 3985365Slm66018 * B_TRUE - The (major,minor) version is supported 3995365Slm66018 * B_FALSE - not supported 4005365Slm66018 */ 4015365Slm66018 boolean_t 4025365Slm66018 vio_ver_is_supported(vio_ver_t ver, uint16_t major, uint16_t minor) 4035365Slm66018 { 4045365Slm66018 if ((ver.major == major) && (ver.minor >= minor)) 4055365Slm66018 return (B_TRUE); 4065365Slm66018 4075365Slm66018 return (B_FALSE); 4085365Slm66018 } 409