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+
306363static 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
330391static 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+
334412static 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,
396484err_register_ds :
397485 kfree (ds );
398486err_alloc_ds :
487+ err_alloc_irq :
399488err_alloc_felix :
400489 kfree (felix );
401490err_dma :
0 commit comments