📄 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.**** 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 <linux/module.h>#include <linux/version.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/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/bios32.h>#include <linux/timer.h>#include <asm/irq.h> /* For NR_IRQS only. */#include <asm/bitops.h>#include <asm/io.h>#if LINUX_VERSION_CODE >= 0x020100#define LINUX_2_1#endif#ifdef LINUX_2_1#include <asm/uaccess.h>#endif#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#define RC_LINUX_MODULE#include "rclanmtl.h"#include "rcif.h"#define RUN_AT(x) (jiffies + (x))#define NEW_MULTICAST#include <linux/delay.h>#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 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 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 32static 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 device *dev);static int RCscan(struct device *dev);static int RCfound_device(struct device *, int, int, int, int, int, int);static int RCopen(struct device *);static int RC_xmit_packet(struct sk_buff *, struct device *);static void RCinterrupt(int, void *, struct pt_regs *);static int RCclose(struct device *dev);static struct enet_statistics *RCget_stats(struct device *);static int RCioctl(struct device *, struct ifreq *, int);static int RCconfig(struct 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 device *, int);/* A list of all installed RC devices, for removing the driver module. */static struct device *root_RCdev = NULL;#ifdef MODULEint init_module(void)#elseint rcpci_probe(struct 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 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 short pci_command, vendor, device, class; unsigned int pci_ioaddr; 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) break; pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_CLASS_DEVICE, &class); pci_ioaddr &= ~0xf;#ifdef RCDEBUG printk("rc: Found RedCreek PCI adapter\n"); printk("rc: pci class = 0x%x 0x%x \n", class, class>>8); 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 if (check_region(pci_ioaddr, 2*32768)) { printk("rc: check_region failed\n"); continue; }#ifdef RCDEBUG else { printk("rc: check_region passed\n"); }#endif /* * Get and check the bus-master and latency values. * Some PCI BIOSes fail to set the master-enable bit. */ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); if ( ! (pci_command & PCI_COMMAND_MASTER)) { printk("rc: PCI Master Bit has not been set!\n"); pci_command |= PCI_COMMAND_MASTER; pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, pci_command); } if ( ! (pci_command & PCI_COMMAND_MEMORY)) { /* * If the BIOS did not set the memory enable bit, what else * did it not initialize? Skip this adapter. */ printk("rc: Adapter %d, PCI Memory Bit has not been set!\n", cards_found); printk("rc: Bios problem? \n"); continue; } 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 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 intRCfound_device(struct 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 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 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 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 device) + 15) & ~15);#else dev->priv = 0; dev->priv = (struct 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 intRCopen(struct 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -