gt96100eth.c

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

C
1,572
字号
	dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));	// wait for abort to complete	while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {		// snooze for 20 msec and check again		gt96100_delay(1);			if (--timedout == 0) {			err("%s: timeout!!\n", __FUNCTION__);			break;		}	}	spin_unlock(&gp->lock);}static voidhard_stop(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	dbg(3, "%s\n", __FUNCTION__);	disable_ether_irq(dev);	abort(dev, sdcmrAR | sdcmrAT);	// disable port	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);}static voidenable_ether_irq(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	u32 intMask;	/*	 * route ethernet interrupt to GT_SERINT0 for port 0,	 * GT_INT0 for port 1.	 */	int intr_mask_reg = (gp->port_num == 0) ?		GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;		if (gp->chip_rev >= REV_GT96100A_1) {		intMask = icrTxBufferLow | icrTxEndLow |			icrTxErrorLow  | icrRxOVR | icrTxUdr |			icrRxBufferQ0 | icrRxErrorQ0 |			icrMIIPhySTC | icrEtherIntSum;	}	else {		intMask = icrTxBufferLow | icrTxEndLow |			icrTxErrorLow  | icrRxOVR | icrTxUdr |			icrRxBuffer | icrRxError |			icrMIIPhySTC | icrEtherIntSum;	}		// unmask interrupts	GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, intMask);    	intMask = GT96100_READ(intr_mask_reg);	intMask |= 1<<gp->port_num;	GT96100_WRITE(intr_mask_reg, intMask);}static voiddisable_ether_irq(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	u32 intMask;	int intr_mask_reg = (gp->port_num == 0) ?		GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;	intMask = GT96100_READ(intr_mask_reg);	intMask &= ~(1<<gp->port_num);	GT96100_WRITE(intr_mask_reg, intMask);    	GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);}/* * Init GT96100 ethernet controller driver */static int gt96100_init_module(void){	struct pci_dev *pci;	int i, retval=0;	u32 cpuConfig;	/*	 * Stupid probe because this really isn't a PCI device	 */	if (!(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,	                            PCI_DEVICE_ID_MARVELL_GT96100, NULL)) &&	    !(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,		                    PCI_DEVICE_ID_MARVELL_GT96100A, NULL))) {		printk(KERN_ERR __FILE__ ": GT96100 not found!\n");		return -ENODEV;	}	cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG);	if (cpuConfig & (1<<12)) {		printk(KERN_ERR __FILE__		       ": must be in Big Endian mode!\n");		return -ENODEV;	}	for (i=0; i < NUM_INTERFACES; i++)		retval |= gt96100_probe1(pci, i);	return retval;}static int __init gt96100_probe1(struct pci_dev *pci, int port_num){	struct gt96100_private *gp = NULL;	struct gt96100_if_t *gtif = &gt96100_iflist[port_num];	int phy_addr, phy_id1, phy_id2;	u32 phyAD;	int retval;	unsigned char chip_rev;	struct net_device *dev = NULL;    	if (gtif->irq < 0) {		printk(KERN_ERR "%s: irq unknown - probing not supported\n",		      __FUNCTION__);		return -ENODEV;	}    	pci_read_config_byte(pci, PCI_REVISION_ID, &chip_rev);	if (chip_rev >= REV_GT96100A_1) {		phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);		phy_addr = (phyAD >> (5*port_num)) & 0x1f;	} else {		/*		 * not sure what's this about -- probably a gt bug		 */		phy_addr = port_num;		phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);		phyAD &= ~(0x1f << (port_num*5));		phyAD |= phy_addr << (port_num*5);		GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD);	}		// probe for the external PHY	if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||	    (phy_id2 = read_MII(phy_addr, 3)) <= 0) {		printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);		return -ENODEV;	}		if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {		printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);		return -EBUSY;	}	dev = alloc_etherdev(sizeof(struct gt96100_private));	if (!dev)		goto out;	gtif->dev = dev;		/* private struct aligned and zeroed by alloc_etherdev */	/* Fill in the 'dev' fields. */	dev->base_addr = gtif->iobase;	dev->irq = gtif->irq;	if ((retval = parse_mac_addr(dev, gtif->mac_str))) {		err("%s: MAC address parse failed\n", __FUNCTION__);		retval = -EINVAL;		goto out1;	}	gp = netdev_priv(dev);	memset(gp, 0, sizeof(*gp)); // clear it	gp->port_num = port_num;	gp->io_size = GT96100_ETH_IO_SIZE;	gp->port_offset = port_num * GT96100_ETH_IO_SIZE;	gp->phy_addr = phy_addr;	gp->chip_rev = chip_rev;	info("%s found at 0x%x, irq %d\n",	     chip_name(gp->chip_rev), gtif->iobase, gtif->irq);	dump_hw_addr(0, dev, "HW Address ", dev->dev_addr);	info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev);	info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num);	info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2);	// Allocate Rx and Tx descriptor rings	if (gp->rx_ring == NULL) {		// All descriptors in ring must be 16-byte aligned		gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE				       + sizeof(gt96100_td_t) * TX_RING_SIZE,				       &gp->rx_ring_dma);		if (gp->rx_ring == NULL) {			retval = -ENOMEM;			goto out1;		}			gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE);		gp->tx_ring_dma =			gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE;	}    	// Allocate the Rx Data Buffers	if (gp->rx_buff == NULL) {		gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE,				       &gp->rx_buff_dma);		if (gp->rx_buff == NULL) {			retval = -ENOMEM;			goto out2;		}	}    	dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,	    gp->rx_ring, gp->tx_ring);	// Allocate Rx Hash Table	if (gp->hash_table == NULL) {		gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE,						 &gp->hash_table_dma);		if (gp->hash_table == NULL) {			retval = -ENOMEM;			goto out3;		}	}    	dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);	spin_lock_init(&gp->lock);    	dev->open = gt96100_open;	dev->hard_start_xmit = gt96100_tx;	dev->stop = gt96100_close;	dev->get_stats = gt96100_get_stats;	//dev->do_ioctl = gt96100_ioctl;	dev->set_multicast_list = gt96100_set_rx_mode;	dev->tx_timeout = gt96100_tx_timeout;	dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT;	retval = register_netdev(dev);	if (retval)		goto out4;	return 0;out4:	dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma);out3:	dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff);out2:	dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE		+ sizeof(gt96100_td_t) * TX_RING_SIZE,		gp->rx_ring);out1:	free_netdev (dev);out:	release_region(gtif->iobase, GT96100_ETH_IO_SIZE);	err("%s failed.  Returns %d\n", __FUNCTION__, retval);	return retval;}static voidreset_tx(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	int i;	abort(dev, sdcmrAT);	for (i=0; i<TX_RING_SIZE; i++) {		if (gp->tx_skbuff[i]) {			if (in_interrupt())				dev_kfree_skb_irq(gp->tx_skbuff[i]);			else				dev_kfree_skb(gp->tx_skbuff[i]);			gp->tx_skbuff[i] = NULL;		}		gp->tx_ring[i].cmdstat = 0; // CPU owns		gp->tx_ring[i].byte_cnt = 0;		gp->tx_ring[i].buff_ptr = 0;		gp->tx_ring[i].next =			cpu_to_dma32(gp->tx_ring_dma +				     sizeof(gt96100_td_t) * (i+1));		dump_tx_desc(4, dev, i);	}	/* Wrap the ring. */	gp->tx_ring[i-1].next = cpu_to_dma32(gp->tx_ring_dma);    	// setup only the lowest priority TxCDP reg	GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma);	GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0);	// init Tx indeces and pkt counter	gp->tx_next_in = gp->tx_next_out = 0;	gp->tx_count = 0;}static voidreset_rx(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	int i;	abort(dev, sdcmrAR);    	for (i=0; i<RX_RING_SIZE; i++) {		gp->rx_ring[i].next =			cpu_to_dma32(gp->rx_ring_dma +				     sizeof(gt96100_rd_t) * (i+1));		gp->rx_ring[i].buff_ptr =			cpu_to_dma32(gp->rx_buff_dma + i*PKT_BUF_SZ);		gp->rx_ring[i].buff_sz = cpu_to_dma16(PKT_BUF_SZ);		// Give ownership to device, set first and last, enable intr		gp->rx_ring[i].cmdstat =			cpu_to_dma32((u32)(rxFirst | rxLast | rxOwn | rxEI));		dump_rx_desc(4, dev, i);	}	/* Wrap the ring. */	gp->rx_ring[i-1].next = cpu_to_dma32(gp->rx_ring_dma);	// Setup only the lowest priority RxFDP and RxCDP regs	for (i=0; i<4; i++) {		if (i == 0) {			GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0,					 gp->rx_ring_dma);			GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0,					 gp->rx_ring_dma);		} else {			GT96100ETH_WRITE(gp,					 GT96100_ETH_1ST_RX_DESC_PTR0 + i*4,					 0);			GT96100ETH_WRITE(gp,					 GT96100_ETH_CURR_RX_DESC_PTR0 + i*4,					 0);		}	}	// init Rx NextOut index	gp->rx_next_out = 0;}// Returns 1 if the Tx counter and indeces don't gelstatic intgt96100_check_tx_consistent(struct gt96100_private *gp){	int diff = gp->tx_next_in - gp->tx_next_out;	diff = diff<0 ? TX_RING_SIZE + diff : diff;	diff = gp->tx_count == TX_RING_SIZE ? diff + TX_RING_SIZE : diff;    	return (diff != gp->tx_count);}static intgt96100_init(struct net_device *dev){	struct gt96100_private *gp = netdev_priv(dev);	u32 tmp;	u16 mii_reg;    	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);	dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__, 	    GT96100_READ(0x8), GT96100_READ(0x10));	dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,	    GT96100_READ(0x18), GT96100_READ(0x20));    	// Stop and disable Port	hard_stop(dev);    	// Setup CIU Arbiter	tmp = GT96100_READ(GT96100_CIU_ARBITER_CONFIG);	tmp |= (0x0c << (gp->port_num*2)); // set Ether DMA req priority to hi#ifndef DESC_BE	tmp &= ~(1<<31);                   // set desc endianess to little#else	tmp |= (1<<31);#endif	GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);	dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__, 	    tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));	// Set routing.	tmp = GT96100_READ(GT96100_ROUTE_MAIN) & (0x3f << 18);	tmp |= (0x07 << (18 + gp->port_num*3));	GT96100_WRITE(GT96100_ROUTE_MAIN, tmp);	/* set MII as peripheral func */	tmp = GT96100_READ(GT96100_GPP_CONFIG2);	tmp |= 0x7fff << (gp->port_num*16);	GT96100_WRITE(GT96100_GPP_CONFIG2, tmp);		/* Set up MII port pin directions */	tmp = GT96100_READ(GT96100_GPP_IO2);	tmp |= 0x003d << (gp->port_num*16);	GT96100_WRITE(GT96100_GPP_IO2, tmp);	// Set-up hash table	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it	gp->hash_mode = 0;	// Add a single entry to hash table - our ethernet address	gt96100_add_hash_entry(dev, dev->dev_addr);	// Set-up DMA ptr to hash table	GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);	dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));	// Setup Tx	reset_tx(dev);	dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));	// Setup Rx	reset_rx(dev);	dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),	    GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));	// eth port config register	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,			 pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen);	mii_reg = read_MII(gp->phy_addr, 0x11); /* int enable register */	mii_reg |= 2;  /* enable mii interrupt */	write_MII(gp->phy_addr, 0x11, mii_reg);		dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,	    GT96100_READ(GT96100_ETH_PHY_ADDR_REG));	// setup DMA	// We want the Rx/Tx DMA to write/read data to/from memory in	// Big Endian mode. Also set DMA Burst Size to 8 64Bit words.#ifdef DESC_DATA_BE	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,			 (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));#else	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,			 sdcrBLMR | sdcrBLMT |			 (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));#endif	dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));	// start Rx DMA	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);	dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));    	// enable this port (set hash size to 1/2K)	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);	dbg(3, "%s: Port Config=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));    	/*	 * Disable all Type-of-Service queueing. All Rx packets will be	 * treated normally and will be sent to the lowest priority	 * queue.	 *	 * Disable flow-control for now. FIXME: support flow control?	 */	// clear all the MIB ctr regs	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,			 pcxrFCTL | pcxrFCTLen | pcxrFLP |			 pcxrPRIOrxOverride);	read_mib_counters(gp);	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,			 pcxrFCTL | pcxrFCTLen | pcxrFLP |			 pcxrPRIOrxOverride | pcxrMIBclrMode);    	dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));	netif_start_queue(dev);	dump_MII(4, dev);	// enable interrupts	enable_ether_irq(dev);	// we should now be receiving frames	return 0;}static intgt96100_open(struct net_device *dev){	int retval;    	dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);	// Initialize and startup the GT-96100 ethernet port	if ((retval = gt96100_init(dev))) {		err("error in gt96100_init\n");		free_irq(dev->irq, dev);		return retval;	}	if ((retval = request_irq(dev->irq, &gt96100_interrupt,				  SA_SHIRQ, dev->name, dev))) {		err("unable to get IRQ %d\n", dev->irq);		return retval;	}		dbg(2, "%s: Initialization done.\n", __FUNCTION__);	return 0;}static intgt96100_close(struct net_device *dev)

⌨️ 快捷键说明

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