2020-01-08 16:10:59 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
/****************************************************************************
|
|
|
|
* Driver for Solarflare network controllers and boards
|
|
|
|
* Copyright 2018 Solarflare Communications Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published
|
|
|
|
* by the Free Software Foundation, incorporated herein by reference.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "net_driver.h"
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include "efx_common.h"
|
|
|
|
#include "efx_channels.h"
|
|
|
|
#include "efx.h"
|
|
|
|
#include "mcdi.h"
|
|
|
|
#include "selftest.h"
|
|
|
|
#include "rx_common.h"
|
|
|
|
#include "tx_common.h"
|
|
|
|
#include "nic.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "mcdi_pcol.h"
|
|
|
|
|
|
|
|
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
|
|
|
|
* queued onto this work queue. This is not a per-nic work queue, because
|
|
|
|
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
|
|
|
|
*/
|
|
|
|
static struct workqueue_struct *reset_workqueue;
|
|
|
|
|
|
|
|
int efx_create_reset_workqueue(void)
|
|
|
|
{
|
|
|
|
reset_workqueue = create_singlethread_workqueue("sfc_reset");
|
|
|
|
if (!reset_workqueue) {
|
|
|
|
printk(KERN_ERR "Failed to create reset workqueue\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void efx_queue_reset_work(struct efx_nic *efx)
|
|
|
|
{
|
|
|
|
queue_work(reset_workqueue, &efx->reset_work);
|
|
|
|
}
|
|
|
|
|
|
|
|
void efx_flush_reset_workqueue(struct efx_nic *efx)
|
|
|
|
{
|
|
|
|
cancel_work_sync(&efx->reset_work);
|
|
|
|
}
|
|
|
|
|
|
|
|
void efx_destroy_reset_workqueue(void)
|
|
|
|
{
|
|
|
|
if (reset_workqueue) {
|
|
|
|
destroy_workqueue(reset_workqueue);
|
|
|
|
reset_workqueue = NULL;
|
|
|
|
}
|
|
|
|
}
|
2020-01-08 16:11:13 +00:00
|
|
|
|
|
|
|
/* We assume that efx->type->reconfigure_mac will always try to sync RX
|
|
|
|
* filters and therefore needs to read-lock the filter table against freeing
|
|
|
|
*/
|
|
|
|
void efx_mac_reconfigure(struct efx_nic *efx)
|
|
|
|
{
|
|
|
|
down_read(&efx->filter_sem);
|
|
|
|
efx->type->reconfigure_mac(efx);
|
|
|
|
up_read(&efx->filter_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This ensures that the kernel is kept informed (via
|
|
|
|
* netif_carrier_on/off) of the link status, and also maintains the
|
|
|
|
* link status's stop on the port's TX queue.
|
|
|
|
*/
|
|
|
|
void efx_link_status_changed(struct efx_nic *efx)
|
|
|
|
{
|
|
|
|
struct efx_link_state *link_state = &efx->link_state;
|
|
|
|
|
|
|
|
/* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
|
|
|
|
* that no events are triggered between unregister_netdev() and the
|
|
|
|
* driver unloading. A more general condition is that NETDEV_CHANGE
|
|
|
|
* can only be generated between NETDEV_UP and NETDEV_DOWN
|
|
|
|
*/
|
|
|
|
if (!netif_running(efx->net_dev))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (link_state->up != netif_carrier_ok(efx->net_dev)) {
|
|
|
|
efx->n_link_state_changes++;
|
|
|
|
|
|
|
|
if (link_state->up)
|
|
|
|
netif_carrier_on(efx->net_dev);
|
|
|
|
else
|
|
|
|
netif_carrier_off(efx->net_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Status message for kernel log */
|
|
|
|
if (link_state->up)
|
|
|
|
netif_info(efx, link, efx->net_dev,
|
|
|
|
"link up at %uMbps %s-duplex (MTU %d)\n",
|
|
|
|
link_state->speed, link_state->fd ? "full" : "half",
|
|
|
|
efx->net_dev->mtu);
|
|
|
|
else
|
|
|
|
netif_info(efx, link, efx->net_dev, "link down\n");
|
|
|
|
}
|