Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/mellanox/mlx5/core/sf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 9 kB image not shown  

Quelle  hw_table.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2020 Mellanox Technologies Ltd */
#include <linux/mlx5/driver.h>
#include "vhca_event.h"
#include "priv.h"
#include "sf.h"
#include "mlx5_ifc_vhca_event.h"
#include "ecpf.h"
#include "mlx5_core.h"
#include "eswitch.h"
#include "diag/sf_tracepoint.h"
#include "devlink.h"

struct mlx5_sf_hw {
 u32 usr_sfnum;
 u8 allocated: 1;
 u8 pending_delete: 1;
};

struct mlx5_sf_hwc_table {
 struct mlx5_sf_hw *sfs;
 int max_fn;
 u16 start_fn_id;
};

enum mlx5_sf_hwc_index {
 MLX5_SF_HWC_LOCAL,
 MLX5_SF_HWC_EXTERNAL,
 MLX5_SF_HWC_MAX,
};

struct mlx5_sf_hw_table {
 struct mlx5_core_dev *dev;
 struct mutex table_lock; /* Serializes sf deletion and vhca state change handler. */
 struct notifier_block vhca_nb;
 struct mlx5_sf_hwc_table hwc[MLX5_SF_HWC_MAX];
};

static struct mlx5_sf_hwc_table *
mlx5_sf_controller_to_hwc(struct mlx5_core_dev *dev, u32 controller)
{
 int idx = !!controller;

 return &dev->priv.sf_hw_table->hwc[idx];
}

u16 mlx5_sf_sw_to_hw_id(struct mlx5_core_dev *dev, u32 controller, u16 sw_id)
{
 struct mlx5_sf_hwc_table *hwc;

 hwc = mlx5_sf_controller_to_hwc(dev, controller);
 return hwc->start_fn_id + sw_id;
}

static u16 mlx5_sf_hw_to_sw_id(struct mlx5_sf_hwc_table *hwc, u16 hw_id)
{
 return hw_id - hwc->start_fn_id;
}

static struct mlx5_sf_hwc_table *
mlx5_sf_table_fn_to_hwc(struct mlx5_sf_hw_table *table, u16 fn_id)
{
 int i;

 for (i = 0; i < ARRAY_SIZE(table->hwc); i++) {
  if (table->hwc[i].max_fn &&
      fn_id >= table->hwc[i].start_fn_id &&
      fn_id < (table->hwc[i].start_fn_id + table->hwc[i].max_fn))
   return &table->hwc[i];
 }
 return NULL;
}

static int mlx5_sf_hw_table_id_alloc(struct mlx5_sf_hw_table *table, u32 controller,
         u32 usr_sfnum)
{
 struct mlx5_sf_hwc_table *hwc;
 int free_idx = -1;
 int i;

 hwc = mlx5_sf_controller_to_hwc(table->dev, controller);
 if (!hwc->sfs)
  return -ENOSPC;

 for (i = 0; i < hwc->max_fn; i++) {
  if (!hwc->sfs[i].allocated && free_idx == -1) {
   free_idx = i;
   continue;
  }

  if (hwc->sfs[i].allocated && hwc->sfs[i].usr_sfnum == usr_sfnum)
   return -EEXIST;
 }

 if (free_idx == -1)
  return -ENOSPC;

 hwc->sfs[free_idx].usr_sfnum = usr_sfnum;
 hwc->sfs[free_idx].allocated = true;
 return free_idx;
}

static void mlx5_sf_hw_table_id_free(struct mlx5_sf_hw_table *table, u32 controller, int id)
{
 struct mlx5_sf_hwc_table *hwc;

 hwc = mlx5_sf_controller_to_hwc(table->dev, controller);
 hwc->sfs[id].allocated = false;
 hwc->sfs[id].pending_delete = false;
}

int mlx5_sf_hw_table_sf_alloc(struct mlx5_core_dev *dev, u32 controller, u32 usr_sfnum)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
 u16 hw_fn_id;
 int sw_id;
 int err;

 if (!table)
  return -EOPNOTSUPP;

 mutex_lock(&table->table_lock);
 sw_id = mlx5_sf_hw_table_id_alloc(table, controller, usr_sfnum);
 if (sw_id < 0) {
  err = sw_id;
  goto exist_err;
 }

 hw_fn_id = mlx5_sf_sw_to_hw_id(dev, controller, sw_id);
 err = mlx5_cmd_alloc_sf(dev, hw_fn_id);
 if (err)
  goto err;

 err = mlx5_modify_vhca_sw_id(dev, hw_fn_id, usr_sfnum);
 if (err)
  goto vhca_err;

 if (controller) {
  /* If this SF is for external controller, SF manager
 * needs to arm firmware to receive the events.
 */

  err = mlx5_vhca_event_arm(dev, hw_fn_id);
  if (err)
   goto vhca_err;
 }

 trace_mlx5_sf_hwc_alloc(dev, controller, hw_fn_id, usr_sfnum);
 mutex_unlock(&table->table_lock);
 return sw_id;

