From 0dd20f3ce04e75521bd3f9867ecbc852ab348912 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:01 +0300 Subject: [PATCH 1/5] NET: nps_enet: replace use of cause register When interrupt is received we read directly from control register for RX/TX instead of reading cause register since this register fails to indicate TX done when TX interrupt is "edge mode". Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 9 +++++---- drivers/net/ethernet/ezchip/nps_enet.h | 20 -------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 24a85b292007c..0e652b4fee8d6 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -211,12 +211,13 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance) { struct net_device *ndev = dev_instance; struct nps_enet_priv *priv = netdev_priv(ndev); - struct nps_enet_buf_int_cause buf_int_cause; + struct nps_enet_rx_ctl rx_ctrl; + struct nps_enet_tx_ctl tx_ctrl; - buf_int_cause.value = - nps_enet_reg_get(priv, NPS_ENET_REG_BUF_INT_CAUSE); + rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); + tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); - if (buf_int_cause.tx_done || buf_int_cause.rx_rdy) + if ((!tx_ctrl.ct && priv->tx_packet_sent) || rx_ctrl.cr) if (likely(napi_schedule_prep(&priv->napi))) { nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); __napi_schedule(&priv->napi); diff --git a/drivers/net/ethernet/ezchip/nps_enet.h b/drivers/net/ethernet/ezchip/nps_enet.h index fc45c9daa1c2d..6703674d679c9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.h +++ b/drivers/net/ethernet/ezchip/nps_enet.h @@ -36,7 +36,6 @@ #define NPS_ENET_REG_RX_CTL 0x810 #define NPS_ENET_REG_RX_BUF 0x818 #define NPS_ENET_REG_BUF_INT_ENABLE 0x8C0 -#define NPS_ENET_REG_BUF_INT_CAUSE 0x8C4 #define NPS_ENET_REG_GE_MAC_CFG_0 0x1000 #define NPS_ENET_REG_GE_MAC_CFG_1 0x1004 #define NPS_ENET_REG_GE_MAC_CFG_2 0x1008 @@ -108,25 +107,6 @@ struct nps_enet_buf_int_enable { }; }; -/* Interrupt cause for data buffer events register */ -struct nps_enet_buf_int_cause { - union { - /* tx_done: Interrupt in the case when current frame was - * read from TX buffer. - * rx_rdy: Interrupt in the case when new frame is ready - * in RX buffer. - */ - struct { - u32 - __reserved:30, - tx_done:1, - rx_rdy:1; - }; - - u32 value; - }; -}; - /* Gbps Eth MAC Configuration 0 register */ struct nps_enet_ge_mac_cfg_0 { union { From 93fcf83eb953d9ca2d3c51ff7f87095f0dd43511 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:02 +0300 Subject: [PATCH 2/5] NET: nps_enet: TX done race condition We need to set tx_skb pointer before send frame. If we receive interrupt before we set pointer we will try to free SKB with wrong pointer. Now we are sure that SKB pointer will never be NULL during handling TX done and check is removed. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 0e652b4fee8d6..8b25f240943d9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -158,11 +158,7 @@ static void nps_enet_tx_handler(struct net_device *ndev) ndev->stats.tx_bytes += tx_ctrl.nt; } - if (priv->tx_skb) { - dev_kfree_skb(priv->tx_skb); - priv->tx_skb = NULL; - } - + dev_kfree_skb(priv->tx_skb); priv->tx_packet_sent = false; if (netif_queue_stopped(ndev)) @@ -528,10 +524,10 @@ static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb, /* This driver handles one frame at a time */ netif_stop_queue(ndev); - nps_enet_send_frame(ndev, skb); - priv->tx_skb = skb; + nps_enet_send_frame(ndev, skb); + return NETDEV_TX_OK; } From de6715677aaa5e9ed27dab1f6ca6597b74a3f7bc Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:03 +0300 Subject: [PATCH 3/5] NET: nps_enet: drop control frames We set controller to drop control frames and not trying to pass them on. This is only needed for debug reasons. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 8b25f240943d9..e553e6aa0e744 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -304,11 +304,8 @@ static void nps_enet_hw_enable_control(struct net_device *ndev) /* Discard Packets bigger than max frame length */ max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN; - if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) { + if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) ge_mac_cfg_3->max_len = max_frame_length; - nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, - ge_mac_cfg_3->value); - } /* Enable interrupts */ buf_int_enable.rx_rdy = NPS_ENET_ENABLE; @@ -336,11 +333,14 @@ static void nps_enet_hw_enable_control(struct net_device *ndev) ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE; ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE; ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR; + ge_mac_cfg_3->cf_drop = NPS_ENET_ENABLE; /* Enable Rx and Tx */ ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE; ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE; + nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, + ge_mac_cfg_3->value); nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, ge_mac_cfg_0.value); } From 3d99b74ab3c4b7e529d5820ccadabfb81085f020 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:04 +0300 Subject: [PATCH 4/5] NET: nps_enet: TX done acknowledge. This is needed for when TX done interrupt is in "level mode". For example it is true for some simulators of this device. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index e553e6aa0e744..69b9129357fd9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -150,6 +150,9 @@ static void nps_enet_tx_handler(struct net_device *ndev) if (!priv->tx_packet_sent || tx_ctrl.ct) return; + /* Ack Tx ctrl register */ + nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, 0); + /* Check Tx transmit error */ if (unlikely(tx_ctrl.et)) { ndev->stats.tx_errors++; From 41493795a4c18170fdf27c0373d386b4039b24df Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:05 +0300 Subject: [PATCH 5/5] NET: nps_enet: minor namespace cleanup We define buf_int_enable in the minimal namespace it is used. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 69b9129357fd9..63c2bcf8031a8 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -179,15 +179,16 @@ static int nps_enet_poll(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; struct nps_enet_priv *priv = netdev_priv(ndev); - struct nps_enet_buf_int_enable buf_int_enable; u32 work_done; - buf_int_enable.rx_rdy = NPS_ENET_ENABLE; - buf_int_enable.tx_done = NPS_ENET_ENABLE; nps_enet_tx_handler(ndev); work_done = nps_enet_rx_handler(ndev); if (work_done < budget) { + struct nps_enet_buf_int_enable buf_int_enable; + napi_complete(napi); + buf_int_enable.rx_rdy = NPS_ENET_ENABLE; + buf_int_enable.tx_done = NPS_ENET_ENABLE; nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, buf_int_enable.value); }