Commit aae0fdac authored by David S. Miller's avatar David S. Miller

Merge branch 'ocelot-ptp'

Yangbo Lu says:

====================
Support Ocelot PTP Sync one-step timestamping

This patch-set is to support Ocelot PTP Sync one-step timestamping.
Actually before that, this patch-set cleans up and optimizes the
DSA slave tx timestamp request handling process.

Changes for v2:
	- Split tx timestamp optimization patch.
	- Updated doc patch.
	- Freed skb->cb usage in dsa core driver, and moved to device
	  drivers.
	- Other minor fixes.
Changes for v3:
	- Switched sequence of patch #3 and #4 with rebasing to fix build.
	- Replaced hard coded 48 of memset(skb->cb, 0, 48) with sizeof().
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 23c9c2b3 39e5308b
......@@ -630,30 +630,45 @@ hardware timestamping on it. This is because the SO_TIMESTAMPING API does not
allow the delivery of multiple hardware timestamps for the same packet, so
anybody else except for the DSA switch port must be prevented from doing so.
In code, DSA provides for most of the infrastructure for timestamping already,
in generic code: a BPF classifier (``ptp_classify_raw``) is used to identify
PTP event messages (any other packets, including PTP general messages, are not
timestamped), and provides two hooks to drivers:
- ``.port_txtstamp()``: The driver is passed a clone of the timestampable skb
to be transmitted, before actually transmitting it. Typically, a switch will
have a PTP TX timestamp register (or sometimes a FIFO) where the timestamp
becomes available. There may be an IRQ that is raised upon this timestamp's
availability, or the driver might have to poll after invoking
``dev_queue_xmit()`` towards the host interface. Either way, in the
``.port_txtstamp()`` method, the driver only needs to save the clone for
later use (when the timestamp becomes available). Each skb is annotated with
a pointer to its clone, in ``DSA_SKB_CB(skb)->clone``, to ease the driver's
job of keeping track of which clone belongs to which skb.
- ``.port_rxtstamp()``: The original (and only) timestampable skb is provided
to the driver, for it to annotate it with a timestamp, if that is immediately
available, or defer to later. On reception, timestamps might either be
available in-band (through metadata in the DSA header, or attached in other
ways to the packet), or out-of-band (through another RX timestamping FIFO).
Deferral on RX is typically necessary when retrieving the timestamp needs a
sleepable context. In that case, it is the responsibility of the DSA driver
to call ``netif_rx_ni()`` on the freshly timestamped skb.
In the generic layer, DSA provides the following infrastructure for PTP
timestamping:
- ``.port_txtstamp()``: a hook called prior to the transmission of
packets with a hardware TX timestamping request from user space.
This is required for two-step timestamping, since the hardware
timestamp becomes available after the actual MAC transmission, so the
driver must be prepared to correlate the timestamp with the original
packet so that it can re-enqueue the packet back into the socket's
error queue. To save the packet for when the timestamp becomes
available, the driver can call ``skb_clone_sk`` , save the clone pointer
in skb->cb and enqueue a tx skb queue. Typically, a switch will have a
PTP TX timestamp register (or sometimes a FIFO) where the timestamp
becomes available. In case of a FIFO, the hardware might store
key-value pairs of PTP sequence ID/message type/domain number and the
actual timestamp. To perform the correlation correctly between the
packets in a queue waiting for timestamping and the actual timestamps,
drivers can use a BPF classifier (``ptp_classify_raw``) to identify
the PTP transport type, and ``ptp_parse_header`` to interpret the PTP
header fields. There may be an IRQ that is raised upon this
timestamp's availability, or the driver might have to poll after
invoking ``dev_queue_xmit()`` towards the host interface.
One-step TX timestamping do not require packet cloning, since there is
no follow-up message required by the PTP protocol (because the
TX timestamp is embedded into the packet by the MAC), and therefore
user space does not expect the packet annotated with the TX timestamp
to be re-enqueued into its socket's error queue.
- ``.port_rxtstamp()``: On RX, the BPF classifier is run by DSA to
identify PTP event messages (any other packets, including PTP general
messages, are not timestamped). The original (and only) timestampable
skb is provided to the driver, for it to annotate it with a timestamp,
if that is immediately available, or defer to later. On reception,
timestamps might either be available in-band (through metadata in the
DSA header, or attached in other ways to the packet), or out-of-band
(through another RX timestamping FIFO). Deferral on RX is typically
necessary when retrieving the timestamp needs a sleepable context. In
that case, it is the responsibility of the DSA driver to call
``netif_rx_ni()`` on the freshly timestamped skb.
3.2.2 Ethernet PHYs
^^^^^^^^^^^^^^^^^^^
......
......@@ -373,30 +373,38 @@ long hellcreek_hwtstamp_work(struct ptp_clock_info *ptp)
return restart ? 1 : -1;
}
bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type)
void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
struct hellcreek *hellcreek = ds->priv;
struct hellcreek_port_hwtstamp *ps;
struct ptp_header *hdr;
struct sk_buff *clone;
unsigned int type;
ps = &hellcreek->ports[port].port_hwtstamp;
/* Check if the driver is expected to do HW timestamping */
if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
return false;
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, clone, type);
hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
if (!hdr)
return false;
return;
clone = skb_clone_sk(skb);
if (!clone)
return;
if (test_and_set_bit_lock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS,
&ps->state))
return false;
&ps->state)) {
kfree_skb(clone);
return;
}
ps->tx_skb = clone;
......@@ -406,8 +414,6 @@ bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
ps->tx_tstamp_start = jiffies;
ptp_schedule_worker(hellcreek->ptp_clock, 0);
return true;
}
bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
......
......@@ -44,8 +44,8 @@ int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb);
int hellcreek_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info);
......
......@@ -468,30 +468,38 @@ long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
return restart ? 1 : -1;
}
bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type)
void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
struct ptp_header *hdr;
struct sk_buff *clone;
unsigned int type;
if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
return false;
type = ptp_classify_raw(skb);
if (type == PTP_CLASS_NONE)
return;
hdr = mv88e6xxx_should_tstamp(chip, port, clone, type);
hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
if (!hdr)
return false;
return;
clone = skb_clone_sk(skb);
if (!clone)
return;
if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
&ps->state))
return false;
&ps->state)) {
kfree_skb(clone);
return;
}
ps->tx_skb = clone;
ps->tx_tstamp_start = jiffies;
ps->tx_seq_id = be16_to_cpu(hdr->sequence_id);
ptp_schedule_worker(chip->ptp_clock, 0);
return true;
}
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
......
......@@ -117,8 +117,8 @@ int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb);
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info);
......@@ -151,11 +151,9 @@ static inline bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
return false;
}
static inline bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone,
unsigned int type)
static inline void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
return false;
}
static inline int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
......
......@@ -1395,19 +1395,20 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
return false;
}
static bool felix_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type)
static void felix_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
struct ocelot *ocelot = ds->priv;
struct ocelot_port *ocelot_port = ocelot->ports[port];
struct sk_buff *clone = NULL;
if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) &&
ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
ocelot_port_add_txtstamp_skb(ocelot, port, clone);
return true;
}
if (!ocelot->ptp)
return;
return false;
if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone))
return;
if (clone)
OCELOT_SKB_CB(skb)->clone = clone;
}
static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
......
......@@ -3137,7 +3137,7 @@ static void sja1105_port_deferred_xmit(struct kthread_work *work)
struct sk_buff *skb;
while ((skb = skb_dequeue(&sp->xmit_queue)) != NULL) {
struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
mutex_lock(&priv->mgmt_lock);
......
......@@ -431,20 +431,24 @@ bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
return true;
}
/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone
* the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit
/* Called from dsa_skb_tx_timestamp. This callback is just to clone
* the skb and have it available in SJA1105_SKB_CB in the .port_deferred_xmit
* callback, where we will timestamp it synchronously.
*/
bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type)
void sja1105_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_port *sp = &priv->ports[port];
struct sk_buff *clone;
if (!sp->hwts_tx_en)
return false;
return;
return true;
clone = skb_clone_sk(skb);
if (!clone)
return;
SJA1105_SKB_CB(skb)->clone = clone;
}
static int sja1105_ptp_reset(struct dsa_switch *ds)
......
......@@ -104,8 +104,8 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot,
bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type);
bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type);
void sja1105_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb);
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
......
......@@ -6,6 +6,7 @@
*/
#include <linux/dsa/ocelot.h>
#include <linux/if_bridge.h>
#include <linux/ptp_classify.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h"
#include "ocelot_vcap.h"
......@@ -530,7 +531,7 @@ void ocelot_port_disable(struct ocelot *ocelot, int port)
}
EXPORT_SYMBOL(ocelot_port_disable);
void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
static void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
struct sk_buff *clone)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
......@@ -538,14 +539,84 @@ void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
spin_lock(&ocelot_port->ts_id_lock);
skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
/* Store timestamp ID in cb[0] of sk_buff */
clone->cb[0] = ocelot_port->ts_id;
/* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id;
ocelot_port->ts_id = (ocelot_port->ts_id + 1) % 4;
skb_queue_tail(&ocelot_port->tx_skbs, clone);
spin_unlock(&ocelot_port->ts_id_lock);
}
EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb);
u32 ocelot_ptp_rew_op(struct sk_buff *skb)
{
struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone;
u8 ptp_cmd = OCELOT_SKB_CB(skb)->ptp_cmd;
u32 rew_op = 0;
if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP && clone) {
rew_op = ptp_cmd;
rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3;
} else if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
rew_op = ptp_cmd;
}
return rew_op;
}
EXPORT_SYMBOL(ocelot_ptp_rew_op);
static bool ocelot_ptp_is_onestep_sync(struct sk_buff *skb)
{
struct ptp_header *hdr;
unsigned int ptp_class;
u8 msgtype, twostep;
ptp_class = ptp_classify_raw(skb);
if (ptp_class == PTP_CLASS_NONE)
return false;
hdr = ptp_parse_header(skb, ptp_class);
if (!hdr)
return false;
msgtype = ptp_get_msgtype(hdr, ptp_class);
twostep = hdr->flag_field[0] & 0x2;
if (msgtype == PTP_MSGTYPE_SYNC && twostep == 0)
return true;
return false;
}
int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
struct sk_buff *skb,
struct sk_buff **clone)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
u8 ptp_cmd = ocelot_port->ptp_cmd;
/* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */
if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
if (ocelot_ptp_is_onestep_sync(skb)) {
OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
return 0;
}
/* Fall back to two-step timestamping */
ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
}
if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
*clone = skb_clone_sk(skb);
if (!(*clone))
return -ENOMEM;
ocelot_port_add_txtstamp_skb(ocelot, port, *clone);
OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
}
return 0;
}
EXPORT_SYMBOL(ocelot_port_txtstamp_request);
static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
struct timespec64 *ts)
......@@ -604,7 +675,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
spin_lock_irqsave(&port->tx_skbs.lock, flags);
skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
if (skb->cb[0] != id)
if (OCELOT_SKB_CB(skb)->ts_id != id)
continue;
__skb_unlink(skb, &port->tx_skbs);
skb_match = skb;
......
......@@ -507,21 +507,17 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check if timestamping is needed */
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
rew_op = ocelot_port->ptp_cmd;
struct sk_buff *clone = NULL;
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
struct sk_buff *clone;
clone = skb_clone_sk(skb);
if (!clone) {
if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
ocelot_port_add_txtstamp_skb(ocelot, port, clone);
if (clone)
OCELOT_SKB_CB(skb)->clone = clone;
rew_op |= clone->cb[0] << 3;
}
rew_op = ocelot_ptp_rew_op(skb);
}
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
......
......@@ -47,11 +47,12 @@ struct sja1105_tagger_data {
};
struct sja1105_skb_cb {
struct sk_buff *clone;
u32 meta_tstamp;
};
#define SJA1105_SKB_CB(skb) \
((struct sja1105_skb_cb *)DSA_SKB_CB_PRIV(skb))
((struct sja1105_skb_cb *)((skb)->cb))
struct sja1105_port {
u16 subvlan_map[DSA_8021Q_N_SUBVLAN];
......
......@@ -117,20 +117,6 @@ struct dsa_netdevice_ops {
#define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \
MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
struct dsa_skb_cb {
struct sk_buff *clone;
};
struct __dsa_skb_cb {
struct dsa_skb_cb cb;
u8 priv[48 - sizeof(struct dsa_skb_cb)];
};
#define DSA_SKB_CB(skb) ((struct dsa_skb_cb *)((skb)->cb))
#define DSA_SKB_CB_PRIV(skb) \
((void *)(skb)->cb + offsetof(struct __dsa_skb_cb, priv))
struct dsa_switch_tree {
struct list_head list;
......@@ -740,8 +726,8 @@ struct dsa_switch_ops {
struct ifreq *ifr);
int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
bool (*port_txtstamp)(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
void (*port_txtstamp)(struct dsa_switch *ds, int port,
struct sk_buff *skb);
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type);
......
......@@ -689,6 +689,15 @@ struct ocelot_policer {
u32 burst; /* bytes */
};
struct ocelot_skb_cb {
struct sk_buff *clone;
u8 ptp_cmd;
u8 ts_id;
};
#define OCELOT_SKB_CB(skb) \
((struct ocelot_skb_cb *)((skb)->cb))
#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi))
#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri))
......@@ -740,15 +749,16 @@ u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset);
/* Packet I/O */
#if IS_ENABLED(CONFIG_MSCC_OCELOT_SWITCH_LIB)
/* Packet I/O */
bool ocelot_can_inject(struct ocelot *ocelot, int grp);
void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
u32 rew_op, struct sk_buff *skb);
int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **skb);
void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp);
u32 ocelot_ptp_rew_op(struct sk_buff *skb);
#else
static inline bool ocelot_can_inject(struct ocelot *ocelot, int grp)
......@@ -772,6 +782,10 @@ static inline void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp)
{
}
static inline u32 ocelot_ptp_rew_op(struct sk_buff *skb)
{
return 0;
}
#endif
/* Hardware initialization */
......@@ -820,8 +834,9 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
struct sk_buff *clone);
int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
struct sk_buff *skb,
struct sk_buff **clone);
void ocelot_get_txtstamp(struct ocelot *ocelot);
void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu);
int ocelot_get_max_mtu(struct ocelot *ocelot, int port);
......
......@@ -111,6 +111,8 @@ config NET_DSA_TAG_RTL4_A
config NET_DSA_TAG_OCELOT
tristate "Tag driver for Ocelot family of switches, using NPI port"
depends on MSCC_OCELOT_SWITCH_LIB || \
(MSCC_OCELOT_SWITCH_LIB=n && COMPILE_TEST)
select PACKING
help
Say Y or M if you want to enable NPI tagging for the Ocelot switches
......
......@@ -20,7 +20,6 @@
#include <linux/if_bridge.h>
#include <linux/if_hsr.h>
#include <linux/netpoll.h>
#include <linux/ptp_classify.h>
#include "dsa_priv.h"
......@@ -556,26 +555,14 @@ static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
struct sk_buff *skb)
{
struct dsa_switch *ds = p->dp->ds;
struct sk_buff *clone;
unsigned int type;
type = ptp_classify_raw(skb);
if (type == PTP_CLASS_NONE)
if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
return;
if (!ds->ops->port_txtstamp)
return;
clone = skb_clone_sk(skb);
if (!clone)
return;
if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type)) {
DSA_SKB_CB(skb)->clone = clone;
return;
}
kfree_skb(clone);
ds->ops->port_txtstamp(ds, p->dp->index, skb);
}
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
......@@ -627,11 +614,9 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
dev_sw_netstats_tx_add(dev, 1, skb->len);
DSA_SKB_CB(skb)->clone = NULL;
memset(skb->cb, 0, sizeof(skb->cb));
/* Identify PTP protocol packets, clone them, and pass them to the
* switch driver
*/
/* Handle tx timestamp if any */
dsa_skb_tx_timestamp(p, skb);
if (dsa_realloc_skb(skb, dev)) {
......
......@@ -5,33 +5,14 @@
#include <soc/mscc/ocelot.h>
#include "dsa_priv.h"
static void ocelot_xmit_ptp(struct dsa_port *dp, void *injection,
struct sk_buff *clone)
{
struct ocelot *ocelot = dp->ds->priv;
struct ocelot_port *ocelot_port;
u64 rew_op;
ocelot_port = ocelot->ports[dp->index];
rew_op = ocelot_port->ptp_cmd;
/* Retrieve timestamp ID populated inside skb->cb[0] of the
* clone by ocelot_port_add_txtstamp_skb
*/
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
rew_op |= clone->cb[0] << 3;
ocelot_ifh_set_rew_op(injection, rew_op);
}
static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
__be32 ifh_prefix, void **ifh)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
struct dsa_switch *ds = dp->ds;
void *injection;
__be32 *prefix;
u32 rew_op = 0;
injection = skb_push(skb, OCELOT_TAG_LEN);
prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
......@@ -42,9 +23,9 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
ocelot_ifh_set_src(injection, ds->num_ports);
ocelot_ifh_set_qos_class(injection, skb->priority);
/* TX timestamping was requested */
if (clone)
ocelot_xmit_ptp(dp, injection, clone);
rew_op = ocelot_ptp_rew_op(skb);
if (rew_op)
ocelot_ifh_set_rew_op(injection, rew_op);
*ifh = injection;
}
......
......@@ -13,44 +13,25 @@
#include <soc/mscc/ocelot_ptp.h>
#include "dsa_priv.h"
static struct sk_buff *ocelot_xmit_ptp(struct dsa_port *dp,
struct sk_buff *skb,
struct sk_buff *clone)
static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
struct ocelot *ocelot = dp->ds->priv;
struct ocelot_port *ocelot_port;
int port = dp->index;
u32 rew_op;
u32 rew_op = 0;
rew_op = ocelot_ptp_rew_op(skb);
if (rew_op) {
if (!ocelot_can_inject(ocelot, 0))
return NULL;
ocelot_port = ocelot->ports[port];
rew_op = ocelot_port->ptp_cmd;
/* Retrieve timestamp ID populated inside skb->cb[0] of the
* clone by ocelot_port_add_txtstamp_skb
*/
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
rew_op |= clone->cb[0] << 3;
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
return NULL;
}
static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
/* TX timestamping was requested, so inject through MMIO */
if (clone)
return ocelot_xmit_ptp(dp, skb, clone);
}
return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q,
((pcp << VLAN_PRIO_SHIFT) | tx_vid));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment