aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/pnpbios
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/pnpbios
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/pnpbios')
-rw-r--r--drivers/pnp/pnpbios/rsparser.c67
1 files changed, 31 insertions, 36 deletions
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index db23ba78d39c..ca567671379e 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -216,7 +216,7 @@ len_err:
216 216
217static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, 217static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
218 unsigned char *p, int size, 218 unsigned char *p, int size,
219 struct pnp_option *option) 219 unsigned int option_flags)
220{ 220{
221 resource_size_t min, max, align, len; 221 resource_size_t min, max, align, len;
222 unsigned char flags; 222 unsigned char flags;
@@ -226,12 +226,13 @@ static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
226 align = (p[9] << 8) | p[8]; 226 align = (p[9] << 8) | p[8];
227 len = ((p[11] << 8) | p[10]) << 8; 227 len = ((p[11] << 8) | p[10]) << 8;
228 flags = p[3]; 228 flags = p[3];
229 pnp_register_mem_resource(dev, option, min, max, align, len, flags); 229 pnp_register_mem_resource(dev, option_flags, min, max, align, len,
230 flags);
230} 231}
231 232
232static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, 233static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
233 unsigned char *p, int size, 234 unsigned char *p, int size,
234 struct pnp_option *option) 235 unsigned int option_flags)
235{ 236{
236 resource_size_t min, max, align, len; 237 resource_size_t min, max, align, len;
237 unsigned char flags; 238 unsigned char flags;
@@ -241,12 +242,13 @@ static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
241 align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; 242 align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
242 len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; 243 len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
243 flags = p[3]; 244 flags = p[3];
244 pnp_register_mem_resource(dev, option, min, max, align, len, flags); 245 pnp_register_mem_resource(dev, option_flags, min, max, align, len,
246 flags);
245} 247}
246 248
247static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, 249static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
248 unsigned char *p, int size, 250 unsigned char *p, int size,
249 struct pnp_option *option) 251 unsigned int option_flags)
250{ 252{
251 resource_size_t base, len; 253 resource_size_t base, len;
252 unsigned char flags; 254 unsigned char flags;
@@ -254,12 +256,12 @@ static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
254 base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; 256 base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
255 len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; 257 len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
256 flags = p[3]; 258 flags = p[3];
257 pnp_register_mem_resource(dev, option, base, base, 0, len, flags); 259 pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
258} 260}
259 261
260static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, 262static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
261 unsigned char *p, int size, 263 unsigned char *p, int size,
262 struct pnp_option *option) 264 unsigned int option_flags)
263{ 265{
264 unsigned long bits; 266 unsigned long bits;
265 pnp_irq_mask_t map; 267 pnp_irq_mask_t map;
@@ -273,19 +275,19 @@ static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
273 if (size > 2) 275 if (size > 2)
274 flags = p[3]; 276 flags = p[3];
275 277
276 pnp_register_irq_resource(dev, option, &map, flags); 278 pnp_register_irq_resource(dev, option_flags, &map, flags);
277} 279}
278 280
279static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, 281static __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
280 unsigned char *p, int size, 282 unsigned char *p, int size,
281 struct pnp_option *option) 283 unsigned int option_flags)
282{ 284{
283 pnp_register_dma_resource(dev, option, p[1], p[2]); 285 pnp_register_dma_resource(dev, option_flags, p[1], p[2]);
284} 286}
285 287
286static __init void pnpbios_parse_port_option(struct pnp_dev *dev, 288static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
287 unsigned char *p, int size, 289 unsigned char *p, int size,
288 struct pnp_option *option) 290 unsigned int option_flags)
289{ 291{
290 resource_size_t min, max, align, len; 292 resource_size_t min, max, align, len;
291 unsigned char flags; 293 unsigned char flags;
@@ -295,38 +297,35 @@ static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
295 align = p[6]; 297 align = p[6];
296 len = p[7]; 298 len = p[7];
297 flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; 299 flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0;
298 pnp_register_port_resource(dev, option, min, max, align, len, flags); 300 pnp_register_port_resource(dev, option_flags, min, max, align, len,
301 flags);
299} 302}
300 303
301static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, 304static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
302 unsigned char *p, int size, 305 unsigned char *p, int size,
303 struct pnp_option *option) 306 unsigned int option_flags)
304{ 307{
305 resource_size_t base, len; 308 resource_size_t base, len;
306 309
307 base = (p[2] << 8) | p[1]; 310 base = (p[2] << 8) | p[1];
308 len = p[3]; 311 len = p[3];
309 pnp_register_port_resource(dev, option, base, base, 0, len, 312 pnp_register_port_resource(dev, option_flags, base, base, 0, len,
310 IORESOURCE_IO_FIXED); 313 IORESOURCE_IO_FIXED);
311} 314}
312 315
313static __init unsigned char * 316static __init unsigned char *
314pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, 317pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
315 struct pnp_dev *dev) 318 struct pnp_dev *dev)
316{ 319{
317 unsigned int len, tag; 320 unsigned int len, tag;
318 int priority; 321 int priority;
319 struct pnp_option *option, *option_independent; 322 unsigned int option_flags;
320 323
321 if (!p) 324 if (!p)
322 return NULL; 325 return NULL;
323 326
324 dev_dbg(&dev->dev, "parse resource options\n"); 327 dev_dbg(&dev->dev, "parse resource options\n");
325 328 option_flags = 0;
326 option_independent = option = pnp_register_independent_option(dev);
327 if (!option)
328 return NULL;
329
330 while ((char *)p < (char *)end) { 329 while ((char *)p < (char *)end) {
331 330
332 /* determine the type of tag */ 331 /* determine the type of tag */
@@ -343,37 +342,38 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
343 case LARGE_TAG_MEM: 342 case LARGE_TAG_MEM:
344 if (len != 9) 343 if (len != 9)
345 goto len_err; 344 goto len_err;
346 pnpbios_parse_mem_option(dev, p, len, option); 345 pnpbios_parse_mem_option(dev, p, len, option_flags);
347 break; 346 break;
348 347
349 case LARGE_TAG_MEM32: 348 case LARGE_TAG_MEM32:
350 if (len != 17) 349 if (len != 17)
351 goto len_err; 350 goto len_err;
352 pnpbios_parse_mem32_option(dev, p, len, option); 351 pnpbios_parse_mem32_option(dev, p, len, option_flags);
353 break; 352 break;
354 353
355 case LARGE_TAG_FIXEDMEM32: 354 case LARGE_TAG_FIXEDMEM32:
356 if (len != 9) 355 if (len != 9)
357 goto len_err; 356 goto len_err;
358 pnpbios_parse_fixed_mem32_option(dev, p, len, option); 357 pnpbios_parse_fixed_mem32_option(dev, p, len,
358 option_flags);
359 break; 359 break;
360 360
361 case SMALL_TAG_IRQ: 361 case SMALL_TAG_IRQ:
362 if (len < 2 || len > 3) 362 if (len < 2 || len > 3)
363 goto len_err; 363 goto len_err;
364 pnpbios_parse_irq_option(dev, p, len, option); 364 pnpbios_parse_irq_option(dev, p, len, option_flags);
365 break; 365 break;
366 366
367 case SMALL_TAG_DMA: 367 case SMALL_TAG_DMA:
368 if (len != 2) 368 if (len != 2)
369 goto len_err; 369 goto len_err;
370 pnpbios_parse_dma_option(dev, p, len, option); 370 pnpbios_parse_dma_option(dev, p, len, option_flags);
371 break; 371 break;
372 372
373 case SMALL_TAG_PORT: 373 case SMALL_TAG_PORT:
374 if (len != 7) 374 if (len != 7)
375 goto len_err; 375 goto len_err;
376 pnpbios_parse_port_option(dev, p, len, option); 376 pnpbios_parse_port_option(dev, p, len, option_flags);
377 break; 377 break;
378 378
379 case SMALL_TAG_VENDOR: 379 case SMALL_TAG_VENDOR:
@@ -383,7 +383,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
383 case SMALL_TAG_FIXEDPORT: 383 case SMALL_TAG_FIXEDPORT:
384 if (len != 3) 384 if (len != 3)
385 goto len_err; 385 goto len_err;
386 pnpbios_parse_fixed_port_option(dev, p, len, option); 386 pnpbios_parse_fixed_port_option(dev, p, len,
387 option_flags);
387 break; 388 break;
388 389
389 case SMALL_TAG_STARTDEP: 390 case SMALL_TAG_STARTDEP:
@@ -392,19 +393,13 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
392 priority = PNP_RES_PRIORITY_ACCEPTABLE; 393 priority = PNP_RES_PRIORITY_ACCEPTABLE;
393 if (len > 0) 394 if (len > 0)
394 priority = p[1]; 395 priority = p[1];
395 option = pnp_register_dependent_option(dev, priority); 396 option_flags = pnp_new_dependent_set(dev, priority);
396 if (!option)
397 return NULL;
398 break; 397 break;
399 398
400 case SMALL_TAG_ENDDEP: 399 case SMALL_TAG_ENDDEP:
401 if (len != 0) 400 if (len != 0)
402 goto len_err; 401 goto len_err;
403 if (option_independent == option) 402 option_flags = 0;
404 dev_warn(&dev->dev, "missing "
405 "SMALL_TAG_STARTDEP tag\n");
406 option = option_independent;
407 dev_dbg(&dev->dev, "end dependent options\n");
408 break; 403 break;
409 404
410 case SMALL_TAG_END: 405 case SMALL_TAG_END: