diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index e759171bfd76..a8aa1b7fe32c 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "lan743x_main.h" #include "lan743x_ethtool.h" @@ -1574,6 +1575,15 @@ static int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter, return result; } +static int lan743x_dmac_tx_reset(struct lan743x_adapter *adapter, + int tx_channel) +{ + lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_TX_SWR_(tx_channel)); + return lan743x_csr_wait_for_bit(adapter, DMAC_CMD, + DMAC_CMD_TX_SWR_(tx_channel), + 0, 1000, 20000, 100); +} + static int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter, int rx_channel) { @@ -1603,6 +1613,15 @@ static int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter, return result; } +static int lan743x_dmac_rx_reset(struct lan743x_adapter *adapter, + int rx_channel) +{ + lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_RX_SWR_(rx_channel)); + return lan743x_csr_wait_for_bit(adapter, DMAC_CMD, + DMAC_CMD_RX_SWR_(rx_channel), + 0, 1000, 20000, 100); +} + static void lan743x_tx_release_desc(struct lan743x_tx *tx, int descriptor_index, bool cleanup) { @@ -1676,10 +1695,23 @@ static int lan743x_tx_next_index(struct lan743x_tx *tx, int index) static void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx) { + struct lan743x_tx_buffer_info *buffer_info; + unsigned int bytes = 0; + unsigned int pkts = 0; + while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) { + buffer_info = &tx->buffer_info[tx->last_head]; + if (buffer_info->skb) { + bytes += buffer_info->skb->len; + pkts++; + } lan743x_tx_release_desc(tx, tx->last_head, false); tx->last_head = lan743x_tx_next_index(tx, tx->last_head); } + + netdev_tx_completed_queue(netdev_get_tx_queue(tx->adapter->netdev, + tx->channel_number), + pkts, bytes); } static void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx) @@ -1971,6 +2003,8 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx, if (ignore_sync) buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; + netif_subqueue_sent(adapter->netdev, tx->channel_number, skb->len); + tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); @@ -2097,7 +2131,8 @@ static int lan743x_tx_napi_poll(struct napi_struct *napi, int weight) /* clean up tx ring */ lan743x_tx_release_completed_descriptors(tx); txq = netdev_get_tx_queue(adapter->netdev, tx->channel_number); - if (netif_tx_queue_stopped(txq)) { + if (netif_tx_queue_stopped(txq) && + netif_device_present(adapter->netdev)) { if (tx->rqd_descriptors) { if (tx->rqd_descriptors <= lan743x_tx_get_avail_desc(tx)) { @@ -2215,7 +2250,16 @@ static void lan743x_tx_close(struct lan743x_tx *tx) lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_STOP_T_(tx->channel_number)); - lan743x_dmac_tx_wait_till_stopped(adapter, tx->channel_number); + if (lan743x_dmac_tx_wait_till_stopped(adapter, + tx->channel_number) < 0) { + netdev_warn(adapter->netdev, + "TX channel %d failed to stop, resetting it\n", + tx->channel_number); + if (lan743x_dmac_tx_reset(adapter, tx->channel_number)) + netdev_err(adapter->netdev, + "TX channel %d reset timed out\n", + tx->channel_number); + } lan743x_csr_write(adapter, DMAC_INT_EN_CLR, @@ -2232,6 +2276,7 @@ static void lan743x_tx_close(struct lan743x_tx *tx) 0, 1000, 20000, 100); lan743x_tx_release_all_descriptors(tx); + netdev_tx_reset_subqueue(adapter->netdev, tx->channel_number); tx->rqd_descriptors = 0; @@ -2774,7 +2819,16 @@ static void lan743x_rx_close(struct lan743x_rx *rx) lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_STOP_R_(rx->channel_number)); - lan743x_dmac_rx_wait_till_stopped(adapter, rx->channel_number); + if (lan743x_dmac_rx_wait_till_stopped(adapter, + rx->channel_number) < 0) { + netdev_warn(adapter->netdev, + "RX channel %d failed to stop, resetting it\n", + rx->channel_number); + if (lan743x_dmac_rx_reset(adapter, rx->channel_number)) + netdev_err(adapter->netdev, + "RX channel %d reset timed out\n", + rx->channel_number); + } lan743x_csr_write(adapter, DMAC_INT_EN_CLR, DMAC_INT_BIT_RXFRM_(rx->channel_number)); @@ -3275,6 +3329,17 @@ static int lan743x_netdev_close(struct net_device *netdev) struct lan743x_adapter *adapter = netdev_priv(netdev); int index; + /* lan743x_reset_work() takes rtnl, so it cannot be waited for here. + * A running one returns if the device is still down when it gets + * rtnl, otherwise it resets the reopened device once more. + */ + cancel_work(&adapter->reset_work); + + lan743x_phylink_disconnect(adapter); + + synchronize_net(); + netif_tx_disable(netdev); + for (index = 0; index < adapter->used_tx_channels; index++) lan743x_tx_close(&adapter->tx[index]); @@ -3283,8 +3348,6 @@ static int lan743x_netdev_close(struct net_device *netdev) lan743x_ptp_close(adapter); - lan743x_phylink_disconnect(adapter); - lan743x_mac_close(adapter); lan743x_intr_close(adapter); @@ -3306,10 +3369,6 @@ static int lan743x_netdev_open(struct net_device *netdev) if (ret) goto close_intr; - ret = lan743x_phylink_connect(adapter); - if (ret) - goto close_mac; - ret = lan743x_ptp_open(adapter); if (ret) goto close_mac; @@ -3328,6 +3387,10 @@ static int lan743x_netdev_open(struct net_device *netdev) goto close_tx; } + ret = lan743x_phylink_connect(adapter); + if (ret) + goto close_tx; + if (netdev->phydev) phy_support_eee(netdev->phydev); @@ -3355,8 +3418,6 @@ static int lan743x_netdev_open(struct net_device *netdev) lan743x_rx_close(&adapter->rx[index]); } lan743x_ptp_close(adapter); - if (adapter->phylink) - lan743x_phylink_disconnect(adapter); close_mac: lan743x_mac_close(adapter); @@ -3370,6 +3431,57 @@ static int lan743x_netdev_open(struct net_device *netdev) return ret; } +static int lan743x_netdev_stop(struct net_device *netdev) +{ + if (!netif_device_present(netdev)) + return 0; + + return lan743x_netdev_close(netdev); +} + +static void lan743x_reset_work(struct work_struct *work) +{ + struct lan743x_adapter *adapter = + container_of(work, struct lan743x_adapter, reset_work); + struct kernel_hwtstamp_config tstamp_config = {}; + struct net_device *netdev = adapter->netdev; + int ret; + + rtnl_lock(); + + if (!netif_running(netdev) || !netif_device_present(netdev)) + goto unlock; + + netdev_warn(netdev, "resetting after TX timeout\n"); + + lan743x_ptp_hwtstamp_get(netdev, &tstamp_config); + + netif_device_detach(netdev); + lan743x_netdev_close(netdev); + + ret = lan743x_dmac_init(adapter); + if (!ret) + ret = lan743x_netdev_open(netdev); + if (ret) { + netdev_err(netdev, "failed to reopen after reset: %d\n", ret); + dev_close(netdev); + } else { + lan743x_ptp_hwtstamp_set(netdev, &tstamp_config, NULL); + } + + netif_device_attach(netdev); +unlock: + rtnl_unlock(); +} + +static void lan743x_netdev_tx_timeout(struct net_device *netdev, + unsigned int txqueue) +{ + struct lan743x_adapter *adapter = netdev_priv(netdev); + + schedule_work(&adapter->reset_work); +} + static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -3476,8 +3588,9 @@ static int lan743x_netdev_set_mac_address(struct net_device *netdev, static const struct net_device_ops lan743x_netdev_ops = { .ndo_open = lan743x_netdev_open, - .ndo_stop = lan743x_netdev_close, + .ndo_stop = lan743x_netdev_stop, .ndo_start_xmit = lan743x_netdev_xmit_frame, + .ndo_tx_timeout = lan743x_netdev_tx_timeout, .ndo_eth_ioctl = lan743x_netdev_ioctl, .ndo_set_rx_mode = lan743x_netdev_set_multicast, .ndo_change_mtu = lan743x_netdev_change_mtu, @@ -3506,6 +3619,7 @@ static void lan743x_destroy_phylink(struct lan743x_adapter *adapter) static void lan743x_full_cleanup(struct lan743x_adapter *adapter) { unregister_netdev(adapter->netdev); + cancel_work_sync(&adapter->reset_work); lan743x_destroy_phylink(adapter); lan743x_mdiobus_cleanup(adapter); @@ -3692,6 +3806,7 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev, NETIF_MSG_LINK | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED; netdev->max_mtu = LAN743X_MAX_FRAME_SIZE; + INIT_WORK(&adapter->reset_work, lan743x_reset_work); of_get_mac_address(pdev->dev.of_node, adapter->mac_address); @@ -3994,8 +4109,14 @@ static int lan743x_pm_resume(struct device *dev) * For instance, it is true when system wakesup after pm-suspend * However, it is false when system wakes up after suspend GUI menu */ - if (netif_running(netdev)) - lan743x_netdev_open(netdev); + if (netif_running(netdev)) { + ret = lan743x_netdev_open(netdev); + if (ret) { + netdev_err(netdev, "failed to reopen on resume: %d\n", + ret); + dev_close(netdev); + } + } netif_device_attach(netdev); rtnl_unlock(); diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h index 1573c8f9c993..b243e76748e8 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.h +++ b/drivers/net/ethernet/microchip/lan743x_main.h @@ -6,6 +6,7 @@ #include #include +#include #include "lan743x_ptp.h" #define DRIVER_AUTHOR "Bryan Whitehead " @@ -1070,6 +1071,7 @@ struct lan743x_adapter { struct lan743x_phy phy; struct lan743x_tx tx[PCI11X1X_USED_TX_CHANNELS]; struct lan743x_rx rx[LAN743X_USED_RX_CHANNELS]; + struct work_struct reset_work; bool is_pci11x1x; bool is_sgmii_en; /* protect ethernet syslock */ diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c index f97a752e900a..518cc4022b30 100644 --- a/lib/dynamic_queue_limits.c +++ b/lib/dynamic_queue_limits.c @@ -193,6 +193,7 @@ void dql_reset(struct dql *dql) dql->limit = dql->min_limit; dql->num_queued = 0; dql->num_completed = 0; + dql->adj_limit = dql->limit; dql->last_obj_cnt = 0; dql->prev_num_queued = 0; dql->prev_last_obj_cnt = 0;