Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 147 additions & 35 deletions drivers/net/ethernet/renesas/rswitch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Copy link
Copy Markdown

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.

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;
Expand All @@ -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, &quota))
goto out;
Expand All @@ -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 */
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
};
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems it is correct to call netif_stop_queue/netif_stop_subqueue here to stop upper layers of network stack to bother us.

Question is - when we should call netif_start_subqueue? It would be really nice to call it when, say, 1/2 or 3/4 of TX chain is free. IIRC, GWCA sends TX interrupt when chain is completely empty, which is late a bit. I wonder - is it possible to flag TX descriptor with some attribute to force GWCA trigger an interrupt when it processed it? In this way we can flag every 64th (or 128th or something like that) TX descriptor and get steady stream of TX interrupts...

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 rx_poll function?

goto out;
}

if (skb_put_padto(skb, ETH_ZLEN))
goto out;
Expand Down Expand Up @@ -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);

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

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

Expand All @@ -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);

Expand Down Expand Up @@ -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,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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.

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

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

Expand Down
Loading