14dea2d1aSSukadev Bhattiprolu /*
24dea2d1aSSukadev Bhattiprolu  * Copyright 2016-17 IBM Corp.
34dea2d1aSSukadev Bhattiprolu  *
44dea2d1aSSukadev Bhattiprolu  * This program is free software; you can redistribute it and/or
54dea2d1aSSukadev Bhattiprolu  * modify it under the terms of the GNU General Public License
64dea2d1aSSukadev Bhattiprolu  * as published by the Free Software Foundation; either version
74dea2d1aSSukadev Bhattiprolu  * 2 of the License, or (at your option) any later version.
84dea2d1aSSukadev Bhattiprolu  */
94dea2d1aSSukadev Bhattiprolu 
10180fe15aSSukadev Bhattiprolu #define pr_fmt(fmt) "vas: " fmt
11180fe15aSSukadev Bhattiprolu 
124dea2d1aSSukadev Bhattiprolu #include <linux/types.h>
134dea2d1aSSukadev Bhattiprolu #include <linux/mutex.h>
14180fe15aSSukadev Bhattiprolu #include <linux/slab.h>
15180fe15aSSukadev Bhattiprolu #include <linux/io.h>
164dea2d1aSSukadev Bhattiprolu 
174dea2d1aSSukadev Bhattiprolu #include "vas.h"
184dea2d1aSSukadev Bhattiprolu 
19180fe15aSSukadev Bhattiprolu /*
20180fe15aSSukadev Bhattiprolu  * Compute the paste address region for the window @window using the
21180fe15aSSukadev Bhattiprolu  * ->paste_base_addr and ->paste_win_id_shift we got from device tree.
22180fe15aSSukadev Bhattiprolu  */
23180fe15aSSukadev Bhattiprolu static void compute_paste_address(struct vas_window *window, u64 *addr, int *len)
24180fe15aSSukadev Bhattiprolu {
25180fe15aSSukadev Bhattiprolu 	int winid;
26180fe15aSSukadev Bhattiprolu 	u64 base, shift;
27180fe15aSSukadev Bhattiprolu 
28180fe15aSSukadev Bhattiprolu 	base = window->vinst->paste_base_addr;
29180fe15aSSukadev Bhattiprolu 	shift = window->vinst->paste_win_id_shift;
30180fe15aSSukadev Bhattiprolu 	winid = window->winid;
31180fe15aSSukadev Bhattiprolu 
32180fe15aSSukadev Bhattiprolu 	*addr  = base + (winid << shift);
33180fe15aSSukadev Bhattiprolu 	if (len)
34180fe15aSSukadev Bhattiprolu 		*len = PAGE_SIZE;
35180fe15aSSukadev Bhattiprolu 
36180fe15aSSukadev Bhattiprolu 	pr_debug("Txwin #%d: Paste addr 0x%llx\n", winid, *addr);
37180fe15aSSukadev Bhattiprolu }
38180fe15aSSukadev Bhattiprolu 
39180fe15aSSukadev Bhattiprolu static inline void get_hvwc_mmio_bar(struct vas_window *window,
40180fe15aSSukadev Bhattiprolu 			u64 *start, int *len)
41180fe15aSSukadev Bhattiprolu {
42180fe15aSSukadev Bhattiprolu 	u64 pbaddr;
43180fe15aSSukadev Bhattiprolu 
44180fe15aSSukadev Bhattiprolu 	pbaddr = window->vinst->hvwc_bar_start;
45180fe15aSSukadev Bhattiprolu 	*start = pbaddr + window->winid * VAS_HVWC_SIZE;
46180fe15aSSukadev Bhattiprolu 	*len = VAS_HVWC_SIZE;
47180fe15aSSukadev Bhattiprolu }
48180fe15aSSukadev Bhattiprolu 
49180fe15aSSukadev Bhattiprolu static inline void get_uwc_mmio_bar(struct vas_window *window,
50180fe15aSSukadev Bhattiprolu 			u64 *start, int *len)
51180fe15aSSukadev Bhattiprolu {
52180fe15aSSukadev Bhattiprolu 	u64 pbaddr;
53180fe15aSSukadev Bhattiprolu 
54180fe15aSSukadev Bhattiprolu 	pbaddr = window->vinst->uwc_bar_start;
55180fe15aSSukadev Bhattiprolu 	*start = pbaddr + window->winid * VAS_UWC_SIZE;
56180fe15aSSukadev Bhattiprolu 	*len = VAS_UWC_SIZE;
57180fe15aSSukadev Bhattiprolu }
58180fe15aSSukadev Bhattiprolu 
59180fe15aSSukadev Bhattiprolu /*
60180fe15aSSukadev Bhattiprolu  * Map the paste bus address of the given send window into kernel address
61180fe15aSSukadev Bhattiprolu  * space. Unlike MMIO regions (map_mmio_region() below), paste region must
62180fe15aSSukadev Bhattiprolu  * be mapped cache-able and is only applicable to send windows.
63180fe15aSSukadev Bhattiprolu  */
64180fe15aSSukadev Bhattiprolu void *map_paste_region(struct vas_window *txwin)
65180fe15aSSukadev Bhattiprolu {
66180fe15aSSukadev Bhattiprolu 	int len;
67180fe15aSSukadev Bhattiprolu 	void *map;
68180fe15aSSukadev Bhattiprolu 	char *name;
69180fe15aSSukadev Bhattiprolu 	u64 start;
70180fe15aSSukadev Bhattiprolu 
71180fe15aSSukadev Bhattiprolu 	name = kasprintf(GFP_KERNEL, "window-v%d-w%d", txwin->vinst->vas_id,
72180fe15aSSukadev Bhattiprolu 				txwin->winid);
73180fe15aSSukadev Bhattiprolu 	if (!name)
74180fe15aSSukadev Bhattiprolu 		goto free_name;
75180fe15aSSukadev Bhattiprolu 
76180fe15aSSukadev Bhattiprolu 	txwin->paste_addr_name = name;
77180fe15aSSukadev Bhattiprolu 	compute_paste_address(txwin, &start, &len);
78180fe15aSSukadev Bhattiprolu 
79180fe15aSSukadev Bhattiprolu 	if (!request_mem_region(start, len, name)) {
80180fe15aSSukadev Bhattiprolu 		pr_devel("%s(): request_mem_region(0x%llx, %d) failed\n",
81180fe15aSSukadev Bhattiprolu 				__func__, start, len);
82180fe15aSSukadev Bhattiprolu 		goto free_name;
83180fe15aSSukadev Bhattiprolu 	}
84180fe15aSSukadev Bhattiprolu 
85180fe15aSSukadev Bhattiprolu 	map = ioremap_cache(start, len);
86180fe15aSSukadev Bhattiprolu 	if (!map) {
87180fe15aSSukadev Bhattiprolu 		pr_devel("%s(): ioremap_cache(0x%llx, %d) failed\n", __func__,
88180fe15aSSukadev Bhattiprolu 				start, len);
89180fe15aSSukadev Bhattiprolu 		goto free_name;
90180fe15aSSukadev Bhattiprolu 	}
91180fe15aSSukadev Bhattiprolu 
92180fe15aSSukadev Bhattiprolu 	pr_devel("Mapped paste addr 0x%llx to kaddr 0x%p\n", start, map);
93180fe15aSSukadev Bhattiprolu 	return map;
94180fe15aSSukadev Bhattiprolu 
95180fe15aSSukadev Bhattiprolu free_name:
96180fe15aSSukadev Bhattiprolu 	kfree(name);
97180fe15aSSukadev Bhattiprolu 	return ERR_PTR(-ENOMEM);
98180fe15aSSukadev Bhattiprolu }
99180fe15aSSukadev Bhattiprolu 
100180fe15aSSukadev Bhattiprolu 
101180fe15aSSukadev Bhattiprolu static void *map_mmio_region(char *name, u64 start, int len)
102180fe15aSSukadev Bhattiprolu {
103180fe15aSSukadev Bhattiprolu 	void *map;
104180fe15aSSukadev Bhattiprolu 
105180fe15aSSukadev Bhattiprolu 	if (!request_mem_region(start, len, name)) {
106180fe15aSSukadev Bhattiprolu 		pr_devel("%s(): request_mem_region(0x%llx, %d) failed\n",
107180fe15aSSukadev Bhattiprolu 				__func__, start, len);
108180fe15aSSukadev Bhattiprolu 		return NULL;
109180fe15aSSukadev Bhattiprolu 	}
110180fe15aSSukadev Bhattiprolu 
111180fe15aSSukadev Bhattiprolu 	map = ioremap(start, len);
112180fe15aSSukadev Bhattiprolu 	if (!map) {
113180fe15aSSukadev Bhattiprolu 		pr_devel("%s(): ioremap(0x%llx, %d) failed\n", __func__, start,
114180fe15aSSukadev Bhattiprolu 				len);
115180fe15aSSukadev Bhattiprolu 		return NULL;
116180fe15aSSukadev Bhattiprolu 	}
117180fe15aSSukadev Bhattiprolu 
118180fe15aSSukadev Bhattiprolu 	return map;
119180fe15aSSukadev Bhattiprolu }
120180fe15aSSukadev Bhattiprolu 
121180fe15aSSukadev Bhattiprolu static void unmap_region(void *addr, u64 start, int len)
122180fe15aSSukadev Bhattiprolu {
123180fe15aSSukadev Bhattiprolu 	iounmap(addr);
124180fe15aSSukadev Bhattiprolu 	release_mem_region((phys_addr_t)start, len);
125180fe15aSSukadev Bhattiprolu }
126180fe15aSSukadev Bhattiprolu 
127180fe15aSSukadev Bhattiprolu /*
128180fe15aSSukadev Bhattiprolu  * Unmap the paste address region for a window.
129180fe15aSSukadev Bhattiprolu  */
130180fe15aSSukadev Bhattiprolu void unmap_paste_region(struct vas_window *window)
131180fe15aSSukadev Bhattiprolu {
132180fe15aSSukadev Bhattiprolu 	int len;
133180fe15aSSukadev Bhattiprolu 	u64 busaddr_start;
134180fe15aSSukadev Bhattiprolu 
135180fe15aSSukadev Bhattiprolu 	if (window->paste_kaddr) {
136180fe15aSSukadev Bhattiprolu 		compute_paste_address(window, &busaddr_start, &len);
137180fe15aSSukadev Bhattiprolu 		unmap_region(window->paste_kaddr, busaddr_start, len);
138180fe15aSSukadev Bhattiprolu 		window->paste_kaddr = NULL;
139180fe15aSSukadev Bhattiprolu 		kfree(window->paste_addr_name);
140180fe15aSSukadev Bhattiprolu 		window->paste_addr_name = NULL;
141180fe15aSSukadev Bhattiprolu 	}
142180fe15aSSukadev Bhattiprolu }
143180fe15aSSukadev Bhattiprolu 
144180fe15aSSukadev Bhattiprolu /*
145180fe15aSSukadev Bhattiprolu  * Unmap the MMIO regions for a window.
146180fe15aSSukadev Bhattiprolu  */
147180fe15aSSukadev Bhattiprolu static void unmap_winctx_mmio_bars(struct vas_window *window)
148180fe15aSSukadev Bhattiprolu {
149180fe15aSSukadev Bhattiprolu 	int len;
150180fe15aSSukadev Bhattiprolu 	u64 busaddr_start;
151180fe15aSSukadev Bhattiprolu 
152180fe15aSSukadev Bhattiprolu 	if (window->hvwc_map) {
153180fe15aSSukadev Bhattiprolu 		get_hvwc_mmio_bar(window, &busaddr_start, &len);
154180fe15aSSukadev Bhattiprolu 		unmap_region(window->hvwc_map, busaddr_start, len);
155180fe15aSSukadev Bhattiprolu 		window->hvwc_map = NULL;
156180fe15aSSukadev Bhattiprolu 	}
157180fe15aSSukadev Bhattiprolu 
158180fe15aSSukadev Bhattiprolu 	if (window->uwc_map) {
159180fe15aSSukadev Bhattiprolu 		get_uwc_mmio_bar(window, &busaddr_start, &len);
160180fe15aSSukadev Bhattiprolu 		unmap_region(window->uwc_map, busaddr_start, len);
161180fe15aSSukadev Bhattiprolu 		window->uwc_map = NULL;
162180fe15aSSukadev Bhattiprolu 	}
163180fe15aSSukadev Bhattiprolu }
164180fe15aSSukadev Bhattiprolu 
165180fe15aSSukadev Bhattiprolu /*
166180fe15aSSukadev Bhattiprolu  * Find the Hypervisor Window Context (HVWC) MMIO Base Address Region and the
167180fe15aSSukadev Bhattiprolu  * OS/User Window Context (UWC) MMIO Base Address Region for the given window.
168180fe15aSSukadev Bhattiprolu  * Map these bus addresses and save the mapped kernel addresses in @window.
169180fe15aSSukadev Bhattiprolu  */
170180fe15aSSukadev Bhattiprolu int map_winctx_mmio_bars(struct vas_window *window)
171180fe15aSSukadev Bhattiprolu {
172180fe15aSSukadev Bhattiprolu 	int len;
173180fe15aSSukadev Bhattiprolu 	u64 start;
174180fe15aSSukadev Bhattiprolu 
175180fe15aSSukadev Bhattiprolu 	get_hvwc_mmio_bar(window, &start, &len);
176180fe15aSSukadev Bhattiprolu 	window->hvwc_map = map_mmio_region("HVWCM_Window", start, len);
177180fe15aSSukadev Bhattiprolu 
178180fe15aSSukadev Bhattiprolu 	get_uwc_mmio_bar(window, &start, &len);
179180fe15aSSukadev Bhattiprolu 	window->uwc_map = map_mmio_region("UWCM_Window", start, len);
180180fe15aSSukadev Bhattiprolu 
181180fe15aSSukadev Bhattiprolu 	if (!window->hvwc_map || !window->uwc_map) {
182180fe15aSSukadev Bhattiprolu 		unmap_winctx_mmio_bars(window);
183180fe15aSSukadev Bhattiprolu 		return -1;
184180fe15aSSukadev Bhattiprolu 	}
185180fe15aSSukadev Bhattiprolu 
186180fe15aSSukadev Bhattiprolu 	return 0;
187180fe15aSSukadev Bhattiprolu }
188180fe15aSSukadev Bhattiprolu 
1894dea2d1aSSukadev Bhattiprolu /* stub for now */
1904dea2d1aSSukadev Bhattiprolu int vas_win_close(struct vas_window *window)
1914dea2d1aSSukadev Bhattiprolu {
1924dea2d1aSSukadev Bhattiprolu 	return -1;
1934dea2d1aSSukadev Bhattiprolu }
194