📄 rcpci45.c
字号:
/* **** 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.**** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional** again. Note that this card is not supported or manufactured by ** RedCreek anymore.** ** 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 <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/timer.h>#include <asm/irq.h> /* For NR_IRQS only. */#include <asm/bitops.h>#include <asm/uaccess.h>static char version[] __initdata = "RedCreek Communications PCI linux driver version 2.20\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/* minimum msg buffer size needed by the card * Note that the size of this buffer is hard code in the * ipsec card's firmware. Thus, the size MUST be a minimum * of 16K. Otherwise the card will end up using memory * that does not belong to it. */#define MSG_BUF_SIZE 16384static 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 __devexitrcpci45_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata (pdev); PDPA pDpa = dev->priv; if (!dev) { printk (KERN_ERR "%s: remove non-existent device\n", dev->name); return; } RCResetIOP (dev); unregister_netdev (dev); free_irq (dev->irq, dev); iounmap ((void *) dev->base_addr); pci_release_regions (pdev); if (pDpa->msgbuf) kfree (pDpa->msgbuf); if (pDpa->pPab) kfree (pDpa->pPab); kfree (dev); pci_set_drvdata (pdev, NULL);}static intrcpci45_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:) init_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } error = pci_enable_device (pdev); if (error) { printk (KERN_ERR "(rcpci45 driver:) %d: pci enable device error\n", card_idx); goto err_out; } error = -ENOMEM; pci_start = pci_resource_start (pdev, 0); pci_len = pci_resource_len (pdev, 0); printk("pci_start %x pci_len %x\n", pci_start, pci_len); 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 mem resources! Aborting\n"); error = -EBUSY; goto err_out_free_dev; } /* * pDpa->msgbuf is where the card will dma the I2O * messages. Thus, we need contiguous physical pages of * memory. */ pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!pDpa->msgbuf) { printk (KERN_ERR "(rcpci45 driver:) \ Could not allocate %d byte memory for the \ private msgbuf!\n", MSG_BUF_SIZE); goto err_out_free_dev; } /* * Save the starting address of the LAN API private area. We'll * pass that to RCInitI2OMsgLayer(). * */ pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); /* 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; } dev->base_addr = (unsigned long) vaddr; dev->irq = pdev->irq; 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; /* 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 -ENODEV;}static struct pci_driver rcpci45_driver = { name: "rcpci45", id_table: rcpci45_pci_table, probe: rcpci45_init_one, remove: __devexit_p(rcpci45_remove_one),};static int __initrcpci_init_module (void){ int rc = pci_module_init (&rcpci45_driver); if (!rc) printk (KERN_ERR "%s", version); return rc;}static intRCopen (struct net_device *dev){ int post_buffers = MAX_NMBR_RCV_BUFFERS; PDPA pDpa = dev->priv; int count = 0; int requested = 0; int error; MOD_INC_USE_COUNT; 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 (KERN_INFO "Waking up adapter...\n"); RCResetLANCard (dev, 0, 0, 0); } else { pDpa->nexus = 1; /* * RCInitI2OMsgLayer is done only once, unless the * adapter was sent a warm reboot */ error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, (PFNRXCALLBACK) RCrecv_callback, (PFNCALLBACK) RCreboot_callback); if (error) { printk (KERN_ERR "%s: Unable to init msg layer (%x)\n", dev->name, error); goto err_out; } if ((error = RCGetMAC (dev, NULL))) { printk (KERN_ERR "%s: Unable to get adapter MAC\n", dev->name); goto err_out; } } /* Request a shared interrupt line. */ error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); if (error) { printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); goto err_out; } DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability (dev, DriverControlWord); printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); RCEnableI2OInterrupts (dev); 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 "%s: \ unable to allocate any buffers\n", dev->name); goto err_out_free_irq; } printk (KERN_WARNING "%s: \ unable to allocate all requested buffers\n", dev->name); 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 */ netif_start_queue (dev); return 0;err_out_free_irq: free_irq (dev->irq, dev);err_out: MOD_DEC_USE_COUNT; return error;}static intRC_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) { printk ("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); if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) != RC_RTN_NO_ERROR) { printk ("%s: send error 0x%x\n", dev->name, (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 voidRCxmit_callback (U32 Status, U16 PcktCount, PU32 BufferContext, struct net_device *dev){ struct sk_buff *skb; PDPA pDpa = dev->priv; if (!pDpa) { printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n", dev->name); return; } if (Status != I2O_REPLY_STATUS_SUCCESS) printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n", dev->name, (uint) Status); if (pDpa->shutdown || pDpa->reboot) printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n", dev->name); while (PcktCount--) { skb = (struct sk_buff *) (BufferContext[0]); BufferContext++; dev_kfree_skb_irq (skb); } netif_wake_queue (dev);}static voidRCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev){ PDPA pDpa = dev->priv; printk ("RCreset_callback Status 0x%x\n", (uint) Status); /* * Check to see why we were called. */ if (pDpa->shutdown) { printk (KERN_INFO "%s: shutting down interface\n", dev->name); pDpa->shutdown = 0; pDpa->reboot = 0; } else if (pDpa->reboot) { printk (KERN_INFO "%s: reboot, shutdown adapter\n", dev->name); /* * 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 "%s: scheduling timer...\n", dev->name); 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 voidRCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev){ PDPA pDpa = dev->priv; printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n", dev->name, (uint) pDpa->numOutRcvBuffers); if (pDpa->shutdown) { printk (KERN_INFO "%s: skip reboot, shutdown initiated\n", dev->name); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -