📄 bcm43xx_main.c
字号:
bcm43xx_phy_connect(bcm, connect_phy); bcm43xx_core_enable(bcm, flags); bcm43xx_write16(bcm, 0x03E6, 0x0000); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | BCM43xx_SBF_400); }}static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm){ bcm43xx_radio_turn_off(bcm); bcm43xx_write16(bcm, 0x03E6, 0x00F4); bcm43xx_core_disable(bcm, 0);}/* Mark the current 80211 core inactive. */static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm){ u32 sbtmstatelow; bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_radio_turn_off(bcm); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow &= 0xDFF5FFFF; sbtmstatelow |= 0x000A0000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow &= 0xFFF5FFFF; sbtmstatelow |= 0x00080000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1);}static void handle_irq_transmit_status(struct bcm43xx_private *bcm){ u32 v0, v1; u16 tmp; struct bcm43xx_xmitstatus stat; while (1) { v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); if (!v0) break; v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); stat.cookie = (v0 >> 16) & 0x0000FFFF; tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); stat.flags = tmp & 0xFF; stat.cnt1 = (tmp & 0x0F00) >> 8; stat.cnt2 = (tmp & 0xF000) >> 12; stat.seq = (u16)(v1 & 0xFFFF); stat.unknown = (u16)((v1 >> 16) & 0xFF); bcm43xx_debugfs_log_txstat(bcm, &stat); if (stat.flags & BCM43xx_TXSTAT_FLAG_AMPDU) continue; if (stat.flags & BCM43xx_TXSTAT_FLAG_INTER) continue; if (bcm43xx_using_pio(bcm)) bcm43xx_pio_handle_xmitstatus(bcm, &stat); else bcm43xx_dma_handle_xmitstatus(bcm, &stat); }}static void drain_txstatus_queue(struct bcm43xx_private *bcm){ u32 dummy; if (bcm->current_core->rev < 5) return; /* Read all entries from the microcode TXstatus FIFO * and throw them away. */ while (1) { dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); if (!dummy) break; dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); }}static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm){ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); assert(bcm->noisecalc.core_at_start == bcm->current_core); assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);}static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm){ /* Top half of Link Quality calculation. */ if (bcm->noisecalc.calculation_running) return; bcm->noisecalc.core_at_start = bcm->current_core; bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; bcm->noisecalc.calculation_running = 1; bcm->noisecalc.nr_samples = 0; bcm43xx_generate_noise_sample(bcm);}static void handle_irq_noise(struct bcm43xx_private *bcm){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; u8 noise[4]; u8 i, j; s32 average; /* Bottom half of Link Quality calculation. */ assert(bcm->noisecalc.calculation_running); if (bcm->noisecalc.core_at_start != bcm->current_core || bcm->noisecalc.channel_at_start != radio->channel) goto drop_calculation; tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); noise[0] = (tmp & 0x00FF); noise[1] = (tmp & 0xFF00) >> 8; tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); noise[2] = (tmp & 0x00FF); noise[3] = (tmp & 0xFF00) >> 8; if (noise[0] == 0x7F || noise[1] == 0x7F || noise[2] == 0x7F || noise[3] == 0x7F) goto generate_new; /* Get the noise samples. */ assert(bcm->noisecalc.nr_samples < 8); i = bcm->noisecalc.nr_samples; noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; bcm->noisecalc.nr_samples++; if (bcm->noisecalc.nr_samples == 8) { /* Calculate the Link Quality by the noise samples. */ average = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 4; j++) average += bcm->noisecalc.samples[i][j]; } average /= (8 * 4); average *= 125; average += 64; average /= 128; tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); tmp = (tmp / 128) & 0x1F; if (tmp >= 8) average += 2; else average -= 25; if (tmp == 8) average -= 72; else average -= 48; bcm->stats.noise = average;drop_calculation: bcm->noisecalc.calculation_running = 0; return; }generate_new: bcm43xx_generate_noise_sample(bcm);}static void handle_irq_ps(struct bcm43xx_private *bcm){ if (bcm->ieee->iw_mode == IW_MODE_MASTER) { ///TODO: PS TBTT } else { if (1/*FIXME: the last PSpoll frame was sent successfully */) bcm43xx_power_saving_ctl_bits(bcm, -1, -1); } if (bcm->ieee->iw_mode == IW_MODE_ADHOC) bcm->reg124_set_0x4 = 1; //FIXME else set to false?}static void handle_irq_reg124(struct bcm43xx_private *bcm){ if (!bcm->reg124_set_0x4) return; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | 0x4); //FIXME: reset reg124_set_0x4 to false?}static void handle_irq_pmq(struct bcm43xx_private *bcm){ u32 tmp; //TODO: AP mode. while (1) { tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); if (!(tmp & 0x00000008)) break; } /* 16bit write is odd, but correct. */ bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);}static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, u16 ram_offset, u16 shm_size_offset){ u32 value; u16 size = 0; /* Timestamp. */ //FIXME: assumption: The chip sets the timestamp value = 0; bcm43xx_ram_write(bcm, ram_offset++, value); bcm43xx_ram_write(bcm, ram_offset++, value); size += 8; /* Beacon Interval / Capability Information */ value = 0x0000;//FIXME: Which interval? value |= (1 << 0) << 16; /* ESS */ value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? if (!bcm->ieee->open_wep) value |= (1 << 4) << 16; /* Privacy */ bcm43xx_ram_write(bcm, ram_offset++, value); size += 4; /* SSID */ //TODO /* FH Parameter Set */ //TODO /* DS Parameter Set */ //TODO /* CF Parameter Set */ //TODO /* TIM */ //TODO bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);}static void handle_irq_beacon(struct bcm43xx_private *bcm){ u32 status; bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); if ((status & 0x1) && (status & 0x2)) { /* ACK beacon IRQ. */ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_BEACON); bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; return; } if (!(status & 0x1)) { bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); status |= 0x1; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); } if (!(status & 0x2)) { bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); status |= 0x2; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); }}/* Interrupt handler bottom-half */static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm){ u32 reason; u32 dma_reason[6]; u32 merged_dma_reason = 0; int i, activity = 0; unsigned long flags;#ifdef CONFIG_BCM43XX_DEBUG u32 _handled = 0x00000000;# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)#else# define bcmirq_handled(irq) do { /* nothing */ } while (0)#endif /* CONFIG_BCM43XX_DEBUG*/ spin_lock_irqsave(&bcm->irq_lock, flags); reason = bcm->irq_reason; for (i = 5; i >= 0; i--) { dma_reason[i] = bcm->dma_reason[i]; merged_dma_reason |= dma_reason[i]; } if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { /* TX error. We get this when Template Ram is written in wrong endianess * in dummy_tx(). We also get this if something is wrong with the TX header * on DMA or PIO queues. * Maybe we get this in other error conditions, too. */ printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); } if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) { printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " "0x%08X, 0x%08X, 0x%08X, " "0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); bcm43xx_controller_restart(bcm, "DMA error"); mmiowb(); spin_unlock_irqrestore(&bcm->irq_lock, flags); return; } if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) { printkl(KERN_ERR PFX "DMA error: " "0x%08X, 0x%08X, 0x%08X, " "0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); } if (reason & BCM43xx_IRQ_PS) { handle_irq_ps(bcm); bcmirq_handled(BCM43xx_IRQ_PS); } if (reason & BCM43xx_IRQ_REG124) { handle_irq_reg124(bcm); bcmirq_handled(BCM43xx_IRQ_REG124); } if (reason & BCM43xx_IRQ_BEACON) { if (bcm->ieee->iw_mode == IW_MODE_MASTER) handle_irq_beacon(bcm); bcmirq_handled(BCM43xx_IRQ_BEACON); } if (reason & BCM43xx_IRQ_PMQ) { handle_irq_pmq(bcm); bcmirq_handled(BCM43xx_IRQ_PMQ); } if (reason & BCM43xx_IRQ_SCAN) { /*TODO*/ //bcmirq_handled(BCM43xx_IRQ_SCAN); } if (reason & BCM43xx_IRQ_NOISE) { handle_irq_noise(bcm); bcmirq_handled(BCM43xx_IRQ_NOISE); } /* Check the DMA reason registers for received data. */ if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); else bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); /* We intentionally don't set "activity" to 1, here. */ } assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); else bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3); activity = 1; } assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE)); assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE)); bcmirq_handled(BCM43xx_IRQ_RX); if (reason & BCM43xx_IRQ_XMIT_STATUS) { handle_irq_transmit_status(bcm); activity = 1; //TODO: In AP mode, this also causes sending of powersave responses. bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } /* IRQ_PIO_WORKAROUND is handled in the top-half. */ bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);#ifdef CONFIG_BCM43XX_DEBUG if (unlikely(reason & ~_handled)) { printkl(KERN_WARNING PFX "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", reason, (reason & ~_handled), dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3]); }#endif#undef bcmirq_handled if (!modparam_noleds) bcm43xx_leds_update(bcm, activity); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&bcm->irq_lock, flags);}static void pio_irq_workaround(struct bcm43xx_private *bcm, u16 base, int queueidx){ u16 rxctl; rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; else bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;}static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason){ if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); } bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON, bcm->dma_reason[0]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, bcm->dma_reason[1]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, bcm->dma_reason[2]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, bcm->dma_reason[3]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, bcm->dma_reason[4]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON, bcm->dma_reason[5]);}/* Interrupt handler top-half */static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id){ irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; u32 reason; if (!bcm) return IRQ_NONE; spin_lock(&bcm->irq_lock); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -