pcnet32.c

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

C
2,361
字号
		netif_wake_queue(dev);	}	spin_unlock_irqrestore(&lp->lock, flags);	if (work_done < budget) {		spin_lock_irqsave(&lp->lock, flags);		__netif_rx_complete(dev, napi);		/* clear interrupt masks */		val = lp->a.read_csr(ioaddr, CSR3);		val &= 0x00ff;		lp->a.write_csr(ioaddr, CSR3, val);		/* Set interrupt enable. */		lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);		mmiowb();		spin_unlock_irqrestore(&lp->lock, flags);	}	return work_done;}#endif#define PCNET32_REGS_PER_PHY	32#define PCNET32_MAX_PHYS	32static int pcnet32_get_regs_len(struct net_device *dev){	struct pcnet32_private *lp = netdev_priv(dev);	int j = lp->phycount * PCNET32_REGS_PER_PHY;	return ((PCNET32_NUM_REGS + j) * sizeof(u16));}static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,			     void *ptr){	int i, csr0;	u16 *buff = ptr;	struct pcnet32_private *lp = netdev_priv(dev);	struct pcnet32_access *a = &lp->a;	ulong ioaddr = dev->base_addr;	unsigned long flags;	spin_lock_irqsave(&lp->lock, flags);	csr0 = a->read_csr(ioaddr, CSR0);	if (!(csr0 & CSR0_STOP))	/* If not stopped */		pcnet32_suspend(dev, &flags, 1);	/* read address PROM */	for (i = 0; i < 16; i += 2)		*buff++ = inw(ioaddr + i);	/* read control and status registers */	for (i = 0; i < 90; i++) {		*buff++ = a->read_csr(ioaddr, i);	}	*buff++ = a->read_csr(ioaddr, 112);	*buff++ = a->read_csr(ioaddr, 114);	/* read bus configuration registers */	for (i = 0; i < 30; i++) {		*buff++ = a->read_bcr(ioaddr, i);	}	*buff++ = 0;		/* skip bcr30 so as not to hang 79C976 */	for (i = 31; i < 36; i++) {		*buff++ = a->read_bcr(ioaddr, i);	}	/* read mii phy registers */	if (lp->mii) {		int j;		for (j = 0; j < PCNET32_MAX_PHYS; j++) {			if (lp->phymask & (1 << j)) {				for (i = 0; i < PCNET32_REGS_PER_PHY; i++) {					lp->a.write_bcr(ioaddr, 33,							(j << 5) | i);					*buff++ = lp->a.read_bcr(ioaddr, 34);				}			}		}	}	if (!(csr0 & CSR0_STOP)) {	/* If not stopped */		int csr5;		/* clear SUSPEND (SPND) - CSR5 bit 0 */		csr5 = a->read_csr(ioaddr, CSR5);		a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));	}	spin_unlock_irqrestore(&lp->lock, flags);}static const struct ethtool_ops pcnet32_ethtool_ops = {	.get_settings		= pcnet32_get_settings,	.set_settings		= pcnet32_set_settings,	.get_drvinfo		= pcnet32_get_drvinfo,	.get_msglevel		= pcnet32_get_msglevel,	.set_msglevel		= pcnet32_set_msglevel,	.nway_reset		= pcnet32_nway_reset,	.get_link		= pcnet32_get_link,	.get_ringparam		= pcnet32_get_ringparam,	.set_ringparam		= pcnet32_set_ringparam,	.get_strings		= pcnet32_get_strings,	.self_test		= pcnet32_ethtool_test,	.phys_id		= pcnet32_phys_id,	.get_regs_len		= pcnet32_get_regs_len,	.get_regs		= pcnet32_get_regs,	.get_sset_count		= pcnet32_get_sset_count,};/* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist){	unsigned int *port, ioaddr;	/* search for PCnet32 VLB cards at known addresses */	for (port = pcnet32_portlist; (ioaddr = *port); port++) {		if (request_region		    (ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) {			/* check if there is really a pcnet chip on that ioaddr */			if ((inb(ioaddr + 14) == 0x57)			    && (inb(ioaddr + 15) == 0x57)) {				pcnet32_probe1(ioaddr, 0, NULL);			} else {				release_region(ioaddr, PCNET32_TOTAL_SIZE);			}		}	}}static int __devinitpcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent){	unsigned long ioaddr;	int err;	err = pci_enable_device(pdev);	if (err < 0) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX			       "failed to enable device -- err=%d\n", err);		return err;	}	pci_set_master(pdev);	ioaddr = pci_resource_start(pdev, 0);	if (!ioaddr) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX			       "card has no PCI IO resources, aborting\n");		return -ENODEV;	}	if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX			       "architecture does not support 32bit PCI busmaster DMA\n");		return -ENODEV;	}	if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") ==	    NULL) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX			       "io address range already allocated\n");		return -EBUSY;	}	err = pcnet32_probe1(ioaddr, 1, pdev);	if (err < 0) {		pci_disable_device(pdev);	}	return err;}/* pcnet32_probe1 *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci. *  pdev will be NULL when called from pcnet32_probe_vlbus. */static int __devinitpcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev){	struct pcnet32_private *lp;	int i, media;	int fdx, mii, fset, dxsuflo;	int chip_version;	char *chipname;	struct net_device *dev;	struct pcnet32_access *a = NULL;	u8 promaddr[6];	int ret = -ENODEV;	/* reset the chip */	pcnet32_wio_reset(ioaddr);	/* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */	if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) {		a = &pcnet32_wio;	} else {		pcnet32_dwio_reset(ioaddr);		if (pcnet32_dwio_read_csr(ioaddr, 0) == 4		    && pcnet32_dwio_check(ioaddr)) {			a = &pcnet32_dwio;		} else			goto err_release_region;	}	chip_version =	    a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16);	if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW))		printk(KERN_INFO "  PCnet chip version is %#x.\n",		       chip_version);	if ((chip_version & 0xfff) != 0x003) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_INFO PFX "Unsupported chip version.\n");		goto err_release_region;	}	/* initialize variables */	fdx = mii = fset = dxsuflo = 0;	chip_version = (chip_version >> 12) & 0xffff;	switch (chip_version) {	case 0x2420:		chipname = "PCnet/PCI 79C970";	/* PCI */		break;	case 0x2430:		if (shared)			chipname = "PCnet/PCI 79C970";	/* 970 gives the wrong chip id back */		else			chipname = "PCnet/32 79C965";	/* 486/VL bus */		break;	case 0x2621:		chipname = "PCnet/PCI II 79C970A";	/* PCI */		fdx = 1;		break;	case 0x2623:		chipname = "PCnet/FAST 79C971";	/* PCI */		fdx = 1;		mii = 1;		fset = 1;		break;	case 0x2624:		chipname = "PCnet/FAST+ 79C972";	/* PCI */		fdx = 1;		mii = 1;		fset = 1;		break;	case 0x2625:		chipname = "PCnet/FAST III 79C973";	/* PCI */		fdx = 1;		mii = 1;		break;	case 0x2626:		chipname = "PCnet/Home 79C978";	/* PCI */		fdx = 1;		/*		 * This is based on specs published at www.amd.com.  This section		 * assumes that a card with a 79C978 wants to go into standard		 * ethernet mode.  The 79C978 can also go into 1Mb HomePNA mode,		 * and the module option homepna=1 can select this instead.		 */		media = a->read_bcr(ioaddr, 49);		media &= ~3;	/* default to 10Mb ethernet */		if (cards_found < MAX_UNITS && homepna[cards_found])			media |= 1;	/* switch to home wiring mode */		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_DEBUG PFX "media set to %sMbit mode.\n",			       (media & 1) ? "1" : "10");		a->write_bcr(ioaddr, 49, media);		break;	case 0x2627:		chipname = "PCnet/FAST III 79C975";	/* PCI */		fdx = 1;		mii = 1;		break;	case 0x2628:		chipname = "PCnet/PRO 79C976";		fdx = 1;		mii = 1;		break;	default:		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_INFO PFX			       "PCnet version %#x, no PCnet32 chip.\n",			       chip_version);		goto err_release_region;	}	/*	 *  On selected chips turn on the BCR18:NOUFLO bit. This stops transmit	 *  starting until the packet is loaded. Strike one for reliability, lose	 *  one for latency - although on PCI this isnt a big loss. Older chips	 *  have FIFO's smaller than a packet, so you can't do this.	 *  Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.	 */	if (fset) {		a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860));		a->write_csr(ioaddr, 80,			     (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);		dxsuflo = 1;	}	dev = alloc_etherdev(sizeof(*lp));	if (!dev) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX "Memory allocation failed.\n");		ret = -ENOMEM;		goto err_release_region;	}	SET_NETDEV_DEV(dev, &pdev->dev);	if (pcnet32_debug & NETIF_MSG_PROBE)		printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);	/* In most chips, after a chip reset, the ethernet address is read from the	 * station address PROM at the base address and programmed into the	 * "Physical Address Registers" CSR12-14.	 * As a precautionary measure, we read the PROM values and complain if	 * they disagree with the CSRs.  If they miscompare, and the PROM addr	 * is valid, then the PROM addr is used.	 */	for (i = 0; i < 3; i++) {		unsigned int val;		val = a->read_csr(ioaddr, i + 12) & 0x0ffff;		/* There may be endianness issues here. */		dev->dev_addr[2 * i] = val & 0x0ff;		dev->dev_addr[2 * i + 1] = (val >> 8) & 0x0ff;	}	/* read PROM address and compare with CSR address */	for (i = 0; i < 6; i++)		promaddr[i] = inb(ioaddr + i);	if (memcmp(promaddr, dev->dev_addr, 6)	    || !is_valid_ether_addr(dev->dev_addr)) {		if (is_valid_ether_addr(promaddr)) {			if (pcnet32_debug & NETIF_MSG_PROBE) {				printk(" warning: CSR address invalid,\n");				printk(KERN_INFO				       "    using instead PROM address of");			}			memcpy(dev->dev_addr, promaddr, 6);		}	}	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);	/* if the ethernet address is not valid, force to 00:00:00:00:00:00 */	if (!is_valid_ether_addr(dev->perm_addr))		memset(dev->dev_addr, 0, sizeof(dev->dev_addr));	if (pcnet32_debug & NETIF_MSG_PROBE) {		for (i = 0; i < 6; i++)			printk(" %2.2x", dev->dev_addr[i]);		/* Version 0x2623 and 0x2624 */		if (((chip_version + 1) & 0xfffe) == 0x2624) {			i = a->read_csr(ioaddr, 80) & 0x0C00;	/* Check tx_start_pt */			printk("\n" KERN_INFO "    tx_start_pt(0x%04x):", i);			switch (i >> 10) {			case 0:				printk("  20 bytes,");				break;			case 1:				printk("  64 bytes,");				break;			case 2:				printk(" 128 bytes,");				break;			case 3:				printk("~220 bytes,");				break;			}			i = a->read_bcr(ioaddr, 18);	/* Check Burst/Bus control */			printk(" BCR18(%x):", i & 0xffff);			if (i & (1 << 5))				printk("BurstWrEn ");			if (i & (1 << 6))				printk("BurstRdEn ");			if (i & (1 << 7))				printk("DWordIO ");			if (i & (1 << 11))				printk("NoUFlow ");			i = a->read_bcr(ioaddr, 25);			printk("\n" KERN_INFO "    SRAMSIZE=0x%04x,", i << 8);			i = a->read_bcr(ioaddr, 26);			printk(" SRAM_BND=0x%04x,", i << 8);			i = a->read_bcr(ioaddr, 27);			if (i & (1 << 14))				printk("LowLatRx");		}	}	dev->base_addr = ioaddr;	lp = netdev_priv(dev);	/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */	if ((lp->init_block =	     pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX			       "Consistent memory allocation failed.\n");		ret = -ENOMEM;		goto err_free_netdev;	}	lp->pci_dev = pdev;	lp->dev = dev;	spin_lock_init(&lp->lock);	SET_NETDEV_DEV(dev, &pdev->dev);	lp->name = chipname;	lp->shared_irq = shared;	lp->tx_ring_size = TX_RING_SIZE;	/* default tx ring size */	lp->rx_ring_size = RX_RING_SIZE;	/* default rx ring size */	lp->tx_mod_mask = lp->tx_ring_size - 1;	lp->rx_mod_mask = lp->rx_ring_size - 1;	lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12);	lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4);	lp->mii_if.full_duplex = fdx;	lp->mii_if.phy_id_mask = 0x1f;	lp->mii_if.reg_num_mask = 0x1f;	lp->dxsuflo = dxsuflo;	lp->mii = mii;	lp->chip_version = chip_version;	lp->msg_enable = pcnet32_debug;	if ((cards_found >= MAX_UNITS)	    || (options[cards_found] > sizeof(options_mapping)))		lp->options = PCNET32_PORT_ASEL;	else		lp->options = options_mapping[options[cards_found]];	lp->mii_if.dev = dev;	lp->mii_if.mdio_read = mdio_read;	lp->mii_if.mdio_write = mdio_write;	/* napi.weight is used in both the napi and non-napi cases */	lp->napi.weight = lp->rx_ring_size / 2;#ifdef CONFIG_PCNET32_NAPI	netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2);#endif	if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&	    ((cards_found >= MAX_UNITS) || full_duplex[cards_found]))		lp->options |= PCNET32_PORT_FD;	if (!a) {		if (pcnet32_debug & NETIF_MSG_PROBE)			printk(KERN_ERR PFX "No access methods\n");		ret = -ENODEV;		goto err_free_consistent;	}	lp->a = *a;	/* prior to register_netdev, dev->name is not yet correct */	if (pcnet32_alloc_ring(dev, pci_name(lp->pci_dev))) {		ret = -ENOMEM;		goto err_free_ring;	}	/* detect special T1/E1 WAN card by checking for MAC address */	if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0	    && dev->dev_addr[2] == 0x75)		lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;	lp->init_block->mode = cpu_to_le16(0x0003);	/* Disable Rx and Tx. */	lp->init_block->tlen_rlen =	    cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);	for (i = 0; i < 6; i++)

⌨️ 快捷键说明

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