static enum xp_retval xpc_make_first_contact_uv(struct xpc_partition *part) { struct xpc_activate_mq_msg_uv msg; /* * We send a sync msg to get the remote partition's remote_act_state * updated to our current act_state which at this point should * be XPC_P_AS_ACTIVATING. */ xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); while (!((part->sn.uv.remote_act_state == XPC_P_AS_ACTIVATING) || (part->sn.uv.remote_act_state == XPC_P_AS_ACTIVE))) { dev_dbg(xpc_part, "waiting to make first contact with " "partition %d\n", XPC_PARTID(part)); /* wait a 1/4 of a second or so */ (void)msleep_interruptible(250); if (part->act_state == XPC_P_AS_DEACTIVATING) return part->reason; } return xpSuccess; }
void xpc_activate_partition(struct xpc_partition *part) { short partid = XPC_PARTID(part); unsigned long irq_flags; struct task_struct *kthread; spin_lock_irqsave(&part->act_lock, irq_flags); DBUG_ON(part->act_state != XPC_P_AS_INACTIVE); part->act_state = XPC_P_AS_ACTIVATION_REQ; XPC_SET_REASON(part, xpCloneKThread, __LINE__); spin_unlock_irqrestore(&part->act_lock, irq_flags); kthread = kthread_run(xpc_activating, (void *)((u64)partid), "xpc%02d", partid); if (IS_ERR(kthread)) { spin_lock_irqsave(&part->act_lock, irq_flags); part->act_state = XPC_P_AS_INACTIVE; XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__); spin_unlock_irqrestore(&part->act_lock, irq_flags); } }
void xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason) { unsigned long irq_flags; int ch_number; struct xpc_channel *ch; dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n", XPC_PARTID(part), reason); if (!xpc_part_ref(part)) { return; } for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; xpc_msgqueue_ref(ch); spin_lock_irqsave(&ch->lock, irq_flags); XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); xpc_msgqueue_deref(ch); } xpc_wakeup_channel_mgr(part); xpc_part_deref(part); }
/* * When XPC HB determines that a partition has come up, it will create a new * kthread and that kthread will call this function to attempt to set up the * basic infrastructure used for Cross Partition Communication with the newly * upped partition. * * The kthread that was created by XPC HB and which setup the XPC * infrastructure will remain assigned to the partition until the partition * goes down. At which time the kthread will teardown the XPC infrastructure * and then exit. * * XPC HB will put the remote partition's XPC per partition specific variables * physical address into xpc_partitions[partid].remote_vars_part_pa prior to * calling xpc_partition_up(). */ static void xpc_partition_up(struct xpc_partition *part) { DBUG_ON(part->channels != NULL); dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part)); if (xpc_setup_infrastructure(part) != xpSuccess) return; /* * The kthread that XPC HB called us with will become the * channel manager for this partition. It will not return * back to XPC HB until the partition's XPC infrastructure * has been dismantled. */ (void)xpc_part_ref(part); /* this will always succeed */ if (xpc_make_first_contact(part) == xpSuccess) xpc_channel_mgr(part); xpc_part_deref(part); xpc_teardown_infrastructure(part); }
/* * XPC's heartbeat code calls this function to inform XPC that a partition is * going down. XPC responds by tearing down the XPartition Communication * infrastructure used for the just downed partition. * * XPC's heartbeat code will never call this function and xpc_partition_up() * at the same time. Nor will it ever make multiple calls to either function * at the same time. */ void xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason) { unsigned long irq_flags; int ch_number; struct xpc_channel *ch; dev_dbg(xpc_chan, "deactivating partition %d, reason=%d\n", XPC_PARTID(part), reason); if (!xpc_part_ref(part)) { /* infrastructure for this partition isn't currently set up */ return; } /* disconnect channels associated with the partition going down */ for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; xpc_msgqueue_ref(ch); spin_lock_irqsave(&ch->lock, irq_flags); XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); xpc_msgqueue_deref(ch); } xpc_wakeup_channel_mgr(part); xpc_part_deref(part); }
/* * Timer function to enforce the timelimit on the partition disengage request. */ static void xpc_timeout_partition_disengage_request(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); (void)xpc_partition_disengaged(part); DBUG_ON(part->disengage_request_timeout != 0); DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); }
/* * Timer function to enforce the timelimit on the partition disengage. */ static void xpc_timeout_partition_disengage(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; DBUG_ON(time_is_after_jiffies(part->disengage_timeout)); (void)xpc_partition_disengaged(part); DBUG_ON(part->disengage_timeout != 0); DBUG_ON(xpc_partition_engaged(XPC_PARTID(part))); }
/* * Mark specified partition as inactive. */ void xpc_mark_partition_inactive(struct xpc_partition *part) { unsigned long irq_flags; dev_dbg(xpc_part, "setting partition %d to INACTIVE\n", XPC_PARTID(part)); spin_lock_irqsave(&part->act_lock, irq_flags); part->act_state = XPC_P_AS_INACTIVE; spin_unlock_irqrestore(&part->act_lock, irq_flags); part->remote_rp_pa = 0; }
/* * Start the process of deactivating the specified partition. */ void xpc_deactivate_partition(const int line, struct xpc_partition *part, enum xp_retval reason) { unsigned long irq_flags; spin_lock_irqsave(&part->act_lock, irq_flags); if (part->act_state == XPC_P_AS_INACTIVE) { XPC_SET_REASON(part, reason, line); spin_unlock_irqrestore(&part->act_lock, irq_flags); if (reason == xpReactivating) { /* we interrupt ourselves to reactivate partition */ xpc_request_partition_reactivation(part); } return; } if (part->act_state == XPC_P_AS_DEACTIVATING) { if ((part->reason == xpUnloading && reason != xpUnloading) || reason == xpReactivating) { XPC_SET_REASON(part, reason, line); } spin_unlock_irqrestore(&part->act_lock, irq_flags); return; } part->act_state = XPC_P_AS_DEACTIVATING; XPC_SET_REASON(part, reason, line); spin_unlock_irqrestore(&part->act_lock, irq_flags); /* ask remote partition to deactivate with regard to us */ xpc_request_partition_deactivation(part); /* set a timelimit on the disengage phase of the deactivation request */ part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ); part->disengage_timer.expires = part->disengage_timeout; add_timer(&part->disengage_timer); dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", XPC_PARTID(part), reason); xpc_partition_going_down(part, reason); }
/* * Mark specified partition as active. */ enum xp_retval xpc_mark_partition_active(struct xpc_partition *part) { unsigned long irq_flags; enum xp_retval ret; dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); spin_lock_irqsave(&part->act_lock, irq_flags); if (part->act_state == XPC_P_AS_ACTIVATING) { part->act_state = XPC_P_AS_ACTIVE; ret = xpSuccess; } else { DBUG_ON(part->reason == xpSuccess); ret = part->reason; } spin_unlock_irqrestore(&part->act_lock, irq_flags); return ret; }
/* * See if the other side has responded to a partition deactivate request * from us. Though we requested the remote partition to deactivate with regard * to us, we really only need to wait for the other side to disengage from us. */ int xpc_partition_disengaged(struct xpc_partition *part) { short partid = XPC_PARTID(part); int disengaged; disengaged = !xpc_partition_engaged(partid); if (part->disengage_timeout) { if (!disengaged) { if (time_is_after_jiffies(part->disengage_timeout)) { /* timelimit hasn't been reached yet */ return 0; } /* * Other side hasn't responded to our deactivate * request in a timely fashion, so assume it's dead. */ dev_info(xpc_part, "deactivate request to remote " "partition %d timed out\n", partid); xpc_disengage_timedout = 1; xpc_assume_partition_disengaged(partid); disengaged = 1; } part->disengage_timeout = 0; /* cancel the timer function, provided it's not us */ if (!in_interrupt()) del_singleshot_timer_sync(&part->disengage_timer); DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING && part->act_state != XPC_P_AS_INACTIVE); if (part->act_state != XPC_P_AS_INACTIVE) xpc_wakeup_channel_mgr(part); xpc_cancel_partition_deactivation_request(part); } return disengaged; }
/* * Establish first contact with the remote partititon. This involves pulling * the XPC per partition variables from the remote partition and waiting for * the remote partition to pull ours. */ static enum xp_retval xpc_make_first_contact(struct xpc_partition *part) { enum xp_retval ret; while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) { if (ret != xpRetry) { XPC_DEACTIVATE_PARTITION(part, ret); return ret; } dev_dbg(xpc_chan, "waiting to make first contact with " "partition %d\n", XPC_PARTID(part)); /* wait a 1/4 of a second or so */ (void)msleep_interruptible(250); if (part->act_state == XPC_P_DEACTIVATING) return part->reason; } return xpc_mark_partition_active(part); }
static enum xp_retval xpc_make_first_contact_uv(struct xpc_partition *part) { struct xpc_activate_mq_msg_uv msg; xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) { dev_dbg(xpc_part, "waiting to make first contact with " "partition %d\n", XPC_PARTID(part)); (void)msleep_interruptible(250); if (part->act_state == XPC_P_AS_DEACTIVATING) return part->reason; } return xpSuccess; }
static void xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, struct xpc_notify_mq_msg_uv *msg) { struct xpc_partition_uv *part_uv = &part->sn.uv; struct xpc_channel *ch; struct xpc_channel_uv *ch_uv; struct xpc_notify_mq_msg_uv *msg_slot; unsigned long irq_flags; int ch_number = msg->hdr.ch_number; if (unlikely(ch_number >= part->nchannels)) { dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid " "channel number=0x%x in message from partid=%d\n", ch_number, XPC_PARTID(part)); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = xpBadChannelNumber; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); wake_up_interruptible(&xpc_activate_IRQ_wq); return; } ch = &part->channels[ch_number]; xpc_msgqueue_ref(ch); if (!(ch->flags & XPC_C_CONNECTED)) { xpc_msgqueue_deref(ch); return; } if (msg->hdr.size == 0) { xpc_handle_notify_mq_ack_uv(ch, msg); xpc_msgqueue_deref(ch); return; } ch_uv = &ch->sn.uv; msg_slot = ch_uv->recv_msg_slots + (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size; BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number); BUG_ON(msg_slot->hdr.size != 0); memcpy(msg_slot, msg, msg->hdr.size); xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next); if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { if (atomic_read(&ch->kthreads_idle) > 0) wake_up_nr(&ch->idle_wq, 1); else xpc_send_chctl_local_msgrequest_uv(part, ch->number); } xpc_msgqueue_deref(ch); }
/* * Setup the channel structures necessary to support XPartition Communication * between the specified remote partition and the local one. */ static enum xp_retval xpc_setup_ch_structures(struct xpc_partition *part) { enum xp_retval ret; int ch_number; struct xpc_channel *ch; short partid = XPC_PARTID(part); /* * Allocate all of the channel structures as a contiguous chunk of * memory. */ DBUG_ON(part->channels != NULL); part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, GFP_KERNEL); if (part->channels == NULL) { dev_err(xpc_chan, "can't get memory for channels\n"); return xpNoMemory; } /* allocate the remote open and close args */ part->remote_openclose_args = xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, &part-> remote_openclose_args_base); if (part->remote_openclose_args == NULL) { dev_err(xpc_chan, "can't get memory for remote connect args\n"); ret = xpNoMemory; goto out_1; } part->chctl.all_flags = 0; spin_lock_init(&part->chctl_lock); atomic_set(&part->channel_mgr_requests, 1); init_waitqueue_head(&part->channel_mgr_wq); part->nchannels = XPC_MAX_NCHANNELS; atomic_set(&part->nchannels_active, 0); atomic_set(&part->nchannels_engaged, 0); for (ch_number = 0; ch_number < part->nchannels; ch_number++) { ch = &part->channels[ch_number]; ch->partid = partid; ch->number = ch_number; ch->flags = XPC_C_DISCONNECTED; atomic_set(&ch->kthreads_assigned, 0); atomic_set(&ch->kthreads_idle, 0); atomic_set(&ch->kthreads_active, 0); atomic_set(&ch->references, 0); atomic_set(&ch->n_to_notify, 0); spin_lock_init(&ch->lock); init_completion(&ch->wdisconnect_wait); atomic_set(&ch->n_on_msg_allocate_wq, 0); init_waitqueue_head(&ch->msg_allocate_wq); init_waitqueue_head(&ch->idle_wq); } ret = xpc_setup_ch_structures_sn(part); if (ret != xpSuccess) goto out_2; /* * With the setting of the partition setup_state to XPC_P_SS_SETUP, * we're declaring that this partition is ready to go. */ part->setup_state = XPC_P_SS_SETUP; return xpSuccess; /* setup of ch structures failed */ out_2: kfree(part->remote_openclose_args_base); part->remote_openclose_args = NULL; out_1: kfree(part->channels); part->channels = NULL; return ret; }
static void xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, struct xpc_activate_mq_msghdr_uv *msg_hdr, int part_setup, int *wakeup_hb_checker) { unsigned long irq_flags; struct xpc_partition_uv *part_uv = &part->sn.uv; struct xpc_openclose_args *args; part_uv->remote_act_state = msg_hdr->act_state; switch (msg_hdr->type) { case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: /* syncing of remote_act_state was just done above */ break; case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { struct xpc_activate_mq_msg_activate_req_uv *msg; /* * ??? Do we deal here with ts_jiffies being different * ??? if act_state != XPC_P_AS_INACTIVE instead of * ??? below? */ msg = container_of(msg_hdr, struct xpc_activate_mq_msg_activate_req_uv, hdr); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; part_uv->heartbeat_gpa = msg->heartbeat_gpa; if (msg->activate_gru_mq_desc_gpa != part_uv->activate_gru_mq_desc_gpa) { spin_lock(&part_uv->flags_lock); part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; spin_unlock(&part_uv->flags_lock); part_uv->activate_gru_mq_desc_gpa = msg->activate_gru_mq_desc_gpa; } spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; break; } case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { struct xpc_activate_mq_msg_deactivate_req_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_deactivate_req_uv, hdr); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = msg->reason; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; return; } case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; if (!part_setup) break; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_closerequest_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->reason = msg->reason; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { struct xpc_activate_mq_msg_chctl_closereply_uv *msg; if (!part_setup) break; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_closereply_uv, hdr); spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; if (!part_setup) break; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_openrequest_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->entry_size = msg->entry_size; args->local_nentries = msg->local_nentries; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { struct xpc_activate_mq_msg_chctl_openreply_uv *msg; if (!part_setup) break; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_openreply_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->remote_nentries = msg->remote_nentries; args->local_nentries = msg->local_nentries; args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: { struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg; if (!part_setup) break; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_opencomplete_uv, hdr); spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENCOMPLETE; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); } case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: spin_lock_irqsave(&part_uv->flags_lock, irq_flags); part_uv->flags |= XPC_P_ENGAGED_UV; spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); break; case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: spin_lock_irqsave(&part_uv->flags_lock, irq_flags); part_uv->flags &= ~XPC_P_ENGAGED_UV; spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); break; default: dev_err(xpc_part, "received unknown activate_mq msg type=%d " "from partition=%d\n", msg_hdr->type, XPC_PARTID(part)); /* get hb checker to deactivate from the remote partition */ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = xpBadMsgType; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; return; } if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && part->remote_rp_ts_jiffies != 0) { /* * ??? Does what we do here need to be sensitive to * ??? act_state or remote_act_state? */ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; } }
static void xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, struct xpc_notify_mq_msg_uv *msg) { struct xpc_partition_uv *part_uv = &part->sn.uv; struct xpc_channel *ch; struct xpc_channel_uv *ch_uv; struct xpc_notify_mq_msg_uv *msg_slot; unsigned long irq_flags; int ch_number = msg->hdr.ch_number; if (unlikely(ch_number >= part->nchannels)) { dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid " "channel number=0x%x in message from partid=%d\n", ch_number, XPC_PARTID(part)); /* get hb checker to deactivate from the remote partition */ spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = xpBadChannelNumber; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); wake_up_interruptible(&xpc_activate_IRQ_wq); return; } ch = &part->channels[ch_number]; xpc_msgqueue_ref(ch); if (!(ch->flags & XPC_C_CONNECTED)) { xpc_msgqueue_deref(ch); return; } /* see if we're really dealing with an ACK for a previously sent msg */ if (msg->hdr.size == 0) { xpc_handle_notify_mq_ack_uv(ch, msg); xpc_msgqueue_deref(ch); return; } /* we're dealing with a normal message sent via the notify_mq */ ch_uv = &ch->sn.uv; msg_slot = ch_uv->recv_msg_slots + (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size; BUG_ON(msg_slot->hdr.size != 0); memcpy(msg_slot, msg, msg->hdr.size); xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next); if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { /* * If there is an existing idle kthread get it to deliver * the payload, otherwise we'll have to get the channel mgr * for this partition to create a kthread to do the delivery. */ if (atomic_read(&ch->kthreads_idle) > 0) wake_up_nr(&ch->idle_wq, 1); else xpc_send_chctl_local_msgrequest_uv(part, ch->number); } xpc_msgqueue_deref(ch); }
static void xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, struct xpc_activate_mq_msghdr_uv *msg_hdr, int *wakeup_hb_checker) { unsigned long irq_flags; struct xpc_partition_uv *part_uv = &part->sn.uv; struct xpc_openclose_args *args; part_uv->remote_act_state = msg_hdr->act_state; switch (msg_hdr->type) { case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: break; case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { struct xpc_activate_mq_msg_activate_req_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_activate_req_uv, hdr); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; part->remote_rp_pa = msg->rp_gpa; part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; part_uv->heartbeat_gpa = msg->heartbeat_gpa; if (msg->activate_gru_mq_desc_gpa != part_uv->activate_gru_mq_desc_gpa) { spin_lock_irqsave(&part_uv->flags_lock, irq_flags); part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); part_uv->activate_gru_mq_desc_gpa = msg->activate_gru_mq_desc_gpa; } spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; break; } case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { struct xpc_activate_mq_msg_deactivate_req_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_deactivate_req_uv, hdr); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = msg->reason; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; return; } case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_closerequest_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->reason = msg->reason; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { struct xpc_activate_mq_msg_chctl_closereply_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_closereply_uv, hdr); spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_openrequest_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->entry_size = msg->entry_size; args->local_nentries = msg->local_nentries; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { struct xpc_activate_mq_msg_chctl_openreply_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_openreply_uv, hdr); args = &part->remote_openclose_args[msg->ch_number]; args->remote_nentries = msg->remote_nentries; args->local_nentries = msg->local_nentries; args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); break; } case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: { struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg; msg = container_of(msg_hdr, struct xpc_activate_mq_msg_chctl_opencomplete_uv, hdr); spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENCOMPLETE; spin_unlock_irqrestore(&part->chctl_lock, irq_flags); xpc_wakeup_channel_mgr(part); } case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: spin_lock_irqsave(&part_uv->flags_lock, irq_flags); part_uv->flags |= XPC_P_ENGAGED_UV; spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); break; case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: spin_lock_irqsave(&part_uv->flags_lock, irq_flags); part_uv->flags &= ~XPC_P_ENGAGED_UV; spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); break; default: dev_err(xpc_part, "received unknown activate_mq msg type=%d " "from partition=%d\n", msg_hdr->type, XPC_PARTID(part)); spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; part_uv->reason = xpBadMsgType; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; return; } if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && part->remote_rp_ts_jiffies != 0) { spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); if (part_uv->act_state_req == 0) xpc_activate_IRQ_rcvd++; part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; } }