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