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

📄 sunhme.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	while ((hme_read32(hp, bregs + BMAC_TXSWRESET) & 1) && --tries)		udelay(20);	/* Lettuce, tomato, buggy hardware (no extra charge)? */	if (!tries)		printk(KERN_ERR "happy meal: Transceiver BigMac ATTACK!");	/* Take care. */	HMD(("done\n"));}static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs){	int tries = RX_RESET_TRIES;	HMD(("happy_meal_rx_reset: reset, "));	/* We have a special on GNU/Viking hardware bugs today. */	hme_write32(hp, bregs + BMAC_RXSWRESET, 0);	while ((hme_read32(hp, bregs + BMAC_RXSWRESET) & 1) && --tries)		udelay(20);	/* Will that be all? */	if (!tries)		printk(KERN_ERR "happy meal: Receiver BigMac ATTACK!");	/* Don't forget your vik_1137125_wa.  Have a nice day. */	HMD(("done\n"));}#define STOP_TRIES         16static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs){	int tries = STOP_TRIES;	HMD(("happy_meal_stop: reset, "));	/* We're consolidating our STB products, it's your lucky day. */	hme_write32(hp, gregs + GREG_SWRESET, GREG_RESET_ALL);	while (hme_read32(hp, gregs + GREG_SWRESET) && --tries)		udelay(20);	/* Come back next week when we are "Sun Microelectronics". */	if (!tries)		printk(KERN_ERR "happy meal: Fry guys.");	/* Remember: "Different name, same old buggy as shit hardware." */	HMD(("done\n"));}static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs){	struct net_device_stats *stats = &hp->net_stats;	stats->rx_crc_errors += hme_read32(hp, bregs + BMAC_RCRCECTR);	hme_write32(hp, bregs + BMAC_RCRCECTR, 0);	stats->rx_frame_errors += hme_read32(hp, bregs + BMAC_UNALECTR);	hme_write32(hp, bregs + BMAC_UNALECTR, 0);	stats->rx_length_errors += hme_read32(hp, bregs + BMAC_GLECTR);	hme_write32(hp, bregs + BMAC_GLECTR, 0);	stats->tx_aborted_errors += hme_read32(hp, bregs + BMAC_EXCTR);	stats->collisions +=		(hme_read32(hp, bregs + BMAC_EXCTR) +		 hme_read32(hp, bregs + BMAC_LTCTR));	hme_write32(hp, bregs + BMAC_EXCTR, 0);	hme_write32(hp, bregs + BMAC_LTCTR, 0);}#if 0static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs){	u32 tmp;	int speed;	ASD(("happy_meal_poll_start: "));	if (!(hp->happy_flags & HFLAG_POLLENABLE)) {		HMD(("polling disabled, return\n"));		return;	}	/* Start the MIF polling on the external transceiver. */	ASD(("polling on, "));	tmp = hme_read32(hp, tregs + TCVR_CFG);	tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);	tmp |= ((hp->paddr & 0x1f) << 10);	tmp |= (TCV_PADDR_ETX << 3);	tmp |= TCV_CFG_PENABLE;	hme_write32(hp, tregs + TCVR_CFG, tmp);	/* Let the bits set. */	udelay(200);	/* We are polling now. */	ASD(("now polling, "));	hp->happy_flags |= HFLAG_POLL;	/* Clear the poll flags, get the basic status as of now. */	hp->poll_flag = 0;	hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;	if (hp->happy_flags & HFLAG_AUTO)		speed = hp->auto_speed;	else		speed = hp->forced_speed;	/* Listen only for the MIF interrupts we want to hear. */	ASD(("mif ints on, "));	if (speed == 100)		hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);	else		hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);	ASD(("done\n"));}#endifstatic void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs){	ASD(("happy_meal_poll_stop: "));	/* If polling disabled or not polling already, nothing to do. */	if ((hp->happy_flags & (HFLAG_POLLENABLE | HFLAG_POLL)) !=	   (HFLAG_POLLENABLE | HFLAG_POLL)) {		HMD(("not polling, return\n"));		return;	}	/* Shut up the MIF. */	ASD(("were polling, mif ints off, "));	hme_write32(hp, tregs + TCVR_IMASK, 0xffff);	/* Turn off polling. */	ASD(("polling off, "));	hme_write32(hp, tregs + TCVR_CFG,		    hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_PENABLE));	/* We are no longer polling. */	hp->happy_flags &= ~(HFLAG_POLL);	/* Let the bits set. */	udelay(200);	ASD(("done\n"));}/* Only Sun can take such nice parts and fuck up the programming interface * like this.  Good job guys... */#define TCVR_RESET_TRIES       16 /* It should reset quickly        */#define TCVR_UNISOLATE_TRIES   32 /* Dis-isolation can take longer. */static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs){	u32 tconfig;	int result, tries = TCVR_RESET_TRIES;	tconfig = hme_read32(hp, tregs + TCVR_CFG);	ASD(("happy_meal_tcvr_reset: tcfg<%08lx> ", tconfig));	if (hp->tcvr_type == external) {		ASD(("external<"));		hme_write32(hp, tregs + TCVR_CFG, tconfig & ~(TCV_CFG_PSELECT));		hp->tcvr_type = internal;		hp->paddr = TCV_PADDR_ITX;		ASD(("ISOLATE,"));		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,				      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if (result == TCVR_FAILURE) {			ASD(("phyread_fail>\n"));			return -1;		}		ASD(("phyread_ok,PSELECT>"));		hme_write32(hp, tregs + TCVR_CFG, tconfig | TCV_CFG_PSELECT);		hp->tcvr_type = external;		hp->paddr = TCV_PADDR_ETX;	} else {		if (tconfig & TCV_CFG_MDIO1) {			ASD(("internal<PSELECT,"));			hme_write32(hp, tregs + TCVR_CFG, (tconfig | TCV_CFG_PSELECT));			ASD(("ISOLATE,"));			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,					      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));			result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);			if (result == TCVR_FAILURE) {				ASD(("phyread_fail>\n"));				return -1;			}			ASD(("phyread_ok,~PSELECT>"));			hme_write32(hp, tregs + TCVR_CFG, (tconfig & ~(TCV_CFG_PSELECT)));			hp->tcvr_type = internal;			hp->paddr = TCV_PADDR_ITX;		}	}	ASD(("BMCR_RESET "));	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, BMCR_RESET);	while (--tries) {		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if (result == TCVR_FAILURE)			return -1;		hp->sw_bmcr = result;		if (!(result & BMCR_RESET))			break;		udelay(20);	}	if (!tries) {		ASD(("BMCR RESET FAILED!\n"));		return -1;	}	ASD(("RESET_OK\n"));	/* Get fresh copies of the PHY registers. */	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);	ASD(("UNISOLATE"));	hp->sw_bmcr &= ~(BMCR_ISOLATE);	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);	tries = TCVR_UNISOLATE_TRIES;	while (--tries) {		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if (result == TCVR_FAILURE)			return -1;		if (!(result & BMCR_ISOLATE))			break;		udelay(20);	}	if (!tries) {		ASD((" FAILED!\n"));		return -1;	}	ASD((" SUCCESS and CSCONFIG_DFBYPASS\n"));	if (!is_lucent_phy(hp)) {		result = happy_meal_tcvr_read(hp, tregs,					      DP83840_CSCONFIG);		happy_meal_tcvr_write(hp, tregs,				      DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS));	}	return 0;}/* Figure out whether we have an internal or external transceiver. */static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs){	unsigned long tconfig = hme_read32(hp, tregs + TCVR_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 + TCVR_CFG, tconfig);			}		} else {			if (hp->tcvr_type == external) {				ASD(("<external> "));				if (!(hme_read32(hp, tregs + TCVR_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 + TCVR_CFG,						    hme_read32(hp, tregs + TCVR_CFG) &						    ~(TCV_CFG_PSELECT));				}				ASD(("\n"));			} else {				ASD(("<none>\n"));			}		}	} else {		u32 reread = hme_read32(hp, tregs + TCVR_CFG);		/* Else we can just work off of the MDIO bits. */		ASD(("<not polling> "));		if (reread & TCV_CFG_MDIO1) {			hme_write32(hp, tregs + TCVR_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 + TCVR_CFG,					    tconfig & ~(TCV_CFG_PSELECT));				hp->paddr = TCV_PADDR_ITX;				hp->tcvr_type = internal;				ASD(("<internal>\n"));			} else {				printk(KERN_ERR "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 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) {			struct sk_buff *skb = hp->rx_skbs[i];			struct happy_meal_rxd *rxd;			u32 dma_addr;			rxd = &hp->happy_block->happy_meal_rxd[i];			dma_addr = hme_read_desc32(hp, &rxd->rx_addr);			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);			dev_kfree_skb_any(skb);			hp->rx_skbs[i] = NULL;		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (hp->tx_skbs[i] != NULL) {			struct sk_buff *skb = hp->tx_skbs[i];			struct happy_meal_txd *txd;			u32 dma_addr;			txd = &hp->happy_block->happy_meal_txd[i];			dma_addr = hme_read_desc32(hp, &txd->tx_addr);			hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);			dev_kfree_skb_any(skb);			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 net_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);		if (!skb) {			hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);			continue;		}		hp->rx_skbs[i] = skb;		skb->dev = dev;		/* Because we reserve afterwards. */		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));		hme_write_rxd(hp, &hb->happy_meal_rxd[i],			      (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),			      hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));		skb_reserve(skb, RX_OFFSET);	}	HMD(("init txring, "));	for (i = 0; i < TX_RING_SIZE; i++)		hme_write_txd(hp, &hb->happy_meal_txd[i], 0, 0);	HMD(("done\n"));}static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,					      unsigned long 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. */

⌨️ 快捷键说明

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