// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2022, Intel Corporation. */
#include "ice_vf_lib_private.h"
#include "ice.h"
#include "ice_lib.h"
#include "ice_fltr.h"
#include "ice_virtchnl_allowlist.h"
/* Public functions which may be accessed by all driver files */
/**
* ice_get_vf_by_id - Get pointer to VF by ID
* @pf: the PF private structure
* @vf_id: the VF ID to locate
*
* Locate and return a pointer to the VF structure associated with a given ID.
* Returns NULL if the ID does not have a valid VF structure associated with
* it.
*
* This function takes a reference to the VF, which must be released by
* calling ice_put_vf() once the caller is finished accessing the VF structure
* returned.
*/
struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
{
struct ice_vf *vf;
rcu_read_lock();
hash_for_each_possible_rcu(pf->vfs.table, vf, entry, vf_id) {
if (vf->vf_id == vf_id) {
struct ice_vf *found;
if (kref_get_unless_zero(&vf->refcnt))
found = vf;
else
found = NULL;
rcu_read_unlock();
return found;
}
}
rcu_read_unlock();
return NULL;
}
/**
* ice_release_vf - Release VF associated with a refcount
* @ref: the kref decremented to zero
*
* Callback function for kref_put to release a VF once its reference count has
* hit zero.
*/
static void ice_release_vf(struct kref *ref)
{
struct ice_vf *vf = container_of(ref, struct ice_vf, refcnt);
pci_dev_put(vf->vfdev);
vf->vf_ops->free(vf);
}
/**
* ice_put_vf - Release a reference to a VF
* @vf: the VF structure to decrease reference count on
*
* Decrease the reference count for a VF, and free the entry if it is no
* longer in use.
*
* This must be called after ice_get_vf_by_id() once the reference to the VF
* structure is no longer used. Otherwise, the VF structure will never be
* freed.
*/
void ice_put_vf(struct ice_vf *vf)
{
kref_put(&vf->refcnt, ice_release_vf);
}
/**
* ice_has_vfs - Return true if the PF has any associated VFs
* @pf: the PF private structure
*
* Return whether or not the PF has any allocated VFs.
*
* Note that this function only guarantees that there are no VFs at the point
* of calling it. It does not guarantee that no more VFs will be added.
*/
bool ice_has_vfs(struct ice_pf *pf)
{
/* A simple check that the hash table is not empty does not require
* the mutex or rcu_read_lock.
*/
return !hash_empty(pf->vfs.table);
}
/**
* ice_get_num_vfs - Get number of allocated VFs
* @pf: the PF private structure
*
* Return the total number of allocated VFs. NOTE: VF IDs are not guaranteed
* to be contiguous. Do not assume that a VF ID is guaranteed to be less than
* the output of this function.
*/
u16 ice_get_num_vfs(struct ice_pf *pf)
{
struct ice_vf *vf;
unsigned int bkt;
u16 num_vfs = 0;
rcu_read_lock();
ice_for_each_vf_rcu(pf, bkt,