resource.c revision a05d0781695566296e74a3670dd5bbd3daf24ae2
1/*
2 * resource.c - Contains functions for registering and analyzing resource information
3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6 */
7
8#include <linux/module.h>
9#include <linux/errno.h>
10#include <linux/interrupt.h>
11#include <linux/kernel.h>
12#include <asm/io.h>
13#include <asm/dma.h>
14#include <asm/irq.h>
15#include <linux/pci.h>
16#include <linux/ioport.h>
17#include <linux/init.h>
18
19#include <linux/pnp.h>
20#include "base.h"
21
22static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
23static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };	/* reserve (don't use) some DMA */
24static int pnp_reserve_io[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
25static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some memory region */
26
27/*
28 * option registration
29 */
30
31static struct pnp_option *pnp_build_option(int priority)
32{
33	struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
34
35	if (!option)
36		return NULL;
37
38	option->priority = priority & 0xff;
39	/* make sure the priority is valid */
40	if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
41		option->priority = PNP_RES_PRIORITY_INVALID;
42
43	return option;
44}
45
46struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
47{
48	struct pnp_option *option;
49
50	option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
51
52	/* this should never happen but if it does we'll try to continue */
53	if (dev->independent)
54		dev_err(&dev->dev, "independent resource already registered\n");
55	dev->independent = option;
56	return option;
57}
58
59struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
60						 int priority)
61{
62	struct pnp_option *option;
63
64	option = pnp_build_option(priority);
65
66	if (dev->dependent) {
67		struct pnp_option *parent = dev->dependent;
68		while (parent->next)
69			parent = parent->next;
70		parent->next = option;
71	} else
72		dev->dependent = option;
73	return option;
74}
75
76int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
77{
78	struct pnp_irq *ptr;
79
80	ptr = option->irq;
81	while (ptr && ptr->next)
82		ptr = ptr->next;
83	if (ptr)
84		ptr->next = data;
85	else
86		option->irq = data;
87
88#ifdef CONFIG_PCI
89	{
90		int i;
91
92		for (i = 0; i < 16; i++)
93			if (test_bit(i, data->map))
94				pcibios_penalize_isa_irq(i, 0);
95	}
96#endif
97	return 0;
98}
99
100int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
101{
102	struct pnp_dma *ptr;
103
104	ptr = option->dma;
105	while (ptr && ptr->next)
106		ptr = ptr->next;
107	if (ptr)
108		ptr->next = data;
109	else
110		option->dma = data;
111
112	return 0;
113}
114
115int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
116{
117	struct pnp_port *ptr;
118
119	ptr = option->port;
120	while (ptr && ptr->next)
121		ptr = ptr->next;
122	if (ptr)
123		ptr->next = data;
124	else
125		option->port = data;
126
127	return 0;
128}
129
130int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
131{
132	struct pnp_mem *ptr;
133
134	ptr = option->mem;
135	while (ptr && ptr->next)
136		ptr = ptr->next;
137	if (ptr)
138		ptr->next = data;
139	else
140		option->mem = data;
141	return 0;
142}
143
144static void pnp_free_port(struct pnp_port *port)
145{
146	struct pnp_port *next;
147
148	while (port) {
149		next = port->next;
150		kfree(port);
151		port = next;
152	}
153}
154
155static void pnp_free_irq(struct pnp_irq *irq)
156{
157	struct pnp_irq *next;
158
159	while (irq) {
160		next = irq->next;
161		kfree(irq);
162		irq = next;
163	}
164}
165
166static void pnp_free_dma(struct pnp_dma *dma)
167{
168	struct pnp_dma *next;
169
170	while (dma) {
171		next = dma->next;
172		kfree(dma);
173		dma = next;
174	}
175}
176
177static void pnp_free_mem(struct pnp_mem *mem)
178{
179	struct pnp_mem *next;
180
181	while (mem) {
182		next = mem->next;
183		kfree(mem);
184		mem = next;
185	}
186}
187
188void pnp_free_option(struct pnp_option *option)
189{
190	struct pnp_option *next;
191
192	while (option) {
193		next = option->next;
194		pnp_free_port(option->port);
195		pnp_free_irq(option->irq);
196		pnp_free_dma(option->dma);
197		pnp_free_mem(option->mem);
198		kfree(option);
199		option = next;
200	}
201}
202
203/*
204 * resource validity checking
205 */
206
207#define length(start, end) (*(end) - *(start) + 1)
208
209/* Two ranges conflict if one doesn't end before the other starts */
210#define ranged_conflict(starta, enda, startb, endb) \
211	!((*(enda) < *(startb)) || (*(endb) < *(starta)))
212
213#define cannot_compare(flags) \
214((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
215
216int pnp_check_port(struct pnp_dev *dev, int idx)
217{
218	int tmp;
219	struct pnp_dev *tdev;
220	resource_size_t *port, *end, *tport, *tend;
221
222	port = &dev->res.port_resource[idx].start;
223	end = &dev->res.port_resource[idx].end;
224
225	/* if the resource doesn't exist, don't complain about it */
226	if (cannot_compare(dev->res.port_resource[idx].flags))
227		return 1;
228
229	/* check if the resource is already in use, skip if the
230	 * device is active because it itself may be in use */
231	if (!dev->active) {
232		if (__check_region(&ioport_resource, *port, length(port, end)))
233			return 0;
234	}
235
236	/* check if the resource is reserved */
237	for (tmp = 0; tmp < 8; tmp++) {
238		int rport = pnp_reserve_io[tmp << 1];
239		int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
240		if (ranged_conflict(port, end, &rport, &rend))
241			return 0;
242	}
243
244	/* check for internal conflicts */
245	for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
246		if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
247			tport = &dev->res.port_resource[tmp].start;
248			tend = &dev->res.port_resource[tmp].end;
249			if (ranged_conflict(port, end, tport, tend))
250				return 0;
251		}
252	}
253
254	/* check for conflicts with other pnp devices */
255	pnp_for_each_dev(tdev) {
256		if (tdev == dev)
257			continue;
258		for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
259			if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
260				if (cannot_compare
261				    (tdev->res.port_resource[tmp].flags))
262					continue;
263				tport = &tdev->res.port_resource[tmp].start;
264				tend = &tdev->res.port_resource[tmp].end;
265				if (ranged_conflict(port, end, tport, tend))
266					return 0;
267			}
268		}
269	}
270
271	return 1;
272}
273
274int pnp_check_mem(struct pnp_dev *dev, int idx)
275{
276	int tmp;
277	struct pnp_dev *tdev;
278	resource_size_t *addr, *end, *taddr, *tend;
279
280	addr = &dev->res.mem_resource[idx].start;
281	end = &dev->res.mem_resource[idx].end;
282
283	/* if the resource doesn't exist, don't complain about it */
284	if (cannot_compare(dev->res.mem_resource[idx].flags))
285		return 1;
286
287	/* check if the resource is already in use, skip if the
288	 * device is active because it itself may be in use */
289	if (!dev->active) {
290		if (check_mem_region(*addr, length(addr, end)))
291			return 0;
292	}
293
294	/* check if the resource is reserved */
295	for (tmp = 0; tmp < 8; tmp++) {
296		int raddr = pnp_reserve_mem[tmp << 1];
297		int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
298		if (ranged_conflict(addr, end, &raddr, &rend))
299			return 0;
300	}
301
302	/* check for internal conflicts */
303	for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
304		if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
305			taddr = &dev->res.mem_resource[tmp].start;
306			tend = &dev->res.mem_resource[tmp].end;
307			if (ranged_conflict(addr, end, taddr, tend))
308				return 0;
309		}
310	}
311
312	/* check for conflicts with other pnp devices */
313	pnp_for_each_dev(tdev) {
314		if (tdev == dev)
315			continue;
316		for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
317			if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
318				if (cannot_compare
319				    (tdev->res.mem_resource[tmp].flags))
320					continue;
321				taddr = &tdev->res.mem_resource[tmp].start;
322				tend = &tdev->res.mem_resource[tmp].end;
323				if (ranged_conflict(addr, end, taddr, tend))
324					return 0;
325			}
326		}
327	}
328
329	return 1;
330}
331
332static irqreturn_t pnp_test_handler(int irq, void *dev_id)
333{
334	return IRQ_HANDLED;
335}
336
337int pnp_check_irq(struct pnp_dev *dev, int idx)
338{
339	int tmp;
340	struct pnp_dev *tdev;
341	resource_size_t *irq = &dev->res.irq_resource[idx].start;
342
343	/* if the resource doesn't exist, don't complain about it */
344	if (cannot_compare(dev->res.irq_resource[idx].flags))
345		return 1;
346
347	/* check if the resource is valid */
348	if (*irq < 0 || *irq > 15)
349		return 0;
350
351	/* check if the resource is reserved */
352	for (tmp = 0; tmp < 16; tmp++) {
353		if (pnp_reserve_irq[tmp] == *irq)
354			return 0;
355	}
356
357	/* check for internal conflicts */
358	for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
359		if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
360			if (dev->res.irq_resource[tmp].start == *irq)
361				return 0;
362		}
363	}
364
365#ifdef CONFIG_PCI
366	/* check if the resource is being used by a pci device */
367	{
368		struct pci_dev *pci = NULL;
369		for_each_pci_dev(pci) {
370			if (pci->irq == *irq)
371				return 0;
372		}
373	}
374#endif
375
376	/* check if the resource is already in use, skip if the
377	 * device is active because it itself may be in use */
378	if (!dev->active) {
379		if (request_irq(*irq, pnp_test_handler,
380				IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
381			return 0;
382		free_irq(*irq, NULL);
383	}
384
385	/* check for conflicts with other pnp devices */
386	pnp_for_each_dev(tdev) {
387		if (tdev == dev)
388			continue;
389		for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
390			if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
391				if (cannot_compare
392				    (tdev->res.irq_resource[tmp].flags))
393					continue;
394				if ((tdev->res.irq_resource[tmp].start == *irq))
395					return 0;
396			}
397		}
398	}
399
400	return 1;
401}
402
403int pnp_check_dma(struct pnp_dev *dev, int idx)
404{
405#ifndef CONFIG_IA64
406	int tmp;
407	struct pnp_dev *tdev;
408	resource_size_t *dma = &dev->res.dma_resource[idx].start;
409
410	/* if the resource doesn't exist, don't complain about it */
411	if (cannot_compare(dev->res.dma_resource[idx].flags))
412		return 1;
413
414	/* check if the resource is valid */
415	if (*dma < 0 || *dma == 4 || *dma > 7)
416		return 0;
417
418	/* check if the resource is reserved */
419	for (tmp = 0; tmp < 8; tmp++) {
420		if (pnp_reserve_dma[tmp] == *dma)
421			return 0;
422	}
423
424	/* check for internal conflicts */
425	for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
426		if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
427			if (dev->res.dma_resource[tmp].start == *dma)
428				return 0;
429		}
430	}
431
432	/* check if the resource is already in use, skip if the
433	 * device is active because it itself may be in use */
434	if (!dev->active) {
435		if (request_dma(*dma, "pnp"))
436			return 0;
437		free_dma(*dma);
438	}
439
440	/* check for conflicts with other pnp devices */
441	pnp_for_each_dev(tdev) {
442		if (tdev == dev)
443			continue;
444		for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
445			if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
446				if (cannot_compare
447				    (tdev->res.dma_resource[tmp].flags))
448					continue;
449				if ((tdev->res.dma_resource[tmp].start == *dma))
450					return 0;
451			}
452		}
453	}
454
455	return 1;
456#else
457	/* IA64 does not have legacy DMA */
458	return 0;
459#endif
460}
461
462/* format is: pnp_reserve_irq=irq1[,irq2] .... */
463static int __init pnp_setup_reserve_irq(char *str)
464{
465	int i;
466
467	for (i = 0; i < 16; i++)
468		if (get_option(&str, &pnp_reserve_irq[i]) != 2)
469			break;
470	return 1;
471}
472
473__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
474
475/* format is: pnp_reserve_dma=dma1[,dma2] .... */
476static int __init pnp_setup_reserve_dma(char *str)
477{
478	int i;
479
480	for (i = 0; i < 8; i++)
481		if (get_option(&str, &pnp_reserve_dma[i]) != 2)
482			break;
483	return 1;
484}
485
486__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
487
488/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
489static int __init pnp_setup_reserve_io(char *str)
490{
491	int i;
492
493	for (i = 0; i < 16; i++)
494		if (get_option(&str, &pnp_reserve_io[i]) != 2)
495			break;
496	return 1;
497}
498
499__setup("pnp_reserve_io=", pnp_setup_reserve_io);
500
501/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
502static int __init pnp_setup_reserve_mem(char *str)
503{
504	int i;
505
506	for (i = 0; i < 16; i++)
507		if (get_option(&str, &pnp_reserve_mem[i]) != 2)
508			break;
509	return 1;
510}
511
512__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
513