root/sys/dev/ice/ice_resmgr.c
/* SPDX-License-Identifier: BSD-3-Clause */
/*  Copyright (c) 2024, Intel Corporation
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *   3. Neither the name of the Intel Corporation nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file ice_resmgr.c
 * @brief Resource allocation manager
 *
 * Manage device resource allocations for a PF, including assigning queues to
 * VSIs, or managing interrupt allocations across the PF.
 *
 * It can handle contiguous and scattered resource allocations, and upon
 * assigning them, will fill in the mapping array with a map of
 * resource IDs to PF-space resource indices.
 */

#include "ice_resmgr.h"

/**
 * @var M_ICE_RESMGR
 * @brief PF resource manager allocation type
 *
 * malloc(9) allocation type used by the resource manager code.
 */
MALLOC_DEFINE(M_ICE_RESMGR, "ice-resmgr", "Intel(R) 100Gb Network Driver resmgr allocations");

/*
 * Public resource manager allocation functions
 */

/**
 * ice_resmgr_init - Initialize a resource manager structure
 * @resmgr: structure to track the resource manager state
 * @num_res: the maximum number of resources it can assign
 *
 * Initialize the state of a resource manager structure, allocating space to
 * assign up to the requested number of resources. Uses bit strings to track
 * which resources have been assigned. This type of resmgr is intended to be
 * used for tracking LAN queue assignments between VSIs.
 */
int
ice_resmgr_init(struct ice_resmgr *resmgr, u16 num_res)
{
        resmgr->resources = bit_alloc(num_res, M_ICE_RESMGR, M_NOWAIT);
        if (resmgr->resources == NULL)
                return (ENOMEM);

        resmgr->num_res = num_res;
        resmgr->contig_only = false;
        return (0);
}

/**
 * ice_resmgr_init_contig_only - Initialize a resource manager structure
 * @resmgr: structure to track the resource manager state
 * @num_res: the maximum number of resources it can assign
 *
 * Functions similarly to ice_resmgr_init(), but the resulting resmgr structure
 * will only allow contiguous allocations. This type of resmgr is intended to
 * be used with tracking device MSI-X interrupt allocations.
 */
int
ice_resmgr_init_contig_only(struct ice_resmgr *resmgr, u16 num_res)
{
        int error;

        error = ice_resmgr_init(resmgr, num_res);
        if (error)
                return (error);

        resmgr->contig_only = true;
        return (0);
}

/**
 * ice_resmgr_destroy - Deallocate memory associated with a resource manager
 * @resmgr: resource manager structure
 *
 * De-allocates the bit string associated with this resource manager. It is
 * expected that this function will not be called until all of the assigned
 * resources have been released.
 */
void
ice_resmgr_destroy(struct ice_resmgr *resmgr)
{
        if (resmgr->resources != NULL) {
#ifdef INVARIANTS
                int set;

                bit_count(resmgr->resources, 0, resmgr->num_res, &set);
                MPASS(set == 0);
#endif

                free(resmgr->resources, M_ICE_RESMGR);
                resmgr->resources = NULL;
        }
        resmgr->num_res = 0;
}

/*
 * Resource allocation functions
 */

/**
 * ice_resmgr_assign_contiguous - Assign contiguous mapping of resources
 * @resmgr: resource manager structure
 * @idx: memory to store mapping, at least num_res wide
 * @num_res: the number of resources to assign
 *
 * Assign num_res number of contiguous resources into the idx mapping. On
 * success, idx will be updated to map each index to a PF resource.
 *
 * This function guarantees that the resource mapping will be contiguous, and
 * will fail if that is not possible.
 */
int
ice_resmgr_assign_contiguous(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
{
        int start, i;

        bit_ffc_area(resmgr->resources, resmgr->num_res, num_res, &start);
        if (start < 0)
                return (ENOSPC);

        /* Set each bit and update the index array */
        for (i = 0; i < num_res; i++) {
                bit_set(resmgr->resources, start + i);
                idx[i] = start + i;
        }

        return (0);
}

/**
 * ice_resmgr_assign_scattered - Assign possibly scattered resources
 * @resmgr: the resource manager structure
 * @idx: memory to store associated resource mapping, at least num_res wide
 * @num_res: the number of resources to assign
 *
 * Assign num_res number of resources into the idx_mapping. On success, idx
 * will be updated to map each index to a PF-space resource.
 *
 * Queues may be allocated non-contiguously, and this function requires that
 * num_res be less than the ICE_MAX_SCATTERED_QUEUES due to hardware
 * limitations on scattered queue assignment.
 */
int
ice_resmgr_assign_scattered(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
{
        int index = 0, i;

        /* Scattered allocations won't work if they weren't allowed at resmgr
         * creation time.
         */
        if (resmgr->contig_only)
                return (EPERM);

        /* Hardware can only support a limited total of scattered queues for
         * a single VSI
         */
        if (num_res > ICE_MAX_SCATTERED_QUEUES)
                return (EOPNOTSUPP);

        for (i = 0; i < num_res; i++) {
                bit_ffc_at(resmgr->resources, index, resmgr->num_res, &index);
                if (index < 0)
                        goto err_no_space;

                bit_set(resmgr->resources, index);
                idx[i] = index;
        }
        return (0);

err_no_space:
        /* Release any resources we did assign up to this point. */
        ice_resmgr_release_map(resmgr, idx, i);
        return (ENOSPC);
}

/**
 * ice_resmgr_release_map - Release previously assigned resource mapping
 * @resmgr: the resource manager structure
 * @idx: previously assigned resource mapping
 * @num_res: number of resources in the mapping
 *
 * Clears the assignment of each resource in the provided resource index. Updates
 * the idx to indicate that each of the virtual indexes have invalid resource
 * mappings by assigning them to ICE_INVALID_RES_IDX.
 */
void
ice_resmgr_release_map(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
{
        int i;

        for (i = 0; i < num_res; i++) {
                if (idx[i] < resmgr->num_res)
                        bit_clear(resmgr->resources, idx[i]);
                idx[i] = ICE_INVALID_RES_IDX;
        }
}