drivers/net/ethernet/meta/fbnic/fbnic_time.c
Source file repositories/reference/linux-study-clean/drivers/net/ethernet/meta/fbnic/fbnic_time.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/net/ethernet/meta/fbnic/fbnic_time.c- Extension
.c- Size
- 8413 bytes
- Lines
- 304
- Domain
- Driver Families
- Bucket
- drivers/net
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/bitfield.hlinux/jiffies.hlinux/limits.hlinux/ptp_clock_kernel.hlinux/timer.hfbnic.hfbnic_csr.hfbnic_netdev.h
Detected Declarations
function nsecs_to_jiffiesfunction __fbnic_time_get_slowfunction __fbnic_time_set_addendfunction fbnic_ptp_fresh_checkfunction fbnic_ptp_refresh_timefunction fbnic_ptp_do_aux_workfunction fbnic_ptp_adjfinefunction fbnic_ptp_adjtimefunction fbnic_ptp_gettimex64function fbnic_ptp_settime64function fbnic_ptp_resetfunction fbnic_time_initfunction fbnic_time_startfunction fbnic_time_stopfunction fbnic_ptp_setupfunction fbnic_ptp_destroy
Annotated Snippet
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <linux/bitfield.h>
#include <linux/jiffies.h>
#include <linux/limits.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timer.h>
#include "fbnic.h"
#include "fbnic_csr.h"
#include "fbnic_netdev.h"
/* FBNIC timing & PTP implementation
* Datapath uses truncated 40b timestamps for scheduling and event reporting.
* We need to promote those to full 64b, hence we periodically cache the top
* 32bit of the HW time counter. Since this makes our time reporting non-atomic
* we leave the HW clock free running and adjust time offsets in SW as needed.
* Time offset is 64bit - we need a seq counter for 32bit machines.
* Time offset and the cache of top bits are independent so we don't need
* a coherent snapshot of both - READ_ONCE()/WRITE_ONCE() + writer side lock
* are enough.
*/
/* Period of refresh of top bits of timestamp, give ourselves a 8x margin.
* This should translate to once a minute.
* The use of nsecs_to_jiffies() should be safe for a <=40b nsec value.
*/
#define FBNIC_TS_HIGH_REFRESH_JIF nsecs_to_jiffies((1ULL << 40) / 16)
static struct fbnic_dev *fbnic_from_ptp_info(struct ptp_clock_info *ptp)
{
return container_of(ptp, struct fbnic_dev, ptp_info);
}
/* This function is "slow" because we could try guessing which high part
* is correct based on low instead of re-reading, and skip reading @hi
* twice altogether if @lo is far enough from 0.
*/
static u64 __fbnic_time_get_slow(struct fbnic_dev *fbd)
{
u32 hi, lo;
lockdep_assert_held(&fbd->time_lock);
do {
hi = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI);
lo = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_LO);
} while (hi != fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI));
return (u64)hi << 32 | lo;
}
static void __fbnic_time_set_addend(struct fbnic_dev *fbd, u64 addend)
{
lockdep_assert_held(&fbd->time_lock);
fbnic_wr32(fbd, FBNIC_PTP_ADD_VAL_NS,
FIELD_PREP(FBNIC_PTP_ADD_VAL_NS_MASK, addend >> 32));
fbnic_wr32(fbd, FBNIC_PTP_ADD_VAL_SUBNS, (u32)addend);
}
static void fbnic_ptp_fresh_check(struct fbnic_dev *fbd)
{
if (time_is_after_jiffies(fbd->last_read +
FBNIC_TS_HIGH_REFRESH_JIF * 3 / 2))
return;
dev_warn(fbd->dev, "NIC timestamp refresh stall, delayed by %lu sec\n",
(jiffies - fbd->last_read - FBNIC_TS_HIGH_REFRESH_JIF) / HZ);
}
static void fbnic_ptp_refresh_time(struct fbnic_dev *fbd, struct fbnic_net *fbn)
{
unsigned long flags;
u32 hi;
spin_lock_irqsave(&fbd->time_lock, flags);
hi = fbnic_rd32(fbn->fbd, FBNIC_PTP_CTR_VAL_HI);
if (!fbnic_present(fbd))
goto out; /* Don't bother handling, reset is pending */
/* Let's keep high cached value a bit lower to avoid race with
* incoming timestamps. The logic in fbnic_ts40_to_ns() will
* take care of overflow in this case. It will make cached time
* ~1 minute lower and incoming timestamp will always be later
* then cached time.
*/
WRITE_ONCE(fbn->time_high, hi - 16);
fbd->last_read = jiffies;
out:
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/jiffies.h`, `linux/limits.h`, `linux/ptp_clock_kernel.h`, `linux/timer.h`, `fbnic.h`, `fbnic_csr.h`, `fbnic_netdev.h`.
- Detected declarations: `function nsecs_to_jiffies`, `function __fbnic_time_get_slow`, `function __fbnic_time_set_addend`, `function fbnic_ptp_fresh_check`, `function fbnic_ptp_refresh_time`, `function fbnic_ptp_do_aux_work`, `function fbnic_ptp_adjfine`, `function fbnic_ptp_adjtime`, `function fbnic_ptp_gettimex64`, `function fbnic_ptp_settime64`.
- Atlas domain: Driver Families / drivers/net.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.