mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-26 17:19:22 +00:00
add missing files.
This commit is contained in:
1 parent
9fe0449a36
commit
ef1679fa92
17 files changed
+8030
No files matched your search
@@ -0,0 +1,963 @@
|
||||
/**************************************************************************
|
||||
Etherboot - BOOTP/TFTP Bootstrap Program
|
||||
i82586 NIC driver for Etherboot
|
||||
Ken Yap, January 1998
|
||||
***************************************************************************/
|
||||
|
||||
/* to get some global routines like printf */
|
||||
#include "etherboot.h"
|
||||
/* to get the interface to the body of the program */
|
||||
#include "nic.h"
|
||||
|
||||
/* Sources of information:
|
||||
|
||||
Donald Becker's excellent 3c507 driver in Linux
|
||||
Intel 82596 data sheet (yes, 82596; it has a 586 compatibility mode)
|
||||
*/
|
||||
|
||||
/* Code below mostly stolen wholesale from 3c507.c driver in Linux */
|
||||
|
||||
/*
|
||||
Details of the i82586.
|
||||
|
||||
You'll really need the databook to understand the details of this part,
|
||||
but the outline is that the i82586 has two separate processing units.
|
||||
Both are started from a list of three configuration tables, of which only
|
||||
the last, the System Control Block (SCB), is used after reset-time. The SCB
|
||||
has the following fields:
|
||||
Status word
|
||||
Command word
|
||||
Tx/Command block addr.
|
||||
Rx block addr.
|
||||
The command word accepts the following controls for the Tx and Rx units:
|
||||
*/
|
||||
|
||||
#define CUC_START 0x0100
|
||||
#define CUC_RESUME 0x0200
|
||||
#define CUC_SUSPEND 0x0300
|
||||
#define RX_START 0x0010
|
||||
#define RX_RESUME 0x0020
|
||||
#define RX_SUSPEND 0x0030
|
||||
|
||||
/* The Rx unit uses a list of frame descriptors and a list of data buffer
|
||||
descriptors. We use full-sized (1518 byte) data buffers, so there is
|
||||
a one-to-one pairing of frame descriptors to buffer descriptors.
|
||||
|
||||
The Tx ("command") unit executes a list of commands that look like:
|
||||
Status word Written by the 82586 when the command is done.
|
||||
Command word Command in lower 3 bits, post-command action in upper 3
|
||||
Link word The address of the next command.
|
||||
Parameters (as needed).
|
||||
|
||||
Some definitions related to the Command Word are:
|
||||
*/
|
||||
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
|
||||
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
|
||||
#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
|
||||
|
||||
enum commands {
|
||||
CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
|
||||
CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
|
||||
|
||||
/*
|
||||
Details of the EtherLink16 Implementation
|
||||
|
||||
The 3c507 and NI5210 are generic shared-memory i82586 implementations.
|
||||
3c507: The host can map 16K, 32K, 48K, or 64K of the 64K memory into
|
||||
0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
|
||||
NI5210: The host can map 8k or 16k at 0x[CDE][048C]000 but we
|
||||
assume 8k because to have 16k you cannot put a ROM on the NIC.
|
||||
*/
|
||||
|
||||
/* Offsets from the base I/O address. */
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
|
||||
#define SA_DATA 0 /* Station address data, or 3Com signature. */
|
||||
#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
|
||||
#define RESET_IRQ 10 /* Reset the latched IRQ line. */
|
||||
#define I82586_ATTN 11 /* Frob the 82586 Channel Attention line. */
|
||||
#define ROM_CONFIG 13
|
||||
#define MEM_CONFIG 14
|
||||
#define IRQ_CONFIG 15
|
||||
#define EL16_IO_EXTENT 16
|
||||
|
||||
/* The ID port is used at boot-time to locate the ethercard. */
|
||||
#define ID_PORT 0x100
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NI5210
|
||||
|
||||
#define NI52_RESET 0 /* writing to this address, resets the i82586 */
|
||||
#define I82586_ATTN 1 /* channel attention, kick the 586 */
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EXOS205
|
||||
|
||||
#define EXOS205_RESET 0 /* writing to this address, resets the i82586 */
|
||||
#define I82586_ATTN 1 /* channel attention, kick the 586 */
|
||||
|
||||
#endif
|
||||
|
||||
/* Offsets to registers in the mailbox (SCB). */
|
||||
#define iSCB_STATUS 0x8
|
||||
#define iSCB_CMD 0xA
|
||||
#define iSCB_CBL 0xC /* Command BLock offset. */
|
||||
#define iSCB_RFA 0xE /* Rx Frame Area offset. */
|
||||
|
||||
/* Since the 3c507 maps the shared memory window so that the last byte is
|
||||
at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
|
||||
48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
|
||||
We can account for this be setting the 'SBC Base' entry in the ISCP table
|
||||
below for all the 16 bit offset addresses, and also adding the 'SCB Base'
|
||||
value to all 24 bit physical addresses (in the SCP table and the TX and RX
|
||||
Buffer Descriptors).
|
||||
-Mark
|
||||
*/
|
||||
|
||||
/*
|
||||
What follows in 'init_words[]' is the "program" that is downloaded to the
|
||||
82586 memory. It's mostly tables and command blocks, and starts at the
|
||||
reset address 0xfffff6. This is designed to be similar to the EtherExpress,
|
||||
thus the unusual location of the SCB at 0x0008.
|
||||
|
||||
Even with the additional "don't care" values, doing it this way takes less
|
||||
program space than initializing the individual tables, and I feel it's much
|
||||
cleaner.
|
||||
|
||||
The databook is particularly useless for the first two structures, I had
|
||||
to use the Crynwr driver as an example.
|
||||
|
||||
The memory setup is as follows:
|
||||
*/
|
||||
|
||||
#define CONFIG_CMD 0x18
|
||||
#define SET_SA_CMD 0x24
|
||||
#define SA_OFFSET 0x2A
|
||||
#define IDLELOOP 0x30
|
||||
#define TDR_CMD 0x38
|
||||
#define TDR_TIME 0x3C
|
||||
#define DUMP_CMD 0x40
|
||||
#define DIAG_CMD 0x48
|
||||
#define SET_MC_CMD 0x4E
|
||||
#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
|
||||
|
||||
#define TX_BUF_START 0x0100
|
||||
#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
|
||||
|
||||
#define RX_BUF_START 0x1000
|
||||
#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
|
||||
#define RX_BUF_END (mem_end - mem_start - 20)
|
||||
|
||||
/*
|
||||
That's it: only 86 bytes to set up the beast, including every extra
|
||||
command available. The 170 byte buffer at DUMP_DATA is shared between the
|
||||
Dump command (called only by the diagnostic program) and the SetMulticastList
|
||||
command.
|
||||
|
||||
To complete the memory setup you only have to write the station address at
|
||||
SA_OFFSET and create the Tx & Rx buffer lists.
|
||||
|
||||
The Tx command chain and buffer list is setup as follows:
|
||||
A Tx command table, with the data buffer pointing to...
|
||||
A Tx data buffer descriptor. The packet is in a single buffer, rather than
|
||||
chaining together several smaller buffers.
|
||||
A NoOp command, which initially points to itself,
|
||||
And the packet data.
|
||||
|
||||
A transmit is done by filling in the Tx command table and data buffer,
|
||||
re-writing the NoOp command, and finally changing the offset of the last
|
||||
command to point to the current Tx command. When the Tx command is finished,
|
||||
it jumps to the NoOp, when it loops until the next Tx command changes the
|
||||
"link offset" in the NoOp. This way the 82586 never has to go through the
|
||||
slow restart sequence.
|
||||
|
||||
The Rx buffer list is set up in the obvious ring structure. We have enough
|
||||
memory (and low enough interrupt latency) that we can avoid the complicated
|
||||
Rx buffer linked lists by alway associating a full-size Rx data buffer with
|
||||
each Rx data frame.
|
||||
|
||||
I currently use one transmit buffer starting at TX_BUF_START (0x0100), and
|
||||
use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
|
||||
|
||||
*/
|
||||
|
||||
static unsigned short init_words[] = {
|
||||
/* System Configuration Pointer (SCP). */
|
||||
#if defined(INCLUDE_3C507)
|
||||
0x0000, /* Set bus size to 16 bits. */
|
||||
#else
|
||||
0x0001, /* Set bus size to 8 bits */
|
||||
#endif
|
||||
0,0, /* pad words. */
|
||||
0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
|
||||
|
||||
/* Intermediate System Configuration Pointer (ISCP). */
|
||||
0x0001, /* Status word that's cleared when init is done. */
|
||||
0x0008,0,0, /* SCB offset, (skip, skip) */
|
||||
|
||||
/* System Control Block (SCB). */
|
||||
0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
|
||||
CONFIG_CMD, /* Command list pointer, points to Configure. */
|
||||
RX_BUF_START, /* Rx block list. */
|
||||
0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
|
||||
|
||||
/* 0x0018: Configure command. Change to put MAC data with packet. */
|
||||
0, CmdConfigure, /* Status, command. */
|
||||
SET_SA_CMD, /* Next command is Set Station Addr. */
|
||||
0x0804, /* "4" bytes of config data, 8 byte FIFO. */
|
||||
0x2e40, /* Magic values, including MAC data location. */
|
||||
0, /* Unused pad word. */
|
||||
|
||||
/* 0x0024: Setup station address command. */
|
||||
0, CmdSASetup,
|
||||
SET_MC_CMD, /* Next command. */
|
||||
0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
|
||||
|
||||
/* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
|
||||
0, CmdNOp, IDLELOOP, 0 /* pad */,
|
||||
|
||||
/* 0x0038: A unused Time-Domain Reflectometer command. */
|
||||
0, CmdTDR, IDLELOOP, 0,
|
||||
|
||||
/* 0x0040: An unused Dump State command. */
|
||||
0, CmdDump, IDLELOOP, DUMP_DATA,
|
||||
|
||||
/* 0x0048: An unused Diagnose command. */
|
||||
0, CmdDiagnose, IDLELOOP,
|
||||
|
||||
/* 0x004E: An empty set-multicast-list command. */
|
||||
0, CmdMulticastList, IDLELOOP, 0,
|
||||
};
|
||||
|
||||
/* NIC specific static variables go here */
|
||||
|
||||
static unsigned short ioaddr, irq, scb_base;
|
||||
static Address mem_start, mem_end;
|
||||
static char if_port;
|
||||
static unsigned short rx_head, rx_tail;
|
||||
|
||||
#define read_mem(m,s) fmemcpy((char *)s, m, sizeof(s))
|
||||
|
||||
static void setup_rx_buffers(struct nic *nic)
|
||||
{
|
||||
Address write_ptr;
|
||||
unsigned short cur_rx_buf;
|
||||
static unsigned short rx_cmd[16] = {
|
||||
0x0000, /* Rx status */
|
||||
0x0000, /* Rx command, only and last */
|
||||
RX_BUF_START, /* Link (will be adjusted) */
|
||||
RX_BUF_START + 22, /* Buffer offset (will be adjusted) */
|
||||
0x0000, 0x0000, 0x0000, /* Pad for dest addr */
|
||||
0x0000, 0x0000, 0x0000, /* Pad for source addr */
|
||||
0x0000, /* Pad for protocol */
|
||||
0x0000, /* Buffer: Actual count */
|
||||
-1, /* Buffer: Next (none) */
|
||||
RX_BUF_START + 0x20, /* Buffer: Address low (+ scb_base) (will be adjusted) */
|
||||
0x0000, /* Buffer: Address high */
|
||||
0x8000 | (RX_BUF_SIZE - 0x20)
|
||||
};
|
||||
|
||||
cur_rx_buf = rx_head = RX_BUF_START;
|
||||
do { /* While there is room for one more buffer */
|
||||
write_ptr = mem_start + cur_rx_buf;
|
||||
/* adjust some contents */
|
||||
rx_cmd[1] = 0x0000;
|
||||
rx_cmd[2] = cur_rx_buf + RX_BUF_SIZE;
|
||||
rx_cmd[3] = cur_rx_buf + 22;
|
||||
rx_cmd[13] = cur_rx_buf + 0x20 + scb_base;
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(rx_cmd));
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(write_ptr, (char *)rx_cmd, sizeof(rx_cmd));
|
||||
#endif
|
||||
rx_tail = cur_rx_buf;
|
||||
cur_rx_buf += RX_BUF_SIZE;
|
||||
} while (cur_rx_buf <= RX_BUF_END - RX_BUF_SIZE);
|
||||
/* Terminate the list by setting the EOL bit and wrap ther pointer
|
||||
to make the list a ring. */
|
||||
write_ptr = mem_start + rx_tail;
|
||||
rx_cmd[1] = 0xC000;
|
||||
rx_cmd[2] = rx_head;
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ack_status(void)
|
||||
{
|
||||
unsigned short cmd, status;
|
||||
#ifdef ETHERBOOT32
|
||||
unsigned short *shmem = (short *)mem_start;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
unsigned short shmem[CONFIG_CMD>>1];
|
||||
#endif
|
||||
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem);
|
||||
#endif
|
||||
cmd = (status = shmem[iSCB_STATUS>>1]) & 0xf000;
|
||||
if (status & 0x100) /* CU suspended? */
|
||||
cmd |= CUC_RESUME;
|
||||
if ((status & 0x200) == 0) /* CU not active? */
|
||||
cmd |= CUC_START;
|
||||
if (status & 0x010) /* RU suspended? */
|
||||
cmd |= RX_RESUME;
|
||||
else if ((status & 0x040) == 0) /* RU not active? */
|
||||
cmd |= RX_START;
|
||||
if (cmd == 0) /* Nothing to do */
|
||||
return;
|
||||
shmem[iSCB_CMD>>1] = cmd;
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_start, shmem, sizeof(shmem));
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
printf("Status %x Command %x\n", status, cmd);
|
||||
#endif
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
RESET - Reset adapter
|
||||
***************************************************************************/
|
||||
|
||||
static void i82586_reset(struct nic *nic)
|
||||
{
|
||||
int boguscnt;
|
||||
#ifdef ETHERBOOT32
|
||||
unsigned short *shmem = (short *)mem_start;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
unsigned short shmem[CONFIG_CMD>>1];
|
||||
#endif
|
||||
|
||||
/* put the card in its initial state */
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
/* Enable loopback to protect the wire while starting up,
|
||||
and hold the 586 in reset during the memory initialisation. */
|
||||
outb(0x20, ioaddr + MISC_CTRL);
|
||||
#endif
|
||||
|
||||
/* Fix the ISCP address and base. */
|
||||
init_words[3] = scb_base;
|
||||
init_words[7] = scb_base;
|
||||
|
||||
/* Write the words at 0xfff6. */
|
||||
/* Write the words at 0x0000. */
|
||||
/* Fill in the station address. */
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
|
||||
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
memcpy((char *)mem_start + SA_OFFSET, nic->node_addr, ETHER_ADDR_SIZE);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_end - 10, (char *)init_words, 10);
|
||||
memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
memcpyf(mem_start + SA_OFFSET, nic->node_addr, ETHER_ADDR_SIZE);
|
||||
#endif
|
||||
setup_rx_buffers(nic);
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
/* Start the 586 by releasing the reset line, but leave loopback. */
|
||||
outb(0xA0, ioaddr + MISC_CTRL);
|
||||
#endif
|
||||
|
||||
/* This was time consuming to track down; you need to give two channel
|
||||
attention signals to reliably start up the i82586. */
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
boguscnt = 10000;
|
||||
while (
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem),
|
||||
#endif
|
||||
shmem[iSCB_STATUS>>1] == 0)
|
||||
{
|
||||
if (--boguscnt == 0)
|
||||
{
|
||||
printf("i82586 initialisation timed out with status %x, cmd %x\n",
|
||||
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Issue channel-attn -- the 82586 won't start. */
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
/* Disable loopback. */
|
||||
outb(0x80, ioaddr + MISC_CTRL);
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem);
|
||||
#endif
|
||||
printf("i82586 status %x, cmd %x\n",
|
||||
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
POLL - Wait for a frame
|
||||
***************************************************************************/
|
||||
static int i82586_poll(struct nic *nic)
|
||||
{
|
||||
int status;
|
||||
unsigned short rfd_cmd, next_rx_frame, data_buffer_addr,
|
||||
frame_status, pkt_len;
|
||||
#ifdef ETHERBOOT32
|
||||
unsigned short *shmem = (short *)mem_start + rx_head;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
unsigned short shmem[16];
|
||||
#endif
|
||||
|
||||
/* return true if there's an ethernet packet ready to read */
|
||||
if (
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start + rx_head, shmem),
|
||||
#endif
|
||||
((frame_status = shmem[0]) & 0x8000) == 0)
|
||||
return (0); /* nope */
|
||||
rfd_cmd = shmem[1];
|
||||
next_rx_frame = shmem[2];
|
||||
data_buffer_addr = shmem[3];
|
||||
pkt_len = shmem[11];
|
||||
status = 0;
|
||||
if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
|
||||
|| (pkt_len & 0xC000) != 0xC000)
|
||||
printf("\nRx frame corrupt, discarded");
|
||||
else if ((frame_status & 0x2000) == 0)
|
||||
printf("\nRx frame had error");
|
||||
else
|
||||
{
|
||||
/* We have a frame, copy it to our buffer */
|
||||
pkt_len &= 0x3FFF;
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy(nic->packet, (char *)mem_start + rx_head + 0x20, pkt_len);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
fmemcpy(nic->packet, mem_start + rx_head + 0x20, pkt_len);
|
||||
#endif
|
||||
/* Only packets not from ourself */
|
||||
if (memcmp(nic->packet + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE) != 0)
|
||||
{
|
||||
nic->packetlen = pkt_len;
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
/* Clear the status word and set EOL on Rx frame */
|
||||
shmem[0] = 0;
|
||||
shmem[1] = 0xC000;
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_start + rx_head, shmem, sizeof(unsigned short) * 2);
|
||||
/* Clear the EOL on previous RFD */
|
||||
memcpyf(mem_start + rx_tail + 2, shmem, sizeof(unsigned short));
|
||||
#endif
|
||||
#ifdef ETHERBOOT32
|
||||
*(short *)(mem_start + rx_tail + 2) = 0;
|
||||
#endif
|
||||
rx_tail = rx_head;
|
||||
rx_head = next_rx_frame;
|
||||
ack_status();
|
||||
return (status);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
TRANSMIT - Transmit a frame
|
||||
***************************************************************************/
|
||||
static void i82586_transmit(
|
||||
struct nic *nic,
|
||||
char *d, /* Destination */
|
||||
unsigned int t, /* Type */
|
||||
unsigned int s, /* size */
|
||||
char *p) /* Packet */
|
||||
{
|
||||
Address bptr;
|
||||
unsigned short type, z;
|
||||
static unsigned short tx_cmd[11] = {
|
||||
0x0, /* Tx status */
|
||||
CmdTx, /* Tx command */
|
||||
TX_BUF_START+16, /* Next command is a NoOp */
|
||||
TX_BUF_START+8, /* Data Buffer offset */
|
||||
0x8000, /* | with size */
|
||||
0xffff, /* No next data buffer */
|
||||
TX_BUF_START+22, /* + scb_base */
|
||||
0x0, /* Buffer address high bits (always zero) */
|
||||
0x0, /* Nop status */
|
||||
CmdNOp, /* Nop command */
|
||||
TX_BUF_START+16 /* Next is myself */
|
||||
};
|
||||
#ifdef ETHERBOOT32
|
||||
unsigned short *shmem = (short *)mem_start + TX_BUF_START;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
unsigned short shmem[11];
|
||||
#endif
|
||||
|
||||
/* send the packet to destination */
|
||||
/* adjust some contents */
|
||||
type = htons(t);
|
||||
if (s < ETH_MIN_PACKET)
|
||||
s = ETH_MIN_PACKET;
|
||||
tx_cmd[4] = (s + ETHER_HDR_SIZE) | 0x8000;
|
||||
tx_cmd[6] = TX_BUF_START + 22 + scb_base;
|
||||
bptr = mem_start + TX_BUF_START;
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)bptr, (char *)tx_cmd, sizeof(tx_cmd));
|
||||
bptr += sizeof(tx_cmd);
|
||||
memcpy((char *)bptr, d, ETHER_ADDR_SIZE);
|
||||
bptr += ETHER_ADDR_SIZE;
|
||||
memcpy((char *)bptr, nic->node_addr, ETHER_ADDR_SIZE);
|
||||
bptr += ETHER_ADDR_SIZE;
|
||||
memcpy((char *)bptr, (char *)&type, sizeof(type));
|
||||
bptr += sizeof(type);
|
||||
memcpy((char *)bptr, p, s);
|
||||
/* Change the offset in the IDLELOOP */
|
||||
*(unsigned short *)(mem_start + IDLELOOP + 4) = TX_BUF_START;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(bptr, (char *)tx_cmd, sizeof(tx_cmd));
|
||||
bptr += sizeof(tx_cmd);
|
||||
memcpyf(bptr, d, ETHER_ADDR_SIZE);
|
||||
bptr += ETHER_ADDR_SIZE;
|
||||
memcpyf(bptr, nic->node_addr, ETHER_ADDR_SIZE);
|
||||
bptr += ETHER_ADDR_SIZE;
|
||||
memcpyf(bptr, (char *)&type, sizeof(type));
|
||||
bptr += sizeof(type);
|
||||
memcpyf(bptr, p, s);
|
||||
/* Change the offset in the IDLELOOP */
|
||||
z = TX_BUF_START;
|
||||
memcpyf(mem_start + IDLELOOP + 4, (char *)&z, sizeof(z));
|
||||
#endif
|
||||
/* Wait for transmit completion */
|
||||
while (
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start + TX_BUF_START, shmem),
|
||||
#endif
|
||||
(shmem[0] & 0x2000) == 0)
|
||||
;
|
||||
/* Change the offset in the IDLELOOP back and
|
||||
change the final loop to point here */
|
||||
#ifdef ETHERBOOT32
|
||||
*(unsigned short *)(mem_start + IDLELOOP + 4) = IDLELOOP;
|
||||
*(unsigned short *)(mem_start + TX_BUF_START + 20) = IDLELOOP;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
z = IDLELOOP;
|
||||
memcpyf(mem_start + IDLELOOP + 4, (char *)&z, sizeof(z));
|
||||
memcpyf(mem_start + TX_BUF_START + 20, (char *)&z, sizeof(z));
|
||||
#endif
|
||||
ack_status();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
DISABLE - Turn off ethernet interface
|
||||
***************************************************************************/
|
||||
static void i82586_disable(struct nic *nic)
|
||||
{
|
||||
#ifdef ETHERBOOT32
|
||||
unsigned short *shmem = (short *)mem_start;
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
unsigned short shmem[CONFIG_CMD>>1];
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Flush the Tx and disable Rx. */
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem);
|
||||
#endif
|
||||
shmem[iSCB_CMD>>1] = RX_SUSPEND | CUC_SUSPEND;
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_start, shmem, sizeof(shmem));
|
||||
#endif
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
#ifdef INCLUDE_NI5210
|
||||
outb(0, ioaddr + NI52_RESET);
|
||||
#endif
|
||||
#endif /* 0 */
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_3C507
|
||||
|
||||
static int t507_probe1(struct nic *nic, unsigned short ioaddr)
|
||||
{
|
||||
int i;
|
||||
Address size;
|
||||
char mem_config;
|
||||
|
||||
if (inb(ioaddr) != '*' || inb(ioaddr+1) != '3'
|
||||
|| inb(ioaddr+2) != 'C' || inb(ioaddr+3) != 'O')
|
||||
return (0);
|
||||
irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
|
||||
mem_config = inb(ioaddr + MEM_CONFIG);
|
||||
if (mem_config & 0x20)
|
||||
{
|
||||
size = 65536L;
|
||||
mem_start = 0xf00000L + (mem_config & 0x08 ? 0x080000L
|
||||
: (((Address)mem_config & 0x3) << 17));
|
||||
}
|
||||
else
|
||||
{
|
||||
size = ((((Address)mem_config & 0x3) + 1) << 14) & 0xffffL;
|
||||
mem_start = 0x0c0000L + (((Address)mem_config & 0x18) << 12);
|
||||
}
|
||||
mem_end = mem_start + size;
|
||||
scb_base = 65536L - size;
|
||||
if_port = inb(ioaddr + ROM_CONFIG) & 0x80;
|
||||
printf("\n3c507 ioaddr 0x%x, IRQ %d, mem [0x%X-0x%X], %sternal xcvr, addr ",
|
||||
ioaddr, irq, mem_start, mem_end, if_port ? "in" : "ex");
|
||||
/* Get station address */
|
||||
outb(0x01, ioaddr + MISC_CTRL);
|
||||
for (i = 0; i < ETHER_ADDR_SIZE; ++i)
|
||||
{
|
||||
printf("%b", nic->node_addr[i] = inb(ioaddr+i));
|
||||
if (i < ETHER_ADDR_SIZE -1)
|
||||
printf(":");
|
||||
}
|
||||
putchar('\n');
|
||||
return (1);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
PROBE - Look for an adapter, this routine's visible to the outside
|
||||
***************************************************************************/
|
||||
|
||||
struct nic *t507_probe(struct nic *nic, unsigned short *probe_addrs)
|
||||
{
|
||||
static unsigned char init_ID_done = 0;
|
||||
unsigned short lrs_state = 0xff;
|
||||
static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x280, 0 };
|
||||
unsigned short *p;
|
||||
int i;
|
||||
|
||||
if (init_ID_done == 0)
|
||||
{
|
||||
/* Send the ID sequence to the ID_PORT to enable the board */
|
||||
outb(0x00, ID_PORT);
|
||||
for (i = 0; i < 255; ++i)
|
||||
{
|
||||
outb(lrs_state, ID_PORT);
|
||||
lrs_state <<= 1;
|
||||
if (lrs_state & 0x100)
|
||||
lrs_state ^= 0xe7;
|
||||
}
|
||||
outb(0x00, ID_PORT);
|
||||
init_ID_done = 1;
|
||||
}
|
||||
/* if probe_addrs is 0, then routine can use a hardwired default */
|
||||
if (probe_addrs == 0)
|
||||
probe_addrs = io_addrs;
|
||||
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
|
||||
if (t507_probe1(nic, ioaddr))
|
||||
break;
|
||||
if (ioaddr != 0)
|
||||
{
|
||||
/* point to NIC specific routines */
|
||||
i82586_reset(nic);
|
||||
nic->reset = i82586_reset;
|
||||
nic->poll = i82586_poll;
|
||||
nic->transmit = i82586_transmit;
|
||||
nic->disable = i82586_disable;
|
||||
return nic;
|
||||
}
|
||||
/* else */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_NI5210
|
||||
|
||||
static int ni5210_probe2(void)
|
||||
{
|
||||
unsigned short i;
|
||||
unsigned short shmem[10];
|
||||
|
||||
/* Fix the ISCP address and base. */
|
||||
init_words[3] = scb_base;
|
||||
init_words[7] = scb_base;
|
||||
|
||||
/* Write the words at 0xfff6. */
|
||||
/* Write the words at 0x0000. */
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
|
||||
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
if (*(unsigned short *)mem_start != 1)
|
||||
return (0);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_end - 10, (char *)init_words, 10);
|
||||
memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
fmemcpy((char *)&i, mem_start, sizeof(unsigned short));
|
||||
if (i != 1)
|
||||
return (0);
|
||||
#endif
|
||||
outb(0, ioaddr + NI52_RESET);
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
i = 50;
|
||||
while (
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem),
|
||||
#endif
|
||||
shmem[iSCB_STATUS>>1] == 0)
|
||||
{
|
||||
if (--i == 0)
|
||||
{
|
||||
printf("i82586 initialisation timed out with status %x, cmd %x\n",
|
||||
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Issue channel-attn -- the 82586 won't start. */
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
#ifdef ETHERBOOT32
|
||||
if (*(unsigned short *)mem_start != 0)
|
||||
return (0);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
fmemcpy((char *)&i, mem_start, sizeof(unsigned short));
|
||||
if (i != 0)
|
||||
return (0);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int ni5210_probe1(struct nic *nic)
|
||||
{
|
||||
int i;
|
||||
static Address mem_addrs[] = {
|
||||
0xc0000, 0xc4000, 0xc8000, 0xcc000,
|
||||
0xd0000, 0xd4000, 0xd8000, 0xdc000,
|
||||
0xe0000, 0xe4000, 0xe8000, 0xec000,
|
||||
0 };
|
||||
Address *p;
|
||||
|
||||
if (inb(ioaddr + 6) != 0x0 || inb(ioaddr + 7) != 0x55)
|
||||
return (0);
|
||||
scb_base = -8192; /* assume 8k memory */
|
||||
for (p = mem_addrs; (mem_start = *p) != 0; ++p)
|
||||
if (mem_end = mem_start + 8192, ni5210_probe2())
|
||||
break;
|
||||
if (mem_start == 0)
|
||||
return (0);
|
||||
printf("\nNI5210 ioaddr 0x%x, mem [0x%X-0x%X], addr ",
|
||||
ioaddr, mem_start, mem_end);
|
||||
/* Get station address */
|
||||
for (i = 0; i < ETHER_ADDR_SIZE; ++i)
|
||||
{
|
||||
printf("%b", nic->node_addr[i] = inb(ioaddr+i));
|
||||
if (i < ETHER_ADDR_SIZE -1)
|
||||
printf(":");
|
||||
}
|
||||
putchar('\n');
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct nic *ni5210_probe(struct nic *nic, unsigned short *probe_addrs)
|
||||
{
|
||||
/* missing entries are addresses usually already used */
|
||||
static unsigned short io_addrs[] = {
|
||||
0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, 0x238,
|
||||
0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, /*Par*/
|
||||
0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8,
|
||||
0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0, /*Ser*/
|
||||
0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330, 0x338,
|
||||
0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, /*Par*/
|
||||
0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, /*Vid,Par*/
|
||||
0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, /*Ser*/
|
||||
0x0
|
||||
};
|
||||
unsigned short *p;
|
||||
int i;
|
||||
|
||||
/* if probe_addrs is 0, then routine can use a hardwired default */
|
||||
if (probe_addrs == 0)
|
||||
probe_addrs = io_addrs;
|
||||
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
|
||||
if (ni5210_probe1(nic))
|
||||
break;
|
||||
if (ioaddr != 0)
|
||||
{
|
||||
/* point to NIC specific routines */
|
||||
i82586_reset(nic);
|
||||
nic->reset = i82586_reset;
|
||||
nic->poll = i82586_poll;
|
||||
nic->transmit = i82586_transmit;
|
||||
nic->disable = i82586_disable;
|
||||
return nic;
|
||||
}
|
||||
/* else */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EXOS205
|
||||
|
||||
/*
|
||||
* Code to download to I186 in EXOS205
|
||||
*/
|
||||
|
||||
static unsigned char exos_i186_init[] =
|
||||
{
|
||||
0x08,0x00,0x14,0x00,0x00,0x00,0xaa,0xfa,0x33,0xc0,0xba,0xfe,0xff,0xef,0xb8,0xf8,
|
||||
0xff,0xe7,0xa0,0xb8,0x7c,0x00,0xe7,0xa4,0xb8,0xbc,0x80,0xe7,0xa8,0x8c,0xc8,0x8e,
|
||||
0xd8,0xbb,0x2f,0x0e,0xc6,0x07,0xa5,0x33,0xc9,0xeb,0x00,0xeb,0x00,0xeb,0x00,0xe2,
|
||||
0xf8,0xbe,0x2c,0x0e,0xba,0x02,0x05,0x33,0xdb,0xb9,0x03,0x00,0xec,0x24,0x0f,0x8a,
|
||||
0xe0,0x02,0xd8,0x42,0x42,0xec,0x02,0xd8,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,
|
||||
0x0a,0xc4,0x88,0x04,0x42,0x42,0x46,0xe2,0xe3,0x8a,0xe3,0xd0,0xec,0xd0,0xec,0xd0,
|
||||
0xec,0xd0,0xec,0x80,0xe3,0x0f,0x02,0xe3,0x80,0xf4,0x05,0xec,0x3a,0xe0,0x74,0x05,
|
||||
0xc6,0x04,0x5a,0xeb,0xfe,0xc6,0x04,0x55,0x33,0xc0,0x8e,0xd8,0xbe,0x38,0x00,0xc7,
|
||||
0x04,0xce,0x0e,0x46,0x46,0xc7,0x04,0x00,0xff,0xfb,0xba,0x3c,0x00,0xb8,0x03,0x00,
|
||||
0xef,0x33,0xdb,0x33,0xc9,0xbd,0x04,0x0f,0x90,0x90,0x90,0x90,0xe2,0xfa,0x43,0x2e,
|
||||
0x89,0x5e,0x00,0xeb,0xf3,0x52,0xba,0x00,0x06,0xef,0x50,0x53,0x55,0xbd,0xf8,0x0e,
|
||||
0x2e,0x8b,0x5e,0x00,0x43,0x2e,0x89,0x5e,0x00,0xba,0x22,0x00,0xb8,0x00,0x80,0xef,
|
||||
0x5d,0x5b,0x58,0x5a,0xcf,0x49,0x4e,0x54,0x52,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,
|
||||
0x00,0x4c,0x4f,0x4f,0x50,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x30,0x0e,0x00,0xff,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,00
|
||||
};
|
||||
|
||||
/* These offsets are from the end of the i186 download code */
|
||||
|
||||
#define OFFSET_SEMA 0x1D1
|
||||
#define OFFSET_ADDR 0x1D7
|
||||
|
||||
static int exos205_probe2(void)
|
||||
{
|
||||
unsigned short i;
|
||||
unsigned short shmem[10];
|
||||
|
||||
/* Fix the ISCP address and base. */
|
||||
init_words[3] = scb_base;
|
||||
init_words[7] = scb_base;
|
||||
|
||||
/* Write the words at 0xfff6. */
|
||||
/* Write the words at 0x0000. */
|
||||
#ifdef ETHERBOOT32
|
||||
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
|
||||
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
if (*(unsigned short *)mem_start != 1)
|
||||
return (0);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
memcpyf(mem_end - 10, (char *)init_words, 10);
|
||||
memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
|
||||
fmemcpy((char *)&i, mem_start, sizeof(unsigned short));
|
||||
if (i != 1)
|
||||
return (0);
|
||||
#endif
|
||||
outb(0, ioaddr + EXOS205_RESET);
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
i = 50;
|
||||
while (
|
||||
#ifdef ETHERBOOT16
|
||||
read_mem(mem_start, shmem),
|
||||
#endif
|
||||
shmem[iSCB_STATUS>>1] == 0)
|
||||
{
|
||||
if (--i == 0)
|
||||
{
|
||||
printf("i82586 initialisation timed out with status %x, cmd %x\n",
|
||||
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Issue channel-attn -- the 82586 won't start. */
|
||||
outb(0, ioaddr + I82586_ATTN);
|
||||
#ifdef ETHERBOOT32
|
||||
if (*(unsigned short *)mem_start != 0)
|
||||
return (0);
|
||||
#endif
|
||||
#ifdef ETHERBOOT16
|
||||
fmemcpy((char *)&i, mem_start, sizeof(unsigned short));
|
||||
if (i != 0)
|
||||
return (0);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int exos205_probe1(struct nic *nic)
|
||||
{
|
||||
int i;
|
||||
/* If you know the other addresses please let me know */
|
||||
static Address mem_addrs[] = {
|
||||
0xcc000, 0 };
|
||||
Address *p;
|
||||
|
||||
scb_base = -16384; /* assume 8k memory */
|
||||
for (p = mem_addrs; (mem_start = *p) != 0; ++p)
|
||||
if (mem_end = mem_start + 16384, exos205_probe2())
|
||||
break;
|
||||
if (mem_start == 0)
|
||||
return (0);
|
||||
printf("\nEXOS205 ioaddr 0x%x, mem [0x%X-0x%X], addr ",
|
||||
ioaddr, mem_start, mem_end);
|
||||
/* Get station address */
|
||||
for (i = 0; i < ETHER_ADDR_SIZE; ++i)
|
||||
{
|
||||
printf("%b", nic->node_addr[i] = inb(ioaddr+i));
|
||||
if (i < ETHER_ADDR_SIZE -1)
|
||||
printf(":");
|
||||
}
|
||||
putchar('\n');
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct nic *exos205_probe(struct nic *nic, unsigned short *probe_addrs)
|
||||
{
|
||||
/* If you know the other addresses, please let me know */
|
||||
static unsigned short io_addrs[] = {
|
||||
0x310, 0x0
|
||||
};
|
||||
unsigned short *p;
|
||||
int i;
|
||||
|
||||
/* if probe_addrs is 0, then routine can use a hardwired default */
|
||||
if (probe_addrs == 0)
|
||||
probe_addrs = io_addrs;
|
||||
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
|
||||
if (exos205_probe1(nic))
|
||||
break;
|
||||
if (ioaddr != 0)
|
||||
{
|
||||
/* point to NIC specific routines */
|
||||
i82586_reset(nic);
|
||||
nic->reset = i82586_reset;
|
||||
nic->poll = i82586_poll;
|
||||
nic->transmit = i82586_transmit;
|
||||
nic->disable = i82586_disable;
|
||||
return nic;
|
||||
}
|
||||
/* else */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user