Commit c96ded1b authored by Jeff Garzik's avatar Jeff Garzik

[netdrvr] remove rcpci driver, for Red Creek Hardware VPNs

Pete Popov, the author says

This driver is obsolete and broken in 2.4 (and I'm pretty sure in 2.6).
The hardware has not been available for a while. I wrote the driver
for 2.2 but after I left RedCreek (which went out of business),
someone in the community updated it to 2.4, but I don't think that
person even had the hardware to test it so the driver remained broken
in 2.4. So my recommendation is that it's really time to remove this
driver from the kernel tree. Just my opinion but I thought I'd share
it with you.
[...]
I can't imagine that there are any users because 2.4 was broken last
time I checked (admittedly that was a year ago).
parent 141baf80
......@@ -2480,16 +2480,6 @@ config IPHASE5526
To compile this driver as a module, choose M here: the module
will be called iph5526.
config RCPCI
tristate "Red Creek Hardware VPN (EXPERIMENTAL)"
depends on NETDEVICES && EXPERIMENTAL && PCI && !64BIT
help
This is a driver for hardware which provides a Virtual Private
Network (VPN). Say Y if you have it.
To compile this driver as a module, choose M here: the module
will be called rcpci.
config SHAPER
tristate "Traffic Shaper (EXPERIMENTAL)"
depends on NETDEVICES && EXPERIMENTAL
......
......@@ -2,8 +2,6 @@
# Makefile for the Linux network (ethercard) device drivers.
#
rcpci-objs := rcpci45.o rclanmtl.o
ifeq ($(CONFIG_ISDN_PPP),y)
obj-$(CONFIG_ISDN) += slhc.o
endif
......@@ -32,7 +30,6 @@ obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_RCPCI) += rcpci.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
......
/*
** *************************************************************************
**
**
** R C I F . H
**
**
** RedCreek InterFace include file.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1998-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Header file private ioctl commands.
**
**
** 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 RCIF_H
#define RCIF_H
/* The following protocol revision # should be incremented every time
a new protocol or new structures are used in this file. */
int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */
/* define a single TCB & buffer */
typedef struct { /* a single buffer */
U32 context; /* context */
U32 scount; /* segment count */
U32 size; /* segment size */
U32 addr; /* segment physical address */
} __attribute__ ((packed))
singleB, *psingleB;
typedef struct { /* a single TCB */
/*
** +-----------------------+
** | 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 /
** +-----------------------+ _/
*/
U32 bcount; /* buffer count */
singleB b; /* buffer */
} __attribute__ ((packed))
singleTCB, *psingleTCB;
/*
When adding new entries, please add all 5 related changes, since
it helps keep everything consistent:
1) User structure entry
2) User data entry
3) Structure short-cut entry
4) Data short-cut entry
5) Command identifier entry
For Example ("GETSPEED"):
1) struct RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed;
2) struct RCgetspeed_tag *getspeed;
3) #define RCUS_GETSPEED data.RCgetspeed;
4) #define RCUD_GETSPEED _RC_user_data.getspeed
5) #define RCUC_GETSPEED 0x02
Notes for the "GETSPEED" entry, above:
1) RCgetspeed - RC{name}
RCgetspeed_tag - RC{name}_tag
LinkSpeedCode - create any structure format desired (not too large,
since memory will be unioned with all other entries)
2) RCgetspeed_tag - RC{name}_tag chosen in #1
getspeed - arbitrary name (ptr to structure in #1)
3) RCUS_GETSPEED - RCUS_{NAME} ("NAME" & "name" do not have to the same)
data.RCgetspeed - data.RC{name} ("RC{name}" from #1)
4) RCUD_GETSPEED - _RC_user_data.getspeed ("getspeed" from #2)
5) RCUC_GETSPEED - unique hex identifier entry.
*/
typedef struct RC_user_tag RCuser_struct;
/* 1) User structure entry */
struct RC_user_tag {
int cmd;
union {
/* GETINFO structure */
struct RCgetinfo_tag {
unsigned long int mem_start;
unsigned long int mem_end;
unsigned long int base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
} RCgetinfo; /* <---- RCgetinfo */
/* GETSPEED structure */
struct RCgetspeed_tag {
U32 LinkSpeedCode;
} RCgetspeed; /* <---- RCgetspeed */
/* SETSPEED structure */
struct RCsetspeed_tag {
U16 LinkSpeedCode;
} RCsetspeed; /* <---- RCsetspeed */
/* GETPROM structure */
struct RCgetprom_tag {
U32 PromMode;
} RCgetprom; /* <---- RCgetprom */
/* SETPROM structure */
struct RCsetprom_tag {
U16 PromMode;
} RCsetprom; /* <---- RCsetprom */
/* GETBROADCAST structure */
struct RCgetbroadcast_tag {
U32 BroadcastMode;
} RCgetbroadcast; /* <---- RCgetbroadcast */
/* SETBROADCAST structure */
struct RCsetbroadcast_tag {
U16 BroadcastMode;
} RCsetbroadcast; /* <---- RCsetbroadcast */
/* GETFIRMWAREVER structure */
#define FirmStringLen 80
struct RCgetfwver_tag {
U8 FirmString[FirmStringLen];
} RCgetfwver; /* <---- RCgetfwver */
/* GETIPANDMASK structure */
struct RCgetipnmask_tag {
U32 IpAddr;
U32 NetMask;
} RCgetipandmask; /* <---- RCgetipandmask */
/* SETIPANDMASK structure */
struct RCsetipnmask_tag {
U32 IpAddr;
U32 NetMask;
} RCsetipandmask; /* <---- RCsetipandmask */
/* GETMAC structure */
#define MAC_SIZE 10
struct RCgetmac_tag {
U8 mac[MAC_SIZE];
} RCgetmac; /* <---- RCgetmac */
/* SETMAC structure */
struct RCsetmac_tag {
U8 mac[MAC_SIZE];
} RCsetmac; /* <---- RCsetmac */
/* GETLINKSTATUS structure */
struct RCgetlnkstatus_tag {
U32 ReturnStatus;
} RCgetlnkstatus; /* <---- RCgetlnkstatus */
/* GETLINKSTATISTICS structure */
struct RCgetlinkstats_tag {
RCLINKSTATS StatsReturn;
} RCgetlinkstats; /* <---- RCgetlinkstats */
/* DEFAULT structure (when no command was recognized) */
struct RCdefault_tag {
int rc;
} RCdefault; /* <---- RCdefault */
} data;
}; /* struct RC_user_tag { ... } */
/* 2) User data entry */
/* RCUD = RedCreek User Data */
union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */
struct RCgetinfo_tag *getinfo;
struct RCgetspeed_tag *getspeed;
struct RCgetprom_tag *getprom;
struct RCgetbroadcast_tag *getbroadcast;
struct RCgetfwver_tag *getfwver;
struct RCgetipnmask_tag *getipandmask;
struct RCgetmac_tag *getmac;
struct RCgetlnkstatus_tag *getlinkstatus;
struct RCgetlinkstats_tag *getlinkstatistics;
struct RCdefault_tag *rcdefault;
struct RCsetspeed_tag *setspeed;
struct RCsetprom_tag *setprom;
struct RCsetbroadcast_tag *setbroadcast;
struct RCsetipnmask_tag *setipandmask;
struct RCsetmac_tag *setmac;
} _RC_user_data; /* declare as a global, so the defines below will work */
/* 3) Structure short-cut entry */
/* define structure short-cuts *//* structure names are taken from RC_user_tag structure above */
#define RCUS_GETINFO data.RCgetinfo;
#define RCUS_GETSPEED data.RCgetspeed;
#define RCUS_GETPROM data.RCgetprom;
#define RCUS_GETBROADCAST data.RCgetbroadcast;
#define RCUS_GETFWVER data.RCgetfwver;
#define RCUS_GETIPANDMASK data.RCgetipandmask;
#define RCUS_GETMAC data.RCgetmac;
#define RCUS_GETLINKSTATUS data.RCgetlnkstatus;
#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;
#define RCUS_DEFAULT data.RCdefault;
#define RCUS_SETSPEED data.RCsetspeed;
#define RCUS_SETPROM data.RCsetprom;
#define RCUS_SETBROADCAST data.RCsetbroadcast;
#define RCUS_SETIPANDMASK data.RCsetipandmask;
#define RCUS_SETMAC data.RCsetmac;
/* 4) Data short-cut entry */
/* define data short-cuts *//* pointer names are from RC_user_data_tag union (just below RC_user_tag) */
#define RCUD_GETINFO _RC_user_data.getinfo
#define RCUD_GETSPEED _RC_user_data.getspeed
#define RCUD_GETPROM _RC_user_data.getprom
#define RCUD_GETBROADCAST _RC_user_data.getbroadcast
#define RCUD_GETFWVER _RC_user_data.getfwver
#define RCUD_GETIPANDMASK _RC_user_data.getipandmask
#define RCUD_GETMAC _RC_user_data.getmac
#define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus
#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics
#define RCUD_DEFAULT _RC_user_data.rcdefault
#define RCUD_SETSPEED _RC_user_data.setspeed
#define RCUD_SETPROM _RC_user_data.setprom
#define RCUD_SETBROADCAST _RC_user_data.setbroadcast
#define RCUD_SETIPANDMASK _RC_user_data.setipandmask
#define RCUD_SETMAC _RC_user_data.setmac
/* 5) Command identifier entry */
/* define command identifiers */
#define RCUC_GETINFO 0x01
#define RCUC_GETSPEED 0x02
#define RCUC_GETFWVER 0x03
#define RCUC_GETIPANDMASK 0x04
#define RCUC_GETMAC 0x05
#define RCUC_GETLINKSTATUS 0x06
#define RCUC_GETLINKSTATISTICS 0x07
#define RCUC_GETPROM 0x14
#define RCUC_GETBROADCAST 0x15
#define RCUC_DEFAULT 0xff
#define RCUC_SETSPEED 0x08
#define RCUC_SETIPANDMASK 0x09
#define RCUC_SETMAC 0x0a
#define RCUC_SETPROM 0x16
#define RCUC_SETBROADCAST 0x17
/* define ioctl commands to use, when talking to RC 45/PCI driver */
#define RCU_PROTOCOL_REV SIOCDEVPRIVATE
#define RCU_COMMAND SIOCDEVPRIVATE+1
/*
Intended use for the above defines is shown below (GETINFO, as this example):
RCuser_struct RCuser; // declare RCuser structure
struct ifreq ifr; // declare an interface request structure
RCuser.cmd = RCUC_GETINFO; // set user command to GETINFO
ifr->ifr_data = (caddr_t) &RCuser; // set point to user structure
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); // get a socket
ioctl(sock, RCU_COMMAND, &ifr); // do ioctl on socket
RCUD_GETINFO = &RCuser.RCUS_GETINFO; // set data pointer for GETINFO
// print results
printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n",
RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end,
RCUD_GETINFO->base_addr, RCUD_GETINFO->irq);
*/
#endif /* RCIF_H */
/*
** *************************************************************************
**
**
** R C L A N M T L . C $Revision: 6 $
**
**
** RedCreek I2O LAN Message Transport Layer program module.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Host side I2O (Intelligent I/O) LAN 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.
**
** 1998-1999, LAN API was modified and enhanced by Alice Hennessy.
**
** Sometime in 1997, LAN API was written from scratch by Wendell Nichols.
** *************************************************************************
*/
#define DEBUG 1
#define RC_LINUX_MODULE
#include "rclanmtl.h"
/* RedCreek LAN device Target ID */
#define RC_LAN_TARGET_ID 0x10
/* RedCreek's OSM default LAN receive Initiator */
#define DEFAULT_RECV_INIT_CONTEXT 0xA17
/*
** I2O message structures
*/
#define I2O_TID_SZ 12
#define I2O_FUNCTION_SZ 8
/* Transaction Reply Lists (TRL) Control Word structure */
#define I2O_TRL_FLAGS_SINGLE_FIXED_LENGTH 0x00
#define I2O_TRL_FLAGS_SINGLE_VARIABLE_LENGTH 0x40
#define I2O_TRL_FLAGS_MULTIPLE_FIXED_LENGTH 0x80
/* LAN Class specific functions */
#define I2O_LAN_PACKET_SEND 0x3B
#define I2O_LAN_SDU_SEND 0x3D
#define I2O_LAN_RECEIVE_POST 0x3E
#define I2O_LAN_RESET 0x35
#define I2O_LAN_SHUTDOWN 0x37
/* Private Class specfic function */
#define I2O_PRIVATE 0xFF
/* I2O Executive Function Codes. */
#define I2O_EXEC_ADAPTER_ASSIGN 0xB3
#define I2O_EXEC_ADAPTER_READ 0xB2
#define I2O_EXEC_ADAPTER_RELEASE 0xB5
#define I2O_EXEC_BIOS_INFO_SET 0xA5
#define I2O_EXEC_BOOT_DEVICE_SET 0xA7
#define I2O_EXEC_CONFIG_VALIDATE 0xBB
#define I2O_EXEC_CONN_SETUP 0xCA
#define I2O_EXEC_DEVICE_ASSIGN 0xB7
#define I2O_EXEC_DEVICE_RELEASE 0xB9
#define I2O_EXEC_HRT_GET 0xA8
#define I2O_EXEC_IOP_CLEAR 0xBE
#define I2O_EXEC_IOP_CONNECT 0xC9
#define I2O_EXEC_IOP_RESET 0xBD
#define I2O_EXEC_LCT_NOTIFY 0xA2
#define I2O_EXEC_OUTBOUND_INIT 0xA1
#define I2O_EXEC_PATH_ENABLE 0xD3
#define I2O_EXEC_PATH_QUIESCE 0xC5
#define I2O_EXEC_PATH_RESET 0xD7
#define I2O_EXEC_STATIC_MF_CREATE 0xDD
#define I2O_EXEC_STATIC_MF_RELEASE 0xDF
#define I2O_EXEC_STATUS_GET 0xA0
#define I2O_EXEC_SW_DOWNLOAD 0xA9
#define I2O_EXEC_SW_UPLOAD 0xAB
#define I2O_EXEC_SW_REMOVE 0xAD
#define I2O_EXEC_SYS_ENABLE 0xD1
#define I2O_EXEC_SYS_MODIFY 0xC1
#define I2O_EXEC_SYS_QUIESCE 0xC3
#define I2O_EXEC_SYS_TAB_SET 0xA3
/* Init Outbound Q status */
#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01
#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02
#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03
#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04
#define I2O_UTIL_NOP 0x00
/* I2O Get Status State values */
#define I2O_IOP_STATE_INITIALIZING 0x01
#define I2O_IOP_STATE_RESET 0x02
#define I2O_IOP_STATE_HOLD 0x04
#define I2O_IOP_STATE_READY 0x05
#define I2O_IOP_STATE_OPERATIONAL 0x08
#define I2O_IOP_STATE_FAILED 0x10
#define I2O_IOP_STATE_FAULTED 0x11
/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */
#define I2O_REPLY_STATUS_SUCCESS 0x00
#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07
#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08
#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09
#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80
/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
#define I2O_DETAIL_STATUS_SUCCESS 0x0000
#define I2O_DETAIL_STATUS_BAD_KEY 0x0001
#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0002
#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x0003
#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x0004
#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x0005
#define I2O_DETAIL_STATUS_DEVICE_RESET 0x0006
#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x0007
#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0008
#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0009
#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000A
#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000B
#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x000C
#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x000D
#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x000E
#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x000F
#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0010
#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0011
#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0012
#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0013
#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0014
#define I2O_DETAIL_STATUS_TCL_ERROR 0x0015
#define I2O_DETAIL_STATUS_TIMEOUT 0x0016
#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0017
#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0018
#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x0019
#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001A
/* I2O msg header defines for VersionOffset */
#define I2OMSGVER_1_5 0x0001
#define SGL_OFFSET_0 I2OMSGVER_1_5
#define SGL_OFFSET_4 (0x0040 | I2OMSGVER_1_5)
#define TRL_OFFSET_5 (0x0050 | I2OMSGVER_1_5)
#define TRL_OFFSET_6 (0x0060 | I2OMSGVER_1_5)
/* I2O 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 I2O_IOP_TID 0
#define I2O_HOST_TID 0xB91
/* RedCreek I2O private message codes */
#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */
#define RC_PRIVATE_SET_MAC_ADDR 0x0002
#define RC_PRIVATE_GET_NIC_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_SET_PROMISCUOUS_MODE 0x000e
#define RC_PRIVATE_GET_PROMISCUOUS_MODE 0x000f
#define RC_PRIVATE_SET_BROADCAST_MODE 0x0010
#define RC_PRIVATE_GET_BROADCAST_MODE 0x0011
#define RC_PRIVATE_REBOOT 0x00FF
/* I2O message header */
typedef struct _I2O_MESSAGE_FRAME {
U8 VersionOffset;
U8 MsgFlags;
U16 MessageSize;
BF TargetAddress:I2O_TID_SZ;
BF InitiatorAddress:I2O_TID_SZ;
BF Function:I2O_FUNCTION_SZ;
U32 InitiatorContext;
/* SGL[] */
} I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME;
/* assumed a 16K minus 256 byte space for outbound queue message frames */
#define MSG_FRAME_SIZE 512
#define NMBR_MSG_FRAMES 30
/*
** in reserved space right after PAB in host memory is area for returning
** values from card
*/
/*
** 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 ProcessOutboundI2OMsg (PPAB pPab, U32 phyMsgAddr);
static int FillI2OMsgSGLFromTCB (PU32 pMsg, PRCTCB pXmitCntrlBlock);
static int GetI2OStatus (PPAB pPab);
static int SendI2OOutboundQInitMsg (PPAB pPab);
static int SendEnableSysMsg (PPAB pPab);
/*
** =========================================================================
** RCInitI2OMsgLayer()
**
** Initialize the RedCreek I2O Module and adapter.
**
** Inputs: dev - the devices net_device struct
** 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
RCInitI2OMsgLayer (struct net_device *dev,
PFNTXCALLBACK TransmitCallbackFunction,
PFNRXCALLBACK ReceiveCallbackFunction,
PFNCALLBACK RebootCallbackFunction)
{
int result;
PPAB pPab;
U32 pciBaseAddr = dev->base_addr;
PDPA pDpa = dev->priv;
PU8 p_msgbuf = pDpa->msgbuf;
PU8 p_phymsgbuf = (PU8) pDpa->msgbuf_dma;
dprintk
("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:%p phymsgbuf:0x%08ulx\n"
"TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n",
pDpa->id, pciBaseAddr, p_msgbuf, (u32) p_phymsgbuf,
(u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction);
/* Check if this interface already initialized - if so, shut it down */
if (pDpa->pPab != NULL) {
printk (KERN_WARNING
"(rcpci45 driver:) pDpa->pPab [%d] != NULL\n",
pDpa->id);
/* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */
pDpa->pPab = NULL;
}
/* store adapter instance values in adapter block.
* Adapter block is at beginning of message buffer */
pPab = kmalloc (sizeof (*pPab), GFP_KERNEL);
if (!pPab) {
printk (KERN_ERR
"(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n");
result = RC_RTN_MALLOC_ERROR;
goto err_out;
}
memset (pPab, 0, sizeof (*pPab));
pDpa->pPab = pPab;
pPab->p_atu = (PATU) pciBaseAddr;
pPab->pPci45LinBaseAddr = (PU8) pciBaseAddr;
/* Set outbound message frame addr */
pPab->outMsgBlockPhyAddr = (U32) p_phymsgbuf;
pPab->pLinOutMsgBlock = (PU8) p_msgbuf;
/* store callback function addresses */
pPab->pTransCallbackFunc = TransmitCallbackFunction;
pPab->pRecvCallbackFunc = ReceiveCallbackFunction;
pPab->pRebootCallbackFunc = RebootCallbackFunction;
pPab->pCallbackFunc = (PFNCALLBACK) NULL;
/*
** Initialize I2O IOP
*/
result = GetI2OStatus (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) {
printk (KERN_INFO
"(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n");
RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL);
}
result = SendI2OOutboundQInitMsg (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
result = SendEnableSysMsg (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
return RC_RTN_NO_ERROR;
err_out_dealloc:
kfree (pPab);
err_out:
return result;
}
/*
** =========================================================================
** Disable and Enable I2O interrupts. I2O 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 RCI2OSendPacket() functions. Disabling I2O interrupts
** will prevent hardware interrupt to host even though the outbound I2O msg
** queue is not emtpy.
** =========================================================================
*/
#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */
RC_RETURN
RCDisableI2OInterrupts (struct net_device * dev)
{
PPAB pPab = ((PDPA) dev->priv)->pPab;
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
RCEnableI2OInterrupts (struct net_device * dev)
{
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCI2OSendPacket()
** =========================================================================
*/
RC_RETURN
RCI2OSendPacket (struct net_device * dev, U32 InitiatorContext,
PRCTCB pTransCtrlBlock)
{
U32 msgOffset;
PU32 pMsg;
int size;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("RCI2OSendPacket()...\n");
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) {
dprintk ("RCI2OSendPacket(): 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);
size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock);
if (size == -1) { /* error processing TCB - send NOP msg */
dprintk ("RCI2OSendPacket(): Error Rrocess TCB!\n");
pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] =
I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_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] =
I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 |
RC_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;
}
}
/*
** =========================================================================
** RCI2OPostRecvBuffer()
**
** inputs: pBufrCntrlBlock - pointer to buffer control block
**
** returns TRUE if successful in sending message, else FALSE.
** =========================================================================
*/
RC_RETURN
RCPostRecvBuffers (struct net_device * dev, PRCTCB pTransCtrlBlock)
{
U32 msgOffset;
PU32 pMsg;
int size;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("RCPostRecvBuffers()...\n");
/* search for DeviceHandle */
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) {
dprintk ("RCPostRecvBuffers(): 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);
size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock);
if (size == -1) { /* error prcessing TCB - send 3 DWORD private msg == NOP */
dprintk
("RCPostRecvBuffers(): Error Processing TCB! size = %d\n",
size);
pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] =
I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_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] =
I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 |
RC_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;
}
}
/*
** =========================================================================
** RCProcI2OMsgQ()
**
** Process I2O outbound message queue until empty.
** =========================================================================
*/
irqreturn_t
RCProcI2OMsgQ (struct net_device *dev)
{
U32 phyAddrMsg;
PU8 p8Msg;
PU32 p32;
U16 count;
PPAB pPab = ((PDPA) dev->priv)->pPab;
unsigned char debug_msg[20];
if (pPab == NULL)
return IRQ_NONE;
phyAddrMsg = pPab->p_atu->OutQueue;
while (phyAddrMsg != 0xFFFFFFFF) {
p8Msg =
pPab->pLinOutMsgBlock + (phyAddrMsg -
pPab->outMsgBlockPhyAddr);
p32 = (PU32) p8Msg;
dprintk ("msg: 0x%x 0x%x \n", p8Msg[7], p32[5]);
/* Send Packet Reply Msg */
if (I2O_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,
dev);
} else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */
dprintk
("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n",
(u32) pPab, (u32) p8Msg, (u32) p32);
dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[0], p32[1], p32[2], p32[3]);
dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[4], p32[5], p32[6], p32[7]);
dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n",
p32[8], p32[9], p32[10], p32[11]);
/* status, count, buckets remaining, packetParmBlock, adapter */
(*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12],
p32[5], p32 + 6, dev);
} else if (I2O_LAN_RESET == p8Msg[7]
|| I2O_LAN_SHUTDOWN == p8Msg[7])
if (pPab->pCallbackFunc)
(*pPab->pCallbackFunc) (p8Msg[19], 0, 0, dev);
else
pPab->pCallbackFunc = (PFNCALLBACK) 1;
else if (I2O_PRIVATE == p8Msg[7]) {
dprintk ("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
switch (p32[5]) {
case RC_PRIVATE_DEBUG_MSG:
msgFlag = 1;
dprintk ("Received I2O_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';
dprintk ("%s", debug_msg);
break;
case RC_PRIVATE_REBOOT:
dprintk ("Adapter reboot initiated...\n");
if (pPab->pRebootCallbackFunc)
(*pPab->pRebootCallbackFunc) (0, 0, 0,
dev);
break;
default:
printk (KERN_WARNING
"(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n",
p32[5]);
break;
}
}
/*
** Process other Msg's
*/
else
ProcessOutboundI2OMsg (pPab, phyAddrMsg);
/* return MFA to outbound free Q */
pPab->p_atu->OutQueue = phyAddrMsg;
/* any more msgs? */
phyAddrMsg = pPab->p_atu->OutQueue;
}
return IRQ_HANDLED;
}
/*
** =========================================================================
** 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 (struct net_device *dev,
P_RCLINKSTATS StatsReturnAddr,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset;
volatile U32 timeout;
volatile PU32 pMsg;
volatile PU32 p32, pReturnAddr;
P_NICSTAT pStats;
int i;
PPAB pPab = ((PDPA) dev->priv)->pPab;
/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("Get8255XStats(): 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);
/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
/*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = 0x112; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS;
pMsg[5] = pPab->outMsgBlockPhyAddr;
p32 = (PU32) pPab->outMsgBlockPhyAddr;
pStats = (P_NICSTAT) pPab->pLinOutMsgBlock;
pStats->dump_status = 0xFFFFFFFF;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
timeout = 100000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (pStats->dump_status != 0xFFFFFFFF)
break;
if (!timeout--) {
dprintk
("RCGet82558Stats() Timeout waiting for NIC statistics\n");
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 (struct net_device * dev, PU32 ReturnAddr,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset;
volatile U32 timeout;
volatile PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n",
(u32) ReturnAddr);
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("Get82558LinkStatus(): 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);
/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
/*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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;
p32 = (PU32) pPab->pLinOutMsgBlock;
*p32 = 0xFFFFFFFF;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
timeout = 100000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (*p32 != 0xFFFFFFFF)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link status\n");
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 (struct net_device * dev, PFNWAITCALLBACK WaitCallback)
{
unsigned timeout;
U32 off;
PU8 mac = dev->dev_addr;
PU32 p;
U32 temp[2];
PPAB pPab = ((PDPA) dev->priv)->pPab;
PATU p_atu;
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);
dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
(uint) p_atu, (uint) off, (uint) p);
/* setup private message */
p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O device */
dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
(uint) p_atu, (uint) off, (uint) p);
/* wait for the rcpci45 board to update the info */
timeout = 1000000;
while (0 == p_atu->EtherMacLow) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
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);
dprintk ("rc_getmac: 0x%x\n", (u32) mac);
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 (struct net_device * dev, PU8 mac)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O 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 (struct net_device * dev, U16 LinkSpeedCode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetPromiscuousMode()
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
RC_RETURN
RCSetPromiscuousMode (struct net_device * dev, U16 Mode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE;
pMsg[5] = Mode; /* promiscuous mode setting */
pPab->p_atu->InQueue = off; /* send it to the device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetPromiscuousMode()
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetPromiscuousMode (struct net_device * dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) 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;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk
("Timeout waiting for promiscuous mode from adapter\n");
dprintk ("0x%8x\n", p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get mode */
*pMode = (U8) ((volatile PU8) p32)[0] & 0x0f;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetBroadcastMode()
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
RC_RETURN
RCSetBroadcastMode (struct net_device * dev, U16 Mode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE;
pMsg[5] = Mode; /* promiscuous mode setting */
pPab->p_atu->InQueue = off; /* send it to the device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetBroadcastMode()
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetBroadcastMode (struct net_device * dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) 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;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
printk (KERN_WARNING
"(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n");
printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n",
p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get mode */
*pMode = (U8) ((volatile PU8) p32)[0] & 0x0f;
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 (struct net_device * dev, PU32 pLinkSpeedCode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
U8 IOPLinkSpeed;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) 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;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link speed from IOP\n");
dprintk ("0x%8x\n", p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get Link speed */
IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f;
*pLinkSpeedCode = IOPLinkSpeed;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCReportDriverCapability(struct net_device *dev, U32 capability)
**
** Currently defined bits:
** WARM_REBOOT_CAPABLE 0x01
**
** =========================================================================
*/
RC_RETURN
RCReportDriverCapability (struct net_device * dev, U32 capability)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetFirmwareVer()
**
** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
**
** =========================================================================
*/
RC_RETURN
RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("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;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link speed from IOP\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 (struct net_device * dev, U16 ResourceFlags, PU32 ReturnAddr,
PFNCALLBACK CallbackFunction)
{
unsigned long off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
long timeout = 0;
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] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = ResourceFlags << 16; /* resource flags */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
if (CallbackFunction == (PFNCALLBACK) NULL) {
/* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
or until timer goes off */
while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) {
RCProcI2OMsgQ (dev);
udelay (1000); /* please don't hog the bus!!! */
timeout++;
if (timeout > 10000) {
break;
}
}
if (ReturnAddr != (PU32) NULL)
*ReturnAddr = (U32) pPab->pCallbackFunc;
}
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCResetIOP()
**
** Send StatusGet Msg, wait for results return directly to buffer.
**
** =========================================================================
*/
RC_RETURN
RCResetIOP (struct net_device * dev)
{
U32 msgOffset, timeout;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
volatile PU32 p32;
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] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_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;
pMsg[7] = 0;
pMsg[8] = 1; /* return 1 byte */
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
p32[1] = 0;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] || p32[1])
break;
if (!timeout--) {
dprintk ("RCResetIOP 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 (struct net_device * dev, U16 ResourceFlags,
PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
{
volatile PU32 pMsg;
U32 off;
PPAB pPab = ((PDPA) dev->priv)->pPab;
long timeout = 0;
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] =
I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = ResourceFlags << 16; /* resource flags */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
if (CallbackFunction == (PFNCALLBACK) NULL) {
/* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
or until timer goes off */
while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) {
RCProcI2OMsgQ (dev);
udelay (1000); /* please don't hog the bus!!! */
timeout++;
if (timeout > 10000) {
printk (KERN_WARNING
"(rcpci45 driver:) RCShutdownLANCard(): timeout\n");
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 (struct net_device * dev, U32 ipAddr, U32 netMask)
{
volatile PU32 pMsg;
U32 off;
PPAB pPab = ((PDPA) dev->priv)->pPab;
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] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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 I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetRavlinIPandMask()
**
** get the IP address and MASK from the card
**
** =========================================================================
*/
RC_RETURN
RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask,
PFNWAITCALLBACK WaitCallback)
{
unsigned timeout;
U32 off;
PU32 pMsg, p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
PATU p_atu;
dprintk
("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n",
(u32) pIpAddr, *pIpAddr);
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;
*p32 = 0xFFFFFFFF;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
dprintk
("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n",
(u32) p_atu, off, (u32) p32);
/* setup private message */
pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_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;
p_atu->InQueue = off; /* send it to the I2O device */
dprintk
("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n",
(u32) p_atu, off, (u32) p32);
/* wait for the rcpci45 board to update the info */
timeout = 100000;
while (0xffffffff == *p32) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (!timeout--) {
dprintk ("RCGetRavlinIPandMask: Timeout\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
dprintk
("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n",
p32[0], p32[1]);
/* send IP and mask to user's space */
*pIpAddr = p32[0];
*pNetMask = p32[1];
dprintk
("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n",
(u32) pIpAddr, *pIpAddr);
return RC_RTN_NO_ERROR;
}
/*
** /////////////////////////////////////////////////////////////////////////
** /////////////////////////////////////////////////////////////////////////
**
** local functions
**
** /////////////////////////////////////////////////////////////////////////
** /////////////////////////////////////////////////////////////////////////
*/
/*
** =========================================================================
** SendI2OOutboundQInitMsg()
**
** =========================================================================
*/
static int
SendI2OOutboundQInitMsg (PPAB pPab)
{
U32 msgOffset, timeout, phyOutQFrames, i;
volatile PU32 pMsg;
volatile PU32 p32;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("SendI2OOutboundQInitMsg(): 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);
dprintk
("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n",
(u32) pMsg, msgOffset);
pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
pMsg[1] =
I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_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;
/* virtual pointer to return buffer - clear first two dwords */
p32 = (PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 100000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0])
break;
if (!timeout--) {
dprintk
("Timeout wait for InitOutQ InPrgress status from IOP\n");
return RC_RTN_NO_I2O_STATUS;
}
}
timeout = 100000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE)
break;
if (!timeout--) {
dprintk
("Timeout wait for InitOutQ Complete status from IOP\n");
return RC_RTN_NO_I2O_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;
}
/*
** =========================================================================
** GetI2OStatus()
**
** Send StatusGet Msg, wait for results return directly to buffer.
**
** =========================================================================
*/
static int
GetI2OStatus (PPAB pPab)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
msgOffset = pPab->p_atu->InQueue;
dprintk ("GetI2OStatus: msg offset = 0x%x\n", msgOffset);
if (msgOffset == 0xFFFFFFFF) {
dprintk ("GetI2OStatus(): 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);
pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_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;
pMsg[7] = 0;
pMsg[8] = 88; /* return 88 bytes */
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
p32[1] = 0;
dprintk
("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n",
(u32) pMsg, msgOffset, pMsg[1], pMsg[6]);
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32);
/* wait for response */
timeout = 1000000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] && p32[1])
break;
if (!timeout--) {
dprintk ("Timeout waiting for status from IOP\n");
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[0], p32[1], p32[2], p32[3]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[4], p32[5], p32[6], p32[7]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[8], p32[9], p32[10], p32[11]);
return RC_RTN_NO_I2O_STATUS;
}
}
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1],
p32[2], p32[3]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5],
p32[6], p32[7]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9],
p32[10], p32[11]);
/* get IOP state */
pPab->IOPState = ((volatile PU8) p32)[10];
pPab->InboundMFrameSize = ((volatile PU16) p32)[6];
dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n",
pPab->IOPState, pPab->InboundMFrameSize);
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** SendEnableSysMsg()
**
**
** =========================================================================
*/
static int
SendEnableSysMsg (PPAB pPab)
{
U32 msgOffset;
volatile PU32 pMsg;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("SendEnableSysMsg(): 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);
dprintk
("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n",
(u32) pMsg, msgOffset);
pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_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;
}
/*
** =========================================================================
** FillI2OMsgFromTCB()
**
** inputs pMsgU32 - virtual 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
FillI2OMsgSGLFromTCB (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;
dprintk ("FillI2OMsgSGLFromTCBX\n");
dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg);
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;
}
/*
** =========================================================================
** ProcessOutboundI2OMsg()
**
** process I2O reply message
** * change to msg structure *
** =========================================================================
*/
static void
ProcessOutboundI2OMsg (PPAB pPab, U32 phyAddrMsg)
{
PU8 p8Msg;
PU32 p32;
/* U16 count; */
p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
p32 = (PU32) p8Msg;
dprintk
("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n",
(u32) pPab, phyAddrMsg, (u32) p8Msg);
dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1],
p32[2], p32[3]);
dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5],
p32[6], p32[7]);
if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) {
dprintk ("Message reply status not success\n");
return;
}
switch (p8Msg[7]) { /* function code byte */
case I2O_EXEC_SYS_TAB_SET:
msgFlag = 1;
dprintk ("Received I2O_EXEC_SYS_TAB_SET reply\n");
break;
case I2O_EXEC_HRT_GET:
msgFlag = 1;
dprintk ("Received I2O_EXEC_HRT_GET reply\n");
break;
case I2O_EXEC_LCT_NOTIFY:
msgFlag = 1;
dprintk ("Received I2O_EXEC_LCT_NOTIFY reply\n");
break;
case I2O_EXEC_SYS_ENABLE:
msgFlag = 1;
dprintk ("Received I2O_EXEC_SYS_ENABLE reply\n");
break;
default:
dprintk ("Received UNKNOWN reply\n");
break;
}
}
/*
** *************************************************************************
**
**
** R C L A N M T L . H $Revision: 6 $
**
**
** RedCreek I2O LAN Message Transport Layer header file.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Header file for host I2O (Intelligent I/O) LAN 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 RCLANMTL_H
#define RCLANMTL_H
/* Linux specific includes */
#include <asm/types.h>
#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */
#include <linux/string.h>
#else
#include <string.h>
#endif
#include <linux/delay.h> /* for udelay() */
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/io.h>
/* Debug stuff. Define for debug output */
#undef RCDEBUG
#ifdef RCDEBUG
#define dprintk(args...) printk(KERN_DEBUG "rc: " args)
#else
#define dprintk(args...) { }
#endif
/* Typedefs */
/* scalar data types */
typedef __u8 U8;
typedef __u16 U16;
typedef __u32 U32;
typedef __u8 *PU8;
typedef __u16 *PU16;
typedef __u32 *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 RCProcI2OMsgQ() when packet have been transmitted from buffers
** given in the RCI2OSendPacket() 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 RCI2OSendPacket() 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, struct net_device *);
/*
** type PFNRXCALLBACK
**
** Pointer to user's receive callback function. This user function
** is called from RCProcI2OMsgQ() 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, struct net_device *);
/*
** 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, struct net_device * dev);
/*
** 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;
} *PATU;
/*
** typedef PAB
**
** PCI Adapter Block - holds instance specific information.
*/
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 IOPState;
U16 InboundMFrameSize;
} *PPAB;
/*
* Driver Private Area, DPA.
*/
typedef struct {
U8 id; /* the AdapterID */
/* These two field are basically for the RCioctl function.
* I could not determine if they could be avoided. (RAA)*/
U32 pci_addr; /* the pci address of the adapter */
U32 pci_addr_len;
struct pci_dev *pci_dev;
struct timer_list timer; /* timer */
struct net_device_stats stats; /* the statistics structure */
unsigned long numOutRcvBuffers; /* number of outstanding receive buffers */
unsigned char shutdown;
unsigned char reboot;
unsigned char nexus;
PU8 msgbuf; /* Pointer to Lan Api Private Area */
dma_addr_t msgbuf_dma;
PPAB pPab; /* Pointer to the PCI Adapter Block */
} *PDPA;
/* 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_I2O_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_I2O_STATUS 9
#define RC_RTN_NO_FIRM_VER 10
#define RC_RTN_NO_LINK_SPEED 11
/* Driver capability flags */
#define WARM_REBOOT_CAPABLE 0x01
/*
** 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 I2O_REPLY_STATUS_SUCCESS 0x00
#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
/* DetailedStatusCode defines */
#define I2O_LAN_DSC_SUCCESS 0x0000
#define I2O_LAN_DSC_DEVICE_FAILURE 0x0001
#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x0002
#define I2O_LAN_DSC_TRANSMIT_ERROR 0x0003
#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x0004
#define I2O_LAN_DSC_RECEIVE_ERROR 0x0005
#define I2O_LAN_DSC_RECEIVE_ABORTED 0x0006
#define I2O_LAN_DSC_DMA_ERROR 0x0007
#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x0008
#define I2O_LAN_DSC_OUT_OF_MEMORY 0x0009
#define I2O_LAN_DSC_BUCKET_OVERRUN 0x000A
#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x000B
#define I2O_LAN_DSC_CANCELED 0x000C
#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x000D
#define I2O_LAN_DSC_DESTINATION_ADDRESS_DETECTED 0x000E
#define I2O_LAN_DSC_DESTINATION_ADDRESS_OMITTED 0x000F
#define I2O_LAN_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
** RCI2OSendPacket() 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 LAN I2O message transport layer
** -------------------------------------------------------------------------
*/
/*
** InitRCI2OMsgLayer()
**
** Called once prior to using the I2O LAN 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 I2O 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.
**
** Inputs: dev - the net_device struct for the device.
** TransmitCallbackFunction - address of user's TX callback function
** ReceiveCallbackFunction - address of user's RX callback function
** RebootCallbackFunction - address of user's reboot callback function
**
*/
RC_RETURN RCInitI2OMsgLayer (struct net_device *dev,
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 (struct net_device *dev, U32 ipAddr,
U32 netMask);
/*
** =========================================================================
** RCGetRavlinIPandMask()
**
** get the IP address and MASK from the card
**
** =========================================================================
*/
RC_RETURN
RCGetRavlinIPandMask (struct net_device *dev, PU32 pIpAddr, PU32 pNetMask,
PFNWAITCALLBACK WaitCallback);
/*
** RCProcI2OMsgQ()
**
** 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.
*/
irqreturn_t RCProcI2OMsgQ (struct net_device *dev);
/*
** Disable and Enable I2O interrupts. I2O 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 RCI2OSendPacket() functions. Disabling I2O interrupts
** will prevent hardware interrupt to host even though the outbound I2O msg
** queue is not emtpy.
*/
RC_RETURN RCEnableI2OInterrupts (struct net_device *dev);
RC_RETURN RCDisableI2OInterrupts (struct net_device *dev);
/*
** 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 (struct net_device *dev,
PRCTCB pTransactionCtrlBlock);
#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
/*
** RCI2OSendPacket()
**
** 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 RCI2OSendPacket (struct net_device *dev,
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 (struct net_device *dev,
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 (struct net_device *dev,
PU32 pReturnStatus, PFNWAITCALLBACK WaitCallback);
/* Link Status defines - value returned in pReturnStatus */
#define RC_LAN_LINK_STATUS_DOWN 0
#define RC_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 (struct net_device *dev, PFNWAITCALLBACK WaitCallback);
/*
** RCSetMAC()
**
** Set a new user port MAC address. This address will be returned on
** subsequent RCGetMAC() calls.
*/
RC_RETURN RCSetMAC (struct net_device *dev, PU8 mac);
/*
** RCSetLinkSpeed()
**
** set adapter's link speed based on given input code.
*/
RC_RETURN RCSetLinkSpeed (struct net_device *dev, 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 (struct net_device *dev, PU32 pLinkSpeedCode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCSetPromiscuousMode(struct net_device *dev, U16 Mode)
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
#define PROMISCUOUS_MODE_OFF 0
#define PROMISCUOUS_MODE_ON 1
RC_RETURN RCSetPromiscuousMode (struct net_device *dev, U16 Mode);
/*
** =========================================================================
** RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback)
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetPromiscuousMode (struct net_device *dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCSetBroadcastMode(struct net_device *dev, U16 Mode)
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
#define BROADCAST_MODE_OFF 0
#define BROADCAST_MODE_ON 1
RC_RETURN RCSetBroadcastMode (struct net_device *dev, U16 Mode);
/*
** =========================================================================
** RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback)
**
** get broadcast mode setting
**
** Possible return values placed in pMode:
** 0 = broadcast mode not set
** 1 = broadcast mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetBroadcastMode (struct net_device *dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCReportDriverCapability(struct net_device *dev, U32 capability)
**
** Currently defined bits:
** WARM_REBOOT_CAPABLE 0x01
**
** =========================================================================
*/
RC_RETURN RCReportDriverCapability (struct net_device *dev, 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 (struct net_device *dev, 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 I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
** detailed status of I2O_LAN_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 I2O 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 (struct net_device *dev, 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 I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER
** and detailed status of I2O_LAN_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 I2O 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 (struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr,
PFNCALLBACK CallbackFunction);
/*
** RCResetIOP();
** Initializes IOPState to I2O_IOP_STATE_RESET.
** Stops access to outbound message Q.
** Discards any outstanding transmit or posted receive buffers.
** Clears outbound message Q.
*/
RC_RETURN RCResetIOP (struct net_device *dev);
#endif /* RCLANMTL_H */
/*
**
** RCpci45.c
**
**
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** Written by Pete Popov and Brian Moyle.
**
** Known Problems
**
** None known at this time.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Francois Romieu, Apr 2003: Converted to pci DMA mapping API.
**
** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional
** again. Note that this card is not supported or manufactured by
** RedCreek anymore.
**
** Rasmus Andersen, December 2000: Converted to new PCI API and general
** cleanup.
**
** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems
** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and
** added a #define(s) to enable the use of the same file for both, the 2.0.x
** kernels as well as the 2.1.x.
**
** Ported to 2.1.x by Alan Cox 1998/12/9.
**
** Sometime in mid 1998, written by Pete Popov and Brian Moyle.
**
***************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <asm/irq.h> /* For NR_IRQS only. */
#include <asm/bitops.h>
#include <asm/uaccess.h>
static char version[] __initdata =
"RedCreek Communications PCI linux driver version 2.21\n";
#define RC_LINUX_MODULE
#include "rclanmtl.h"
#include "rcif.h"
#define RUN_AT(x) (jiffies + (x))
#define NEW_MULTICAST
#define MAX_ETHER_SIZE 1520
#define MAX_NMBR_RCV_BUFFERS 96
#define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16
#define BD_SIZE 3 /* Bucket Descriptor size */
#define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */
/* RedCreek LAN device Target ID */
#define RC_LAN_TARGET_ID 0x10
/* RedCreek's OSM default LAN receive Initiator */
#define DEFAULT_RECV_INIT_CONTEXT 0xA17
/* minimum msg buffer size needed by the card
* Note that the size of this buffer is hard code in the
* ipsec card's firmware. Thus, the size MUST be a minimum
* of 16K. Otherwise the card will end up using memory
* that does not belong to it.
*/
#define MSG_BUF_SIZE 16384
/* 2003/04/20: I don't know about the hardware ability but the driver won't
* play safe with 64 bit addressing and DAC without NETIF_F_HIGHDMA doesn't
* really make sense anyway. Let's play safe - romieu.
*/
#define RCPCI45_DMA_MASK ((u64) 0xffffffff)
static U32 DriverControlWord;
static void rc_timer (unsigned long);
static int RCopen (struct net_device *);
static int RC_xmit_packet (struct sk_buff *, struct net_device *);
static irqreturn_t RCinterrupt (int, void *, struct pt_regs *);
static int RCclose (struct net_device *dev);
static struct net_device_stats *RCget_stats (struct net_device *);
static int RCioctl (struct net_device *, struct ifreq *, int);
static int RCconfig (struct net_device *, struct ifmap *);
static void RCxmit_callback (U32, U16, PU32, struct net_device *);
static void RCrecv_callback (U32, U8, U32, PU32, struct net_device *);
static void RCreset_callback (U32, U32, U32, struct net_device *);
static void RCreboot_callback (U32, U32, U32, struct net_device *);
static int RC_allocate_and_post_buffers (struct net_device *, int);
static struct pci_device_id rcpci45_pci_table[] = {
{ PCI_VENDOR_ID_REDCREEK, PCI_DEVICE_ID_RC45, PCI_ANY_ID, PCI_ANY_ID,},
{}
};
MODULE_DEVICE_TABLE (pci, rcpci45_pci_table);
MODULE_LICENSE("GPL");
static void __devexit
rcpci45_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
PDPA pDpa = dev->priv;
RCResetIOP (dev);
unregister_netdev (dev);
free_irq (dev->irq, dev);
iounmap ((void *) dev->base_addr);
pci_release_regions (pdev);
pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf,
pDpa->msgbuf_dma);
if (pDpa->pPab)
kfree (pDpa->pPab);
free_netdev (dev);
pci_set_drvdata (pdev, NULL);
}
static int
rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned long *vaddr;
PDPA pDpa;
int error;
static int card_idx = -1;
struct net_device *dev;
unsigned long pci_start, pci_len;
card_idx++;
/*
* Allocate and fill new device structure.
* We need enough for struct net_device plus DPA plus the LAN
* API private area, which requires a minimum of 16KB. The top
* of the allocated area will be assigned to struct net_device;
* the next chunk will be assigned to DPA; and finally, the rest
* will be assigned to the LAN API layer.
*/
dev = alloc_etherdev(sizeof(*pDpa));
if (!dev) {
printk (KERN_ERR
"(rcpci45 driver:) alloc_etherdev alloc failed\n");
error = -ENOMEM;
goto err_out;
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
error = pci_enable_device (pdev);
if (error) {
printk (KERN_ERR
"(rcpci45 driver:) %d: pci enable device error\n",
card_idx);
goto err_out;
}
pci_start = pci_resource_start (pdev, 0);
pci_len = pci_resource_len (pdev, 0);
printk("pci_start %lx pci_len %lx\n", pci_start, pci_len);
pci_set_drvdata (pdev, dev);
pDpa = dev->priv;
pDpa->id = card_idx;
pDpa->pci_dev = pdev;
pDpa->pci_addr = pci_start;
if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) {
printk (KERN_ERR
"(rcpci45 driver:) No PCI mem resources! Aborting\n");
error = -EBUSY;
goto err_out_free_dev;
}
/*
* pDpa->msgbuf is where the card will dma the I2O
* messages. Thus, we need contiguous physical pages of memory.
* 2003/04/20: pci_alloc_consistent() provides well over the needed
* alignment on a 256 bytes boundary for the LAN API private area.
* Thus it isn't needed anymore to align it by hand.
*/
pDpa->msgbuf = pci_alloc_consistent (pdev, MSG_BUF_SIZE,
&pDpa->msgbuf_dma);
if (!pDpa->msgbuf) {
printk (KERN_ERR "(rcpci45 driver:) \
Could not allocate %d byte memory for the \
private msgbuf!\n", MSG_BUF_SIZE);
error = -ENOMEM;
goto err_out_free_dev;
}
/* The adapter is accessible through memory-access read/write, not
* I/O read/write. Thus, we need to map it to some virtual address
* area in order to access the registers as normal memory.
*/
error = pci_request_regions (pdev, dev->name);
if (error)
goto err_out_free_msgbuf;
error = pci_set_dma_mask (pdev, RCPCI45_DMA_MASK);
if (error) {
printk (KERN_ERR
"(rcpci45 driver:) pci_set_dma_mask failed!\n");
goto err_out_free_region;
}
vaddr = (ulong *) ioremap (pci_start, pci_len);
if (!vaddr) {
printk (KERN_ERR
"(rcpci45 driver:) \
Unable to remap address range from %lu to %lu\n",
pci_start, pci_start + pci_len);
error = -EIO;
goto err_out_free_region;
}
dev->base_addr = (unsigned long) vaddr;
dev->irq = pdev->irq;
dev->open = &RCopen;
dev->hard_start_xmit = &RC_xmit_packet;
dev->stop = &RCclose;
dev->get_stats = &RCget_stats;
dev->do_ioctl = &RCioctl;
dev->set_config = &RCconfig;
if ((error = register_netdev(dev)))
goto err_out_iounmap;
return 0; /* success */
err_out_iounmap:
iounmap((void *) dev->base_addr);
err_out_free_region:
pci_release_regions (pdev);
err_out_free_msgbuf:
pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf,
pDpa->msgbuf_dma);
err_out_free_dev:
free_netdev (dev);
err_out:
card_idx--;
return error;
}
static struct pci_driver rcpci45_driver = {
.name = "rcpci45",
.id_table = rcpci45_pci_table,
.probe = rcpci45_init_one,
.remove = __devexit_p(rcpci45_remove_one),
};
static int __init
rcpci_init_module (void)
{
int rc = pci_module_init (&rcpci45_driver);
if (!rc)
printk (KERN_ERR "%s", version);
return rc;
}
static int
RCopen (struct net_device *dev)
{
int post_buffers = MAX_NMBR_RCV_BUFFERS;
PDPA pDpa = dev->priv;
int count = 0;
int requested = 0;
int error;
if (pDpa->nexus) {
/* This is not the first time RCopen is called. Thus,
* the interface was previously opened and later closed
* by RCclose(). RCclose() does a Shutdown; to wake up
* the adapter, a reset is mandatory before we can post
* receive buffers. However, if the adapter initiated
* a reboot while the interface was closed -- and interrupts
* were turned off -- we need will need to reinitialize
* the adapter, rather than simply waking it up.
*/
printk (KERN_INFO "Waking up adapter...\n");
RCResetLANCard (dev, 0, 0, 0);
} else {
pDpa->nexus = 1;
/*
* RCInitI2OMsgLayer is done only once, unless the
* adapter was sent a warm reboot
*/
error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback,
(PFNRXCALLBACK) RCrecv_callback,
(PFNCALLBACK) RCreboot_callback);
if (error) {
printk (KERN_ERR "%s: Unable to init msg layer (%x)\n",
dev->name, error);
goto err_out;
}
if ((error = RCGetMAC (dev, NULL))) {
printk (KERN_ERR "%s: Unable to get adapter MAC\n",
dev->name);
goto err_out;
}
}
/* Request a shared interrupt line. */
error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev);
if (error) {
printk (KERN_ERR "%s: unable to get IRQ %d\n",
dev->name, dev->irq);
goto err_out;
}
DriverControlWord |= WARM_REBOOT_CAPABLE;
RCReportDriverCapability (dev, DriverControlWord);
printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n",
dev->name);
RCEnableI2OInterrupts (dev);
while (post_buffers) {
if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
else
requested = post_buffers;
count = RC_allocate_and_post_buffers (dev, requested);
if (count < requested) {
/*
* Check to see if we were able to post
* any buffers at all.
*/
if (post_buffers == MAX_NMBR_RCV_BUFFERS) {
printk (KERN_ERR "%s: \
unable to allocate any buffers\n",
dev->name);
goto err_out_free_irq;
}
printk (KERN_WARNING "%s: \
unable to allocate all requested buffers\n", dev->name);
break; /* we'll try to post more buffers later */
} else
post_buffers -= count;
}
pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
pDpa->shutdown = 0; /* just in case */
netif_start_queue (dev);
return 0;
err_out_free_irq:
free_irq (dev->irq, dev);
err_out:
return error;
}
static int
RC_xmit_packet (struct sk_buff *skb, struct net_device *dev)
{
PDPA pDpa = dev->priv;
singleTCB tcb;
psingleTCB ptcb = &tcb;
RC_RETURN status = 0;
netif_stop_queue (dev);
if (pDpa->shutdown || pDpa->reboot) {
printk ("RC_xmit_packet: tbusy!\n");
return 1;
}
/*
* The user is free to reuse the TCB after RCI2OSendPacket()
* returns, since the function copies the necessary info into its
* own private space. Thus, our TCB can be a local structure.
* The skb, on the other hand, will be freed up in our interrupt
* handler.
*/
ptcb->bcount = 1;
/*
* we'll get the context when the adapter interrupts us to tell us that
* the transmission is done. At that time, we can free skb.
*/
ptcb->b.context = (U32) skb;
ptcb->b.scount = 1;
ptcb->b.size = skb->len;
ptcb->b.addr = pci_map_single(pDpa->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb))
!= RC_RTN_NO_ERROR) {
printk ("%s: send error 0x%x\n", dev->name, (uint) status);
return 1;
} else {
dev->trans_start = jiffies;
netif_wake_queue (dev);
}
/*
* That's it!
*/
return 0;
}
/*
* RCxmit_callback()
*
* The transmit callback routine. It's called by RCProcI2OMsgQ()
* because the adapter is done with one or more transmit buffers and
* it's returning them to us, or we asked the adapter to return the
* outstanding transmit buffers by calling RCResetLANCard() with
* RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag.
* All we need to do is free the buffers.
*/
static void
RCxmit_callback (U32 Status,
U16 PcktCount, PU32 BufferContext, struct net_device *dev)
{
struct sk_buff *skb;
PDPA pDpa = dev->priv;
if (!pDpa) {
printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n",
dev->name);
return;
}
if (Status != I2O_REPLY_STATUS_SUCCESS)
printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n",
dev->name, (uint) Status);
if (pDpa->shutdown || pDpa->reboot)
printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n",
dev->name);
while (PcktCount--) {
skb = (struct sk_buff *) (BufferContext[0]);
BufferContext++;
pci_unmap_single(pDpa->pci_dev, BufferContext[1], skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq (skb);
}
netif_wake_queue (dev);
}
static void
RCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk ("RCreset_callback Status 0x%x\n", (uint) Status);
/*
* Check to see why we were called.
*/
if (pDpa->shutdown) {
printk (KERN_INFO "%s: shutting down interface\n",
dev->name);
pDpa->shutdown = 0;
pDpa->reboot = 0;
} else if (pDpa->reboot) {
printk (KERN_INFO "%s: reboot, shutdown adapter\n",
dev->name);
/*
* We don't set any of the flags in RCShutdownLANCard()
* and we don't pass a callback routine to it.
* The adapter will have already initiated the reboot by
* the time the function returns.
*/
RCDisableI2OInterrupts (dev);
RCShutdownLANCard (dev, 0, 0, 0);
printk (KERN_INFO "%s: scheduling timer...\n", dev->name);
init_timer (&pDpa->timer);
pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */
pDpa->timer.data = (unsigned long) dev;
pDpa->timer.function = &rc_timer; /* timer handler */
add_timer (&pDpa->timer);
}
}
static void
RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n",
dev->name, (uint) pDpa->numOutRcvBuffers);
if (pDpa->shutdown) {
printk (KERN_INFO "%s: skip reboot, shutdown initiated\n",
dev->name);
return;
}
pDpa->reboot = 1;
/*
* OK, we reset the adapter and ask it to return all
* outstanding transmit buffers as well as the posted
* receive buffers. When the adapter is done returning
* those buffers, it will call our RCreset_callback()
* routine. In that routine, we'll call RCShutdownLANCard()
* to tell the adapter that it's OK to start the reboot and
* schedule a timer callback routine to execute 3 seconds
* later; this routine will reinitialize the adapter at that time.
*/
RCResetLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0,
(PFNCALLBACK) RCreset_callback);
}
/*
* RCrecv_callback()
*
* The receive packet callback routine. This is called by
* RCProcI2OMsgQ() after the adapter posts buffers which have been
* filled (one ethernet packet per buffer).
*/
static void
RCrecv_callback (U32 Status,
U8 PktCount,
U32 BucketsRemain,
PU32 PacketDescBlock, struct net_device *dev)
{
U32 len, count;
PDPA pDpa = dev->priv;
struct sk_buff *skb;
singleTCB tcb;
psingleTCB ptcb = &tcb;
ptcb->bcount = 1;
if ((pDpa->shutdown || pDpa->reboot) && !Status)
printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n",
dev->name, PktCount);
if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) {
/*
* Free whatever buffers the adapter returned, but don't
* pass them to the kernel.
*/
if (!pDpa->shutdown && !pDpa->reboot)
printk (KERN_INFO "%s: recv error status = 0x%x\n",
dev->name, (uint) Status);
else
printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n",
dev->name, 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 (PacketDescBlock) {
while (PktCount--) {
skb = (struct sk_buff *) PacketDescBlock[0];
dev_kfree_skb (skb);
pDpa->numOutRcvBuffers--;
/* point to next context field */
PacketDescBlock += BD_SIZE;
}
}
return;
} else {
while (PktCount--) {
skb = (struct sk_buff *) PacketDescBlock[0];
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--;
/* point to next context field */
PacketDescBlock += BD_SIZE;
}
}
/*
* Replenish the posted receive buffers.
* DO NOT replenish buffers if the driver has already
* initiated a reboot or shutdown!
*/
if (!pDpa->shutdown && !pDpa->reboot) {
count = RC_allocate_and_post_buffers (dev,
MAX_NMBR_RCV_BUFFERS -
pDpa->numOutRcvBuffers);
pDpa->numOutRcvBuffers += count;
}
}
/*
* RCinterrupt()
*
* Interrupt handler.
* This routine sets up a couple of pointers and calls
* RCProcI2OMsgQ(), which in turn process the message and
* calls one of our callback functions.
*/
static irqreturn_t
RCinterrupt (int irq, void *dev_id, struct pt_regs *regs)
{
PDPA pDpa;
struct net_device *dev = dev_id;
pDpa = dev->priv;
if (pDpa->shutdown)
printk (KERN_DEBUG "%s: shutdown, service irq\n",
dev->name);
return RCProcI2OMsgQ (dev);
}
#define REBOOT_REINIT_RETRY_LIMIT 4
static void
rc_timer (unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
PDPA pDpa = dev->priv;
int init_status;
static int retry;
int post_buffers = MAX_NMBR_RCV_BUFFERS;
int count = 0;
int requested = 0;
if (pDpa->reboot) {
init_status =
RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback,
(PFNRXCALLBACK) RCrecv_callback,
(PFNCALLBACK) RCreboot_callback);
switch (init_status) {
case RC_RTN_NO_ERROR:
pDpa->reboot = 0;
pDpa->shutdown = 0; /* just in case */
RCReportDriverCapability (dev, DriverControlWord);
RCEnableI2OInterrupts (dev);
if (!(dev->flags & IFF_UP)) {
retry = 0;
return;
}
while (post_buffers) {
if (post_buffers >
MAX_NMBR_POST_BUFFERS_PER_MSG)
requested =
MAX_NMBR_POST_BUFFERS_PER_MSG;
else
requested = post_buffers;
count =
RC_allocate_and_post_buffers (dev,
requested);
post_buffers -= count;
if (count < requested)
break;
}
pDpa->numOutRcvBuffers =
MAX_NMBR_RCV_BUFFERS - post_buffers;
printk ("Initialization done.\n");
netif_wake_queue (dev);
retry = 0;
return;
case RC_RTN_FREE_Q_EMPTY:
retry++;
printk (KERN_WARNING "%s inbound free q empty\n",
dev->name);
break;
default:
retry++;
printk (KERN_WARNING "%s bad stat after reboot: %d\n",
dev->name, init_status);
break;
}
if (retry > REBOOT_REINIT_RETRY_LIMIT) {
printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name);
printk (KERN_WARNING "%s shutting down interface\n", dev->name);
RCDisableI2OInterrupts (dev);
dev->flags &= ~IFF_UP;
} else {
printk (KERN_INFO "%s: rescheduling timer...\n",
dev->name);
init_timer (&pDpa->timer);
pDpa->timer.expires = RUN_AT ((40 * HZ) / 10);
pDpa->timer.data = (unsigned long) dev;
pDpa->timer.function = &rc_timer;
add_timer (&pDpa->timer);
}
} else
printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name);
}
static int
RCclose (struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk("RCclose\n");
netif_stop_queue (dev);
if (pDpa->reboot) {
printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name);
dev->flags &= ~IFF_UP;
pDpa->shutdown = 1;
return 0;
}
pDpa->shutdown = 1;
/*
* We can't allow the driver to be unloaded until the adapter returns
* all posted receive buffers. It doesn't hurt to tell the adapter
* to return all posted receive buffers and outstanding xmit buffers,
* even if there are none.
*/
RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0,
(PFNCALLBACK) RCreset_callback);
dev->flags &= ~IFF_UP;
return 0;
}
static struct net_device_stats *
RCget_stats (struct net_device *dev)
{
RCLINKSTATS RCstats;
PDPA pDpa = dev->priv;
if (!pDpa) {
return 0;
} else if (!(dev->flags & IFF_UP)) {
return 0;
}
memset (&RCstats, 0, sizeof (RCLINKSTATS));
if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) ==
RC_RTN_NO_ERROR) {
/* total packets received */
pDpa->stats.rx_packets = RCstats.Rcv_good
/* total packets transmitted */;
pDpa->stats.tx_packets = RCstats.TX_good;
pDpa->stats.rx_errors = RCstats.Rcv_CRCerr +
RCstats.Rcv_alignerr + RCstats.Rcv_reserr +
RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt;
pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs +
RCstats.TX_def + RCstats.TX_totcol;
/*
* 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;
pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr;
pDpa->stats.rx_frame_errors = 0;
pDpa->stats.rx_fifo_errors = 0;
pDpa->stats.rx_missed_errors = 0;
/* detailed tx_errors */
pDpa->stats.tx_aborted_errors = 0;
pDpa->stats.tx_carrier_errors = 0;
pDpa->stats.tx_fifo_errors = 0;
pDpa->stats.tx_heartbeat_errors = 0;
pDpa->stats.tx_window_errors = 0;
return ((struct net_device_stats *) &(pDpa->stats));
}
return 0;
}
static int
RCioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
RCuser_struct RCuser;
PDPA pDpa = dev->priv;
if (!capable (CAP_NET_ADMIN))
return -EPERM;
switch (cmd) {
case RCU_PROTOCOL_REV:
/*
* Assign user protocol revision, to tell user-level
* controller program whether or not it's in sync.
*/
rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
break;
case RCU_COMMAND:
{
if (copy_from_user
(&RCuser, rq->ifr_data, sizeof (RCuser)))
return -EFAULT;
dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
switch (RCuser.cmd) {
case RCUC_GETFWVER:
RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
RCGetFirmwareVer (dev,
(PU8) & RCUD_GETFWVER->
FirmString, NULL);
break;
case RCUC_GETINFO:
RCUD_GETINFO = &RCuser.RCUS_GETINFO;
RCUD_GETINFO->mem_start = dev->base_addr;
RCUD_GETINFO->mem_end =
dev->base_addr + pDpa->pci_addr_len;
RCUD_GETINFO->base_addr = pDpa->pci_addr;
RCUD_GETINFO->irq = dev->irq;
break;
case RCUC_GETIPANDMASK:
RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
RCGetRavlinIPandMask (dev,
(PU32) &
RCUD_GETIPANDMASK->IpAddr,
(PU32) &
RCUD_GETIPANDMASK->
NetMask, NULL);
break;
case RCUC_GETLINKSTATISTICS:
RCUD_GETLINKSTATISTICS =
&RCuser.RCUS_GETLINKSTATISTICS;
RCGetLinkStatistics (dev,
(P_RCLINKSTATS) &
RCUD_GETLINKSTATISTICS->
StatsReturn, NULL);
break;
case RCUC_GETLINKSTATUS:
RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
RCGetLinkStatus (dev,
(PU32) & RCUD_GETLINKSTATUS->
ReturnStatus, NULL);
break;
case RCUC_GETMAC:
RCUD_GETMAC = &RCuser.RCUS_GETMAC;
RCGetMAC (dev, NULL);
memcpy(RCUD_GETMAC, dev->dev_addr, 8);
break;
case RCUC_GETPROM:
RCUD_GETPROM = &RCuser.RCUS_GETPROM;
RCGetPromiscuousMode (dev,
(PU32) & RCUD_GETPROM->
PromMode, NULL);
break;
case RCUC_GETBROADCAST:
RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST;
RCGetBroadcastMode (dev,
(PU32) & RCUD_GETBROADCAST->
BroadcastMode, NULL);
break;
case RCUC_GETSPEED:
if (!(dev->flags & IFF_UP)) {
return -ENODATA;
}
RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
RCGetLinkSpeed (dev,
(PU32) & RCUD_GETSPEED->
LinkSpeedCode, NULL);
break;
case RCUC_SETIPANDMASK:
RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK;
RCSetRavlinIPandMask (dev,
(U32) RCUD_SETIPANDMASK->
IpAddr,
(U32) RCUD_SETIPANDMASK->
NetMask);
break;
case RCUC_SETMAC:
RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac);
break;
case RCUC_SETSPEED:
RCUD_SETSPEED = &RCuser.RCUS_SETSPEED;
RCSetLinkSpeed (dev,
(U16) RCUD_SETSPEED->
LinkSpeedCode);
break;
case RCUC_SETPROM:
RCUD_SETPROM = &RCuser.RCUS_SETPROM;
RCSetPromiscuousMode (dev,
(U16) RCUD_SETPROM->
PromMode);
break;
case RCUC_SETBROADCAST:
RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST;
RCSetBroadcastMode (dev,
(U16) RCUD_SETBROADCAST->
BroadcastMode);
break;
default:
RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
RCUD_DEFAULT->rc = 0x11223344;
break;
}
if (copy_to_user (rq->ifr_data, &RCuser,
sizeof (RCuser)))
return -EFAULT;
break;
} /* RCU_COMMAND */
default:
rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
return -EINVAL;
}
return 0;
}
static int
RCconfig (struct net_device *dev, struct ifmap *map)
{
/*
* To be completed ...
*/
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 "%s Change I/O address not implemented\n",
dev->name);
return -EOPNOTSUPP;
}
return 0;
}
static void __exit
rcpci_cleanup_module (void)
{
pci_unregister_driver (&rcpci45_driver);
}
module_init (rcpci_init_module);
module_exit (rcpci_cleanup_module);
static int
RC_allocate_and_post_buffers (struct net_device *dev, int numBuffers)
{
int i;
PU32 p;
psingleB pB;
struct sk_buff *skb;
PDPA pDpa = dev->priv;
RC_RETURN status;
U32 res = 0;
if (!numBuffers)
return 0;
else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) {
printk (KERN_ERR "%s: Too many buffers requested!\n",
dev->name);
numBuffers = 32;
}
p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB),
GFP_DMA | GFP_ATOMIC);
if (!p) {
printk (KERN_WARNING "%s unable to allocate TCB\n",
dev->name);
goto out;
}
p[0] = 0; /* Buffer Count */
pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */
for (i = 0; i < numBuffers; i++) {
skb = dev_alloc_skb (MAX_ETHER_SIZE + 2);
if (!skb) {
printk (KERN_WARNING
"%s: unable to allocate enough skbs!\n",
dev->name);
goto err_out_unmap;
}
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 = pci_map_single(pDpa->pci_dev, skb->data,
MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
p[0]++;
pB++;
}
if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) {
printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n",
dev->name, status);
goto err_out_unmap;
}
out_free:
res = p[0];
kfree (p);
out:
return (res); /* return the number of posted buffers */
err_out_unmap:
for (; p[0] > 0; p[0]--) {
--pB;
skb = (struct sk_buff *) pB->context;
pci_unmap_single(pDpa->pci_dev, pB->addr, MAX_ETHER_SIZE,
PCI_DMA_FROMDEVICE);
dev_kfree_skb (skb);
}
goto out_free;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment