Skip to content

Commit

Permalink
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/bwh/sfc-next

Ben Hutchings says:

====================
1. More workarounds for TX queue flush failures that can occur during
   interface reconfiguration.
2. Fix spurious failure of a firmware request running during a system
   clock change, e.g. ntpd started at the same time as driver load.
3. Fix inconsistent statistics after a firmware upgrade.
4. Fix a variable (non-)initialisation in offline self-test that can
   make it more disruptive than intended.
5. Fix a race that can (at least) cause an assertion failure.
6. Miscellaneous cleanup.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 1, 2012
2 parents a20da98 + b9cc977 commit abe303d
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 83 deletions.
12 changes: 6 additions & 6 deletions drivers/net/ethernet/sfc/efx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2279,7 +2279,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);
Expand Down Expand Up @@ -2758,7 +2758,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);
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/ethernet/sfc/efx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(dev);
netif_device_detach(dev);
netif_tx_unlock(dev);
}

#endif /* EFX_EFX_H */
25 changes: 14 additions & 11 deletions drivers/net/ethernet/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

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

Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/sfc/falcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
43 changes: 14 additions & 29 deletions drivers/net/ethernet/sfc/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
23 changes: 15 additions & 8 deletions drivers/net/ethernet/sfc/mcdi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -207,7 +207,9 @@ static int efx_mcdi_poll(struct efx_nic *efx)
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);
Expand All @@ -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);

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

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/sfc/net_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand Down Expand Up @@ -907,6 +908,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
Expand Down Expand Up @@ -954,6 +956,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);
Expand Down
Loading

0 comments on commit abe303d

Please sign in to comment.