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

📄 acenic.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
#if (BITS_PER_LONG == 64)			writel(0, &ap->tx_ring[idx].addr.addrhi);#endif			writel(0, &ap->tx_ring[idx].addr.addrlo);			writel(0, &ap->tx_ring[idx].flagsize);			idx = (idx + 1) % TX_RING_ENTRIES;		} while (idx != txcsm);		if (ap->tx_full && dev->tbusy &&		    (((ap->tx_prd + 1) % TX_RING_ENTRIES) != txcsm)){			ap->tx_full = 0;			dev->tbusy = 0;			mark_bh(NET_BH);			/*			 * TX ring is no longer full, aka the			 * transmitter is working fine - kill timer.			 */			del_timer(&ap->timer);		}		ap->tx_ret_csm = txcsm;	}	evtcsm = readl(&regs->EvtCsm);	evtprd = ap->evt_prd;	if (evtcsm != evtprd){		evtcsm = ace_handle_event(dev, evtcsm, evtprd);	}	writel(evtcsm, &regs->EvtCsm);	writel(0, &regs->Mb0Lo);	spin_unlock(&ap->lock);}static int ace_open(struct device *dev){	struct ace_private *ap;	struct ace_regs *regs;	struct cmd cmd;	ap = dev->priv;	regs = ap->regs;	if (!(ap->fw_running)){		printk(KERN_WARNING "%s: firmware not running!\n", dev->name);		return -EBUSY;	}	writel(dev->mtu + ETH_HLEN + 4, &regs->IfMtu);	cmd.evt = C_HOST_STATE;	cmd.code = C_C_STACK_UP;	cmd.idx = 0;	ace_issue_cmd(regs, &cmd);	if (ap->jumbo)		ace_load_jumbo_rx_ring(dev);	if (dev->flags & IFF_PROMISC){		cmd.evt = C_SET_PROMISC_MODE;		cmd.code = C_C_PROMISC_ENABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->promisc = 1;	}else		ap->promisc = 0;	ap->mcast_all = 0;#if 0	{ long myjif = jiffies + HZ;	while (time_before(jiffies, myjif));	}	cmd.evt = C_LNK_NEGOTIATION;	cmd.code = 0;	cmd.idx = 0;	ace_issue_cmd(regs, &cmd);#endif	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	MOD_INC_USE_COUNT;	/*	 * Setup the timer	 */	init_timer(&ap->timer);	ap->timer.data = (unsigned long)dev;	ap->timer.function = ace_timer;	return 0;}static int ace_close(struct device *dev){	struct ace_private *ap;	struct ace_regs *regs;	struct cmd cmd;	unsigned long flags;	short i;	dev->start = 0;	set_bit(0, (void*)&dev->tbusy);	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	del_timer(&ap->timer);	if (ap->promisc){		cmd.evt = C_SET_PROMISC_MODE;		cmd.code = C_C_PROMISC_DISABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->promisc = 0;	}	cmd.evt = C_HOST_STATE;	cmd.code = C_C_STACK_DOWN;	cmd.idx = 0;	ace_issue_cmd(regs, &cmd);	spin_lock_irqsave(&ap->lock, flags);	for (i = 0; i < TX_RING_ENTRIES; i++) {		if (ap->tx_skbuff[i]) {			writel(0, &ap->tx_ring[i].addr.addrhi);			writel(0, &ap->tx_ring[i].addr.addrlo);			writel(0, &ap->tx_ring[i].flagsize);			dev_kfree_skb(ap->tx_skbuff[i]);		}	}	if (ap->jumbo)		ace_flush_jumbo_rx_ring(dev);	spin_unlock_irqrestore(&ap->lock, flags);	MOD_DEC_USE_COUNT;	return 0;}static int ace_start_xmit(struct sk_buff *skb, struct device *dev){	struct ace_private *ap = (struct ace_private *)dev->priv;	struct ace_regs *regs = ap->regs;	unsigned long flags;	unsigned long addr;	u32 idx, flagsize;	spin_lock_irqsave(&ap->lock, flags);	idx = ap->tx_prd;	ap->tx_skbuff[idx] = skb;	addr = virt_to_bus(skb->data);#if (BITS_PER_LONG == 64)	writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);#endif	writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo);	flagsize = (skb->len << 16) | (DESC_END) ;	writel(flagsize, &ap->tx_ring[idx].flagsize);	mb();	idx = (idx + 1) % TX_RING_ENTRIES;	ap->tx_prd = idx;	writel(idx, &regs->TxPrd);	if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){		ap->tx_full = 1;		set_bit(0, (void*)&dev->tbusy);		/*		 * Queue is full, add timer to detect whether the		 * transmitter is stuck. Use mod_timer as we can get		 * into the situation where we risk adding several		 * timers.		 */		mod_timer(&ap->timer, jiffies + (3 * HZ));	}	spin_unlock_irqrestore(&ap->lock, flags);	dev->trans_start = jiffies;	return 0;}static int ace_change_mtu(struct device *dev, int new_mtu){	struct ace_private *ap = dev->priv;	struct ace_regs *regs = ap->regs;	if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU))		return -EINVAL;	writel(new_mtu + ETH_HLEN + 4, &regs->IfMtu);	dev->mtu = new_mtu;	if (new_mtu > ACE_STD_MTU){		if (!(ap->jumbo)){			printk(KERN_INFO "%s: Enabling Jumbo frame "			       "support\n", dev->name);			ap->jumbo = 1;			ace_load_jumbo_rx_ring(dev);		}		ap->jumbo = 1;	}else{		if (ap->jumbo){			ace_flush_jumbo_rx_ring(dev);			printk(KERN_INFO "%s: Disabling Jumbo frame support\n",			       dev->name);		}		ap->jumbo = 0;	}	return 0;}/* * Set the hardware MAC address. */static int ace_set_mac_addr(struct device *dev, void *p){	struct sockaddr *addr=p;	struct ace_regs *regs;	u16 *da;	struct cmd cmd;	if(dev->start)		return -EBUSY;	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);	da = (u16 *)dev->dev_addr;	regs = ((struct ace_private *)dev->priv)->regs;	writel(da[0], &regs->MacAddrHi);	writel((da[1] << 16) | da[2], &regs->MacAddrLo);	cmd.evt = C_SET_MAC_ADDR;	cmd.code = 0;	cmd.idx = 0;	ace_issue_cmd(regs, &cmd);	return 0;}static void ace_set_multicast_list(struct device *dev){	struct ace_private *ap = dev->priv;	struct ace_regs *regs = ap->regs;	struct cmd cmd;	if ((dev->flags & IFF_ALLMULTI) && !(ap->mcast_all)) {		cmd.evt = C_SET_MULTICAST_MODE;		cmd.code = C_C_MCAST_ENABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->mcast_all = 1;	} else if (ap->mcast_all){		cmd.evt = C_SET_MULTICAST_MODE;		cmd.code = C_C_MCAST_ENABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->mcast_all = 0;	}	if ((dev->flags & IFF_PROMISC) && !(ap->promisc)) {		cmd.evt = C_SET_PROMISC_MODE;		cmd.code = C_C_PROMISC_ENABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->promisc = 1;	}else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)){		cmd.evt = C_SET_PROMISC_MODE;		cmd.code = C_C_PROMISC_DISABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		ap->promisc = 0;	}	/*	 * For the time being multicast relies on the upper layers	 * filtering it properly. The Firmware does not allow one to	 * set the entire multicast list at a time and keeping track of	 * it here is going to be messy.	 */	if ((dev->mc_count) && !(ap->mcast_all)) {		cmd.evt = C_SET_MULTICAST_MODE;		cmd.code = C_C_MCAST_ENABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);	}else if (!ap->mcast_all) {		cmd.evt = C_SET_MULTICAST_MODE;		cmd.code = C_C_MCAST_DISABLE;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);	}}static struct net_device_stats *ace_get_stats(struct device *dev){	struct ace_private *ap = dev->priv;	return(&ap->stats);}__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)){	unsigned long tdest;	u32 *wsrc;	short tsize, i;	if (size <= 0)		return;	while (size > 0){		tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),			    min(size, ACE_WINDOW_SIZE));		tdest = (unsigned long)&regs->Window +			(dest & (ACE_WINDOW_SIZE - 1));		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);#ifdef __BIG_ENDIAN#error "data must be swapped here"#else/* * XXX - special memcpy needed here!!! */		wsrc = src;		for (i = 0; i < (tsize / 4); i++){			writel(wsrc[i], tdest + i*4);		}#endif		dest += tsize;		src += tsize;		size -= tsize;	}	return;}__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size)){	unsigned long tdest;	short tsize = 0, i;	if (size <= 0)		return;	while (size > 0){		tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),			    min(size, ACE_WINDOW_SIZE));		tdest = (unsigned long)&regs->Window +			(dest & (ACE_WINDOW_SIZE - 1));		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);		for (i = 0; i < (tsize / 4); i++){			writel(0, tdest + i*4);		}		dest += tsize;		size -= tsize;	}	return;}/* * Download the firmware into the SRAM on the NIC * * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */__initfunc(int ace_load_firmware(struct device *dev)){	struct ace_private *ap;	struct ace_regs *regs;	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	if (!(readl(&regs->CpuCtrl) & CPU_HALTED)){		printk(KERN_ERR "%s: trying to download firmware while the "		       "CPU is running!\n", dev->name);		return -EFAULT;	}	/*	 * Do not try to clear more than 512KB or we end up seeing	 * funny things on NICs with only 512KB SRAM	 */	ace_clear(regs, 0x2000, 0x80000-0x2000);	if (ap->version == 1){		ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen);		ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen);		ace_copy(regs, tigonFwRodata, tigonFwRodataAddr,			 tigonFwRodataLen);		ace_clear(regs, tigonFwBssAddr, tigonFwBssLen);		ace_clear(regs, tigonFwSbssAddr, tigonFwSbssLen);	}else if (ap->version == 2){		ace_clear(regs, tigon2FwBssAddr, tigon2FwBssLen);		ace_clear(regs, tigon2FwSbssAddr, tigon2FwSbssLen);		ace_copy(regs, tigon2FwText, tigon2FwTextAddr,tigon2FwTextLen);		ace_copy(regs, tigon2FwRodata, tigon2FwRodataAddr,			 tigon2FwRodataLen);		ace_copy(regs, tigon2FwData, tigon2FwDataAddr,tigon2FwDataLen);	}	return 0;}/* * The eeprom on the AceNIC is an Atmel i2c EEPROM. * * Accessing the EEPROM is `interesting' to say the least - don't read * this code right after dinner. * * This is all about black magic and bit-banging the device .... I * wonder in what hospital they have put the guy who designed the i2c * specs. * * Oh yes, this is only the beginning! */static void eeprom_start(struct ace_regs *regs){	u32 local = readl(&regs->LocalCtrl);	udelay(1);	local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local |= EEPROM_CLK_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local &= ~EEPROM_DATA_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local &= ~EEPROM_CLK_OUT;	writel(local, &regs->LocalCtrl);	mb();}static void eeprom_prep(struct ace_regs *regs, u8 magic){	short i;	u32 local;	udelay(2);	local = readl(&regs->LocalCtrl);	local &= ~EEPROM_DATA_OUT;	local |= EEPROM_WRITE_ENABLE;	writel(local, &regs->LocalCtrl);	mb();	for (i = 0; i < 8; i++, magic <<= 1) {		udelay(2);		if (magic & 0x80) 			local |= EEPROM_DATA_OUT;		else			local &= ~EEPROM_DATA_OUT;		writel(local, &regs->LocalCtrl);		mb();		udelay(1);		local |= EEPROM_CLK_OUT;		writel(local, &regs->LocalCtrl);		mb();		udelay(1);		local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);		writel(local, &regs->LocalCtrl);		mb();	}}static int eeprom_check_ack(struct ace_regs *regs){	int state;	u32 local;	local = readl(&regs->LocalCtrl);	local &= ~EEPROM_WRITE_ENABLE;	writel(local, &regs->LocalCtrl);	mb();	udelay(2);	local |= EEPROM_CLK_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	/* sample data in middle of high clk */	state = (readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0;	udelay(1);	mb();	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);	mb();	return state;}static void eeprom_stop(struct ace_regs *regs){	u32 local;	local = readl(&regs->LocalCtrl);	local |= EEPROM_WRITE_ENABLE;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local &= ~EEPROM_DATA_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local |= EEPROM_CLK_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(1);	local |= EEPROM_DATA_OUT;	writel(local, &regs->LocalCtrl);	mb();	udelay(2);	local &= ~EEPROM_CLK_OUT;	writel(local, &regs->LocalCtrl);	mb();}/* * Read a whole byte from the EEPROM. */static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset){	u32 local;	short i;	u8 result = 0;	if (!regs){		printk(KERN_ERR "No regs!\n");		return 0;	}	eeprom_start(regs);	eeprom_prep(regs, EEPROM_WRITE_SELECT);	if (eeprom_check_ack(regs)){		printk("Unable to sync eeprom\n");		return 0;	}	eeprom_prep(regs, (offset >> 8) & 0xff);	if (eeprom_check_ack(regs))		return 0;	eeprom_prep(regs, offset & 0xff);	if (eeprom_check_ack(regs))		return 0;	eeprom_start(regs);	eeprom_prep(regs, EEPROM_READ_SELECT);	if (eeprom_check_ack(regs))		return 0;	for (i = 0; i < 8; i++) {		local = readl(&regs->LocalCtrl);		local &= ~EEPROM_WRITE_ENABLE;		writel(local, &regs->LocalCtrl);		udelay(2);		mb();		local |= EEPROM_CLK_OUT;		writel(local, &regs->LocalCtrl);		udelay(1);		mb();		/* sample data mid high clk */		result = (result << 1) |			((readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0);		udelay(1);		mb();		local = readl(&regs->LocalCtrl);		local &= ~EEPROM_CLK_OUT;		writel(local, &regs->LocalCtrl);		mb();		if (i == 7){			local |= EEPROM_WRITE_ENABLE;			writel(local, &regs->LocalCtrl);			mb();		}	}	local |= EEPROM_DATA_OUT;	writel(local, &regs->LocalCtrl);	udelay(1);	writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);	udelay(2);	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);	eeprom_stop(regs);	return result;}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h   -c -o acenic.o acenic.c" * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -