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

📄 via-velocity.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	{		/*		 *	Map the linear network buffer into PCI space and		 *	add it to the transmit ring.		 */		tdinfo->skb = skb;		tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);		td_ptr->tdesc0.pktsize = pktlen;		td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);		td_ptr->td_buf[0].pa_high = 0;		td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;		tdinfo->nskb_dma = 1;		td_ptr->tdesc1.CMDZ = 2;	}	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {		td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);		td_ptr->tdesc1.pqinf.priority = 0;		td_ptr->tdesc1.pqinf.CFI = 0;		td_ptr->tdesc1.TCR |= TCR0_VETAG;	}	/*	 *	Handle hardware checksum	 */	if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)				 && (skb->ip_summed == CHECKSUM_HW)) {		struct iphdr *ip = skb->nh.iph;		if (ip->protocol == IPPROTO_TCP)			td_ptr->tdesc1.TCR |= TCR0_TCPCK;		else if (ip->protocol == IPPROTO_UDP)			td_ptr->tdesc1.TCR |= (TCR0_UDPCK);		td_ptr->tdesc1.TCR |= TCR0_IPCK;	}	{		int prev = index - 1;		if (prev < 0)			prev = vptr->options.numtx - 1;		td_ptr->tdesc0.owner = OWNED_BY_NIC;		vptr->td_used[qnum]++;		vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;		if (AVAIL_TD(vptr, qnum) < 1)			netif_stop_queue(dev);		td_ptr = &(vptr->td_rings[qnum][prev]);		td_ptr->td_buf[0].queue = 1;		mac_tx_queue_wake(vptr->mac_regs, qnum);	}	dev->trans_start = jiffies;	spin_unlock_irqrestore(&vptr->lock, flags);	return 0;}/** *	velocity_intr		-	interrupt callback *	@irq: interrupt number *	@dev_instance: interrupting device *	@pt_regs: CPU register state at interrupt * *	Called whenever an interrupt is generated by the velocity *	adapter IRQ line. We may not be the source of the interrupt *	and need to identify initially if we are, and if not exit as *	efficiently as possible. */ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs){	struct net_device *dev = dev_instance;	struct velocity_info *vptr = dev->priv;	u32 isr_status;	int max_count = 0;	spin_lock(&vptr->lock);	isr_status = mac_read_isr(vptr->mac_regs);	/* Not us ? */	if (isr_status == 0) {		spin_unlock(&vptr->lock);		return IRQ_NONE;	}	mac_disable_int(vptr->mac_regs);	/*	 *	Keep processing the ISR until we have completed	 *	processing and the isr_status becomes zero	 */	 	while (isr_status != 0) {		mac_write_isr(vptr->mac_regs, isr_status);		if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))			velocity_error(vptr, isr_status);		if (isr_status & (ISR_PRXI | ISR_PPRXI))			max_count += velocity_rx_srv(vptr, isr_status);		if (isr_status & (ISR_PTXI | ISR_PPTXI))			max_count += velocity_tx_srv(vptr, isr_status);		isr_status = mac_read_isr(vptr->mac_regs);		if (max_count > vptr->options.int_works)		{			printk(KERN_WARNING "%s: excessive work at interrupt.\n", 				dev->name);			max_count = 0;		}	}	spin_unlock(&vptr->lock);	mac_enable_int(vptr->mac_regs);	return IRQ_HANDLED;}/** *	velocity_set_multi	-	filter list change callback *	@dev: network device * *	Called by the network layer when the filter lists need to change *	for a velocity adapter. Reload the CAMs with the new address *	filter ruleset. */ static void velocity_set_multi(struct net_device *dev){	struct velocity_info *vptr = dev->priv;	struct mac_regs * regs = vptr->mac_regs;	u8 rx_mode;	int i;	struct dev_mc_list *mclist;	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		writel(0xffffffff, &regs->MARCAM[0]);		writel(0xffffffff, &regs->MARCAM[4]);		rx_mode = (RCR_AM | RCR_AB | RCR_PROM);	} else if ((dev->mc_count > vptr->multicast_limit)		   || (dev->flags & IFF_ALLMULTI)) {		writel(0xffffffff, &regs->MARCAM[0]);		writel(0xffffffff, &regs->MARCAM[4]);		rx_mode = (RCR_AM | RCR_AB);	} else {		int offset = MCAM_SIZE - vptr->multicast_limit;		mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {			mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);			vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);		}		mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);		rx_mode = (RCR_AM | RCR_AB);	}	if (dev->mtu > 1500)		rx_mode |= RCR_AL;	BYTE_REG_BITS_ON(rx_mode, &regs->RCR);}/** *	velocity_get_status	-	statistics callback *	@dev: network device * *	Callback from the network layer to allow driver statistics *	to be resynchronized with hardware collected state. In the *	case of the velocity we need to pull the MIB counters from *	the hardware into the counters before letting the network *	layer display them. */ static struct net_device_stats *velocity_get_stats(struct net_device *dev){	struct velocity_info *vptr = dev->priv;		/* If the hardware is down, don't touch MII */	if(!netif_running(dev))		return &vptr->stats;	spin_lock_irq(&vptr->lock);	velocity_update_hw_mibs(vptr);	spin_unlock_irq(&vptr->lock);	vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];	vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];	vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];//  unsigned long   rx_dropped;     /* no space in linux buffers    */	vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];	/* detailed rx_errors: *///  unsigned long   rx_length_errors;//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */	vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error *///  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      *///  unsigned long   rx_missed_errors;   /* receiver missed packet   */	/* detailed tx_errors *///  unsigned long   tx_fifo_errors;	return &vptr->stats;}/** *	velocity_ioctl		-	ioctl entry point *	@dev: network device *	@rq: interface request ioctl *	@cmd: command code * *	Called when the user issues an ioctl request to the network *	device in question. The velocity interface supports MII. */ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct velocity_info *vptr = dev->priv;	int ret;	/* If we are asked for information and the device is power	   saving then we need to bring the device back up to talk to it */	   		if(!netif_running(dev))		pci_set_power_state(vptr->pdev, 0);			switch (cmd) {	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */	case SIOCGMIIREG:	/* Read MII PHY register. */	case SIOCSMIIREG:	/* Write to MII PHY register. */		ret = velocity_mii_ioctl(dev, rq, cmd);		break;	default:		ret = -EOPNOTSUPP;	}	if(!netif_running(dev))		pci_set_power_state(vptr->pdev, 3);					return ret;}/* *	Definition for our device driver. The PCI layer interface *	uses this to handle all our card discover and plugging */ static struct pci_driver velocity_driver = {      .name	= VELOCITY_NAME,      .id_table	= velocity_id_table,      .probe	= velocity_found1,      .remove	= __devexit_p(velocity_remove1),#ifdef CONFIG_PM      .suspend	= velocity_suspend,      .resume	= velocity_resume,#endif};/** *	velocity_init_module	-	load time function * *	Called when the velocity module is loaded. The PCI driver *	is registered with the PCI layer, and in turn will call *	the probe functions for each velocity adapter installed *	in the system. */ static int __init velocity_init_module(void){	int ret;	velocity_register_notifier();	ret = pci_module_init(&velocity_driver);	if (ret < 0)		velocity_unregister_notifier();	return ret;}/** *	velocity_cleanup	-	module unload * *	When the velocity hardware is unloaded this function is called. *	It will clean up the notifiers and the unregister the PCI  *	driver interface for this hardware. This in turn cleans up *	all discovered interfaces before returning from the function */ static void __exit velocity_cleanup_module(void){	velocity_unregister_notifier();	pci_unregister_driver(&velocity_driver);}module_init(velocity_init_module);module_exit(velocity_cleanup_module);/* * MII access , media link mode setting functions */  /** *	mii_init	-	set up MII *	@vptr: velocity adapter *	@mii_status:  links tatus * *	Set up the PHY for the current link state. */ static void mii_init(struct velocity_info *vptr, u32 mii_status){	u16 BMCR;	switch (PHYID_GET_PHY_ID(vptr->phy_id)) {	case PHYID_CICADA_CS8201:		/*		 *	Reset to hardware default		 */		MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);		/*		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it		 *	off it in NWay-forced half mode for NWay-forced v.s. 		 *	legacy-forced issue.		 */		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);		else			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);		/*		 *	Turn on Link/Activity LED enable bit for CIS8201		 */		MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);		break;	case PHYID_VT3216_32BIT:	case PHYID_VT3216_64BIT:		/*		 *	Reset to hardware default		 */		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);		/*		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it		 *	off it in NWay-forced half mode for NWay-forced v.s. 		 *	legacy-forced issue		 */		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);		else			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);		break;	case PHYID_MARVELL_1000:	case PHYID_MARVELL_1000S:		/*		 *	Assert CRS on Transmit 		 */		MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);		/*		 *	Reset to hardware default 		 */		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);		break;	default:		;	}	velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);	if (BMCR & BMCR_ISO) {		BMCR &= ~BMCR_ISO;		velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);	}}/** *	safe_disable_mii_autopoll	-	autopoll off *	@regs: velocity registers * *	Turn off the autopoll and wait for it to disable on the chip */ static void safe_disable_mii_autopoll(struct mac_regs * regs){	u16 ww;	/*  turn off MAUTO */	writeb(0, &regs->MIICR);	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {		udelay(1);		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))			break;	}}/** *	enable_mii_autopoll	-	turn on autopolling *	@regs: velocity registers * *	Enable the MII link status autopoll feature on the Velocity *	hardware. Wait for it to enable. */static void enable_mii_autopoll(struct mac_regs * regs){	int ii;	writeb(0, &(regs->MIICR));	writeb(MIIADR_SWMPL, &regs->MIIADR);	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {		udelay(1);		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))			break;	}	writeb(MIICR_MAUTO, &regs->MIICR);	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {		udelay(1);		if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))			break;	}}/** *	velocity_mii_read	-	read MII data *	@regs: velocity registers *	@index: MII register index *	@data: buffer for received data * *	Perform a single read of an MII 16bit register. Returns zero *	on success or -ETIMEDOUT if the PHY did not respond. */ static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data){	u16 ww;	/*	 *	Disable MIICR_MAUTO, so that mii addr can be set normally	 */	safe_disable_mii_autopoll(regs);	writeb(index, &regs->MIIADR);	BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {		if (!(readb(&regs->MIICR) & MIICR_RCMD))			break;	}	*data = readw(&regs->MIIDATA);	enable_mii_autopoll(regs);	if (ww == W_MAX_TIMEOUT)		return -ETIMEDOUT;	return 0;}/** *	velocity_mii_write	-	write MII data *	@regs: velocity registers *	@index: MII register index *	@data: 16bit data for the MII register * *	Perform a single write to an MII 16bit register. Returns zero *	on success or -ETIMEDOUT if the PHY did not respond. */ static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data){	u16 ww;	/*	 *	Disable MIICR_MAUTO, so that mii addr can be set normally	 */	safe_disable_mii_autopoll(regs);	/* MII reg offset */	writeb(mii_addr, &regs->MIIADR);	/* set MII data */	writew(data, &regs->MIIDATA);	/* turn on MIICR_WCMD */	BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);	/* W_MAX_TIMEOUT is the timeout period */	for (w

⌨️ 快捷键说明

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