Skip to content

Commit

Permalink
net: wangxun: add ethtool_ops for channel number
Browse files Browse the repository at this point in the history
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: Jiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiawen Wu authored and David S. Miller committed Jan 4, 2024
1 parent 4ac2d9d commit 937d46e
Show file tree
Hide file tree
Showing 12 changed files with 380 additions and 68 deletions.
57 changes: 57 additions & 0 deletions drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,60 @@ int wx_set_coalesce(struct net_device *netdev,
return 0;
}
EXPORT_SYMBOL(wx_set_coalesce);

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 changes: 4 additions & 0 deletions drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ int wx_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack);
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_ */
103 changes: 101 additions & 2 deletions drivers/net/ethernet/wangxun/libwx/wx_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
86 changes: 59 additions & 27 deletions drivers/net/ethernet/wangxun/libwx/wx_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -1595,35 +1601,51 @@ static int wx_acquire_msix_vectors(struct wx *wx)
struct irq_affinity affd = {0, };
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),
GFP_KERNEL);
if (!wx->msix_entries)
wx->msix_q_entries = kcalloc(nvecs, sizeof(struct msix_entry),
GFP_KERNEL);
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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
Expand All @@ -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);

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 |
Expand Down
Loading

0 comments on commit 937d46e

Please sign in to comment.