aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-01-21 13:55:09 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:10:46 -0500
commit61cb5dd6d1c81fbb5629f60db4e2a7faa7124b7a (patch)
tree5f0d0c7f1e7830a8149c94012feb80c160cb0b6d /drivers/net/wireless
parent71ebb4aac87e4a1504a155084d658d0a92ac63fb (diff)
b43: Fix firmware caching
We must also store the ID string (filename) for the cached firmware blobs and verify that we really have the right firmware cached before using it. If we don't have the right fw cached, we must free it and request the correct blobs. This fixes bandswitch on A/B/G multi-PHY devices. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/b43/b43.h15
-rw-r--r--drivers/net/wireless/b43/main.c229
2 files changed, 134 insertions, 110 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c7eea30aa949..32a24f5c4fa6 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -665,16 +665,23 @@ struct b43_wl {
665 bool beacon1_uploaded; 665 bool beacon1_uploaded;
666}; 666};
667 667
668/* In-memory representation of a cached microcode file. */
669struct b43_firmware_file {
670 const char *filename;
671 const struct firmware *data;
672};
673
668/* Pointers to the firmware data and meta information about it. */ 674/* Pointers to the firmware data and meta information about it. */
669struct b43_firmware { 675struct b43_firmware {
670 /* Microcode */ 676 /* Microcode */
671 const struct firmware *ucode; 677 struct b43_firmware_file ucode;
672 /* PCM code */ 678 /* PCM code */
673 const struct firmware *pcm; 679 struct b43_firmware_file pcm;
674 /* Initial MMIO values for the firmware */ 680 /* Initial MMIO values for the firmware */
675 const struct firmware *initvals; 681 struct b43_firmware_file initvals;
676 /* Initial MMIO values for the firmware, band-specific */ 682 /* Initial MMIO values for the firmware, band-specific */
677 const struct firmware *initvals_band; 683 struct b43_firmware_file initvals_band;
684
678 /* Firmware revision */ 685 /* Firmware revision */
679 u16 rev; 686 u16 rev;
680 /* Firmware patchlevel */ 687 /* Firmware patchlevel */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 0d9824c7e28f..2e563662c9a2 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1557,16 +1557,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
1557 return ret; 1557 return ret;
1558} 1558}
1559 1559
1560static void do_release_fw(struct b43_firmware_file *fw)
1561{
1562 release_firmware(fw->data);
1563 fw->data = NULL;
1564 fw->filename = NULL;
1565}
1566
1560static void b43_release_firmware(struct b43_wldev *dev) 1567static void b43_release_firmware(struct b43_wldev *dev)
1561{ 1568{
1562 release_firmware(dev->fw.ucode); 1569 do_release_fw(&dev->fw.ucode);
1563 dev->fw.ucode = NULL; 1570 do_release_fw(&dev->fw.pcm);
1564 release_firmware(dev->fw.pcm); 1571 do_release_fw(&dev->fw.initvals);
1565 dev->fw.pcm = NULL; 1572 do_release_fw(&dev->fw.initvals_band);
1566 release_firmware(dev->fw.initvals);
1567 dev->fw.initvals = NULL;
1568 release_firmware(dev->fw.initvals_band);
1569 dev->fw.initvals_band = NULL;
1570} 1573}
1571 1574
1572static void b43_print_fw_helptext(struct b43_wl *wl, bool error) 1575static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
@@ -1584,33 +1587,43 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
1584 1587
1585static int do_request_fw(struct b43_wldev *dev, 1588static int do_request_fw(struct b43_wldev *dev,
1586 const char *name, 1589 const char *name,
1587 const struct firmware **fw) 1590 struct b43_firmware_file *fw)
1588{ 1591{
1589 char path[sizeof(modparam_fwpostfix) + 32]; 1592 char path[sizeof(modparam_fwpostfix) + 32];
1593 const struct firmware *blob;
1590 struct b43_fw_header *hdr; 1594 struct b43_fw_header *hdr;
1591 u32 size; 1595 u32 size;
1592 int err; 1596 int err;
1593 1597
1594 if (!name) 1598 if (!name) {
1599 /* Don't fetch anything. Free possibly cached firmware. */
1600 do_release_fw(fw);
1595 return 0; 1601 return 0;
1602 }
1603 if (fw->filename) {
1604 if (strcmp(fw->filename, name) == 0)
1605 return 0; /* Already have this fw. */
1606 /* Free the cached firmware first. */
1607 do_release_fw(fw);
1608 }
1596 1609
1597 snprintf(path, ARRAY_SIZE(path), 1610 snprintf(path, ARRAY_SIZE(path),
1598 "b43%s/%s.fw", 1611 "b43%s/%s.fw",
1599 modparam_fwpostfix, name); 1612 modparam_fwpostfix, name);
1600 err = request_firmware(fw, path, dev->dev->dev); 1613 err = request_firmware(&blob, path, dev->dev->dev);
1601 if (err) { 1614 if (err) {
1602 b43err(dev->wl, "Firmware file \"%s\" not found " 1615 b43err(dev->wl, "Firmware file \"%s\" not found "
1603 "or load failed.\n", path); 1616 "or load failed.\n", path);
1604 return err; 1617 return err;
1605 } 1618 }
1606 if ((*fw)->size < sizeof(struct b43_fw_header)) 1619 if (blob->size < sizeof(struct b43_fw_header))
1607 goto err_format; 1620 goto err_format;
1608 hdr = (struct b43_fw_header *)((*fw)->data); 1621 hdr = (struct b43_fw_header *)(blob->data);
1609 switch (hdr->type) { 1622 switch (hdr->type) {
1610 case B43_FW_TYPE_UCODE: 1623 case B43_FW_TYPE_UCODE:
1611 case B43_FW_TYPE_PCM: 1624 case B43_FW_TYPE_PCM:
1612 size = be32_to_cpu(hdr->size); 1625 size = be32_to_cpu(hdr->size);
1613 if (size != (*fw)->size - sizeof(struct b43_fw_header)) 1626 if (size != blob->size - sizeof(struct b43_fw_header))
1614 goto err_format; 1627 goto err_format;
1615 /* fallthrough */ 1628 /* fallthrough */
1616 case B43_FW_TYPE_IV: 1629 case B43_FW_TYPE_IV:
@@ -1621,10 +1634,15 @@ static int do_request_fw(struct b43_wldev *dev,
1621 goto err_format; 1634 goto err_format;
1622 } 1635 }
1623 1636
1624 return err; 1637 fw->data = blob;
1638 fw->filename = name;
1639
1640 return 0;
1625 1641
1626err_format: 1642err_format:
1627 b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); 1643 b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
1644 release_firmware(blob);
1645
1628 return -EPROTO; 1646 return -EPROTO;
1629} 1647}
1630 1648
@@ -1636,97 +1654,96 @@ static int b43_request_firmware(struct b43_wldev *dev)
1636 u32 tmshigh; 1654 u32 tmshigh;
1637 int err; 1655 int err;
1638 1656
1657 /* Get microcode */
1639 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); 1658 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
1640 if (!fw->ucode) { 1659 if ((rev >= 5) && (rev <= 10))
1660 filename = "ucode5";
1661 else if ((rev >= 11) && (rev <= 12))
1662 filename = "ucode11";
1663 else if (rev >= 13)
1664 filename = "ucode13";
1665 else
1666 goto err_no_ucode;
1667 err = do_request_fw(dev, filename, &fw->ucode);
1668 if (err)
1669 goto err_load;
1670
1671 /* Get PCM code */
1672 if ((rev >= 5) && (rev <= 10))
1673 filename = "pcm5";
1674 else if (rev >= 11)
1675 filename = NULL;
1676 else
1677 goto err_no_pcm;
1678 err = do_request_fw(dev, filename, &fw->pcm);
1679 if (err)
1680 goto err_load;
1681
1682 /* Get initvals */
1683 switch (dev->phy.type) {
1684 case B43_PHYTYPE_A:
1685 if ((rev >= 5) && (rev <= 10)) {
1686 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
1687 filename = "a0g1initvals5";
1688 else
1689 filename = "a0g0initvals5";
1690 } else
1691 goto err_no_initvals;
1692 break;
1693 case B43_PHYTYPE_G:
1641 if ((rev >= 5) && (rev <= 10)) 1694 if ((rev >= 5) && (rev <= 10))
1642 filename = "ucode5"; 1695 filename = "b0g0initvals5";
1643 else if ((rev >= 11) && (rev <= 12))
1644 filename = "ucode11";
1645 else if (rev >= 13) 1696 else if (rev >= 13)
1646 filename = "ucode13"; 1697 filename = "lp0initvals13";
1647 else 1698 else
1648 goto err_no_ucode; 1699 goto err_no_initvals;
1649 err = do_request_fw(dev, filename, &fw->ucode); 1700 break;
1650 if (err) 1701 case B43_PHYTYPE_N:
1651 goto err_load; 1702 if ((rev >= 11) && (rev <= 12))
1703 filename = "n0initvals11";
1704 else
1705 goto err_no_initvals;
1706 break;
1707 default:
1708 goto err_no_initvals;
1652 } 1709 }
1653 if (!fw->pcm) { 1710 err = do_request_fw(dev, filename, &fw->initvals);
1711 if (err)
1712 goto err_load;
1713
1714 /* Get bandswitch initvals */
1715 switch (dev->phy.type) {
1716 case B43_PHYTYPE_A:
1717 if ((rev >= 5) && (rev <= 10)) {
1718 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
1719 filename = "a0g1bsinitvals5";
1720 else
1721 filename = "a0g0bsinitvals5";
1722 } else if (rev >= 11)
1723 filename = NULL;
1724 else
1725 goto err_no_initvals;
1726 break;
1727 case B43_PHYTYPE_G:
1654 if ((rev >= 5) && (rev <= 10)) 1728 if ((rev >= 5) && (rev <= 10))
1655 filename = "pcm5"; 1729 filename = "b0g0bsinitvals5";
1656 else if (rev >= 11) 1730 else if (rev >= 11)
1657 filename = NULL; 1731 filename = NULL;
1658 else 1732 else
1659 goto err_no_pcm;
1660 err = do_request_fw(dev, filename, &fw->pcm);
1661 if (err)
1662 goto err_load;
1663 }
1664 if (!fw->initvals) {
1665 switch (dev->phy.type) {
1666 case B43_PHYTYPE_A:
1667 if ((rev >= 5) && (rev <= 10)) {
1668 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
1669 filename = "a0g1initvals5";
1670 else
1671 filename = "a0g0initvals5";
1672 } else
1673 goto err_no_initvals;
1674 break;
1675 case B43_PHYTYPE_G:
1676 if ((rev >= 5) && (rev <= 10))
1677 filename = "b0g0initvals5";
1678 else if (rev >= 13)
1679 filename = "lp0initvals13";
1680 else
1681 goto err_no_initvals;
1682 break;
1683 case B43_PHYTYPE_N:
1684 if ((rev >= 11) && (rev <= 12))
1685 filename = "n0initvals11";
1686 else
1687 goto err_no_initvals;
1688 break;
1689 default:
1690 goto err_no_initvals; 1733 goto err_no_initvals;
1691 } 1734 break;
1692 err = do_request_fw(dev, filename, &fw->initvals); 1735 case B43_PHYTYPE_N:
1693 if (err) 1736 if ((rev >= 11) && (rev <= 12))
1694 goto err_load; 1737 filename = "n0bsinitvals11";
1695 } 1738 else
1696 if (!fw->initvals_band) {
1697 switch (dev->phy.type) {
1698 case B43_PHYTYPE_A:
1699 if ((rev >= 5) && (rev <= 10)) {
1700 if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
1701 filename = "a0g1bsinitvals5";
1702 else
1703 filename = "a0g0bsinitvals5";
1704 } else if (rev >= 11)
1705 filename = NULL;
1706 else
1707 goto err_no_initvals;
1708 break;
1709 case B43_PHYTYPE_G:
1710 if ((rev >= 5) && (rev <= 10))
1711 filename = "b0g0bsinitvals5";
1712 else if (rev >= 11)
1713 filename = NULL;
1714 else
1715 goto err_no_initvals;
1716 break;
1717 case B43_PHYTYPE_N:
1718 if ((rev >= 11) && (rev <= 12))
1719 filename = "n0bsinitvals11";
1720 else
1721 goto err_no_initvals;
1722 break;
1723 default:
1724 goto err_no_initvals; 1739 goto err_no_initvals;
1725 } 1740 break;
1726 err = do_request_fw(dev, filename, &fw->initvals_band); 1741 default:
1727 if (err) 1742 goto err_no_initvals;
1728 goto err_load;
1729 } 1743 }
1744 err = do_request_fw(dev, filename, &fw->initvals_band);
1745 if (err)
1746 goto err_load;
1730 1747
1731 return 0; 1748 return 0;
1732 1749
@@ -1765,18 +1782,18 @@ static int b43_upload_microcode(struct b43_wldev *dev)
1765 int err = 0; 1782 int err = 0;
1766 1783
1767 /* Upload Microcode. */ 1784 /* Upload Microcode. */
1768 data = (__be32 *) (dev->fw.ucode->data + hdr_len); 1785 data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
1769 len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); 1786 len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
1770 b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); 1787 b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
1771 for (i = 0; i < len; i++) { 1788 for (i = 0; i < len; i++) {
1772 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); 1789 b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
1773 udelay(10); 1790 udelay(10);
1774 } 1791 }
1775 1792
1776 if (dev->fw.pcm) { 1793 if (dev->fw.pcm.data) {
1777 /* Upload PCM data. */ 1794 /* Upload PCM data. */
1778 data = (__be32 *) (dev->fw.pcm->data + hdr_len); 1795 data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
1779 len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); 1796 len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
1780 b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); 1797 b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
1781 b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); 1798 b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
1782 /* No need for autoinc bit in SHM_HW */ 1799 /* No need for autoinc bit in SHM_HW */
@@ -1913,19 +1930,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
1913 size_t count; 1930 size_t count;
1914 int err; 1931 int err;
1915 1932
1916 hdr = (const struct b43_fw_header *)(fw->initvals->data); 1933 hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
1917 ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); 1934 ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
1918 count = be32_to_cpu(hdr->size); 1935 count = be32_to_cpu(hdr->size);
1919 err = b43_write_initvals(dev, ivals, count, 1936 err = b43_write_initvals(dev, ivals, count,
1920 fw->initvals->size - hdr_len); 1937 fw->initvals.data->size - hdr_len);
1921 if (err) 1938 if (err)
1922 goto out; 1939 goto out;
1923 if (fw->initvals_band) { 1940 if (fw->initvals_band.data) {
1924 hdr = (const struct b43_fw_header *)(fw->initvals_band->data); 1941 hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
1925 ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); 1942 ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
1926 count = be32_to_cpu(hdr->size); 1943 count = be32_to_cpu(hdr->size);
1927 err = b43_write_initvals(dev, ivals, count, 1944 err = b43_write_initvals(dev, ivals, count,
1928 fw->initvals_band->size - hdr_len); 1945 fw->initvals_band.data->size - hdr_len);
1929 if (err) 1946 if (err)
1930 goto out; 1947 goto out;
1931 } 1948 }