diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 4d7b2ca3404e97..e4cb321e1b7f85 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1154,8 +1154,6 @@ void rswitch_enadis_rdev_irqs(struct rswitch_device *rdev, bool enable) if (rdev->rx_learning_chain) rswitch_enadis_data_irq(rdev->priv, rdev->rx_learning_chain->index, enable); - rswitch_enadis_data_irq(rdev->priv, rdev->tx_chain->index, - enable); } else { if (enable) rswitch_vmq_front_rx_done(rdev); @@ -1207,6 +1205,7 @@ static bool rswitch_rx_chain(struct net_device *ndev, int *quota, struct rswitch struct rswitch_device *rdev = ndev_to_rdev(ndev); struct rswitch_private *priv = rdev->priv; int boguscnt = c->dirty + c->num_ring - c->cur; + int rx_counter = 0; int entry = c->cur % c->num_ring; struct rswitch_ext_ts_desc *desc = &c->rx_ring[entry]; int limit; @@ -1214,6 +1213,7 @@ static bool rswitch_rx_chain(struct net_device *ndev, int *quota, struct rswitch struct sk_buff *skb; dma_addr_t dma_addr; u32 get_ts; + u64 rxed = 0; boguscnt = min(boguscnt, *quota); limit = boguscnt; @@ -1348,6 +1348,8 @@ static bool rswitch_rx_chain(struct net_device *ndev, int *quota, struct rswitch napi_gro_receive(&rdev->napi, skb); rdev->ndev->stats.rx_packets++; rdev->ndev->stats.rx_bytes += pkt_len; + if (rdev->is_vmq) + rx_counter++; next: c->rx_bufs[entry] = NULL; @@ -1380,6 +1382,19 @@ static bool rswitch_rx_chain(struct net_device *ndev, int *quota, struct rswitch desc->die_dt = DT_FEMPTY | DIE; } + if (rdev->is_vmq) { + if (rswitch_is_front_dev(rdev)) { + rxed = READ_ONCE(rdev->vmq_info->front_rx); + rxed += rx_counter; + WRITE_ONCE(rdev->vmq_info->front_rx, rxed); + } else { + rxed = READ_ONCE(rdev->vmq_info->back_rx); + rxed += rx_counter; + WRITE_ONCE(rdev->vmq_info->back_rx, rxed); + } + } + + *quota -= limit - (++boguscnt); return boguscnt <= 0; @@ -1439,6 +1454,31 @@ int rswitch_tx_free(struct net_device *ndev, bool free_txed_only) return free_num; } +int rswitch_tx_poll(struct napi_struct *napi, int budget) +{ + struct net_device *ndev = napi->dev; + struct rswitch_device *rdev = ndev_to_rdev(ndev); + struct rswitch_private *priv = rdev->priv; + int num; + unsigned long flags; + + num = rswitch_tx_free(ndev, true); + /* We have free descriptors to process new TX packages */ + if (budget && napi_complete_done(napi, num)) { + if (!rswitch_is_front_dev(rdev)) { + spin_lock_irqsave(&priv->lock, flags); + rswitch_enadis_data_irq(rdev->priv, rdev->tx_chain->index, + true); + spin_unlock_irqrestore(&priv->lock, flags); + } else { + rswitch_vmq_front_trigger_tx(rdev); + } + } + netif_wake_subqueue(ndev, 0); + + return min(num, budget - 1); +} + int rswitch_poll(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; @@ -1448,7 +1488,6 @@ int rswitch_poll(struct napi_struct *napi, int budget) int quota = budget; retry: - rswitch_tx_free(ndev, true); if (rswitch_rx(ndev, "a)) goto out; @@ -1457,8 +1496,6 @@ int rswitch_poll(struct napi_struct *napi, int budget) else if (rdev->rx_learning_chain && rswitch_is_chain_rxed(rdev->rx_learning_chain, DT_FEMPTY)) goto retry; - netif_wake_subqueue(ndev, 0); - if (napi_complete_done(napi, budget - quota)) { spin_lock_irqsave(&priv->lock, flags); /* Re-enable RX/TX interrupts */ @@ -2232,6 +2269,7 @@ static int rswitch_open(struct net_device *ndev) unsigned long flags; napi_enable(&rdev->napi); + napi_enable(&rdev->tx_napi); if (!parallel_mode && rdev->etha) { if (!rdev->etha->operated) { @@ -2311,6 +2349,7 @@ static int rswitch_open(struct net_device *ndev) phy_stop(ndev->phydev); rswitch_phy_deinit(rdev); rswitch_mii_unregister(rdev); + napi_disable(&rdev->tx_napi); napi_disable(&rdev->napi); goto out; }; @@ -2324,6 +2363,7 @@ static int rswitch_stop(struct net_device *ndev) phy_stop(ndev->phydev); napi_disable(&rdev->napi); + napi_disable(&rdev->tx_napi); if (!rswitch_is_front_dev(rdev)) { rdev->priv->chan_running &= ~BIT(rdev->port); @@ -2412,16 +2452,35 @@ static int rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev) unsigned long flags; struct rswitch_gwca_chain *c = rdev->tx_chain; int i, num_desc, pkt_len, size; + int rx_chain_free = RX_RING_SIZE; + u64 txed; spin_lock_irqsave(&rdev->lock, flags); num_desc = skb->len % MAX_DESC_SZ ? skb->len / MAX_DESC_SZ + 1 : skb->len / MAX_DESC_SZ; + if (rdev->is_vmq) { + if (rswitch_is_front_dev(rdev)) { + rx_chain_free = RX_RING_SIZE - + (READ_ONCE(rdev->vmq_info->front_tx) - + READ_ONCE(rdev->vmq_info->back_rx)); + } else { + rx_chain_free = RX_RING_SIZE - + (READ_ONCE(rdev->vmq_info->back_tx) - + READ_ONCE(rdev->vmq_info->front_rx)); + } + } if (c->cur - c->dirty > c->num_ring - num_desc) { netif_stop_subqueue(ndev, 0); ret = NETDEV_TX_BUSY; goto out; } + + if (num_desc > rx_chain_free) { + curr_time = ktime_get(); + ret = NETDEV_TX_BUSY; + goto out; + } if (skb_put_padto(skb, ETH_ZLEN)) goto out; @@ -2506,6 +2565,18 @@ static int rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev) desc->die_dt = DT_FSINGLE | DIE; } + if (rdev->is_vmq) { + if (rswitch_is_front_dev(rdev)) { + txed = READ_ONCE(rdev->vmq_info->front_tx); + txed += num_desc; + WRITE_ONCE(rdev->vmq_info->front_tx, txed); + } else { + txed = READ_ONCE(rdev->vmq_info->back_tx); + txed += num_desc; + WRITE_ONCE(rdev->vmq_info->back_tx, txed); + } + } + c->cur += num_desc; rswitch_trigger_chain(rdev->priv, c); @@ -4045,7 +4116,7 @@ int rswitch_rxdmac_init(struct net_device *ndev, struct rswitch_private *priv, rdev->rx_default_chain = rswitch_gwca_get(priv); if (!rdev->rx_default_chain) return -EBUSY; - if (!parallel_mode) { + if (!parallel_mode && !rdev->is_vmq) { rdev->rx_learning_chain = rswitch_gwca_get(priv); if (!rdev->rx_learning_chain) goto put_default; @@ -4064,26 +4135,36 @@ int rswitch_rxdmac_init(struct net_device *ndev, struct rswitch_private *priv, RX_RING_SIZE); if (err < 0) goto put_learning; - err = rswitch_gwca_chain_init(ndev, priv, rdev->rx_learning_chain, false, - RX_RING_SIZE); - if (err < 0) - goto free_default; + + if (!rdev->is_vmq) { + err = rswitch_gwca_chain_init(ndev, priv, rdev->rx_learning_chain, false, + RX_RING_SIZE); + if (err < 0) + goto free_default; + } err = rswitch_gwca_chain_ext_ts_format(ndev, priv, rdev->rx_default_chain); if (err < 0) goto free_learning; - err = rswitch_gwca_chain_ext_ts_format(ndev, priv, rdev->rx_learning_chain); - if (err < 0) - goto free_learning; + + if (!rdev->is_vmq) { + err = rswitch_gwca_chain_ext_ts_format(ndev, priv, rdev->rx_learning_chain); + if (err < 0) + goto free_learning; + } else { + rdev->rx_learning_chain = NULL; + } return 0; free_learning: - rswitch_gwca_chain_free(ndev, priv, rdev->rx_learning_chain); + if (!rdev->is_vmq) + rswitch_gwca_chain_free(ndev, priv, rdev->rx_learning_chain); free_default: rswitch_gwca_chain_free(ndev, priv, rdev->rx_default_chain); put_learning: - rswitch_gwca_put(priv, rdev->rx_learning_chain); + if (!rdev->is_vmq) + rswitch_gwca_put(priv, rdev->rx_learning_chain); put_default: rswitch_gwca_put(priv, rdev->rx_default_chain); @@ -4190,6 +4271,7 @@ static int rswitch_ndev_create(struct rswitch_private *priv, int index, bool rmo ndev->netdev_ops = &rswitch_netdev_ops; netif_napi_add(ndev, &rdev->napi, rswitch_poll, 64); + netif_tx_napi_add(ndev, &rdev->tx_napi, rswitch_tx_poll, 64); /* FIXME: it seems S4 VPF has FWPBFCSDC0/1 only so that we cannot set * CSD = 1 (rx_default_chain->index = 1) for FWPBFCS03. So, use index = 0 @@ -4227,6 +4309,8 @@ static int rswitch_ndev_create(struct rswitch_private *priv, int index, bool rmo } } + rdev->is_vmq = false; + /* Print device information */ netdev_info(ndev, "MAC address %pMn", ndev->dev_addr); @@ -4236,6 +4320,7 @@ static int rswitch_ndev_create(struct rswitch_private *priv, int index, bool rmo rswitch_rxdmac_free(ndev, priv); out_rxdmac: + netif_napi_del(&rdev->tx_napi); netif_napi_del(&rdev->napi); free_netdev(ndev); @@ -4277,12 +4362,39 @@ static void rswitch_coma_init(struct rswitch_private *priv) iowrite32(CABPPFLC_INIT_VALUE, priv->addr + CABPPFLC0); } -static void rswitch_queue_interrupt(struct rswitch_device *rdev) +static void rswitch_queue_rmon_interrupt(struct rswitch_gwca_chain *c) { - if (!rdev->mondev) { - if (napi_schedule_prep(&rdev->napi)) { + struct rswitch_device *rdev = c->rdev; + struct rswitch_private *priv = rdev->priv; + int i; + + /* Schedule napi for all rmon devices as they share the same chain. */ + for (i = 0; i < RSWITCH_MAX_RMON_DEV; i++) { + if (priv->rmon_dev[i] && napi_schedule_prep(&priv->rmon_dev[i]->napi)) { + spin_lock(&rdev->priv->lock); + rswitch_enadis_data_irq(priv->rmon_dev[i]->priv, + priv->rmon_dev[i]->rx_default_chain->index, + false); + spin_unlock(&rdev->priv->lock); + __napi_schedule(&priv->rmon_dev[i]->napi); + } + } +} + +static void rswitch_queue_rdev_interrupt(struct rswitch_gwca_chain *c) +{ + struct rswitch_device *rdev = c->rdev; + + if (c->dir_tx) { + if (napi_schedule_prep(&rdev->tx_napi)) { spin_lock(&rdev->priv->lock); rswitch_enadis_data_irq(rdev->priv, rdev->tx_chain->index, false); + spin_unlock(&rdev->priv->lock); + __napi_schedule(&rdev->tx_napi); + } + } else { + if (napi_schedule_prep(&rdev->napi)) { + spin_lock(&rdev->priv->lock); rswitch_enadis_data_irq(rdev->priv, rdev->rx_default_chain->index, false); if (rdev->rx_learning_chain) { rswitch_enadis_data_irq(rdev->priv, @@ -4291,23 +4403,18 @@ static void rswitch_queue_interrupt(struct rswitch_device *rdev) spin_unlock(&rdev->priv->lock); __napi_schedule(&rdev->napi); } - } else { - struct rswitch_private *priv = rdev->priv; - int i; + } + +} - /* Schedule napi for all rmon devices as - * they share the same chain. - */ - for (i = 0; i < RSWITCH_MAX_RMON_DEV; i++) { - if (priv->rmon_dev[i] && napi_schedule_prep(&priv->rmon_dev[i]->napi)) { - spin_lock(&rdev->priv->lock); - rswitch_enadis_data_irq(priv->rmon_dev[i]->priv, - priv->rmon_dev[i]->rx_default_chain->index, - false); - spin_unlock(&rdev->priv->lock); - __napi_schedule(&priv->rmon_dev[i]->napi); - } - } +static void rswitch_queue_interrupt(struct rswitch_gwca_chain *c) +{ + struct rswitch_device *rdev = c->rdev; + + if (!rdev->mondev) { + rswitch_queue_rdev_interrupt(c); + } else { + rswitch_queue_rmon_interrupt(c); } } @@ -4326,7 +4433,7 @@ static irqreturn_t __maybe_unused rswitch_data_irq(struct rswitch_private *priv, rswitch_ack_data_irq(priv, c->index); if (!c->back_info) - rswitch_queue_interrupt(c->rdev); + rswitch_queue_interrupt(c); else rswitch_vmq_back_data_irq(c); } @@ -4977,8 +5084,11 @@ static int vlan_dev_register(struct net_device *ndev) goto err_rx; netif_napi_add(ndev, &rdev->napi, rswitch_poll, 64); + netif_tx_napi_add(ndev, &rdev->tx_napi, rswitch_tx_poll, 64); netdev_info(ndev, "MAC address %pMn", ndev->dev_addr); + rdev->is_vmq = false; napi_enable(&rdev->napi); + napi_enable(&rdev->tx_napi); return 0; err_rx: rswitch_txdmac_free(ndev, priv); @@ -5037,6 +5147,8 @@ static void vlan_dev_unregister(struct net_device *ndev) rdev = ndev_to_rdev(ndev); rswitch_rxdmac_free(ndev, priv); rswitch_txdmac_free(ndev, priv); + napi_disable(&rdev->tx_napi); + netif_napi_del(&rdev->tx_napi); napi_disable(&rdev->napi); netif_napi_del(&rdev->napi); diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index b54e2e14e253c1..1d556a30ec2ab8 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -209,8 +209,8 @@ struct rswitch_gwca_chain { #define RSWITCH_MAX_NUM_NDEV 8 #define RSWITCH_MAX_NUM_L23 256 -#define TX_RING_SIZE 1024 -#define RX_RING_SIZE 1024 +#define TX_RING_SIZE 10240 +#define RX_RING_SIZE 10240 #define RSWITCH_ALIGN 128 #define RSWITCH_MAX_CTAG_PCP 7 @@ -275,11 +275,18 @@ struct rswitch_filters { DECLARE_BITMAP(cascade, PFL_CADF_N); }; +struct rswitch_vmq_status { + uint64_t front_tx, front_rx; + uint64_t back_tx, back_rx; + uint64_t tx_ring_size, rx_ring_size; +}; + struct rswitch_device { struct list_head list; struct rswitch_private *priv; struct net_device *ndev; struct napi_struct napi; + struct napi_struct tx_napi; void __iomem *addr; struct rswitch_gwca_chain *tx_chain; struct rswitch_gwca_chain *rx_default_chain; @@ -307,6 +314,8 @@ struct rswitch_device { */ struct device *vlan_parent; bool mondev; + struct rswitch_vmq_status *vmq_info; + bool is_vmq; }; struct rswitch_private { @@ -448,6 +457,7 @@ void rswitch_rxdmac_free(struct net_device *ndev, struct rswitch_private *priv); void rswitch_ndev_unregister(struct rswitch_device *rdev, int index); int rswitch_poll(struct napi_struct *napi, int budget); +int rswitch_tx_poll(struct napi_struct *napi, int budget); int rswitch_tx_free(struct net_device *ndev, bool free_txed_only); void rswitch_gwca_chain_register(struct rswitch_private *priv, diff --git a/drivers/net/ethernet/renesas/rswitch_xenback.c b/drivers/net/ethernet/renesas/rswitch_xenback.c index d1b95afd9061fb..0890e111ac8f87 100644 --- a/drivers/net/ethernet/renesas/rswitch_xenback.c +++ b/drivers/net/ethernet/renesas/rswitch_xenback.c @@ -82,6 +82,9 @@ rswitch_vmq_back_ndev_register(struct rswitch_private *priv, int index) spin_lock_init(&rdev->lock); INIT_LIST_HEAD(&rdev->routing_list); +#if IS_ENABLED(CONFIG_IP_MROUTE) + INIT_LIST_HEAD(&rdev->mult_routing_list); +#endif ndev->features = NETIF_F_RXCSUM; ndev->hw_features = NETIF_F_RXCSUM; @@ -90,6 +93,7 @@ rswitch_vmq_back_ndev_register(struct rswitch_private *priv, int index) ndev->netdev_ops = &rswitch_netdev_ops; netif_napi_add(ndev, &rdev->napi, rswitch_poll, 64); + netif_tx_napi_add(ndev, &rdev->tx_napi, rswitch_tx_poll, 64); eth_hw_addr_random(ndev); @@ -102,6 +106,8 @@ rswitch_vmq_back_ndev_register(struct rswitch_private *priv, int index) if (err < 0) goto out_txdmac; + rdev->is_vmq = true; + /* Print device information */ netdev_info(ndev, "MAC address %pMn", ndev->dev_addr); @@ -111,6 +117,7 @@ rswitch_vmq_back_ndev_register(struct rswitch_private *priv, int index) rswitch_rxdmac_free(ndev, priv); out_rxdmac: + netif_napi_del(&rdev->tx_napi); netif_napi_del(&rdev->napi); free_netdev(ndev); @@ -212,9 +219,6 @@ static int rswitch_vmq_back_probe(struct xenbus_device *dev, be->tx_chain->osid = be->osid; be->rx_chain->osid = be->osid; - rswitch_gwca_chain_set_irq_delay(priv, be->tx_chain, chain_irq_delay); - rswitch_gwca_chain_set_irq_delay(priv, be->rx_chain, chain_irq_delay); - snprintf(be->name, sizeof(be->name) - 1, "rswitch-vmq-osid%d", be->osid); be->if_num = xenbus_read_unsigned(dev->otherend, "if-num", 255); @@ -232,6 +236,8 @@ static int rswitch_vmq_back_probe(struct xenbus_device *dev, err); goto fail; } + rswitch_gwca_chain_set_irq_delay(priv, be->tx_chain, chain_irq_delay); + rswitch_gwca_chain_set_irq_delay(priv, be->rx_chain, chain_irq_delay); } else if (strcmp(type_str, "tsn") == 0) { struct rswitch_device *rdev = rswitch_find_rdev_by_port(be->rswitch_priv, @@ -249,6 +255,8 @@ static int rswitch_vmq_back_probe(struct xenbus_device *dev, err = -ENODEV; goto fail; } + rswitch_gwca_chain_set_irq_delay(priv, be->tx_chain, 0); + rswitch_gwca_chain_set_irq_delay(priv, be->rx_chain, 0); be->type = RSWITCH_PV_TSN; netif_dormant_on(rdev->ndev); @@ -371,11 +379,15 @@ static int rswitch_vmq_back_connect(struct xenbus_device *dev) struct rswitch_vmq_back_info *be = dev_get_drvdata(&dev->dev); unsigned int tx_evt; unsigned int rx_evt; + unsigned int gref; int err; + struct gnttab_map_grant_ref map; + struct page *page; err = xenbus_gather(XBT_NIL, dev->otherend, "tx-evtch", "%u", &tx_evt, "rx-evtch", "%u", &rx_evt, + "gref", "%u", &gref, NULL); if (err) { xenbus_dev_fatal(dev, err, "Failed to read front-end info: %d", err); @@ -424,6 +436,22 @@ static int rswitch_vmq_back_connect(struct xenbus_device *dev) break; } + + err = gnttab_alloc_pages(1, &page); + if (err) { + pr_err("Failed to allocate GNT page %d\n", err); + return err; + } + + gnttab_set_map_op(&map, (uintptr_t)pfn_to_kaddr(page_to_xen_pfn((page))), + GNTMAP_host_map, gref, dev->otherend_id); + err = gnttab_map_refs(&map, NULL, &page, 1); + if (err) { + pr_err("Failed to map grant refs %d\n", err); + } else { + be->rdev->vmq_info = (struct rswitch_vmq_status *)page_address(page); + } + return err; } diff --git a/drivers/net/ethernet/renesas/rswitch_xenfront.c b/drivers/net/ethernet/renesas/rswitch_xenfront.c index 52021a176471f8..da8519506dcd44 100644 --- a/drivers/net/ethernet/renesas/rswitch_xenfront.c +++ b/drivers/net/ethernet/renesas/rswitch_xenfront.c @@ -117,6 +117,7 @@ static int rswitch_vmq_front_ndev_register(struct rswitch_device *rdev, rdev->port = rdev->priv->gwca.index; netif_napi_add(ndev, &rdev->napi, rswitch_poll, 64); + netif_tx_napi_add(ndev, &rdev->tx_napi, rswitch_tx_poll, 64); if (!mac) eth_hw_addr_random(ndev); @@ -138,6 +139,7 @@ static int rswitch_vmq_front_ndev_register(struct rswitch_device *rdev, /* Print device information */ netdev_info(ndev, "MAC address %pMn", ndev->dev_addr); + rdev->is_vmq = true; return 0; @@ -148,6 +150,7 @@ static int rswitch_vmq_front_ndev_register(struct rswitch_device *rdev, rswitch_rxdmac_free(ndev, NULL); out_rxdmac: + netif_napi_del(&rdev->tx_napi); netif_napi_del(&rdev->napi); return err; @@ -166,7 +169,7 @@ static irqreturn_t rswitch_vmq_front_tx_interrupt(int irq, void *dev_id) { struct rswitch_device *rdev = dev_id; - napi_schedule(&rdev->napi); + napi_schedule(&rdev->tx_napi); /* TODO: This is better, but there is a possibility for locking issues */ /* rswitch_tx_free(rdev->ndev, true); */ @@ -198,6 +201,7 @@ static int rswitch_vmq_front_connect(struct net_device *dev) char *type; char *mac_str; u8 mac[ETH_ALEN]; + int ret, gref; tx_chain_id = xenbus_read_unsigned(np->xbdev->otherend, "tx-chain-id", 0); @@ -236,8 +240,25 @@ static int rswitch_vmq_front_connect(struct net_device *dev) err = rswitch_vmq_front_ndev_register(rdev, type, index, tx_chain_id, rx_chain_id, mac_str ? mac : NULL); + + rdev->vmq_info = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + /* TODO: correct process error */ + if (!rdev->vmq_info) { + pr_err("rdev->rswitch_vmq_status ERROR\n"); + return -1; + } + + gref = gnttab_grant_foreign_access(np->xbdev->otherend_id, + virt_to_gfn(rdev->vmq_info), 0); kfree(type); + WRITE_ONCE(rdev->vmq_info->front_tx, 0); + WRITE_ONCE(rdev->vmq_info->front_rx, 0); + WRITE_ONCE(rdev->vmq_info->back_tx, 0); + WRITE_ONCE(rdev->vmq_info->back_rx, 0); + WRITE_ONCE(rdev->vmq_info->tx_ring_size, RX_RING_SIZE); + WRITE_ONCE(rdev->vmq_info->rx_ring_size, TX_RING_SIZE); + if (mac_str) kfree(mac_str); @@ -295,6 +316,14 @@ static int rswitch_vmq_front_connect(struct net_device *dev) return err; } + ret = xenbus_printf(XBT_NIL, np->xbdev->nodename, "gref", + "%u", gref); + if (err) { + xenbus_dev_fatal(np->xbdev, err, + "Failed to write TX event channel id: %d\n", err); + return err; + } + return 0; }