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