sgi-xp: add usage of GRU driver by xpc_remote_memcpy()
[linux-2.6] / drivers / misc / sgi-xp / xpc_channel.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 /*
10  * Cross Partition Communication (XPC) channel support.
11  *
12  *      This is the part of XPC that manages the channels and
13  *      sends/receives messages across them to/from other partitions.
14  *
15  */
16
17 #include <linux/device.h>
18 #include "xpc.h"
19
20 /*
21  * Process a connect message from a remote partition.
22  *
23  * Note: xpc_process_connect() is expecting to be called with the
24  * spin_lock_irqsave held and will leave it locked upon return.
25  */
26 static void
27 xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
28 {
29         enum xp_retval ret;
30
31         DBUG_ON(!spin_is_locked(&ch->lock));
32
33         if (!(ch->flags & XPC_C_OPENREQUEST) ||
34             !(ch->flags & XPC_C_ROPENREQUEST)) {
35                 /* nothing more to do for now */
36                 return;
37         }
38         DBUG_ON(!(ch->flags & XPC_C_CONNECTING));
39
40         if (!(ch->flags & XPC_C_SETUP)) {
41                 spin_unlock_irqrestore(&ch->lock, *irq_flags);
42                 ret = xpc_allocate_msgqueues(ch);
43                 spin_lock_irqsave(&ch->lock, *irq_flags);
44
45                 if (ret != xpSuccess)
46                         XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags);
47
48                 ch->flags |= XPC_C_SETUP;
49
50                 if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING))
51                         return;
52
53                 DBUG_ON(ch->local_msgqueue == NULL);
54                 DBUG_ON(ch->remote_msgqueue == NULL);
55         }
56
57         if (!(ch->flags & XPC_C_OPENREPLY)) {
58                 ch->flags |= XPC_C_OPENREPLY;
59                 xpc_send_chctl_openreply(ch, irq_flags);
60         }
61
62         if (!(ch->flags & XPC_C_ROPENREPLY))
63                 return;
64
65         DBUG_ON(ch->remote_msgqueue_pa == 0);
66
67         ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP);    /* clear all else */
68
69         dev_info(xpc_chan, "channel %d to partition %d connected\n",
70                  ch->number, ch->partid);
71
72         spin_unlock_irqrestore(&ch->lock, *irq_flags);
73         xpc_create_kthreads(ch, 1, 0);
74         spin_lock_irqsave(&ch->lock, *irq_flags);
75 }
76
77 /*
78  * spin_lock_irqsave() is expected to be held on entry.
79  */
80 static void
81 xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
82 {
83         struct xpc_partition *part = &xpc_partitions[ch->partid];
84         u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED);
85
86         DBUG_ON(!spin_is_locked(&ch->lock));
87
88         if (!(ch->flags & XPC_C_DISCONNECTING))
89                 return;
90
91         DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
92
93         /* make sure all activity has settled down first */
94
95         if (atomic_read(&ch->kthreads_assigned) > 0 ||
96             atomic_read(&ch->references) > 0) {
97                 return;
98         }
99         DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
100                 !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE));
101
102         if (part->act_state == XPC_P_DEACTIVATING) {
103                 /* can't proceed until the other side disengages from us */
104                 if (xpc_partition_engaged(ch->partid))
105                         return;
106
107         } else {
108
109                 /* as long as the other side is up do the full protocol */
110
111                 if (!(ch->flags & XPC_C_RCLOSEREQUEST))
112                         return;
113
114                 if (!(ch->flags & XPC_C_CLOSEREPLY)) {
115                         ch->flags |= XPC_C_CLOSEREPLY;
116                         xpc_send_chctl_closereply(ch, irq_flags);
117                 }
118
119                 if (!(ch->flags & XPC_C_RCLOSEREPLY))
120                         return;
121         }
122
123         /* wake those waiting for notify completion */
124         if (atomic_read(&ch->n_to_notify) > 0) {
125                 /* we do callout while holding ch->lock, callout can't block */
126                 xpc_notify_senders_of_disconnect(ch);
127         }
128
129         /* both sides are disconnected now */
130
131         if (ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE) {
132                 spin_unlock_irqrestore(&ch->lock, *irq_flags);
133                 xpc_disconnect_callout(ch, xpDisconnected);
134                 spin_lock_irqsave(&ch->lock, *irq_flags);
135         }
136
137         /* it's now safe to free the channel's message queues */
138         xpc_free_msgqueues(ch);
139
140         /*
141          * Mark the channel disconnected and clear all other flags, including
142          * XPC_C_SETUP (because of call to xpc_free_msgqueues()) but not
143          * including XPC_C_WDISCONNECT (if it was set).
144          */
145         ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT));
146
147         atomic_dec(&part->nchannels_active);
148
149         if (channel_was_connected) {
150                 dev_info(xpc_chan, "channel %d to partition %d disconnected, "
151                          "reason=%d\n", ch->number, ch->partid, ch->reason);
152         }
153
154         if (ch->flags & XPC_C_WDISCONNECT) {
155                 /* we won't lose the CPU since we're holding ch->lock */
156                 complete(&ch->wdisconnect_wait);
157         } else if (ch->delayed_chctl_flags) {
158                 if (part->act_state != XPC_P_DEACTIVATING) {
159                         /* time to take action on any delayed chctl flags */
160                         spin_lock(&part->chctl_lock);
161                         part->chctl.flags[ch->number] |=
162                             ch->delayed_chctl_flags;
163                         spin_unlock(&part->chctl_lock);
164                 }
165                 ch->delayed_chctl_flags = 0;
166         }
167 }
168
169 /*
170  * Process a change in the channel's remote connection state.
171  */
172 static void
173 xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number,
174                                   u8 chctl_flags)
175 {
176         unsigned long irq_flags;
177         struct xpc_openclose_args *args =
178             &part->remote_openclose_args[ch_number];
179         struct xpc_channel *ch = &part->channels[ch_number];
180         enum xp_retval reason;
181
182         spin_lock_irqsave(&ch->lock, irq_flags);
183
184 again:
185
186         if ((ch->flags & XPC_C_DISCONNECTED) &&
187             (ch->flags & XPC_C_WDISCONNECT)) {
188                 /*
189                  * Delay processing chctl flags until thread waiting disconnect
190                  * has had a chance to see that the channel is disconnected.
191                  */
192                 ch->delayed_chctl_flags |= chctl_flags;
193                 spin_unlock_irqrestore(&ch->lock, irq_flags);
194                 return;
195         }
196
197         if (chctl_flags & XPC_CHCTL_CLOSEREQUEST) {
198
199                 dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREQUEST (reason=%d) received "
200                         "from partid=%d, channel=%d\n", args->reason,
201                         ch->partid, ch->number);
202
203                 /*
204                  * If RCLOSEREQUEST is set, we're probably waiting for
205                  * RCLOSEREPLY. We should find it and a ROPENREQUEST packed
206                  * with this RCLOSEREQUEST in the chctl_flags.
207                  */
208
209                 if (ch->flags & XPC_C_RCLOSEREQUEST) {
210                         DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING));
211                         DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
212                         DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY));
213                         DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY);
214
215                         DBUG_ON(!(chctl_flags & XPC_CHCTL_CLOSEREPLY));
216                         chctl_flags &= ~XPC_CHCTL_CLOSEREPLY;
217                         ch->flags |= XPC_C_RCLOSEREPLY;
218
219                         /* both sides have finished disconnecting */
220                         xpc_process_disconnect(ch, &irq_flags);
221                         DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));
222                         goto again;
223                 }
224
225                 if (ch->flags & XPC_C_DISCONNECTED) {
226                         if (!(chctl_flags & XPC_CHCTL_OPENREQUEST)) {
227                                 if (part->chctl.flags[ch_number] &
228                                     XPC_CHCTL_OPENREQUEST) {
229
230                                         DBUG_ON(ch->delayed_chctl_flags != 0);
231                                         spin_lock(&part->chctl_lock);
232                                         part->chctl.flags[ch_number] |=
233                                             XPC_CHCTL_CLOSEREQUEST;
234                                         spin_unlock(&part->chctl_lock);
235                                 }
236                                 spin_unlock_irqrestore(&ch->lock, irq_flags);
237                                 return;
238                         }
239
240                         XPC_SET_REASON(ch, 0, 0);
241                         ch->flags &= ~XPC_C_DISCONNECTED;
242
243                         atomic_inc(&part->nchannels_active);
244                         ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST);
245                 }
246
247                 chctl_flags &= ~(XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY);
248
249                 /*
250                  * The meaningful CLOSEREQUEST connection state fields are:
251                  *      reason = reason connection is to be closed
252                  */
253
254                 ch->flags |= XPC_C_RCLOSEREQUEST;
255
256                 if (!(ch->flags & XPC_C_DISCONNECTING)) {
257                         reason = args->reason;
258                         if (reason <= xpSuccess || reason > xpUnknownReason)
259                                 reason = xpUnknownReason;
260                         else if (reason == xpUnregistering)
261                                 reason = xpOtherUnregistering;
262
263                         XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
264
265                         DBUG_ON(chctl_flags & XPC_CHCTL_CLOSEREPLY);
266                         spin_unlock_irqrestore(&ch->lock, irq_flags);
267                         return;
268                 }
269
270                 xpc_process_disconnect(ch, &irq_flags);
271         }
272
273         if (chctl_flags & XPC_CHCTL_CLOSEREPLY) {
274
275                 dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREPLY received from partid="
276                         "%d, channel=%d\n", ch->partid, ch->number);
277
278                 if (ch->flags & XPC_C_DISCONNECTED) {
279                         DBUG_ON(part->act_state != XPC_P_DEACTIVATING);
280                         spin_unlock_irqrestore(&ch->lock, irq_flags);
281                         return;
282                 }
283
284                 DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));
285
286                 if (!(ch->flags & XPC_C_RCLOSEREQUEST)) {
287                         if (part->chctl.flags[ch_number] &
288                             XPC_CHCTL_CLOSEREQUEST) {
289
290                                 DBUG_ON(ch->delayed_chctl_flags != 0);
291                                 spin_lock(&part->chctl_lock);
292                                 part->chctl.flags[ch_number] |=
293                                     XPC_CHCTL_CLOSEREPLY;
294                                 spin_unlock(&part->chctl_lock);
295                         }
296                         spin_unlock_irqrestore(&ch->lock, irq_flags);
297                         return;
298                 }
299
300                 ch->flags |= XPC_C_RCLOSEREPLY;
301
302                 if (ch->flags & XPC_C_CLOSEREPLY) {
303                         /* both sides have finished disconnecting */
304                         xpc_process_disconnect(ch, &irq_flags);
305                 }
306         }
307
308         if (chctl_flags & XPC_CHCTL_OPENREQUEST) {
309
310                 dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (msg_size=%d, "
311                         "local_nentries=%d) received from partid=%d, "
312                         "channel=%d\n", args->msg_size, args->local_nentries,
313                         ch->partid, ch->number);
314
315                 if (part->act_state == XPC_P_DEACTIVATING ||
316                     (ch->flags & XPC_C_ROPENREQUEST)) {
317                         spin_unlock_irqrestore(&ch->lock, irq_flags);
318                         return;
319                 }
320
321                 if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) {
322                         ch->delayed_chctl_flags |= XPC_CHCTL_OPENREQUEST;
323                         spin_unlock_irqrestore(&ch->lock, irq_flags);
324                         return;
325                 }
326                 DBUG_ON(!(ch->flags & (XPC_C_DISCONNECTED |
327                                        XPC_C_OPENREQUEST)));
328                 DBUG_ON(ch->flags & (XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
329                                      XPC_C_OPENREPLY | XPC_C_CONNECTED));
330
331                 /*
332                  * The meaningful OPENREQUEST connection state fields are:
333                  *      msg_size = size of channel's messages in bytes
334                  *      local_nentries = remote partition's local_nentries
335                  */
336                 if (args->msg_size == 0 || args->local_nentries == 0) {
337                         /* assume OPENREQUEST was delayed by mistake */
338                         spin_unlock_irqrestore(&ch->lock, irq_flags);
339                         return;
340                 }
341
342                 ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING);
343                 ch->remote_nentries = args->local_nentries;
344
345                 if (ch->flags & XPC_C_OPENREQUEST) {
346                         if (args->msg_size != ch->msg_size) {
347                                 XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
348                                                        &irq_flags);
349                                 spin_unlock_irqrestore(&ch->lock, irq_flags);
350                                 return;
351                         }
352                 } else {
353                         ch->msg_size = args->msg_size;
354
355                         XPC_SET_REASON(ch, 0, 0);
356                         ch->flags &= ~XPC_C_DISCONNECTED;
357
358                         atomic_inc(&part->nchannels_active);
359                 }
360
361                 xpc_process_connect(ch, &irq_flags);
362         }
363
364         if (chctl_flags & XPC_CHCTL_OPENREPLY) {
365
366                 dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa="
367                         "0x%lx, local_nentries=%d, remote_nentries=%d) "
368                         "received from partid=%d, channel=%d\n",
369                         args->local_msgqueue_pa, args->local_nentries,
370                         args->remote_nentries, ch->partid, ch->number);
371
372                 if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) {
373                         spin_unlock_irqrestore(&ch->lock, irq_flags);
374                         return;
375                 }
376                 if (!(ch->flags & XPC_C_OPENREQUEST)) {
377                         XPC_DISCONNECT_CHANNEL(ch, xpOpenCloseError,
378                                                &irq_flags);
379                         spin_unlock_irqrestore(&ch->lock, irq_flags);
380                         return;
381                 }
382
383                 DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST));
384                 DBUG_ON(ch->flags & XPC_C_CONNECTED);
385
386                 /*
387                  * The meaningful OPENREPLY connection state fields are:
388                  *      local_msgqueue_pa = physical address of remote
389                  *                          partition's local_msgqueue
390                  *      local_nentries = remote partition's local_nentries
391                  *      remote_nentries = remote partition's remote_nentries
392                  */
393                 DBUG_ON(args->local_msgqueue_pa == 0);
394                 DBUG_ON(args->local_nentries == 0);
395                 DBUG_ON(args->remote_nentries == 0);
396
397                 ch->flags |= XPC_C_ROPENREPLY;
398                 ch->remote_msgqueue_pa = args->local_msgqueue_pa;
399
400                 if (args->local_nentries < ch->remote_nentries) {
401                         dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new "
402                                 "remote_nentries=%d, old remote_nentries=%d, "
403                                 "partid=%d, channel=%d\n",
404                                 args->local_nentries, ch->remote_nentries,
405                                 ch->partid, ch->number);
406
407                         ch->remote_nentries = args->local_nentries;
408                 }
409                 if (args->remote_nentries < ch->local_nentries) {
410                         dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new "
411                                 "local_nentries=%d, old local_nentries=%d, "
412                                 "partid=%d, channel=%d\n",
413                                 args->remote_nentries, ch->local_nentries,
414                                 ch->partid, ch->number);
415
416                         ch->local_nentries = args->remote_nentries;
417                 }
418
419                 xpc_process_connect(ch, &irq_flags);
420         }
421
422         spin_unlock_irqrestore(&ch->lock, irq_flags);
423 }
424
425 /*
426  * Attempt to establish a channel connection to a remote partition.
427  */
428 static enum xp_retval
429 xpc_connect_channel(struct xpc_channel *ch)
430 {
431         unsigned long irq_flags;
432         struct xpc_registration *registration = &xpc_registrations[ch->number];
433
434         if (mutex_trylock(&registration->mutex) == 0)
435                 return xpRetry;
436
437         if (!XPC_CHANNEL_REGISTERED(ch->number)) {
438                 mutex_unlock(&registration->mutex);
439                 return xpUnregistered;
440         }
441
442         spin_lock_irqsave(&ch->lock, irq_flags);
443
444         DBUG_ON(ch->flags & XPC_C_CONNECTED);
445         DBUG_ON(ch->flags & XPC_C_OPENREQUEST);
446
447         if (ch->flags & XPC_C_DISCONNECTING) {
448                 spin_unlock_irqrestore(&ch->lock, irq_flags);
449                 mutex_unlock(&registration->mutex);
450                 return ch->reason;
451         }
452
453         /* add info from the channel connect registration to the channel */
454
455         ch->kthreads_assigned_limit = registration->assigned_limit;
456         ch->kthreads_idle_limit = registration->idle_limit;
457         DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);
458         DBUG_ON(atomic_read(&ch->kthreads_idle) != 0);
459         DBUG_ON(atomic_read(&ch->kthreads_active) != 0);
460
461         ch->func = registration->func;
462         DBUG_ON(registration->func == NULL);
463         ch->key = registration->key;
464
465         ch->local_nentries = registration->nentries;
466
467         if (ch->flags & XPC_C_ROPENREQUEST) {
468                 if (registration->msg_size != ch->msg_size) {
469                         /* the local and remote sides aren't the same */
470
471                         /*
472                          * Because XPC_DISCONNECT_CHANNEL() can block we're
473                          * forced to up the registration sema before we unlock
474                          * the channel lock. But that's okay here because we're
475                          * done with the part that required the registration
476                          * sema. XPC_DISCONNECT_CHANNEL() requires that the
477                          * channel lock be locked and will unlock and relock
478                          * the channel lock as needed.
479                          */
480                         mutex_unlock(&registration->mutex);
481                         XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
482                                                &irq_flags);
483                         spin_unlock_irqrestore(&ch->lock, irq_flags);
484                         return xpUnequalMsgSizes;
485                 }
486         } else {
487                 ch->msg_size = registration->msg_size;
488
489                 XPC_SET_REASON(ch, 0, 0);
490                 ch->flags &= ~XPC_C_DISCONNECTED;
491
492                 atomic_inc(&xpc_partitions[ch->partid].nchannels_active);
493         }
494
495         mutex_unlock(&registration->mutex);
496
497         /* initiate the connection */
498
499         ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING);
500         xpc_send_chctl_openrequest(ch, &irq_flags);
501
502         xpc_process_connect(ch, &irq_flags);
503
504         spin_unlock_irqrestore(&ch->lock, irq_flags);
505
506         return xpSuccess;
507 }
508
509 void
510 xpc_process_sent_chctl_flags(struct xpc_partition *part)
511 {
512         unsigned long irq_flags;
513         union xpc_channel_ctl_flags chctl;
514         struct xpc_channel *ch;
515         int ch_number;
516         u32 ch_flags;
517
518         chctl.all_flags = xpc_get_chctl_all_flags(part);
519
520         /*
521          * Initiate channel connections for registered channels.
522          *
523          * For each connected channel that has pending messages activate idle
524          * kthreads and/or create new kthreads as needed.
525          */
526
527         for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
528                 ch = &part->channels[ch_number];
529
530                 /*
531                  * Process any open or close related chctl flags, and then deal
532                  * with connecting or disconnecting the channel as required.
533                  */
534
535                 if (chctl.flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS) {
536                         xpc_process_openclose_chctl_flags(part, ch_number,
537                                                         chctl.flags[ch_number]);
538                 }
539
540                 ch_flags = ch->flags;   /* need an atomic snapshot of flags */
541
542                 if (ch_flags & XPC_C_DISCONNECTING) {
543                         spin_lock_irqsave(&ch->lock, irq_flags);
544                         xpc_process_disconnect(ch, &irq_flags);
545                         spin_unlock_irqrestore(&ch->lock, irq_flags);
546                         continue;
547                 }
548
549                 if (part->act_state == XPC_P_DEACTIVATING)
550                         continue;
551
552                 if (!(ch_flags & XPC_C_CONNECTED)) {
553                         if (!(ch_flags & XPC_C_OPENREQUEST)) {
554                                 DBUG_ON(ch_flags & XPC_C_SETUP);
555                                 (void)xpc_connect_channel(ch);
556                         } else {
557                                 spin_lock_irqsave(&ch->lock, irq_flags);
558                                 xpc_process_connect(ch, &irq_flags);
559                                 spin_unlock_irqrestore(&ch->lock, irq_flags);
560                         }
561                         continue;
562                 }
563
564                 /*
565                  * Process any message related chctl flags, this may involve
566                  * the activation of kthreads to deliver any pending messages
567                  * sent from the other partition.
568                  */
569
570                 if (chctl.flags[ch_number] & XPC_MSG_CHCTL_FLAGS)
571                         xpc_process_msg_chctl_flags(part, ch_number);
572         }
573 }
574
575 /*
576  * XPC's heartbeat code calls this function to inform XPC that a partition is
577  * going down.  XPC responds by tearing down the XPartition Communication
578  * infrastructure used for the just downed partition.
579  *
580  * XPC's heartbeat code will never call this function and xpc_partition_up()
581  * at the same time. Nor will it ever make multiple calls to either function
582  * at the same time.
583  */
584 void
585 xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason)
586 {
587         unsigned long irq_flags;
588         int ch_number;
589         struct xpc_channel *ch;
590
591         dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n",
592                 XPC_PARTID(part), reason);
593
594         if (!xpc_part_ref(part)) {
595                 /* infrastructure for this partition isn't currently set up */
596                 return;
597         }
598
599         /* disconnect channels associated with the partition going down */
600
601         for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
602                 ch = &part->channels[ch_number];
603
604                 xpc_msgqueue_ref(ch);
605                 spin_lock_irqsave(&ch->lock, irq_flags);
606
607                 XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
608
609                 spin_unlock_irqrestore(&ch->lock, irq_flags);
610                 xpc_msgqueue_deref(ch);
611         }
612
613         xpc_wakeup_channel_mgr(part);
614
615         xpc_part_deref(part);
616 }
617
618 /*
619  * Called by XP at the time of channel connection registration to cause
620  * XPC to establish connections to all currently active partitions.
621  */
622 void
623 xpc_initiate_connect(int ch_number)
624 {
625         short partid;
626         struct xpc_partition *part;
627         struct xpc_channel *ch;
628
629         DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS);
630
631         for (partid = 0; partid < xp_max_npartitions; partid++) {
632                 part = &xpc_partitions[partid];
633
634                 if (xpc_part_ref(part)) {
635                         ch = &part->channels[ch_number];
636
637                         /*
638                          * Initiate the establishment of a connection on the
639                          * newly registered channel to the remote partition.
640                          */
641                         xpc_wakeup_channel_mgr(part);
642                         xpc_part_deref(part);
643                 }
644         }
645 }
646
647 void
648 xpc_connected_callout(struct xpc_channel *ch)
649 {
650         /* let the registerer know that a connection has been established */
651
652         if (ch->func != NULL) {
653                 dev_dbg(xpc_chan, "ch->func() called, reason=xpConnected, "
654                         "partid=%d, channel=%d\n", ch->partid, ch->number);
655
656                 ch->func(xpConnected, ch->partid, ch->number,
657                          (void *)(u64)ch->local_nentries, ch->key);
658
659                 dev_dbg(xpc_chan, "ch->func() returned, reason=xpConnected, "
660                         "partid=%d, channel=%d\n", ch->partid, ch->number);
661         }
662 }
663
664 /*
665  * Called by XP at the time of channel connection unregistration to cause
666  * XPC to teardown all current connections for the specified channel.
667  *
668  * Before returning xpc_initiate_disconnect() will wait until all connections
669  * on the specified channel have been closed/torndown. So the caller can be
670  * assured that they will not be receiving any more callouts from XPC to the
671  * function they registered via xpc_connect().
672  *
673  * Arguments:
674  *
675  *      ch_number - channel # to unregister.
676  */
677 void
678 xpc_initiate_disconnect(int ch_number)
679 {
680         unsigned long irq_flags;
681         short partid;
682         struct xpc_partition *part;
683         struct xpc_channel *ch;
684
685         DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS);
686
687         /* initiate the channel disconnect for every active partition */
688         for (partid = 0; partid < xp_max_npartitions; partid++) {
689                 part = &xpc_partitions[partid];
690
691                 if (xpc_part_ref(part)) {
692                         ch = &part->channels[ch_number];
693                         xpc_msgqueue_ref(ch);
694
695                         spin_lock_irqsave(&ch->lock, irq_flags);
696
697                         if (!(ch->flags & XPC_C_DISCONNECTED)) {
698                                 ch->flags |= XPC_C_WDISCONNECT;
699
700                                 XPC_DISCONNECT_CHANNEL(ch, xpUnregistering,
701                                                        &irq_flags);
702                         }
703
704                         spin_unlock_irqrestore(&ch->lock, irq_flags);
705
706                         xpc_msgqueue_deref(ch);
707                         xpc_part_deref(part);
708                 }
709         }
710
711         xpc_disconnect_wait(ch_number);
712 }
713
714 /*
715  * To disconnect a channel, and reflect it back to all who may be waiting.
716  *
717  * An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by
718  * xpc_process_disconnect(), and if set, XPC_C_WDISCONNECT is cleared by
719  * xpc_disconnect_wait().
720  *
721  * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN.
722  */
723 void
724 xpc_disconnect_channel(const int line, struct xpc_channel *ch,
725                        enum xp_retval reason, unsigned long *irq_flags)
726 {
727         u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED);
728
729         DBUG_ON(!spin_is_locked(&ch->lock));
730
731         if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED))
732                 return;
733
734         DBUG_ON(!(ch->flags & (XPC_C_CONNECTING | XPC_C_CONNECTED)));
735
736         dev_dbg(xpc_chan, "reason=%d, line=%d, partid=%d, channel=%d\n",
737                 reason, line, ch->partid, ch->number);
738
739         XPC_SET_REASON(ch, reason, line);
740
741         ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING);
742         /* some of these may not have been set */
743         ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY |
744                        XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
745                        XPC_C_CONNECTING | XPC_C_CONNECTED);
746
747         xpc_send_chctl_closerequest(ch, irq_flags);
748
749         if (channel_was_connected)
750                 ch->flags |= XPC_C_WASCONNECTED;
751
752         spin_unlock_irqrestore(&ch->lock, *irq_flags);
753
754         /* wake all idle kthreads so they can exit */
755         if (atomic_read(&ch->kthreads_idle) > 0) {
756                 wake_up_all(&ch->idle_wq);
757
758         } else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
759                    !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
760                 /* start a kthread that will do the xpDisconnecting callout */
761                 xpc_create_kthreads(ch, 1, 1);
762         }
763
764         /* wake those waiting to allocate an entry from the local msg queue */
765         if (atomic_read(&ch->n_on_msg_allocate_wq) > 0)
766                 wake_up(&ch->msg_allocate_wq);
767
768         spin_lock_irqsave(&ch->lock, *irq_flags);
769 }
770
771 void
772 xpc_disconnect_callout(struct xpc_channel *ch, enum xp_retval reason)
773 {
774         /*
775          * Let the channel's registerer know that the channel is being
776          * disconnected. We don't want to do this if the registerer was never
777          * informed of a connection being made.
778          */
779
780         if (ch->func != NULL) {
781                 dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, "
782                         "channel=%d\n", reason, ch->partid, ch->number);
783
784                 ch->func(reason, ch->partid, ch->number, NULL, ch->key);
785
786                 dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, "
787                         "channel=%d\n", reason, ch->partid, ch->number);
788         }
789 }
790
791 /*
792  * Wait for a message entry to become available for the specified channel,
793  * but don't wait any longer than 1 jiffy.
794  */
795 enum xp_retval
796 xpc_allocate_msg_wait(struct xpc_channel *ch)
797 {
798         enum xp_retval ret;
799
800         if (ch->flags & XPC_C_DISCONNECTING) {
801                 DBUG_ON(ch->reason == xpInterrupted);
802                 return ch->reason;
803         }
804
805         atomic_inc(&ch->n_on_msg_allocate_wq);
806         ret = interruptible_sleep_on_timeout(&ch->msg_allocate_wq, 1);
807         atomic_dec(&ch->n_on_msg_allocate_wq);
808
809         if (ch->flags & XPC_C_DISCONNECTING) {
810                 ret = ch->reason;
811                 DBUG_ON(ch->reason == xpInterrupted);
812         } else if (ret == 0) {
813                 ret = xpTimeout;
814         } else {
815                 ret = xpInterrupted;
816         }
817
818         return ret;
819 }
820
821 /*
822  * Send a message that contains the user's payload on the specified channel
823  * connected to the specified partition.
824  *
825  * NOTE that this routine can sleep waiting for a message entry to become
826  * available. To not sleep, pass in the XPC_NOWAIT flag.
827  *
828  * Once sent, this routine will not wait for the message to be received, nor
829  * will notification be given when it does happen.
830  *
831  * Arguments:
832  *
833  *      partid - ID of partition to which the channel is connected.
834  *      ch_number - channel # to send message on.
835  *      flags - see xp.h for valid flags.
836  *      payload - pointer to the payload which is to be sent.
837  *      payload_size - size of the payload in bytes.
838  */
839 enum xp_retval
840 xpc_initiate_send(short partid, int ch_number, u32 flags, void *payload,
841                   u16 payload_size)
842 {
843         struct xpc_partition *part = &xpc_partitions[partid];
844         enum xp_retval ret = xpUnknownReason;
845
846         dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload,
847                 partid, ch_number);
848
849         DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
850         DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
851         DBUG_ON(payload == NULL);
852
853         if (xpc_part_ref(part)) {
854                 ret = xpc_send_msg(&part->channels[ch_number], flags, payload,
855                                    payload_size, 0, NULL, NULL);
856                 xpc_part_deref(part);
857         }
858
859         return ret;
860 }
861
862 /*
863  * Send a message that contains the user's payload on the specified channel
864  * connected to the specified partition.
865  *
866  * NOTE that this routine can sleep waiting for a message entry to become
867  * available. To not sleep, pass in the XPC_NOWAIT flag.
868  *
869  * This routine will not wait for the message to be sent or received.
870  *
871  * Once the remote end of the channel has received the message, the function
872  * passed as an argument to xpc_initiate_send_notify() will be called. This
873  * allows the sender to free up or re-use any buffers referenced by the
874  * message, but does NOT mean the message has been processed at the remote
875  * end by a receiver.
876  *
877  * If this routine returns an error, the caller's function will NOT be called.
878  *
879  * Arguments:
880  *
881  *      partid - ID of partition to which the channel is connected.
882  *      ch_number - channel # to send message on.
883  *      flags - see xp.h for valid flags.
884  *      payload - pointer to the payload which is to be sent.
885  *      payload_size - size of the payload in bytes.
886  *      func - function to call with asynchronous notification of message
887  *                receipt. THIS FUNCTION MUST BE NON-BLOCKING.
888  *      key - user-defined key to be passed to the function when it's called.
889  */
890 enum xp_retval
891 xpc_initiate_send_notify(short partid, int ch_number, u32 flags, void *payload,
892                          u16 payload_size, xpc_notify_func func, void *key)
893 {
894         struct xpc_partition *part = &xpc_partitions[partid];
895         enum xp_retval ret = xpUnknownReason;
896
897         dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload,
898                 partid, ch_number);
899
900         DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
901         DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
902         DBUG_ON(payload == NULL);
903         DBUG_ON(func == NULL);
904
905         if (xpc_part_ref(part)) {
906                 ret = xpc_send_msg(&part->channels[ch_number], flags, payload,
907                                    payload_size, XPC_N_CALL, func, key);
908                 xpc_part_deref(part);
909         }
910         return ret;
911 }
912
913 /*
914  * Deliver a message to its intended recipient.
915  */
916 void
917 xpc_deliver_msg(struct xpc_channel *ch)
918 {
919         struct xpc_msg *msg;
920
921         msg = xpc_get_deliverable_msg(ch);
922         if (msg != NULL) {
923
924                 /*
925                  * This ref is taken to protect the payload itself from being
926                  * freed before the user is finished with it, which the user
927                  * indicates by calling xpc_initiate_received().
928                  */
929                 xpc_msgqueue_ref(ch);
930
931                 atomic_inc(&ch->kthreads_active);
932
933                 if (ch->func != NULL) {
934                         dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, "
935                                 "msg_number=%ld, partid=%d, channel=%d\n",
936                                 msg, (signed long)msg->number, ch->partid,
937                                 ch->number);
938
939                         /* deliver the message to its intended recipient */
940                         ch->func(xpMsgReceived, ch->partid, ch->number,
941                                  &msg->payload, ch->key);
942
943                         dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
944                                 "msg_number=%ld, partid=%d, channel=%d\n",
945                                 msg, (signed long)msg->number, ch->partid,
946                                 ch->number);
947                 }
948
949                 atomic_dec(&ch->kthreads_active);
950         }
951 }
952
953 /*
954  * Acknowledge receipt of a delivered message.
955  *
956  * If a message has XPC_M_INTERRUPT set, send an interrupt to the partition
957  * that sent the message.
958  *
959  * This function, although called by users, does not call xpc_part_ref() to
960  * ensure that the partition infrastructure is in place. It relies on the
961  * fact that we called xpc_msgqueue_ref() in xpc_deliver_msg().
962  *
963  * Arguments:
964  *
965  *      partid - ID of partition to which the channel is connected.
966  *      ch_number - channel # message received on.
967  *      payload - pointer to the payload area allocated via
968  *                      xpc_initiate_send() or xpc_initiate_send_notify().
969  */
970 void
971 xpc_initiate_received(short partid, int ch_number, void *payload)
972 {
973         struct xpc_partition *part = &xpc_partitions[partid];
974         struct xpc_channel *ch;
975         struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
976
977         DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
978         DBUG_ON(ch_number < 0 || ch_number >= part->nchannels);
979
980         ch = &part->channels[ch_number];
981         xpc_received_msg(ch, msg);
982
983         /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg()  */
984         xpc_msgqueue_deref(ch);
985 }