drivers/net/ethernet/mscc/ocelot_ptp.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mscc/ocelot_ptp.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mscc/ocelot_ptp.c
Extension
.c
Size
24575 bytes
Lines
913
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!on) {
			spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
			val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
			ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
			spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
			break;
		}

		if (rq->perout.flags & PTP_PEROUT_PHASE) {
			ts_phase.tv_sec = rq->perout.phase.sec;
			ts_phase.tv_nsec = rq->perout.phase.nsec;
		} else {
			/* Compatibility */
			ts_phase.tv_sec = rq->perout.start.sec;
			ts_phase.tv_nsec = rq->perout.start.nsec;
		}
		if (ts_phase.tv_sec || (ts_phase.tv_nsec && !pps)) {
			dev_warn(ocelot->dev,
				 "Absolute start time not supported!\n");
			dev_warn(ocelot->dev,
				 "Accept nsec for PPS phase adjustment, otherwise start time should be 0 0.\n");
			return -EINVAL;
		}

		/* Calculate waveform high and low times */
		if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
			struct timespec64 ts_on;

			ts_on.tv_sec = rq->perout.on.sec;
			ts_on.tv_nsec = rq->perout.on.nsec;

			wf_high = timespec64_to_ns(&ts_on);
		} else {
			if (pps) {
				wf_high = 1000;
			} else {
				wf_high = timespec64_to_ns(&ts_period);
				wf_high = div_s64(wf_high, 2);
			}
		}

		wf_low = timespec64_to_ns(&ts_period);
		wf_low -= wf_high;

		/* Handle PPS request */
		if (pps) {
			spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
			ocelot_write_rix(ocelot, ts_phase.tv_nsec,
					 PTP_PIN_WF_LOW_PERIOD, ptp_pin);
			ocelot_write_rix(ocelot, wf_high,
					 PTP_PIN_WF_HIGH_PERIOD, ptp_pin);
			val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
			val |= PTP_PIN_CFG_SYNC;
			ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
			spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
			break;
		}

		/* Handle periodic clock */
		if (wf_high > 0x3fffffff || wf_high <= 0x6)
			return -EINVAL;
		if (wf_low > 0x3fffffff || wf_low <= 0x6)
			return -EINVAL;

		spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
		ocelot_write_rix(ocelot, wf_low, PTP_PIN_WF_LOW_PERIOD,
				 ptp_pin);
		ocelot_write_rix(ocelot, wf_high, PTP_PIN_WF_HIGH_PERIOD,
				 ptp_pin);
		val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
		ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
		spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
		break;
	default:
		return -EOPNOTSUPP;
	}
	return 0;
}
EXPORT_SYMBOL(ocelot_ptp_enable);

static void ocelot_populate_l2_ptp_trap_key(struct ocelot_vcap_filter *trap)
{
	trap->key_type = OCELOT_VCAP_KEY_ETYPE;
	*(__be16 *)trap->key.etype.etype.value = htons(ETH_P_1588);
	*(__be16 *)trap->key.etype.etype.mask = htons(0xffff);
}

static void
ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
{

Annotation

Implementation Notes