vhca_err:
 mlx5_cmd_dealloc_sf(dev, hw_fn_id);
err:
 mlx5_sf_hw_table_id_free(table, controller, sw_id);
exist_err:
 mutex_unlock(&table->table_lock);
 return err;
}

void mlx5_sf_hw_table_sf_free(struct mlx5_core_dev *dev, u32 controller, u16 id)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
 u16 hw_fn_id;

 mutex_lock(&table->table_lock);
 hw_fn_id = mlx5_sf_sw_to_hw_id(dev, controller, id);
 mlx5_cmd_dealloc_sf(dev, hw_fn_id);
 mlx5_sf_hw_table_id_free(table, controller, id);
 mutex_unlock(&table->table_lock);
}

static void mlx5_sf_hw_table_hwc_sf_free(struct mlx5_core_dev *dev,
      struct mlx5_sf_hwc_table *hwc, int idx)
{
 mlx5_cmd_dealloc_sf(dev, hwc->start_fn_id + idx);
 hwc->sfs[idx].allocated = false;
 hwc->sfs[idx].pending_delete = false;
 trace_mlx5_sf_hwc_free(dev, hwc->start_fn_id + idx);
}

void mlx5_sf_hw_table_sf_deferred_free(struct mlx5_core_dev *dev, u32 controller, u16 id)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
 u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {};
 struct mlx5_sf_hwc_table *hwc;
 u16 hw_fn_id;
 u8 state;
 int err;

 hw_fn_id = mlx5_sf_sw_to_hw_id(dev, controller, id);
 hwc = mlx5_sf_controller_to_hwc(dev, controller);
 mutex_lock(&table->table_lock);
 err = mlx5_cmd_query_vhca_state(dev, hw_fn_id, out, sizeof(out));
 if (err)
  goto err;
 state = MLX5_GET(query_vhca_state_out, out, vhca_state_context.vhca_state);
 if (state == MLX5_VHCA_STATE_ALLOCATED) {
  mlx5_cmd_dealloc_sf(dev, hw_fn_id);
  hwc->sfs[id].allocated = false;
 } else {
  hwc->sfs[id].pending_delete = true;
  trace_mlx5_sf_hwc_deferred_free(dev, hw_fn_id);
 }
err:
 mutex_unlock(&table->table_lock);
}

static void mlx5_sf_hw_table_hwc_dealloc_all(struct mlx5_core_dev *dev,
          struct mlx5_sf_hwc_table *hwc)
{
 int i;

 for (i = 0; i < hwc->max_fn; i++) {
  if (hwc->sfs[i].allocated)
   mlx5_sf_hw_table_hwc_sf_free(dev, hwc, i);
 }
}

static void mlx5_sf_hw_table_dealloc_all(struct mlx5_sf_hw_table *table)
{
 mlx5_sf_hw_table_hwc_dealloc_all(table->dev, &table->hwc[MLX5_SF_HWC_EXTERNAL]);
 mlx5_sf_hw_table_hwc_dealloc_all(table->dev, &table->hwc[MLX5_SF_HWC_LOCAL]);
}

static int mlx5_sf_hw_table_hwc_init(struct mlx5_sf_hwc_table *hwc, u16 max_fn, u16 base_id)
{
 struct mlx5_sf_hw *sfs;

 if (!max_fn)
  return 0;

 sfs = kcalloc(max_fn, sizeof(*sfs), GFP_KERNEL);
 if (!sfs)
  return -ENOMEM;

 hwc->sfs = sfs;
 hwc->max_fn = max_fn;
 hwc->start_fn_id = base_id;
 return 0;
}

static void mlx5_sf_hw_table_hwc_cleanup(struct mlx5_sf_hwc_table *hwc)
{
 kfree(hwc->sfs);
}

static void mlx5_sf_hw_table_res_unregister(struct mlx5_core_dev *dev)
{
 devl_resources_unregister(priv_to_devlink(dev));
}

static int mlx5_sf_hw_table_res_register(struct mlx5_core_dev *dev, u16 max_fn,
      u16 max_ext_fn)
{
 struct devlink_resource_size_params size_params;
 struct devlink *devlink = priv_to_devlink(dev);
 int err;

 devlink_resource_size_params_init(&size_params, max_fn, max_fn, 1,
       DEVLINK_RESOURCE_UNIT_ENTRY);
 err = devl_resource_register(devlink, "max_local_SFs", max_fn, MLX5_DL_RES_MAX_LOCAL_SFS,
         DEVLINK_RESOURCE_ID_PARENT_TOP, &size_params);
 if (err)
  return err;

 devlink_resource_size_params_init(&size_params, max_ext_fn, max_ext_fn, 1,
       DEVLINK_RESOURCE_UNIT_ENTRY);
 return devl_resource_register(devlink, "max_external_SFs", max_ext_fn,
          MLX5_DL_RES_MAX_EXTERNAL_SFS, DEVLINK_RESOURCE_ID_PARENT_TOP,
          &size_params);
}

