@@ -1136,6 +1136,10 @@ static inline void restore_sprs(struct thread_struct *old_thread,
1136
1136
if (old_thread -> tar != new_thread -> tar )
1137
1137
mtspr (SPRN_TAR , new_thread -> tar );
1138
1138
}
1139
+
1140
+ if (cpu_has_feature (CPU_FTR_ARCH_300 ) &&
1141
+ old_thread -> tidr != new_thread -> tidr )
1142
+ mtspr (SPRN_TIDR , new_thread -> tidr );
1139
1143
#endif
1140
1144
}
1141
1145
@@ -1451,6 +1455,116 @@ void flush_thread(void)
1451
1455
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
1452
1456
}
1453
1457
1458
+ #ifdef CONFIG_PPC64
1459
+ static DEFINE_SPINLOCK (vas_thread_id_lock );
1460
+ static DEFINE_IDA (vas_thread_ida );
1461
+
1462
+ /*
1463
+ * We need to assign a unique thread id to each thread in a process.
1464
+ *
1465
+ * This thread id, referred to as TIDR, and separate from the Linux's tgid,
1466
+ * is intended to be used to direct an ASB_Notify from the hardware to the
1467
+ * thread, when a suitable event occurs in the system.
1468
+ *
1469
+ * One such event is a "paste" instruction in the context of Fast Thread
1470
+ * Wakeup (aka Core-to-core wake up in the Virtual Accelerator Switchboard
1471
+ * (VAS) in POWER9.
1472
+ *
1473
+ * To get a unique TIDR per process we could simply reuse task_pid_nr() but
1474
+ * the problem is that task_pid_nr() is not yet available copy_thread() is
1475
+ * called. Fixing that would require changing more intrusive arch-neutral
1476
+ * code in code path in copy_process()?.
1477
+ *
1478
+ * Further, to assign unique TIDRs within each process, we need an atomic
1479
+ * field (or an IDR) in task_struct, which again intrudes into the arch-
1480
+ * neutral code. So try to assign globally unique TIDRs for now.
1481
+ *
1482
+ * NOTE: TIDR 0 indicates that the thread does not need a TIDR value.
1483
+ * For now, only threads that expect to be notified by the VAS
1484
+ * hardware need a TIDR value and we assign values > 0 for those.
1485
+ */
1486
+ #define MAX_THREAD_CONTEXT ((1 << 16) - 1)
1487
+ static int assign_thread_tidr (void )
1488
+ {
1489
+ int index ;
1490
+ int err ;
1491
+
1492
+ again :
1493
+ if (!ida_pre_get (& vas_thread_ida , GFP_KERNEL ))
1494
+ return - ENOMEM ;
1495
+
1496
+ spin_lock (& vas_thread_id_lock );
1497
+ err = ida_get_new_above (& vas_thread_ida , 1 , & index );
1498
+ spin_unlock (& vas_thread_id_lock );
1499
+
1500
+ if (err == - EAGAIN )
1501
+ goto again ;
1502
+ else if (err )
1503
+ return err ;
1504
+
1505
+ if (index > MAX_THREAD_CONTEXT ) {
1506
+ spin_lock (& vas_thread_id_lock );
1507
+ ida_remove (& vas_thread_ida , index );
1508
+ spin_unlock (& vas_thread_id_lock );
1509
+ return - ENOMEM ;
1510
+ }
1511
+
1512
+ return index ;
1513
+ }
1514
+
1515
+ static void free_thread_tidr (int id )
1516
+ {
1517
+ spin_lock (& vas_thread_id_lock );
1518
+ ida_remove (& vas_thread_ida , id );
1519
+ spin_unlock (& vas_thread_id_lock );
1520
+ }
1521
+
1522
+ /*
1523
+ * Clear any TIDR value assigned to this thread.
1524
+ */
1525
+ void clear_thread_tidr (struct task_struct * t )
1526
+ {
1527
+ if (!t -> thread .tidr )
1528
+ return ;
1529
+
1530
+ if (!cpu_has_feature (CPU_FTR_ARCH_300 )) {
1531
+ WARN_ON_ONCE (1 );
1532
+ return ;
1533
+ }
1534
+
1535
+ mtspr (SPRN_TIDR , 0 );
1536
+ free_thread_tidr (t -> thread .tidr );
1537
+ t -> thread .tidr = 0 ;
1538
+ }
1539
+
1540
+ void arch_release_task_struct (struct task_struct * t )
1541
+ {
1542
+ clear_thread_tidr (t );
1543
+ }
1544
+
1545
+ /*
1546
+ * Assign a unique TIDR (thread id) for task @t and set it in the thread
1547
+ * structure. For now, we only support setting TIDR for 'current' task.
1548
+ */
1549
+ int set_thread_tidr (struct task_struct * t )
1550
+ {
1551
+ if (!cpu_has_feature (CPU_FTR_ARCH_300 ))
1552
+ return - EINVAL ;
1553
+
1554
+ if (t != current )
1555
+ return - EINVAL ;
1556
+
1557
+ t -> thread .tidr = assign_thread_tidr ();
1558
+ if (t -> thread .tidr < 0 )
1559
+ return t -> thread .tidr ;
1560
+
1561
+ mtspr (SPRN_TIDR , t -> thread .tidr );
1562
+
1563
+ return 0 ;
1564
+ }
1565
+
1566
+ #endif /* CONFIG_PPC64 */
1567
+
1454
1568
void
1455
1569
release_thread (struct task_struct * t )
1456
1570
{
@@ -1597,6 +1711,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
1597
1711
}
1598
1712
if (cpu_has_feature (CPU_FTR_HAS_PPR ))
1599
1713
p -> thread .ppr = INIT_PPR ;
1714
+
1715
+ p -> thread .tidr = 0 ;
1600
1716
#endif
1601
1717
kregs -> nip = ppc_function_entry (f );
1602
1718
return 0 ;
0 commit comments