Skip to content

Commit c0bcf53

Browse files
yangbolu1991davem330
authored andcommitted
net: dsa: ocelot: add hardware timestamping support for Felix
This patch is to reuse ocelot functions as possible to enable PTP clock and to support hardware timestamping on Felix. On TX path, timestamping works on packet which requires timestamp. The injection header will be configured accordingly, and skb clone requires timestamp will be added into a list. The TX timestamp is final handled in threaded interrupt handler when PTP timestamp FIFO is ready. On RX path, timestamping is always working. The RX timestamp could be got from extraction header. Signed-off-by: Yangbo Lu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5df66c4 commit c0bcf53

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
#include <uapi/linux/if_bridge.h>
55
#include <soc/mscc/ocelot.h>
6+
#include <linux/packing.h>
67
#include <linux/module.h>
78
#include <linux/pci.h>
89
#include <linux/of.h>
@@ -303,6 +304,62 @@ static void felix_teardown(struct dsa_switch *ds)
303304
ocelot_deinit(ocelot);
304305
}
305306

307+
static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
308+
struct ifreq *ifr)
309+
{
310+
struct ocelot *ocelot = ds->priv;
311+
312+
return ocelot_hwstamp_get(ocelot, port, ifr);
313+
}
314+
315+
static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
316+
struct ifreq *ifr)
317+
{
318+
struct ocelot *ocelot = ds->priv;
319+
320+
return ocelot_hwstamp_set(ocelot, port, ifr);
321+
}
322+
323+
static bool felix_rxtstamp(struct dsa_switch *ds, int port,
324+
struct sk_buff *skb, unsigned int type)
325+
{
326+
struct skb_shared_hwtstamps *shhwtstamps;
327+
struct ocelot *ocelot = ds->priv;
328+
u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
329+
u32 tstamp_lo, tstamp_hi;
330+
struct timespec64 ts;
331+
u64 tstamp, val;
332+
333+
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
334+
tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
335+
336+
packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0);
337+
tstamp_lo = (u32)val;
338+
339+
tstamp_hi = tstamp >> 32;
340+
if ((tstamp & 0xffffffff) < tstamp_lo)
341+
tstamp_hi--;
342+
343+
tstamp = ((u64)tstamp_hi << 32) | tstamp_lo;
344+
345+
shhwtstamps = skb_hwtstamps(skb);
346+
memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
347+
shhwtstamps->hwtstamp = tstamp;
348+
return false;
349+
}
350+
351+
bool felix_txtstamp(struct dsa_switch *ds, int port,
352+
struct sk_buff *clone, unsigned int type)
353+
{
354+
struct ocelot *ocelot = ds->priv;
355+
struct ocelot_port *ocelot_port = ocelot->ports[port];
356+
357+
if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone))
358+
return true;
359+
360+
return false;
361+
}
362+
306363
static const struct dsa_switch_ops felix_switch_ops = {
307364
.get_tag_protocol = felix_get_tag_protocol,
308365
.setup = felix_setup,
@@ -325,12 +382,33 @@ static const struct dsa_switch_ops felix_switch_ops = {
325382
.port_vlan_filtering = felix_vlan_filtering,
326383
.port_vlan_add = felix_vlan_add,
327384
.port_vlan_del = felix_vlan_del,
385+
.port_hwtstamp_get = felix_hwtstamp_get,
386+
.port_hwtstamp_set = felix_hwtstamp_set,
387+
.port_rxtstamp = felix_rxtstamp,
388+
.port_txtstamp = felix_txtstamp,
328389
};
329390

330391
static struct felix_info *felix_instance_tbl[] = {
331392
[FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959,
332393
};
333394

395+
static irqreturn_t felix_irq_handler(int irq, void *data)
396+
{
397+
struct ocelot *ocelot = (struct ocelot *)data;
398+
399+
/* The INTB interrupt is used for both PTP TX timestamp interrupt
400+
* and preemption status change interrupt on each port.
401+
*
402+
* - Get txtstamp if have
403+
* - TODO: handle preemption. Without handling it, driver may get
404+
* interrupt storm.
405+
*/
406+
407+
ocelot_get_txtstamp(ocelot);
408+
409+
return IRQ_HANDLED;
410+
}
411+
334412
static int felix_pci_probe(struct pci_dev *pdev,
335413
const struct pci_device_id *id)
336414
{
@@ -372,6 +450,16 @@ static int felix_pci_probe(struct pci_dev *pdev,
372450

373451
pci_set_master(pdev);
374452

453+
err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL,
454+
&felix_irq_handler, IRQF_ONESHOT,
455+
"felix-intb", ocelot);
456+
if (err) {
457+
dev_err(&pdev->dev, "Failed to request irq\n");
458+
goto err_alloc_irq;
459+
}
460+
461+
ocelot->ptp = 1;
462+
375463
ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
376464
if (!ds) {
377465
err = -ENOMEM;
@@ -396,6 +484,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
396484
err_register_ds:
397485
kfree(ds);
398486
err_alloc_ds:
487+
err_alloc_irq:
399488
err_alloc_felix:
400489
kfree(felix);
401490
err_dma:

net/dsa/tag_ocelot.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,11 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
137137
struct net_device *netdev)
138138
{
139139
struct dsa_port *dp = dsa_slave_to_port(netdev);
140-
u64 bypass, dest, src, qos_class;
140+
u64 bypass, dest, src, qos_class, rew_op;
141141
struct dsa_switch *ds = dp->ds;
142142
int port = dp->index;
143+
struct ocelot *ocelot = ds->priv;
144+
struct ocelot_port *ocelot_port = ocelot->ports[port];
143145
u8 *injection;
144146

145147
if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
@@ -161,6 +163,16 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
161163
packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0);
162164
packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0);
163165

166+
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
167+
rew_op = ocelot_port->ptp_cmd;
168+
if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
169+
rew_op |= (ocelot_port->ts_id % 4) << 3;
170+
ocelot_port->ts_id++;
171+
}
172+
173+
packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
174+
}
175+
164176
return skb;
165177
}
166178

0 commit comments

Comments
 (0)