1 /*
2  * Copyright (c) 2017 Cray Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include "gnix_util.h"
34 #include "gnix_smrn.h"
35 
36 static struct gnix_smrn global_smrn;
37 
_gnix_smrn_init(void)38 int _gnix_smrn_init(void)
39 {
40 	int ret;
41 
42 	fastlock_init(&global_smrn.lock);
43 	global_smrn.references = 0;
44 	dlist_init(&global_smrn.rq_head);
45 
46 	ret = _gnix_notifier_init();
47 
48 	return ret;
49 }
50 
_gnix_smrn_open(struct gnix_smrn ** smrn)51 int _gnix_smrn_open(struct gnix_smrn **smrn)
52 {
53 	struct gnix_smrn *tmp = &global_smrn;
54 	int ret = FI_SUCCESS;
55 
56 	fastlock_acquire(&tmp->lock);
57 	if (tmp->references == 0)
58 		ret = _gnix_notifier_open(&tmp->notifier);
59 
60 	if (!ret)
61 		tmp->references += 1;
62 	fastlock_release(&tmp->lock);
63 
64 	if (!ret)
65 		*smrn = tmp;
66 
67 	return ret;
68 }
69 
_gnix_smrn_close(struct gnix_smrn * smrn)70 int _gnix_smrn_close(struct gnix_smrn *smrn)
71 {
72 	int ret = FI_SUCCESS;
73 
74 	fastlock_acquire(&smrn->lock);
75 	if (smrn->references == 0)
76 		ret = -FI_EINVAL;
77 
78 	if (smrn->references == 1)
79 		ret = _gnix_notifier_close(smrn->notifier);
80 
81 	if (!ret)
82 		smrn->references -= 1;
83 	fastlock_release(&smrn->lock);
84 
85 	return ret;
86 }
87 
_gnix_smrn_monitor(struct gnix_smrn * smrn,struct gnix_smrn_rq * rq,void * addr,uint64_t len,uint64_t cookie,struct gnix_smrn_context * context)88 int _gnix_smrn_monitor(struct gnix_smrn *smrn,
89 	struct gnix_smrn_rq *rq,
90 	void *addr,
91 	uint64_t len,
92 	uint64_t cookie,
93 	struct gnix_smrn_context *context)
94 {
95 	int ret;
96 
97 	if (!context || !rq || !smrn)
98 		return -FI_EINVAL;
99 
100 	context->rq = rq;
101 	context->cookie = cookie;
102 
103 	ret = _gnix_notifier_monitor(smrn->notifier, addr,
104 				len, (uint64_t) context);
105 	if (ret == FI_SUCCESS)
106 		GNIX_DEBUG(FI_LOG_FABRIC,
107 				"monitoring addr=%p len=%d cookie=%p "
108 				"context=%p rq=%p notifier=%p\n",
109 				addr, len, context->cookie,
110 				context, rq, smrn->notifier);
111 	return ret;
112 }
113 
_gnix_smrn_unmonitor(struct gnix_smrn * smrn,uint64_t cookie,struct gnix_smrn_context * context)114 int _gnix_smrn_unmonitor(struct gnix_smrn *smrn,
115 	uint64_t cookie,
116 	struct gnix_smrn_context *context)
117 {
118 	if (!smrn)
119 		return -FI_EINVAL;
120 
121 	if (cookie != context->cookie)
122 		return -FI_EINVAL;
123 
124 	return _gnix_notifier_unmonitor(smrn->notifier, (uint64_t) context);
125 }
126 
__gnix_smrn_read_events(struct gnix_smrn * smrn)127 static void __gnix_smrn_read_events(struct gnix_smrn *smrn)
128 {
129 	int ret;
130 	struct gnix_smrn_context *context;
131 	struct gnix_smrn_rq *rq;
132 	int len = sizeof(uint64_t);
133 
134 	do {
135 		ret = _gnix_notifier_get_event(smrn->notifier,
136 			(void *) &context, len);
137 		if (ret != len) {
138 			GNIX_DEBUG(FI_LOG_FABRIC,
139 				"no more events to be read\n");
140 			break;
141 		}
142 
143 		GNIX_DEBUG(FI_LOG_FABRIC,
144 			"found event, context=%p rq=%p cookie=%lx\n",
145 			context, context->rq, context->cookie);
146 
147 		rq = context->rq;
148 		fastlock_acquire(&rq->lock);
149 		dlist_insert_tail(&context->entry, &rq->list);
150 		fastlock_release(&rq->lock);
151 	} while (ret == len);
152 }
153 
_gnix_smrn_get_event(struct gnix_smrn * smrn,struct gnix_smrn_rq * rq,struct gnix_smrn_context ** context)154 int _gnix_smrn_get_event(struct gnix_smrn *smrn,
155 	struct gnix_smrn_rq *rq,
156 	struct gnix_smrn_context **context)
157 {
158 	int ret;
159 
160 	if (!smrn || !context)
161 		return -FI_EINVAL;
162 
163 	__gnix_smrn_read_events(smrn);
164 
165 	fastlock_acquire(&rq->lock);
166 	if (!dlist_empty(&rq->list)) {
167 		dlist_pop_front(&rq->list, struct gnix_smrn_context,
168 			*context, entry);
169 		ret = FI_SUCCESS;
170 	} else
171 		ret = -FI_EAGAIN;
172 	fastlock_release(&rq->lock);
173 
174 	return ret;
175 }
176 
177