diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-01-02 16:22:50 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-01-17 12:30:59 -0500 |
commit | 3f32b3c093eddc03ed477ae0d7a6938db6b94a05 (patch) | |
tree | 3e949845afa85bb76cb50e5532d7b1825ad39c72 /drivers/pcmcia | |
parent | 180c33ee409eb3ed605d4ad9884e4a526a7655ff (diff) |
pcmcia: rsrc_nonstatic io memory probe improvements
Add a lot of documentation to the rsrc_nonstatic io memory probe
functions. Also, add a first memory probe call -- just checking
whether request_resource() succeeds -- upon adding of resources.
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 174 |
1 files changed, 114 insertions, 60 deletions
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index b886385f12e2..120d5ad99296 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -264,18 +264,15 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, | |||
264 | } | 264 | } |
265 | #endif | 265 | #endif |
266 | 266 | ||
267 | /*====================================================================== | 267 | /*======================================================================*/ |
268 | |||
269 | This is tricky... when we set up CIS memory, we try to validate | ||
270 | the memory window space allocations. | ||
271 | |||
272 | ======================================================================*/ | ||
273 | 268 | ||
274 | /* Validation function for cards with a valid CIS */ | 269 | /** |
270 | * readable() - iomem validation function for cards with a valid CIS | ||
271 | */ | ||
275 | static int readable(struct pcmcia_socket *s, struct resource *res, | 272 | static int readable(struct pcmcia_socket *s, struct resource *res, |
276 | unsigned int *count) | 273 | unsigned int *count) |
277 | { | 274 | { |
278 | int ret = -1; | 275 | int ret = -EINVAL; |
279 | 276 | ||
280 | s->cis_mem.res = res; | 277 | s->cis_mem.res = res; |
281 | s->cis_virt = ioremap(res->start, s->map_size); | 278 | s->cis_virt = ioremap(res->start, s->map_size); |
@@ -286,13 +283,16 @@ static int readable(struct pcmcia_socket *s, struct resource *res, | |||
286 | s->cis_virt = NULL; | 283 | s->cis_virt = NULL; |
287 | } | 284 | } |
288 | s->cis_mem.res = NULL; | 285 | s->cis_mem.res = NULL; |
289 | if ((ret != 0) || (*count == 0)) | 286 | if ((ret) || (*count == 0)) |
290 | return 0; | 287 | return -EINVAL; |
291 | return 1; | 288 | return 0; |
292 | } | 289 | } |
293 | 290 | ||
294 | /* Validation function for simple memory cards */ | 291 | /** |
295 | static int checksum(struct pcmcia_socket *s, struct resource *res) | 292 | * checksum() - iomem validation function for simple memory cards |
293 | */ | ||
294 | static int checksum(struct pcmcia_socket *s, struct resource *res, | ||
295 | unsigned int *value) | ||
296 | { | 296 | { |
297 | pccard_mem_map map; | 297 | pccard_mem_map map; |
298 | int i, a = 0, b = -1, d; | 298 | int i, a = 0, b = -1, d; |
@@ -320,61 +320,83 @@ static int checksum(struct pcmcia_socket *s, struct resource *res) | |||
320 | iounmap(virt); | 320 | iounmap(virt); |
321 | } | 321 | } |
322 | 322 | ||
323 | return (b == -1) ? -1 : (a>>1); | 323 | if (b == -1) |
324 | } | 324 | return -EINVAL; |
325 | |||
326 | static int | ||
327 | cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) | ||
328 | { | ||
329 | struct resource *res1, *res2; | ||
330 | unsigned int info1, info2; | ||
331 | int ret = 0; | ||
332 | |||
333 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); | ||
334 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, | ||
335 | "PCMCIA memprobe"); | ||
336 | |||
337 | if (res1 && res2) { | ||
338 | ret = readable(s, res1, &info1); | ||
339 | ret += readable(s, res2, &info2); | ||
340 | } | ||
341 | 325 | ||
342 | free_region(res2); | 326 | *value = a; |
343 | free_region(res1); | ||
344 | 327 | ||
345 | return (ret == 2) && (info1 == info2); | 328 | return 0; |
346 | } | 329 | } |
347 | 330 | ||
348 | static int | 331 | /** |
349 | checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) | 332 | * do_validate_mem() - low level validate a memory region for PCMCIA use |
333 | * @s: PCMCIA socket to validate | ||
334 | * @base: start address of resource to check | ||
335 | * @size: size of resource to check | ||
336 | * @validate: validation function to use | ||
337 | * | ||
338 | * do_validate_mem() splits up the memory region which is to be checked | ||
339 | * into two parts. Both are passed to the @validate() function. If | ||
340 | * @validate() returns non-zero, or the value parameter to @validate() | ||
341 | * is zero, or the value parameter is different between both calls, | ||
342 | * the check fails, and -EINVAL is returned. Else, 0 is returned. | ||
343 | */ | ||
344 | static int do_validate_mem(struct pcmcia_socket *s, | ||
345 | unsigned long base, unsigned long size, | ||
346 | int validate (struct pcmcia_socket *s, | ||
347 | struct resource *res, | ||
348 | unsigned int *value)) | ||
350 | { | 349 | { |
351 | struct resource *res1, *res2; | 350 | struct resource *res1, *res2; |
352 | int a = -1, b = -1; | 351 | unsigned int info1 = 1, info2 = 1; |
352 | int ret = -EINVAL; | ||
353 | 353 | ||
354 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); | 354 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); |
355 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, | 355 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, |
356 | "PCMCIA memprobe"); | 356 | "PCMCIA memprobe"); |
357 | 357 | ||
358 | if (res1 && res2) { | 358 | if (res1 && res2) { |
359 | a = checksum(s, res1); | 359 | ret = 0; |
360 | b = checksum(s, res2); | 360 | if (validate) { |
361 | ret = validate(s, res1, &info1); | ||
362 | ret += validate(s, res2, &info2); | ||
363 | } | ||
361 | } | 364 | } |
362 | 365 | ||
363 | free_region(res2); | 366 | free_region(res2); |
364 | free_region(res1); | 367 | free_region(res1); |
365 | 368 | ||
366 | return (a == b) && (a >= 0); | 369 | dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u", |
367 | } | 370 | base, base+size-1, res1, res2, ret, info1, info2); |
368 | 371 | ||
369 | /*====================================================================== | 372 | if ((ret) || (info1 != info2) || (info1 == 0)) |
373 | return -EINVAL; | ||
370 | 374 | ||
371 | The memory probe. If the memory list includes a 64K-aligned block | 375 | return 0; |
372 | below 1MB, we probe in 64K chunks, and as soon as we accumulate at | 376 | } |
373 | least mem_limit free space, we quit. | ||
374 | 377 | ||
375 | ======================================================================*/ | ||
376 | 378 | ||
377 | static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | 379 | /** |
380 | * do_mem_probe() - validate a memory region for PCMCIA use | ||
381 | * @s: PCMCIA socket to validate | ||
382 | * @base: start address of resource to check | ||
383 | * @num: size of resource to check | ||
384 | * @validate: validation function to use | ||
385 | * @fallback: validation function to use if validate fails | ||
386 | * | ||
387 | * do_mem_probe() checks a memory region for use by the PCMCIA subsystem. | ||
388 | * To do so, the area is split up into sensible parts, and then passed | ||
389 | * into the @validate() function. Only if @validate() and @fallback() fail, | ||
390 | * the area is marked as unavaibale for use by the PCMCIA subsystem. The | ||
391 | * function returns the size of the usable memory area. | ||
392 | */ | ||
393 | static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, | ||
394 | int validate (struct pcmcia_socket *s, | ||
395 | struct resource *res, | ||
396 | unsigned int *value), | ||
397 | int fallback (struct pcmcia_socket *s, | ||
398 | struct resource *res, | ||
399 | unsigned int *value)) | ||
378 | { | 400 | { |
379 | struct socket_data *s_data = s->resource_data; | 401 | struct socket_data *s_data = s->resource_data; |
380 | u_long i, j, bad, fail, step; | 402 | u_long i, j, bad, fail, step; |
@@ -392,15 +414,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
392 | for (i = j = base; i < base+num; i = j + step) { | 414 | for (i = j = base; i < base+num; i = j + step) { |
393 | if (!fail) { | 415 | if (!fail) { |
394 | for (j = i; j < base+num; j += step) { | 416 | for (j = i; j < base+num; j += step) { |
395 | if (cis_readable(s, j, step)) | 417 | if (!do_validate_mem(s, j, step, validate)) |
396 | break; | 418 | break; |
397 | } | 419 | } |
398 | fail = ((i == base) && (j == base+num)); | 420 | fail = ((i == base) && (j == base+num)); |
399 | } | 421 | } |
400 | if (fail) { | 422 | if ((fail) && (fallback)) { |
401 | for (j = i; j < base+num; j += 2*step) | 423 | for (j = i; j < base+num; j += step) |
402 | if (checksum_match(s, j, step) && | 424 | if (!do_validate_mem(s, j, step, fallback)) |
403 | checksum_match(s, j + step, step)) | ||
404 | break; | 425 | break; |
405 | } | 426 | } |
406 | if (i != j) { | 427 | if (i != j) { |
@@ -415,8 +436,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
415 | return num - bad; | 436 | return num - bad; |
416 | } | 437 | } |
417 | 438 | ||
439 | |||
418 | #ifdef CONFIG_PCMCIA_PROBE | 440 | #ifdef CONFIG_PCMCIA_PROBE |
419 | 441 | ||
442 | /** | ||
443 | * inv_probe() - top-to-bottom search for one usuable high memory area | ||
444 | * @s: PCMCIA socket to validate | ||
445 | * @m: resource_map to check | ||
446 | */ | ||
420 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | 447 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) |
421 | { | 448 | { |
422 | struct socket_data *s_data = s->resource_data; | 449 | struct socket_data *s_data = s->resource_data; |
@@ -431,9 +458,18 @@ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | |||
431 | } | 458 | } |
432 | if (m->base < 0x100000) | 459 | if (m->base < 0x100000) |
433 | return 0; | 460 | return 0; |
434 | return do_mem_probe(m->base, m->num, s); | 461 | return do_mem_probe(s, m->base, m->num, readable, checksum); |
435 | } | 462 | } |
436 | 463 | ||
464 | /** | ||
465 | * validate_mem() - memory probe function | ||
466 | * @s: PCMCIA socket to validate | ||
467 | * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH | ||
468 | * | ||
469 | * The memory probe. If the memory list includes a 64K-aligned block | ||
470 | * below 1MB, we probe in 64K chunks, and as soon as we accumulate at | ||
471 | * least mem_limit free space, we quit. Returns 0 on usuable ports. | ||
472 | */ | ||
437 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 473 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
438 | { | 474 | { |
439 | struct resource_map *m, mm; | 475 | struct resource_map *m, mm; |
@@ -456,7 +492,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
456 | if (mm.base >= 0x100000) | 492 | if (mm.base >= 0x100000) |
457 | continue; | 493 | continue; |
458 | if ((mm.base | mm.num) & 0xffff) { | 494 | if ((mm.base | mm.num) & 0xffff) { |
459 | ok += do_mem_probe(mm.base, mm.num, s); | 495 | ok += do_mem_probe(s, mm.base, mm.num, readable, |
496 | checksum); | ||
460 | continue; | 497 | continue; |
461 | } | 498 | } |
462 | /* Special probe for 64K-aligned block */ | 499 | /* Special probe for 64K-aligned block */ |
@@ -466,7 +503,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
466 | if (ok >= mem_limit) | 503 | if (ok >= mem_limit) |
467 | sub_interval(&s_data->mem_db, b, 0x10000); | 504 | sub_interval(&s_data->mem_db, b, 0x10000); |
468 | else | 505 | else |
469 | ok += do_mem_probe(b, 0x10000, s); | 506 | ok += do_mem_probe(s, b, 0x10000, |
507 | readable, checksum); | ||
470 | } | 508 | } |
471 | } | 509 | } |
472 | } | 510 | } |
@@ -479,6 +517,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
479 | 517 | ||
480 | #else /* CONFIG_PCMCIA_PROBE */ | 518 | #else /* CONFIG_PCMCIA_PROBE */ |
481 | 519 | ||
520 | /** | ||
521 | * validate_mem() - memory probe function | ||
522 | * @s: PCMCIA socket to validate | ||
523 | * @probe_mask: ignored | ||
524 | * | ||
525 | * Returns 0 on usuable ports. | ||
526 | */ | ||
482 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 527 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
483 | { | 528 | { |
484 | struct resource_map *m, mm; | 529 | struct resource_map *m, mm; |
@@ -487,7 +532,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
487 | 532 | ||
488 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | 533 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
489 | mm = *m; | 534 | mm = *m; |
490 | ok += do_mem_probe(mm.base, mm.num, s); | 535 | ok += do_mem_probe(s, mm.base, mm.num, readable, checksum); |
491 | } | 536 | } |
492 | if (ok > 0) | 537 | if (ok > 0) |
493 | return 0; | 538 | return 0; |
@@ -497,7 +542,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
497 | #endif /* CONFIG_PCMCIA_PROBE */ | 542 | #endif /* CONFIG_PCMCIA_PROBE */ |
498 | 543 | ||
499 | 544 | ||
500 | /* | 545 | /** |
546 | * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use | ||
547 | * @s: PCMCIA socket to validate | ||
548 | * | ||
549 | * This is tricky... when we set up CIS memory, we try to validate | ||
550 | * the memory window space allocations. | ||
551 | * | ||
501 | * Locking note: Must be called with skt_mutex held! | 552 | * Locking note: Must be called with skt_mutex held! |
502 | */ | 553 | */ |
503 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | 554 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) |
@@ -515,10 +566,11 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | |||
515 | probe_mask = MEM_PROBE_HIGH; | 566 | probe_mask = MEM_PROBE_HIGH; |
516 | 567 | ||
517 | if (probe_mask & ~s_data->rsrc_mem_probe) { | 568 | if (probe_mask & ~s_data->rsrc_mem_probe) { |
518 | if (s->state & SOCKET_PRESENT) | 569 | if (s->state & SOCKET_PRESENT) { |
519 | ret = validate_mem(s, probe_mask); | 570 | ret = validate_mem(s, probe_mask); |
520 | if (!ret) | 571 | if (!ret) |
521 | s_data->rsrc_mem_probe |= probe_mask; | 572 | s_data->rsrc_mem_probe |= probe_mask; |
573 | } | ||
522 | } | 574 | } |
523 | 575 | ||
524 | mutex_unlock(&rsrc_mutex); | 576 | mutex_unlock(&rsrc_mutex); |
@@ -723,6 +775,8 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned | |||
723 | switch (action) { | 775 | switch (action) { |
724 | case ADD_MANAGED_RESOURCE: | 776 | case ADD_MANAGED_RESOURCE: |
725 | ret = add_interval(&data->mem_db, start, size); | 777 | ret = add_interval(&data->mem_db, start, size); |
778 | if (!ret) | ||
779 | do_mem_probe(s, start, size, NULL, NULL); | ||
726 | break; | 780 | break; |
727 | case REMOVE_MANAGED_RESOURCE: | 781 | case REMOVE_MANAGED_RESOURCE: |
728 | ret = sub_interval(&data->mem_db, start, size); | 782 | ret = sub_interval(&data->mem_db, start, size); |