Commit b32add2d authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2023-08-24 (igc, e1000e)

This series contains updates to igc and e1000e drivers.

Vinicius adds support for utilizing multiple PTP registers on igc.

Sasha reduces interval time for PTM on igc and adds new device support
on e1000e.

* '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  e1000e: Add support for the next LOM generation
  igc: Decrease PTM short interval from 10 us to 1 us
  igc: Add support for multiple in-flight TX timestamps
====================

Link: https://lore.kernel.org/r/20230824204418.1551093-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 52d08fda 1fe4f45e
......@@ -917,6 +917,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
mask |= BIT(18);
break;
default:
......@@ -1585,6 +1586,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
fext_nvm11 = er32(FEXTNVM11);
fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX;
ew32(FEXTNVM11, fext_nvm11);
......
......@@ -122,6 +122,8 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_PTP_I219_V26 0x57B6
#define E1000_DEV_ID_PCH_PTP_I219_LM27 0x57B7
#define E1000_DEV_ID_PCH_PTP_I219_V27 0x57B8
#define E1000_DEV_ID_PCH_NVL_I219_LM29 0x57B9
#define E1000_DEV_ID_PCH_NVL_I219_V29 0x57BA
#define E1000_REVISION_4 4
......@@ -150,6 +152,7 @@ enum e1000_mac_type {
e1000_pch_mtp,
e1000_pch_lnp,
e1000_pch_ptp,
e1000_pch_nvp,
};
enum e1000_media_type {
......
......@@ -323,6 +323,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
if (e1000_phy_is_accessible_pchlan(hw))
break;
......@@ -470,6 +471,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
/* In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
......@@ -717,6 +719,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
case e1000_pchlan:
/* check management mode */
mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
......@@ -1685,6 +1688,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
rc = e1000_init_phy_params_pchlan(hw);
break;
default:
......@@ -2142,6 +2146,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
break;
default:
......@@ -3188,6 +3193,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
bank1_offset = nvm->flash_bank_size;
act_offset = E1000_ICH_NVM_SIG_WORD;
......@@ -4129,6 +4135,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
word = NVM_COMPAT;
valid_csum_mask = NVM_COMPAT_VALID_CSUM;
break;
......
......@@ -3545,6 +3545,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
/* Stable 24MHz frequency */
incperiod = INCPERIOD_24MHZ;
......@@ -4061,6 +4062,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
fc->refresh_time = 0xFFFF;
fc->pause_time = 0xFFFF;
......@@ -7913,6 +7915,8 @@ static const struct pci_device_id e1000_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V26), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_mtp },
{ 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
};
......
......@@ -288,6 +288,7 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
if ((hw->mac.type < e1000_pch_lpt) ||
(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
adapter->ptp_clock_info.max_adj = 24000000 - 1;
......
......@@ -38,6 +38,8 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_FLEX_FILTER 32
#define IGC_MAX_TX_TSTAMP_REGS 4
enum igc_mac_filter_type {
IGC_MAC_FILTER_TYPE_DST = 0,
IGC_MAC_FILTER_TYPE_SRC
......@@ -70,6 +72,15 @@ struct igc_rx_packet_stats {
u64 other_packets;
};
struct igc_tx_timestamp_request {
struct sk_buff *skb; /* reference to the packet being timestamped */
unsigned long start; /* when the tstamp request started (jiffies) */
u32 mask; /* _TSYNCTXCTL_TXTT_{X} bit for this request */
u32 regl; /* which TXSTMPL_{X} register should be used */
u32 regh; /* which TXSTMPH_{X} register should be used */
u32 flags; /* flags that should be added to the tx_buffer */
};
struct igc_ring_container {
struct igc_ring *ring; /* pointer to linked list of rings */
unsigned int total_bytes; /* total bytes processed this int */
......@@ -245,9 +256,8 @@ struct igc_adapter {
* ptp_tx_lock.
*/
spinlock_t ptp_tx_lock;
struct sk_buff *ptp_tx_skb;
struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned int ptp_flags;
/* System time value lock */
spinlock_t tmreg_lock;
......@@ -455,6 +465,10 @@ enum igc_tx_flags {
/* olinfo flags */
IGC_TX_FLAGS_IPV4 = 0x10,
IGC_TX_FLAGS_CSUM = 0x20,
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
};
enum igc_boards {
......
......@@ -34,6 +34,9 @@ struct igc_adv_tx_context_desc {
/* Adv Transmit Descriptor Config Masks */
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
......
......@@ -454,6 +454,9 @@
/* Time Sync Transmit Control bit definitions */
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
#define IGC_TSYNCTXCTL_TXTT_1 0x00000002 /* Tx timestamp reg 1 valid */
#define IGC_TSYNCTXCTL_TXTT_2 0x00000004 /* Tx timestamp reg 2 valid */
#define IGC_TSYNCTXCTL_TXTT_3 0x00000008 /* Tx timestamp reg 3 valid */
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
......@@ -461,6 +464,10 @@
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
#define IGC_TSYNCTXCTL_TXTT_ANY ( \
IGC_TSYNCTXCTL_TXTT_0 | IGC_TSYNCTXCTL_TXTT_1 | \
IGC_TSYNCTXCTL_TXTT_2 | IGC_TSYNCTXCTL_TXTT_3)
/* Timer selection bits */
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
......@@ -549,7 +556,7 @@
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2)
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
#define IGC_PTM_SHORT_CYC_DEFAULT 10 /* Default Short/interrupted cycle interval */
#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
......
......@@ -1271,10 +1271,21 @@ static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
(IGC_ADVTXD_DCMD_TSE));
/* set timestamp bit if present */
/* set timestamp bit if present, will select the register set
* based on the _TSTAMP(_X) bit.
*/
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
(IGC_ADVTXD_MAC_TSTAMP));
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_1,
(IGC_ADVTXD_TSTAMP_REG_1));
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_2,
(IGC_ADVTXD_TSTAMP_REG_2));
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_3,
(IGC_ADVTXD_TSTAMP_REG_3));
/* insert frame checksum */
cmd_type ^= IGC_SET_FLAG(skb->no_fcs, 1, IGC_ADVTXD_DCMD_IFCS);
......@@ -1533,6 +1544,26 @@ static int igc_tso(struct igc_ring *tx_ring,
return 1;
}
static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *skb, u32 *flags)
{
int i;
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
if (tstamp->skb)
continue;
tstamp->skb = skb_get(skb);
tstamp->start = jiffies;
*flags = tstamp->flags;
return true;
}
return false;
}
static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
struct igc_ring *tx_ring)
{
......@@ -1614,14 +1645,12 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
* timestamping request.
*/
unsigned long flags;
u32 tstamp_flags;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
if (!adapter->ptp_tx_skb) {
if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGC_TX_FLAGS_TSTAMP;
adapter->ptp_tx_skb = skb_get(skb);
adapter->ptp_tx_start = jiffies;
tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
} else {
adapter->tx_hwtstamp_skipped++;
}
......
......@@ -558,11 +558,16 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
{
unsigned long flags;
int i;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
dev_kfree_skb_any(tstamp->skb);
tstamp->skb = NULL;
}
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
......@@ -659,61 +664,106 @@ static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter,
}
/* Requires adapter->ptp_tx_lock held by caller. */
static void igc_ptp_tx_timeout(struct igc_adapter *adapter)
static void igc_ptp_tx_timeout(struct igc_adapter *adapter,
struct igc_tx_timestamp_request *tstamp)
{
struct igc_hw *hw = &adapter->hw;
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
dev_kfree_skb_any(tstamp->skb);
tstamp->skb = NULL;
adapter->tx_hwtstamp_timeouts++;
/* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */
rd32(IGC_TXSTMPH);
netdev_warn(adapter->netdev, "Tx timestamp timeout\n");
}
void igc_ptp_tx_hang(struct igc_adapter *adapter)
{
struct igc_tx_timestamp_request *tstamp;
struct igc_hw *hw = &adapter->hw;
unsigned long flags;
bool found = false;
int i;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
if (!adapter->ptp_tx_skb)
goto unlock;
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
tstamp = &adapter->tx_tstamp[i];
if (!tstamp->skb)
continue;
if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT))
goto unlock;
if (time_is_after_jiffies(tstamp->start + IGC_PTP_TX_TIMEOUT))
continue;
igc_ptp_tx_timeout(adapter);
igc_ptp_tx_timeout(adapter, tstamp);
found = true;
}
if (found) {
/* Reading the high register of the first set of timestamp registers
* clears all the equivalent bits in the TSYNCTXCTL register.
*/
rd32(IGC_TXSTMPH_0);
}
unlock:
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
struct igc_tx_timestamp_request *tstamp, u64 regval)
{
struct skb_shared_hwtstamps shhwtstamps;
struct sk_buff *skb;
int adjust = 0;
skb = tstamp->skb;
if (!skb)
return;
if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
return;
switch (adapter->link_speed) {
case SPEED_10:
adjust = IGC_I225_TX_LATENCY_10;
break;
case SPEED_100:
adjust = IGC_I225_TX_LATENCY_100;
break;
case SPEED_1000:
adjust = IGC_I225_TX_LATENCY_1000;
break;
case SPEED_2500:
adjust = IGC_I225_TX_LATENCY_2500;
break;
}
shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
tstamp->skb = NULL;
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
}
/**
* igc_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure
*
* If we were asked to do hardware stamping and such a time stamp is
* available, then it must have been for this skb here because we only
* allow only one such packet into the queue.
* Check against the ready mask for which of the timestamp register
* sets are ready to be retrieved, then retrieve that and notify the
* rest of the stack.
*
* Context: Expects adapter->ptp_tx_lock to be held by caller.
*/
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
{
struct sk_buff *skb = adapter->ptp_tx_skb;
struct skb_shared_hwtstamps shhwtstamps;
struct igc_hw *hw = &adapter->hw;
u32 tsynctxctl;
int adjust = 0;
u64 regval;
u32 mask;
int i;
if (WARN_ON_ONCE(!skb))
return;
tsynctxctl = rd32(IGC_TSYNCTXCTL);
tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0;
if (tsynctxctl) {
mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
if (mask & IGC_TSYNCTXCTL_TXTT_0) {
regval = rd32(IGC_TXSTMPL);
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
} else {
......@@ -742,37 +792,30 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
txstmpl_new = rd32(IGC_TXSTMPL);
if (txstmpl_old == txstmpl_new)
return;
goto done;
regval = txstmpl_new;
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
}
if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
return;
switch (adapter->link_speed) {
case SPEED_10:
adjust = IGC_I225_TX_LATENCY_10;
break;
case SPEED_100:
adjust = IGC_I225_TX_LATENCY_100;
break;
case SPEED_1000:
adjust = IGC_I225_TX_LATENCY_1000;
break;
case SPEED_2500:
adjust = IGC_I225_TX_LATENCY_2500;
break;
}
igc_ptp_tx_reg_to_stamp(adapter, &adapter->tx_tstamp[0], regval);
shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
done:
/* Now that the problematic first register was handled, we can
* use retrieve the timestamps from the other registers
* (starting from '1') with less complications.
*/
for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
adapter->ptp_tx_skb = NULL;
if (!(tstamp->mask & mask))
continue;
/* Notify the stack and free the skb after we've unlocked */
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
regval = rd32(tstamp->regl);
regval |= (u64)rd32(tstamp->regh) << 32;
igc_ptp_tx_reg_to_stamp(adapter, tstamp, regval);
}
}
/**
......@@ -788,12 +831,8 @@ void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter)
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
if (!adapter->ptp_tx_skb)
goto unlock;
igc_ptp_tx_hwtstamp(adapter);
unlock:
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
......@@ -1006,9 +1045,34 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
void igc_ptp_init(struct igc_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct igc_tx_timestamp_request *tstamp;
struct igc_hw *hw = &adapter->hw;
int i;
tstamp = &adapter->tx_tstamp[0];
tstamp->mask = IGC_TSYNCTXCTL_TXTT_0;
tstamp->regl = IGC_TXSTMPL_0;
tstamp->regh = IGC_TXSTMPH_0;
tstamp->flags = 0;
tstamp = &adapter->tx_tstamp[1];
tstamp->mask = IGC_TSYNCTXCTL_TXTT_1;
tstamp->regl = IGC_TXSTMPL_1;
tstamp->regh = IGC_TXSTMPH_1;
tstamp->flags = IGC_TX_FLAGS_TSTAMP_1;
tstamp = &adapter->tx_tstamp[2];
tstamp->mask = IGC_TSYNCTXCTL_TXTT_2;
tstamp->regl = IGC_TXSTMPL_2;
tstamp->regh = IGC_TXSTMPH_2;
tstamp->flags = IGC_TX_FLAGS_TSTAMP_2;
tstamp = &adapter->tx_tstamp[3];
tstamp->mask = IGC_TSYNCTXCTL_TXTT_3;
tstamp->regl = IGC_TXSTMPL_3;
tstamp->regh = IGC_TXSTMPH_3;
tstamp->flags = IGC_TX_FLAGS_TSTAMP_3;
switch (hw->mac.type) {
case igc_i225:
for (i = 0; i < IGC_N_SDP; i++) {
......
......@@ -243,6 +243,18 @@
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
/* TX Timestamp Low */
#define IGC_TXSTMPL_0 0x0B618
#define IGC_TXSTMPL_1 0x0B698
#define IGC_TXSTMPL_2 0x0B6B8
#define IGC_TXSTMPL_3 0x0B6D8
/* TX Timestamp High */
#define IGC_TXSTMPH_0 0x0B61C
#define IGC_TXSTMPH_1 0x0B69C
#define IGC_TXSTMPH_2 0x0B6BC
#define IGC_TXSTMPH_3 0x0B6DC
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment