linux-loongson/drivers/net/ethernet/intel/ice/ice_idc.c
Dave Ertman c24a65b6a2 iidc/ice/irdma: Update IDC to support multiple consumers
In preparation of supporting more than a single core PCI driver
for RDMA, move ice specific structs like qset_params, qos_info
and qos_params from iidc_rdma.h to iidc_rdma_ice.h.

Previously, the ice driver was just exporting its entire PF struct
to the auxiliary driver, but since each core driver will have its own
different PF struct, implement a universal struct that all core drivers
can provide to the auxiliary driver through the probe call.

Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
Co-developed-by: Mustafa Ismail <mustafa.ismail@intel.com>
Signed-off-by: Mustafa Ismail <mustafa.ismail@intel.com>
Co-developed-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
Co-developed-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
2025-05-09 11:35:43 -07:00

439 lines
9.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021, Intel Corporation. */
/* Inter-Driver Communication */
#include "ice.h"
#include "ice_lib.h"
#include "ice_dcb_lib.h"
static DEFINE_XARRAY_ALLOC1(ice_aux_id);
/**
* ice_get_auxiliary_drv - retrieve iidc_rdma_core_auxiliary_drv struct
* @cdev: pointer to iidc_rdma_core_dev_info struct
*
* This function has to be called with a device_lock on the
* cdev->adev.dev to avoid race conditions.
*
* Return: pointer to the matched auxiliary driver struct
*/
static struct iidc_rdma_core_auxiliary_drv *
ice_get_auxiliary_drv(struct iidc_rdma_core_dev_info *cdev)
{
struct auxiliary_device *adev;
adev = cdev->adev;
if (!adev || !adev->dev.driver)
return NULL;
return container_of(adev->dev.driver,
struct iidc_rdma_core_auxiliary_drv, adrv.driver);
}
/**
* ice_send_event_to_aux - send event to RDMA AUX driver
* @pf: pointer to PF struct
* @event: event struct
*/
void ice_send_event_to_aux(struct ice_pf *pf, struct iidc_rdma_event *event)
{
struct iidc_rdma_core_auxiliary_drv *iadrv;
struct iidc_rdma_core_dev_info *cdev;
if (WARN_ON_ONCE(!in_task()))
return;
cdev = pf->cdev_info;
if (!cdev)
return;
mutex_lock(&pf->adev_mutex);
if (!cdev->adev)
goto finish;
device_lock(&cdev->adev->dev);
iadrv = ice_get_auxiliary_drv(cdev);
if (iadrv && iadrv->event_handler)
iadrv->event_handler(cdev, event);
device_unlock(&cdev->adev->dev);
finish:
mutex_unlock(&pf->adev_mutex);
}
/**
* ice_add_rdma_qset - Add Leaf Node for RDMA Qset
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @qset: Resource to be allocated
*
* Return: Zero on success or error code encountered
*/
int ice_add_rdma_qset(struct iidc_rdma_core_dev_info *cdev,
struct iidc_rdma_qset_params *qset)
{
u16 max_rdmaqs[ICE_MAX_TRAFFIC_CLASS];
struct ice_vsi *vsi;
struct device *dev;
struct ice_pf *pf;
u32 qset_teid;
u16 qs_handle;
int status;
int i;
if (WARN_ON(!cdev || !qset))
return -EINVAL;
pf = pci_get_drvdata(cdev->pdev);
dev = ice_pf_to_dev(pf);
if (!ice_is_rdma_ena(pf))
return -EINVAL;
vsi = ice_get_main_vsi(pf);
if (!vsi) {
dev_err(dev, "RDMA QSet invalid VSI\n");
return -EINVAL;
}
ice_for_each_traffic_class(i)
max_rdmaqs[i] = 0;
max_rdmaqs[qset->tc]++;
qs_handle = qset->qs_handle;
status = ice_cfg_vsi_rdma(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
max_rdmaqs);
if (status) {
dev_err(dev, "Failed VSI RDMA Qset config\n");
return status;
}
status = ice_ena_vsi_rdma_qset(vsi->port_info, vsi->idx, qset->tc,
&qs_handle, 1, &qset_teid);
if (status) {
dev_err(dev, "Failed VSI RDMA Qset enable\n");
return status;
}
qset->teid = qset_teid;
return 0;
}
EXPORT_SYMBOL_GPL(ice_add_rdma_qset);
/**
* ice_del_rdma_qset - Delete leaf node for RDMA Qset
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @qset: Resource to be freed
*
* Return: Zero on success, error code on failure
*/
int ice_del_rdma_qset(struct iidc_rdma_core_dev_info *cdev,
struct iidc_rdma_qset_params *qset)
{
struct ice_vsi *vsi;
struct ice_pf *pf;
u32 teid;
u16 q_id;
if (WARN_ON(!cdev || !qset))
return -EINVAL;
pf = pci_get_drvdata(cdev->pdev);
vsi = ice_find_vsi(pf, qset->vport_id);
if (!vsi) {
dev_err(ice_pf_to_dev(pf), "RDMA Invalid VSI\n");
return -EINVAL;
}
q_id = qset->qs_handle;
teid = qset->teid;
return ice_dis_vsi_rdma_qset(vsi->port_info, 1, &teid, &q_id);
}
EXPORT_SYMBOL_GPL(ice_del_rdma_qset);
/**
* ice_rdma_request_reset - accept request from RDMA to perform a reset
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @reset_type: type of reset
*
* Return: Zero on success, error code on failure
*/
int ice_rdma_request_reset(struct iidc_rdma_core_dev_info *cdev,
enum iidc_rdma_reset_type reset_type)
{
enum ice_reset_req reset;
struct ice_pf *pf;
if (WARN_ON(!cdev))
return -EINVAL;
pf = pci_get_drvdata(cdev->pdev);
switch (reset_type) {
case IIDC_FUNC_RESET:
reset = ICE_RESET_PFR;
break;
case IIDC_DEV_RESET:
reset = ICE_RESET_CORER;
break;
default:
return -EINVAL;
}
return ice_schedule_reset(pf, reset);
}
EXPORT_SYMBOL_GPL(ice_rdma_request_reset);
/**
* ice_rdma_update_vsi_filter - update main VSI filters for RDMA
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @vsi_id: VSI HW idx to update filter on
* @enable: bool whether to enable or disable filters
*
* Return: Zero on success, error code on failure
*/
int ice_rdma_update_vsi_filter(struct iidc_rdma_core_dev_info *cdev,
u16 vsi_id, bool enable)
{
struct ice_vsi *vsi;
struct ice_pf *pf;
int status;
if (WARN_ON(!cdev))
return -EINVAL;
pf = pci_get_drvdata(cdev->pdev);
vsi = ice_find_vsi(pf, vsi_id);
if (!vsi)
return -EINVAL;
status = ice_cfg_rdma_fltr(&pf->hw, vsi->idx, enable);
if (status) {
dev_err(ice_pf_to_dev(pf), "Failed to %sable RDMA filtering\n",
enable ? "en" : "dis");
} else {
if (enable)
vsi->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
else
vsi->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
}
return status;
}
EXPORT_SYMBOL_GPL(ice_rdma_update_vsi_filter);
/**
* ice_alloc_rdma_qvector - alloc vector resources reserved for RDMA driver
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @entry: MSI-X entry to be removed
*
* Return: Zero on success, error code on failure
*/
int ice_alloc_rdma_qvector(struct iidc_rdma_core_dev_info *cdev,
struct msix_entry *entry)
{
struct msi_map map;
struct ice_pf *pf;
if (WARN_ON(!cdev))
return -EINVAL;
pf = pci_get_drvdata(cdev->pdev);
map = ice_alloc_irq(pf, true);
if (map.index < 0)
return -ENOMEM;
entry->entry = map.index;
entry->vector = map.virq;
return 0;
}
EXPORT_SYMBOL_GPL(ice_alloc_rdma_qvector);
/**
* ice_free_rdma_qvector - free vector resources reserved for RDMA driver
* @cdev: pointer to iidc_rdma_core_dev_info struct
* @entry: MSI-X entry to be removed
*/
void ice_free_rdma_qvector(struct iidc_rdma_core_dev_info *cdev,
struct msix_entry *entry)
{
struct msi_map map;
struct ice_pf *pf;
if (WARN_ON(!cdev || !entry))
return;
pf = pci_get_drvdata(cdev->pdev);
map.index = entry->entry;
map.virq = entry->vector;
ice_free_irq(pf, map);
}
EXPORT_SYMBOL_GPL(ice_free_rdma_qvector);
/**
* ice_adev_release - function to be mapped to AUX dev's release op
* @dev: pointer to device to free
*/
static void ice_adev_release(struct device *dev)
{
struct iidc_rdma_core_auxiliary_dev *iadev;
iadev = container_of(dev, struct iidc_rdma_core_auxiliary_dev,
adev.dev);
kfree(iadev);
}
/**
* ice_plug_aux_dev - allocate and register AUX device
* @pf: pointer to pf struct
*
* Return: Zero on success, error code on failure
*/
int ice_plug_aux_dev(struct ice_pf *pf)
{
struct iidc_rdma_core_auxiliary_dev *iadev;
struct iidc_rdma_core_dev_info *cdev;
struct auxiliary_device *adev;
int ret;
/* if this PF doesn't support a technology that requires auxiliary
* devices, then gracefully exit
*/
if (!ice_is_rdma_ena(pf))
return 0;
cdev = pf->cdev_info;
if (!cdev)
return -ENODEV;
iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
if (!iadev)
return -ENOMEM;
adev = &iadev->adev;
iadev->cdev_info = cdev;
adev->id = pf->aux_idx;
adev->dev.release = ice_adev_release;
adev->dev.parent = &pf->pdev->dev;
adev->name = cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_ROCEV2 ?
"roce" : "iwarp";
ret = auxiliary_device_init(adev);
if (ret) {
kfree(iadev);
return ret;
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ret;
}
mutex_lock(&pf->adev_mutex);
cdev->adev = adev;
mutex_unlock(&pf->adev_mutex);
return 0;
}
/* ice_unplug_aux_dev - unregister and free AUX device
* @pf: pointer to pf struct
*/
void ice_unplug_aux_dev(struct ice_pf *pf)
{
struct auxiliary_device *adev;
mutex_lock(&pf->adev_mutex);
adev = pf->cdev_info->adev;
pf->cdev_info->adev = NULL;
mutex_unlock(&pf->adev_mutex);
if (adev) {
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
}
/**
* ice_init_rdma - initializes PF for RDMA use
* @pf: ptr to ice_pf
*/
int ice_init_rdma(struct ice_pf *pf)
{
struct iidc_rdma_priv_dev_info *privd;
struct device *dev = &pf->pdev->dev;
struct iidc_rdma_core_dev_info *cdev;
int ret;
if (!ice_is_rdma_ena(pf)) {
dev_warn(dev, "RDMA is not supported on this device\n");
return 0;
}
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
pf->cdev_info = cdev;
privd = kzalloc(sizeof(*privd), GFP_KERNEL);
if (!privd) {
ret = -ENOMEM;
goto err_privd_alloc;
}
privd->pf_id = pf->hw.pf_id;
ret = xa_alloc(&ice_aux_id, &pf->aux_idx, NULL, XA_LIMIT(1, INT_MAX),
GFP_KERNEL);
if (ret) {
dev_err(dev, "Failed to allocate device ID for AUX driver\n");
ret = -ENOMEM;
goto err_alloc_xa;
}
cdev->iidc_priv = privd;
privd->netdev = pf->vsi[0]->netdev;
privd->hw_addr = (u8 __iomem *)pf->hw.hw_addr;
cdev->pdev = pf->pdev;
privd->vport_id = pf->vsi[0]->vsi_num;
pf->cdev_info->rdma_protocol |= IIDC_RDMA_PROTOCOL_ROCEV2;
ice_setup_dcb_qos_info(pf, &privd->qos_info);
ret = ice_plug_aux_dev(pf);
if (ret)
goto err_plug_aux_dev;
return 0;
err_plug_aux_dev:
pf->cdev_info->adev = NULL;
xa_erase(&ice_aux_id, pf->aux_idx);
err_alloc_xa:
kfree(privd);
err_privd_alloc:
kfree(cdev);
pf->cdev_info = NULL;
return ret;
}
/**
* ice_deinit_rdma - deinitialize RDMA on PF
* @pf: ptr to ice_pf
*/
void ice_deinit_rdma(struct ice_pf *pf)
{
if (!ice_is_rdma_ena(pf))
return;
ice_unplug_aux_dev(pf);
xa_erase(&ice_aux_id, pf->aux_idx);
kfree(pf->cdev_info->iidc_priv);
kfree(pf->cdev_info);
pf->cdev_info = NULL;
}