/* ** ** 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. ** ** TODO: ** -Get rid of the wait loops in the API and replace them ** with system independent delays ...something like ** "delayms(2)". However, under normal circumstances, the ** delays are very short so they're not a problem. ** ** 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. ** ** ** 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. ** ***************************************************************************/ static char *version = "RedCreek Communications PCI linux driver version 2.02\n"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For NR_IRQS only. */ #include #include #if LINUX_VERSION_CODE >= 0x020100 #define LINUX_2_1 #endif #ifdef LINUX_2_1 #include #endif #include #include #include #include #define RC_LINUX_MODULE #include "rclanmtl.h" #include "rcif.h" #define RUN_AT(x) (jiffies + (x)) #define NEW_MULTICAST #include #ifndef LINUX_2_1 #define ioremap vremap #define iounmap vfree #endif /* 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 = 0; static void rc_timer(unsigned long); /* * Driver Private Area, DPA. */ typedef struct { /* * pointer to the device structure which is part * of the interface to the Linux kernel. */ struct net_device *dev; char devname[8]; /* "ethN" string */ U8 id; /* the AdapterID */ U32 pci_addr; /* the pci address of the adapter */ U32 bus; U32 function; struct timer_list timer; /* timer */ struct enet_statistics stats; /* the statistics structure */ struct net_device *next; /* points to the next RC adapter */ unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/ unsigned char shutdown; unsigned char reboot; unsigned char nexus; PU8 PLanApiPA; /* Pointer to Lan Api Private Area */ } DPA, *PDPA; #define MAX_ADAPTERS 32 static PDPA PCIAdapters[MAX_ADAPTERS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static int RCinit(struct net_device *dev); static int RCscan(struct net_device *dev); static int RCfound_device(struct net_device *, int, int, int, int, int, int); 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 enet_statistics *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, U16); static void RCrecv_callback(U32, U8, U32, PU32, U16); static void RCreset_callback(U32, U32, U32, U16); static void RCreboot_callback(U32, U32, U32, U16); static int RC_allocate_and_post_buffers(struct net_device *, int); /* A list of all installed RC devices, for removing the driver module. */ static struct net_device *root_RCdev = NULL; #ifdef MODULE int init_module(void) #else int rcpci_probe(struct net_device *dev) #endif { int cards_found; #ifdef MODULE cards_found = RCscan(NULL); #else cards_found = RCscan(dev); #endif if (cards_found) printk(version); return cards_found ? 0 : -ENODEV; } static int RCscan(struct net_device *dev) { int cards_found = 0; static int pci_index = 0; if (!pcibios_present()) return cards_found; for (;pci_index < 0x8; pci_index++) { unsigned char pci_bus, pci_device_fn; int scan_status; int board_index = 0; unsigned char pci_irq_line; unsigned int pci_ioaddr; struct pci_dev *pdev; scan_status = (pcibios_find_device (RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, pci_index, &pci_bus, &pci_device_fn)); #ifdef RCDEBUG printk("rc scan_status = 0x%X\n", scan_status); #endif if (scan_status != PCIBIOS_SUCCESSFUL || !((pdev = pci_find_slot(pci_bus, pci_device_fn)))) break; pci_irq_line = pdev->irq; pci_ioaddr = pdev->resource[0].start; #ifdef RCDEBUG printk("rc: Found RedCreek PCI adapter\n"); printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn); printk("rc: pci_irq_line = 0x%x \n", pci_irq_line); printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr); #endif pci_set_master(pdev); if (!RCfound_device(dev, pci_ioaddr, pci_irq_line, pci_bus, pci_device_fn, board_index++, cards_found)) { dev = 0; cards_found++; } } #ifdef RCDEBUG printk("rc: found %d cards \n", cards_found); #endif return cards_found; } 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 RCfound_device(struct net_device *dev, int memaddr, int irq, int bus, int function, int product_index, int card_idx) { int dev_size = 32768; unsigned long *vaddr=0; PDPA pDpa; int init_status; /* * 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. */ #ifdef MODULE dev = (struct net_device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC); if (!dev) { printk("rc: unable to kmalloc dev\n"); return 1; } memset(dev, 0, dev_size); /* * dev->priv will point to the start of DPA. */ dev->priv = (void *)(((long)dev + sizeof(struct net_device) + 15) & ~15); #else dev->priv = 0; dev->priv = (struct net_device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC); if (!dev->priv) { printk("rc: unable to kmalloc private area\n"); return 1; } memset(dev->priv, 0, dev_size); #endif #ifdef RCDEBUG printk("rc: dev = 0x%x, dev->priv = 0x%x\n", (uint)dev, (uint)dev->priv); #endif pDpa = dev->priv; if (!dev->name) dev->name = pDpa->devname; pDpa->dev = dev; /* this is just for easy reference */ pDpa->function = function; pDpa->bus = bus; pDpa->id = card_idx; /* the device number */ pDpa->pci_addr = memaddr; PCIAdapters[card_idx] = pDpa; #ifdef RCDEBUG printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id); #endif /* * Save the starting address of the LAN API private area. We'll * pass that to RCInitI2OMsgLayer(). */ pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff); #ifdef RCDEBUG printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA); #endif /* The adapter is accessable 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 are normal memory. */ vaddr = (ulong *) ioremap (memaddr, 2*32768); #ifdef RCDEBUG printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n", (uint)dev, (uint)dev->priv, (uint)vaddr); #endif dev->base_addr = (unsigned long)vaddr; dev->irq = irq; dev->interrupt = 0; /* * Request a shared interrupt line. */ if ( request_irq(dev->irq, (void *)RCinterrupt, SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev) ) { printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq ); iounmap(vaddr); kfree(dev); return 1; } init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA), (PFNTXCALLBACK)RCxmit_callback, (PFNRXCALLBACK)RCrecv_callback, (PFNCALLBACK)RCreboot_callback); if (init_status) { printk("rc: Unable to initialize msg layer\n"); free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); return 1; } if (RCGetMAC(pDpa->id, dev->dev_addr, NULL)) { printk("rc: Unable to get adapter MAC\n"); free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); return 1; } DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability(pDpa->id, DriverControlWord); dev->init = &RCinit; ether_setup(dev); /* linux kernel interface */ pDpa->next = root_RCdev; root_RCdev = dev; #ifdef MODULE if (register_netdev(dev) != 0) /* linux kernel interface */ { printk("rc: unable to register device \n"); free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); return 1; } #else RCinit(dev); #endif printk("%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); return 0; /* success */ } static int RCopen(struct net_device *dev) { int post_buffers = MAX_NMBR_RCV_BUFFERS; PDPA pDpa = (PDPA) dev->priv; int count = 0; int requested = 0; #ifdef RCDEBUG printk("rc: RCopen\n"); #endif RCEnableI2OInterrupts(pDpa->id); 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. */ printk("rc: Waking up adapter...\n"); RCResetLANCard(pDpa->id,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("rc: Error RCopen: not able to allocate any buffers\r\n"); return(-ENOMEM); } printk("rc: 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 */ #ifdef RCDEBUG printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers); #endif MOD_INC_USE_COUNT; return 0; } static int RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) { PDPA pDpa = (PDPA) dev->priv; singleTCB tcb; psingleTCB ptcb = &tcb; RC_RETURN status = 0; if (dev->tbusy || pDpa->shutdown || pDpa->reboot) { #ifdef RCDEBUG printk("rc: RC_xmit_packet: tbusy!\n"); #endif dev->tbusy = 1; return 1; } if ( skb->len <= 0 ) { printk("RC_xmit_packet: skb->len less than 0!\n"); return 0; } /* * 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 transmision 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); #ifdef RCDEBUG printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb); #endif if ( (status = RCI2OSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb)) != RC_RTN_NO_ERROR) { #ifdef RCDEBUG printk("rc: RC send error 0x%x\n", (uint)status); #endif dev->tbusy = 1; return 1; } else { dev->trans_start = jiffies; // dev->tbusy = 0; } /* * 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, U16 AdapterID) { struct sk_buff *skb; PDPA pDpa; struct net_device *dev; pDpa = PCIAdapters[AdapterID]; if (!pDpa) { printk("rc: Fatal error: xmit callback, !pDpa\n"); return; } dev = pDpa->dev; // printk("xmit_callback: Status = 0x%x\n", (uint)Status); if (Status != I2O_REPLY_STATUS_SUCCESS) { printk("rc: xmit_callback: Status = 0x%x\n", (uint)Status); } #ifdef RCDEBUG if (pDpa->shutdown || pDpa->reboot) printk("rc: xmit callback: shutdown||reboot\n"); #endif #ifdef RCDEBUG printk("rc: xmit_callback: PcktCount = %d, BC = 0x%x\n", (uint)PcktCount, (uint)BufferContext); #endif while (PcktCount--) { skb = (struct sk_buff *)(BufferContext[0]); #ifdef RCDEBUG printk("rc: skb = 0x%x\n", (uint)skb); #endif BufferContext++; #ifdef LINUX_2_1 dev_kfree_skb (skb); #else dev_kfree_skb (skb, FREE_WRITE); #endif } dev->tbusy = 0; } static void RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID) { PDPA pDpa; struct net_device *dev; pDpa = PCIAdapters[AdapterID]; dev = pDpa->dev; #ifdef RCDEBUG printk("rc: RCreset_callback Status 0x%x\n", (uint)Status); #endif /* * Check to see why we were called. */ if (pDpa->shutdown) { printk("rc: Shutting down interface\n"); pDpa->shutdown = 0; pDpa->reboot = 0; MOD_DEC_USE_COUNT; } else if (pDpa->reboot) { printk("rc: 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(pDpa->id); RCShutdownLANCard(pDpa->id,0,0,0); printk("rc: 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, U16 AdapterID) { PDPA pDpa; pDpa = PCIAdapters[AdapterID]; #ifdef RCDEBUG printk("rc: RCreboot: rcv buffers outstanding = %d\n", (uint)pDpa->numOutRcvBuffers); #endif if (pDpa->shutdown) { printk("rc: 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(pDpa->id, 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, U16 AdapterID) { U32 len, count; PDPA pDpa; struct sk_buff *skb; struct net_device *dev; singleTCB tcb; psingleTCB ptcb = &tcb; pDpa = PCIAdapters[AdapterID]; dev = pDpa->dev; ptcb->bcount = 1; #ifdef RCDEBUG printk("rc: RCrecv_callback: 0x%x, 0x%x, 0x%x\n", (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock); #endif #ifdef RCDEBUG if ((pDpa->shutdown || pDpa->reboot) && !Status) printk("shutdown||reboot && !Status: PktCount = %d\n",PktCount); #endif 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("rc: RCrecv error: status = 0x%x\n", (uint)Status); #ifdef RCDEBUG else printk("rc: Returning %d buffers, status = 0x%x\n", PktCount, (uint)Status); #endif /* * 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) { #ifdef RCDEBUG printk("RCrecv status ABORT NO DATA TRANSFER\n"); #endif } /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ if (PacketDescBlock) { while(PktCount--) { skb = (struct sk_buff *)PacketDescBlock[0]; #ifndef LINUX_2_1 skb->free = 1; skb->lock = 0; #endif #ifdef RCDEBUG printk("free skb 0x%p\n", skb); #endif #ifdef LINUX_2_1 dev_kfree_skb (skb); #else dev_kfree_skb(skb, FREE_READ); #endif pDpa->numOutRcvBuffers--; PacketDescBlock += BD_SIZE; /* point to next context field */ } } return; } else { while(PktCount--) { skb = (struct sk_buff *)PacketDescBlock[0]; #ifdef RCDEBUG if (pDpa->shutdown) printk("shutdown: skb=0x%x\n", (uint)skb); printk("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]); #endif #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(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR) { printk("rc: RCrecv_callback: post buffer failed!\n"); #ifdef LINUX_2_1 dev_kfree_skb (skb); #else skb->free = 1; dev_kfree_skb(skb, FREE_READ); #endif } 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 = (struct net_device *)(dev_id); pDpa = (PDPA) (dev->priv); #ifdef RCDEBUG if (pDpa->shutdown) printk("rc: shutdown: service irq\n"); printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", (uint)pDpa, (uint)dev, (uint)pDpa->id); printk("dev = 0x%x\n", (uint)dev); #endif if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; RCProcI2OMsgQ(pDpa->id); dev->interrupt = 0; return; } #define REBOOT_REINIT_RETRY_LIMIT 4 static void rc_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; PDPA pDpa = (PDPA) (dev->priv); int init_status; static int retry = 0; int post_buffers = MAX_NMBR_RCV_BUFFERS; int count = 0; int requested = 0; if (pDpa->reboot) { init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA), (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(pDpa->id, DriverControlWord); RCEnableI2OInterrupts(pDpa->id); 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; printk("rc: posted %d buffers \r\n", (uint)pDpa->numOutRcvBuffers); } printk("rc: Initialization done.\n"); dev->tbusy=0; retry=0; return; case RC_RTN_FREE_Q_EMPTY: retry++; printk("rc: inbound free q empty\n"); break; default: retry++; printk("rc: bad status after reboot: %d\n", init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { printk("rc: unable to reinitialize adapter after reboot\n"); printk("rc: decrementing driver and closing interface\n"); RCDisableI2OInterrupts(pDpa->id); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { printk("rc: 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("rc: timer??\n"); } } static int RCclose(struct net_device *dev) { PDPA pDpa = (PDPA) dev->priv; #ifdef RCDEBUG printk("rc: RCclose\r\n"); #endif if (pDpa->reboot) { printk("rc: skipping reset -- adapter already in reboot mode\n"); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; return 0; } #ifdef RCDEBUG printk("rc: receive buffers outstanding: %d\n", (uint)pDpa->numOutRcvBuffers); #endif 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(pDpa->id, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0, (PFNCALLBACK)RCreset_callback); dev->flags &= ~IFF_UP; return 0; } static struct enet_statistics * RCget_stats(struct net_device *dev) { RCLINKSTATS RCstats; PDPA pDpa = dev->priv; if (!pDpa) { printk("rc: RCget_stats: !pDpa\n"); return 0; } else if (!(dev->flags & IFF_UP)) { #ifdef RCDEBUG printk("rc: RCget_stats: device down\n"); #endif return 0; } memset(&RCstats, 0, sizeof(RCLINKSTATS)); if ( (RCGetLinkStatistics(pDpa->id, &RCstats, (void *)0)) == RC_RTN_NO_ERROR ) { #ifdef RCDEBUG printk("rc: TX_good 0x%x\n", (uint)RCstats.TX_good); printk("rc: TX_maxcol 0x%x\n", (uint)RCstats.TX_maxcol); printk("rc: TX_latecol 0x%x\n", (uint)RCstats.TX_latecol); printk("rc: TX_urun 0x%x\n", (uint)RCstats.TX_urun); printk("rc: TX_crs 0x%x\n", (uint)RCstats.TX_crs); printk("rc: TX_def 0x%x\n", (uint)RCstats.TX_def); printk("rc: TX_singlecol 0x%x\n", (uint)RCstats.TX_singlecol); printk("rc: TX_multcol 0x%x\n", (uint)RCstats.TX_multcol); printk("rc: TX_totcol 0x%x\n", (uint)RCstats.TX_totcol); printk("rc: Rcv_good 0x%x\n", (uint)RCstats.Rcv_good); printk("rc: Rcv_CRCerr 0x%x\n", (uint)RCstats.Rcv_CRCerr); printk("rc: Rcv_alignerr 0x%x\n", (uint)RCstats.Rcv_alignerr); printk("rc: Rcv_reserr 0x%x\n", (uint)RCstats.Rcv_reserr); printk("rc: Rcv_orun 0x%x\n", (uint)RCstats.Rcv_orun); printk("rc: Rcv_cdt 0x%x\n", (uint)RCstats.Rcv_cdt); printk("rc: Rcv_runt 0x%x\n", (uint)RCstats.Rcv_runt); #endif 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 enet_statistics *)&(pDpa->stats)); } return 0; } static int RCioctl(struct net_device *dev, struct ifreq *rq, int cmd) { RCuser_struct RCuser; PDPA pDpa = dev->priv; #if RCDEBUG printk("RCioctl: cmd = 0x%x\n", cmd); #endif 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: { #ifdef LINUX_2_1 if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser))) return -EFAULT; #else int error; error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser)); if (error) { return error; } memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser)); #endif #ifdef RCDEBUG printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); #endif switch(RCuser.cmd) { case RCUC_GETFWVER: printk("RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL); break; case RCUC_GETINFO: printk("RC GETINFO\n"); RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO -> mem_start = dev->base_addr; RCUD_GETINFO -> mem_end = dev->base_addr + 2*32768; RCUD_GETINFO -> base_addr = pDpa->pci_addr; RCUD_GETINFO -> irq = dev->irq; break; case RCUC_GETIPANDMASK: printk("RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr, (PU32) &RCUD_GETIPANDMASK->NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: printk("RC GETLINKSTATISTICS\n"); RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics(pDpa->id, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: printk("RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL); break; case RCUC_GETMAC: printk("RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL); break; case RCUC_GETPROM: printk("RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode(pDpa->id, (PU32) &RCUD_GETPROM->PromMode, NULL); break; case RCUC_GETBROADCAST: printk("RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode(pDpa->id, (PU32) &RCUD_GETBROADCAST->BroadcastMode, NULL); break; case RCUC_GETSPEED: printk("RC GETSPEED\n"); if (!(dev->flags & IFF_UP)) { printk("RCioctl, GETSPEED error: interface down\n"); return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL); printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: printk("RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; printk ("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 ("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(pDpa->id, (U32) RCUD_SETIPANDMASK->IpAddr, (U32) RCUD_SETIPANDMASK->NetMask); break; case RCUC_SETMAC: printk("RC SETMAC\n"); RCUD_SETMAC = &RCuser.RCUS_SETMAC; printk ("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(pDpa->id, (PU8) &RCUD_SETMAC->mac); break; case RCUC_SETSPEED: printk("RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed(pDpa->id, (U16) RCUD_SETSPEED->LinkSpeedCode); printk("RC New speed = 0x%d\n", RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: printk("RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode(pDpa->id,(U16)RCUD_SETPROM->PromMode); printk("RC New prom mode = 0x%d\n", RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: printk("RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode(pDpa->id,(U16)RCUD_SETBROADCAST->BroadcastMode); printk("RC New broadcast mode = 0x%d\n", RCUD_SETBROADCAST->BroadcastMode); break; default: printk("RC command default\n"); RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT -> rc = 0x11223344; break; } #ifdef LINUX_2_1 copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser)); #else memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser)); #endif break; } /* RCU_COMMAND */ default: printk("RC default\n"); rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; break; } return 0; } static int RCconfig(struct net_device *dev, struct ifmap *map) { /* * To be completed ... */ printk("rc: 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 "RC pci45: Change I/O address not implemented\n"); return -EOPNOTSUPP; } return 0; } #ifdef MODULE void cleanup_module(void) { PDPA pDpa; struct net_device *next; #ifdef RCDEBUG printk("rc: RC cleanup_module\n"); printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev); #endif while (root_RCdev) { pDpa = (PDPA) root_RCdev->priv; #ifdef RCDEBUG printk("rc: cleanup 0x%08X\n", (uint)root_RCdev); #endif printk("IOP reset: 0x%x\n", RCResetIOP(pDpa->id)); unregister_netdev(root_RCdev); next = pDpa->next; iounmap((unsigned long *)root_RCdev->base_addr); free_irq( root_RCdev->irq, root_RCdev ); kfree(root_RCdev); root_RCdev = next; } } #endif static int RC_allocate_and_post_buffers(struct net_device *dev, int numBuffers) { int i; PDPA pDpa = (PDPA)dev->priv; PU32 p; psingleB pB; struct sk_buff *skb; RC_RETURN status; if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { #ifdef RCDEBUG printk("rc: Too many buffers requested!\n"); printk("rc: attempting to allocate only 32 buffers\n"); #endif numBuffers = 32; } p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC); #ifdef RCDEBUG printk("rc: TCB = 0x%x\n", (uint)p); #endif if (!p) { printk("rc: RCopen: unable to allocate TCB\n"); return 0; } p[0] = 0; /* Buffer Count */ pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */ #ifdef RCDEBUG printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB); printk("rc: pB = 0x%x\n", (uint)pB); #endif for (i=0; icontext = (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(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR) { printk("rc: 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; #ifndef LINUX_2_1 skb->free = 1; #endif #ifdef RCDEBUG printk("rc: freeing 0x%x\n", (uint)skb); #endif #ifdef LINUX_2_1 dev_kfree_skb (skb); #else dev_kfree_skb(skb, FREE_READ); #endif p[0]--; pB++; } #ifdef RCDEBUG printk("rc: freed all buffers, p[0] = %ld\n", p[0]); #endif } kfree(p); return(p[0]); /* return the number of posted buffers */ }