mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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: Stuart 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: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
		
							parent
							
								
									576eda8b08
								
							
						
					
					
						commit
						7c236c43b8
					
				
					 11 changed files with 1562 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -34,3 +34,10 @@ 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
sfc-$(CONFIG_SFC_MTD)	+= mtd.o
 | 
			
		||||
sfc-$(CONFIG_SFC_SRIOV)	+= siena_sriov.o
 | 
			
		||||
sfc-$(CONFIG_SFC_PTP)	+= ptp.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_SFC)	+= sfc.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 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 */
 | 
			
		||||
	if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
 | 
			
		||||
	    (data->phy_id & 0xfc00) == 0x0400)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1174,6 +1174,7 @@ const struct ethtool_ops efx_ethtool_ops = {
 | 
			
		|||
	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size,
 | 
			
		||||
	.get_rxfh_indir		= efx_ethtool_get_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_eeprom	= efx_ethtool_get_module_eeprom,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -578,6 +578,11 @@ void efx_mcdi_process_event(struct efx_channel *channel,
 | 
			
		|||
	case MCDI_EVENT_CODE_FLR:
 | 
			
		||||
		efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
 | 
			
		||||
		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:
 | 
			
		||||
		netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -289,6 +289,7 @@
 | 
			
		|||
#define          MCDI_EVENT_CODE_TX_FLUSH  0xc /* enum */
 | 
			
		||||
#define          MCDI_EVENT_CODE_PTP_RX  0xd /* 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_LBN 0
 | 
			
		||||
#define       MCDI_EVENT_CMDDONE_DATA_WIDTH 32
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,8 @@
 | 
			
		|||
#define EFX_MAX_CHANNELS 32U
 | 
			
		||||
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
 | 
			
		||||
#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
 | 
			
		||||
 * queue visible to the networking core is backed by two hardware TX
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +69,9 @@
 | 
			
		|||
#define EFX_TXQ_TYPES		4
 | 
			
		||||
#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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -736,6 +740,7 @@ struct vfdi_status;
 | 
			
		|||
 *	%local_addr_list. Protected by %local_lock.
 | 
			
		||||
 * @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
 | 
			
		||||
 * @monitor_work: Hardware monitor workitem
 | 
			
		||||
 * @biu_lock: BIU (bus interface unit) lock
 | 
			
		||||
 * @last_irq_cpu: Last CPU to handle a possible test interrupt.  This
 | 
			
		||||
| 
						 | 
				
			
			@ -863,6 +868,10 @@ 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 */
 | 
			
		||||
 | 
			
		||||
	struct delayed_work monitor_work ____cacheline_aligned_in_smp;
 | 
			
		||||
| 
						 | 
				
			
			@ -1125,5 +1134,13 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr)
 | 
			
		|||
#define EFX_MAX_FRAME_LEN(mtu) \
 | 
			
		||||
	((((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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
#ifndef EFX_NIC_H
 | 
			
		||||
#define EFX_NIC_H
 | 
			
		||||
 | 
			
		||||
#include <linux/net_tstamp.h>
 | 
			
		||||
#include <linux/i2c-algo-bit.h>
 | 
			
		||||
#include "net_driver.h"
 | 
			
		||||
#include "efx.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
				     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_b0_nic_type;
 | 
			
		||||
extern const struct efx_nic_type siena_a0_nic_type;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1483
									
								
								drivers/net/ethernet/sfc/ptp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1483
									
								
								drivers/net/ethernet/sfc/ptp.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -335,6 +335,7 @@ static int siena_probe_nic(struct efx_nic *efx)
 | 
			
		|||
		goto fail5;
 | 
			
		||||
 | 
			
		||||
	efx_sriov_probe(efx);
 | 
			
		||||
	efx_ptp_probe(efx);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -339,6 +339,12 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
 | 
			
		|||
 | 
			
		||||
	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);
 | 
			
		||||
	type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0;
 | 
			
		||||
	if (index >= efx->n_tx_channels) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue