Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12bb03b4 authored by Maxime Ripard's avatar Maxime Ripard Committed by David S. Miller
Browse files

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: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2502d0ef
Loading
Loading
Loading
Loading
+62 −29
Original line number Diff line number Diff line
@@ -285,7 +285,21 @@ struct mvneta_pcpu_stats {
	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_pcpu_port __percpu	*ports;
	struct mvneta_pcpu_stats __percpu	*stats;

	int pkt_size;
	unsigned int frag_size;
	void __iomem *base;
@@ -293,15 +307,11 @@ struct mvneta_port {
	struct mvneta_tx_queue *txqs;
	struct net_device *dev;

	u32 cause_rx_tx;
	struct napi_struct napi;

	/* Core clock */
	struct clk *clk;
	u8 mcast_count[256];
	u16 tx_ring_size;
	u16 rx_ring_size;
	struct mvneta_pcpu_stats *stats;

	struct mii_bus *mii_bus;
	struct phy_device *phy_dev;
@@ -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,
		     struct mvneta_rx_queue *rxq)
{
	struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
	struct net_device *dev = pp->dev;
	int rx_done;
	u32 rcvd_pkts = 0;
@@ -1515,7 +1526,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,

			skb->protocol = eth_type_trans(skb, dev);
			mvneta_rx_csum(pp, rx_status, skb);
			napi_gro_receive(&pp->napi, skb);
			napi_gro_receive(&port->napi, skb);

			rcvd_pkts++;
			rcvd_bytes += rx_bytes;
@@ -1550,7 +1561,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,

		mvneta_rx_csum(pp, rx_status, skb);

		napi_gro_receive(&pp->napi, skb);
		napi_gro_receive(&port->napi, skb);
	}

	if (rcvd_pkts) {
@@ -2061,12 +2072,11 @@ static void mvneta_set_rx_mode(struct net_device *dev)
/* Interrupt handling - the callback for request_irq() */
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 */
	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
	disable_percpu_irq(port->pp->dev->irq);

	napi_schedule(&pp->napi);
	napi_schedule(&port->napi);

	return IRQ_HANDLED;
}
@@ -2104,11 +2114,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
{
	int rx_done = 0;
	u32 cause_rx_tx;
	unsigned long flags;
	struct mvneta_port *pp = netdev_priv(napi->dev);
	struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);

	if (!netif_running(pp->dev)) {
		napi_complete(napi);
		napi_complete(&port->napi);
		return rx_done;
	}

@@ -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
	 * RX packets
	 */
	cause_rx_tx |= pp->cause_rx_tx;
	cause_rx_tx |= port->cause_rx_tx;
	if (rxq_number > 1) {
		while ((cause_rx_tx & MVNETA_RX_INTR_MASK_ALL) && (budget > 0)) {
			int count;
@@ -2166,16 +2176,11 @@ static int mvneta_poll(struct napi_struct *napi, int budget)

	if (budget > 0) {
		cause_rx_tx = 0;
		napi_complete(napi);
		local_irq_save(flags);
		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);
		napi_complete(&port->napi);
		enable_percpu_irq(pp->dev->irq, 0);
	}

	pp->cause_rx_tx = cause_rx_tx;
	port->cause_rx_tx = cause_rx_tx;
	return rx_done;
}

@@ -2424,6 +2429,8 @@ static int mvneta_setup_txqs(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_txq_max_tx_size_set(pp, pp->pkt_size);

@@ -2431,7 +2438,11 @@ static void mvneta_start_dev(struct mvneta_port *pp)
	mvneta_port_enable(pp);

	/* 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 */
	mvreg_write(pp, MVNETA_INTR_NEW_MASK,
@@ -2449,9 +2460,15 @@ static void mvneta_start_dev(struct mvneta_port *pp)

static void mvneta_stop_dev(struct mvneta_port *pp)
{
	unsigned int cpu;

	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);

@@ -2709,8 +2726,8 @@ static int mvneta_open(struct net_device *dev)
		goto err_cleanup_rxqs;

	/* Connect to port interrupt line */
	ret = request_irq(pp->dev->irq, mvneta_isr, 0,
			  MVNETA_DRIVER_NAME, pp);
	ret = request_percpu_irq(pp->dev->irq, mvneta_isr,
				 MVNETA_DRIVER_NAME, pp->ports);
	if (ret) {
		netdev_err(pp->dev, "cannot request irq %d\n", pp->dev->irq);
		goto err_cleanup_txqs;
@@ -2730,7 +2747,7 @@ static int mvneta_open(struct net_device *dev)
	return 0;

err_free_irq:
	free_irq(pp->dev->irq, pp);
	free_percpu_irq(pp->dev->irq, pp->ports);
err_cleanup_txqs:
	mvneta_cleanup_txqs(pp);
err_cleanup_rxqs:
@@ -2745,7 +2762,7 @@ static int mvneta_stop(struct net_device *dev)

	mvneta_stop_dev(pp);
	mvneta_mdio_remove(pp);
	free_irq(dev->irq, pp);
	free_percpu_irq(dev->irq, pp->ports);
	mvneta_cleanup_rxqs(pp);
	mvneta_cleanup_txqs(pp);

@@ -3032,6 +3049,7 @@ static int mvneta_probe(struct platform_device *pdev)
	const char *managed;
	int phy_mode;
	int err;
	int cpu;

	/* Our multiqueue support is not complete, so for now, only
	 * allow the usage of the first RX queue
@@ -3107,11 +3125,18 @@ static int mvneta_probe(struct platform_device *pdev)
		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 */
	pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats);
	if (!pp->stats) {
		err = -ENOMEM;
		goto err_clk;
		goto err_free_ports;
	}

	dt_mac_addr = of_get_mac_address(dn);
@@ -3152,7 +3177,12 @@ static int mvneta_probe(struct platform_device *pdev)
	if (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->hw_features |= dev->features;
@@ -3183,6 +3213,8 @@ static int mvneta_probe(struct platform_device *pdev)

err_free_stats:
	free_percpu(pp->stats);
err_free_ports:
	free_percpu(pp->ports);
err_clk:
	clk_disable_unprepare(pp->clk);
err_put_phy_node:
@@ -3202,6 +3234,7 @@ static int mvneta_remove(struct platform_device *pdev)

	unregister_netdev(dev);
	clk_disable_unprepare(pp->clk);
	free_percpu(pp->ports);
	free_percpu(pp->stats);
	irq_dispose_mapping(dev->irq);
	of_node_put(pp->phy_node);