---
drivers/net/Kconfig | 7 ++++
drivers/net/fec_mpc52xx.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+)
===================================================================
@@ -1896,6 +1896,13 @@ config FEC_MPC52xx
Fast Ethernet Controller
If compiled as module, it will be called fec_mpc52xx.
+config FEC_MPC52xx_NAPI
+ bool "Use NAPI for MPC52xx FEC driver"
+ depends on FEC_MPC52xx
+ ---help---
+ This option enables NAPI support for the MPC5200's on-chip
+ Fast Ethernet Controller driver.
+
config FEC_MPC52xx_MDIO
bool "MPC52xx FEC MDIO bus driver"
depends on FEC_MPC52xx
===================================================================
@@ -44,6 +44,8 @@
#define DRIVER_NAME "mpc52xx-fec"
+#define FEC_MPC52xx_NAPI_WEIGHT 64
+
/* Private driver data structure */
struct mpc52xx_fec_priv {
struct net_device *ndev;
@@ -63,6 +65,9 @@ struct mpc52xx_fec_priv {
struct phy_device *phydev;
enum phy_state link;
int seven_wire_mode;
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ struct napi_struct napi;
+#endif
};
@@ -226,6 +231,10 @@ static int mpc52xx_fec_open(struct net_d
phy_start(priv->phydev);
}
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ napi_enable(&priv->napi);
+#endif
+
if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED,
DRIVER_NAME "_ctrl", dev)) {
dev_err(&dev->dev, "ctrl interrupt request failed\n");
@@ -273,6 +282,9 @@ static int mpc52xx_fec_open(struct net_d
priv->phydev = NULL;
}
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ napi_disable(&priv->napi);
+#endif
return err;
}
@@ -280,6 +292,10 @@ static int mpc52xx_fec_close(struct net_
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ napi_disable(&priv->napi);
+#endif
+
netif_stop_queue(dev);
mpc52xx_fec_stop(dev);
@@ -379,17 +395,48 @@ static irqreturn_t mpc52xx_fec_tx_interr
return IRQ_HANDLED;
}
+#ifdef CONFIG_FEC_MPC52xx_NAPI
static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ /* Disable the RX interrupt */
+ if (napi_schedule_prep(&priv->napi)) {
+ disable_irq_nosync(irq);
+ __napi_schedule(&priv->napi);
+ } else {
+ dev_err(dev->dev.parent, "FEC BUG: interrupt while in poll\n");
+ }
+ return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+static int mpc52xx_fec_rx_poll(struct napi_struct *napi, int budget)
+#else
+static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
+#endif
+{
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ struct mpc52xx_fec_priv *priv =
+ container_of(napi, struct mpc52xx_fec_priv, napi);
+ struct net_device *dev = napi->dev;
+ int pkt_received = 0;
+#else
+ struct net_device *dev = dev_id;
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+#endif
+
while (bcom_buffer_done(priv->rx_dmatsk)) {
struct sk_buff *skb;
struct sk_buff *rskb;
struct bcom_fec_bd *bd;
u32 status;
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ pkt_received++;
+#endif
rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status,
(struct bcom_bd **)&bd);
dma_unmap_single(dev->dev.parent, bd->skb_pa, rskb->len,
@@ -410,6 +457,10 @@ static irqreturn_t mpc52xx_fec_rx_interr
dev->stats.rx_dropped++;
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ if (pkt_received >= budget)
+ break;
+#endif
continue;
}
@@ -425,7 +476,11 @@ static irqreturn_t mpc52xx_fec_rx_interr
rskb->dev = dev;
rskb->protocol = eth_type_trans(rskb, dev);
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ netif_receive_skb(rskb);
+#else
netif_rx(rskb);
+#endif
} else {
/* Can't get a new one : reuse the same & drop pkt */
dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
@@ -442,9 +497,23 @@ static irqreturn_t mpc52xx_fec_rx_interr
FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ if (pkt_received >= budget)
+ break;
+#endif
+ }
+
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ if (pkt_received < budget) {
+ napi_complete(napi);
+ enable_irq(priv->r_irq);
}
+ return pkt_received;
+#else
return IRQ_HANDLED;
+#endif
}
static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
@@ -950,6 +1019,13 @@ mpc52xx_fec_probe(struct of_device *op,
priv->duplex = DUPLEX_HALF;
priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->node) >> 20) / 5) << 1;
+#ifdef CONFIG_FEC_MPC52xx_NAPI
+ netif_napi_add(ndev, &priv->napi, mpc52xx_fec_rx_poll,
+ FEC_MPC52xx_NAPI_WEIGHT);
+ dev_info(&op->dev, "using NAPI with weigth %d\n",
+ FEC_MPC52xx_NAPI_WEIGHT);
+#endif
+
/* The current speed preconfigures the speed of the MII link */
prop = of_get_property(op->node, "current-speed", &prop_size);
if (prop && (prop_size >= sizeof(u32) * 2)) {