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

📄 pasemi_mac.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			  mac->tx->irq_name, dev);	if (ret) {		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",			base_irq + mac->dma_txch, ret);		goto out_tx_int;	}	ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED,			  mac->rx->irq_name, dev);	if (ret) {		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",			base_irq + 20 + mac->dma_rxch, ret);		goto out_rx_int;	}	if (mac->phydev)		phy_start(mac->phydev);	return 0;out_rx_int:	free_irq(mac->tx_irq, dev);out_tx_int:	napi_disable(&mac->napi);	netif_stop_queue(dev);	pasemi_mac_free_tx_resources(dev);out_tx_resources:	pasemi_mac_free_rx_resources(dev);out_rx_resources:	return ret;}#define MAX_RETRIES 5000static int pasemi_mac_close(struct net_device *dev){	struct pasemi_mac *mac = netdev_priv(dev);	unsigned int sta;	int retries;	if (mac->phydev) {		phy_stop(mac->phydev);		phy_disconnect(mac->phydev);	}	netif_stop_queue(dev);	napi_disable(&mac->napi);	sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));	if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |		      PAS_DMA_RXINT_RCMDSTA_OO |		      PAS_DMA_RXINT_RCMDSTA_BT))		printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);	sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));	if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |		     PAS_DMA_RXCHAN_CCMDSTA_OD |		     PAS_DMA_RXCHAN_CCMDSTA_FD |		     PAS_DMA_RXCHAN_CCMDSTA_DT))		printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);	sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |		      PAS_DMA_TXCHAN_TCMDSTA_DB |		      PAS_DMA_TXCHAN_TCMDSTA_DE |		      PAS_DMA_TXCHAN_TCMDSTA_DA))		printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);	/* Clean out any pending buffers */	pasemi_mac_clean_tx(mac);	pasemi_mac_clean_rx(mac, RX_RING_SIZE);	/* Disable interface */	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST);	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST);	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);	for (retries = 0; retries < MAX_RETRIES; retries++) {		sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))			break;		cond_resched();	}	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");	for (retries = 0; retries < MAX_RETRIES; retries++) {		sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))			break;		cond_resched();	}	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");	for (retries = 0; retries < MAX_RETRIES; retries++) {		sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))			break;		cond_resched();	}	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");	/* Then, disable the channel. This must be done separately from	 * stopping, since you can't disable when active.	 */	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);	free_irq(mac->tx_irq, dev);	free_irq(mac->rx_irq, dev);	/* Free resources */	pasemi_mac_free_rx_resources(dev);	pasemi_mac_free_tx_resources(dev);	return 0;}static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev){	struct pasemi_mac *mac = netdev_priv(dev);	struct pasemi_mac_txring *txring;	u64 dflags, mactx;	dma_addr_t map[MAX_SKB_FRAGS+1];	unsigned int map_size[MAX_SKB_FRAGS+1];	unsigned long flags;	int i, nfrags;	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD;	if (skb->ip_summed == CHECKSUM_PARTIAL) {		const unsigned char *nh = skb_network_header(skb);		switch (ip_hdr(skb)->protocol) {		case IPPROTO_TCP:			dflags |= XCT_MACTX_CSUM_TCP;			dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2);			dflags |= XCT_MACTX_IPO(nh - skb->data);			break;		case IPPROTO_UDP:			dflags |= XCT_MACTX_CSUM_UDP;			dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2);			dflags |= XCT_MACTX_IPO(nh - skb->data);			break;		}	}	nfrags = skb_shinfo(skb)->nr_frags;	map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),				PCI_DMA_TODEVICE);	map_size[0] = skb_headlen(skb);	if (dma_mapping_error(map[0]))		goto out_err_nolock;	for (i = 0; i < nfrags; i++) {		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];		map[i+1] = pci_map_page(mac->dma_pdev, frag->page,					frag->page_offset, frag->size,					PCI_DMA_TODEVICE);		map_size[i+1] = frag->size;		if (dma_mapping_error(map[i+1])) {			nfrags = i;			goto out_err_nolock;		}	}	mactx = dflags | XCT_MACTX_LLEN(skb->len);	txring = mac->tx;	spin_lock_irqsave(&txring->lock, flags);	/* Avoid stepping on the same cache line that the DMA controller	 * is currently about to send, so leave at least 8 words available.	 * Total free space needed is mactx + fragments + 8	 */	if (RING_AVAIL(txring) < nfrags + 10) {		/* no room -- stop the queue and wait for tx intr */		netif_stop_queue(dev);		goto out_err;	}	TX_RING(mac, txring->next_to_fill) = mactx;	txring->next_to_fill++;	TX_RING_INFO(mac, txring->next_to_fill).skb = skb;	for (i = 0; i <= nfrags; i++) {		TX_RING(mac, txring->next_to_fill+i) =		XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);		TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];	}	/* We have to add an even number of 8-byte entries to the ring	 * even if the last one is unused. That means always an odd number	 * of pointers + one mactx descriptor.	 */	if (nfrags & 1)		nfrags++;	txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &				(TX_RING_SIZE-1);	dev->stats.tx_packets++;	dev->stats.tx_bytes += skb->len;	spin_unlock_irqrestore(&txring->lock, flags);	write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);	return NETDEV_TX_OK;out_err:	spin_unlock_irqrestore(&txring->lock, flags);out_err_nolock:	while (nfrags--)		pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],				 PCI_DMA_TODEVICE);	return NETDEV_TX_BUSY;}static void pasemi_mac_set_rx_mode(struct net_device *dev){	struct pasemi_mac *mac = netdev_priv(dev);	unsigned int flags;	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);	/* Set promiscuous */	if (dev->flags & IFF_PROMISC)		flags |= PAS_MAC_CFG_PCFG_PR;	else		flags &= ~PAS_MAC_CFG_PCFG_PR;	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);}static int pasemi_mac_poll(struct napi_struct *napi, int budget){	struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);	struct net_device *dev = mac->netdev;	int pkts;	pasemi_mac_clean_tx(mac);	pkts = pasemi_mac_clean_rx(mac, budget);	if (pkts < budget) {		/* all done, no more packets present */		netif_rx_complete(dev, napi);		pasemi_mac_restart_rx_intr(mac);	}	return pkts;}static void __iomem * __devinit map_onedev(struct pci_dev *p, int index){	struct device_node *dn;	void __iomem *ret;	dn = pci_device_to_OF_node(p);	if (!dn)		goto fallback;	ret = of_iomap(dn, index);	if (!ret)		goto fallback;	return ret;fallback:	/* This is hardcoded and ugly, but we have some firmware versions	 * that don't provide the register space in the device tree. Luckily	 * they are at well-known locations so we can just do the math here.	 */	return ioremap(0xe0000000 + (p->devfn << 12), 0x2000);}static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac){	struct resource res;	struct device_node *dn;	int err;	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);	if (!mac->dma_pdev) {		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");		return -ENODEV;	}	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);	if (!mac->iob_pdev) {		dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");		return -ENODEV;	}	mac->regs = map_onedev(mac->pdev, 0);	mac->dma_regs = map_onedev(mac->dma_pdev, 0);	mac->iob_regs = map_onedev(mac->iob_pdev, 0);	if (!mac->regs || !mac->dma_regs || !mac->iob_regs) {		dev_err(&mac->pdev->dev, "Can't map registers\n");		return -ENODEV;	}	/* The dma status structure is located in the I/O bridge, and	 * is cache coherent.	 */	if (!dma_status) {		dn = pci_device_to_OF_node(mac->iob_pdev);		if (dn)			err = of_address_to_resource(dn, 1, &res);		if (!dn || err) {			/* Fallback for old firmware */			res.start = 0xfd800000;			res.end = res.start + 0x1000;		}		dma_status = __ioremap(res.start, res.end-res.start, 0);	}	return 0;}static int __devinitpasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent){	static int index = 0;	struct net_device *dev;	struct pasemi_mac *mac;	int err;	DECLARE_MAC_BUF(mac_buf);	err = pci_enable_device(pdev);	if (err)		return err;	dev = alloc_etherdev(sizeof(struct pasemi_mac));	if (dev == NULL) {		dev_err(&pdev->dev,			"pasemi_mac: Could not allocate ethernet device.\n");		err = -ENOMEM;		goto out_disable_device;	}	pci_set_drvdata(pdev, dev);	SET_NETDEV_DEV(dev, &pdev->dev);	mac = netdev_priv(dev);	mac->pdev = pdev;	mac->netdev = dev;	netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG;	/* These should come out of the device tree eventually */	mac->dma_txch = index;	mac->dma_rxch = index;	/* We probe GMAC before XAUI, but the DMA interfaces are	 * in XAUI, GMAC order.	 */	if (index < 4)		mac->dma_if = index + 2;	else		mac->dma_if = index - 4;	index++;	switch (pdev->device) {	case 0xa005:		mac->type = MAC_TYPE_GMAC;		break;	case 0xa006:		mac->type = MAC_TYPE_XAUI;		break;	default:		err = -ENODEV;		goto out;	}	/* get mac addr from device tree */	if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {		err = -ENODEV;		goto out;	}	memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));	dev->open = pasemi_mac_open;	dev->stop = pasemi_mac_close;	dev->hard_start_xmit = pasemi_mac_start_tx;	dev->set_multicast_list = pasemi_mac_set_rx_mode;	err = pasemi_mac_map_regs(mac);	if (err)		goto out;	mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];	mac->tx_status = &dma_status->tx_sta[mac->dma_txch];	mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);	/* Enable most messages by default */	mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;	err = register_netdev(dev);	if (err) {		dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",			err);		goto out;	} else if netif_msg_probe(mac)		printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "		       "hw addr %s\n",		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",		       mac->dma_if, mac->dma_txch, mac->dma_rxch,		       print_mac(mac_buf, dev->dev_addr));	return err;out:	if (mac->iob_pdev)		pci_dev_put(mac->iob_pdev);	if (mac->dma_pdev)		pci_dev_put(mac->dma_pdev);	if (mac->dma_regs)		iounmap(mac->dma_regs);	if (mac->iob_regs)		iounmap(mac->iob_regs);	if (mac->regs)		iounmap(mac->regs);	free_netdev(dev);out_disable_device:	pci_disable_device(pdev);	return err;}static void __devexit pasemi_mac_remove(struct pci_dev *pdev){	struct net_device *netdev = pci_get_drvdata(pdev);	struct pasemi_mac *mac;	if (!netdev)		return;	mac = netdev_priv(netdev);	unregister_netdev(netdev);	pci_disable_device(pdev);	pci_dev_put(mac->dma_pdev);	pci_dev_put(mac->iob_pdev);	iounmap(mac->regs);	iounmap(mac->dma_regs);	iounmap(mac->iob_regs);	pci_set_drvdata(pdev, NULL);	free_netdev(netdev);}static struct pci_device_id pasemi_mac_pci_tbl[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },	{ },};MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);static struct pci_driver pasemi_mac_driver = {	.name		= "pasemi_mac",	.id_table	= pasemi_mac_pci_tbl,	.probe		= pasemi_mac_probe,	.remove		= __devexit_p(pasemi_mac_remove),};static void __exit pasemi_mac_cleanup_module(void){	pci_unregister_driver(&pasemi_mac_driver);	__iounmap(dma_status);	dma_status = NULL;}int pasemi_mac_init_module(void){	return pci_register_driver(&pasemi_mac_driver);}module_init(pasemi_mac_init_module);module_exit(pasemi_mac_cleanup_module);

⌨️ 快捷键说明

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