fealnx.c

来自「linux 内核源代码」· C语言 代码 · 共 1,989 行 · 第 1/4 页

C
1,989
字号
	option = card_idx < MAX_UNITS ? options[card_idx] : 0;	i = pci_enable_device(pdev);	if (i) return i;	pci_set_master(pdev);	len = pci_resource_len(pdev, bar);	if (len < MIN_REGION_SIZE) {		dev_err(&pdev->dev,			   "region size %ld too small, aborting\n", len);		return -ENODEV;	}	i = pci_request_regions(pdev, boardname);	if (i)		return i;	irq = pdev->irq;	ioaddr = pci_iomap(pdev, bar, len);	if (!ioaddr) {		err = -ENOMEM;		goto err_out_res;	}	dev = alloc_etherdev(sizeof(struct netdev_private));	if (!dev) {		err = -ENOMEM;		goto err_out_unmap;	}	SET_NETDEV_DEV(dev, &pdev->dev);	/* read ethernet id */	for (i = 0; i < 6; ++i)		dev->dev_addr[i] = ioread8(ioaddr + PAR0 + i);	/* Reset the chip to erase previous misconfiguration. */	iowrite32(0x00000001, ioaddr + BCR);	dev->base_addr = (unsigned long)ioaddr;	dev->irq = irq;	/* Make certain the descriptor lists are aligned. */	np = netdev_priv(dev);	np->mem = ioaddr;	spin_lock_init(&np->lock);	np->pci_dev = pdev;	np->flags = skel_netdrv_tbl[chip_id].flags;	pci_set_drvdata(pdev, dev);	np->mii.dev = dev;	np->mii.mdio_read = mdio_read;	np->mii.mdio_write = mdio_write;	np->mii.phy_id_mask = 0x1f;	np->mii.reg_num_mask = 0x1f;	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);	if (!ring_space) {		err = -ENOMEM;		goto err_out_free_dev;	}	np->rx_ring = (struct fealnx_desc *)ring_space;	np->rx_ring_dma = ring_dma;	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);	if (!ring_space) {		err = -ENOMEM;		goto err_out_free_rx;	}	np->tx_ring = (struct fealnx_desc *)ring_space;	np->tx_ring_dma = ring_dma;	/* find the connected MII xcvrs */	if (np->flags == HAS_MII_XCVR) {		int phy, phy_idx = 0;		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(dev, phy, 1);			if (mii_status != 0xffff && mii_status != 0x0000) {				np->phys[phy_idx++] = phy;				dev_info(&pdev->dev,				       "MII PHY found at address %d, status "				       "0x%4.4x.\n", phy, mii_status);				/* get phy type */				{					unsigned int data;					data = mdio_read(dev, np->phys[0], 2);					if (data == SeeqPHYID0)						np->PHYType = SeeqPHY;					else if (data == AhdocPHYID0)						np->PHYType = AhdocPHY;					else if (data == MarvellPHYID0)						np->PHYType = MarvellPHY;					else if (data == MysonPHYID0)						np->PHYType = Myson981;					else if (data == LevelOnePHYID0)						np->PHYType = LevelOnePHY;					else						np->PHYType = OtherPHY;				}			}		}		np->mii_cnt = phy_idx;		if (phy_idx == 0)			dev_warn(&pdev->dev,				"MII PHY not found -- this device may "			       "not operate correctly.\n");	} else {		np->phys[0] = 32;/* 89/6/23 add, (begin) */		/* get phy type */		if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID)			np->PHYType = MysonPHY;		else			np->PHYType = OtherPHY;	}	np->mii.phy_id = np->phys[0];	if (dev->mem_start)		option = dev->mem_start;	/* The lower four bits are the media type. */	if (option > 0) {		if (option & 0x200)			np->mii.full_duplex = 1;		np->default_port = option & 15;	}	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)		np->mii.full_duplex = full_duplex[card_idx];	if (np->mii.full_duplex) {		dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");/* 89/6/13 add, (begin) *///      if (np->PHYType==MarvellPHY)		if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {			unsigned int data;			data = mdio_read(dev, np->phys[0], 9);			data = (data & 0xfcff) | 0x0200;			mdio_write(dev, np->phys[0], 9, data);		}/* 89/6/13 add, (end) */		if (np->flags == HAS_MII_XCVR)			mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);		else			iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR);		np->mii.force_media = 1;	}	/* The chip-specific entries in the device structure. */	dev->open = &netdev_open;	dev->hard_start_xmit = &start_tx;	dev->stop = &netdev_close;	dev->get_stats = &get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &mii_ioctl;	dev->ethtool_ops = &netdev_ethtool_ops;	dev->tx_timeout = &tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	err = register_netdev(dev);	if (err)		goto err_out_free_tx;	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr,	       print_mac(mac, dev->dev_addr), irq);	return 0;err_out_free_tx:	pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);err_out_free_rx:	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);err_out_free_dev:	free_netdev(dev);err_out_unmap:	pci_iounmap(pdev, ioaddr);err_out_res:	pci_release_regions(pdev);	return err;}static void __devexit fealnx_remove_one(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	if (dev) {		struct netdev_private *np = netdev_priv(dev);		pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,			np->tx_ring_dma);		pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,			np->rx_ring_dma);		unregister_netdev(dev);		pci_iounmap(pdev, np->mem);		free_netdev(dev);		pci_release_regions(pdev);		pci_set_drvdata(pdev, NULL);	} else		printk(KERN_ERR "fealnx: remove for unknown device\n");}static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad){	ulong miir;	int i;	unsigned int mask, data;	/* enable MII output */	miir = (ulong) ioread32(miiport);	miir &= 0xfffffff0;	miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;	/* send 32 1's preamble */	for (i = 0; i < 32; i++) {		/* low MDC; MDO is already high (miir) */		miir &= ~MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);		/* high MDC */		miir |= MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);	}	/* calculate ST+OP+PHYAD+REGAD+TA */	data = opcode | (phyad << 7) | (regad << 2);	/* sent out */	mask = 0x8000;	while (mask) {		/* low MDC, prepare MDO */		miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);		if (mask & data)			miir |= MASK_MIIR_MII_MDO;		iowrite32(miir, miiport);		/* high MDC */		miir |= MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);		udelay(30);		/* next */		mask >>= 1;		if (mask == 0x2 && opcode == OP_READ)			miir &= ~MASK_MIIR_MII_WRITE;	}	return miir;}static int mdio_read(struct net_device *dev, int phyad, int regad){	struct netdev_private *np = netdev_priv(dev);	void __iomem *miiport = np->mem + MANAGEMENT;	ulong miir;	unsigned int mask, data;	miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);	/* read data */	mask = 0x8000;	data = 0;	while (mask) {		/* low MDC */		miir &= ~MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);		/* read MDI */		miir = ioread32(miiport);		if (miir & MASK_MIIR_MII_MDI)			data |= mask;		/* high MDC, and wait */		miir |= MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);		udelay(30);		/* next */		mask >>= 1;	}	/* low MDC */	miir &= ~MASK_MIIR_MII_MDC;	iowrite32(miir, miiport);	return data & 0xffff;}static void mdio_write(struct net_device *dev, int phyad, int regad, int data){	struct netdev_private *np = netdev_priv(dev);	void __iomem *miiport = np->mem + MANAGEMENT;	ulong miir;	unsigned int mask;	miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);	/* write data */	mask = 0x8000;	while (mask) {		/* low MDC, prepare MDO */		miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);		if (mask & data)			miir |= MASK_MIIR_MII_MDO;		iowrite32(miir, miiport);		/* high MDC */		miir |= MASK_MIIR_MII_MDC;		iowrite32(miir, miiport);		/* next */		mask >>= 1;	}	/* low MDC */	miir &= ~MASK_MIIR_MII_MDC;	iowrite32(miir, miiport);}static int netdev_open(struct net_device *dev){	struct netdev_private *np = netdev_priv(dev);	void __iomem *ioaddr = np->mem;	int i;	iowrite32(0x00000001, ioaddr + BCR);	/* Reset */	if (request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev))		return -EAGAIN;	for (i = 0; i < 3; i++)		iowrite16(((unsigned short*)dev->dev_addr)[i],				ioaddr + PAR0 + i*2);	init_ring(dev);	iowrite32(np->rx_ring_dma, ioaddr + RXLBA);	iowrite32(np->tx_ring_dma, ioaddr + TXLBA);	/* Initialize other registers. */	/* Configure the PCI bus bursts and FIFO thresholds.	   486: Set 8 longword burst.	   586: no burst limit.	   Burst length 5:3	   0 0 0   1	   0 0 1   4	   0 1 0   8	   0 1 1   16	   1 0 0   32	   1 0 1   64	   1 1 0   128	   1 1 1   256	   Wait the specified 50 PCI cycles after a reset by initializing	   Tx and Rx queues and the address filter list.	   FIXME (Ueimor): optimistic for alpha + posted writes ? */#if defined(__powerpc__) || defined(__sparc__)// 89/9/1 modify,//   np->bcrvalue=0x04 | 0x0x38;  /* big-endian, 256 burst length */	np->bcrvalue = 0x04 | 0x10;	/* big-endian, tx 8 burst length */	np->crvalue = 0xe00;	/* rx 128 burst length */#elif defined(__alpha__) || defined(__x86_64__)// 89/9/1 modify,//   np->bcrvalue=0x38;           /* little-endian, 256 burst length */	np->bcrvalue = 0x10;	/* little-endian, 8 burst length */	np->crvalue = 0xe00;	/* rx 128 burst length */#elif defined(__i386__)#if defined(MODULE)// 89/9/1 modify,//   np->bcrvalue=0x38;           /* little-endian, 256 burst length */	np->bcrvalue = 0x10;	/* little-endian, 8 burst length */	np->crvalue = 0xe00;	/* rx 128 burst length */#else	/* When not a module we can work around broken '486 PCI boards. */#define x86 boot_cpu_data.x86// 89/9/1 modify,//   np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38);	np->bcrvalue = 0x10;	np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00);	if (x86 <= 4)		printk(KERN_INFO "%s: This is a 386/486 PCI system, setting burst "		       "length to %x.\n", dev->name, (x86 <= 4 ? 0x10 : 0x38));#endif#else// 89/9/1 modify,//   np->bcrvalue=0x38;	np->bcrvalue = 0x10;	np->crvalue = 0xe00;	/* rx 128 burst length */#warning Processor architecture undefined!#endif// 89/12/29 add,// 90/1/16 modify,//   np->imrvalue=FBE|TUNF|CNTOVF|RBU|TI|RI;	np->imrvalue = TUNF | CNTOVF | RBU | TI | RI;	if (np->pci_dev->device == 0x891) {		np->bcrvalue |= 0x200;	/* set PROG bit */		np->crvalue |= CR_W_ENH;	/* set enhanced bit */		np->imrvalue |= ETI;	}	iowrite32(np->bcrvalue, ioaddr + BCR);	if (dev->if_port == 0)		dev->if_port = np->default_port;	iowrite32(0, ioaddr + RXPDR);// 89/9/1 modify,//   np->crvalue = 0x00e40001;    /* tx store and forward, tx/rx enable */	np->crvalue |= 0x00e40001;	/* tx store and forward, tx/rx enable */	np->mii.full_duplex = np->mii.force_media;	getlinkstatus(dev);	if (np->linkok)		getlinktype(dev);	__set_rx_mode(dev);	netif_start_queue(dev);	/* Clear and Enable interrupts by setting the interrupt mask. */	iowrite32(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);	iowrite32(np->imrvalue, ioaddr + IMR);	if (debug)		printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);	/* Set the timer to check for link beat. */	init_timer(&np->timer);	np->timer.expires = RUN_AT(3 * HZ);	np->timer.data = (unsigned long) dev;	np->timer.function = &netdev_timer;	/* timer handler */	add_timer(&np->timer);	init_timer(&np->reset_timer);	np->reset_timer.data = (unsigned long) dev;	np->reset_timer.function = &reset_timer;	np->reset_timer_armed = 0;	return 0;}static void getlinkstatus(struct net_device *dev)/* function: Routine will read MII Status Register to get link status.       *//* input   : dev... pointer to the adapter block.                            *//* output  : none.                                                           */{	struct netdev_private *np = netdev_priv(dev);	unsigned int i, DelayTime = 0x1000;	np->linkok = 0;	if (np->PHYType == MysonPHY) {		for (i = 0; i < DelayTime; ++i) {			if (ioread32(np->mem + BMCRSR) & LinkIsUp2) {				np->linkok = 1;				return;			}			udelay(100);		}	} else {		for (i = 0; i < DelayTime; ++i) {			if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) {				np->linkok = 1;				return;			}			udelay(100);		}	}}static void getlinktype(struct net_device *dev){	struct netdev_private *np = netdev_priv(dev);	if (np->PHYType == MysonPHY) {	/* 3-in-1 case */		if (ioread32(np->mem + TCRRCR) & CR_R_FD)			np->duplexmode = 2;	/* full duplex */		else			np->duplexmode = 1;	/* half duplex */		if (ioread32(np->mem + TCRRCR) & CR_R_PS10)			np->line_speed = 1;	/* 10M */		else			np->line_speed = 2;	/* 100M */	} else {		if (np->PHYType == SeeqPHY) {	/* this PHY is SEEQ 80225 */			unsigned int data;			data = mdio_read(dev, np->phys[0], MIIRegister18);

⌨️ 快捷键说明

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