igb: access to NIC time

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

Signed-off-by: John Ronciak <john.ronciak@intel.com>
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Patrick Ohly
2009-02-12 05:03:41 +00:00
committed by David S. Miller
parent d24fff22d8
commit 38c845c764
3 changed files with 143 additions and 0 deletions

View File

@@ -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",