aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/resource.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2008-06-27 18:57:17 -0400
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 17:27:07 -0400
commit1f32ca31e7409d37c1b25e5f81840fb184380cdf (patch)
treee587c85b46b04dbbb5987e2a4986ab174f3bd6fa /drivers/pnp/resource.c
parentbbe413b4fc7f791248c7ee00ce7b3778491a3700 (diff)
PNP: convert resource options to single linked list
ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of a device, i.e., the possibilities an OS bus driver has when it assigns I/O port, MMIO, and other resources to the device. PNP used to maintain this "possible resource setting" information in one independent option structure and a list of dependent option structures for each device. Each of these option structures had lists of I/O, memory, IRQ, and DMA resources, for example: dev independent options ind-io0 -> ind-io1 ... ind-mem0 -> ind-mem1 ... ... dependent option set 0 dep0-io0 -> dep0-io1 ... dep0-mem0 -> dep0-mem1 ... ... dependent option set 1 dep1-io0 -> dep1-io1 ... dep1-mem0 -> dep1-mem1 ... ... ... This data structure was designed for ISAPNP, where the OS configures device resource settings by writing directly to configuration registers. The OS can write the registers in arbitrary order much like it writes PCI BARs. However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces that perform device configuration, and it is important to pass the desired settings to those interfaces in the correct order. The OS learns the correct order by using firmware interfaces that return the "current resource settings" and "possible resource settings," but the option structures above doesn't store the ordering information. This patch replaces the independent and dependent lists with a single list of options. For example, a device might have possible resource settings like this: dev options ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ... All the possible settings are in the same list, in the order they come from the firmware "possible resource settings" list. Each entry is tagged with an independent/dependent flag. Dependent entries also have a "set number" and an optional priority value. All dependent entries must be assigned from the same set. For example, the OS can use all the entries from dependent set 0, or all the entries from dependent set 1, but it cannot mix entries from set 0 with entries from set 1. Prior to this patch PNP didn't keep track of the order of this list, and it assigned all independent options first, then all dependent ones. Using the example above, that resulted in a "desired configuration" list like this: ind->io0 -> ind->io1 -> depN-io0 ... instead of the list the firmware expects, which looks like this: ind->io0 -> depN-io0 -> ind-io1 ... Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Acked-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/pnp/resource.c')
-rw-r--r--drivers/pnp/resource.c268
1 files changed, 65 insertions, 203 deletions
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index a795864dc695..d6388970a1a4 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> 4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 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>
6 */ 8 */
7 9
8#include <linux/module.h> 10#include <linux/module.h>
@@ -28,78 +30,36 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some
28 * option registration 30 * option registration
29 */ 31 */
30 32
31struct pnp_option *pnp_build_option(int priority) 33struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
34 unsigned int option_flags)
32{ 35{
33 struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); 36 struct pnp_option *option;
34 37
38 option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
35 if (!option) 39 if (!option)
36 return NULL; 40 return NULL;
37 41
38 option->priority = priority & 0xff; 42 option->flags = option_flags;
39 /* make sure the priority is valid */ 43 option->type = type;
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
57 dev_dbg(&dev->dev, "new independent option\n");
58 return option;
59}
60
61struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
62 int priority)
63{
64 struct pnp_option *option;
65 44
66 option = pnp_build_option(priority); 45 list_add_tail(&option->list, &dev->options);
67
68 if (dev->dependent) {
69 struct pnp_option *parent = dev->dependent;
70 while (parent->next)
71 parent = parent->next;
72 parent->next = option;
73 } else
74 dev->dependent = option;
75
76 dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
77 return option; 46 return option;
78} 47}
79 48
80int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, 49int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
81 pnp_irq_mask_t *map, unsigned char flags) 50 pnp_irq_mask_t *map, unsigned char flags)
82{ 51{
83 struct pnp_irq *irq, *ptr; 52 struct pnp_option *option;
84#ifdef DEBUG 53 struct pnp_irq *irq;
85 char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
86#endif
87 54
88 irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); 55 option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags);
89 if (!irq) 56 if (!option)
90 return -ENOMEM; 57 return -ENOMEM;
91 58
59 irq = &option->u.irq;
92 irq->map = *map; 60 irq->map = *map;
93 irq->flags = flags; 61 irq->flags = flags;
94 62
95 ptr = option->irq;
96 while (ptr && ptr->next)
97 ptr = ptr->next;
98 if (ptr)
99 ptr->next = irq;
100 else
101 option->irq = irq;
102
103#ifdef CONFIG_PCI 63#ifdef CONFIG_PCI
104 { 64 {
105 int i; 65 int i;
@@ -110,163 +70,81 @@ int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
110 } 70 }
111#endif 71#endif
112 72
113#ifdef DEBUG 73 dbg_pnp_show_option(dev, option);
114 bitmap_scnprintf(buf, sizeof(buf), irq->map.bits, PNP_IRQ_NR);
115 dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
116 irq->flags);
117#endif
118 return 0; 74 return 0;
119} 75}
120 76
121int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, 77int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
122 unsigned char map, unsigned char flags) 78 unsigned char map, unsigned char flags)
123{ 79{
124 struct pnp_dma *dma, *ptr; 80 struct pnp_option *option;
81 struct pnp_dma *dma;
125 82
126 dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); 83 option = pnp_build_option(dev, IORESOURCE_DMA, option_flags);
127 if (!dma) 84 if (!option)
128 return -ENOMEM; 85 return -ENOMEM;
129 86
87 dma = &option->u.dma;
130 dma->map = map; 88 dma->map = map;
131 dma->flags = flags; 89 dma->flags = flags;
132 90
133 ptr = option->dma; 91 dbg_pnp_show_option(dev, option);
134 while (ptr && ptr->next)
135 ptr = ptr->next;
136 if (ptr)
137 ptr->next = dma;
138 else
139 option->dma = dma;
140
141 dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", dma->map,
142 dma->flags);
143 return 0; 92 return 0;
144} 93}
145 94
146int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, 95int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
147 resource_size_t min, resource_size_t max, 96 resource_size_t min, resource_size_t max,
148 resource_size_t align, resource_size_t size, 97 resource_size_t align, resource_size_t size,
149 unsigned char flags) 98 unsigned char flags)
150{ 99{
151 struct pnp_port *port, *ptr; 100 struct pnp_option *option;
101 struct pnp_port *port;
152 102
153 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); 103 option = pnp_build_option(dev, IORESOURCE_IO, option_flags);
154 if (!port) 104 if (!option)
155 return -ENOMEM; 105 return -ENOMEM;
156 106
107 port = &option->u.port;
157 port->min = min; 108 port->min = min;
158 port->max = max; 109 port->max = max;
159 port->align = align; 110 port->align = align;
160 port->size = size; 111 port->size = size;
161 port->flags = flags; 112 port->flags = flags;
162 113
163 ptr = option->port; 114 dbg_pnp_show_option(dev, option);
164 while (ptr && ptr->next)
165 ptr = ptr->next;
166 if (ptr)
167 ptr->next = port;
168 else
169 option->port = port;
170
171 dev_dbg(&dev->dev, " io "
172 "min %#llx max %#llx align %lld size %lld flags %#x\n",
173 (unsigned long long) port->min,
174 (unsigned long long) port->max,
175 (unsigned long long) port->align,
176 (unsigned long long) port->size, port->flags);
177 return 0; 115 return 0;
178} 116}
179 117
180int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, 118int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
181 resource_size_t min, resource_size_t max, 119 resource_size_t min, resource_size_t max,
182 resource_size_t align, resource_size_t size, 120 resource_size_t align, resource_size_t size,
183 unsigned char flags) 121 unsigned char flags)
184{ 122{
185 struct pnp_mem *mem, *ptr; 123 struct pnp_option *option;
124 struct pnp_mem *mem;
186 125
187 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); 126 option = pnp_build_option(dev, IORESOURCE_MEM, option_flags);
188 if (!mem) 127 if (!option)
189 return -ENOMEM; 128 return -ENOMEM;
190 129
130 mem = &option->u.mem;
191 mem->min = min; 131 mem->min = min;
192 mem->max = max; 132 mem->max = max;
193 mem->align = align; 133 mem->align = align;
194 mem->size = size; 134 mem->size = size;
195 mem->flags = flags; 135 mem->flags = flags;
196 136
197 ptr = option->mem; 137 dbg_pnp_show_option(dev, option);
198 while (ptr && ptr->next)
199 ptr = ptr->next;
200 if (ptr)
201 ptr->next = mem;
202 else
203 option->mem = mem;
204
205 dev_dbg(&dev->dev, " mem "
206 "min %#llx max %#llx align %lld size %lld flags %#x\n",
207 (unsigned long long) mem->min,
208 (unsigned long long) mem->max,
209 (unsigned long long) mem->align,
210 (unsigned long long) mem->size, mem->flags);
211 return 0; 138 return 0;
212} 139}
213 140
214static void pnp_free_port(struct pnp_port *port) 141void pnp_free_options(struct pnp_dev *dev)
215{
216 struct pnp_port *next;
217
218 while (port) {
219 next = port->next;
220 kfree(port);
221 port = next;
222 }
223}
224
225static void pnp_free_irq(struct pnp_irq *irq)
226{
227 struct pnp_irq *next;
228
229 while (irq) {
230 next = irq->next;
231 kfree(irq);
232 irq = next;
233 }
234}
235
236static void pnp_free_dma(struct pnp_dma *dma)
237{
238 struct pnp_dma *next;
239
240 while (dma) {
241 next = dma->next;
242 kfree(dma);
243 dma = next;
244 }
245}
246
247static void pnp_free_mem(struct pnp_mem *mem)
248{ 142{
249 struct pnp_mem *next; 143 struct pnp_option *option, *tmp;
250
251 while (mem) {
252 next = mem->next;
253 kfree(mem);
254 mem = next;
255 }
256}
257 144
258void pnp_free_option(struct pnp_option *option) 145 list_for_each_entry_safe(option, tmp, &dev->options, list) {
259{ 146 list_del(&option->list);
260 struct pnp_option *next;
261
262 while (option) {
263 next = option->next;
264 pnp_free_port(option->port);
265 pnp_free_irq(option->irq);
266 pnp_free_dma(option->dma);
267 pnp_free_mem(option->mem);
268 kfree(option); 147 kfree(option);
269 option = next;
270 } 148 }
271} 149}
272 150
@@ -668,66 +546,50 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
668 return pnp_res; 546 return pnp_res;
669} 547}
670 548
671static int pnp_possible_option(struct pnp_option *option, int type, 549/*
672 resource_size_t start, resource_size_t size) 550 * Determine whether the specified resource is a possible configuration
551 * for this device.
552 */
553int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
554 resource_size_t size)
673{ 555{
674 struct pnp_option *tmp; 556 struct pnp_option *option;
675 struct pnp_port *port; 557 struct pnp_port *port;
676 struct pnp_mem *mem; 558 struct pnp_mem *mem;
677 struct pnp_irq *irq; 559 struct pnp_irq *irq;
678 struct pnp_dma *dma; 560 struct pnp_dma *dma;
679 561
680 if (!option) 562 list_for_each_entry(option, &dev->options, list) {
681 return 0; 563 if (option->type != type)
564 continue;
682 565
683 for (tmp = option; tmp; tmp = tmp->next) { 566 switch (option->type) {
684 switch (type) {
685 case IORESOURCE_IO: 567 case IORESOURCE_IO:
686 for (port = tmp->port; port; port = port->next) { 568 port = &option->u.port;
687 if (port->min == start && port->size == size) 569 if (port->min == start && port->size == size)
688 return 1; 570 return 1;
689 }
690 break; 571 break;
691 case IORESOURCE_MEM: 572 case IORESOURCE_MEM:
692 for (mem = tmp->mem; mem; mem = mem->next) { 573 mem = &option->u.mem;
693 if (mem->min == start && mem->size == size) 574 if (mem->min == start && mem->size == size)
694 return 1; 575 return 1;
695 }
696 break; 576 break;
697 case IORESOURCE_IRQ: 577 case IORESOURCE_IRQ:
698 for (irq = tmp->irq; irq; irq = irq->next) { 578 irq = &option->u.irq;
699 if (start < PNP_IRQ_NR && 579 if (start < PNP_IRQ_NR &&
700 test_bit(start, irq->map.bits)) 580 test_bit(start, irq->map.bits))
701 return 1; 581 return 1;
702 }
703 break; 582 break;
704 case IORESOURCE_DMA: 583 case IORESOURCE_DMA:
705 for (dma = tmp->dma; dma; dma = dma->next) { 584 dma = &option->u.dma;
706 if (dma->map & (1 << start)) 585 if (dma->map & (1 << start))
707 return 1; 586 return 1;
708 }
709 break; 587 break;
710 } 588 }
711 } 589 }
712 590
713 return 0; 591 return 0;
714} 592}
715
716/*
717 * Determine whether the specified resource is a possible configuration
718 * for this device.
719 */
720int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
721 resource_size_t size)
722{
723 if (pnp_possible_option(dev->independent, type, start, size))
724 return 1;
725
726 if (pnp_possible_option(dev->dependent, type, start, size))
727 return 1;
728
729 return 0;
730}
731EXPORT_SYMBOL(pnp_possible_config); 593EXPORT_SYMBOL(pnp_possible_config);
732 594
733/* format is: pnp_reserve_irq=irq1[,irq2] .... */ 595/* format is: pnp_reserve_irq=irq1[,irq2] .... */