Skip to content

Commit 2fe9451

Browse files
committed
ice: Add unified ice_capture_crosststamp
JIRA: https://issues.redhat.com/browse/RHEL-89579 Upstream commit(s): commit 92456e7 Author: Jacob Keller <jacob.e.keller@intel.com> Date: Mon Sep 30 14:12:42 2024 +0200 ice: Add unified ice_capture_crosststamp Devices supported by ice driver use essentially the same logic for performing a crosstimestamp. The only difference is that E830 hardware has different offsets. Instead of having multiple implementations, combine them into a single ice_capture_crosststamp() function. To support both hardware types, the ice_capture_crosststamp function must be able to determine the appropriate registers to access. To handle this, pass a custom context structure instead of the PF pointer. This structure, ice_crosststamp_ctx, contains a pointer to the PF, and a pointer to the device configuration structure. This new structure also will make it easier to implement historic snapshot support in a future commit. The device configuration structure is a static const data which defines the offsets and flags for the various registers. This includes the lock register, the cross timestamp control register, the upper and lower ART system time capture registers, and the upper and lower device time capture registers for each timer index. Use the configuration structure to access all of the registers in ice_capture_crosststamp(). Ensure that we don't over-run the device time array by checking that the timer index is 0 or 1. Previously this was simply assumed, and it would cause the device to read an incorrect and likely garbage register. It does feel like there should be a kernel interface for managing register offsets like this, but the closest thing I saw was <linux/regmap.h> which is interesting but not quite what we're looking for... Use rd32_poll_timeout() to read lock_reg and ctl_reg. Add snapshot system time for historic interpolation. Remove X86_FEATURE_ART and X86_FEATURE_TSC_KNOWN_FREQ from all E82X devices because those are SoCs, which will always have those features. Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com> Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> Signed-off-by: Petr Oros <poros@redhat.com>
1 parent ffd6321 commit 2fe9451

File tree

1 file changed

+129
-75
lines changed

1 file changed

+129
-75
lines changed

drivers/net/ethernet/intel/ice/ice_ptp.c

Lines changed: 129 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,116 +2181,174 @@ static int ice_ptp_adjtime(struct ptp_clock_info *info, s64 delta)
21812181
return 0;
21822182
}
21832183

2184-
#ifdef CONFIG_ICE_HWTS
21852184
/**
2186-
* ice_ptp_get_syncdevicetime - Get the cross time stamp info
2185+
* struct ice_crosststamp_cfg - Device cross timestamp configuration
2186+
* @lock_reg: The hardware semaphore lock to use
2187+
* @lock_busy: Bit in the semaphore lock indicating the lock is busy
2188+
* @ctl_reg: The hardware register to request cross timestamp
2189+
* @ctl_active: Bit in the control register to request cross timestamp
2190+
* @art_time_l: Lower 32-bits of ART system time
2191+
* @art_time_h: Upper 32-bits of ART system time
2192+
* @dev_time_l: Lower 32-bits of device time (per timer index)
2193+
* @dev_time_h: Upper 32-bits of device time (per timer index)
2194+
*/
2195+
struct ice_crosststamp_cfg {
2196+
/* HW semaphore lock register */
2197+
u32 lock_reg;
2198+
u32 lock_busy;
2199+
2200+
/* Capture control register */
2201+
u32 ctl_reg;
2202+
u32 ctl_active;
2203+
2204+
/* Time storage */
2205+
u32 art_time_l;
2206+
u32 art_time_h;
2207+
u32 dev_time_l[2];
2208+
u32 dev_time_h[2];
2209+
};
2210+
2211+
static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e82x = {
2212+
.lock_reg = PFHH_SEM,
2213+
.lock_busy = PFHH_SEM_BUSY_M,
2214+
.ctl_reg = GLHH_ART_CTL,
2215+
.ctl_active = GLHH_ART_CTL_ACTIVE_M,
2216+
.art_time_l = GLHH_ART_TIME_L,
2217+
.art_time_h = GLHH_ART_TIME_H,
2218+
.dev_time_l[0] = GLTSYN_HHTIME_L(0),
2219+
.dev_time_h[0] = GLTSYN_HHTIME_H(0),
2220+
.dev_time_l[1] = GLTSYN_HHTIME_L(1),
2221+
.dev_time_h[1] = GLTSYN_HHTIME_H(1),
2222+
};
2223+
2224+
/**
2225+
* struct ice_crosststamp_ctx - Device cross timestamp context
2226+
* @snapshot: snapshot of system clocks for historic interpolation
2227+
* @pf: pointer to the PF private structure
2228+
* @cfg: pointer to hardware configuration for cross timestamp
2229+
*/
2230+
struct ice_crosststamp_ctx {
2231+
struct system_time_snapshot snapshot;
2232+
struct ice_pf *pf;
2233+
const struct ice_crosststamp_cfg *cfg;
2234+
};
2235+
2236+
/**
2237+
* ice_capture_crosststamp - Capture a device/system cross timestamp
21872238
* @device: Current device time
21882239
* @system: System counter value read synchronously with device time
2189-
* @ctx: Context provided by timekeeping code
2240+
* @__ctx: Context passed from ice_ptp_getcrosststamp
21902241
*
21912242
* Read device and system (ART) clock simultaneously and return the corrected
21922243
* clock values in ns.
2244+
*
2245+
* Return: zero on success, or a negative error code on failure.
21932246
*/
2194-
static int
2195-
ice_ptp_get_syncdevicetime(ktime_t *device,
2196-
struct system_counterval_t *system,
2197-
void *ctx)
2247+
static int ice_capture_crosststamp(ktime_t *device,
2248+
struct system_counterval_t *system,
2249+
void *__ctx)
21982250
{
2199-
struct ice_pf *pf = (struct ice_pf *)ctx;
2200-
struct ice_hw *hw = &pf->hw;
2201-
u32 hh_lock, hh_art_ctl;
2202-
int i;
2251+
struct ice_crosststamp_ctx *ctx = __ctx;
2252+
const struct ice_crosststamp_cfg *cfg;
2253+
u32 lock, ctl, ts_lo, ts_hi, tmr_idx;
2254+
struct ice_pf *pf;
2255+
struct ice_hw *hw;
2256+
int err;
2257+
u64 ts;
22032258

2204-
#define MAX_HH_HW_LOCK_TRIES 5
2205-
#define MAX_HH_CTL_LOCK_TRIES 100
2259+
cfg = ctx->cfg;
2260+
pf = ctx->pf;
2261+
hw = &pf->hw;
22062262

2207-
for (i = 0; i < MAX_HH_HW_LOCK_TRIES; i++) {
2208-
/* Get the HW lock */
2209-
hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
2210-
if (hh_lock & PFHH_SEM_BUSY_M) {
2211-
usleep_range(10000, 15000);
2212-
continue;
2213-
}
2214-
break;
2215-
}
2216-
if (hh_lock & PFHH_SEM_BUSY_M) {
2217-
dev_err(ice_pf_to_dev(pf), "PTP failed to get hh lock\n");
2263+
tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
2264+
if (tmr_idx > 1)
2265+
return -EINVAL;
2266+
2267+
/* Poll until we obtain the cross-timestamp hardware semaphore */
2268+
err = rd32_poll_timeout(hw, cfg->lock_reg, lock,
2269+
!(lock & cfg->lock_busy),
2270+
10 * USEC_PER_MSEC, 50 * USEC_PER_MSEC);
2271+
if (err) {
2272+
dev_err(ice_pf_to_dev(pf), "PTP failed to get cross timestamp lock\n");
22182273
return -EBUSY;
22192274
}
22202275

2276+
/* Snapshot system time for historic interpolation */
2277+
ktime_get_snapshot(&ctx->snapshot);
2278+
22212279
/* Program cmd to master timer */
22222280
ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
22232281

22242282
/* Start the ART and device clock sync sequence */
2225-
hh_art_ctl = rd32(hw, GLHH_ART_CTL);
2226-
hh_art_ctl = hh_art_ctl | GLHH_ART_CTL_ACTIVE_M;
2227-
wr32(hw, GLHH_ART_CTL, hh_art_ctl);
2228-
2229-
for (i = 0; i < MAX_HH_CTL_LOCK_TRIES; i++) {
2230-
/* Wait for sync to complete */
2231-
hh_art_ctl = rd32(hw, GLHH_ART_CTL);
2232-
if (hh_art_ctl & GLHH_ART_CTL_ACTIVE_M) {
2233-
udelay(1);
2234-
continue;
2235-
} else {
2236-
u32 hh_ts_lo, hh_ts_hi, tmr_idx;
2237-
u64 hh_ts;
2238-
2239-
tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
2240-
/* Read ART time */
2241-
hh_ts_lo = rd32(hw, GLHH_ART_TIME_L);
2242-
hh_ts_hi = rd32(hw, GLHH_ART_TIME_H);
2243-
hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
2244-
system->cycles = hh_ts;
2245-
system->cs_id = CSID_X86_ART;
2246-
/* Read Device source clock time */
2247-
hh_ts_lo = rd32(hw, GLTSYN_HHTIME_L(tmr_idx));
2248-
hh_ts_hi = rd32(hw, GLTSYN_HHTIME_H(tmr_idx));
2249-
hh_ts = ((u64)hh_ts_hi << 32) | hh_ts_lo;
2250-
*device = ns_to_ktime(hh_ts);
2251-
break;
2252-
}
2253-
}
2283+
ctl = rd32(hw, cfg->ctl_reg);
2284+
ctl |= cfg->ctl_active;
2285+
wr32(hw, cfg->ctl_reg, ctl);
22542286

2287+
/* Poll until hardware completes the capture */
2288+
err = rd32_poll_timeout(hw, cfg->ctl_reg, ctl, !(ctl & cfg->ctl_active),
2289+
5, 20 * USEC_PER_MSEC);
2290+
if (err)
2291+
goto err_timeout;
2292+
2293+
/* Read ART system time */
2294+
ts_lo = rd32(hw, cfg->art_time_l);
2295+
ts_hi = rd32(hw, cfg->art_time_h);
2296+
ts = ((u64)ts_hi << 32) | ts_lo;
2297+
system->cycles = ts;
2298+
system->cs_id = CSID_X86_ART;
2299+
2300+
/* Read Device source clock time */
2301+
ts_lo = rd32(hw, cfg->dev_time_l[tmr_idx]);
2302+
ts_hi = rd32(hw, cfg->dev_time_h[tmr_idx]);
2303+
ts = ((u64)ts_hi << 32) | ts_lo;
2304+
*device = ns_to_ktime(ts);
2305+
2306+
err_timeout:
22552307
/* Clear the master timer */
22562308
ice_ptp_src_cmd(hw, ICE_PTP_NOP);
22572309

22582310
/* Release HW lock */
2259-
hh_lock = rd32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
2260-
hh_lock = hh_lock & ~PFHH_SEM_BUSY_M;
2261-
wr32(hw, PFHH_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), hh_lock);
2262-
2263-
if (i == MAX_HH_CTL_LOCK_TRIES)
2264-
return -ETIMEDOUT;
2311+
lock = rd32(hw, cfg->lock_reg);
2312+
lock &= ~cfg->lock_busy;
2313+
wr32(hw, cfg->lock_reg, lock);
22652314

2266-
return 0;
2315+
return err;
22672316
}
22682317

22692318
/**
2270-
* ice_ptp_getcrosststamp_e82x - Capture a device cross timestamp
2319+
* ice_ptp_getcrosststamp - Capture a device cross timestamp
22712320
* @info: the driver's PTP info structure
22722321
* @cts: The memory to fill the cross timestamp info
22732322
*
22742323
* Capture a cross timestamp between the ART and the device PTP hardware
22752324
* clock. Fill the cross timestamp information and report it back to the
22762325
* caller.
22772326
*
2278-
* This is only valid for E822 and E823 devices which have support for
2279-
* generating the cross timestamp via PCIe PTM.
2280-
*
22812327
* In order to correctly correlate the ART timestamp back to the TSC time, the
22822328
* CPU must have X86_FEATURE_TSC_KNOWN_FREQ.
2329+
*
2330+
* Return: zero on success, or a negative error code on failure.
22832331
*/
2284-
static int
2285-
ice_ptp_getcrosststamp_e82x(struct ptp_clock_info *info,
2286-
struct system_device_crosststamp *cts)
2332+
static int ice_ptp_getcrosststamp(struct ptp_clock_info *info,
2333+
struct system_device_crosststamp *cts)
22872334
{
22882335
struct ice_pf *pf = ptp_info_to_pf(info);
2336+
struct ice_crosststamp_ctx ctx = {
2337+
.pf = pf,
2338+
};
2339+
2340+
switch (pf->hw.mac_type) {
2341+
case ICE_MAC_GENERIC:
2342+
case ICE_MAC_GENERIC_3K_E825:
2343+
ctx.cfg = &ice_crosststamp_cfg_e82x;
2344+
break;
2345+
default:
2346+
return -EOPNOTSUPP;
2347+
}
22892348

2290-
return get_device_system_crosststamp(ice_ptp_get_syncdevicetime,
2291-
pf, NULL, cts);
2349+
return get_device_system_crosststamp(ice_capture_crosststamp, &ctx,
2350+
&ctx.snapshot, cts);
22922351
}
2293-
#endif /* CONFIG_ICE_HWTS */
22942352

22952353
/**
22962354
* ice_ptp_get_ts_config - ioctl interface to read the timestamping config
@@ -2551,12 +2609,8 @@ static int ice_ptp_parse_sdp_entries(struct ice_pf *pf, __le16 *entries,
25512609
*/
25522610
static void ice_ptp_set_funcs_e82x(struct ice_pf *pf)
25532611
{
2554-
#ifdef CONFIG_ICE_HWTS
2555-
if (boot_cpu_has(X86_FEATURE_ART) &&
2556-
boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ))
2557-
pf->ptp.info.getcrosststamp = ice_ptp_getcrosststamp_e82x;
2612+
pf->ptp.info.getcrosststamp = ice_ptp_getcrosststamp;
25582613

2559-
#endif /* CONFIG_ICE_HWTS */
25602614
if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
25612615
pf->ptp.ice_pin_desc = ice_pin_desc_e825c;
25622616
pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e825c);

0 commit comments

Comments
 (0)