diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-02-05 10:50:43 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-02-05 10:50:58 -0500 |
commit | 0abbf05cdd69d74f92628bf444cd210ba046f6eb (patch) | |
tree | 369550d01b22fc9a68d07652513e532b97ec8975 /include/asm-s390 | |
parent | b6b40c532a36f91df9c21caf9baba3b635e99d4e (diff) |
[S390] Cleanup & optimize bitops.
The bitops header is now a bit shorter and easier to understand since
it uses less inline assembly. It requires some tricks to persuade the
compiler to generate decent code. The ffz/ffs functions now use the
_zb_findmap/_sb_findmap table as well.
With this cleanup the new bitops for ext4 can be implemented with a
few lines, instead of another large inline assembly.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'include/asm-s390')
-rw-r--r-- | include/asm-s390/bitops.h | 515 |
1 files changed, 219 insertions, 296 deletions
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index dba6fecad0be..95d93955a9bb 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h | |||
@@ -440,242 +440,256 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) { | |||
440 | __test_bit((nr),(addr)) ) | 440 | __test_bit((nr),(addr)) ) |
441 | 441 | ||
442 | /* | 442 | /* |
443 | * ffz = Find First Zero in word. Undefined if no zero exists, | 443 | * Optimized find bit helper functions. |
444 | * so code should check against ~0UL first.. | ||
445 | */ | 444 | */ |
446 | static inline unsigned long ffz(unsigned long word) | 445 | |
446 | /** | ||
447 | * __ffz_word_loop - find byte offset of first long != -1UL | ||
448 | * @addr: pointer to array of unsigned long | ||
449 | * @size: size of the array in bits | ||
450 | */ | ||
451 | static inline unsigned long __ffz_word_loop(const unsigned long *addr, | ||
452 | unsigned long size) | ||
453 | { | ||
454 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | ||
455 | unsigned long bytes = 0; | ||
456 | |||
457 | asm volatile( | ||
458 | #ifndef __s390x__ | ||
459 | " ahi %1,31\n" | ||
460 | " srl %1,5\n" | ||
461 | "0: c %2,0(%0,%3)\n" | ||
462 | " jne 1f\n" | ||
463 | " la %0,4(%0)\n" | ||
464 | " brct %1,0b\n" | ||
465 | "1:\n" | ||
466 | #else | ||
467 | " aghi %1,63\n" | ||
468 | " srlg %1,%1,6\n" | ||
469 | "0: cg %2,0(%0,%3)\n" | ||
470 | " jne 1f\n" | ||
471 | " la %0,8(%0)\n" | ||
472 | " brct %1,0b\n" | ||
473 | "1:\n" | ||
474 | #endif | ||
475 | : "+a" (bytes), "+d" (size) | ||
476 | : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr) | ||
477 | : "cc" ); | ||
478 | return bytes; | ||
479 | } | ||
480 | |||
481 | /** | ||
482 | * __ffs_word_loop - find byte offset of first long != 0UL | ||
483 | * @addr: pointer to array of unsigned long | ||
484 | * @size: size of the array in bits | ||
485 | */ | ||
486 | static inline unsigned long __ffs_word_loop(const unsigned long *addr, | ||
487 | unsigned long size) | ||
447 | { | 488 | { |
448 | unsigned long bit = 0; | 489 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; |
490 | unsigned long bytes = 0; | ||
449 | 491 | ||
492 | asm volatile( | ||
493 | #ifndef __s390x__ | ||
494 | " ahi %1,31\n" | ||
495 | " srl %1,5\n" | ||
496 | "0: c %2,0(%0,%3)\n" | ||
497 | " jne 1f\n" | ||
498 | " la %0,4(%0)\n" | ||
499 | " brct %1,0b\n" | ||
500 | "1:\n" | ||
501 | #else | ||
502 | " aghi %1,63\n" | ||
503 | " srlg %1,%1,6\n" | ||
504 | "0: cg %2,0(%0,%3)\n" | ||
505 | " jne 1f\n" | ||
506 | " la %0,8(%0)\n" | ||
507 | " brct %1,0b\n" | ||
508 | "1:\n" | ||
509 | #endif | ||
510 | : "+a" (bytes), "+a" (size) | ||
511 | : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr) | ||
512 | : "cc" ); | ||
513 | return bytes; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * __ffz_word - add number of the first unset bit | ||
518 | * @nr: base value the bit number is added to | ||
519 | * @word: the word that is searched for unset bits | ||
520 | */ | ||
521 | static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) | ||
522 | { | ||
450 | #ifdef __s390x__ | 523 | #ifdef __s390x__ |
451 | if (likely((word & 0xffffffff) == 0xffffffff)) { | 524 | if (likely((word & 0xffffffff) == 0xffffffff)) { |
452 | word >>= 32; | 525 | word >>= 32; |
453 | bit += 32; | 526 | nr += 32; |
454 | } | 527 | } |
455 | #endif | 528 | #endif |
456 | if (likely((word & 0xffff) == 0xffff)) { | 529 | if (likely((word & 0xffff) == 0xffff)) { |
457 | word >>= 16; | 530 | word >>= 16; |
458 | bit += 16; | 531 | nr += 16; |
459 | } | 532 | } |
460 | if (likely((word & 0xff) == 0xff)) { | 533 | if (likely((word & 0xff) == 0xff)) { |
461 | word >>= 8; | 534 | word >>= 8; |
462 | bit += 8; | 535 | nr += 8; |
463 | } | 536 | } |
464 | return bit + _zb_findmap[word & 0xff]; | 537 | return nr + _zb_findmap[(unsigned char) word]; |
465 | } | 538 | } |
466 | 539 | ||
467 | /* | 540 | /** |
468 | * __ffs = find first bit in word. Undefined if no bit exists, | 541 | * __ffs_word - add number of the first set bit |
469 | * so code should check against 0UL first.. | 542 | * @nr: base value the bit number is added to |
543 | * @word: the word that is searched for set bits | ||
470 | */ | 544 | */ |
471 | static inline unsigned long __ffs (unsigned long word) | 545 | static inline unsigned long __ffs_word(unsigned long nr, unsigned long word) |
472 | { | 546 | { |
473 | unsigned long bit = 0; | ||
474 | |||
475 | #ifdef __s390x__ | 547 | #ifdef __s390x__ |
476 | if (likely((word & 0xffffffff) == 0)) { | 548 | if (likely((word & 0xffffffff) == 0)) { |
477 | word >>= 32; | 549 | word >>= 32; |
478 | bit += 32; | 550 | nr += 32; |
479 | } | 551 | } |
480 | #endif | 552 | #endif |
481 | if (likely((word & 0xffff) == 0)) { | 553 | if (likely((word & 0xffff) == 0)) { |
482 | word >>= 16; | 554 | word >>= 16; |
483 | bit += 16; | 555 | nr += 16; |
484 | } | 556 | } |
485 | if (likely((word & 0xff) == 0)) { | 557 | if (likely((word & 0xff) == 0)) { |
486 | word >>= 8; | 558 | word >>= 8; |
487 | bit += 8; | 559 | nr += 8; |
488 | } | 560 | } |
489 | return bit + _sb_findmap[word & 0xff]; | 561 | return nr + _sb_findmap[(unsigned char) word]; |
490 | } | 562 | } |
491 | 563 | ||
492 | /* | ||
493 | * Find-bit routines.. | ||
494 | */ | ||
495 | 564 | ||
496 | #ifndef __s390x__ | 565 | /** |
566 | * __load_ulong_be - load big endian unsigned long | ||
567 | * @p: pointer to array of unsigned long | ||
568 | * @offset: byte offset of source value in the array | ||
569 | */ | ||
570 | static inline unsigned long __load_ulong_be(const unsigned long *p, | ||
571 | unsigned long offset) | ||
572 | { | ||
573 | p = (unsigned long *)((unsigned long) p + offset); | ||
574 | return *p; | ||
575 | } | ||
497 | 576 | ||
498 | static inline int | 577 | /** |
499 | find_first_zero_bit(const unsigned long * addr, unsigned long size) | 578 | * __load_ulong_le - load little endian unsigned long |
579 | * @p: pointer to array of unsigned long | ||
580 | * @offset: byte offset of source value in the array | ||
581 | */ | ||
582 | static inline unsigned long __load_ulong_le(const unsigned long *p, | ||
583 | unsigned long offset) | ||
500 | { | 584 | { |
501 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 585 | unsigned long word; |
502 | unsigned long cmp, count; | ||
503 | unsigned int res; | ||
504 | 586 | ||
505 | if (!size) | 587 | p = (unsigned long *)((unsigned long) p + offset); |
506 | return 0; | 588 | #ifndef __s390x__ |
507 | asm volatile( | 589 | asm volatile( |
508 | " lhi %1,-1\n" | 590 | " ic %0,0(%1)\n" |
509 | " lr %2,%3\n" | 591 | " icm %0,2,1(%1)\n" |
510 | " slr %0,%0\n" | 592 | " icm %0,4,2(%1)\n" |
511 | " ahi %2,31\n" | 593 | " icm %0,8,3(%1)" |
512 | " srl %2,5\n" | 594 | : "=&d" (word) : "a" (p), "m" (*p) : "cc"); |
513 | "0: c %1,0(%0,%4)\n" | 595 | #else |
514 | " jne 1f\n" | 596 | asm volatile( |
515 | " la %0,4(%0)\n" | 597 | " lrvg %0,%1" |
516 | " brct %2,0b\n" | 598 | : "=d" (word) : "m" (*p) ); |
517 | " lr %0,%3\n" | 599 | #endif |
518 | " j 4f\n" | 600 | return word; |
519 | "1: l %2,0(%0,%4)\n" | ||
520 | " sll %0,3\n" | ||
521 | " lhi %1,0xff\n" | ||
522 | " tml %2,0xffff\n" | ||
523 | " jno 2f\n" | ||
524 | " ahi %0,16\n" | ||
525 | " srl %2,16\n" | ||
526 | "2: tml %2,0x00ff\n" | ||
527 | " jno 3f\n" | ||
528 | " ahi %0,8\n" | ||
529 | " srl %2,8\n" | ||
530 | "3: nr %2,%1\n" | ||
531 | " ic %2,0(%2,%5)\n" | ||
532 | " alr %0,%2\n" | ||
533 | "4:" | ||
534 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
535 | : "a" (size), "a" (addr), "a" (&_zb_findmap), | ||
536 | "m" (*(addrtype *) addr) : "cc"); | ||
537 | return (res < size) ? res : size; | ||
538 | } | 601 | } |
539 | 602 | ||
540 | static inline int | 603 | /* |
541 | find_first_bit(const unsigned long * addr, unsigned long size) | 604 | * The various find bit functions. |
605 | */ | ||
606 | |||
607 | /* | ||
608 | * ffz - find first zero in word. | ||
609 | * @word: The word to search | ||
610 | * | ||
611 | * Undefined if no zero exists, so code should check against ~0UL first. | ||
612 | */ | ||
613 | static inline unsigned long ffz(unsigned long word) | ||
542 | { | 614 | { |
543 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 615 | return __ffz_word(0, word); |
544 | unsigned long cmp, count; | 616 | } |
545 | unsigned int res; | ||
546 | 617 | ||
547 | if (!size) | 618 | /** |
548 | return 0; | 619 | * __ffs - find first bit in word. |
549 | asm volatile( | 620 | * @word: The word to search |
550 | " slr %1,%1\n" | 621 | * |
551 | " lr %2,%3\n" | 622 | * Undefined if no bit exists, so code should check against 0 first. |
552 | " slr %0,%0\n" | 623 | */ |
553 | " ahi %2,31\n" | 624 | static inline unsigned long __ffs (unsigned long word) |
554 | " srl %2,5\n" | 625 | { |
555 | "0: c %1,0(%0,%4)\n" | 626 | return __ffs_word(0, word); |
556 | " jne 1f\n" | ||
557 | " la %0,4(%0)\n" | ||
558 | " brct %2,0b\n" | ||
559 | " lr %0,%3\n" | ||
560 | " j 4f\n" | ||
561 | "1: l %2,0(%0,%4)\n" | ||
562 | " sll %0,3\n" | ||
563 | " lhi %1,0xff\n" | ||
564 | " tml %2,0xffff\n" | ||
565 | " jnz 2f\n" | ||
566 | " ahi %0,16\n" | ||
567 | " srl %2,16\n" | ||
568 | "2: tml %2,0x00ff\n" | ||
569 | " jnz 3f\n" | ||
570 | " ahi %0,8\n" | ||
571 | " srl %2,8\n" | ||
572 | "3: nr %2,%1\n" | ||
573 | " ic %2,0(%2,%5)\n" | ||
574 | " alr %0,%2\n" | ||
575 | "4:" | ||
576 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
577 | : "a" (size), "a" (addr), "a" (&_sb_findmap), | ||
578 | "m" (*(addrtype *) addr) : "cc"); | ||
579 | return (res < size) ? res : size; | ||
580 | } | 627 | } |
581 | 628 | ||
582 | #else /* __s390x__ */ | 629 | /** |
630 | * ffs - find first bit set | ||
631 | * @x: the word to search | ||
632 | * | ||
633 | * This is defined the same way as | ||
634 | * the libc and compiler builtin ffs routines, therefore | ||
635 | * differs in spirit from the above ffz (man ffs). | ||
636 | */ | ||
637 | static inline int ffs(int x) | ||
638 | { | ||
639 | if (!x) | ||
640 | return 0; | ||
641 | return __ffs_word(1, x); | ||
642 | } | ||
583 | 643 | ||
584 | static inline unsigned long | 644 | /** |
585 | find_first_zero_bit(const unsigned long * addr, unsigned long size) | 645 | * find_first_zero_bit - find the first zero bit in a memory region |
646 | * @addr: The address to start the search at | ||
647 | * @size: The maximum size to search | ||
648 | * | ||
649 | * Returns the bit-number of the first zero bit, not the number of the byte | ||
650 | * containing a bit. | ||
651 | */ | ||
652 | static inline unsigned long find_first_zero_bit(const unsigned long *addr, | ||
653 | unsigned long size) | ||
586 | { | 654 | { |
587 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 655 | unsigned long bytes, bits; |
588 | unsigned long res, cmp, count; | ||
589 | 656 | ||
590 | if (!size) | 657 | if (!size) |
591 | return 0; | 658 | return 0; |
592 | asm volatile( | 659 | bytes = __ffz_word_loop(addr, size); |
593 | " lghi %1,-1\n" | 660 | bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes)); |
594 | " lgr %2,%3\n" | 661 | return (bits < size) ? bits : size; |
595 | " slgr %0,%0\n" | 662 | } |
596 | " aghi %2,63\n" | 663 | |
597 | " srlg %2,%2,6\n" | 664 | /** |
598 | "0: cg %1,0(%0,%4)\n" | 665 | * find_first_bit - find the first set bit in a memory region |
599 | " jne 1f\n" | 666 | * @addr: The address to start the search at |
600 | " la %0,8(%0)\n" | 667 | * @size: The maximum size to search |
601 | " brct %2,0b\n" | 668 | * |
602 | " lgr %0,%3\n" | 669 | * Returns the bit-number of the first set bit, not the number of the byte |
603 | " j 5f\n" | 670 | * containing a bit. |
604 | "1: lg %2,0(%0,%4)\n" | 671 | */ |
605 | " sllg %0,%0,3\n" | 672 | static inline unsigned long find_first_bit(const unsigned long * addr, |
606 | " clr %2,%1\n" | 673 | unsigned long size) |
607 | " jne 2f\n" | ||
608 | " aghi %0,32\n" | ||
609 | " srlg %2,%2,32\n" | ||
610 | "2: lghi %1,0xff\n" | ||
611 | " tmll %2,0xffff\n" | ||
612 | " jno 3f\n" | ||
613 | " aghi %0,16\n" | ||
614 | " srl %2,16\n" | ||
615 | "3: tmll %2,0x00ff\n" | ||
616 | " jno 4f\n" | ||
617 | " aghi %0,8\n" | ||
618 | " srl %2,8\n" | ||
619 | "4: ngr %2,%1\n" | ||
620 | " ic %2,0(%2,%5)\n" | ||
621 | " algr %0,%2\n" | ||
622 | "5:" | ||
623 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
624 | : "a" (size), "a" (addr), "a" (&_zb_findmap), | ||
625 | "m" (*(addrtype *) addr) : "cc"); | ||
626 | return (res < size) ? res : size; | ||
627 | } | ||
628 | |||
629 | static inline unsigned long | ||
630 | find_first_bit(const unsigned long * addr, unsigned long size) | ||
631 | { | 674 | { |
632 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 675 | unsigned long bytes, bits; |
633 | unsigned long res, cmp, count; | ||
634 | 676 | ||
635 | if (!size) | 677 | if (!size) |
636 | return 0; | 678 | return 0; |
637 | asm volatile( | 679 | bytes = __ffs_word_loop(addr, size); |
638 | " slgr %1,%1\n" | 680 | bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes)); |
639 | " lgr %2,%3\n" | 681 | return (bits < size) ? bits : size; |
640 | " slgr %0,%0\n" | ||
641 | " aghi %2,63\n" | ||
642 | " srlg %2,%2,6\n" | ||
643 | "0: cg %1,0(%0,%4)\n" | ||
644 | " jne 1f\n" | ||
645 | " aghi %0,8\n" | ||
646 | " brct %2,0b\n" | ||
647 | " lgr %0,%3\n" | ||
648 | " j 5f\n" | ||
649 | "1: lg %2,0(%0,%4)\n" | ||
650 | " sllg %0,%0,3\n" | ||
651 | " clr %2,%1\n" | ||
652 | " jne 2f\n" | ||
653 | " aghi %0,32\n" | ||
654 | " srlg %2,%2,32\n" | ||
655 | "2: lghi %1,0xff\n" | ||
656 | " tmll %2,0xffff\n" | ||
657 | " jnz 3f\n" | ||
658 | " aghi %0,16\n" | ||
659 | " srl %2,16\n" | ||
660 | "3: tmll %2,0x00ff\n" | ||
661 | " jnz 4f\n" | ||
662 | " aghi %0,8\n" | ||
663 | " srl %2,8\n" | ||
664 | "4: ngr %2,%1\n" | ||
665 | " ic %2,0(%2,%5)\n" | ||
666 | " algr %0,%2\n" | ||
667 | "5:" | ||
668 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
669 | : "a" (size), "a" (addr), "a" (&_sb_findmap), | ||
670 | "m" (*(addrtype *) addr) : "cc"); | ||
671 | return (res < size) ? res : size; | ||
672 | } | 682 | } |
673 | 683 | ||
674 | #endif /* __s390x__ */ | 684 | /** |
675 | 685 | * find_next_zero_bit - find the first zero bit in a memory region | |
676 | static inline int | 686 | * @addr: The address to base the search on |
677 | find_next_zero_bit (const unsigned long * addr, unsigned long size, | 687 | * @offset: The bitnumber to start searching at |
678 | unsigned long offset) | 688 | * @size: The maximum size to search |
689 | */ | ||
690 | static inline int find_next_zero_bit (const unsigned long * addr, | ||
691 | unsigned long size, | ||
692 | unsigned long offset) | ||
679 | { | 693 | { |
680 | const unsigned long *p; | 694 | const unsigned long *p; |
681 | unsigned long bit, set; | 695 | unsigned long bit, set; |
@@ -688,10 +702,10 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, | |||
688 | p = addr + offset / __BITOPS_WORDSIZE; | 702 | p = addr + offset / __BITOPS_WORDSIZE; |
689 | if (bit) { | 703 | if (bit) { |
690 | /* | 704 | /* |
691 | * s390 version of ffz returns __BITOPS_WORDSIZE | 705 | * __ffz_word returns __BITOPS_WORDSIZE |
692 | * if no zero bit is present in the word. | 706 | * if no zero bit is present in the word. |
693 | */ | 707 | */ |
694 | set = ffz(*p >> bit) + bit; | 708 | set = __ffz_word(0, *p >> bit) + bit; |
695 | if (set >= size) | 709 | if (set >= size) |
696 | return size + offset; | 710 | return size + offset; |
697 | if (set < __BITOPS_WORDSIZE) | 711 | if (set < __BITOPS_WORDSIZE) |
@@ -703,9 +717,15 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, | |||
703 | return offset + find_first_zero_bit(p, size); | 717 | return offset + find_first_zero_bit(p, size); |
704 | } | 718 | } |
705 | 719 | ||
706 | static inline int | 720 | /** |
707 | find_next_bit (const unsigned long * addr, unsigned long size, | 721 | * find_next_bit - find the first set bit in a memory region |
708 | unsigned long offset) | 722 | * @addr: The address to base the search on |
723 | * @offset: The bitnumber to start searching at | ||
724 | * @size: The maximum size to search | ||
725 | */ | ||
726 | static inline int find_next_bit (const unsigned long * addr, | ||
727 | unsigned long size, | ||
728 | unsigned long offset) | ||
709 | { | 729 | { |
710 | const unsigned long *p; | 730 | const unsigned long *p; |
711 | unsigned long bit, set; | 731 | unsigned long bit, set; |
@@ -718,10 +738,10 @@ find_next_bit (const unsigned long * addr, unsigned long size, | |||
718 | p = addr + offset / __BITOPS_WORDSIZE; | 738 | p = addr + offset / __BITOPS_WORDSIZE; |
719 | if (bit) { | 739 | if (bit) { |
720 | /* | 740 | /* |
721 | * s390 version of __ffs returns __BITOPS_WORDSIZE | 741 | * __ffs_word returns __BITOPS_WORDSIZE |
722 | * if no one bit is present in the word. | 742 | * if no one bit is present in the word. |
723 | */ | 743 | */ |
724 | set = __ffs(*p & (~0UL << bit)); | 744 | set = __ffs_word(0, *p & (~0UL << bit)); |
725 | if (set >= size) | 745 | if (set >= size) |
726 | return size + offset; | 746 | return size + offset; |
727 | if (set < __BITOPS_WORDSIZE) | 747 | if (set < __BITOPS_WORDSIZE) |
@@ -744,8 +764,6 @@ static inline int sched_find_first_bit(unsigned long *b) | |||
744 | return find_first_bit(b, 140); | 764 | return find_first_bit(b, 140); |
745 | } | 765 | } |
746 | 766 | ||
747 | #include <asm-generic/bitops/ffs.h> | ||
748 | |||
749 | #include <asm-generic/bitops/fls.h> | 767 | #include <asm-generic/bitops/fls.h> |
750 | #include <asm-generic/bitops/fls64.h> | 768 | #include <asm-generic/bitops/fls64.h> |
751 | 769 | ||
@@ -775,105 +793,22 @@ static inline int sched_find_first_bit(unsigned long *b) | |||
775 | #define ext2_find_next_bit(addr, size, off) \ | 793 | #define ext2_find_next_bit(addr, size, off) \ |
776 | generic_find_next_le_bit((unsigned long *)(addr), (size), (off)) | 794 | generic_find_next_le_bit((unsigned long *)(addr), (size), (off)) |
777 | 795 | ||
778 | #ifndef __s390x__ | 796 | static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size) |
779 | |||
780 | static inline int | ||
781 | ext2_find_first_zero_bit(void *vaddr, unsigned int size) | ||
782 | { | 797 | { |
783 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 798 | unsigned long bytes, bits; |
784 | unsigned long cmp, count; | ||
785 | unsigned int res; | ||
786 | 799 | ||
787 | if (!size) | 800 | if (!size) |
788 | return 0; | 801 | return 0; |
789 | asm volatile( | 802 | bytes = __ffz_word_loop(vaddr, size); |
790 | " lhi %1,-1\n" | 803 | bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes)); |
791 | " lr %2,%3\n" | 804 | return (bits < size) ? bits : size; |
792 | " ahi %2,31\n" | ||
793 | " srl %2,5\n" | ||
794 | " slr %0,%0\n" | ||
795 | "0: cl %1,0(%0,%4)\n" | ||
796 | " jne 1f\n" | ||
797 | " ahi %0,4\n" | ||
798 | " brct %2,0b\n" | ||
799 | " lr %0,%3\n" | ||
800 | " j 4f\n" | ||
801 | "1: l %2,0(%0,%4)\n" | ||
802 | " sll %0,3\n" | ||
803 | " ahi %0,24\n" | ||
804 | " lhi %1,0xff\n" | ||
805 | " tmh %2,0xffff\n" | ||
806 | " jo 2f\n" | ||
807 | " ahi %0,-16\n" | ||
808 | " srl %2,16\n" | ||
809 | "2: tml %2,0xff00\n" | ||
810 | " jo 3f\n" | ||
811 | " ahi %0,-8\n" | ||
812 | " srl %2,8\n" | ||
813 | "3: nr %2,%1\n" | ||
814 | " ic %2,0(%2,%5)\n" | ||
815 | " alr %0,%2\n" | ||
816 | "4:" | ||
817 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
818 | : "a" (size), "a" (vaddr), "a" (&_zb_findmap), | ||
819 | "m" (*(addrtype *) vaddr) : "cc"); | ||
820 | return (res < size) ? res : size; | ||
821 | } | 805 | } |
822 | 806 | ||
823 | #else /* __s390x__ */ | 807 | static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size, |
824 | 808 | unsigned long offset) | |
825 | static inline unsigned long | ||
826 | ext2_find_first_zero_bit(void *vaddr, unsigned long size) | ||
827 | { | ||
828 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | ||
829 | unsigned long res, cmp, count; | ||
830 | |||
831 | if (!size) | ||
832 | return 0; | ||
833 | asm volatile( | ||
834 | " lghi %1,-1\n" | ||
835 | " lgr %2,%3\n" | ||
836 | " aghi %2,63\n" | ||
837 | " srlg %2,%2,6\n" | ||
838 | " slgr %0,%0\n" | ||
839 | "0: clg %1,0(%0,%4)\n" | ||
840 | " jne 1f\n" | ||
841 | " aghi %0,8\n" | ||
842 | " brct %2,0b\n" | ||
843 | " lgr %0,%3\n" | ||
844 | " j 5f\n" | ||
845 | "1: cl %1,0(%0,%4)\n" | ||
846 | " jne 2f\n" | ||
847 | " aghi %0,4\n" | ||
848 | "2: l %2,0(%0,%4)\n" | ||
849 | " sllg %0,%0,3\n" | ||
850 | " aghi %0,24\n" | ||
851 | " lghi %1,0xff\n" | ||
852 | " tmlh %2,0xffff\n" | ||
853 | " jo 3f\n" | ||
854 | " aghi %0,-16\n" | ||
855 | " srl %2,16\n" | ||
856 | "3: tmll %2,0xff00\n" | ||
857 | " jo 4f\n" | ||
858 | " aghi %0,-8\n" | ||
859 | " srl %2,8\n" | ||
860 | "4: ngr %2,%1\n" | ||
861 | " ic %2,0(%2,%5)\n" | ||
862 | " algr %0,%2\n" | ||
863 | "5:" | ||
864 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
865 | : "a" (size), "a" (vaddr), "a" (&_zb_findmap), | ||
866 | "m" (*(addrtype *) vaddr) : "cc"); | ||
867 | return (res < size) ? res : size; | ||
868 | } | ||
869 | |||
870 | #endif /* __s390x__ */ | ||
871 | |||
872 | static inline int | ||
873 | ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) | ||
874 | { | 809 | { |
875 | unsigned long *addr = vaddr, *p; | 810 | unsigned long *addr = vaddr, *p; |
876 | unsigned long word, bit, set; | 811 | unsigned long bit, set; |
877 | 812 | ||
878 | if (offset >= size) | 813 | if (offset >= size) |
879 | return size; | 814 | return size; |
@@ -882,23 +817,11 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) | |||
882 | size -= offset; | 817 | size -= offset; |
883 | p = addr + offset / __BITOPS_WORDSIZE; | 818 | p = addr + offset / __BITOPS_WORDSIZE; |
884 | if (bit) { | 819 | if (bit) { |
885 | #ifndef __s390x__ | ||
886 | asm volatile( | ||
887 | " ic %0,0(%1)\n" | ||
888 | " icm %0,2,1(%1)\n" | ||
889 | " icm %0,4,2(%1)\n" | ||
890 | " icm %0,8,3(%1)" | ||
891 | : "=&a" (word) : "a" (p), "m" (*p) : "cc"); | ||
892 | #else | ||
893 | asm volatile( | ||
894 | " lrvg %0,%1" | ||
895 | : "=a" (word) : "m" (*p) ); | ||
896 | #endif | ||
897 | /* | 820 | /* |
898 | * s390 version of ffz returns __BITOPS_WORDSIZE | 821 | * s390 version of ffz returns __BITOPS_WORDSIZE |
899 | * if no zero bit is present in the word. | 822 | * if no zero bit is present in the word. |
900 | */ | 823 | */ |
901 | set = ffz(word >> bit) + bit; | 824 | set = ffz(__load_ulong_le(p, 0) >> bit) + bit; |
902 | if (set >= size) | 825 | if (set >= size) |
903 | return size + offset; | 826 | return size + offset; |
904 | if (set < __BITOPS_WORDSIZE) | 827 | if (set < __BITOPS_WORDSIZE) |