hp100.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,162 行 · 第 1/5 页

C
2,162
字号
 *  hp100_rxfill - attempt to fill the Rx Ring will empty skb's * * Makes assumption that skb's are always contiguous memory areas and * therefore PDLs contain only 2 physical fragments. * -  While the number of Rx PDLs with buffers is less than maximum *      a.  Get a maximum packet size skb *      b.  Put the physical address of the buffer into the PDL. *      c.  Output physical address of PDL to adapter. */static void hp100_rxfill(struct net_device *dev){	int ioaddr = dev->base_addr;	struct hp100_private *lp = (struct hp100_private *) dev->priv;	hp100_ring_t *ringptr;#ifdef HP100_DEBUG_B	hp100_outw(0x4208, TRACE);	printk("hp100: %s: rxfill\n", dev->name);#endif	hp100_page(PERFORMANCE);	while (lp->rxrcommit < MAX_RX_PDL) {		/*		   ** Attempt to get a buffer and build a Rx PDL.		 */		ringptr = lp->rxrtail;		if (0 == hp100_build_rx_pdl(ringptr, dev)) {			return;	/* None available, return */		}		/* Hand this PDL over to the card */		/* Note: This needs performance page selected! */#ifdef HP100_DEBUG_BM		printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",				     dev->name, lp->rxrcommit, (u_int) ringptr->pdl,				     (u_int) ringptr->pdl_paddr, (u_int) ringptr->pdl[3]);#endif		hp100_outl((u32) ringptr->pdl_paddr, RX_PDA);		lp->rxrcommit += 1;		lp->rxrtail = ringptr->next;	}}/* * BM_shutdown - shutdown bus mastering and leave chip in reset state */static void hp100_BM_shutdown(struct net_device *dev){	int ioaddr = dev->base_addr;	struct hp100_private *lp = (struct hp100_private *) dev->priv;	unsigned long time;#ifdef HP100_DEBUG_B	hp100_outw(0x4209, TRACE);	printk("hp100: %s: bm shutdown\n", dev->name);#endif	hp100_page(PERFORMANCE);	hp100_outw(0xfefe, IRQ_MASK);	/* mask off all ints */	hp100_outw(0xffff, IRQ_STATUS);	/* Ack all ints */	/* Ensure Interrupts are off */	hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);	/* Disable all MAC activity */	hp100_page(MAC_CTRL);	hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);	/* stop rx/tx */	/* If cascade MMU is not already in reset */	if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) {		/* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so		 * MMU pointers will not be reset out from underneath		 */		hp100_page(MAC_CTRL);		for (time = 0; time < 5000; time++) {			if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE))				break;		}		/* Shutdown algorithm depends on the generation of Cascade */		if (lp->chip == HP100_CHIPID_LASSEN) {	/* ETR shutdown/reset */			/* Disable Busmaster mode and wait for bit to go to zero. */			hp100_page(HW_MAP);			hp100_andb(~HP100_BM_MASTER, BM);			/* 100 ms timeout */			for (time = 0; time < 32000; time++) {				if (0 == (hp100_inb(BM) & HP100_BM_MASTER))					break;			}		} else {	/* Shasta or Rainier Shutdown/Reset */			/* To ensure all bus master inloading activity has ceased,			 * wait for no Rx PDAs or no Rx packets on card. 			 */			hp100_page(PERFORMANCE);			/* 100 ms timeout */			for (time = 0; time < 10000; time++) {				/* RX_PDL: PDLs not executed. */				/* RX_PKT_CNT: RX'd packets on card. */				if ((hp100_inb(RX_PDL) == 0) && (hp100_inb(RX_PKT_CNT) == 0))					break;			}			if (time >= 10000)				printk("hp100: %s: BM shutdown error.\n", dev->name);			/* To ensure all bus master outloading activity has ceased,			 * wait until the Tx PDA count goes to zero or no more Tx space			 * available in the Tx region of the card. 			 */			/* 100 ms timeout */			for (time = 0; time < 10000; time++) {				if ((0 == hp100_inb(TX_PKT_CNT)) &&				    (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE)))					break;			}			/* Disable Busmaster mode */			hp100_page(HW_MAP);			hp100_andb(~HP100_BM_MASTER, BM);		}	/* end of shutdown procedure for non-etr parts */		hp100_cascade_reset(dev, 1);	}	hp100_page(PERFORMANCE);	/* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */	/* Busmaster mode should be shut down now. */}static int hp100_check_lan(struct net_device *dev){	struct hp100_private *lp = (struct hp100_private *) dev->priv;	if (lp->lan_type < 0) {	/* no LAN type detected yet? */		hp100_stop_interface(dev);		if ((lp->lan_type = hp100_sense_lan(dev)) < 0) {			printk("hp100: %s: no connection found - check wire\n", dev->name);			hp100_start_interface(dev);	/* 10Mb/s RX packets maybe handled */			return -EIO;		}		if (lp->lan_type == HP100_LAN_100)			lp->hub_status = hp100_login_to_vg_hub(dev, 0);	/* relogin */		hp100_start_interface(dev);	}	return 0;}/*  *  transmit functions *//* tx function for busmaster mode */static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev){	unsigned long flags;	int i, ok_flag;	int ioaddr = dev->base_addr;	struct hp100_private *lp = (struct hp100_private *) dev->priv;	hp100_ring_t *ringptr;#ifdef HP100_DEBUG_B	hp100_outw(0x4210, TRACE);	printk("hp100: %s: start_xmit_bm\n", dev->name);#endif	if (skb == NULL) {		return 0;	}	if (skb->len <= 0)		return 0;			if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) {		skb = skb_padto(skb, ETH_ZLEN);		if (skb == NULL)			return 0;	}	/* Get Tx ring tail pointer */	if (lp->txrtail->next == lp->txrhead) {		/* No memory. */#ifdef HP100_DEBUG		printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);#endif		/* not waited long enough since last tx? */		if (jiffies - dev->trans_start < HZ)			return -EAGAIN;		if (hp100_check_lan(dev))			return -EIO;		if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) {			/* we have a 100Mb/s adapter but it isn't connected to hub */			printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name);			hp100_stop_interface(dev);			lp->hub_status = hp100_login_to_vg_hub(dev, 0);			hp100_start_interface(dev);		} else {			spin_lock_irqsave(&lp->lock, flags);			hp100_ints_off();	/* Useful ? Jean II */			i = hp100_sense_lan(dev);			hp100_ints_on();			spin_unlock_irqrestore(&lp->lock, flags);			if (i == HP100_LAN_ERR)				printk("hp100: %s: link down detected\n", dev->name);			else if (lp->lan_type != i) {	/* cable change! */				/* it's very hard - all network settings must be changed!!! */				printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);				lp->lan_type = i;				hp100_stop_interface(dev);				if (lp->lan_type == HP100_LAN_100)					lp->hub_status = hp100_login_to_vg_hub(dev, 0);				hp100_start_interface(dev);			} else {				printk("hp100: %s: interface reset\n", dev->name);				hp100_stop_interface(dev);				if (lp->lan_type == HP100_LAN_100)					lp->hub_status = hp100_login_to_vg_hub(dev, 0);				hp100_start_interface(dev);			}		}		dev->trans_start = jiffies;		return -EAGAIN;	}	/*	 * we have to turn int's off before modifying this, otherwise	 * a tx_pdl_cleanup could occur at the same time	 */	spin_lock_irqsave(&lp->lock, flags);	ringptr = lp->txrtail;	lp->txrtail = ringptr->next;	/* Check whether packet has minimal packet size */	ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;	i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;	ringptr->skb = skb;	ringptr->pdl[0] = ((1 << 16) | i);	/* PDH: 1 Fragment & length */	if (lp->chip == HP100_CHIPID_SHASTA) {		/* TODO:Could someone who has the EISA card please check if this works? */		ringptr->pdl[2] = i;	} else {		/* Lassen */		/* In the PDL, don't use the padded size but the real packet size: */		ringptr->pdl[2] = skb->len;	/* 1st Frag: Length of frag */	}	/* Conversion to new PCI API : map skbuf data to PCI bus.	 * Doc says it's OK for EISA as well - Jean II */	ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE));	/* 1st Frag: Adr. of data */	/* Hand this PDL to the card. */	hp100_outl(ringptr->pdl_paddr, TX_PDA_L);	/* Low Prio. Queue */	lp->txrcommit++;	spin_unlock_irqrestore(&lp->lock, flags);	/* Update statistics */	lp->stats.tx_packets++;	lp->stats.tx_bytes += skb->len;	dev->trans_start = jiffies;	return 0;}/* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the * number of commited packets. It then frees the skb's of the packets that * obviously have been sent to the network. * * Needs the PERFORMANCE page selected.  */static void hp100_clean_txring(struct net_device *dev){	struct hp100_private *lp = (struct hp100_private *) dev->priv;	int ioaddr = dev->base_addr;	int donecount;#ifdef HP100_DEBUG_B	hp100_outw(0x4211, TRACE);	printk("hp100: %s: clean txring\n", dev->name);#endif	/* How many PDLs have been transmitted? */	donecount = (lp->txrcommit) - hp100_inb(TX_PDL);#ifdef HP100_DEBUG	if (donecount > MAX_TX_PDL)		printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n", dev->name);#endif	for (; 0 != donecount; donecount--) {#ifdef HP100_DEBUG_BM		printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",				dev->name, (u_int) lp->txrhead->skb->data,				lp->txrcommit, hp100_inb(TX_PDL), donecount);#endif		/* Conversion to new PCI API : NOP */		pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE);		dev_kfree_skb_any(lp->txrhead->skb);		lp->txrhead->skb = (void *) NULL;		lp->txrhead = lp->txrhead->next;		lp->txrcommit--;	}}/* tx function for slave modes */static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev){	unsigned long flags;	int i, ok_flag;	int ioaddr = dev->base_addr;	u_short val;	struct hp100_private *lp = (struct hp100_private *) dev->priv;#ifdef HP100_DEBUG_B	hp100_outw(0x4212, TRACE);	printk("hp100: %s: start_xmit\n", dev->name);#endif	if (skb == NULL) {		return 0;	}	if (skb->len <= 0)		return 0;	if (hp100_check_lan(dev))		return -EIO;	/* If there is not enough free memory on the card... */	i = hp100_inl(TX_MEM_FREE) & 0x7fffffff;	if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) {#ifdef HP100_DEBUG		printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i);#endif		/* not waited long enough since last failed tx try? */		if (jiffies - dev->trans_start < HZ) {#ifdef HP100_DEBUG			printk("hp100: %s: trans_start timing problem\n",			       dev->name);#endif			return -EAGAIN;		}		if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) {			/* we have a 100Mb/s adapter but it isn't connected to hub */			printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name);			hp100_stop_interface(dev);			lp->hub_status = hp100_login_to_vg_hub(dev, 0);			hp100_start_interface(dev);		} else {			spin_lock_irqsave(&lp->lock, flags);			hp100_ints_off();	/* Useful ? Jean II */			i = hp100_sense_lan(dev);			hp100_ints_on();			spin_unlock_irqrestore(&lp->lock, flags);			if (i == HP100_LAN_ERR)				printk("hp100: %s: link down detected\n", dev->name);			else if (lp->lan_type != i) {	/* cable change! */				/* it's very hard - all network setting must be changed!!! */				printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);				lp->lan_type = i;				hp100_stop_interface(dev);				if (lp->lan_type == HP100_LAN_100)					lp->hub_status = hp100_login_to_vg_hub(dev, 0);				hp100_start_interface(dev);			} else {				printk("hp100: %s: interface reset\n", dev->name);				hp100_stop_interface(dev);				if (lp->lan_type == HP100_LAN_100)					lp->hub_status = hp100_login_to_vg_hub(dev, 0);				hp100_start_interface(dev);				mdelay(1);			}		}		dev->trans_start = jiffies;		return -EAGAIN;	}	for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) {#ifdef HP100_DEBUG_TX		printk("hp100: %s: start_xmit: busy\n", dev->name);#endif	}	spin_lock_irqsave(&lp->lock, flags);	hp100_ints_off();	val = hp100_inw(IRQ_STATUS);	/* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set	 * when the current packet being transmitted on the wire is completed. */	hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS);#ifdef HP100_DEBUG_TX	printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",			dev->name, val, hp100_inw(IRQ_MASK), (int) skb->len);#endif	ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;	i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;	hp100_outw(i, DATA32);	/* tell card the total packet length */	hp100_outw(i, FRAGMENT_LEN);	/* and first/only fragment length    */	if (lp->mode == 2) {	/* memory mapped */		if (lp->mem_ptr_virt) {	/* high pci memory was remapped */			/* Note: The J2585B needs alignment to 32bits here!  */			memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3);			if (!ok_flag)				memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len);		} else {			/* Note: The J2585B needs alignment to 32bits here!  */			isa_memcpy_toio(lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3);			if (!ok_flag)				isa_memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len);		}	} else {		/* programmed i/o */		outsl(ioaddr + HP100_REG_DATA32, skb->data,		      (skb->len + 3) >> 2);		if (!ok_flag)			for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4)				hp100_outl(0, DATA32);	}	hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW);	/* send packet */	lp->stats.tx_packets++;	lp->stats.tx_bytes += skb->len;	dev->trans_start = jiffies;	hp100_ints_on();

⌨️ 快捷键说明

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