Exemplo n.º 1
0
int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
			int cq_idx)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	int err = 0;
	char name[25];
	int timestamp_en = 0;
	bool assigned_eq = false;

	cq->dev = mdev->pndev[priv->port];
	cq->mcq.set_ci_db  = cq->wqres.db.db;
	cq->mcq.arm_db     = cq->wqres.db.db + 1;
	*cq->mcq.set_ci_db = 0;
	*cq->mcq.arm_db    = 0;
	memset(cq->buf, 0, cq->buf_size);

	if (cq->is_tx == RX) {
		if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port,
					     cq->vector)) {
			cq->vector = cpumask_first(priv->rx_ring[cq->ring]->affinity_mask);

			err = mlx4_assign_eq(mdev->dev, priv->port,
					     MLX4_EQ_ID_TO_UUID(MLX4_EQ_ID_EN,
								priv->port,
								cq_idx),
					     mlx4_en_cq_eq_cb,
					     &priv->rx_cq[cq_idx],
					     &cq->vector);
			if (err) {
				mlx4_err(mdev, "Failed assigning an EQ to %s\n",
					 name);
				goto free_eq;
			}

			assigned_eq = true;
		}

		/* Set IRQ for specific name (per ring) */
		err = mlx4_rename_eq(mdev->dev, priv->port, cq->vector,
				     MLX4_EN_EQ_NAME_PRIORITY, "%s-%d",
				     priv->dev->name, cq->ring);

		if (err) {
			mlx4_warn(mdev, "Failed to rename EQ, continuing with default name\n");
			err = 0;
		}

#if defined(HAVE_IRQ_DESC_GET_IRQ_DATA) && defined(HAVE_IRQ_TO_DESC_EXPORTED)
		cq->irq_desc =
			irq_to_desc(mlx4_eq_get_irq(mdev->dev,
						    cq->vector));
#endif
	} else {
		/* For TX we use the same irq per
		ring we assigned for the RX    */
		struct mlx4_en_cq *rx_cq;

		cq_idx = cq_idx % priv->rx_ring_num;
		rx_cq = priv->rx_cq[cq_idx];
		cq->vector = rx_cq->vector;
	}

	if (!cq->is_tx)
		cq->size = priv->rx_ring[cq->ring]->actual_size;

	if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
	    (!cq->is_tx && priv->hwtstamp_config.rx_filter))
		timestamp_en = 1;

	err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt,
			    &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq,
			    cq->vector, 0, timestamp_en, &cq->wqres.buf, false);
	if (err)
		goto free_eq;

	cq->mcq.comp  = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq;
	cq->mcq.event = mlx4_en_cq_event;

	if (cq->is_tx) {
		netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_tx_cq,
			       NAPI_POLL_WEIGHT);
	} else {
		netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
#ifdef HAVE_NAPI_HASH_ADD
		napi_hash_add(&cq->napi);
#endif
	}

	napi_enable(&cq->napi);

	return 0;

free_eq:
	if (assigned_eq)
		mlx4_release_eq(mdev->dev, MLX4_EQ_ID_TO_UUID(
					MLX4_EQ_ID_EN, priv->port, cq_idx),
				cq->vector);
	cq->vector = mdev->dev->caps.num_comp_vectors;
	return err;
}
Exemplo n.º 2
0
int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
			int cq_idx)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	int err = 0;
	char name[25];
	int timestamp_en = 0;
	struct cpu_rmap *rmap =
#ifdef CONFIG_RFS_ACCEL
		priv->dev->rx_cpu_rmap;
#else
		NULL;
#endif

	cq->dev = mdev->pndev[priv->port];
	cq->mcq.set_ci_db  = cq->wqres.db.db;
	cq->mcq.arm_db     = cq->wqres.db.db + 1;
	*cq->mcq.set_ci_db = 0;
	*cq->mcq.arm_db    = 0;
	memset(cq->buf, 0, cq->buf_size);

	if (cq->is_tx == RX) {
		if (mdev->dev->caps.comp_pool) {
			if (!cq->vector) {
				sprintf(name, "%s-%d", priv->dev->name,
					cq->ring);
				/* Set IRQ for specific name (per ring) */
				if (mlx4_assign_eq(mdev->dev, name, rmap,
						   &cq->vector)) {
					cq->vector = (cq->ring + 1 + priv->port)
					    % mdev->dev->caps.num_comp_vectors;
					mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n",
						  name);
				}

				cq->irq_desc =
					irq_to_desc(mlx4_eq_get_irq(mdev->dev,
								    cq->vector));
			}
		} else {
			cq->vector = (cq->ring + 1 + priv->port) %
				mdev->dev->caps.num_comp_vectors;
		}
	} else {
		/* For TX we use the same irq per
		ring we assigned for the RX    */
		struct mlx4_en_cq *rx_cq;

		cq_idx = cq_idx % priv->rx_ring_num;
		rx_cq = priv->rx_cq[cq_idx];
		cq->vector = rx_cq->vector;
	}

	if (!cq->is_tx)
		cq->size = priv->rx_ring[cq->ring]->actual_size;

	if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
	    (!cq->is_tx && priv->hwtstamp_config.rx_filter))
		timestamp_en = 1;

	err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt,
			    &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq,
			    cq->vector, 0, timestamp_en);
	if (err)
		return err;

	cq->mcq.comp  = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq;
	cq->mcq.event = mlx4_en_cq_event;

	if (cq->is_tx) {
		netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_tx_cq,
			       NAPI_POLL_WEIGHT);
	} else {
		struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring];

		err = irq_set_affinity_hint(cq->mcq.irq,
					    ring->affinity_mask);
		if (err)
			mlx4_warn(mdev, "Failed setting affinity hint\n");

		netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
		napi_hash_add(&cq->napi);
	}

	napi_enable(&cq->napi);

	return 0;
}
Exemplo n.º 3
0
/**
 * ixgbe_alloc_q_vector - Allocate memory for a single interrupt vector
 * @adapter: board private structure to initialize
 * @v_count: q_vectors allocated on adapter, used for ring interleaving
 * @v_idx: index of vector in adapter struct
 * @txr_count: total number of Tx rings to allocate
 * @txr_idx: index of first Tx ring to allocate
 * @rxr_count: total number of Rx rings to allocate
 * @rxr_idx: index of first Rx ring to allocate
 *
 * We allocate one q_vector.  If allocation fails we return -ENOMEM.
 **/
