Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  irq_affinity.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */

#include "mlx5_core.h"
#include "mlx5_irq.h"
#include "pci_irq.h"

static void cpu_put(struct mlx5_irq_pool *pool, int cpu)
{
 pool->irqs_per_cpu[cpu]--;
}

static void cpu_get(struct mlx5_irq_pool *pool, int cpu)
{
 pool->irqs_per_cpu[cpu]++;
}

/* Gets the least loaded CPU. e.g.: the CPU with least IRQs bound to it */
static int cpu_get_least_loaded(struct mlx5_irq_pool *pool,
    const struct cpumask *req_mask)
{
 int best_cpu = -1;
 int cpu;

 for_each_cpu_and(cpu, req_mask, cpu_online_mask) {
  /* CPU has zero IRQs on it. No need to search any more CPUs. */
  if (!pool->irqs_per_cpu[cpu]) {
   best_cpu = cpu;
   break;
  }
  if (best_cpu < 0)
   best_cpu = cpu;
  if (pool->irqs_per_cpu[cpu] < pool->irqs_per_cpu[best_cpu])
   best_cpu = cpu;
 }
 if (best_cpu == -1) {
  /* There isn't online CPUs in req_mask */
  mlx5_core_err(pool->dev, "NO online CPUs in req_mask (%*pbl)\n",
         cpumask_pr_args(req_mask));
  best_cpu = cpumask_first(cpu_online_mask);
 }
 pool->irqs_per_cpu[best_cpu]++;
 return best_cpu;
}

/* Creating an IRQ from irq_pool */
static struct mlx5_irq *
irq_pool_request_irq(struct mlx5_irq_pool *pool, struct irq_affinity_desc *af_desc)
{
 struct irq_affinity_desc *auto_desc;
 struct mlx5_irq *irq;
 u32 irq_index;
 int err;

 auto_desc = kvzalloc(sizeof(*auto_desc), GFP_KERNEL);
 if (!auto_desc)
  return ERR_PTR(-ENOMEM);

 err = xa_alloc(&pool->irqs, &irq_index, NULL, pool->xa_num_irqs, GFP_KERNEL);
 if (err) {
  kvfree(auto_desc);
  return ERR_PTR(err);
 }

 if (pool->irqs_per_cpu) {
  if (cpumask_weight(&af_desc->mask) > 1)
   /* if req_mask contain more then one CPU, set the least loadad CPU
 * of req_mask
 */

   cpumask_set_cpu(cpu_get_least_loaded(pool, &af_desc->mask),
     &auto_desc->mask);
  else
   cpu_get(pool, cpumask_first(&af_desc->mask));
 }

 irq = mlx5_irq_alloc(pool, irq_index,
        cpumask_empty(&auto_desc->mask) ? af_desc : auto_desc,
        NULL);
 if (IS_ERR(irq))
  xa_erase(&pool->irqs, irq_index);

 kvfree(auto_desc);

 return irq;
}

/* Looking for the IRQ with the smallest refcount that fits req_mask.
 * If pool is sf_comp_pool, then we are looking for an IRQ with any of the
 * requested CPUs in req_mask.
 * for example: req_mask = 0xf, irq0_mask = 0x10, irq1_mask = 0x1. irq0_mask
 * isn't subset of req_mask, so we will skip it. irq1_mask is subset of req_mask,
 * we don't skip it.
 * If pool is sf_ctrl_pool, then all IRQs have the same mask, so any IRQ will
 * fit. And since mask is subset of itself, we will pass the first if bellow.
 */

static struct mlx5_irq *
irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req_mask)
{
 int start = pool->xa_num_irqs.min;
 int end = pool->xa_num_irqs.max;
 struct mlx5_irq *irq = NULL;
 struct mlx5_irq *iter;
 int irq_refcount = 0;
 unsigned long index;

 lockdep_assert_held(&pool->lock);
 xa_for_each_range(&pool->irqs, index, iter, start, end) {
  struct cpumask *iter_mask = mlx5_irq_get_affinity_mask(iter);
  int iter_refcount = mlx5_irq_read_locked(iter);

  if (!cpumask_subset(iter_mask, req_mask))
   /* skip IRQs with a mask which is not subset of req_mask */
   continue;
  if (iter_refcount < pool->min_threshold)
   /* If we found an IRQ with less than min_thres, return it */
   return iter;
  if (!irq || iter_refcount < irq_refcount) {
   /* In case we won't find an IRQ with less than min_thres,
 * keep a pointer to the least used IRQ
 */

   irq_refcount = iter_refcount;
   irq = iter;
  }
 }
 return irq;
}

