treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / misc / mic / scif / scif_rma_list.c
blobef923ba134c8d47804a43c6841059a1c53451036
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Intel MIC Platform Software Stack (MPSS)
5 * Copyright(c) 2015 Intel Corporation.
7 * Intel SCIF driver.
8 */
9 #include "scif_main.h"
10 #include <linux/mmu_notifier.h>
11 #include <linux/highmem.h>
14 * scif_insert_tcw:
16 * Insert a temp window to the temp registration list sorted by va_for_temp.
17 * RMA lock must be held.
19 void scif_insert_tcw(struct scif_window *window, struct list_head *head)
21 struct scif_window *curr = NULL;
22 struct scif_window *prev = list_entry(head, struct scif_window, list);
23 struct list_head *item;
25 INIT_LIST_HEAD(&window->list);
26 /* Compare with tail and if the entry is new tail add it to the end */
27 if (!list_empty(head)) {
28 curr = list_entry(head->prev, struct scif_window, list);
29 if (curr->va_for_temp < window->va_for_temp) {
30 list_add_tail(&window->list, head);
31 return;
34 list_for_each(item, head) {
35 curr = list_entry(item, struct scif_window, list);
36 if (curr->va_for_temp > window->va_for_temp)
37 break;
38 prev = curr;
40 list_add(&window->list, &prev->list);
44 * scif_insert_window:
46 * Insert a window to the self registration list sorted by offset.
47 * RMA lock must be held.
49 void scif_insert_window(struct scif_window *window, struct list_head *head)
51 struct scif_window *curr = NULL, *prev = NULL;
52 struct list_head *item;
54 INIT_LIST_HEAD(&window->list);
55 list_for_each(item, head) {
56 curr = list_entry(item, struct scif_window, list);
57 if (curr->offset > window->offset)
58 break;
59 prev = curr;
61 if (!prev)
62 list_add(&window->list, head);
63 else
64 list_add(&window->list, &prev->list);
65 scif_set_window_ref(window, window->nr_pages);
69 * scif_query_tcw:
71 * Query the temp cached registration list of ep for an overlapping window
72 * in case of permission mismatch, destroy the previous window. if permissions
73 * match and overlap is partial, destroy the window but return the new range
74 * RMA lock must be held.
76 int scif_query_tcw(struct scif_endpt *ep, struct scif_rma_req *req)
78 struct list_head *item, *temp, *head = req->head;
79 struct scif_window *window;
80 u64 start_va_window, start_va_req = req->va_for_temp;
81 u64 end_va_window, end_va_req = start_va_req + req->nr_bytes;
83 if (!req->nr_bytes)
84 return -EINVAL;
86 * Avoid traversing the entire list to find out that there
87 * is no entry that matches
89 if (!list_empty(head)) {
90 window = list_last_entry(head, struct scif_window, list);
91 end_va_window = window->va_for_temp +
92 (window->nr_pages << PAGE_SHIFT);
93 if (start_va_req > end_va_window)
94 return -ENXIO;
96 list_for_each_safe(item, temp, head) {
97 window = list_entry(item, struct scif_window, list);
98 start_va_window = window->va_for_temp;
99 end_va_window = window->va_for_temp +
100 (window->nr_pages << PAGE_SHIFT);
101 if (start_va_req < start_va_window &&
102 end_va_req < start_va_window)
103 break;
104 if (start_va_req >= end_va_window)
105 continue;
106 if ((window->prot & req->prot) == req->prot) {
107 if (start_va_req >= start_va_window &&
108 end_va_req <= end_va_window) {
109 *req->out_window = window;
110 return 0;
112 /* expand window */
113 if (start_va_req < start_va_window) {
114 req->nr_bytes +=
115 start_va_window - start_va_req;
116 req->va_for_temp = start_va_window;
118 if (end_va_req >= end_va_window)
119 req->nr_bytes += end_va_window - end_va_req;
121 /* Destroy the old window to create a new one */
122 __scif_rma_destroy_tcw_helper(window);
123 break;
125 return -ENXIO;
129 * scif_query_window:
131 * Query the registration list and check if a valid contiguous
132 * range of windows exist.
133 * RMA lock must be held.
135 int scif_query_window(struct scif_rma_req *req)
137 struct list_head *item;
138 struct scif_window *window;
139 s64 end_offset, offset = req->offset;
140 u64 tmp_min, nr_bytes_left = req->nr_bytes;
142 if (!req->nr_bytes)
143 return -EINVAL;
145 list_for_each(item, req->head) {
146 window = list_entry(item, struct scif_window, list);
147 end_offset = window->offset +
148 (window->nr_pages << PAGE_SHIFT);
149 if (offset < window->offset)
150 /* Offset not found! */
151 return -ENXIO;
152 if (offset >= end_offset)
153 continue;
154 /* Check read/write protections. */
155 if ((window->prot & req->prot) != req->prot)
156 return -EPERM;
157 if (nr_bytes_left == req->nr_bytes)
158 /* Store the first window */
159 *req->out_window = window;
160 tmp_min = min((u64)end_offset - offset, nr_bytes_left);
161 nr_bytes_left -= tmp_min;
162 offset += tmp_min;
164 * Range requested encompasses
165 * multiple windows contiguously.
167 if (!nr_bytes_left) {
168 /* Done for partial window */
169 if (req->type == SCIF_WINDOW_PARTIAL ||
170 req->type == SCIF_WINDOW_SINGLE)
171 return 0;
172 /* Extra logic for full windows */
173 if (offset == end_offset)
174 /* Spanning multiple whole windows */
175 return 0;
176 /* Not spanning multiple whole windows */
177 return -ENXIO;
179 if (req->type == SCIF_WINDOW_SINGLE)
180 break;
182 dev_err(scif_info.mdev.this_device,
183 "%s %d ENXIO\n", __func__, __LINE__);
184 return -ENXIO;
188 * scif_rma_list_unregister:
190 * Traverse the self registration list starting from window:
191 * 1) Call scif_unregister_window(..)
192 * RMA lock must be held.
194 int scif_rma_list_unregister(struct scif_window *window,
195 s64 offset, int nr_pages)
197 struct scif_endpt *ep = (struct scif_endpt *)window->ep;
198 struct list_head *head = &ep->rma_info.reg_list;
199 s64 end_offset;
200 int err = 0;
201 int loop_nr_pages;
202 struct scif_window *_window;
204 list_for_each_entry_safe_from(window, _window, head, list) {
205 end_offset = window->offset + (window->nr_pages << PAGE_SHIFT);
206 loop_nr_pages = min((int)((end_offset - offset) >> PAGE_SHIFT),
207 nr_pages);
208 err = scif_unregister_window(window);
209 if (err)
210 return err;
211 nr_pages -= loop_nr_pages;
212 offset += (loop_nr_pages << PAGE_SHIFT);
213 if (!nr_pages)
214 break;
216 return 0;
220 * scif_unmap_all_window:
222 * Traverse all the windows in the self registration list and:
223 * 1) Delete any DMA mappings created
225 void scif_unmap_all_windows(scif_epd_t epd)
227 struct list_head *item, *tmp;
228 struct scif_window *window;
229 struct scif_endpt *ep = (struct scif_endpt *)epd;
230 struct list_head *head = &ep->rma_info.reg_list;
232 mutex_lock(&ep->rma_info.rma_lock);
233 list_for_each_safe(item, tmp, head) {
234 window = list_entry(item, struct scif_window, list);
235 scif_unmap_window(ep->remote_dev, window);
237 mutex_unlock(&ep->rma_info.rma_lock);
241 * scif_unregister_all_window:
243 * Traverse all the windows in the self registration list and:
244 * 1) Call scif_unregister_window(..)
245 * RMA lock must be held.
247 int scif_unregister_all_windows(scif_epd_t epd)
249 struct list_head *item, *tmp;
250 struct scif_window *window;
251 struct scif_endpt *ep = (struct scif_endpt *)epd;
252 struct list_head *head = &ep->rma_info.reg_list;
253 int err = 0;
255 mutex_lock(&ep->rma_info.rma_lock);
256 retry:
257 item = NULL;
258 tmp = NULL;
259 list_for_each_safe(item, tmp, head) {
260 window = list_entry(item, struct scif_window, list);
261 ep->rma_info.async_list_del = 0;
262 err = scif_unregister_window(window);
263 if (err)
264 dev_err(scif_info.mdev.this_device,
265 "%s %d err %d\n",
266 __func__, __LINE__, err);
268 * Need to restart list traversal if there has been
269 * an asynchronous list entry deletion.
271 if (READ_ONCE(ep->rma_info.async_list_del))
272 goto retry;
274 mutex_unlock(&ep->rma_info.rma_lock);
275 if (!list_empty(&ep->rma_info.mmn_list)) {
276 spin_lock(&scif_info.rmalock);
277 list_add_tail(&ep->mmu_list, &scif_info.mmu_notif_cleanup);
278 spin_unlock(&scif_info.rmalock);
279 schedule_work(&scif_info.mmu_notif_work);
281 return err;