162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Cross Partition Communication (XPC) uv-based functions.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Architecture specific implementation of common functions.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/mm.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci#include <linux/device.h>
2162306a36Sopenharmony_ci#include <linux/cpu.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/err.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <linux/numa.h>
2662306a36Sopenharmony_ci#include <asm/uv/uv_hub.h>
2762306a36Sopenharmony_ci#if defined CONFIG_X86_64
2862306a36Sopenharmony_ci#include <asm/uv/bios.h>
2962306a36Sopenharmony_ci#include <asm/uv/uv_irq.h>
3062306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
3162306a36Sopenharmony_ci#include <asm/sn/intr.h>
3262306a36Sopenharmony_ci#include <asm/sn/sn_sal.h>
3362306a36Sopenharmony_ci#endif
3462306a36Sopenharmony_ci#include "../sgi-gru/gru.h"
3562306a36Sopenharmony_ci#include "../sgi-gru/grukservices.h"
3662306a36Sopenharmony_ci#include "xpc.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#if defined CONFIG_IA64_SGI_UV
3962306a36Sopenharmony_cistruct uv_IO_APIC_route_entry {
4062306a36Sopenharmony_ci	__u64	vector		:  8,
4162306a36Sopenharmony_ci		delivery_mode	:  3,
4262306a36Sopenharmony_ci		dest_mode	:  1,
4362306a36Sopenharmony_ci		delivery_status	:  1,
4462306a36Sopenharmony_ci		polarity	:  1,
4562306a36Sopenharmony_ci		__reserved_1	:  1,
4662306a36Sopenharmony_ci		trigger		:  1,
4762306a36Sopenharmony_ci		mask		:  1,
4862306a36Sopenharmony_ci		__reserved_2	: 15,
4962306a36Sopenharmony_ci		dest		: 32;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define sn_partition_id 0
5362306a36Sopenharmony_ci#endif
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic struct xpc_heartbeat_uv *xpc_heartbeat_uv;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define XPC_ACTIVATE_MSG_SIZE_UV	(1 * GRU_CACHE_LINE_BYTES)
5862306a36Sopenharmony_ci#define XPC_ACTIVATE_MQ_SIZE_UV		(4 * XP_MAX_NPARTITIONS_UV * \
5962306a36Sopenharmony_ci					 XPC_ACTIVATE_MSG_SIZE_UV)
6062306a36Sopenharmony_ci#define XPC_ACTIVATE_IRQ_NAME		"xpc_activate"
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define XPC_NOTIFY_MSG_SIZE_UV		(2 * GRU_CACHE_LINE_BYTES)
6362306a36Sopenharmony_ci#define XPC_NOTIFY_MQ_SIZE_UV		(4 * XP_MAX_NPARTITIONS_UV * \
6462306a36Sopenharmony_ci					 XPC_NOTIFY_MSG_SIZE_UV)
6562306a36Sopenharmony_ci#define XPC_NOTIFY_IRQ_NAME		"xpc_notify"
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int xpc_mq_node = NUMA_NO_NODE;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct xpc_gru_mq_uv *xpc_activate_mq_uv;
7062306a36Sopenharmony_cistatic struct xpc_gru_mq_uv *xpc_notify_mq_uv;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int
7362306a36Sopenharmony_cixpc_setup_partitions_uv(void)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	short partid;
7662306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
7962306a36Sopenharmony_ci		part_uv = &xpc_partitions[partid].sn.uv;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		mutex_init(&part_uv->cached_activate_gru_mq_desc_mutex);
8262306a36Sopenharmony_ci		spin_lock_init(&part_uv->flags_lock);
8362306a36Sopenharmony_ci		part_uv->remote_act_state = XPC_P_AS_INACTIVE;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void
8962306a36Sopenharmony_cixpc_teardown_partitions_uv(void)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	short partid;
9262306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv;
9362306a36Sopenharmony_ci	unsigned long irq_flags;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
9662306a36Sopenharmony_ci		part_uv = &xpc_partitions[partid].sn.uv;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		if (part_uv->cached_activate_gru_mq_desc != NULL) {
9962306a36Sopenharmony_ci			mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
10062306a36Sopenharmony_ci			spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
10162306a36Sopenharmony_ci			part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
10262306a36Sopenharmony_ci			spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
10362306a36Sopenharmony_ci			kfree(part_uv->cached_activate_gru_mq_desc);
10462306a36Sopenharmony_ci			part_uv->cached_activate_gru_mq_desc = NULL;
10562306a36Sopenharmony_ci			mutex_unlock(&part_uv->
10662306a36Sopenharmony_ci				     cached_activate_gru_mq_desc_mutex);
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int
11262306a36Sopenharmony_cixpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#if defined CONFIG_X86_64
11762306a36Sopenharmony_ci	mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
11862306a36Sopenharmony_ci			UV_AFFINITY_CPU);
11962306a36Sopenharmony_ci	if (mq->irq < 0)
12062306a36Sopenharmony_ci		return mq->irq;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
12562306a36Sopenharmony_ci	if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
12662306a36Sopenharmony_ci		mq->irq = SGI_XPC_ACTIVATE;
12762306a36Sopenharmony_ci	else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
12862306a36Sopenharmony_ci		mq->irq = SGI_XPC_NOTIFY;
12962306a36Sopenharmony_ci	else
13062306a36Sopenharmony_ci		return -EINVAL;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	mq->mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
13362306a36Sopenharmony_ci	uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mq->mmr_value);
13462306a36Sopenharmony_ci#else
13562306a36Sopenharmony_ci	#error not a supported configuration
13662306a36Sopenharmony_ci#endif
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void
14262306a36Sopenharmony_cixpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci#if defined CONFIG_X86_64
14562306a36Sopenharmony_ci	uv_teardown_irq(mq->irq);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
14862306a36Sopenharmony_ci	int mmr_pnode;
14962306a36Sopenharmony_ci	unsigned long mmr_value;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
15262306a36Sopenharmony_ci	mmr_value = 1UL << 16;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value);
15562306a36Sopenharmony_ci#else
15662306a36Sopenharmony_ci	#error not a supported configuration
15762306a36Sopenharmony_ci#endif
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int
16162306a36Sopenharmony_cixpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	int ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#if defined CONFIG_IA64_SGI_UV
16662306a36Sopenharmony_ci	int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address),
16962306a36Sopenharmony_ci				    mq->order, &mq->mmr_offset);
17062306a36Sopenharmony_ci	if (ret < 0) {
17162306a36Sopenharmony_ci		dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n",
17262306a36Sopenharmony_ci			ret);
17362306a36Sopenharmony_ci		return -EBUSY;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci#elif defined CONFIG_X86_64
17662306a36Sopenharmony_ci	ret = uv_bios_mq_watchlist_alloc(uv_gpa(mq->address),
17762306a36Sopenharmony_ci					 mq->order, &mq->mmr_offset);
17862306a36Sopenharmony_ci	if (ret < 0) {
17962306a36Sopenharmony_ci		dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, "
18062306a36Sopenharmony_ci			"ret=%d\n", ret);
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci#else
18462306a36Sopenharmony_ci	#error not a supported configuration
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	mq->watchlist_num = ret;
18862306a36Sopenharmony_ci	return 0;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void
19262306a36Sopenharmony_cixpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	int ret;
19562306a36Sopenharmony_ci	int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#if defined CONFIG_X86_64
19862306a36Sopenharmony_ci	ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
19962306a36Sopenharmony_ci	BUG_ON(ret != BIOS_STATUS_SUCCESS);
20062306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
20162306a36Sopenharmony_ci	ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
20262306a36Sopenharmony_ci	BUG_ON(ret != SALRET_OK);
20362306a36Sopenharmony_ci#else
20462306a36Sopenharmony_ci	#error not a supported configuration
20562306a36Sopenharmony_ci#endif
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic struct xpc_gru_mq_uv *
20962306a36Sopenharmony_cixpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
21062306a36Sopenharmony_ci		     irq_handler_t irq_handler)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	enum xp_retval xp_ret;
21362306a36Sopenharmony_ci	int ret;
21462306a36Sopenharmony_ci	int nid;
21562306a36Sopenharmony_ci	int nasid;
21662306a36Sopenharmony_ci	int pg_order;
21762306a36Sopenharmony_ci	struct page *page;
21862306a36Sopenharmony_ci	struct xpc_gru_mq_uv *mq;
21962306a36Sopenharmony_ci	struct uv_IO_APIC_route_entry *mmr_value;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL);
22262306a36Sopenharmony_ci	if (mq == NULL) {
22362306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
22462306a36Sopenharmony_ci			"a xpc_gru_mq_uv structure\n");
22562306a36Sopenharmony_ci		ret = -ENOMEM;
22662306a36Sopenharmony_ci		goto out_0;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	mq->gru_mq_desc = kzalloc(sizeof(struct gru_message_queue_desc),
23062306a36Sopenharmony_ci				  GFP_KERNEL);
23162306a36Sopenharmony_ci	if (mq->gru_mq_desc == NULL) {
23262306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
23362306a36Sopenharmony_ci			"a gru_message_queue_desc structure\n");
23462306a36Sopenharmony_ci		ret = -ENOMEM;
23562306a36Sopenharmony_ci		goto out_1;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	pg_order = get_order(mq_size);
23962306a36Sopenharmony_ci	mq->order = pg_order + PAGE_SHIFT;
24062306a36Sopenharmony_ci	mq_size = 1UL << mq->order;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	mq->mmr_blade = uv_cpu_to_blade_id(cpu);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	nid = cpu_to_node(cpu);
24562306a36Sopenharmony_ci	page = __alloc_pages_node(nid,
24662306a36Sopenharmony_ci				      GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
24762306a36Sopenharmony_ci				      pg_order);
24862306a36Sopenharmony_ci	if (page == NULL) {
24962306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
25062306a36Sopenharmony_ci			"bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
25162306a36Sopenharmony_ci		ret = -ENOMEM;
25262306a36Sopenharmony_ci		goto out_2;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	mq->address = page_address(page);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* enable generation of irq when GRU mq operation occurs to this mq */
25762306a36Sopenharmony_ci	ret = xpc_gru_mq_watchlist_alloc_uv(mq);
25862306a36Sopenharmony_ci	if (ret != 0)
25962306a36Sopenharmony_ci		goto out_3;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ret = xpc_get_gru_mq_irq_uv(mq, cpu, irq_name);
26262306a36Sopenharmony_ci	if (ret != 0)
26362306a36Sopenharmony_ci		goto out_4;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL);
26662306a36Sopenharmony_ci	if (ret != 0) {
26762306a36Sopenharmony_ci		dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
26862306a36Sopenharmony_ci			mq->irq, -ret);
26962306a36Sopenharmony_ci		goto out_5;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	nasid = UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpu));
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value;
27562306a36Sopenharmony_ci	ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size,
27662306a36Sopenharmony_ci				     nasid, mmr_value->vector, mmr_value->dest);
27762306a36Sopenharmony_ci	if (ret != 0) {
27862306a36Sopenharmony_ci		dev_err(xpc_part, "gru_create_message_queue() returned "
27962306a36Sopenharmony_ci			"error=%d\n", ret);
28062306a36Sopenharmony_ci		ret = -EINVAL;
28162306a36Sopenharmony_ci		goto out_6;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* allow other partitions to access this GRU mq */
28562306a36Sopenharmony_ci	xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size);
28662306a36Sopenharmony_ci	if (xp_ret != xpSuccess) {
28762306a36Sopenharmony_ci		ret = -EACCES;
28862306a36Sopenharmony_ci		goto out_6;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return mq;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* something went wrong */
29462306a36Sopenharmony_ciout_6:
29562306a36Sopenharmony_ci	free_irq(mq->irq, NULL);
29662306a36Sopenharmony_ciout_5:
29762306a36Sopenharmony_ci	xpc_release_gru_mq_irq_uv(mq);
29862306a36Sopenharmony_ciout_4:
29962306a36Sopenharmony_ci	xpc_gru_mq_watchlist_free_uv(mq);
30062306a36Sopenharmony_ciout_3:
30162306a36Sopenharmony_ci	free_pages((unsigned long)mq->address, pg_order);
30262306a36Sopenharmony_ciout_2:
30362306a36Sopenharmony_ci	kfree(mq->gru_mq_desc);
30462306a36Sopenharmony_ciout_1:
30562306a36Sopenharmony_ci	kfree(mq);
30662306a36Sopenharmony_ciout_0:
30762306a36Sopenharmony_ci	return ERR_PTR(ret);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic void
31162306a36Sopenharmony_cixpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	unsigned int mq_size;
31462306a36Sopenharmony_ci	int pg_order;
31562306a36Sopenharmony_ci	int ret;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* disallow other partitions to access GRU mq */
31862306a36Sopenharmony_ci	mq_size = 1UL << mq->order;
31962306a36Sopenharmony_ci	ret = xp_restrict_memprotect(xp_pa(mq->address), mq_size);
32062306a36Sopenharmony_ci	BUG_ON(ret != xpSuccess);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* unregister irq handler and release mq irq/vector mapping */
32362306a36Sopenharmony_ci	free_irq(mq->irq, NULL);
32462306a36Sopenharmony_ci	xpc_release_gru_mq_irq_uv(mq);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* disable generation of irq when GRU mq op occurs to this mq */
32762306a36Sopenharmony_ci	xpc_gru_mq_watchlist_free_uv(mq);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	pg_order = mq->order - PAGE_SHIFT;
33062306a36Sopenharmony_ci	free_pages((unsigned long)mq->address, pg_order);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	kfree(mq);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic enum xp_retval
33662306a36Sopenharmony_cixpc_send_gru_msg(struct gru_message_queue_desc *gru_mq_desc, void *msg,
33762306a36Sopenharmony_ci		 size_t msg_size)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	enum xp_retval xp_ret;
34062306a36Sopenharmony_ci	int ret;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	while (1) {
34362306a36Sopenharmony_ci		ret = gru_send_message_gpa(gru_mq_desc, msg, msg_size);
34462306a36Sopenharmony_ci		if (ret == MQE_OK) {
34562306a36Sopenharmony_ci			xp_ret = xpSuccess;
34662306a36Sopenharmony_ci			break;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		if (ret == MQE_QUEUE_FULL) {
35062306a36Sopenharmony_ci			dev_dbg(xpc_chan, "gru_send_message_gpa() returned "
35162306a36Sopenharmony_ci				"error=MQE_QUEUE_FULL\n");
35262306a36Sopenharmony_ci			/* !!! handle QLimit reached; delay & try again */
35362306a36Sopenharmony_ci			/* ??? Do we add a limit to the number of retries? */
35462306a36Sopenharmony_ci			(void)msleep_interruptible(10);
35562306a36Sopenharmony_ci		} else if (ret == MQE_CONGESTION) {
35662306a36Sopenharmony_ci			dev_dbg(xpc_chan, "gru_send_message_gpa() returned "
35762306a36Sopenharmony_ci				"error=MQE_CONGESTION\n");
35862306a36Sopenharmony_ci			/* !!! handle LB Overflow; simply try again */
35962306a36Sopenharmony_ci			/* ??? Do we add a limit to the number of retries? */
36062306a36Sopenharmony_ci		} else {
36162306a36Sopenharmony_ci			/* !!! Currently this is MQE_UNEXPECTED_CB_ERR */
36262306a36Sopenharmony_ci			dev_err(xpc_chan, "gru_send_message_gpa() returned "
36362306a36Sopenharmony_ci				"error=%d\n", ret);
36462306a36Sopenharmony_ci			xp_ret = xpGruSendMqError;
36562306a36Sopenharmony_ci			break;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci	return xp_ret;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic void
37262306a36Sopenharmony_cixpc_process_activate_IRQ_rcvd_uv(void)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	unsigned long irq_flags;
37562306a36Sopenharmony_ci	short partid;
37662306a36Sopenharmony_ci	struct xpc_partition *part;
37762306a36Sopenharmony_ci	u8 act_state_req;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	DBUG_ON(xpc_activate_IRQ_rcvd == 0);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
38262306a36Sopenharmony_ci	for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
38362306a36Sopenharmony_ci		part = &xpc_partitions[partid];
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		if (part->sn.uv.act_state_req == 0)
38662306a36Sopenharmony_ci			continue;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		xpc_activate_IRQ_rcvd--;
38962306a36Sopenharmony_ci		BUG_ON(xpc_activate_IRQ_rcvd < 0);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		act_state_req = part->sn.uv.act_state_req;
39262306a36Sopenharmony_ci		part->sn.uv.act_state_req = 0;
39362306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		if (act_state_req == XPC_P_ASR_ACTIVATE_UV) {
39662306a36Sopenharmony_ci			if (part->act_state == XPC_P_AS_INACTIVE)
39762306a36Sopenharmony_ci				xpc_activate_partition(part);
39862306a36Sopenharmony_ci			else if (part->act_state == XPC_P_AS_DEACTIVATING)
39962306a36Sopenharmony_ci				XPC_DEACTIVATE_PARTITION(part, xpReactivating);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		} else if (act_state_req == XPC_P_ASR_REACTIVATE_UV) {
40262306a36Sopenharmony_ci			if (part->act_state == XPC_P_AS_INACTIVE)
40362306a36Sopenharmony_ci				xpc_activate_partition(part);
40462306a36Sopenharmony_ci			else
40562306a36Sopenharmony_ci				XPC_DEACTIVATE_PARTITION(part, xpReactivating);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		} else if (act_state_req == XPC_P_ASR_DEACTIVATE_UV) {
40862306a36Sopenharmony_ci			XPC_DEACTIVATE_PARTITION(part, part->sn.uv.reason);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		} else {
41162306a36Sopenharmony_ci			BUG();
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
41562306a36Sopenharmony_ci		if (xpc_activate_IRQ_rcvd == 0)
41662306a36Sopenharmony_ci			break;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic void
42362306a36Sopenharmony_cixpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
42462306a36Sopenharmony_ci			      struct xpc_activate_mq_msghdr_uv *msg_hdr,
42562306a36Sopenharmony_ci			      int part_setup,
42662306a36Sopenharmony_ci			      int *wakeup_hb_checker)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	unsigned long irq_flags;
42962306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &part->sn.uv;
43062306a36Sopenharmony_ci	struct xpc_openclose_args *args;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	part_uv->remote_act_state = msg_hdr->act_state;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	switch (msg_hdr->type) {
43562306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV:
43662306a36Sopenharmony_ci		/* syncing of remote_act_state was just done above */
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: {
44062306a36Sopenharmony_ci		struct xpc_activate_mq_msg_activate_req_uv *msg;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		/*
44362306a36Sopenharmony_ci		 * ??? Do we deal here with ts_jiffies being different
44462306a36Sopenharmony_ci		 * ??? if act_state != XPC_P_AS_INACTIVE instead of
44562306a36Sopenharmony_ci		 * ??? below?
44662306a36Sopenharmony_ci		 */
44762306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
44862306a36Sopenharmony_ci				   xpc_activate_mq_msg_activate_req_uv, hdr);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
45162306a36Sopenharmony_ci		if (part_uv->act_state_req == 0)
45262306a36Sopenharmony_ci			xpc_activate_IRQ_rcvd++;
45362306a36Sopenharmony_ci		part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV;
45462306a36Sopenharmony_ci		part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */
45562306a36Sopenharmony_ci		part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies;
45662306a36Sopenharmony_ci		part_uv->heartbeat_gpa = msg->heartbeat_gpa;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		if (msg->activate_gru_mq_desc_gpa !=
45962306a36Sopenharmony_ci		    part_uv->activate_gru_mq_desc_gpa) {
46062306a36Sopenharmony_ci			spin_lock(&part_uv->flags_lock);
46162306a36Sopenharmony_ci			part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
46262306a36Sopenharmony_ci			spin_unlock(&part_uv->flags_lock);
46362306a36Sopenharmony_ci			part_uv->activate_gru_mq_desc_gpa =
46462306a36Sopenharmony_ci			    msg->activate_gru_mq_desc_gpa;
46562306a36Sopenharmony_ci		}
46662306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		(*wakeup_hb_checker)++;
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: {
47262306a36Sopenharmony_ci		struct xpc_activate_mq_msg_deactivate_req_uv *msg;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
47562306a36Sopenharmony_ci				   xpc_activate_mq_msg_deactivate_req_uv, hdr);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
47862306a36Sopenharmony_ci		if (part_uv->act_state_req == 0)
47962306a36Sopenharmony_ci			xpc_activate_IRQ_rcvd++;
48062306a36Sopenharmony_ci		part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
48162306a36Sopenharmony_ci		part_uv->reason = msg->reason;
48262306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		(*wakeup_hb_checker)++;
48562306a36Sopenharmony_ci		return;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: {
48862306a36Sopenharmony_ci		struct xpc_activate_mq_msg_chctl_closerequest_uv *msg;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		if (!part_setup)
49162306a36Sopenharmony_ci			break;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
49462306a36Sopenharmony_ci				   xpc_activate_mq_msg_chctl_closerequest_uv,
49562306a36Sopenharmony_ci				   hdr);
49662306a36Sopenharmony_ci		args = &part->remote_openclose_args[msg->ch_number];
49762306a36Sopenharmony_ci		args->reason = msg->reason;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		spin_lock_irqsave(&part->chctl_lock, irq_flags);
50062306a36Sopenharmony_ci		part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST;
50162306a36Sopenharmony_ci		spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		xpc_wakeup_channel_mgr(part);
50462306a36Sopenharmony_ci		break;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: {
50762306a36Sopenharmony_ci		struct xpc_activate_mq_msg_chctl_closereply_uv *msg;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		if (!part_setup)
51062306a36Sopenharmony_ci			break;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
51362306a36Sopenharmony_ci				   xpc_activate_mq_msg_chctl_closereply_uv,
51462306a36Sopenharmony_ci				   hdr);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		spin_lock_irqsave(&part->chctl_lock, irq_flags);
51762306a36Sopenharmony_ci		part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY;
51862306a36Sopenharmony_ci		spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		xpc_wakeup_channel_mgr(part);
52162306a36Sopenharmony_ci		break;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: {
52462306a36Sopenharmony_ci		struct xpc_activate_mq_msg_chctl_openrequest_uv *msg;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		if (!part_setup)
52762306a36Sopenharmony_ci			break;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
53062306a36Sopenharmony_ci				   xpc_activate_mq_msg_chctl_openrequest_uv,
53162306a36Sopenharmony_ci				   hdr);
53262306a36Sopenharmony_ci		args = &part->remote_openclose_args[msg->ch_number];
53362306a36Sopenharmony_ci		args->entry_size = msg->entry_size;
53462306a36Sopenharmony_ci		args->local_nentries = msg->local_nentries;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		spin_lock_irqsave(&part->chctl_lock, irq_flags);
53762306a36Sopenharmony_ci		part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST;
53862306a36Sopenharmony_ci		spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		xpc_wakeup_channel_mgr(part);
54162306a36Sopenharmony_ci		break;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: {
54462306a36Sopenharmony_ci		struct xpc_activate_mq_msg_chctl_openreply_uv *msg;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		if (!part_setup)
54762306a36Sopenharmony_ci			break;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
55062306a36Sopenharmony_ci				   xpc_activate_mq_msg_chctl_openreply_uv, hdr);
55162306a36Sopenharmony_ci		args = &part->remote_openclose_args[msg->ch_number];
55262306a36Sopenharmony_ci		args->remote_nentries = msg->remote_nentries;
55362306a36Sopenharmony_ci		args->local_nentries = msg->local_nentries;
55462306a36Sopenharmony_ci		args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		spin_lock_irqsave(&part->chctl_lock, irq_flags);
55762306a36Sopenharmony_ci		part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY;
55862306a36Sopenharmony_ci		spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		xpc_wakeup_channel_mgr(part);
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: {
56462306a36Sopenharmony_ci		struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		if (!part_setup)
56762306a36Sopenharmony_ci			break;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		msg = container_of(msg_hdr, struct
57062306a36Sopenharmony_ci				xpc_activate_mq_msg_chctl_opencomplete_uv, hdr);
57162306a36Sopenharmony_ci		spin_lock_irqsave(&part->chctl_lock, irq_flags);
57262306a36Sopenharmony_ci		part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENCOMPLETE;
57362306a36Sopenharmony_ci		spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		xpc_wakeup_channel_mgr(part);
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci		fallthrough;
57862306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV:
57962306a36Sopenharmony_ci		spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
58062306a36Sopenharmony_ci		part_uv->flags |= XPC_P_ENGAGED_UV;
58162306a36Sopenharmony_ci		spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV:
58562306a36Sopenharmony_ci		spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
58662306a36Sopenharmony_ci		part_uv->flags &= ~XPC_P_ENGAGED_UV;
58762306a36Sopenharmony_ci		spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
58862306a36Sopenharmony_ci		break;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	default:
59162306a36Sopenharmony_ci		dev_err(xpc_part, "received unknown activate_mq msg type=%d "
59262306a36Sopenharmony_ci			"from partition=%d\n", msg_hdr->type, XPC_PARTID(part));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		/* get hb checker to deactivate from the remote partition */
59562306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
59662306a36Sopenharmony_ci		if (part_uv->act_state_req == 0)
59762306a36Sopenharmony_ci			xpc_activate_IRQ_rcvd++;
59862306a36Sopenharmony_ci		part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
59962306a36Sopenharmony_ci		part_uv->reason = xpBadMsgType;
60062306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		(*wakeup_hb_checker)++;
60362306a36Sopenharmony_ci		return;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies &&
60762306a36Sopenharmony_ci	    part->remote_rp_ts_jiffies != 0) {
60862306a36Sopenharmony_ci		/*
60962306a36Sopenharmony_ci		 * ??? Does what we do here need to be sensitive to
61062306a36Sopenharmony_ci		 * ??? act_state or remote_act_state?
61162306a36Sopenharmony_ci		 */
61262306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
61362306a36Sopenharmony_ci		if (part_uv->act_state_req == 0)
61462306a36Sopenharmony_ci			xpc_activate_IRQ_rcvd++;
61562306a36Sopenharmony_ci		part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV;
61662306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		(*wakeup_hb_checker)++;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic irqreturn_t
62362306a36Sopenharmony_cixpc_handle_activate_IRQ_uv(int irq, void *dev_id)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct xpc_activate_mq_msghdr_uv *msg_hdr;
62662306a36Sopenharmony_ci	short partid;
62762306a36Sopenharmony_ci	struct xpc_partition *part;
62862306a36Sopenharmony_ci	int wakeup_hb_checker = 0;
62962306a36Sopenharmony_ci	int part_referenced;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	while (1) {
63262306a36Sopenharmony_ci		msg_hdr = gru_get_next_message(xpc_activate_mq_uv->gru_mq_desc);
63362306a36Sopenharmony_ci		if (msg_hdr == NULL)
63462306a36Sopenharmony_ci			break;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		partid = msg_hdr->partid;
63762306a36Sopenharmony_ci		if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
63862306a36Sopenharmony_ci			dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() "
63962306a36Sopenharmony_ci				"received invalid partid=0x%x in message\n",
64062306a36Sopenharmony_ci				partid);
64162306a36Sopenharmony_ci		} else {
64262306a36Sopenharmony_ci			part = &xpc_partitions[partid];
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci			part_referenced = xpc_part_ref(part);
64562306a36Sopenharmony_ci			xpc_handle_activate_mq_msg_uv(part, msg_hdr,
64662306a36Sopenharmony_ci						      part_referenced,
64762306a36Sopenharmony_ci						      &wakeup_hb_checker);
64862306a36Sopenharmony_ci			if (part_referenced)
64962306a36Sopenharmony_ci				xpc_part_deref(part);
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		gru_free_message(xpc_activate_mq_uv->gru_mq_desc, msg_hdr);
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (wakeup_hb_checker)
65662306a36Sopenharmony_ci		wake_up_interruptible(&xpc_activate_IRQ_wq);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return IRQ_HANDLED;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic enum xp_retval
66262306a36Sopenharmony_cixpc_cache_remote_gru_mq_desc_uv(struct gru_message_queue_desc *gru_mq_desc,
66362306a36Sopenharmony_ci				unsigned long gru_mq_desc_gpa)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	enum xp_retval ret;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	ret = xp_remote_memcpy(uv_gpa(gru_mq_desc), gru_mq_desc_gpa,
66862306a36Sopenharmony_ci			       sizeof(struct gru_message_queue_desc));
66962306a36Sopenharmony_ci	if (ret == xpSuccess)
67062306a36Sopenharmony_ci		gru_mq_desc->mq = NULL;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return ret;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic enum xp_retval
67662306a36Sopenharmony_cixpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size,
67762306a36Sopenharmony_ci			 int msg_type)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct xpc_activate_mq_msghdr_uv *msg_hdr = msg;
68062306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &part->sn.uv;
68162306a36Sopenharmony_ci	struct gru_message_queue_desc *gru_mq_desc;
68262306a36Sopenharmony_ci	unsigned long irq_flags;
68362306a36Sopenharmony_ci	enum xp_retval ret;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	msg_hdr->type = msg_type;
68862306a36Sopenharmony_ci	msg_hdr->partid = xp_partition_id;
68962306a36Sopenharmony_ci	msg_hdr->act_state = part->act_state;
69062306a36Sopenharmony_ci	msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex);
69362306a36Sopenharmony_ciagain:
69462306a36Sopenharmony_ci	if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV)) {
69562306a36Sopenharmony_ci		gru_mq_desc = part_uv->cached_activate_gru_mq_desc;
69662306a36Sopenharmony_ci		if (gru_mq_desc == NULL) {
69762306a36Sopenharmony_ci			gru_mq_desc = kmalloc(sizeof(struct
69862306a36Sopenharmony_ci					      gru_message_queue_desc),
69962306a36Sopenharmony_ci					      GFP_ATOMIC);
70062306a36Sopenharmony_ci			if (gru_mq_desc == NULL) {
70162306a36Sopenharmony_ci				ret = xpNoMemory;
70262306a36Sopenharmony_ci				goto done;
70362306a36Sopenharmony_ci			}
70462306a36Sopenharmony_ci			part_uv->cached_activate_gru_mq_desc = gru_mq_desc;
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		ret = xpc_cache_remote_gru_mq_desc_uv(gru_mq_desc,
70862306a36Sopenharmony_ci						      part_uv->
70962306a36Sopenharmony_ci						      activate_gru_mq_desc_gpa);
71062306a36Sopenharmony_ci		if (ret != xpSuccess)
71162306a36Sopenharmony_ci			goto done;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
71462306a36Sopenharmony_ci		part_uv->flags |= XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
71562306a36Sopenharmony_ci		spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */
71962306a36Sopenharmony_ci	ret = xpc_send_gru_msg(part_uv->cached_activate_gru_mq_desc, msg,
72062306a36Sopenharmony_ci			       msg_size);
72162306a36Sopenharmony_ci	if (ret != xpSuccess) {
72262306a36Sopenharmony_ci		smp_rmb();	/* ensure a fresh copy of part_uv->flags */
72362306a36Sopenharmony_ci		if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV))
72462306a36Sopenharmony_ci			goto again;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_cidone:
72762306a36Sopenharmony_ci	mutex_unlock(&part_uv->cached_activate_gru_mq_desc_mutex);
72862306a36Sopenharmony_ci	return ret;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void
73262306a36Sopenharmony_cixpc_send_activate_IRQ_part_uv(struct xpc_partition *part, void *msg,
73362306a36Sopenharmony_ci			      size_t msg_size, int msg_type)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	enum xp_retval ret;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
73862306a36Sopenharmony_ci	if (unlikely(ret != xpSuccess))
73962306a36Sopenharmony_ci		XPC_DEACTIVATE_PARTITION(part, ret);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void
74362306a36Sopenharmony_cixpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags,
74462306a36Sopenharmony_ci			 void *msg, size_t msg_size, int msg_type)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct xpc_partition *part = &xpc_partitions[ch->partid];
74762306a36Sopenharmony_ci	enum xp_retval ret;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type);
75062306a36Sopenharmony_ci	if (unlikely(ret != xpSuccess)) {
75162306a36Sopenharmony_ci		if (irq_flags != NULL)
75262306a36Sopenharmony_ci			spin_unlock_irqrestore(&ch->lock, *irq_flags);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		XPC_DEACTIVATE_PARTITION(part, ret);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		if (irq_flags != NULL)
75762306a36Sopenharmony_ci			spin_lock_irqsave(&ch->lock, *irq_flags);
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic void
76262306a36Sopenharmony_cixpc_send_local_activate_IRQ_uv(struct xpc_partition *part, int act_state_req)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	unsigned long irq_flags;
76562306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &part->sn.uv;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	/*
76862306a36Sopenharmony_ci	 * !!! Make our side think that the remote partition sent an activate
76962306a36Sopenharmony_ci	 * !!! mq message our way by doing what the activate IRQ handler would
77062306a36Sopenharmony_ci	 * !!! do had one really been sent.
77162306a36Sopenharmony_ci	 */
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
77462306a36Sopenharmony_ci	if (part_uv->act_state_req == 0)
77562306a36Sopenharmony_ci		xpc_activate_IRQ_rcvd++;
77662306a36Sopenharmony_ci	part_uv->act_state_req = act_state_req;
77762306a36Sopenharmony_ci	spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	wake_up_interruptible(&xpc_activate_IRQ_wq);
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic enum xp_retval
78362306a36Sopenharmony_cixpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
78462306a36Sopenharmony_ci				  size_t *len)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	s64 status;
78762306a36Sopenharmony_ci	enum xp_retval ret;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci#if defined CONFIG_X86_64
79062306a36Sopenharmony_ci	status = uv_bios_reserved_page_pa((u64)buf, cookie, (u64 *)rp_pa,
79162306a36Sopenharmony_ci					  (u64 *)len);
79262306a36Sopenharmony_ci	if (status == BIOS_STATUS_SUCCESS)
79362306a36Sopenharmony_ci		ret = xpSuccess;
79462306a36Sopenharmony_ci	else if (status == BIOS_STATUS_MORE_PASSES)
79562306a36Sopenharmony_ci		ret = xpNeedMoreInfo;
79662306a36Sopenharmony_ci	else
79762306a36Sopenharmony_ci		ret = xpBiosError;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci#elif defined CONFIG_IA64_SGI_UV
80062306a36Sopenharmony_ci	status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len);
80162306a36Sopenharmony_ci	if (status == SALRET_OK)
80262306a36Sopenharmony_ci		ret = xpSuccess;
80362306a36Sopenharmony_ci	else if (status == SALRET_MORE_PASSES)
80462306a36Sopenharmony_ci		ret = xpNeedMoreInfo;
80562306a36Sopenharmony_ci	else
80662306a36Sopenharmony_ci		ret = xpSalError;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci#else
80962306a36Sopenharmony_ci	#error not a supported configuration
81062306a36Sopenharmony_ci#endif
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return ret;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int
81662306a36Sopenharmony_cixpc_setup_rsvd_page_uv(struct xpc_rsvd_page *rp)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	xpc_heartbeat_uv =
81962306a36Sopenharmony_ci	    &xpc_partitions[sn_partition_id].sn.uv.cached_heartbeat;
82062306a36Sopenharmony_ci	rp->sn.uv.heartbeat_gpa = uv_gpa(xpc_heartbeat_uv);
82162306a36Sopenharmony_ci	rp->sn.uv.activate_gru_mq_desc_gpa =
82262306a36Sopenharmony_ci	    uv_gpa(xpc_activate_mq_uv->gru_mq_desc);
82362306a36Sopenharmony_ci	return 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic void
82762306a36Sopenharmony_cixpc_allow_hb_uv(short partid)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic void
83262306a36Sopenharmony_cixpc_disallow_hb_uv(short partid)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic void
83762306a36Sopenharmony_cixpc_disallow_all_hbs_uv(void)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic void
84262306a36Sopenharmony_cixpc_increment_heartbeat_uv(void)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	xpc_heartbeat_uv->value++;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void
84862306a36Sopenharmony_cixpc_offline_heartbeat_uv(void)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	xpc_increment_heartbeat_uv();
85162306a36Sopenharmony_ci	xpc_heartbeat_uv->offline = 1;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic void
85562306a36Sopenharmony_cixpc_online_heartbeat_uv(void)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	xpc_increment_heartbeat_uv();
85862306a36Sopenharmony_ci	xpc_heartbeat_uv->offline = 0;
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic void
86262306a36Sopenharmony_cixpc_heartbeat_init_uv(void)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	xpc_heartbeat_uv->value = 1;
86562306a36Sopenharmony_ci	xpc_heartbeat_uv->offline = 0;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic void
86962306a36Sopenharmony_cixpc_heartbeat_exit_uv(void)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	xpc_offline_heartbeat_uv();
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic enum xp_retval
87562306a36Sopenharmony_cixpc_get_remote_heartbeat_uv(struct xpc_partition *part)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &part->sn.uv;
87862306a36Sopenharmony_ci	enum xp_retval ret;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	ret = xp_remote_memcpy(uv_gpa(&part_uv->cached_heartbeat),
88162306a36Sopenharmony_ci			       part_uv->heartbeat_gpa,
88262306a36Sopenharmony_ci			       sizeof(struct xpc_heartbeat_uv));
88362306a36Sopenharmony_ci	if (ret != xpSuccess)
88462306a36Sopenharmony_ci		return ret;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (part_uv->cached_heartbeat.value == part->last_heartbeat &&
88762306a36Sopenharmony_ci	    !part_uv->cached_heartbeat.offline) {
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		ret = xpNoHeartbeat;
89062306a36Sopenharmony_ci	} else {
89162306a36Sopenharmony_ci		part->last_heartbeat = part_uv->cached_heartbeat.value;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	return ret;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic void
89762306a36Sopenharmony_cixpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp,
89862306a36Sopenharmony_ci				    unsigned long remote_rp_gpa, int nasid)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	short partid = remote_rp->SAL_partid;
90162306a36Sopenharmony_ci	struct xpc_partition *part = &xpc_partitions[partid];
90262306a36Sopenharmony_ci	struct xpc_activate_mq_msg_activate_req_uv msg;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */
90562306a36Sopenharmony_ci	part->remote_rp_ts_jiffies = remote_rp->ts_jiffies;
90662306a36Sopenharmony_ci	part->sn.uv.heartbeat_gpa = remote_rp->sn.uv.heartbeat_gpa;
90762306a36Sopenharmony_ci	part->sn.uv.activate_gru_mq_desc_gpa =
90862306a36Sopenharmony_ci	    remote_rp->sn.uv.activate_gru_mq_desc_gpa;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/*
91162306a36Sopenharmony_ci	 * ??? Is it a good idea to make this conditional on what is
91262306a36Sopenharmony_ci	 * ??? potentially stale state information?
91362306a36Sopenharmony_ci	 */
91462306a36Sopenharmony_ci	if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) {
91562306a36Sopenharmony_ci		msg.rp_gpa = uv_gpa(xpc_rsvd_page);
91662306a36Sopenharmony_ci		msg.heartbeat_gpa = xpc_rsvd_page->sn.uv.heartbeat_gpa;
91762306a36Sopenharmony_ci		msg.activate_gru_mq_desc_gpa =
91862306a36Sopenharmony_ci		    xpc_rsvd_page->sn.uv.activate_gru_mq_desc_gpa;
91962306a36Sopenharmony_ci		xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
92062306a36Sopenharmony_ci					   XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV);
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (part->act_state == XPC_P_AS_INACTIVE)
92462306a36Sopenharmony_ci		xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV);
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic void
92862306a36Sopenharmony_cixpc_request_partition_reactivation_uv(struct xpc_partition *part)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV);
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic void
93462306a36Sopenharmony_cixpc_request_partition_deactivation_uv(struct xpc_partition *part)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct xpc_activate_mq_msg_deactivate_req_uv msg;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/*
93962306a36Sopenharmony_ci	 * ??? Is it a good idea to make this conditional on what is
94062306a36Sopenharmony_ci	 * ??? potentially stale state information?
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	if (part->sn.uv.remote_act_state != XPC_P_AS_DEACTIVATING &&
94362306a36Sopenharmony_ci	    part->sn.uv.remote_act_state != XPC_P_AS_INACTIVE) {
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		msg.reason = part->reason;
94662306a36Sopenharmony_ci		xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
94762306a36Sopenharmony_ci					 XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV);
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic void
95262306a36Sopenharmony_cixpc_cancel_partition_deactivation_request_uv(struct xpc_partition *part)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	/* nothing needs to be done */
95562306a36Sopenharmony_ci	return;
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic void
95962306a36Sopenharmony_cixpc_init_fifo_uv(struct xpc_fifo_head_uv *head)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	head->first = NULL;
96262306a36Sopenharmony_ci	head->last = NULL;
96362306a36Sopenharmony_ci	spin_lock_init(&head->lock);
96462306a36Sopenharmony_ci	head->n_entries = 0;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cistatic void *
96862306a36Sopenharmony_cixpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	unsigned long irq_flags;
97162306a36Sopenharmony_ci	struct xpc_fifo_entry_uv *first;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	spin_lock_irqsave(&head->lock, irq_flags);
97462306a36Sopenharmony_ci	first = head->first;
97562306a36Sopenharmony_ci	if (head->first != NULL) {
97662306a36Sopenharmony_ci		head->first = first->next;
97762306a36Sopenharmony_ci		if (head->first == NULL)
97862306a36Sopenharmony_ci			head->last = NULL;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		head->n_entries--;
98162306a36Sopenharmony_ci		BUG_ON(head->n_entries < 0);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		first->next = NULL;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci	spin_unlock_irqrestore(&head->lock, irq_flags);
98662306a36Sopenharmony_ci	return first;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic void
99062306a36Sopenharmony_cixpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head,
99162306a36Sopenharmony_ci		      struct xpc_fifo_entry_uv *last)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	unsigned long irq_flags;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	last->next = NULL;
99662306a36Sopenharmony_ci	spin_lock_irqsave(&head->lock, irq_flags);
99762306a36Sopenharmony_ci	if (head->last != NULL)
99862306a36Sopenharmony_ci		head->last->next = last;
99962306a36Sopenharmony_ci	else
100062306a36Sopenharmony_ci		head->first = last;
100162306a36Sopenharmony_ci	head->last = last;
100262306a36Sopenharmony_ci	head->n_entries++;
100362306a36Sopenharmony_ci	spin_unlock_irqrestore(&head->lock, irq_flags);
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic int
100762306a36Sopenharmony_cixpc_n_of_fifo_entries_uv(struct xpc_fifo_head_uv *head)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	return head->n_entries;
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/*
101362306a36Sopenharmony_ci * Setup the channel structures that are uv specific.
101462306a36Sopenharmony_ci */
101562306a36Sopenharmony_cistatic enum xp_retval
101662306a36Sopenharmony_cixpc_setup_ch_structures_uv(struct xpc_partition *part)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv;
101962306a36Sopenharmony_ci	int ch_number;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
102262306a36Sopenharmony_ci		ch_uv = &part->channels[ch_number].sn.uv;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
102562306a36Sopenharmony_ci		xpc_init_fifo_uv(&ch_uv->recv_msg_list);
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return xpSuccess;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/*
103262306a36Sopenharmony_ci * Teardown the channel structures that are uv specific.
103362306a36Sopenharmony_ci */
103462306a36Sopenharmony_cistatic void
103562306a36Sopenharmony_cixpc_teardown_ch_structures_uv(struct xpc_partition *part)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	/* nothing needs to be done */
103862306a36Sopenharmony_ci	return;
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic enum xp_retval
104262306a36Sopenharmony_cixpc_make_first_contact_uv(struct xpc_partition *part)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	struct xpc_activate_mq_msg_uv msg;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/*
104762306a36Sopenharmony_ci	 * We send a sync msg to get the remote partition's remote_act_state
104862306a36Sopenharmony_ci	 * updated to our current act_state which at this point should
104962306a36Sopenharmony_ci	 * be XPC_P_AS_ACTIVATING.
105062306a36Sopenharmony_ci	 */
105162306a36Sopenharmony_ci	xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
105262306a36Sopenharmony_ci				      XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	while (!((part->sn.uv.remote_act_state == XPC_P_AS_ACTIVATING) ||
105562306a36Sopenharmony_ci		 (part->sn.uv.remote_act_state == XPC_P_AS_ACTIVE))) {
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		dev_dbg(xpc_part, "waiting to make first contact with "
105862306a36Sopenharmony_ci			"partition %d\n", XPC_PARTID(part));
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		/* wait a 1/4 of a second or so */
106162306a36Sopenharmony_ci		(void)msleep_interruptible(250);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		if (part->act_state == XPC_P_AS_DEACTIVATING)
106462306a36Sopenharmony_ci			return part->reason;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return xpSuccess;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic u64
107162306a36Sopenharmony_cixpc_get_chctl_all_flags_uv(struct xpc_partition *part)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	unsigned long irq_flags;
107462306a36Sopenharmony_ci	union xpc_channel_ctl_flags chctl;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	spin_lock_irqsave(&part->chctl_lock, irq_flags);
107762306a36Sopenharmony_ci	chctl = part->chctl;
107862306a36Sopenharmony_ci	if (chctl.all_flags != 0)
107962306a36Sopenharmony_ci		part->chctl.all_flags = 0;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
108262306a36Sopenharmony_ci	return chctl.all_flags;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic enum xp_retval
108662306a36Sopenharmony_cixpc_allocate_send_msg_slot_uv(struct xpc_channel *ch)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv = &ch->sn.uv;
108962306a36Sopenharmony_ci	struct xpc_send_msg_slot_uv *msg_slot;
109062306a36Sopenharmony_ci	unsigned long irq_flags;
109162306a36Sopenharmony_ci	int nentries;
109262306a36Sopenharmony_ci	int entry;
109362306a36Sopenharmony_ci	size_t nbytes;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	for (nentries = ch->local_nentries; nentries > 0; nentries--) {
109662306a36Sopenharmony_ci		nbytes = nentries * sizeof(struct xpc_send_msg_slot_uv);
109762306a36Sopenharmony_ci		ch_uv->send_msg_slots = kzalloc(nbytes, GFP_KERNEL);
109862306a36Sopenharmony_ci		if (ch_uv->send_msg_slots == NULL)
109962306a36Sopenharmony_ci			continue;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		for (entry = 0; entry < nentries; entry++) {
110262306a36Sopenharmony_ci			msg_slot = &ch_uv->send_msg_slots[entry];
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci			msg_slot->msg_slot_number = entry;
110562306a36Sopenharmony_ci			xpc_put_fifo_entry_uv(&ch_uv->msg_slot_free_list,
110662306a36Sopenharmony_ci					      &msg_slot->next);
110762306a36Sopenharmony_ci		}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		spin_lock_irqsave(&ch->lock, irq_flags);
111062306a36Sopenharmony_ci		if (nentries < ch->local_nentries)
111162306a36Sopenharmony_ci			ch->local_nentries = nentries;
111262306a36Sopenharmony_ci		spin_unlock_irqrestore(&ch->lock, irq_flags);
111362306a36Sopenharmony_ci		return xpSuccess;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return xpNoMemory;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic enum xp_retval
112062306a36Sopenharmony_cixpc_allocate_recv_msg_slot_uv(struct xpc_channel *ch)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv = &ch->sn.uv;
112362306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg_slot;
112462306a36Sopenharmony_ci	unsigned long irq_flags;
112562306a36Sopenharmony_ci	int nentries;
112662306a36Sopenharmony_ci	int entry;
112762306a36Sopenharmony_ci	size_t nbytes;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	for (nentries = ch->remote_nentries; nentries > 0; nentries--) {
113062306a36Sopenharmony_ci		nbytes = nentries * ch->entry_size;
113162306a36Sopenharmony_ci		ch_uv->recv_msg_slots = kzalloc(nbytes, GFP_KERNEL);
113262306a36Sopenharmony_ci		if (ch_uv->recv_msg_slots == NULL)
113362306a36Sopenharmony_ci			continue;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		for (entry = 0; entry < nentries; entry++) {
113662306a36Sopenharmony_ci			msg_slot = ch_uv->recv_msg_slots +
113762306a36Sopenharmony_ci			    entry * ch->entry_size;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci			msg_slot->hdr.msg_slot_number = entry;
114062306a36Sopenharmony_ci		}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		spin_lock_irqsave(&ch->lock, irq_flags);
114362306a36Sopenharmony_ci		if (nentries < ch->remote_nentries)
114462306a36Sopenharmony_ci			ch->remote_nentries = nentries;
114562306a36Sopenharmony_ci		spin_unlock_irqrestore(&ch->lock, irq_flags);
114662306a36Sopenharmony_ci		return xpSuccess;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return xpNoMemory;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci/*
115362306a36Sopenharmony_ci * Allocate msg_slots associated with the channel.
115462306a36Sopenharmony_ci */
115562306a36Sopenharmony_cistatic enum xp_retval
115662306a36Sopenharmony_cixpc_setup_msg_structures_uv(struct xpc_channel *ch)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	static enum xp_retval ret;
115962306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv = &ch->sn.uv;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	DBUG_ON(ch->flags & XPC_C_SETUP);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	ch_uv->cached_notify_gru_mq_desc = kmalloc(sizeof(struct
116462306a36Sopenharmony_ci						   gru_message_queue_desc),
116562306a36Sopenharmony_ci						   GFP_KERNEL);
116662306a36Sopenharmony_ci	if (ch_uv->cached_notify_gru_mq_desc == NULL)
116762306a36Sopenharmony_ci		return xpNoMemory;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	ret = xpc_allocate_send_msg_slot_uv(ch);
117062306a36Sopenharmony_ci	if (ret == xpSuccess) {
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		ret = xpc_allocate_recv_msg_slot_uv(ch);
117362306a36Sopenharmony_ci		if (ret != xpSuccess) {
117462306a36Sopenharmony_ci			kfree(ch_uv->send_msg_slots);
117562306a36Sopenharmony_ci			xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
117662306a36Sopenharmony_ci		}
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci	return ret;
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci/*
118262306a36Sopenharmony_ci * Free up msg_slots and clear other stuff that were setup for the specified
118362306a36Sopenharmony_ci * channel.
118462306a36Sopenharmony_ci */
118562306a36Sopenharmony_cistatic void
118662306a36Sopenharmony_cixpc_teardown_msg_structures_uv(struct xpc_channel *ch)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv = &ch->sn.uv;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	lockdep_assert_held(&ch->lock);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	kfree(ch_uv->cached_notify_gru_mq_desc);
119362306a36Sopenharmony_ci	ch_uv->cached_notify_gru_mq_desc = NULL;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (ch->flags & XPC_C_SETUP) {
119662306a36Sopenharmony_ci		xpc_init_fifo_uv(&ch_uv->msg_slot_free_list);
119762306a36Sopenharmony_ci		kfree(ch_uv->send_msg_slots);
119862306a36Sopenharmony_ci		xpc_init_fifo_uv(&ch_uv->recv_msg_list);
119962306a36Sopenharmony_ci		kfree(ch_uv->recv_msg_slots);
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic void
120462306a36Sopenharmony_cixpc_send_chctl_closerequest_uv(struct xpc_channel *ch, unsigned long *irq_flags)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	struct xpc_activate_mq_msg_chctl_closerequest_uv msg;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	msg.ch_number = ch->number;
120962306a36Sopenharmony_ci	msg.reason = ch->reason;
121062306a36Sopenharmony_ci	xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
121162306a36Sopenharmony_ci				    XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV);
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic void
121562306a36Sopenharmony_cixpc_send_chctl_closereply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct xpc_activate_mq_msg_chctl_closereply_uv msg;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	msg.ch_number = ch->number;
122062306a36Sopenharmony_ci	xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
122162306a36Sopenharmony_ci				    XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV);
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cistatic void
122562306a36Sopenharmony_cixpc_send_chctl_openrequest_uv(struct xpc_channel *ch, unsigned long *irq_flags)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	struct xpc_activate_mq_msg_chctl_openrequest_uv msg;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	msg.ch_number = ch->number;
123062306a36Sopenharmony_ci	msg.entry_size = ch->entry_size;
123162306a36Sopenharmony_ci	msg.local_nentries = ch->local_nentries;
123262306a36Sopenharmony_ci	xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
123362306a36Sopenharmony_ci				    XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV);
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic void
123762306a36Sopenharmony_cixpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	struct xpc_activate_mq_msg_chctl_openreply_uv msg;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	msg.ch_number = ch->number;
124262306a36Sopenharmony_ci	msg.local_nentries = ch->local_nentries;
124362306a36Sopenharmony_ci	msg.remote_nentries = ch->remote_nentries;
124462306a36Sopenharmony_ci	msg.notify_gru_mq_desc_gpa = uv_gpa(xpc_notify_mq_uv->gru_mq_desc);
124562306a36Sopenharmony_ci	xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
124662306a36Sopenharmony_ci				    XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV);
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cistatic void
125062306a36Sopenharmony_cixpc_send_chctl_opencomplete_uv(struct xpc_channel *ch, unsigned long *irq_flags)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	struct xpc_activate_mq_msg_chctl_opencomplete_uv msg;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	msg.ch_number = ch->number;
125562306a36Sopenharmony_ci	xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg),
125662306a36Sopenharmony_ci				    XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic void
126062306a36Sopenharmony_cixpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	unsigned long irq_flags;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	spin_lock_irqsave(&part->chctl_lock, irq_flags);
126562306a36Sopenharmony_ci	part->chctl.flags[ch_number] |= XPC_CHCTL_MSGREQUEST;
126662306a36Sopenharmony_ci	spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	xpc_wakeup_channel_mgr(part);
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic enum xp_retval
127262306a36Sopenharmony_cixpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch,
127362306a36Sopenharmony_ci			       unsigned long gru_mq_desc_gpa)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv = &ch->sn.uv;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	DBUG_ON(ch_uv->cached_notify_gru_mq_desc == NULL);
127862306a36Sopenharmony_ci	return xpc_cache_remote_gru_mq_desc_uv(ch_uv->cached_notify_gru_mq_desc,
127962306a36Sopenharmony_ci					       gru_mq_desc_gpa);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic void
128362306a36Sopenharmony_cixpc_indicate_partition_engaged_uv(struct xpc_partition *part)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct xpc_activate_mq_msg_uv msg;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
128862306a36Sopenharmony_ci				      XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV);
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic void
129262306a36Sopenharmony_cixpc_indicate_partition_disengaged_uv(struct xpc_partition *part)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct xpc_activate_mq_msg_uv msg;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg),
129762306a36Sopenharmony_ci				      XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV);
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic void
130162306a36Sopenharmony_cixpc_assume_partition_disengaged_uv(short partid)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &xpc_partitions[partid].sn.uv;
130462306a36Sopenharmony_ci	unsigned long irq_flags;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
130762306a36Sopenharmony_ci	part_uv->flags &= ~XPC_P_ENGAGED_UV;
130862306a36Sopenharmony_ci	spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int
131262306a36Sopenharmony_cixpc_partition_engaged_uv(short partid)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	return (xpc_partitions[partid].sn.uv.flags & XPC_P_ENGAGED_UV) != 0;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic int
131862306a36Sopenharmony_cixpc_any_partition_engaged_uv(void)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv;
132162306a36Sopenharmony_ci	short partid;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) {
132462306a36Sopenharmony_ci		part_uv = &xpc_partitions[partid].sn.uv;
132562306a36Sopenharmony_ci		if ((part_uv->flags & XPC_P_ENGAGED_UV) != 0)
132662306a36Sopenharmony_ci			return 1;
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci	return 0;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic enum xp_retval
133262306a36Sopenharmony_cixpc_allocate_msg_slot_uv(struct xpc_channel *ch, u32 flags,
133362306a36Sopenharmony_ci			 struct xpc_send_msg_slot_uv **address_of_msg_slot)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	enum xp_retval ret;
133662306a36Sopenharmony_ci	struct xpc_send_msg_slot_uv *msg_slot;
133762306a36Sopenharmony_ci	struct xpc_fifo_entry_uv *entry;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	while (1) {
134062306a36Sopenharmony_ci		entry = xpc_get_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list);
134162306a36Sopenharmony_ci		if (entry != NULL)
134262306a36Sopenharmony_ci			break;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci		if (flags & XPC_NOWAIT)
134562306a36Sopenharmony_ci			return xpNoWait;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		ret = xpc_allocate_msg_wait(ch);
134862306a36Sopenharmony_ci		if (ret != xpInterrupted && ret != xpTimeout)
134962306a36Sopenharmony_ci			return ret;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	msg_slot = container_of(entry, struct xpc_send_msg_slot_uv, next);
135362306a36Sopenharmony_ci	*address_of_msg_slot = msg_slot;
135462306a36Sopenharmony_ci	return xpSuccess;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_cistatic void
135862306a36Sopenharmony_cixpc_free_msg_slot_uv(struct xpc_channel *ch,
135962306a36Sopenharmony_ci		     struct xpc_send_msg_slot_uv *msg_slot)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	xpc_put_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list, &msg_slot->next);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/* wakeup anyone waiting for a free msg slot */
136462306a36Sopenharmony_ci	if (atomic_read(&ch->n_on_msg_allocate_wq) > 0)
136562306a36Sopenharmony_ci		wake_up(&ch->msg_allocate_wq);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic void
136962306a36Sopenharmony_cixpc_notify_sender_uv(struct xpc_channel *ch,
137062306a36Sopenharmony_ci		     struct xpc_send_msg_slot_uv *msg_slot,
137162306a36Sopenharmony_ci		     enum xp_retval reason)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	xpc_notify_func func = msg_slot->func;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (func != NULL && cmpxchg(&msg_slot->func, func, NULL) == func) {
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		atomic_dec(&ch->n_to_notify);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci		dev_dbg(xpc_chan, "msg_slot->func() called, msg_slot=0x%p "
138062306a36Sopenharmony_ci			"msg_slot_number=%d partid=%d channel=%d\n", msg_slot,
138162306a36Sopenharmony_ci			msg_slot->msg_slot_number, ch->partid, ch->number);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci		func(reason, ch->partid, ch->number, msg_slot->key);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci		dev_dbg(xpc_chan, "msg_slot->func() returned, msg_slot=0x%p "
138662306a36Sopenharmony_ci			"msg_slot_number=%d partid=%d channel=%d\n", msg_slot,
138762306a36Sopenharmony_ci			msg_slot->msg_slot_number, ch->partid, ch->number);
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic void
139262306a36Sopenharmony_cixpc_handle_notify_mq_ack_uv(struct xpc_channel *ch,
139362306a36Sopenharmony_ci			    struct xpc_notify_mq_msg_uv *msg)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct xpc_send_msg_slot_uv *msg_slot;
139662306a36Sopenharmony_ci	int entry = msg->hdr.msg_slot_number % ch->local_nentries;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	msg_slot = &ch->sn.uv.send_msg_slots[entry];
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	BUG_ON(msg_slot->msg_slot_number != msg->hdr.msg_slot_number);
140162306a36Sopenharmony_ci	msg_slot->msg_slot_number += ch->local_nentries;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (msg_slot->func != NULL)
140462306a36Sopenharmony_ci		xpc_notify_sender_uv(ch, msg_slot, xpMsgDelivered);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	xpc_free_msg_slot_uv(ch, msg_slot);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic void
141062306a36Sopenharmony_cixpc_handle_notify_mq_msg_uv(struct xpc_partition *part,
141162306a36Sopenharmony_ci			    struct xpc_notify_mq_msg_uv *msg)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	struct xpc_partition_uv *part_uv = &part->sn.uv;
141462306a36Sopenharmony_ci	struct xpc_channel *ch;
141562306a36Sopenharmony_ci	struct xpc_channel_uv *ch_uv;
141662306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg_slot;
141762306a36Sopenharmony_ci	unsigned long irq_flags;
141862306a36Sopenharmony_ci	int ch_number = msg->hdr.ch_number;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (unlikely(ch_number >= part->nchannels)) {
142162306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid "
142262306a36Sopenharmony_ci			"channel number=0x%x in message from partid=%d\n",
142362306a36Sopenharmony_ci			ch_number, XPC_PARTID(part));
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci		/* get hb checker to deactivate from the remote partition */
142662306a36Sopenharmony_ci		spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
142762306a36Sopenharmony_ci		if (part_uv->act_state_req == 0)
142862306a36Sopenharmony_ci			xpc_activate_IRQ_rcvd++;
142962306a36Sopenharmony_ci		part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV;
143062306a36Sopenharmony_ci		part_uv->reason = xpBadChannelNumber;
143162306a36Sopenharmony_ci		spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		wake_up_interruptible(&xpc_activate_IRQ_wq);
143462306a36Sopenharmony_ci		return;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	ch = &part->channels[ch_number];
143862306a36Sopenharmony_ci	xpc_msgqueue_ref(ch);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (!(ch->flags & XPC_C_CONNECTED)) {
144162306a36Sopenharmony_ci		xpc_msgqueue_deref(ch);
144262306a36Sopenharmony_ci		return;
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	/* see if we're really dealing with an ACK for a previously sent msg */
144662306a36Sopenharmony_ci	if (msg->hdr.size == 0) {
144762306a36Sopenharmony_ci		xpc_handle_notify_mq_ack_uv(ch, msg);
144862306a36Sopenharmony_ci		xpc_msgqueue_deref(ch);
144962306a36Sopenharmony_ci		return;
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* we're dealing with a normal message sent via the notify_mq */
145362306a36Sopenharmony_ci	ch_uv = &ch->sn.uv;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	msg_slot = ch_uv->recv_msg_slots +
145662306a36Sopenharmony_ci	    (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	BUG_ON(msg_slot->hdr.size != 0);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	memcpy(msg_slot, msg, msg->hdr.size);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) {
146562306a36Sopenharmony_ci		/*
146662306a36Sopenharmony_ci		 * If there is an existing idle kthread get it to deliver
146762306a36Sopenharmony_ci		 * the payload, otherwise we'll have to get the channel mgr
146862306a36Sopenharmony_ci		 * for this partition to create a kthread to do the delivery.
146962306a36Sopenharmony_ci		 */
147062306a36Sopenharmony_ci		if (atomic_read(&ch->kthreads_idle) > 0)
147162306a36Sopenharmony_ci			wake_up_nr(&ch->idle_wq, 1);
147262306a36Sopenharmony_ci		else
147362306a36Sopenharmony_ci			xpc_send_chctl_local_msgrequest_uv(part, ch->number);
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci	xpc_msgqueue_deref(ch);
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic irqreturn_t
147962306a36Sopenharmony_cixpc_handle_notify_IRQ_uv(int irq, void *dev_id)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg;
148262306a36Sopenharmony_ci	short partid;
148362306a36Sopenharmony_ci	struct xpc_partition *part;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	while ((msg = gru_get_next_message(xpc_notify_mq_uv->gru_mq_desc)) !=
148662306a36Sopenharmony_ci	       NULL) {
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci		partid = msg->hdr.partid;
148962306a36Sopenharmony_ci		if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
149062306a36Sopenharmony_ci			dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received "
149162306a36Sopenharmony_ci				"invalid partid=0x%x in message\n", partid);
149262306a36Sopenharmony_ci		} else {
149362306a36Sopenharmony_ci			part = &xpc_partitions[partid];
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci			if (xpc_part_ref(part)) {
149662306a36Sopenharmony_ci				xpc_handle_notify_mq_msg_uv(part, msg);
149762306a36Sopenharmony_ci				xpc_part_deref(part);
149862306a36Sopenharmony_ci			}
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		gru_free_message(xpc_notify_mq_uv->gru_mq_desc, msg);
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	return IRQ_HANDLED;
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic int
150862306a36Sopenharmony_cixpc_n_of_deliverable_payloads_uv(struct xpc_channel *ch)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	return xpc_n_of_fifo_entries_uv(&ch->sn.uv.recv_msg_list);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic void
151462306a36Sopenharmony_cixpc_process_msg_chctl_flags_uv(struct xpc_partition *part, int ch_number)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct xpc_channel *ch = &part->channels[ch_number];
151762306a36Sopenharmony_ci	int ndeliverable_payloads;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	xpc_msgqueue_ref(ch);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	ndeliverable_payloads = xpc_n_of_deliverable_payloads_uv(ch);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (ndeliverable_payloads > 0 &&
152462306a36Sopenharmony_ci	    (ch->flags & XPC_C_CONNECTED) &&
152562306a36Sopenharmony_ci	    (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)) {
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		xpc_activate_kthreads(ch, ndeliverable_payloads);
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	xpc_msgqueue_deref(ch);
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_cistatic enum xp_retval
153462306a36Sopenharmony_cixpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload,
153562306a36Sopenharmony_ci		    u16 payload_size, u8 notify_type, xpc_notify_func func,
153662306a36Sopenharmony_ci		    void *key)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	enum xp_retval ret = xpSuccess;
153962306a36Sopenharmony_ci	struct xpc_send_msg_slot_uv *msg_slot = NULL;
154062306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg;
154162306a36Sopenharmony_ci	u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV];
154262306a36Sopenharmony_ci	size_t msg_size;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	DBUG_ON(notify_type != XPC_N_CALL);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size;
154762306a36Sopenharmony_ci	if (msg_size > ch->entry_size)
154862306a36Sopenharmony_ci		return xpPayloadTooBig;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	xpc_msgqueue_ref(ch);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	if (ch->flags & XPC_C_DISCONNECTING) {
155362306a36Sopenharmony_ci		ret = ch->reason;
155462306a36Sopenharmony_ci		goto out_1;
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci	if (!(ch->flags & XPC_C_CONNECTED)) {
155762306a36Sopenharmony_ci		ret = xpNotConnected;
155862306a36Sopenharmony_ci		goto out_1;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot);
156262306a36Sopenharmony_ci	if (ret != xpSuccess)
156362306a36Sopenharmony_ci		goto out_1;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (func != NULL) {
156662306a36Sopenharmony_ci		atomic_inc(&ch->n_to_notify);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		msg_slot->key = key;
156962306a36Sopenharmony_ci		smp_wmb(); /* a non-NULL func must hit memory after the key */
157062306a36Sopenharmony_ci		msg_slot->func = func;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		if (ch->flags & XPC_C_DISCONNECTING) {
157362306a36Sopenharmony_ci			ret = ch->reason;
157462306a36Sopenharmony_ci			goto out_2;
157562306a36Sopenharmony_ci		}
157662306a36Sopenharmony_ci	}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer;
157962306a36Sopenharmony_ci	msg->hdr.partid = xp_partition_id;
158062306a36Sopenharmony_ci	msg->hdr.ch_number = ch->number;
158162306a36Sopenharmony_ci	msg->hdr.size = msg_size;
158262306a36Sopenharmony_ci	msg->hdr.msg_slot_number = msg_slot->msg_slot_number;
158362306a36Sopenharmony_ci	memcpy(&msg->payload, payload, payload_size);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
158662306a36Sopenharmony_ci			       msg_size);
158762306a36Sopenharmony_ci	if (ret == xpSuccess)
158862306a36Sopenharmony_ci		goto out_1;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
159162306a36Sopenharmony_ciout_2:
159262306a36Sopenharmony_ci	if (func != NULL) {
159362306a36Sopenharmony_ci		/*
159462306a36Sopenharmony_ci		 * Try to NULL the msg_slot's func field. If we fail, then
159562306a36Sopenharmony_ci		 * xpc_notify_senders_of_disconnect_uv() beat us to it, in which
159662306a36Sopenharmony_ci		 * case we need to pretend we succeeded to send the message
159762306a36Sopenharmony_ci		 * since the user will get a callout for the disconnect error
159862306a36Sopenharmony_ci		 * by xpc_notify_senders_of_disconnect_uv(), and to also get an
159962306a36Sopenharmony_ci		 * error returned here will confuse them. Additionally, since
160062306a36Sopenharmony_ci		 * in this case the channel is being disconnected we don't need
160162306a36Sopenharmony_ci		 * to put the msg_slot back on the free list.
160262306a36Sopenharmony_ci		 */
160362306a36Sopenharmony_ci		if (cmpxchg(&msg_slot->func, func, NULL) != func) {
160462306a36Sopenharmony_ci			ret = xpSuccess;
160562306a36Sopenharmony_ci			goto out_1;
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		msg_slot->key = NULL;
160962306a36Sopenharmony_ci		atomic_dec(&ch->n_to_notify);
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci	xpc_free_msg_slot_uv(ch, msg_slot);
161262306a36Sopenharmony_ciout_1:
161362306a36Sopenharmony_ci	xpc_msgqueue_deref(ch);
161462306a36Sopenharmony_ci	return ret;
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/*
161862306a36Sopenharmony_ci * Tell the callers of xpc_send_notify() that the status of their payloads
161962306a36Sopenharmony_ci * is unknown because the channel is now disconnecting.
162062306a36Sopenharmony_ci *
162162306a36Sopenharmony_ci * We don't worry about putting these msg_slots on the free list since the
162262306a36Sopenharmony_ci * msg_slots themselves are about to be kfree'd.
162362306a36Sopenharmony_ci */
162462306a36Sopenharmony_cistatic void
162562306a36Sopenharmony_cixpc_notify_senders_of_disconnect_uv(struct xpc_channel *ch)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	struct xpc_send_msg_slot_uv *msg_slot;
162862306a36Sopenharmony_ci	int entry;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING));
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	for (entry = 0; entry < ch->local_nentries; entry++) {
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		if (atomic_read(&ch->n_to_notify) == 0)
163562306a36Sopenharmony_ci			break;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci		msg_slot = &ch->sn.uv.send_msg_slots[entry];
163862306a36Sopenharmony_ci		if (msg_slot->func != NULL)
163962306a36Sopenharmony_ci			xpc_notify_sender_uv(ch, msg_slot, ch->reason);
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/*
164462306a36Sopenharmony_ci * Get the next deliverable message's payload.
164562306a36Sopenharmony_ci */
164662306a36Sopenharmony_cistatic void *
164762306a36Sopenharmony_cixpc_get_deliverable_payload_uv(struct xpc_channel *ch)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	struct xpc_fifo_entry_uv *entry;
165062306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg;
165162306a36Sopenharmony_ci	void *payload = NULL;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	if (!(ch->flags & XPC_C_DISCONNECTING)) {
165462306a36Sopenharmony_ci		entry = xpc_get_fifo_entry_uv(&ch->sn.uv.recv_msg_list);
165562306a36Sopenharmony_ci		if (entry != NULL) {
165662306a36Sopenharmony_ci			msg = container_of(entry, struct xpc_notify_mq_msg_uv,
165762306a36Sopenharmony_ci					   hdr.u.next);
165862306a36Sopenharmony_ci			payload = &msg->payload;
165962306a36Sopenharmony_ci		}
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci	return payload;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic void
166562306a36Sopenharmony_cixpc_received_payload_uv(struct xpc_channel *ch, void *payload)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct xpc_notify_mq_msg_uv *msg;
166862306a36Sopenharmony_ci	enum xp_retval ret;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	msg = container_of(payload, struct xpc_notify_mq_msg_uv, payload);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	/* return an ACK to the sender of this message */
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	msg->hdr.partid = xp_partition_id;
167562306a36Sopenharmony_ci	msg->hdr.size = 0;	/* size of zero indicates this is an ACK */
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg,
167862306a36Sopenharmony_ci			       sizeof(struct xpc_notify_mq_msghdr_uv));
167962306a36Sopenharmony_ci	if (ret != xpSuccess)
168062306a36Sopenharmony_ci		XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret);
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistatic const struct xpc_arch_operations xpc_arch_ops_uv = {
168462306a36Sopenharmony_ci	.setup_partitions = xpc_setup_partitions_uv,
168562306a36Sopenharmony_ci	.teardown_partitions = xpc_teardown_partitions_uv,
168662306a36Sopenharmony_ci	.process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv,
168762306a36Sopenharmony_ci	.get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv,
168862306a36Sopenharmony_ci	.setup_rsvd_page = xpc_setup_rsvd_page_uv,
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	.allow_hb = xpc_allow_hb_uv,
169162306a36Sopenharmony_ci	.disallow_hb = xpc_disallow_hb_uv,
169262306a36Sopenharmony_ci	.disallow_all_hbs = xpc_disallow_all_hbs_uv,
169362306a36Sopenharmony_ci	.increment_heartbeat = xpc_increment_heartbeat_uv,
169462306a36Sopenharmony_ci	.offline_heartbeat = xpc_offline_heartbeat_uv,
169562306a36Sopenharmony_ci	.online_heartbeat = xpc_online_heartbeat_uv,
169662306a36Sopenharmony_ci	.heartbeat_init = xpc_heartbeat_init_uv,
169762306a36Sopenharmony_ci	.heartbeat_exit = xpc_heartbeat_exit_uv,
169862306a36Sopenharmony_ci	.get_remote_heartbeat = xpc_get_remote_heartbeat_uv,
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	.request_partition_activation =
170162306a36Sopenharmony_ci		xpc_request_partition_activation_uv,
170262306a36Sopenharmony_ci	.request_partition_reactivation =
170362306a36Sopenharmony_ci		xpc_request_partition_reactivation_uv,
170462306a36Sopenharmony_ci	.request_partition_deactivation =
170562306a36Sopenharmony_ci		xpc_request_partition_deactivation_uv,
170662306a36Sopenharmony_ci	.cancel_partition_deactivation_request =
170762306a36Sopenharmony_ci		xpc_cancel_partition_deactivation_request_uv,
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	.setup_ch_structures = xpc_setup_ch_structures_uv,
171062306a36Sopenharmony_ci	.teardown_ch_structures = xpc_teardown_ch_structures_uv,
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	.make_first_contact = xpc_make_first_contact_uv,
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	.get_chctl_all_flags = xpc_get_chctl_all_flags_uv,
171562306a36Sopenharmony_ci	.send_chctl_closerequest = xpc_send_chctl_closerequest_uv,
171662306a36Sopenharmony_ci	.send_chctl_closereply = xpc_send_chctl_closereply_uv,
171762306a36Sopenharmony_ci	.send_chctl_openrequest = xpc_send_chctl_openrequest_uv,
171862306a36Sopenharmony_ci	.send_chctl_openreply = xpc_send_chctl_openreply_uv,
171962306a36Sopenharmony_ci	.send_chctl_opencomplete = xpc_send_chctl_opencomplete_uv,
172062306a36Sopenharmony_ci	.process_msg_chctl_flags = xpc_process_msg_chctl_flags_uv,
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	.save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_uv,
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	.setup_msg_structures = xpc_setup_msg_structures_uv,
172562306a36Sopenharmony_ci	.teardown_msg_structures = xpc_teardown_msg_structures_uv,
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	.indicate_partition_engaged = xpc_indicate_partition_engaged_uv,
172862306a36Sopenharmony_ci	.indicate_partition_disengaged = xpc_indicate_partition_disengaged_uv,
172962306a36Sopenharmony_ci	.assume_partition_disengaged = xpc_assume_partition_disengaged_uv,
173062306a36Sopenharmony_ci	.partition_engaged = xpc_partition_engaged_uv,
173162306a36Sopenharmony_ci	.any_partition_engaged = xpc_any_partition_engaged_uv,
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	.n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_uv,
173462306a36Sopenharmony_ci	.send_payload = xpc_send_payload_uv,
173562306a36Sopenharmony_ci	.get_deliverable_payload = xpc_get_deliverable_payload_uv,
173662306a36Sopenharmony_ci	.received_payload = xpc_received_payload_uv,
173762306a36Sopenharmony_ci	.notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv,
173862306a36Sopenharmony_ci};
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic int
174162306a36Sopenharmony_cixpc_init_mq_node(int nid)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	int cpu;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	cpus_read_lock();
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	for_each_cpu(cpu, cpumask_of_node(nid)) {
174862306a36Sopenharmony_ci		xpc_activate_mq_uv =
174962306a36Sopenharmony_ci			xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, nid,
175062306a36Sopenharmony_ci					     XPC_ACTIVATE_IRQ_NAME,
175162306a36Sopenharmony_ci					     xpc_handle_activate_IRQ_uv);
175262306a36Sopenharmony_ci		if (!IS_ERR(xpc_activate_mq_uv))
175362306a36Sopenharmony_ci			break;
175462306a36Sopenharmony_ci	}
175562306a36Sopenharmony_ci	if (IS_ERR(xpc_activate_mq_uv)) {
175662306a36Sopenharmony_ci		cpus_read_unlock();
175762306a36Sopenharmony_ci		return PTR_ERR(xpc_activate_mq_uv);
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	for_each_cpu(cpu, cpumask_of_node(nid)) {
176162306a36Sopenharmony_ci		xpc_notify_mq_uv =
176262306a36Sopenharmony_ci			xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, nid,
176362306a36Sopenharmony_ci					     XPC_NOTIFY_IRQ_NAME,
176462306a36Sopenharmony_ci					     xpc_handle_notify_IRQ_uv);
176562306a36Sopenharmony_ci		if (!IS_ERR(xpc_notify_mq_uv))
176662306a36Sopenharmony_ci			break;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci	if (IS_ERR(xpc_notify_mq_uv)) {
176962306a36Sopenharmony_ci		xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
177062306a36Sopenharmony_ci		cpus_read_unlock();
177162306a36Sopenharmony_ci		return PTR_ERR(xpc_notify_mq_uv);
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	cpus_read_unlock();
177562306a36Sopenharmony_ci	return 0;
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ciint
177962306a36Sopenharmony_cixpc_init_uv(void)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	int nid;
178262306a36Sopenharmony_ci	int ret = 0;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	xpc_arch_ops = xpc_arch_ops_uv;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) {
178762306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_notify_mq_msghdr_uv is larger than %d\n",
178862306a36Sopenharmony_ci			XPC_MSG_HDR_MAX_SIZE);
178962306a36Sopenharmony_ci		return -E2BIG;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (xpc_mq_node < 0)
179362306a36Sopenharmony_ci		for_each_online_node(nid) {
179462306a36Sopenharmony_ci			ret = xpc_init_mq_node(nid);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci			if (!ret)
179762306a36Sopenharmony_ci				break;
179862306a36Sopenharmony_ci		}
179962306a36Sopenharmony_ci	else
180062306a36Sopenharmony_ci		ret = xpc_init_mq_node(xpc_mq_node);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	if (ret < 0)
180362306a36Sopenharmony_ci		dev_err(xpc_part, "xpc_init_mq_node() returned error=%d\n",
180462306a36Sopenharmony_ci			-ret);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	return ret;
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_civoid
181062306a36Sopenharmony_cixpc_exit_uv(void)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	xpc_destroy_gru_mq_uv(xpc_notify_mq_uv);
181362306a36Sopenharmony_ci	xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_cimodule_param(xpc_mq_node, int, 0);
181762306a36Sopenharmony_ciMODULE_PARM_DESC(xpc_mq_node, "Node number on which to allocate message queues.");
1818