static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
				int v_count, int v_idx,
				int txr_count, int txr_idx,
				int rxr_count, int rxr_idx)
{
	struct ixgbe_q_vector *q_vector;
	struct ixgbe_ring *ring;
	int node = NUMA_NO_NODE;
	int cpu = -1;
	int ring_count, size;
	u8 tcs = netdev_get_num_tc(adapter->netdev);

	ring_count = txr_count + rxr_count;
	size = sizeof(struct ixgbe_q_vector) +
	       (sizeof(struct ixgbe_ring) * ring_count);

	/* customize cpu for Flow Director mapping */
	if ((tcs <= 1) && !(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) {
		u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
		if (rss_i > 1 && adapter->atr_sample_rate) {
			if (cpu_online(v_idx)) {
				cpu = v_idx;
				node = cpu_to_node(cpu);
			}
		}
	}

	/* allocate q_vector and rings */
	q_vector = kzalloc_node(size, GFP_KERNEL, node);
	if (!q_vector)
		q_vector = kzalloc(size, GFP_KERNEL);
	if (!q_vector)
		return -ENOMEM;

	/* setup affinity mask and node */
	if (cpu != -1)
		cpumask_set_cpu(cpu, &q_vector->affinity_mask);
	q_vector->numa_node = node;

#ifdef CONFIG_IXGBE_DCA
	/* initialize CPU for DCA */
	q_vector->cpu = -1;

#endif
	/* initialize NAPI */
	netif_napi_add(adapter->netdev, &q_vector->napi,
		       ixgbe_poll, 64);
	napi_hash_add(&q_vector->napi);

	/* tie q_vector and adapter together */
	adapter->q_vector[v_idx] = q_vector;
	q_vector->adapter = adapter;
	q_vector->v_idx = v_idx;

	/* initialize work limits */
	q_vector->tx.work_limit = adapter->tx_work_limit;

	/* initialize pointer to rings */
	ring = q_vector->ring;

	/* intialize ITR */
	if (txr_count && !rxr_count) {
		/* tx only vector */
		if (adapter->tx_itr_setting == 1)
			q_vector->itr = IXGBE_10K_ITR;
		else
			q_vector->itr = adapter->tx_itr_setting;
	} else {
		/* rx or rx/tx vector */
		if (adapter->rx_itr_setting == 1)
			q_vector->itr = IXGBE_20K_ITR;
		else
			q_vector->itr = adapter->rx_itr_setting;
	}

	while (txr_count) {
		/* assign generic ring traits */
		ring->dev = &adapter->pdev->dev;
		ring->netdev = adapter->netdev;

		/* configure backlink on ring */
		ring->q_vector = q_vector;

		/* update q_vector Tx values */
		ixgbe_add_ring(ring, &q_vector->tx);

		/* apply Tx specific ring traits */
		ring->count = adapter->tx_ring_count;
		if (adapter->num_rx_pools > 1)
			ring->queue_index =
				txr_idx % adapter->num_rx_queues_per_pool;
		else
			ring->queue_index = txr_idx;

		/* assign ring to adapter */
		adapter->tx_ring[txr_idx] = ring;

		/* update count and index */
		txr_count--;
		txr_idx += v_count;

		/* push pointer to next ring */
		ring++;
	}

	while (rxr_count) {
		/* assign generic ring traits */
		ring->dev = &adapter->pdev->dev;
		ring->netdev = adapter->netdev;

		/* configure backlink on ring */
		ring->q_vector = q_vector;

		/* update q_vector Rx values */
		ixgbe_add_ring(ring, &q_vector->rx);

		/*
		 * 82599 errata, UDP frames with a 0 checksum
		 * can be marked as checksum errors.
		 */
		if (adapter->hw.mac.type == ixgbe_mac_82599EB)
			set_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, &ring->state);

#ifdef IXGBE_FCOE
		if (adapter->netdev->features & NETIF_F_FCOE_MTU) {
			struct ixgbe_ring_feature *f;
			f = &adapter->ring_feature[RING_F_FCOE];
			if ((rxr_idx >= f->offset) &&
			    (rxr_idx < f->offset + f->indices))
				set_bit(__IXGBE_RX_FCOE, &ring->state);
		}

#endif /* IXGBE_FCOE */
		/* apply Rx specific ring traits */
		ring->count = adapter->rx_ring_count;
		if (adapter->num_rx_pools > 1)
			ring->queue_index =
				rxr_idx % adapter->num_rx_queues_per_pool;
		else
			ring->queue_index = rxr_idx;

		/* assign ring to adapter */
		adapter->rx_ring[rxr_idx] = ring;

		/* update count and index */
		rxr_count--;
		rxr_idx += v_count;

		/* push pointer to next ring */
		ring++;
	}

	return 0;
}
Exemplo n.º 4
0
static int sn_alloc_queues(struct sn_device *dev,
		void *rings, uint64_t rings_size,
		struct tx_queue_opts *txq_opts,
		struct rx_queue_opts *rxq_opts)
{
	struct sn_queue *queue;
	char *p = rings;

	void *memchunk;

	int num_queues;
	int i;

	int ret;

	ret = netif_set_real_num_tx_queues(dev->netdev, dev->num_txq);
	if (ret) {
		log_err("netif_set_real_num_tx_queues() failed\n");
		return ret;
	}

	ret = netif_set_real_num_rx_queues(dev->netdev, dev->num_rxq);
	if (ret) {
		log_err("netif_set_real_num_rx_queues() failed\n");
		return ret;
	}

	num_queues = dev->num_txq + dev->num_rxq;

	memchunk = kzalloc(sizeof(struct sn_queue) * num_queues, GFP_KERNEL);
	if (!memchunk)
		return -ENOMEM;

	queue = memchunk;

	for (i = 0; i < dev->num_txq; i++) {
		dev->tx_queues[i] = queue;

		queue->dev = dev;
		queue->queue_id = i;
		queue->tx.opts = *txq_opts;

		queue->tx.netdev_txq = netdev_get_tx_queue(dev->netdev, i);

		queue->drv_to_sn = (struct llring *)p;
		p += llring_bytes(queue->drv_to_sn);

		queue->sn_to_drv = (struct llring *)p;
		p += llring_bytes(queue->sn_to_drv);

		queue++;
	}

	for (i = 0; i < dev->num_rxq; i++) {
		dev->rx_queues[i] = queue;

		queue->dev = dev;
		queue->queue_id = i;
		queue->rx.opts = *rxq_opts;

		queue->rx.rx_regs = (struct sn_rxq_registers *)p;
		p += sizeof(struct sn_rxq_registers);

		queue->drv_to_sn = (struct llring *)p;
		p += llring_bytes(queue->drv_to_sn);

		queue->sn_to_drv = (struct llring *)p;
		p += llring_bytes(queue->sn_to_drv);

		queue++;
	}

	if ((uintptr_t)p != (uintptr_t)rings + rings_size) {
		log_err("Invalid ring space size: %llu, not %llu, at%p)\n",
				rings_size,
				(uint64_t)((uintptr_t)p - (uintptr_t)rings),
				rings);
		kfree(memchunk);
		return -EFAULT;
	}

	for (i = 0; i < dev->num_rxq; i++) {
		netif_napi_add(dev->netdev, &dev->rx_queues[i]->rx.napi,
				sn_poll, NAPI_POLL_WEIGHT);
#ifdef CONFIG_NET_RX_BUSY_POLL
		napi_hash_add(&dev->rx_queues[i]->rx.napi);
#endif
		spin_lock_init(&dev->rx_queues[i]->rx.lock);
	}

	sn_test_cache_alignment(dev);

	return 0;
}
Exemplo n.º 5
0
static int sn_alloc_queues(struct sn_device *dev, void *rings, u64 rings_size)
{
	struct sn_queue *queue;
	char *p = rings;

	void *memchunk;

	int num_queues;
	int i;

	int ret;
	
	ret = netif_set_real_num_tx_queues(dev->netdev, dev->num_txq);
	if (ret) {
		log_err("netif_set_real_num_tx_queues() failed\n");
		return ret;
	}

	ret = netif_set_real_num_rx_queues(dev->netdev, dev->num_rxq);
	if (ret) {
		log_err("netif_set_real_num_rx_queues() failed\n");
		return ret;
	}

	num_queues = dev->num_txq + dev->num_rxq;

	memchunk = kzalloc(sizeof(struct sn_queue) * num_queues, GFP_KERNEL);
	if (!memchunk)
		return -ENOMEM;

	queue = memchunk;

	for (i = 0; i < dev->num_txq; i++) {
		dev->tx_queues[i] = queue;

		queue->dev = dev;
		queue->queue_id = i;
		queue->is_rx = false;
		
		queue->drv_to_sn = (struct llring *)p;
		p += llring_bytes(queue->drv_to_sn);

		queue->sn_to_drv = (struct llring *)p;
		p += llring_bytes(queue->sn_to_drv);

		queue++;
	}

	for (i = 0; i < dev->num_rxq; i++) {
		dev->rx_queues[i] = queue;

		queue->dev = dev;
		queue->queue_id = i;
		queue->is_rx = true;
		sn_stack_init(&queue->ready_tx_meta);

		queue->rx_regs = (struct sn_rxq_registers *)p;
		p += sizeof(struct sn_rxq_registers);

		queue->drv_to_sn = (struct llring *)p;
		p += llring_bytes(queue->drv_to_sn);

		queue->sn_to_drv = (struct llring *)p;
		p += llring_bytes(queue->sn_to_drv);

		queue++;
	}

	if ((uint64_t)p != (uint64_t)rings + rings_size) {
		log_err("Invalid ring space size: %llu, not %llu, at%p)\n", 
				rings_size, 
				(uint64_t)p - (uint64_t)rings,
				rings);
		kfree(memchunk);
		return -EFAULT;
	}

	for (i = 0; i < dev->num_rxq; i++) {
		netif_napi_add(dev->netdev, &dev->rx_queues[i]->napi,
				sn_poll, NAPI_POLL_WEIGHT);
		napi_hash_add(&dev->rx_queues[i]->napi);
		spin_lock_init(&dev->rx_queues[i]->lock);
	}

	sn_test_cache_alignment(dev);

	return 0;
}