int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
{
 struct mlx5_sf_hw_table *table;
 u16 max_ext_fn = 0;
 u16 ext_base_id = 0;
 u16 base_id;
 u16 max_fn;
 int err;

 if (!mlx5_vhca_event_supported(dev))
  return 0;

 max_fn = mlx5_sf_max_functions(dev);

 err = mlx5_esw_sf_max_hpf_functions(dev, &max_ext_fn, &ext_base_id);
 if (err)
  return err;

 if (mlx5_sf_hw_table_res_register(dev, max_fn, max_ext_fn))
  mlx5_core_dbg(dev, "failed to register max SFs resources");

 if (!max_fn && !max_ext_fn)
  return 0;

 table = kzalloc(sizeof(*table), GFP_KERNEL);
 if (!table) {
  err = -ENOMEM;
  goto alloc_err;
 }

 mutex_init(&table->table_lock);
 table->dev = dev;
 dev->priv.sf_hw_table = table;

 base_id = mlx5_sf_start_function_id(dev);
 err = mlx5_sf_hw_table_hwc_init(&table->hwc[MLX5_SF_HWC_LOCAL], max_fn, base_id);
 if (err)
  goto table_err;

 err = mlx5_sf_hw_table_hwc_init(&table->hwc[MLX5_SF_HWC_EXTERNAL],
     max_ext_fn, ext_base_id);
 if (err)
  goto ext_err;

 mlx5_core_dbg(dev, "SF HW table: max sfs = %d, ext sfs = %d\n", max_fn, max_ext_fn);
 return 0;

ext_err:
 mlx5_sf_hw_table_hwc_cleanup(&table->hwc[MLX5_SF_HWC_LOCAL]);
table_err:
 mutex_destroy(&table->table_lock);
 kfree(table);
alloc_err:
 mlx5_sf_hw_table_res_unregister(dev);
 return err;
}

void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;

 if (!table)
  goto res_unregister;

 mlx5_sf_hw_table_hwc_cleanup(&table->hwc[MLX5_SF_HWC_EXTERNAL]);
 mlx5_sf_hw_table_hwc_cleanup(&table->hwc[MLX5_SF_HWC_LOCAL]);
 mutex_destroy(&table->table_lock);
 kfree(table);
res_unregister:
 mlx5_sf_hw_table_res_unregister(dev);
}

static int mlx5_sf_hw_vhca_event(struct notifier_block *nb, unsigned long opcode, void *data)
{
 struct mlx5_sf_hw_table *table = container_of(nb, struct mlx5_sf_hw_table, vhca_nb);
 const struct mlx5_vhca_state_event *event = data;
 struct mlx5_sf_hwc_table *hwc;
 struct mlx5_sf_hw *sf_hw;
 u16 sw_id;

 if (event->new_vhca_state != MLX5_VHCA_STATE_ALLOCATED)
  return 0;

 hwc = mlx5_sf_table_fn_to_hwc(table, event->function_id);
 if (!hwc)
  return 0;

 sw_id = mlx5_sf_hw_to_sw_id(hwc, event->function_id);
 sf_hw = &hwc->sfs[sw_id];

 mutex_lock(&table->table_lock);
 /* SF driver notified through firmware that SF is finally detached.
 * Hence recycle the sf hardware id for reuse.
 */

 if (sf_hw->allocated && sf_hw->pending_delete)
  mlx5_sf_hw_table_hwc_sf_free(table->dev, hwc, sw_id);
 mutex_unlock(&table->table_lock);
 return 0;
}

int mlx5_sf_hw_table_create(struct mlx5_core_dev *dev)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;

 if (!table)
  return 0;

 table->vhca_nb.notifier_call = mlx5_sf_hw_vhca_event;
 return mlx5_vhca_event_notifier_register(dev, &table->vhca_nb);
}

void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev)
{
 struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;

 if (!table)
  return;

 mlx5_vhca_event_notifier_unregister(dev, &table->vhca_nb);
 /* Dealloc SFs whose firmware event has been missed. */
 mlx5_sf_hw_table_dealloc_all(table);
}

bool mlx5_sf_hw_table_supported(const struct mlx5_core_dev *dev)
{
 return !!dev->priv.sf_hw_table;
}

Messung V0.5
C=98 H=92 G=94

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.