vio_util.c revision 3af08d828975d7e2581b6829e0eecff14d87a483
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * CDDL HEADER START
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * The contents of this file are subject to the terms of the
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Common Development and Distribution License (the "License").
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * You may not use this file except in compliance with the License.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * or http://www.opensolaris.org/os/licensing.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * See the License for the specific language governing permissions
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * and limitations under the License.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * When distributing Covered Code, include this CDDL HEADER in each
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * If applicable, add the following below this CDDL HEADER, with the
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * fields enclosed by brackets "[]" replaced with your own identifying
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * information: Portions Copyright [yyyy] [name of copyright owner]
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * CDDL HEADER END
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Use is subject to license terms.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#pragma ident "%Z%%M% %I% %E% SMI"
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/types.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/sysmacros.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/cmn_err.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/errno.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/kmem.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/ksynch.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/stream.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/ddi.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/sunddi.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan#include <sys/vio_util.h>
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Create a pool of mblks from which future vio_allocb() requests
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * will be serviced.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * NOTE: num_mblks has to non-zero and a power-of-2
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Returns 0 on success or EINVAL if num_mblks is zero or not
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * a power of 2.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanint
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvio_create_mblks(uint64_t num_mblks, size_t mblk_size, vio_mblk_pool_t **poolp)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan{
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vio_mblk_pool_t *vmplp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vio_mblk_t *vmp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan uint8_t *datap;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan int i;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (!(num_mblks) || (!ISP2(num_mblks))) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *poolp = 0;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (EINVAL);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan }
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp = kmem_zalloc(sizeof (*vmplp), KM_SLEEP);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->quelen = num_mblks;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->quemask = num_mblks - 1; /* expects quelen is power-of-2 */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->mblk_size = mblk_size;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_init(&vmplp->hlock, NULL, MUTEX_DRIVER,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT));
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_init(&vmplp->tlock, NULL, MUTEX_DRIVER,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan DDI_INTR_PRI(DDI_INTR_SOFTPRI_DEFAULT));
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->basep = kmem_zalloc(num_mblks * sizeof (vio_mblk_t), KM_SLEEP);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->datap = kmem_zalloc(num_mblks * mblk_size, KM_SLEEP);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->nextp = NULL;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* create a queue of pointers to free vio_mblk_t's */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->quep = kmem_zalloc(vmplp->quelen * sizeof (vio_mblk_t *),
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan KM_SLEEP);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->head = 0;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->tail = 0;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan for (i = 0, datap = vmplp->datap; i < num_mblks; i++) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp = &(vmplp->basep[i]);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->vmplp = vmplp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->datap = datap;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->reclaim.free_func = vio_freeb;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->reclaim.free_arg = (caddr_t)vmp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->mp = desballoc(vmp->datap, mblk_size, BPRI_MED,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan &vmp->reclaim);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (vmp->mp == NULL)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan continue;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* put this vmp on the free stack */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->quep[vmplp->tail] = vmp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan datap += mblk_size;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan }
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *poolp = vmplp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (0);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan}
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Destroy the pool of mblks. This can only succeed when
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * all allocated mblks have been returned to the pool.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * It is up to the caller to ensure that no further mblks are
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * requested from the pool after destroy has been invoked.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Returns 0 on success, EINVAL if handle is invalid, or
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * EBUSY if not all mblks reclaimed yet.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanint
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvio_destroy_mblks(vio_mblk_pool_t *vmplp)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan{
3af08d828975d7e2581b6829e0eecff14d87a483lm uint64_t i;
3af08d828975d7e2581b6829e0eecff14d87a483lm uint64_t num_mblks;
3af08d828975d7e2581b6829e0eecff14d87a483lm vio_mblk_t *vmp;
3af08d828975d7e2581b6829e0eecff14d87a483lm
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (vmplp == NULL)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (EINVAL);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * We can only destroy the pool once all the mblks have
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * been reclaimed.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (vmplp->head != vmplp->tail) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* some mblks still in use */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (EBUSY);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan }
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
3af08d828975d7e2581b6829e0eecff14d87a483lm num_mblks = vmplp->quelen;
3af08d828975d7e2581b6829e0eecff14d87a483lm
3af08d828975d7e2581b6829e0eecff14d87a483lm /*
3af08d828975d7e2581b6829e0eecff14d87a483lm * Set pool flag to tell vio_freeb() which is invoked from freeb(),
3af08d828975d7e2581b6829e0eecff14d87a483lm * that it is being called in the context of vio_destroy_mblks().
3af08d828975d7e2581b6829e0eecff14d87a483lm * This results in freeing only mblk_t and dblk_t structures for
3af08d828975d7e2581b6829e0eecff14d87a483lm * each mp. The associated data buffers are freed below as one big
3af08d828975d7e2581b6829e0eecff14d87a483lm * chunk through kmem_free(vmplp->datap).
3af08d828975d7e2581b6829e0eecff14d87a483lm */
3af08d828975d7e2581b6829e0eecff14d87a483lm vmplp->flag |= VMPL_FLAG_DESTROYING;
3af08d828975d7e2581b6829e0eecff14d87a483lm for (i = 0; i < num_mblks; i++) {
3af08d828975d7e2581b6829e0eecff14d87a483lm vmp = &(vmplp->basep[i]);
3af08d828975d7e2581b6829e0eecff14d87a483lm if (vmp->mp)
3af08d828975d7e2581b6829e0eecff14d87a483lm freeb(vmp->mp);
3af08d828975d7e2581b6829e0eecff14d87a483lm }
3af08d828975d7e2581b6829e0eecff14d87a483lm vmplp->flag &= ~(VMPL_FLAG_DESTROYING);
3af08d828975d7e2581b6829e0eecff14d87a483lm
3af08d828975d7e2581b6829e0eecff14d87a483lm kmem_free(vmplp->basep, num_mblks * sizeof (vio_mblk_t));
3af08d828975d7e2581b6829e0eecff14d87a483lm kmem_free(vmplp->datap, num_mblks * vmplp->mblk_size);
3af08d828975d7e2581b6829e0eecff14d87a483lm kmem_free(vmplp->quep, num_mblks * sizeof (vio_mblk_t *));
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_destroy(&vmplp->hlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_destroy(&vmplp->tlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan kmem_free(vmplp, sizeof (*vmplp));
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (0);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan}
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Allocate a mblk from the free pool if one is available.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Otherwise returns NULL.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanmblk_t *
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvio_allocb(vio_mblk_pool_t *vmplp)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan{
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vio_mblk_t *vmp = NULL;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mblk_t *mp = NULL;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan uint32_t head;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_enter(&vmplp->hlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan head = (vmplp->head + 1) & vmplp->quemask;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan if (head != vmplp->tail) {
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan /* we have free mblks */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp = vmplp->quep[vmplp->head];
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mp = vmp->mp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->head = head;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan }
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_exit(&vmplp->hlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan return (mp);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan}
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan/*
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * Return a mblk to the free pool. Invoked when the upper IP
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan * layers do freemsg() etc on the mblk they were passed.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvoid
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayanvio_freeb(void *arg)
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan{
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vio_mblk_t *vmp = (vio_mblk_t *)arg;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vio_mblk_pool_t *vmplp = vmp->vmplp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
3af08d828975d7e2581b6829e0eecff14d87a483lm if (vmplp->flag & VMPL_FLAG_DESTROYING) {
3af08d828975d7e2581b6829e0eecff14d87a483lm /*
3af08d828975d7e2581b6829e0eecff14d87a483lm * This flag indicates that freeb() is being called from
3af08d828975d7e2581b6829e0eecff14d87a483lm * vio_destroy_mblks().
3af08d828975d7e2581b6829e0eecff14d87a483lm * We don't need to alloc a new mblk_t/dblk_t pair for
3af08d828975d7e2581b6829e0eecff14d87a483lm * this data buffer, return from here and the data buffer
3af08d828975d7e2581b6829e0eecff14d87a483lm * itself will be freed in vio_destroy_mblks().
3af08d828975d7e2581b6829e0eecff14d87a483lm */
3af08d828975d7e2581b6829e0eecff14d87a483lm return;
3af08d828975d7e2581b6829e0eecff14d87a483lm }
3af08d828975d7e2581b6829e0eecff14d87a483lm
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmp->mp = desballoc(vmp->datap, vmplp->mblk_size,
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan BPRI_MED, &vmp->reclaim);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_enter(&vmplp->tlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->quep[vmplp->tail] = vmp;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan vmplp->tail = (vmplp->tail + 1) & vmplp->quemask;
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan mutex_exit(&vmplp->tlock);
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan}