diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-27 19:18:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-27 19:18:30 -0500 |
commit | 8d37a371b6869920e6c40c495c68eabba1ef3909 (patch) | |
tree | dad784512b13832f4f5494cfe0791965c6a2b0f6 /drivers/pcmcia/rsrc_nonstatic.c | |
parent | ef1a8de8ea004a689b2aa9f5cefcba2b1a0262f2 (diff) | |
parent | 7b4884ca8853a638df0eb5d251d80d67777b8b1a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6: (49 commits)
pcmcia: validate late-added resources
pcmcia: allow for extension of resource interval
pcmcia: remove useless msleep in ds.c
pcmcia: use read_cis_mem return value
pcmcia: handle error in serial_cs config calls
pcmcia: add locking to pcmcia_{read,write}_cis_mem
pcmcia: avoid prod_id memleak
pcmcia: avoid sysfs-related lockup for cardbus
pcmcia: use state machine for extended requery
pcmcia: delay re-scanning and re-querying of PCMCIA bus
pcmcia: use pccardd to handle eject, insert, suspend and resume requests
pcmcia: use ops_mutex for rsrc_{mgr,nonstatic} locking
pcmcia: use mutex for dynid lock
pcmcia: assert locking to struct pcmcia_device
pcmcia: add locking documentation
pcmcia: simplify locking
pcmcia: add locking to struct pcmcia_socket->pcmcia_state()
pcmcia: protect s->device_count
pcmcia: properly lock skt->irq, skt->irq_mask
pcmcia: lock ops->set_socket
...
Diffstat (limited to 'drivers/pcmcia/rsrc_nonstatic.c')
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 285 |
1 files changed, 179 insertions, 106 deletions
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c67638fe6914..4663b3fa9f96 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -55,11 +55,10 @@ struct resource_map { | |||
55 | 55 | ||
56 | struct socket_data { | 56 | struct socket_data { |
57 | struct resource_map mem_db; | 57 | struct resource_map mem_db; |
58 | struct resource_map mem_db_valid; | ||
58 | struct resource_map io_db; | 59 | struct resource_map io_db; |
59 | unsigned int rsrc_mem_probe; | ||
60 | }; | 60 | }; |
61 | 61 | ||
62 | static DEFINE_MUTEX(rsrc_mutex); | ||
63 | #define MEM_PROBE_LOW (1 << 0) | 62 | #define MEM_PROBE_LOW (1 << 0) |
64 | #define MEM_PROBE_HIGH (1 << 1) | 63 | #define MEM_PROBE_HIGH (1 << 1) |
65 | 64 | ||
@@ -125,8 +124,10 @@ static int add_interval(struct resource_map *map, u_long base, u_long num) | |||
125 | struct resource_map *p, *q; | 124 | struct resource_map *p, *q; |
126 | 125 | ||
127 | for (p = map; ; p = p->next) { | 126 | for (p = map; ; p = p->next) { |
128 | if ((p != map) && (p->base+p->num-1 >= base)) | 127 | if ((p != map) && (p->base+p->num >= base)) { |
129 | return -1; | 128 | p->num = max(num + base - p->base, p->num); |
129 | return 0; | ||
130 | } | ||
130 | if ((p->next == map) || (p->next->base > base+num-1)) | 131 | if ((p->next == map) || (p->next->base > base+num-1)) |
131 | break; | 132 | break; |
132 | } | 133 | } |
@@ -264,36 +265,44 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, | |||
264 | } | 265 | } |
265 | #endif | 266 | #endif |
266 | 267 | ||
267 | /*====================================================================== | 268 | /*======================================================================*/ |
268 | |||
269 | This is tricky... when we set up CIS memory, we try to validate | ||
270 | the memory window space allocations. | ||
271 | |||
272 | ======================================================================*/ | ||
273 | 269 | ||
274 | /* Validation function for cards with a valid CIS */ | 270 | /** |
271 | * readable() - iomem validation function for cards with a valid CIS | ||
272 | */ | ||
275 | static int readable(struct pcmcia_socket *s, struct resource *res, | 273 | static int readable(struct pcmcia_socket *s, struct resource *res, |
276 | unsigned int *count) | 274 | unsigned int *count) |
277 | { | 275 | { |
278 | int ret = -1; | 276 | int ret = -EINVAL; |
277 | |||
278 | if (s->fake_cis) { | ||
279 | dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n"); | ||
280 | return 0; | ||
281 | } | ||
279 | 282 | ||
280 | s->cis_mem.res = res; | 283 | s->cis_mem.res = res; |
281 | s->cis_virt = ioremap(res->start, s->map_size); | 284 | s->cis_virt = ioremap(res->start, s->map_size); |
282 | if (s->cis_virt) { | 285 | if (s->cis_virt) { |
283 | ret = pccard_validate_cis(s, count); | 286 | mutex_unlock(&s->ops_mutex); |
284 | /* invalidate mapping and CIS cache */ | 287 | /* as we're only called from pcmcia.c, we're safe */ |
288 | if (s->callback->validate) | ||
289 | ret = s->callback->validate(s, count); | ||
290 | /* invalidate mapping */ | ||
291 | mutex_lock(&s->ops_mutex); | ||
285 | iounmap(s->cis_virt); | 292 | iounmap(s->cis_virt); |
286 | s->cis_virt = NULL; | 293 | s->cis_virt = NULL; |
287 | destroy_cis_cache(s); | ||
288 | } | 294 | } |
289 | s->cis_mem.res = NULL; | 295 | s->cis_mem.res = NULL; |
290 | if ((ret != 0) || (*count == 0)) | 296 | if ((ret) || (*count == 0)) |
291 | return 0; | 297 | return -EINVAL; |
292 | return 1; | 298 | return 0; |
293 | } | 299 | } |
294 | 300 | ||
295 | /* Validation function for simple memory cards */ | 301 | /** |
296 | static int checksum(struct pcmcia_socket *s, struct resource *res) | 302 | * checksum() - iomem validation function for simple memory cards |
303 | */ | ||
304 | static int checksum(struct pcmcia_socket *s, struct resource *res, | ||
305 | unsigned int *value) | ||
297 | { | 306 | { |
298 | pccard_mem_map map; | 307 | pccard_mem_map map; |
299 | int i, a = 0, b = -1, d; | 308 | int i, a = 0, b = -1, d; |
@@ -321,61 +330,90 @@ static int checksum(struct pcmcia_socket *s, struct resource *res) | |||
321 | iounmap(virt); | 330 | iounmap(virt); |
322 | } | 331 | } |
323 | 332 | ||
324 | return (b == -1) ? -1 : (a>>1); | 333 | if (b == -1) |
334 | return -EINVAL; | ||
335 | |||
336 | *value = a; | ||
337 | |||
338 | return 0; | ||
325 | } | 339 | } |
326 | 340 | ||
327 | static int | 341 | /** |
328 | cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) | 342 | * do_validate_mem() - low level validate a memory region for PCMCIA use |
343 | * @s: PCMCIA socket to validate | ||
344 | * @base: start address of resource to check | ||
345 | * @size: size of resource to check | ||
346 | * @validate: validation function to use | ||
347 | * | ||
348 | * do_validate_mem() splits up the memory region which is to be checked | ||
349 | * into two parts. Both are passed to the @validate() function. If | ||
350 | * @validate() returns non-zero, or the value parameter to @validate() | ||
351 | * is zero, or the value parameter is different between both calls, | ||
352 | * the check fails, and -EINVAL is returned. Else, 0 is returned. | ||
353 | */ | ||
354 | static int do_validate_mem(struct pcmcia_socket *s, | ||
355 | unsigned long base, unsigned long size, | ||
356 | int validate (struct pcmcia_socket *s, | ||
357 | struct resource *res, | ||
358 | unsigned int *value)) | ||
329 | { | 359 | { |
360 | struct socket_data *s_data = s->resource_data; | ||
330 | struct resource *res1, *res2; | 361 | struct resource *res1, *res2; |
331 | unsigned int info1, info2; | 362 | unsigned int info1 = 1, info2 = 1; |
332 | int ret = 0; | 363 | int ret = -EINVAL; |
333 | 364 | ||
334 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); | 365 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); |
335 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, | 366 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, |
336 | "PCMCIA memprobe"); | 367 | "PCMCIA memprobe"); |
337 | 368 | ||
338 | if (res1 && res2) { | 369 | if (res1 && res2) { |
339 | ret = readable(s, res1, &info1); | 370 | ret = 0; |
340 | ret += readable(s, res2, &info2); | 371 | if (validate) { |
372 | ret = validate(s, res1, &info1); | ||
373 | ret += validate(s, res2, &info2); | ||
374 | } | ||
341 | } | 375 | } |
342 | 376 | ||
343 | free_region(res2); | 377 | free_region(res2); |
344 | free_region(res1); | 378 | free_region(res1); |
345 | 379 | ||
346 | return (ret == 2) && (info1 == info2); | 380 | dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u", |
347 | } | 381 | base, base+size-1, res1, res2, ret, info1, info2); |
348 | 382 | ||
349 | static int | 383 | if ((ret) || (info1 != info2) || (info1 == 0)) |
350 | checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) | 384 | return -EINVAL; |
351 | { | ||
352 | struct resource *res1, *res2; | ||
353 | int a = -1, b = -1; | ||
354 | |||
355 | res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe"); | ||
356 | res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, | ||
357 | "PCMCIA memprobe"); | ||
358 | 385 | ||
359 | if (res1 && res2) { | 386 | if (validate && !s->fake_cis) { |
360 | a = checksum(s, res1); | 387 | /* move it to the validated data set */ |
361 | b = checksum(s, res2); | 388 | add_interval(&s_data->mem_db_valid, base, size); |
389 | sub_interval(&s_data->mem_db, base, size); | ||
362 | } | 390 | } |
363 | 391 | ||
364 | free_region(res2); | 392 | return 0; |
365 | free_region(res1); | ||
366 | |||
367 | return (a == b) && (a >= 0); | ||
368 | } | 393 | } |
369 | 394 | ||
370 | /*====================================================================== | ||
371 | |||
372 | The memory probe. If the memory list includes a 64K-aligned block | ||
373 | below 1MB, we probe in 64K chunks, and as soon as we accumulate at | ||
374 | least mem_limit free space, we quit. | ||
375 | |||
376 | ======================================================================*/ | ||
377 | 395 | ||
378 | static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | 396 | /** |
397 | * do_mem_probe() - validate a memory region for PCMCIA use | ||
398 | * @s: PCMCIA socket to validate | ||
399 | * @base: start address of resource to check | ||
400 | * @num: size of resource to check | ||
401 | * @validate: validation function to use | ||
402 | * @fallback: validation function to use if validate fails | ||
403 | * | ||
404 | * do_mem_probe() checks a memory region for use by the PCMCIA subsystem. | ||
405 | * To do so, the area is split up into sensible parts, and then passed | ||
406 | * into the @validate() function. Only if @validate() and @fallback() fail, | ||
407 | * the area is marked as unavaibale for use by the PCMCIA subsystem. The | ||
408 | * function returns the size of the usable memory area. | ||
409 | */ | ||
410 | static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, | ||
411 | int validate (struct pcmcia_socket *s, | ||
412 | struct resource *res, | ||
413 | unsigned int *value), | ||
414 | int fallback (struct pcmcia_socket *s, | ||
415 | struct resource *res, | ||
416 | unsigned int *value)) | ||
379 | { | 417 | { |
380 | struct socket_data *s_data = s->resource_data; | 418 | struct socket_data *s_data = s->resource_data; |
381 | u_long i, j, bad, fail, step; | 419 | u_long i, j, bad, fail, step; |
@@ -393,15 +431,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
393 | for (i = j = base; i < base+num; i = j + step) { | 431 | for (i = j = base; i < base+num; i = j + step) { |
394 | if (!fail) { | 432 | if (!fail) { |
395 | for (j = i; j < base+num; j += step) { | 433 | for (j = i; j < base+num; j += step) { |
396 | if (cis_readable(s, j, step)) | 434 | if (!do_validate_mem(s, j, step, validate)) |
397 | break; | 435 | break; |
398 | } | 436 | } |
399 | fail = ((i == base) && (j == base+num)); | 437 | fail = ((i == base) && (j == base+num)); |
400 | } | 438 | } |
401 | if (fail) { | 439 | if ((fail) && (fallback)) { |
402 | for (j = i; j < base+num; j += 2*step) | 440 | for (j = i; j < base+num; j += step) |
403 | if (checksum_match(s, j, step) && | 441 | if (!do_validate_mem(s, j, step, fallback)) |
404 | checksum_match(s, j + step, step)) | ||
405 | break; | 442 | break; |
406 | } | 443 | } |
407 | if (i != j) { | 444 | if (i != j) { |
@@ -416,8 +453,14 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
416 | return num - bad; | 453 | return num - bad; |
417 | } | 454 | } |
418 | 455 | ||
456 | |||
419 | #ifdef CONFIG_PCMCIA_PROBE | 457 | #ifdef CONFIG_PCMCIA_PROBE |
420 | 458 | ||
459 | /** | ||
460 | * inv_probe() - top-to-bottom search for one usuable high memory area | ||
461 | * @s: PCMCIA socket to validate | ||
462 | * @m: resource_map to check | ||
463 | */ | ||
421 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | 464 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) |
422 | { | 465 | { |
423 | struct socket_data *s_data = s->resource_data; | 466 | struct socket_data *s_data = s->resource_data; |
@@ -432,9 +475,18 @@ static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | |||
432 | } | 475 | } |
433 | if (m->base < 0x100000) | 476 | if (m->base < 0x100000) |
434 | return 0; | 477 | return 0; |
435 | return do_mem_probe(m->base, m->num, s); | 478 | return do_mem_probe(s, m->base, m->num, readable, checksum); |
436 | } | 479 | } |
437 | 480 | ||
481 | /** | ||
482 | * validate_mem() - memory probe function | ||
483 | * @s: PCMCIA socket to validate | ||
484 | * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH | ||
485 | * | ||
486 | * The memory probe. If the memory list includes a 64K-aligned block | ||
487 | * below 1MB, we probe in 64K chunks, and as soon as we accumulate at | ||
488 | * least mem_limit free space, we quit. Returns 0 on usuable ports. | ||
489 | */ | ||
438 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 490 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
439 | { | 491 | { |
440 | struct resource_map *m, mm; | 492 | struct resource_map *m, mm; |
@@ -446,6 +498,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
446 | if (probe_mask & MEM_PROBE_HIGH) { | 498 | if (probe_mask & MEM_PROBE_HIGH) { |
447 | if (inv_probe(s_data->mem_db.next, s) > 0) | 499 | if (inv_probe(s_data->mem_db.next, s) > 0) |
448 | return 0; | 500 | return 0; |
501 | if (s_data->mem_db_valid.next != &s_data->mem_db_valid) | ||
502 | return 0; | ||
449 | dev_printk(KERN_NOTICE, &s->dev, | 503 | dev_printk(KERN_NOTICE, &s->dev, |
450 | "cs: warning: no high memory space available!\n"); | 504 | "cs: warning: no high memory space available!\n"); |
451 | return -ENODEV; | 505 | return -ENODEV; |
@@ -457,7 +511,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
457 | if (mm.base >= 0x100000) | 511 | if (mm.base >= 0x100000) |
458 | continue; | 512 | continue; |
459 | if ((mm.base | mm.num) & 0xffff) { | 513 | if ((mm.base | mm.num) & 0xffff) { |
460 | ok += do_mem_probe(mm.base, mm.num, s); | 514 | ok += do_mem_probe(s, mm.base, mm.num, readable, |
515 | checksum); | ||
461 | continue; | 516 | continue; |
462 | } | 517 | } |
463 | /* Special probe for 64K-aligned block */ | 518 | /* Special probe for 64K-aligned block */ |
@@ -467,7 +522,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
467 | if (ok >= mem_limit) | 522 | if (ok >= mem_limit) |
468 | sub_interval(&s_data->mem_db, b, 0x10000); | 523 | sub_interval(&s_data->mem_db, b, 0x10000); |
469 | else | 524 | else |
470 | ok += do_mem_probe(b, 0x10000, s); | 525 | ok += do_mem_probe(s, b, 0x10000, |
526 | readable, checksum); | ||
471 | } | 527 | } |
472 | } | 528 | } |
473 | } | 529 | } |
@@ -480,6 +536,13 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
480 | 536 | ||
481 | #else /* CONFIG_PCMCIA_PROBE */ | 537 | #else /* CONFIG_PCMCIA_PROBE */ |
482 | 538 | ||
539 | /** | ||
540 | * validate_mem() - memory probe function | ||
541 | * @s: PCMCIA socket to validate | ||
542 | * @probe_mask: ignored | ||
543 | * | ||
544 | * Returns 0 on usuable ports. | ||
545 | */ | ||
483 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 546 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
484 | { | 547 | { |
485 | struct resource_map *m, mm; | 548 | struct resource_map *m, mm; |
@@ -488,7 +551,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
488 | 551 | ||
489 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | 552 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
490 | mm = *m; | 553 | mm = *m; |
491 | ok += do_mem_probe(mm.base, mm.num, s); | 554 | ok += do_mem_probe(s, mm.base, mm.num, readable, checksum); |
492 | } | 555 | } |
493 | if (ok > 0) | 556 | if (ok > 0) |
494 | return 0; | 557 | return 0; |
@@ -498,31 +561,31 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
498 | #endif /* CONFIG_PCMCIA_PROBE */ | 561 | #endif /* CONFIG_PCMCIA_PROBE */ |
499 | 562 | ||
500 | 563 | ||
501 | /* | 564 | /** |
565 | * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use | ||
566 | * @s: PCMCIA socket to validate | ||
567 | * | ||
568 | * This is tricky... when we set up CIS memory, we try to validate | ||
569 | * the memory window space allocations. | ||
570 | * | ||
502 | * Locking note: Must be called with skt_mutex held! | 571 | * Locking note: Must be called with skt_mutex held! |
503 | */ | 572 | */ |
504 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | 573 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) |
505 | { | 574 | { |
506 | struct socket_data *s_data = s->resource_data; | 575 | struct socket_data *s_data = s->resource_data; |
507 | unsigned int probe_mask = MEM_PROBE_LOW; | 576 | unsigned int probe_mask = MEM_PROBE_LOW; |
508 | int ret = 0; | 577 | int ret; |
509 | 578 | ||
510 | if (!probe_mem) | 579 | if (!probe_mem || !(s->state & SOCKET_PRESENT)) |
511 | return 0; | 580 | return 0; |
512 | 581 | ||
513 | mutex_lock(&rsrc_mutex); | ||
514 | |||
515 | if (s->features & SS_CAP_PAGE_REGS) | 582 | if (s->features & SS_CAP_PAGE_REGS) |
516 | probe_mask = MEM_PROBE_HIGH; | 583 | probe_mask = MEM_PROBE_HIGH; |
517 | 584 | ||
518 | if (probe_mask & ~s_data->rsrc_mem_probe) { | 585 | ret = validate_mem(s, probe_mask); |
519 | if (s->state & SOCKET_PRESENT) | ||
520 | ret = validate_mem(s, probe_mask); | ||
521 | if (!ret) | ||
522 | s_data->rsrc_mem_probe |= probe_mask; | ||
523 | } | ||
524 | 586 | ||
525 | mutex_unlock(&rsrc_mutex); | 587 | if (s_data->mem_db_valid.next != &s_data->mem_db_valid) |
588 | return 0; | ||
526 | 589 | ||
527 | return ret; | 590 | return ret; |
528 | } | 591 | } |
@@ -602,7 +665,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
602 | struct socket_data *s_data = s->resource_data; | 665 | struct socket_data *s_data = s->resource_data; |
603 | int ret = -ENOMEM; | 666 | int ret = -ENOMEM; |
604 | 667 | ||
605 | mutex_lock(&rsrc_mutex); | ||
606 | for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) { | 668 | for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) { |
607 | unsigned long start = m->base; | 669 | unsigned long start = m->base; |
608 | unsigned long end = m->base + m->num - 1; | 670 | unsigned long end = m->base + m->num - 1; |
@@ -613,7 +675,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
613 | ret = adjust_resource(res, r_start, r_end - r_start + 1); | 675 | ret = adjust_resource(res, r_start, r_end - r_start + 1); |
614 | break; | 676 | break; |
615 | } | 677 | } |
616 | mutex_unlock(&rsrc_mutex); | ||
617 | 678 | ||
618 | return ret; | 679 | return ret; |
619 | } | 680 | } |
@@ -647,7 +708,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
647 | data.offset = base & data.mask; | 708 | data.offset = base & data.mask; |
648 | data.map = &s_data->io_db; | 709 | data.map = &s_data->io_db; |
649 | 710 | ||
650 | mutex_lock(&rsrc_mutex); | ||
651 | #ifdef CONFIG_PCI | 711 | #ifdef CONFIG_PCI |
652 | if (s->cb_dev) { | 712 | if (s->cb_dev) { |
653 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, | 713 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, |
@@ -656,7 +716,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
656 | #endif | 716 | #endif |
657 | ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, | 717 | ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, |
658 | 1, pcmcia_align, &data); | 718 | 1, pcmcia_align, &data); |
659 | mutex_unlock(&rsrc_mutex); | ||
660 | 719 | ||
661 | if (ret != 0) { | 720 | if (ret != 0) { |
662 | kfree(res); | 721 | kfree(res); |
@@ -672,15 +731,15 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | |||
672 | struct socket_data *s_data = s->resource_data; | 731 | struct socket_data *s_data = s->resource_data; |
673 | struct pcmcia_align_data data; | 732 | struct pcmcia_align_data data; |
674 | unsigned long min, max; | 733 | unsigned long min, max; |
675 | int ret, i; | 734 | int ret, i, j; |
676 | 735 | ||
677 | low = low || !(s->features & SS_CAP_PAGE_REGS); | 736 | low = low || !(s->features & SS_CAP_PAGE_REGS); |
678 | 737 | ||
679 | data.mask = align - 1; | 738 | data.mask = align - 1; |
680 | data.offset = base & data.mask; | 739 | data.offset = base & data.mask; |
681 | data.map = &s_data->mem_db; | ||
682 | 740 | ||
683 | for (i = 0; i < 2; i++) { | 741 | for (i = 0; i < 2; i++) { |
742 | data.map = &s_data->mem_db_valid; | ||
684 | if (low) { | 743 | if (low) { |
685 | max = 0x100000UL; | 744 | max = 0x100000UL; |
686 | min = base < max ? base : 0; | 745 | min = base < max ? base : 0; |
@@ -689,17 +748,23 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | |||
689 | min = 0x100000UL + base; | 748 | min = 0x100000UL + base; |
690 | } | 749 | } |
691 | 750 | ||
692 | mutex_lock(&rsrc_mutex); | 751 | for (j = 0; j < 2; j++) { |
693 | #ifdef CONFIG_PCI | 752 | #ifdef CONFIG_PCI |
694 | if (s->cb_dev) { | 753 | if (s->cb_dev) { |
695 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, | 754 | ret = pci_bus_alloc_resource(s->cb_dev->bus, |
696 | 1, min, 0, | 755 | res, num, 1, min, 0, |
697 | pcmcia_align, &data); | 756 | pcmcia_align, &data); |
698 | } else | 757 | } else |
699 | #endif | 758 | #endif |
700 | ret = allocate_resource(&iomem_resource, res, num, min, | 759 | { |
701 | max, 1, pcmcia_align, &data); | 760 | ret = allocate_resource(&iomem_resource, |
702 | mutex_unlock(&rsrc_mutex); | 761 | res, num, min, max, 1, |
762 | pcmcia_align, &data); | ||
763 | } | ||
764 | if (ret == 0) | ||
765 | break; | ||
766 | data.map = &s_data->mem_db; | ||
767 | } | ||
703 | if (ret == 0 || low) | 768 | if (ret == 0 || low) |
704 | break; | 769 | break; |
705 | low = 1; | 770 | low = 1; |
@@ -722,25 +787,18 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned | |||
722 | if (end < start) | 787 | if (end < start) |
723 | return -EINVAL; | 788 | return -EINVAL; |
724 | 789 | ||
725 | mutex_lock(&rsrc_mutex); | ||
726 | switch (action) { | 790 | switch (action) { |
727 | case ADD_MANAGED_RESOURCE: | 791 | case ADD_MANAGED_RESOURCE: |
728 | ret = add_interval(&data->mem_db, start, size); | 792 | ret = add_interval(&data->mem_db, start, size); |
793 | if (!ret) | ||
794 | do_mem_probe(s, start, size, NULL, NULL); | ||
729 | break; | 795 | break; |
730 | case REMOVE_MANAGED_RESOURCE: | 796 | case REMOVE_MANAGED_RESOURCE: |
731 | ret = sub_interval(&data->mem_db, start, size); | 797 | ret = sub_interval(&data->mem_db, start, size); |
732 | if (!ret) { | ||
733 | struct pcmcia_socket *socket; | ||
734 | down_read(&pcmcia_socket_list_rwsem); | ||
735 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) | ||
736 | release_cis_mem(socket); | ||
737 | up_read(&pcmcia_socket_list_rwsem); | ||
738 | } | ||
739 | break; | 798 | break; |
740 | default: | 799 | default: |
741 | ret = -EINVAL; | 800 | ret = -EINVAL; |
742 | } | 801 | } |
743 | mutex_unlock(&rsrc_mutex); | ||
744 | 802 | ||
745 | return ret; | 803 | return ret; |
746 | } | 804 | } |
@@ -758,7 +816,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long | |||
758 | if (end > IO_SPACE_LIMIT) | 816 | if (end > IO_SPACE_LIMIT) |
759 | return -EINVAL; | 817 | return -EINVAL; |
760 | 818 | ||
761 | mutex_lock(&rsrc_mutex); | ||
762 | switch (action) { | 819 | switch (action) { |
763 | case ADD_MANAGED_RESOURCE: | 820 | case ADD_MANAGED_RESOURCE: |
764 | if (add_interval(&data->io_db, start, size) != 0) { | 821 | if (add_interval(&data->io_db, start, size) != 0) { |
@@ -777,7 +834,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long | |||
777 | ret = -EINVAL; | 834 | ret = -EINVAL; |
778 | break; | 835 | break; |
779 | } | 836 | } |
780 | mutex_unlock(&rsrc_mutex); | ||
781 | 837 | ||
782 | return ret; | 838 | return ret; |
783 | } | 839 | } |
@@ -860,6 +916,7 @@ static int nonstatic_init(struct pcmcia_socket *s) | |||
860 | return -ENOMEM; | 916 | return -ENOMEM; |
861 | 917 | ||
862 | data->mem_db.next = &data->mem_db; | 918 | data->mem_db.next = &data->mem_db; |
919 | data->mem_db_valid.next = &data->mem_db_valid; | ||
863 | data->io_db.next = &data->io_db; | 920 | data->io_db.next = &data->io_db; |
864 | 921 | ||
865 | s->resource_data = (void *) data; | 922 | s->resource_data = (void *) data; |
@@ -874,7 +931,10 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) | |||
874 | struct socket_data *data = s->resource_data; | 931 | struct socket_data *data = s->resource_data; |
875 | struct resource_map *p, *q; | 932 | struct resource_map *p, *q; |
876 | 933 | ||
877 | mutex_lock(&rsrc_mutex); | 934 | for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) { |
935 | q = p->next; | ||
936 | kfree(p); | ||
937 | } | ||
878 | for (p = data->mem_db.next; p != &data->mem_db; p = q) { | 938 | for (p = data->mem_db.next; p != &data->mem_db; p = q) { |
879 | q = p->next; | 939 | q = p->next; |
880 | kfree(p); | 940 | kfree(p); |
@@ -883,7 +943,6 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) | |||
883 | q = p->next; | 943 | q = p->next; |
884 | kfree(p); | 944 | kfree(p); |
885 | } | 945 | } |
886 | mutex_unlock(&rsrc_mutex); | ||
887 | } | 946 | } |
888 | 947 | ||
889 | 948 | ||
@@ -910,7 +969,7 @@ static ssize_t show_io_db(struct device *dev, | |||
910 | struct resource_map *p; | 969 | struct resource_map *p; |
911 | ssize_t ret = 0; | 970 | ssize_t ret = 0; |
912 | 971 | ||
913 | mutex_lock(&rsrc_mutex); | 972 | mutex_lock(&s->ops_mutex); |
914 | data = s->resource_data; | 973 | data = s->resource_data; |
915 | 974 | ||
916 | for (p = data->io_db.next; p != &data->io_db; p = p->next) { | 975 | for (p = data->io_db.next; p != &data->io_db; p = p->next) { |
@@ -922,7 +981,7 @@ static ssize_t show_io_db(struct device *dev, | |||
922 | ((unsigned long) p->base + p->num - 1)); | 981 | ((unsigned long) p->base + p->num - 1)); |
923 | } | 982 | } |
924 | 983 | ||
925 | mutex_unlock(&rsrc_mutex); | 984 | mutex_unlock(&s->ops_mutex); |
926 | return ret; | 985 | return ret; |
927 | } | 986 | } |
928 | 987 | ||
@@ -950,9 +1009,11 @@ static ssize_t store_io_db(struct device *dev, | |||
950 | if (end_addr < start_addr) | 1009 | if (end_addr < start_addr) |
951 | return -EINVAL; | 1010 | return -EINVAL; |
952 | 1011 | ||
1012 | mutex_lock(&s->ops_mutex); | ||
953 | ret = adjust_io(s, add, start_addr, end_addr); | 1013 | ret = adjust_io(s, add, start_addr, end_addr); |
954 | if (!ret) | 1014 | if (!ret) |
955 | s->resource_setup_new = 1; | 1015 | s->resource_setup_new = 1; |
1016 | mutex_unlock(&s->ops_mutex); | ||
956 | 1017 | ||
957 | return ret ? ret : count; | 1018 | return ret ? ret : count; |
958 | } | 1019 | } |
@@ -966,9 +1027,19 @@ static ssize_t show_mem_db(struct device *dev, | |||
966 | struct resource_map *p; | 1027 | struct resource_map *p; |
967 | ssize_t ret = 0; | 1028 | ssize_t ret = 0; |
968 | 1029 | ||
969 | mutex_lock(&rsrc_mutex); | 1030 | mutex_lock(&s->ops_mutex); |
970 | data = s->resource_data; | 1031 | data = s->resource_data; |
971 | 1032 | ||
1033 | for (p = data->mem_db_valid.next; p != &data->mem_db_valid; | ||
1034 | p = p->next) { | ||
1035 | if (ret > (PAGE_SIZE - 10)) | ||
1036 | continue; | ||
1037 | ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1), | ||
1038 | "0x%08lx - 0x%08lx\n", | ||
1039 | ((unsigned long) p->base), | ||
1040 | ((unsigned long) p->base + p->num - 1)); | ||
1041 | } | ||
1042 | |||
972 | for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { | 1043 | for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { |
973 | if (ret > (PAGE_SIZE - 10)) | 1044 | if (ret > (PAGE_SIZE - 10)) |
974 | continue; | 1045 | continue; |
@@ -978,7 +1049,7 @@ static ssize_t show_mem_db(struct device *dev, | |||
978 | ((unsigned long) p->base + p->num - 1)); | 1049 | ((unsigned long) p->base + p->num - 1)); |
979 | } | 1050 | } |
980 | 1051 | ||
981 | mutex_unlock(&rsrc_mutex); | 1052 | mutex_unlock(&s->ops_mutex); |
982 | return ret; | 1053 | return ret; |
983 | } | 1054 | } |
984 | 1055 | ||
@@ -1006,9 +1077,11 @@ static ssize_t store_mem_db(struct device *dev, | |||
1006 | if (end_addr < start_addr) | 1077 | if (end_addr < start_addr) |
1007 | return -EINVAL; | 1078 | return -EINVAL; |
1008 | 1079 | ||
1080 | mutex_lock(&s->ops_mutex); | ||
1009 | ret = adjust_memory(s, add, start_addr, end_addr); | 1081 | ret = adjust_memory(s, add, start_addr, end_addr); |
1010 | if (!ret) | 1082 | if (!ret) |
1011 | s->resource_setup_new = 1; | 1083 | s->resource_setup_new = 1; |
1084 | mutex_unlock(&s->ops_mutex); | ||
1012 | 1085 | ||
1013 | return ret ? ret : count; | 1086 | return ret ? ret : count; |
1014 | } | 1087 | } |