diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-12-19 16:51:57 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:58:33 -0500 |
commit | 3ebbbb56a162b8f9b9a77bc7810b9d4e0868e039 (patch) | |
tree | 0d4a7c60d8cdee68878a97bbc4b9d358396f7ba3 /drivers/net/wireless/b43/main.c | |
parent | e808e586b77a10949e209f8a00cb8bf27e51df12 (diff) |
b43: Use 64bit atomic register access for TSF
On modern b43 devices with core rev >=3, the hardware guarantees us an
atomic 64bit read/write of the TSF, if we access the lower 32bits first.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 89 |
1 files changed, 20 insertions, 69 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index dad0781b4b67..ba989ae132a7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -526,52 +526,20 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) | |||
526 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); | 526 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); |
527 | } | 527 | } |
528 | 528 | ||
529 | void b43_tsf_read(struct b43_wldev *dev, u64 * tsf) | 529 | void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) |
530 | { | 530 | { |
531 | /* We need to be careful. As we read the TSF from multiple | 531 | u32 low, high; |
532 | * registers, we should take care of register overflows. | ||
533 | * In theory, the whole tsf read process should be atomic. | ||
534 | * We try to be atomic here, by restaring the read process, | ||
535 | * if any of the high registers changed (overflew). | ||
536 | */ | ||
537 | if (dev->dev->id.revision >= 3) { | ||
538 | u32 low, high, high2; | ||
539 | |||
540 | do { | ||
541 | high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); | ||
542 | low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW); | ||
543 | high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); | ||
544 | } while (unlikely(high != high2)); | ||
545 | |||
546 | *tsf = high; | ||
547 | *tsf <<= 32; | ||
548 | *tsf |= low; | ||
549 | } else { | ||
550 | u64 tmp; | ||
551 | u16 v0, v1, v2, v3; | ||
552 | u16 test1, test2, test3; | ||
553 | 532 | ||
554 | do { | 533 | B43_WARN_ON(dev->dev->id.revision < 3); |
555 | v3 = b43_read16(dev, B43_MMIO_TSF_3); | ||
556 | v2 = b43_read16(dev, B43_MMIO_TSF_2); | ||
557 | v1 = b43_read16(dev, B43_MMIO_TSF_1); | ||
558 | v0 = b43_read16(dev, B43_MMIO_TSF_0); | ||
559 | 534 | ||
560 | test3 = b43_read16(dev, B43_MMIO_TSF_3); | 535 | /* The hardware guarantees us an atomic read, if we |
561 | test2 = b43_read16(dev, B43_MMIO_TSF_2); | 536 | * read the low register first. */ |
562 | test1 = b43_read16(dev, B43_MMIO_TSF_1); | 537 | low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW); |
563 | } while (v3 != test3 || v2 != test2 || v1 != test1); | 538 | high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); |
564 | 539 | ||
565 | *tsf = v3; | 540 | *tsf = high; |
566 | *tsf <<= 48; | 541 | *tsf <<= 32; |
567 | tmp = v2; | 542 | *tsf |= low; |
568 | tmp <<= 32; | ||
569 | *tsf |= tmp; | ||
570 | tmp = v1; | ||
571 | tmp <<= 16; | ||
572 | *tsf |= tmp; | ||
573 | *tsf |= v0; | ||
574 | } | ||
575 | } | 543 | } |
576 | 544 | ||
577 | static void b43_time_lock(struct b43_wldev *dev) | 545 | static void b43_time_lock(struct b43_wldev *dev) |
@@ -598,35 +566,18 @@ static void b43_time_unlock(struct b43_wldev *dev) | |||
598 | 566 | ||
599 | static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf) | 567 | static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf) |
600 | { | 568 | { |
601 | /* Be careful with the in-progress timer. | 569 | u32 low, high; |
602 | * First zero out the low register, so we have a full | ||
603 | * register-overflow duration to complete the operation. | ||
604 | */ | ||
605 | if (dev->dev->id.revision >= 3) { | ||
606 | u32 lo = (tsf & 0x00000000FFFFFFFFULL); | ||
607 | u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; | ||
608 | 570 | ||
609 | b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0); | 571 | B43_WARN_ON(dev->dev->id.revision < 3); |
610 | mmiowb(); | ||
611 | b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi); | ||
612 | mmiowb(); | ||
613 | b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo); | ||
614 | } else { | ||
615 | u16 v0 = (tsf & 0x000000000000FFFFULL); | ||
616 | u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; | ||
617 | u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; | ||
618 | u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; | ||
619 | 572 | ||
620 | b43_write16(dev, B43_MMIO_TSF_0, 0); | 573 | low = tsf; |
621 | mmiowb(); | 574 | high = (tsf >> 32); |
622 | b43_write16(dev, B43_MMIO_TSF_3, v3); | 575 | /* The hardware guarantees us an atomic write, if we |
623 | mmiowb(); | 576 | * write the low register first. */ |
624 | b43_write16(dev, B43_MMIO_TSF_2, v2); | 577 | b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, low); |
625 | mmiowb(); | 578 | mmiowb(); |
626 | b43_write16(dev, B43_MMIO_TSF_1, v1); | 579 | b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, high); |
627 | mmiowb(); | 580 | mmiowb(); |
628 | b43_write16(dev, B43_MMIO_TSF_0, v0); | ||
629 | } | ||
630 | } | 581 | } |
631 | 582 | ||
632 | void b43_tsf_write(struct b43_wldev *dev, u64 tsf) | 583 | void b43_tsf_write(struct b43_wldev *dev, u64 tsf) |