Commit 38c845c7 authored by Patrick Ohly's avatar Patrick Ohly Committed by David S. Miller
Browse files

igb: access to NIC time



Adds the register definitions and code to read the time
register.

Signed-off-by: default avatarJohn Ronciak <john.ronciak@intel.com>
Signed-off-by: default avatarPatrick Ohly <patrick.ohly@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d24fff22
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -75,6 +75,34 @@
#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */

/* IEEE 1588 TIMESYNCH */
#define E1000_TSYNCTXCTL 0x0B614
#define E1000_TSYNCRXCTL 0x0B620
#define E1000_TSYNCRXCFG 0x05F50

#define E1000_SYSTIML 0x0B600
#define E1000_SYSTIMH 0x0B604
#define E1000_TIMINCA 0x0B608

#define E1000_RXMTRL     0x0B634
#define E1000_RXSTMPL 0x0B624
#define E1000_RXSTMPH 0x0B628
#define E1000_RXSATRL 0x0B62C
#define E1000_RXSATRH 0x0B630

#define E1000_TXSTMPL 0x0B618
#define E1000_TXSTMPH 0x0B61C

#define E1000_ETQF0   0x05CB0
#define E1000_ETQF1   0x05CB4
#define E1000_ETQF2   0x05CB8
#define E1000_ETQF3   0x05CBC
#define E1000_ETQF4   0x05CC0
#define E1000_ETQF5   0x05CC4
#define E1000_ETQF6   0x05CC8
#define E1000_ETQF7   0x05CCC

/* Split and Replication RX Control - RW */
/*
 * Convenience macros
+4 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include "e1000_mac.h"
#include "e1000_82575.h"

#include <linux/clocksource.h>

struct igb_adapter;

/* Interrupt defines */
@@ -251,6 +253,8 @@ struct igb_adapter {
	struct napi_struct napi;
	struct pci_dev *pdev;
	struct net_device_stats net_stats;
	struct cyclecounter cycles;
	struct timecounter clock;

	/* structs defined in e1000_hw.h */
	struct e1000_hw hw;
+111 −0
Original line number Diff line number Diff line
@@ -175,6 +175,54 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

/**
 * Scale the NIC clock cycle by a large factor so that
 * relatively small clock corrections can be added or
 * substracted at each clock tick. The drawbacks of a
 * large factor are a) that the clock register overflows
 * more quickly (not such a big deal) and b) that the
 * increment per tick has to fit into 24 bits.
 *
 * Note that
 *   TIMINCA = IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS *
 *             IGB_TSYNC_SCALE
 *   TIMINCA += TIMINCA * adjustment [ppm] / 1e9
 *
 * The base scale factor is intentionally a power of two
 * so that the division in %struct timecounter can be done with
 * a shift.
 */
#define IGB_TSYNC_SHIFT (19)
#define IGB_TSYNC_SCALE (1<<IGB_TSYNC_SHIFT)

/**
 * The duration of one clock cycle of the NIC.
 *
 * @todo This hard-coded value is part of the specification and might change
 * in future hardware revisions. Add revision check.
 */
#define IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS 16

#if (IGB_TSYNC_SCALE * IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS) >= (1<<24)
# error IGB_TSYNC_SCALE and/or IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS are too large to fit into TIMINCA
#endif

/**
 * igb_read_clock - read raw cycle counter (to be used by time counter)
 */
static cycle_t igb_read_clock(const struct cyclecounter *tc)
{
	struct igb_adapter *adapter =
		container_of(tc, struct igb_adapter, cycles);
	struct e1000_hw *hw = &adapter->hw;
	u64 stamp;

	stamp =  rd32(E1000_SYSTIML);
	stamp |= (u64)rd32(E1000_SYSTIMH) << 32ULL;

	return stamp;
}

#ifdef DEBUG
/**
 * igb_get_hw_dev_name - return device name string
@@ -185,6 +233,29 @@ char *igb_get_hw_dev_name(struct e1000_hw *hw)
	struct igb_adapter *adapter = hw->back;
	return adapter->netdev->name;
}

/**
 * igb_get_time_str - format current NIC and system time as string
 */
static char *igb_get_time_str(struct igb_adapter *adapter,
			      char buffer[160])
{
	cycle_t hw = adapter->cycles.read(&adapter->cycles);
	struct timespec nic = ns_to_timespec(timecounter_read(&adapter->clock));
	struct timespec sys;
	struct timespec delta;
	getnstimeofday(&sys);

	delta = timespec_sub(nic, sys);

	sprintf(buffer,
		"NIC %ld.%09lus, SYS %ld.%09lus, NIC-SYS %lds + %09luns",
		(long)nic.tv_sec, nic.tv_nsec,
		(long)sys.tv_sec, sys.tv_nsec,
		(long)delta.tv_sec, delta.tv_nsec);

	return buffer;
}
#endif

/**
@@ -1298,6 +1369,46 @@ static int __devinit igb_probe(struct pci_dev *pdev,
	}
#endif

	/*
	 * Initialize hardware timer: we keep it running just in case
	 * that some program needs it later on.
	 */
	memset(&adapter->cycles, 0, sizeof(adapter->cycles));
	adapter->cycles.read = igb_read_clock;
	adapter->cycles.mask = CLOCKSOURCE_MASK(64);
	adapter->cycles.mult = 1;
	adapter->cycles.shift = IGB_TSYNC_SHIFT;
	wr32(E1000_TIMINCA,
	     (1<<24) |
	     IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS * IGB_TSYNC_SCALE);
#if 0
	/*
	 * Avoid rollover while we initialize by resetting the time counter.
	 */
	wr32(E1000_SYSTIML, 0x00000000);
	wr32(E1000_SYSTIMH, 0x00000000);
#else
	/*
	 * Set registers so that rollover occurs soon to test this.
	 */
	wr32(E1000_SYSTIML, 0x00000000);
	wr32(E1000_SYSTIMH, 0xFF800000);
#endif
	wrfl();
	timecounter_init(&adapter->clock,
			 &adapter->cycles,
			 ktime_to_ns(ktime_get_real()));

#ifdef DEBUG
	{
		char buffer[160];
		printk(KERN_DEBUG
			"igb: %s: hw %p initialized timer\n",
			igb_get_time_str(adapter, buffer),
			&adapter->hw);
	}
#endif

	dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
	/* print bus type/speed/width info */
	dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",