📄 bcm43xx_main.c
字号:
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow &= ~0xa0000; sbtmstatelow |= 0x80000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { old_core = bcm->current_core; err = bcm43xx_switch_core(bcm, active_80211_core); if (err) goto out; sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow &= ~0x20000000; sbtmstatelow |= 0x20000000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); err = bcm43xx_switch_core(bcm, old_core); }out: return err;}static void handle_irq_transmit_status(struct bcm43xx_private *bcm){ u32 v0, v1; u16 tmp; struct bcm43xx_xmitstatus stat; assert(bcm->current_core->id == BCM43xx_COREID_80211); assert(bcm->current_core->rev >= 5); 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_IGNORE) continue; if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) { //TODO: packet was not acked (was lost) } //TODO: There are more (unknown) flags to test. see bcm43xx_main.h if (bcm43xx_using_pio(bcm)) bcm43xx_pio_handle_xmitstatus(bcm, &stat); else bcm43xx_dma_handle_xmitstatus(bcm, &stat); }}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 == bcm->current_core->radio->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 = bcm->current_core->radio->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 = bcm->current_core->radio; 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; if (average > -65) bcm->stats.link_quality = 0; else if (average > -75) bcm->stats.link_quality = 1; else if (average > -85) bcm->stats.link_quality = 2; else bcm->stats.link_quality = 3;// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, 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[4]; int 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*/ bcm43xx_lock_mmio(bcm, flags); reason = bcm->irq_reason; dma_reason[0] = bcm->dma_reason[0]; dma_reason[1] = bcm->dma_reason[1]; dma_reason[2] = bcm->dma_reason[2]; dma_reason[3] = bcm->dma_reason[3]; 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((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) | (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) | (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) { printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3]); bcm43xx_controller_restart(bcm, "DMA error"); bcm43xx_unlock_mmio(bcm, flags); return; } if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) | (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) | (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) { printkl(KERN_ERR PFX "DMA error: " "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3]); } 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. */ assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue0); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (likely(bcm->current_core->rev < 5)) { if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue3); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); activity = 1; } else assert(0); } bcmirq_handled(BCM43xx_IRQ_RX); if (reason & BCM43xx_IRQ_XMIT_STATUS) { if (bcm->current_core->rev >= 5) { handle_irq_transmit_status(bcm); activity = 1; } //TODO: In AP mode, this also causes sending of powersave responses. bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } /* We get spurious IRQs, althought they are masked. * Assume they are void and ignore them. */ bcmirq_handled(~(bcm->irq_savedstate)); /* 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); bcm43xx_unlock_mmio(bcm, flags);}static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason, u32 mask){ bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) & 0x0001dc00; bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) & 0x0000dc00; bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) & 0x0000dc00; bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) & 0x0001dc00; if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */#define apply_pio_workaround(BASE, QNUM) \ do { \ if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \ bcm->dma_reason[QNUM] |= 0x00010000; \ else \ bcm->dma_reason[QNUM] &= ~0x00010000; \ } while (0) apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0); apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1); apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2); apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);#undef apply_pio_workaround } bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason & mask); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, bcm->dma_reason[0]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, bcm->dma_reason[1]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, bcm->dma_reason[2]); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, bcm->dma_reason[3]);}/* Interrupt handler top-half */static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs){ irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; u32 reason, mask; if (!bcm) return IRQ_NONE; spin_lock(&bcm->_lock); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) { /* irq not for us (shared irq) */ ret = IRQ_NONE; goto out; } mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -