-
Notifications
You must be signed in to change notification settings - Fork 0
Rswitch refactoring #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v5.10.41/rcar-5.1.7.rc11.2-xt
Are you sure you want to change the base?
Changes from all commits
930a38f
90891a1
108ef12
934c2b1
ac6bbac
bade029
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,13 +1205,15 @@ 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; | ||
| u16 pkt_len; | ||
| 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; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems it is correct to call Question is - when we should call On other hand, we really interested in interrupt from other side (e.g. from backend). Can you try the following: send TX done event to DomU every time DomD exits its |
||
| 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, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, this should be a separate case (learning chain). In this implementation IRQs for learning chain will disable IRQs for default chain. |
||
|
|
@@ -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); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if should pass actual number of packets in this function. NAPI documentation says that TX operations can ignore budget.