• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 HiSilicon Limited, All Rights Reserved.
4  * Author: Gabriele Paoloni <gabriele.paoloni@huawei.com>
5  * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
6  */
7 
8 #define pr_fmt(fmt)	"LOGIC PIO: " fmt
9 
10 #include <linux/of.h>
11 #include <linux/io.h>
12 #include <linux/logic_pio.h>
13 #include <linux/mm.h>
14 #include <linux/rculist.h>
15 #include <linux/sizes.h>
16 #include <linux/slab.h>
17 
18 /* The unique hardware address list */
19 static LIST_HEAD(io_range_list);
20 static DEFINE_MUTEX(io_range_mutex);
21 
22 /* Consider a kernel general helper for this */
23 #define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + (len))
24 
25 /**
26  * logic_pio_register_range - register logical PIO range for a host
27  * @new_range: pointer to the IO range to be registered.
28  *
29  * Returns 0 on success, the error code in case of failure.
30  * If the range already exists, -EEXIST will be returned, which should be
31  * considered a success.
32  *
33  * Register a new IO range node in the IO range list.
34  */
logic_pio_register_range(struct logic_pio_hwaddr * new_range)35 int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
36 {
37 	struct logic_pio_hwaddr *range;
38 	resource_size_t start;
39 	resource_size_t end;
40 	resource_size_t mmio_end = 0;
41 	resource_size_t iio_sz = MMIO_UPPER_LIMIT;
42 	int ret = 0;
43 
44 	if (!new_range || !new_range->fwnode || !new_range->size)
45 		return -EINVAL;
46 
47 	start = new_range->hw_start;
48 	end = new_range->hw_start + new_range->size;
49 
50 	mutex_lock(&io_range_mutex);
51 	list_for_each_entry(range, &io_range_list, list) {
52 		if (range->fwnode == new_range->fwnode) {
53 			/* range already there */
54 			ret = -EEXIST;
55 			goto end_register;
56 		}
57 		if (range->flags == LOGIC_PIO_CPU_MMIO &&
58 		    new_range->flags == LOGIC_PIO_CPU_MMIO) {
59 			/* for MMIO ranges we need to check for overlap */
60 			if (start >= range->hw_start + range->size ||
61 			    end < range->hw_start) {
62 				mmio_end = range->io_start + range->size;
63 			} else {
64 				ret = -EFAULT;
65 				goto end_register;
66 			}
67 		} else if (range->flags == LOGIC_PIO_INDIRECT &&
68 			   new_range->flags == LOGIC_PIO_INDIRECT) {
69 			iio_sz += range->size;
70 		}
71 	}
72 
73 	/* range not registered yet, check for available space */
74 	if (new_range->flags == LOGIC_PIO_CPU_MMIO) {
75 		if (mmio_end + new_range->size - 1 > MMIO_UPPER_LIMIT) {
76 			/* if it's too big check if 64K space can be reserved */
77 			if (mmio_end + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
78 				ret = -E2BIG;
79 				goto end_register;
80 			}
81 			new_range->size = SZ_64K;
82 			pr_warn("Requested IO range too big, new size set to 64K\n");
83 		}
84 		new_range->io_start = mmio_end;
85 	} else if (new_range->flags == LOGIC_PIO_INDIRECT) {
86 		if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) {
87 			ret = -E2BIG;
88 			goto end_register;
89 		}
90 		new_range->io_start = iio_sz;
91 	} else {
92 		/* invalid flag */
93 		ret = -EINVAL;
94 		goto end_register;
95 	}
96 
97 	list_add_tail_rcu(&new_range->list, &io_range_list);
98 
99 end_register:
100 	mutex_unlock(&io_range_mutex);
101 	return ret;
102 }
103 
104 /**
105  * logic_pio_unregister_range - unregister a logical PIO range for a host
106  * @range: pointer to the IO range which has been already registered.
107  *
108  * Unregister a previously-registered IO range node.
109  */
logic_pio_unregister_range(struct logic_pio_hwaddr * range)110 void logic_pio_unregister_range(struct logic_pio_hwaddr *range)
111 {
112 	mutex_lock(&io_range_mutex);
113 	list_del_rcu(&range->list);
114 	mutex_unlock(&io_range_mutex);
115 	synchronize_rcu();
116 }
117 
118 /**
119  * find_io_range_by_fwnode - find logical PIO range for given FW node
120  * @fwnode: FW node handle associated with logical PIO range
121  *
122  * Returns pointer to node on success, NULL otherwise.
123  *
124  * Traverse the io_range_list to find the registered node for @fwnode.
125  */
find_io_range_by_fwnode(struct fwnode_handle * fwnode)126 struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
127 {
128 	struct logic_pio_hwaddr *range, *found_range = NULL;
129 
130 	rcu_read_lock();
131 	list_for_each_entry_rcu(range, &io_range_list, list) {
132 		if (range->fwnode == fwnode) {
133 			found_range = range;
134 			break;
135 		}
136 	}
137 	rcu_read_unlock();
138 
139 	return found_range;
140 }
141 
142 /* Return a registered range given an input PIO token */
find_io_range(unsigned long pio)143 static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
144 {
145 	struct logic_pio_hwaddr *range, *found_range = NULL;
146 
147 	rcu_read_lock();
148 	list_for_each_entry_rcu(range, &io_range_list, list) {
149 		if (in_range(pio, range->io_start, range->size)) {
150 			found_range = range;
151 			break;
152 		}
153 	}
154 	rcu_read_unlock();
155 
156 	if (!found_range)
157 		pr_err("PIO entry token 0x%lx invalid\n", pio);
158 
159 	return found_range;
160 }
161 
162 /**
163  * logic_pio_to_hwaddr - translate logical PIO to HW address
164  * @pio: logical PIO value
165  *
166  * Returns HW address if valid, ~0 otherwise.
167  *
168  * Translate the input logical PIO to the corresponding hardware address.
169  * The input PIO should be unique in the whole logical PIO space.
170  */
logic_pio_to_hwaddr(unsigned long pio)171 resource_size_t logic_pio_to_hwaddr(unsigned long pio)
172 {
173 	struct logic_pio_hwaddr *range;
174 
175 	range = find_io_range(pio);
176 	if (range)
177 		return range->hw_start + pio - range->io_start;
178 
179 	return (resource_size_t)~0;
180 }
181 
182 /**
183  * logic_pio_trans_hwaddr - translate HW address to logical PIO
184  * @fwnode: FW node reference for the host
185  * @addr: Host-relative HW address
186  * @size: size to translate
187  *
188  * Returns Logical PIO value if successful, ~0UL otherwise
189  */
logic_pio_trans_hwaddr(struct fwnode_handle * fwnode,resource_size_t addr,resource_size_t size)190 unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
191 				     resource_size_t addr, resource_size_t size)
192 {
193 	struct logic_pio_hwaddr *range;
194 
195 	range = find_io_range_by_fwnode(fwnode);
196 	if (!range || range->flags == LOGIC_PIO_CPU_MMIO) {
197 		pr_err("IO range not found or invalid\n");
198 		return ~0UL;
199 	}
200 	if (range->size < size) {
201 		pr_err("resource size %pa cannot fit in IO range size %pa\n",
202 		       &size, &range->size);
203 		return ~0UL;
204 	}
205 	return addr - range->hw_start + range->io_start;
206 }
207 
logic_pio_trans_cpuaddr(resource_size_t addr)208 unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
209 {
210 	struct logic_pio_hwaddr *range;
211 
212 	rcu_read_lock();
213 	list_for_each_entry_rcu(range, &io_range_list, list) {
214 		if (range->flags != LOGIC_PIO_CPU_MMIO)
215 			continue;
216 		if (in_range(addr, range->hw_start, range->size)) {
217 			unsigned long cpuaddr;
218 
219 			cpuaddr = addr - range->hw_start + range->io_start;
220 
221 			rcu_read_unlock();
222 			return cpuaddr;
223 		}
224 	}
225 	rcu_read_unlock();
226 
227 	pr_err("addr %pa not registered in io_range_list\n", &addr);
228 
229 	return ~0UL;
230 }
231 
232 #if defined(CONFIG_INDIRECT_PIO) && defined(PCI_IOBASE)
233 #define BUILD_LOGIC_IO(bw, type)					\
234 type logic_in##bw(unsigned long addr)					\
235 {									\
236 	type ret = (type)~0;						\
237 									\
238 	if (addr < MMIO_UPPER_LIMIT) {					\
239 		ret = read##bw(PCI_IOBASE + addr);			\
240 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \
241 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
242 									\
243 		if (entry && entry->ops)				\
244 			ret = entry->ops->in(entry->hostdata,		\
245 					addr, sizeof(type));		\
246 		else							\
247 			WARN_ON_ONCE(1);				\
248 	}								\
249 	return ret;							\
250 }									\
251 									\
252 void logic_out##bw(type value, unsigned long addr)			\
253 {									\
254 	if (addr < MMIO_UPPER_LIMIT) {					\
255 		write##bw(value, PCI_IOBASE + addr);			\
256 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
257 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
258 									\
259 		if (entry && entry->ops)				\
260 			entry->ops->out(entry->hostdata,		\
261 					addr, value, sizeof(type));	\
262 		else							\
263 			WARN_ON_ONCE(1);				\
264 	}								\
265 }									\
266 									\
267 void logic_ins##bw(unsigned long addr, void *buffer,		\
268 		   unsigned int count)					\
269 {									\
270 	if (addr < MMIO_UPPER_LIMIT) {					\
271 		reads##bw(PCI_IOBASE + addr, buffer, count);		\
272 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
273 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
274 									\
275 		if (entry && entry->ops)				\
276 			entry->ops->ins(entry->hostdata,		\
277 				addr, buffer, sizeof(type), count);	\
278 		else							\
279 			WARN_ON_ONCE(1);				\
280 	}								\
281 									\
282 }									\
283 									\
284 void logic_outs##bw(unsigned long addr, const void *buffer,		\
285 		    unsigned int count)					\
286 {									\
287 	if (addr < MMIO_UPPER_LIMIT) {					\
288 		writes##bw(PCI_IOBASE + addr, buffer, count);		\
289 	} else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) {	\
290 		struct logic_pio_hwaddr *entry = find_io_range(addr);	\
291 									\
292 		if (entry && entry->ops)				\
293 			entry->ops->outs(entry->hostdata,		\
294 				addr, buffer, sizeof(type), count);	\
295 		else							\
296 			WARN_ON_ONCE(1);				\
297 	}								\
298 }
299 
300 BUILD_LOGIC_IO(b, u8)
301 EXPORT_SYMBOL(logic_inb);
302 EXPORT_SYMBOL(logic_insb);
303 EXPORT_SYMBOL(logic_outb);
304 EXPORT_SYMBOL(logic_outsb);
305 
306 BUILD_LOGIC_IO(w, u16)
307 EXPORT_SYMBOL(logic_inw);
308 EXPORT_SYMBOL(logic_insw);
309 EXPORT_SYMBOL(logic_outw);
310 EXPORT_SYMBOL(logic_outsw);
311 
312 BUILD_LOGIC_IO(l, u32)
313 EXPORT_SYMBOL(logic_inl);
314 EXPORT_SYMBOL(logic_insl);
315 EXPORT_SYMBOL(logic_outl);
316 EXPORT_SYMBOL(logic_outsl);
317 
318 #endif /* CONFIG_INDIRECT_PIO && PCI_IOBASE */
319