Commit 7ed2a0d0 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next

Ben Hutchings says:

====================
1. Change PTP clock name to 'sfc'.
2. Complete support for hardware timestamping and PTP clock on the
SFC9100 family.
3. Various cleanups for the PTP code.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f52d81dc bbbe7149
......@@ -264,6 +264,8 @@ static int efx_ef10_probe(struct efx_nic *efx)
if (rc)
goto fail3;
efx_ptp_probe(efx, NULL);
return 0;
fail3:
......@@ -472,9 +474,10 @@ static void efx_ef10_remove(struct efx_nic *efx)
struct efx_ef10_nic_data *nic_data = efx->nic_data;
int rc;
efx_ptp_remove(efx);
efx_mcdi_mon_remove(efx);
/* This needs to be after efx_ptp_remove_channel() with no filters */
efx_ef10_rx_free_indir_table(efx);
if (nic_data->wc_membase)
......@@ -1469,8 +1472,9 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_LABEL, efx_rx_queue_index(rx_queue));
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_INSTANCE,
efx_rx_queue_index(rx_queue));
MCDI_POPULATE_DWORD_1(inbuf, INIT_RXQ_IN_FLAGS,
INIT_RXQ_IN_FLAG_PREFIX, 1);
MCDI_POPULATE_DWORD_2(inbuf, INIT_RXQ_IN_FLAGS,
INIT_RXQ_IN_FLAG_PREFIX, 1,
INIT_RXQ_IN_FLAG_TIMESTAMP, 1);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0);
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
......@@ -3406,6 +3410,119 @@ static void efx_ef10_ptp_write_host_time(struct efx_nic *efx, u32 host_time)
_efx_writed(efx, cpu_to_le32(host_time), ER_DZ_MC_DB_LWRD);
}
static int efx_ef10_rx_enable_timestamping(struct efx_channel *channel,
bool temp)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_LEN);
int rc;
if (channel->sync_events_state == SYNC_EVENTS_REQUESTED ||
channel->sync_events_state == SYNC_EVENTS_VALID ||
(temp && channel->sync_events_state == SYNC_EVENTS_DISABLED))
return 0;
channel->sync_events_state = SYNC_EVENTS_REQUESTED;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_TIME_EVENT_SUBSCRIBE);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE,
channel->channel);
rc = efx_mcdi_rpc(channel->efx, MC_CMD_PTP,
inbuf, sizeof(inbuf), NULL, 0, NULL);
if (rc != 0)
channel->sync_events_state = temp ? SYNC_EVENTS_QUIESCENT :
SYNC_EVENTS_DISABLED;
return rc;
}
static int efx_ef10_rx_disable_timestamping(struct efx_channel *channel,
bool temp)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_LEN);
int rc;
if (channel->sync_events_state == SYNC_EVENTS_DISABLED ||
(temp && channel->sync_events_state == SYNC_EVENTS_QUIESCENT))
return 0;
if (channel->sync_events_state == SYNC_EVENTS_QUIESCENT) {
channel->sync_events_state = SYNC_EVENTS_DISABLED;
return 0;
}
channel->sync_events_state = temp ? SYNC_EVENTS_QUIESCENT :
SYNC_EVENTS_DISABLED;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_TIME_EVENT_UNSUBSCRIBE);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_UNSUBSCRIBE_CONTROL,
MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_SINGLE);
MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_UNSUBSCRIBE_QUEUE,
channel->channel);
rc = efx_mcdi_rpc(channel->efx, MC_CMD_PTP,
inbuf, sizeof(inbuf), NULL, 0, NULL);
return rc;
}
static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en,
bool temp)
{
int (*set)(struct efx_channel *channel, bool temp);
struct efx_channel *channel;
set = en ?
efx_ef10_rx_enable_timestamping :
efx_ef10_rx_disable_timestamping;
efx_for_each_channel(channel, efx) {
int rc = set(channel, temp);
if (en && rc != 0) {
efx_ef10_ptp_set_ts_sync_events(efx, false, temp);
return rc;
}
}
return 0;
}
static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx,
struct hwtstamp_config *init)
{
int rc;
switch (init->rx_filter) {
case HWTSTAMP_FILTER_NONE:
efx_ef10_ptp_set_ts_sync_events(efx, false, false);
/* if TX timestamping is still requested then leave PTP on */
return efx_ptp_change_mode(efx,
init->tx_type != HWTSTAMP_TX_OFF, 0);
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
init->rx_filter = HWTSTAMP_FILTER_ALL;
rc = efx_ptp_change_mode(efx, true, 0);
if (!rc)
rc = efx_ef10_ptp_set_ts_sync_events(efx, true, false);
if (rc)
efx_ptp_change_mode(efx, false, 0);
return rc;
default:
return -ERANGE;
}
}
const struct efx_nic_type efx_hunt_a0_nic_type = {
.mem_map_size = efx_ef10_mem_map_size,
.probe = efx_ef10_probe,
......@@ -3484,11 +3601,14 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.mtd_sync = efx_mcdi_mtd_sync,
#endif
.ptp_write_host_time = efx_ef10_ptp_write_host_time,
.ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events,
.ptp_set_ts_config = efx_ef10_ptp_set_ts_config,
.revision = EFX_REV_HUNT_A0,
.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
.rx_prefix_size = ES_DZ_RX_PREFIX_SIZE,
.rx_hash_offset = ES_DZ_RX_PREFIX_HASH_OFST,
.rx_ts_offset = ES_DZ_RX_PREFIX_TSTAMP_OFST,
.can_rx_scatter = true,
.always_rx_scatter = true,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
......@@ -3497,4 +3617,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
NETIF_F_RXHASH | NETIF_F_NTUPLE),
.mcdi_max_ver = 2,
.max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
.hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
1 << HWTSTAMP_FILTER_ALL,
};
......@@ -1117,6 +1117,77 @@ static void efx_remove_port(struct efx_nic *efx)
*
**************************************************************************/
static LIST_HEAD(efx_primary_list);
static LIST_HEAD(efx_unassociated_list);
static bool efx_same_controller(struct efx_nic *left, struct efx_nic *right)
{
return left->type == right->type &&
left->vpd_sn && right->vpd_sn &&
!strcmp(left->vpd_sn, right->vpd_sn);
}
static void efx_associate(struct efx_nic *efx)
{
struct efx_nic *other, *next;
if (efx->primary == efx) {
/* Adding primary function; look for secondaries */
netif_dbg(efx, probe, efx->net_dev, "adding to primary list\n");
list_add_tail(&efx->node, &efx_primary_list);
list_for_each_entry_safe(other, next, &efx_unassociated_list,
node) {
if (efx_same_controller(efx, other)) {
list_del(&other->node);
netif_dbg(other, probe, other->net_dev,
"moving to secondary list of %s %s\n",
pci_name(efx->pci_dev),
efx->net_dev->name);
list_add_tail(&other->node,
&efx->secondary_list);
other->primary = efx;
}
}
} else {
/* Adding secondary function; look for primary */
list_for_each_entry(other, &efx_primary_list, node) {
if (efx_same_controller(efx, other)) {
netif_dbg(efx, probe, efx->net_dev,
"adding to secondary list of %s %s\n",
pci_name(other->pci_dev),
other->net_dev->name);
list_add_tail(&efx->node,
&other->secondary_list);
efx->primary = other;
return;
}
}
netif_dbg(efx, probe, efx->net_dev,
"adding to unassociated list\n");
list_add_tail(&efx->node, &efx_unassociated_list);
}
}
static void efx_dissociate(struct efx_nic *efx)
{
struct efx_nic *other, *next;
list_del(&efx->node);
efx->primary = NULL;
list_for_each_entry_safe(other, next, &efx->secondary_list, node) {
list_del(&other->node);
netif_dbg(other, probe, other->net_dev,
"moving to unassociated list\n");
list_add_tail(&other->node, &efx_unassociated_list);
other->primary = NULL;
}
}
/* This configures the PCI device to enable I/O and DMA. */
static int efx_init_io(struct efx_nic *efx)
{
......@@ -2214,6 +2285,8 @@ static int efx_register_netdev(struct efx_nic *efx)
efx_init_tx_queue_core_txq(tx_queue);
}
efx_associate(efx);
rtnl_unlock();
rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
......@@ -2227,6 +2300,7 @@ static int efx_register_netdev(struct efx_nic *efx)
fail_registered:
rtnl_lock();
efx_dissociate(efx);
unregister_netdevice(net_dev);
fail_locked:
efx->state = STATE_UNINIT;
......@@ -2568,6 +2642,8 @@ static int efx_init_struct(struct efx_nic *efx,
int i;
/* Initialise common structures */
INIT_LIST_HEAD(&efx->node);
INIT_LIST_HEAD(&efx->secondary_list);
spin_lock_init(&efx->biu_lock);
#ifdef CONFIG_SFC_MTD
INIT_LIST_HEAD(&efx->mtd_list);
......@@ -2586,6 +2662,8 @@ static int efx_init_struct(struct efx_nic *efx,
NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0;
efx->rx_packet_hash_offset =
efx->type->rx_hash_offset - efx->type->rx_prefix_size;
efx->rx_packet_ts_offset =
efx->type->rx_ts_offset - efx->type->rx_prefix_size;
spin_lock_init(&efx->stats_lock);
mutex_init(&efx->mac_lock);
efx->phy_op = &efx_dummy_phy_operations;
......@@ -2626,6 +2704,8 @@ static void efx_fini_struct(struct efx_nic *efx)
for (i = 0; i < EFX_MAX_CHANNELS; i++)
kfree(efx->channel[i]);
kfree(efx->vpd_sn);
if (efx->workqueue) {
destroy_workqueue(efx->workqueue);
efx->workqueue = NULL;
......@@ -2670,6 +2750,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
/* Mark the NIC as fini, then stop the interface */
rtnl_lock();
efx_dissociate(efx);
dev_close(efx->net_dev);
efx_disable_interrupts(efx);
rtnl_unlock();
......@@ -2696,12 +2777,12 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
* always appear within the first 512 bytes.
*/
#define SFC_VPD_LEN 512
static void efx_print_product_vpd(struct efx_nic *efx)
static void efx_probe_vpd_strings(struct efx_nic *efx)
{
struct pci_dev *dev = efx->pci_dev;
char vpd_data[SFC_VPD_LEN];
ssize_t vpd_size;
int i, j;
int ro_start, ro_size, i, j;
/* Get the vpd data from the device */
vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data);
......@@ -2711,14 +2792,15 @@ static void efx_print_product_vpd(struct efx_nic *efx)
}
/* Get the Read only section */
i = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA);
if (i < 0) {
ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA);
if (ro_start < 0) {
netif_err(efx, drv, efx->net_dev, "VPD Read-only not found\n");
return;
}
j = pci_vpd_lrdt_size(&vpd_data[i]);
i += PCI_VPD_LRDT_TAG_SIZE;
ro_size = pci_vpd_lrdt_size(&vpd_data[ro_start]);
j = ro_size;
i = ro_start + PCI_VPD_LRDT_TAG_SIZE;
if (i + j > vpd_size)
j = vpd_size - i;
......@@ -2738,6 +2820,27 @@ static void efx_print_product_vpd(struct efx_nic *efx)
netif_info(efx, drv, efx->net_dev,
"Part Number : %.*s\n", j, &vpd_data[i]);
i = ro_start + PCI_VPD_LRDT_TAG_SIZE;
j = ro_size;
i = pci_vpd_find_info_keyword(vpd_data, i, j, "SN");
if (i < 0) {
netif_err(efx, drv, efx->net_dev, "Serial number not found\n");
return;
}
j = pci_vpd_info_field_size(&vpd_data[i]);
i += PCI_VPD_INFO_FLD_HDR_SIZE;
if (i + j > vpd_size) {
netif_err(efx, drv, efx->net_dev, "Incomplete serial number\n");
return;
}
efx->vpd_sn = kmalloc(j + 1, GFP_KERNEL);
if (!efx->vpd_sn)
return;
snprintf(efx->vpd_sn, j + 1, "%s", &vpd_data[i]);
}
......@@ -2834,7 +2937,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
netif_info(efx, probe, efx->net_dev,
"Solarflare NIC detected\n");
efx_print_product_vpd(efx);
efx_probe_vpd_strings(efx);
/* Set up basic I/O (BAR mappings etc) */
rc = efx_init_io(efx);
......
......@@ -2247,6 +2247,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
struct falcon_board *board;
int rc;
efx->primary = efx; /* only one usable function per controller */
/* Allocate storage for hardware specific data */
nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
if (!nic_data)
......
......@@ -102,6 +102,10 @@ int efx_mcdi_init(struct efx_nic *efx)
netif_err(efx, probe, efx->net_dev,
"Host already registered with MCPU\n");
if (efx->mcdi->fn_flags &
(1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY))
efx->primary = efx;
return 0;
}
......@@ -1018,6 +1022,9 @@ void efx_mcdi_process_event(struct efx_channel *channel,
case MCDI_EVENT_CODE_PTP_PPS:
efx_ptp_event(efx, event);
break;
case MCDI_EVENT_CODE_PTP_TIME:
efx_time_sync_event(channel, event);
break;
case MCDI_EVENT_CODE_TX_FLUSH:
case MCDI_EVENT_CODE_RX_FLUSH:
/* Two flush events will be sent: one to the same event
......@@ -1132,13 +1139,27 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
goto fail;
}
if (driver_operating) {
if (outlen >= MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
efx->mcdi->fn_flags =
MCDI_DWORD(outbuf,
DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
} else {
/* Synthesise flags for Siena */
efx->mcdi->fn_flags =
1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED |
(efx_port_num(efx) == 0) <<
MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY;
}
}
/* We currently assume we have control of the external link
* and are completely trusted by firmware. Abort probing
* if that's not true for this function.
*/
if (driver_operating &&
outlen >= MC_CMD_DRV_ATTACH_EXT_OUT_LEN &&
(MCDI_DWORD(outbuf, DRV_ATTACH_EXT_OUT_FUNC_FLAGS) &
(efx->mcdi->fn_flags &
(1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) !=
(1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
......
......@@ -94,12 +94,14 @@ struct efx_mcdi_mtd_partition {
* struct efx_mcdi_data - extra state for NICs that implement MCDI
* @iface: Interface/protocol state
* @hwmon: Hardware monitor state
* @fn_flags: Flags for this function, as returned by %MC_CMD_DRV_ATTACH.
*/
struct efx_mcdi_data {
struct efx_mcdi_iface iface;
#ifdef CONFIG_SFC_MCDI_MON
struct efx_mcdi_mon hwmon;
#endif
u32 fn_flags;
};
#ifdef CONFIG_SFC_MCDI_MON
......
......@@ -91,6 +91,7 @@
/* Forward declare Precision Time Protocol (PTP) support structure. */
struct efx_ptp_data;
struct hwtstamp_config;
struct efx_self_tests;
......@@ -368,6 +369,13 @@ enum efx_rx_alloc_method {
RX_ALLOC_METHOD_PAGE = 2,
};
enum efx_sync_events_state {
SYNC_EVENTS_DISABLED = 0,
SYNC_EVENTS_QUIESCENT,
SYNC_EVENTS_REQUESTED,
SYNC_EVENTS_VALID,
};
/**
* struct efx_channel - An Efx channel
*
......@@ -407,6 +415,9 @@ enum efx_rx_alloc_method {
* by __efx_rx_packet(), if @rx_pkt_n_frags != 0
* @rx_queue: RX queue for this channel
* @tx_queue: TX queues for this channel
* @sync_events_state: Current state of sync events on this channel
* @sync_timestamp_major: Major part of the last ptp sync event
* @sync_timestamp_minor: Minor part of the last ptp sync event
*/
struct efx_channel {
struct efx_nic *efx;
......@@ -445,6 +456,10 @@ struct efx_channel {
struct efx_rx_queue rx_queue;
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES];
enum efx_sync_events_state sync_events_state;
u32 sync_timestamp_major;
u32 sync_timestamp_minor;
};
/**
......@@ -520,15 +535,6 @@ enum nic_state {
STATE_RECOVERY = 3, /* device recovering from PCI error */
};
/*
* Alignment of the skb->head which wraps a page-allocated RX buffer
*
* The skb allocated to wrap an rx_buffer can have this alignment. Since
* the data is memcpy'd from the rx_buf, it does not need to be equal to
* NET_IP_ALIGN.
*/
#define EFX_PAGE_SKB_ALIGN 2
/* Forward declaration */
struct efx_nic;
......@@ -651,6 +657,13 @@ struct vfdi_status;
* struct efx_nic - an Efx NIC
* @name: Device name (net device name or bus id before net device registered)
* @pci_dev: The PCI device
* @node: List node for maintaning primary/secondary function lists
* @primary: &struct efx_nic instance for the primary function of this
* controller. May be the same structure, and may be %NULL if no
* primary function is bound. Serialised by rtnl_lock.
* @secondary_list: List of &struct efx_nic instances for the secondary PCI
* functions of the controller, if this is for the primary function.
* Serialised by rtnl_lock.
* @type: Controller type attributes
* @legacy_irq: IRQ number
* @workqueue: Workqueue for port reconfigures and the HW monitor.
......@@ -694,6 +707,8 @@ struct vfdi_status;
* (valid only if @rx_prefix_size != 0; always negative)
* @rx_packet_len_offset: Offset of RX packet length from start of packet data
* (valid only for NICs that set %EFX_RX_PKT_PREFIX_LEN; always negative)
* @rx_packet_ts_offset: Offset of timestamp from start of packet data
* (valid only if channel->sync_timestamps_enabled; always negative)
* @rx_hash_key: Toeplitz hash key for RSS
* @rx_indir_table: Indirection table for RSS
* @rx_scatter: Scatter mode enabled for receives
......@@ -763,6 +778,7 @@ struct vfdi_status;
* @local_lock: Mutex protecting %local_addr_list and %local_page_list.
* @peer_work: Work item to broadcast peer addresses to VMs.
* @ptp_data: PTP state data
* @vpd_sn: Serial number read from VPD
* @monitor_work: Hardware monitor workitem
* @biu_lock: BIU (bus interface unit) lock
* @last_irq_cpu: Last CPU to handle a possible test interrupt. This
......@@ -777,6 +793,9 @@ struct efx_nic {
/* The following fields should be written very rarely */
char name[IFNAMSIZ];
struct list_head node;
struct efx_nic *primary;
struct list_head secondary_list;
struct pci_dev *pci_dev;
unsigned int port_num;
const struct efx_nic_type *type;
......@@ -828,6 +847,7 @@ struct efx_nic {
unsigned int rx_prefix_size;
int rx_packet_hash_offset;
int rx_packet_len_offset;
int rx_packet_ts_offset;
u8 rx_hash_key[40];
u32 rx_indir_table[128];
bool rx_scatter;
......@@ -911,6 +931,8 @@ struct efx_nic {
struct efx_ptp_data *ptp_data;
char *vpd_sn;
/* The following fields may be written more often */
struct delayed_work monitor_work ____cacheline_aligned_in_smp;
......@@ -1042,6 +1064,12 @@ struct efx_mtd_partition {
* @mtd_sync: Wait for write-back to complete on MTD partition. This
* also notifies the driver that a writer has finished using this
* partition.
* @ptp_write_host_time: Send host time to MC as part of sync protocol
* @ptp_set_ts_sync_events: Enable or disable sync events for inline RX
* timestamping, possibly only temporarily for the purposes of a reset.
* @ptp_set_ts_config: Set hardware timestamp configuration. The flags
* and tx_type will already have been validated but this operation
* must validate and update rx_filter.
* @revision: Hardware architecture revision
* @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address
......@@ -1051,6 +1079,7 @@ struct efx_mtd_partition {
* @max_dma_mask: Maximum possible DMA mask
* @rx_prefix_size: Size of RX prefix before packet data
* @rx_hash_offset: Offset of RX flow hash within prefix
* @rx_ts_offset: Offset of timestamp within prefix
* @rx_buffer_padding: Size of padding at end of RX packet
* @can_rx_scatter: NIC is able to scatter packets to multiple buffers
* @always_rx_scatter: NIC will always scatter packets to multiple buffers
......@@ -1060,6 +1089,7 @@ struct efx_mtd_partition {
* @offload_features: net_device feature flags for protocol offload
* features implemented in hardware
* @mcdi_max_ver: Maximum MCDI version supported
* @hwtstamp_filters: Mask of hardware timestamp filter types supported
*/
struct efx_nic_type {
unsigned int (*mem_map_size)(struct efx_nic *efx);
......@@ -1161,6 +1191,9 @@ struct efx_nic_type {
int (*mtd_sync)(struct mtd_info *mtd);
#endif
void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time);
int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp);
int (*ptp_set_ts_config)(struct efx_nic *efx,
struct hwtstamp_config *init);
int revision;
unsigned int txd_ptr_tbl_base;
......@@ -1171,6 +1204,7 @@ struct efx_nic_type {
u64 max_dma_mask;
unsigned int rx_prefix_size;
unsigned int rx_hash_offset;
unsigned int rx_ts_offset;
unsigned int rx_buffer_padding;
bool can_rx_scatter;
bool always_rx_scatter;
......@@ -1179,6 +1213,7 @@ struct efx_nic_type {
netdev_features_t offload_features;
int mcdi_max_ver;
unsigned int max_rx_ip_filters;
u32 hwtstamp_filters;
};
/**************************************************************************
......
......@@ -561,8 +561,20 @@ int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info);
bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
int efx_ptp_get_mode(struct efx_nic *efx);
int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
unsigned int new_mode);
int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev);
void __efx_rx_skb_attach_timestamp(struct efx_channel *channel,
struct sk_buff *skb);
static inline void efx_rx_skb_attach_timestamp(struct efx_channel *channel,
struct sk_buff *skb)
{
if (channel->sync_events_state == SYNC_EVENTS_VALID)
__efx_rx_skb_attach_timestamp(channel, skb);
}
void efx_ptp_start_datapath(struct efx_nic *efx);
void efx_ptp_stop_datapath(struct efx_nic *efx);
......
This diff is collapsed.
......@@ -476,14 +476,18 @@ static struct sk_buff *efx_rx_mk_skb(struct efx_channel *channel,
struct sk_buff *skb;
/* Allocate an SKB to store the headers */
skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
skb = netdev_alloc_skb(efx->net_dev,
efx->rx_ip_align + efx->rx_prefix_size +
hdr_len);
if (unlikely(skb == NULL))
return NULL;
EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
memcpy(__skb_put(skb, hdr_len), eh, hdr_len);
memcpy(skb->data + efx->rx_ip_align, eh - efx->rx_prefix_size,
efx->rx_prefix_size + hdr_len);
skb_reserve(skb, efx->rx_ip_align + efx->rx_prefix_size);
__skb_put(skb, hdr_len);
/* Append the remaining page(s) onto the frag list */
if (rx_buf->len > hdr_len) {
......@@ -620,6 +624,8 @@ static void efx_rx_deliver(struct efx_channel *channel, u8 *eh,
if (likely(rx_buf->flags & EFX_RX_PKT_CSUMMED))
skb->ip_summed = CHECKSUM_UNNECESSARY;
efx_rx_skb_attach_timestamp(channel, skb);
if (channel->type->receive_skb)
if (channel->type->receive_skb(channel, skb))
return;
......
......@@ -116,6 +116,54 @@ static int siena_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
return rc ? rc : rc2;
}
/**************************************************************************
*
* PTP
*
**************************************************************************
*/
static void siena_ptp_write_host_time(struct efx_nic *efx, u32 host_time)
{
_efx_writed(efx, cpu_to_le32(host_time),
FR_CZ_MC_TREG_SMEM + MC_SMEM_P0_PTP_TIME_OFST);
}
static int siena_ptp_set_ts_config(struct efx_nic *efx,
struct hwtstamp_config *init)
{
int rc;
switch (init->rx_filter) {
case HWTSTAMP_FILTER_NONE:
/* if TX timestamping is still requested then leave PTP on */
return efx_ptp_change_mode(efx,
init->tx_type != HWTSTAMP_TX_OFF,
efx_ptp_get_mode(efx));
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
init->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
return efx_ptp_change_mode(efx, true, MC_CMD_PTP_MODE_V1);
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
rc = efx_ptp_change_mode(efx, true,
MC_CMD_PTP_MODE_V2_ENHANCED);
/* bug 33070 - old versions of the firmware do not support the
* improved UUID filtering option. Similarly old versions of the
* application do not expect it to be enabled. If the firmware
* does not accept the enhanced mode, fall back to the standard
* PTP v2 UUID filtering. */
if (rc != 0)
rc = efx_ptp_change_mode(efx, true, MC_CMD_PTP_MODE_V2);
return rc;
default:
return -ERANGE;
}
}
/**************************************************************************
*
* Device reset
......@@ -837,19 +885,6 @@ static int siena_mtd_probe(struct efx_nic *efx)
#endif /* CONFIG_SFC_MTD */
/**************************************************************************
*
* PTP
*
**************************************************************************
*/
static void siena_ptp_write_host_time(struct efx_nic *efx, u32 host_time)
{
_efx_writed(efx, cpu_to_le32(host_time),
FR_CZ_MC_TREG_SMEM + MC_SMEM_P0_PTP_TIME_OFST);
}
/**************************************************************************
*
* Revision-dependent attributes used by efx.c and nic.c
......@@ -942,6 +977,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.mtd_sync = efx_mcdi_mtd_sync,
#endif
.ptp_write_host_time = siena_ptp_write_host_time,
.ptp_set_ts_config = siena_ptp_set_ts_config,
.revision = EFX_REV_SIENA_A0,
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
......@@ -960,4 +996,11 @@ const struct efx_nic_type siena_a0_nic_type = {
NETIF_F_RXHASH | NETIF_F_NTUPLE),
.mcdi_max_ver = 1,
.max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS,
.hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE |
1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT |
1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC |
1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ |
1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT |
1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC |
1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ),
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment