1
2
3
4
5
6
7
8
9
10
11
12
13#ifndef _DRIVERS_MISC_SGIXP_XPC_H
14#define _DRIVERS_MISC_SGIXP_XPC_H
15
16#include <linux/wait.h>
17#include <linux/completion.h>
18#include <linux/timer.h>
19#include <linux/sched.h>
20#include "xp.h"
21
22
23
24
25
26
27#define _XPC_VERSION(_maj, _min) (((_maj) << 4) | ((_min) & 0xf))
28#define XPC_VERSION_MAJOR(_v) ((_v) >> 4)
29#define XPC_VERSION_MINOR(_v) ((_v) & 0xf)
30
31
32#define XPC_HB_DEFAULT_INTERVAL 5
33#define XPC_HB_CHECK_DEFAULT_INTERVAL 20
34
35
36#define XPC_HB_CHECK_THREAD_NAME "xpc_hb"
37#define XPC_HB_CHECK_CPU 0
38
39
40#define XPC_DISCOVERY_THREAD_NAME "xpc_discovery"
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82struct xpc_rsvd_page {
83 u64 SAL_signature;
84 u64 SAL_version;
85 short SAL_partid;
86 short max_npartitions;
87 u8 version;
88 u8 pad1[3];
89 unsigned long ts_jiffies;
90 union {
91 struct {
92 unsigned long heartbeat_gpa;
93 unsigned long activate_gru_mq_desc_gpa;
94 } uv;
95 } sn;
96 u64 pad2[9];
97 u64 SAL_nasids_size;
98};
99
100#define XPC_RP_VERSION _XPC_VERSION(3, 0)
101
102
103
104#define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
105
106#define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \
107 XPC_RP_HEADER_SIZE))
108#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \
109 xpc_nasid_mask_nlongs)
110
111
112
113
114
115
116
117struct xpc_heartbeat_uv {
118 unsigned long value;
119 unsigned long offline;
120};
121
122
123
124
125struct xpc_gru_mq_uv {
126 void *address;
127 unsigned int order;
128 int irq;
129 int mmr_blade;
130 unsigned long mmr_offset;
131 unsigned long mmr_value;
132 int watchlist_num;
133 void *gru_mq_desc;
134};
135
136
137
138
139
140struct xpc_activate_mq_msghdr_uv {
141 unsigned int gru_msg_hdr;
142 short partid;
143 u8 act_state;
144 u8 type;
145 unsigned long rp_ts_jiffies;
146};
147
148
149#define XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV 0
150
151#define XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV 1
152#define XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV 2
153
154#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV 3
155#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV 4
156#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV 5
157#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV 6
158#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV 7
159
160#define XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV 8
161#define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 9
162
163struct xpc_activate_mq_msg_uv {
164 struct xpc_activate_mq_msghdr_uv hdr;
165};
166
167struct xpc_activate_mq_msg_activate_req_uv {
168 struct xpc_activate_mq_msghdr_uv hdr;
169 unsigned long rp_gpa;
170 unsigned long heartbeat_gpa;
171 unsigned long activate_gru_mq_desc_gpa;
172};
173
174struct xpc_activate_mq_msg_deactivate_req_uv {
175 struct xpc_activate_mq_msghdr_uv hdr;
176 enum xp_retval reason;
177};
178
179struct xpc_activate_mq_msg_chctl_closerequest_uv {
180 struct xpc_activate_mq_msghdr_uv hdr;
181 short ch_number;
182 enum xp_retval reason;
183};
184
185struct xpc_activate_mq_msg_chctl_closereply_uv {
186 struct xpc_activate_mq_msghdr_uv hdr;
187 short ch_number;
188};
189
190struct xpc_activate_mq_msg_chctl_openrequest_uv {
191 struct xpc_activate_mq_msghdr_uv hdr;
192 short ch_number;
193 short entry_size;
194 short local_nentries;
195};
196
197struct xpc_activate_mq_msg_chctl_openreply_uv {
198 struct xpc_activate_mq_msghdr_uv hdr;
199 short ch_number;
200 short remote_nentries;
201 short local_nentries;
202 unsigned long notify_gru_mq_desc_gpa;
203};
204
205struct xpc_activate_mq_msg_chctl_opencomplete_uv {
206 struct xpc_activate_mq_msghdr_uv hdr;
207 short ch_number;
208};
209
210
211
212
213
214
215
216#define XPC_PACK_ARGS(_arg1, _arg2) \
217 ((((u64)_arg1) & 0xffffffff) | \
218 ((((u64)_arg2) & 0xffffffff) << 32))
219
220#define XPC_UNPACK_ARG1(_args) (((u64)_args) & 0xffffffff)
221#define XPC_UNPACK_ARG2(_args) ((((u64)_args) >> 32) & 0xffffffff)
222
223
224
225
226
227struct xpc_openclose_args {
228 u16 reason;
229 u16 entry_size;
230 u16 remote_nentries;
231 u16 local_nentries;
232 unsigned long local_msgqueue_pa;
233};
234
235#define XPC_OPENCLOSE_ARGS_SIZE \
236 L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \
237 XPC_MAX_NCHANNELS)
238
239
240
241
242
243
244struct xpc_fifo_entry_uv {
245 struct xpc_fifo_entry_uv *next;
246};
247
248struct xpc_fifo_head_uv {
249 struct xpc_fifo_entry_uv *first;
250 struct xpc_fifo_entry_uv *last;
251 spinlock_t lock;
252 int n_entries;
253};
254
255
256
257
258
259
260
261
262
263
264
265struct xpc_notify_mq_msghdr_uv {
266 union {
267 unsigned int gru_msg_hdr;
268 struct xpc_fifo_entry_uv next;
269 } u;
270 short partid;
271 u8 ch_number;
272 u8 size;
273 unsigned int msg_slot_number;
274};
275
276struct xpc_notify_mq_msg_uv {
277 struct xpc_notify_mq_msghdr_uv hdr;
278 unsigned long payload;
279};
280
281
282
283#define XPC_N_CALL 0x01
284
285
286
287
288
289struct xpc_send_msg_slot_uv {
290 struct xpc_fifo_entry_uv next;
291 unsigned int msg_slot_number;
292 xpc_notify_func func;
293 void *key;
294};
295
296
297
298
299
300
301
302
303
304
305
306
307
308struct xpc_channel_uv {
309 void *cached_notify_gru_mq_desc;
310
311
312 struct xpc_send_msg_slot_uv *send_msg_slots;
313 void *recv_msg_slots;
314
315
316 struct xpc_fifo_head_uv msg_slot_free_list;
317 struct xpc_fifo_head_uv recv_msg_list;
318};
319
320struct xpc_channel {
321 short partid;
322 spinlock_t lock;
323 unsigned int flags;
324
325 enum xp_retval reason;
326 int reason_line;
327
328 u16 number;
329
330 u16 entry_size;
331 u16 local_nentries;
332 u16 remote_nentries;
333
334 atomic_t references;
335
336 atomic_t n_on_msg_allocate_wq;
337 wait_queue_head_t msg_allocate_wq;
338
339 u8 delayed_chctl_flags;
340
341
342 atomic_t n_to_notify;
343
344 xpc_channel_func func;
345 void *key;
346
347 struct completion wdisconnect_wait;
348
349
350
351 atomic_t kthreads_assigned;
352 u32 kthreads_assigned_limit;
353 atomic_t kthreads_idle;
354 u32 kthreads_idle_limit;
355 atomic_t kthreads_active;
356
357 wait_queue_head_t idle_wq;
358
359 union {
360 struct xpc_channel_uv uv;
361 } sn;
362
363} ____cacheline_aligned;
364
365
366
367#define XPC_C_WASCONNECTED 0x00000001
368
369#define XPC_C_ROPENCOMPLETE 0x00000002
370#define XPC_C_OPENCOMPLETE 0x00000004
371#define XPC_C_ROPENREPLY 0x00000008
372#define XPC_C_OPENREPLY 0x00000010
373#define XPC_C_ROPENREQUEST 0x00000020
374#define XPC_C_OPENREQUEST 0x00000040
375
376#define XPC_C_SETUP 0x00000080
377#define XPC_C_CONNECTEDCALLOUT 0x00000100
378#define XPC_C_CONNECTEDCALLOUT_MADE \
379 0x00000200
380#define XPC_C_CONNECTED 0x00000400
381#define XPC_C_CONNECTING 0x00000800
382
383#define XPC_C_RCLOSEREPLY 0x00001000
384#define XPC_C_CLOSEREPLY 0x00002000
385#define XPC_C_RCLOSEREQUEST 0x00004000
386#define XPC_C_CLOSEREQUEST 0x00008000
387
388#define XPC_C_DISCONNECTED 0x00010000
389#define XPC_C_DISCONNECTING 0x00020000
390#define XPC_C_DISCONNECTINGCALLOUT \
391 0x00040000
392#define XPC_C_DISCONNECTINGCALLOUT_MADE \
393 0x00080000
394#define XPC_C_WDISCONNECT 0x00100000
395
396
397
398
399
400
401
402
403union xpc_channel_ctl_flags {
404 u64 all_flags;
405 u8 flags[XPC_MAX_NCHANNELS];
406};
407
408
409#define XPC_CHCTL_CLOSEREQUEST 0x01
410#define XPC_CHCTL_CLOSEREPLY 0x02
411#define XPC_CHCTL_OPENREQUEST 0x04
412#define XPC_CHCTL_OPENREPLY 0x08
413#define XPC_CHCTL_OPENCOMPLETE 0x10
414#define XPC_CHCTL_MSGREQUEST 0x20
415
416#define XPC_OPENCLOSE_CHCTL_FLAGS \
417 (XPC_CHCTL_CLOSEREQUEST | XPC_CHCTL_CLOSEREPLY | \
418 XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY | \
419 XPC_CHCTL_OPENCOMPLETE)
420#define XPC_MSG_CHCTL_FLAGS XPC_CHCTL_MSGREQUEST
421
422static inline int
423xpc_any_openclose_chctl_flags_set(union xpc_channel_ctl_flags *chctl)
424{
425 int ch_number;
426
427 for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) {
428 if (chctl->flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS)
429 return 1;
430 }
431 return 0;
432}
433
434static inline int
435xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl)
436{
437 int ch_number;
438
439 for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) {
440 if (chctl->flags[ch_number] & XPC_MSG_CHCTL_FLAGS)
441 return 1;
442 }
443 return 0;
444}
445
446struct xpc_partition_uv {
447 unsigned long heartbeat_gpa;
448 struct xpc_heartbeat_uv cached_heartbeat;
449
450 unsigned long activate_gru_mq_desc_gpa;
451
452
453 void *cached_activate_gru_mq_desc;
454
455 struct mutex cached_activate_gru_mq_desc_mutex;
456 spinlock_t flags_lock;
457 unsigned int flags;
458 u8 remote_act_state;
459 u8 act_state_req;
460 enum xp_retval reason;
461};
462
463
464
465#define XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV 0x00000001
466#define XPC_P_ENGAGED_UV 0x00000002
467
468
469
470#define XPC_P_ASR_ACTIVATE_UV 0x01
471#define XPC_P_ASR_REACTIVATE_UV 0x02
472#define XPC_P_ASR_DEACTIVATE_UV 0x03
473
474struct xpc_partition {
475
476
477
478 u8 remote_rp_version;
479 unsigned long remote_rp_ts_jiffies;
480 unsigned long remote_rp_pa;
481 u64 last_heartbeat;
482 u32 activate_IRQ_rcvd;
483 spinlock_t act_lock;
484 u8 act_state;
485 enum xp_retval reason;
486 int reason_line;
487
488 unsigned long disengage_timeout;
489 struct timer_list disengage_timer;
490
491
492
493 u8 setup_state;
494 wait_queue_head_t teardown_wq;
495 atomic_t references;
496
497 u8 nchannels;
498 atomic_t nchannels_active;
499 atomic_t nchannels_engaged;
500 struct xpc_channel *channels;
501
502
503
504 union xpc_channel_ctl_flags chctl;
505 spinlock_t chctl_lock;
506
507 void *remote_openclose_args_base;
508 struct xpc_openclose_args *remote_openclose_args;
509
510
511
512
513 atomic_t channel_mgr_requests;
514 wait_queue_head_t channel_mgr_wq;
515
516 union {
517 struct xpc_partition_uv uv;
518 } sn;
519
520} ____cacheline_aligned;
521
522struct xpc_arch_operations {
523 int (*setup_partitions) (void);
524 void (*teardown_partitions) (void);
525 void (*process_activate_IRQ_rcvd) (void);
526 enum xp_retval (*get_partition_rsvd_page_pa)
527 (void *, u64 *, unsigned long *, size_t *);
528 int (*setup_rsvd_page) (struct xpc_rsvd_page *);
529
530 void (*allow_hb) (short);
531 void (*disallow_hb) (short);
532 void (*disallow_all_hbs) (void);
533 void (*increment_heartbeat) (void);
534 void (*offline_heartbeat) (void);
535 void (*online_heartbeat) (void);
536 void (*heartbeat_init) (void);
537 void (*heartbeat_exit) (void);
538 enum xp_retval (*get_remote_heartbeat) (struct xpc_partition *);
539
540 void (*request_partition_activation) (struct xpc_rsvd_page *,
541 unsigned long, int);
542 void (*request_partition_reactivation) (struct xpc_partition *);
543 void (*request_partition_deactivation) (struct xpc_partition *);
544 void (*cancel_partition_deactivation_request) (struct xpc_partition *);
545 enum xp_retval (*setup_ch_structures) (struct xpc_partition *);
546 void (*teardown_ch_structures) (struct xpc_partition *);
547
548 enum xp_retval (*make_first_contact) (struct xpc_partition *);
549
550 u64 (*get_chctl_all_flags) (struct xpc_partition *);
551 void (*send_chctl_closerequest) (struct xpc_channel *, unsigned long *);
552 void (*send_chctl_closereply) (struct xpc_channel *, unsigned long *);
553 void (*send_chctl_openrequest) (struct xpc_channel *, unsigned long *);
554 void (*send_chctl_openreply) (struct xpc_channel *, unsigned long *);
555 void (*send_chctl_opencomplete) (struct xpc_channel *, unsigned long *);
556 void (*process_msg_chctl_flags) (struct xpc_partition *, int);
557
558 enum xp_retval (*save_remote_msgqueue_pa) (struct xpc_channel *,
559 unsigned long);
560
561 enum xp_retval (*setup_msg_structures) (struct xpc_channel *);
562 void (*teardown_msg_structures) (struct xpc_channel *);
563
564 void (*indicate_partition_engaged) (struct xpc_partition *);
565 void (*indicate_partition_disengaged) (struct xpc_partition *);
566 void (*assume_partition_disengaged) (short);
567 int (*partition_engaged) (short);
568 int (*any_partition_engaged) (void);
569
570 int (*n_of_deliverable_payloads) (struct xpc_channel *);
571 enum xp_retval (*send_payload) (struct xpc_channel *, u32, void *,
572 u16, u8, xpc_notify_func, void *);
573 void *(*get_deliverable_payload) (struct xpc_channel *);
574 void (*received_payload) (struct xpc_channel *, void *);
575 void (*notify_senders_of_disconnect) (struct xpc_channel *);
576};
577
578
579
580#define XPC_P_AS_INACTIVE 0x00
581#define XPC_P_AS_ACTIVATION_REQ 0x01
582#define XPC_P_AS_ACTIVATING 0x02
583#define XPC_P_AS_ACTIVE 0x03
584#define XPC_P_AS_DEACTIVATING 0x04
585
586#define XPC_DEACTIVATE_PARTITION(_p, _reason) \
587 xpc_deactivate_partition(__LINE__, (_p), (_reason))
588
589
590
591#define XPC_P_SS_UNSET 0x00
592#define XPC_P_SS_SETUP 0x01
593#define XPC_P_SS_WTEARDOWN 0x02
594#define XPC_P_SS_TORNDOWN 0x03
595
596
597#define XPC_DISENGAGE_DEFAULT_TIMELIMIT 90
598
599
600#define XPC_DEACTIVATE_PRINTMSG_INTERVAL 10
601
602#define XPC_PARTID(_p) ((short)((_p) - &xpc_partitions[0]))
603
604
605extern struct xpc_registration xpc_registrations[];
606
607
608extern struct device *xpc_part;
609extern struct device *xpc_chan;
610extern struct xpc_arch_operations xpc_arch_ops;
611extern int xpc_disengage_timelimit;
612extern int xpc_disengage_timedout;
613extern int xpc_activate_IRQ_rcvd;
614extern spinlock_t xpc_activate_IRQ_rcvd_lock;
615extern wait_queue_head_t xpc_activate_IRQ_wq;
616extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **);
617extern void xpc_activate_partition(struct xpc_partition *);
618extern void xpc_activate_kthreads(struct xpc_channel *, int);
619extern void xpc_create_kthreads(struct xpc_channel *, int, int);
620extern void xpc_disconnect_wait(int);
621
622
623extern int xpc_init_uv(void);
624extern void xpc_exit_uv(void);
625
626
627extern int xpc_exiting;
628extern int xpc_nasid_mask_nlongs;
629extern struct xpc_rsvd_page *xpc_rsvd_page;
630extern unsigned long *xpc_mach_nasids;
631extern struct xpc_partition *xpc_partitions;
632extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **);
633extern int xpc_setup_rsvd_page(void);
634extern void xpc_teardown_rsvd_page(void);
635extern int xpc_identify_activate_IRQ_sender(void);
636extern int xpc_partition_disengaged(struct xpc_partition *);
637extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *);
638extern void xpc_mark_partition_inactive(struct xpc_partition *);
639extern void xpc_discovery(void);
640extern enum xp_retval xpc_get_remote_rp(int, unsigned long *,
641 struct xpc_rsvd_page *,
642 unsigned long *);
643extern void xpc_deactivate_partition(const int, struct xpc_partition *,
644 enum xp_retval);
645extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *);
646
647
648extern void xpc_initiate_connect(int);
649extern void xpc_initiate_disconnect(int);
650extern enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *);
651extern enum xp_retval xpc_initiate_send(short, int, u32, void *, u16);
652extern enum xp_retval xpc_initiate_send_notify(short, int, u32, void *, u16,
653 xpc_notify_func, void *);
654extern void xpc_initiate_received(short, int, void *);
655extern void xpc_process_sent_chctl_flags(struct xpc_partition *);
656extern void xpc_connected_callout(struct xpc_channel *);
657extern void xpc_deliver_payload(struct xpc_channel *);
658extern void xpc_disconnect_channel(const int, struct xpc_channel *,
659 enum xp_retval, unsigned long *);
660extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval);
661extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval);
662
663static inline void
664xpc_wakeup_channel_mgr(struct xpc_partition *part)
665{
666 if (atomic_inc_return(&part->channel_mgr_requests) == 1)
667 wake_up(&part->channel_mgr_wq);
668}
669
670
671
672
673
674static inline void
675xpc_msgqueue_ref(struct xpc_channel *ch)
676{
677 atomic_inc(&ch->references);
678}
679
680static inline void
681xpc_msgqueue_deref(struct xpc_channel *ch)
682{
683 s32 refs = atomic_dec_return(&ch->references);
684
685 DBUG_ON(refs < 0);
686 if (refs == 0)
687 xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]);
688}
689
690#define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \
691 xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs)
692
693
694
695
696
697static inline void
698xpc_part_deref(struct xpc_partition *part)
699{
700 s32 refs = atomic_dec_return(&part->references);
701
702 DBUG_ON(refs < 0);
703 if (refs == 0 && part->setup_state == XPC_P_SS_WTEARDOWN)
704 wake_up(&part->teardown_wq);
705}
706
707static inline int
708xpc_part_ref(struct xpc_partition *part)
709{
710 int setup;
711
712 atomic_inc(&part->references);
713 setup = (part->setup_state == XPC_P_SS_SETUP);
714 if (!setup)
715 xpc_part_deref(part);
716
717 return setup;
718}
719
720
721
722
723
724
725#define XPC_SET_REASON(_p, _reason, _line) \
726 { \
727 (_p)->reason = _reason; \
728 (_p)->reason_line = _line; \
729 }
730
731#endif
732