3
3
*/
4
4
#include <uapi/linux/if_bridge.h>
5
5
#include <soc/mscc/ocelot.h>
6
+ #include <linux/packing.h>
6
7
#include <linux/module.h>
7
8
#include <linux/pci.h>
8
9
#include <linux/of.h>
@@ -303,6 +304,62 @@ static void felix_teardown(struct dsa_switch *ds)
303
304
ocelot_deinit (ocelot );
304
305
}
305
306
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
+
306
363
static const struct dsa_switch_ops felix_switch_ops = {
307
364
.get_tag_protocol = felix_get_tag_protocol ,
308
365
.setup = felix_setup ,
@@ -325,12 +382,33 @@ static const struct dsa_switch_ops felix_switch_ops = {
325
382
.port_vlan_filtering = felix_vlan_filtering ,
326
383
.port_vlan_add = felix_vlan_add ,
327
384
.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 ,
328
389
};
329
390
330
391
static struct felix_info * felix_instance_tbl [] = {
331
392
[FELIX_INSTANCE_VSC9959 ] = & felix_info_vsc9959 ,
332
393
};
333
394
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
+
334
412
static int felix_pci_probe (struct pci_dev * pdev ,
335
413
const struct pci_device_id * id )
336
414
{
@@ -372,6 +450,16 @@ static int felix_pci_probe(struct pci_dev *pdev,
372
450
373
451
pci_set_master (pdev );
374
452
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
+
375
463
ds = kzalloc (sizeof (struct dsa_switch ), GFP_KERNEL );
376
464
if (!ds ) {
377
465
err = - ENOMEM ;
@@ -396,6 +484,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
396
484
err_register_ds :
397
485
kfree (ds );
398
486
err_alloc_ds :
487
+ err_alloc_irq :
399
488
err_alloc_felix :
400
489
kfree (felix );
401
490
err_dma :
0 commit comments