Commit 7c236c43 authored by Stuart Hodgson's avatar Stuart Hodgson Committed by Ben Hutchings

sfc: Add support for IEEE-1588 PTP

Add PTP IEEE-1588 support and make accesible via the PHC subsystem.

This work is based on prior code by Andrew Jackson
Signed-off-by: default avatarStuart Hodgson <smhodgson@solarflare.com>
[bwh:
 - Add byte order conversion in efx_ptp_send_times()
 - Simplify conversion of PPS event times
 - Add the built-in vs module check to CONFIG_SFC_PTP dependencies]
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 576eda8b
...@@ -34,3 +34,10 @@ config SFC_SRIOV ...@@ -34,3 +34,10 @@ config SFC_SRIOV
This enables support for the SFC9000 I/O Virtualization This enables support for the SFC9000 I/O Virtualization
features, allowing accelerated network performance in features, allowing accelerated network performance in
virtualized environments. 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
...@@ -5,5 +5,6 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \ ...@@ -5,5 +5,6 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
mcdi.o mcdi_phy.o mcdi_mon.o mcdi.o mcdi_phy.o mcdi_mon.o
sfc-$(CONFIG_SFC_MTD) += mtd.o sfc-$(CONFIG_SFC_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o
sfc-$(CONFIG_SFC_PTP) += ptp.o
obj-$(CONFIG_SFC) += sfc.o obj-$(CONFIG_SFC) += sfc.o
...@@ -1779,6 +1779,9 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) ...@@ -1779,6 +1779,9 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
struct efx_nic *efx = netdev_priv(net_dev); struct efx_nic *efx = netdev_priv(net_dev);
struct mii_ioctl_data *data = if_mii(ifr); struct mii_ioctl_data *data = if_mii(ifr);
if (cmd == SIOCSHWTSTAMP)
return efx_ptp_ioctl(efx, ifr, cmd);
/* Convert phy_id from older PRTAD/DEVAD format */ /* Convert phy_id from older PRTAD/DEVAD format */
if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
(data->phy_id & 0xfc00) == 0x0400) (data->phy_id & 0xfc00) == 0x0400)
......
...@@ -1174,6 +1174,7 @@ const struct ethtool_ops efx_ethtool_ops = { ...@@ -1174,6 +1174,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_indir = efx_ethtool_get_rxfh_indir, .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
.set_rxfh_indir = efx_ethtool_set_rxfh_indir, .set_rxfh_indir = efx_ethtool_set_rxfh_indir,
.get_ts_info = efx_ptp_get_ts_info,
.get_module_info = efx_ethtool_get_module_info, .get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom, .get_module_eeprom = efx_ethtool_get_module_eeprom,
}; };
...@@ -578,6 +578,11 @@ void efx_mcdi_process_event(struct efx_channel *channel, ...@@ -578,6 +578,11 @@ void efx_mcdi_process_event(struct efx_channel *channel,
case MCDI_EVENT_CODE_FLR: case MCDI_EVENT_CODE_FLR:
efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF)); efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
break; break;
case MCDI_EVENT_CODE_PTP_RX:
case MCDI_EVENT_CODE_PTP_FAULT:
case MCDI_EVENT_CODE_PTP_PPS:
efx_ptp_event(efx, event);
break;
default: default:
netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n", netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
......
...@@ -289,6 +289,7 @@ ...@@ -289,6 +289,7 @@
#define MCDI_EVENT_CODE_TX_FLUSH 0xc /* enum */ #define MCDI_EVENT_CODE_TX_FLUSH 0xc /* enum */
#define MCDI_EVENT_CODE_PTP_RX 0xd /* enum */ #define MCDI_EVENT_CODE_PTP_RX 0xd /* enum */
#define MCDI_EVENT_CODE_PTP_FAULT 0xe /* enum */ #define MCDI_EVENT_CODE_PTP_FAULT 0xe /* enum */
#define MCDI_EVENT_CODE_PTP_PPS 0xf /* enum */
#define MCDI_EVENT_CMDDONE_DATA_OFST 0 #define MCDI_EVENT_CMDDONE_DATA_OFST 0
#define MCDI_EVENT_CMDDONE_DATA_LBN 0 #define MCDI_EVENT_CMDDONE_DATA_LBN 0
#define MCDI_EVENT_CMDDONE_DATA_WIDTH 32 #define MCDI_EVENT_CMDDONE_DATA_WIDTH 32
......
...@@ -56,7 +56,8 @@ ...@@ -56,7 +56,8 @@
#define EFX_MAX_CHANNELS 32U #define EFX_MAX_CHANNELS 32U
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
#define EFX_EXTRA_CHANNEL_IOV 0 #define EFX_EXTRA_CHANNEL_IOV 0
#define EFX_MAX_EXTRA_CHANNELS 1U #define EFX_EXTRA_CHANNEL_PTP 1
#define EFX_MAX_EXTRA_CHANNELS 2U
/* Checksum generation is a per-queue option in hardware, so each /* Checksum generation is a per-queue option in hardware, so each
* queue visible to the networking core is backed by two hardware TX * queue visible to the networking core is backed by two hardware TX
...@@ -68,6 +69,9 @@ ...@@ -68,6 +69,9 @@
#define EFX_TXQ_TYPES 4 #define EFX_TXQ_TYPES 4
#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) #define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS)
/* Forward declare Precision Time Protocol (PTP) support structure. */
struct efx_ptp_data;
struct efx_self_tests; struct efx_self_tests;
/** /**
...@@ -736,6 +740,7 @@ struct vfdi_status; ...@@ -736,6 +740,7 @@ struct vfdi_status;
* %local_addr_list. Protected by %local_lock. * %local_addr_list. Protected by %local_lock.
* @local_lock: Mutex protecting %local_addr_list and %local_page_list. * @local_lock: Mutex protecting %local_addr_list and %local_page_list.
* @peer_work: Work item to broadcast peer addresses to VMs. * @peer_work: Work item to broadcast peer addresses to VMs.
* @ptp_data: PTP state data
* @monitor_work: Hardware monitor workitem * @monitor_work: Hardware monitor workitem
* @biu_lock: BIU (bus interface unit) lock * @biu_lock: BIU (bus interface unit) lock
* @last_irq_cpu: Last CPU to handle a possible test interrupt. This * @last_irq_cpu: Last CPU to handle a possible test interrupt. This
...@@ -863,6 +868,10 @@ struct efx_nic { ...@@ -863,6 +868,10 @@ struct efx_nic {
struct work_struct peer_work; struct work_struct peer_work;
#endif #endif
#ifdef CONFIG_SFC_PTP
struct efx_ptp_data *ptp_data;
#endif
/* The following fields may be written more often */ /* The following fields may be written more often */
struct delayed_work monitor_work ____cacheline_aligned_in_smp; struct delayed_work monitor_work ____cacheline_aligned_in_smp;
...@@ -1125,5 +1134,13 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr) ...@@ -1125,5 +1134,13 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr)
#define EFX_MAX_FRAME_LEN(mtu) \ #define EFX_MAX_FRAME_LEN(mtu) \
((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16) ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16)
static inline bool efx_xmit_with_hwtstamp(struct sk_buff *skb)
{
return skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP;
}
static inline void efx_xmit_hwtstamp_pending(struct sk_buff *skb)
{
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
}
#endif /* EFX_NET_DRIVER_H */ #endif /* EFX_NET_DRIVER_H */
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#ifndef EFX_NIC_H #ifndef EFX_NIC_H
#define EFX_NIC_H #define EFX_NIC_H
#include <linux/net_tstamp.h>
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include "net_driver.h" #include "net_driver.h"
#include "efx.h" #include "efx.h"
...@@ -250,6 +251,41 @@ extern int efx_sriov_get_vf_config(struct net_device *dev, int vf, ...@@ -250,6 +251,41 @@ extern int efx_sriov_get_vf_config(struct net_device *dev, int vf,
extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf, extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
bool spoofchk); 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,
struct ethtool_ts_info *ts_info);
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_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type; extern const struct efx_nic_type falcon_b0_nic_type;
extern const struct efx_nic_type siena_a0_nic_type; extern const struct efx_nic_type siena_a0_nic_type;
......
This diff is collapsed.
...@@ -335,6 +335,7 @@ static int siena_probe_nic(struct efx_nic *efx) ...@@ -335,6 +335,7 @@ static int siena_probe_nic(struct efx_nic *efx)
goto fail5; goto fail5;
efx_sriov_probe(efx); efx_sriov_probe(efx);
efx_ptp_probe(efx);
return 0; return 0;
......
...@@ -339,6 +339,12 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, ...@@ -339,6 +339,12 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); EFX_WARN_ON_PARANOID(!netif_device_present(net_dev));
/* PTP "event" packet */
if (unlikely(efx_xmit_with_hwtstamp(skb)) &&
unlikely(efx_ptp_is_ptp_tx(efx, skb))) {
return efx_ptp_tx(efx, skb);
}
index = skb_get_queue_mapping(skb); index = skb_get_queue_mapping(skb);
type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0;
if (index >= efx->n_tx_channels) { if (index >= efx->n_tx_channels) {
......
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