1/*
2 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
7 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
8 */
9
10#include <linux/errno.h>
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/pnp.h>
15#include <linux/bitmap.h>
16#include <linux/mutex.h>
17#include "base.h"
18
19DEFINE_MUTEX(pnp_res_mutex);
20
21static struct resource *pnp_find_resource(struct pnp_dev *dev,
22					  unsigned char rule,
23					  unsigned long type,
24					  unsigned int bar)
25{
26	struct resource *res = pnp_get_resource(dev, type, bar);
27
28	/* when the resource already exists, set its resource bits from rule */
29	if (res) {
30		res->flags &= ~IORESOURCE_BITS;
31		res->flags |= rule & IORESOURCE_BITS;
32	}
33
34	return res;
35}
36
37static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
38{
39	struct resource *res, local_res;
40
41	res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx);
42	if (res) {
43		pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
44			"flags %#lx\n", idx, (unsigned long long) res->start,
45			(unsigned long long) res->end, res->flags);
46		return 0;
47	}
48
49	res = &local_res;
50	res->flags = rule->flags | IORESOURCE_AUTO;
51	res->start = 0;
52	res->end = 0;
53
54	if (!rule->size) {
55		res->flags |= IORESOURCE_DISABLED;
56		pnp_dbg(&dev->dev, "  io %d disabled\n", idx);
57		goto __add;
58	}
59
60	res->start = rule->min;
61	res->end = res->start + rule->size - 1;
62
63	while (!pnp_check_port(dev, res)) {
64		res->start += rule->align;
65		res->end = res->start + rule->size - 1;
66		if (res->start > rule->max || !rule->align) {
67			pnp_dbg(&dev->dev, "  couldn't assign io %d "
68				"(min %#llx max %#llx)\n", idx,
69				(unsigned long long) rule->min,
70				(unsigned long long) rule->max);
71			return -EBUSY;
72		}
73	}
74
75__add:
76	pnp_add_io_resource(dev, res->start, res->end, res->flags);
77	return 0;
78}
79
80static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
81{
82	struct resource *res, local_res;
83
84	res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx);
85	if (res) {
86		pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
87			"flags %#lx\n", idx, (unsigned long long) res->start,
88			(unsigned long long) res->end, res->flags);
89		return 0;
90	}
91
92	res = &local_res;
93	res->flags = rule->flags | IORESOURCE_AUTO;
94	res->start = 0;
95	res->end = 0;
96
97	/* ??? rule->flags restricted to 8 bits, all tests bogus ??? */
98	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
99		res->flags |= IORESOURCE_READONLY;
100	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
101		res->flags |= IORESOURCE_CACHEABLE;
102	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
103		res->flags |= IORESOURCE_RANGELENGTH;
104	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
105		res->flags |= IORESOURCE_SHADOWABLE;
106
107	if (!rule->size) {
108		res->flags |= IORESOURCE_DISABLED;
109		pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
110		goto __add;
111	}
112
113	res->start = rule->min;
114	res->end = res->start + rule->size - 1;
115
116	while (!pnp_check_mem(dev, res)) {
117		res->start += rule->align;
118		res->end = res->start + rule->size - 1;
119		if (res->start > rule->max || !rule->align) {
120			pnp_dbg(&dev->dev, "  couldn't assign mem %d "
121				"(min %#llx max %#llx)\n", idx,
122				(unsigned long long) rule->min,
123				(unsigned long long) rule->max);
124			return -EBUSY;
125		}
126	}
127
128__add:
129	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
130	return 0;
131}
132
133static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
134{
135	struct resource *res, local_res;
136	int i;
137
138	/* IRQ priority: this table is good for i386 */
139	static unsigned short xtab[16] = {
140		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
141	};
142
143	res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
144	if (res) {
145		pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
146			idx, (int) res->start, res->flags);
147		return 0;
148	}
149
150	res = &local_res;
151	res->flags = rule->flags | IORESOURCE_AUTO;
152	res->start = -1;
153	res->end = -1;
154
155	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
156		res->flags |= IORESOURCE_DISABLED;
157		pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
158		goto __add;
159	}
160
161	/* TBD: need check for >16 IRQ */
162	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
163	if (res->start < PNP_IRQ_NR) {
164		res->end = res->start;
165		goto __add;
166	}
167	for (i = 0; i < 16; i++) {
168		if (test_bit(xtab[i], rule->map.bits)) {
169			res->start = res->end = xtab[i];
170			if (pnp_check_irq(dev, res))
171				goto __add;
172		}
173	}
174
175	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
176		res->start = -1;
177		res->end = -1;
178		res->flags |= IORESOURCE_DISABLED;
179		pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
180		goto __add;
181	}
182
183	pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
184	return -EBUSY;
185
186__add:
187	pnp_add_irq_resource(dev, res->start, res->flags);
188	return 0;
189}
190
191#ifdef CONFIG_ISA_DMA_API
192static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
193{
194	struct resource *res, local_res;
195	int i;
196
197	/* DMA priority: this table is good for i386 */
198	static unsigned short xtab[8] = {
199		1, 3, 5, 6, 7, 0, 2, 4
200	};
201
202	res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
203	if (res) {
204		pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
205			idx, (int) res->start, res->flags);
206		return 0;
207	}
208
209	res = &local_res;
210	res->flags = rule->flags | IORESOURCE_AUTO;
211	res->start = -1;
212	res->end = -1;
213
214	if (!rule->map) {
215		res->flags |= IORESOURCE_DISABLED;
216		pnp_dbg(&dev->dev, "  dma %d disabled\n", idx);
217		goto __add;
218	}
219
220	for (i = 0; i < 8; i++) {
221		if (rule->map & (1 << xtab[i])) {
222			res->start = res->end = xtab[i];
223			if (pnp_check_dma(dev, res))
224				goto __add;
225		}
226	}
227
228	pnp_dbg(&dev->dev, "  couldn't assign dma %d\n", idx);
229	return -EBUSY;
230
231__add:
232	pnp_add_dma_resource(dev, res->start, res->flags);
233	return 0;
234}
235#endif /* CONFIG_ISA_DMA_API */
236
237void pnp_init_resources(struct pnp_dev *dev)
238{
239	pnp_free_resources(dev);
240}
241
242static void pnp_clean_resource_table(struct pnp_dev *dev)
243{
244	struct pnp_resource *pnp_res, *tmp;
245
246	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
247		if (pnp_res->res.flags & IORESOURCE_AUTO)
248			pnp_free_resource(pnp_res);
249	}
250}
251
252/**
253 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
254 * @dev: pointer to the desired device
255 * @set: the dependent function number
256 */
257static int pnp_assign_resources(struct pnp_dev *dev, int set)
258{
259	struct pnp_option *option;
260	int nport = 0, nmem = 0, nirq = 0;
261	int ndma __maybe_unused = 0;
262	int ret = 0;
263
264	pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
265	mutex_lock(&pnp_res_mutex);
266	pnp_clean_resource_table(dev);
267
268	list_for_each_entry(option, &dev->options, list) {
269		if (pnp_option_is_dependent(option) &&
270		    pnp_option_set(option) != set)
271				continue;
272
273		switch (option->type) {
274		case IORESOURCE_IO:
275			ret = pnp_assign_port(dev, &option->u.port, nport++);
276			break;
277		case IORESOURCE_MEM:
278			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
279			break;
280		case IORESOURCE_IRQ:
281			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
282			break;
283#ifdef CONFIG_ISA_DMA_API
284		case IORESOURCE_DMA:
285			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
286			break;
287#endif
288		default:
289			ret = -EINVAL;
290			break;
291		}
292		if (ret < 0)
293			break;
294	}
295
296	mutex_unlock(&pnp_res_mutex);
297	if (ret < 0) {
298		pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
299		pnp_clean_resource_table(dev);
300	} else
301		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
302	return ret;
303}
304
305/**
306 * pnp_auto_config_dev - automatically assigns resources to a device
307 * @dev: pointer to the desired device
308 */
309int pnp_auto_config_dev(struct pnp_dev *dev)
310{
311	int i, ret;
312
313	if (!pnp_can_configure(dev)) {
314		pnp_dbg(&dev->dev, "configuration not supported\n");
315		return -ENODEV;
316	}
317
318	ret = pnp_assign_resources(dev, 0);
319	if (ret == 0)
320		return 0;
321
322	for (i = 1; i < dev->num_dependent_sets; i++) {
323		ret = pnp_assign_resources(dev, i);
324		if (ret == 0)
325			return 0;
326	}
327
328	dev_err(&dev->dev, "unable to assign resources\n");
329	return ret;
330}
331
332/**
333 * pnp_start_dev - low-level start of the PnP device
334 * @dev: pointer to the desired device
335 *
336 * assumes that resources have already been allocated
337 */
338int pnp_start_dev(struct pnp_dev *dev)
339{
340	if (!pnp_can_write(dev)) {
341		pnp_dbg(&dev->dev, "activation not supported\n");
342		return -EINVAL;
343	}
344
345	dbg_pnp_show_resources(dev, "pnp_start_dev");
346	if (dev->protocol->set(dev) < 0) {
347		dev_err(&dev->dev, "activation failed\n");
348		return -EIO;
349	}
350
351	dev_info(&dev->dev, "activated\n");
352	return 0;
353}
354
355/**
356 * pnp_stop_dev - low-level disable of the PnP device
357 * @dev: pointer to the desired device
358 *
359 * does not free resources
360 */
361int pnp_stop_dev(struct pnp_dev *dev)
362{
363	if (!pnp_can_disable(dev)) {
364		pnp_dbg(&dev->dev, "disabling not supported\n");
365		return -EINVAL;
366	}
367	if (dev->protocol->disable(dev) < 0) {
368		dev_err(&dev->dev, "disable failed\n");
369		return -EIO;
370	}
371
372	dev_info(&dev->dev, "disabled\n");
373	return 0;
374}
375
376/**
377 * pnp_activate_dev - activates a PnP device for use
378 * @dev: pointer to the desired device
379 *
380 * does not validate or set resources so be careful.
381 */
382int pnp_activate_dev(struct pnp_dev *dev)
383{
384	int error;
385
386	if (dev->active)
387		return 0;
388
389	/* ensure resources are allocated */
390	if (pnp_auto_config_dev(dev))
391		return -EBUSY;
392
393	error = pnp_start_dev(dev);
394	if (error)
395		return error;
396
397	dev->active = 1;
398	return 0;
399}
400
401/**
402 * pnp_disable_dev - disables device
403 * @dev: pointer to the desired device
404 *
405 * inform the correct pnp protocol so that resources can be used by other devices
406 */
407int pnp_disable_dev(struct pnp_dev *dev)
408{
409	int error;
410
411	if (!dev->active)
412		return 0;
413
414	error = pnp_stop_dev(dev);
415	if (error)
416		return error;
417
418	dev->active = 0;
419
420	/* release the resources so that other devices can use them */
421	mutex_lock(&pnp_res_mutex);
422	pnp_clean_resource_table(dev);
423	mutex_unlock(&pnp_res_mutex);
424
425	return 0;
426}
427
428EXPORT_SYMBOL(pnp_start_dev);
429EXPORT_SYMBOL(pnp_stop_dev);
430EXPORT_SYMBOL(pnp_activate_dev);
431EXPORT_SYMBOL(pnp_disable_dev);
432