/**
 * mlx5_irq_affinity_request - request an IRQ according to the given mask.
 * @dev: mlx5 core device which is requesting the IRQ.
 * @pool: IRQ pool to request from.
 * @af_desc: affinity descriptor for this IRQ.
 *
 * This function returns a pointer to IRQ, or ERR_PTR in case of error.
 */

struct mlx5_irq *
mlx5_irq_affinity_request(struct mlx5_core_dev *dev, struct mlx5_irq_pool *pool,
     struct irq_affinity_desc *af_desc)
{
 struct mlx5_irq *least_loaded_irq, *new_irq;
 int ret;

 mutex_lock(&pool->lock);
 least_loaded_irq = irq_pool_find_least_loaded(pool, &af_desc->mask);
 if (least_loaded_irq &&
     mlx5_irq_read_locked(least_loaded_irq) < pool->min_threshold)
  goto out;
 /* We didn't find an IRQ with less than min_thres, try to allocate a new IRQ */
 new_irq = irq_pool_request_irq(pool, af_desc);
 if (IS_ERR(new_irq)) {
  if (!least_loaded_irq) {
   /* We failed to create an IRQ and we didn't find an IRQ */
   mlx5_core_err(pool->dev, "Didn't find a matching IRQ. err = %ld\n",
          PTR_ERR(new_irq));
   mutex_unlock(&pool->lock);
   return new_irq;
  }
  /* We failed to create a new IRQ for the requested affinity,
 * sharing existing IRQ.
 */

  goto out;
 }
 least_loaded_irq = new_irq;
 goto unlock;
out:
 mlx5_irq_get_locked(least_loaded_irq);
 if (mlx5_irq_read_locked(least_loaded_irq) > pool->max_threshold)
  mlx5_core_dbg(pool->dev, "IRQ %u overloaded, pool_name: %s, %u EQs on this irq\n",
         pci_irq_vector(pool->dev->pdev,
          mlx5_irq_get_index(least_loaded_irq)), pool->name,
         mlx5_irq_read_locked(least_loaded_irq) / MLX5_EQ_REFS_PER_IRQ);
unlock:
 mutex_unlock(&pool->lock);
 if (mlx5_irq_pool_is_sf_pool(pool)) {
  ret = auxiliary_device_sysfs_irq_add(mlx5_sf_coredev_to_adev(dev),
           mlx5_irq_get_irq(least_loaded_irq));
  if (ret) {
   mlx5_core_err(dev, "Failed to create sysfs entry for irq %d, ret = %d\n",
          mlx5_irq_get_irq(least_loaded_irq), ret);
   mlx5_irq_put(least_loaded_irq);
   least_loaded_irq = ERR_PTR(ret);
  }
 }
 return least_loaded_irq;
}

void mlx5_irq_affinity_irq_release(struct mlx5_core_dev *dev, struct mlx5_irq *irq)
{
 struct mlx5_irq_pool *pool = mlx5_irq_get_pool(irq);
 int cpu;

 cpu = cpumask_first(mlx5_irq_get_affinity_mask(irq));
 synchronize_irq(pci_irq_vector(pool->dev->pdev,
           mlx5_irq_get_index(irq)));
 if (mlx5_irq_pool_is_sf_pool(pool))
  auxiliary_device_sysfs_irq_remove(mlx5_sf_coredev_to_adev(dev),
        mlx5_irq_get_irq(irq));
 if (mlx5_irq_put(irq))
  if (pool->irqs_per_cpu)
   cpu_put(pool, cpu);
}

Messung V0.5
C=99 H=93 G=95

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge