提交 12bb03b4 编写于 作者: M Maxime Ripard 提交者: David S. Miller

net: mvneta: Handle per-cpu interrupts

Now that our interrupt controller is allowing us to use per-CPU interrupts,
actually use it in the mvneta driver.

This involves obviously reworking the driver to have a CPU-local NAPI
structure, and report for incoming packet using that structure.
Signed-off-by: NMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: NGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 2502d0ef
...@@ -285,7 +285,21 @@ struct mvneta_pcpu_stats { ...@@ -285,7 +285,21 @@ struct mvneta_pcpu_stats {
u64 tx_bytes; u64 tx_bytes;
}; };
struct mvneta_pcpu_port {
/* Pointer to the shared port */
struct mvneta_port *pp;
/* Pointer to the CPU-local NAPI struct */
struct napi_struct napi;
/* Cause of the previous interrupt */
u32 cause_rx_tx;
};
struct mvneta_port { struct mvneta_port {
struct mvneta_pcpu_port __percpu *ports;
struct mvneta_pcpu_stats __percpu *stats;
int pkt_size; int pkt_size;
unsigned int frag_size; unsigned int frag_size;
void __iomem *base; void __iomem *base;
...@@ -293,15 +307,11 @@ struct mvneta_port { ...@@ -293,15 +307,11 @@ struct mvneta_port {
struct mvneta_tx_queue *txqs; struct mvneta_tx_queue *txqs;
struct net_device *dev; struct net_device *dev;
u32 cause_rx_tx;
struct napi_struct napi;
/* Core clock */ /* Core clock */
struct clk *clk; struct clk *clk;
u8 mcast_count[256]; u8 mcast_count[256];
u16 tx_ring_size; u16 tx_ring_size;
u16 rx_ring_size; u16 rx_ring_size;
struct mvneta_pcpu_stats *stats;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
struct phy_device *phy_dev; struct phy_device *phy_dev;
...@@ -1461,6 +1471,7 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, ...@@ -1461,6 +1471,7 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
static int mvneta_rx(struct mvneta_port *pp, int rx_todo, static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
struct mvneta_rx_queue *rxq) struct mvneta_rx_queue *rxq)
{ {
struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
struct net_device *dev = pp->dev; struct net_device *dev = pp->dev;
int rx_done; int rx_done;
u32 rcvd_pkts = 0; u32 rcvd_pkts = 0;
...@@ -1515,7 +1526,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, ...@@ -1515,7 +1526,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
mvneta_rx_csum(pp, rx_status, skb); mvneta_rx_csum(pp, rx_status, skb);
napi_gro_receive(&pp->napi, skb); napi_gro_receive(&port->napi, skb);
rcvd_pkts++; rcvd_pkts++;
rcvd_bytes += rx_bytes; rcvd_bytes += rx_bytes;
...@@ -1550,7 +1561,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, ...@@ -1550,7 +1561,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
mvneta_rx_csum(pp, rx_status, skb); mvneta_rx_csum(pp, rx_status, skb);
napi_gro_receive(&pp->napi, skb); napi_gro_receive(&port->napi, skb);
} }
if (rcvd_pkts) { if (rcvd_pkts) {
...@@ -2061,12 +2072,11 @@ static void mvneta_set_rx_mode(struct net_device *dev) ...@@ -2061,12 +2072,11 @@ static void mvneta_set_rx_mode(struct net_device *dev)
/* Interrupt handling - the callback for request_irq() */ /* Interrupt handling - the callback for request_irq() */
static irqreturn_t mvneta_isr(int irq, void *dev_id) static irqreturn_t mvneta_isr(int irq, void *dev_id)
{ {
struct mvneta_port *pp = (struct mvneta_port *)dev_id; struct mvneta_pcpu_port *port = (struct mvneta_pcpu_port *)dev_id;
/* Mask all interrupts */ disable_percpu_irq(port->pp->dev->irq);
mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
napi_schedule(&pp->napi); napi_schedule(&port->napi);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2104,11 +2114,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget) ...@@ -2104,11 +2114,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
{ {
int rx_done = 0; int rx_done = 0;
u32 cause_rx_tx; u32 cause_rx_tx;
unsigned long flags;
struct mvneta_port *pp = netdev_priv(napi->dev); struct mvneta_port *pp = netdev_priv(napi->dev);
struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
if (!netif_running(pp->dev)) { if (!netif_running(pp->dev)) {
napi_complete(napi); napi_complete(&port->napi);
return rx_done; return rx_done;
} }
...@@ -2135,7 +2145,7 @@ static int mvneta_poll(struct napi_struct *napi, int budget) ...@@ -2135,7 +2145,7 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
/* For the case where the last mvneta_poll did not process all /* For the case where the last mvneta_poll did not process all
* RX packets * RX packets
*/ */
cause_rx_tx |= pp->cause_rx_tx; cause_rx_tx |= port->cause_rx_tx;
if (rxq_number > 1) { if (rxq_number > 1) {
while ((cause_rx_tx & MVNETA_RX_INTR_MASK_ALL) && (budget > 0)) { while ((cause_rx_tx & MVNETA_RX_INTR_MASK_ALL) && (budget > 0)) {
int count; int count;
...@@ -2166,16 +2176,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget) ...@@ -2166,16 +2176,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
if (budget > 0) { if (budget > 0) {
cause_rx_tx = 0; cause_rx_tx = 0;
napi_complete(napi); napi_complete(&port->napi);
local_irq_save(flags); enable_percpu_irq(pp->dev->irq, 0);
mvreg_write(pp, MVNETA_INTR_NEW_MASK,
MVNETA_RX_INTR_MASK(rxq_number) |
MVNETA_TX_INTR_MASK(txq_number) |
MVNETA_MISCINTR_INTR_MASK);
local_irq_restore(flags);
} }
pp->cause_rx_tx = cause_rx_tx; port->cause_rx_tx = cause_rx_tx;
return rx_done; return rx_done;
} }
...@@ -2424,6 +2429,8 @@ static int mvneta_setup_txqs(struct mvneta_port *pp) ...@@ -2424,6 +2429,8 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)
static void mvneta_start_dev(struct mvneta_port *pp) static void mvneta_start_dev(struct mvneta_port *pp)
{ {
unsigned int cpu;
mvneta_max_rx_size_set(pp, pp->pkt_size); mvneta_max_rx_size_set(pp, pp->pkt_size);
mvneta_txq_max_tx_size_set(pp, pp->pkt_size); mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
...@@ -2431,7 +2438,11 @@ static void mvneta_start_dev(struct mvneta_port *pp) ...@@ -2431,7 +2438,11 @@ static void mvneta_start_dev(struct mvneta_port *pp)
mvneta_port_enable(pp); mvneta_port_enable(pp);
/* Enable polling on the port */ /* Enable polling on the port */
napi_enable(&pp->napi); for_each_present_cpu(cpu) {
struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
napi_enable(&port->napi);
}
/* Unmask interrupts */ /* Unmask interrupts */
mvreg_write(pp, MVNETA_INTR_NEW_MASK, mvreg_write(pp, MVNETA_INTR_NEW_MASK,
...@@ -2449,9 +2460,15 @@ static void mvneta_start_dev(struct mvneta_port *pp) ...@@ -2449,9 +2460,15 @@ static void mvneta_start_dev(struct mvneta_port *pp)
static void mvneta_stop_dev(struct mvneta_port *pp) static void mvneta_stop_dev(struct mvneta_port *pp)
{ {
unsigned int cpu;
phy_stop(pp->phy_dev); phy_stop(pp->phy_dev);
napi_disable(&pp->napi); for_each_present_cpu(cpu) {
struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
napi_disable(&port->napi);
}
netif_carrier_off(pp->dev); netif_carrier_off(pp->dev);
...@@ -2709,8 +2726,8 @@ static int mvneta_open(struct net_device *dev) ...@@ -2709,8 +2726,8 @@ static int mvneta_open(struct net_device *dev)
goto err_cleanup_rxqs; goto err_cleanup_rxqs;
/* Connect to port interrupt line */ /* Connect to port interrupt line */
ret = request_irq(pp->dev->irq, mvneta_isr, 0, ret = request_percpu_irq(pp->dev->irq, mvneta_isr,
MVNETA_DRIVER_NAME, pp); MVNETA_DRIVER_NAME, pp->ports);
if (ret) { if (ret) {
netdev_err(pp->dev, "cannot request irq %d\n", pp->dev->irq); netdev_err(pp->dev, "cannot request irq %d\n", pp->dev->irq);
goto err_cleanup_txqs; goto err_cleanup_txqs;
...@@ -2730,7 +2747,7 @@ static int mvneta_open(struct net_device *dev) ...@@ -2730,7 +2747,7 @@ static int mvneta_open(struct net_device *dev)
return 0; return 0;
err_free_irq: err_free_irq:
free_irq(pp->dev->irq, pp); free_percpu_irq(pp->dev->irq, pp->ports);
err_cleanup_txqs: err_cleanup_txqs:
mvneta_cleanup_txqs(pp); mvneta_cleanup_txqs(pp);
err_cleanup_rxqs: err_cleanup_rxqs:
...@@ -2745,7 +2762,7 @@ static int mvneta_stop(struct net_device *dev) ...@@ -2745,7 +2762,7 @@ static int mvneta_stop(struct net_device *dev)
mvneta_stop_dev(pp); mvneta_stop_dev(pp);
mvneta_mdio_remove(pp); mvneta_mdio_remove(pp);
free_irq(dev->irq, pp); free_percpu_irq(dev->irq, pp->ports);
mvneta_cleanup_rxqs(pp); mvneta_cleanup_rxqs(pp);
mvneta_cleanup_txqs(pp); mvneta_cleanup_txqs(pp);
...@@ -3032,6 +3049,7 @@ static int mvneta_probe(struct platform_device *pdev) ...@@ -3032,6 +3049,7 @@ static int mvneta_probe(struct platform_device *pdev)
const char *managed; const char *managed;
int phy_mode; int phy_mode;
int err; int err;
int cpu;
/* Our multiqueue support is not complete, so for now, only /* Our multiqueue support is not complete, so for now, only
* allow the usage of the first RX queue * allow the usage of the first RX queue
...@@ -3107,11 +3125,18 @@ static int mvneta_probe(struct platform_device *pdev) ...@@ -3107,11 +3125,18 @@ static int mvneta_probe(struct platform_device *pdev)
goto err_clk; goto err_clk;
} }
/* Alloc per-cpu port structure */
pp->ports = alloc_percpu(struct mvneta_pcpu_port);
if (!pp->ports) {
err = -ENOMEM;
goto err_clk;
}
/* Alloc per-cpu stats */ /* Alloc per-cpu stats */
pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats); pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats);
if (!pp->stats) { if (!pp->stats) {
err = -ENOMEM; err = -ENOMEM;
goto err_clk; goto err_free_ports;
} }
dt_mac_addr = of_get_mac_address(dn); dt_mac_addr = of_get_mac_address(dn);
...@@ -3152,7 +3177,12 @@ static int mvneta_probe(struct platform_device *pdev) ...@@ -3152,7 +3177,12 @@ static int mvneta_probe(struct platform_device *pdev)
if (dram_target_info) if (dram_target_info)
mvneta_conf_mbus_windows(pp, dram_target_info); mvneta_conf_mbus_windows(pp, dram_target_info);
netif_napi_add(dev, &pp->napi, mvneta_poll, NAPI_POLL_WEIGHT); for_each_present_cpu(cpu) {
struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
netif_napi_add(dev, &port->napi, mvneta_poll, NAPI_POLL_WEIGHT);
port->pp = pp;
}
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->hw_features |= dev->features; dev->hw_features |= dev->features;
...@@ -3183,6 +3213,8 @@ static int mvneta_probe(struct platform_device *pdev) ...@@ -3183,6 +3213,8 @@ static int mvneta_probe(struct platform_device *pdev)
err_free_stats: err_free_stats:
free_percpu(pp->stats); free_percpu(pp->stats);
err_free_ports:
free_percpu(pp->ports);
err_clk: err_clk:
clk_disable_unprepare(pp->clk); clk_disable_unprepare(pp->clk);
err_put_phy_node: err_put_phy_node:
...@@ -3202,6 +3234,7 @@ static int mvneta_remove(struct platform_device *pdev) ...@@ -3202,6 +3234,7 @@ static int mvneta_remove(struct platform_device *pdev)
unregister_netdev(dev); unregister_netdev(dev);
clk_disable_unprepare(pp->clk); clk_disable_unprepare(pp->clk);
free_percpu(pp->ports);
free_percpu(pp->stats); free_percpu(pp->stats);
irq_dispose_mapping(dev->irq); irq_dispose_mapping(dev->irq);
of_node_put(pp->phy_node); of_node_put(pp->phy_node);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册