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(®s->HostCtrl) & NIC_HALTED){ 26362306a36Sopenharmony_ci printk("issuing command for halted NIC, code 0x%x, " 26462306a36Sopenharmony_ci "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); 26562306a36Sopenharmony_ci if (readl(®s->Mode) & FATAL_ERR) 26662306a36Sopenharmony_ci printk("error codes Fail1 %02x, Fail2 %02x\n", 26762306a36Sopenharmony_ci readl(®s->Fail1), readl(®s->Fail2)); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci idx = rrpriv->info->cmd_ctrl.pi; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci writel(*(u32*)(cmd), ®s->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(®s->Mode) & FATAL_ERR) 28062306a36Sopenharmony_ci printk("error code %02x\n", readl(®s->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, ®s->TX_state); 30162306a36Sopenharmony_ci writel(0xff800000, ®s->RX_state); 30262306a36Sopenharmony_ci writel(0, ®s->AssistState); 30362306a36Sopenharmony_ci writel(CLEAR_INTA, ®s->LocalCtrl); 30462306a36Sopenharmony_ci writel(0x01, ®s->BrkPt); 30562306a36Sopenharmony_ci writel(0, ®s->Timer); 30662306a36Sopenharmony_ci writel(0, ®s->TimerRef); 30762306a36Sopenharmony_ci writel(RESET_DMA, ®s->DmaReadState); 30862306a36Sopenharmony_ci writel(RESET_DMA, ®s->DmaWriteState); 30962306a36Sopenharmony_ci writel(0, ®s->DmaWriteHostHi); 31062306a36Sopenharmony_ci writel(0, ®s->DmaWriteHostLo); 31162306a36Sopenharmony_ci writel(0, ®s->DmaReadHostHi); 31262306a36Sopenharmony_ci writel(0, ®s->DmaReadHostLo); 31362306a36Sopenharmony_ci writel(0, ®s->DmaReadLen); 31462306a36Sopenharmony_ci writel(0, ®s->DmaWriteLen); 31562306a36Sopenharmony_ci writel(0, ®s->DmaWriteLcl); 31662306a36Sopenharmony_ci writel(0, ®s->DmaWriteIPchecksum); 31762306a36Sopenharmony_ci writel(0, ®s->DmaReadLcl); 31862306a36Sopenharmony_ci writel(0, ®s->DmaReadIPchecksum); 31962306a36Sopenharmony_ci writel(0, ®s->PciState); 32062306a36Sopenharmony_ci#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN 32162306a36Sopenharmony_ci writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); 32262306a36Sopenharmony_ci#elif (BITS_PER_LONG == 64) 32362306a36Sopenharmony_ci writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); 32462306a36Sopenharmony_ci#else 32562306a36Sopenharmony_ci writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->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, ®s->RxBase); 33362306a36Sopenharmony_ci writel(0xdf000, ®s->RxPrd); 33462306a36Sopenharmony_ci writel(0xdf000, ®s->RxCon); 33562306a36Sopenharmony_ci writel(0xce000, ®s->TxBase); 33662306a36Sopenharmony_ci writel(0xce000, ®s->TxPrd); 33762306a36Sopenharmony_ci writel(0xce000, ®s->TxCon); 33862306a36Sopenharmony_ci writel(0, ®s->RxIndPro); 33962306a36Sopenharmony_ci writel(0, ®s->RxIndCon); 34062306a36Sopenharmony_ci writel(0, ®s->RxIndRef); 34162306a36Sopenharmony_ci writel(0, ®s->TxIndPro); 34262306a36Sopenharmony_ci writel(0, ®s->TxIndCon); 34362306a36Sopenharmony_ci writel(0, ®s->TxIndRef); 34462306a36Sopenharmony_ci writel(0xcc000, ®s->pad10[0]); 34562306a36Sopenharmony_ci writel(0, ®s->DrCmndPro); 34662306a36Sopenharmony_ci writel(0, ®s->DrCmndCon); 34762306a36Sopenharmony_ci writel(0, ®s->DwCmndPro); 34862306a36Sopenharmony_ci writel(0, ®s->DwCmndCon); 34962306a36Sopenharmony_ci writel(0, ®s->DwCmndRef); 35062306a36Sopenharmony_ci writel(0, ®s->DrDataPro); 35162306a36Sopenharmony_ci writel(0, ®s->DrDataCon); 35262306a36Sopenharmony_ci writel(0, ®s->DrDataRef); 35362306a36Sopenharmony_ci writel(0, ®s->DwDataPro); 35462306a36Sopenharmony_ci writel(0, ®s->DwDataCon); 35562306a36Sopenharmony_ci writel(0, ®s->DwDataRef); 35662306a36Sopenharmony_ci#endif 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci writel(0xffffffff, ®s->MbEvent); 35962306a36Sopenharmony_ci writel(0, ®s->Event); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci writel(0, ®s->TxPi); 36262306a36Sopenharmony_ci writel(0, ®s->IpRxPi); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci writel(0, ®s->EvtCon); 36562306a36Sopenharmony_ci writel(0, ®s->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, ®s->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, ®s->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, ®s->Pc); 38762306a36Sopenharmony_ci wmb(); 38862306a36Sopenharmony_ci udelay(5); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci writel(start_pc, ®s->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(®s->ExtIo); 40962306a36Sopenharmony_ci writel(0, ®s->ExtIo); 41062306a36Sopenharmony_ci misc = readl(®s->LocalCtrl); 41162306a36Sopenharmony_ci writel(0, ®s->LocalCtrl); 41262306a36Sopenharmony_ci host = readl(®s->HostCtrl); 41362306a36Sopenharmony_ci writel(host | HALT_NIC, ®s->HostCtrl); 41462306a36Sopenharmony_ci mb(); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for (i = 0; i < length; i++){ 41762306a36Sopenharmony_ci writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); 41862306a36Sopenharmony_ci mb(); 41962306a36Sopenharmony_ci buf[i] = (readl(®s->WinData) >> 24) & 0xff; 42062306a36Sopenharmony_ci mb(); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci writel(host, ®s->HostCtrl); 42462306a36Sopenharmony_ci writel(misc, ®s->LocalCtrl); 42562306a36Sopenharmony_ci writel(io, ®s->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(®s->ExtIo); 46162306a36Sopenharmony_ci writel(0, ®s->ExtIo); 46262306a36Sopenharmony_ci misc = readl(®s->LocalCtrl); 46362306a36Sopenharmony_ci writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); 46462306a36Sopenharmony_ci mb(); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci for (i = 0; i < length; i++){ 46762306a36Sopenharmony_ci writel((EEPROM_BASE + ((offset+i) << 3)), ®s->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(®s->WinData) & 0xff000000) != data){ 47562306a36Sopenharmony_ci writel(data, ®s->WinData); 47662306a36Sopenharmony_ci ready = 0; 47762306a36Sopenharmony_ci j = 0; 47862306a36Sopenharmony_ci mb(); 47962306a36Sopenharmony_ci while(!ready){ 48062306a36Sopenharmony_ci udelay(20); 48162306a36Sopenharmony_ci if ((readl(®s->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(®s->WinData)); 48962306a36Sopenharmony_ci ready = 1; 49062306a36Sopenharmony_ci error = 1; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci writel(misc, ®s->LocalCtrl); 49762306a36Sopenharmony_ci writel(io, ®s->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(®s->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(®s->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(®s->HostCtrl); 57362306a36Sopenharmony_ci writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->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, ®s->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, ®s->ConRetry); 62762306a36Sopenharmony_ci writel(0x100, ®s->ConRetryTmr); 62862306a36Sopenharmony_ci writel(0x500000, ®s->ConTmout); 62962306a36Sopenharmony_ci writel(0x60, ®s->IntrTmr); 63062306a36Sopenharmony_ci writel(0x500000, ®s->TxDataMvTimeout); 63162306a36Sopenharmony_ci writel(0x200000, ®s->RxDataMvTimeout); 63262306a36Sopenharmony_ci writel(0x80, ®s->WriteDmaThresh); 63362306a36Sopenharmony_ci writel(0x80, ®s->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, ®s->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(®s->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, ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 76562306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 77262306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 79662306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 80862306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 81562306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 82262306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 82962306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 88362306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 89062306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 89762306a36Sopenharmony_ci ®s->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, ®s->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(®s->HostCtrl) & RR_INT)) 103562306a36Sopenharmony_ci return IRQ_NONE; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci spin_lock(&rrpriv->lock); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci prodidx = readl(®s->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, ®s->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(®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, 117462306a36Sopenharmony_ci ®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); 122162306a36Sopenharmony_ci readl(®s->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(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->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(®s->RxPrd), readl(®s->TxPrd), 128162306a36Sopenharmony_ci readl(®s->EvtPrd), readl(®s->TxPi), 128262306a36Sopenharmony_ci rrpriv->info->tx_ctrl.pi); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci printk("Error code 0x%x\n", readl(®s->Fail1)); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci index = (((readl(®s->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(®s->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, ®s->HostCtrl); 135462306a36Sopenharmony_ci readl(®s->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, ®s->TxPi); 136462306a36Sopenharmony_ci writel(0, ®s->IpRxPi); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci writel(0, ®s->EvtCon); 136762306a36Sopenharmony_ci writel(0, ®s->EvtPrd); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci for (i = 0; i < CMD_RING_ENTRIES; i++) 137062306a36Sopenharmony_ci writel(0, ®s->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(®s->Mode) & FATAL_ERR) 140862306a36Sopenharmony_ci printk("error codes Fail1 %02x, Fail2 %02x\n", 140962306a36Sopenharmony_ci readl(®s->Fail1), readl(®s->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, ®s->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(®s->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(®s->LocalCtrl); 149362306a36Sopenharmony_ci writel(0, ®s->LocalCtrl); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci writel(0, ®s->EvtPrd); 149662306a36Sopenharmony_ci writel(0, ®s->RxPrd); 149762306a36Sopenharmony_ci writel(0, ®s->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(®s->ExtIo); 150562306a36Sopenharmony_ci writel(0, ®s->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, ®s->WinBase); 151062306a36Sopenharmony_ci mb(); 151162306a36Sopenharmony_ci writel(0, ®s->WinData); 151262306a36Sopenharmony_ci mb(); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci writel(io, ®s->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, ®s->WinBase); 156162306a36Sopenharmony_ci mb(); 156262306a36Sopenharmony_ci writel(tmp, ®s->WinData); 156362306a36Sopenharmony_ci mb(); 156462306a36Sopenharmony_ci segptr += 4; 156562306a36Sopenharmony_ci sptr += 4; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ciout: 157062306a36Sopenharmony_ci writel(localctrl, ®s->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