162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1998-2002 by Jes Sorensen, <jes@wildopensource.com>.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Thanks to Essential Communication for providing us with hardware
862306a36Sopenharmony_ci * and very comprehensive documentation without which I would not have
962306a36Sopenharmony_ci * been able to write this driver. A special thank you to John Gibbon
1062306a36Sopenharmony_ci * for sorting out the legal issues, with the NDA, allowing the code to
1162306a36Sopenharmony_ci * be released under the GPL.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the
1462306a36Sopenharmony_ci * stupid bugs in my code.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Softnet support and various other patches from Val Henson of
1762306a36Sopenharmony_ci * ODS/Essential.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * PCI DMA mapping code partly based on work by Francois Romieu.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define DEBUG 1
2462306a36Sopenharmony_ci#define RX_DMA_SKBUFF 1
2562306a36Sopenharmony_ci#define PKT_COPY_THRESHOLD 512
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/types.h>
2962306a36Sopenharmony_ci#include <linux/errno.h>
3062306a36Sopenharmony_ci#include <linux/ioport.h>
3162306a36Sopenharmony_ci#include <linux/pci.h>
3262306a36Sopenharmony_ci#include <linux/kernel.h>
3362306a36Sopenharmony_ci#include <linux/netdevice.h>
3462306a36Sopenharmony_ci#include <linux/hippidevice.h>
3562306a36Sopenharmony_ci#include <linux/skbuff.h>
3662306a36Sopenharmony_ci#include <linux/delay.h>
3762306a36Sopenharmony_ci#include <linux/mm.h>
3862306a36Sopenharmony_ci#include <linux/slab.h>
3962306a36Sopenharmony_ci#include <net/sock.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include <asm/cache.h>
4262306a36Sopenharmony_ci#include <asm/byteorder.h>
4362306a36Sopenharmony_ci#include <asm/io.h>
4462306a36Sopenharmony_ci#include <asm/irq.h>
4562306a36Sopenharmony_ci#include <linux/uaccess.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define rr_if_busy(dev)     netif_queue_stopped(dev)
4862306a36Sopenharmony_ci#define rr_if_running(dev)  netif_running(dev)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include "rrunner.h"
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define RUN_AT(x) (jiffies + (x))
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciMODULE_AUTHOR("Jes Sorensen <jes@wildopensource.com>");
5662306a36Sopenharmony_ciMODULE_DESCRIPTION("Essential RoadRunner HIPPI driver");
5762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const char version[] =
6062306a36Sopenharmony_ci"rrunner.c: v0.50 11/11/2002  Jes Sorensen (jes@wildopensource.com)\n";
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const struct net_device_ops rr_netdev_ops = {
6462306a36Sopenharmony_ci	.ndo_open 		= rr_open,
6562306a36Sopenharmony_ci	.ndo_stop		= rr_close,
6662306a36Sopenharmony_ci	.ndo_siocdevprivate	= rr_siocdevprivate,
6762306a36Sopenharmony_ci	.ndo_start_xmit		= rr_start_xmit,
6862306a36Sopenharmony_ci	.ndo_set_mac_address	= hippi_mac_addr,
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * Implementation notes:
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * The DMA engine only allows for DMA within physical 64KB chunks of
7562306a36Sopenharmony_ci * memory. The current approach of the driver (and stack) is to use
7662306a36Sopenharmony_ci * linear blocks of memory for the skbuffs. However, as the data block
7762306a36Sopenharmony_ci * is always the first part of the skb and skbs are 2^n aligned so we
7862306a36Sopenharmony_ci * are guarantted to get the whole block within one 64KB align 64KB
7962306a36Sopenharmony_ci * chunk.
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * On the long term, relying on being able to allocate 64KB linear
8262306a36Sopenharmony_ci * chunks of memory is not feasible and the skb handling code and the
8362306a36Sopenharmony_ci * stack will need to know about I/O vectors or something similar.
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int rr_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct net_device *dev;
8962306a36Sopenharmony_ci	static int version_disp;
9062306a36Sopenharmony_ci	u8 pci_latency;
9162306a36Sopenharmony_ci	struct rr_private *rrpriv;
9262306a36Sopenharmony_ci	void *tmpptr;
9362306a36Sopenharmony_ci	dma_addr_t ring_dma;
9462306a36Sopenharmony_ci	int ret = -ENOMEM;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	dev = alloc_hippi_dev(sizeof(struct rr_private));
9762306a36Sopenharmony_ci	if (!dev)
9862306a36Sopenharmony_ci		goto out3;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
10162306a36Sopenharmony_ci	if (ret) {
10262306a36Sopenharmony_ci		ret = -ENODEV;
10362306a36Sopenharmony_ci		goto out2;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ret = pci_request_regions(pdev, "rrunner");
11162306a36Sopenharmony_ci	if (ret < 0)
11262306a36Sopenharmony_ci		goto out;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	rrpriv->pci_dev = pdev;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	spin_lock_init(&rrpriv->lock);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	dev->netdev_ops = &rr_netdev_ops;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* display version info if adapter is found */
12362306a36Sopenharmony_ci	if (!version_disp) {
12462306a36Sopenharmony_ci		/* set display flag to TRUE so that */
12562306a36Sopenharmony_ci		/* we only display this string ONCE */
12662306a36Sopenharmony_ci		version_disp = 1;
12762306a36Sopenharmony_ci		printk(version);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
13162306a36Sopenharmony_ci	if (pci_latency <= 0x58){
13262306a36Sopenharmony_ci		pci_latency = 0x58;
13362306a36Sopenharmony_ci		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency);
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	pci_set_master(pdev);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
13962306a36Sopenharmony_ci	       "at 0x%llx, irq %i, PCI latency %i\n", dev->name,
14062306a36Sopenharmony_ci	       (unsigned long long)pci_resource_start(pdev, 0),
14162306a36Sopenharmony_ci	       pdev->irq, pci_latency);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * Remap the MMIO regs into kernel space.
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	rrpriv->regs = pci_iomap(pdev, 0, 0x1000);
14762306a36Sopenharmony_ci	if (!rrpriv->regs) {
14862306a36Sopenharmony_ci		printk(KERN_ERR "%s:  Unable to map I/O register, "
14962306a36Sopenharmony_ci			"RoadRunner will be disabled.\n", dev->name);
15062306a36Sopenharmony_ci		ret = -EIO;
15162306a36Sopenharmony_ci		goto out;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma,
15562306a36Sopenharmony_ci				    GFP_KERNEL);
15662306a36Sopenharmony_ci	rrpriv->tx_ring = tmpptr;
15762306a36Sopenharmony_ci	rrpriv->tx_ring_dma = ring_dma;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (!tmpptr) {
16062306a36Sopenharmony_ci		ret = -ENOMEM;
16162306a36Sopenharmony_ci		goto out;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma,
16562306a36Sopenharmony_ci				    GFP_KERNEL);
16662306a36Sopenharmony_ci	rrpriv->rx_ring = tmpptr;
16762306a36Sopenharmony_ci	rrpriv->rx_ring_dma = ring_dma;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (!tmpptr) {
17062306a36Sopenharmony_ci		ret = -ENOMEM;
17162306a36Sopenharmony_ci		goto out;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	tmpptr = dma_alloc_coherent(&pdev->dev, EVT_RING_SIZE, &ring_dma,
17562306a36Sopenharmony_ci				    GFP_KERNEL);
17662306a36Sopenharmony_ci	rrpriv->evt_ring = tmpptr;
17762306a36Sopenharmony_ci	rrpriv->evt_ring_dma = ring_dma;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (!tmpptr) {
18062306a36Sopenharmony_ci		ret = -ENOMEM;
18162306a36Sopenharmony_ci		goto out;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * Don't access any register before this point!
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
18862306a36Sopenharmony_ci	writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP,
18962306a36Sopenharmony_ci		&rrpriv->regs->HostCtrl);
19062306a36Sopenharmony_ci#endif
19162306a36Sopenharmony_ci	/*
19262306a36Sopenharmony_ci	 * Need to add a case for little-endian 64-bit hosts here.
19362306a36Sopenharmony_ci	 */
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	rr_init(dev);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ret = register_netdev(dev);
19862306a36Sopenharmony_ci	if (ret)
19962306a36Sopenharmony_ci		goto out;
20062306a36Sopenharmony_ci	return 0;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci out:
20362306a36Sopenharmony_ci	if (rrpriv->evt_ring)
20462306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, EVT_RING_SIZE, rrpriv->evt_ring,
20562306a36Sopenharmony_ci				  rrpriv->evt_ring_dma);
20662306a36Sopenharmony_ci	if (rrpriv->rx_ring)
20762306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, rrpriv->rx_ring,
20862306a36Sopenharmony_ci				  rrpriv->rx_ring_dma);
20962306a36Sopenharmony_ci	if (rrpriv->tx_ring)
21062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, rrpriv->tx_ring,
21162306a36Sopenharmony_ci				  rrpriv->tx_ring_dma);
21262306a36Sopenharmony_ci	if (rrpriv->regs)
21362306a36Sopenharmony_ci		pci_iounmap(pdev, rrpriv->regs);
21462306a36Sopenharmony_ci	if (pdev)
21562306a36Sopenharmony_ci		pci_release_regions(pdev);
21662306a36Sopenharmony_ci	pci_disable_device(pdev);
21762306a36Sopenharmony_ci out2:
21862306a36Sopenharmony_ci	free_netdev(dev);
21962306a36Sopenharmony_ci out3:
22062306a36Sopenharmony_ci	return ret;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic void rr_remove_one(struct pci_dev *pdev)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
22662306a36Sopenharmony_ci	struct rr_private *rr = netdev_priv(dev);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)) {
22962306a36Sopenharmony_ci		printk(KERN_ERR "%s: trying to unload running NIC\n",
23062306a36Sopenharmony_ci		       dev->name);
23162306a36Sopenharmony_ci		writel(HALT_NIC, &rr->regs->HostCtrl);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	unregister_netdev(dev);
23562306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, EVT_RING_SIZE, rr->evt_ring,
23662306a36Sopenharmony_ci			  rr->evt_ring_dma);
23762306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, rr->rx_ring,
23862306a36Sopenharmony_ci			  rr->rx_ring_dma);
23962306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, rr->tx_ring,
24062306a36Sopenharmony_ci			  rr->tx_ring_dma);
24162306a36Sopenharmony_ci	pci_iounmap(pdev, rr->regs);
24262306a36Sopenharmony_ci	pci_release_regions(pdev);
24362306a36Sopenharmony_ci	pci_disable_device(pdev);
24462306a36Sopenharmony_ci	free_netdev(dev);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/*
24962306a36Sopenharmony_ci * Commands are considered to be slow, thus there is no reason to
25062306a36Sopenharmony_ci * inline this.
25162306a36Sopenharmony_ci */
25262306a36Sopenharmony_cistatic void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
25562306a36Sopenharmony_ci	u32 idx;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	regs = rrpriv->regs;
25862306a36Sopenharmony_ci	/*
25962306a36Sopenharmony_ci	 * This is temporary - it will go away in the final version.
26062306a36Sopenharmony_ci	 * We probably also want to make this function inline.
26162306a36Sopenharmony_ci	 */
26262306a36Sopenharmony_ci	if (readl(&regs->HostCtrl) & NIC_HALTED){
26362306a36Sopenharmony_ci		printk("issuing command for halted NIC, code 0x%x, "
26462306a36Sopenharmony_ci		       "HostCtrl %08x\n", cmd->code, readl(&regs->HostCtrl));
26562306a36Sopenharmony_ci		if (readl(&regs->Mode) & FATAL_ERR)
26662306a36Sopenharmony_ci			printk("error codes Fail1 %02x, Fail2 %02x\n",
26762306a36Sopenharmony_ci			       readl(&regs->Fail1), readl(&regs->Fail2));
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	idx = rrpriv->info->cmd_ctrl.pi;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	writel(*(u32*)(cmd), &regs->CmdRing[idx]);
27362306a36Sopenharmony_ci	wmb();
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	idx = (idx - 1) % CMD_RING_ENTRIES;
27662306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = idx;
27762306a36Sopenharmony_ci	wmb();
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (readl(&regs->Mode) & FATAL_ERR)
28062306a36Sopenharmony_ci		printk("error code %02x\n", readl(&regs->Fail1));
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/*
28562306a36Sopenharmony_ci * Reset the board in a sensible manner. The NIC is already halted
28662306a36Sopenharmony_ci * when we get here and a spin-lock is held.
28762306a36Sopenharmony_ci */
28862306a36Sopenharmony_cistatic int rr_reset(struct net_device *dev)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct rr_private *rrpriv;
29162306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
29262306a36Sopenharmony_ci	u32 start_pc;
29362306a36Sopenharmony_ci	int i;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
29662306a36Sopenharmony_ci	regs = rrpriv->regs;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	rr_load_firmware(dev);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	writel(0x01000000, &regs->TX_state);
30162306a36Sopenharmony_ci	writel(0xff800000, &regs->RX_state);
30262306a36Sopenharmony_ci	writel(0, &regs->AssistState);
30362306a36Sopenharmony_ci	writel(CLEAR_INTA, &regs->LocalCtrl);
30462306a36Sopenharmony_ci	writel(0x01, &regs->BrkPt);
30562306a36Sopenharmony_ci	writel(0, &regs->Timer);
30662306a36Sopenharmony_ci	writel(0, &regs->TimerRef);
30762306a36Sopenharmony_ci	writel(RESET_DMA, &regs->DmaReadState);
30862306a36Sopenharmony_ci	writel(RESET_DMA, &regs->DmaWriteState);
30962306a36Sopenharmony_ci	writel(0, &regs->DmaWriteHostHi);
31062306a36Sopenharmony_ci	writel(0, &regs->DmaWriteHostLo);
31162306a36Sopenharmony_ci	writel(0, &regs->DmaReadHostHi);
31262306a36Sopenharmony_ci	writel(0, &regs->DmaReadHostLo);
31362306a36Sopenharmony_ci	writel(0, &regs->DmaReadLen);
31462306a36Sopenharmony_ci	writel(0, &regs->DmaWriteLen);
31562306a36Sopenharmony_ci	writel(0, &regs->DmaWriteLcl);
31662306a36Sopenharmony_ci	writel(0, &regs->DmaWriteIPchecksum);
31762306a36Sopenharmony_ci	writel(0, &regs->DmaReadLcl);
31862306a36Sopenharmony_ci	writel(0, &regs->DmaReadIPchecksum);
31962306a36Sopenharmony_ci	writel(0, &regs->PciState);
32062306a36Sopenharmony_ci#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN
32162306a36Sopenharmony_ci	writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, &regs->Mode);
32262306a36Sopenharmony_ci#elif (BITS_PER_LONG == 64)
32362306a36Sopenharmony_ci	writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, &regs->Mode);
32462306a36Sopenharmony_ci#else
32562306a36Sopenharmony_ci	writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, &regs->Mode);
32662306a36Sopenharmony_ci#endif
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci#if 0
32962306a36Sopenharmony_ci	/*
33062306a36Sopenharmony_ci	 * Don't worry, this is just black magic.
33162306a36Sopenharmony_ci	 */
33262306a36Sopenharmony_ci	writel(0xdf000, &regs->RxBase);
33362306a36Sopenharmony_ci	writel(0xdf000, &regs->RxPrd);
33462306a36Sopenharmony_ci	writel(0xdf000, &regs->RxCon);
33562306a36Sopenharmony_ci	writel(0xce000, &regs->TxBase);
33662306a36Sopenharmony_ci	writel(0xce000, &regs->TxPrd);
33762306a36Sopenharmony_ci	writel(0xce000, &regs->TxCon);
33862306a36Sopenharmony_ci	writel(0, &regs->RxIndPro);
33962306a36Sopenharmony_ci	writel(0, &regs->RxIndCon);
34062306a36Sopenharmony_ci	writel(0, &regs->RxIndRef);
34162306a36Sopenharmony_ci	writel(0, &regs->TxIndPro);
34262306a36Sopenharmony_ci	writel(0, &regs->TxIndCon);
34362306a36Sopenharmony_ci	writel(0, &regs->TxIndRef);
34462306a36Sopenharmony_ci	writel(0xcc000, &regs->pad10[0]);
34562306a36Sopenharmony_ci	writel(0, &regs->DrCmndPro);
34662306a36Sopenharmony_ci	writel(0, &regs->DrCmndCon);
34762306a36Sopenharmony_ci	writel(0, &regs->DwCmndPro);
34862306a36Sopenharmony_ci	writel(0, &regs->DwCmndCon);
34962306a36Sopenharmony_ci	writel(0, &regs->DwCmndRef);
35062306a36Sopenharmony_ci	writel(0, &regs->DrDataPro);
35162306a36Sopenharmony_ci	writel(0, &regs->DrDataCon);
35262306a36Sopenharmony_ci	writel(0, &regs->DrDataRef);
35362306a36Sopenharmony_ci	writel(0, &regs->DwDataPro);
35462306a36Sopenharmony_ci	writel(0, &regs->DwDataCon);
35562306a36Sopenharmony_ci	writel(0, &regs->DwDataRef);
35662306a36Sopenharmony_ci#endif
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	writel(0xffffffff, &regs->MbEvent);
35962306a36Sopenharmony_ci	writel(0, &regs->Event);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	writel(0, &regs->TxPi);
36262306a36Sopenharmony_ci	writel(0, &regs->IpRxPi);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	writel(0, &regs->EvtCon);
36562306a36Sopenharmony_ci	writel(0, &regs->EvtPrd);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++)
37062306a36Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/*
37362306a36Sopenharmony_ci * Why 32 ? is this not cache line size dependent?
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_ci	writel(RBURST_64|WBURST_64, &regs->PciState);
37662306a36Sopenharmony_ci	wmb();
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	start_pc = rr_read_eeprom_word(rrpriv,
37962306a36Sopenharmony_ci			offsetof(struct eeprom, rncd_info.FwStart));
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci#if (DEBUG > 1)
38262306a36Sopenharmony_ci	printk("%s: Executing firmware at address 0x%06x\n",
38362306a36Sopenharmony_ci	       dev->name, start_pc);
38462306a36Sopenharmony_ci#endif
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	writel(start_pc + 0x800, &regs->Pc);
38762306a36Sopenharmony_ci	wmb();
38862306a36Sopenharmony_ci	udelay(5);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	writel(start_pc, &regs->Pc);
39162306a36Sopenharmony_ci	wmb();
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * Read a string from the EEPROM.
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_cistatic unsigned int rr_read_eeprom(struct rr_private *rrpriv,
40162306a36Sopenharmony_ci				unsigned long offset,
40262306a36Sopenharmony_ci				unsigned char *buf,
40362306a36Sopenharmony_ci				unsigned long length)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
40662306a36Sopenharmony_ci	u32 misc, io, host, i;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	io = readl(&regs->ExtIo);
40962306a36Sopenharmony_ci	writel(0, &regs->ExtIo);
41062306a36Sopenharmony_ci	misc = readl(&regs->LocalCtrl);
41162306a36Sopenharmony_ci	writel(0, &regs->LocalCtrl);
41262306a36Sopenharmony_ci	host = readl(&regs->HostCtrl);
41362306a36Sopenharmony_ci	writel(host | HALT_NIC, &regs->HostCtrl);
41462306a36Sopenharmony_ci	mb();
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	for (i = 0; i < length; i++){
41762306a36Sopenharmony_ci		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
41862306a36Sopenharmony_ci		mb();
41962306a36Sopenharmony_ci		buf[i] = (readl(&regs->WinData) >> 24) & 0xff;
42062306a36Sopenharmony_ci		mb();
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	writel(host, &regs->HostCtrl);
42462306a36Sopenharmony_ci	writel(misc, &regs->LocalCtrl);
42562306a36Sopenharmony_ci	writel(io, &regs->ExtIo);
42662306a36Sopenharmony_ci	mb();
42762306a36Sopenharmony_ci	return i;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/*
43262306a36Sopenharmony_ci * Shortcut to read one word (4 bytes) out of the EEPROM and convert
43362306a36Sopenharmony_ci * it to our CPU byte-order.
43462306a36Sopenharmony_ci */
43562306a36Sopenharmony_cistatic u32 rr_read_eeprom_word(struct rr_private *rrpriv,
43662306a36Sopenharmony_ci			    size_t offset)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	__be32 word;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if ((rr_read_eeprom(rrpriv, offset,
44162306a36Sopenharmony_ci			    (unsigned char *)&word, 4) == 4))
44262306a36Sopenharmony_ci		return be32_to_cpu(word);
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/*
44862306a36Sopenharmony_ci * Write a string to the EEPROM.
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * This is only called when the firmware is not running.
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cistatic unsigned int write_eeprom(struct rr_private *rrpriv,
45362306a36Sopenharmony_ci				 unsigned long offset,
45462306a36Sopenharmony_ci				 unsigned char *buf,
45562306a36Sopenharmony_ci				 unsigned long length)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
45862306a36Sopenharmony_ci	u32 misc, io, data, i, j, ready, error = 0;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	io = readl(&regs->ExtIo);
46162306a36Sopenharmony_ci	writel(0, &regs->ExtIo);
46262306a36Sopenharmony_ci	misc = readl(&regs->LocalCtrl);
46362306a36Sopenharmony_ci	writel(ENABLE_EEPROM_WRITE, &regs->LocalCtrl);
46462306a36Sopenharmony_ci	mb();
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	for (i = 0; i < length; i++){
46762306a36Sopenharmony_ci		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
46862306a36Sopenharmony_ci		mb();
46962306a36Sopenharmony_ci		data = buf[i] << 24;
47062306a36Sopenharmony_ci		/*
47162306a36Sopenharmony_ci		 * Only try to write the data if it is not the same
47262306a36Sopenharmony_ci		 * value already.
47362306a36Sopenharmony_ci		 */
47462306a36Sopenharmony_ci		if ((readl(&regs->WinData) & 0xff000000) != data){
47562306a36Sopenharmony_ci			writel(data, &regs->WinData);
47662306a36Sopenharmony_ci			ready = 0;
47762306a36Sopenharmony_ci			j = 0;
47862306a36Sopenharmony_ci			mb();
47962306a36Sopenharmony_ci			while(!ready){
48062306a36Sopenharmony_ci				udelay(20);
48162306a36Sopenharmony_ci				if ((readl(&regs->WinData) & 0xff000000) ==
48262306a36Sopenharmony_ci				    data)
48362306a36Sopenharmony_ci					ready = 1;
48462306a36Sopenharmony_ci				mb();
48562306a36Sopenharmony_ci				if (j++ > 5000){
48662306a36Sopenharmony_ci					printk("data mismatch: %08x, "
48762306a36Sopenharmony_ci					       "WinData %08x\n", data,
48862306a36Sopenharmony_ci					       readl(&regs->WinData));
48962306a36Sopenharmony_ci					ready = 1;
49062306a36Sopenharmony_ci					error = 1;
49162306a36Sopenharmony_ci				}
49262306a36Sopenharmony_ci			}
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	writel(misc, &regs->LocalCtrl);
49762306a36Sopenharmony_ci	writel(io, &regs->ExtIo);
49862306a36Sopenharmony_ci	mb();
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	return error;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int rr_init(struct net_device *dev)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	u8 addr[HIPPI_ALEN] __aligned(4);
50762306a36Sopenharmony_ci	struct rr_private *rrpriv;
50862306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
50962306a36Sopenharmony_ci	u32 sram_size, rev;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
51262306a36Sopenharmony_ci	regs = rrpriv->regs;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	rev = readl(&regs->FwRev);
51562306a36Sopenharmony_ci	rrpriv->fw_rev = rev;
51662306a36Sopenharmony_ci	if (rev > 0x00020024)
51762306a36Sopenharmony_ci		printk("  Firmware revision: %i.%i.%i\n", (rev >> 16),
51862306a36Sopenharmony_ci		       ((rev >> 8) & 0xff), (rev & 0xff));
51962306a36Sopenharmony_ci	else if (rev >= 0x00020000) {
52062306a36Sopenharmony_ci		printk("  Firmware revision: %i.%i.%i (2.0.37 or "
52162306a36Sopenharmony_ci		       "later is recommended)\n", (rev >> 16),
52262306a36Sopenharmony_ci		       ((rev >> 8) & 0xff), (rev & 0xff));
52362306a36Sopenharmony_ci	}else{
52462306a36Sopenharmony_ci		printk("  Firmware revision too old: %i.%i.%i, please "
52562306a36Sopenharmony_ci		       "upgrade to 2.0.37 or later.\n",
52662306a36Sopenharmony_ci		       (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#if (DEBUG > 2)
53062306a36Sopenharmony_ci	printk("  Maximum receive rings %i\n", readl(&regs->MaxRxRng));
53162306a36Sopenharmony_ci#endif
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/*
53462306a36Sopenharmony_ci	 * Read the hardware address from the eeprom.  The HW address
53562306a36Sopenharmony_ci	 * is not really necessary for HIPPI but awfully convenient.
53662306a36Sopenharmony_ci	 * The pointer arithmetic to put it in dev_addr is ugly, but
53762306a36Sopenharmony_ci	 * Donald Becker does it this way for the GigE version of this
53862306a36Sopenharmony_ci	 * card and it's shorter and more portable than any
53962306a36Sopenharmony_ci	 * other method I've seen.  -VAL
54062306a36Sopenharmony_ci	 */
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	*(__be16 *)(addr) =
54362306a36Sopenharmony_ci	  htons(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA)));
54462306a36Sopenharmony_ci	*(__be32 *)(addr+2) =
54562306a36Sopenharmony_ci	  htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4])));
54662306a36Sopenharmony_ci	dev_addr_set(dev, addr);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	printk("  MAC: %pM\n", dev->dev_addr);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	sram_size = rr_read_eeprom_word(rrpriv, 8);
55162306a36Sopenharmony_ci	printk("  SRAM size 0x%06x\n", sram_size);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic int rr_init1(struct net_device *dev)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct rr_private *rrpriv;
56062306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
56162306a36Sopenharmony_ci	unsigned long myjif, flags;
56262306a36Sopenharmony_ci	struct cmd cmd;
56362306a36Sopenharmony_ci	u32 hostctrl;
56462306a36Sopenharmony_ci	int ecode = 0;
56562306a36Sopenharmony_ci	short i;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
56862306a36Sopenharmony_ci	regs = rrpriv->regs;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	hostctrl = readl(&regs->HostCtrl);
57362306a36Sopenharmony_ci	writel(hostctrl | HALT_NIC | RR_CLEAR_INT, &regs->HostCtrl);
57462306a36Sopenharmony_ci	wmb();
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (hostctrl & PARITY_ERR){
57762306a36Sopenharmony_ci		printk("%s: Parity error halting NIC - this is serious!\n",
57862306a36Sopenharmony_ci		       dev->name);
57962306a36Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
58062306a36Sopenharmony_ci		ecode = -EFAULT;
58162306a36Sopenharmony_ci		goto error;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	set_rxaddr(regs, rrpriv->rx_ctrl_dma);
58562306a36Sopenharmony_ci	set_infoaddr(regs, rrpriv->info_dma);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.entry_size = sizeof(struct event);
58862306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES;
58962306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.mode = 0;
59062306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
59162306a36Sopenharmony_ci	set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring_dma);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd);
59462306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES;
59562306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.mode = 0;
59662306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = 15;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++) {
59962306a36Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++) {
60362306a36Sopenharmony_ci		rrpriv->tx_ring[i].size = 0;
60462306a36Sopenharmony_ci		set_rraddr(&rrpriv->tx_ring[i].addr, 0);
60562306a36Sopenharmony_ci		rrpriv->tx_skbuff[i] = NULL;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci	rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc);
60862306a36Sopenharmony_ci	rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES;
60962306a36Sopenharmony_ci	rrpriv->info->tx_ctrl.mode = 0;
61062306a36Sopenharmony_ci	rrpriv->info->tx_ctrl.pi = 0;
61162306a36Sopenharmony_ci	set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring_dma);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/*
61462306a36Sopenharmony_ci	 * Set dirty_tx before we start receiving interrupts, otherwise
61562306a36Sopenharmony_ci	 * the interrupt handler might think it is supposed to process
61662306a36Sopenharmony_ci	 * tx ints before we are up and running, which may cause a null
61762306a36Sopenharmony_ci	 * pointer access in the int handler.
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci	rrpriv->tx_full = 0;
62062306a36Sopenharmony_ci	rrpriv->cur_rx = 0;
62162306a36Sopenharmony_ci	rrpriv->dirty_rx = rrpriv->dirty_tx = 0;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	rr_reset(dev);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* Tuning values */
62662306a36Sopenharmony_ci	writel(0x5000, &regs->ConRetry);
62762306a36Sopenharmony_ci	writel(0x100, &regs->ConRetryTmr);
62862306a36Sopenharmony_ci	writel(0x500000, &regs->ConTmout);
62962306a36Sopenharmony_ci 	writel(0x60, &regs->IntrTmr);
63062306a36Sopenharmony_ci	writel(0x500000, &regs->TxDataMvTimeout);
63162306a36Sopenharmony_ci	writel(0x200000, &regs->RxDataMvTimeout);
63262306a36Sopenharmony_ci 	writel(0x80, &regs->WriteDmaThresh);
63362306a36Sopenharmony_ci 	writel(0x80, &regs->ReadDmaThresh);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	rrpriv->fw_running = 0;
63662306a36Sopenharmony_ci	wmb();
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR);
63962306a36Sopenharmony_ci	writel(hostctrl, &regs->HostCtrl);
64062306a36Sopenharmony_ci	wmb();
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
64562306a36Sopenharmony_ci		struct sk_buff *skb;
64662306a36Sopenharmony_ci		dma_addr_t addr;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		rrpriv->rx_ring[i].mode = 0;
64962306a36Sopenharmony_ci		skb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC);
65062306a36Sopenharmony_ci		if (!skb) {
65162306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Unable to allocate memory "
65262306a36Sopenharmony_ci			       "for receive ring - halting NIC\n", dev->name);
65362306a36Sopenharmony_ci			ecode = -ENOMEM;
65462306a36Sopenharmony_ci			goto error;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci		rrpriv->rx_skbuff[i] = skb;
65762306a36Sopenharmony_ci		addr = dma_map_single(&rrpriv->pci_dev->dev, skb->data,
65862306a36Sopenharmony_ci				      dev->mtu + HIPPI_HLEN, DMA_FROM_DEVICE);
65962306a36Sopenharmony_ci		/*
66062306a36Sopenharmony_ci		 * Sanity test to see if we conflict with the DMA
66162306a36Sopenharmony_ci		 * limitations of the Roadrunner.
66262306a36Sopenharmony_ci		 */
66362306a36Sopenharmony_ci		if ((((unsigned long)skb->data) & 0xfff) > ~65320)
66462306a36Sopenharmony_ci			printk("skb alloc error\n");
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		set_rraddr(&rrpriv->rx_ring[i].addr, addr);
66762306a36Sopenharmony_ci		rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	rrpriv->rx_ctrl[4].entry_size = sizeof(struct rx_desc);
67162306a36Sopenharmony_ci	rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES;
67262306a36Sopenharmony_ci	rrpriv->rx_ctrl[4].mode = 8;
67362306a36Sopenharmony_ci	rrpriv->rx_ctrl[4].pi = 0;
67462306a36Sopenharmony_ci	wmb();
67562306a36Sopenharmony_ci	set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring_dma);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	udelay(1000);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/*
68062306a36Sopenharmony_ci	 * Now start the FirmWare.
68162306a36Sopenharmony_ci	 */
68262306a36Sopenharmony_ci	cmd.code = C_START_FW;
68362306a36Sopenharmony_ci	cmd.ring = 0;
68462306a36Sopenharmony_ci	cmd.index = 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	rr_issue_cmd(rrpriv, &cmd);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/*
68962306a36Sopenharmony_ci	 * Give the FirmWare time to chew on the `get running' command.
69062306a36Sopenharmony_ci	 */
69162306a36Sopenharmony_ci	myjif = jiffies + 5 * HZ;
69262306a36Sopenharmony_ci	while (time_before(jiffies, myjif) && !rrpriv->fw_running)
69362306a36Sopenharmony_ci		cpu_relax();
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	netif_start_queue(dev);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return ecode;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci error:
70062306a36Sopenharmony_ci	/*
70162306a36Sopenharmony_ci	 * We might have gotten here because we are out of memory,
70262306a36Sopenharmony_ci	 * make sure we release everything we allocated before failing
70362306a36Sopenharmony_ci	 */
70462306a36Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
70562306a36Sopenharmony_ci		struct sk_buff *skb = rrpriv->rx_skbuff[i];
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		if (skb) {
70862306a36Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
70962306a36Sopenharmony_ci					 rrpriv->rx_ring[i].addr.addrlo,
71062306a36Sopenharmony_ci					 dev->mtu + HIPPI_HLEN,
71162306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
71262306a36Sopenharmony_ci			rrpriv->rx_ring[i].size = 0;
71362306a36Sopenharmony_ci			set_rraddr(&rrpriv->rx_ring[i].addr, 0);
71462306a36Sopenharmony_ci			dev_kfree_skb(skb);
71562306a36Sopenharmony_ci			rrpriv->rx_skbuff[i] = NULL;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	return ecode;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/*
72362306a36Sopenharmony_ci * All events are considered to be slow (RX/TX ints do not generate
72462306a36Sopenharmony_ci * events) and are handled here, outside the main interrupt handler,
72562306a36Sopenharmony_ci * to reduce the size of the handler.
72662306a36Sopenharmony_ci */
72762306a36Sopenharmony_cistatic u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct rr_private *rrpriv;
73062306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
73162306a36Sopenharmony_ci	u32 tmp;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
73462306a36Sopenharmony_ci	regs = rrpriv->regs;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	while (prodidx != eidx){
73762306a36Sopenharmony_ci		switch (rrpriv->evt_ring[eidx].code){
73862306a36Sopenharmony_ci		case E_NIC_UP:
73962306a36Sopenharmony_ci			tmp = readl(&regs->FwRev);
74062306a36Sopenharmony_ci			printk(KERN_INFO "%s: Firmware revision %i.%i.%i "
74162306a36Sopenharmony_ci			       "up and running\n", dev->name,
74262306a36Sopenharmony_ci			       (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff));
74362306a36Sopenharmony_ci			rrpriv->fw_running = 1;
74462306a36Sopenharmony_ci			writel(RX_RING_ENTRIES - 1, &regs->IpRxPi);
74562306a36Sopenharmony_ci			wmb();
74662306a36Sopenharmony_ci			break;
74762306a36Sopenharmony_ci		case E_LINK_ON:
74862306a36Sopenharmony_ci			printk(KERN_INFO "%s: Optical link ON\n", dev->name);
74962306a36Sopenharmony_ci			break;
75062306a36Sopenharmony_ci		case E_LINK_OFF:
75162306a36Sopenharmony_ci			printk(KERN_INFO "%s: Optical link OFF\n", dev->name);
75262306a36Sopenharmony_ci			break;
75362306a36Sopenharmony_ci		case E_RX_IDLE:
75462306a36Sopenharmony_ci			printk(KERN_WARNING "%s: RX data not moving\n",
75562306a36Sopenharmony_ci			       dev->name);
75662306a36Sopenharmony_ci			goto drop;
75762306a36Sopenharmony_ci		case E_WATCHDOG:
75862306a36Sopenharmony_ci			printk(KERN_INFO "%s: The watchdog is here to see "
75962306a36Sopenharmony_ci			       "us\n", dev->name);
76062306a36Sopenharmony_ci			break;
76162306a36Sopenharmony_ci		case E_INTERN_ERR:
76262306a36Sopenharmony_ci			printk(KERN_ERR "%s: HIPPI Internal NIC error\n",
76362306a36Sopenharmony_ci			       dev->name);
76462306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
76562306a36Sopenharmony_ci			       &regs->HostCtrl);
76662306a36Sopenharmony_ci			wmb();
76762306a36Sopenharmony_ci			break;
76862306a36Sopenharmony_ci		case E_HOST_ERR:
76962306a36Sopenharmony_ci			printk(KERN_ERR "%s: Host software error\n",
77062306a36Sopenharmony_ci			       dev->name);
77162306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
77262306a36Sopenharmony_ci			       &regs->HostCtrl);
77362306a36Sopenharmony_ci			wmb();
77462306a36Sopenharmony_ci			break;
77562306a36Sopenharmony_ci		/*
77662306a36Sopenharmony_ci		 * TX events.
77762306a36Sopenharmony_ci		 */
77862306a36Sopenharmony_ci		case E_CON_REJ:
77962306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Connection rejected\n",
78062306a36Sopenharmony_ci			       dev->name);
78162306a36Sopenharmony_ci			dev->stats.tx_aborted_errors++;
78262306a36Sopenharmony_ci			break;
78362306a36Sopenharmony_ci		case E_CON_TMOUT:
78462306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Connection timeout\n",
78562306a36Sopenharmony_ci			       dev->name);
78662306a36Sopenharmony_ci			break;
78762306a36Sopenharmony_ci		case E_DISC_ERR:
78862306a36Sopenharmony_ci			printk(KERN_WARNING "%s: HIPPI disconnect error\n",
78962306a36Sopenharmony_ci			       dev->name);
79062306a36Sopenharmony_ci			dev->stats.tx_aborted_errors++;
79162306a36Sopenharmony_ci			break;
79262306a36Sopenharmony_ci		case E_INT_PRTY:
79362306a36Sopenharmony_ci			printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
79462306a36Sopenharmony_ci			       dev->name);
79562306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
79662306a36Sopenharmony_ci			       &regs->HostCtrl);
79762306a36Sopenharmony_ci			wmb();
79862306a36Sopenharmony_ci			break;
79962306a36Sopenharmony_ci		case E_TX_IDLE:
80062306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Transmitter idle\n",
80162306a36Sopenharmony_ci			       dev->name);
80262306a36Sopenharmony_ci			break;
80362306a36Sopenharmony_ci		case E_TX_LINK_DROP:
80462306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Link lost during transmit\n",
80562306a36Sopenharmony_ci			       dev->name);
80662306a36Sopenharmony_ci			dev->stats.tx_aborted_errors++;
80762306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
80862306a36Sopenharmony_ci			       &regs->HostCtrl);
80962306a36Sopenharmony_ci			wmb();
81062306a36Sopenharmony_ci			break;
81162306a36Sopenharmony_ci		case E_TX_INV_RNG:
81262306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid send ring block\n",
81362306a36Sopenharmony_ci			       dev->name);
81462306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
81562306a36Sopenharmony_ci			       &regs->HostCtrl);
81662306a36Sopenharmony_ci			wmb();
81762306a36Sopenharmony_ci			break;
81862306a36Sopenharmony_ci		case E_TX_INV_BUF:
81962306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid send buffer address\n",
82062306a36Sopenharmony_ci			       dev->name);
82162306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
82262306a36Sopenharmony_ci			       &regs->HostCtrl);
82362306a36Sopenharmony_ci			wmb();
82462306a36Sopenharmony_ci			break;
82562306a36Sopenharmony_ci		case E_TX_INV_DSC:
82662306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid descriptor address\n",
82762306a36Sopenharmony_ci			       dev->name);
82862306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
82962306a36Sopenharmony_ci			       &regs->HostCtrl);
83062306a36Sopenharmony_ci			wmb();
83162306a36Sopenharmony_ci			break;
83262306a36Sopenharmony_ci		/*
83362306a36Sopenharmony_ci		 * RX events.
83462306a36Sopenharmony_ci		 */
83562306a36Sopenharmony_ci		case E_RX_RNG_OUT:
83662306a36Sopenharmony_ci			printk(KERN_INFO "%s: Receive ring full\n", dev->name);
83762306a36Sopenharmony_ci			break;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		case E_RX_PAR_ERR:
84062306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Receive parity error\n",
84162306a36Sopenharmony_ci			       dev->name);
84262306a36Sopenharmony_ci			goto drop;
84362306a36Sopenharmony_ci		case E_RX_LLRC_ERR:
84462306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Receive LLRC error\n",
84562306a36Sopenharmony_ci			       dev->name);
84662306a36Sopenharmony_ci			goto drop;
84762306a36Sopenharmony_ci		case E_PKT_LN_ERR:
84862306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Receive packet length "
84962306a36Sopenharmony_ci			       "error\n", dev->name);
85062306a36Sopenharmony_ci			goto drop;
85162306a36Sopenharmony_ci		case E_DTA_CKSM_ERR:
85262306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Data checksum error\n",
85362306a36Sopenharmony_ci			       dev->name);
85462306a36Sopenharmony_ci			goto drop;
85562306a36Sopenharmony_ci		case E_SHT_BST:
85662306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Unexpected short burst "
85762306a36Sopenharmony_ci			       "error\n", dev->name);
85862306a36Sopenharmony_ci			goto drop;
85962306a36Sopenharmony_ci		case E_STATE_ERR:
86062306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Recv. state transition"
86162306a36Sopenharmony_ci			       " error\n", dev->name);
86262306a36Sopenharmony_ci			goto drop;
86362306a36Sopenharmony_ci		case E_UNEXP_DATA:
86462306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Unexpected data error\n",
86562306a36Sopenharmony_ci			       dev->name);
86662306a36Sopenharmony_ci			goto drop;
86762306a36Sopenharmony_ci		case E_LST_LNK_ERR:
86862306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Link lost error\n",
86962306a36Sopenharmony_ci			       dev->name);
87062306a36Sopenharmony_ci			goto drop;
87162306a36Sopenharmony_ci		case E_FRM_ERR:
87262306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Framing Error\n",
87362306a36Sopenharmony_ci			       dev->name);
87462306a36Sopenharmony_ci			goto drop;
87562306a36Sopenharmony_ci		case E_FLG_SYN_ERR:
87662306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Flag sync. lost during "
87762306a36Sopenharmony_ci			       "packet\n", dev->name);
87862306a36Sopenharmony_ci			goto drop;
87962306a36Sopenharmony_ci		case E_RX_INV_BUF:
88062306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid receive buffer "
88162306a36Sopenharmony_ci			       "address\n", dev->name);
88262306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
88362306a36Sopenharmony_ci			       &regs->HostCtrl);
88462306a36Sopenharmony_ci			wmb();
88562306a36Sopenharmony_ci			break;
88662306a36Sopenharmony_ci		case E_RX_INV_DSC:
88762306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid receive descriptor "
88862306a36Sopenharmony_ci			       "address\n", dev->name);
88962306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
89062306a36Sopenharmony_ci			       &regs->HostCtrl);
89162306a36Sopenharmony_ci			wmb();
89262306a36Sopenharmony_ci			break;
89362306a36Sopenharmony_ci		case E_RNG_BLK:
89462306a36Sopenharmony_ci			printk(KERN_ERR "%s: Invalid ring block\n",
89562306a36Sopenharmony_ci			       dev->name);
89662306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
89762306a36Sopenharmony_ci			       &regs->HostCtrl);
89862306a36Sopenharmony_ci			wmb();
89962306a36Sopenharmony_ci			break;
90062306a36Sopenharmony_ci		drop:
90162306a36Sopenharmony_ci			/* Label packet to be dropped.
90262306a36Sopenharmony_ci			 * Actual dropping occurs in rx
90362306a36Sopenharmony_ci			 * handling.
90462306a36Sopenharmony_ci			 *
90562306a36Sopenharmony_ci			 * The index of packet we get to drop is
90662306a36Sopenharmony_ci			 * the index of the packet following
90762306a36Sopenharmony_ci			 * the bad packet. -kbf
90862306a36Sopenharmony_ci			 */
90962306a36Sopenharmony_ci			{
91062306a36Sopenharmony_ci				u16 index = rrpriv->evt_ring[eidx].index;
91162306a36Sopenharmony_ci				index = (index + (RX_RING_ENTRIES - 1)) %
91262306a36Sopenharmony_ci					RX_RING_ENTRIES;
91362306a36Sopenharmony_ci				rrpriv->rx_ring[index].mode |=
91462306a36Sopenharmony_ci					(PACKET_BAD | PACKET_END);
91562306a36Sopenharmony_ci			}
91662306a36Sopenharmony_ci			break;
91762306a36Sopenharmony_ci		default:
91862306a36Sopenharmony_ci			printk(KERN_WARNING "%s: Unhandled event 0x%02x\n",
91962306a36Sopenharmony_ci			       dev->name, rrpriv->evt_ring[eidx].code);
92062306a36Sopenharmony_ci		}
92162306a36Sopenharmony_ci		eidx = (eidx + 1) % EVT_RING_ENTRIES;
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = eidx;
92562306a36Sopenharmony_ci	wmb();
92662306a36Sopenharmony_ci	return eidx;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
93362306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	do {
93662306a36Sopenharmony_ci		struct rx_desc *desc;
93762306a36Sopenharmony_ci		u32 pkt_len;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		desc = &(rrpriv->rx_ring[index]);
94062306a36Sopenharmony_ci		pkt_len = desc->size;
94162306a36Sopenharmony_ci#if (DEBUG > 2)
94262306a36Sopenharmony_ci		printk("index %i, rxlimit %i\n", index, rxlimit);
94362306a36Sopenharmony_ci		printk("len %x, mode %x\n", pkt_len, desc->mode);
94462306a36Sopenharmony_ci#endif
94562306a36Sopenharmony_ci		if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){
94662306a36Sopenharmony_ci			dev->stats.rx_dropped++;
94762306a36Sopenharmony_ci			goto defer;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		if (pkt_len > 0){
95162306a36Sopenharmony_ci			struct sk_buff *skb, *rx_skb;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci			rx_skb = rrpriv->rx_skbuff[index];
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci			if (pkt_len < PKT_COPY_THRESHOLD) {
95662306a36Sopenharmony_ci				skb = alloc_skb(pkt_len, GFP_ATOMIC);
95762306a36Sopenharmony_ci				if (skb == NULL){
95862306a36Sopenharmony_ci					printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
95962306a36Sopenharmony_ci					dev->stats.rx_dropped++;
96062306a36Sopenharmony_ci					goto defer;
96162306a36Sopenharmony_ci				} else {
96262306a36Sopenharmony_ci					dma_sync_single_for_cpu(&rrpriv->pci_dev->dev,
96362306a36Sopenharmony_ci								desc->addr.addrlo,
96462306a36Sopenharmony_ci								pkt_len,
96562306a36Sopenharmony_ci								DMA_FROM_DEVICE);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci					skb_put_data(skb, rx_skb->data,
96862306a36Sopenharmony_ci						     pkt_len);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci					dma_sync_single_for_device(&rrpriv->pci_dev->dev,
97162306a36Sopenharmony_ci								   desc->addr.addrlo,
97262306a36Sopenharmony_ci								   pkt_len,
97362306a36Sopenharmony_ci								   DMA_FROM_DEVICE);
97462306a36Sopenharmony_ci				}
97562306a36Sopenharmony_ci			}else{
97662306a36Sopenharmony_ci				struct sk_buff *newskb;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci				newskb = alloc_skb(dev->mtu + HIPPI_HLEN,
97962306a36Sopenharmony_ci					GFP_ATOMIC);
98062306a36Sopenharmony_ci				if (newskb){
98162306a36Sopenharmony_ci					dma_addr_t addr;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci					dma_unmap_single(&rrpriv->pci_dev->dev,
98462306a36Sopenharmony_ci							 desc->addr.addrlo,
98562306a36Sopenharmony_ci							 dev->mtu + HIPPI_HLEN,
98662306a36Sopenharmony_ci							 DMA_FROM_DEVICE);
98762306a36Sopenharmony_ci					skb = rx_skb;
98862306a36Sopenharmony_ci					skb_put(skb, pkt_len);
98962306a36Sopenharmony_ci					rrpriv->rx_skbuff[index] = newskb;
99062306a36Sopenharmony_ci					addr = dma_map_single(&rrpriv->pci_dev->dev,
99162306a36Sopenharmony_ci							      newskb->data,
99262306a36Sopenharmony_ci							      dev->mtu + HIPPI_HLEN,
99362306a36Sopenharmony_ci							      DMA_FROM_DEVICE);
99462306a36Sopenharmony_ci					set_rraddr(&desc->addr, addr);
99562306a36Sopenharmony_ci				} else {
99662306a36Sopenharmony_ci					printk("%s: Out of memory, deferring "
99762306a36Sopenharmony_ci					       "packet\n", dev->name);
99862306a36Sopenharmony_ci					dev->stats.rx_dropped++;
99962306a36Sopenharmony_ci					goto defer;
100062306a36Sopenharmony_ci				}
100162306a36Sopenharmony_ci			}
100262306a36Sopenharmony_ci			skb->protocol = hippi_type_trans(skb, dev);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci			netif_rx(skb);		/* send it up */
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci			dev->stats.rx_packets++;
100762306a36Sopenharmony_ci			dev->stats.rx_bytes += pkt_len;
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci	defer:
101062306a36Sopenharmony_ci		desc->mode = 0;
101162306a36Sopenharmony_ci		desc->size = dev->mtu + HIPPI_HLEN;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		if ((index & 7) == 7)
101462306a36Sopenharmony_ci			writel(index, &regs->IpRxPi);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		index = (index + 1) % RX_RING_ENTRIES;
101762306a36Sopenharmony_ci	} while(index != rxlimit);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	rrpriv->cur_rx = index;
102062306a36Sopenharmony_ci	wmb();
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic irqreturn_t rr_interrupt(int irq, void *dev_id)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct rr_private *rrpriv;
102762306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
102862306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *)dev_id;
102962306a36Sopenharmony_ci	u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
103262306a36Sopenharmony_ci	regs = rrpriv->regs;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (!(readl(&regs->HostCtrl) & RR_INT))
103562306a36Sopenharmony_ci		return IRQ_NONE;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	spin_lock(&rrpriv->lock);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	prodidx = readl(&regs->EvtPrd);
104062306a36Sopenharmony_ci	txcsmr = (prodidx >> 8) & 0xff;
104162306a36Sopenharmony_ci	rxlimit = (prodidx >> 16) & 0xff;
104262306a36Sopenharmony_ci	prodidx &= 0xff;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci#if (DEBUG > 2)
104562306a36Sopenharmony_ci	printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name,
104662306a36Sopenharmony_ci	       prodidx, rrpriv->info->evt_ctrl.pi);
104762306a36Sopenharmony_ci#endif
104862306a36Sopenharmony_ci	/*
104962306a36Sopenharmony_ci	 * Order here is important.  We must handle events
105062306a36Sopenharmony_ci	 * before doing anything else in order to catch
105162306a36Sopenharmony_ci	 * such things as LLRC errors, etc -kbf
105262306a36Sopenharmony_ci	 */
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	eidx = rrpriv->info->evt_ctrl.pi;
105562306a36Sopenharmony_ci	if (prodidx != eidx)
105662306a36Sopenharmony_ci		eidx = rr_handle_event(dev, prodidx, eidx);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	rxindex = rrpriv->cur_rx;
105962306a36Sopenharmony_ci	if (rxindex != rxlimit)
106062306a36Sopenharmony_ci		rx_int(dev, rxlimit, rxindex);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	txcon = rrpriv->dirty_tx;
106362306a36Sopenharmony_ci	if (txcsmr != txcon) {
106462306a36Sopenharmony_ci		do {
106562306a36Sopenharmony_ci			/* Due to occational firmware TX producer/consumer out
106662306a36Sopenharmony_ci			 * of sync. error need to check entry in ring -kbf
106762306a36Sopenharmony_ci			 */
106862306a36Sopenharmony_ci			if(rrpriv->tx_skbuff[txcon]){
106962306a36Sopenharmony_ci				struct tx_desc *desc;
107062306a36Sopenharmony_ci				struct sk_buff *skb;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci				desc = &(rrpriv->tx_ring[txcon]);
107362306a36Sopenharmony_ci				skb = rrpriv->tx_skbuff[txcon];
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci				dev->stats.tx_packets++;
107662306a36Sopenharmony_ci				dev->stats.tx_bytes += skb->len;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci				dma_unmap_single(&rrpriv->pci_dev->dev,
107962306a36Sopenharmony_ci						 desc->addr.addrlo, skb->len,
108062306a36Sopenharmony_ci						 DMA_TO_DEVICE);
108162306a36Sopenharmony_ci				dev_kfree_skb_irq(skb);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci				rrpriv->tx_skbuff[txcon] = NULL;
108462306a36Sopenharmony_ci				desc->size = 0;
108562306a36Sopenharmony_ci				set_rraddr(&rrpriv->tx_ring[txcon].addr, 0);
108662306a36Sopenharmony_ci				desc->mode = 0;
108762306a36Sopenharmony_ci			}
108862306a36Sopenharmony_ci			txcon = (txcon + 1) % TX_RING_ENTRIES;
108962306a36Sopenharmony_ci		} while (txcsmr != txcon);
109062306a36Sopenharmony_ci		wmb();
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		rrpriv->dirty_tx = txcon;
109362306a36Sopenharmony_ci		if (rrpriv->tx_full && rr_if_busy(dev) &&
109462306a36Sopenharmony_ci		    (((rrpriv->info->tx_ctrl.pi + 1) % TX_RING_ENTRIES)
109562306a36Sopenharmony_ci		     != rrpriv->dirty_tx)){
109662306a36Sopenharmony_ci			rrpriv->tx_full = 0;
109762306a36Sopenharmony_ci			netif_wake_queue(dev);
109862306a36Sopenharmony_ci		}
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	eidx |= ((txcsmr << 8) | (rxlimit << 16));
110262306a36Sopenharmony_ci	writel(eidx, &regs->EvtCon);
110362306a36Sopenharmony_ci	wmb();
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	spin_unlock(&rrpriv->lock);
110662306a36Sopenharmony_ci	return IRQ_HANDLED;
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_cistatic inline void rr_raz_tx(struct rr_private *rrpriv,
111062306a36Sopenharmony_ci			     struct net_device *dev)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	int i;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++) {
111562306a36Sopenharmony_ci		struct sk_buff *skb = rrpriv->tx_skbuff[i];
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		if (skb) {
111862306a36Sopenharmony_ci			struct tx_desc *desc = &(rrpriv->tx_ring[i]);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
112162306a36Sopenharmony_ci					 desc->addr.addrlo, skb->len,
112262306a36Sopenharmony_ci					 DMA_TO_DEVICE);
112362306a36Sopenharmony_ci			desc->size = 0;
112462306a36Sopenharmony_ci			set_rraddr(&desc->addr, 0);
112562306a36Sopenharmony_ci			dev_kfree_skb(skb);
112662306a36Sopenharmony_ci			rrpriv->tx_skbuff[i] = NULL;
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic inline void rr_raz_rx(struct rr_private *rrpriv,
113362306a36Sopenharmony_ci			     struct net_device *dev)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	int i;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	for (i = 0; i < RX_RING_ENTRIES; i++) {
113862306a36Sopenharmony_ci		struct sk_buff *skb = rrpriv->rx_skbuff[i];
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		if (skb) {
114162306a36Sopenharmony_ci			struct rx_desc *desc = &(rrpriv->rx_ring[i]);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci			dma_unmap_single(&rrpriv->pci_dev->dev,
114462306a36Sopenharmony_ci					 desc->addr.addrlo,
114562306a36Sopenharmony_ci					 dev->mtu + HIPPI_HLEN,
114662306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
114762306a36Sopenharmony_ci			desc->size = 0;
114862306a36Sopenharmony_ci			set_rraddr(&desc->addr, 0);
114962306a36Sopenharmony_ci			dev_kfree_skb(skb);
115062306a36Sopenharmony_ci			rrpriv->rx_skbuff[i] = NULL;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_cistatic void rr_timer(struct timer_list *t)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	struct rr_private *rrpriv = from_timer(rrpriv, t, timer);
115862306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(rrpriv->pci_dev);
115962306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
116062306a36Sopenharmony_ci	unsigned long flags;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (readl(&regs->HostCtrl) & NIC_HALTED){
116362306a36Sopenharmony_ci		printk("%s: Restarting nic\n", dev->name);
116462306a36Sopenharmony_ci		memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
116562306a36Sopenharmony_ci		memset(rrpriv->info, 0, sizeof(struct rr_info));
116662306a36Sopenharmony_ci		wmb();
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		rr_raz_tx(rrpriv, dev);
116962306a36Sopenharmony_ci		rr_raz_rx(rrpriv, dev);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		if (rr_init1(dev)) {
117262306a36Sopenharmony_ci			spin_lock_irqsave(&rrpriv->lock, flags);
117362306a36Sopenharmony_ci			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
117462306a36Sopenharmony_ci			       &regs->HostCtrl);
117562306a36Sopenharmony_ci			spin_unlock_irqrestore(&rrpriv->lock, flags);
117662306a36Sopenharmony_ci		}
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci	rrpriv->timer.expires = RUN_AT(5*HZ);
117962306a36Sopenharmony_ci	add_timer(&rrpriv->timer);
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int rr_open(struct net_device *dev)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
118662306a36Sopenharmony_ci	struct pci_dev *pdev = rrpriv->pci_dev;
118762306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
118862306a36Sopenharmony_ci	int ecode = 0;
118962306a36Sopenharmony_ci	unsigned long flags;
119062306a36Sopenharmony_ci	dma_addr_t dma_addr;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	regs = rrpriv->regs;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (rrpriv->fw_rev < 0x00020000) {
119562306a36Sopenharmony_ci		printk(KERN_WARNING "%s: trying to configure device with "
119662306a36Sopenharmony_ci		       "obsolete firmware\n", dev->name);
119762306a36Sopenharmony_ci		ecode = -EBUSY;
119862306a36Sopenharmony_ci		goto error;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	rrpriv->rx_ctrl = dma_alloc_coherent(&pdev->dev,
120262306a36Sopenharmony_ci					     256 * sizeof(struct ring_ctrl),
120362306a36Sopenharmony_ci					     &dma_addr, GFP_KERNEL);
120462306a36Sopenharmony_ci	if (!rrpriv->rx_ctrl) {
120562306a36Sopenharmony_ci		ecode = -ENOMEM;
120662306a36Sopenharmony_ci		goto error;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci	rrpriv->rx_ctrl_dma = dma_addr;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	rrpriv->info = dma_alloc_coherent(&pdev->dev, sizeof(struct rr_info),
121162306a36Sopenharmony_ci					  &dma_addr, GFP_KERNEL);
121262306a36Sopenharmony_ci	if (!rrpriv->info) {
121362306a36Sopenharmony_ci		ecode = -ENOMEM;
121462306a36Sopenharmony_ci		goto error;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci	rrpriv->info_dma = dma_addr;
121762306a36Sopenharmony_ci	wmb();
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
122062306a36Sopenharmony_ci	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
122162306a36Sopenharmony_ci	readl(&regs->HostCtrl);
122262306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (request_irq(pdev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) {
122562306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
122662306a36Sopenharmony_ci		       dev->name, pdev->irq);
122762306a36Sopenharmony_ci		ecode = -EAGAIN;
122862306a36Sopenharmony_ci		goto error;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if ((ecode = rr_init1(dev)))
123262306a36Sopenharmony_ci		goto error;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	/* Set the timer to switch to check for link beat and perhaps switch
123562306a36Sopenharmony_ci	   to an alternate media type. */
123662306a36Sopenharmony_ci	timer_setup(&rrpriv->timer, rr_timer, 0);
123762306a36Sopenharmony_ci	rrpriv->timer.expires = RUN_AT(5*HZ);           /* 5 sec. watchdog */
123862306a36Sopenharmony_ci	add_timer(&rrpriv->timer);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	netif_start_queue(dev);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return ecode;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci error:
124562306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
124662306a36Sopenharmony_ci	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
124762306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (rrpriv->info) {
125062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct rr_info),
125162306a36Sopenharmony_ci				  rrpriv->info, rrpriv->info_dma);
125262306a36Sopenharmony_ci		rrpriv->info = NULL;
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci	if (rrpriv->rx_ctrl) {
125562306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, 256 * sizeof(struct ring_ctrl),
125662306a36Sopenharmony_ci				  rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma);
125762306a36Sopenharmony_ci		rrpriv->rx_ctrl = NULL;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	netif_stop_queue(dev);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	return ecode;
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic void rr_dump(struct net_device *dev)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct rr_private *rrpriv;
126962306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
127062306a36Sopenharmony_ci	u32 index, cons;
127162306a36Sopenharmony_ci	short i;
127262306a36Sopenharmony_ci	int len;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
127562306a36Sopenharmony_ci	regs = rrpriv->regs;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	printk("%s: dumping NIC TX rings\n", dev->name);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n",
128062306a36Sopenharmony_ci	       readl(&regs->RxPrd), readl(&regs->TxPrd),
128162306a36Sopenharmony_ci	       readl(&regs->EvtPrd), readl(&regs->TxPi),
128262306a36Sopenharmony_ci	       rrpriv->info->tx_ctrl.pi);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	printk("Error code 0x%x\n", readl(&regs->Fail1));
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	index = (((readl(&regs->EvtPrd) >> 8) & 0xff) - 1) % TX_RING_ENTRIES;
128762306a36Sopenharmony_ci	cons = rrpriv->dirty_tx;
128862306a36Sopenharmony_ci	printk("TX ring index %i, TX consumer %i\n",
128962306a36Sopenharmony_ci	       index, cons);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (rrpriv->tx_skbuff[index]){
129262306a36Sopenharmony_ci		len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len);
129362306a36Sopenharmony_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);
129462306a36Sopenharmony_ci		for (i = 0; i < len; i++){
129562306a36Sopenharmony_ci			if (!(i & 7))
129662306a36Sopenharmony_ci				printk("\n");
129762306a36Sopenharmony_ci			printk("%02x ", (unsigned char) rrpriv->tx_skbuff[index]->data[i]);
129862306a36Sopenharmony_ci		}
129962306a36Sopenharmony_ci		printk("\n");
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (rrpriv->tx_skbuff[cons]){
130362306a36Sopenharmony_ci		len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len);
130462306a36Sopenharmony_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);
130562306a36Sopenharmony_ci		printk("mode 0x%x, size 0x%x,\n phys %08Lx, skbuff-addr %p, truesize 0x%x\n",
130662306a36Sopenharmony_ci		       rrpriv->tx_ring[cons].mode,
130762306a36Sopenharmony_ci		       rrpriv->tx_ring[cons].size,
130862306a36Sopenharmony_ci		       (unsigned long long) rrpriv->tx_ring[cons].addr.addrlo,
130962306a36Sopenharmony_ci		       rrpriv->tx_skbuff[cons]->data,
131062306a36Sopenharmony_ci		       (unsigned int)rrpriv->tx_skbuff[cons]->truesize);
131162306a36Sopenharmony_ci		for (i = 0; i < len; i++){
131262306a36Sopenharmony_ci			if (!(i & 7))
131362306a36Sopenharmony_ci				printk("\n");
131462306a36Sopenharmony_ci			printk("%02x ", (unsigned char)rrpriv->tx_ring[cons].size);
131562306a36Sopenharmony_ci		}
131662306a36Sopenharmony_ci		printk("\n");
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	printk("dumping TX ring info:\n");
132062306a36Sopenharmony_ci	for (i = 0; i < TX_RING_ENTRIES; i++)
132162306a36Sopenharmony_ci		printk("mode 0x%x, size 0x%x, phys-addr %08Lx\n",
132262306a36Sopenharmony_ci		       rrpriv->tx_ring[i].mode,
132362306a36Sopenharmony_ci		       rrpriv->tx_ring[i].size,
132462306a36Sopenharmony_ci		       (unsigned long long) rrpriv->tx_ring[i].addr.addrlo);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic int rr_close(struct net_device *dev)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
133262306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
133362306a36Sopenharmony_ci	struct pci_dev *pdev = rrpriv->pci_dev;
133462306a36Sopenharmony_ci	unsigned long flags;
133562306a36Sopenharmony_ci	u32 tmp;
133662306a36Sopenharmony_ci	short i;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	netif_stop_queue(dev);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/*
134262306a36Sopenharmony_ci	 * Lock to make sure we are not cleaning up while another CPU
134362306a36Sopenharmony_ci	 * is handling interrupts.
134462306a36Sopenharmony_ci	 */
134562306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	tmp = readl(&regs->HostCtrl);
134862306a36Sopenharmony_ci	if (tmp & NIC_HALTED){
134962306a36Sopenharmony_ci		printk("%s: NIC already halted\n", dev->name);
135062306a36Sopenharmony_ci		rr_dump(dev);
135162306a36Sopenharmony_ci	}else{
135262306a36Sopenharmony_ci		tmp |= HALT_NIC | RR_CLEAR_INT;
135362306a36Sopenharmony_ci		writel(tmp, &regs->HostCtrl);
135462306a36Sopenharmony_ci		readl(&regs->HostCtrl);
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	rrpriv->fw_running = 0;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
136062306a36Sopenharmony_ci	del_timer_sync(&rrpriv->timer);
136162306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	writel(0, &regs->TxPi);
136462306a36Sopenharmony_ci	writel(0, &regs->IpRxPi);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	writel(0, &regs->EvtCon);
136762306a36Sopenharmony_ci	writel(0, &regs->EvtPrd);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	for (i = 0; i < CMD_RING_ENTRIES; i++)
137062306a36Sopenharmony_ci		writel(0, &regs->CmdRing[i]);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	rrpriv->info->tx_ctrl.entries = 0;
137362306a36Sopenharmony_ci	rrpriv->info->cmd_ctrl.pi = 0;
137462306a36Sopenharmony_ci	rrpriv->info->evt_ctrl.pi = 0;
137562306a36Sopenharmony_ci	rrpriv->rx_ctrl[4].entries = 0;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	rr_raz_tx(rrpriv, dev);
137862306a36Sopenharmony_ci	rr_raz_rx(rrpriv, dev);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, 256 * sizeof(struct ring_ctrl),
138162306a36Sopenharmony_ci			  rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma);
138262306a36Sopenharmony_ci	rrpriv->rx_ctrl = NULL;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, sizeof(struct rr_info), rrpriv->info,
138562306a36Sopenharmony_ci			  rrpriv->info_dma);
138662306a36Sopenharmony_ci	rrpriv->info = NULL;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
138962306a36Sopenharmony_ci	free_irq(pdev->irq, dev);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return 0;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic netdev_tx_t rr_start_xmit(struct sk_buff *skb,
139662306a36Sopenharmony_ci				 struct net_device *dev)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct rr_private *rrpriv = netdev_priv(dev);
139962306a36Sopenharmony_ci	struct rr_regs __iomem *regs = rrpriv->regs;
140062306a36Sopenharmony_ci	struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
140162306a36Sopenharmony_ci	struct ring_ctrl *txctrl;
140262306a36Sopenharmony_ci	unsigned long flags;
140362306a36Sopenharmony_ci	u32 index, len = skb->len;
140462306a36Sopenharmony_ci	u32 *ifield;
140562306a36Sopenharmony_ci	struct sk_buff *new_skb;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (readl(&regs->Mode) & FATAL_ERR)
140862306a36Sopenharmony_ci		printk("error codes Fail1 %02x, Fail2 %02x\n",
140962306a36Sopenharmony_ci		       readl(&regs->Fail1), readl(&regs->Fail2));
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/*
141262306a36Sopenharmony_ci	 * We probably need to deal with tbusy here to prevent overruns.
141362306a36Sopenharmony_ci	 */
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (skb_headroom(skb) < 8){
141662306a36Sopenharmony_ci		printk("incoming skb too small - reallocating\n");
141762306a36Sopenharmony_ci		if (!(new_skb = dev_alloc_skb(len + 8))) {
141862306a36Sopenharmony_ci			dev_kfree_skb(skb);
141962306a36Sopenharmony_ci			netif_wake_queue(dev);
142062306a36Sopenharmony_ci			return NETDEV_TX_OK;
142162306a36Sopenharmony_ci		}
142262306a36Sopenharmony_ci		skb_reserve(new_skb, 8);
142362306a36Sopenharmony_ci		skb_put(new_skb, len);
142462306a36Sopenharmony_ci		skb_copy_from_linear_data(skb, new_skb->data, len);
142562306a36Sopenharmony_ci		dev_kfree_skb(skb);
142662306a36Sopenharmony_ci		skb = new_skb;
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	ifield = skb_push(skb, 8);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	ifield[0] = 0;
143262306a36Sopenharmony_ci	ifield[1] = hcb->ifield;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	/*
143562306a36Sopenharmony_ci	 * We don't need the lock before we are actually going to start
143662306a36Sopenharmony_ci	 * fiddling with the control blocks.
143762306a36Sopenharmony_ci	 */
143862306a36Sopenharmony_ci	spin_lock_irqsave(&rrpriv->lock, flags);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	txctrl = &rrpriv->info->tx_ctrl;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	index = txctrl->pi;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	rrpriv->tx_skbuff[index] = skb;
144562306a36Sopenharmony_ci	set_rraddr(&rrpriv->tx_ring[index].addr,
144662306a36Sopenharmony_ci		   dma_map_single(&rrpriv->pci_dev->dev, skb->data, len + 8, DMA_TO_DEVICE));
144762306a36Sopenharmony_ci	rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */
144862306a36Sopenharmony_ci	rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END;
144962306a36Sopenharmony_ci	txctrl->pi = (index + 1) % TX_RING_ENTRIES;
145062306a36Sopenharmony_ci	wmb();
145162306a36Sopenharmony_ci	writel(txctrl->pi, &regs->TxPi);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (txctrl->pi == rrpriv->dirty_tx){
145462306a36Sopenharmony_ci		rrpriv->tx_full = 1;
145562306a36Sopenharmony_ci		netif_stop_queue(dev);
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	spin_unlock_irqrestore(&rrpriv->lock, flags);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	return NETDEV_TX_OK;
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci/*
146562306a36Sopenharmony_ci * Read the firmware out of the EEPROM and put it into the SRAM
146662306a36Sopenharmony_ci * (or from user space - later)
146762306a36Sopenharmony_ci *
146862306a36Sopenharmony_ci * This operation requires the NIC to be halted and is performed with
146962306a36Sopenharmony_ci * interrupts disabled and with the spinlock hold.
147062306a36Sopenharmony_ci */
147162306a36Sopenharmony_cistatic int rr_load_firmware(struct net_device *dev)
147262306a36Sopenharmony_ci{
147362306a36Sopenharmony_ci	struct rr_private *rrpriv;
147462306a36Sopenharmony_ci	struct rr_regs __iomem *regs;
147562306a36Sopenharmony_ci	size_t eptr, segptr;
147662306a36Sopenharmony_ci	int i, j;
147762306a36Sopenharmony_ci	u32 localctrl, sptr, len, tmp;
147862306a36Sopenharmony_ci	u32 p2len, p2size, nr_seg, revision, io, sram_size;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
148162306a36Sopenharmony_ci	regs = rrpriv->regs;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (dev->flags & IFF_UP)
148462306a36Sopenharmony_ci		return -EBUSY;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (!(readl(&regs->HostCtrl) & NIC_HALTED)){
148762306a36Sopenharmony_ci		printk("%s: Trying to load firmware to a running NIC.\n",
148862306a36Sopenharmony_ci		       dev->name);
148962306a36Sopenharmony_ci		return -EBUSY;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	localctrl = readl(&regs->LocalCtrl);
149362306a36Sopenharmony_ci	writel(0, &regs->LocalCtrl);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	writel(0, &regs->EvtPrd);
149662306a36Sopenharmony_ci	writel(0, &regs->RxPrd);
149762306a36Sopenharmony_ci	writel(0, &regs->TxPrd);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	/*
150062306a36Sopenharmony_ci	 * First wipe the entire SRAM, otherwise we might run into all
150162306a36Sopenharmony_ci	 * kinds of trouble ... sigh, this took almost all afternoon
150262306a36Sopenharmony_ci	 * to track down ;-(
150362306a36Sopenharmony_ci	 */
150462306a36Sopenharmony_ci	io = readl(&regs->ExtIo);
150562306a36Sopenharmony_ci	writel(0, &regs->ExtIo);
150662306a36Sopenharmony_ci	sram_size = rr_read_eeprom_word(rrpriv, 8);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	for (i = 200; i < sram_size / 4; i++){
150962306a36Sopenharmony_ci		writel(i * 4, &regs->WinBase);
151062306a36Sopenharmony_ci		mb();
151162306a36Sopenharmony_ci		writel(0, &regs->WinData);
151262306a36Sopenharmony_ci		mb();
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci	writel(io, &regs->ExtIo);
151562306a36Sopenharmony_ci	mb();
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	eptr = rr_read_eeprom_word(rrpriv,
151862306a36Sopenharmony_ci		       offsetof(struct eeprom, rncd_info.AddrRunCodeSegs));
151962306a36Sopenharmony_ci	eptr = ((eptr & 0x1fffff) >> 3);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	p2len = rr_read_eeprom_word(rrpriv, 0x83*4);
152262306a36Sopenharmony_ci	p2len = (p2len << 2);
152362306a36Sopenharmony_ci	p2size = rr_read_eeprom_word(rrpriv, 0x84*4);
152462306a36Sopenharmony_ci	p2size = ((p2size & 0x1fffff) >> 3);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	if ((eptr < p2size) || (eptr > (p2size + p2len))){
152762306a36Sopenharmony_ci		printk("%s: eptr is invalid\n", dev->name);
152862306a36Sopenharmony_ci		goto out;
152962306a36Sopenharmony_ci	}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	revision = rr_read_eeprom_word(rrpriv,
153262306a36Sopenharmony_ci			offsetof(struct eeprom, manf.HeaderFmt));
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (revision != 1){
153562306a36Sopenharmony_ci		printk("%s: invalid firmware format (%i)\n",
153662306a36Sopenharmony_ci		       dev->name, revision);
153762306a36Sopenharmony_ci		goto out;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	nr_seg = rr_read_eeprom_word(rrpriv, eptr);
154162306a36Sopenharmony_ci	eptr +=4;
154262306a36Sopenharmony_ci#if (DEBUG > 1)
154362306a36Sopenharmony_ci	printk("%s: nr_seg %i\n", dev->name, nr_seg);
154462306a36Sopenharmony_ci#endif
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	for (i = 0; i < nr_seg; i++){
154762306a36Sopenharmony_ci		sptr = rr_read_eeprom_word(rrpriv, eptr);
154862306a36Sopenharmony_ci		eptr += 4;
154962306a36Sopenharmony_ci		len = rr_read_eeprom_word(rrpriv, eptr);
155062306a36Sopenharmony_ci		eptr += 4;
155162306a36Sopenharmony_ci		segptr = rr_read_eeprom_word(rrpriv, eptr);
155262306a36Sopenharmony_ci		segptr = ((segptr & 0x1fffff) >> 3);
155362306a36Sopenharmony_ci		eptr += 4;
155462306a36Sopenharmony_ci#if (DEBUG > 1)
155562306a36Sopenharmony_ci		printk("%s: segment %i, sram address %06x, length %04x, segptr %06x\n",
155662306a36Sopenharmony_ci		       dev->name, i, sptr, len, segptr);
155762306a36Sopenharmony_ci#endif
155862306a36Sopenharmony_ci		for (j = 0; j < len; j++){
155962306a36Sopenharmony_ci			tmp = rr_read_eeprom_word(rrpriv, segptr);
156062306a36Sopenharmony_ci			writel(sptr, &regs->WinBase);
156162306a36Sopenharmony_ci			mb();
156262306a36Sopenharmony_ci			writel(tmp, &regs->WinData);
156362306a36Sopenharmony_ci			mb();
156462306a36Sopenharmony_ci			segptr += 4;
156562306a36Sopenharmony_ci			sptr += 4;
156662306a36Sopenharmony_ci		}
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ciout:
157062306a36Sopenharmony_ci	writel(localctrl, &regs->LocalCtrl);
157162306a36Sopenharmony_ci	mb();
157262306a36Sopenharmony_ci	return 0;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic int rr_siocdevprivate(struct net_device *dev, struct ifreq *rq,
157762306a36Sopenharmony_ci			     void __user *data, int cmd)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	struct rr_private *rrpriv;
158062306a36Sopenharmony_ci	unsigned char *image, *oldimage;
158162306a36Sopenharmony_ci	unsigned long flags;
158262306a36Sopenharmony_ci	unsigned int i;
158362306a36Sopenharmony_ci	int error = -EOPNOTSUPP;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	rrpriv = netdev_priv(dev);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	switch(cmd){
158862306a36Sopenharmony_ci	case SIOCRRGFW:
158962306a36Sopenharmony_ci		if (!capable(CAP_SYS_RAWIO)){
159062306a36Sopenharmony_ci			return -EPERM;
159162306a36Sopenharmony_ci		}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci		image = kmalloc_array(EEPROM_WORDS, sizeof(u32), GFP_KERNEL);
159462306a36Sopenharmony_ci		if (!image)
159562306a36Sopenharmony_ci			return -ENOMEM;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci		if (rrpriv->fw_running){
159862306a36Sopenharmony_ci			printk("%s: Firmware already running\n", dev->name);
159962306a36Sopenharmony_ci			error = -EPERM;
160062306a36Sopenharmony_ci			goto gf_out;
160162306a36Sopenharmony_ci		}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		spin_lock_irqsave(&rrpriv->lock, flags);
160462306a36Sopenharmony_ci		i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
160562306a36Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
160662306a36Sopenharmony_ci		if (i != EEPROM_BYTES){
160762306a36Sopenharmony_ci			printk(KERN_ERR "%s: Error reading EEPROM\n",
160862306a36Sopenharmony_ci			       dev->name);
160962306a36Sopenharmony_ci			error = -EFAULT;
161062306a36Sopenharmony_ci			goto gf_out;
161162306a36Sopenharmony_ci		}
161262306a36Sopenharmony_ci		error = copy_to_user(data, image, EEPROM_BYTES);
161362306a36Sopenharmony_ci		if (error)
161462306a36Sopenharmony_ci			error = -EFAULT;
161562306a36Sopenharmony_ci	gf_out:
161662306a36Sopenharmony_ci		kfree(image);
161762306a36Sopenharmony_ci		return error;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	case SIOCRRPFW:
162062306a36Sopenharmony_ci		if (!capable(CAP_SYS_RAWIO)){
162162306a36Sopenharmony_ci			return -EPERM;
162262306a36Sopenharmony_ci		}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci		image = memdup_user(data, EEPROM_BYTES);
162562306a36Sopenharmony_ci		if (IS_ERR(image))
162662306a36Sopenharmony_ci			return PTR_ERR(image);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		oldimage = kmalloc(EEPROM_BYTES, GFP_KERNEL);
162962306a36Sopenharmony_ci		if (!oldimage) {
163062306a36Sopenharmony_ci			kfree(image);
163162306a36Sopenharmony_ci			return -ENOMEM;
163262306a36Sopenharmony_ci		}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		if (rrpriv->fw_running){
163562306a36Sopenharmony_ci			printk("%s: Firmware already running\n", dev->name);
163662306a36Sopenharmony_ci			error = -EPERM;
163762306a36Sopenharmony_ci			goto wf_out;
163862306a36Sopenharmony_ci		}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci		printk("%s: Updating EEPROM firmware\n", dev->name);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		spin_lock_irqsave(&rrpriv->lock, flags);
164362306a36Sopenharmony_ci		error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES);
164462306a36Sopenharmony_ci		if (error)
164562306a36Sopenharmony_ci			printk(KERN_ERR "%s: Error writing EEPROM\n",
164662306a36Sopenharmony_ci			       dev->name);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
164962306a36Sopenharmony_ci		spin_unlock_irqrestore(&rrpriv->lock, flags);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		if (i != EEPROM_BYTES)
165262306a36Sopenharmony_ci			printk(KERN_ERR "%s: Error reading back EEPROM "
165362306a36Sopenharmony_ci			       "image\n", dev->name);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		error = memcmp(image, oldimage, EEPROM_BYTES);
165662306a36Sopenharmony_ci		if (error){
165762306a36Sopenharmony_ci			printk(KERN_ERR "%s: Error verifying EEPROM image\n",
165862306a36Sopenharmony_ci			       dev->name);
165962306a36Sopenharmony_ci			error = -EFAULT;
166062306a36Sopenharmony_ci		}
166162306a36Sopenharmony_ci	wf_out:
166262306a36Sopenharmony_ci		kfree(oldimage);
166362306a36Sopenharmony_ci		kfree(image);
166462306a36Sopenharmony_ci		return error;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	case SIOCRRID:
166762306a36Sopenharmony_ci		return put_user(0x52523032, (int __user *)data);
166862306a36Sopenharmony_ci	default:
166962306a36Sopenharmony_ci		return error;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic const struct pci_device_id rr_pci_tbl[] = {
167462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
167562306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, },
167662306a36Sopenharmony_ci	{ 0,}
167762306a36Sopenharmony_ci};
167862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rr_pci_tbl);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic struct pci_driver rr_driver = {
168162306a36Sopenharmony_ci	.name		= "rrunner",
168262306a36Sopenharmony_ci	.id_table	= rr_pci_tbl,
168362306a36Sopenharmony_ci	.probe		= rr_init_one,
168462306a36Sopenharmony_ci	.remove		= rr_remove_one,
168562306a36Sopenharmony_ci};
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_cimodule_pci_driver(rr_driver);
1688