/* ** ** RCpci45.c ** ** ** ** --------------------------------------------------------------------- ** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. --- ** --- All rights reserved. --- ** --------------------------------------------------------------------- ** ** Written by Pete Popov and Brian Moyle. ** ** Known Problems ** ** None known at this time. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Rasmus Andersen, December 2000: Converted to new PCI API and general ** cleanup. ** ** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems ** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and ** added a #define(s) to enable the use of the same file for both, the 2.0.x ** kernels as well as the 2.1.x. ** ** Ported to 2.1.x by Alan Cox 1998/12/9. ** ** Sometime in mid 1998, written by Pete Popov and Brian Moyle. ** ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For NR_IRQS only. */ #include #include static char version[] __initdata = "RedCreek Communications PCI linux driver version 2.03\n"; #define RC_LINUX_MODULE #include "rclanmtl.h" #include "rcif.h" #define RUN_AT(x) (jiffies + (x)) #define NEW_MULTICAST /* PCI/45 Configuration space values */ #define RC_PCI45_VENDOR_ID 0x4916 #define RC_PCI45_DEVICE_ID 0x1960 #define MAX_ETHER_SIZE 1520 #define MAX_NMBR_RCV_BUFFERS 96 #define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16 #define BD_SIZE 3 /* Bucket Descriptor size */ #define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */ /* RedCreek LAN device Target ID */ #define RC_LAN_TARGET_ID 0x10 /* RedCreek's OSM default LAN receive Initiator */ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 static U32 DriverControlWord; static void rc_timer (unsigned long); static int RCinit (struct net_device *); static int RCopen (struct net_device *); static int RC_xmit_packet (struct sk_buff *, struct net_device *); static void RCinterrupt (int, void *, struct pt_regs *); static int RCclose (struct net_device *dev); static struct net_device_stats *RCget_stats (struct net_device *); static int RCioctl (struct net_device *, struct ifreq *, int); static int RCconfig (struct net_device *, struct ifmap *); static void RCxmit_callback (U32, U16, PU32, struct net_device *); static void RCrecv_callback (U32, U8, U32, PU32, struct net_device *); static void RCreset_callback (U32, U32, U32, struct net_device *); static void RCreboot_callback (U32, U32, U32, struct net_device *); static int RC_allocate_and_post_buffers (struct net_device *, int); static struct pci_device_id rcpci45_pci_table[] __devinitdata = { {RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {} }; MODULE_DEVICE_TABLE (pci, rcpci45_pci_table); MODULE_LICENSE("GPL"); static void __exit rcpci45_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); PDPA pDpa = dev->priv; if (!dev) { printk (KERN_ERR "(rcpci45 driver:) remove non-existent device\n"); return; } dprintk ("remove_one: IOP reset: 0x%x\n", RCResetIOP (dev)); /* RAA Inspired by starfire.c and yellowfin.c we keep these * here. */ unregister_netdev (dev); free_irq (dev->irq, dev); iounmap ((void *) dev->base_addr); pci_release_regions (pdev); kfree (pDpa->PLanApiPA); kfree (pDpa->pPab); kfree (pDpa); kfree (dev); pci_set_drvdata (pdev, NULL); } static int RCinit (struct net_device *dev) { dev->open = &RCopen; dev->hard_start_xmit = &RC_xmit_packet; dev->stop = &RCclose; dev->get_stats = &RCget_stats; dev->do_ioctl = &RCioctl; dev->set_config = &RCconfig; return 0; } static int rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long *vaddr; PDPA pDpa; int error; static int card_idx = -1; struct net_device *dev; unsigned long pci_start, pci_len; card_idx++; /* * Allocate and fill new device structure. * We need enough for struct net_device plus DPA plus the LAN API private * area, which requires a minimum of 16KB. The top of the allocated * area will be assigned to struct net_device; the next chunk will be * assigned to DPA; and finally, the rest will be assigned to the * the LAN API layer. */ dev = init_etherdev (NULL, sizeof (*pDpa)); if (!dev) { printk (KERN_ERR "(rcpci45 driver:) unable to allocate in init_etherdev\n"); error = -ENOMEM; goto err_out; } error = pci_enable_device (pdev); if (error) { printk (KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n", card_idx); goto err_out; } error = -ENOMEM; pci_start = pci_resource_start (pdev, 0); pci_len = pci_resource_len (pdev, 0); pci_set_drvdata (pdev, dev); pDpa = dev->priv; pDpa->id = card_idx; pDpa->pci_addr = pci_start; if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { printk (KERN_ERR "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); error = -EBUSY; goto err_out_free_dev; } /* * Save the starting address of the LAN API private area. We'll * pass that to RCInitI2OMsgLayer(). */ /* RAA FIXME: This size should be a #define somewhere after I * clear up some questions: What flags are neeeded in the alloc below * and what needs to be done before the memarea is long word aligned? * (Look in old code for an approach.) (Also note that the 16K below * is substantially less than the 32K allocated before (even though * some of the spacce was used for data structures.) */ pDpa->msgbuf = kmalloc (16384, GFP_KERNEL); if (!pDpa->msgbuf) { printk (KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ goto err_out_free_dev; } pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA); /* The adapter is accessible through memory-access read/write, not * I/O read/write. Thus, we need to map it to some virtual address * area in order to access the registers as normal memory. */ error = pci_request_regions (pdev, dev->name); if (error) goto err_out_free_msgbuf; vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk (KERN_ERR "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", pci_start, pci_start + pci_len); goto err_out_free_region; } dprintk ("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", (uint) dev, (uint) dev->priv, (uint) vaddr); dev->base_addr = (unsigned long) vaddr; dev->irq = pdev->irq; dev->init = &RCinit; return 0; /* success */ err_out_free_region: pci_release_regions (pdev); err_out_free_msgbuf: kfree (pDpa->msgbuf); err_out_free_dev: unregister_netdev (dev); kfree (dev); err_out: card_idx--; return error; } static struct pci_driver rcpci45_driver = { name: "rcpci45", id_table: rcpci45_pci_table, probe: rcpci45_init_one, remove: rcpci45_remove_one, }; static int __init rcpci_init_module (void) { int rc = pci_module_init (&rcpci45_driver); if (!rc) printk (KERN_INFO "%s", version); return rc; } static int RCopen (struct net_device *dev) { int post_buffers = MAX_NMBR_RCV_BUFFERS; PDPA pDpa = dev->priv; int count = 0; int requested = 0; int error; dprintk ("(rcpci45 driver:) RCopen\n"); /* Request a shared interrupt line. */ error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); if (error) { printk (KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", dev->name, dev->irq); goto err_out; } error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, (PFNRXCALLBACK) RCrecv_callback, (PFNCALLBACK) RCreboot_callback); if (error) { printk (KERN_ERR "(rcpci45 driver:) Unable to initialize msg layer\n"); goto err_out_free_irq; } if ((error = RCGetMAC (dev, NULL))) { printk (KERN_ERR "(rcpci45 driver:) Unable to get adapter MAC\n"); goto err_out_free_irq; } DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability (dev, DriverControlWord); printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); /* RAA: Old RCopen starts here */ RCEnableI2OInterrupts (dev); /* RAA Hmm, how does the comment below jibe with the newly imported * code above? A FIXME!!*/ if (pDpa->nexus) { /* This is not the first time RCopen is called. Thus, * the interface was previously opened and later closed * by RCclose(). RCclose() does a Shutdown; to wake up * the adapter, a reset is mandatory before we can post * receive buffers. However, if the adapter initiated * a reboot while the interface was closed -- and interrupts * were turned off -- we need will need to reinitialize * the adapter, rather than simply waking it up. */ dprintk (KERN_INFO "Waking up adapter...\n"); RCResetLANCard (dev, 0, 0, 0); } else pDpa->nexus = 1; while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; else requested = post_buffers; count = RC_allocate_and_post_buffers (dev, requested); if (count < requested) { /* * Check to see if we were able to post any buffers at all. */ if (post_buffers == MAX_NMBR_RCV_BUFFERS) { printk (KERN_ERR "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); return (-ENOMEM); } printk (KERN_WARNING "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); break; /* we'll try to post more buffers later */ } else post_buffers -= count; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; pDpa->shutdown = 0; /* just in case */ dprintk ("RCopen: posted %d buffers\n", (uint) pDpa->numOutRcvBuffers); MOD_INC_USE_COUNT; netif_start_queue (dev); return 0; err_out_free_irq: free_irq (dev->irq, dev); err_out: return error; } static int RC_xmit_packet (struct sk_buff *skb, struct net_device *dev) { PDPA pDpa = dev->priv; singleTCB tcb; psingleTCB ptcb = &tcb; RC_RETURN status = 0; netif_stop_queue (dev); if (pDpa->shutdown || pDpa->reboot) { dprintk ("RC_xmit_packet: tbusy!\n"); return 1; } /* * The user is free to reuse the TCB after RCI2OSendPacket() returns, since * the function copies the necessary info into its own private space. Thus, * our TCB can be a local structure. The skb, on the other hand, will be * freed up in our interrupt handler. */ ptcb->bcount = 1; /* * we'll get the context when the adapter interrupts us to tell us that * the transmission is done. At that time, we can free skb. */ ptcb->b.context = (U32) skb; ptcb->b.scount = 1; ptcb->b.size = skb->len; ptcb->b.addr = virt_to_bus ((void *) skb->data); dprintk ("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", (uint) skb, (uint) pDpa, (uint) pDpa->id, (uint) ptcb); if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) != RC_RTN_NO_ERROR) { dprintk ("RC send error 0x%x\n", (uint) status); return 1; } else { dev->trans_start = jiffies; netif_wake_queue (dev); } /* * That's it! */ return 0; } /* * RCxmit_callback() * * The transmit callback routine. It's called by RCProcI2OMsgQ() * because the adapter is done with one or more transmit buffers and * it's returning them to us, or we asked the adapter to return the * outstanding transmit buffers by calling RCResetLANCard() with * RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag. * All we need to do is free the buffers. */ static void RCxmit_callback (U32 Status, U16 PcktCount, PU32 BufferContext, struct net_device *dev) { struct sk_buff *skb; PDPA pDpa = dev->priv; if (!pDpa) { printk (KERN_ERR "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); return; } /* dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); */ if (Status != I2O_REPLY_STATUS_SUCCESS) dprintk ("xmit_callback: Status = 0x%x\n", (uint) Status); if (pDpa->shutdown || pDpa->reboot) dprintk ("xmit callback: shutdown||reboot\n"); dprintk ("xmit_callback: PcktCount = %d, BC = 0x%x\n", (uint) PcktCount, (uint) BufferContext); while (PcktCount--) { skb = (struct sk_buff *) (BufferContext[0]); dprintk ("skb = 0x%x\n", (uint) skb); BufferContext++; dev_kfree_skb_irq (skb); } netif_wake_queue (dev); } static void RCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) { PDPA pDpa = dev->priv; dprintk ("RCreset_callback Status 0x%x\n", (uint) Status); /* * Check to see why we were called. */ if (pDpa->shutdown) { printk (KERN_INFO "(rcpci45 driver:) Shutting down interface\n"); pDpa->shutdown = 0; pDpa->reboot = 0; MOD_DEC_USE_COUNT; } else if (pDpa->reboot) { printk (KERN_INFO "(rcpci45 driver:) reboot, shutdown adapter\n"); /* * We don't set any of the flags in RCShutdownLANCard() * and we don't pass a callback routine to it. * The adapter will have already initiated the reboot by * the time the function returns. */ RCDisableI2OInterrupts (dev); RCShutdownLANCard (dev, 0, 0, 0); printk (KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ pDpa->timer.data = (unsigned long) dev; pDpa->timer.function = &rc_timer; /* timer handler */ add_timer (&pDpa->timer); } } static void RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) { PDPA pDpa = dev->priv; dprintk ("RCreboot: rcv buffers outstanding = %d\n", (uint) pDpa->numOutRcvBuffers); if (pDpa->shutdown) { printk (KERN_INFO "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); return; } pDpa->reboot = 1; /* * OK, we reset the adapter and ask it to return all * outstanding transmit buffers as well as the posted * receive buffers. When the adapter is done returning * those buffers, it will call our RCreset_callback() * routine. In that routine, we'll call RCShutdownLANCard() * to tell the adapter that it's OK to start the reboot and * schedule a timer callback routine to execute 3 seconds * later; this routine will reinitialize the adapter at that time. */ RCResetLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, (PFNCALLBACK) RCreset_callback); } int broadcast_packet (unsigned char *address) { int i; for (i = 0; i < 6; i++) if (address[i] != 0xff) return 0; return 1; } /* * RCrecv_callback() * * The receive packet callback routine. This is called by * RCProcI2OMsgQ() after the adapter posts buffers which have been * filled (one ethernet packet per buffer). */ static void RCrecv_callback (U32 Status, U8 PktCount, U32 BucketsRemain, PU32 PacketDescBlock, struct net_device *dev) { U32 len, count; PDPA pDpa = dev->priv; struct sk_buff *skb; singleTCB tcb; psingleTCB ptcb = &tcb; ptcb->bcount = 1; dprintk ("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", (uint) PktCount, (uint) BucketsRemain, (uint) PacketDescBlock); if ((pDpa->shutdown || pDpa->reboot) && !Status) dprintk ("shutdown||reboot && !Status: PktCount = %d\n", PktCount); if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { /* * Free whatever buffers the adapter returned, but don't * pass them to the kernel. */ if (!pDpa->shutdown && !pDpa->reboot) printk (KERN_INFO "(rcpci45 driver:) RCrecv error: status = 0x%x\n", (uint) Status); else dprintk ("Returning %d buffers, status = 0x%x\n", PktCount, (uint) Status); /* * TO DO: check the nature of the failure and put the adapter in * failed mode if it's a hard failure. Send a reset to the adapter * and free all outstanding memory. */ if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) dprintk ("RCrecv status ABORT NO DATA TRANSFER\n"); /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ if (PacketDescBlock) { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; dprintk ("free skb 0x%p\n", skb); dev_kfree_skb (skb); pDpa->numOutRcvBuffers--; PacketDescBlock += BD_SIZE; /* point to next context field */ } } return; } else { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; if (pDpa->shutdown) dprintk ("shutdown: skb=0x%x\n", (uint) skb); dprintk ("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint) skb, (uint) skb->data[0], (uint) skb->data[1], (uint) skb->data[2], (uint) skb->data[3], (uint) skb->data[4], (uint) skb->data[5]); #ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ if ((memcmp (dev->dev_addr, skb->data, 6)) && (!broadcast_packet (skb->data))) { /* * Re-post the buffer to the adapter. Since the adapter usually * return 1 to 2 receive buffers at a time, it's not too inefficient * post one buffer at a time but ... may be that should be * optimized at some point. */ ptcb->b.context = (U32) skb; ptcb->b.scount = 1; ptcb->b.size = MAX_ETHER_SIZE; ptcb->b.addr = virt_to_bus ((void *) skb->data); if (RCPostRecvBuffers (dev, (PRCTCB) ptcb) != RC_RTN_NO_ERROR) { printk (KERN_WARNING "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); dev_kfree_skb (skb); } else pDpa->numOutRcvBuffers++; } else #endif /* PROMISCUOUS_BY_DEFAULT */ { len = PacketDescBlock[2]; skb->dev = dev; skb_put (skb, len); /* adjust length and tail */ skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); /* send the packet to the kernel */ dev->last_rx = jiffies; } pDpa->numOutRcvBuffers--; PacketDescBlock += BD_SIZE; /* point to next context field */ } } /* * Replenish the posted receive buffers. * DO NOT replenish buffers if the driver has already * initiated a reboot or shutdown! */ if (!pDpa->shutdown && !pDpa->reboot) { count = RC_allocate_and_post_buffers (dev, MAX_NMBR_RCV_BUFFERS - pDpa->numOutRcvBuffers); pDpa->numOutRcvBuffers += count; } } /* * RCinterrupt() * * Interrupt handler. * This routine sets up a couple of pointers and calls * RCProcI2OMsgQ(), which in turn process the message and * calls one of our callback functions. */ static void RCinterrupt (int irq, void *dev_id, struct pt_regs *regs) { PDPA pDpa; struct net_device *dev = dev_id; pDpa = dev->priv; if (pDpa->shutdown) dprintk ("shutdown: service irq\n"); dprintk ("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", (uint) pDpa, (uint) dev, (uint) pDpa->id); dprintk ("dev = 0x%x\n", (uint) dev); RCProcI2OMsgQ (dev); } #define REBOOT_REINIT_RETRY_LIMIT 4 static void rc_timer (unsigned long data) { struct net_device *dev = (struct net_device *) data; PDPA pDpa = dev->priv; int init_status; static int retry; int post_buffers = MAX_NMBR_RCV_BUFFERS; int count = 0; int requested = 0; if (pDpa->reboot) { init_status = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, (PFNRXCALLBACK) RCrecv_callback, (PFNCALLBACK) RCreboot_callback); switch (init_status) { case RC_RTN_NO_ERROR: pDpa->reboot = 0; pDpa->shutdown = 0; /* just in case */ RCReportDriverCapability (dev, DriverControlWord); RCEnableI2OInterrupts (dev); if (dev->flags & IFF_UP) { while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; else requested = post_buffers; count = RC_allocate_and_post_buffers (dev, requested); post_buffers -= count; if (count < requested) break; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; dprintk ("rc: posted %d buffers \r\n", (uint) pDpa->numOutRcvBuffers); } dprintk ("Initialization done.\n"); netif_wake_queue (dev); retry = 0; return; case RC_RTN_FREE_Q_EMPTY: retry++; printk (KERN_WARNING "(rcpci45 driver:) inbound free q empty\n"); break; default: retry++; printk (KERN_WARNING "(rcpci45 driver:) bad status after reboot: %d\n", init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { printk (KERN_WARNING "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); printk (KERN_WARNING "(rcpci45 driver:) decrementing driver and closing interface\n"); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { printk (KERN_INFO "(rcpci45 driver:) rescheduling timer...\n"); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 3 sec. */ pDpa->timer.data = (unsigned long) dev; pDpa->timer.function = &rc_timer; /* timer handler */ add_timer (&pDpa->timer); } } else printk (KERN_WARNING "(rcpci45 driver:) timer??\n"); } static int RCclose (struct net_device *dev) { PDPA pDpa = dev->priv; netif_stop_queue (dev); dprintk ("RCclose\r\n"); if (pDpa->reboot) { printk (KERN_INFO "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; return 0; } dprintk ("receive buffers outstanding: %d\n", (uint) pDpa->numOutRcvBuffers); pDpa->shutdown = 1; /* * We can't allow the driver to be unloaded until the adapter returns * all posted receive buffers. It doesn't hurt to tell the adapter * to return all posted receive buffers and outstanding xmit buffers, * even if there are none. */ RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, (PFNCALLBACK) RCreset_callback); dev->flags &= ~IFF_UP; return 0; } static struct net_device_stats * RCget_stats (struct net_device *dev) { RCLINKSTATS RCstats; PDPA pDpa = dev->priv; if (!pDpa) { dprintk ("RCget_stats: !pDpa\n"); return 0; } else if (!(dev->flags & IFF_UP)) { dprintk ("RCget_stats: device down\n"); return 0; } memset (&RCstats, 0, sizeof (RCLINKSTATS)); if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == RC_RTN_NO_ERROR) { dprintk ("TX_good 0x%x\n", (uint) RCstats.TX_good); dprintk ("TX_maxcol 0x%x\n", (uint) RCstats.TX_maxcol); dprintk ("TX_latecol 0x%x\n", (uint) RCstats.TX_latecol); dprintk ("TX_urun 0x%x\n", (uint) RCstats.TX_urun); dprintk ("TX_crs 0x%x\n", (uint) RCstats.TX_crs); dprintk ("TX_def 0x%x\n", (uint) RCstats.TX_def); dprintk ("TX_singlecol 0x%x\n", (uint) RCstats.TX_singlecol); dprintk ("TX_multcol 0x%x\n", (uint) RCstats.TX_multcol); dprintk ("TX_totcol 0x%x\n", (uint) RCstats.TX_totcol); dprintk ("Rcv_good 0x%x\n", (uint) RCstats.Rcv_good); dprintk ("Rcv_CRCerr 0x%x\n", (uint) RCstats.Rcv_CRCerr); dprintk ("Rcv_alignerr 0x%x\n", (uint) RCstats.Rcv_alignerr); dprintk ("Rcv_reserr 0x%x\n", (uint) RCstats.Rcv_reserr); dprintk ("Rcv_orun 0x%x\n", (uint) RCstats.Rcv_orun); dprintk ("Rcv_cdt 0x%x\n", (uint) RCstats.Rcv_cdt); dprintk ("Rcv_runt 0x%x\n", (uint) RCstats.Rcv_runt); pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; /* bad packets received */ pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* packet transmit problems */ /* * This needs improvement. */ pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ pDpa->stats.tx_dropped = 0; /* no space available in linux */ pDpa->stats.multicast = 0; /* multicast packets received */ pDpa->stats.collisions = RCstats.TX_totcol; /* detailed rx_errors: */ pDpa->stats.rx_length_errors = 0; pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ /* detailed tx_errors */ pDpa->stats.tx_aborted_errors = 0; pDpa->stats.tx_carrier_errors = 0; pDpa->stats.tx_fifo_errors = 0; pDpa->stats.tx_heartbeat_errors = 0; pDpa->stats.tx_window_errors = 0; return ((struct net_device_stats *) &(pDpa->stats)); } return 0; } static int RCioctl (struct net_device *dev, struct ifreq *rq, int cmd) { RCuser_struct RCuser; PDPA pDpa = dev->priv; dprintk ("RCioctl: cmd = 0x%x\n", cmd); if (!capable (CAP_NET_ADMIN)) return -EPERM; switch (cmd) { case RCU_PROTOCOL_REV: /* * Assign user protocol revision, to tell user-level * controller program whether or not it's in sync. */ rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV; break; case RCU_COMMAND: { if (copy_from_user (&RCuser, rq->ifr_data, sizeof (RCuser))) return -EFAULT; dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); switch (RCuser.cmd) { case RCUC_GETFWVER: printk (KERN_INFO "(rcpci45 driver:) RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer (dev, (PU8) & RCUD_GETFWVER-> FirmString, NULL); break; case RCUC_GETINFO: printk (KERN_INFO "(rcpci45 driver:) RC GETINFO\n"); RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO->mem_start = dev->base_addr; RCUD_GETINFO->mem_end = dev->base_addr + pDpa->pci_addr_len; RCUD_GETINFO->base_addr = pDpa->pci_addr; RCUD_GETINFO->irq = dev->irq; break; case RCUC_GETIPANDMASK: printk (KERN_INFO "(rcpci45 driver:) RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask (dev, (PU32) & RCUD_GETIPANDMASK->IpAddr, (PU32) & RCUD_GETIPANDMASK-> NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: printk (KERN_INFO "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics (dev, (P_RCLINKSTATS) & RCUD_GETLINKSTATISTICS-> StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: printk (KERN_INFO "(rcpci45 driver:) RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus (dev, (PU32) & RCUD_GETLINKSTATUS-> ReturnStatus, NULL); break; case RCUC_GETMAC: printk (KERN_INFO "(rcpci45 driver:) RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC (dev, NULL); break; case RCUC_GETPROM: printk (KERN_INFO "(rcpci45 driver:) RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode (dev, (PU32) & RCUD_GETPROM-> PromMode, NULL); break; case RCUC_GETBROADCAST: printk (KERN_INFO "(rcpci45 driver:) RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode (dev, (PU32) & RCUD_GETBROADCAST-> BroadcastMode, NULL); break; case RCUC_GETSPEED: printk (KERN_INFO "(rcpci45 driver:) RC GETSPEED\n"); if (!(dev->flags & IFF_UP)) { printk (KERN_ERR "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed (dev, (PU32) & RCUD_GETSPEED-> LinkSpeedCode, NULL); printk (KERN_INFO "(rcpci45 driver:) RC speed = 0x%u\n", RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: printk (KERN_INFO "(rcpci45 driver:) RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; printk (KERN_INFO "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", (U8) ((RCUD_SETIPANDMASK-> IpAddr) & 0xff), (U8) ((RCUD_SETIPANDMASK-> IpAddr >> 8) & 0xff), (U8) ((RCUD_SETIPANDMASK-> IpAddr >> 16) & 0xff), (U8) ((RCUD_SETIPANDMASK-> IpAddr >> 24) & 0xff)); printk (KERN_INFO "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", (U8) ((RCUD_SETIPANDMASK-> NetMask) & 0xff), (U8) ((RCUD_SETIPANDMASK-> NetMask >> 8) & 0xff), (U8) ((RCUD_SETIPANDMASK-> NetMask >> 16) & 0xff), (U8) ((RCUD_SETIPANDMASK-> NetMask >> 24) & 0xff)); RCSetRavlinIPandMask (dev, (U32) RCUD_SETIPANDMASK-> IpAddr, (U32) RCUD_SETIPANDMASK-> NetMask); break; case RCUC_SETMAC: printk (KERN_INFO "(rcpci45 driver:) RC SETMAC\n"); RCUD_SETMAC = &RCuser.RCUS_SETMAC; printk (KERN_INFO "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", (U8) (RCUD_SETMAC->mac[0]), (U8) (RCUD_SETMAC->mac[1]), (U8) (RCUD_SETMAC->mac[2]), (U8) (RCUD_SETMAC->mac[3]), (U8) (RCUD_SETMAC->mac[4]), (U8) (RCUD_SETMAC->mac[5])); RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); break; case RCUC_SETSPEED: printk (KERN_INFO "(rcpci45 driver:) RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed (dev, (U16) RCUD_SETSPEED-> LinkSpeedCode); printk (KERN_INFO "(rcpci45 driver:) RC New speed = 0x%x\n", RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: printk (KERN_INFO "(rcpci45 driver:) RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode (dev, (U16) RCUD_SETPROM-> PromMode); printk (KERN_INFO "(rcpci45 driver:) RC New prom mode = 0x%x\n", RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: printk (KERN_INFO "(rcpci45 driver:) RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode (dev, (U16) RCUD_SETBROADCAST-> BroadcastMode); printk (KERN_INFO "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", RCUD_SETBROADCAST->BroadcastMode); break; default: printk (KERN_INFO "(rcpci45 driver:) RC command default\n"); RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT->rc = 0x11223344; break; } if (copy_to_user (rq->ifr_data, &RCuser, sizeof (RCuser))) return -EFAULT; break; } /* RCU_COMMAND */ default: rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; return -EINVAL; } return 0; } static int RCconfig (struct net_device *dev, struct ifmap *map) { /* * To be completed ... */ dprintk ("RCconfig\n"); return 0; if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { printk (KERN_WARNING "(rcpci45 driver:) Change I/O address not implemented\n"); return -EOPNOTSUPP; } return 0; } static void __exit rcpci_cleanup_module (void) { pci_unregister_driver (&rcpci45_driver); } module_init (rcpci_init_module); module_exit (rcpci_cleanup_module); static int RC_allocate_and_post_buffers (struct net_device *dev, int numBuffers) { int i; PU32 p; psingleB pB; struct sk_buff *skb; RC_RETURN status; U32 res; if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { dprintk ("Too many buffers requested!\n"); dprintk ("attempting to allocate only 32 buffers\n"); numBuffers = 32; } p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), GFP_KERNEL); dprintk ("TCB = 0x%x\n", (uint) p); if (!p) { printk (KERN_WARNING "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); return 0; } p[0] = 0; /* Buffer Count */ pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ dprintk ("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint) p[0], (uint) p, (uint) pB); dprintk ("pB = 0x%x\n", (uint) pB); for (i = 0; i < numBuffers; i++) { skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); if (!skb) { dprintk ("Doh! RCopen: unable to allocate enough skbs!\n"); if (*p != 0) { /* did we allocate any buffers at all? */ dprintk ("will post only %d buffers \n", (uint) (*p)); break; } else { kfree (p); /* Free the TCB */ return 0; } } dprintk ("post 0x%x\n", (uint) skb); skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ pB->context = (U32) skb; pB->scount = 1; /* segment count */ pB->size = MAX_ETHER_SIZE; pB->addr = virt_to_bus ((void *) skb->data); p[0]++; pB++; } if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { printk (KERN_WARNING "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", status); pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ while (p[0]) { skb = (struct sk_buff *) pB->context; dprintk ("freeing 0x%x\n", (uint) skb); dev_kfree_skb (skb); p[0]--; pB++; } dprintk ("freed all buffers, p[0] = %d\n", (uint) p[0]); } res = p[0]; kfree (p); return (res); /* return the number of posted buffers */ }