Add e1000 network driver in libe1k
Signed-off-by: Avik Sil <aviksil@linux.vnet.ibm.com> Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
This commit is contained in:
parent
46a32aa9c7
commit
9c928cc428
|
@ -15,7 +15,7 @@ BOARD_TARGETS = tools_build romfs_build clients_build netdrivers stage1 subdirs
|
||||||
SUBDIRS = slof veth virtio-net
|
SUBDIRS = slof veth virtio-net
|
||||||
|
|
||||||
COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio libusb \
|
COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio libusb \
|
||||||
libveth
|
libveth libe1k
|
||||||
|
|
||||||
all: $(BOARD_TARGETS)
|
all: $(BOARD_TARGETS)
|
||||||
$(MAKE) boot_rom.bin
|
$(MAKE) boot_rom.bin
|
||||||
|
|
|
@ -21,7 +21,8 @@ all: Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin
|
||||||
|
|
||||||
CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \
|
CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \
|
||||||
-I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \
|
-I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \
|
||||||
-I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth
|
-I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \
|
||||||
|
-I$(LIBCMNDIR)/libe1k
|
||||||
SLOF_LIBS = \
|
SLOF_LIBS = \
|
||||||
$(LIBCMNDIR)/libbootmsg.a \
|
$(LIBCMNDIR)/libbootmsg.a \
|
||||||
$(LIBCMNDIR)/libelf.a \
|
$(LIBCMNDIR)/libelf.a \
|
||||||
|
@ -29,7 +30,8 @@ SLOF_LIBS = \
|
||||||
$(LIBCMNDIR)/libvirtio.a \
|
$(LIBCMNDIR)/libvirtio.a \
|
||||||
$(LIBCMNDIR)/libusb.a \
|
$(LIBCMNDIR)/libusb.a \
|
||||||
$(LIBCMNDIR)/libnvram.a \
|
$(LIBCMNDIR)/libnvram.a \
|
||||||
$(LIBCMNDIR)/libveth.a
|
$(LIBCMNDIR)/libveth.a \
|
||||||
|
$(LIBCMNDIR)/libe1k.a
|
||||||
BOARD_SLOF_IN = \
|
BOARD_SLOF_IN = \
|
||||||
$(LIBCMNDIR)/libhvcall/hvcall.in \
|
$(LIBCMNDIR)/libhvcall/hvcall.in \
|
||||||
$(LIBCMNDIR)/libvirtio/virtio.in \
|
$(LIBCMNDIR)/libvirtio/virtio.in \
|
||||||
|
@ -38,7 +40,8 @@ BOARD_SLOF_IN = \
|
||||||
$(LIBCMNDIR)/libelf/libelf.in \
|
$(LIBCMNDIR)/libelf/libelf.in \
|
||||||
$(LIBCMNDIR)/libnvram/libnvram.in \
|
$(LIBCMNDIR)/libnvram/libnvram.in \
|
||||||
$(LIBCMNDIR)/libbases/libbases.in \
|
$(LIBCMNDIR)/libbases/libbases.in \
|
||||||
$(LIBCMNDIR)/libveth/veth.in
|
$(LIBCMNDIR)/libveth/veth.in \
|
||||||
|
$(LIBCMNDIR)/libe1k/e1k.in
|
||||||
BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)
|
BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)
|
||||||
|
|
||||||
include $(SLOFCMNDIR)/Makefile.inc
|
include $(SLOFCMNDIR)/Makefile.inc
|
||||||
|
@ -91,6 +94,8 @@ OF_FFS_FILES = \
|
||||||
$(SLOFBRDDIR)/rtas.fs \
|
$(SLOFBRDDIR)/rtas.fs \
|
||||||
$(SLOFBRDDIR)/pci-device_1234_1111.fs \
|
$(SLOFBRDDIR)/pci-device_1234_1111.fs \
|
||||||
$(SLOFBRDDIR)/pci-device_1013_00b8.fs \
|
$(SLOFBRDDIR)/pci-device_1013_00b8.fs \
|
||||||
|
$(SLOFBRDDIR)/pci-device_8086_100e.fs \
|
||||||
|
$(SLOFBRDDIR)/e1k.fs \
|
||||||
$(FCODE_FFS_FILES)
|
$(FCODE_FFS_FILES)
|
||||||
|
|
||||||
# Uncomment the following line to enable the USB code:
|
# Uncomment the following line to enable the USB code:
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
\ *****************************************************************************
|
||||||
|
\ * Copyright (c) 2013 IBM Corporation
|
||||||
|
\ * All rights reserved.
|
||||||
|
\ * This program and the accompanying materials
|
||||||
|
\ * are made available under the terms of the BSD License
|
||||||
|
\ * which accompanies this distribution, and is available at
|
||||||
|
\ * http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
\ *
|
||||||
|
\ * Contributors:
|
||||||
|
\ * IBM Corporation - initial implementation
|
||||||
|
\ ****************************************************************************/
|
||||||
|
|
||||||
|
\ Handle e1000 device
|
||||||
|
|
||||||
|
s" network" device-type
|
||||||
|
|
||||||
|
INSTANCE VARIABLE obp-tftp-package
|
||||||
|
|
||||||
|
0 VALUE e1k-priv
|
||||||
|
0 VALUE open-count
|
||||||
|
|
||||||
|
: open ( -- okay? )
|
||||||
|
open-count 0= IF
|
||||||
|
open IF
|
||||||
|
my-args s" obp-tftp" $open-package obp-tftp-package !
|
||||||
|
e1k-open dup not IF ." e1k-open failed" EXIT THEN
|
||||||
|
drop TO e1k-priv
|
||||||
|
true
|
||||||
|
ELSE
|
||||||
|
false
|
||||||
|
THEN
|
||||||
|
ELSE
|
||||||
|
true
|
||||||
|
THEN
|
||||||
|
open-count 1 + to open-count
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
: close ( -- )
|
||||||
|
open-count 0> IF
|
||||||
|
open-count 1 - dup to open-count
|
||||||
|
0= IF
|
||||||
|
s" close" obp-tftp-package @ $call-method
|
||||||
|
e1k-priv e1k-close
|
||||||
|
close
|
||||||
|
THEN
|
||||||
|
THEN
|
||||||
|
;
|
||||||
|
|
||||||
|
: read ( buf len -- actual )
|
||||||
|
dup IF
|
||||||
|
e1k-read
|
||||||
|
ELSE
|
||||||
|
nip
|
||||||
|
THEN
|
||||||
|
;
|
||||||
|
|
||||||
|
: write ( buf len -- actual )
|
||||||
|
dup IF
|
||||||
|
e1k-write
|
||||||
|
ELSE
|
||||||
|
nip
|
||||||
|
THEN
|
||||||
|
;
|
||||||
|
|
||||||
|
: load ( addr -- len )
|
||||||
|
s" load" obp-tftp-package @ $call-method
|
||||||
|
;
|
||||||
|
|
||||||
|
: ping ( -- )
|
||||||
|
s" ping" obp-tftp-package @ $call-method
|
||||||
|
;
|
||||||
|
|
||||||
|
6 BUFFER: local-mac
|
||||||
|
: setup-mac ( -- )
|
||||||
|
pci-mem-enable
|
||||||
|
" vendor-id" get-node get-property IF EXIT THEN
|
||||||
|
decode-int nip nip
|
||||||
|
" device-id" get-node get-property IF EXIT THEN
|
||||||
|
decode-int nip nip
|
||||||
|
" 10 config-l@ translate-my-address 3 not AND" evaluate
|
||||||
|
local-mac e1k-mac-setup IF
|
||||||
|
encode-bytes " local-mac-address" property
|
||||||
|
THEN
|
||||||
|
;
|
||||||
|
setup-mac
|
||||||
|
|
||||||
|
: setup-alias ( -- )
|
||||||
|
s" net" find-alias 0= IF
|
||||||
|
s" net" get-node node>path set-alias
|
||||||
|
ELSE
|
||||||
|
drop
|
||||||
|
THEN
|
||||||
|
;
|
||||||
|
setup-alias
|
|
@ -0,0 +1,23 @@
|
||||||
|
\ *****************************************************************************
|
||||||
|
\ * Copyright (c) 2013 IBM Corporation
|
||||||
|
\ * All rights reserved.
|
||||||
|
\ * This program and the accompanying materials
|
||||||
|
\ * are made available under the terms of the BSD License
|
||||||
|
\ * which accompanies this distribution, and is available at
|
||||||
|
\ * http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
\ *
|
||||||
|
\ * Contributors:
|
||||||
|
\ * IBM Corporation - initial implementation
|
||||||
|
\ ****************************************************************************/
|
||||||
|
|
||||||
|
\ Handle e1000 device
|
||||||
|
|
||||||
|
s" e1000 [ net ]" type cr
|
||||||
|
|
||||||
|
my-space pci-device-generic-setup
|
||||||
|
|
||||||
|
pci-io-enable
|
||||||
|
|
||||||
|
s" e1k.fs" included
|
||||||
|
|
||||||
|
pci-device-disable
|
|
@ -36,7 +36,6 @@ typedef struct {
|
||||||
} mod_descriptor_t;
|
} mod_descriptor_t;
|
||||||
|
|
||||||
static const mod_descriptor_t modules[] = {
|
static const mod_descriptor_t modules[] = {
|
||||||
{ "net_e1000", MOD_TYPE_NETWORK },
|
|
||||||
{ "net_bcm", MOD_TYPE_NETWORK },
|
{ "net_bcm", MOD_TYPE_NETWORK },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# ****************************************************************************/
|
# ****************************************************************************/
|
||||||
|
|
||||||
SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \
|
SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \
|
||||||
libusb libveth
|
libusb libveth libe1k
|
||||||
|
|
||||||
all: subdirs
|
all: subdirs
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
# *****************************************************************************
|
||||||
|
# * Copyright (c) 2004, 2008, 2013 IBM Corporation
|
||||||
|
# * All rights reserved.
|
||||||
|
# * This program and the accompanying materials
|
||||||
|
# * are made available under the terms of the BSD License
|
||||||
|
# * which accompanies this distribution, and is available at
|
||||||
|
# * http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
# *
|
||||||
|
# * Contributors:
|
||||||
|
# * IBM Corporation - initial implementation
|
||||||
|
# ****************************************************************************/
|
||||||
|
|
||||||
|
TOPCMNDIR ?= ../..
|
||||||
|
|
||||||
|
CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
|
||||||
|
-I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
|
||||||
|
|
||||||
|
LDFLAGS = -nostdlib
|
||||||
|
|
||||||
|
TARGET = ../libe1k.a
|
||||||
|
|
||||||
|
|
||||||
|
all: $(TARGET) Makefile.dep
|
||||||
|
|
||||||
|
SRCS = e1k.c
|
||||||
|
|
||||||
|
OBJS = $(SRCS:%.c=%.o)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(AR) -rc $@ $(OBJS)
|
||||||
|
$(RANLIB) $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(TARGET) $(OBJS)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
$(RM) Makefile.dep
|
||||||
|
|
||||||
|
|
||||||
|
# Rules for creating the dependency file:
|
||||||
|
depend:
|
||||||
|
$(RM) Makefile.dep
|
||||||
|
$(MAKE) Makefile.dep
|
||||||
|
|
||||||
|
Makefile.dep: Makefile
|
||||||
|
$(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
|
||||||
|
|
||||||
|
# Include dependency file if available:
|
||||||
|
-include Makefile.dep
|
|
@ -0,0 +1,999 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (c) 2007, 2011, 2013 IBM Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the BSD License
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial implementation
|
||||||
|
*****************************************************************************/
|
||||||
|
/*
|
||||||
|
* e1000 Gigabit Ethernet Driver for SLOF
|
||||||
|
*
|
||||||
|
* Reference:
|
||||||
|
* PCI/PCI-X Family of Gigabit Ethernet Controllers
|
||||||
|
* Software Developer's Manual Rev. 3.3, Intel, December 2006
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <byteorder.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
#include <netdriver.h>
|
||||||
|
#include "e1k.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* local defines
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#define E1K_NUM_RX_DESC 128 // do not change
|
||||||
|
#define E1K_NUM_TX_DESC 128 // do not change
|
||||||
|
#define E1K_BUF_SIZE 2096 // do not change
|
||||||
|
|
||||||
|
#define NUM_MAC_ADDR 16 // number of mac address register pairs
|
||||||
|
#define EEPROM_MAC_OFFS 0 // position of mac address in eeprom
|
||||||
|
|
||||||
|
/*
|
||||||
|
* local types
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t m_dev_u32;
|
||||||
|
uint64_t m_devmsk_u64;
|
||||||
|
char *m_name;
|
||||||
|
} e1k_dev_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e1k common data structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transmit buffer descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t m_buffer_u64;
|
||||||
|
uint16_t m_len_u16;
|
||||||
|
uint8_t m_cso_u08;
|
||||||
|
uint8_t m_cmd_u08;
|
||||||
|
uint8_t m_sta_u08;
|
||||||
|
uint8_t m_css_u08;
|
||||||
|
uint16_t m_spe_u16;
|
||||||
|
} __attribute__ ((packed)) e1k_tx_desc_st;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* receive buffer descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t m_buffer_u64;
|
||||||
|
uint16_t m_len_u16;
|
||||||
|
uint16_t m_csm_u16;
|
||||||
|
uint8_t m_sta_u08;
|
||||||
|
uint8_t m_err_u08;
|
||||||
|
uint16_t m_spe_u16;
|
||||||
|
} __attribute__ ((packed)) e1k_rx_desc_st;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e1k device structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/*
|
||||||
|
* device identification mask
|
||||||
|
*/
|
||||||
|
uint64_t m_device_u64;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory mapped base address of NIC
|
||||||
|
*/
|
||||||
|
uint64_t m_baseaddr_u64;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transmit & receive rings
|
||||||
|
* must be 16 byte aligned
|
||||||
|
*/
|
||||||
|
e1k_tx_desc_st m_tx_ring_pst[E1K_NUM_TX_DESC];
|
||||||
|
e1k_rx_desc_st m_rx_ring_pst[E1K_NUM_RX_DESC];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transmit & receive buffers
|
||||||
|
* must be 16 byte aligned
|
||||||
|
*/
|
||||||
|
uint8_t m_tx_buffer_pu08[E1K_NUM_TX_DESC][E1K_BUF_SIZE];
|
||||||
|
uint8_t m_rx_buffer_pu08[E1K_NUM_RX_DESC][E1K_BUF_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* next receive descriptor index
|
||||||
|
*/
|
||||||
|
uint32_t m_rx_next_u32;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* command register storage
|
||||||
|
*/
|
||||||
|
uint16_t m_com_r_u16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* padding to make the size of the structure a multiple of 16 byte
|
||||||
|
*/
|
||||||
|
uint16_t m_pad16_u16;
|
||||||
|
uint64_t m_pad64_u32;
|
||||||
|
|
||||||
|
} __attribute__ ((packed)) e1k_st;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* local constants
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#define E1K_82540 ((uint64_t) 0x1)
|
||||||
|
#define E1K_82541 ((uint64_t) 0x2)
|
||||||
|
#define E1K_82544 ((uint64_t) 0x4)
|
||||||
|
#define E1K_82545 ((uint64_t) 0x8)
|
||||||
|
#define E1K_82546 ((uint64_t) 0x10)
|
||||||
|
#define E1K_82547 ((uint64_t) 0x20)
|
||||||
|
|
||||||
|
#define IS_82541 ((m_e1k.m_device_u64 & E1K_82541) != 0)
|
||||||
|
#define IS_82546 ((m_e1k.m_device_u64 & E1K_82546) != 0)
|
||||||
|
#define IS_82547 ((m_e1k.m_device_u64 & E1K_82547) != 0)
|
||||||
|
|
||||||
|
static const e1k_dev_t e1k_dev[] = {
|
||||||
|
{ 0x1019, E1K_82547, "82547EI/GI Copper" },
|
||||||
|
{ 0x101A, E1K_82547, "82547EI Mobile" },
|
||||||
|
{ 0x1010, E1K_82546, "52546EB Copper, Dual Port" },
|
||||||
|
{ 0x1012, E1K_82546, "82546EB Fiber, Dual Port" },
|
||||||
|
/* { 0x101D, E1K_82546, "82546EB Copper, Quad Port" }, */
|
||||||
|
{ 0x1079, E1K_82546, "82546GB Copper, Dual Port" },
|
||||||
|
{ 0x107A, E1K_82546, "82546GB Fiber, Dual Port" },
|
||||||
|
{ 0x107B, E1K_82546, "82546GB SerDes, Dual Port" },
|
||||||
|
{ 0x100F, E1K_82545, "82545EM Copper" },
|
||||||
|
{ 0x1011, E1K_82545, "82545EM Fiber" },
|
||||||
|
{ 0x1026, E1K_82545, "82545GM Copper" },
|
||||||
|
{ 0x1027, E1K_82545, "82545GM Fiber" },
|
||||||
|
{ 0x1028, E1K_82545, "82545GM SerDes" },
|
||||||
|
{ 0x1107, E1K_82544, "82544EI Copper" },
|
||||||
|
{ 0x1112, E1K_82544, "82544GC Copper" },
|
||||||
|
{ 0x1013, E1K_82541, "82541EI Copper" },
|
||||||
|
{ 0x1018, E1K_82541, "82541EI Mobile" },
|
||||||
|
{ 0x1076, E1K_82541, "82541GI Copper" },
|
||||||
|
{ 0x1077, E1K_82541, "82541GI Mobile" },
|
||||||
|
{ 0x1078, E1K_82541, "82541ER Copper" },
|
||||||
|
{ 0x107C, E1K_82541, "82541PI" },
|
||||||
|
{ 0x1015, E1K_82540, "82540EM Mobile" },
|
||||||
|
{ 0x1016, E1K_82540, "82540EP Mobile" },
|
||||||
|
{ 0x1017, E1K_82540, "82540EP Desktop" },
|
||||||
|
{ 0x100E, E1K_82540, "82540EM Desktop" },
|
||||||
|
{ 0 , 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* local variables
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
static e1k_st m_e1k __attribute__ ((aligned(16)));
|
||||||
|
static long dma_offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* global functions
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
check_driver(uint16_t vendor_id, uint16_t device_id);
|
||||||
|
|
||||||
|
static int e1k_init(net_driver_t *driver);
|
||||||
|
static int e1k_term(void);
|
||||||
|
static int e1k_xmit(char *f_buffer_pc, int f_len_i);
|
||||||
|
static int e1k_receive(char *f_buffer_pc, int f_len_i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate virtual to "physical" address, ie. an address
|
||||||
|
* which can be used for DMA transfers.
|
||||||
|
*/
|
||||||
|
static uint64_t
|
||||||
|
virt2dma(void *addr)
|
||||||
|
{
|
||||||
|
return (uint64_t)addr + dma_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
dma2virt(uint64_t addr)
|
||||||
|
{
|
||||||
|
return (void *)(addr - dma_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* local inline functions for e1k register access
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
e1k_rd32(uint16_t f_offs_u16)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
return bswap_32(rd32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static uint16_t
|
||||||
|
e1k_rd16(uint16_t f_offs_u16)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
return bswap_16(rd16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static uint8_t
|
||||||
|
e1k_rd08(uint16_t f_offs_u16)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
return rd08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
e1k_wr32(uint16_t f_offs_u16, uint32_t f_val_u32)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
wr32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_32(f_val_u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_wr16(uint16_t f_offs_u16, uint16_t f_val_u16)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
wr16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_16(f_val_u16));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_wr08(uint16_t f_offs_u16, uint8_t f_val_u08)
|
||||||
|
{ // caution: shall only be used after initialization!
|
||||||
|
wr08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
e1k_setb32(uint16_t f_offs_u16, uint32_t f_mask_u32)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = e1k_rd32(f_offs_u16);
|
||||||
|
v |= f_mask_u32;
|
||||||
|
e1k_wr32(f_offs_u16, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_setb16(uint16_t f_offs_u16, uint16_t f_mask_u16)
|
||||||
|
{
|
||||||
|
uint16_t v;
|
||||||
|
v = e1k_rd16(f_offs_u16);
|
||||||
|
v |= f_mask_u16;
|
||||||
|
e1k_wr16(f_offs_u16, v);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_setb08(uint16_t f_offs_u16, uint8_t f_mask_u08)
|
||||||
|
{
|
||||||
|
uint8_t v;
|
||||||
|
v = e1k_rd08(f_offs_u16);
|
||||||
|
v |= f_mask_u08;
|
||||||
|
e1k_wr08(f_offs_u16, v);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
e1k_clrb32(uint16_t f_offs_u16, uint32_t f_mask_u32)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
v = e1k_rd32(f_offs_u16);
|
||||||
|
v &= ~f_mask_u32;
|
||||||
|
e1k_wr32(f_offs_u16, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_clrb16(uint16_t f_offs_u16, uint16_t f_mask_u16)
|
||||||
|
{
|
||||||
|
uint16_t v;
|
||||||
|
|
||||||
|
v = e1k_rd16(f_offs_u16);
|
||||||
|
v &= ~f_mask_u16;
|
||||||
|
e1k_wr16(f_offs_u16, v);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* not used so far
|
||||||
|
static void
|
||||||
|
e1k_clrb08(uint16_t f_offs_u16, uint8_t f_mask_u08)
|
||||||
|
{
|
||||||
|
uint8_t v;
|
||||||
|
v = e1k_rd08(f_offs_u16);
|
||||||
|
v &= ~f_mask_u08;
|
||||||
|
e1k_wr08(f_offs_u16, v);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static int32_t
|
||||||
|
e1k_eep_rd16(uint8_t f_offs_u08, uint16_t *f_data_pu16)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t v;
|
||||||
|
int32_t done_shft;
|
||||||
|
int32_t addr_shft;
|
||||||
|
|
||||||
|
if(IS_82541 || IS_82547) {
|
||||||
|
addr_shft = 2;
|
||||||
|
done_shft = 1;
|
||||||
|
} else {
|
||||||
|
addr_shft = 8;
|
||||||
|
done_shft = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initiate eeprom read
|
||||||
|
*/
|
||||||
|
e1k_wr32(EERD, ((uint32_t) f_offs_u08 << addr_shft) | // address
|
||||||
|
BIT32(0)); // start read
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for read done bit to be set
|
||||||
|
*/
|
||||||
|
i = 1000;
|
||||||
|
v = e1k_rd32(EERD);
|
||||||
|
while ((--i) &&
|
||||||
|
((v & BIT32(done_shft)) == 0)) {
|
||||||
|
SLOF_msleep(1);
|
||||||
|
v = e1k_rd32(EERD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return on error
|
||||||
|
*/
|
||||||
|
if ((v & BIT32(done_shft)) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return data
|
||||||
|
*/
|
||||||
|
*f_data_pu16 = (uint16_t) ((v >> 16) & 0xffff);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ring initialization
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
e1k_init_receiver(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disable receiver for initialization
|
||||||
|
*/
|
||||||
|
e1k_wr32(RCTL, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear receive desciptors and setup buffer pointers
|
||||||
|
*/
|
||||||
|
for (i = 0; i < E1K_NUM_RX_DESC; i++) {
|
||||||
|
memset((uint8_t *) &m_e1k.m_rx_ring_pst[i], 0,
|
||||||
|
sizeof(e1k_rx_desc_st));
|
||||||
|
mb();
|
||||||
|
|
||||||
|
m_e1k.m_rx_ring_pst[i].m_buffer_u64 =
|
||||||
|
bswap_64(virt2dma(&m_e1k.m_rx_buffer_pu08[i][0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize previously received index
|
||||||
|
*/
|
||||||
|
m_e1k.m_rx_next_u32 = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the base address and the length of the rx descriptor ring
|
||||||
|
*/
|
||||||
|
addr = virt2dma(&m_e1k.m_rx_ring_pst[0]);
|
||||||
|
e1k_wr32(RDBAH, (uint32_t) ((uint64_t) addr >> 32));
|
||||||
|
e1k_wr32(RDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff));
|
||||||
|
e1k_wr32(RDLEN, E1K_NUM_RX_DESC * sizeof(e1k_rx_desc_st));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the rx head and tail descriptor indices
|
||||||
|
*/
|
||||||
|
e1k_wr32(RDH, 0);
|
||||||
|
e1k_wr32(RDT, E1K_NUM_RX_DESC - 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the receive delay timer register
|
||||||
|
*/
|
||||||
|
e1k_wr32(RDTR, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the receive control register
|
||||||
|
*/
|
||||||
|
e1k_wr32(RCTL, BIT32( 1) | // enable receiver
|
||||||
|
BIT32( 4) | // enable multicast reception
|
||||||
|
BIT32(15)); // broadcast accept mode
|
||||||
|
// packet size 2048
|
||||||
|
// no buffer extension
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e1k_init_transmitter(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t addr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear transmit desciptors and setup buffer pointers
|
||||||
|
*/
|
||||||
|
for (i = 0; i < E1K_NUM_TX_DESC; i++) {
|
||||||
|
memset((uint8_t *) &m_e1k.m_tx_ring_pst[i], 0,
|
||||||
|
sizeof(e1k_tx_desc_st));
|
||||||
|
mb();
|
||||||
|
|
||||||
|
m_e1k.m_tx_ring_pst[i].m_buffer_u64 =
|
||||||
|
bswap_64(virt2dma(&m_e1k.m_tx_buffer_pu08[i][0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the base address and the length of the tx descriptor ring
|
||||||
|
*/
|
||||||
|
addr = virt2dma(&m_e1k.m_tx_ring_pst[0]);
|
||||||
|
e1k_wr32(TDBAH, (uint32_t) ((uint64_t) addr >> 32));
|
||||||
|
e1k_wr32(TDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff));
|
||||||
|
e1k_wr32(TDLEN, E1K_NUM_TX_DESC * sizeof(e1k_tx_desc_st));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup the rx head and tail descriptor indices
|
||||||
|
*/
|
||||||
|
e1k_wr32(TDH, 0);
|
||||||
|
e1k_wr32(TDT, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize the transmit control register
|
||||||
|
*/
|
||||||
|
e1k_wr32(TCTL, BIT32(1) | // enable transmitter
|
||||||
|
BIT32(3) | // pad short packets
|
||||||
|
((uint32_t) 0x0f << 4) | // collision threshhold
|
||||||
|
((uint32_t) 0x40 << 12)); // collision distance
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t
|
||||||
|
e1k_mac_init(uint8_t *f_mac_pu08)
|
||||||
|
{
|
||||||
|
uint32_t l_ah_u32;
|
||||||
|
uint32_t l_al_u32;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use MAC address from device tree if possible
|
||||||
|
*/
|
||||||
|
for (i = 0, v = 0; i < 6; i++) {
|
||||||
|
v += (uint32_t) f_mac_pu08[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v != 0) {
|
||||||
|
/*
|
||||||
|
* use passed mac address for transmission to nic
|
||||||
|
*/
|
||||||
|
l_al_u32 = ((uint32_t) f_mac_pu08[3] << 24);
|
||||||
|
l_al_u32 |= ((uint32_t) f_mac_pu08[2] << 16);
|
||||||
|
l_al_u32 |= ((uint32_t) f_mac_pu08[1] << 8);
|
||||||
|
l_al_u32 |= ((uint32_t) f_mac_pu08[0] << 0);
|
||||||
|
l_ah_u32 = ((uint32_t) f_mac_pu08[5] << 8);
|
||||||
|
l_ah_u32 |= ((uint32_t) f_mac_pu08[4] << 0);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* read mac address from eeprom
|
||||||
|
*/
|
||||||
|
uint16_t w[3]; // 3 16 bit words from eeprom
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (e1k_eep_rd16(EEPROM_MAC_OFFS + i, &w[i]) != 0) {
|
||||||
|
printf("Failed to read MAC address from EEPROM!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* invert the least significant bit for 82546 dual port
|
||||||
|
* if the second device is in use (remember word is byteswapped)
|
||||||
|
*/
|
||||||
|
if ((IS_82546) &&
|
||||||
|
((e1k_rd32(STATUS) & BIT32(2)) != 0)) {
|
||||||
|
w[2] ^= (uint16_t) 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* store mac address for transmission to nic
|
||||||
|
*/
|
||||||
|
l_ah_u32 = ((uint32_t) w[2] << 0);
|
||||||
|
l_al_u32 = ((uint32_t) w[1] << 16);
|
||||||
|
l_al_u32 |= ((uint32_t) w[0] << 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return mac address
|
||||||
|
* mac address in eeprom is stored byteswapped
|
||||||
|
*/
|
||||||
|
f_mac_pu08[1] = (uint8_t) ((w[0] >> 8) & 0xff);
|
||||||
|
f_mac_pu08[0] = (uint8_t) ((w[0] >> 0) & 0xff);
|
||||||
|
f_mac_pu08[3] = (uint8_t) ((w[1] >> 8) & 0xff);
|
||||||
|
f_mac_pu08[2] = (uint8_t) ((w[1] >> 0) & 0xff);
|
||||||
|
f_mac_pu08[5] = (uint8_t) ((w[2] >> 8) & 0xff);
|
||||||
|
f_mac_pu08[4] = (uint8_t) ((w[2] >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* insert mac address in receive address register
|
||||||
|
* and set AV bit
|
||||||
|
*/
|
||||||
|
e1k_wr32(RAL0, l_al_u32);
|
||||||
|
e1k_wr32(RAH0, l_ah_u32 | BIT32(31));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear remaining receive address registers
|
||||||
|
*/
|
||||||
|
for (i = 1; i < NUM_MAC_ADDR; i++) {
|
||||||
|
e1k_wr32(RAL0 + i * sizeof(uint64_t), 0);
|
||||||
|
e1k_wr32(RAH0 + i * sizeof(uint64_t), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interface
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e1k_receive
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
e1k_receive(char *f_buffer_pc, int f_len_i)
|
||||||
|
{
|
||||||
|
uint32_t l_rdh_u32 = e1k_rd32(RDH); // this includes needed dummy read
|
||||||
|
e1k_rx_desc_st *rx;
|
||||||
|
int l_ret_i;
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
#ifdef E1K_SHOW_RCV_DATA
|
||||||
|
int i;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check whether new packets have arrived
|
||||||
|
*/
|
||||||
|
if (m_e1k.m_rx_next_u32 == l_rdh_u32) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a pointer to the next rx descriptor for ease of use
|
||||||
|
*/
|
||||||
|
rx = &m_e1k.m_rx_ring_pst[m_e1k.m_rx_next_u32];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check whether the descriptor done bit is set
|
||||||
|
*/
|
||||||
|
if ((rx->m_sta_u08 & 0x1) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the length of the packet, throw away checksum
|
||||||
|
*/
|
||||||
|
l_ret_i = (int) bswap_16(rx->m_len_u16) - (int) 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy the data
|
||||||
|
*/
|
||||||
|
memcpy((uint8_t *) f_buffer_pc, dma2virt(bswap_64(rx->m_buffer_u64)),
|
||||||
|
(size_t) l_ret_i);
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
#if defined(E1K_SHOW_RCV) || defined(E1K_SHOW_RCV_DATA)
|
||||||
|
printf("e1k: %d bytes received\n", l_ret_i);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef E1K_SHOW_RCV_DATA
|
||||||
|
for (i = 0; i < l_ret_i; i++) {
|
||||||
|
|
||||||
|
if ((i & 0x1f) == 0) {
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%02X ", f_buffer_pc[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\n");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear descriptor for reusage, but leave buffer pointer untouched
|
||||||
|
*/
|
||||||
|
memset((uint8_t *) &rx->m_len_u16, 0,
|
||||||
|
sizeof(e1k_rx_desc_st) - sizeof(uint64_t));
|
||||||
|
mb();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* write new tail pointer
|
||||||
|
*/
|
||||||
|
e1k_wr32(RDT, m_e1k.m_rx_next_u32);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update next receive index
|
||||||
|
*/
|
||||||
|
m_e1k.m_rx_next_u32 = (m_e1k.m_rx_next_u32 + 1) & (E1K_NUM_RX_DESC - 1);
|
||||||
|
|
||||||
|
return l_ret_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
e1k_xmit(char *f_buffer_pc, int f_len_i)
|
||||||
|
{
|
||||||
|
uint32_t l_tdh_u32 = e1k_rd32(TDH);
|
||||||
|
uint32_t l_tdt_u32 = e1k_rd32(TDT);
|
||||||
|
uint32_t l_pre_u32 = (l_tdh_u32 + (E1K_NUM_TX_DESC - 1)) &
|
||||||
|
(E1K_NUM_TX_DESC - 1);
|
||||||
|
e1k_tx_desc_st *tx;
|
||||||
|
#if defined(E1K_DEBUG) && defined(E1K_SHOW_XMIT_DATA)
|
||||||
|
int i;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for available buffers
|
||||||
|
*/
|
||||||
|
if (l_pre_u32 == l_tdt_u32) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a pointer to the next tx descriptor for ease of use
|
||||||
|
*/
|
||||||
|
tx = &m_e1k.m_tx_ring_pst[l_tdt_u32];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy the data
|
||||||
|
*/
|
||||||
|
memcpy(dma2virt(bswap_64(tx->m_buffer_u64)), (uint8_t *) f_buffer_pc,
|
||||||
|
(size_t) f_len_i);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* insert length & command flags
|
||||||
|
*/
|
||||||
|
tx->m_len_u16 = bswap_16((uint16_t) f_len_i);
|
||||||
|
tx->m_cmd_u08 = (BIT08(0) | // EOP
|
||||||
|
BIT08(1)); // IFCS
|
||||||
|
tx->m_sta_u08 = 0;
|
||||||
|
mb();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update tail index
|
||||||
|
*/
|
||||||
|
l_tdt_u32 = (l_tdt_u32 + 1) & (E1K_NUM_TX_DESC - 1);
|
||||||
|
e1k_wr32(TDT, l_tdt_u32);
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
#if defined(E1K_SHOW_XMIT) || defined(E1K_SHOW_XMIT_DATA)
|
||||||
|
printf("e1k: %d bytes transmitted\n", bswap_16(tx->m_len_u16));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef E1K_SHOW_XMIT_DATA
|
||||||
|
for (i = 0; i < bswap_16(tx->m_len_u16); i++) {
|
||||||
|
|
||||||
|
if ((i & 0x1f) == 0) {
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
|
||||||
|
f_buffer_pc = dma2virt(bswap_64(tx->m_buffer_u64));
|
||||||
|
printf("%02X ", f_buffer_pc[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\n");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return f_len_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
check_driver(uint16_t vendor_id, uint16_t device_id)
|
||||||
|
{
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checks whether the driver is handling this device
|
||||||
|
* by verifying vendor & device id
|
||||||
|
* vendor id 0x8086 == Intel
|
||||||
|
*/
|
||||||
|
if (vendor_id != 0x8086) {
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: netdevice with vendor id %04X not supported\n",
|
||||||
|
vendor_id);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; e1k_dev[i].m_dev_u32 != 0; i++) {
|
||||||
|
if (e1k_dev[i].m_dev_u32 == (uint32_t) device_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e1k_dev[i].m_dev_u32 == 0) {
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: netdevice with device id %04X not supported\n",
|
||||||
|
device_id);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize static variables
|
||||||
|
*/
|
||||||
|
m_e1k.m_device_u64 = e1k_dev[i].m_devmsk_u64;
|
||||||
|
m_e1k.m_baseaddr_u64 = 0;
|
||||||
|
|
||||||
|
// success
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: found device %s\n", e1k_dev[i].m_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
e1k_init(net_driver_t *driver)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
if (!driver)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("\ne1k: initializing\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dma_offset = SLOF_dma_map_in(&m_e1k, sizeof(m_e1k), 0);
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: dma offset: %lx - %lx = %lx\n", dma_offset, (long)&m_e1k,
|
||||||
|
dma_offset - (long)&m_e1k);
|
||||||
|
#endif
|
||||||
|
dma_offset = dma_offset - (long)&m_e1k;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup register & memory base addresses of NIC
|
||||||
|
*/
|
||||||
|
//m_e1k.m_baseaddr_u64 = baseaddr;
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: base address register = 0x%llx\n", m_e1k.m_baseaddr_u64);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e1k hardware initialization
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* at first disable all interrupts
|
||||||
|
*/
|
||||||
|
e1k_wr32(IMC, (uint32_t) ~0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for link up
|
||||||
|
*/
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: checking link status..\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
i = 50;
|
||||||
|
v = e1k_rd32(STATUS);
|
||||||
|
while ((--i) &&
|
||||||
|
((v & BIT32(1)) == 0)) {
|
||||||
|
SLOF_msleep(100);
|
||||||
|
v = e1k_rd32(STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & BIT32(1)) == 0) {
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: link is down.\n");
|
||||||
|
printf(" terminating.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: link is up\n");
|
||||||
|
|
||||||
|
switch ((v >> 6) & 0x3) {
|
||||||
|
case 0: {
|
||||||
|
printf(" 10 Mb/s\n");
|
||||||
|
} break;
|
||||||
|
case 1: {
|
||||||
|
printf(" 100 Mb/s\n");
|
||||||
|
} break;
|
||||||
|
case 2:
|
||||||
|
case 3: {
|
||||||
|
printf(" 1000 Mb/s\n");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & BIT32(0)) == 0) {
|
||||||
|
printf(" half-duplex\n");
|
||||||
|
} else {
|
||||||
|
printf(" full-duplex\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize mac address
|
||||||
|
*/
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: initializing mac address.. ");
|
||||||
|
#endif
|
||||||
|
if (e1k_mac_init((uint8_t *)driver->mac_addr) != 0) {
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("failed.\n");
|
||||||
|
printf(" terminating.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("done.\n");
|
||||||
|
printf(" mac address = %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||||
|
driver->mac_addr[0], driver->mac_addr[1], driver->mac_addr[2],
|
||||||
|
driver->mac_addr[3], driver->mac_addr[4], driver->mac_addr[5]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize transmitter
|
||||||
|
*/
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: initializing transmitter.. ");
|
||||||
|
#endif
|
||||||
|
e1k_init_transmitter();
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("done.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize receiver
|
||||||
|
*/
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: initializing receiver.. ");
|
||||||
|
#endif
|
||||||
|
e1k_init_receiver();
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("done.\n");
|
||||||
|
printf("e1k: initialization complete\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
driver->running = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
e1k_reset(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* reset the PHY
|
||||||
|
*/
|
||||||
|
e1k_setb32(CTRL, BIT32(31));
|
||||||
|
SLOF_msleep(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset the MAC
|
||||||
|
*/
|
||||||
|
e1k_setb32(CTRL, BIT32(26));
|
||||||
|
SLOF_msleep(10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
e1k_term(void)
|
||||||
|
{
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("e1k: shutdown.. ");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disable receiver & transmitter
|
||||||
|
*/
|
||||||
|
e1k_wr32(RCTL, 0);
|
||||||
|
e1k_wr32(TCTL, 0);
|
||||||
|
SLOF_msleep(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset the ring indices
|
||||||
|
*/
|
||||||
|
e1k_wr32(RDH, 0);
|
||||||
|
e1k_wr32(RDT, 0);
|
||||||
|
e1k_wr32(TDH, 0);
|
||||||
|
e1k_wr32(TDT, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disable receive address
|
||||||
|
*/
|
||||||
|
e1k_clrb32(RAH0, BIT32(31));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset the mac/phy
|
||||||
|
*/
|
||||||
|
e1k_reset();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable DMA translation
|
||||||
|
*/
|
||||||
|
SLOF_dma_map_out((long)&m_e1k, (void *)virt2dma(&m_e1k), (long)sizeof(m_e1k));
|
||||||
|
|
||||||
|
#ifdef E1K_DEBUG
|
||||||
|
printf("done.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_driver_t *e1k_open(void)
|
||||||
|
{
|
||||||
|
net_driver_t *driver;
|
||||||
|
|
||||||
|
driver = SLOF_alloc_mem(sizeof(*driver));
|
||||||
|
if (!driver) {
|
||||||
|
printf("Unable to allocate virtio-net driver\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(driver, 0, sizeof(*driver));
|
||||||
|
|
||||||
|
if (e1k_init(driver))
|
||||||
|
goto FAIL;
|
||||||
|
|
||||||
|
return driver;
|
||||||
|
|
||||||
|
FAIL: SLOF_free_mem(driver, sizeof(*driver));
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void e1k_close(net_driver_t *driver)
|
||||||
|
{
|
||||||
|
if (driver->running == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
e1k_term();
|
||||||
|
driver->running = 0;
|
||||||
|
SLOF_free_mem(driver, sizeof(*driver));
|
||||||
|
}
|
||||||
|
|
||||||
|
int e1k_read(char *buf, int len)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
return e1k_receive(buf, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int e1k_write(char *buf, int len)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
return e1k_xmit(buf, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id,
|
||||||
|
uint64_t baseaddr, char *mac_addr)
|
||||||
|
{
|
||||||
|
if (check_driver(vendor_id, device_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
m_e1k.m_baseaddr_u64 = baseaddr;
|
||||||
|
memset(mac_addr, 0, 6);
|
||||||
|
|
||||||
|
return e1k_mac_init((uint8_t *)mac_addr);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (c) 2013 IBM Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the BSD License
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial implementation
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libe1k Forth wrapper
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <e1k.h>
|
||||||
|
|
||||||
|
// : e1k-open ( -- false | [ driver true ] )
|
||||||
|
PRIM(E1K_X2d_OPEN)
|
||||||
|
{
|
||||||
|
net_driver_t *net_driver = e1k_open();
|
||||||
|
if (net_driver) {
|
||||||
|
PUSH;
|
||||||
|
TOS.u = (unsigned long)net_driver; PUSH;
|
||||||
|
TOS.n = -1;
|
||||||
|
} else {
|
||||||
|
PUSH;
|
||||||
|
TOS.n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MIRP
|
||||||
|
|
||||||
|
// : e1k-close ( driver -- )
|
||||||
|
PRIM(E1K_X2d_CLOSE)
|
||||||
|
{
|
||||||
|
net_driver_t *driver = TOS.a; POP;
|
||||||
|
e1k_close(driver);
|
||||||
|
}
|
||||||
|
MIRP
|
||||||
|
|
||||||
|
|
||||||
|
// : e1k-read ( addr len -- actual )
|
||||||
|
PRIM(E1K_X2d_READ)
|
||||||
|
{
|
||||||
|
int len = TOS.u; POP;
|
||||||
|
TOS.n = e1k_read(TOS.a, len);
|
||||||
|
}
|
||||||
|
MIRP
|
||||||
|
|
||||||
|
// : e1k-write ( addr len -- actual )
|
||||||
|
PRIM(E1K_X2d_WRITE)
|
||||||
|
{
|
||||||
|
int len = TOS.u; POP;
|
||||||
|
TOS.n = e1k_write(TOS.a, len);
|
||||||
|
}
|
||||||
|
MIRP
|
||||||
|
|
||||||
|
// : e1k-mac-setup ( vendor-id device-id baseaddr addr -- false | [ mac-addr len true ] )
|
||||||
|
PRIM(E1K_X2d_MAC_X2d_SETUP)
|
||||||
|
{
|
||||||
|
char *mac_addr = TOS.a; POP;
|
||||||
|
uint64_t baseaddr = TOS.u; POP;
|
||||||
|
unsigned int device_id = TOS.u; POP;
|
||||||
|
|
||||||
|
int ret = e1k_mac_setup(TOS.u, device_id, baseaddr, mac_addr);
|
||||||
|
if (!ret) {
|
||||||
|
TOS.a = mac_addr; PUSH;
|
||||||
|
TOS.n = 6; PUSH;
|
||||||
|
TOS.n = -1;
|
||||||
|
} else
|
||||||
|
TOS.n = 0;
|
||||||
|
}
|
||||||
|
MIRP
|
|
@ -0,0 +1,108 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (c) 2007, 2011, 2013 IBM Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the BSD License
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial implementation
|
||||||
|
*****************************************************************************/
|
||||||
|
/*
|
||||||
|
* Definitions for the e1000 Gigabit Ethernet Driver for SLOF
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <cache.h>
|
||||||
|
|
||||||
|
// compiler switches
|
||||||
|
|
||||||
|
// Debug switches
|
||||||
|
//#define E1K_DEBUG // main debug switch, w/o it the other ones don't work
|
||||||
|
//#define E1K_SHOW_RCV
|
||||||
|
//#define E1K_SHOW_RCV_DATA
|
||||||
|
//#define E1K_SHOW_XMIT
|
||||||
|
//#define E1K_SHOW_XMIT_DATA
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pci register offsets
|
||||||
|
*/
|
||||||
|
// PCI command register
|
||||||
|
#define PCI_COM_R ((uint16_t) 0x0004)
|
||||||
|
// PCI Cache Line Size register
|
||||||
|
#define PCI_CACHELS_R ((uint16_t) 0x000c)
|
||||||
|
// PCI bar1 register
|
||||||
|
#define PCI_BAR1_R ((uint16_t) 0x0010)
|
||||||
|
// PCI bar2 register
|
||||||
|
#define PCI_BAR2_R ((uint16_t) 0x0014)
|
||||||
|
// PCI bar1 register
|
||||||
|
#define PCI_SUBID_R ((uint16_t) 0x002e)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e1000 register offsets
|
||||||
|
*/
|
||||||
|
// Device Control register
|
||||||
|
#define CTRL ((uint16_t) 0x0000)
|
||||||
|
// Device Status register
|
||||||
|
#define STATUS ((uint16_t) 0x0008)
|
||||||
|
// Eeprom Read register
|
||||||
|
#define EERD ((uint16_t) 0x0014)
|
||||||
|
// Interrupt Mask Clear register
|
||||||
|
#define IMC ((uint16_t) 0x00d8)
|
||||||
|
// Receive Control register
|
||||||
|
#define RCTL ((uint16_t) 0x0100)
|
||||||
|
// Receive Descriptor Base Address Low register
|
||||||
|
#define RDBAL ((uint16_t) 0x2800)
|
||||||
|
// Receive Descriptor Base Address High register
|
||||||
|
#define RDBAH ((uint16_t) 0x2804)
|
||||||
|
// Receive Descriptor Length register
|
||||||
|
#define RDLEN ((uint16_t) 0x2808)
|
||||||
|
// Receive Descriptor Head register
|
||||||
|
#define RDH ((uint16_t) 0x2810)
|
||||||
|
// Receive Descriptor Tail register
|
||||||
|
#define RDT ((uint16_t) 0x2818)
|
||||||
|
// Receive Delay Timer register
|
||||||
|
#define RDTR ((uint16_t) 0x2820)
|
||||||
|
// Transmit Control register
|
||||||
|
#define TCTL ((uint16_t) 0x0400)
|
||||||
|
// Transmit Descriptor Base Address Low register
|
||||||
|
#define TDBAL ((uint16_t) 0x3800)
|
||||||
|
// Transmit Descriptor Base Address High register
|
||||||
|
#define TDBAH ((uint16_t) 0x3804)
|
||||||
|
// Transmit Descriptor Length register
|
||||||
|
#define TDLEN ((uint16_t) 0x3808)
|
||||||
|
// Transmit Descriptor Head register
|
||||||
|
#define TDH ((uint16_t) 0x3810)
|
||||||
|
// Transmit Descriptor Tail register
|
||||||
|
#define TDT ((uint16_t) 0x3818)
|
||||||
|
// Receive Address Low register
|
||||||
|
#define RAL0 ((uint16_t) 0x5400)
|
||||||
|
// Receive Address High register
|
||||||
|
#define RAH0 ((uint16_t) 0x5404)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* useful def's
|
||||||
|
*/
|
||||||
|
#define rd08(a) ci_read_8((uint32_t *)(a))
|
||||||
|
#define rd16(a) ci_read_16((uint32_t *)(a))
|
||||||
|
#define rd32(a) ci_read_32((uint32_t *)(a))
|
||||||
|
#define wr08(a,v) ci_write_8((uint32_t *)(a), (v))
|
||||||
|
#define wr16(a,v) ci_write_16((uint32_t *)(a), (v))
|
||||||
|
#define wr32(a,v) ci_write_32((uint32_t *)(a), (v))
|
||||||
|
//#define printk snk_kernel_interface->print
|
||||||
|
//#define ms_delay snk_kernel_interface->ms_delay
|
||||||
|
|
||||||
|
#define BIT08(bit) ((uint8_t) 0x1 << (bit))
|
||||||
|
#define BIT16(bit) ((uint16_t) 0x1 << (bit))
|
||||||
|
#define BIT32(bit) ((uint32_t) 0x1 << (bit))
|
||||||
|
|
||||||
|
//#define mb() asm volatile("sync" ::: "memory");
|
||||||
|
|
||||||
|
extern net_driver_t *e1k_open(void);
|
||||||
|
extern void e1k_close(net_driver_t *driver);
|
||||||
|
extern int e1k_read(char *buf, int len);
|
||||||
|
extern int e1k_write(char *buf, int len);
|
||||||
|
extern int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id,
|
||||||
|
uint64_t baseaddr, char *mac_addr);
|
|
@ -0,0 +1,21 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (c) 2013 IBM Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the BSD License
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial implementation
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libe1k bindings for Forth - definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
cod(E1K-OPEN)
|
||||||
|
cod(E1K-CLOSE)
|
||||||
|
cod(E1K-READ)
|
||||||
|
cod(E1K-WRITE)
|
||||||
|
cod(E1K-MAC-SETUP)
|
Loading…
Reference in New Issue