summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/sfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r--drivers/net/ethernet/sfc/Kconfig10
-rw-r--r--drivers/net/ethernet/sfc/Makefile3
-rw-r--r--drivers/net/ethernet/sfc/efx.c32
-rw-r--r--drivers/net/ethernet/sfc/efx.h13
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c25
-rw-r--r--drivers/net/ethernet/sfc/falcon.c2
-rw-r--r--drivers/net/ethernet/sfc/io.h43
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c23
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h9
-rw-r--r--drivers/net/ethernet/sfc/nic.c81
-rw-r--r--drivers/net/ethernet/sfc/nic.h28
-rw-r--r--drivers/net/ethernet/sfc/ptp.c2
-rw-r--r--drivers/net/ethernet/sfc/rx.c31
-rw-r--r--drivers/net/ethernet/sfc/selftest.c4
-rw-r--r--drivers/net/ethernet/sfc/siena.c17
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c8
16 files changed, 192 insertions, 139 deletions
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 25906c1..435b4f1 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -1,10 +1,11 @@
config SFC
tristate "Solarflare SFC4000/SFC9000-family support"
- depends on PCI && INET
+ depends on PCI
select MDIO
select CRC32
select I2C
select I2C_ALGOBIT
+ select PTP_1588_CLOCK
---help---
This driver supports 10-gigabit Ethernet cards based on
the Solarflare SFC4000 and SFC9000-family controllers.
@@ -34,10 +35,3 @@ config SFC_SRIOV
This enables support for the SFC9000 I/O Virtualization
features, allowing accelerated network performance in
virtualized environments.
-config SFC_PTP
- bool "Solarflare SFC9000-family PTP support"
- depends on SFC && PTP_1588_CLOCK && !(SFC=y && PTP_1588_CLOCK=m)
- default y
- ---help---
- This enables support for the Precision Time Protocol (PTP)
- on SFC9000-family NICs
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index e11f2ec..945bf06 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -2,9 +2,8 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
falcon_xmac.o mcdi_mac.o \
selftest.o ethtool.o qt202x_phy.o mdio_10g.o \
tenxpress.o txc43128_phy.o falcon_boards.o \
- mcdi.o mcdi_phy.o mcdi_mon.o
+ mcdi.o mcdi_phy.o mcdi_mon.o ptp.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o
-sfc-$(CONFIG_SFC_PTP) += ptp.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 4f86d0c..0bc0099 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -106,8 +106,8 @@ static struct workqueue_struct *reset_workqueue;
*
* This is only used in MSI-X interrupt mode
*/
-static unsigned int separate_tx_channels;
-module_param(separate_tx_channels, uint, 0444);
+static bool separate_tx_channels;
+module_param(separate_tx_channels, bool, 0444);
MODULE_PARM_DESC(separate_tx_channels,
"Use separate channels for TX and RX");
@@ -160,8 +160,8 @@ static unsigned int rss_cpus;
module_param(rss_cpus, uint, 0444);
MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
-static int phy_flash_cfg;
-module_param(phy_flash_cfg, int, 0644);
+static bool phy_flash_cfg;
+module_param(phy_flash_cfg, bool, 0644);
MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
static unsigned irq_adapt_low_thresh = 8000;
@@ -779,6 +779,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
tx_queue->txd.entries);
}
+ efx_device_detach_sync(efx);
efx_stop_all(efx);
efx_stop_interrupts(efx, true);
@@ -832,6 +833,7 @@ out:
efx_start_interrupts(efx, true);
efx_start_all(efx);
+ netif_device_attach(efx->net_dev);
return rc;
rollback:
@@ -1641,8 +1643,12 @@ static void efx_stop_all(struct efx_nic *efx)
/* Flush efx_mac_work(), refill_workqueue, monitor_work */
efx_flush_all(efx);
- /* Stop the kernel transmit interface late, so the watchdog
- * timer isn't ticking over the flush */
+ /* Stop the kernel transmit interface. This is only valid if
+ * the device is stopped or detached; otherwise the watchdog
+ * may fire immediately.
+ */
+ WARN_ON(netif_running(efx->net_dev) &&
+ netif_device_present(efx->net_dev));
netif_tx_disable(efx->net_dev);
efx_stop_datapath(efx);
@@ -1963,16 +1969,18 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
if (new_mtu > EFX_MAX_MTU)
return -EINVAL;
- efx_stop_all(efx);
-
netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu);
+ efx_device_detach_sync(efx);
+ efx_stop_all(efx);
+
mutex_lock(&efx->mac_lock);
net_dev->mtu = new_mtu;
efx->type->reconfigure_mac(efx);
mutex_unlock(&efx->mac_lock);
efx_start_all(efx);
+ netif_device_attach(efx->net_dev);
return 0;
}
@@ -2279,7 +2287,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
netif_info(efx, drv, efx->net_dev, "resetting (%s)\n",
RESET_TYPE(method));
- netif_device_detach(efx->net_dev);
+ efx_device_detach_sync(efx);
efx_reset_down(efx, method);
rc = efx->type->reset(efx, method);
@@ -2669,8 +2677,8 @@ static int efx_pci_probe_main(struct efx_nic *efx)
* transmission; this is left to the first time one of the network
* interfaces is brought up (i.e. efx_net_open).
*/
-static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *entry)
+static int efx_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *entry)
{
struct net_device *net_dev;
struct efx_nic *efx;
@@ -2758,7 +2766,7 @@ static int efx_pm_freeze(struct device *dev)
if (efx->state != STATE_DISABLED) {
efx->state = STATE_UNINIT;
- netif_device_detach(efx->net_dev);
+ efx_device_detach_sync(efx);
efx_stop_all(efx);
efx_stop_interrupts(efx, false);
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index f11170b..d2f790d 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -163,4 +163,17 @@ extern void efx_link_status_changed(struct efx_nic *efx);
extern void efx_link_set_advertising(struct efx_nic *efx, u32);
extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8);
+static inline void efx_device_detach_sync(struct efx_nic *efx)
+{
+ struct net_device *dev = efx->net_dev;
+
+ /* Lock/freeze all TX queues so that we can be sure the
+ * TX scheduler is stopped when we're done and before
+ * netif_device_present() becomes false.
+ */
+ netif_tx_lock_bh(dev);
+ netif_device_detach(dev);
+ netif_tx_unlock_bh(dev);
+}
+
#endif /* EFX_EFX_H */
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 90f078e..8e61cd0 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -816,6 +816,9 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
/* MAC address mask including only MC flag */
static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+#define IP4_ADDR_FULL_MASK ((__force __be32)~0)
+#define PORT_FULL_MASK ((__force __be16)~0)
+
static int efx_ethtool_get_class_rule(struct efx_nic *efx,
struct ethtool_rx_flow_spec *rule)
{
@@ -865,12 +868,12 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
&spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst,
&ip_entry->ip4src, &ip_entry->psrc);
EFX_WARN_ON_PARANOID(rc);
- ip_mask->ip4src = ~0;
- ip_mask->psrc = ~0;
+ ip_mask->ip4src = IP4_ADDR_FULL_MASK;
+ ip_mask->psrc = PORT_FULL_MASK;
}
rule->flow_type = (proto == IPPROTO_TCP) ? TCP_V4_FLOW : UDP_V4_FLOW;
- ip_mask->ip4dst = ~0;
- ip_mask->pdst = ~0;
+ ip_mask->ip4dst = IP4_ADDR_FULL_MASK;
+ ip_mask->pdst = PORT_FULL_MASK;
return rc;
}
@@ -971,7 +974,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
/* Check for unsupported extensions */
if ((rule->flow_type & FLOW_EXT) &&
- (rule->m_ext.vlan_etype | rule->m_ext.data[0] |
+ (rule->m_ext.vlan_etype || rule->m_ext.data[0] ||
rule->m_ext.data[1]))
return -EINVAL;
@@ -986,16 +989,16 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
IPPROTO_TCP : IPPROTO_UDP);
/* Must match all of destination, */
- if ((__force u32)~ip_mask->ip4dst |
- (__force u16)~ip_mask->pdst)
+ if (!(ip_mask->ip4dst == IP4_ADDR_FULL_MASK &&
+ ip_mask->pdst == PORT_FULL_MASK))
return -EINVAL;
/* all or none of source, */
- if ((ip_mask->ip4src | ip_mask->psrc) &&
- ((__force u32)~ip_mask->ip4src |
- (__force u16)~ip_mask->psrc))
+ if ((ip_mask->ip4src || ip_mask->psrc) &&
+ !(ip_mask->ip4src == IP4_ADDR_FULL_MASK &&
+ ip_mask->psrc == PORT_FULL_MASK))
return -EINVAL;
/* and nothing else */
- if (ip_mask->tos | rule->m_ext.vlan_tci)
+ if (ip_mask->tos || rule->m_ext.vlan_tci)
return -EINVAL;
if (ip_mask->ip4src)
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index 12b573a..49bcd19 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -1792,6 +1792,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
.remove_port = falcon_remove_port,
.handle_global_event = falcon_handle_global_event,
.prepare_flush = falcon_prepare_flush,
+ .finish_flush = efx_port_dummy_op_void,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
.stop_stats = falcon_stop_nic_stats,
@@ -1834,6 +1835,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
.remove_port = falcon_remove_port,
.handle_global_event = falcon_handle_global_event,
.prepare_flush = falcon_prepare_flush,
+ .finish_flush = efx_port_dummy_op_void,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
.stop_stats = falcon_stop_nic_stats,
diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h
index 751d1ec..96759aee 100644
--- a/drivers/net/ethernet/sfc/io.h
+++ b/drivers/net/ethernet/sfc/io.h
@@ -22,22 +22,21 @@
*
* Notes on locking strategy:
*
- * Most CSRs are 128-bit (oword) and therefore cannot be read or
- * written atomically. Access from the host is buffered by the Bus
- * Interface Unit (BIU). Whenever the host reads from the lowest
- * address of such a register, or from the address of a different such
- * register, the BIU latches the register's value. Subsequent reads
- * from higher addresses of the same register will read the latched
- * value. Whenever the host writes part of such a register, the BIU
- * collects the written value and does not write to the underlying
- * register until all 4 dwords have been written. A similar buffering
- * scheme applies to host access to the NIC's 64-bit SRAM.
+ * Many CSRs are very wide and cannot be read or written atomically.
+ * Writes from the host are buffered by the Bus Interface Unit (BIU)
+ * up to 128 bits. Whenever the host writes part of such a register,
+ * the BIU collects the written value and does not write to the
+ * underlying register until all 4 dwords have been written. A
+ * similar buffering scheme applies to host access to the NIC's 64-bit
+ * SRAM.
*
- * Access to different CSRs and 64-bit SRAM words must be serialised,
- * since interleaved access can result in lost writes or lost
- * information from read-to-clear fields. We use efx_nic::biu_lock
- * for this. (We could use separate locks for read and write, but
- * this is not normally a performance bottleneck.)
+ * Writes to different CSRs and 64-bit SRAM words must be serialised,
+ * since interleaved access can result in lost writes. We use
+ * efx_nic::biu_lock for this.
+ *
+ * We also serialise reads from 128-bit CSRs and SRAM with the same
+ * spinlock. This may not be necessary, but it doesn't really matter
+ * as there are no such reads on the fast path.
*
* The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are
* 128-bit but are special-cased in the BIU to avoid the need for
@@ -204,20 +203,6 @@ static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
}
-/* Write a 32-bit CSR forming part of a table, or 32-bit SRAM */
-static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg, unsigned int index)
-{
- efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Read a 32-bit CSR forming part of a table, or 32-bit SRAM */
-static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg, unsigned int index)
-{
- efx_readd(efx, value, reg + index * sizeof(efx_dword_t));
-}
-
/* Page-mapped register block size */
#define EFX_PAGE_BLOCK_SIZE 0x2000
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index aea43cb..0095ce9 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -22,7 +22,7 @@
**************************************************************************
*/
-#define MCDI_RPC_TIMEOUT 10 /*seconds */
+#define MCDI_RPC_TIMEOUT (10 * HZ)
#define MCDI_PDU(efx) \
(efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST)
@@ -120,7 +120,7 @@ static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
static int efx_mcdi_poll(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned int time, finish;
+ unsigned long time, finish;
unsigned int respseq, respcmd, error;
unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
unsigned int rc, spins;
@@ -136,7 +136,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
* and poll once a jiffy (approximately)
*/
spins = TICK_USEC;
- finish = get_seconds() + MCDI_RPC_TIMEOUT;
+ finish = jiffies + MCDI_RPC_TIMEOUT;
while (1) {
if (spins != 0) {
@@ -146,7 +146,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
schedule_timeout_uninterruptible(1);
}
- time = get_seconds();
+ time = jiffies;
rmb();
efx_readd(efx, &reg, pdu);
@@ -158,7 +158,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE))
break;
- if (time >= finish)
+ if (time_after(time, finish))
return -ETIMEDOUT;
}
@@ -207,7 +207,9 @@ out:
return 0;
}
-/* Test and clear MC-rebooted flag for this port/function */
+/* Test and clear MC-rebooted flag for this port/function; reset
+ * software state as necessary.
+ */
int efx_mcdi_poll_reboot(struct efx_nic *efx)
{
unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx);
@@ -223,6 +225,11 @@ int efx_mcdi_poll_reboot(struct efx_nic *efx)
if (value == 0)
return 0;
+ /* MAC statistics have been cleared on the NIC; clear our copy
+ * so that efx_update_diff_stat() can continue to work.
+ */
+ memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
+
EFX_ZERO_DWORD(reg);
efx_writed(efx, &reg, addr);
@@ -250,7 +257,7 @@ static int efx_mcdi_await_completion(struct efx_nic *efx)
if (wait_event_timeout(
mcdi->wq,
atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED,
- msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0)
+ MCDI_RPC_TIMEOUT) == 0)
return -ETIMEDOUT;
/* Check if efx_mcdi_set_mode() switched us back to polled completions.
@@ -1216,7 +1223,7 @@ int efx_mcdi_flush_rxqs(struct efx_nic *efx)
rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, (u8 *)qid,
count * sizeof(*qid), NULL, 0, NULL);
- WARN_ON(rc > 0);
+ WARN_ON(rc < 0);
kfree(qid);
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 576a310..0a90abd 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -200,6 +200,7 @@ struct efx_tx_queue {
/* Members shared between paths and sometimes updated */
unsigned int empty_read_count ____cacheline_aligned_in_smp;
#define EFX_EMPTY_COUNT_VALID 0x80000000
+ atomic_t flush_outstanding;
};
/**
@@ -209,6 +210,7 @@ struct efx_tx_queue {
* Will be %NULL if the buffer slot is currently free.
* @page: The associated page buffer. Valif iff @flags & %EFX_RX_BUF_PAGE.
* Will be %NULL if the buffer slot is currently free.
+ * @page_offset: Offset within page. Valid iff @flags & %EFX_RX_BUF_PAGE.
* @len: Buffer length, in bytes.
* @flags: Flags for buffer and packet state.
*/
@@ -218,7 +220,8 @@ struct efx_rx_buffer {
struct sk_buff *skb;
struct page *page;
} u;
- unsigned int len;
+ u16 page_offset;
+ u16 len;
u16 flags;
};
#define EFX_RX_BUF_PAGE 0x0001
@@ -868,9 +871,7 @@ struct efx_nic {
struct work_struct peer_work;
#endif
-#ifdef CONFIG_SFC_PTP
struct efx_ptp_data *ptp_data;
-#endif
/* The following fields may be written more often */
@@ -909,6 +910,7 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @remove_port: Free resources allocated by probe_port()
* @handle_global_event: Handle a "global" event (may be %NULL)
* @prepare_flush: Prepare the hardware for flushing the DMA queues
+ * @finish_flush: Clean up after flushing the DMA queues
* @update_stats: Update statistics not provided by event handling
* @start_stats: Start the regular fetching of statistics
* @stop_stats: Stop the regular fetching of statistics
@@ -956,6 +958,7 @@ struct efx_nic_type {
void (*remove_port)(struct efx_nic *efx);
bool (*handle_global_event)(struct efx_channel *channel, efx_qword_t *);
void (*prepare_flush)(struct efx_nic *efx);
+ void (*finish_flush)(struct efx_nic *efx);
void (*update_stats)(struct efx_nic *efx);
void (*start_stats)(struct efx_nic *efx);
void (*stop_stats)(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index aab7cac..0ad790c 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -73,6 +73,8 @@
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TX_DRAIN, \
(_tx_queue)->queue)
+static void efx_magic_event(struct efx_channel *channel, u32 magic);
+
/**************************************************************************
*
* Solarstorm hardware access
@@ -255,9 +257,6 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
buffer->entries = len / EFX_BUF_SIZE;
BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1));
- /* All zeros is a potentially valid event so memset to 0xff */
- memset(buffer->addr, 0xff, len);
-
/* Select new buffer ID */
buffer->index = efx->next_buffer_table;
efx->next_buffer_table += buffer->entries;
@@ -494,6 +493,9 @@ static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue)
struct efx_nic *efx = tx_queue->efx;
efx_oword_t tx_flush_descq;
+ WARN_ON(atomic_read(&tx_queue->flush_outstanding));
+ atomic_set(&tx_queue->flush_outstanding, 1);
+
EFX_POPULATE_OWORD_2(tx_flush_descq,
FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
@@ -669,6 +671,47 @@ static bool efx_flush_wake(struct efx_nic *efx)
&& atomic_read(&efx->rxq_flush_pending) > 0));
}
+static bool efx_check_tx_flush_complete(struct efx_nic *efx)
+{
+ bool i = true;
+ efx_oword_t txd_ptr_tbl;
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ efx_reado_table(efx, &txd_ptr_tbl,
+ FR_BZ_TX_DESC_PTR_TBL, tx_queue->queue);
+ if (EFX_OWORD_FIELD(txd_ptr_tbl,
+ FRF_AZ_TX_DESCQ_FLUSH) ||
+ EFX_OWORD_FIELD(txd_ptr_tbl,
+ FRF_AZ_TX_DESCQ_EN)) {
+ netif_dbg(efx, hw, efx->net_dev,
+ "flush did not complete on TXQ %d\n",
+ tx_queue->queue);
+ i = false;
+ } else if (atomic_cmpxchg(&tx_queue->flush_outstanding,
+ 1, 0)) {
+ /* The flush is complete, but we didn't
+ * receive a flush completion event
+ */
+ netif_dbg(efx, hw, efx->net_dev,
+ "flush complete on TXQ %d, so drain "
+ "the queue\n", tx_queue->queue);
+ /* Don't need to increment drain_pending as it
+ * has already been incremented for the queues
+ * which did not drain
+ */
+ efx_magic_event(channel,
+ EFX_CHANNEL_MAGIC_TX_DRAIN(
+ tx_queue));
+ }
+ }
+ }
+
+ return i;
+}
+
/* Flush all the transmit queues, and continue flushing receive queues until
* they're all flushed. Wait for the DRAIN events to be recieved so that there
* are no more RX and TX events left on any channel. */
@@ -680,7 +723,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
struct efx_tx_queue *tx_queue;
int rc = 0;
- efx->fc_disable++;
efx->type->prepare_flush(efx);
efx_for_each_channel(channel, efx) {
@@ -730,7 +772,8 @@ int efx_nic_flush_queues(struct efx_nic *efx)
timeout);
}
- if (atomic_read(&efx->drain_pending)) {
+ if (atomic_read(&efx->drain_pending) &&
+ !efx_check_tx_flush_complete(efx)) {
netif_err(efx, hw, efx->net_dev, "failed to flush %d queues "
"(rx %d+%d)\n", atomic_read(&efx->drain_pending),
atomic_read(&efx->rxq_flush_outstanding),
@@ -742,7 +785,7 @@ int efx_nic_flush_queues(struct efx_nic *efx)
atomic_set(&efx->rxq_flush_outstanding, 0);
}
- efx->fc_disable--;
+ efx->type->finish_flush(efx);
return rc;
}
@@ -766,8 +809,13 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR,
channel->eventq_read_ptr & channel->eventq_mask);
- efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base,
- channel->channel);
+
+ /* For Falcon A1, EVQ_RPTR_KER is documented as having a step size
+ * of 4 bytes, but it is really 16 bytes just like later revisions.
+ */
+ efx_writed(efx, &reg,
+ efx->type->evq_rptr_tbl_base +
+ FR_BZ_EVQ_RPTR_STEP * channel->channel);
}
/* Use HW to insert a SW defined event */
@@ -1017,9 +1065,10 @@ efx_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) {
tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES,
qid % EFX_TXQ_TYPES);
-
- efx_magic_event(tx_queue->channel,
- EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
+ if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) {
+ efx_magic_event(tx_queue->channel,
+ EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
+ }
}
}
@@ -1565,7 +1614,9 @@ void efx_nic_push_rx_indir_table(struct efx_nic *efx)
for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
efx->rx_indir_table[i]);
- efx_writed_table(efx, &dword, FR_BZ_RX_INDIRECTION_TBL, i);
+ efx_writed(efx, &dword,
+ FR_BZ_RX_INDIRECTION_TBL +
+ FR_BZ_RX_INDIRECTION_TBL_STEP * i);
}
}
@@ -2029,15 +2080,15 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
for (i = 0; i < table->rows; i++) {
switch (table->step) {
- case 4: /* 32-bit register or SRAM */
- efx_readd_table(efx, buf, table->offset, i);
+ case 4: /* 32-bit SRAM */
+ efx_readd(efx, buf, table->offset + 4 * i);
break;
case 8: /* 64-bit SRAM */
efx_sram_readq(efx,
efx->membase + table->offset,
buf, i);
break;
- case 16: /* 128-bit register */
+ case 16: /* 128-bit-readable register */
efx_reado_table(efx, buf, table->offset, i);
break;
case 32: /* 128-bit register, interleaved */
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 438cef1..1b00033 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -252,7 +252,6 @@ extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
bool spoofchk);
struct ethtool_ts_info;
-#ifdef CONFIG_SFC_PTP
extern void efx_ptp_probe(struct efx_nic *efx);
extern int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd);
extern int efx_ptp_get_ts_info(struct net_device *net_dev,
@@ -260,31 +259,6 @@ extern int efx_ptp_get_ts_info(struct net_device *net_dev,
extern bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
extern int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
extern void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
-#else
-static inline void efx_ptp_probe(struct efx_nic *efx) {}
-static inline int efx_ptp_ioctl(struct efx_nic *efx, struct ifreq *ifr, int cmd)
-{
- return -EOPNOTSUPP;
-}
-static inline int efx_ptp_get_ts_info(struct net_device *net_dev,
- struct ethtool_ts_info *ts_info)
-{
- ts_info->so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
- SOF_TIMESTAMPING_RX_SOFTWARE);
- ts_info->phc_index = -1;
-
- return 0;
-}
-static inline bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb)
-{
- return false;
-}
-static inline int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb)
-{
- return NETDEV_TX_OK;
-}
-static inline void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev) {}
-#endif
extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type;
@@ -370,6 +344,8 @@ static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx)
/* Global Resources */
extern int efx_nic_flush_queues(struct efx_nic *efx);
+extern void siena_prepare_flush(struct efx_nic *efx);
+extern void siena_finish_flush(struct efx_nic *efx);
extern void falcon_start_nic_stats(struct efx_nic *efx);
extern void falcon_stop_nic_stats(struct efx_nic *efx);
extern void falcon_setup_xaui(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 0767043f..3f93624 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -1439,7 +1439,7 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
delta = timespec_sub(*e_ts, time_now);
- efx_phc_adjtime(ptp, timespec_to_ns(&delta));
+ rc = efx_phc_adjtime(ptp, timespec_to_ns(&delta));
if (rc != 0)
return rc;
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index 9e0ad1b..bb579a6 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -90,11 +90,7 @@ static unsigned int rx_refill_threshold;
static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx,
struct efx_rx_buffer *buf)
{
- /* Offset is always within one page, so we don't need to consider
- * the page order.
- */
- return ((unsigned int) buf->dma_addr & (PAGE_SIZE - 1)) +
- efx->type->rx_buffer_hash_size;
+ return buf->page_offset + efx->type->rx_buffer_hash_size;
}
static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
{
@@ -187,7 +183,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
struct page *page;
- void *page_addr;
+ unsigned int page_offset;
struct efx_rx_page_state *state;
dma_addr_t dma_addr;
unsigned index, count;
@@ -207,19 +203,19 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
__free_pages(page, efx->rx_buffer_order);
return -EIO;
}
- page_addr = page_address(page);
- state = page_addr;
+ state = page_address(page);
state->refcnt = 0;
state->dma_addr = dma_addr;
- page_addr += sizeof(struct efx_rx_page_state);
dma_addr += sizeof(struct efx_rx_page_state);
+ page_offset = sizeof(struct efx_rx_page_state);
split:
index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
rx_buf->u.page = page;
+ rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN;
rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
rx_buf->flags = EFX_RX_BUF_PAGE;
++rx_queue->added_count;
@@ -230,7 +226,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
/* Use the second half of the page */
get_page(page);
dma_addr += (PAGE_SIZE >> 1);
- page_addr += (PAGE_SIZE >> 1);
+ page_offset += (PAGE_SIZE >> 1);
++count;
goto split;
}
@@ -240,7 +236,8 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
}
static void efx_unmap_rx_buffer(struct efx_nic *efx,
- struct efx_rx_buffer *rx_buf)
+ struct efx_rx_buffer *rx_buf,
+ unsigned int used_len)
{
if ((rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.page) {
struct efx_rx_page_state *state;
@@ -251,6 +248,10 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,
state->dma_addr,
efx_rx_buf_size(efx),
DMA_FROM_DEVICE);
+ } else if (used_len) {
+ dma_sync_single_for_cpu(&efx->pci_dev->dev,
+ rx_buf->dma_addr, used_len,
+ DMA_FROM_DEVICE);
}
} else if (!(rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.skb) {
dma_unmap_single(&efx->pci_dev->dev, rx_buf->dma_addr,
@@ -273,7 +274,7 @@ static void efx_free_rx_buffer(struct efx_nic *efx,
static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
- efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
+ efx_unmap_rx_buffer(rx_queue->efx, rx_buf, 0);
efx_free_rx_buffer(rx_queue->efx, rx_buf);
}
@@ -539,10 +540,10 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
goto out;
}
- /* Release card resources - assumes all RX buffers consumed in-order
- * per RX queue
+ /* Release and/or sync DMA mapping - assumes all RX buffers
+ * consumed in-order per RX queue
*/
- efx_unmap_rx_buffer(efx, rx_buf);
+ efx_unmap_rx_buffer(efx, rx_buf, len);
/* Prefetch nice and early so data will (hopefully) be in cache by
* the time we look at it.
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index ce72ae4..2069f51 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -373,7 +373,7 @@ static void efx_iterate_state(struct efx_nic *efx)
/* saddr set later and used as incrementing count */
payload->ip.daddr = htonl(INADDR_LOOPBACK);
payload->ip.ihl = 5;
- payload->ip.check = htons(0xdead);
+ payload->ip.check = (__force __sum16) htons(0xdead);
payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr));
payload->ip.version = IPVERSION;
payload->ip.protocol = IPPROTO_UDP;
@@ -722,7 +722,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
/* Detach the device so the kernel doesn't transmit during the
* loopback test and the watchdog timeout doesn't fire.
*/
- netif_device_detach(efx->net_dev);
+ efx_device_detach_sync(efx);
if (efx->type->test_chip) {
rc_reset = efx->type->test_chip(efx, tests);
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index 84b41bf..ba40f67 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -127,6 +127,18 @@ static void siena_remove_port(struct efx_nic *efx)
efx_nic_free_buffer(efx, &efx->stats_buffer);
}
+void siena_prepare_flush(struct efx_nic *efx)
+{
+ if (efx->fc_disable++ == 0)
+ efx_mcdi_set_mac(efx);
+}
+
+void siena_finish_flush(struct efx_nic *efx)
+{
+ if (--efx->fc_disable == 0)
+ efx_mcdi_set_mac(efx);
+}
+
static const struct efx_nic_register_test siena_register_tests[] = {
{ FR_AZ_ADR_REGION,
EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
@@ -158,7 +170,7 @@ static const struct efx_nic_register_test siena_register_tests[] = {
static int siena_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
- enum reset_type reset_method = reset_method;
+ enum reset_type reset_method = RESET_TYPE_ALL;
int rc, rc2;
efx_reset_down(efx, reset_method);
@@ -659,7 +671,8 @@ const struct efx_nic_type siena_a0_nic_type = {
.reset = siena_reset_hw,
.probe_port = siena_probe_port,
.remove_port = siena_remove_port,
- .prepare_flush = efx_port_dummy_op_void,
+ .prepare_flush = siena_prepare_flush,
+ .finish_flush = siena_finish_flush,
.update_stats = siena_update_nic_stats,
.start_stats = siena_start_nic_stats,
.stop_stats = siena_stop_nic_stats,
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index d49b53d..90f8d16 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -695,8 +695,7 @@ static int efx_vfdi_fini_all_queues(struct efx_vf *vf)
return VFDI_RC_ENOMEM;
rtnl_lock();
- if (efx->fc_disable++ == 0)
- efx_mcdi_set_mac(efx);
+ siena_prepare_flush(efx);
rtnl_unlock();
/* Flush all the initialized queues */
@@ -733,8 +732,7 @@ static int efx_vfdi_fini_all_queues(struct efx_vf *vf)
}
rtnl_lock();
- if (--efx->fc_disable == 0)
- efx_mcdi_set_mac(efx);
+ siena_finish_flush(efx);
rtnl_unlock();
/* Irrespective of success/failure, fini the queues */
@@ -995,7 +993,7 @@ static void efx_sriov_reset_vf(struct efx_vf *vf, struct efx_buffer *buffer)
FRF_AZ_EVQ_BUF_BASE_ID, buftbl);
efx_writeo_table(efx, &reg, FR_BZ_EVQ_PTR_TBL, abs_evq);
EFX_POPULATE_DWORD_1(ptr, FRF_AZ_EVQ_RPTR, 0);
- efx_writed_table(efx, &ptr, FR_BZ_EVQ_RPTR, abs_evq);
+ efx_writed(efx, &ptr, FR_BZ_EVQ_RPTR + FR_BZ_EVQ_RPTR_STEP * abs_evq);
mutex_unlock(&vf->status_lock);
}