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

📄 gmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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;		/* 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);		/* Shut down chip */	gmac_set_power(gm, 0);	/* Empty rings of any remaining gremlins */	for (i = 0; i < NRX; ++i) {		if (gm->rx_buff[i] != 0) {			dev_kfree_skb(gm->rx_buff[i]);			gm->rx_buff[i] = 0;		}	}	for (i = 0; i < NTX; ++i) {		if (gm->tx_buff[i] != 0) {			dev_kfree_skb(gm->tx_buff[i]);			gm->tx_buff[i] = 0;		}	}	return 0;}#ifdef CONFIG_PMAC_PBOOKintgmac_sleep_notify(struct pmu_sleep_notifier *self, int when){	struct gmac *gm;	int i;		/* XXX should handle more than one */	if (gmacs == NULL)		return PBOOK_SLEEP_OK;	gm = (struct gmac *) gmacs->priv;	if (!gm->opened)		return PBOOK_SLEEP_OK;			switch (when) {	case PBOOK_SLEEP_REQUEST:		break;	case PBOOK_SLEEP_REJECT:		break;	case PBOOK_SLEEP_NOW:		disable_irq(gm->dev->irq);		netif_stop_queue(gm->dev);		gmac_stop_dma(gm);		mii_poll_stop(gm);		gmac_set_power(gm, 0);		for (i = 0; i < NRX; ++i) {			if (gm->rx_buff[i] != 0) {				dev_kfree_skb(gm->rx_buff[i]);				gm->rx_buff[i] = 0;			}		}		for (i = 0; i < NTX; ++i) {			if (gm->tx_buff[i] != 0) {				dev_kfree_skb(gm->tx_buff[i]);				gm->tx_buff[i] = 0;			}		}		break;	case PBOOK_WAKE:		/* see if this is enough */		gmac_powerup_and_reset(gm->dev);		gm->full_duplex = 0;		gm->phy_status = 0;		mii_lookup_and_reset(gm);		mii_setup_phy(gm);		gmac_init_rings(gm, 0);		gmac_mac_init(gm, gm->dev->dev_addr);		gmac_set_multicast(gm->dev);		mii_interrupt(gm);		gmac_start_dma(gm);		netif_start_queue(gm->dev);		enable_irq(gm->dev->irq);		break;	}	return PBOOK_SLEEP_OK;}

⌨️ 快捷键说明

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