/* Enabling/disabling TX and RX HW timestamping for different PTP messages is * not available in the switch. Thus, this function only serves as a check if * the user requested what is actually available or not
*/ staticint hellcreek_set_hwtstamp_config(struct hellcreek *hellcreek, int port, struct kernel_hwtstamp_config *config)
{ struct hellcreek_port_hwtstamp *ps =
&hellcreek->ports[port].port_hwtstamp; bool tx_tstamp_enable = false; bool rx_tstamp_enable = false;
/* Interaction with the timestamp hardware is prevented here. It is * enabled when this config function ends successfully
*/
clear_bit_unlock(HELLCREEK_HWTSTAMP_ENABLED, &ps->state);
switch (config->tx_type) { case HWTSTAMP_TX_ON:
tx_tstamp_enable = true; break;
/* TX HW timestamping can't be disabled on the switch */ case HWTSTAMP_TX_OFF:
config->tx_type = HWTSTAMP_TX_ON; break;
default: return -ERANGE;
}
switch (config->rx_filter) { /* RX HW timestamping can't be disabled on the switch */ case HWTSTAMP_FILTER_NONE:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
rx_tstamp_enable = true; break;
/* RX HW timestamping can't be enabled for all messages on the switch */ case HWTSTAMP_FILTER_ALL:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break;
default: return -ERANGE;
}
if (!tx_tstamp_enable) return -ERANGE;
if (!rx_tstamp_enable) return -ERANGE;
/* If this point is reached, then the requested hwtstamp config is * compatible with the hwtstamp offered by the switch. Therefore, * enable the interaction with the HW timestamping
*/
set_bit(HELLCREEK_HWTSTAMP_ENABLED, &ps->state);
return 0;
}
int hellcreek_port_hwtstamp_set(struct dsa_switch *ds, int port, struct kernel_hwtstamp_config *config, struct netlink_ext_ack *extack)
{ struct hellcreek *hellcreek = ds->priv; struct hellcreek_port_hwtstamp *ps; int err;
ps = &hellcreek->ports[port].port_hwtstamp;
err = hellcreek_set_hwtstamp_config(hellcreek, port, config); if (err) return err;
/* Save the chosen configuration to be returned later */
ps->tstamp_config = *config;
return 0;
}
int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port, struct kernel_hwtstamp_config *config)
{ struct hellcreek *hellcreek = ds->priv; struct hellcreek_port_hwtstamp *ps;
/* Returns a pointer to the PTP header if the caller should time stamp, or NULL * if the caller should not.
*/ staticstruct ptp_header *hellcreek_should_tstamp(struct hellcreek *hellcreek, int port, struct sk_buff *skb, unsignedint type)
{ struct hellcreek_port_hwtstamp *ps =
&hellcreek->ports[port].port_hwtstamp; struct ptp_header *hdr;
hdr = ptp_parse_header(skb, type); if (!hdr) return NULL;
if (!test_bit(HELLCREEK_HWTSTAMP_ENABLED, &ps->state)) return NULL;
if (status & PR_TS_STATUS_TS_LOST)
dev_err(hellcreek->dev, "Tx time stamp lost! This should never happen!\n");
/* If hwtstamp is not available, this means the previous hwtstamp was * successfully read, and the one we need is not yet available
*/ return (status & PR_TS_STATUS_TS_AVAIL) ? 1 : 0;
}
/* Get nanoseconds timestamp from timestamping unit */ static u64 hellcreek_ptp_hwtstamp_read(struct hellcreek *hellcreek, unsignedint ts_reg)
{
u16 nsl, nsh;
/* Not available yet? */ if (ts_status == 0) { /* Check whether the operation of reading the tx timestamp has * exceeded its allowed period
*/ if (time_is_before_jiffies(ps->tx_tstamp_start +
TX_TSTAMP_TIMEOUT)) {
dev_err(hellcreek->dev, "Timeout while waiting for Tx timestamp!\n"); goto free_and_clear_skb;
}
/* The timestamp should be available quickly, while getting it * in high priority. Restart the work
*/ return 1;
}
/* Now we have the timestamp in nanoseconds, store it in the correct * structure in order to send it to the user
*/
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(ns);
tmp_skb = ps->tx_skb;
ps->tx_skb = NULL;
/* skb_complete_tx_timestamp() frees up the client to make another * timestampable transmit. We have to be ready for it by clearing the * ps->tx_skb "flag" beforehand
*/
clear_bit_unlock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
/* Deliver a clone of the original outgoing tx_skb with tx hwtstamp */
skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
type = ptp_classify_raw(skb); if (type == PTP_CLASS_NONE) return;
/* Make sure the message is a PTP message that needs to be timestamped * and the interaction with the HW timestamping is enabled. If not, stop * here
*/
hdr = hellcreek_should_tstamp(hellcreek, port, skb, type); if (!hdr) return;
clone = skb_clone_sk(skb); if (!clone) return;
if (test_and_set_bit_lock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS,
&ps->state)) {
kfree_skb(clone); return;
}
ps->tx_skb = clone;
/* store the number of ticks occurred since system start-up till this * moment
*/
ps->tx_tstamp_start = jiffies;
/* This check only fails if the user did not initialize hardware * timestamping beforehand.
*/ if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT) returnfalse;
/* Make sure the message is a PTP message that needs to be timestamped * and the interaction with the HW timestamping is enabled. If not, stop * here
*/
hdr = hellcreek_should_tstamp(hellcreek, port, skb, type); if (!hdr) returnfalse;
int hellcreek_hwtstamp_setup(struct hellcreek *hellcreek)
{ struct dsa_switch *ds = hellcreek->ds; int i;
/* Initialize timestamping ports. */ for (i = 0; i < ds->num_ports; ++i) { if (!dsa_is_user_port(ds, i)) continue;
hellcreek_hwtstamp_port_setup(hellcreek, i);
}
/* Select the synchronized clock as the source timekeeper for the * timestamps and enable inline timestamping.
*/
hellcreek_ptp_write(hellcreek, PR_SETTINGS_C_TS_SRC_TK_MASK |
PR_SETTINGS_C_RES3TS,
PR_SETTINGS_C);
return 0;
}
void hellcreek_hwtstamp_free(struct hellcreek *hellcreek)
{ /* Nothing todo */
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.