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

📄 gmac.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
			MII_CR_RAN|			MII_CR_SPEEDSEL2 /* chip specific, gigabit enable ? */);	data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;	mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);}static intmii_lookup_and_reset(struct gmac *gm){	int	i, mii_status, mii_control;	gm->phy_addr = -1;	gm->phy_type = PHY_UNKNOWN;	/* Hard reset the PHY */	pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gm->of_node, 0, 0);			/* Find the PHY */	for(i=0; i<=31; i++) {		mii_control = mii_read(gm, i, MII_CR);		mii_status = mii_read(gm, i, MII_SR);		if (mii_control != -1  && mii_status != -1 &&			(mii_control != 0xffff || mii_status != 0xffff))			break;	}	gm->phy_addr = i;	if (gm->phy_addr > 31)		return 0;	/* Reset it */	if (mii_do_reset_phy(gm, gm->phy_addr))		goto fail;		/* Read the PHY ID */	gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |		mii_read(gm, gm->phy_addr, MII_ID1);#ifdef DEBUG_PHY	printk(KERN_INFO "%s: PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);#endif	if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {		gm->phy_type = PHY_B5400;		printk(KERN_INFO  "%s: Found Broadcom BCM5400 PHY (Gigabit)\n",			gm->dev->name);		mii_init_BCM5400(gm);			} else if ((gm->phy_id & MII_BCM5401_MASK) == MII_BCM5401_ID) {		gm->phy_type = PHY_B5401;		printk(KERN_INFO  "%s: Found Broadcom BCM5401 PHY (Gigabit)\n",			gm->dev->name);		mii_init_BCM5401(gm);			} else if ((gm->phy_id & MII_BCM5411_MASK) == MII_BCM5411_ID) {		gm->phy_type = PHY_B5411;		printk(KERN_INFO  "%s: Found Broadcom BCM5411 PHY (Gigabit)\n",			gm->dev->name);		mii_init_BCM5411(gm);			} else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {		gm->phy_type = PHY_B5201;		printk(KERN_INFO "%s: Found Broadcom BCM5201 PHY\n", gm->dev->name);	} else if ((gm->phy_id & MII_BCM5221_MASK) == MII_BCM5221_ID) {		gm->phy_type = PHY_B5221;		printk(KERN_INFO "%s: Found Broadcom BCM5221 PHY\n", gm->dev->name);	} else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) {		gm->phy_type = PHY_LXT971;		printk(KERN_INFO "%s: Found LevelOne LX971 PHY\n", gm->dev->name);	} else {		printk(KERN_WARNING "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n",			gm->dev->name, gm->phy_id);	}	return 1;	fail:	gm->phy_addr = -1;	return 0;}/*  * Setup the PHY autonegociation parameters *  * Code to force the PHY duplex mode and speed should be * added here */static voidmii_setup_phy(struct gmac *gm){	int data;		/* Stop auto-negociation */	data = mii_read(gm, gm->phy_addr, MII_CR);	mii_write(gm, gm->phy_addr, MII_CR, data & ~MII_CR_ASSE);	/* Set advertisement to 10/100 and Half/Full duplex	 * (full capabilities) */	data = mii_read(gm, gm->phy_addr, MII_ANA);	data |= MII_ANA_TXAM | MII_ANA_FDAM | MII_ANA_10M;	mii_write(gm, gm->phy_addr, MII_ANA, data);		/* Restart auto-negociation */	data = mii_read(gm, gm->phy_addr, MII_CR);	data |= MII_CR_ASSE;	mii_write(gm, gm->phy_addr, MII_CR, data);	data |= MII_CR_RAN;	mii_write(gm, gm->phy_addr, MII_CR, data);}/*  * Turn On/Off the gmac cell inside Uni-N *  * ToDo: Add code to support powering down of the PHY. */static voidgmac_set_power(struct gmac *gm, int power_up){	if (power_up) {		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gm->of_node, 0, 1);		if (gm->pci_devfn != 0xff) {			u16 cmd;						/*			 * Make sure PCI is correctly configured			 *			 * We use old pci_bios versions of the function since, by			 * default, gmac is not powered up, and so will be absent			 * from the kernel initial PCI lookup. 			 * 			 * Should be replaced by 2.4 new PCI mecanisms and really			 * regiser the device.			 */			pcibios_read_config_word(gm->pci_bus, gm->pci_devfn,				PCI_COMMAND, &cmd);			cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;	    		pcibios_write_config_word(gm->pci_bus, gm->pci_devfn,	    			PCI_COMMAND, cmd);	    		pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,	    			PCI_LATENCY_TIMER, 16);	    		pcibios_write_config_byte(gm->pci_bus, gm->pci_devfn,	    			PCI_CACHE_LINE_SIZE, 8);		}	} else {		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gm->of_node, 0, 0);	}}/* * Makes sure the GMAC cell is powered up, and reset it */static intgmac_powerup_and_reset(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	int timeout;		/* turn on GB clock */	gmac_set_power(gm, 1);	/* Perform a software reset */	GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);	for (timeout = 100; timeout > 0; --timeout) {		mdelay(10);		if ((GM_IN(GM_RESET) & (GM_RESET_TX | GM_RESET_RX)) == 0) {			/* Mask out all chips interrupts */			GM_OUT(GM_IRQ_MASK, 0xffffffff);			GM_OUT(GM_MAC_TX_RESET, GM_MAC_TX_RESET_NOW);			GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW);			return 0;		}	}	printk(KERN_ERR "%s reset failed!\n", dev->name);	gmac_set_power(gm, 0);	gm->phy_type = 0;	return -1;}/* * Set the MAC duplex mode. *  * Side effect: stops Tx MAC */static voidgmac_set_duplex_mode(struct gmac *gm, int full_duplex){	/* Stop Tx MAC */	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);	while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)		;		if (full_duplex) {		GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER			| GM_MAC_TX_CONF_IGNORE_COLL);		GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);	} else {		GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_IGNORE_CARRIER			| GM_MAC_TX_CONF_IGNORE_COLL);		GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_DISABLE_ECHO);	}}/* Set the MAC gigabit mode. Side effect: stops Tx MAC */static voidgmac_set_gigabit_mode(struct gmac *gm, int gigabit){	/* Stop Tx MAC */	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);	while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)		;		if (gigabit) {		GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);	} else {		GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);	}}/* * Initialize a bunch of registers to put the chip into a known * and hopefully happy state */static voidgmac_mac_init(struct gmac *gm, unsigned char *mac_addr){	int i, fifo_size;	/* Set random seed to low bits of MAC address */	GM_OUT(GM_MAC_RANDOM_SEED, mac_addr[5] | (mac_addr[4] << 8));		/* Configure the data path mode to MII/GII */	GM_OUT(GM_PCS_DATAPATH_MODE, GM_PCS_DATAPATH_MII);		/* Configure XIF to MII mode. Full duplex led is set	 * by Apple, so...	 */	GM_OUT(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_TX_MII_OUT_EN		| GM_MAC_XIF_CONF_FULL_DPLX_LED);	/* Mask out all MAC interrupts */	GM_OUT(GM_MAC_TX_MASK, 0xffff);	GM_OUT(GM_MAC_RX_MASK, 0xffff);	GM_OUT(GM_MAC_CTRLSTAT_MASK, 0xff);		/* Setup bits of MAC */	GM_OUT(GM_MAC_SND_PAUSE, GM_MAC_SND_PAUSE_DEFAULT);	GM_OUT(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_RCV_PAUSE_EN);		/* Configure GEM DMA */	GM_OUT(GM_GCONF, GM_GCONF_BURST_SZ |		(31 << GM_GCONF_TXDMA_LIMIT_SHIFT) |		(31 << GM_GCONF_RXDMA_LIMIT_SHIFT));	GM_OUT(GM_TX_CONF,		(GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) |		NTX_CONF);	/* 34 byte offset for checksum computation.  This works because ip_input() will clear out	 * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are	 * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr) 	*/	GM_OUT(GM_RX_CONF,		(RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) |		(0x22 << GM_RX_CONF_CHK_START_SHIFT) |		(GM_RX_CONF_DMA_THR_DEFAULT << GM_RX_CONF_DMA_THR_SHIFT) |		NRX_CONF);	/* Configure other bits of MAC */	GM_OUT(GM_MAC_INTR_PKT_GAP0, GM_MAC_INTR_PKT_GAP0_DEFAULT);	GM_OUT(GM_MAC_INTR_PKT_GAP1, GM_MAC_INTR_PKT_GAP1_DEFAULT);	GM_OUT(GM_MAC_INTR_PKT_GAP2, GM_MAC_INTR_PKT_GAP2_DEFAULT);	GM_OUT(GM_MAC_MIN_FRAME_SIZE, GM_MAC_MIN_FRAME_SIZE_DEFAULT);	GM_OUT(GM_MAC_MAX_FRAME_SIZE, GM_MAC_MAX_FRAME_SIZE_DEFAULT);	GM_OUT(GM_MAC_PREAMBLE_LEN, GM_MAC_PREAMBLE_LEN_DEFAULT);	GM_OUT(GM_MAC_JAM_SIZE, GM_MAC_JAM_SIZE_DEFAULT);	GM_OUT(GM_MAC_ATTEMPT_LIMIT, GM_MAC_ATTEMPT_LIMIT_DEFAULT);	GM_OUT(GM_MAC_SLOT_TIME, GM_MAC_SLOT_TIME_DEFAULT);	GM_OUT(GM_MAC_CONTROL_TYPE, GM_MAC_CONTROL_TYPE_DEFAULT);		/* Setup MAC addresses, clear filters, clear hash table */	GM_OUT(GM_MAC_ADDR_NORMAL0, (mac_addr[4] << 8) + mac_addr[5]);	GM_OUT(GM_MAC_ADDR_NORMAL1, (mac_addr[2] << 8) + mac_addr[3]);	GM_OUT(GM_MAC_ADDR_NORMAL2, (mac_addr[0] << 8) + mac_addr[1]);	GM_OUT(GM_MAC_ADDR_ALT0, 0);	GM_OUT(GM_MAC_ADDR_ALT1, 0);	GM_OUT(GM_MAC_ADDR_ALT2, 0);	GM_OUT(GM_MAC_ADDR_CTRL0, 0x0001);	GM_OUT(GM_MAC_ADDR_CTRL1, 0xc200);	GM_OUT(GM_MAC_ADDR_CTRL2, 0x0180);	GM_OUT(GM_MAC_ADDR_FILTER0, 0);	GM_OUT(GM_MAC_ADDR_FILTER1, 0);	GM_OUT(GM_MAC_ADDR_FILTER2, 0);	GM_OUT(GM_MAC_ADDR_FILTER_MASK1_2, 0);	GM_OUT(GM_MAC_ADDR_FILTER_MASK0, 0);	for (i = 0; i < 27; ++i)		GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + i, 0);		/* Clear stat counters */	GM_OUT(GM_MAC_COLLISION_CTR, 0);	GM_OUT(GM_MAC_FIRST_COLLISION_CTR, 0);	GM_OUT(GM_MAC_EXCS_COLLISION_CTR, 0);	GM_OUT(GM_MAC_LATE_COLLISION_CTR, 0);	GM_OUT(GM_MAC_DEFER_TIMER_COUNTER, 0);	GM_OUT(GM_MAC_PEAK_ATTEMPTS, 0);	GM_OUT(GM_MAC_RX_FRAME_CTR, 0);	GM_OUT(GM_MAC_RX_LEN_ERR_CTR, 0);	GM_OUT(GM_MAC_RX_ALIGN_ERR_CTR, 0);	GM_OUT(GM_MAC_RX_CRC_ERR_CTR, 0);	GM_OUT(GM_MAC_RX_CODE_VIOLATION_CTR, 0);		/* default to half duplex */	GM_OUT(GM_MAC_TX_CONFIG, 0);	GM_OUT(GM_MAC_RX_CONFIG, 0);	gmac_set_duplex_mode(gm, gm->full_duplex);		/* Setup pause thresholds */	fifo_size = GM_IN(GM_RX_FIFO_SIZE);	GM_OUT(GM_RX_PTH,		((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 2 / GM_RX_PTH_UNITS))			<< GM_RX_PTH_OFF_SHIFT) |		((fifo_size - ((GM_MAC_MAX_FRAME_SIZE_ALIGN + 8) * 3 / GM_RX_PTH_UNITS))			<< GM_RX_PTH_ON_SHIFT));			/* Setup interrupt blanking */	if (GM_IN(GM_BIF_CFG) & GM_BIF_CFG_M66EN)		GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)			| (8 << GM_RX_BLANK_INTR_TIME_SHIFT));	else		GM_OUT(GM_RX_BLANK, (5 << GM_RX_BLANK_INTR_PACKETS_SHIFT)			| (4 << GM_RX_BLANK_INTR_TIME_SHIFT));	}/* * Fill the Rx and Tx rings with good initial values, alloc * fresh Rx skb's. */static voidgmac_init_rings(struct gmac *gm, int from_irq){	int i;	struct sk_buff *skb;	unsigned char *data;	struct gmac_dma_desc *ring;	int gfp_flags = GFP_KERNEL;	if (from_irq || in_interrupt())		gfp_flags = GFP_ATOMIC;	/* init rx ring */	ring = (struct gmac_dma_desc *) gm->rxring;	memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));	for (i = 0; i < NRX; ++i, ++ring) {		data = dummy_buf;		gm->rx_buff[i] = skb = gmac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);		if (skb != 0) {			skb->dev = gm->dev;			skb_put(skb, ETH_FRAME_LEN + RX_OFFSET);			skb_reserve(skb, RX_OFFSET);			data = skb->data - RX_OFFSET;		}		st_le32(&ring->lo_addr, virt_to_bus(data));		st_le32(&ring->size, RX_SZ_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET) << RX_SZ_SHIFT));	}	/* init tx ring */	ring = (struct gmac_dma_desc *) gm->txring;	memset(ring, 0, NTX * sizeof(struct gmac_dma_desc));	gm->next_rx = 0;	gm->next_tx = 0;	gm->tx_gone = 0;	/* set pointers in chip */	mb();	GM_OUT(GM_RX_DESC_HI, 0);	GM_OUT(GM_RX_DESC_LO, virt_to_bus(gm->rxring));	GM_OUT(GM_TX_DESC_HI, 0);	GM_OUT(GM_TX_DESC_LO, virt_to_bus(gm->txring));}/* * Start the Tx and Rx DMA engines and enable interrupts *  * Note: The various mdelay(20); come from Darwin implentation. Some * tests (doc ?) are needed to replace those with something more intrusive. */static voidgmac_start_dma(struct gmac *gm){	/* Enable Tx and Rx */	GM_BIS(GM_TX_CONF, GM_TX_CONF_DMA_EN);	mdelay(20);	GM_BIS(GM_RX_CONF, GM_RX_CONF_DMA_EN);	mdelay(20);	GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);	mdelay(20);	GM_BIS(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);	mdelay(20);	/* Kick the receiver and enable interrupts */	GM_OUT(GM_RX_KICK, NRX);	GM_BIC(GM_IRQ_MASK, 	GM_IRQ_TX_INT_ME |				GM_IRQ_TX_ALL |				GM_IRQ_RX_DONE |				GM_IRQ_RX_TAG_ERR |				GM_IRQ_MAC_RX |				GM_IRQ_MIF |				GM_IRQ_BUS_ERROR);}/* * Stop the Tx and Rx DMA engines after disabling interrupts *  * Note: The various mdelay(20); come from Darwin implentation. Some * tests (doc ?) are needed to replace those with something more intrusive. */static voidgmac_stop_dma(struct gmac *gm){	/* disable interrupts */	GM_OUT(GM_IRQ_MASK, 0xffffffff);	/* Enable Tx and Rx */	GM_BIC(GM_TX_CONF, GM_TX_CONF_DMA_EN);	mdelay(20);	GM_BIC(GM_RX_CONF, GM_RX_CONF_DMA_EN);	mdelay(20);	GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);	mdelay(20);	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);	mdelay(20);}/* * Configure promisc mode and setup multicast hash table * filter */#define CRC_POLY	0xedb88320static voidgmac_set_multicast(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	struct dev_mc_list *dmi = dev->mc_list;	int i,j,k,b;	unsigned long crc;	int multicast_hash = 0;	int multicast_all = 0;	int promisc = 0;	if (gm->sleeping)		return;	/* Lock out others. */	netif_stop_queue(dev);	if (dev->flags & IFF_PROMISC)		promisc = 1;	else if ((dev->flags & IFF_ALLMULTI) /* || (dev->mc_count > XXX) */) {		multicast_all = 1;	} else {		u16 hash_table[16];		for(i = 0; i < 16; i++)			hash_table[i] = 0;	    	for (i = 0; i < dev->mc_count; i++) {			crc = ~0;			for (j = 0; j < 6; ++j) {			    b = dmi->dmi_addr[j];			    for (k = 0; k < 8; ++k) {				if ((crc ^ b) & 1)				    crc = (crc >> 1) ^ CRC_POLY;				else				    crc >>= 1;				b >>= 1;			    }			}			j = crc >> 24;	/* bit number in multicast_filter */			hash_table[j >> 4] |= 1 << (15 - (j & 0xf));			dmi = dmi->next;	    	}	    	for (i = 0; i < 16; i++)	    		GM_OUT(GM_MAC_ADDR_FILTER_HASH0 + (i*4), hash_table[i]);		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);	    	multicast_hash = 1;	}	if (promisc)		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);	else		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL);	if (multicast_hash)		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);	else		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_HASH_ENABLE);	if (multicast_all)		GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);	else		GM_BIC(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_RX_ALL_MULTI);		/* Let us get going again. */	netif_wake_queue(dev);}/* * Open the interface */static intgmac_open(struct net_device *dev){	int ret;	struct gmac *gm = (struct gmac *) dev->priv;	/* Power up and reset chip */	if (gmac_powerup_and_reset(dev))		return -EIO;	/* Get our interrupt */	ret = request_irq(dev->irq, gmac_interrupt, 0, dev->name, dev);	if (ret) {		printk(KERN_ERR "%s can't get irq %d\n", dev->name, dev->irq);		return ret;	}	gm->full_duplex = 0;	gm->phy_status = 0;		/* Find a PHY */	if (!mii_lookup_and_reset(gm))		printk(KERN_WARNING "%s WARNING ! Can't find PHY\n", dev->name);	/* Configure the PHY */	mii_setup_phy(gm);		/* Initialize the descriptor rings */	gmac_init_rings(gm, 0);	/* Initialize the MAC */	gmac_mac_init(gm, dev->dev_addr);		/* Initialize the multicast tables & promisc mode if any */	gmac_set_multicast(dev);		/*	 * Check out PHY status and start auto-poll	 * 	 * Note: do this before enabling interrutps	 */	mii_interrupt(gm);	/* Start the chip */	gmac_start_dma(gm);	gm->opened = 1;	return 0;}/*  * Close the interface */static intgmac_close(struct net_device *dev){	struct gmac *gm = (struct gmac *) dev->priv;	int i;	gm->opened = 0;	/* Stop chip and interrupts */	gmac_stop_dma(gm);	/* Stop polling PHY */	mii_poll_stop(gm);	/* Free interrupt */	free_irq(dev->irq, dev);

⌨️ 快捷键说明

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