read the file Documentation/riscom8.txt. Also it's possible to say
M here and compile this driver as kernel loadable module.
+Specialix IO8+ card support
+CONFIG_SPECIALIX
+ This is a driver for the Specialix IO8+ multiport card (both the
+ ISA and the PCI version), that gives you 8 serial ports. You would
+ need a card like this to connect more than two modems to your linux
+ box, for instance in order to become a BBS. If you have a card like
+ that, say Y here and read the file Documentation/specialix.txt. Also
+ it's possible to say M here and compile this driver as kernel
+ loadable module.
+
+Specialix DTR/RTS pin is RTS
+CONFIG_SPECIALIX_RTSCTS
+ The Specialix card can only support either RTS or DTR. When this
+ option is off, the driver will use the pin as "DTR" when the tty is
+ in software handshake mode. When this option is on or hardware
+ handshake is on, it will always be RTS. Read the file
+ Documentation/specialix.txt for more information.
+
Cyclades async mux support
CONFIG_CYCLADES
This is a driver for a card that gives you many serial ports. You
--- /dev/null
+\r
+\r
+Application Information\r
+\r
+The included application, called "rcc" (for RedCreek Control), is an \r
+example of a user-space application (i.e., not running within kernel\r
+space). It issues ioctl commands to communicate with the PCI driver. \r
+It is intended for reference only. It can currently report any of \r
+the following information:\r
+\r
+ - PCI driver information ("getinfo")\r
+ - card statistics ("getstats")\r
+ - card's ip address & netmask ("getipnmask")\r
+ - card's mac address ("getmac")\r
+ - current speed ("getspeed")\r
+ - firmware version string ("getfirmware")\r
+ - status of the link (up or down) ("getstatus")\r
+\r
+This program needs to run as root, to avoid encountering permission \r
+problems. An alternative is to change the permission and ownership\r
+so that it runs as a setuid root process (for example, "chown \r
+root.root rcc; chmod u+s rcc").\r
+\r
+\r
+Quick PCI driver background\r
+\r
+The adapter has its own IP and mac addresses which you have to\r
+assign using the RedCreek manager (assuming the adapter is\r
+running 3.X firmware). Your linux box will not know anything \r
+about the adapter's IP address -- ie, the adapter will show up \r
+as a regular nic. You will assign the linux box IP address using \r
+the "ifconfig" command, as mentioned below.\r
+\r
+To compile the driver, simply type "make". \r
+This, of course, assumes that you have GNU compiler environment\r
+already setup on a linux box. The .c and .h files were copied \r
+to a dos filesystem (the floppy), so you may have to use "dos2unix" to \r
+convert it back to a unix text file. Keep in mind that the driver\r
+currently works with kernels 2.0.X only. Furthermore, it was only\r
+tested with kernel 2.0.34. There is work being done on porting the\r
+driver to the 2.1.X kernel, however, it's still incomplete.\r
+\r
+When the compile is done, you'll send up with three object files\r
+related to the driver: rcmtl.o, rcpci45.o, and rc.o; rcmtl.o\r
+is the RedCreek API message layer; rcpci45.o is the upper level\r
+Linux driver which contains the interface to the kernel. Finally,\r
+since the driver is compiled as a loadable module, rcmtl.o and\r
+rcpci45.o are linked together into a third file, rc.o, which is the\r
+actual driver. \r
+\r
+To load the driver:\r
+\r
+"insmod rc"\r
+\r
+If you are in console mode, you'll see a few messages send by the\r
+driver. One of the messages will indicated how many adapters were\r
+found; the messages are also stored in /var/log/messages, so they\r
+can be viewed later. If you are running X, then you'll have to \r
+view the messages by examining /var/log/messages.\r
+\r
+The adapter will show up as a regular nic. Thus, if you have only\r
+one nic (the pci card) in your box, you would at this point configure\r
+it with the following commands:\r
+\r
+mandatory:\r
+"ifconfig eth0 <your linux box IP address (NOT the IP address of the \r
+ adapter!>"\r
+"route add -net <your network address> eth0"\r
+\r
+optional (if you want to be able to access other networks):\r
+"route add default gw <your default gateway IP address> eth0"\r
+\r
+Done. Type "ifconfig" to see "eth0" and the packet count, as well\r
+as the IP address, net mask, etc.\r
+\r
+To unload the driver, you first have to shutdown the interface:\r
+\r
+"ifconfig eth0 down"\r
+\r
+Then you unload the driver with "rmmod rc".\r
+\r
+\r
+For technical support, please send email to Pete Popov at \r
+ppopov@redcreek.com. Please have as complete of a description of\r
+the problem as possible.\r
written by Dmitry Gorodchanin. The specialix IO8+ card
programming information was obtained from the CL-CD1865 Data
Book, and Specialix document number 6200059: IO8+ Hardware
- Functional Specification.
+ Functional Specification, augmented by document number 6200088:
+ Merak Hardware Functional Specification. (IO8+/PCI is also
+ called Merak)
+
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
kernel sources? And the manual of one of the boards in your computer?
-Adresses and interrupts
-=======================
+Addresses and interrupts
+========================
-Addres dip switch settings:
+Address dip switch settings:
The dip switch sets bits 2-9 of the IO address.
9 8 7 6 5 4 3 2
other computer runs just fine with the Specialix card at 0x100....
The card occupies 4 addresses, but actually only two are really used.
+The PCI version doesn't have any dip switches. The BIOS assigns
+an IO address.
+
The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260. If
that causes trouble for you, please report that. I'll remove
autoprobing then.
change any jumpers to change the IRQ. Just use a command line
argument (irq=xx) to the insmod program to set the interrupt.
+The BIOS assigns the IRQ on the PCI version. You have no say in what
+IRQ to use in that case.
+
If your specialix cards are not at the default locations, you can use
the kernel command line argument "specialix=io0,irq0,io1,irq1...".
Here "io0" is the io address for the first card, and "irq0" is the
in your /etc/lilo.conf file if you use lilo.
+The Specialix driver is slightly odd: It allows you to have the second
+or third card detected without having a first card. This has
+advantages and disadvantages. A slot that isn't filled by an ISA card,
+might be filled if a PCI card is detected. Thus if you have an ISA
+card at 0x250 and a PCI card, you would get:
+
+sx0: specialix IO8+ Board at 0x100 not found.
+sx1: specialix IO8+ Board at 0x180 not found.
+sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B.
+sx3: specialix IO8+ Board at 0x260 not found.
+sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+This would happen if you don't give any probe hints to the driver.
+If you would specify:
+
+ specialix=0x250,11
+
+you'd get the following messages:
+
+sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B.
+sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+ISA probing is aborted after the IO address you gave is exhausted, and
+the PCI card is now detected as the second card. The ISA card is now
+also forced to IRQ11....
+
Baud rates
==========
fact is a divided by two mode). This is not enough to reach the rated
115k2 on all ports at the same time. With this clock rate you can only
do 37% of this rate. This means that at 115k2 on all ports you are
-going to loose characters (The chip cannot handle that many incoming
+going to lose characters (The chip cannot handle that many incoming
bits at this clock rate.) (Yes, you read that correctly: there is a
limit to the number of -=bits=- per second that the chip can handle.)
If you near the "limit" you will first start to see a graceful
degradation in that the chip cannot keep the transmitter busy at all
times. However with a central clock this slow, you can also get it to
-miss incoming characters.
+miss incoming characters. The driver will print a warning message when
+you are outside the official specs. The messages usually show up in
+the file /var/log/messages .
The specialix card cannot reliably do 115k2. If you use it, you have
to do "extensive testing" (*) to verify if it actually works.
When "mgetty" communicates with my modem at 115k2 it reports:
got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a]
- ^^^^ ^^^^ ^^^^
+ ^^^^ ^^^^ ^^^^
The three characters that have the "^^^" under them have suffered a
bit error in the highest bit. In conclusion: I've tested it, and found
-that it simply DOESN"T work for me. I also suspect that this is also
+that it simply DOESN'T work for me. I also suspect that this is also
caused by the baud rate being just a little bit out of tune.
+I upgraded the crystal to 66Mhz on one of my Specialix cards. Works
+great! Contact me for details. (Voids warranty, requires a steady hand
+and more such restrictions....)
+
(*) Cirrus logic CD1864 databook, page 40.
Ports and devices
=================
-Port 0 is the one furthest from the ISA connector.
+Port 0 is the one furthest from the card-edge connector.
Devices:
done
echo ""
+If your system doesn't come with these devices preinstalled, bug your
+linux-vendor about this. They have had ample time to get this
+implemented by now.
You cannot have more than 4 boards in one computer. The card only
supports 4 different interrupts. If you really want this, contact me
about this and I'll give you a few tips (requires soldering iron)....
+If you have enough PCI slots, you can probably use more than 4 PCI
+versions of the card though....
+
+The PCI version of the card cannot adhere to the mechanical part of
+the PCI spec because the 8 serial connectors are simply too large. If
+it doesn't fit in your computer, bring back the card.
+
------------------------------------------------------------------------
orb $0x10,%bx # by setting bit 4
setCx86($0xc3,%bx)
+ getCx86($0xfe) # DIR0 : let's check this is a 6x86(L)
+ andb $0xf0,%ax # should be 3xh
+ cmpb $0x30,%ax #
+ jne n6x86
+
getCx86($0xe8) # now we can get CCR4
orb $0x80,%ax # and set bit 7 (CPUIDEN)
movb %ax,%bx # to enable CPUID execution
setCx86($0xe8,%bx)
- getCx86($0xfe) # DIR0 : let's check this is a 6x86(L)
- andb $0xf0,%ax # should be 3xh
- cmpb $0x30,%ax #
- jne n6x86
getCx86($0xe9) # CCR5 : we reset the SLOP bit
andb $0xfd,%ax # so that udelay calculation
movb %ax,%bx # is correct on 6x86(L) CPUs
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
#endif
+
+ /*
+ * The 1Gig sanity checker.
+ */
+
+ if (memory_end > 980*1024*1024)
+ {
+ printk(KERN_WARNING "Warning only 980Mb will be used.\n");
+ memory_end = 980 * 1024 * 1024;
+ }
+
if (!MOUNT_ROOT_RDONLY)
root_mountflags &= ~MS_RDONLY;
memory_start = (unsigned long) &_end;
#if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
- defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || \
+ defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || defined(CONFIG_WDT) || \
defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
misc_init();
#endif
* Changed the specialix=... format to include interrupt.
* Revision 1.7: May 27 1997
* Made many more debug printk's a compile time option.
+ * Revision 1.8: Port to 2.1 kernel. -- Not here.
+ *
+ * Revision 1.9: October 1 1998
+ * Support for the PCI version of the card.
*
*/
-#define VERSION "1.7"
+#define VERSION "1.9"
/*
#include <linux/delay.h>
#include <linux/tqueue.h>
#include <linux/version.h>
-
+#include <linux/pci.h>
+#include <linux/bios32.h>
/* ************************************************************** */
/* * This section can be removed when 2.0 becomes outdated.... * */
#define SPECIALIX_TYPE_NORMAL 1
#define SPECIALIX_TYPE_CALLOUT 2
-static struct specialix_board * IRQ_to_board[16] = { NULL, } ;
static struct tty_driver specialix_driver, specialix_callout_driver;
static int specialix_refcount = 0;
static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT] = { NULL, };
extern inline int sx_check_io_range(struct specialix_board * bp)
{
- return check_region (bp->base, SX_IO_SPACE);
+ return check_region (bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
}
extern inline void sx_request_io_range(struct specialix_board * bp)
{
- request_region(bp->base, SX_IO_SPACE, "specialix IO8+" );
+ request_region(bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE,
+ "specialix IO8+" );
}
extern inline void sx_release_io_range(struct specialix_board * bp)
{
- release_region(bp->base, SX_IO_SPACE);
+ release_region(bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
}
/* Must be called with enabled interrupts */
+/* Ugly. Don't use this for anything else than initialization code */
extern inline void sx_long_delay(unsigned long delay)
{
unsigned long i;
int virq;
int i;
+ if (bp->flags & SX_BOARD_IS_PCI)
+ return 1;
switch (bp->irq) {
/* In the same order as in the docs... */
case 15: virq = 0;break;
printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
board_No(bp), val1, val2);
#endif
- if (val1 != 0xb2) {
- printk(KERN_INFO "sx%d: specialix IO8+ ID at 0x%03x not found.\n",
- board_No(bp), bp->base);
+ /* They managed to switch the bit order between the docs and
+ the IO8+ card. The new PCI card now conforms to old docs.
+ They changed the PCI docs to reflect the situation on the
+ old card. */
+ val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
+ if (val1 != val2) {
+ printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
+ board_No(bp), val2, bp->base, val1);
return 1;
}
unsigned long loop = 0;
int saved_reg;
- bp = IRQ_to_board[irq];
+ bp = dev_id;
if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
#ifdef SPECIALIX_DEBUG
* Routines for open & close processing.
*/
+void turn_ints_off (struct specialix_board *bp)
+{
+ if (bp->flags & SX_BOARD_IS_PCI) {
+ /* This was intended for enabeling the interrupt on the
+ * PCI card. However it seems that it's already enabled
+ * and as PCI interrupts can be shared, there is no real
+ * reason to have to turn it off. */
+ }
+ (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+}
+
+void turn_ints_on (struct specialix_board *bp)
+{
+ if (bp->flags & SX_BOARD_IS_PCI) {
+ /* play with the PCI chip. See comment above */
+ }
+ (void) sx_in (bp, 0); /* Turn ON interrupts. */
+}
+
/* Called with disabled interrupts */
extern inline int sx_setup_board(struct specialix_board * bp)
if (bp->flags & SX_BOARD_ACTIVE)
return 0;
- error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", NULL);
+ error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
if (error)
return error;
- IRQ_to_board[bp->irq] = bp;
- (void) sx_in (bp, 0); /* Turn ON interrupts. */
-
+ turn_ints_on (bp);
bp->flags |= SX_BOARD_ACTIVE;
MOD_INC_USE_COUNT;
bp->flags &= ~SX_BOARD_ACTIVE;
- free_irq(bp->irq, NULL);
- (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+#if SPECIALIX_DEBUG > 2
+ printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
+#endif
+ free_irq(bp->irq, bp);
+
+ turn_ints_off (bp);
- IRQ_to_board[bp->irq] = NULL;
-
MOD_DEC_USE_COUNT;
}
/* Page 48 of version 2.0 of the CL-CD1865 databook */
if (tmp >= 12) {
printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
- "Performance degradation is possible.\n",
+ "Performance degradation is possible.\n"
+ "Read specialix.txt for more info.\n",
port_No (port), tmp);
} else {
printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
"Warning: overstressing Cirrus chip. "
- "This might not work.\n",
+ "This might not work.\n"
+ "Read specialix.txt for more info.\n",
port_No (port), tmp);
}
}
return 1;
}
init_bh(SPECIALIX_BH, do_specialix_bh);
- memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
memset(&specialix_driver, 0, sizeof(specialix_driver));
specialix_driver.magic = TTY_DRIVER_MAGIC;
specialix_driver.name = "ttyW";
void specialix_setup(char *str, int * ints)
{
int i;
-
+
for (i=0;i<SX_NBOARD;i++) {
sx_board[i].base = 0;
}
{
int i;
int found = 0;
+#ifdef CONFIG_PCI
+ int pci_index;
+ unsigned char pci_bus, pci_device_fn;
+#endif
- printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997.\n");
+ printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
#ifdef CONFIG_SPECIALIX_RTSCTS
printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
if (sx_board[i].base && !sx_probe(&sx_board[i]))
found++;
+#ifdef CONFIG_PCI
+ i=0;
+ pci_index = 0;
+ while ((i < SX_NBOARD) && (pci_index < 0xff)) {
+ unsigned char tbyte;
+ unsigned int tint;
+ if (sx_board[i].flags & SX_BOARD_PRESENT) {
+ i++;
+ continue;
+ }
+ if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_IO8,
+ pci_index, &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &tbyte);
+ sx_board[i].irq = tbyte;
+
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2, &tint);
+ /* Mask out the fact that it's IO-space */
+ sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK;
+ sx_board[i].flags |= SX_BOARD_IS_PCI;
+ if (!sx_probe(&sx_board[i]))
+ found ++;
+ pci_index++;
+ }
+#endif
+
if (!found) {
sx_release_drivers();
printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
/*
* You can setup up to 4 boards.
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
+ * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
+ * You should specify the IRQs too in that case "irq=....,...".
*
* More than 4 boards in one computer is not possible, as the card can
* only use 4 different interrupts.
#ifdef __KERNEL__
-#define SX_NBOARD 4
+/* You can have max 4 ISA cards in one PC, and I recommend not much
+more than a few PCI versions of the card. */
+
+#define SX_NBOARD 8
+
/* NOTE: Specialix decoder recognizes 4 addresses, but only two are used.... */
#define SX_IO_SPACE 4
+/* The PCI version decodes 8 addresses, but still only 2 are used. */
+#define SX_PCI_IO_SPACE 8
+
/* eight ports per board. */
#define SX_NPORT 8
#define SX_BOARD(line) ((line) / SX_NPORT)
#define SX_PORT(line) ((line) & (SX_NPORT - 1))
-
#define SX_DATA_REG 0 /* Base+0 : Data register */
#define SX_ADDR_REG 1 /* base+1 : Address register. */
#define SX_BOARD_PRESENT 0x00000001
#define SX_BOARD_ACTIVE 0x00000002
+#define SX_BOARD_IS_PCI 0x00000004
struct specialix_port {
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
+ tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
fi
endif
endif
+
+
+ifeq ($(CONFIG_RCPCI),y)
+L_OBJS += rcpci.o
+else
+ ifeq ($(CONFIG_RCPCI),m)
+ M_OBJS += rcpci.o
+ endif
+endif
+
include $(TOPDIR)/Rules.make
clean:
rm -f core *.o *.a *.s
+rcpci.o: rcpci45.o rcmtl.o
+ $(LD) -r -o rcpci.o rcpci45.o rcmtl.o
+
wd.o: wd.c CONFIG
$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
static void srom_repair(struct device *dev, int card);
static int test_bad_enet(struct device *dev, int status);
static int an_exception(struct bus_type *lp);
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
static void eisa_probe(struct device *dev, u_long iobase);
#endif
static void pci_probe(struct device *dev, u_long iobase);
#endif /* MODULE */
static char name[DE4X5_NAME_LENGTH + 1];
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
static int lastEISA = 0;
#else
{
u_long iobase = dev->base_addr;
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
eisa_probe(dev, iobase);
#endif
if (lastEISA == MAX_EISA_SLOTS) {
return;
}
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
/*
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard. Upto 15 EISA devices are supported.
return;
}
-#endif /* !(__sparc_v9__) && !(__powerpc__) */
+#endif /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__)*/
/*
** PCI bus I/O device probe
u_int class = DE4X5_CLASS_CODE;
u_int device;
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
char name[DE4X5_STRLEN];
u_long iobase = 0x1000;
--- /dev/null
+/*\r
+** *************************************************************************\r
+**\r
+**\r
+** R C I F . H\r
+**\r
+**\r
+** RedCreek InterFace include file.\r
+**\r
+** ---------------------------------------------------------------------\r
+** --- Copyright (c) 1998, RedCreek Communications Inc. ---\r
+** --- All rights reserved. ---\r
+** ---------------------------------------------------------------------\r
+**\r
+** File Description:\r
+**\r
+** Header file private ioctl commands.\r
+**\r
+**\r
+** This program is free software; you can redistribute it and/or modify\r
+** it under the terms of the GNU General Public License as published by\r
+** the Free Software Foundation; either version 2 of the License, or\r
+** (at your option) any later version.\r
+\r
+** This program is distributed in the hope that it will be useful,\r
+** but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+** GNU General Public License for more details.\r
+\r
+** You should have received a copy of the GNU General Public License\r
+** along with this program; if not, write to the Free Software\r
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+**\r
+***************************************************************************/\r
+\r
+#ifndef RCIF_H\r
+#define RCIF_H\r
+\r
+/* The following protocol revision # should be incremented every time\r
+ a new protocol or new structures are used in this file. */\r
+int USER_PROTOCOL_REV = 1; /* used to track different protocol revisions */\r
+\r
+/* define a single TCB & buffer */\r
+typedef struct /* a single buffer */\r
+{\r
+ U32 context; /* context */\r
+ U32 scount; /* segment count */\r
+ U32 size; /* segment size */\r
+ U32 addr; /* segment physical address */\r
+}\r
+__attribute__((packed))\r
+singleB, *psingleB ;\r
+typedef struct /* a single TCB */\r
+{\r
+ /*\r
+ ** +-----------------------+\r
+ ** | 1 | one buffer in the TCB\r
+ ** +-----------------------+\r
+ ** | <user's Context> | user's buffer reference\r
+ ** +-----------------------+\r
+ ** | 1 | one segment buffer\r
+ ** +-----------------------+ _\r
+ ** | <buffer size> | size \ \r
+ ** +-----------------------+ \ segment descriptor\r
+ ** | <physical address> | physical address of buffer /\r
+ ** +-----------------------+ _/\r
+ */\r
+ U32 bcount; /* buffer count */\r
+ singleB b; /* buffer */\r
+\r
+}\r
+__attribute__((packed))\r
+singleTCB, *psingleTCB;\r
+\r
+/*\r
+ When adding new entries, please add all 5 related changes, since \r
+ it helps keep everything consistent:\r
+ 1) User structure entry\r
+ 2) User data entry\r
+ 3) Structure short-cut entry\r
+ 4) Data short-cut entry\r
+ 5) Command identifier entry\r
+\r
+ For Example ("GETSPEED"):\r
+ 1) struct RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed;\r
+ 2) struct RCgetspeed_tag *getspeed;\r
+ 3) #define RCUS_GETSPEED data.RCgetspeed;\r
+ 4) #define RCUD_GETSPEED _RC_user_data.getspeed\r
+ 5) #define RCUC_GETSPEED 0x02\r
+ \r
+ Notes for the "GETSPEED" entry, above:\r
+ 1) RCgetspeed - RC{name}\r
+ RCgetspeed_tag - RC{name}_tag\r
+ LinkSpeedCode - create any structure format desired (not too large,\r
+ since memory will be unioned with all other entries)\r
+ 2) RCgetspeed_tag - RC{name}_tag chosen in #1\r
+ getspeed - arbitrary name (ptr to structure in #1)\r
+ 3) RCUS_GETSPEED - RCUS_{NAME} ("NAME" & "name" do not have to the same)\r
+ data.RCgetspeed - data.RC{name} ("RC{name}" from #1)\r
+ 4) RCUD_GETSPEED - _RC_user_data.getspeed ("getspeed" from #2)\r
+ 5) RCUC_GETSPEED - unique hex identifier entry.\r
+*/\r
+\r
+typedef struct RC_user_tag RCuser_struct;\r
+\r
+/* 1) User structure entry */\r
+struct RC_user_tag\r
+{\r
+ int cmd;\r
+ union\r
+ {\r
+ /* GETINFO structure */\r
+ struct RCgetinfo_tag {\r
+ unsigned long int mem_start;\r
+ unsigned long int mem_end;\r
+ unsigned long int base_addr;\r
+ unsigned char irq;\r
+ unsigned char dma;\r
+ unsigned char port;\r
+ } RCgetinfo; /* <---- RCgetinfo */\r
+ \r
+ /* GETSPEED structure */\r
+ struct RCgetspeed_tag {\r
+ U32 LinkSpeedCode;\r
+ } RCgetspeed; /* <---- RCgetspeed */\r
+ \r
+ /* GETFIRMWAREVER structure */\r
+ #define FirmStringLen 80\r
+ struct RCgetfwver_tag {\r
+ U8 FirmString[FirmStringLen];\r
+ } RCgetfwver; /* <---- RCgetfwver */\r
+ \r
+ /* GETIPANDMASK structure */\r
+ struct RCgetipnmask_tag {\r
+ U32 IpAddr;\r
+ U32 NetMask;\r
+ } RCgetipandmask; /* <---- RCgetipandmask */\r
+\r
+ /* GETMAC structure */\r
+ #define MAC_SIZE 10\r
+ struct RCgetmac_tag {\r
+ U8 mac[MAC_SIZE];\r
+ } RCgetmac; /* <---- RCgetmac */\r
+\r
+ /* GETLINKSTATUS structure */\r
+ struct RCgetlnkstatus_tag {\r
+ U32 ReturnStatus;\r
+ } RCgetlnkstatus; /* <---- RCgetlnkstatus */\r
+\r
+ /* GETLINKSTATISTICS structure */\r
+ struct RCgetlinkstats_tag {\r
+ RCLINKSTATS StatsReturn;\r
+ } RCgetlinkstats; /* <---- RCgetlinkstats */\r
+\r
+ /* DEFAULT structure (when no command was recognized) */\r
+ struct RCdefault_tag {\r
+ int rc;\r
+ } RCdefault; /* <---- RCdefault */\r
+\r
+ } data;\r
+\r
+}; /* struct RC_user_tag { ... } */\r
+\r
+/* 2) User data entry */\r
+/* RCUD = RedCreek User Data */\r
+union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */\r
+ struct RCgetinfo_tag *getinfo;\r
+ struct RCgetspeed_tag *getspeed;\r
+ struct RCgetfwver_tag *getfwver;\r
+ struct RCgetipnmask_tag *getipandmask;\r
+ struct RCgetmac_tag *getmac;\r
+ struct RCgetlnkstatus_tag *getlinkstatus;\r
+ struct RCgetlinkstats_tag *getlinkstatistics;\r
+ struct RCdefault_tag *rcdefault;\r
+} _RC_user_data; /* declare as a global, so the defines below will work */\r
+\r
+/* 3) Structure short-cut entry */\r
+/* define structure short-cuts */ /* structure names are taken from RC_user_tag structure above */\r
+#define RCUS_GETINFO data.RCgetinfo;\r
+#define RCUS_GETSPEED data.RCgetspeed;\r
+#define RCUS_GETFWVER data.RCgetfwver;\r
+#define RCUS_GETIPANDMASK data.RCgetipandmask;\r
+#define RCUS_GETMAC data.RCgetmac;\r
+#define RCUS_GETLINKSTATUS data.RCgetlnkstatus;\r
+#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;\r
+#define RCUS_DEFAULT data.RCdefault;\r
+\r
+/* 4) Data short-cut entry */\r
+/* define data short-cuts */ /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */\r
+#define RCUD_GETINFO _RC_user_data.getinfo\r
+#define RCUD_GETSPEED _RC_user_data.getspeed\r
+#define RCUD_GETFWVER _RC_user_data.getfwver\r
+#define RCUD_GETIPANDMASK _RC_user_data.getipandmask\r
+#define RCUD_GETMAC _RC_user_data.getmac\r
+#define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus\r
+#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics\r
+#define RCUD_DEFAULT _RC_user_data.rcdefault\r
+\r
+/* 5) Command identifier entry */\r
+/* define command identifiers */\r
+#define RCUC_GETINFO 0x01\r
+#define RCUC_GETSPEED 0x02\r
+#define RCUC_GETFWVER 0x03\r
+#define RCUC_GETIPANDMASK 0x04\r
+#define RCUC_GETMAC 0x05\r
+#define RCUC_GETLINKSTATUS 0x06\r
+#define RCUC_GETLINKSTATISTICS 0x07\r
+#define RCUC_DEFAULT 0xff\r
+\r
+/* define ioctl commands to use, when talking to RC 45/PCI driver */\r
+#define RCU_PROTOCOL_REV SIOCDEVPRIVATE\r
+#define RCU_COMMAND SIOCDEVPRIVATE+1\r
+\r
+/*\r
+ Intended use for the above defines is shown below (GETINFO, as this example):\r
+\r
+ RCuser_struct RCuser; // declare RCuser structure\r
+ struct ifreq ifr; // declare an interface request structure\r
+\r
+ RCuser.cmd = RCUC_GETINFO; // set user command to GETINFO\r
+ ifr->ifr_data = (caddr_t) &RCuser; // set point to user structure\r
+\r
+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); // get a socket\r
+ ioctl(sock, RCU_COMMAND, &ifr); // do ioctl on socket\r
+\r
+ RCUD_GETINFO = &RCuser.RCUS_GETINFO; // set data pointer for GETINFO\r
+\r
+ // print results\r
+ printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n",\r
+ RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end,\r
+ RCUD_GETINFO->base_addr, RCUD_GETINFO->irq);\r
+*/\r
+\r
+#endif /* RCIF_H */\r
+\r
--- /dev/null
+/*
+** *************************************************************************
+**
+**
+** R C M T L . C $Revision: 1.1 $
+**
+**
+** RedCreek Message Transport Layer program module.
+**
+** ---------------------------------------------------------------------
+** --- Copyright (c) 1997-1998, RedCreek Communications Inc. ---
+** --- All rights reserved. ---
+** ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Host side message transport layer.
+**
+** 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.
+**
+***************************************************************************/
+
+#undef DEBUG
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+
+#define dprintf kprintf
+
+extern int printk(const char * fmt, ...);
+
+ /* RedCreek LAN device Target ID */
+#define LAN_TARGET_ID 0x10
+ /* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT 0xA17
+
+
+/*
+** message structures
+*/
+
+#define TID_SZ 12
+#define FUNCTION_SZ 8
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define TRL_SINGLE_FIXED_LENGTH 0x00
+#define TRL_SINGLE_VARIABLE_LENGTH 0x40
+#define TRL_MULTIPLE_FIXED_LENGTH 0x80
+
+/* LAN Class specific functions */
+
+#define LAN_PACKET_SEND 0x3B
+#define LAN_SDU_SEND 0x3D
+#define LAN_RECEIVE_POST 0x3E
+#define LAN_RESET 0x35
+#define LAN_SHUTDOWN 0x37
+
+/* Private Class specfic function */
+#define RC_PRIVATE 0xFF
+
+/* RC Executive Function Codes. */
+
+#define RC_CMD_ADAPTER_ASSIGN 0xB3
+#define RC_CMD_ADAPTER_READ 0xB2
+#define RC_CMD_ADAPTER_RELEASE 0xB5
+#define RC_CMD_BIOS_INFO_SET 0xA5
+#define RC_CMD_BOOT_DEVICE_SET 0xA7
+#define RC_CMD_CONFIG_VALIDATE 0xBB
+#define RC_CMD_CONN_SETUP 0xCA
+#define RC_CMD_DEVICE_ASSIGN 0xB7
+#define RC_CMD_DEVICE_RELEASE 0xB9
+#define RC_CMD_HRT_GET 0xA8
+#define RC_CMD_ADAPTER_CLEAR 0xBE
+#define RC_CMD_ADAPTER_CONNECT 0xC9
+#define RC_CMD_ADAPTER_RESET 0xBD
+#define RC_CMD_LCT_NOTIFY 0xA2
+#define RC_CMD_OUTBOUND_INIT 0xA1
+#define RC_CMD_PATH_ENABLE 0xD3
+#define RC_CMD_PATH_QUIESCE 0xC5
+#define RC_CMD_PATH_RESET 0xD7
+#define RC_CMD_STATIC_MF_CREATE 0xDD
+#define RC_CMD_STATIC_MF_RELEASE 0xDF
+#define RC_CMD_STATUS_GET 0xA0
+#define RC_CMD_SW_DOWNLOAD 0xA9
+#define RC_CMD_SW_UPLOAD 0xAB
+#define RC_CMD_SW_REMOVE 0xAD
+#define RC_CMD_SYS_ENABLE 0xD1
+#define RC_CMD_SYS_MODIFY 0xC1
+#define RC_CMD_SYS_QUIESCE 0xC3
+#define RC_CMD_SYS_TAB_SET 0xA3
+
+
+ /* Init Outbound Q status */
+#define RC_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01
+#define RC_CMD_OUTBOUND_INIT_REJECTED 0x02
+#define RC_CMD_OUTBOUND_INIT_FAILED 0x03
+#define RC_CMD_OUTBOUND_INIT_COMPLETE 0x04
+
+
+#define UTIL_NOP 0x00
+
+
+/* RC Get Status State values */
+
+#define ADAPTER_STATE_INITIALIZING 0x01
+#define ADAPTER_STATE_RESET 0x02
+#define ADAPTER_STATE_HOLD 0x04
+#define ADAPTER_STATE_READY 0x05
+#define ADAPTER_STATE_OPERATIONAL 0x08
+#define ADAPTER_STATE_FAILED 0x10
+#define ADAPTER_STATE_FAULTED 0x11
+
+
+/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */
+
+#define RC_REPLY_STATUS_SUCCESS 0x00
+#define RC_REPLY_STATUS_ABORT_DIRTY 0x01
+#define RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define RC_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
+#define RC_REPLY_STATUS_ERROR_DIRTY 0x04
+#define RC_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
+#define RC_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
+#define RC_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07
+#define RC_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08
+#define RC_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09
+#define RC_REPLY_STATUS_TRANSACTION_ERROR 0x0A
+#define RC_REPLY_STATUS_PROGRESS_REPORT 0x80
+
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
+
+#define RC_DS_SUCCESS 0x0000
+#define RC_DS_BAD_KEY 0x0001
+#define RC_DS_CHAIN_BUFFER_TOO_LARGE 0x0002
+#define RC_DS_DEVICE_BUSY 0x0003
+#define RC_DS_DEVICE_LOCKED 0x0004
+#define RC_DS_DEVICE_NOT_AVAILABLE 0x0005
+#define RC_DS_DEVICE_RESET 0x0006
+#define RC_DS_INAPPROPRIATE_FUNCTION 0x0007
+#define RC_DS_INSUFFICIENT_RESOURCE_HARD 0x0008
+#define RC_DS_INSUFFICIENT_RESOURCE_SOFT 0x0009
+#define RC_DS_INVALID_INITIATOR_ADDRESS 0x000A
+#define RC_DS_INVALID_MESSAGE_FLAGS 0x000B
+#define RC_DS_INVALID_OFFSET 0x000C
+#define RC_DS_INVALID_PARAMETER 0x000D
+#define RC_DS_INVALID_REQUEST 0x000E
+#define RC_DS_INVALID_TARGET_ADDRESS 0x000F
+#define RC_DS_MESSAGE_TOO_LARGE 0x0010
+#define RC_DS_MESSAGE_TOO_SMALL 0x0011
+#define RC_DS_MISSING_PARAMETER 0x0012
+#define RC_DS_NO_SUCH_PAGE 0x0013
+#define RC_DS_REPLY_BUFFER_FULL 0x0014
+#define RC_DS_TCL_ERROR 0x0015
+#define RC_DS_TIMEOUT 0x0016
+#define RC_DS_UNKNOWN_ERROR 0x0017
+#define RC_DS_UNKNOWN_FUNCTION 0x0018
+#define RC_DS_UNSUPPORTED_FUNCTION 0x0019
+#define RC_DS_UNSUPPORTED_VERSION 0x001A
+
+ /* msg header defines for VersionOffset */
+#define RCMSGVER_1 0x0001
+#define SGL_OFFSET_0 RCMSGVER_1
+#define SGL_OFFSET_4 (0x0040 | RCMSGVER_1)
+#define TRL_OFFSET_5 (0x0050 | RCMSGVER_1)
+#define TRL_OFFSET_6 (0x0060 | RCMSGVER_1)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC 0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL 0x2000
+#define MSG_LAST 0x4000
+#define MSG_REPLY 0x8000
+
+ /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE 0x00040000
+#define FIVE_WORD_MSG_SIZE 0x00050000
+#define SIX_WORD_MSG_SIZE 0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE 0x00090000
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID 0
+#define HOST_TID 1
+
+ /* RedCreek private message codes */
+#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */
+#define RC_PRIVATE_SET_MAC_ADDR 0x0002
+#define RC_PRIVATE_GET_LAN_STATS 0x0003
+#define RC_PRIVATE_GET_LINK_STATUS 0x0004
+#define RC_PRIVATE_SET_LINK_SPEED 0x0005
+#define RC_PRIVATE_SET_IP_AND_MASK 0x0006
+/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 */ /* OBSOLETE */
+#define RC_PRIVATE_GET_LINK_SPEED 0x0008
+#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
+/* #define RC_PRIVATE_GET_MAC_ADDR 0x000A *//**/
+#define RC_PRIVATE_GET_IP_AND_MASK 0x000B /**/
+#define RC_PRIVATE_DEBUG_MSG 0x000C
+#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D
+
+#define RC_PRIVATE_REBOOT 0x00FF
+
+
+/* RC message header */
+typedef struct _RC_MSG_FRAME
+{
+ U8 VersionOffset;
+ U8 MsgFlags;
+ U16 MessageSize;
+ BF TargetAddress:TID_SZ;
+ BF InitiatorAddress:TID_SZ;
+ BF Function:FUNCTION_SZ;
+ U32 InitiatorContext;
+ /* SGL[] */
+}
+ RC_MSG_FRAME, *PRC_MSG_FRAME;
+
+
+ /* assumed a 16K minus 256 byte space for outbound queue message frames */
+#define MSG_FRAME_SIZE 512
+#define NMBR_MSG_FRAMES 30
+
+/*
+** Message Unit CSR definitions for RedCreek PCI45 board
+*/
+typedef struct tag_rcatu
+{
+ volatile unsigned long APICRegSel; /* APIC Register Select */
+ volatile unsigned long reserved0;
+ volatile unsigned long APICWinReg; /* APIC Window Register */
+ volatile unsigned long reserved1;
+ volatile unsigned long InMsgReg0; /* inbound message register 0 */
+ volatile unsigned long InMsgReg1; /* inbound message register 1 */
+ volatile unsigned long OutMsgReg0; /* outbound message register 0 */
+ volatile unsigned long OutMsgReg1; /* outbound message register 1 */
+ volatile unsigned long InDoorReg; /* inbound doorbell register */
+ volatile unsigned long InIntStat; /* inbound interrupt status register */
+ volatile unsigned long InIntMask; /* inbound interrupt mask register */
+ volatile unsigned long OutDoorReg; /* outbound doorbell register */
+ volatile unsigned long OutIntStat; /* outbound interrupt status register */
+ volatile unsigned long OutIntMask; /* outbound interrupt mask register */
+ volatile unsigned long reserved2;
+ volatile unsigned long reserved3;
+ volatile unsigned long InQueue; /* inbound queue port */
+ volatile unsigned long OutQueue; /* outbound queue port */
+ volatile unsigned long reserved4;
+ volatile unsigned long reserver5;
+ /* RedCreek extension */
+ volatile unsigned long EtherMacLow;
+ volatile unsigned long EtherMacHi;
+ volatile unsigned long IPaddr;
+ volatile unsigned long IPmask;
+}
+ ATU, *PATU;
+
+ /*
+ ** typedef PAB
+ **
+ ** PCI Adapter Block - holds instance specific information and is located
+ ** in a reserved space at the start of the message buffer allocated by user.
+ */
+typedef struct
+{
+ PATU p_atu; /* ptr to ATU register block */
+ PU8 pPci45LinBaseAddr;
+ PU8 pLinOutMsgBlock;
+ U32 outMsgBlockPhyAddr;
+ PFNTXCALLBACK pTransCallbackFunc;
+ PFNRXCALLBACK pRecvCallbackFunc;
+ PFNCALLBACK pRebootCallbackFunc;
+ PFNCALLBACK pCallbackFunc;
+ U16 ADAPTERState;
+ U16 InboundMFrameSize;
+}
+ PAB, *PPAB;
+
+ /*
+ ** in reserved space right after PAB in host memory is area for returning
+ ** values from card
+ */
+
+ /*
+ ** Array of pointers to PCI Adapter Blocks.
+ ** Indexed by a zero based (0-31) interface number.
+ */
+#define MAX_ADAPTERS 32
+static PPAB PCIAdapterBlock[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
+};
+
+
+/*
+** typedef NICSTAT
+**
+** Data structure for NIC statistics retruned from PCI card. Data copied from
+** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
+*/
+typedef struct tag_NicStat
+{
+ unsigned long TX_good;
+ unsigned long TX_maxcol;
+ unsigned long TX_latecol;
+ unsigned long TX_urun;
+ unsigned long TX_crs; /* lost carrier sense */
+ unsigned long TX_def; /* transmit deferred */
+ unsigned long TX_singlecol; /* single collisions */
+ unsigned long TX_multcol;
+ unsigned long TX_totcol;
+ unsigned long Rcv_good;
+ unsigned long Rcv_CRCerr;
+ unsigned long Rcv_alignerr;
+ unsigned long Rcv_reserr; /* rnr'd pkts */
+ unsigned long Rcv_orun;
+ unsigned long Rcv_cdt;
+ unsigned long Rcv_runt;
+ unsigned long dump_status; /* last field directly from the chip */
+}
+ NICSTAT, *P_NICSTAT;
+
+
+#define DUMP_DONE 0x0000A005 /* completed statistical dump */
+#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */
+
+
+static volatile int msgFlag;
+
+
+/* local function prototypes */
+static void ProcessOutboundAdapterMsg(PPAB pPab, U32 phyMsgAddr);
+static int FillAdapterMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
+static int GetAdapterStatus(PPAB pPab);
+static int SendAdapterOutboundQInitMsg(PPAB pPab);
+static int SendEnableSysMsg(PPAB pPab);
+
+
+ /* 1st 100h bytes of message block is reserved for messenger instance */
+#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
+
+/*
+** =========================================================================
+** InitRCApiMsgLayer()
+**
+** Initialize the RedCreek API Module and adapter.
+**
+** Inputs: AdapterID - interface number from 0 to 15
+** pciBaseAddr - virual base address of PCI (set by BIOS)
+** p_msgbuf - virual address to private message block (min. 16K)
+** p_phymsgbuf - physical address of private message block
+** TransmitCallbackFunction - address of transmit callback function
+** ReceiveCallbackFunction - address of receive callback function
+**
+** private message block is allocated by user. It must be in locked pages.
+** p_msgbuf and p_phymsgbuf point to the same location. Must be contigous
+** memory block of a minimum of 16K byte and long word aligned.
+** =========================================================================
+*/
+RC_RETURN
+InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr,
+ PU8 p_msgbuf, PU8 p_phymsgbuf,
+ PFNTXCALLBACK TransmitCallbackFunction,
+ PFNRXCALLBACK ReceiveCallbackFunction,
+ PFNCALLBACK RebootCallbackFunction)
+{
+ int result;
+ PPAB pPab;
+
+#ifdef DEBUG
+ kprintf("InitAPI: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
+ "TransmitCallbackFunction:0x%08.8ulx ReceiveCallbackFunction:0x%08.8ulx\n",
+ AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
+#endif /* DEBUG */
+
+
+ /* Check if this interface already initialized - if so, shut it down */
+ if (PCIAdapterBlock[AdapterID] != NULL)
+ {
+ printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
+// RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+ PCIAdapterBlock[AdapterID] = NULL;
+ }
+
+ /*
+ ** store adapter instance values in adapter block.
+ ** Adapter block is at beginning of message buffer
+ */
+ pPab = (PPAB)p_msgbuf;
+
+ pPab->p_atu = (PATU)pciBaseAddr;
+ pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr;
+
+ /* Set outbound message frame addr - skip over Adapter Block */
+ pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+ pPab->pLinOutMsgBlock = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+
+ /* store callback function addresses */
+ pPab->pTransCallbackFunc = TransmitCallbackFunction;
+ pPab->pRecvCallbackFunc = ReceiveCallbackFunction;
+ pPab->pRebootCallbackFunc = RebootCallbackFunction;
+ pPab->pCallbackFunc = (PFNCALLBACK)NULL;
+
+ /*
+ ** Initialize API
+ */
+ result = GetAdapterStatus(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ if (pPab->ADAPTERState == ADAPTER_STATE_OPERATIONAL)
+ {
+ printk("pPab->ADAPTERState == op: resetting adapter\n");
+ RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+ }
+
+ result = SendAdapterOutboundQInitMsg(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ result = SendEnableSysMsg(pPab);
+
+ if (result != RC_RTN_NO_ERROR)
+ return result;
+
+ PCIAdapterBlock[AdapterID] = pPab;
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** Disable and Enable Adapter interrupts. Adapter interrupts are enabled at Init time
+** but can be disabled and re-enabled through these two function calls.
+** Packets will still be put into any posted received buffers and packets will
+** be sent through RCSendPacket() functions. Disabling Adapter interrupts
+** will prevent hardware interrupt to host even though the outbound Adapter msg
+** queue is not emtpy.
+** =========================================================================
+*/
+#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */
+
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID)
+{
+ PPAB pPab;
+
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
+
+ return RC_RTN_NO_ERROR;
+}
+
+RC_RETURN RCEnableAdapterInterrupts(U16 AdapterID)
+{
+ PPAB pPab;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
+
+ return RC_RTN_NO_ERROR;
+
+}
+
+
+/*
+** =========================================================================
+** RCSendPacket()
+** =========================================================================
+*/
+RC_RETURN
+RCSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
+{
+ U32 msgOffset;
+ PU32 pMsg;
+ int size;
+ PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCSendPacket()...\n");
+#endif /* DEBUG */
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ /* get Inbound free Q entry - reading from In Q gets free Q entry */
+ /* offset to Msg Frame in PCI msg block */
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("RCSendPacket(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+ if (size == -1) /* error processing TCB - send NOP msg */
+ {
+#ifdef DEBUG
+ kprintf("RCSendPacket(): Error Rrocess TCB!\n");
+#endif /* DEBUG */
+ pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ return RC_RTN_TCB_ERROR;
+ }
+ else /* send over msg header */
+ {
+ pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+ pMsg[1] = LAN_PACKET_SEND << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = InitiatorContext;
+ pMsg[3] = 0; /* batch reply */
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_NO_ERROR;
+ }
+}
+
+
+/*
+** =========================================================================
+** RCPostRecvBuffer()
+**
+** inputs: pBufrCntrlBlock - pointer to buffer control block
+**
+** returns TRUE if successful in sending message, else FALSE.
+** =========================================================================
+*/
+RC_RETURN
+RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
+{
+ U32 msgOffset;
+ PU32 pMsg;
+ int size;
+ PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCPostRecvBuffers()...\n");
+#endif /* DEBUG */
+
+ /* search for DeviceHandle */
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+
+ /* get Inbound free Q entry - reading from In Q gets free Q entry */
+ /* offset to Msg Frame in PCI msg block */
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+
+ }
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+ if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
+ {
+#ifdef DEBUG
+ kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
+#endif /* DEBUG */
+ pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ /* post to Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_TCB_ERROR;
+ }
+ else /* send over size msg header */
+ {
+ pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+ pMsg[1] = LAN_RECEIVE_POST << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
+ /* post to Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+ return RC_RTN_NO_ERROR;
+ }
+}
+
+
+/*
+** =========================================================================
+** RCProcMsgQ()
+**
+** Process outbound message queue until empty.
+** =========================================================================
+*/
+void
+RCProcMsgQ(U16 AdapterID)
+{
+ U32 phyAddrMsg;
+ PU8 p8Msg;
+ PU32 p32;
+ U16 count;
+ PPAB pPab;
+ unsigned char debug_msg[20];
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return;
+
+ phyAddrMsg = pPab->p_atu->OutQueue;
+
+ while (phyAddrMsg != 0xFFFFFFFF)
+ {
+ p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+ p32 = (PU32)p8Msg;
+
+ //printk(" msg: 0x%x 0x%x \n", p8Msg[7], p32[5]);
+
+ /*
+ ** Send Packet Reply Msg
+ */
+ if (LAN_PACKET_SEND == p8Msg[7]) /* function code byte */
+ {
+ count = *(PU16)(p8Msg+2);
+ count -= p8Msg[0] >> 4;
+ /* status, count, context[], adapter */
+ (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
+ }
+ /*
+ ** Receive Packet Reply Msg */
+ else if (LAN_RECEIVE_POST == p8Msg[7])
+ {
+#ifdef DEBUG
+ kprintf("RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
+ kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[0], p32[1], p32[2], p32[3]);
+ kprintf(" 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[4], p32[5], p32[6], p32[7]);
+ kprintf(" 0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ p32[8], p32[9], p32[10], p32[11]);
+#endif
+ /* status, count, buckets remaining, packetParmBlock, adapter */
+ (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
+
+
+ }
+ else if (LAN_RESET == p8Msg[7] || LAN_SHUTDOWN == p8Msg[7])
+ {
+ if (pPab->pCallbackFunc)
+ {
+ (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
+ }
+ else
+ {
+ pPab->pCallbackFunc = (PFNCALLBACK) 1;
+ }
+ //PCIAdapterBlock[AdapterID] = 0;
+ }
+ else if (RC_PRIVATE == p8Msg[7])
+ {
+ //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
+ switch (p32[5])
+ {
+ case RC_PRIVATE_DEBUG_MSG:
+ msgFlag = 1;
+ /*printk("Received RC_PRIVATE msg\n");*/
+ debug_msg[15] = (p32[6]&0xff000000) >> 24;
+ debug_msg[14] = (p32[6]&0x00ff0000) >> 16;
+ debug_msg[13] = (p32[6]&0x0000ff00) >> 8;
+ debug_msg[12] = (p32[6]&0x000000ff);
+
+ debug_msg[11] = (p32[7]&0xff000000) >> 24;
+ debug_msg[10] = (p32[7]&0x00ff0000) >> 16;
+ debug_msg[ 9] = (p32[7]&0x0000ff00) >> 8;
+ debug_msg[ 8] = (p32[7]&0x000000ff);
+
+ debug_msg[ 7] = (p32[8]&0xff000000) >> 24;
+ debug_msg[ 6] = (p32[8]&0x00ff0000) >> 16;
+ debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
+ debug_msg[ 4] = (p32[8]&0x000000ff);
+
+ debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
+ debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
+ debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
+ debug_msg[ 0] = (p32[9]&0x000000ff);
+
+ debug_msg[16] = '\0';
+ printk (debug_msg);
+ break;
+ case RC_PRIVATE_REBOOT:
+ printk("Adapter reboot initiated...\n");
+ if (pPab->pRebootCallbackFunc)
+ {
+ (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
+ }
+ break;
+ default:
+ printk("Unknown private msg received: 0x%x\n",
+ p32[5]);
+ break;
+ }
+ }
+
+ /*
+ ** Process other Msg's
+ */
+ else
+ {
+ ProcessOutboundAdapterMsg(pPab, phyAddrMsg);
+ }
+
+ /* return MFA to outbound free Q*/
+ pPab->p_atu->OutQueue = phyAddrMsg;
+
+ /* any more msgs? */
+ phyAddrMsg = pPab->p_atu->OutQueue;
+ }
+}
+
+
+/*
+** =========================================================================
+** Returns LAN interface statistical counters to space provided by caller at
+** StatsReturnAddr. Returns 0 if success, else RC_RETURN code.
+** This function will call the WaitCallback function provided by
+** user while waiting for card to respond.
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatistics(U16 AdapterID,
+ P_RCLINKSTATS StatsReturnAddr,
+ PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset;
+ volatile U32 timeout;
+ volatile PU32 pMsg;
+ volatile PU32 p32, pReturnAddr;
+ P_NICSTAT pStats;
+ int i;
+ PPAB pPab;
+
+/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ #ifdef DEBUG
+ kprintf("Get8255XStats(): Inbound Free Q empty!\n");
+ #endif
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x112; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LAN_STATS;
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+
+ pStats = (P_NICSTAT)p32;
+ pStats->dump_status = 0xFFFFFFFF;
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ timeout = 100000;
+ while (1)
+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (pStats->dump_status != 0xFFFFFFFF)
+ break;
+
+ if (!timeout--)
+ {
+ #ifdef DEBUG
+ kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
+ #endif
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ pReturnAddr = (PU32)StatsReturnAddr;
+
+ /* copy Nic stats to user's structure */
+ for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
+ pReturnAddr[i] = p32[i];
+
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** Get82558LinkStatus()
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset;
+ volatile U32 timeout;
+ volatile PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ #ifdef DEBUG
+ dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
+ #endif
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x112; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ *p32 = 0xFFFFFFFF;
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ timeout = 100000;
+ while (1)
+ {
+ U32 i;
+
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (*p32 != 0xFFFFFFFF)
+ break;
+
+ if (!timeout--)
+ {
+ #ifdef DEBUG
+ kprintf("Timeout waiting for link status\n");
+ #endif
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ *ReturnAddr = *p32; /* 1 = up 0 = down */
+
+ return RC_RTN_NO_ERROR;
+
+}
+
+/*
+** =========================================================================
+** RCGetMAC()
+**
+** get the MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
+{
+ unsigned i, timeout;
+ U32 off;
+ PU32 p;
+ U32 temp[2];
+ PPAB pPab;
+ PATU p_atu;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ p_atu = pPab->p_atu;
+
+ p_atu->EtherMacLow = 0; /* first zero return data */
+ p_atu->EtherMacHi = 0;
+
+ off = p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ p = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef RCDEBUG
+ printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
+ (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+ /* setup private message */
+ p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ p[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ p[2] = 0; /* initiator context */
+ p[3] = 0x218; /* transaction context */
+ p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
+
+
+ p_atu->InQueue = off; /* send it to the device */
+#ifdef RCDEBUG
+ printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
+ (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+
+ /* wait for the rcpci45 board to update the info */
+ timeout = 1000000;
+ while (0 == p_atu->EtherMacLow)
+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (!timeout--)
+ {
+ printk("rc_getmac: Timeout\n");
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+ /* read the mac address */
+ temp[0] = p_atu->EtherMacLow;
+ temp[1] = p_atu->EtherMacHi;
+ memcpy((char *)mac, (char *)temp, 6);
+
+
+#ifdef RCDEBUG
+// printk("rc_getmac: 0x%X\n", ptr);
+#endif /* RCDEBUG */
+
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** RCSetMAC()
+**
+** set MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCSetMAC(U16 AdapterID, PU8 mac)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
+ pMsg[5] = *(unsigned *)mac; /* first four bytes */
+ pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetLinkSpeed()
+**
+** set ethernet link speed.
+** input: speedControl - determines action to take as follows
+** 0 = reset and auto-negotiate (NWay)
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex 10BaseT
+** 4 = Half duplex 10BaseT
+** all other values are ignore (do nothing)
+** =========================================================================
+*/
+RC_RETURN
+RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
+ pMsg[5] = LinkSpeedCode; /* link speed code */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetLinkSpeed()
+**
+** get ethernet link speed.
+**
+** 0 = Unknown
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex 10BaseT
+** 4 = Half duplex 10BaseT
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ U8 AdapterLinkSpeed;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for link speed from adapter\n");
+ kprintf("0x%08.8ulx\n", p32[0]);
+ return RC_RTN_NO_LINK_SPEED;
+ }
+ }
+
+ /* get Link speed */
+ AdapterLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+ *pLinkSpeedCode= AdapterLinkSpeed;
+
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE 0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability)
+{
+ U32 off;
+ PU32 pMsg;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
+ pMsg[5] = capability;
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+ PPAB pPab;
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ /* virtual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0xff;
+
+ /* setup private message */
+ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
+ /* phys address to return status - area right after PAB */
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] != 0xff)
+ break;
+
+ if (!timeout--)
+ {
+ kprintf("Timeout waiting for link speed from adapter\n");
+ return RC_RTN_NO_FIRM_VER;
+ }
+ }
+
+ strcpy(pFirmString, (PU8)p32);
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCResetLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when
+** reset is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** reset is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN
+RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+ unsigned long off;
+ unsigned long *pMsg;
+ PPAB pPab;
+ int i;
+ long timeout = 0;
+
+
+ pPab =PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pPab->pCallbackFunc = CallbackFunction;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup message */
+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = LAN_RESET << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = ResourceFlags << 16; /* resource flags */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ if (CallbackFunction == (PFNCALLBACK)NULL)
+ {
+ /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+ or until timer goes off */
+ while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+ {
+ RCProcMsgQ(AdapterID);
+ for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
+ ;
+ timeout++;
+ if (timeout > 10000)
+ {
+ break;
+ }
+ }
+ if (ReturnAddr != (PU32)NULL)
+ *ReturnAddr = (U32)pPab->pCallbackFunc;
+ }
+
+ return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCResetAdapter()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+RC_RETURN
+RCResetAdapter(U16 AdapterID)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ PPAB pPab;
+ volatile PU32 p32;
+
+ pPab = PCIAdapterBlock[AdapterID];
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virtual address of msg - virtual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID;
+ pMsg[2] = 0; /* universal context */
+ pMsg[3] = 0; /* universal context */
+ pMsg[4] = 0; /* universal context */
+ pMsg[5] = 0; /* universal context */
+ /* phys address to return status - area right after PAB */
+ pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+ pMsg[7] = 0;
+ pMsg[8] = 1; /* return 1 byte */
+
+ /* virual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0;
+ p32[1] = 0;
+
+ /* post to Inbound Post Q */
+
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] || p32[1])
+ break;
+
+ if (!timeout--)
+ {
+ printk("RCResetAdapter timeout\n");
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCShutdownLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when
+** shutdown is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** shutdown is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+ volatile PU32 pMsg;
+ U32 off;
+ PPAB pPab;
+ int i;
+ long timeout = 0;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pPab->pCallbackFunc = CallbackFunction;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup message */
+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = LAN_SHUTDOWN << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = ResourceFlags << 16; /* resource flags */
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+
+ if (CallbackFunction == (PFNCALLBACK)NULL)
+ {
+ /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+ or until timer goes off */
+ while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+ {
+ RCProcMsgQ(AdapterID);
+ for (i = 0; i < 100000; i++) /* please don't hog the bus!!! */
+ ;
+ timeout++;
+ if (timeout > 10000)
+ {
+ break;
+ }
+ }
+ if (ReturnAddr != (PU32)NULL)
+ *ReturnAddr = (U32)pPab->pCallbackFunc;
+ }
+ return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetRavlinIPandMask()
+**
+** Set the Ravlin 45/PCI cards IP address and network mask.
+**
+** IP address and mask must be in network byte order.
+** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+** 0x04030201 and 0x00FFFFFF on a little endian machine.
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
+{
+ volatile PU32 pMsg;
+ U32 off;
+ PPAB pPab;
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ off = pPab->p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+ /* setup private message */
+ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x219; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
+ pMsg[5] = ipAddr;
+ pMsg[6] = netMask;
+
+
+ pPab->p_atu->InQueue = off; /* send it to the device */
+ return RC_RTN_NO_ERROR ;
+
+}
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
+ PFNWAITCALLBACK WaitCallback)
+{
+ unsigned i, timeout;
+ U32 off;
+ PU32 pMsg, p32;
+ PPAB pPab;
+ PATU p_atu;
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+ pPab = PCIAdapterBlock[AdapterID];
+
+ if (pPab == NULL)
+ return RC_RTN_ADPTR_NOT_REGISTERED;
+
+ p_atu = pPab->p_atu;
+ off = p_atu->InQueue; /* get addresss of message */
+
+ if (0xFFFFFFFF == off)
+ return RC_RTN_FREE_Q_EMPTY;
+
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ *p32 = 0xFFFFFFFF;
+
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+ /* setup private message */
+ pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+ pMsg[2] = 0; /* initiator context */
+ pMsg[3] = 0x218; /* transaction context */
+ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
+ pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ p_atu->InQueue = off; /* send it to the device */
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+
+ /* wait for the rcpci45 board to update the info */
+ timeout = 100000;
+ while (0xffffffff == *p32)
+ {
+ if (WaitCallback)
+ (*WaitCallback)();
+
+ for (i = 0; i < 1000; i++)
+ ;
+
+ if (!timeout--)
+ {
+ #ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: Timeout\n");
+ #endif /* DEBUG */
+ return RC_RTN_MSG_REPLY_TIMEOUT;
+ }
+ }
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: after time out\n", \
+ "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);
+#endif /* DEBUG */
+
+ /* send IP and mask to user's space */
+ *pIpAddr = p32[0];
+ *pNetMask = p32[1];
+
+
+#ifdef DEBUG
+ kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+ return RC_RTN_NO_ERROR;
+}
+
+/*
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+**
+** local functions
+**
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+*/
+
+/*
+** =========================================================================
+** SendAdapterOutboundQInitMsg()
+**
+** =========================================================================
+*/
+static int
+SendAdapterOutboundQInitMsg(PPAB pPab)
+{
+ U32 msgOffset, timeout, phyOutQFrames, i;
+ volatile PU32 pMsg;
+ volatile PU32 p32;
+
+
+
+ msgOffset = pPab->p_atu->InQueue;
+
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("SendAdapterOutboundQInitMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendAdapterOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+ pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+ pMsg[1] = RC_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x106; /* transaction context */
+ pMsg[4] = 4096; /* Host page frame size */
+ pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */
+ pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */
+ /* phys address to return status - area right after PAB */
+ pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+
+ /* virual pointer to return buffer - clear first two dwords */
+ p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0;
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ /* wait for response */
+ timeout = 100000;
+ while(1)
+ {
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0])
+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG
+ kprintf("Timeout wait for InitOutQ InPrgress status from adapter\n");
+#endif /* DEBUG */
+ return RC_RTN_NO_STATUS;
+ }
+ }
+
+ timeout = 100000;
+ while(1)
+ {
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] == RC_CMD_OUTBOUND_INIT_COMPLETE)
+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG
+ kprintf("Timeout wait for InitOutQ Complete status from adapter\n");
+#endif /* DEBUG */
+ return RC_RTN_NO_STATUS;
+ }
+ }
+
+ /* load PCI outbound free Q with MF physical addresses */
+ phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+ for (i = 0; i < NMBR_MSG_FRAMES; i++)
+ {
+ pPab->p_atu->OutQueue = phyOutQFrames;
+ phyOutQFrames += MSG_FRAME_SIZE;
+ }
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** GetAdapterStatus()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+static int
+GetAdapterStatus(PPAB pPab)
+{
+ U32 msgOffset, timeout;
+ PU32 pMsg;
+ volatile PU32 p32;
+
+
+ msgOffset = pPab->p_atu->InQueue;
+ printk("GetAdapterStatus: msg offset = 0x%x\n", msgOffset);
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("GetAdapterStatus(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+ pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID;
+ pMsg[2] = 0; /* universal context */
+ pMsg[3] = 0; /* universal context */
+ pMsg[4] = 0; /* universal context */
+ pMsg[5] = 0; /* universal context */
+ /* phys address to return status - area right after PAB */
+ pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB);
+ pMsg[7] = 0;
+ pMsg[8] = 88; /* return 88 bytes */
+
+ /* virual pointer to return buffer - clear first two dwords */
+ p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+ p32[0] = 0;
+ p32[1] = 0;
+
+#ifdef DEBUG
+kprintf("GetAdapterStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
+ pMsg, msgOffset, pMsg[1], pMsg[6]);
+#endif /* DEBUG */
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+#ifdef DEBUG
+kprintf("Return status to p32 = 0x%08.8ulx\n", p32);
+#endif /* DEBUG */
+
+ /* wait for response */
+ timeout = 1000000;
+ while(1)
+ {
+ int i;
+
+ for (i = 0; i < 1000; i++) /* please don't hog the bus!!! */
+ ;
+
+ if (p32[0] && p32[1])
+ break;
+
+ if (!timeout--)
+ {
+#ifdef DEBUG
+ kprintf("Timeout waiting for status from adapter\n");
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+ return RC_RTN_NO_STATUS;
+ }
+ }
+
+#ifdef DEBUG
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+ /* get adapter state */
+ pPab->ADAPTERState = ((volatile PU8)p32)[10];
+ pPab->InboundMFrameSize = ((volatile PU16)p32)[6];
+
+#ifdef DEBUG
+ kprintf("adapter state 0x%02.2x InFrameSize = 0x%04.4x\n",
+ pPab->ADAPTERState, pPab->InboundMFrameSize);
+#endif /* DEBUG */
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** SendEnableSysMsg()
+**
+**
+** =========================================================================
+*/
+static int
+SendEnableSysMsg(PPAB pPab)
+{
+ U32 msgOffset; // timeout;
+ volatile PU32 pMsg;
+
+ msgOffset = pPab->p_atu->InQueue;
+
+ if (msgOffset == 0xFFFFFFFF)
+ {
+#ifdef DEBUG
+ kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+ return RC_RTN_FREE_Q_EMPTY;
+ }
+
+ /* calc virual address of msg - virual already mapped to physical */
+ pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+ pMsg[1] = RC_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID;
+ pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+ pMsg[3] = 0x110; /* transaction context */
+ pMsg[4] = 0x50657465; /* RedCreek Private */
+
+ /* post to Inbound Post Q */
+ pPab->p_atu->InQueue = msgOffset;
+
+ return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** FillI12OMsgFromTCB()
+**
+** inputs pMsgU32 - virual pointer (mapped to physical) of message frame
+** pXmitCntrlBlock - pointer to caller buffer control block.
+**
+** fills in LAN SGL after Transaction Control Word or Bucket Count.
+** =========================================================================
+*/
+static int
+FillAdapterMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
+{
+ unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
+ PU32 pTCB, pMsg;
+
+ /* SGL element flags */
+#define EOB 0x40000000
+#define LE 0x80000000
+#define SIMPLE_SGL 0x10000000
+#define BC_PRESENT 0x01000000
+
+ pTCB = (PU32)pTransCtrlBlock;
+ pMsg = pMsgFrame;
+ nmbrDwords = 0;
+
+#ifdef DEBUG
+ kprintf("FillAdapterMsgSGLFromTCBX\n");
+kprintf("TCB 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+ pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
+kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);
+#endif /* DEBUG */
+
+ nmbrBuffers = *pTCB++;
+
+ if (!nmbrBuffers)
+ {
+ return -1;
+ }
+
+ do
+ {
+ context = *pTCB++; /* buffer tag (context) */
+ nmbrSeg = *pTCB++; /* number of segments */
+
+ if (!nmbrSeg)
+ {
+ return -1;
+ }
+
+ flags = SIMPLE_SGL | BC_PRESENT;
+
+ if (1 == nmbrSeg)
+ {
+ flags |= EOB;
+
+ if (1 == nmbrBuffers)
+ flags |= LE;
+ }
+
+ /* 1st SGL buffer element has context */
+ pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
+ pMsg[1] = context;
+ pMsg[2] = pTCB[1]; /* send buffer segment physical address */
+ nmbrDwords += 3;
+ pMsg += 3;
+ pTCB += 2;
+
+
+ if (--nmbrSeg)
+ {
+ do
+ {
+ flags = SIMPLE_SGL;
+
+ if (1 == nmbrSeg)
+ {
+ flags |= EOB;
+
+ if (1 == nmbrBuffers)
+ flags |= LE;
+ }
+
+ pMsg[0] = pTCB[0] | flags; /* send over count */
+ pMsg[1] = pTCB[1]; /* send buffer segment physical address */
+ nmbrDwords += 2;
+ pTCB += 2;
+ pMsg += 2;
+
+ } while (--nmbrSeg);
+ }
+
+ } while (--nmbrBuffers);
+
+ return nmbrDwords;
+}
+
+
+/*
+** =========================================================================
+** ProcessOutboundAdapterMsg()
+**
+** process reply message
+** * change to msg structure *
+** =========================================================================
+*/
+static void
+ProcessOutboundAdapterMsg(PPAB pPab, U32 phyAddrMsg)
+{
+ PU8 p8Msg;
+ PU32 p32;
+ // U16 count;
+
+
+ p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+ p32 = (PU32)p8Msg;
+
+#ifdef DEBUG
+ kprintf("VXD: ProcessOutboundAdapterMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+#endif /* DEBUG */
+
+ if (p32[4] >> 24 != RC_REPLY_STATUS_SUCCESS)
+ {
+#ifdef DEBUG
+ kprintf("Message reply status not success\n");
+#endif /* DEBUG */
+ return;
+ }
+
+ switch (p8Msg[7] ) /* function code byte */
+ {
+ case RC_CMD_SYS_TAB_SET:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received RC_CMD_SYS_TAB_SET reply\n");
+#endif /* DEBUG */
+ break;
+
+ case RC_CMD_HRT_GET:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received RC_CMD_HRT_GET reply\n");
+#endif /* DEBUG */
+ break;
+
+ case RC_CMD_LCT_NOTIFY:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received RC_CMD_LCT_NOTIFY reply\n");
+#endif /* DEBUG */
+ break;
+
+ case RC_CMD_SYS_ENABLE:
+ msgFlag = 1;
+#ifdef DEBUG
+ kprintf("Received RC_CMD_SYS_ENABLE reply\n");
+#endif /* DEBUG */
+ break;
+
+ default:
+#ifdef DEBUG
+ kprintf("Received UNKNOWN reply\n");
+#endif /* DEBUG */
+ break;
+ }
+}
--- /dev/null
+/*
+** *************************************************************************
+**
+**
+** R C M T L . H $Revision: 1.1 $
+**
+**
+** RedCreek Message Transport Layer header file.
+**
+** ---------------------------------------------------------------------
+** --- Copyright (c) 1997-1998, RedCreek Communications Inc. ---
+** --- All rights reserved. ---
+** ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Header file for host message transport layer API and data types.
+**
+** 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.
+**
+***************************************************************************/
+
+#ifndef RCMTL_H
+#define RCMTL_H
+
+/* Linux specific includes */
+#define kprintf printk
+#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID 0x4916
+#define RC_PCI45_DEVICE_ID 0x1960
+
+
+ /* RedCreek API function return values */
+#define RC_RTN_NO_ERROR 0
+#define RC_RTN_NOT_INIT 1
+#define RC_RTN_FREE_Q_EMPTY 2
+#define RC_RTN_TCB_ERROR 3
+#define RC_RTN_TRANSACTION_ERROR 4
+#define RC_RTN_ADAPTER_ALREADY_INIT 5
+#define RC_RTN_MALLOC_ERROR 6
+#define RC_RTN_ADPTR_NOT_REGISTERED 7
+#define RC_RTN_MSG_REPLY_TIMEOUT 8
+#define RC_RTN_NO_STATUS 9
+#define RC_RTN_NO_FIRM_VER 10
+#define RC_RTN_NO_LINK_SPEED 11
+
+/* Driver capability flags */
+#define WARM_REBOOT_CAPABLE 0x01
+
+ /* scalar data types */
+typedef unsigned char U8;
+typedef unsigned char* PU8;
+typedef unsigned short U16;
+typedef unsigned short* PU16;
+typedef unsigned long U32;
+typedef unsigned long* PU32;
+typedef unsigned long BF;
+typedef int RC_RETURN;
+
+
+ /*
+ ** type PFNWAITCALLBACK
+ **
+ ** pointer to void function - type used for WaitCallback in some functions
+ */
+typedef void (*PFNWAITCALLBACK)(void); /* void argument avoids compiler complaint */
+
+ /*
+ ** type PFNTXCALLBACK
+ **
+ ** Pointer to user's transmit callback function. This user function is
+ ** called from RCProcMsgQ() when packet have been transmitted from buffers
+ ** given in the RCSendPacket() function. BufferContext is a pointer to
+ ** an array of 32 bit context values. These are the values the user assigned
+ ** and passed in the TCB to the RCSendPacket() function. PcktCount
+ ** indicates the number of buffer context values in the BufferContext[] array.
+ ** The User's TransmitCallbackFunction should recover (put back in free queue)
+ ** the packet buffers associated with the buffer context values.
+ */
+typedef void (*PFNTXCALLBACK)(U32 Status,
+ U16 PcktCount,
+ PU32 BufferContext,
+ U16 AdaterID);
+
+ /*
+ ** type PFNRXCALLBACK
+ **
+ ** Pointer to user's receive callback function. This user function
+ ** is called from RCProcMsgQ() when packets have been received into
+ ** previously posted packet buffers throught the RCPostRecvBuffers() function.
+ ** The received callback function should process the Packet Descriptor Block
+ ** pointed to by PacketDescBlock. See Packet Decription Block below.
+ */
+typedef void (*PFNRXCALLBACK)(U32 Status,
+ U8 PktCount,
+ U32 BucketsRemain,
+ PU32 PacketDescBlock,
+ U16 AdapterID);
+
+ /*
+ ** type PFNCALLBACK
+ **
+ ** Pointer to user's generic callback function. This user function
+ ** can be passed to LANReset or LANShutdown and is called when the
+ ** the reset or shutdown is complete.
+ ** Param1 and Param2 are invalid for LANReset and LANShutdown.
+ */
+typedef void (*PFNCALLBACK)(U32 Status,
+ U32 Param1,
+ U32 Param2,
+ U16 AdapterID);
+
+/*
+** Status - Transmit and Receive callback status word
+**
+** A 32 bit Status is returned to the TX and RX callback functions. This value
+** contains both the reply status and the detailed status as follows:
+**
+** 32 24 16 0
+** +------+------+------------+
+** | Reply| | Detailed |
+** |Status| 0 | Status |
+** +------+------+------------+
+**
+** Reply Status and Detailed Status of zero indicates No Errors.
+*/
+ /* reply message status defines */
+#define RC_REPLY_STATUS_SUCCESS 0x00
+#define RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define RC_REPLY_STATUS_TRANSACTION_ERROR 0x0A
+
+
+/* DetailedStatusCode defines */
+#define RC_DSC_SUCCESS 0x0000
+#define RC_DSC_DEVICE_FAILURE 0x0001
+#define RC_DSC_DESTINATION_NOT_FOUND 0x0002
+#define RC_DSC_TRANSMIT_ERROR 0x0003
+#define RC_DSC_TRANSMIT_ABORTED 0x0004
+#define RC_DSC_RECEIVE_ERROR 0x0005
+#define RC_DSC_RECEIVE_ABORTED 0x0006
+#define RC_DSC_DMA_ERROR 0x0007
+#define RC_DSC_BAD_PACKET_DETECTED 0x0008
+#define RC_DSC_OUT_OF_MEMORY 0x0009
+#define RC_DSC_BUCKET_OVERRUN 0x000A
+#define RC_DSC_IOP_INTERNAL_ERROR 0x000B
+#define RC_DSC_CANCELED 0x000C
+#define RC_DSC_INVALID_TRANSACTION_CONTEXT 0x000D
+#define RC_DSC_DESTINATION_ADDRESS_DETECTED 0x000E
+#define RC_DSC_DESTINATION_ADDRESS_OMITTED 0x000F
+#define RC_DSC_PARTIAL_PACKET_RETURNED 0x0010
+
+
+/*
+** Packet Description Block (Received packets)
+**
+** A pointer to this block structure is returned to the ReceiveCallback
+** function. It contains the list of packet buffers which have either been
+** filled with a packet or returned to host due to a LANReset function.
+** Currently there will only be one packet per receive bucket (buffer) posted.
+**
+** 32 24 0
+** +-----------------------+ -\
+** | Buffer 1 Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / First Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet 1 length | /
+** +-----------------------+ -\
+** | Buffer 2 Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / Second Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet 2 length | /
+** +-----+-----------------+ -
+** | ... | ----- more bucket descriptors
+** +-----------------------+ -\
+** | Buffer n Context | \
+** +-----------------------+ \
+** | 0xC0000000 | / Last Bucket Descriptor
+** +-----+-----------------+ /
+** | 0 | packet n length | /
+** +-----+-----------------+ -
+**
+** Buffer Context values are those given to adapter in the TCB on calls to
+** RCPostRecvBuffers().
+**
+*/
+
+
+
+/*
+** Transaction Control Block (TCB) structure
+**
+** A structure like this is filled in by the user and passed by reference to
+** RCSendPacket() and RCPostRecvBuffers() functions. Minimum size is five
+** 32-bit words for one buffer with one segment descriptor.
+** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
+** that can be described in a given TCB.
+**
+** 32 0
+** +-----------------------+
+** | Buffer Count | Number of buffers in the TCB
+** +-----------------------+
+** | Buffer 1 Context | first buffer reference
+** +-----------------------+
+** | Buffer 1 Seg Count | number of segments in buffer
+** +-----------------------+
+** | Buffer 1 Seg Desc 1 | first segment descriptor (size, physical address)
+** +-----------------------+
+** | ... | more segment descriptors (size, physical address)
+** +-----------------------+
+** | Buffer 1 Seg Desc n | last segment descriptor (size, physical address)
+** +-----------------------+
+** | Buffer 2 Context | second buffer reference
+** +-----------------------+
+** | Buffer 2 Seg Count | number of segments in buffer
+** +-----------------------+
+** | Buffer 2 Seg Desc 1 | segment descriptor (size, physical address)
+** +-----------------------+
+** | ... | more segment descriptors (size, physical address)
+** +-----------------------+
+** | Buffer 2 Seg Desc n |
+** +-----------------------+
+** | ... | more buffer descriptor blocks ...
+** +-----------------------+
+** | Buffer n Context |
+** +-----------------------+
+** | Buffer n Seg Count |
+** +-----------------------+
+** | Buffer n Seg Desc 1 |
+** +-----------------------+
+** | ... |
+** +-----------------------+
+** | Buffer n Seg Desc n |
+** +-----------------------+
+**
+**
+** A TCB for one contigous packet buffer would look like the following:
+**
+** 32 0
+** +-----------------------+
+** | 1 | one buffer in the TCB
+** +-----------------------+
+** | <user's Context> | user's buffer reference
+** +-----------------------+
+** | 1 | one segment buffer
+** +-----------------------+ _
+** | <buffer size> | size \
+** +-----------------------+ \ segment descriptor
+** | <physical address> | physical address of buffer /
+** +-----------------------+ _/
+**
+*/
+
+ /* Buffer Segment Descriptor */
+typedef struct
+{
+ U32 size;
+ U32 phyAddress;
+}
+ BSD, *PBSD;
+
+typedef PU32 PRCTCB;
+/*
+** -------------------------------------------------------------------------
+** Exported functions comprising the API to the message transport layer
+** -------------------------------------------------------------------------
+*/
+
+
+ /*
+ ** InitRCApiMsgLayer()
+ **
+ ** Called once prior to using the API message transport layer. User
+ ** provides both the physical and virual address of a locked page buffer
+ ** that is used as a private buffer for the RedCreek API message
+ ** transport layer. This buffer must be a contigous memory block of a
+ ** minimum of 16K bytes and long word aligned. The user also must provide
+ ** the base address of the RedCreek PCI adapter assigned by BIOS or operating
+ ** system. The user provided value AdapterID is a zero based index of the
+ ** Ravlin 45/PCI adapter. This interface number is used in all subsequent API
+ ** calls to identify which adpapter for which the function is intended.
+ ** Up to sixteen interfaces are supported with this API.
+ **
+ ** Inputs: AdapterID - interface number from 0 to 15
+ ** pciBaseAddr - virual base address of PCI (set by BIOS)
+ ** p_msgbuf - virual address to private message block (min. 16K)
+ ** p_phymsgbuf - physical address of private message block
+ ** TransmitCallbackFunction - address of user's TX callback function
+ ** ReceiveCallbackFunction - address of user's RX callback function
+ **
+ */
+RC_RETURN InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr,
+ PU8 p_msgbuf, PU8 p_phymsgbuf,
+ PFNTXCALLBACK TransmitCallbackFunction,
+ PFNRXCALLBACK ReceiveCallbackFunction,
+ PFNCALLBACK RebootCallbackFunction);
+
+ /*
+ ** RCSetRavlinIPandMask()
+ **
+ ** Set the Ravlin 45/PCI cards IP address and network mask.
+ **
+ ** IP address and mask must be in network byte order.
+ ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+ ** 0x04030201 and 0x00FFFFFF on a little endian machine.
+ **
+ */
+RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask);
+
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask,
+ PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCProcMsgQ()
+ **
+ ** Called from user's polling loop or Interrupt Service Routine for a PCI
+ ** interrupt from the RedCreek PCI adapter. User responsible for determining
+ ** and hooking the PCI interrupt. This function will call the registered
+ ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
+ ** if a TX or RX transaction has completed.
+ */
+void RCProcMsgQ(U16 AdapterID);
+
+
+ /*
+ ** Disable and Enable Adapter interrupts. Adapter interrupts are enabled at
+ ** Init time but can be disabled and re-enabled through these two function calls.
+ ** Packets will still be put into any posted recieved buffers and packets will
+ ** be sent through RCSendPacket() functions. Disabling Adapter interrupts
+ ** will prevent hardware interrupt to host even though the outbound msg
+ ** queue is not emtpy.
+ */
+RC_RETURN RCEnableAdapterInterrupts(U16 adapterID);
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID);
+
+
+ /*
+ ** RCPostRecvBuffers()
+ **
+ ** Post user's page locked buffers for use by the PCI adapter to
+ ** return ethernet packets received from the LAN. Transaction Control Block,
+ ** provided by user, contains buffer descriptor(s) which includes a buffer
+ ** context number along with buffer size and physical address. See TCB above.
+ ** The buffer context and actual packet length are returned to the
+ ** ReceiveCallbackFunction when packets have been received. Buffers posted
+ ** to the RedCreek adapter are considered owned by the adapter until the
+ ** context is return to user through the ReceiveCallbackFunction.
+ */
+RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock);
+#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
+
+ /*
+ ** RCSendPacket()
+ **
+ ** Send user's ethernet packet from a locked page buffer.
+ ** Packet must have full MAC header, however without a CRC.
+ ** Initiator context is a user provided value that is returned
+ ** to the TransmitCallbackFunction when packet buffer is free.
+ ** Transmit buffer are considered owned by the adapter until context's
+ ** returned to user through the TransmitCallbackFunction.
+ */
+RC_RETURN RCSendPacket(U16 AdapterID,
+ U32 context,
+ PRCTCB pTransactionCtrlBlock);
+
+
+ /* Ethernet Link Statistics structure */
+typedef struct tag_RC_link_stats
+{
+ U32 TX_good; /* good transmit frames */
+ U32 TX_maxcol; /* frames not TX due to MAX collisions */
+ U32 TX_latecol; /* frames not TX due to late collisions */
+ U32 TX_urun; /* frames not TX due to DMA underrun */
+ U32 TX_crs; /* frames TX with lost carrier sense */
+ U32 TX_def; /* frames deferred due to activity on link */
+ U32 TX_singlecol; /* frames TX with one and only on collision */
+ U32 TX_multcol; /* frames TX with more than one collision */
+ U32 TX_totcol; /* total collisions detected during TX */
+ U32 Rcv_good; /* good frames received */
+ U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */
+ U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
+ U32 Rcv_reserr; /* good frames discarded due to no RX buffer */
+ U32 Rcv_orun; /* RX frames lost due to FIFO overrun */
+ U32 Rcv_cdt; /* RX frames with collision during RX */
+ U32 Rcv_runt; /* RX frames shorter than 64 bytes */
+}
+ RCLINKSTATS, *P_RCLINKSTATS;
+
+ /*
+ ** RCGetLinkStatistics()
+ **
+ ** Returns link statistics in user's structure at address StatsReturnAddr
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatistics(U16 AdapterID,
+ P_RCLINKSTATS StatsReturnAddr,
+ PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCGetLinkStatus()
+ **
+ ** Return link status, up or down, to user's location addressed by ReturnAddr.
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatus(U16 AdapterID,
+ PU32 pReturnStatus,
+ PFNWAITCALLBACK WaitCallback);
+
+ /* Link Status defines - value returned in pReturnStatus */
+#define LAN_LINK_STATUS_DOWN 0
+#define LAN_LINK_STATUS_UP 1
+
+ /*
+ ** RCGetMAC()
+ **
+ ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI
+ ** has two MAC addresses. One which is private to the PCI Card, and
+ ** another MAC which is given to the user as its link layer MAC address. The
+ ** adapter runs in promiscous mode because of the dual address requirement.
+ ** The MAC address is returned to the unsigned char array pointer to by mac.
+ */
+RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCSetMAC()
+ **
+ ** Set a new user port MAC address. This address will be returned on
+ ** subsequent RCGetMAC() calls.
+ */
+RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac);
+
+ /*
+ ** RCSetLinkSpeed()
+ **
+ ** set adapter's link speed based on given input code.
+ */
+RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode);
+ /* Set link speed codes */
+#define LNK_SPD_AUTO_NEG_NWAY 0
+#define LNK_SPD_100MB_FULL 1
+#define LNK_SPD_100MB_HALF 2
+#define LNK_SPD_10MB_FULL 3
+#define LNK_SPD_10MB_HALF 4
+
+
+
+
+ /*
+ ** RCGetLinkSpeed()
+ **
+ ** Return link speed code.
+ */
+ /* Return link speed codes */
+#define LNK_SPD_UNKNOWN 0
+#define LNK_SPD_100MB_FULL 1
+#define LNK_SPD_100MB_HALF 2
+#define LNK_SPD_10MB_FULL 3
+#define LNK_SPD_10MB_HALF 4
+
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback);
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE 0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability);
+
+/*
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback);
+
+/*
+** ----------------------------------------------
+** LAN adapter Reset and Shutdown functions
+** ----------------------------------------------
+*/
+ /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
+#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001
+#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002
+
+ /*
+ ** RCResetLANCard()
+ **
+ ** Reset LAN card operation. Causes a software reset of the ethernet
+ ** controller and restarts the command and receive units. Depending on
+ ** the ResourceFlags given, the buffers are either returned to the
+ ** host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
+ ** detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete. If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** A call to RCPostRecvBuffers() is needed to return the ethernet to full
+ ** operation if the receive buffers were returned during LANReset.
+ ** Note: The IOP status is not affected by a LAN reset.
+ */
+RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+
+ /*
+ ** RCShutdownLANCard()
+ **
+ ** Shutdown LAN card operation and put into an idle (suspended) state.
+ ** The LAN card is restarted with RCResetLANCard() function.
+ ** Depending on the ResourceFlags given, the buffers are either returned
+ ** to the host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER
+ ** and detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete. If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** Note: The IOP status is not affected by a LAN shutdown.
+ */
+RC_RETURN
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+ /*
+ ** RCResetAdapter();
+ ** Initializes ADAPTERState to ADAPTER_STATE_RESET.
+ ** Stops access to outbound message Q.
+ ** Discards any outstanding transmit or posted receive buffers.
+ ** Clears outbound message Q.
+ */
+RC_RETURN
+RCResetAdapter(U16 AdapterID);
+
+#endif /* RCMTL_H */
--- /dev/null
+
+/*
+** RCpci45.c
+**
+**
+**
+** ---------------------------------------------------------------------
+** --- Copyright (c) 1998, RedCreek Communications Inc. ---
+** --- All rights reserved. ---
+** ---------------------------------------------------------------------
+**
+** This software is RedCreek Communications proprietary and confidential.
+** No further distribution or copying is allowed without the express
+** written consent of RedCreek Communications.
+**
+** Known Problems
+**
+** Billions and Billions...
+**
+** ... apparently added by Brian. Pete knows of no bugs.
+**
+** TODO:
+** -Get rid of the wait loops in the API and replace them
+** with system independent delays ...something like
+** "delayms(2)".
+** -Process the warm reboot in a timer callback routine,
+** rather than at interrupt level.
+**
+** 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.
+**
+***************************************************************************/
+
+#define __NO_VERSION__ /* don't define kernel_verion in module.h */
+
+static char *version =
+"RedCreek Communications PCI linux driver version 1.31 Beta\n";
+
+
+#include <linux/config.h>
+#include <linux/modversions.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+char kernel_version [] = UTS_RELEASE;
+
+#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>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+#include "rcif.h"
+
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+
+#define NEW_MULTICAST
+#include <linux/delay.h>
+
+/* 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;
+
+/*
+ * 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 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 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 RCscan(void);
+static struct device
+*RCfound_device(struct device *, int, int, int, int, int, int);
+
+static int RCprobe1(struct device *);
+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;
+
+int
+init_module(void)
+{
+ int cards_found;
+
+ printk(version);
+
+ root_RCdev = NULL;
+ cards_found = RCscan();
+ return cards_found ? 0 : -ENODEV;
+}
+
+static int RCscan()
+{
+ int cards_found = 0;
+ struct device *dev = 0;
+
+ if (pcibios_present())
+ {
+ static int pci_index = 0;
+ unsigned char pci_bus, pci_device_fn;
+ int scan_status;
+ int board_index = 0;
+
+ for (;pci_index < 0xff; pci_index++)
+ {
+ 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 0
+ if (check_region(pci_ioaddr, 32768))
+ {
+ printk("rc: check_region failed\n");
+ continue;
+ }
+ 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;
+ }
+
+ dev = RCfound_device(dev, pci_ioaddr, pci_irq_line,
+ pci_bus, pci_device_fn,
+ board_index++, cards_found);
+
+ if (dev) {
+ dev = 0;
+ cards_found++;
+ }
+ }
+ }
+ printk("rc: found %d cards \n", cards_found);
+ return cards_found;
+}
+
+static struct device *
+RCfound_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.
+ */
+ dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+ memset(dev, 0, dev_size);
+#ifdef RCDEBUG
+ printk("rc: dev = 0x%08X\n", (uint)dev);
+#endif
+
+ /*
+ * dev->priv will point to the start of DPA.
+ */
+ dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
+ pDpa = dev->priv;
+ 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 InitRCApiMsgLayer().
+ */
+ 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 *) vremap (memaddr, 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, dev->name, dev) )
+ {
+ printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq );
+ vfree(vaddr);
+ kfree(dev);
+ return 0;
+ }
+
+ init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr,
+ pDpa->PLanApiPA, pDpa->PLanApiPA,
+ (PFNTXCALLBACK)RCxmit_callback,
+ (PFNRXCALLBACK)RCrecv_callback,
+ (PFNCALLBACK)RCreboot_callback);
+#ifdef RCDEBUG
+ printk("rc: msg initted: status = 0x%x\n", init_status);
+#endif
+ if (init_status)
+ {
+ printk("rc: Unable to initialize msg layer\n");
+ free_irq(dev->irq, dev);
+ vfree(vaddr);
+ kfree(dev);
+ return 0;
+ }
+ if (RCGetMAC(pDpa->id, dev->dev_addr, NULL))
+ {
+ printk("rc: Unable to get adapter MAC\n");
+ free_irq(dev->irq, dev);
+ vfree(vaddr);
+ kfree(dev);
+ return 0;
+ }
+
+ DriverControlWord |= WARM_REBOOT_CAPABLE;
+ RCReportDriverCapability(pDpa->id, DriverControlWord);
+
+ dev->init = RCprobe1;
+ ether_setup(dev); /* linux kernel interface */
+
+ pDpa->next = root_RCdev;
+ root_RCdev = dev;
+
+ if (register_netdev(dev) != 0) /* linux kernel interface */
+ {
+ printk("rc: unable to register device \n");
+ free_irq(dev->irq, dev);
+ vfree(vaddr);
+ kfree(dev);
+ return 0;
+ }
+ return dev;
+}
+
+static int RCprobe1(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 int
+RCopen(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
+ RCEnableAdapterInterrupts(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 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
+ 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 RCSendPacket() 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 = (U32)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 = RCSendPacket(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;
+ }
+ else
+ {
+ dev->trans_start = jiffies;
+ // dev->tbusy = 0;
+ }
+ /*
+ * That's it!
+ */
+ return 0;
+}
+
+/*
+ * RCxmit_callback()
+ *
+ * The transmit callback routine. It's called by RCProcMsgQ()
+ * 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 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 != RC_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++;
+ dev_kfree_skb (skb, FREE_WRITE);
+ }
+ dev->tbusy = 0;
+
+}
+
+static void
+RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
+{
+ PDPA pDpa;
+ struct device *dev;
+ U32 watchdog = 0;
+ volatile unsigned int i, j;
+ RC_RETURN init_status = 1;
+ unsigned short pci_command, pci_int;
+ int post_buffers = MAX_NMBR_RCV_BUFFERS;
+ int count = 0;
+ int requested = 0;
+
+ pDpa = PCIAdapters[AdapterID];
+ dev = pDpa->dev;
+#ifdef RCDEBUG
+ printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
+#endif
+ /*
+ * Check to see why we did a reset.
+ */
+ if (pDpa->shutdown)
+ {
+ /* shutdown overrides reboot */
+ printk("rc: Shutting down interface\n");
+ }
+ else if (pDpa->reboot)
+ {
+ char did_shutdown = 0;
+
+ watchdog = 0;
+ do {
+ /*
+ * OK, we have to first wait for the bus master
+ * bit to become 0, indicating that the adapter
+ * has initiated the shutdown. Then, in the next
+ * loop, we'll wait for the adapter to turn on
+ * the bus master bit, indicating that it is done
+ * rebooting.
+ */
+ watchdog++;
+ if (watchdog > 100)
+ break;
+ pcibios_read_config_word(pDpa->bus,
+ pDpa->function,
+ PCI_COMMAND,
+ &pci_command);
+ // printk("1: pci_command = 0x%x\n", pci_command);
+ if (!did_shutdown)
+ {
+ /*
+ * Yes, this is precisely where I want to
+ * do the shutdown!!! Right here, in this
+ * do/while loop.
+ */
+ RCShutdownLANCard(pDpa->id, 0, 0, 0);
+ did_shutdown = 1;
+ }
+ } while (pci_command & PCI_COMMAND_MASTER);
+
+ printk("rc: Adapter is rebooting...\n");
+ printk("rc: Waiting for adapter to become ready\n");
+
+ watchdog = 0;
+ while(watchdog < 10)
+ {
+ watchdog++;
+ for (i=0; i<1000000; i++)
+ for (j=0; j<100; j++);
+ pcibios_read_config_word(pDpa->bus,
+ pDpa->function,
+ PCI_COMMAND,
+ &pci_command);
+ //printk("2: pci_command = 0x%x\n", pci_command);
+ if (pci_command & PCI_COMMAND_MASTER) {
+ break;
+ }
+ }
+ pDpa->reboot = 0;
+ if (watchdog >= 10)
+ {
+ printk("rc: Adapter ready timeout\n");
+ printk("rc: releasing driver...\n");
+ RCDisableAdapterInterrupts(AdapterID);
+ dev->flags &= ~IFF_UP;
+ }
+ else
+ {
+ pci_command |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(pDpa->bus,
+ pDpa->function,
+ PCI_COMMAND,
+ pci_command);
+ printk("rc: Adapter ready\n");
+ printk("rc: Initializing ...\n");
+ init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr,
+ pDpa->PLanApiPA, pDpa->PLanApiPA,
+ (PFNTXCALLBACK)RCxmit_callback,
+ (PFNRXCALLBACK)RCrecv_callback,
+ (PFNCALLBACK)RCreboot_callback);
+
+ printk("rc: status = 0x%x\n", init_status);
+ if (init_status)
+ {
+ printk("rc: Unable to initialize adapter\n");
+ printk("rc: releasing driver...\n");
+ }
+ else
+ {
+ pcibios_read_config_word(pDpa->bus,
+ pDpa->function,
+ PCI_INTERRUPT_LINE,
+ &pci_int);
+ if (dev->irq != (pci_int & 0xff))
+ {
+ printk("rc: Interrupt line set to 0x%x\n", pci_int);
+ printk("rc: Resetting to 0x%x\n", dev->irq);
+ pcibios_write_config_word(pDpa->bus,
+ pDpa->function,
+ PCI_INTERRUPT_LINE,
+ dev->irq);
+ }
+
+ RCReportDriverCapability(pDpa->id, DriverControlWord);
+ RCEnableAdapterInterrupts(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;
+ pDpa->shutdown = 0; /* just in case */
+
+ printk("rc: posted %d buffers \r\n", (uint)pDpa->numOutRcvBuffers);
+ }
+ printk("rc: Initialization done.\n");
+ return;
+ }
+ }
+ }
+ pDpa->shutdown = 0;
+ pDpa->reboot = 0;
+ //RCDisableAdapterInterrupts(AdapterID);
+
+ MOD_DEC_USE_COUNT;
+
+}
+
+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;
+ //RCShutdownLANCard(pDpa->id,
+ 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
+ * RCProcMsgQ() 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 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 != RC_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);
+ else
+ printk("rc: 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 == RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER)
+ {
+ #ifdef RCDEBUG
+ printk("RCrecv status ABORT NO DATA TRANSFER\n");
+ #endif
+ }
+ /* check for reset status: RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */
+ if (PacketDescBlock)
+ {
+ while(PktCount--)
+ {
+ skb = (struct sk_buff *)PacketDescBlock[0];
+ skb->free = 1;
+ skb->lock = 0;
+ #ifdef RCDEBUG
+ printk("free skb 0x%p\n", skb);
+ #endif
+ dev_kfree_skb(skb, FREE_READ);
+ 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
+ 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 = (U32)skb->data;
+
+ if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR)
+ {
+ printk("rc: RCrecv_callback: post buffer failed!\n");
+ skb->free = 1;
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ else
+ {
+ pDpa->numOutRcvBuffers++;
+ }
+ }
+ else
+ {
+ 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
+ * RCProcMsgQ(), 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 device *dev = (struct device *)(dev_id);
+
+ pDpa = (PDPA) (dev->priv);
+
+ if (pDpa->shutdown)
+ printk("rc: shutdown: service irq\n");
+
+#ifdef RCDEBUG
+ 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;
+
+ RCProcMsgQ(pDpa->id);
+ dev->interrupt = 0;
+
+ return;
+}
+
+static int
+RCclose(struct 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 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 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:
+ {
+ int error;
+
+ error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser));
+ if (error) {
+ return error;
+ }
+ memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser));
+
+#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 + 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_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;
+ default:
+ printk("RC command default\n");
+ RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
+ RCUD_DEFAULT -> rc = 0x11223344;
+ break;
+ }
+ memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser));
+ break;
+ } /* RCU_COMMAND */
+
+ default:
+ printk("RC default\n");
+ rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
+ break;
+ }
+ return 0;
+}
+
+static int RCconfig(struct 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;
+}
+
+void
+cleanup_module(void)
+{
+ PDPA pDpa;
+ struct 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("Adapter reset: 0x%x\n", RCResetAdapter(pDpa->id));
+ unregister_netdev(root_RCdev);
+ next = pDpa->next;
+
+ vfree((unsigned long *)root_RCdev->base_addr);
+ free_irq( root_RCdev->irq, root_RCdev );
+ kfree(root_RCdev);
+ root_RCdev = next;
+ }
+}
+
+static int
+RC_allocate_and_post_buffers(struct 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; i<numBuffers; i++)
+ {
+ skb = dev_alloc_skb(MAX_ETHER_SIZE+2);
+ if (!skb)
+ {
+ printk("rc: Doh! RCopen: unable to allocate enough skbs!\n");
+ if (*p != 0) /* did we allocate any buffers at all? */
+ {
+#ifdef RCDEBUG
+ printk("rc: will post only %d buffers \n", (uint)(*p));
+#endif
+ break;
+ }
+ else
+ {
+ kfree(p); /* Free the TCB */
+ return 0;
+ }
+ }
+#ifdef RCDEBUG
+ printk("post 0x%x\n", (uint)skb);
+#endif
+ 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 = (U32)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;
+ skb->free = 1;
+#ifdef RCDEBUG
+ printk("rc: freeing 0x%x\n", (uint)skb);
+#endif
+ dev_kfree_skb(skb, FREE_READ);
+ 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 */
+}
case SHAPER_GET_DEV:
if(sh->dev==NULL)
return -ENODEV;
- memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+ memcpy(ss->ss_name, sh->dev->name, strlen(sh->dev->name)+1);
return 0;
case SHAPER_SET_SPEED:
shaper_setspeed(sh,ss->ss_speed);
DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"),
DEVICE( NP, NP_PCI_FDDI, "NP-PCI"),
DEVICE( ATT, ATT_L56XMF, "L56xMF"),
+ DEVICE( SPECIALIX, SPECIALIX_IO8, "IO8+/PCI"),
DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"),
DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"),
DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"),
case PCI_VENDOR_ID_ATRONICS: return "Atronics";
case PCI_VENDOR_ID_ARK: return "ARK Logic";
case PCI_VENDOR_ID_ASIX: return "ASIX";
+ case PCI_VENDOR_ID_LITEON: return "Lite-on";
default: return "Unknown vendor";
}
}
* This is no longer true, it is GFP_BUFFER again, the
* swapping code now knows not to perform I/O when that
* GFP level is specified... -DaveM
+ *
+ * Ouch, another bug! get_free_page() does not call
+ * try_to_free_page() if priority == GFP_BUFFER. This
+ * lets kswapd get into a lockup situation if there is
+ * no free space for buffer growth but we need more
+ * memory for a buffer_head for swapping. If memory is
+ * full of recyclable buffers, we deadlock because
+ * kswapd won't recycle them! Use GFP_IO instead: it
+ * still won't recurse (GFP_IO sets can_do_io to zero in
+ * try_to_free_page), but it lets us recover those
+ * buffer heads. --sct
*/
/* we now use kmalloc() here instead of gfp as we want
to be able to easily release buffer heads - they
took up quite a bit of memory (tridge) */
- bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_BUFFER);
+ bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_IO);
if (bh) {
put_unused_buffer_head(bh);
nr_buffer_heads++;
#else
if (count <= 0) return 0;
#endif
+ if (filp->f_pos + count > 0x7FFFFFFFLL) {
+ count = 0x7FFFFFFFLL - filp->f_pos;
+ if (!count)
+ return -EFBIG;
+ }
+
error = carry = 0;
for (start = buf; count || carry; count -= size) {
while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
res = 0;
- return 0;
} else {
res = -ENOENT;
}
{ /* if has DIR0/DIR1 */
char ccr3;
+ char dir0;
x86_model = 0;
/* Enable MAPEN */
ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
- /* try enabling cpuid */
- setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
+ dir0 = getCx86(CX86_DIR0);
+ if ((dir0 & 0xf0) == 0x30) /* Use DIR0 to determine if this is a 6x86 class processor */
+ {
+ /* try enabling cpuid */
+ setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
+ }
if (test_cpuid())
{
/* disable MAPEN */
setCx86(CX86_CCR3, ccr3);
} /* endif has DIR0/DIR1 */
+ sti();
restore_flags(flags); /* restore interrupt state */
} /* endif it's a Cyrix */
}
#define PCI_DEVICE_ID_ATT_L56XMF 0x0440
#define PCI_VENDOR_ID_SPECIALIX 0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000
#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000
#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
oom(current);
return BAD_PAGE;
}
+ repeat:
pte_val(pte) = shp->shm_pages[idx];
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
}
if (!pte_none(pte)) {
read_swap_page(pte_val(pte), (char *) page);
- pte_val(pte) = shp->shm_pages[idx];
- if (pte_present(pte)) {
- free_page (page); /* doesn't sleep */
- goto done;
- }
+ if (pte_val(pte) != shp->shm_pages[idx])
+ goto repeat;
swap_free(pte_val(pte));
shm_swp--;
}
int shm_swap (int prio, int dma)
{
pte_t page;
+ struct page *page_map;
struct shmid_ds *shp;
struct vm_area_struct *shmd;
unsigned long swap_nr;
pte_val(page) = shp->shm_pages[idx];
if (!pte_present(page))
goto check_table;
- if (dma && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
+ page_map = &mem_map[MAP_NR(pte_page(page))];
+ if (PageLocked(page_map))
+ goto check_table;
+ if (dma && !PageDMA(page_map))
goto check_table;
swap_attempts++;
switch (state) {
do {
case 0:
- if (shrink_mmap(i, dma, can_do_io))
+ if (shrink_mmap(i, dma, 1))
return 1;
state = 1;
case 1:
* much hacked by: Alan Cox
*/
-#include <linux/config.h>
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/firewall.h>
/* Bind this socket to a particular device like "eth0",
* as specified in an ifreq structure. If the device
* is "", socket is NOT bound to a device. */
+
+ if(!suser())
+ return -EPERM;
+
if (!valbool) {
sk->bound_device = NULL;
} else {
/*
* SYN_RECV with data maybe.. drop through
*/
- goto rfc_step6;
+ goto rfc_step4;
}
/*
#endif
}
+rfc_step4: /* I'll clean this up later */
+
/*
* We are now in normal data flow (see the step list in the RFC)
* Note most of these are inline now. I'll inline the lot when
* Process the ACK
*/
+ if(!th->ack)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
- if(th->ack && !tcp_ack(sk,th,skb->ack_seq,len))
+ if(!tcp_ack(sk,th,skb->ack_seq,len))
{
/*
* Our three way handshake failed.
return 0;
}
-rfc_step6: /* I'll clean this up later */
/*
* If the accepted buffer put us over our queue size we
sock_register(rose_proto_ops.family, &rose_proto_ops);
register_netdevice_notifier(&rose_dev_notifier);
- printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.035 Linux 2.0\n");
+ printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.63 for AX25.035 Linux 2.0\n");
if (!ax25_protocol_register(AX25_P_ROSE, rose_route_frame))
printk(KERN_ERR "ROSE: unable to register protocol with AX.25\n");
kfree_skb(skb, FREE_WRITE);
while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb, FREE_WRITE);
#ifdef M_BIT
- while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+ while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL)
kfree_skb(skb, FREE_READ);
- }
#endif
}
int size);
static void sock_close(struct inode *inode, struct file *file);
+static int sock_no_open(struct inode *inode, struct file *file);
static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
static int sock_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
sock_select,
sock_ioctl,
NULL, /* mmap */
- NULL, /* no special open code... */
+ sock_no_open, /* special open code... */
sock_close,
NULL, /* no fsync */
sock_fasync
sock_wake_async(peer, 1);
}
+/*
+ * In theory you can't get an open on this inode, but /proc provides
+ * a back door. Remember to keep it shut otherwise you'll let the
+ * creepy crawlies in.
+ */
+
+static int sock_no_open(struct inode *inode, struct file *file)
+{
+ return -ENXIO;
+}
+
void sock_release(struct socket *sock)
{
int oldstate;
* 2 of the License, or (at your option) any later version.
*
* Fixes:
+ * Al Viro 11 Oct 1998
+ * Graph may have cycles. That is, we can send the descriptor
+ * of foo to bar and vice versa. Current code chokes on that.
+ * Fix: move SCM_RIGHTS ones into the separate list and then
+ * kfree_skb() them all instead of doing explicit fput's.
+ * Another problem: since fput() may block somebody may
+ * create a new unix_socket when we are in the middle of sweep
+ * phase. Fix: revert the logic wrt MARKED. Mark everything
+ * upon the beginning and unmark non-junk ones.
+ *
+ * [12 Oct 1998] AAARGH! New code purges all SCM_RIGHTS
+ * sent to connect()'ed but still not accept()'ed sockets.
+ * Fixed. Old code had slightly different problem here:
+ * extra fput() in situation when we passed the descriptor via
+ * such socket and closed it (descriptor). That would happen on
+ * each unix_gc() until the accept(). Since the struct file in
+ * question would go to the free list and might be reused...
+ * That might be the reason of random oopses on close_fp() in
+ * unrelated processes.
*
*/
return in_stack == 0;
}
-extern inline void maybe_mark_and_push(unix_socket *x)
+extern inline void maybe_unmark_and_push(unix_socket *x)
{
- if (x->protinfo.af_unix.marksweep&MARKED)
+ if (!(x->protinfo.af_unix.marksweep&MARKED))
return;
- x->protinfo.af_unix.marksweep|=MARKED;
+ x->protinfo.af_unix.marksweep&=~MARKED;
push_stack(x);
}
{
static int in_unix_gc=0;
unix_socket *s;
- unix_socket *next;
-
+ struct sk_buff *skb;
+ struct sk_buff_head hitlist;
+
/*
* Avoid a recursive GC.
*/
}
/*
- * Assume everything is now unmarked
+ * Everything is now marked
*/
+ for(s=unix_socket_list;s!=NULL;s=s->next)
+ {
+ s->protinfo.af_unix.marksweep|=MARKED;
+ }
+
/* Invariant to be maintained:
- - everything marked is either:
+ - everything unmarked is either:
-- (a) on the stack, or
- -- (b) has all of its children marked
- - everything on the stack is always marked
+ -- (b) has all of its children unmarked
+ - everything on the stack is always unmarked
- nothing is ever pushed onto the stack twice, because:
- -- nothing previously marked is ever pushed on the stack
+ -- nothing previously unmarked is ever pushed on the stack
*/
/*
* If all instances of the descriptor are not
* in flight we are in use.
*/
- if(s->socket && s->socket->file && s->socket->file->f_count > s->protinfo.af_unix.inflight)
- maybe_mark_and_push(s);
+ if(s->socket && s->socket->file &&
+ s->socket->file->f_count > s->protinfo.af_unix.inflight)
+ maybe_unmark_and_push(s);
}
/*
- * Mark phase
+ * Mark phase
*/
while (!empty_stack())
{
unix_socket *x = pop_stack();
unix_socket *f=NULL,*sk;
- struct sk_buff *skb;
tail:
skb=skb_peek(&x->receive_queue);
if((sk=unix_get_socket(*fp++))!=NULL)
{
/*
- * Remember the first, mark the
+ * Remember the first, unmark the
* rest.
*/
if(f==NULL)
f=sk;
else
- maybe_mark_and_push(sk);
+ maybe_unmark_and_push(sk);
}
}
}
+ /*
+ * If we are connecting we need to handle this too
+ */
+ if(x->state == TCP_LISTEN)
+ {
+ if(f==NULL)
+ f=skb->sk;
+ else
+ maybe_unmark_and_push(skb->sk);
+ }
skb=skb->next;
}
+
/*
* Handle first born specially
*/
if (f)
{
- if (!(f->protinfo.af_unix.marksweep&MARKED))
+ if (f->protinfo.af_unix.marksweep&MARKED)
{
- f->protinfo.af_unix.marksweep|=MARKED;
+ f->protinfo.af_unix.marksweep&=~MARKED;
x=f;
f=NULL;
goto tail;
}
}
- /*
- * Sweep phase. NOTE: this part dominates the time complexity
- */
+ skb_queue_head_init(&hitlist);
- for(s=unix_socket_list;s!=NULL;s=next)
+ for(s=unix_socket_list;s!=NULL;s=s->next)
{
- next=s->next;
- if (!(s->protinfo.af_unix.marksweep&MARKED))
+ if (s->protinfo.af_unix.marksweep&MARKED)
{
- /*
- * We exist only in the passing tree of sockets
- * that is no longer connected to active descriptors
- * Time to die..
- *
- * Subtle item: We will correctly sweep out the
- * socket that has just been closed by the user.
- * We must not close this as we are in the middle
- * of its close at this moment. Skip that file
- * using f_count==0 to spot it.
- */
-
- if(s->socket && s->socket->file && s->socket->file->f_count)
- close_fp(s->socket->file);
+ struct sk_buff *nextsk;
+ skb=skb_peek(&s->receive_queue);
+ while(skb && skb != (struct sk_buff *)&s->receive_queue)
+ {
+ nextsk=skb->next;
+ /*
+ * Do we have file descriptors ?
+ */
+ if(*(int *)(skb->h.filp))
+ {
+ /*
+ * Pull these buffers out of line
+ * so they will each be freed once
+ * at the end.
+ */
+ skb_unlink(skb);
+ skb_queue_tail(&hitlist,skb);
+ }
+ skb=nextsk;
+ }
}
- else
- s->protinfo.af_unix.marksweep&=~MARKED; /* unmark everything for next collection */
}
-
+
+ /*
+ * Here we are. Hitlist is filled. Die.
+ */
+
+ while ((skb=skb_dequeue(&hitlist))!=NULL)
+ {
+ kfree_skb(skb, FREE_READ);
+ }
+
in_unix_gc=0;
-
vfree(stack);
}