Add support for the console over Ethernet (through PCI NE2000).

Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
Acked-by: Cristian Magherusan-Stanciu <cristi.magherusan@gmail.com>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5666 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Rudolf Marek 2010-07-16 20:02:09 +00:00
parent 7fc9e291d7
commit 4aa93ccd33
11 changed files with 728 additions and 4 deletions

View File

@ -21,8 +21,17 @@
#include <console/vtxprintf.h> #include <console/vtxprintf.h>
#include <uart8250.h> #include <uart8250.h>
#if CONFIG_CONSOLE_NE2K
#include <console/ne2k.h>
#endif
static void console_tx_byte(unsigned char byte) static void console_tx_byte(unsigned char byte)
{ {
#if CONFIG_CONSOLE_NE2K
#ifdef __PRE_RAM__
ne2k_append_data(&byte, 1, CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
#endif
if (byte == '\n') if (byte == '\n')
uart8250_tx_byte(CONFIG_TTYS0_BASE, '\r'); uart8250_tx_byte(CONFIG_TTYS0_BASE, '\r');
@ -41,6 +50,8 @@ int do_printk(int msg_level, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
i = vtxprintf(console_tx_byte, fmt, args); i = vtxprintf(console_tx_byte, fmt, args);
va_end(args); va_end(args);
#if CONFIG_CONSOLE_NE2K
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
return i; return i;
} }

View File

@ -1,5 +1,4 @@
menu "Console options" menu "Console options"
# TODO: Rename to SERIAL_CONSOLE once Kconfig transition is complete. # TODO: Rename to SERIAL_CONSOLE once Kconfig transition is complete.
config CONSOLE_SERIAL8250 config CONSOLE_SERIAL8250
bool "Serial port console output" bool "Serial port console output"
@ -130,6 +129,49 @@ config CONSOLE_VGA_ONBOARD_AT_FIRST
help help
If not selected, the last adapter found will be used. If not selected, the last adapter found will be used.
config CONSOLE_NE2K
bool "Network console over NE2000 compatible Ethernet adapter"
default n
help
Send coreboot debug output to a Ethernet console, it works
same way as Linux netconsole, packets are received to UDP
port 6666 on IP/MAC specified with options bellow.
Use following netcat command: nc -u -l -p 6666
config CONSOLE_NE2K_DST_MAC
depends on CONSOLE_NE2K
string "Destination MAC address of remote system"
default "00:13:d4:76:a2:ac"
help
Type in either MAC address of logging system or MAC address
of the router.
config CONSOLE_NE2K_DST_IP
depends on CONSOLE_NE2K
string "Destination IP of logging system"
default "10.0.1.27"
help
This is IP adress of the system running for example
netcat command to dump the packets.
config CONSOLE_NE2K_SRC_IP
depends on CONSOLE_NE2K
string "IP adress of Coreboot system"
default "10.0.1.253"
help
This is the IP of the Coreboot system
config CONSOLE_NE2K_IO_PORT
depends on CONSOLE_NE2K
hex "NE2000 adapter fixed IO port address"
default 0xe00
help
This is the IO port address for the IO port
on the card, please select some non-conflicting region,
32 bytes of IO spaces will be used (and align on 32 bytes
boundary, qemu needs broader align)
choice choice
prompt "Maximum console log level" prompt "Maximum console log level"
default MAXIMUM_CONSOLE_LOGLEVEL_8 default MAXIMUM_CONSOLE_LOGLEVEL_8

View File

@ -15,6 +15,7 @@ driver-$(CONFIG_CONSOLE_VGA) += vga_console.o
driver-$(CONFIG_CONSOLE_BTEXT) += btext_console.o driver-$(CONFIG_CONSOLE_BTEXT) += btext_console.o
driver-$(CONFIG_CONSOLE_BTEXT) += font-8x16.o driver-$(CONFIG_CONSOLE_BTEXT) += font-8x16.o
driver-$(CONFIG_CONSOLE_LOGBUF) += logbuf_console.o driver-$(CONFIG_CONSOLE_LOGBUF) += logbuf_console.o
driver-$(CONFIG_CONSOLE_NE2K) += ne2k_console.o
$(obj)/console/console.o : $(obj)/build.h $(obj)/console/console.o : $(obj)/build.h
$(obj)/console/console.initobj.o : $(obj)/build.h $(obj)/console/console.initobj.o : $(obj)/build.h

View File

@ -7,11 +7,14 @@
#include <arch/hlt.h> #include <arch/hlt.h>
#include <arch/io.h> #include <arch/io.h>
#if CONFIG_CONSOLE_NE2K
#include <console/ne2k.h>
#endif
#ifndef __PRE_RAM__ #ifndef __PRE_RAM__
#include <string.h> #include <string.h>
#include <pc80/mc146818rtc.h> #include <pc80/mc146818rtc.h>
/* initialize the console */ /* initialize the console */
void console_init(void) void console_init(void)
{ {
@ -99,6 +102,10 @@ void __attribute__((noreturn)) die(const char *msg)
void console_init(void) void console_init(void)
{ {
#if CONFIG_CONSOLE_NE2K
ne2k_init(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
static const char console_test[] = static const char console_test[] =
"\n\ncoreboot-" "\n\ncoreboot-"
COREBOOT_VERSION COREBOOT_VERSION

View File

@ -0,0 +1,37 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
* Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
*
* 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; version 2 of the License.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <console/console.h>
#include <console/ne2k.h>
static void ne2k_tx_byte(unsigned char data)
{
ne2k_append_data(&data, 1, CONFIG_CONSOLE_NE2K_IO_PORT);
}
static void ne2k_tx_flush(void)
{
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
}
static const struct console_driver ne2k_console __console = {
.tx_byte = ne2k_tx_byte,
.tx_flush = ne2k_tx_flush,
};

View File

@ -131,10 +131,17 @@ int do_printk(int msg_level, const char *fmt, ...) __attribute__((format(printf,
#include <pc80/serial.c> #include <pc80/serial.c>
#if CONFIG_CONSOLE_NE2K
#include "lib/ne2k.c"
#endif
/* __ROMCC__ */ /* __ROMCC__ */
static void __console_tx_byte(unsigned char byte) static void __console_tx_byte(unsigned char byte)
{ {
uart_tx_byte(byte); uart_tx_byte(byte);
#if CONFIG_CONSOLE_NE2K
ne2k_append_data_byte(byte, CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
static void __console_tx_nibble(unsigned nibble) static void __console_tx_nibble(unsigned nibble)
@ -151,6 +158,10 @@ static void __console_tx_char(int loglevel, unsigned char byte)
{ {
if (console_loglevel >= loglevel) { if (console_loglevel >= loglevel) {
uart_tx_byte(byte); uart_tx_byte(byte);
#if CONFIG_CONSOLE_NE2K
ne2k_append_data_byte(byte, CONFIG_CONSOLE_NE2K_IO_PORT);
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
} }
@ -160,6 +171,9 @@ static void __console_tx_hex8(int loglevel, unsigned char value)
__console_tx_nibble((value >> 4U) & 0x0fU); __console_tx_nibble((value >> 4U) & 0x0fU);
__console_tx_nibble(value & 0x0fU); __console_tx_nibble(value & 0x0fU);
} }
#if CONFIG_CONSOLE_NE2K
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
static void __console_tx_hex16(int loglevel, unsigned short value) static void __console_tx_hex16(int loglevel, unsigned short value)
@ -170,6 +184,9 @@ static void __console_tx_hex16(int loglevel, unsigned short value)
__console_tx_nibble((value >> 4U) & 0x0fU); __console_tx_nibble((value >> 4U) & 0x0fU);
__console_tx_nibble(value & 0x0fU); __console_tx_nibble(value & 0x0fU);
} }
#if CONFIG_CONSOLE_NE2K
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
static void __console_tx_hex32(int loglevel, unsigned int value) static void __console_tx_hex32(int loglevel, unsigned int value)
@ -184,6 +201,9 @@ static void __console_tx_hex32(int loglevel, unsigned int value)
__console_tx_nibble((value >> 4U) & 0x0fU); __console_tx_nibble((value >> 4U) & 0x0fU);
__console_tx_nibble(value & 0x0fU); __console_tx_nibble(value & 0x0fU);
} }
#if CONFIG_CONSOLE_NE2K
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
static void __console_tx_string(int loglevel, const char *str) static void __console_tx_string(int loglevel, const char *str)
@ -195,6 +215,9 @@ static void __console_tx_string(int loglevel, const char *str)
__console_tx_byte('\r'); __console_tx_byte('\r');
__console_tx_byte(ch); __console_tx_byte(ch);
} }
#if CONFIG_CONSOLE_NE2K
ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
#endif
} }
} }

View File

@ -0,0 +1,27 @@
#ifndef _NE2K_H__
#define _NE2K_H__
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
*
* 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; version 2 of the License.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ROMCC__
void ne2k_append_data(unsigned char *d, int len, unsigned int base);
int ne2k_init(unsigned int eth_nic_base);
void ne2k_transmit(unsigned int eth_nic_base);
#endif
#endif /* _NE2K_H */

View File

@ -1,7 +1,8 @@
#ifndef IP_CHECKSUM_H #ifndef IP_CHECKSUM_H
#define IP_CHECKSUM_H #define IP_CHECKSUM_H
#ifndef __ROMCC__
unsigned long compute_ip_checksum(void *addr, unsigned long length); unsigned long compute_ip_checksum(void *addr, unsigned long length);
unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new); unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
#endif
#endif /* IP_CHECKSUM_H */ #endif /* IP_CHECKSUM_H */

View File

@ -22,6 +22,9 @@ initobj-y += memcmp.o
initobj-y += cbfs.o initobj-y += cbfs.o
initobj-y += lzma.o initobj-y += lzma.o
#initobj-y += lzmadecode.o #initobj-y += lzmadecode.o
initobj-$(CONFIG_CONSOLE_NE2K) += ne2k.o
initobj-$(CONFIG_CONSOLE_NE2K) += compute_ip_checksum.o
driver-$(CONFIG_CONSOLE_NE2K) += ne2k.o
obj-$(CONFIG_USBDEBUG) += usbdebug.o obj-$(CONFIG_USBDEBUG) += usbdebug.o

462
src/lib/ne2k.c Normal file
View File

@ -0,0 +1,462 @@
/*
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: May/94
This code is based heavily on David Greenman's if_ed.c driver
Copyright (C) 1993-1994, David Greenman, Martin Renters.
This software may be used, modified, copied, distributed, and sold, in
both source and binary form provided that the above copyright and these
terms are retained. Under no circumstances are the authors responsible for
the proper functioning of this software, nor do the authors assume any
responsibility for damages incurred with its use.
Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
(C) Rudolf Marek <r.marek@assembler.cz> Simplify for RTL8029, Add coreboot glue logic
*/
#define ETH_ALEN 6 /* Size of Ethernet address */
#define ETH_HLEN 14 /* Size of ethernet header */
#define ETH_ZLEN 60 /* Minimum packet */
#define ETH_FRAME_LEN 1514 /* Maximum packet */
#define ETH_DATA_ALIGN 2 /* Amount needed to align the data after an ethernet header */
#define ETH_MAX_MTU (ETH_FRAME_LEN-ETH_HLEN)
#include "ns8390.h"
#include <ip_checksum.h>
#include <console/ne2k.h>
#include <arch/io.h>
//#include <arch/romcc_io.h>
#define MEM_SIZE MEM_32768
#define TX_START 64
#define RX_START (64 + D8390_TXBUF_SIZE)
static unsigned int get_count(unsigned int eth_nic_base)
{
unsigned int ret;
outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
eth_nic_base + D8390_P0_COMMAND);
ret = inb(eth_nic_base + 8 + 0) | (inb(eth_nic_base + 8 + 1) << 8);
outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
eth_nic_base + D8390_P0_COMMAND);
return ret;
}
static void set_count(unsigned int eth_nic_base, unsigned int what)
{
outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
eth_nic_base + D8390_P0_COMMAND);
outb(what & 0xff,eth_nic_base + 8);
outb((what >> 8) & 0xff,eth_nic_base + 8 + 1);
outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
eth_nic_base + D8390_P0_COMMAND);
}
static void eth_pio_write(unsigned char *src, unsigned int dst, unsigned int cnt,
unsigned int eth_nic_base)
{
outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
outb(cnt, eth_nic_base + D8390_P0_RBCR0);
outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
outb(dst, eth_nic_base + D8390_P0_RSAR0);
outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
while (cnt--) {
outb(*(src++), eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
}
/*
#warning "Add timeout"
*/
/* wait for operation finish */
while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
;
}
void ne2k_append_data(unsigned char *d, int len, unsigned int base)
{
eth_pio_write(d, (TX_START << 8) + 42 + get_count(base), len, base);
set_count(base, get_count(base)+len);
}
#ifdef __ROMCC__
void eth_pio_write_byte(int data, unsigned short dst, unsigned int eth_nic_base)
{
outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
outb(1, eth_nic_base + D8390_P0_RBCR0);
outb(0, eth_nic_base + D8390_P0_RBCR1);
outb(dst, eth_nic_base + D8390_P0_RSAR0);
outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(data, eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
;
}
void ne2k_append_data_byte(int d, unsigned int base)
{
eth_pio_write_byte(d, (TX_START << 8) + 42 + get_count(base), base);
set_count(base, get_count(base)+1);
}
static unsigned char eth_pio_read_byte(unsigned int src,
unsigned int eth_nic_base)
{
outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(0, eth_nic_base + D8390_P0_RBCR0);
outb(1, eth_nic_base + D8390_P0_RBCR1);
outb(src, eth_nic_base + D8390_P0_RSAR0);
outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
return inb(eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
}
/* varition of compute_ip_checksum which works on SRAM */
unsigned long compute_ip_checksum_from_sram(unsigned short offset, unsigned short length,
unsigned int eth_nic_base)
{
unsigned long sum;
unsigned long i;
/* In the most straight forward way possible,
* compute an ip style checksum.
*/
sum = 0;
for(i = 0; i < length; i++) {
unsigned long v;
v = eth_pio_read_byte((TX_START << 8)+i+offset, eth_nic_base);
if (i & 1) {
v <<= 8;
}
/* Add the new value */
sum += v;
/* Wrap around the carry */
if (sum > 0xFFFF) {
sum = (sum + (sum >> 16)) & 0xFFFF;
}
}
return (~((sum & 0xff) | (((sum >> 8) & 0xff) << 8) )) & 0xffff;
}
static void str2ip_load(const char *str, unsigned short offset, unsigned int eth_nic_base)
#else
static void str2ip(const char *str, unsigned char *ip)
#endif
{
unsigned char c, i = 0;
int acc = 0;
do {
c = str[i];
if ((c >= '0') && (c <= '9')) {
acc *= 10;
acc += (c - '0');
} else {
#ifdef __ROMCC__
eth_pio_write_byte(acc, (TX_START << 8)+offset, eth_nic_base);
offset++;
#else
*ip++ = acc;
#endif
acc = 0;
}
i++;
} while (c != '\0');
}
#ifdef __ROMCC__
static void str2mac_load(const char *str, unsigned short offset, unsigned int eth_nic_base)
#else
static void str2mac(const char *str, unsigned char *mac)
#endif
{
unsigned char c, i = 0;
int acc = 0;
do {
c = str[i];
if ((c >= '0') && (c <= '9')) {
acc *= 16;
acc += (c - '0');
} else if ((c >= 'a') && (c <= 'f')) {
acc *= 16;
acc += ((c - 'a') + 10) ;
} else if ((c >= 'A') && (c <= 'F')) {
acc *= 16;
acc += ((c - 'A') + 10) ;
} else {
#ifdef __ROMCC__
eth_pio_write_byte(acc, ((TX_START << 8)+offset), eth_nic_base);
offset++;
#else
*mac++ = acc;
#endif
acc = 0;
}
i++;
} while (c != '\0');
}
#ifndef __ROMCC__
static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen) {
unsigned short chksum;
unsigned char hdr[] = {
#else
static const unsigned char hdr[] = {
#endif
/*
* ETHERNET HDR
*/
// destination macaddr
0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
/* source mac */
0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
/* ethtype (IP) */
0x08, 0x00,
/*
* IP HDR
*/
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
/* TTL, proto (UDP), chksum_hi, chksum_lo, IP0, IP1, IP2, IP3, */
0x40, 0x11, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1,
/* IP0, IP1, IP2, IP3 */
0xff, 0xff, 0xff, 0xff,
/*
* UDP HDR
*/
/* SRC PORT DST PORT (2bytes each), ulen, uchksum (must be zero or correct */
0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00,
};
#ifndef __ROMCC__
str2mac(CONFIG_CONSOLE_NE2K_DST_MAC, &hdr[0]);
str2ip(CONFIG_CONSOLE_NE2K_DST_IP, &hdr[30]);
str2ip(CONFIG_CONSOLE_NE2K_SRC_IP, &hdr[26]);
/* zero checksum */
hdr[24] = 0;
hdr[25] = 0;
/* update IP packet len */
hdr[16] = ((28 + pktlen) >> 8) & 0xff;
hdr[17] = (28 + pktlen) & 0xff;
/* update UDP len */
hdr[38] = (8 + pktlen) >> 8;
hdr[39] = 8 + pktlen;
chksum = compute_ip_checksum(&hdr[14], 20);
hdr[25] = chksum >> 8;
hdr[24] = chksum;
eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
}
#else
/* ROMCC madness */
static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen)
{
unsigned short chksum;
eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
str2mac_load(CONFIG_CONSOLE_NE2K_DST_MAC, 0, eth_nic_base);
str2ip_load(CONFIG_CONSOLE_NE2K_DST_IP, 30, eth_nic_base);
str2ip_load(CONFIG_CONSOLE_NE2K_SRC_IP, 26, eth_nic_base);
/* zero checksum */
eth_pio_write_byte(0, (TX_START << 8)+24, eth_nic_base);
eth_pio_write_byte(0, (TX_START << 8)+25, eth_nic_base);
/* update IP packet len */
eth_pio_write_byte(((28 + pktlen) >> 8) & 0xff, (TX_START << 8)+16, eth_nic_base);
eth_pio_write_byte( (28 + pktlen) & 0xff, (TX_START << 8)+17, eth_nic_base);
/* update UDP len */
eth_pio_write_byte((8 + pktlen) >> 8, (TX_START << 8)+38, eth_nic_base);
eth_pio_write_byte( 8 + pktlen, (TX_START << 8)+39, eth_nic_base);
chksum = compute_ip_checksum_from_sram(14, 20, eth_nic_base);
eth_pio_write_byte(chksum, (TX_START << 8)+24, eth_nic_base);
eth_pio_write_byte(chksum >> 8, (TX_START << 8)+25, eth_nic_base);
}
#endif
void ne2k_transmit(unsigned int eth_nic_base) {
unsigned int pktsize;
unsigned int len = get_count(eth_nic_base);
// so place whole header inside chip buffer
ns8390_tx_header(eth_nic_base, len);
// commit sending now
outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(TX_START, eth_nic_base + D8390_P0_TPSR);
pktsize = 42 + len;
if (pktsize < 64)
pktsize = 64;
outb(pktsize, eth_nic_base + D8390_P0_TBCR0);
outb(pktsize >> 8, eth_nic_base + D8390_P0_TBCR1);
outb(D8390_ISR_PTX, eth_nic_base + D8390_P0_ISR);
outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
/* wait for operation finish */
while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_PTX) != D8390_ISR_PTX) ;
set_count(eth_nic_base, 0);
}
#ifdef __PRE_RAM__
#include <arch/romcc_io.h>
static void ns8390_reset(unsigned int eth_nic_base)
{
int i;
outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
D8390_COMMAND_STP, eth_nic_base + D8390_P0_COMMAND);
outb(0x48, eth_nic_base + D8390_P0_DCR);
outb(0, eth_nic_base + D8390_P0_RBCR0);
outb(0, eth_nic_base + D8390_P0_RBCR1);
outb(0x20, eth_nic_base + D8390_P0_RCR);
outb(2, eth_nic_base + D8390_P0_TCR);
outb(TX_START, eth_nic_base + D8390_P0_TPSR);
outb(RX_START, eth_nic_base + D8390_P0_PSTART);
outb(MEM_SIZE, eth_nic_base + D8390_P0_PSTOP);
outb(MEM_SIZE - 1, eth_nic_base + D8390_P0_BOUND);
outb(0xFF, eth_nic_base + D8390_P0_ISR);
outb(0, eth_nic_base + D8390_P0_IMR);
outb(D8390_COMMAND_PS1 |
D8390_COMMAND_RD2 | D8390_COMMAND_STP,
eth_nic_base + D8390_P0_COMMAND);
for (i = 0; i < ETH_ALEN; i++)
outb(0x0C, eth_nic_base + D8390_P1_PAR0 + i);
for (i = 0; i < ETH_ALEN; i++)
outb(0xFF, eth_nic_base + D8390_P1_MAR0 + i);
outb(RX_START, eth_nic_base + D8390_P1_CURR);
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_RD2 | D8390_COMMAND_STA,
eth_nic_base + D8390_P0_COMMAND);
outb(0xFF, eth_nic_base + D8390_P0_ISR);
outb(0, eth_nic_base + D8390_P0_TCR);
outb(4, eth_nic_base + D8390_P0_RCR);
set_count(eth_nic_base, 0);
}
int ne2k_init(unsigned int eth_nic_base) {
device_t dev;
unsigned char c;
/* Power management controller */
dev = pci_locate_device(PCI_ID(0x10ec,
0x8029), 0);
if (dev == PCI_DEV_INVALID)
return 0;
pci_write_config32(dev, 0x10, eth_nic_base | 1 );
pci_write_config8(dev, 0x4, 0x1);
c = inb(eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
outb(c, eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
(void) inb(0x84);
outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
ns8390_reset(eth_nic_base);
return 1;
}
#else
#include <delay.h>
#include <stdlib.h>
#include <string.h>
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
static void read_resources(struct device *dev)
{
struct resource *res;
res = new_resource(dev, PCI_BASE_ADDRESS_0);
res->base = CONFIG_CONSOLE_NE2K_IO_PORT;
res->size = 32;
res->align = 5;
res->gran = 5;
res->limit = res->base + res->size - 1;
res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_STORED |
IORESOURCE_ASSIGNED;
return;
}
static struct device_operations si_sata_ops = {
.read_resources = read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = 0,
.scan_bus = 0,
};
static const struct pci_driver si_sata_driver __pci_driver = {
.ops = &si_sata_ops,
.vendor = 0x10ec,
.device = 0x8029,
};
#endif

110
src/lib/ns8390.h Normal file
View File

@ -0,0 +1,110 @@
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: Jun/94
**************************************************************************/
//FILE_LICENCE ( BSD2 );
#define VENDOR_NONE 0
#define VENDOR_WD 1
#define VENDOR_NOVELL 2
#define VENDOR_3COM 3
#define FLAG_PIO 0x01
#define FLAG_16BIT 0x02
#define FLAG_790 0x04
#define MEM_8192 32
#define MEM_16384 64
#define MEM_32768 128
#define ISA_MAX_ADDR 0x400
/**************************************************************************
NE1000/2000 definitions
**************************************************************************/
#define NE_ASIC_OFFSET 0x10
#define NE_RESET 0x0F /* Used to reset card */
#define NE_DATA 0x00 /* Used to read/write NIC mem */
#define COMPEX_RL2000_TRIES 200
/**************************************************************************
8390 Register Definitions
**************************************************************************/
#define D8390_P0_COMMAND 0x00
#define D8390_P0_PSTART 0x01
#define D8390_P0_PSTOP 0x02
#define D8390_P0_BOUND 0x03
#define D8390_P0_TSR 0x04
#define D8390_P0_TPSR 0x04
#define D8390_P0_TBCR0 0x05
#define D8390_P0_TBCR1 0x06
#define D8390_P0_ISR 0x07
#define D8390_P0_RSAR0 0x08
#define D8390_P0_RSAR1 0x09
#define D8390_P0_RBCR0 0x0A
#define D8390_P0_RBCR1 0x0B
#define D8390_P0_RSR 0x0C
#define D8390_P0_RCR 0x0C
#define D8390_P0_TCR 0x0D
#define D8390_P0_DCR 0x0E
#define D8390_P0_IMR 0x0F
#define D8390_P1_COMMAND 0x00
#define D8390_P1_PAR0 0x01
#define D8390_P1_PAR1 0x02
#define D8390_P1_PAR2 0x03
#define D8390_P1_PAR3 0x04
#define D8390_P1_PAR4 0x05
#define D8390_P1_PAR5 0x06
#define D8390_P1_CURR 0x07
#define D8390_P1_MAR0 0x08
#define D8390_COMMAND_PS0 0x0 /* Page 0 select */
#define D8390_COMMAND_PS1 0x40 /* Page 1 select */
#define D8390_COMMAND_PS2 0x80 /* Page 2 select */
#define D8390_COMMAND_RD2 0x20 /* Remote DMA control */
#define D8390_COMMAND_RD1 0x10
#define D8390_COMMAND_RD0 0x08
#define D8390_COMMAND_TXP 0x04 /* transmit packet */
#define D8390_COMMAND_STA 0x02 /* start */
#define D8390_COMMAND_STP 0x01 /* stop */
#define D8390_RCR_MON 0x20 /* monitor mode */
#define D8390_DCR_FT1 0x40
#define D8390_DCR_LS 0x08 /* Loopback select */
#define D8390_DCR_WTS 0x01 /* Word transfer select */
#define D8390_ISR_PRX 0x01 /* successful recv */
#define D8390_ISR_PTX 0x02 /* successful xmit */
#define D8390_ISR_RXE 0x04 /* receive error */
#define D8390_ISR_TXE 0x08 /* transmit error */
#define D8390_ISR_OVW 0x10 /* Overflow */
#define D8390_ISR_CNT 0x20 /* Counter overflow */
#define D8390_ISR_RDC 0x40 /* Remote DMA complete */
#define D8390_ISR_RST 0x80 /* reset */
#define D8390_RSTAT_PRX 0x01 /* successful recv */
#define D8390_RSTAT_CRC 0x02 /* CRC error */
#define D8390_RSTAT_FAE 0x04 /* Frame alignment error */
#define D8390_RSTAT_OVER 0x08 /* FIFO overrun */
#define D8390_TXBUF_SIZE 6
#define D8390_RXBUF_END 32
#define D8390_PAGE_SIZE 256
struct ringbuffer {
unsigned char status;
unsigned char next;
unsigned short len;
};
/*
* Local variables:
* c-basic-offset: 8
* End:
*/