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

📄 spider_net.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Network device driver for Cell Processor-Based Blade and Celleb platform * * (C) Copyright IBM Corp. 2005 * (C) Copyright 2006 TOSHIBA CORPORATION * * Authors : Utz Bacher <utz.bacher@de.ibm.com> *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/compiler.h>#include <linux/crc32.h>#include <linux/delay.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/firmware.h>#include <linux/if_vlan.h>#include <linux/in.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/ip.h>#include <linux/kernel.h>#include <linux/mii.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/device.h>#include <linux/pci.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/tcp.h>#include <linux/types.h>#include <linux/vmalloc.h>#include <linux/wait.h>#include <linux/workqueue.h>#include <linux/bitops.h>#include <asm/pci-bridge.h>#include <net/checksum.h>#include "spider_net.h"MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \	      "<Jens.Osterkamp@de.ibm.com>");MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(VERSION);static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;module_param(rx_descriptors, int, 0444);module_param(tx_descriptors, int, 0444);MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \		 "in rx chains");MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \		 "in tx chain");char spider_net_driver_name[] = "spidernet";static struct pci_device_id spider_net_pci_tbl[] = {	{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ 0, }};MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);/** * spider_net_read_reg - reads an SMMIO register of a card * @card: device structure * @reg: register to read from * * returns the content of the specified SMMIO register. */static inline u32spider_net_read_reg(struct spider_net_card *card, u32 reg){	/* We use the powerpc specific variants instead of readl_be() because	 * we know spidernet is not a real PCI device and we can thus avoid the	 * performance hit caused by the PCI workarounds.	 */	return in_be32(card->regs + reg);}/** * spider_net_write_reg - writes to an SMMIO register of a card * @card: device structure * @reg: register to write to * @value: value to write into the specified SMMIO register */static inline voidspider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value){	/* We use the powerpc specific variants instead of writel_be() because	 * we know spidernet is not a real PCI device and we can thus avoid the	 * performance hit caused by the PCI workarounds.	 */	out_be32(card->regs + reg, value);}/** spider_net_write_phy - write to phy register * @netdev: adapter to be written to * @mii_id: id of MII * @reg: PHY register * @val: value to be written to phy register * * spider_net_write_phy_register writes to an arbitrary PHY * register via the spider GPCWOPCMD register. We assume the queue does * not run full (not more than 15 commands outstanding). **/static voidspider_net_write_phy(struct net_device *netdev, int mii_id,		     int reg, int val){	struct spider_net_card *card = netdev_priv(netdev);	u32 writevalue;	writevalue = ((u32)mii_id << 21) |		((u32)reg << 16) | ((u32)val);	spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);}/** spider_net_read_phy - read from phy register * @netdev: network device to be read from * @mii_id: id of MII * @reg: PHY register * * Returns value read from PHY register * * spider_net_write_phy reads from an arbitrary PHY * register via the spider GPCROPCMD register **/static intspider_net_read_phy(struct net_device *netdev, int mii_id, int reg){	struct spider_net_card *card = netdev_priv(netdev);	u32 readvalue;	readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);	spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);	/* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT	 * interrupt, as we poll for the completion of the read operation	 * in spider_net_read_phy. Should take about 50 us */	do {		readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);	} while (readvalue & SPIDER_NET_GPREXEC);	readvalue &= SPIDER_NET_GPRDAT_MASK;	return readvalue;}/** * spider_net_setup_aneg - initial auto-negotiation setup * @card: device structure **/static voidspider_net_setup_aneg(struct spider_net_card *card){	struct mii_phy *phy = &card->phy;	u32 advertise = 0;	u16 bmsr, estat;	bmsr  = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);	estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);	if (bmsr & BMSR_10HALF)		advertise |= ADVERTISED_10baseT_Half;	if (bmsr & BMSR_10FULL)		advertise |= ADVERTISED_10baseT_Full;	if (bmsr & BMSR_100HALF)		advertise |= ADVERTISED_100baseT_Half;	if (bmsr & BMSR_100FULL)		advertise |= ADVERTISED_100baseT_Full;	if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))		advertise |= SUPPORTED_1000baseT_Full;	if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))		advertise |= SUPPORTED_1000baseT_Half;	mii_phy_probe(phy, phy->mii_id);	phy->def->ops->setup_aneg(phy, advertise);}/** * spider_net_rx_irq_off - switch off rx irq on this spider card * @card: device structure * * switches off rx irq by masking them out in the GHIINTnMSK register */static voidspider_net_rx_irq_off(struct spider_net_card *card){	u32 regvalue;	regvalue = SPIDER_NET_INT0_MASK_VALUE & (~SPIDER_NET_RXINT);	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);}/** * spider_net_rx_irq_on - switch on rx irq on this spider card * @card: device structure * * switches on rx irq by enabling them in the GHIINTnMSK register */static voidspider_net_rx_irq_on(struct spider_net_card *card){	u32 regvalue;	regvalue = SPIDER_NET_INT0_MASK_VALUE | SPIDER_NET_RXINT;	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);}/** * spider_net_set_promisc - sets the unicast address or the promiscuous mode * @card: card structure * * spider_net_set_promisc sets the unicast destination address filter and * thus either allows for non-promisc mode or promisc mode */static voidspider_net_set_promisc(struct spider_net_card *card){	u32 macu, macl;	struct net_device *netdev = card->netdev;	if (netdev->flags & IFF_PROMISC) {		/* clear destination entry 0 */		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);		spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,				     SPIDER_NET_PROMISC_VALUE);	} else {		macu = netdev->dev_addr[0];		macu <<= 8;		macu |= netdev->dev_addr[1];		memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));		macu |= SPIDER_NET_UA_DESCR_VALUE;		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);		spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,				     SPIDER_NET_NONPROMISC_VALUE);	}}/** * spider_net_get_mac_address - read mac address from spider card * @card: device structure * * reads MAC address from GMACUNIMACU and GMACUNIMACL registers */static intspider_net_get_mac_address(struct net_device *netdev){	struct spider_net_card *card = netdev_priv(netdev);	u32 macl, macu;	macl = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACL);	macu = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACU);	netdev->dev_addr[0] = (macu >> 24) & 0xff;	netdev->dev_addr[1] = (macu >> 16) & 0xff;	netdev->dev_addr[2] = (macu >> 8) & 0xff;	netdev->dev_addr[3] = macu & 0xff;	netdev->dev_addr[4] = (macl >> 8) & 0xff;	netdev->dev_addr[5] = macl & 0xff;	if (!is_valid_ether_addr(&netdev->dev_addr[0]))		return -EINVAL;	return 0;}/** * spider_net_get_descr_status -- returns the status of a descriptor * @descr: descriptor to look at * * returns the status as in the dmac_cmd_status field of the descriptor */static inline intspider_net_get_descr_status(struct spider_net_hw_descr *hwdescr){	return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;}/** * spider_net_free_chain - free descriptor chain * @card: card structure * @chain: address of chain * */static voidspider_net_free_chain(struct spider_net_card *card,		      struct spider_net_descr_chain *chain){	struct spider_net_descr *descr;	descr = chain->ring;	do {		descr->bus_addr = 0;		descr->hwdescr->next_descr_addr = 0;		descr = descr->next;	} while (descr != chain->ring);	dma_free_coherent(&card->pdev->dev, chain->num_desc,	    chain->hwring, chain->dma_addr);}/** * spider_net_init_chain - alloc and link descriptor chain * @card: card structure * @chain: address of chain * * We manage a circular list that mirrors the hardware structure, * except that the hardware uses bus addresses. * * Returns 0 on success, <0 on failure */static intspider_net_init_chain(struct spider_net_card *card,		       struct spider_net_descr_chain *chain){	int i;	struct spider_net_descr *descr;	struct spider_net_hw_descr *hwdescr;	dma_addr_t buf;	size_t alloc_size;	alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);	chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,		&chain->dma_addr, GFP_KERNEL);	if (!chain->hwring)		return -ENOMEM;	memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));	/* Set up the hardware pointers in each descriptor */	descr = chain->ring;	hwdescr = chain->hwring;	buf = chain->dma_addr;	for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;		hwdescr->next_descr_addr = 0;		descr->hwdescr = hwdescr;		descr->bus_addr = buf;		descr->next = descr + 1;		descr->prev = descr - 1;		buf += sizeof(struct spider_net_hw_descr);	}	/* do actual circular list */	(descr-1)->next = chain->ring;	chain->ring->prev = descr-1;	spin_lock_init(&chain->lock);	chain->head = chain->ring;	chain->tail = chain->ring;	return 0;}/** * spider_net_free_rx_chain_contents - frees descr contents in rx chain * @card: card structure * * returns 0 on success, <0 on failure */static voidspider_net_free_rx_chain_contents(struct spider_net_card *card){	struct spider_net_descr *descr;	descr = card->rx_chain.head;	do {		if (descr->skb) {			pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,					 SPIDER_NET_MAX_FRAME,					 PCI_DMA_BIDIRECTIONAL);			dev_kfree_skb(descr->skb);			descr->skb = NULL;		}		descr = descr->next;	} while (descr != card->rx_chain.head);}/** * spider_net_prepare_rx_descr - Reinitialize RX descriptor * @card: card structure * @descr: descriptor to re-init * * Return 0 on succes, <0 on failure. * * Allocates a new rx skb, iommu-maps it and attaches it to the * descriptor. Mark the descriptor as activated, ready-to-use. */static intspider_net_prepare_rx_descr(struct spider_net_card *card,			    struct spider_net_descr *descr){	struct spider_net_hw_descr *hwdescr = descr->hwdescr;	dma_addr_t buf;	int offset;	int bufsize;	/* we need to round up the buffer size to a multiple of 128 */	bufsize = (SPIDER_NET_MAX_FRAME + SPIDER_NET_RXBUF_ALIGN - 1) &		(~(SPIDER_NET_RXBUF_ALIGN - 1));	/* and we need to have it 128 byte aligned, therefore we allocate a	 * bit more */	/* allocate an skb */	descr->skb = netdev_alloc_skb(card->netdev,				      bufsize + SPIDER_NET_RXBUF_ALIGN - 1);	if (!descr->skb) {		if (netif_msg_rx_err(card) && net_ratelimit())			dev_err(&card->netdev->dev,			        "Not enough memory to allocate rx buffer\n");		card->spider_stats.alloc_rx_skb_error++;		return -ENOMEM;	}	hwdescr->buf_size = bufsize;	hwdescr->result_size = 0;	hwdescr->valid_size = 0;	hwdescr->data_status = 0;	hwdescr->data_error = 0;	offset = ((unsigned long)descr->skb->data) &		(SPIDER_NET_RXBUF_ALIGN - 1);	if (offset)		skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);	/* iommu-map the skb */	buf = pci_map_single(card->pdev, descr->skb->data,			SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);	if (pci_dma_mapping_error(buf)) {		dev_kfree_skb_any(descr->skb);		descr->skb = NULL;		if (netif_msg_rx_err(card) && net_ratelimit())			dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");		card->spider_stats.rx_iommu_map_error++;		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;	} else {		hwdescr->buf_addr = buf;		wmb();		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |					 SPIDER_NET_DMAC_NOINTR_COMPLETE;	}	return 0;}

⌨️ 快捷键说明

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