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

📄 sunhme.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	return 0;}/* Figure out whether we have an internal or external transceiver. */static void happy_meal_transceiver_check(struct happy_meal *hp,					 struct hmeal_tcvregs *tregs){	unsigned long tconfig = hme_read32(hp, &tregs->cfg);	ASD(("happy_meal_transceiver_check: tcfg=%08lx ", tconfig));	if(hp->happy_flags & HFLAG_POLL) {		/* If we are polling, we must stop to get the transceiver type. */		ASD(("<polling> "));		if(hp->tcvr_type == internal) {			if(tconfig & TCV_CFG_MDIO1) {				ASD(("<internal> <poll stop> "));				happy_meal_poll_stop(hp, tregs);				hp->paddr = TCV_PADDR_ETX;				hp->tcvr_type = external;				ASD(("<external>\n"));				tconfig &= ~(TCV_CFG_PENABLE);				tconfig |= TCV_CFG_PSELECT;				hme_write32(hp, &tregs->cfg, tconfig);			}		} else {			if(hp->tcvr_type == external) {				ASD(("<external> "));				if(!(hme_read32(hp, &tregs->status) >> 16)) {					ASD(("<poll stop> "));					happy_meal_poll_stop(hp, tregs);					hp->paddr = TCV_PADDR_ITX;					hp->tcvr_type = internal;					ASD(("<internal>\n"));					hme_write32(hp, &tregs->cfg,						    hme_read32(hp, &tregs->cfg) &						    ~(TCV_CFG_PSELECT));				}				ASD(("\n"));			} else {				ASD(("<none>\n"));			}		}	} else {		unsigned long reread = hme_read32(hp, &tregs->cfg);		/* Else we can just work off of the MDIO bits. */		ASD(("<not polling> "));		if(reread & TCV_CFG_MDIO1) {			hme_write32(hp, &tregs->cfg, tconfig | TCV_CFG_PSELECT);			hp->paddr = TCV_PADDR_ETX;			hp->tcvr_type = external;			ASD(("<external>\n"));		} else {			if(reread & TCV_CFG_MDIO0) {				hme_write32(hp, &tregs->cfg,					    tconfig & ~(TCV_CFG_PSELECT));				hp->paddr = TCV_PADDR_ITX;				hp->tcvr_type = internal;				ASD(("<internal>\n"));			} else {				printk("happy meal: Transceiver and a coke please.");				hp->tcvr_type = none; /* Grrr... */				ASD(("<none>\n"));			}		}	}}/* The receive ring buffers are a bit tricky to get right.  Here goes... * * The buffers we dma into must be 64 byte aligned.  So we use a special * alloc_skb() routine for the happy meal to allocate 64 bytes more than * we really need. * * We use skb_reserve() to align the data block we get in the skb.  We * also program the etxregs->cfg register to use an offset of 2.  This * imperical constant plus the ethernet header size will always leave * us with a nicely aligned ip header once we pass things up to the * protocol layers. * * The numbers work out to: * *         Max ethernet frame size         1518 *         Ethernet header size              14 *         Happy Meal base offset             2 * * Say a skb data area is at 0xf001b010, and its size alloced is * (ETH_FRAME_LEN + 64 + 2) = (1514 + 64 + 2) = 1580 bytes. * * First our alloc_skb() routine aligns the data base to a 64 byte * boundry.  We now have 0xf001b040 as our skb data address.  We * plug this into the receive descriptor address. * * Next, we skb_reserve() 2 bytes to account for the Happy Meal offset. * So now the data we will end up looking at starts at 0xf001b042.  When * the packet arrives, we will check out the size received and subtract * this from the skb->length.  Then we just pass the packet up to the * protocols as is, and allocate a new skb to replace this slot we have * just received from. * * The ethernet layer will strip the ether header from the front of the * skb we just sent to it, this leaves us with the ip header sitting * nicely aligned at 0xf001b050.  Also, for tcp and udp packets the * Happy Meal has even checksummed the tcp/udp data for us.  The 16 * bit checksum is obtained from the low bits of the receive descriptor * flags, thus: * * 	skb->csum = rxd->rx_flags & 0xffff; * 	skb->ip_summed = CHECKSUM_HW; * * before sending off the skb to the protocols, and we are good as gold. */static inline void happy_meal_clean_rings(struct happy_meal *hp){	int i;	for(i = 0; i < RX_RING_SIZE; i++) {		if(hp->rx_skbs[i] != NULL) {			dev_kfree_skb(hp->rx_skbs[i]);			hp->rx_skbs[i] = NULL;		}	}	for(i = 0; i < TX_RING_SIZE; i++) {		if(hp->tx_skbs[i] != NULL) {			dev_kfree_skb(hp->tx_skbs[i]);			hp->tx_skbs[i] = NULL;		}	}}static void happy_meal_init_rings(struct happy_meal *hp, int from_irq){	struct hmeal_init_block *hb = hp->happy_block;	struct device *dev = hp->dev;	int i, gfp_flags = GFP_KERNEL;	if(from_irq || in_interrupt())		gfp_flags = GFP_ATOMIC;	HMD(("happy_meal_init_rings: counters to zero, "));	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;	/* Free any skippy bufs left around in the rings. */	HMD(("clean, "));	happy_meal_clean_rings(hp);	/* Now get new skippy bufs for the receive ring. */	HMD(("init rxring, "));	for(i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb;		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags | GFP_DMA);		if(!skb)			continue;		hp->rx_skbs[i] = skb;		skb->dev = dev;		/* Because we reserve afterwards. */		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));#ifdef CONFIG_PCI		if(hp->happy_flags & HFLAG_PCI) {			pcihme_write_rxd(&hb->happy_meal_rxd[i],					 (RXFLAG_OWN |					  ((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),					 (u32)virt_to_bus((volatile void *)skb->data));		} else#endif#ifndef __sparc_v9__		if (sparc_cpu_model == sun4d) {			__u32 va = (__u32)hp->sun4d_buffers + i * PAGE_SIZE;			hb->happy_meal_rxd[i].rx_addr =				iounit_map_dma_page(va, skb->data, hp->happy_sbus_dev->my_bus);			hb->happy_meal_rxd[i].rx_flags =				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));		} else#endif		{			hb->happy_meal_rxd[i].rx_addr = sbus_dvma_addr(skb->data);			hb->happy_meal_rxd[i].rx_flags =				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));		}		skb_reserve(skb, RX_OFFSET);	}	HMD(("init txring, "));	for(i = 0; i < TX_RING_SIZE; i++)		hb->happy_meal_txd[i].tx_flags = 0;	HMD(("done\n"));}#ifndef __sparc_v9__static void sun4c_happy_meal_init_rings(struct happy_meal *hp){	struct hmeal_init_block *hb = hp->happy_block;	__u32 hbufs = hp->s4c_buf_dvma;	int i;	HMD(("happy_meal_init_rings: counters to zero, "));	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;	HMD(("init rxring, "));	for(i = 0; i < RX_RING_SIZE; i++) {		hb->happy_meal_rxd[i].rx_addr = hbufs + hbuf_offset(rx_buf, i);		hb->happy_meal_rxd[i].rx_flags =			(RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16));	}	HMD(("init txring, "));	for(i = 0; i < TX_RING_SIZE; i++)		hb->happy_meal_txd[i].tx_flags = 0;	HMD(("done\n"));}#endifstatic void happy_meal_begin_auto_negotiation(struct happy_meal *hp,					      struct hmeal_tcvregs *tregs,					      struct ethtool_cmd *ep){	int timeout;	/* Read all of the registers we are interested in now. */	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);	hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);	/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);	if(ep == NULL || ep->autoneg == AUTONEG_ENABLE) {		/* Advertise everything we can support. */		if(hp->sw_bmsr & BMSR_10HALF)			hp->sw_advertise |= (ADVERTISE_10HALF);		else			hp->sw_advertise &= ~(ADVERTISE_10HALF);		if(hp->sw_bmsr & BMSR_10FULL)			hp->sw_advertise |= (ADVERTISE_10FULL);		else			hp->sw_advertise &= ~(ADVERTISE_10FULL);		if(hp->sw_bmsr & BMSR_100HALF)			hp->sw_advertise |= (ADVERTISE_100HALF);		else			hp->sw_advertise &= ~(ADVERTISE_100HALF);		if(hp->sw_bmsr & BMSR_100FULL)			hp->sw_advertise |= (ADVERTISE_100FULL);		else			hp->sw_advertise &= ~(ADVERTISE_100FULL);		happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);		/* XXX Currently no Happy Meal cards I know off support 100BaseT4,		 * XXX and this is because the DP83840 does not support it, changes		 * XXX would need to be made to the tx/rx logic in the driver as well		 * XXX so I completely skip checking for it in the BMSR for now.		 */#ifdef AUTO_SWITCH_DEBUG		ASD(("%s: Advertising [ ", hp->dev->name));		if(hp->sw_advertise & ADVERTISE_10HALF)			ASD(("10H "));		if(hp->sw_advertise & ADVERTISE_10FULL)			ASD(("10F "));		if(hp->sw_advertise & ADVERTISE_100HALF)			ASD(("100H "));		if(hp->sw_advertise & ADVERTISE_100FULL)			ASD(("100F "));#endif		/* Enable Auto-Negotiation, this is usually on already... */		hp->sw_bmcr |= BMCR_ANENABLE;		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		/* Restart it to make sure it is going. */		hp->sw_bmcr |= BMCR_ANRESTART;		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		/* BMCR_ANRESTART self clears when the process has begun. */		timeout = 64;  /* More than enough. */		while(--timeout) {			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);			if(!(hp->sw_bmcr & BMCR_ANRESTART))				break; /* got it. */			udelay(10);		}		if(!timeout) {			printk("%s: Happy Meal would not start auto negotiation "			       "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr);			printk("%s: Performing force link detection.\n",			       hp->dev->name);			goto force_link;		} else {			hp->timer_state = arbwait;		}	} else {force_link:		/* Force the link up, trying first a particular mode.		 * Either we are here at the request of ethtool or		 * because the Happy Meal would not start to autoneg.		 */		/* Disable auto-negotiation in BMCR, enable the duplex and		 * speed setting, init the timer state machine, and fire it off.		 */		if(ep == NULL || ep->autoneg == AUTONEG_ENABLE) {			hp->sw_bmcr = BMCR_SPEED100;		} else {			if(ep->speed == SPEED_100)				hp->sw_bmcr = BMCR_SPEED100;			else				hp->sw_bmcr = 0;			if(ep->duplex == DUPLEX_FULL)				hp->sw_bmcr |= BMCR_FULLDPLX;		}		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		/* OK, seems we need do disable the transceiver for the first		 * tick to make sure we get an accurate link state at the		 * second tick.		 */		hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,						       DP83840_CSCONFIG);		hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);		happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,				      hp->sw_csconfig);		hp->timer_state = ltrywait;	}	hp->timer_ticks = 0;	hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */	hp->happy_timer.data = (unsigned long) hp;	hp->happy_timer.function = &happy_meal_timer;	add_timer(&hp->happy_timer);}#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */static int happy_meal_init(struct happy_meal *hp, int from_irq){	struct hmeal_gregs   *gregs        = hp->gregs;	struct hmeal_etxregs *etxregs      = hp->etxregs;	struct hmeal_erxregs *erxregs      = hp->erxregs;	struct hmeal_bigmacregs *bregs     = hp->bigmacregs;	struct hmeal_tcvregs *tregs        = hp->tcvregs;	unsigned long regtmp, rxcfg;	unsigned char *e = &hp->dev->dev_addr[0];	/* If auto-negotiation timer is running, kill it. */	del_timer(&hp->happy_timer);	HMD(("happy_meal_init: happy_flags[%08x] ",	     hp->happy_flags));	if(!(hp->happy_flags & HFLAG_INIT)) {		HMD(("set HFLAG_INIT, "));		hp->happy_flags |= HFLAG_INIT;		happy_meal_get_counters(hp, bregs);	}	/* Stop polling. */	HMD(("to happy_meal_poll_stop\n"));	happy_meal_poll_stop(hp, tregs);	/* Stop transmitter and receiver. */	HMD(("happy_meal_init: to happy_meal_stop\n"));	happy_meal_stop(hp, gregs);	/* Alloc and reset the tx/rx descriptor chains. */	HMD(("happy_meal_init: to happy_meal_init_rings\n"));#ifndef __sparc_v9__		if(sparc_cpu_model == sun4c)		sun4c_happy_meal_init_rings(hp);	else#endif			happy_meal_init_rings(hp, from_irq);	/* Shut up the MIF. */	HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",	     hme_read32(hp, &tregs->int_mask)));	hme_write32(hp, &tregs->int_mask, 0xffff);	/* See if we can enable the MIF frame on this card to speak to the DP83840. */	if(hp->happy_flags & HFLAG_FENABLE) {		HMD(("use frame old[%08x], ",		     hme_read32(hp, &tregs->cfg)));		hme_write32(hp, &tregs->cfg,			    hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_BENABLE));	} else {		HMD(("use bitbang old[%08x], ",		     hme_read32(hp, &tregs->cfg)));		hme_write32(hp, &tregs->cfg,			    hme_read32(hp, &tregs->cfg) | TCV_CFG_BENABLE);	}	/* Check the state of the transceiver. */	HMD(("to happy_meal_transceiver_check\n"));	happy_meal_transceiver_check(hp, tregs);	/* Put the Big Mac into a sane state. */	HMD(("happy_meal_init: "));	switch(hp->tcvr_type) {	case none:		/* Cannot operate if we don't know the transceiver type! */		HMD(("AAIEEE no transceiver type, EAGAIN"));		return -EAGAIN;	case internal:		/* Using the MII buffers. */		HMD(("internal, using MII, "));		hme_write32(hp, &bregs->xif_cfg, 0);		break;	case external:		/* Not using the MII, disable it. */		HMD(("external, disable MII, "));		hme_write32(hp, &bregs->xif_cfg, BIGMAC_XCFG_MIIDISAB);		break;	};	if(happy_meal_tcvr_reset(hp, tregs))		return -EAGAIN;	/* Reset the Happy Meal Big Mac transceiver and the receiver. */	HMD(("tx/rx reset, "));	happy_meal_tx_reset(hp, bregs);	happy_meal_rx_reset(hp, bregs);	/* Set jam size and inter-packet gaps to reasonable defaults. */	HMD(("jsize/ipg1/ipg2, "));	hme_write32(hp, &bregs->jsize, DEFAULT_JAMSIZE);	hme_write32(hp, &bregs->ipkt_gap1, DEFAULT_IPG1);	hme_write32(hp, &bregs->ipkt_gap2, DEFAULT_IPG2);	/* Load up the MAC address and random seed. */	HMD(("rseed/macaddr, "));	/* The docs recommend to use the 10LSB of our MAC here. */	hme_write32(hp, &bregs->rand_seed, ((e[5] | e[4]<<8)&0x3ff));	hme_write32(hp, &bregs->mac_addr2, ((e[4] << 8) | e[5]));	hme_write32(hp, &bregs->mac_addr1, ((e[2] << 8) | e[3]));	hme_write32(hp, &bregs->mac_addr0, ((e[0] << 8) | e[1]));	HMD(("htable, "));	if((hp->dev->flags & IFF_ALLMULTI) ||	   (hp->dev->mc_count > 64)) {		hme_write32(hp, &bregs->htable0, 0xffff);		hme_write32(hp, &bregs->htable1, 0xffff);		hme_write32(hp, &bregs->htable2, 0xffff);		hme_write32(hp, &bregs->htable3, 0xffff);	} else if((hp->dev->flags & IFF_PROMISC) == 0) {		u16 hash_table[4];		struct dev_mc_list *dmi = hp->dev->mc_list;

⌨️ 快捷键说明

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