⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bcm43xx_main.c

📁 博通的bcm43xx系列Minipci接口无线网卡驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -