Commit 3b21c128 authored by Jiawen Wu's avatar Jiawen Wu Committed by Duanqiang Wen
Browse files

net: wangxun: add ethtool_ops for channel number

mainline inclusion
from mainline-v6.8-rc1
commit 907ee6681788556b9ade3ad0a1f6f4aea192399c
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9IP8F
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=937d46ecc5f941b26270bdf7ce37495f12b25955



---------------------------------------------------------

Add support to get RX/TX queue number with ethtool -l, and set RX/TX
queue number with ethtool -L. Since interrupts need to be rescheduled,
adjust the allocation of msix enties.

Signed-off-by: default avatarJiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarDuanqiang Wen <duanqiangwen@net-swift.com>
parent 3b1ebd8a
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -364,3 +364,59 @@ void wx_set_msglevel(struct net_device *netdev, u32 data)
	wx->msg_enable = data;
}
EXPORT_SYMBOL(wx_set_msglevel);
static unsigned int wx_max_channels(struct wx *wx)
{
	unsigned int max_combined;

	if (!wx->msix_q_entries) {
		/* We only support one q_vector without MSI-X */
		max_combined = 1;
	} else {
		/* support up to max allowed queues with RSS */
		if (wx->mac.type == wx_mac_sp)
			max_combined = 63;
		else
			max_combined = 8;
	}

	return max_combined;
}

void wx_get_channels(struct net_device *dev,
		     struct ethtool_channels *ch)
{
	struct wx *wx = netdev_priv(dev);

	/* report maximum channels */
	ch->max_combined = wx_max_channels(wx);

	/* report info for other vector */
	if (wx->msix_q_entries) {
		ch->max_other = 1;
		ch->other_count = 1;
	}

	/* record RSS queues */
	ch->combined_count = wx->ring_feature[RING_F_RSS].indices;
}
EXPORT_SYMBOL(wx_get_channels);

int wx_set_channels(struct net_device *dev,
		    struct ethtool_channels *ch)
{
	unsigned int count = ch->combined_count;
	struct wx *wx = netdev_priv(dev);

	/* verify other_count has not changed */
	if (ch->other_count != 1)
		return -EINVAL;

	/* verify the number of channels does not exceed hardware limits */
	if (count > wx_max_channels(wx))
		return -EINVAL;

	wx->ring_feature[RING_F_RSS].limit = count;

	return 0;
}
EXPORT_SYMBOL(wx_set_channels);
+4 −0
Original line number Diff line number Diff line
@@ -36,4 +36,8 @@ int wx_set_coalesce(struct net_device *netdev,
		    struct netlink_ext_ack *extack);
u32 wx_get_msglevel(struct net_device *netdev);
void wx_set_msglevel(struct net_device *netdev, u32 data);
void wx_get_channels(struct net_device *dev,
		     struct ethtool_channels *ch);
int wx_set_channels(struct net_device *dev,
		    struct ethtool_channels *ch);
#endif /* _WX_ETHTOOL_H_ */
+101 −2
Original line number Diff line number Diff line
@@ -149,9 +149,9 @@ void wx_irq_disable(struct wx *wx)
		int vector;

		for (vector = 0; vector < wx->num_q_vectors; vector++)
			synchronize_irq(wx->msix_entries[vector].vector);
			synchronize_irq(wx->msix_q_entries[vector].vector);

		synchronize_irq(wx->msix_entries[vector].vector);
		synchronize_irq(wx->msix_entry->vector);
	} else {
		synchronize_irq(pdev->irq);
	}
@@ -1597,6 +1597,72 @@ static void wx_restore_vlan(struct wx *wx)
		wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid);
}

static void wx_store_reta(struct wx *wx)
{
	u8 *indir_tbl = wx->rss_indir_tbl;
	u32 reta = 0;
	u32 i;

	/* Fill out the redirection table as follows:
	 *  - 8 bit wide entries containing 4 bit RSS index
	 */
	for (i = 0; i < WX_MAX_RETA_ENTRIES; i++) {
		reta |= indir_tbl[i] << (i & 0x3) * 8;
		if ((i & 3) == 3) {
			wr32(wx, WX_RDB_RSSTBL(i >> 2), reta);
			reta = 0;
		}
	}
}

static void wx_setup_reta(struct wx *wx)
{
	u16 rss_i = wx->ring_feature[RING_F_RSS].indices;
	u32 random_key_size = WX_RSS_KEY_SIZE / 4;
	u32 i, j;

	/* Fill out hash function seeds */
	for (i = 0; i < random_key_size; i++)
		wr32(wx, WX_RDB_RSSRK(i), wx->rss_key[i]);

	/* Fill out redirection table */
	memset(wx->rss_indir_tbl, 0, sizeof(wx->rss_indir_tbl));

	for (i = 0, j = 0; i < WX_MAX_RETA_ENTRIES; i++, j++) {
		if (j == rss_i)
			j = 0;

		wx->rss_indir_tbl[i] = j;
	}

	wx_store_reta(wx);
}

static void wx_setup_mrqc(struct wx *wx)
{
	u32 rss_field = 0;

	/* Disable indicating checksum in descriptor, enables RSS hash */
	wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_PCSD, WX_PSR_CTL_PCSD);

	/* Perform hash on these packet types */
	rss_field = WX_RDB_RA_CTL_RSS_IPV4 |
		    WX_RDB_RA_CTL_RSS_IPV4_TCP |
		    WX_RDB_RA_CTL_RSS_IPV4_UDP |
		    WX_RDB_RA_CTL_RSS_IPV6 |
		    WX_RDB_RA_CTL_RSS_IPV6_TCP |
		    WX_RDB_RA_CTL_RSS_IPV6_UDP;

	netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key));

	wx_setup_reta(wx);

	if (wx->rss_enabled)
		rss_field |= WX_RDB_RA_CTL_RSS_EN;

	wr32(wx, WX_RDB_RA_CTL, rss_field);
}

/**
 * wx_configure_rx - Configure Receive Unit after Reset
 * @wx: pointer to private structure
@@ -1629,6 +1695,8 @@ void wx_configure_rx(struct wx *wx)
		wr32(wx, WX_PSR_CTL, psrctl);
	}

	wx_setup_mrqc(wx);

	/* set_rx_buffer_len must be called before ring initialization */
	wx_set_rx_buffer_len(wx);

@@ -1826,6 +1894,28 @@ int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count)
}
EXPORT_SYMBOL(wx_get_pcie_msix_counts);

/**
 * wx_init_rss_key - Initialize wx RSS key
 * @wx: device handle
 *
 * Allocates and initializes the RSS key if it is not allocated.
 **/
static int wx_init_rss_key(struct wx *wx)
{
	u32 *rss_key;

	if (!wx->rss_key) {
		rss_key = kzalloc(WX_RSS_KEY_SIZE, GFP_KERNEL);
		if (unlikely(!rss_key))
			return -ENOMEM;

		netdev_rss_key_fill(rss_key, WX_RSS_KEY_SIZE);
		wx->rss_key = rss_key;
	}

	return 0;
}

int wx_sw_init(struct wx *wx)
{
	struct pci_dev *pdev = wx->pdev;
@@ -1853,14 +1943,23 @@ int wx_sw_init(struct wx *wx)
		wx->subsystem_device_id = swab16((u16)ssid);
	}

	err = wx_init_rss_key(wx);
	if (err < 0) {
		wx_err(wx, "rss key allocation failed\n");
		return err;
	}

	wx->mac_table = kcalloc(wx->mac.num_rar_entries,
				sizeof(struct wx_mac_addr),
				GFP_KERNEL);
	if (!wx->mac_table) {
		wx_err(wx, "mac_table allocation failed\n");
		kfree(wx->rss_key);
		return -ENOMEM;
	}

	wx->msix_in_use = false;

	return 0;
}
EXPORT_SYMBOL(wx_sw_init);
+59 −27
Original line number Diff line number Diff line
@@ -1568,8 +1568,14 @@ EXPORT_SYMBOL(wx_napi_disable_all);
 **/
static void wx_set_rss_queues(struct wx *wx)
{
	wx->num_rx_queues = wx->mac.max_rx_queues;
	wx->num_tx_queues = wx->mac.max_tx_queues;
	struct wx_ring_feature *f;

	/* set mask for 16 queue limit of RSS */
	f = &wx->ring_feature[RING_F_RSS];
	f->indices = f->limit;

	wx->num_rx_queues = f->limit;
	wx->num_tx_queues = f->limit;
}

static void wx_set_num_queues(struct wx *wx)
@@ -1595,35 +1601,51 @@ static int wx_acquire_msix_vectors(struct wx *wx)
	struct irq_affinity affd = { .pre_vectors = 1 };
	int nvecs, i;

	nvecs = min_t(int, num_online_cpus(), wx->mac.max_msix_vectors);
	/* We start by asking for one vector per queue pair */
	nvecs = max(wx->num_rx_queues, wx->num_tx_queues);
	nvecs = min_t(int, nvecs, num_online_cpus());
	nvecs = min_t(int, nvecs, wx->mac.max_msix_vectors);

	wx->msix_entries = kcalloc(nvecs,
				   sizeof(struct msix_entry),
	wx->msix_q_entries = kcalloc(nvecs, sizeof(struct msix_entry),
				     GFP_KERNEL);
	if (!wx->msix_entries)
	if (!wx->msix_q_entries)
		return -ENOMEM;

	/* One for non-queue interrupts */
	nvecs += 1;

	if (!wx->msix_in_use) {
		wx->msix_entry = kcalloc(1, sizeof(struct msix_entry),
					 GFP_KERNEL);
		if (!wx->msix_entry) {
			kfree(wx->msix_q_entries);
			wx->msix_q_entries = NULL;
			return -ENOMEM;
		}
	}

	nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs,
					       nvecs,
					       PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
					       &affd);
	if (nvecs < 0) {
		wx_err(wx, "Failed to allocate MSI-X interrupts. Err: %d\n", nvecs);
		kfree(wx->msix_entries);
		wx->msix_entries = NULL;
		kfree(wx->msix_q_entries);
		wx->msix_q_entries = NULL;
		kfree(wx->msix_entry);
		wx->msix_entry = NULL;
		return nvecs;
	}

	wx->msix_entry->entry = 0;
	wx->msix_entry->vector = pci_irq_vector(wx->pdev, 0);
	nvecs -= 1;
	for (i = 0; i < nvecs; i++) {
		wx->msix_entries[i].entry = i;
		wx->msix_entries[i].vector = pci_irq_vector(wx->pdev, i);
		wx->msix_q_entries[i].entry = i;
		wx->msix_q_entries[i].vector = pci_irq_vector(wx->pdev, i + 1);
	}

	/* one for msix_other */
	nvecs -= 1;
	wx->num_q_vectors = nvecs;
	wx->num_rx_queues = nvecs;
	wx->num_tx_queues = nvecs;

	return 0;
}
@@ -1645,9 +1667,11 @@ static int wx_set_interrupt_capability(struct wx *wx)
	if (ret == 0 || (ret == -ENOMEM))
		return ret;

	wx->num_rx_queues = 1;
	wx->num_tx_queues = 1;
	wx->num_q_vectors = 1;
	/* Disable RSS */
	dev_warn(&wx->pdev->dev, "Disabling RSS support\n");
	wx->ring_feature[RING_F_RSS].limit = 1;

	wx_set_num_queues(wx);

	/* minmum one for queue, one for misc*/
	nvecs = 1;
@@ -1905,8 +1929,12 @@ void wx_reset_interrupt_capability(struct wx *wx)
		return;

	if (pdev->msix_enabled) {
		kfree(wx->msix_entries);
		wx->msix_entries = NULL;
		kfree(wx->msix_q_entries);
		wx->msix_q_entries = NULL;
		if (!wx->msix_in_use) {
			kfree(wx->msix_entry);
			wx->msix_entry = NULL;
		}
	}
	pci_free_irq_vectors(wx->pdev);
}
@@ -1978,7 +2006,7 @@ void wx_free_irq(struct wx *wx)

	for (vector = 0; vector < wx->num_q_vectors; vector++) {
		struct wx_q_vector *q_vector = wx->q_vector[vector];
		struct msix_entry *entry = &wx->msix_entries[vector];
		struct msix_entry *entry = &wx->msix_q_entries[vector];

		/* free only the irqs that were actually requested */
		if (!q_vector->rx.ring && !q_vector->tx.ring)
@@ -1988,7 +2016,7 @@ void wx_free_irq(struct wx *wx)
	}

	if (wx->mac.type == wx_mac_em)
		free_irq(wx->msix_entries[vector].vector, wx);
		free_irq(wx->msix_entry->vector, wx);
}
EXPORT_SYMBOL(wx_free_irq);

@@ -2065,6 +2093,7 @@ static void wx_set_ivar(struct wx *wx, s8 direction,
		wr32(wx, WX_PX_MISC_IVAR, ivar);
	} else {
		/* tx or rx causes */
		msix_vector += 1; /* offset for queue vectors */
		msix_vector |= WX_PX_IVAR_ALLOC_VAL;
		index = ((16 * (queue & 1)) + (8 * direction));
		ivar = rd32(wx, WX_PX_IVAR(queue >> 1));
@@ -2095,7 +2124,7 @@ void wx_write_eitr(struct wx_q_vector *q_vector)

	itr_reg |= WX_PX_ITR_CNT_WDIS;

	wr32(wx, WX_PX_ITR(v_idx), itr_reg);
	wr32(wx, WX_PX_ITR(v_idx + 1), itr_reg);
}

/**
@@ -2141,9 +2170,9 @@ void wx_configure_vectors(struct wx *wx)
		wx_write_eitr(q_vector);
	}

	wx_set_ivar(wx, -1, 0, v_idx);
	wx_set_ivar(wx, -1, 0, 0);
	if (pdev->msix_enabled)
		wr32(wx, WX_PX_ITR(v_idx), 1950);
		wr32(wx, WX_PX_ITR(0), 1950);
}
EXPORT_SYMBOL(wx_configure_vectors);

@@ -2656,11 +2685,14 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
	netdev_features_t changed = netdev->features ^ features;
	struct wx *wx = netdev_priv(netdev);

	if (changed & NETIF_F_RXHASH)
	if (features & NETIF_F_RXHASH) {
		wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN,
		      WX_RDB_RA_CTL_RSS_EN);
	else
		wx->rss_enabled = true;
	} else {
		wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0);
		wx->rss_enabled = false;
	}

	if (changed &
	    (NETIF_F_HW_VLAN_CTAG_RX |
+28 −3
Original line number Diff line number Diff line
@@ -147,8 +147,16 @@
#define WX_RDB_PL_CFG_L2HDR          BIT(3)
#define WX_RDB_PL_CFG_TUN_TUNHDR     BIT(4)
#define WX_RDB_PL_CFG_TUN_OUTL2HDR   BIT(5)
#define WX_RDB_RSSTBL(_i)            (0x19400 + ((_i) * 4))
#define WX_RDB_RSSRK(_i)             (0x19480 + ((_i) * 4))
#define WX_RDB_RA_CTL                0x194F4
#define WX_RDB_RA_CTL_RSS_EN         BIT(2) /* RSS Enable */
#define WX_RDB_RA_CTL_RSS_IPV4_TCP   BIT(16)
#define WX_RDB_RA_CTL_RSS_IPV4       BIT(17)
#define WX_RDB_RA_CTL_RSS_IPV6       BIT(20)
#define WX_RDB_RA_CTL_RSS_IPV6_TCP   BIT(21)
#define WX_RDB_RA_CTL_RSS_IPV4_UDP   BIT(22)
#define WX_RDB_RA_CTL_RSS_IPV6_UDP   BIT(23)

/******************************* PSR Registers *******************************/
/* psr control */
@@ -921,6 +929,19 @@ struct wx_q_vector {
	struct wx_ring ring[] ____cacheline_internodealigned_in_smp;
};

struct wx_ring_feature {
	u16 limit;      /* upper limit on feature indices */
	u16 indices;    /* current value of indices */
	u16 mask;       /* Mask used for feature to ring mapping */
	u16 offset;     /* offset to start of feature */
};

enum wx_ring_f_enum {
	RING_F_NONE = 0,
	RING_F_RSS,
	RING_F_ARRAY_SIZE  /* must be last in enum set */
};

enum wx_isb_idx {
	WX_ISB_HEADER,
	WX_ISB_MISC,
@@ -1024,7 +1045,10 @@ struct wx {
	struct wx_q_vector *q_vector[64];

	unsigned int queues_per_pool;
	struct msix_entry *msix_entries;
	struct msix_entry *msix_q_entries;
	struct msix_entry *msix_entry;
	bool msix_in_use;
	struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE];

	/* misc interrupt status block */
	dma_addr_t isb_dma;
@@ -1032,8 +1056,9 @@ struct wx {
	u32 isb_tag[WX_ISB_MAX];

#define WX_MAX_RETA_ENTRIES 128
#define WX_RSS_INDIR_TBL_MAX 64
	u8 rss_indir_tbl[WX_MAX_RETA_ENTRIES];

	bool rss_enabled;
#define WX_RSS_KEY_SIZE     40  /* size of RSS Hash Key in bytes */
	u32 *rss_key;
	u32 wol;
@@ -1050,7 +1075,7 @@ struct wx {
};

#define WX_INTR_ALL (~0ULL)
#define WX_INTR_Q(i) BIT(i)
#define WX_INTR_Q(i) BIT((i) + 1)

/* register operations */
#define wr32(a, reg, value)	writel((value), ((a)->hw_addr + (reg)))
Loading