diff options
author | Michael Buesch <mb@bu3sch.de> | 2006-07-08 16:02:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-07-27 18:19:18 -0400 |
commit | 58e5528ee464d38040b9489e10033c9387a10d56 (patch) | |
tree | 58023ac8bf79757e37a4d05ce7fa63fb3f2388b9 /drivers/net/wireless/bcm43xx/bcm43xx_main.c | |
parent | 3234faa8abe0c3d6da12cc4a38ce790134c92564 (diff) |
[PATCH] bcm43xx: init routine rewrite
Rewrite of the bcm43xx initialization routines.
This fixes several issues:
* up-down-up-down-up... stale data issue
(May fix some DHCP issues)
* Fix the init vs IRQ handler race (and remove the workaround)
* Fix init for cards with multiple cores (APHY)
As softmac has no internal PHY handling (unlike dscape),
this adds the file "phymode" to sysfs.
The active PHY can be selected by writing either a, b or g
to this file. Current PHY can be determined by reading from it.
* Fix the controller restart code.
Controller restart can now also be triggered through
echo 1 > /debug/bcm43xx/ethX/restart
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_main.c')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 634 |
1 files changed, 367 insertions, 267 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 1c04722edaa0..e5829056cc3f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) | |||
509 | } | 509 | } |
510 | 510 | ||
511 | /* Make sure we don't receive more data from the device. */ | 511 | /* Make sure we don't receive more data from the device. */ |
512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) | 512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm) |
513 | { | 513 | { |
514 | unsigned long flags; | 514 | unsigned long flags; |
515 | u32 old; | ||
516 | 515 | ||
517 | spin_lock_irqsave(&bcm->irq_lock, flags); | 516 | spin_lock_irqsave(&bcm->irq_lock, flags); |
518 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { | 517 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { |
519 | spin_unlock_irqrestore(&bcm->irq_lock, flags); | 518 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
520 | return -EBUSY; | 519 | return -EBUSY; |
521 | } | 520 | } |
522 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 521 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
523 | spin_unlock_irqrestore(&bcm->irq_lock, flags); | 522 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
524 | bcm43xx_synchronize_irq(bcm); | 523 | bcm43xx_synchronize_irq(bcm); |
525 | 524 | ||
526 | if (oldstate) | ||
527 | *oldstate = old; | ||
528 | |||
529 | return 0; | 525 | return 0; |
530 | } | 526 | } |
531 | 527 | ||
@@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) | |||
537 | u16 manufact; | 533 | u16 manufact; |
538 | u16 version; | 534 | u16 version; |
539 | u8 revision; | 535 | u8 revision; |
540 | s8 i; | ||
541 | 536 | ||
542 | if (bcm->chip_id == 0x4317) { | 537 | if (bcm->chip_id == 0x4317) { |
543 | if (bcm->chip_rev == 0x00) | 538 | if (bcm->chip_rev == 0x00) |
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) | |||
580 | radio->version = version; | 575 | radio->version = version; |
581 | radio->revision = revision; | 576 | radio->revision = revision; |
582 | 577 | ||
583 | /* Set default attenuation values. */ | ||
584 | radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); | ||
585 | radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); | ||
586 | radio->txctl1 = bcm43xx_default_txctl1(bcm); | ||
587 | radio->txctl2 = 0xFFFF; | ||
588 | if (phy->type == BCM43xx_PHYTYPE_A) | 578 | if (phy->type == BCM43xx_PHYTYPE_A) |
589 | radio->txpower_desired = bcm->sprom.maxpower_aphy; | 579 | radio->txpower_desired = bcm->sprom.maxpower_aphy; |
590 | else | 580 | else |
591 | radio->txpower_desired = bcm->sprom.maxpower_bgphy; | 581 | radio->txpower_desired = bcm->sprom.maxpower_bgphy; |
592 | 582 | ||
593 | /* Initialize the in-memory nrssi Lookup Table. */ | ||
594 | for (i = 0; i < 64; i++) | ||
595 | radio->nrssi_lt[i] = i; | ||
596 | |||
597 | return 0; | 583 | return 0; |
598 | 584 | ||
599 | err_unsupported_radio: | 585 | err_unsupported_radio: |
@@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne | |||
1250 | goto out; | 1236 | goto out; |
1251 | 1237 | ||
1252 | bcm->current_core = new_core; | 1238 | bcm->current_core = new_core; |
1253 | bcm->current_80211_core_idx = -1; | ||
1254 | if (new_core->id == BCM43xx_COREID_80211) | ||
1255 | bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); | ||
1256 | |||
1257 | out: | 1239 | out: |
1258 | return err; | 1240 | return err; |
1259 | } | 1241 | } |
@@ -1423,43 +1405,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) | |||
1423 | bcm43xx_core_disable(bcm, 0); | 1405 | bcm43xx_core_disable(bcm, 0); |
1424 | } | 1406 | } |
1425 | 1407 | ||
1426 | /* Mark the current 80211 core inactive. | 1408 | /* Mark the current 80211 core inactive. */ |
1427 | * "active_80211_core" is the other 80211 core, which is used. | 1409 | static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm) |
1428 | */ | ||
1429 | static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, | ||
1430 | struct bcm43xx_coreinfo *active_80211_core) | ||
1431 | { | 1410 | { |
1432 | u32 sbtmstatelow; | 1411 | u32 sbtmstatelow; |
1433 | struct bcm43xx_coreinfo *old_core; | ||
1434 | int err = 0; | ||
1435 | 1412 | ||
1436 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 1413 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
1437 | bcm43xx_radio_turn_off(bcm); | 1414 | bcm43xx_radio_turn_off(bcm); |
1438 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 1415 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
1439 | sbtmstatelow &= ~0x200a0000; | 1416 | sbtmstatelow &= 0xDFF5FFFF; |
1440 | sbtmstatelow |= 0xa0000; | 1417 | sbtmstatelow |= 0x000A0000; |
1441 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | 1418 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
1442 | udelay(1); | 1419 | udelay(1); |
1443 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 1420 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
1444 | sbtmstatelow &= ~0xa0000; | 1421 | sbtmstatelow &= 0xFFF5FFFF; |
1445 | sbtmstatelow |= 0x80000; | 1422 | sbtmstatelow |= 0x00080000; |
1446 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | 1423 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
1447 | udelay(1); | 1424 | udelay(1); |
1448 | |||
1449 | if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { | ||
1450 | old_core = bcm->current_core; | ||
1451 | err = bcm43xx_switch_core(bcm, active_80211_core); | ||
1452 | if (err) | ||
1453 | goto out; | ||
1454 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | ||
1455 | sbtmstatelow &= ~0x20000000; | ||
1456 | sbtmstatelow |= 0x20000000; | ||
1457 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | ||
1458 | err = bcm43xx_switch_core(bcm, old_core); | ||
1459 | } | ||
1460 | |||
1461 | out: | ||
1462 | return err; | ||
1463 | } | 1425 | } |
1464 | 1426 | ||
1465 | static void handle_irq_transmit_status(struct bcm43xx_private *bcm) | 1427 | static void handle_irq_transmit_status(struct bcm43xx_private *bcm) |
@@ -1885,14 +1847,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
1885 | 1847 | ||
1886 | spin_lock(&bcm->irq_lock); | 1848 | spin_lock(&bcm->irq_lock); |
1887 | 1849 | ||
1888 | /* Only accept IRQs, if we are initialized properly. | 1850 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
1889 | * This avoids an RX race while initializing. | 1851 | assert(bcm->current_core->id == BCM43xx_COREID_80211); |
1890 | * We should probably not enable IRQs before we are initialized | ||
1891 | * completely, but some careful work is needed to fix this. I think it | ||
1892 | * is best to stay with this cheap workaround for now... . | ||
1893 | */ | ||
1894 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) | ||
1895 | goto out; | ||
1896 | 1852 | ||
1897 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 1853 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
1898 | if (reason == 0xffffffff) { | 1854 | if (reason == 0xffffffff) { |
@@ -1930,16 +1886,18 @@ out: | |||
1930 | 1886 | ||
1931 | static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) | 1887 | static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) |
1932 | { | 1888 | { |
1889 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
1890 | |||
1933 | if (bcm->firmware_norelease && !force) | 1891 | if (bcm->firmware_norelease && !force) |
1934 | return; /* Suspending or controller reset. */ | 1892 | return; /* Suspending or controller reset. */ |
1935 | release_firmware(bcm->ucode); | 1893 | release_firmware(phy->ucode); |
1936 | bcm->ucode = NULL; | 1894 | phy->ucode = NULL; |
1937 | release_firmware(bcm->pcm); | 1895 | release_firmware(phy->pcm); |
1938 | bcm->pcm = NULL; | 1896 | phy->pcm = NULL; |
1939 | release_firmware(bcm->initvals0); | 1897 | release_firmware(phy->initvals0); |
1940 | bcm->initvals0 = NULL; | 1898 | phy->initvals0 = NULL; |
1941 | release_firmware(bcm->initvals1); | 1899 | release_firmware(phy->initvals1); |
1942 | bcm->initvals1 = NULL; | 1900 | phy->initvals1 = NULL; |
1943 | } | 1901 | } |
1944 | 1902 | ||
1945 | static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | 1903 | static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) |
@@ -1950,11 +1908,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1950 | int nr; | 1908 | int nr; |
1951 | char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; | 1909 | char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; |
1952 | 1910 | ||
1953 | if (!bcm->ucode) { | 1911 | if (!phy->ucode) { |
1954 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", | 1912 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", |
1955 | (rev >= 5 ? 5 : rev), | 1913 | (rev >= 5 ? 5 : rev), |
1956 | modparam_fwpostfix); | 1914 | modparam_fwpostfix); |
1957 | err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); | 1915 | err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev); |
1958 | if (err) { | 1916 | if (err) { |
1959 | printk(KERN_ERR PFX | 1917 | printk(KERN_ERR PFX |
1960 | "Error: Microcode \"%s\" not available or load failed.\n", | 1918 | "Error: Microcode \"%s\" not available or load failed.\n", |
@@ -1963,12 +1921,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1963 | } | 1921 | } |
1964 | } | 1922 | } |
1965 | 1923 | ||
1966 | if (!bcm->pcm) { | 1924 | if (!phy->pcm) { |
1967 | snprintf(buf, ARRAY_SIZE(buf), | 1925 | snprintf(buf, ARRAY_SIZE(buf), |
1968 | "bcm43xx_pcm%d%s.fw", | 1926 | "bcm43xx_pcm%d%s.fw", |
1969 | (rev < 5 ? 4 : 5), | 1927 | (rev < 5 ? 4 : 5), |
1970 | modparam_fwpostfix); | 1928 | modparam_fwpostfix); |
1971 | err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); | 1929 | err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev); |
1972 | if (err) { | 1930 | if (err) { |
1973 | printk(KERN_ERR PFX | 1931 | printk(KERN_ERR PFX |
1974 | "Error: PCM \"%s\" not available or load failed.\n", | 1932 | "Error: PCM \"%s\" not available or load failed.\n", |
@@ -1977,7 +1935,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1977 | } | 1935 | } |
1978 | } | 1936 | } |
1979 | 1937 | ||
1980 | if (!bcm->initvals0) { | 1938 | if (!phy->initvals0) { |
1981 | if (rev == 2 || rev == 4) { | 1939 | if (rev == 2 || rev == 4) { |
1982 | switch (phy->type) { | 1940 | switch (phy->type) { |
1983 | case BCM43xx_PHYTYPE_A: | 1941 | case BCM43xx_PHYTYPE_A: |
@@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
2008 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", | 1966 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", |
2009 | nr, modparam_fwpostfix); | 1967 | nr, modparam_fwpostfix); |
2010 | 1968 | ||
2011 | err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); | 1969 | err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev); |
2012 | if (err) { | 1970 | if (err) { |
2013 | printk(KERN_ERR PFX | 1971 | printk(KERN_ERR PFX |
2014 | "Error: InitVals \"%s\" not available or load failed.\n", | 1972 | "Error: InitVals \"%s\" not available or load failed.\n", |
2015 | buf); | 1973 | buf); |
2016 | goto error; | 1974 | goto error; |
2017 | } | 1975 | } |
2018 | if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { | 1976 | if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) { |
2019 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); | 1977 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); |
2020 | goto error; | 1978 | goto error; |
2021 | } | 1979 | } |
2022 | } | 1980 | } |
2023 | 1981 | ||
2024 | if (!bcm->initvals1) { | 1982 | if (!phy->initvals1) { |
2025 | if (rev >= 5) { | 1983 | if (rev >= 5) { |
2026 | u32 sbtmstatehigh; | 1984 | u32 sbtmstatehigh; |
2027 | 1985 | ||
@@ -2043,14 +2001,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
2043 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", | 2001 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", |
2044 | nr, modparam_fwpostfix); | 2002 | nr, modparam_fwpostfix); |
2045 | 2003 | ||
2046 | err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); | 2004 | err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev); |
2047 | if (err) { | 2005 | if (err) { |
2048 | printk(KERN_ERR PFX | 2006 | printk(KERN_ERR PFX |
2049 | "Error: InitVals \"%s\" not available or load failed.\n", | 2007 | "Error: InitVals \"%s\" not available or load failed.\n", |
2050 | buf); | 2008 | buf); |
2051 | goto error; | 2009 | goto error; |
2052 | } | 2010 | } |
2053 | if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { | 2011 | if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) { |
2054 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); | 2012 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); |
2055 | goto error; | 2013 | goto error; |
2056 | } | 2014 | } |
@@ -2070,12 +2028,13 @@ err_noinitval: | |||
2070 | 2028 | ||
2071 | static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) | 2029 | static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) |
2072 | { | 2030 | { |
2031 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
2073 | const u32 *data; | 2032 | const u32 *data; |
2074 | unsigned int i, len; | 2033 | unsigned int i, len; |
2075 | 2034 | ||
2076 | /* Upload Microcode. */ | 2035 | /* Upload Microcode. */ |
2077 | data = (u32 *)(bcm->ucode->data); | 2036 | data = (u32 *)(phy->ucode->data); |
2078 | len = bcm->ucode->size / sizeof(u32); | 2037 | len = phy->ucode->size / sizeof(u32); |
2079 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); | 2038 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); |
2080 | for (i = 0; i < len; i++) { | 2039 | for (i = 0; i < len; i++) { |
2081 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, | 2040 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, |
@@ -2084,8 +2043,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) | |||
2084 | } | 2043 | } |
2085 | 2044 | ||
2086 | /* Upload PCM data. */ | 2045 | /* Upload PCM data. */ |
2087 | data = (u32 *)(bcm->pcm->data); | 2046 | data = (u32 *)(phy->pcm->data); |
2088 | len = bcm->pcm->size / sizeof(u32); | 2047 | len = phy->pcm->size / sizeof(u32); |
2089 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); | 2048 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); |
2090 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); | 2049 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); |
2091 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); | 2050 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); |
@@ -2131,15 +2090,16 @@ err_format: | |||
2131 | 2090 | ||
2132 | static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) | 2091 | static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) |
2133 | { | 2092 | { |
2093 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
2134 | int err; | 2094 | int err; |
2135 | 2095 | ||
2136 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, | 2096 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data, |
2137 | bcm->initvals0->size / sizeof(struct bcm43xx_initval)); | 2097 | phy->initvals0->size / sizeof(struct bcm43xx_initval)); |
2138 | if (err) | 2098 | if (err) |
2139 | goto out; | 2099 | goto out; |
2140 | if (bcm->initvals1) { | 2100 | if (phy->initvals1) { |
2141 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, | 2101 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data, |
2142 | bcm->initvals1->size / sizeof(struct bcm43xx_initval)); | 2102 | phy->initvals1->size / sizeof(struct bcm43xx_initval)); |
2143 | if (err) | 2103 | if (err) |
2144 | goto out; | 2104 | goto out; |
2145 | } | 2105 | } |
@@ -2156,9 +2116,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = { | |||
2156 | 2116 | ||
2157 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | 2117 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) |
2158 | { | 2118 | { |
2159 | int res; | 2119 | int err; |
2160 | unsigned int i; | ||
2161 | u32 data; | ||
2162 | 2120 | ||
2163 | bcm->irq = bcm->pci_dev->irq; | 2121 | bcm->irq = bcm->pci_dev->irq; |
2164 | #ifdef CONFIG_BCM947XX | 2122 | #ifdef CONFIG_BCM947XX |
@@ -2175,32 +2133,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | |||
2175 | } | 2133 | } |
2176 | } | 2134 | } |
2177 | #endif | 2135 | #endif |
2178 | res = request_irq(bcm->irq, bcm43xx_interrupt_handler, | 2136 | err = request_irq(bcm->irq, bcm43xx_interrupt_handler, |
2179 | IRQF_SHARED, KBUILD_MODNAME, bcm); | 2137 | IRQF_SHARED, KBUILD_MODNAME, bcm); |
2180 | if (res) { | 2138 | if (err) |
2181 | printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); | 2139 | printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); |
2182 | return -ENODEV; | ||
2183 | } | ||
2184 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); | ||
2185 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); | ||
2186 | i = 0; | ||
2187 | while (1) { | ||
2188 | data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2189 | if (data == BCM43xx_IRQ_READY) | ||
2190 | break; | ||
2191 | i++; | ||
2192 | if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { | ||
2193 | printk(KERN_ERR PFX "Card IRQ register not responding. " | ||
2194 | "Giving up.\n"); | ||
2195 | free_irq(bcm->irq, bcm); | ||
2196 | return -ENODEV; | ||
2197 | } | ||
2198 | udelay(10); | ||
2199 | } | ||
2200 | // dummy read | ||
2201 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2202 | 2140 | ||
2203 | return 0; | 2141 | return err; |
2204 | } | 2142 | } |
2205 | 2143 | ||
2206 | /* Switch to the core used to write the GPIO register. | 2144 | /* Switch to the core used to write the GPIO register. |
@@ -2403,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) | |||
2403 | if (!modparam_noleds) | 2341 | if (!modparam_noleds) |
2404 | bcm43xx_leds_exit(bcm); | 2342 | bcm43xx_leds_exit(bcm); |
2405 | bcm43xx_gpio_cleanup(bcm); | 2343 | bcm43xx_gpio_cleanup(bcm); |
2406 | free_irq(bcm->irq, bcm); | ||
2407 | bcm43xx_release_firmware(bcm, 0); | 2344 | bcm43xx_release_firmware(bcm, 0); |
2408 | } | 2345 | } |
2409 | 2346 | ||
@@ -2415,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2415 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2352 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
2416 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2353 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2417 | int err; | 2354 | int err; |
2418 | int tmp; | 2355 | int i, tmp; |
2419 | u32 value32; | 2356 | u32 value32; |
2420 | u16 value16; | 2357 | u16 value16; |
2421 | 2358 | ||
@@ -2428,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2428 | goto out; | 2365 | goto out; |
2429 | bcm43xx_upload_microcode(bcm); | 2366 | bcm43xx_upload_microcode(bcm); |
2430 | 2367 | ||
2431 | err = bcm43xx_initialize_irq(bcm); | 2368 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); |
2432 | if (err) | 2369 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); |
2433 | goto err_release_fw; | 2370 | i = 0; |
2371 | while (1) { | ||
2372 | value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2373 | if (value32 == BCM43xx_IRQ_READY) | ||
2374 | break; | ||
2375 | i++; | ||
2376 | if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { | ||
2377 | printk(KERN_ERR PFX "IRQ_READY timeout\n"); | ||
2378 | err = -ENODEV; | ||
2379 | goto err_release_fw; | ||
2380 | } | ||
2381 | udelay(10); | ||
2382 | } | ||
2383 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
2434 | 2384 | ||
2435 | err = bcm43xx_gpio_init(bcm); | 2385 | err = bcm43xx_gpio_init(bcm); |
2436 | if (err) | 2386 | if (err) |
2437 | goto err_free_irq; | 2387 | goto err_release_fw; |
2438 | 2388 | ||
2439 | err = bcm43xx_upload_initvals(bcm); | 2389 | err = bcm43xx_upload_initvals(bcm); |
2440 | if (err) | 2390 | if (err) |
@@ -2518,8 +2468,6 @@ err_radio_off: | |||
2518 | bcm43xx_radio_turn_off(bcm); | 2468 | bcm43xx_radio_turn_off(bcm); |
2519 | err_gpio_cleanup: | 2469 | err_gpio_cleanup: |
2520 | bcm43xx_gpio_cleanup(bcm); | 2470 | bcm43xx_gpio_cleanup(bcm); |
2521 | err_free_irq: | ||
2522 | free_irq(bcm->irq, bcm); | ||
2523 | err_release_fw: | 2471 | err_release_fw: |
2524 | bcm43xx_release_firmware(bcm, 1); | 2472 | bcm43xx_release_firmware(bcm, 1); |
2525 | goto out; | 2473 | goto out; |
@@ -2559,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) | |||
2559 | { | 2507 | { |
2560 | /* Initialize a "phyinfo" structure. The structure is already | 2508 | /* Initialize a "phyinfo" structure. The structure is already |
2561 | * zeroed out. | 2509 | * zeroed out. |
2510 | * This is called on insmod time to initialize members. | ||
2562 | */ | 2511 | */ |
2563 | phy->antenna_diversity = 0xFFFF; | ||
2564 | phy->savedpctlreg = 0xFFFF; | 2512 | phy->savedpctlreg = 0xFFFF; |
2565 | phy->minlowsig[0] = 0xFFFF; | ||
2566 | phy->minlowsig[1] = 0xFFFF; | ||
2567 | spin_lock_init(&phy->lock); | 2513 | spin_lock_init(&phy->lock); |
2568 | } | 2514 | } |
2569 | 2515 | ||
@@ -2571,14 +2517,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) | |||
2571 | { | 2517 | { |
2572 | /* Initialize a "radioinfo" structure. The structure is already | 2518 | /* Initialize a "radioinfo" structure. The structure is already |
2573 | * zeroed out. | 2519 | * zeroed out. |
2520 | * This is called on insmod time to initialize members. | ||
2574 | */ | 2521 | */ |
2575 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; | 2522 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; |
2576 | radio->channel = 0xFF; | 2523 | radio->channel = 0xFF; |
2577 | radio->initial_channel = 0xFF; | 2524 | radio->initial_channel = 0xFF; |
2578 | radio->lofcal = 0xFFFF; | ||
2579 | radio->initval = 0xFFFF; | ||
2580 | radio->nrssi[0] = -1000; | ||
2581 | radio->nrssi[1] = -1000; | ||
2582 | } | 2525 | } |
2583 | 2526 | ||
2584 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | 2527 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) |
@@ -2596,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2596 | * BCM43xx_MAX_80211_CORES); | 2539 | * BCM43xx_MAX_80211_CORES); |
2597 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) | 2540 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) |
2598 | * BCM43xx_MAX_80211_CORES); | 2541 | * BCM43xx_MAX_80211_CORES); |
2599 | bcm->current_80211_core_idx = -1; | ||
2600 | bcm->nr_80211_available = 0; | 2542 | bcm->nr_80211_available = 0; |
2601 | bcm->current_core = NULL; | 2543 | bcm->current_core = NULL; |
2602 | bcm->active_80211_core = NULL; | 2544 | bcm->active_80211_core = NULL; |
@@ -2766,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2766 | goto out; | 2708 | goto out; |
2767 | } | 2709 | } |
2768 | bcm->nr_80211_available++; | 2710 | bcm->nr_80211_available++; |
2711 | core->priv = ext_80211; | ||
2769 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); | 2712 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); |
2770 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); | 2713 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); |
2771 | break; | 2714 | break; |
@@ -2866,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) | |||
2866 | } | 2809 | } |
2867 | 2810 | ||
2868 | /* http://bcm-specs.sipsolutions.net/80211Init */ | 2811 | /* http://bcm-specs.sipsolutions.net/80211Init */ |
2869 | static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | 2812 | static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, |
2813 | int active_wlcore) | ||
2870 | { | 2814 | { |
2871 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2815 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2872 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2816 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
@@ -2948,19 +2892,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | |||
2948 | if (bcm->current_core->rev >= 5) | 2892 | if (bcm->current_core->rev >= 5) |
2949 | bcm43xx_write16(bcm, 0x043C, 0x000C); | 2893 | bcm43xx_write16(bcm, 0x043C, 0x000C); |
2950 | 2894 | ||
2951 | if (bcm43xx_using_pio(bcm)) | 2895 | if (active_wlcore) { |
2952 | err = bcm43xx_pio_init(bcm); | 2896 | if (bcm43xx_using_pio(bcm)) |
2953 | else | 2897 | err = bcm43xx_pio_init(bcm); |
2954 | err = bcm43xx_dma_init(bcm); | 2898 | else |
2955 | if (err) | 2899 | err = bcm43xx_dma_init(bcm); |
2956 | goto err_chip_cleanup; | 2900 | if (err) |
2901 | goto err_chip_cleanup; | ||
2902 | } | ||
2957 | bcm43xx_write16(bcm, 0x0612, 0x0050); | 2903 | bcm43xx_write16(bcm, 0x0612, 0x0050); |
2958 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); | 2904 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); |
2959 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); | 2905 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); |
2960 | 2906 | ||
2961 | bcm43xx_mac_enable(bcm); | 2907 | if (active_wlcore) { |
2962 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 2908 | if (radio->initial_channel != 0xFF) |
2909 | bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0); | ||
2910 | } | ||
2963 | 2911 | ||
2912 | /* Don't enable MAC/IRQ here, as it will race with the IRQ handler. | ||
2913 | * We enable it later. | ||
2914 | */ | ||
2964 | bcm->current_core->initialized = 1; | 2915 | bcm->current_core->initialized = 1; |
2965 | out: | 2916 | out: |
2966 | return err; | 2917 | return err; |
@@ -3075,11 +3026,6 @@ out: | |||
3075 | return err; | 3026 | return err; |
3076 | } | 3027 | } |
3077 | 3028 | ||
3078 | static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) | ||
3079 | { | ||
3080 | ieee80211softmac_start(bcm->net_dev); | ||
3081 | } | ||
3082 | |||
3083 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) | 3029 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) |
3084 | { | 3030 | { |
3085 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 3031 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
@@ -3281,141 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm) | |||
3281 | return err; | 3227 | return err; |
3282 | } | 3228 | } |
3283 | 3229 | ||
3284 | /* This is the opposite of bcm43xx_init_board() */ | 3230 | static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) |
3285 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | ||
3286 | { | 3231 | { |
3232 | int ret = 0; | ||
3287 | int i, err; | 3233 | int i, err; |
3234 | struct bcm43xx_coreinfo *core; | ||
3288 | 3235 | ||
3289 | mutex_lock(&bcm->mutex); | 3236 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
3237 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3238 | core = &(bcm->core_80211[i]); | ||
3239 | assert(core->available); | ||
3240 | if (!core->initialized) | ||
3241 | continue; | ||
3242 | err = bcm43xx_switch_core(bcm, core); | ||
3243 | if (err) { | ||
3244 | dprintk(KERN_ERR PFX "shutdown_all_wireless_cores " | ||
3245 | "switch_core failed (%d)\n", err); | ||
3246 | ret = err; | ||
3247 | continue; | ||
3248 | } | ||
3249 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3250 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
3251 | bcm43xx_wireless_core_cleanup(bcm); | ||
3252 | if (core == bcm->active_80211_core) | ||
3253 | bcm->active_80211_core = NULL; | ||
3254 | } | ||
3255 | free_irq(bcm->irq, bcm); | ||
3256 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3257 | |||
3258 | return ret; | ||
3259 | } | ||
3260 | |||
3261 | /* This is the opposite of bcm43xx_init_board() */ | ||
3262 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | ||
3263 | { | ||
3290 | bcm43xx_sysfs_unregister(bcm); | 3264 | bcm43xx_sysfs_unregister(bcm); |
3291 | bcm43xx_periodic_tasks_delete(bcm); | 3265 | bcm43xx_periodic_tasks_delete(bcm); |
3292 | 3266 | ||
3293 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); | 3267 | bcm43xx_lock_noirq(bcm); |
3268 | bcm43xx_shutdown_all_wireless_cores(bcm); | ||
3269 | bcm43xx_pctl_set_crystal(bcm, 0); | ||
3270 | bcm43xx_unlock_noirq(bcm); | ||
3271 | } | ||
3294 | 3272 | ||
3295 | bcm43xx_rng_exit(bcm); | 3273 | static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy) |
3274 | { | ||
3275 | phy->antenna_diversity = 0xFFFF; | ||
3276 | memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); | ||
3277 | memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); | ||
3278 | |||
3279 | /* Flags */ | ||
3280 | phy->calibrated = 0; | ||
3281 | phy->is_locked = 0; | ||
3282 | |||
3283 | if (phy->_lo_pairs) { | ||
3284 | memset(phy->_lo_pairs, 0, | ||
3285 | sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT); | ||
3286 | } | ||
3287 | memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); | ||
3288 | } | ||
3289 | |||
3290 | static void prepare_radiodata_for_init(struct bcm43xx_private *bcm, | ||
3291 | struct bcm43xx_radioinfo *radio) | ||
3292 | { | ||
3293 | int i; | ||
3294 | |||
3295 | /* Set default attenuation values. */ | ||
3296 | radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); | ||
3297 | radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); | ||
3298 | radio->txctl1 = bcm43xx_default_txctl1(bcm); | ||
3299 | radio->txctl2 = 0xFFFF; | ||
3300 | radio->txpwr_offset = 0; | ||
3301 | |||
3302 | /* NRSSI */ | ||
3303 | radio->nrssislope = 0; | ||
3304 | for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++) | ||
3305 | radio->nrssi[i] = -1000; | ||
3306 | for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++) | ||
3307 | radio->nrssi_lt[i] = i; | ||
3308 | |||
3309 | radio->lofcal = 0xFFFF; | ||
3310 | radio->initval = 0xFFFF; | ||
3311 | |||
3312 | radio->aci_enable = 0; | ||
3313 | radio->aci_wlan_automatic = 0; | ||
3314 | radio->aci_hw_rssi = 0; | ||
3315 | } | ||
3316 | |||
3317 | static void prepare_priv_for_init(struct bcm43xx_private *bcm) | ||
3318 | { | ||
3319 | int i; | ||
3320 | struct bcm43xx_coreinfo *core; | ||
3321 | struct bcm43xx_coreinfo_80211 *wlext; | ||
3322 | |||
3323 | assert(!bcm->active_80211_core); | ||
3324 | |||
3325 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | ||
3326 | |||
3327 | /* Flags */ | ||
3328 | bcm->was_initialized = 0; | ||
3329 | bcm->reg124_set_0x4 = 0; | ||
3330 | |||
3331 | /* Stats */ | ||
3332 | memset(&bcm->stats, 0, sizeof(bcm->stats)); | ||
3333 | |||
3334 | /* Wireless core data */ | ||
3296 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3335 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3297 | if (!bcm->core_80211[i].available) | 3336 | core = &(bcm->core_80211[i]); |
3298 | continue; | 3337 | wlext = core->priv; |
3299 | if (!bcm->core_80211[i].initialized) | 3338 | |
3339 | if (!core->available) | ||
3300 | continue; | 3340 | continue; |
3341 | assert(wlext == &(bcm->core_80211_ext[i])); | ||
3301 | 3342 | ||
3302 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3343 | prepare_phydata_for_init(&wlext->phy); |
3303 | assert(err == 0); | 3344 | prepare_radiodata_for_init(bcm, &wlext->radio); |
3304 | bcm43xx_wireless_core_cleanup(bcm); | ||
3305 | } | 3345 | } |
3306 | 3346 | ||
3307 | bcm43xx_pctl_set_crystal(bcm, 0); | 3347 | /* IRQ related flags */ |
3348 | bcm->irq_reason = 0; | ||
3349 | memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason)); | ||
3350 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | ||
3308 | 3351 | ||
3309 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | 3352 | /* Noise calculation context */ |
3310 | mutex_unlock(&bcm->mutex); | 3353 | memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc)); |
3354 | |||
3355 | /* Periodic work context */ | ||
3356 | bcm->periodic_state = 0; | ||
3311 | } | 3357 | } |
3312 | 3358 | ||
3313 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | 3359 | static int wireless_core_up(struct bcm43xx_private *bcm, |
3360 | int active_wlcore) | ||
3361 | { | ||
3362 | int err; | ||
3363 | |||
3364 | if (!bcm43xx_core_enabled(bcm)) | ||
3365 | bcm43xx_wireless_core_reset(bcm, 1); | ||
3366 | if (!active_wlcore) | ||
3367 | bcm43xx_wireless_core_mark_inactive(bcm); | ||
3368 | err = bcm43xx_wireless_core_init(bcm, active_wlcore); | ||
3369 | if (err) | ||
3370 | goto out; | ||
3371 | if (!active_wlcore) | ||
3372 | bcm43xx_radio_turn_off(bcm); | ||
3373 | out: | ||
3374 | return err; | ||
3375 | } | ||
3376 | |||
3377 | /* Select and enable the "to be used" wireless core. | ||
3378 | * Locking: bcm->mutex must be aquired before calling this. | ||
3379 | * bcm->irq_lock must not be aquired. | ||
3380 | */ | ||
3381 | int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, | ||
3382 | int phytype) | ||
3314 | { | 3383 | { |
3315 | int i, err; | 3384 | int i, err; |
3316 | int connect_phy; | 3385 | struct bcm43xx_coreinfo *active_core = NULL; |
3386 | struct bcm43xx_coreinfo_80211 *active_wlext = NULL; | ||
3387 | struct bcm43xx_coreinfo *core; | ||
3388 | struct bcm43xx_coreinfo_80211 *wlext; | ||
3389 | int adjust_active_sbtmstatelow = 0; | ||
3317 | 3390 | ||
3318 | might_sleep(); | 3391 | might_sleep(); |
3319 | 3392 | ||
3320 | mutex_lock(&bcm->mutex); | 3393 | if (phytype < 0) { |
3321 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | 3394 | /* If no phytype is requested, select the first core. */ |
3395 | assert(bcm->core_80211[0].available); | ||
3396 | wlext = bcm->core_80211[0].priv; | ||
3397 | phytype = wlext->phy.type; | ||
3398 | } | ||
3399 | /* Find the requested core. */ | ||
3400 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3401 | core = &(bcm->core_80211[i]); | ||
3402 | wlext = core->priv; | ||
3403 | if (wlext->phy.type == phytype) { | ||
3404 | active_core = core; | ||
3405 | active_wlext = wlext; | ||
3406 | break; | ||
3407 | } | ||
3408 | } | ||
3409 | if (!active_core) | ||
3410 | return -ESRCH; /* No such PHYTYPE on this board. */ | ||
3411 | |||
3412 | if (bcm->active_80211_core) { | ||
3413 | /* We already selected a wl core in the past. | ||
3414 | * So first clean up everything. | ||
3415 | */ | ||
3416 | dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n"); | ||
3417 | ieee80211softmac_stop(bcm->net_dev); | ||
3418 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | ||
3419 | err = bcm43xx_disable_interrupts_sync(bcm); | ||
3420 | assert(!err); | ||
3421 | tasklet_enable(&bcm->isr_tasklet); | ||
3422 | err = bcm43xx_shutdown_all_wireless_cores(bcm); | ||
3423 | if (err) | ||
3424 | goto error; | ||
3425 | /* Ok, everything down, continue to re-initialize. */ | ||
3426 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | ||
3427 | } | ||
3322 | 3428 | ||
3323 | bcm->mac_suspended = 1; | 3429 | /* Reset all data structures. */ |
3430 | prepare_priv_for_init(bcm); | ||
3324 | 3431 | ||
3325 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
3326 | if (err) | ||
3327 | goto out; | ||
3328 | err = bcm43xx_pctl_init(bcm); | ||
3329 | if (err) | ||
3330 | goto err_crystal_off; | ||
3331 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); | 3432 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); |
3332 | if (err) | 3433 | if (err) |
3333 | goto err_crystal_off; | 3434 | goto error; |
3334 | 3435 | ||
3335 | tasklet_enable(&bcm->isr_tasklet); | 3436 | /* Mark all unused cores "inactive". */ |
3336 | for (i = 0; i < bcm->nr_80211_available; i++) { | 3437 | for (i = 0; i < bcm->nr_80211_available; i++) { |
3337 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3438 | core = &(bcm->core_80211[i]); |
3338 | assert(err != -ENODEV); | 3439 | wlext = core->priv; |
3339 | if (err) | ||
3340 | goto err_80211_unwind; | ||
3341 | 3440 | ||
3342 | /* Enable the selected wireless core. | 3441 | if (core == active_core) |
3343 | * Connect PHY only on the first core. | 3442 | continue; |
3344 | */ | 3443 | err = bcm43xx_switch_core(bcm, core); |
3345 | if (!bcm43xx_core_enabled(bcm)) { | 3444 | if (err) { |
3346 | if (bcm->nr_80211_available == 1) { | 3445 | dprintk(KERN_ERR PFX "Could not switch to inactive " |
3347 | connect_phy = bcm43xx_current_phy(bcm)->connected; | 3446 | "802.11 core (%d)\n", err); |
3348 | } else { | 3447 | goto error; |
3349 | if (i == 0) | ||
3350 | connect_phy = 1; | ||
3351 | else | ||
3352 | connect_phy = 0; | ||
3353 | } | ||
3354 | bcm43xx_wireless_core_reset(bcm, connect_phy); | ||
3355 | } | 3448 | } |
3449 | err = wireless_core_up(bcm, 0); | ||
3450 | if (err) { | ||
3451 | dprintk(KERN_ERR PFX "core_up for inactive 802.11 core " | ||
3452 | "failed (%d)\n", err); | ||
3453 | goto error; | ||
3454 | } | ||
3455 | adjust_active_sbtmstatelow = 1; | ||
3456 | } | ||
3356 | 3457 | ||
3357 | if (i != 0) | 3458 | /* Now initialize the active 802.11 core. */ |
3358 | bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); | 3459 | err = bcm43xx_switch_core(bcm, active_core); |
3359 | 3460 | if (err) { | |
3360 | err = bcm43xx_wireless_core_init(bcm); | 3461 | dprintk(KERN_ERR PFX "Could not switch to active " |
3361 | if (err) | 3462 | "802.11 core (%d)\n", err); |
3362 | goto err_80211_unwind; | 3463 | goto error; |
3464 | } | ||
3465 | if (adjust_active_sbtmstatelow && | ||
3466 | active_wlext->phy.type == BCM43xx_PHYTYPE_G) { | ||
3467 | u32 sbtmstatelow; | ||
3363 | 3468 | ||
3364 | if (i != 0) { | 3469 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
3365 | bcm43xx_mac_suspend(bcm); | 3470 | sbtmstatelow |= 0x20000000; |
3366 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3471 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
3367 | bcm43xx_radio_turn_off(bcm); | ||
3368 | } | ||
3369 | } | 3472 | } |
3370 | bcm->active_80211_core = &bcm->core_80211[0]; | 3473 | err = wireless_core_up(bcm, 1); |
3371 | if (bcm->nr_80211_available >= 2) { | 3474 | if (err) { |
3372 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); | 3475 | dprintk(KERN_ERR PFX "core_up for active 802.11 core " |
3373 | bcm43xx_mac_enable(bcm); | 3476 | "failed (%d)\n", err); |
3477 | goto error; | ||
3374 | } | 3478 | } |
3375 | err = bcm43xx_rng_init(bcm); | 3479 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); |
3376 | if (err) | 3480 | if (err) |
3377 | goto err_80211_unwind; | 3481 | goto error; |
3482 | bcm->active_80211_core = active_core; | ||
3483 | |||
3378 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); | 3484 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); |
3379 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); | 3485 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); |
3380 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); | ||
3381 | bcm43xx_security_init(bcm); | 3486 | bcm43xx_security_init(bcm); |
3382 | bcm43xx_softmac_init(bcm); | 3487 | ieee80211softmac_start(bcm->net_dev); |
3383 | 3488 | ||
3384 | bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); | 3489 | /* Let's go! Be careful after enabling the IRQs. |
3490 | * Don't switch cores, for example. | ||
3491 | */ | ||
3492 | bcm43xx_mac_enable(bcm); | ||
3493 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | ||
3494 | err = bcm43xx_initialize_irq(bcm); | ||
3495 | if (err) | ||
3496 | goto error; | ||
3497 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | ||
3385 | 3498 | ||
3386 | if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { | 3499 | dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n", |
3387 | bcm43xx_mac_suspend(bcm); | 3500 | active_wlext->phy.type); |
3388 | bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); | ||
3389 | bcm43xx_mac_enable(bcm); | ||
3390 | } | ||
3391 | 3501 | ||
3392 | /* Initialization of the board is done. Flag it as such. */ | 3502 | return 0; |
3393 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | 3503 | |
3504 | error: | ||
3505 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3506 | bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); | ||
3507 | return err; | ||
3508 | } | ||
3509 | |||
3510 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | ||
3511 | { | ||
3512 | int err; | ||
3513 | |||
3514 | bcm43xx_lock_noirq(bcm); | ||
3515 | |||
3516 | tasklet_enable(&bcm->isr_tasklet); | ||
3517 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
3518 | if (err) | ||
3519 | goto err_tasklet; | ||
3520 | err = bcm43xx_pctl_init(bcm); | ||
3521 | if (err) | ||
3522 | goto err_crystal_off; | ||
3523 | err = bcm43xx_select_wireless_core(bcm, -1); | ||
3524 | if (err) | ||
3525 | goto err_crystal_off; | ||
3394 | 3526 | ||
3395 | bcm43xx_periodic_tasks_setup(bcm); | 3527 | bcm43xx_periodic_tasks_setup(bcm); |
3396 | bcm43xx_sysfs_register(bcm); | 3528 | err = bcm43xx_sysfs_register(bcm); |
3397 | //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... | 3529 | if (err) |
3530 | goto err_wlshutdown; | ||
3398 | 3531 | ||
3399 | /*FIXME: This should be handled by softmac instead. */ | 3532 | /*FIXME: This should be handled by softmac instead. */ |
3400 | schedule_work(&bcm->softmac->associnfo.work); | 3533 | schedule_work(&bcm->softmac->associnfo.work); |
3401 | 3534 | ||
3402 | assert(err == 0); | ||
3403 | out: | 3535 | out: |
3404 | mutex_unlock(&bcm->mutex); | 3536 | bcm43xx_unlock_noirq(bcm); |
3405 | 3537 | ||
3406 | return err; | 3538 | return err; |
3407 | 3539 | ||
3408 | err_80211_unwind: | 3540 | err_wlshutdown: |
3409 | tasklet_disable(&bcm->isr_tasklet); | 3541 | bcm43xx_shutdown_all_wireless_cores(bcm); |
3410 | /* unwind all 80211 initialization */ | ||
3411 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3412 | if (!bcm->core_80211[i].initialized) | ||
3413 | continue; | ||
3414 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3415 | bcm43xx_wireless_core_cleanup(bcm); | ||
3416 | } | ||
3417 | err_crystal_off: | 3542 | err_crystal_off: |
3418 | bcm43xx_pctl_set_crystal(bcm, 0); | 3543 | bcm43xx_pctl_set_crystal(bcm, 0); |
3544 | err_tasklet: | ||
3545 | tasklet_disable(&bcm->isr_tasklet); | ||
3419 | goto out; | 3546 | goto out; |
3420 | } | 3547 | } |
3421 | 3548 | ||
@@ -3797,7 +3924,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev) | |||
3797 | unsigned long flags; | 3924 | unsigned long flags; |
3798 | 3925 | ||
3799 | local_irq_save(flags); | 3926 | local_irq_save(flags); |
3800 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | 3927 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
3928 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | ||
3801 | local_irq_restore(flags); | 3929 | local_irq_restore(flags); |
3802 | } | 3930 | } |
3803 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | 3931 | #endif /* CONFIG_NET_POLL_CONTROLLER */ |
@@ -3815,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev) | |||
3815 | int err; | 3943 | int err; |
3816 | 3944 | ||
3817 | ieee80211softmac_stop(net_dev); | 3945 | ieee80211softmac_stop(net_dev); |
3818 | err = bcm43xx_disable_interrupts_sync(bcm, NULL); | 3946 | err = bcm43xx_disable_interrupts_sync(bcm); |
3819 | assert(!err); | 3947 | assert(!err); |
3820 | bcm43xx_free_board(bcm); | 3948 | bcm43xx_free_board(bcm); |
3821 | 3949 | ||
@@ -3957,7 +4085,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3957 | bcm43xx_debugfs_remove_device(bcm); | 4085 | bcm43xx_debugfs_remove_device(bcm); |
3958 | unregister_netdev(net_dev); | 4086 | unregister_netdev(net_dev); |
3959 | bcm43xx_detach_board(bcm); | 4087 | bcm43xx_detach_board(bcm); |
3960 | assert(bcm->ucode == NULL); | ||
3961 | free_ieee80211softmac(net_dev); | 4088 | free_ieee80211softmac(net_dev); |
3962 | } | 4089 | } |
3963 | 4090 | ||
@@ -3967,47 +4094,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3967 | static void bcm43xx_chip_reset(void *_bcm) | 4094 | static void bcm43xx_chip_reset(void *_bcm) |
3968 | { | 4095 | { |
3969 | struct bcm43xx_private *bcm = _bcm; | 4096 | struct bcm43xx_private *bcm = _bcm; |
3970 | struct net_device *net_dev = bcm->net_dev; | 4097 | struct bcm43xx_phyinfo *phy; |
3971 | struct pci_dev *pci_dev = bcm->pci_dev; | ||
3972 | int err; | 4098 | int err; |
3973 | int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
3974 | 4099 | ||
3975 | netif_stop_queue(bcm->net_dev); | 4100 | bcm43xx_lock_noirq(bcm); |
3976 | tasklet_disable(&bcm->isr_tasklet); | 4101 | phy = bcm43xx_current_phy(bcm); |
4102 | err = bcm43xx_select_wireless_core(bcm, phy->type); | ||
4103 | bcm43xx_unlock_noirq(bcm); | ||
3977 | 4104 | ||
3978 | bcm->firmware_norelease = 1; | 4105 | printk(KERN_ERR PFX "Controller restart%s\n", |
3979 | if (was_initialized) | 4106 | (err == 0) ? "ed" : " failed"); |
3980 | bcm43xx_free_board(bcm); | ||
3981 | bcm->firmware_norelease = 0; | ||
3982 | bcm43xx_detach_board(bcm); | ||
3983 | err = bcm43xx_init_private(bcm, net_dev, pci_dev); | ||
3984 | if (err) | ||
3985 | goto failure; | ||
3986 | err = bcm43xx_attach_board(bcm); | ||
3987 | if (err) | ||
3988 | goto failure; | ||
3989 | if (was_initialized) { | ||
3990 | err = bcm43xx_init_board(bcm); | ||
3991 | if (err) | ||
3992 | goto failure; | ||
3993 | } | ||
3994 | netif_wake_queue(bcm->net_dev); | ||
3995 | printk(KERN_INFO PFX "Controller restarted\n"); | ||
3996 | |||
3997 | return; | ||
3998 | failure: | ||
3999 | printk(KERN_ERR PFX "Controller restart failed\n"); | ||
4000 | } | 4107 | } |
4001 | 4108 | ||
4002 | /* Hard-reset the chip. | 4109 | /* Hard-reset the chip. |
4003 | * This can be called from interrupt or process context. | 4110 | * This can be called from interrupt or process context. |
4004 | * Make sure to _not_ re-enable device interrupts after this has been called. | 4111 | */ |
4005 | */ | ||
4006 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 4112 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) |
4007 | { | 4113 | { |
4114 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
4008 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); | 4115 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); |
4009 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
4010 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | ||
4011 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); | 4116 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); |
4012 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); | 4117 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); |
4013 | schedule_work(&bcm->restart_work); | 4118 | schedule_work(&bcm->restart_work); |
@@ -4019,18 +4124,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4019 | { | 4124 | { |
4020 | struct net_device *net_dev = pci_get_drvdata(pdev); | 4125 | struct net_device *net_dev = pci_get_drvdata(pdev); |
4021 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 4126 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
4022 | int try_to_shutdown = 0, err; | 4127 | int err; |
4023 | 4128 | ||
4024 | dprintk(KERN_INFO PFX "Suspending...\n"); | 4129 | dprintk(KERN_INFO PFX "Suspending...\n"); |
4025 | 4130 | ||
4026 | bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
4027 | if (bcm->was_initialized) | ||
4028 | try_to_shutdown = 1; | ||
4029 | |||
4030 | netif_device_detach(net_dev); | 4131 | netif_device_detach(net_dev); |
4031 | if (try_to_shutdown) { | 4132 | bcm->was_initialized = 0; |
4133 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | ||
4134 | bcm->was_initialized = 1; | ||
4032 | ieee80211softmac_stop(net_dev); | 4135 | ieee80211softmac_stop(net_dev); |
4033 | err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); | 4136 | err = bcm43xx_disable_interrupts_sync(bcm); |
4034 | if (unlikely(err)) { | 4137 | if (unlikely(err)) { |
4035 | dprintk(KERN_ERR PFX "Suspend failed.\n"); | 4138 | dprintk(KERN_ERR PFX "Suspend failed.\n"); |
4036 | return -EAGAIN; | 4139 | return -EAGAIN; |
@@ -4063,17 +4166,14 @@ static int bcm43xx_resume(struct pci_dev *pdev) | |||
4063 | pci_restore_state(pdev); | 4166 | pci_restore_state(pdev); |
4064 | 4167 | ||
4065 | bcm43xx_chipset_attach(bcm); | 4168 | bcm43xx_chipset_attach(bcm); |
4066 | if (bcm->was_initialized) { | 4169 | if (bcm->was_initialized) |
4067 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | ||
4068 | err = bcm43xx_init_board(bcm); | 4170 | err = bcm43xx_init_board(bcm); |
4069 | } | ||
4070 | if (err) { | 4171 | if (err) { |
4071 | printk(KERN_ERR PFX "Resume failed!\n"); | 4172 | printk(KERN_ERR PFX "Resume failed!\n"); |
4072 | return err; | 4173 | return err; |
4073 | } | 4174 | } |
4074 | |||
4075 | netif_device_attach(net_dev); | 4175 | netif_device_attach(net_dev); |
4076 | 4176 | ||
4077 | dprintk(KERN_INFO PFX "Device resumed.\n"); | 4177 | dprintk(KERN_INFO PFX "Device resumed.\n"); |
4078 | 4178 | ||
4079 | return 0; | 4179 | return 0; |