Skip to content

Commit

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

Ben Hutchings says:

====================
SIOCGHWTSTAMP ioctl

1. Add the SIOCGHWTSTAMP ioctl and update the timestamping
documentation.
2. Implement SIOCGHWTSTAMP in most drivers that support SIOCSHWTSTAMP.
3. Add a test program to exercise SIOC{G,S}HWTSTAMP.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Dec 6, 2013
2 parents e1ca87b + a4bcc79 commit 426e1fa
Show file tree
Hide file tree
Showing 23 changed files with 423 additions and 100 deletions.
9 changes: 7 additions & 2 deletions Documentation/networking/timestamping.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support
by the network device and will be empty without that support.


SIOCSHWTSTAMP:
SIOCSHWTSTAMP, SIOCGHWTSTAMP:

Hardware time stamping must also be initialized for each device driver
that is expected to do hardware time stamping. The parameter is defined in
Expand Down Expand Up @@ -115,6 +115,10 @@ Only a processes with admin rights may change the configuration. User
space is responsible to ensure that multiple processes don't interfere
with each other and that the settings are reset.

Any process can read the actual configuration by passing this
structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has
not been implemented in all drivers.

/* possible values for hwtstamp_config->tx_type */
enum {
/*
Expand Down Expand Up @@ -157,7 +161,8 @@ DEVICE IMPLEMENTATION

A driver which supports hardware time stamping must support the
SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
the actual values as described in the section on SIOCSHWTSTAMP.
the actual values as described in the section on SIOCSHWTSTAMP. It
should also support SIOCGHWTSTAMP.

Time stamps for received packets must be stored in the skb. To get a pointer
to the shared time stamp structure of the skb call skb_hwtstamps(). Then
Expand Down
1 change: 1 addition & 0 deletions Documentation/networking/timestamping/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
timestamping
hwtstamp_config
5 changes: 3 additions & 2 deletions Documentation/networking/timestamping/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
obj- := dummy.o

# List of programs to build
hostprogs-y := timestamping
hostprogs-y := timestamping hwtstamp_config

# Tell kbuild to always build the programs
always := $(hostprogs-y)

HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include

clean:
rm -f timestamping
rm -f timestamping hwtstamp_config
134 changes: 134 additions & 0 deletions Documentation/networking/timestamping/hwtstamp_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* Test program for SIOC{G,S}HWTSTAMP
* Copyright 2013 Solarflare Communications
* Author: Ben Hutchings
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/if.h>
#include <linux/net_tstamp.h>
#include <linux/sockios.h>

static int
lookup_value(const char **names, int size, const char *name)
{
int value;

for (value = 0; value < size; value++)
if (names[value] && strcasecmp(names[value], name) == 0)
return value;

return -1;
}

static const char *
lookup_name(const char **names, int size, int value)
{
return (value >= 0 && value < size) ? names[value] : NULL;
}

static void list_names(FILE *f, const char **names, int size)
{
int value;

for (value = 0; value < size; value++)
if (names[value])
fprintf(f, " %s\n", names[value]);
}

static const char *tx_types[] = {
#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
TX_TYPE(OFF),
TX_TYPE(ON),
TX_TYPE(ONESTEP_SYNC)
#undef TX_TYPE
};
#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))

static const char *rx_filters[] = {
#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
RX_FILTER(NONE),
RX_FILTER(ALL),
RX_FILTER(SOME),
RX_FILTER(PTP_V1_L4_EVENT),
RX_FILTER(PTP_V1_L4_SYNC),
RX_FILTER(PTP_V1_L4_DELAY_REQ),
RX_FILTER(PTP_V2_L4_EVENT),
RX_FILTER(PTP_V2_L4_SYNC),
RX_FILTER(PTP_V2_L4_DELAY_REQ),
RX_FILTER(PTP_V2_L2_EVENT),
RX_FILTER(PTP_V2_L2_SYNC),
RX_FILTER(PTP_V2_L2_DELAY_REQ),
RX_FILTER(PTP_V2_EVENT),
RX_FILTER(PTP_V2_SYNC),
RX_FILTER(PTP_V2_DELAY_REQ),
#undef RX_FILTER
};
#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))

static void usage(void)
{
fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
"tx_type is any of (case-insensitive):\n",
stderr);
list_names(stderr, tx_types, N_TX_TYPES);
fputs("rx_filter is any of (case-insensitive):\n", stderr);
list_names(stderr, rx_filters, N_RX_FILTERS);
}

int main(int argc, char **argv)
{
struct ifreq ifr;
struct hwtstamp_config config;
const char *name;
int sock;

if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
usage();
return 2;
}

if (argc == 4) {
config.flags = 0;
config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
if (config.tx_type < 0 || config.rx_filter < 0) {
usage();
return 2;
}
}

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return 1;
}

strcpy(ifr.ifr_name, argv[1]);
ifr.ifr_data = (caddr_t)&config;

if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
perror("ioctl");
return 1;
}

printf("flags = %#x\n", config.flags);
name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
if (name)
printf("tx_type = %s\n", name);
else
printf("tx_type = %d\n", config.tx_type);
name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
if (name)
printf("rx_filter = %s\n", name);
else
printf("rx_filter = %d\n", config.rx_filter);

return 0;
}
21 changes: 17 additions & 4 deletions drivers/net/ethernet/adi/bfin_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,8 @@ static u32 bfin_select_phc_clock(u32 input_clk, unsigned int *shift_result)
return 1000000000UL / ppn;
}

static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
static int bfin_mac_hwtstamp_set(struct net_device *netdev,
struct ifreq *ifr)
{
struct hwtstamp_config config;
struct bfin_mac_local *lp = netdev_priv(netdev);
Expand Down Expand Up @@ -824,6 +824,16 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
-EFAULT : 0;
}

static int bfin_mac_hwtstamp_get(struct net_device *netdev,
struct ifreq *ifr)
{
struct bfin_mac_local *lp = netdev_priv(netdev);

return copy_to_user(ifr->ifr_data, &lp->stamp_cfg,
sizeof(lp->stamp_cfg)) ?
-EFAULT : 0;
}

static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
Expand Down Expand Up @@ -1062,7 +1072,8 @@ static void bfin_phc_release(struct bfin_mac_local *lp)
#else
# define bfin_mac_hwtstamp_is_none(cfg) 0
# define bfin_mac_hwtstamp_init(dev)
# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
# define bfin_mac_hwtstamp_set(dev, ifr) (-EOPNOTSUPP)
# define bfin_mac_hwtstamp_get(dev, ifr) (-EOPNOTSUPP)
# define bfin_rx_hwtstamp(dev, skb)
# define bfin_tx_hwtstamp(dev, skb)
# define bfin_phc_init(netdev, dev) 0
Expand Down Expand Up @@ -1496,7 +1507,9 @@ static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)

switch (cmd) {
case SIOCSHWTSTAMP:
return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd);
return bfin_mac_hwtstamp_set(netdev, ifr);
case SIOCGHWTSTAMP:
return bfin_mac_hwtstamp_get(netdev, ifr);
default:
if (lp->phydev)
return phy_mii_ioctl(lp->phydev, ifr, cmd);
Expand Down
71 changes: 67 additions & 4 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -13594,14 +13594,13 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,

}

static int tg3_hwtstamp_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
{
struct tg3 *tp = netdev_priv(dev);
struct hwtstamp_config stmpconf;

if (!tg3_flag(tp, PTP_CAPABLE))
return -EINVAL;
return -EOPNOTSUPP;

if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
return -EFAULT;
Expand Down Expand Up @@ -13682,6 +13681,67 @@ static int tg3_hwtstamp_ioctl(struct net_device *dev,
-EFAULT : 0;
}

static int tg3_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
{
struct tg3 *tp = netdev_priv(dev);
struct hwtstamp_config stmpconf;

if (!tg3_flag(tp, PTP_CAPABLE))
return -EOPNOTSUPP;

stmpconf.flags = 0;
stmpconf.tx_type = (tg3_flag(tp, TX_TSTAMP_EN) ?
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF);

switch (tp->rxptpctl) {
case 0:
stmpconf.rx_filter = HWTSTAMP_FILTER_NONE;
break;
case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_ALL_V1_EVENTS:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_SYNC_EVNT:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
break;
case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_DELAY_REQ:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_SYNC_EVNT:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_SYNC_EVNT:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_SYNC_EVNT:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_DELAY_REQ:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_DELAY_REQ:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ;
break;
case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_DELAY_REQ:
stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
break;
default:
WARN_ON_ONCE(1);
return -ERANGE;
}

return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
-EFAULT : 0;
}

static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
Expand Down Expand Up @@ -13735,7 +13795,10 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;

case SIOCSHWTSTAMP:
return tg3_hwtstamp_ioctl(dev, ifr, cmd);
return tg3_hwtstamp_set(dev, ifr);

case SIOCGHWTSTAMP:
return tg3_hwtstamp_get(dev, ifr);

default:
/* do nothing */
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/freescale/fec.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,8 @@ struct fec_enet_private {

void fec_ptp_init(struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);

/****************************************************************************/
#endif /* FEC_H */
8 changes: 6 additions & 2 deletions drivers/net/ethernet/freescale/fec_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1683,8 +1683,12 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;

if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex)
return fec_ptp_ioctl(ndev, rq, cmd);
if (fep->bufdesc_ex) {
if (cmd == SIOCSHWTSTAMP)
return fec_ptp_set(ndev, rq);
if (cmd == SIOCGHWTSTAMP)
return fec_ptp_get(ndev, rq);
}

return phy_mii_ioctl(phydev, rq, cmd);
}
Expand Down
16 changes: 15 additions & 1 deletion drivers/net/ethernet/freescale/fec_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
* @ifreq: ioctl data
* @cmd: particular ioctl requested
*/
int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
{
struct fec_enet_private *fep = netdev_priv(ndev);

Expand Down Expand Up @@ -321,6 +321,20 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
-EFAULT : 0;
}

int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct hwtstamp_config config;

config.flags = 0;
config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
config.rx_filter = (fep->hwts_rx_en ?
HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);

return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}

/**
* fec_time_keep - call timecounter_read every second to avoid timer overrun
* because ENET just support 32bit counter, will timeout in 4s
Expand Down
Loading

0 comments on commit 426e1fa

Please sign in to comment.