diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 15:19:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 15:19:34 -0500 |
commit | 61bd5e5683244a564ecfe31c73575ee0bc708ccc (patch) | |
tree | 6df40bc0d8bd3e27588349fe8b469286fd48bdf9 /drivers | |
parent | bccd17294a26b67a8a19aaa120e3eeaa7da49281 (diff) |
brcmsmac: fix reading of PCI sprom contents
It appears that you can only read the sprom contents with aligned 16-bit
reads: anything else causes at least some versions of the broadcom
chipset to abort the PCI transaction, returning 0xff.
This apparently doesn't trigger very often, because most setups don't
use an external srom chip, and the OTP sprom loading doesn't have this
issue. But at least the current 11" Macbook Air does trigger it, and
wireless communications were broken as a result.
Acked-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/srom.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c index 61092156755e..563743643038 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c | |||
@@ -764,6 +764,22 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) | |||
764 | } | 764 | } |
765 | 765 | ||
766 | /* | 766 | /* |
767 | * The crc check is done on a little-endian array, we need | ||
768 | * to switch the bytes around before checking crc (and | ||
769 | * then switch it back). | ||
770 | */ | ||
771 | static int do_crc_check(u16 *buf, unsigned nwords) | ||
772 | { | ||
773 | u8 crc; | ||
774 | |||
775 | cpu_to_le16_buf(buf, nwords); | ||
776 | crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE); | ||
777 | le16_to_cpu_buf(buf, nwords); | ||
778 | |||
779 | return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table); | ||
780 | } | ||
781 | |||
782 | /* | ||
767 | * Read in and validate sprom. | 783 | * Read in and validate sprom. |
768 | * Return 0 on success, nonzero on error. | 784 | * Return 0 on success, nonzero on error. |
769 | */ | 785 | */ |
@@ -772,8 +788,6 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc) | |||
772 | { | 788 | { |
773 | int err = 0; | 789 | int err = 0; |
774 | uint i; | 790 | uint i; |
775 | u8 *bbuf = (u8 *)buf; /* byte buffer */ | ||
776 | uint nbytes = nwords << 1; | ||
777 | struct bcma_device *core; | 791 | struct bcma_device *core; |
778 | uint sprom_offset; | 792 | uint sprom_offset; |
779 | 793 | ||
@@ -786,9 +800,9 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc) | |||
786 | sprom_offset = CHIPCREGOFFS(sromotp); | 800 | sprom_offset = CHIPCREGOFFS(sromotp); |
787 | } | 801 | } |
788 | 802 | ||
789 | /* read the sprom in bytes */ | 803 | /* read the sprom */ |
790 | for (i = 0; i < nbytes; i++) | 804 | for (i = 0; i < nwords; i++) |
791 | bbuf[i] = bcma_read8(core, sprom_offset+i); | 805 | buf[i] = bcma_read16(core, sprom_offset+i*2); |
792 | 806 | ||
793 | if (buf[0] == 0xffff) | 807 | if (buf[0] == 0xffff) |
794 | /* | 808 | /* |
@@ -798,13 +812,8 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc) | |||
798 | */ | 812 | */ |
799 | return -ENODATA; | 813 | return -ENODATA; |
800 | 814 | ||
801 | if (check_crc && | 815 | if (check_crc && !do_crc_check(buf, nwords)) |
802 | crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) != | ||
803 | CRC8_GOOD_VALUE(brcms_srom_crc8_table)) | ||
804 | err = -EIO; | 816 | err = -EIO; |
805 | else | ||
806 | /* now correct the endianness of the byte array */ | ||
807 | le16_to_cpu_buf(buf, nwords); | ||
808 | 817 | ||
809 | return err; | 818 | return err; |
810 | } | 819 | } |