Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 135 additions & 14 deletions drivers/net/ethernet/microchip/lan743x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/iopoll.h>
#include <linux/crc16.h>
#include <linux/phylink.h>
#include <net/netdev_queues.h>
#include "lan743x_main.h"
#include "lan743x_ethtool.h"

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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]);

Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/microchip/lan743x_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/workqueue.h>
#include "lan743x_ptp.h"

#define DRIVER_AUTHOR "Bryan Whitehead <Bryan.Whitehead@microchip.com>"
Expand Down Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions lib/dynamic_queue_limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading