>From fc396501b8d0906253b1f85945b86da4130ee665 Mon Sep 17 00:00:00 2001 From: Christopher Zimmermann Date: Wed, 7 Oct 2009 17:28:26 +0200 Subject: [PATCH 3/3] Change kernel timestamping interface Allow userspace to fine-tune hardware registers. Stay backwards compatible to old userspace? --- .gitignore | 1 + drivers/net/igb/e1000_regs.h | 41 ++++++++++-------- drivers/net/igb/igb_main.c | 95 +++++++++++++++++++++++++---------------- include/linux/net_tstamp.h | 35 +++++++++++---- 4 files changed, 107 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index b93fb7e..6fac88c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ # # Top-level generic files # +debian tags TAGS vmlinux diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 6e59245..1785b30 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -83,30 +83,33 @@ #define E1000_TSYNCRXCTL_VALID (1<<0) #define E1000_TSYNCRXCTL_ENABLED (1<<4) enum { + /* bits 1 to 3 need leftshift <<1 for direct register access. */ E1000_TSYNCRXCTL_TYPE_L2_V2 = 0, - E1000_TSYNCRXCTL_TYPE_L4_V1 = (1<<1), - E1000_TSYNCRXCTL_TYPE_L2_L4_V2 = (1<<2), - E1000_TSYNCRXCTL_TYPE_ALL = (1<<3), - E1000_TSYNCRXCTL_TYPE_EVENT_V2 = (1<<3) | (1<<1), + E1000_TSYNCRXCTL_TYPE_L4_V1 = (1<<0), + E1000_TSYNCRXCTL_TYPE_L2_L4_V2 = (1<<1), + E1000_TSYNCRXCTL_TYPE_ALL = (1<<2), + E1000_TSYNCRXCTL_TYPE_EVENT_V2 = (1<<2) | (1<<0), }; #define E1000_TSYNCRXCFG 0x05F50 enum { - E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE = 0<<0, - E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE = 1<<0, - E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE = 2<<0, - E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE = 3<<0, - E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE = 4<<0, + /* bits 0 to 7 */ + E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE = 0, + E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE = 1, + E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE = 2, + E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE = 3, + E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE = 4, - E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE = 0<<8, - E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE = 1<<8, - E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE = 2<<8, - E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE = 3<<8, - E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE = 8<<8, - E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE = 9<<8, - E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE = 0xA<<8, - E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE = 0xB<<8, - E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE = 0xC<<8, - E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE = 0xD<<8, + /* bits 8 to 11 need leftshift <<8 for direct register access */ + E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE = 0, + E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE = 1, + E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE = 2, + E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE = 3, + E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE = 8, + E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE = 9, + E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE = 0xA, + E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE = 0xB, + E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE = 0xC, + E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE = 0xD, }; #define E1000_SYSTIML 0x0B600 #define E1000_SYSTIMH 0x0B604 diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index adb09d3..17bfd5b 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1512,7 +1512,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, wr32(E1000_TIMINCA, (1<<24) | IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS * IGB_TSYNC_SCALE); -#if 0 +#if 1 /* * Avoid rollover while we initialize by resetting the time counter. */ @@ -4881,28 +4881,33 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct hwtstamp_config config; +#if 0 u32 tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED; u32 tsync_rx_ctl_bit = E1000_TSYNCRXCTL_ENABLED; u32 tsync_rx_ctl_type = 0; u32 tsync_rx_cfg = 0; int is_l4 = 0; int is_l2 = 0; - short port = 319; /* PTP */ +#endif u32 regval; + memset(&config, 0, sizeof(config)); + /* TODO: first check, weather old or new interface is passed. */ if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) return -EFAULT; /* reserved for future extensions */ if (config.flags) - return -EINVAL; + goto manual; switch (config.tx_type) { case HWTSTAMP_TX_OFF: - tsync_tx_ctl_bit = 0; + //tsync_tx_ctl_bit = 0; + config.flags &= ~HWTSTAMP_TX; break; case HWTSTAMP_TX_ON: - tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED; + //tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED; + config.flags |= HWTSTAMP_TX; break; default: return -ERANGE; @@ -4910,7 +4915,7 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev, switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - tsync_rx_ctl_bit = 0; + config.flags &= ~HWTSTAMP_RX; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: @@ -4921,57 +4926,68 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev, * possible to time stamp both Sync and Delay_Req messages * => fall back to time stamping all packets */ - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_ALL; + //tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_ALL; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_ALL; config.rx_filter = HWTSTAMP_FILTER_ALL; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; - is_l4 = 1; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_L4_V1; + config.igb.ptp1_control = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; + config.igb.port = htons(319); /* PTP */ break; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; - is_l4 = 1; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_L4_V1; + config.igb.ptp1_control = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; + config.igb.port = htons(319); /* PTP */ break; case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE; - is_l2 = 1; - is_l4 = 1; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; + config.igb.ptp2_id = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE; + config.igb.etype = 0x88F7; + config.igb.port = htons(319); /* PTP */ config.rx_filter = HWTSTAMP_FILTER_SOME; break; case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; - tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE; - is_l2 = 1; - is_l4 = 1; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2; + config.igb.ptp2_id = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE; + config.igb.etype = 0x88F7; + config.igb.port = htons(319); /* PTP */ config.rx_filter = HWTSTAMP_FILTER_SOME; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_EVENT_V2; + config.igb.ptp_type = E1000_TSYNCRXCTL_TYPE_EVENT_V2; config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - is_l2 = 1; + config.igb.etype = 0x88F7; break; default: return -ERANGE; } +manual: /* enable/disable TX */ regval = rd32(E1000_TSYNCTXCTL); - regval = (regval & ~E1000_TSYNCTXCTL_ENABLED) | tsync_tx_ctl_bit; + if(config.flags & HWTSTAMP_TX) + regval = (regval | E1000_TSYNCTXCTL_ENABLED); + else regval = (regval & ~E1000_TSYNCTXCTL_ENABLED); wr32(E1000_TSYNCTXCTL, regval); /* enable/disable RX, define which PTP packets are time stamped */ regval = rd32(E1000_TSYNCRXCTL); - regval = (regval & ~E1000_TSYNCRXCTL_ENABLED) | tsync_rx_ctl_bit; - regval = (regval & ~0xE) | tsync_rx_ctl_type; + if(config.flags & HWTSTAMP_RX) + regval = (regval | E1000_TSYNCRXCTL_ENABLED); + else regval = (regval & ~E1000_TSYNCRXCTL_ENABLED); + regval = (regval & ~0xE) | config.igb.ptp_type << 1; wr32(E1000_TSYNCRXCTL, regval); - wr32(E1000_TSYNCRXCFG, tsync_rx_cfg); + + /* we don't need to read since we can reset the whole register. */ + regval = config.igb.ptp1_control + | config.igb.ptp2_id << 8 + | config.igb.ptp2_val << 12; + wr32(E1000_TSYNCRXCFG, regval); /* * Ethertype Filter Queue Filter[0][15:0] = 0x88F7 @@ -4979,27 +4995,32 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev, * Ethertype Filter Queue Filter[0][26] = 0x1 (Enable filter) * Ethertype Filter Queue Filter[0][30] = 0x1 (Enable Timestamping) */ - wr32(E1000_ETQF0, is_l2 ? 0x440088f7 : 0); + wr32(E1000_ETQF0, config.igb.etype ? 0x4400 << 16 | config.igb.etype : 0); /* L4 Queue Filter[0]: only filter by source and destination port */ - wr32(E1000_SPQF0, htons(port)); - wr32(E1000_IMIREXT(0), is_l4 ? + /* wr32(E1000_SPQF0, port); XXX why source port? */ + wr32(E1000_IMIREXT(0), config.igb.port ? ((1<<12) | (1<<19) /* bypass size and control flags */) : 0); - wr32(E1000_IMIR(0), is_l4 ? - (htons(port) + wr32(E1000_IMIR(0), config.igb.port ? + (config.igb.port | (0<<16) /* immediate interrupt disabled */ - | 0 /* (1<<17) bit cleared: do not bypass + | (0<<17) /* (1<<17) bit cleared: do not bypass destination port check */) : 0); - wr32(E1000_FTQF0, is_l4 ? + wr32(E1000_FTQF0, config.igb.port ? (0x11 /* UDP */ | (1<<15) /* VF not compared */ | (1<<27) /* Enable Timestamping */ +#if 0 | (7<<28) /* only source port filter enabled, source/target address and protocol - masked */) - : ((1<<15) | (15<<28) /* all mask bits set = filter not - enabled */)); + masked */ +#endif + | (0xe<<28) /* only protocol filter enabled + * everything else is masked. */ + ) + : (1<<15) | (15<<28) /* all mask bits set = filter not + enabled */); wrfl(); diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h index a3b8546..7b069dd 100644 --- a/include/linux/net_tstamp.h +++ b/include/linux/net_tstamp.h @@ -40,26 +40,43 @@ enum { */ struct hwtstamp_config { int flags; - int tx_type; - int rx_filter; + /* deprecated, only used for backwards compatibility when flags == 0 */ + int tx_type; /* put this into flags ? */ + int rx_filter; /* deprecated */ + /* hardware dependend part starts here */ + union { + struct { + unsigned short port; /* for dst port filter, zero to disable */ + unsigned short etype; /* for ethertype filter, zero to disable */ + unsigned ptp1_control :8; /* TSYNCRXCFG.CTRLT */ + /* Careful! According to reference manual message ids + * 2 and 3 always get timestamped. */ + unsigned ptp2_id :4; /* TSYNCRXCFG.MSGT */ + unsigned ptp2_val :4; /* TSYNCRXCFG.TRNSSPC */ + unsigned ptp_type :3; /* TSYNCRXCTL.Type */ + } igb; + }; }; -/* possible values for hwtstamp_config->tx_type */ +/* flags for hwtstamp_config */ enum { /* - * No outgoing packet will need hardware time stamping; - * should a packet arrive which asks for it, no hardware - * time stamping will be done. + * these first two values are the only allowed values in + * deprecated hwtstamp_config->tx_type */ - HWTSTAMP_TX_OFF, - /* * Enables hardware time stamping for outgoing packets; * the sender of the packet decides which are to be * time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE * before sending the packet. + * If disabled no packet will be timestamped; even if it + * asks for it. */ - HWTSTAMP_TX_ON, + HWTSTAMP_TX_OFF = 0, /* only used in hwtstamp_config->tx_type */ + HWTSTAMP_TX_ON = 1, + HWTSTAMP_TX = 1, + + HWTSTAMP_RX = 2 }; /* possible values for hwtstamp_config->rx_filter */ -- 1.6.3.3