net: dsa: sja1105: Expose PTP timestamping ioctls to userspace
This enables the PTP support towards userspace applications such as linuxptp. The switches can timestamp only trapped multicast MAC frames, and therefore only the profiles of 1588 over L2 are supported. TX timestamping can be enabled per port, but RX timestamping is enabled globally. As long as RX timestamping is enabled, the switch will emit metadata follow-up frames that will be processed by the tagger. It may be a problem that linuxptp does not restore the RX timestamping settings when exiting. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f3097be21b
commit
a602afd200
@ -1755,6 +1755,100 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds,
|
|||||||
return sja1105_static_config_reload(priv);
|
return sja1105_static_config_reload(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Caller must hold priv->tagger_data.meta_lock */
|
||||||
|
static int sja1105_change_rxtstamping(struct sja1105_private *priv,
|
||||||
|
bool on)
|
||||||
|
{
|
||||||
|
struct sja1105_general_params_entry *general_params;
|
||||||
|
struct sja1105_table *table;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
|
||||||
|
general_params = table->entries;
|
||||||
|
general_params->send_meta1 = on;
|
||||||
|
general_params->send_meta0 = on;
|
||||||
|
|
||||||
|
rc = sja1105_init_avb_params(priv, on);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Initialize the meta state machine to a known state */
|
||||||
|
if (priv->tagger_data.stampable_skb) {
|
||||||
|
kfree_skb(priv->tagger_data.stampable_skb);
|
||||||
|
priv->tagger_data.stampable_skb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sja1105_static_config_reload(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
|
||||||
|
struct ifreq *ifr)
|
||||||
|
{
|
||||||
|
struct sja1105_private *priv = ds->priv;
|
||||||
|
struct hwtstamp_config config;
|
||||||
|
bool rx_on;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
switch (config.tx_type) {
|
||||||
|
case HWTSTAMP_TX_OFF:
|
||||||
|
priv->ports[port].hwts_tx_en = false;
|
||||||
|
break;
|
||||||
|
case HWTSTAMP_TX_ON:
|
||||||
|
priv->ports[port].hwts_tx_en = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (config.rx_filter) {
|
||||||
|
case HWTSTAMP_FILTER_NONE:
|
||||||
|
rx_on = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rx_on = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_on != priv->tagger_data.hwts_rx_en) {
|
||||||
|
spin_lock(&priv->tagger_data.meta_lock);
|
||||||
|
rc = sja1105_change_rxtstamping(priv, rx_on);
|
||||||
|
spin_unlock(&priv->tagger_data.meta_lock);
|
||||||
|
if (rc < 0) {
|
||||||
|
dev_err(ds->dev,
|
||||||
|
"Failed to change RX timestamping: %d\n", rc);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
priv->tagger_data.hwts_rx_en = rx_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
|
||||||
|
struct ifreq *ifr)
|
||||||
|
{
|
||||||
|
struct sja1105_private *priv = ds->priv;
|
||||||
|
struct hwtstamp_config config;
|
||||||
|
|
||||||
|
config.flags = 0;
|
||||||
|
if (priv->ports[port].hwts_tx_en)
|
||||||
|
config.tx_type = HWTSTAMP_TX_ON;
|
||||||
|
else
|
||||||
|
config.tx_type = HWTSTAMP_TX_OFF;
|
||||||
|
if (priv->tagger_data.hwts_rx_en)
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
|
||||||
|
else
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||||
|
|
||||||
|
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
||||||
|
-EFAULT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define to_tagger(d) \
|
#define to_tagger(d) \
|
||||||
container_of((d), struct sja1105_tagger_data, rxtstamp_work)
|
container_of((d), struct sja1105_tagger_data, rxtstamp_work)
|
||||||
#define to_sja1105(d) \
|
#define to_sja1105(d) \
|
||||||
@ -1847,6 +1941,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
|
|||||||
.port_mdb_add = sja1105_mdb_add,
|
.port_mdb_add = sja1105_mdb_add,
|
||||||
.port_mdb_del = sja1105_mdb_del,
|
.port_mdb_del = sja1105_mdb_del,
|
||||||
.port_deferred_xmit = sja1105_port_deferred_xmit,
|
.port_deferred_xmit = sja1105_port_deferred_xmit,
|
||||||
|
.port_hwtstamp_get = sja1105_hwtstamp_get,
|
||||||
|
.port_hwtstamp_set = sja1105_hwtstamp_set,
|
||||||
.port_rxtstamp = sja1105_port_rxtstamp,
|
.port_rxtstamp = sja1105_port_rxtstamp,
|
||||||
.port_txtstamp = sja1105_port_txtstamp,
|
.port_txtstamp = sja1105_port_txtstamp,
|
||||||
};
|
};
|
||||||
|
@ -70,8 +70,10 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port,
|
|||||||
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
|
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
|
||||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||||
info->tx_types = (1 << HWTSTAMP_TX_OFF);
|
info->tx_types = (1 << HWTSTAMP_TX_OFF) |
|
||||||
info->rx_filters = (1 << HWTSTAMP_FILTER_NONE);
|
(1 << HWTSTAMP_TX_ON);
|
||||||
|
info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
|
||||||
|
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
|
||||||
info->phc_index = ptp_clock_index(priv->clock);
|
info->phc_index = ptp_clock_index(priv->clock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user