Commit c4b83061 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sfc-driver-for-EF100-family-NICs-part-2'



Edward Cree says:

====================
sfc: driver for EF100 family NICs, part 2

This series implements the data path and various other functionality
 for Xilinx/Solarflare EF100 NICs.

Changed from v2:
 * Improved error handling of design params (patch #3)
 * Removed 'inline' from .c file in patch #4
 * Don't report common stats to ethtool -S (patch #8)

Changed from v1:
 * Fixed build errors on CONFIG_RFS_ACCEL=n (patch #5) and 32-bit
   (patch #8)
 * Dropped patch #10 (ethtool ops) as it's buggy and will need a
   bigger rework to fix.
====================

Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 215602a8 d61592a1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -527,6 +527,8 @@ fail:
static const struct pci_device_id ef100_pci_table[] = {
	{PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x0100),  /* Riverhead PF */
		.driver_data = (unsigned long) &ef100_pf_nic_type },
	{PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x1100),  /* Riverhead VF */
		.driver_data = (unsigned long) &ef100_vf_nic_type },
	{0}                     /* end of list */
};

+16 −0
Original line number Diff line number Diff line
@@ -86,9 +86,11 @@ static int ef100_net_stop(struct net_device *net_dev)

	netif_stop_queue(net_dev);
	efx_stop_all(efx);
	efx_mcdi_mac_fini_stats(efx);
	efx_disable_interrupts(efx);
	efx_clear_interrupt_affinity(efx);
	efx_nic_fini_interrupt(efx);
	efx_remove_filters(efx);
	efx_fini_napi(efx);
	efx_remove_channels(efx);
	efx_mcdi_free_vis(efx);
@@ -138,6 +140,10 @@ static int ef100_net_open(struct net_device *net_dev)

	efx_init_napi(efx);

	rc = efx_probe_filters(efx);
	if (rc)
		goto fail;

	rc = efx_nic_init_interrupt(efx);
	if (rc)
		goto fail;
@@ -152,6 +158,10 @@ static int ef100_net_open(struct net_device *net_dev)
	 */
	(void) efx_mcdi_poll_reboot(efx);

	rc = efx_mcdi_mac_init_stats(efx);
	if (rc)
		goto fail;

	efx_start_all(efx);

	/* Link state detection is normally event-driven; we have
@@ -207,8 +217,14 @@ static const struct net_device_ops ef100_netdev_ops = {
	.ndo_open               = ef100_net_open,
	.ndo_stop               = ef100_net_stop,
	.ndo_start_xmit         = ef100_hard_start_xmit,
	.ndo_get_stats64        = efx_net_stats,
	.ndo_validate_addr      = eth_validate_addr,
	.ndo_set_rx_mode        = efx_set_rx_mode, /* Lookout */
	.ndo_get_phys_port_id   = efx_get_phys_port_id,
	.ndo_get_phys_port_name = efx_get_phys_port_name,
#ifdef CONFIG_RFS_ACCEL
	.ndo_rx_flow_steer      = efx_filter_rfs,
#endif
};

/*	Netdev registration
+657 −0

File changed.

Preview size limit exceeded, changes collapsed.

+48 −0
Original line number Diff line number Diff line
@@ -13,19 +13,67 @@
#include "nic_common.h"

extern const struct efx_nic_type ef100_pf_nic_type;
extern const struct efx_nic_type ef100_vf_nic_type;

int ef100_probe_pf(struct efx_nic *efx);
int ef100_probe_vf(struct efx_nic *efx);
void ef100_remove(struct efx_nic *efx);

enum {
	EF100_STAT_port_tx_bytes = GENERIC_STAT_COUNT,
	EF100_STAT_port_tx_packets,
	EF100_STAT_port_tx_pause,
	EF100_STAT_port_tx_unicast,
	EF100_STAT_port_tx_multicast,
	EF100_STAT_port_tx_broadcast,
	EF100_STAT_port_tx_lt64,
	EF100_STAT_port_tx_64,
	EF100_STAT_port_tx_65_to_127,
	EF100_STAT_port_tx_128_to_255,
	EF100_STAT_port_tx_256_to_511,
	EF100_STAT_port_tx_512_to_1023,
	EF100_STAT_port_tx_1024_to_15xx,
	EF100_STAT_port_tx_15xx_to_jumbo,
	EF100_STAT_port_rx_bytes,
	EF100_STAT_port_rx_packets,
	EF100_STAT_port_rx_good,
	EF100_STAT_port_rx_bad,
	EF100_STAT_port_rx_pause,
	EF100_STAT_port_rx_unicast,
	EF100_STAT_port_rx_multicast,
	EF100_STAT_port_rx_broadcast,
	EF100_STAT_port_rx_lt64,
	EF100_STAT_port_rx_64,
	EF100_STAT_port_rx_65_to_127,
	EF100_STAT_port_rx_128_to_255,
	EF100_STAT_port_rx_256_to_511,
	EF100_STAT_port_rx_512_to_1023,
	EF100_STAT_port_rx_1024_to_15xx,
	EF100_STAT_port_rx_15xx_to_jumbo,
	EF100_STAT_port_rx_gtjumbo,
	EF100_STAT_port_rx_bad_gtjumbo,
	EF100_STAT_port_rx_align_error,
	EF100_STAT_port_rx_length_error,
	EF100_STAT_port_rx_overflow,
	EF100_STAT_port_rx_nodesc_drops,
	EF100_STAT_COUNT
};

struct ef100_nic_data {
	struct efx_nic *efx;
	struct efx_buffer mcdi_buf;
	u32 datapath_caps;
	u32 datapath_caps2;
	u32 datapath_caps3;
	unsigned int pf_index;
	u16 warm_boot_count;
	u8 port_id[ETH_ALEN];
	DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS);
	u64 stats[EF100_STAT_COUNT];
	u16 tso_max_hdr_len;
	u16 tso_max_payload_num_segs;
	u16 tso_max_frames;
	unsigned int tso_max_payload_len;
};

#define efx_ef100_has_cap(caps, flag) \
+143 −7
Original line number Diff line number Diff line
@@ -12,20 +12,156 @@
#include "ef100_rx.h"
#include "rx_common.h"
#include "efx.h"
#include "nic_common.h"
#include "mcdi_functions.h"
#include "ef100_regs.h"
#include "ef100_nic.h"
#include "io.h"

/* RX stubs */
/* Get the value of a field in the RX prefix */
#define PREFIX_OFFSET_W(_f)	(ESF_GZ_RX_PREFIX_ ## _f ## _LBN / 32)
#define PREFIX_OFFSET_B(_f)	(ESF_GZ_RX_PREFIX_ ## _f ## _LBN % 32)
#define PREFIX_WIDTH_MASK(_f)	((1UL << ESF_GZ_RX_PREFIX_ ## _f ## _WIDTH) - 1)
#define PREFIX_WORD(_p, _f)	le32_to_cpu((__force __le32)(_p)[PREFIX_OFFSET_W(_f)])
#define PREFIX_FIELD(_p, _f)	((PREFIX_WORD(_p, _f) >> PREFIX_OFFSET_B(_f)) & \
				 PREFIX_WIDTH_MASK(_f))

void ef100_rx_write(struct efx_rx_queue *rx_queue)
#define ESF_GZ_RX_PREFIX_NT_OR_INNER_L3_CLASS_LBN	\
		(ESF_GZ_RX_PREFIX_CLASS_LBN + ESF_GZ_RX_PREFIX_HCLASS_NT_OR_INNER_L3_CLASS_LBN)
#define ESF_GZ_RX_PREFIX_NT_OR_INNER_L3_CLASS_WIDTH	\
		ESF_GZ_RX_PREFIX_HCLASS_NT_OR_INNER_L3_CLASS_WIDTH

static bool check_fcs(struct efx_channel *channel, u32 *prefix)
{
	u16 rxclass;
	u8 l2status;

	rxclass = le16_to_cpu((__force __le16)PREFIX_FIELD(prefix, CLASS));
	l2status = PREFIX_FIELD(&rxclass, HCLASS_L2_STATUS);

	if (likely(l2status == ESE_GZ_RH_HCLASS_L2_STATUS_OK))
		/* Everything is ok */
		return 0;

	if (l2status == ESE_GZ_RH_HCLASS_L2_STATUS_FCS_ERR)
		channel->n_rx_eth_crc_err++;
	return 1;
}

void __ef100_rx_packet(struct efx_channel *channel)
{
	/* Stub.  No RX path yet.  Discard the buffer. */
	struct efx_rx_buffer *rx_buf = efx_rx_buffer(&channel->rx_queue,
						     channel->rx_pkt_index);
	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
	struct efx_rx_buffer *rx_buf = efx_rx_buffer(&channel->rx_queue, channel->rx_pkt_index);
	struct efx_nic *efx = channel->efx;
	u8 *eh = efx_rx_buf_va(rx_buf);
	__wsum csum = 0;
	u32 *prefix;

	prefix = (u32 *)(eh - ESE_GZ_RX_PKT_PREFIX_LEN);

	if (check_fcs(channel, prefix) &&
	    unlikely(!(efx->net_dev->features & NETIF_F_RXALL)))
		goto out;

	rx_buf->len = le16_to_cpu((__force __le16)PREFIX_FIELD(prefix, LENGTH));
	if (rx_buf->len <= sizeof(struct ethhdr)) {
		if (net_ratelimit())
			netif_err(channel->efx, rx_err, channel->efx->net_dev,
				  "RX packet too small (%d)\n", rx_buf->len);
		++channel->n_rx_frm_trunc;
		goto out;
	}

	if (likely(efx->net_dev->features & NETIF_F_RXCSUM)) {
		if (PREFIX_FIELD(prefix, NT_OR_INNER_L3_CLASS) == 1) {
			++channel->n_rx_ip_hdr_chksum_err;
		} else {
			u16 sum = be16_to_cpu((__force __be16)PREFIX_FIELD(prefix, CSUM_FRAME));

			csum = (__force __wsum) sum;
		}
	}

	if (channel->type->receive_skb) {
		struct efx_rx_queue *rx_queue =
			efx_channel_get_rx_queue(channel);

		/* no support for special channels yet, so just discard */
		WARN_ON_ONCE(1);
		efx_free_rx_buffers(rx_queue, rx_buf, 1);
		goto out;
	}

	efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh, csum);

out:
	channel->rx_pkt_n_frags = 0;
}

static void ef100_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index)
{
	struct efx_rx_buffer *rx_buf = efx_rx_buffer(rx_queue, index);
	struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
	struct efx_nic *efx = rx_queue->efx;

	++rx_queue->rx_packets;

	netif_vdbg(efx, rx_status, efx->net_dev,
		   "RX queue %d received id %x\n",
		   efx_rx_queue_index(rx_queue), index);

	efx_sync_rx_buffer(efx, rx_buf, efx->rx_dma_len);

	prefetch(efx_rx_buf_va(rx_buf));

	rx_buf->page_offset += efx->rx_prefix_size;

	efx_recycle_rx_pages(channel, rx_buf, 1);

	efx_rx_flush_packet(channel);
	channel->rx_pkt_n_frags = 1;
	channel->rx_pkt_index = index;
}

void efx_ef100_ev_rx(struct efx_channel *channel, const efx_qword_t *p_event)
{
	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
	unsigned int n_packets =
		EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_RXPKTS_NUM_PKT);
	int i;

	WARN_ON_ONCE(!n_packets);
	if (n_packets > 1)
		++channel->n_rx_merge_events;

	channel->irq_mod_score += 2 * n_packets;

	for (i = 0; i < n_packets; ++i) {
		ef100_rx_packet(rx_queue,
				rx_queue->removed_count & rx_queue->ptr_mask);
		++rx_queue->removed_count;
	}
}

void ef100_rx_write(struct efx_rx_queue *rx_queue)
{
	struct efx_rx_buffer *rx_buf;
	unsigned int idx;
	efx_qword_t *rxd;
	efx_dword_t rxdb;

	while (rx_queue->notified_count != rx_queue->added_count) {
		idx = rx_queue->notified_count & rx_queue->ptr_mask;
		rx_buf = efx_rx_buffer(rx_queue, idx);
		rxd = efx_rx_desc(rx_queue, idx);

		EFX_POPULATE_QWORD_1(*rxd, ESF_GZ_RX_BUF_ADDR, rx_buf->dma_addr);

		++rx_queue->notified_count;
	}

	wmb();
	EFX_POPULATE_DWORD_1(rxdb, ERF_GZ_RX_RING_PIDX,
			     rx_queue->added_count & rx_queue->ptr_mask);
	efx_writed_page(rx_queue->efx, &rxdb,
			ER_GZ_RX_RING_DOORBELL, efx_rx_queue_index(rx_queue));
}
Loading