18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1998-2002 by Jes Sorensen, <jes@wildopensource.com>.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Thanks to Essential Communication for providing us with hardware
88c2ecf20Sopenharmony_ci * and very comprehensive documentation without which I would not have
98c2ecf20Sopenharmony_ci * been able to write this driver. A special thank you to John Gibbon
108c2ecf20Sopenharmony_ci * for sorting out the legal issues, with the NDA, allowing the code to
118c2ecf20Sopenharmony_ci * be released under the GPL.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the
148c2ecf20Sopenharmony_ci * stupid bugs in my code.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Softnet support and various other patches from Val Henson of
178c2ecf20Sopenharmony_ci * ODS/Essential.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * PCI DMA mapping code partly based on work by Francois Romieu.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DEBUG 1
248c2ecf20Sopenharmony_ci#define RX_DMA_SKBUFF 1
258c2ecf20Sopenharmony_ci#define PKT_COPY_THRESHOLD 512
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/types.h>
298c2ecf20Sopenharmony_ci#include <linux/errno.h>
308c2ecf20Sopenharmony_ci#include <linux/ioport.h>
318c2ecf20Sopenharmony_ci#include <linux/pci.h>
328c2ecf20Sopenharmony_ci#include <linux/kernel.h>
338c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
348c2ecf20Sopenharmony_ci#include <linux/hippidevice.h>
358c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
368c2ecf20Sopenharmony_ci#include <linux/delay.h>
378c2ecf20Sopenharmony_ci#include <linux/mm.h>
388c2ecf20Sopenharmony_ci#include <linux/slab.h>
398c2ecf20Sopenharmony_ci#include <net/sock.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <asm/cache.h>
428c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
438c2ecf20Sopenharmony_ci#include <asm/io.h>
448c2ecf20Sopenharmony_ci#include <asm/irq.h>
458c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define rr_if_busy(dev)     netif_queue_stopped(dev)
488c2ecf20Sopenharmony_ci#define rr_if_running(dev)  netif_running(dev)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include "rrunner.h"
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define RUN_AT(x) (jiffies + (x))
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jes Sorensen <jes@wildopensource.com>");
568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Essential RoadRunner HIPPI driver");
578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic const char version[] =
608c2ecf20Sopenharmony_ci"rrunner.c: v0.50 11/11/2002  Jes Sorensen (jes@wildopensource.com)\n";
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const struct net_device_ops rr_netdev_ops = {
648c2ecf20Sopenharmony_ci	.ndo_open 		= rr_open,
658c2ecf20Sopenharmony_ci	.ndo_stop		= rr_close,
668c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= rr_ioctl,
678c2ecf20Sopenharmony_ci	.ndo_start_xmit		= rr_start_xmit,
688c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= hippi_mac_addr,
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * Implementation notes:
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * The DMA engine only allows for DMA within physical 64KB chunks of
758c2ecf20Sopenharmony_ci * memory. The current approach of the driver (and stack) is to use
768c2ecf20Sopenharmony_ci * linear blocks of memory for the skbuffs. However, as the data block
778c2ecf20Sopenharmony_ci * is always the first part of the skb and skbs are 2^n aligned so we
788c2ecf20Sopenharmony_ci * are guarantted to get the whole block within one 64KB align 64KB
798c2ecf20Sopenharmony_ci * chunk.
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci * On the long term, relying on being able to allocate 64KB linear
828c2ecf20Sopenharmony_ci * chunks of memory is not feasible and the skb handling code and the
838c2ecf20Sopenharmony_ci * stack will need to know about I/O vectors or something similar.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int rr_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct net_device *dev;
898c2ecf20Sopenharmony_ci	static int version_disp;
908c2ecf20Sopenharmony_ci	u8 pci_latency;
918c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
928c2ecf20Sopenharmony_ci	void *tmpptr;
938c2ecf20Sopenharmony_ci	dma_addr_t ring_dma;
948c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	dev = alloc_hippi_dev(sizeof(struct rr_private));
978c2ecf20Sopenharmony_ci	if (!dev)
988c2ecf20Sopenharmony_ci		goto out3;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
1018c2ecf20Sopenharmony_ci	if (ret) {
1028c2ecf20Sopenharmony_ci		ret = -ENODEV;
1038c2ecf20Sopenharmony_ci		goto out2;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	ret = pci_request_regions(pdev, "rrunner");
1118c2ecf20Sopenharmony_ci	if (ret < 0)
1128c2ecf20Sopenharmony_ci		goto out;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, dev);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	rrpriv->pci_dev = pdev;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	spin_lock_init(&rrpriv->lock);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	dev->netdev_ops = &rr_netdev_ops;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* display version info if adapter is found */
1238c2ecf20Sopenharmony_ci	if (!version_disp) {
1248c2ecf20Sopenharmony_ci		/* set display flag to TRUE so that */
1258c2ecf20Sopenharmony_ci		/* we only display this string ONCE */
1268c2ecf20Sopenharmony_ci		version_disp = 1;
1278c2ecf20Sopenharmony_ci		printk(version);
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
1318c2ecf20Sopenharmony_ci	if (pci_latency <= 0x58){
1328c2ecf20Sopenharmony_ci		pci_latency = 0x58;
1338c2ecf20Sopenharmony_ci		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	pci_set_master(pdev);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
1398c2ecf20Sopenharmony_ci	       "at 0x%llx, irq %i, PCI latency %i\n", dev->name,
1408c2ecf20Sopenharmony_ci	       (unsigned long long)pci_resource_start(pdev, 0),
1418c2ecf20Sopenharmony_ci	       pdev->irq, pci_latency);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * Remap the MMIO regs into kernel space.
1458c2ecf20Sopenharmony_ci	 */
1468c2ecf20Sopenharmony_ci	rrpriv->regs = pci_iomap(pdev, 0, 0x1000);
1478c2ecf20Sopenharmony_ci	if (!rrpriv->regs) {
1488c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s:  Unable to map I/O register, "
1498c2ecf20Sopenharmony_ci			"RoadRunner will be disabled.\n", dev->name);
1508c2ecf20Sopenharmony_ci		ret = -EIO;
1518c2ecf20Sopenharmony_ci		goto out;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma,
1558c2ecf20Sopenharmony_ci				    GFP_KERNEL);
1568c2ecf20Sopenharmony_ci	rrpriv->tx_ring = tmpptr;
1578c2ecf20Sopenharmony_ci	rrpriv->tx_ring_dma = ring_dma;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (!tmpptr) {
1608c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1618c2ecf20Sopenharmony_ci		goto out;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma,
1658c2ecf20Sopenharmony_ci				    GFP_KERNEL);
1668c2ecf20Sopenharmony_ci	rrpriv->rx_ring = tmpptr;
1678c2ecf20Sopenharmony_ci	rrpriv->rx_ring_dma = ring_dma;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (!tmpptr) {
1708c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1718c2ecf20Sopenharmony_ci		goto out;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, EVT_RING_SIZE, &ring_dma,
1758c2ecf20Sopenharmony_ci				    GFP_KERNEL);
1768c2ecf20Sopenharmony_ci	rrpriv->evt_ring = tmpptr;
1778c2ecf20Sopenharmony_ci	rrpriv->evt_ring_dma = ring_dma;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (!tmpptr) {
1808c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1818c2ecf20Sopenharmony_ci		goto out;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/*
1858c2ecf20Sopenharmony_ci	 * Don't access any register before this point!
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
1888c2ecf20Sopenharmony_ci	writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP,
1898c2ecf20Sopenharmony_ci		&rrpriv->regs->HostCtrl);
1908c2ecf20Sopenharmony_ci#endif
1918c2ecf20Sopenharmony_ci	/*
1928c2ecf20Sopenharmony_ci	 * Need to add a case for little-endian 64-bit hosts here.
1938c2ecf20Sopenharmony_ci	 */
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	rr_init(dev);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ret = register_netdev(dev);
1988c2ecf20Sopenharmony_ci	if (ret)
1998c2ecf20Sopenharmony_ci		goto out;
2008c2ecf20Sopenharmony_ci	return 0;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci out:
2038c2ecf20Sopenharmony_ci	if (rrpriv->evt_ring)
2048c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, EVT_RING_SIZE, rrpriv->evt_ring,
2058c2ecf20Sopenharmony_ci				  rrpriv->evt_ring_dma);
2068c2ecf20Sopenharmony_ci	if (rrpriv->rx_ring)
2078c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, rrpriv->rx_ring,
2088c2ecf20Sopenharmony_ci				  rrpriv->rx_ring_dma);
2098c2ecf20Sopenharmony_ci	if (rrpriv->tx_ring)
2108c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, rrpriv->tx_ring,
2118c2ecf20Sopenharmony_ci				  rrpriv->tx_ring_dma);
2128c2ecf20Sopenharmony_ci	if (rrpriv->regs)
2138c2ecf20Sopenharmony_ci		pci_iounmap(pdev, rrpriv->regs);
2148c2ecf20Sopenharmony_ci	if (pdev)
2158c2ecf20Sopenharmony_ci		pci_release_regions(pdev);
2168c2ecf20Sopenharmony_ci out2:
2178c2ecf20Sopenharmony_ci	free_netdev(dev);
2188c2ecf20Sopenharmony_ci out3:
2198c2ecf20Sopenharmony_ci	return ret;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void rr_remove_one(struct pci_dev *pdev)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
2258c2ecf20Sopenharmony_ci	struct rr_private *rr = netdev_priv(dev);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)) {
2288c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: trying to unload running NIC\n",
2298c2ecf20Sopenharmony_ci		       dev->name);
2308c2ecf20Sopenharmony_ci		writel(HALT_NIC, &rr->regs->HostCtrl);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	unregister_netdev(dev);
2348c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, EVT_RING_SIZE, rr->evt_ring,
2358c2ecf20Sopenharmony_ci			  rr->evt_ring_dma);
2368c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, rr->rx_ring,
2378c2ecf20Sopenharmony_ci			  rr->rx_ring_dma);
2388c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, rr->tx_ring,
2398c2ecf20Sopenharmony_ci			  rr->tx_ring_dma);
2408c2ecf20Sopenharmony_ci	pci_iounmap(pdev, rr->regs);
2418c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
2428c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
2438c2ecf20Sopenharmony_ci	free_netdev(dev);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/*
2488c2ecf20Sopenharmony_ci * Commands are considered to be slow, thus there is no reason to
2498c2ecf20Sopenharmony_ci * inline this.
2508c2ecf20Sopenharmony_ci */
2518c2ecf20Sopenharmony_cistatic void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
2548c2ecf20Sopenharmony_ci	u32 idx;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * This is temporary - it will go away in the final version.
2598c2ecf20Sopenharmony_ci	 * We probably also want to make this function inline.
2608c2ecf20Sopenharmony_ci	 */
2618c2ecf20Sopenharmony_ci	if (readl(&regs->HostCtrl) & NIC_HALTED){
2628c2ecf20Sopenharmony_ci		printk("issuing command for halted NIC, code 0x%x, "
2638c2ecf20Sopenharmony_ci		       "HostCtrl %08x\n", cmd->code, readl(&regs->HostCtrl));
2648c2ecf20Sopenharmony_ci		if (readl(&regs->Mode) & FATAL_ERR)
2658c2ecf20Sopenharmony_ci			printk("error codes Fail1 %02x, Fail2 %02x\n",
2668c2ecf20Sopenharmony_ci			       readl(&regs->Fail1), readl(&regs->Fail2));
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	idx = rrpriv->info->cmd_ctrl.pi;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	writel(*(u32*)(cmd), &regs->CmdRing[idx]);
2728c2ecf20Sopenharmony_ci	wmb();
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	idx = (idx - 1) % CMD_RING_ENTRIES;
2758c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = idx;
2768c2ecf20Sopenharmony_ci	wmb();
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (readl(&regs->Mode) & FATAL_ERR)
2798c2ecf20Sopenharmony_ci		printk("error code %02x\n", readl(&regs->Fail1));
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/*
2848c2ecf20Sopenharmony_ci * Reset the board in a sensible manner. The NIC is already halted
2858c2ecf20Sopenharmony_ci * when we get here and a spin-lock is held.
2868c2ecf20Sopenharmony_ci */
2878c2ecf20Sopenharmony_cistatic int rr_reset(struct net_device *dev)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
2908c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
2918c2ecf20Sopenharmony_ci	u32 start_pc;
2928c2ecf20Sopenharmony_ci	int i;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
2958c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	rr_load_firmware(dev);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	writel(0x01000000, &regs->TX_state);
3008c2ecf20Sopenharmony_ci	writel(0xff800000, &regs->RX_state);
3018c2ecf20Sopenharmony_ci	writel(0, &regs->AssistState);
3028c2ecf20Sopenharmony_ci	writel(CLEAR_INTA, &regs->LocalCtrl);
3038c2ecf20Sopenharmony_ci	writel(0x01, &regs->BrkPt);
3048c2ecf20Sopenharmony_ci	writel(0, &regs->Timer);
3058c2ecf20Sopenharmony_ci	writel(0, &regs->TimerRef);
3068c2ecf20Sopenharmony_ci	writel(RESET_DMA, &regs->DmaReadState);
3078c2ecf20Sopenharmony_ci	writel(RESET_DMA, &regs->DmaWriteState);
3088c2ecf20Sopenharmony_ci	writel(0, &regs->DmaWriteHostHi);
3098c2ecf20Sopenharmony_ci	writel(0, &regs->DmaWriteHostLo);
3108c2ecf20Sopenharmony_ci	writel(0, &regs->DmaReadHostHi);
3118c2ecf20Sopenharmony_ci	writel(0, &regs->DmaReadHostLo);
3128c2ecf20Sopenharmony_ci	writel(0, &regs->DmaReadLen);
3138c2ecf20Sopenharmony_ci	writel(0, &regs->DmaWriteLen);
3148c2ecf20Sopenharmony_ci	writel(0, &regs->DmaWriteLcl);
3158c2ecf20Sopenharmony_ci	writel(0, &regs->DmaWriteIPchecksum);
3168c2ecf20Sopenharmony_ci	writel(0, &regs->DmaReadLcl);
3178c2ecf20Sopenharmony_ci	writel(0, &regs->DmaReadIPchecksum);
3188c2ecf20Sopenharmony_ci	writel(0, &regs->PciState);
3198c2ecf20Sopenharmony_ci#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN
3208c2ecf20Sopenharmony_ci	writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, &regs->Mode);
3218c2ecf20Sopenharmony_ci#elif (BITS_PER_LONG == 64)
3228c2ecf20Sopenharmony_ci	writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, &regs->Mode);
3238c2ecf20Sopenharmony_ci#else
3248c2ecf20Sopenharmony_ci	writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, &regs->Mode);
3258c2ecf20Sopenharmony_ci#endif
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci#if 0
3288c2ecf20Sopenharmony_ci	/*
3298c2ecf20Sopenharmony_ci	 * Don't worry, this is just black magic.
3308c2ecf20Sopenharmony_ci	 */
3318c2ecf20Sopenharmony_ci	writel(0xdf000, &regs->RxBase);
3328c2ecf20Sopenharmony_ci	writel(0xdf000, &regs->RxPrd);
3338c2ecf20Sopenharmony_ci	writel(0xdf000, &regs->RxCon);
3348c2ecf20Sopenharmony_ci	writel(0xce000, &regs->TxBase);
3358c2ecf20Sopenharmony_ci	writel(0xce000, &regs->TxPrd);
3368c2ecf20Sopenharmony_ci	writel(0xce000, &regs->TxCon);
3378c2ecf20Sopenharmony_ci	writel(0, &regs->RxIndPro);
3388c2ecf20Sopenharmony_ci	writel(0, &regs->RxIndCon);
3398c2ecf20Sopenharmony_ci	writel(0, &regs->RxIndRef);
3408c2ecf20Sopenharmony_ci	writel(0, &regs->TxIndPro);
3418c2ecf20Sopenharmony_ci	writel(0, &regs->TxIndCon);
3428c2ecf20Sopenharmony_ci	writel(0, &regs->TxIndRef);
3438c2ecf20Sopenharmony_ci	writel(0xcc000, &regs->pad10[0]);
3448c2ecf20Sopenharmony_ci	writel(0, &regs->DrCmndPro);
3458c2ecf20Sopenharmony_ci	writel(0, &regs->DrCmndCon);
3468c2ecf20Sopenharmony_ci	writel(0, &regs->DwCmndPro);
3478c2ecf20Sopenharmony_ci	writel(0, &regs->DwCmndCon);
3488c2ecf20Sopenharmony_ci	writel(0, &regs->DwCmndRef);
3498c2ecf20Sopenharmony_ci	writel(0, &regs->DrDataPro);
3508c2ecf20Sopenharmony_ci	writel(0, &regs->DrDataCon);
3518c2ecf20Sopenharmony_ci	writel(0, &regs->DrDataRef);
3528c2ecf20Sopenharmony_ci	writel(0, &regs->DwDataPro);
3538c2ecf20Sopenharmony_ci	writel(0, &regs->DwDataCon);
3548c2ecf20Sopenharmony_ci	writel(0, &regs->DwDataRef);
3558c2ecf20Sopenharmony_ci#endif
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	writel(0xffffffff, &regs->MbEvent);
3588c2ecf20Sopenharmony_ci	writel(0, &regs->Event);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	writel(0, &regs->TxPi);
3618c2ecf20Sopenharmony_ci	writel(0, &regs->IpRxPi);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	writel(0, &regs->EvtCon);
3648c2ecf20Sopenharmony_ci	writel(0, &regs->EvtPrd);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++)
3698c2ecf20Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/*
3728c2ecf20Sopenharmony_ci * Why 32 ? is this not cache line size dependent?
3738c2ecf20Sopenharmony_ci */
3748c2ecf20Sopenharmony_ci	writel(RBURST_64|WBURST_64, &regs->PciState);
3758c2ecf20Sopenharmony_ci	wmb();
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	start_pc = rr_read_eeprom_word(rrpriv,
3788c2ecf20Sopenharmony_ci			offsetof(struct eeprom, rncd_info.FwStart));
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#if (DEBUG > 1)
3818c2ecf20Sopenharmony_ci	printk("%s: Executing firmware at address 0x%06x\n",
3828c2ecf20Sopenharmony_ci	       dev->name, start_pc);
3838c2ecf20Sopenharmony_ci#endif
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	writel(start_pc + 0x800, &regs->Pc);
3868c2ecf20Sopenharmony_ci	wmb();
3878c2ecf20Sopenharmony_ci	udelay(5);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	writel(start_pc, &regs->Pc);
3908c2ecf20Sopenharmony_ci	wmb();
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/*
3978c2ecf20Sopenharmony_ci * Read a string from the EEPROM.
3988c2ecf20Sopenharmony_ci */
3998c2ecf20Sopenharmony_cistatic unsigned int rr_read_eeprom(struct rr_private *rrpriv,
4008c2ecf20Sopenharmony_ci				unsigned long offset,
4018c2ecf20Sopenharmony_ci				unsigned char *buf,
4028c2ecf20Sopenharmony_ci				unsigned long length)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
4058c2ecf20Sopenharmony_ci	u32 misc, io, host, i;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	io = readl(&regs->ExtIo);
4088c2ecf20Sopenharmony_ci	writel(0, &regs->ExtIo);
4098c2ecf20Sopenharmony_ci	misc = readl(&regs->LocalCtrl);
4108c2ecf20Sopenharmony_ci	writel(0, &regs->LocalCtrl);
4118c2ecf20Sopenharmony_ci	host = readl(&regs->HostCtrl);
4128c2ecf20Sopenharmony_ci	writel(host | HALT_NIC, &regs->HostCtrl);
4138c2ecf20Sopenharmony_ci	mb();
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	for (i = 0; i < length; i++){
4168c2ecf20Sopenharmony_ci		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
4178c2ecf20Sopenharmony_ci		mb();
4188c2ecf20Sopenharmony_ci		buf[i] = (readl(&regs->WinData) >> 24) & 0xff;
4198c2ecf20Sopenharmony_ci		mb();
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	writel(host, &regs->HostCtrl);
4238c2ecf20Sopenharmony_ci	writel(misc, &regs->LocalCtrl);
4248c2ecf20Sopenharmony_ci	writel(io, &regs->ExtIo);
4258c2ecf20Sopenharmony_ci	mb();
4268c2ecf20Sopenharmony_ci	return i;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci/*
4318c2ecf20Sopenharmony_ci * Shortcut to read one word (4 bytes) out of the EEPROM and convert
4328c2ecf20Sopenharmony_ci * it to our CPU byte-order.
4338c2ecf20Sopenharmony_ci */
4348c2ecf20Sopenharmony_cistatic u32 rr_read_eeprom_word(struct rr_private *rrpriv,
4358c2ecf20Sopenharmony_ci			    size_t offset)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	__be32 word;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if ((rr_read_eeprom(rrpriv, offset,
4408c2ecf20Sopenharmony_ci			    (unsigned char *)&word, 4) == 4))
4418c2ecf20Sopenharmony_ci		return be32_to_cpu(word);
4428c2ecf20Sopenharmony_ci	return 0;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci/*
4478c2ecf20Sopenharmony_ci * Write a string to the EEPROM.
4488c2ecf20Sopenharmony_ci *
4498c2ecf20Sopenharmony_ci * This is only called when the firmware is not running.
4508c2ecf20Sopenharmony_ci */
4518c2ecf20Sopenharmony_cistatic unsigned int write_eeprom(struct rr_private *rrpriv,
4528c2ecf20Sopenharmony_ci				 unsigned long offset,
4538c2ecf20Sopenharmony_ci				 unsigned char *buf,
4548c2ecf20Sopenharmony_ci				 unsigned long length)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
4578c2ecf20Sopenharmony_ci	u32 misc, io, data, i, j, ready, error = 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	io = readl(&regs->ExtIo);
4608c2ecf20Sopenharmony_ci	writel(0, &regs->ExtIo);
4618c2ecf20Sopenharmony_ci	misc = readl(&regs->LocalCtrl);
4628c2ecf20Sopenharmony_ci	writel(ENABLE_EEPROM_WRITE, &regs->LocalCtrl);
4638c2ecf20Sopenharmony_ci	mb();
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	for (i = 0; i < length; i++){
4668c2ecf20Sopenharmony_ci		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
4678c2ecf20Sopenharmony_ci		mb();
4688c2ecf20Sopenharmony_ci		data = buf[i] << 24;
4698c2ecf20Sopenharmony_ci		/*
4708c2ecf20Sopenharmony_ci		 * Only try to write the data if it is not the same
4718c2ecf20Sopenharmony_ci		 * value already.
4728c2ecf20Sopenharmony_ci		 */
4738c2ecf20Sopenharmony_ci		if ((readl(&regs->WinData) & 0xff000000) != data){
4748c2ecf20Sopenharmony_ci			writel(data, &regs->WinData);
4758c2ecf20Sopenharmony_ci			ready = 0;
4768c2ecf20Sopenharmony_ci			j = 0;
4778c2ecf20Sopenharmony_ci			mb();
4788c2ecf20Sopenharmony_ci			while(!ready){
4798c2ecf20Sopenharmony_ci				udelay(20);
4808c2ecf20Sopenharmony_ci				if ((readl(&regs->WinData) & 0xff000000) ==
4818c2ecf20Sopenharmony_ci				    data)
4828c2ecf20Sopenharmony_ci					ready = 1;
4838c2ecf20Sopenharmony_ci				mb();
4848c2ecf20Sopenharmony_ci				if (j++ > 5000){
4858c2ecf20Sopenharmony_ci					printk("data mismatch: %08x, "
4868c2ecf20Sopenharmony_ci					       "WinData %08x\n", data,
4878c2ecf20Sopenharmony_ci					       readl(&regs->WinData));
4888c2ecf20Sopenharmony_ci					ready = 1;
4898c2ecf20Sopenharmony_ci					error = 1;
4908c2ecf20Sopenharmony_ci				}
4918c2ecf20Sopenharmony_ci			}
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	writel(misc, &regs->LocalCtrl);
4968c2ecf20Sopenharmony_ci	writel(io, &regs->ExtIo);
4978c2ecf20Sopenharmony_ci	mb();
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	return error;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int rr_init(struct net_device *dev)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
5068c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
5078c2ecf20Sopenharmony_ci	u32 sram_size, rev;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
5108c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	rev = readl(&regs->FwRev);
5138c2ecf20Sopenharmony_ci	rrpriv->fw_rev = rev;
5148c2ecf20Sopenharmony_ci	if (rev > 0x00020024)
5158c2ecf20Sopenharmony_ci		printk("  Firmware revision: %i.%i.%i\n", (rev >> 16),
5168c2ecf20Sopenharmony_ci		       ((rev >> 8) & 0xff), (rev & 0xff));
5178c2ecf20Sopenharmony_ci	else if (rev >= 0x00020000) {
5188c2ecf20Sopenharmony_ci		printk("  Firmware revision: %i.%i.%i (2.0.37 or "
5198c2ecf20Sopenharmony_ci		       "later is recommended)\n", (rev >> 16),
5208c2ecf20Sopenharmony_ci		       ((rev >> 8) & 0xff), (rev & 0xff));
5218c2ecf20Sopenharmony_ci	}else{
5228c2ecf20Sopenharmony_ci		printk("  Firmware revision too old: %i.%i.%i, please "
5238c2ecf20Sopenharmony_ci		       "upgrade to 2.0.37 or later.\n",
5248c2ecf20Sopenharmony_ci		       (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci#if (DEBUG > 2)
5288c2ecf20Sopenharmony_ci	printk("  Maximum receive rings %i\n", readl(&regs->MaxRxRng));
5298c2ecf20Sopenharmony_ci#endif
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/*
5328c2ecf20Sopenharmony_ci	 * Read the hardware address from the eeprom.  The HW address
5338c2ecf20Sopenharmony_ci	 * is not really necessary for HIPPI but awfully convenient.
5348c2ecf20Sopenharmony_ci	 * The pointer arithmetic to put it in dev_addr is ugly, but
5358c2ecf20Sopenharmony_ci	 * Donald Becker does it this way for the GigE version of this
5368c2ecf20Sopenharmony_ci	 * card and it's shorter and more portable than any
5378c2ecf20Sopenharmony_ci	 * other method I've seen.  -VAL
5388c2ecf20Sopenharmony_ci	 */
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	*(__be16 *)(dev->dev_addr) =
5418c2ecf20Sopenharmony_ci	  htons(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA)));
5428c2ecf20Sopenharmony_ci	*(__be32 *)(dev->dev_addr+2) =
5438c2ecf20Sopenharmony_ci	  htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4])));
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	printk("  MAC: %pM\n", dev->dev_addr);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	sram_size = rr_read_eeprom_word(rrpriv, 8);
5488c2ecf20Sopenharmony_ci	printk("  SRAM size 0x%06x\n", sram_size);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int rr_init1(struct net_device *dev)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
5578c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
5588c2ecf20Sopenharmony_ci	unsigned long myjif, flags;
5598c2ecf20Sopenharmony_ci	struct cmd cmd;
5608c2ecf20Sopenharmony_ci	u32 hostctrl;
5618c2ecf20Sopenharmony_ci	int ecode = 0;
5628c2ecf20Sopenharmony_ci	short i;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
5658c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	hostctrl = readl(&regs->HostCtrl);
5708c2ecf20Sopenharmony_ci	writel(hostctrl | HALT_NIC | RR_CLEAR_INT, &regs->HostCtrl);
5718c2ecf20Sopenharmony_ci	wmb();
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (hostctrl & PARITY_ERR){
5748c2ecf20Sopenharmony_ci		printk("%s: Parity error halting NIC - this is serious!\n",
5758c2ecf20Sopenharmony_ci		       dev->name);
5768c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
5778c2ecf20Sopenharmony_ci		ecode = -EFAULT;
5788c2ecf20Sopenharmony_ci		goto error;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	set_rxaddr(regs, rrpriv->rx_ctrl_dma);
5828c2ecf20Sopenharmony_ci	set_infoaddr(regs, rrpriv->info_dma);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.entry_size = sizeof(struct event);
5858c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES;
5868c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.mode = 0;
5878c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
5888c2ecf20Sopenharmony_ci	set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring_dma);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd);
5918c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES;
5928c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.mode = 0;
5938c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = 15;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++) {
5968c2ecf20Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++) {
6008c2ecf20Sopenharmony_ci		rrpriv->tx_ring[i].size = 0;
6018c2ecf20Sopenharmony_ci		set_rraddr(&rrpriv->tx_ring[i].addr, 0);
6028c2ecf20Sopenharmony_ci		rrpriv->tx_skbuff[i] = NULL;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc);
6058c2ecf20Sopenharmony_ci	rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES;
6068c2ecf20Sopenharmony_ci	rrpriv->info->tx_ctrl.mode = 0;
6078c2ecf20Sopenharmony_ci	rrpriv->info->tx_ctrl.pi = 0;
6088c2ecf20Sopenharmony_ci	set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring_dma);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/*
6118c2ecf20Sopenharmony_ci	 * Set dirty_tx before we start receiving interrupts, otherwise
6128c2ecf20Sopenharmony_ci	 * the interrupt handler might think it is supposed to process
6138c2ecf20Sopenharmony_ci	 * tx ints before we are up and running, which may cause a null
6148c2ecf20Sopenharmony_ci	 * pointer access in the int handler.
6158c2ecf20Sopenharmony_ci	 */
6168c2ecf20Sopenharmony_ci	rrpriv->tx_full = 0;
6178c2ecf20Sopenharmony_ci	rrpriv->cur_rx = 0;
6188c2ecf20Sopenharmony_ci	rrpriv->dirty_rx = rrpriv->dirty_tx = 0;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	rr_reset(dev);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* Tuning values */
6238c2ecf20Sopenharmony_ci	writel(0x5000, &regs->ConRetry);
6248c2ecf20Sopenharmony_ci	writel(0x100, &regs->ConRetryTmr);
6258c2ecf20Sopenharmony_ci	writel(0x500000, &regs->ConTmout);
6268c2ecf20Sopenharmony_ci 	writel(0x60, &regs->IntrTmr);
6278c2ecf20Sopenharmony_ci	writel(0x500000, &regs->TxDataMvTimeout);
6288c2ecf20Sopenharmony_ci	writel(0x200000, &regs->RxDataMvTimeout);
6298c2ecf20Sopenharmony_ci 	writel(0x80, &regs->WriteDmaThresh);
6308c2ecf20Sopenharmony_ci 	writel(0x80, &regs->ReadDmaThresh);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	rrpriv->fw_running = 0;
6338c2ecf20Sopenharmony_ci	wmb();
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR);
6368c2ecf20Sopenharmony_ci	writel(hostctrl, &regs->HostCtrl);
6378c2ecf20Sopenharmony_ci	wmb();
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
6428c2ecf20Sopenharmony_ci		struct sk_buff *skb;
6438c2ecf20Sopenharmony_ci		dma_addr_t addr;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		rrpriv->rx_ring[i].mode = 0;
6468c2ecf20Sopenharmony_ci		skb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC);
6478c2ecf20Sopenharmony_ci		if (!skb) {
6488c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Unable to allocate memory "
6498c2ecf20Sopenharmony_ci			       "for receive ring - halting NIC\n", dev->name);
6508c2ecf20Sopenharmony_ci			ecode = -ENOMEM;
6518c2ecf20Sopenharmony_ci			goto error;
6528c2ecf20Sopenharmony_ci		}
6538c2ecf20Sopenharmony_ci		rrpriv->rx_skbuff[i] = skb;
6548c2ecf20Sopenharmony_ci		addr = dma_map_single(&rrpriv->pci_dev->dev, skb->data,
6558c2ecf20Sopenharmony_ci				      dev->mtu + HIPPI_HLEN, DMA_FROM_DEVICE);
6568c2ecf20Sopenharmony_ci		/*
6578c2ecf20Sopenharmony_ci		 * Sanity test to see if we conflict with the DMA
6588c2ecf20Sopenharmony_ci		 * limitations of the Roadrunner.
6598c2ecf20Sopenharmony_ci		 */
6608c2ecf20Sopenharmony_ci		if ((((unsigned long)skb->data) & 0xfff) > ~65320)
6618c2ecf20Sopenharmony_ci			printk("skb alloc error\n");
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		set_rraddr(&rrpriv->rx_ring[i].addr, addr);
6648c2ecf20Sopenharmony_ci		rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl[4].entry_size = sizeof(struct rx_desc);
6688c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES;
6698c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl[4].mode = 8;
6708c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl[4].pi = 0;
6718c2ecf20Sopenharmony_ci	wmb();
6728c2ecf20Sopenharmony_ci	set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring_dma);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	udelay(1000);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/*
6778c2ecf20Sopenharmony_ci	 * Now start the FirmWare.
6788c2ecf20Sopenharmony_ci	 */
6798c2ecf20Sopenharmony_ci	cmd.code = C_START_FW;
6808c2ecf20Sopenharmony_ci	cmd.ring = 0;
6818c2ecf20Sopenharmony_ci	cmd.index = 0;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	rr_issue_cmd(rrpriv, &cmd);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	/*
6868c2ecf20Sopenharmony_ci	 * Give the FirmWare time to chew on the `get running' command.
6878c2ecf20Sopenharmony_ci	 */
6888c2ecf20Sopenharmony_ci	myjif = jiffies + 5 * HZ;
6898c2ecf20Sopenharmony_ci	while (time_before(jiffies, myjif) && !rrpriv->fw_running)
6908c2ecf20Sopenharmony_ci		cpu_relax();
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	netif_start_queue(dev);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	return ecode;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci error:
6978c2ecf20Sopenharmony_ci	/*
6988c2ecf20Sopenharmony_ci	 * We might have gotten here because we are out of memory,
6998c2ecf20Sopenharmony_ci	 * make sure we release everything we allocated before failing
7008c2ecf20Sopenharmony_ci	 */
7018c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
7028c2ecf20Sopenharmony_ci		struct sk_buff *skb = rrpriv->rx_skbuff[i];
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		if (skb) {
7058c2ecf20Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
7068c2ecf20Sopenharmony_ci					 rrpriv->rx_ring[i].addr.addrlo,
7078c2ecf20Sopenharmony_ci					 dev->mtu + HIPPI_HLEN,
7088c2ecf20Sopenharmony_ci					 DMA_FROM_DEVICE);
7098c2ecf20Sopenharmony_ci			rrpriv->rx_ring[i].size = 0;
7108c2ecf20Sopenharmony_ci			set_rraddr(&rrpriv->rx_ring[i].addr, 0);
7118c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
7128c2ecf20Sopenharmony_ci			rrpriv->rx_skbuff[i] = NULL;
7138c2ecf20Sopenharmony_ci		}
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci	return ecode;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/*
7208c2ecf20Sopenharmony_ci * All events are considered to be slow (RX/TX ints do not generate
7218c2ecf20Sopenharmony_ci * events) and are handled here, outside the main interrupt handler,
7228c2ecf20Sopenharmony_ci * to reduce the size of the handler.
7238c2ecf20Sopenharmony_ci */
7248c2ecf20Sopenharmony_cistatic u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
7278c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
7288c2ecf20Sopenharmony_ci	u32 tmp;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
7318c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	while (prodidx != eidx){
7348c2ecf20Sopenharmony_ci		switch (rrpriv->evt_ring[eidx].code){
7358c2ecf20Sopenharmony_ci		case E_NIC_UP:
7368c2ecf20Sopenharmony_ci			tmp = readl(&regs->FwRev);
7378c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Firmware revision %i.%i.%i "
7388c2ecf20Sopenharmony_ci			       "up and running\n", dev->name,
7398c2ecf20Sopenharmony_ci			       (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff));
7408c2ecf20Sopenharmony_ci			rrpriv->fw_running = 1;
7418c2ecf20Sopenharmony_ci			writel(RX_RING_ENTRIES - 1, &regs->IpRxPi);
7428c2ecf20Sopenharmony_ci			wmb();
7438c2ecf20Sopenharmony_ci			break;
7448c2ecf20Sopenharmony_ci		case E_LINK_ON:
7458c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Optical link ON\n", dev->name);
7468c2ecf20Sopenharmony_ci			break;
7478c2ecf20Sopenharmony_ci		case E_LINK_OFF:
7488c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Optical link OFF\n", dev->name);
7498c2ecf20Sopenharmony_ci			break;
7508c2ecf20Sopenharmony_ci		case E_RX_IDLE:
7518c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: RX data not moving\n",
7528c2ecf20Sopenharmony_ci			       dev->name);
7538c2ecf20Sopenharmony_ci			goto drop;
7548c2ecf20Sopenharmony_ci		case E_WATCHDOG:
7558c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: The watchdog is here to see "
7568c2ecf20Sopenharmony_ci			       "us\n", dev->name);
7578c2ecf20Sopenharmony_ci			break;
7588c2ecf20Sopenharmony_ci		case E_INTERN_ERR:
7598c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: HIPPI Internal NIC error\n",
7608c2ecf20Sopenharmony_ci			       dev->name);
7618c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
7628c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
7638c2ecf20Sopenharmony_ci			wmb();
7648c2ecf20Sopenharmony_ci			break;
7658c2ecf20Sopenharmony_ci		case E_HOST_ERR:
7668c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Host software error\n",
7678c2ecf20Sopenharmony_ci			       dev->name);
7688c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
7698c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
7708c2ecf20Sopenharmony_ci			wmb();
7718c2ecf20Sopenharmony_ci			break;
7728c2ecf20Sopenharmony_ci		/*
7738c2ecf20Sopenharmony_ci		 * TX events.
7748c2ecf20Sopenharmony_ci		 */
7758c2ecf20Sopenharmony_ci		case E_CON_REJ:
7768c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Connection rejected\n",
7778c2ecf20Sopenharmony_ci			       dev->name);
7788c2ecf20Sopenharmony_ci			dev->stats.tx_aborted_errors++;
7798c2ecf20Sopenharmony_ci			break;
7808c2ecf20Sopenharmony_ci		case E_CON_TMOUT:
7818c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Connection timeout\n",
7828c2ecf20Sopenharmony_ci			       dev->name);
7838c2ecf20Sopenharmony_ci			break;
7848c2ecf20Sopenharmony_ci		case E_DISC_ERR:
7858c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: HIPPI disconnect error\n",
7868c2ecf20Sopenharmony_ci			       dev->name);
7878c2ecf20Sopenharmony_ci			dev->stats.tx_aborted_errors++;
7888c2ecf20Sopenharmony_ci			break;
7898c2ecf20Sopenharmony_ci		case E_INT_PRTY:
7908c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
7918c2ecf20Sopenharmony_ci			       dev->name);
7928c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
7938c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
7948c2ecf20Sopenharmony_ci			wmb();
7958c2ecf20Sopenharmony_ci			break;
7968c2ecf20Sopenharmony_ci		case E_TX_IDLE:
7978c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Transmitter idle\n",
7988c2ecf20Sopenharmony_ci			       dev->name);
7998c2ecf20Sopenharmony_ci			break;
8008c2ecf20Sopenharmony_ci		case E_TX_LINK_DROP:
8018c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Link lost during transmit\n",
8028c2ecf20Sopenharmony_ci			       dev->name);
8038c2ecf20Sopenharmony_ci			dev->stats.tx_aborted_errors++;
8048c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8058c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8068c2ecf20Sopenharmony_ci			wmb();
8078c2ecf20Sopenharmony_ci			break;
8088c2ecf20Sopenharmony_ci		case E_TX_INV_RNG:
8098c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid send ring block\n",
8108c2ecf20Sopenharmony_ci			       dev->name);
8118c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8128c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8138c2ecf20Sopenharmony_ci			wmb();
8148c2ecf20Sopenharmony_ci			break;
8158c2ecf20Sopenharmony_ci		case E_TX_INV_BUF:
8168c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid send buffer address\n",
8178c2ecf20Sopenharmony_ci			       dev->name);
8188c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8198c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8208c2ecf20Sopenharmony_ci			wmb();
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci		case E_TX_INV_DSC:
8238c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid descriptor address\n",
8248c2ecf20Sopenharmony_ci			       dev->name);
8258c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8268c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8278c2ecf20Sopenharmony_ci			wmb();
8288c2ecf20Sopenharmony_ci			break;
8298c2ecf20Sopenharmony_ci		/*
8308c2ecf20Sopenharmony_ci		 * RX events.
8318c2ecf20Sopenharmony_ci		 */
8328c2ecf20Sopenharmony_ci		case E_RX_RNG_OUT:
8338c2ecf20Sopenharmony_ci			printk(KERN_INFO "%s: Receive ring full\n", dev->name);
8348c2ecf20Sopenharmony_ci			break;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		case E_RX_PAR_ERR:
8378c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Receive parity error\n",
8388c2ecf20Sopenharmony_ci			       dev->name);
8398c2ecf20Sopenharmony_ci			goto drop;
8408c2ecf20Sopenharmony_ci		case E_RX_LLRC_ERR:
8418c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Receive LLRC error\n",
8428c2ecf20Sopenharmony_ci			       dev->name);
8438c2ecf20Sopenharmony_ci			goto drop;
8448c2ecf20Sopenharmony_ci		case E_PKT_LN_ERR:
8458c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Receive packet length "
8468c2ecf20Sopenharmony_ci			       "error\n", dev->name);
8478c2ecf20Sopenharmony_ci			goto drop;
8488c2ecf20Sopenharmony_ci		case E_DTA_CKSM_ERR:
8498c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Data checksum error\n",
8508c2ecf20Sopenharmony_ci			       dev->name);
8518c2ecf20Sopenharmony_ci			goto drop;
8528c2ecf20Sopenharmony_ci		case E_SHT_BST:
8538c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Unexpected short burst "
8548c2ecf20Sopenharmony_ci			       "error\n", dev->name);
8558c2ecf20Sopenharmony_ci			goto drop;
8568c2ecf20Sopenharmony_ci		case E_STATE_ERR:
8578c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Recv. state transition"
8588c2ecf20Sopenharmony_ci			       " error\n", dev->name);
8598c2ecf20Sopenharmony_ci			goto drop;
8608c2ecf20Sopenharmony_ci		case E_UNEXP_DATA:
8618c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Unexpected data error\n",
8628c2ecf20Sopenharmony_ci			       dev->name);
8638c2ecf20Sopenharmony_ci			goto drop;
8648c2ecf20Sopenharmony_ci		case E_LST_LNK_ERR:
8658c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Link lost error\n",
8668c2ecf20Sopenharmony_ci			       dev->name);
8678c2ecf20Sopenharmony_ci			goto drop;
8688c2ecf20Sopenharmony_ci		case E_FRM_ERR:
8698c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Framing Error\n",
8708c2ecf20Sopenharmony_ci			       dev->name);
8718c2ecf20Sopenharmony_ci			goto drop;
8728c2ecf20Sopenharmony_ci		case E_FLG_SYN_ERR:
8738c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Flag sync. lost during "
8748c2ecf20Sopenharmony_ci			       "packet\n", dev->name);
8758c2ecf20Sopenharmony_ci			goto drop;
8768c2ecf20Sopenharmony_ci		case E_RX_INV_BUF:
8778c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid receive buffer "
8788c2ecf20Sopenharmony_ci			       "address\n", dev->name);
8798c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8808c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8818c2ecf20Sopenharmony_ci			wmb();
8828c2ecf20Sopenharmony_ci			break;
8838c2ecf20Sopenharmony_ci		case E_RX_INV_DSC:
8848c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid receive descriptor "
8858c2ecf20Sopenharmony_ci			       "address\n", dev->name);
8868c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8878c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8888c2ecf20Sopenharmony_ci			wmb();
8898c2ecf20Sopenharmony_ci			break;
8908c2ecf20Sopenharmony_ci		case E_RNG_BLK:
8918c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Invalid ring block\n",
8928c2ecf20Sopenharmony_ci			       dev->name);
8938c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
8948c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
8958c2ecf20Sopenharmony_ci			wmb();
8968c2ecf20Sopenharmony_ci			break;
8978c2ecf20Sopenharmony_ci		drop:
8988c2ecf20Sopenharmony_ci			/* Label packet to be dropped.
8998c2ecf20Sopenharmony_ci			 * Actual dropping occurs in rx
9008c2ecf20Sopenharmony_ci			 * handling.
9018c2ecf20Sopenharmony_ci			 *
9028c2ecf20Sopenharmony_ci			 * The index of packet we get to drop is
9038c2ecf20Sopenharmony_ci			 * the index of the packet following
9048c2ecf20Sopenharmony_ci			 * the bad packet. -kbf
9058c2ecf20Sopenharmony_ci			 */
9068c2ecf20Sopenharmony_ci			{
9078c2ecf20Sopenharmony_ci				u16 index = rrpriv->evt_ring[eidx].index;
9088c2ecf20Sopenharmony_ci				index = (index + (RX_RING_ENTRIES - 1)) %
9098c2ecf20Sopenharmony_ci					RX_RING_ENTRIES;
9108c2ecf20Sopenharmony_ci				rrpriv->rx_ring[index].mode |=
9118c2ecf20Sopenharmony_ci					(PACKET_BAD | PACKET_END);
9128c2ecf20Sopenharmony_ci			}
9138c2ecf20Sopenharmony_ci			break;
9148c2ecf20Sopenharmony_ci		default:
9158c2ecf20Sopenharmony_ci			printk(KERN_WARNING "%s: Unhandled event 0x%02x\n",
9168c2ecf20Sopenharmony_ci			       dev->name, rrpriv->evt_ring[eidx].code);
9178c2ecf20Sopenharmony_ci		}
9188c2ecf20Sopenharmony_ci		eidx = (eidx + 1) % EVT_RING_ENTRIES;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = eidx;
9228c2ecf20Sopenharmony_ci	wmb();
9238c2ecf20Sopenharmony_ci	return eidx;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_cistatic void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
9308c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	do {
9338c2ecf20Sopenharmony_ci		struct rx_desc *desc;
9348c2ecf20Sopenharmony_ci		u32 pkt_len;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci		desc = &(rrpriv->rx_ring[index]);
9378c2ecf20Sopenharmony_ci		pkt_len = desc->size;
9388c2ecf20Sopenharmony_ci#if (DEBUG > 2)
9398c2ecf20Sopenharmony_ci		printk("index %i, rxlimit %i\n", index, rxlimit);
9408c2ecf20Sopenharmony_ci		printk("len %x, mode %x\n", pkt_len, desc->mode);
9418c2ecf20Sopenharmony_ci#endif
9428c2ecf20Sopenharmony_ci		if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){
9438c2ecf20Sopenharmony_ci			dev->stats.rx_dropped++;
9448c2ecf20Sopenharmony_ci			goto defer;
9458c2ecf20Sopenharmony_ci		}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		if (pkt_len > 0){
9488c2ecf20Sopenharmony_ci			struct sk_buff *skb, *rx_skb;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci			rx_skb = rrpriv->rx_skbuff[index];
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci			if (pkt_len < PKT_COPY_THRESHOLD) {
9538c2ecf20Sopenharmony_ci				skb = alloc_skb(pkt_len, GFP_ATOMIC);
9548c2ecf20Sopenharmony_ci				if (skb == NULL){
9558c2ecf20Sopenharmony_ci					printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
9568c2ecf20Sopenharmony_ci					dev->stats.rx_dropped++;
9578c2ecf20Sopenharmony_ci					goto defer;
9588c2ecf20Sopenharmony_ci				} else {
9598c2ecf20Sopenharmony_ci					dma_sync_single_for_cpu(&rrpriv->pci_dev->dev,
9608c2ecf20Sopenharmony_ci								desc->addr.addrlo,
9618c2ecf20Sopenharmony_ci								pkt_len,
9628c2ecf20Sopenharmony_ci								DMA_FROM_DEVICE);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci					skb_put_data(skb, rx_skb->data,
9658c2ecf20Sopenharmony_ci						     pkt_len);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci					dma_sync_single_for_device(&rrpriv->pci_dev->dev,
9688c2ecf20Sopenharmony_ci								   desc->addr.addrlo,
9698c2ecf20Sopenharmony_ci								   pkt_len,
9708c2ecf20Sopenharmony_ci								   DMA_FROM_DEVICE);
9718c2ecf20Sopenharmony_ci				}
9728c2ecf20Sopenharmony_ci			}else{
9738c2ecf20Sopenharmony_ci				struct sk_buff *newskb;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci				newskb = alloc_skb(dev->mtu + HIPPI_HLEN,
9768c2ecf20Sopenharmony_ci					GFP_ATOMIC);
9778c2ecf20Sopenharmony_ci				if (newskb){
9788c2ecf20Sopenharmony_ci					dma_addr_t addr;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci					dma_unmap_single(&rrpriv->pci_dev->dev,
9818c2ecf20Sopenharmony_ci							 desc->addr.addrlo,
9828c2ecf20Sopenharmony_ci							 dev->mtu + HIPPI_HLEN,
9838c2ecf20Sopenharmony_ci							 DMA_FROM_DEVICE);
9848c2ecf20Sopenharmony_ci					skb = rx_skb;
9858c2ecf20Sopenharmony_ci					skb_put(skb, pkt_len);
9868c2ecf20Sopenharmony_ci					rrpriv->rx_skbuff[index] = newskb;
9878c2ecf20Sopenharmony_ci					addr = dma_map_single(&rrpriv->pci_dev->dev,
9888c2ecf20Sopenharmony_ci							      newskb->data,
9898c2ecf20Sopenharmony_ci							      dev->mtu + HIPPI_HLEN,
9908c2ecf20Sopenharmony_ci							      DMA_FROM_DEVICE);
9918c2ecf20Sopenharmony_ci					set_rraddr(&desc->addr, addr);
9928c2ecf20Sopenharmony_ci				} else {
9938c2ecf20Sopenharmony_ci					printk("%s: Out of memory, deferring "
9948c2ecf20Sopenharmony_ci					       "packet\n", dev->name);
9958c2ecf20Sopenharmony_ci					dev->stats.rx_dropped++;
9968c2ecf20Sopenharmony_ci					goto defer;
9978c2ecf20Sopenharmony_ci				}
9988c2ecf20Sopenharmony_ci			}
9998c2ecf20Sopenharmony_ci			skb->protocol = hippi_type_trans(skb, dev);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci			netif_rx(skb);		/* send it up */
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci			dev->stats.rx_packets++;
10048c2ecf20Sopenharmony_ci			dev->stats.rx_bytes += pkt_len;
10058c2ecf20Sopenharmony_ci		}
10068c2ecf20Sopenharmony_ci	defer:
10078c2ecf20Sopenharmony_ci		desc->mode = 0;
10088c2ecf20Sopenharmony_ci		desc->size = dev->mtu + HIPPI_HLEN;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		if ((index & 7) == 7)
10118c2ecf20Sopenharmony_ci			writel(index, &regs->IpRxPi);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci		index = (index + 1) % RX_RING_ENTRIES;
10148c2ecf20Sopenharmony_ci	} while(index != rxlimit);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	rrpriv->cur_rx = index;
10178c2ecf20Sopenharmony_ci	wmb();
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic irqreturn_t rr_interrupt(int irq, void *dev_id)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
10248c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
10258c2ecf20Sopenharmony_ci	struct net_device *dev = (struct net_device *)dev_id;
10268c2ecf20Sopenharmony_ci	u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
10298c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (!(readl(&regs->HostCtrl) & RR_INT))
10328c2ecf20Sopenharmony_ci		return IRQ_NONE;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	spin_lock(&rrpriv->lock);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	prodidx = readl(&regs->EvtPrd);
10378c2ecf20Sopenharmony_ci	txcsmr = (prodidx >> 8) & 0xff;
10388c2ecf20Sopenharmony_ci	rxlimit = (prodidx >> 16) & 0xff;
10398c2ecf20Sopenharmony_ci	prodidx &= 0xff;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci#if (DEBUG > 2)
10428c2ecf20Sopenharmony_ci	printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name,
10438c2ecf20Sopenharmony_ci	       prodidx, rrpriv->info->evt_ctrl.pi);
10448c2ecf20Sopenharmony_ci#endif
10458c2ecf20Sopenharmony_ci	/*
10468c2ecf20Sopenharmony_ci	 * Order here is important.  We must handle events
10478c2ecf20Sopenharmony_ci	 * before doing anything else in order to catch
10488c2ecf20Sopenharmony_ci	 * such things as LLRC errors, etc -kbf
10498c2ecf20Sopenharmony_ci	 */
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	eidx = rrpriv->info->evt_ctrl.pi;
10528c2ecf20Sopenharmony_ci	if (prodidx != eidx)
10538c2ecf20Sopenharmony_ci		eidx = rr_handle_event(dev, prodidx, eidx);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	rxindex = rrpriv->cur_rx;
10568c2ecf20Sopenharmony_ci	if (rxindex != rxlimit)
10578c2ecf20Sopenharmony_ci		rx_int(dev, rxlimit, rxindex);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	txcon = rrpriv->dirty_tx;
10608c2ecf20Sopenharmony_ci	if (txcsmr != txcon) {
10618c2ecf20Sopenharmony_ci		do {
10628c2ecf20Sopenharmony_ci			/* Due to occational firmware TX producer/consumer out
10638c2ecf20Sopenharmony_ci			 * of sync. error need to check entry in ring -kbf
10648c2ecf20Sopenharmony_ci			 */
10658c2ecf20Sopenharmony_ci			if(rrpriv->tx_skbuff[txcon]){
10668c2ecf20Sopenharmony_ci				struct tx_desc *desc;
10678c2ecf20Sopenharmony_ci				struct sk_buff *skb;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci				desc = &(rrpriv->tx_ring[txcon]);
10708c2ecf20Sopenharmony_ci				skb = rrpriv->tx_skbuff[txcon];
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci				dev->stats.tx_packets++;
10738c2ecf20Sopenharmony_ci				dev->stats.tx_bytes += skb->len;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci				dma_unmap_single(&rrpriv->pci_dev->dev,
10768c2ecf20Sopenharmony_ci						 desc->addr.addrlo, skb->len,
10778c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
10788c2ecf20Sopenharmony_ci				dev_kfree_skb_irq(skb);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci				rrpriv->tx_skbuff[txcon] = NULL;
10818c2ecf20Sopenharmony_ci				desc->size = 0;
10828c2ecf20Sopenharmony_ci				set_rraddr(&rrpriv->tx_ring[txcon].addr, 0);
10838c2ecf20Sopenharmony_ci				desc->mode = 0;
10848c2ecf20Sopenharmony_ci			}
10858c2ecf20Sopenharmony_ci			txcon = (txcon + 1) % TX_RING_ENTRIES;
10868c2ecf20Sopenharmony_ci		} while (txcsmr != txcon);
10878c2ecf20Sopenharmony_ci		wmb();
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		rrpriv->dirty_tx = txcon;
10908c2ecf20Sopenharmony_ci		if (rrpriv->tx_full && rr_if_busy(dev) &&
10918c2ecf20Sopenharmony_ci		    (((rrpriv->info->tx_ctrl.pi + 1) % TX_RING_ENTRIES)
10928c2ecf20Sopenharmony_ci		     != rrpriv->dirty_tx)){
10938c2ecf20Sopenharmony_ci			rrpriv->tx_full = 0;
10948c2ecf20Sopenharmony_ci			netif_wake_queue(dev);
10958c2ecf20Sopenharmony_ci		}
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	eidx |= ((txcsmr << 8) | (rxlimit << 16));
10998c2ecf20Sopenharmony_ci	writel(eidx, &regs->EvtCon);
11008c2ecf20Sopenharmony_ci	wmb();
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	spin_unlock(&rrpriv->lock);
11038c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic inline void rr_raz_tx(struct rr_private *rrpriv,
11078c2ecf20Sopenharmony_ci			     struct net_device *dev)
11088c2ecf20Sopenharmony_ci{
11098c2ecf20Sopenharmony_ci	int i;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++) {
11128c2ecf20Sopenharmony_ci		struct sk_buff *skb = rrpriv->tx_skbuff[i];
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		if (skb) {
11158c2ecf20Sopenharmony_ci			struct tx_desc *desc = &(rrpriv->tx_ring[i]);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
11188c2ecf20Sopenharmony_ci					 desc->addr.addrlo, skb->len,
11198c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
11208c2ecf20Sopenharmony_ci			desc->size = 0;
11218c2ecf20Sopenharmony_ci			set_rraddr(&desc->addr, 0);
11228c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
11238c2ecf20Sopenharmony_ci			rrpriv->tx_skbuff[i] = NULL;
11248c2ecf20Sopenharmony_ci		}
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic inline void rr_raz_rx(struct rr_private *rrpriv,
11308c2ecf20Sopenharmony_ci			     struct net_device *dev)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	int i;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
11358c2ecf20Sopenharmony_ci		struct sk_buff *skb = rrpriv->rx_skbuff[i];
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		if (skb) {
11388c2ecf20Sopenharmony_ci			struct rx_desc *desc = &(rrpriv->rx_ring[i]);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
11418c2ecf20Sopenharmony_ci					 desc->addr.addrlo,
11428c2ecf20Sopenharmony_ci					 dev->mtu + HIPPI_HLEN,
11438c2ecf20Sopenharmony_ci					 DMA_FROM_DEVICE);
11448c2ecf20Sopenharmony_ci			desc->size = 0;
11458c2ecf20Sopenharmony_ci			set_rraddr(&desc->addr, 0);
11468c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
11478c2ecf20Sopenharmony_ci			rrpriv->rx_skbuff[i] = NULL;
11488c2ecf20Sopenharmony_ci		}
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic void rr_timer(struct timer_list *t)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	struct rr_private *rrpriv = from_timer(rrpriv, t, timer);
11558c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(rrpriv->pci_dev);
11568c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
11578c2ecf20Sopenharmony_ci	unsigned long flags;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	if (readl(&regs->HostCtrl) & NIC_HALTED){
11608c2ecf20Sopenharmony_ci		printk("%s: Restarting nic\n", dev->name);
11618c2ecf20Sopenharmony_ci		memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
11628c2ecf20Sopenharmony_ci		memset(rrpriv->info, 0, sizeof(struct rr_info));
11638c2ecf20Sopenharmony_ci		wmb();
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		rr_raz_tx(rrpriv, dev);
11668c2ecf20Sopenharmony_ci		rr_raz_rx(rrpriv, dev);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		if (rr_init1(dev)) {
11698c2ecf20Sopenharmony_ci			spin_lock_irqsave(&rrpriv->lock, flags);
11708c2ecf20Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
11718c2ecf20Sopenharmony_ci			       &regs->HostCtrl);
11728c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&rrpriv->lock, flags);
11738c2ecf20Sopenharmony_ci		}
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci	rrpriv->timer.expires = RUN_AT(5*HZ);
11768c2ecf20Sopenharmony_ci	add_timer(&rrpriv->timer);
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_cistatic int rr_open(struct net_device *dev)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
11838c2ecf20Sopenharmony_ci	struct pci_dev *pdev = rrpriv->pci_dev;
11848c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
11858c2ecf20Sopenharmony_ci	int ecode = 0;
11868c2ecf20Sopenharmony_ci	unsigned long flags;
11878c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	if (rrpriv->fw_rev < 0x00020000) {
11928c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: trying to configure device with "
11938c2ecf20Sopenharmony_ci		       "obsolete firmware\n", dev->name);
11948c2ecf20Sopenharmony_ci		ecode = -EBUSY;
11958c2ecf20Sopenharmony_ci		goto error;
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl = dma_alloc_coherent(&pdev->dev,
11998c2ecf20Sopenharmony_ci					     256 * sizeof(struct ring_ctrl),
12008c2ecf20Sopenharmony_ci					     &dma_addr, GFP_KERNEL);
12018c2ecf20Sopenharmony_ci	if (!rrpriv->rx_ctrl) {
12028c2ecf20Sopenharmony_ci		ecode = -ENOMEM;
12038c2ecf20Sopenharmony_ci		goto error;
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl_dma = dma_addr;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	rrpriv->info = dma_alloc_coherent(&pdev->dev, sizeof(struct rr_info),
12088c2ecf20Sopenharmony_ci					  &dma_addr, GFP_KERNEL);
12098c2ecf20Sopenharmony_ci	if (!rrpriv->info) {
12108c2ecf20Sopenharmony_ci		ecode = -ENOMEM;
12118c2ecf20Sopenharmony_ci		goto error;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci	rrpriv->info_dma = dma_addr;
12148c2ecf20Sopenharmony_ci	wmb();
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
12178c2ecf20Sopenharmony_ci	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
12188c2ecf20Sopenharmony_ci	readl(&regs->HostCtrl);
12198c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (request_irq(pdev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) {
12228c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
12238c2ecf20Sopenharmony_ci		       dev->name, pdev->irq);
12248c2ecf20Sopenharmony_ci		ecode = -EAGAIN;
12258c2ecf20Sopenharmony_ci		goto error;
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if ((ecode = rr_init1(dev)))
12298c2ecf20Sopenharmony_ci		goto error;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	/* Set the timer to switch to check for link beat and perhaps switch
12328c2ecf20Sopenharmony_ci	   to an alternate media type. */
12338c2ecf20Sopenharmony_ci	timer_setup(&rrpriv->timer, rr_timer, 0);
12348c2ecf20Sopenharmony_ci	rrpriv->timer.expires = RUN_AT(5*HZ);           /* 5 sec. watchdog */
12358c2ecf20Sopenharmony_ci	add_timer(&rrpriv->timer);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	netif_start_queue(dev);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	return ecode;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci error:
12428c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
12438c2ecf20Sopenharmony_ci	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
12448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	if (rrpriv->info) {
12478c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct rr_info),
12488c2ecf20Sopenharmony_ci				  rrpriv->info, rrpriv->info_dma);
12498c2ecf20Sopenharmony_ci		rrpriv->info = NULL;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci	if (rrpriv->rx_ctrl) {
12528c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, 256 * sizeof(struct ring_ctrl),
12538c2ecf20Sopenharmony_ci				  rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma);
12548c2ecf20Sopenharmony_ci		rrpriv->rx_ctrl = NULL;
12558c2ecf20Sopenharmony_ci	}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	return ecode;
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic void rr_dump(struct net_device *dev)
12648c2ecf20Sopenharmony_ci{
12658c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
12668c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
12678c2ecf20Sopenharmony_ci	u32 index, cons;
12688c2ecf20Sopenharmony_ci	short i;
12698c2ecf20Sopenharmony_ci	int len;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
12728c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	printk("%s: dumping NIC TX rings\n", dev->name);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n",
12778c2ecf20Sopenharmony_ci	       readl(&regs->RxPrd), readl(&regs->TxPrd),
12788c2ecf20Sopenharmony_ci	       readl(&regs->EvtPrd), readl(&regs->TxPi),
12798c2ecf20Sopenharmony_ci	       rrpriv->info->tx_ctrl.pi);
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	printk("Error code 0x%x\n", readl(&regs->Fail1));
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	index = (((readl(&regs->EvtPrd) >> 8) & 0xff) - 1) % TX_RING_ENTRIES;
12848c2ecf20Sopenharmony_ci	cons = rrpriv->dirty_tx;
12858c2ecf20Sopenharmony_ci	printk("TX ring index %i, TX consumer %i\n",
12868c2ecf20Sopenharmony_ci	       index, cons);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (rrpriv->tx_skbuff[index]){
12898c2ecf20Sopenharmony_ci		len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len);
12908c2ecf20Sopenharmony_ci		printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size);
12918c2ecf20Sopenharmony_ci		for (i = 0; i < len; i++){
12928c2ecf20Sopenharmony_ci			if (!(i & 7))
12938c2ecf20Sopenharmony_ci				printk("\n");
12948c2ecf20Sopenharmony_ci			printk("%02x ", (unsigned char) rrpriv->tx_skbuff[index]->data[i]);
12958c2ecf20Sopenharmony_ci		}
12968c2ecf20Sopenharmony_ci		printk("\n");
12978c2ecf20Sopenharmony_ci	}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	if (rrpriv->tx_skbuff[cons]){
13008c2ecf20Sopenharmony_ci		len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len);
13018c2ecf20Sopenharmony_ci		printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len);
13028c2ecf20Sopenharmony_ci		printk("mode 0x%x, size 0x%x,\n phys %08Lx, skbuff-addr %p, truesize 0x%x\n",
13038c2ecf20Sopenharmony_ci		       rrpriv->tx_ring[cons].mode,
13048c2ecf20Sopenharmony_ci		       rrpriv->tx_ring[cons].size,
13058c2ecf20Sopenharmony_ci		       (unsigned long long) rrpriv->tx_ring[cons].addr.addrlo,
13068c2ecf20Sopenharmony_ci		       rrpriv->tx_skbuff[cons]->data,
13078c2ecf20Sopenharmony_ci		       (unsigned int)rrpriv->tx_skbuff[cons]->truesize);
13088c2ecf20Sopenharmony_ci		for (i = 0; i < len; i++){
13098c2ecf20Sopenharmony_ci			if (!(i & 7))
13108c2ecf20Sopenharmony_ci				printk("\n");
13118c2ecf20Sopenharmony_ci			printk("%02x ", (unsigned char)rrpriv->tx_ring[cons].size);
13128c2ecf20Sopenharmony_ci		}
13138c2ecf20Sopenharmony_ci		printk("\n");
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	printk("dumping TX ring info:\n");
13178c2ecf20Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++)
13188c2ecf20Sopenharmony_ci		printk("mode 0x%x, size 0x%x, phys-addr %08Lx\n",
13198c2ecf20Sopenharmony_ci		       rrpriv->tx_ring[i].mode,
13208c2ecf20Sopenharmony_ci		       rrpriv->tx_ring[i].size,
13218c2ecf20Sopenharmony_ci		       (unsigned long long) rrpriv->tx_ring[i].addr.addrlo);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic int rr_close(struct net_device *dev)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
13298c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
13308c2ecf20Sopenharmony_ci	struct pci_dev *pdev = rrpriv->pci_dev;
13318c2ecf20Sopenharmony_ci	unsigned long flags;
13328c2ecf20Sopenharmony_ci	u32 tmp;
13338c2ecf20Sopenharmony_ci	short i;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	/*
13398c2ecf20Sopenharmony_ci	 * Lock to make sure we are not cleaning up while another CPU
13408c2ecf20Sopenharmony_ci	 * is handling interrupts.
13418c2ecf20Sopenharmony_ci	 */
13428c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	tmp = readl(&regs->HostCtrl);
13458c2ecf20Sopenharmony_ci	if (tmp & NIC_HALTED){
13468c2ecf20Sopenharmony_ci		printk("%s: NIC already halted\n", dev->name);
13478c2ecf20Sopenharmony_ci		rr_dump(dev);
13488c2ecf20Sopenharmony_ci	}else{
13498c2ecf20Sopenharmony_ci		tmp |= HALT_NIC | RR_CLEAR_INT;
13508c2ecf20Sopenharmony_ci		writel(tmp, &regs->HostCtrl);
13518c2ecf20Sopenharmony_ci		readl(&regs->HostCtrl);
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	rrpriv->fw_running = 0;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
13578c2ecf20Sopenharmony_ci	del_timer_sync(&rrpriv->timer);
13588c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	writel(0, &regs->TxPi);
13618c2ecf20Sopenharmony_ci	writel(0, &regs->IpRxPi);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	writel(0, &regs->EvtCon);
13648c2ecf20Sopenharmony_ci	writel(0, &regs->EvtPrd);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++)
13678c2ecf20Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	rrpriv->info->tx_ctrl.entries = 0;
13708c2ecf20Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = 0;
13718c2ecf20Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
13728c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl[4].entries = 0;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	rr_raz_tx(rrpriv, dev);
13758c2ecf20Sopenharmony_ci	rr_raz_rx(rrpriv, dev);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, 256 * sizeof(struct ring_ctrl),
13788c2ecf20Sopenharmony_ci			  rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma);
13798c2ecf20Sopenharmony_ci	rrpriv->rx_ctrl = NULL;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, sizeof(struct rr_info), rrpriv->info,
13828c2ecf20Sopenharmony_ci			  rrpriv->info_dma);
13838c2ecf20Sopenharmony_ci	rrpriv->info = NULL;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
13868c2ecf20Sopenharmony_ci	free_irq(pdev->irq, dev);
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	return 0;
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_cistatic netdev_tx_t rr_start_xmit(struct sk_buff *skb,
13938c2ecf20Sopenharmony_ci				 struct net_device *dev)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
13968c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
13978c2ecf20Sopenharmony_ci	struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
13988c2ecf20Sopenharmony_ci	struct ring_ctrl *txctrl;
13998c2ecf20Sopenharmony_ci	unsigned long flags;
14008c2ecf20Sopenharmony_ci	u32 index, len = skb->len;
14018c2ecf20Sopenharmony_ci	u32 *ifield;
14028c2ecf20Sopenharmony_ci	struct sk_buff *new_skb;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	if (readl(&regs->Mode) & FATAL_ERR)
14058c2ecf20Sopenharmony_ci		printk("error codes Fail1 %02x, Fail2 %02x\n",
14068c2ecf20Sopenharmony_ci		       readl(&regs->Fail1), readl(&regs->Fail2));
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/*
14098c2ecf20Sopenharmony_ci	 * We probably need to deal with tbusy here to prevent overruns.
14108c2ecf20Sopenharmony_ci	 */
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (skb_headroom(skb) < 8){
14138c2ecf20Sopenharmony_ci		printk("incoming skb too small - reallocating\n");
14148c2ecf20Sopenharmony_ci		if (!(new_skb = dev_alloc_skb(len + 8))) {
14158c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
14168c2ecf20Sopenharmony_ci			netif_wake_queue(dev);
14178c2ecf20Sopenharmony_ci			return NETDEV_TX_OK;
14188c2ecf20Sopenharmony_ci		}
14198c2ecf20Sopenharmony_ci		skb_reserve(new_skb, 8);
14208c2ecf20Sopenharmony_ci		skb_put(new_skb, len);
14218c2ecf20Sopenharmony_ci		skb_copy_from_linear_data(skb, new_skb->data, len);
14228c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
14238c2ecf20Sopenharmony_ci		skb = new_skb;
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	ifield = skb_push(skb, 8);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	ifield[0] = 0;
14298c2ecf20Sopenharmony_ci	ifield[1] = hcb->ifield;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	/*
14328c2ecf20Sopenharmony_ci	 * We don't need the lock before we are actually going to start
14338c2ecf20Sopenharmony_ci	 * fiddling with the control blocks.
14348c2ecf20Sopenharmony_ci	 */
14358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	txctrl = &rrpriv->info->tx_ctrl;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	index = txctrl->pi;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	rrpriv->tx_skbuff[index] = skb;
14428c2ecf20Sopenharmony_ci	set_rraddr(&rrpriv->tx_ring[index].addr,
14438c2ecf20Sopenharmony_ci		   dma_map_single(&rrpriv->pci_dev->dev, skb->data, len + 8, DMA_TO_DEVICE));
14448c2ecf20Sopenharmony_ci	rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */
14458c2ecf20Sopenharmony_ci	rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END;
14468c2ecf20Sopenharmony_ci	txctrl->pi = (index + 1) % TX_RING_ENTRIES;
14478c2ecf20Sopenharmony_ci	wmb();
14488c2ecf20Sopenharmony_ci	writel(txctrl->pi, &regs->TxPi);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	if (txctrl->pi == rrpriv->dirty_tx){
14518c2ecf20Sopenharmony_ci		rrpriv->tx_full = 1;
14528c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
14538c2ecf20Sopenharmony_ci	}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci/*
14628c2ecf20Sopenharmony_ci * Read the firmware out of the EEPROM and put it into the SRAM
14638c2ecf20Sopenharmony_ci * (or from user space - later)
14648c2ecf20Sopenharmony_ci *
14658c2ecf20Sopenharmony_ci * This operation requires the NIC to be halted and is performed with
14668c2ecf20Sopenharmony_ci * interrupts disabled and with the spinlock hold.
14678c2ecf20Sopenharmony_ci */
14688c2ecf20Sopenharmony_cistatic int rr_load_firmware(struct net_device *dev)
14698c2ecf20Sopenharmony_ci{
14708c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
14718c2ecf20Sopenharmony_ci	struct rr_regs __iomem *regs;
14728c2ecf20Sopenharmony_ci	size_t eptr, segptr;
14738c2ecf20Sopenharmony_ci	int i, j;
14748c2ecf20Sopenharmony_ci	u32 localctrl, sptr, len, tmp;
14758c2ecf20Sopenharmony_ci	u32 p2len, p2size, nr_seg, revision, io, sram_size;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
14788c2ecf20Sopenharmony_ci	regs = rrpriv->regs;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	if (dev->flags & IFF_UP)
14818c2ecf20Sopenharmony_ci		return -EBUSY;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	if (!(readl(&regs->HostCtrl) & NIC_HALTED)){
14848c2ecf20Sopenharmony_ci		printk("%s: Trying to load firmware to a running NIC.\n",
14858c2ecf20Sopenharmony_ci		       dev->name);
14868c2ecf20Sopenharmony_ci		return -EBUSY;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	localctrl = readl(&regs->LocalCtrl);
14908c2ecf20Sopenharmony_ci	writel(0, &regs->LocalCtrl);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	writel(0, &regs->EvtPrd);
14938c2ecf20Sopenharmony_ci	writel(0, &regs->RxPrd);
14948c2ecf20Sopenharmony_ci	writel(0, &regs->TxPrd);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/*
14978c2ecf20Sopenharmony_ci	 * First wipe the entire SRAM, otherwise we might run into all
14988c2ecf20Sopenharmony_ci	 * kinds of trouble ... sigh, this took almost all afternoon
14998c2ecf20Sopenharmony_ci	 * to track down ;-(
15008c2ecf20Sopenharmony_ci	 */
15018c2ecf20Sopenharmony_ci	io = readl(&regs->ExtIo);
15028c2ecf20Sopenharmony_ci	writel(0, &regs->ExtIo);
15038c2ecf20Sopenharmony_ci	sram_size = rr_read_eeprom_word(rrpriv, 8);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	for (i = 200; i < sram_size / 4; i++){
15068c2ecf20Sopenharmony_ci		writel(i * 4, &regs->WinBase);
15078c2ecf20Sopenharmony_ci		mb();
15088c2ecf20Sopenharmony_ci		writel(0, &regs->WinData);
15098c2ecf20Sopenharmony_ci		mb();
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci	writel(io, &regs->ExtIo);
15128c2ecf20Sopenharmony_ci	mb();
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	eptr = rr_read_eeprom_word(rrpriv,
15158c2ecf20Sopenharmony_ci		       offsetof(struct eeprom, rncd_info.AddrRunCodeSegs));
15168c2ecf20Sopenharmony_ci	eptr = ((eptr & 0x1fffff) >> 3);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	p2len = rr_read_eeprom_word(rrpriv, 0x83*4);
15198c2ecf20Sopenharmony_ci	p2len = (p2len << 2);
15208c2ecf20Sopenharmony_ci	p2size = rr_read_eeprom_word(rrpriv, 0x84*4);
15218c2ecf20Sopenharmony_ci	p2size = ((p2size & 0x1fffff) >> 3);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	if ((eptr < p2size) || (eptr > (p2size + p2len))){
15248c2ecf20Sopenharmony_ci		printk("%s: eptr is invalid\n", dev->name);
15258c2ecf20Sopenharmony_ci		goto out;
15268c2ecf20Sopenharmony_ci	}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	revision = rr_read_eeprom_word(rrpriv,
15298c2ecf20Sopenharmony_ci			offsetof(struct eeprom, manf.HeaderFmt));
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if (revision != 1){
15328c2ecf20Sopenharmony_ci		printk("%s: invalid firmware format (%i)\n",
15338c2ecf20Sopenharmony_ci		       dev->name, revision);
15348c2ecf20Sopenharmony_ci		goto out;
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	nr_seg = rr_read_eeprom_word(rrpriv, eptr);
15388c2ecf20Sopenharmony_ci	eptr +=4;
15398c2ecf20Sopenharmony_ci#if (DEBUG > 1)
15408c2ecf20Sopenharmony_ci	printk("%s: nr_seg %i\n", dev->name, nr_seg);
15418c2ecf20Sopenharmony_ci#endif
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	for (i = 0; i < nr_seg; i++){
15448c2ecf20Sopenharmony_ci		sptr = rr_read_eeprom_word(rrpriv, eptr);
15458c2ecf20Sopenharmony_ci		eptr += 4;
15468c2ecf20Sopenharmony_ci		len = rr_read_eeprom_word(rrpriv, eptr);
15478c2ecf20Sopenharmony_ci		eptr += 4;
15488c2ecf20Sopenharmony_ci		segptr = rr_read_eeprom_word(rrpriv, eptr);
15498c2ecf20Sopenharmony_ci		segptr = ((segptr & 0x1fffff) >> 3);
15508c2ecf20Sopenharmony_ci		eptr += 4;
15518c2ecf20Sopenharmony_ci#if (DEBUG > 1)
15528c2ecf20Sopenharmony_ci		printk("%s: segment %i, sram address %06x, length %04x, segptr %06x\n",
15538c2ecf20Sopenharmony_ci		       dev->name, i, sptr, len, segptr);
15548c2ecf20Sopenharmony_ci#endif
15558c2ecf20Sopenharmony_ci		for (j = 0; j < len; j++){
15568c2ecf20Sopenharmony_ci			tmp = rr_read_eeprom_word(rrpriv, segptr);
15578c2ecf20Sopenharmony_ci			writel(sptr, &regs->WinBase);
15588c2ecf20Sopenharmony_ci			mb();
15598c2ecf20Sopenharmony_ci			writel(tmp, &regs->WinData);
15608c2ecf20Sopenharmony_ci			mb();
15618c2ecf20Sopenharmony_ci			segptr += 4;
15628c2ecf20Sopenharmony_ci			sptr += 4;
15638c2ecf20Sopenharmony_ci		}
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ciout:
15678c2ecf20Sopenharmony_ci	writel(localctrl, &regs->LocalCtrl);
15688c2ecf20Sopenharmony_ci	mb();
15698c2ecf20Sopenharmony_ci	return 0;
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_cistatic int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct rr_private *rrpriv;
15768c2ecf20Sopenharmony_ci	unsigned char *image, *oldimage;
15778c2ecf20Sopenharmony_ci	unsigned long flags;
15788c2ecf20Sopenharmony_ci	unsigned int i;
15798c2ecf20Sopenharmony_ci	int error = -EOPNOTSUPP;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	rrpriv = netdev_priv(dev);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	switch(cmd){
15848c2ecf20Sopenharmony_ci	case SIOCRRGFW:
15858c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_RAWIO)){
15868c2ecf20Sopenharmony_ci			return -EPERM;
15878c2ecf20Sopenharmony_ci		}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci		image = kmalloc_array(EEPROM_WORDS, sizeof(u32), GFP_KERNEL);
15908c2ecf20Sopenharmony_ci		if (!image)
15918c2ecf20Sopenharmony_ci			return -ENOMEM;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		if (rrpriv->fw_running){
15948c2ecf20Sopenharmony_ci			printk("%s: Firmware already running\n", dev->name);
15958c2ecf20Sopenharmony_ci			error = -EPERM;
15968c2ecf20Sopenharmony_ci			goto gf_out;
15978c2ecf20Sopenharmony_ci		}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci		spin_lock_irqsave(&rrpriv->lock, flags);
16008c2ecf20Sopenharmony_ci		i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
16018c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
16028c2ecf20Sopenharmony_ci		if (i != EEPROM_BYTES){
16038c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Error reading EEPROM\n",
16048c2ecf20Sopenharmony_ci			       dev->name);
16058c2ecf20Sopenharmony_ci			error = -EFAULT;
16068c2ecf20Sopenharmony_ci			goto gf_out;
16078c2ecf20Sopenharmony_ci		}
16088c2ecf20Sopenharmony_ci		error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES);
16098c2ecf20Sopenharmony_ci		if (error)
16108c2ecf20Sopenharmony_ci			error = -EFAULT;
16118c2ecf20Sopenharmony_ci	gf_out:
16128c2ecf20Sopenharmony_ci		kfree(image);
16138c2ecf20Sopenharmony_ci		return error;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	case SIOCRRPFW:
16168c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_RAWIO)){
16178c2ecf20Sopenharmony_ci			return -EPERM;
16188c2ecf20Sopenharmony_ci		}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		image = memdup_user(rq->ifr_data, EEPROM_BYTES);
16218c2ecf20Sopenharmony_ci		if (IS_ERR(image))
16228c2ecf20Sopenharmony_ci			return PTR_ERR(image);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci		oldimage = kmalloc(EEPROM_BYTES, GFP_KERNEL);
16258c2ecf20Sopenharmony_ci		if (!oldimage) {
16268c2ecf20Sopenharmony_ci			kfree(image);
16278c2ecf20Sopenharmony_ci			return -ENOMEM;
16288c2ecf20Sopenharmony_ci		}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci		if (rrpriv->fw_running){
16318c2ecf20Sopenharmony_ci			printk("%s: Firmware already running\n", dev->name);
16328c2ecf20Sopenharmony_ci			error = -EPERM;
16338c2ecf20Sopenharmony_ci			goto wf_out;
16348c2ecf20Sopenharmony_ci		}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci		printk("%s: Updating EEPROM firmware\n", dev->name);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		spin_lock_irqsave(&rrpriv->lock, flags);
16398c2ecf20Sopenharmony_ci		error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES);
16408c2ecf20Sopenharmony_ci		if (error)
16418c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Error writing EEPROM\n",
16428c2ecf20Sopenharmony_ci			       dev->name);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci		i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
16458c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		if (i != EEPROM_BYTES)
16488c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Error reading back EEPROM "
16498c2ecf20Sopenharmony_ci			       "image\n", dev->name);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci		error = memcmp(image, oldimage, EEPROM_BYTES);
16528c2ecf20Sopenharmony_ci		if (error){
16538c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Error verifying EEPROM image\n",
16548c2ecf20Sopenharmony_ci			       dev->name);
16558c2ecf20Sopenharmony_ci			error = -EFAULT;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci	wf_out:
16588c2ecf20Sopenharmony_ci		kfree(oldimage);
16598c2ecf20Sopenharmony_ci		kfree(image);
16608c2ecf20Sopenharmony_ci		return error;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	case SIOCRRID:
16638c2ecf20Sopenharmony_ci		return put_user(0x52523032, (int __user *)rq->ifr_data);
16648c2ecf20Sopenharmony_ci	default:
16658c2ecf20Sopenharmony_ci		return error;
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_cistatic const struct pci_device_id rr_pci_tbl[] = {
16708c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
16718c2ecf20Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, },
16728c2ecf20Sopenharmony_ci	{ 0,}
16738c2ecf20Sopenharmony_ci};
16748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rr_pci_tbl);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic struct pci_driver rr_driver = {
16778c2ecf20Sopenharmony_ci	.name		= "rrunner",
16788c2ecf20Sopenharmony_ci	.id_table	= rr_pci_tbl,
16798c2ecf20Sopenharmony_ci	.probe		= rr_init_one,
16808c2ecf20Sopenharmony_ci	.remove		= rr_remove_one,
16818c2ecf20Sopenharmony_ci};
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cimodule_pci_driver(rr_driver);
1684