metalsvm/drivers/net/rckemac.c
Stefan Lankes 2f64a5c772 replace tcpip_input by ethernet_input/ip_input
All MetalSVM drivers guarantee that the input function will be called in the context of the tcpip thread.
Therefore, we are able to use ethernet_input/ip_input instead of tcpip_input
2012-09-11 10:36:29 +02:00

830 lines
28 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2011 Stefan Lankes, Chair for Operating Systems,
* RWTH Aachen University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of MetalSVM.
*/
/*
* This eMAC driver required at least sccKit 1.4.0 and based on
* the eMAC Driver Description (section 9.6.5) in the
* SccKit 1.4.0 Users Guide (Revision 0.92 Part 9).
*/
#include <metalsvm/stddef.h>
#include <metalsvm/stdio.h>
#include <metalsvm/string.h>
#include <metalsvm/processor.h>
#include <metalsvm/mailbox.h>
#include <metalsvm/page.h>
#include <metalsvm/time.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/RCCE.h>
#include <asm/RCCE_lib.h>
#include <asm/SCC_API.h>
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
#include <lwip/sys.h>
#include <lwip/stats.h>
#include <lwip/netif.h>
#include <lwip/tcpip.h>
#include <netif/etharp.h>
#include <net/rckemac.h>
/* enables the cache for the receive buffer */
#define RX_CACHING 1
#ifdef RX_CACHING
#define CL1INV asm volatile ( ".byte 0x0f; .byte 0x0a;\n" ) // CL1FLUSHMB
#else
#define CL1INV
#endif
/* Limits */
#define BUFFER_ORDER 9
#define BUFFER_NUM (1 << BUFFER_ORDER)
#define BUFFER_SIZE (BUFFER_NUM * PAGE_SIZE)
#define EMAC0 0x01
#define EMAC1 0x02
#define EMAC2 0x04
#define EMAC3 0x08
#define EMAC_IPCONF 0x3200
#define EMAC_RX_CONTROL 0x9000
#define EMAC_TX_CONTROL 0x9900
/* IP configuration - offsets */
#define CONFIG_FLOW_CONTROL_ADD 0xC0
#define TRANSMITTER_ADDRESS 0x80
#define RECEIVER1_ADDRESS 0x40
#define CONFIG_ADD 0x100
#define ADD_FILTER_MOD 0x190
/* EMAC RX */
#define EMAC_RX_BUFFER_START_ADDRESS 0x0000
#define EMAC_RX_BUFFER_READ_OFFSET 0x0100
#define EMAC_RX_BUFFER_WRITE_OFFSET 0x0200
#define EMAC_RX_BUFFER_SIZE 0x0300
#define EMAC_RX_BUFFER_THRESHOLD 0x0400
#define EMAC_RX_MODE 0x0500
#define EMAC_RX_NETWORK_PORT_MAC_ADDRESS_HI 0x0600
#define EMAC_RX_NETWORK_PORT_MAC_ADDRESS_LO 0x0700
#define EMAC_RX_NETWORK_PORT_ENABLE 0x0800
/* EMAC TX */
#define EMAC_TX_BUFFER_START_ADDRESS 0x0000
#define EMAC_TX_BUFFER_READ_OFFSET 0x0100
#define EMAC_TX_BUFFER_WRITE_OFFSET 0x0200
#define EMAC_TX_BUFFER_SIZE 0x0300
#define EMAC_TX_MODE 0x0400
#define EMAC_TX_NETWORK_PORT_ENABLE 0x0500
#if 1
// Using of LVT0 as interrupt line
#define EMAC_IRQ_MASK 0x00000002
#define EMAC_IRQ_NR 4
#define EMAC_LVT APIC_LVT0
#define EMAC_IRQ_CONFIG 0
#else
// Using of LVT1 as interrupt line
#define EMAC_IRQ_MASK 0x00000001
#define EMAC_IRQ_NR 3
#define EMAC_LVT APIC_LVT1
#define EMAC_IRQ_CONFIG 1
#endif
#define IRQ_STATUS 0xD000
#define IRQ_MASK 0xD200
#define IRQ_RESET 0xD400
#define IRQ_REQUEST 0xD600
#define IRQ_CONFIG 0xD800
/* Cache line wrappers */
#define CLINE_SHIFT 5
#define CLINE_SIZE (1UL << CLINE_SHIFT)
#define CLINE_MASK (~(CLINE_SIZE - 1))
#define CLINE_ALIGN(_x) (((_x) + CLINE_SIZE - 1) & CLINE_MASK)
#define CLINE_PACKETS(_x) (CLINE_ALIGN(_x) >> CLINE_SHIFT)
/* Read 16bit from buffer */
#define U16(_addr) (256 * (*((uint8_t*) (_addr + 1))) + (*((uint8_t*)(_addr))))
#define MAC_ADDRESS 0x00454D414331ULL
#define MAC_HI(_x) ((((_x) >> 32)) & 0xFFFF)
#define MAC_LO(_x) (((_x) ) & 0xFFFFFFFF)
#define MIN(a, b) (a) < (b) ? (a) : (b)
static struct netif* mynetif;
inline static void* memcpy_from_nc(void *dest, const void *src, size_t count)
{
int32_t h, i, j, k, l, m;
asm volatile ("cld;\n\t"
"1: cmpl $0, %%eax ; je 3f\n\t"
"movl (%%edi), %%edx\n\t"
"cmpl $1, %%eax ; je 2f\n\t"
"movl 32(%%edi), %%edx\n\t"
"2: movl 0(%%esi), %%ecx\n\t"
"movl 4(%%esi), %%edx\n\t"
"movl %%ecx, 0(%%edi)\n\t"
"movl %%edx, 4(%%edi)\n\t"
"movl 8(%%esi), %%ecx\n\t"
"movl 12(%%esi), %%edx\n\t"
"movl %%ecx, 8(%%edi)\n\t"
"movl %%edx, 12(%%edi)\n\t"
"movl 16(%%esi), %%ecx\n\t"
"movl 20(%%esi), %%edx\n\t"
"movl %%ecx, 16(%%edi)\n\t"
"movl %%edx, 20(%%edi)\n\t"
"movl 24(%%esi), %%ecx\n\t"
"movl 28(%%esi), %%edx\n\t"
"movl %%ecx, 24(%%edi)\n\t"
"movl %%edx, 28(%%edi)\n\t"
"addl $32, %%esi\n\t"
"addl $32, %%edi\n\t"
"dec %%eax ; jmp 1b\n\t"
"3: movl %%ebx, %%ecx\n\t"
"movl (%%edi), %%edx\n\t"
"andl $31, %%ecx\n\t"
"rep ; movsb\n\t" : "=&a"(h), "=&D"(i), "=&S"(j), "=&b"(k), "=&c"(l), "=&d"(m)
: "0"(count / 32), "1"(dest), "2"(src), "3"(count) : "memory","cc");
return dest;
}
inline static void* memcpy_to_nc(void* dest, const void *src, size_t count)
{
int32_t i, j, k;
asm volatile (
"cld; rep movsl\n\t"
"movl %4, %%ecx\n\t"
"andl $3, %%ecx\n\t"
"rep movsb\n\t"
: "=&c"(i), "=&D"(j), "=&S"(k)
: "0"(count/4), "g"(count), "1"(dest), "2"(src) : "memory","cc");
return dest;
}
static int read_emac(int num_emac, int offset, int core)
{
int ret;
ret = *((volatile int*) (FPGA_BASE + num_emac * 0x1000 + offset + core * 4));
/* no error: read twice, as xilinx ip need some time... */
ret = *((volatile int*) (FPGA_BASE + num_emac * 0x1000 + offset + core * 4));
return ret;
}
static void write_emac(int num_emac, int offset, int core, int value)
{
*((volatile int*) (FPGA_BASE + num_emac * 0x1000 + offset + core * 4)) = value;
}
/*
* @return error code
* - ERR_OK: packet transferred to hardware
* - ERR_CONN: no link or link failure
* - ERR_IF: could not transfer to link (hardware buffer full?)
*/
static err_t rckemacif_output(struct netif* netif, struct pbuf* p)
{
rckemacif_t* rckemacif = netif->state;
uint32_t i;
struct pbuf *q;
void *addr;
uint16_t read_offset;
int rest;
int packets;
int sum = 0;
int chance = 20;
/* check for over/underflow */
if (BUILTIN_EXPECT((p->tot_len < 20 /* IP header size */) || (p->tot_len > 1536), 0)) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_output: illegal packet length %d => drop\n", p->tot_len));
return ERR_IF;
}
rckemacif->tx_write_offset++;
/* check if we need to wrap */
if (rckemacif->tx_write_offset > rckemacif->tx_buffer_max)
rckemacif->tx_write_offset = 1;
packets = CLINE_PACKETS(p->tot_len + 2);
//LWIP_DEBUGF(NETIF_DEBUG, ("TX packets: %d\n", packets));
read_offset = read_emac(rckemacif->num_emac, EMAC_TX_CONTROL+EMAC_TX_BUFFER_READ_OFFSET, rckemacif->core);
#if 1
again:
if (read_offset < rckemacif->tx_write_offset)
sum = rckemacif->tx_buffer_max - rckemacif->tx_write_offset + read_offset - 1;
else if (read_offset > rckemacif->tx_write_offset)
sum = read_offset - rckemacif->tx_write_offset - 1;
if (sum < packets) {
LWIP_DEBUGF(NETIF_DEBUG, ("Warning: not enough space available, retrying...\n"));
chance--;
if (chance < 0)
return ERR_MEM;
goto again;
}
#endif
addr = rckemacif->tx_buffer + rckemacif->tx_write_offset * 32;
/* Set frame length */
((uint8_t*)addr)[0] = p->tot_len % 256;
((uint8_t*)addr)[1] = p->tot_len / 256;
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
if (rckemacif->tx_write_offset + packets - 1 <= rckemacif->tx_buffer_max) {
/*
* q traverses through linked list of pbuf's
* This list MUST consist of a single packet ONLY
*/
for (q=p, i=0; q!=0; q=q->next) {
memcpy_to_nc(((uint8_t*)addr) + 2 + i, q->payload, q->len);
i += q->len;
}
/* increment write ptr */
rckemacif->tx_write_offset += packets - 1;
} else {
/* wrap in offsets. first copy to the end, second at the starting
* point
*/
int bytes_left = p->tot_len;
int bytes_to_copy = (rckemacif->tx_buffer_max - rckemacif->tx_write_offset + 1) * 32 - 2;
int sz = 0;
if (bytes_left < bytes_to_copy)
bytes_to_copy = bytes_left;
//LWIP_DEBUGF(NETIF_DEBUG, ("special case: copy last %d bytes\n", bytes_to_copy));
q = p; i = 0;
while ((q != 0) && (i < bytes_to_copy)) {
sz = MIN(bytes_to_copy-i, q->len);
memcpy_to_nc(((uint8_t*) addr) + 2 + i, q->payload, sz);
bytes_left -= sz;
i += sz;
if (i < bytes_to_copy)
q = q->next;
}
if (bytes_left != 0) {
rckemacif->tx_write_offset = 1;
addr = rckemacif->tx_buffer + 32;
//LWIP_DEBUGF(NETIF_DEBUG, ("special case: copy remaining %d bytes\n", bytes_left));
i = 0;
if (sz < q->len) {
memcpy_to_nc((uint8_t*) addr, q->payload + sz, q->len - sz);
i = q->len - sz;
}
for(q=q->next; (q != 0); q = q->next) {
memcpy_to_nc(((uint8_t*) addr) + i, q->payload, q->len);
i += q->len;
}
rest = bytes_left % 32;
if (rest != 0)
rest = 32 - rest;
//LWIP_DEBUGF(NETIF_DEBUG, ("Rest is %d\n", rest));
rckemacif->tx_write_offset += CLINE_PACKETS(bytes_left + rest) - 1;
}
}
*((volatile int*) rckemacif->tx_buffer) = 2;
// flush write combining buffers
*((int*)RCCE_fool_write_combine_buffer) = 1;
/* set new write offset */
//LWIP_DEBUGF(NETIF_DEBUG, ("Update tx write offset: %d (read offset %d)\n", rckemacif->tx_write_offset, read_offset));
write_emac(rckemacif->num_emac, EMAC_TX_CONTROL+EMAC_TX_BUFFER_WRITE_OFFSET, rckemacif->core, rckemacif->tx_write_offset);
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
static void rckemacif_rx_handler(struct netif* netif, unsigned int write_offset)
{
rckemacif_t* rckemacif = netif->state;
unsigned short read_offset = rckemacif->rx_read_offset;
volatile void *addr = NULL;
uint16_t i, length = 0;
struct pbuf *p = NULL;
struct pbuf* q;
if (write_offset > rckemacif->rx_buffer_max) {
LWIP_DEBUGF(NETIF_DEBUG, ("Warning, write offset > buffer max!! (%d > %d)\n", write_offset, rckemacif->rx_buffer_max));
read_offset = 1;
goto rxDone;
}
again:
CL1INV; // invalidate L1 cache entries of the receiver buffers
read_offset++;
if (read_offset < 1 || read_offset > rckemacif->rx_buffer_max) {
read_offset = 1;
}
addr = rckemacif->rx_buffer + read_offset * 32;
length = U16(addr);
// Check for over/underflow
if (BUILTIN_EXPECT((length < 20) || (length > 1536), 0)) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_rx_handler(): illegal packet length %d => drop\n", length));
LWIP_DEBUGF(NETIF_DEBUG, ("start read at %d; write_offset at %d; addr: %p, packet len: %d\n", read_offset, write_offset, addr, length));
read_offset = write_offset;
#if 1
kprintf("Buffer:\n");
for (i = 0; i < 32; i++) {
kprintf("%2.2x ", ((char*)addr)[i] & 0xFF);
}
kprintf("\n");
kprintf("Buffer0:\n");
for (i = 0; i < 32; i++) {
kprintf("%2.2x ", ((char*)rckemacif->rx_buffer)[i] & 0xFF);
}
kprintf("\n");
#endif
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
goto rxDone;
}
#if ETH_PAD_SIZE
length += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
//LWIP_DEBUGF(NETIF_DEBUG, ("length %u, read_offset %u, write_offset %u\n", length, read_offset, write_offset));
p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
if (BUILTIN_EXPECT(p != NULL, 1)) {
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
if (read_offset < write_offset) {
unsigned int counter;
for (q=p, counter=0; q!=NULL; q=q->next) {
memcpy_from_nc((uint8_t*) q->payload, (uint8_t*)addr + 2 + counter, q->len);
counter += q->len;
}
read_offset += CLINE_PACKETS(p->tot_len + 2) - 1;
} else {
int rest;
int bytesLeft = length;
int bytesToCopy = length;
int counter = 0;
/* rest to the end of buffer - 2 bytes length information */
rest = (rckemacif->rx_buffer_max - read_offset + 1) * 32 - 2;
if (length > rest)
bytesToCopy = rest;
//LWIP_DEBUGF(NETIF_DEBUG, ("bytes to copy: %d, bytesLeft: %d\n", bytesToCopy, bytesLeft));
q = p;
i = 0;
while ((q != NULL) && (counter < bytesToCopy)) {
i = MIN(q->len, bytesToCopy - counter);
memcpy_from_nc(q->payload, (uint8_t*) addr + 2 + counter, i);
counter += i;
if (counter >= bytesToCopy)
goto out;
else
q = q->next;
}
out:
bytesLeft -= bytesToCopy;
if (bytesLeft != 0) {
addr = rckemacif->rx_buffer + 0x20;
counter = 0;
//LWIP_DEBUGF(NETIF_DEBUG, ("copying from %p, left: %d (%x)\n", addr, bytesLeft, ((uint8_t*)addr)[0]));
if (i < q->len) {
counter = MIN(q->len - i, bytesLeft);
memcpy_from_nc((uint8_t*)q->payload + i, (uint8_t*) addr, counter);
}
for(q=q->next; (q!=NULL) && (counter < bytesLeft); q=q->next) {
i = MIN(q->len, bytesLeft - counter);
memcpy_from_nc((uint8_t*)q->payload, (uint8_t*)addr + counter, i);
counter += i;
}
read_offset = CLINE_PACKETS(bytesLeft);
} else {
read_offset += CLINE_PACKETS(p->tot_len + 2) - 1;
}
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.recv);
} else {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_rx_inthandler: not enough memory!\n"));
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
}
rxDone:
/* set new read pointer */
//LWIP_DEBUGF(NETIF_DEBUG, ("Update rx read offset: %d\n", read_offset));
write_emac(rckemacif->num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_READ_OFFSET, rckemacif->core, read_offset);
rckemacif->rx_read_offset = read_offset;
if (p) {
netif->input(p, netif);
p = NULL;
}
if (read_offset != write_offset)
goto again;
/* Enable eMAC interrupt */
unsigned int tmp = *((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4));
// read twice to be sure
tmp = *((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4));
*((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)) = tmp & ~(1 << rckemacif->num_emac);
rckemacif->polling = 0;
}
/* this function is called in the context of the tcpip thread */
static void rckemacif_poll(void* ctx)
{
unsigned int write_offset = (unsigned int) ctx;
rckemacif_rx_handler(mynetif, write_offset);
}
void rckemacif_handler(struct state* s, uint32_t status)
{
unsigned int write_offset;
rckemacif_t* rckemacif = mynetif->state;
if (!(status & (1 << rckemacif->num_emac)))
return;
/* check for updated write offset */
write_offset = *((volatile unsigned int*) (rckemacif->rx_buffer)) & 0xFFFF;
//write_offset = read_emac(rckemacif->num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_WRITE_OFFSET, rckemacif->core);
if ((write_offset != 0) && (rckemacif->rx_read_offset != write_offset) && !rckemacif->polling) {
#if NO_SYS
rckemacif_poll((void*) write_offset);
#else
if (tcpip_callback_with_block(rckemacif_poll, (void*) write_offset, 0) == ERR_OK) {
/* Mask eMAC interrupt */
unsigned int tmp = *((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4));
// read twice to be sure
tmp = *((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4));
*((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)) = tmp | (1 << rckemacif->num_emac);
rckemacif->polling = 1;
} else {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_handler: unable to send a poll request to the tcpip thread\n"));
}
#endif
}
}
err_t rckemacif_init(struct netif* netif)
{
rckemacif_t* rckemacif;
int num_emac;
int macPorts;
int i, tmp, x, y, z, core;
uint64_t tile_offset;
uint16_t write_offset;
uint16_t read_offset;
int mode;
int subdest;
int route;
LWIP_DEBUGF(NETIF_DEBUG, ("Initialize eMAC device...\n"));
LWIP_ASSERT("netif != NULL", (netif != NULL));
// Find out who I am...
tmp = ReadConfigReg(CRB_OWN+MYTILEID);
x = (tmp>>3) & 0x0f; // bits 06:03
y = (tmp>>7) & 0x0f; // bits 10:07
z = (tmp ) & 0x07; // bits 02:00
core = 12 * y + 2 * x + z;
rckemacif = kmalloc(sizeof(rckemacif_t));
if (!rckemacif) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: out of memory\n"));
return ERR_MEM;
}
memset(rckemacif, 0x00, sizeof(rckemacif_t));
rckemacif->core = core;
/* allocate the receive buffer */
#ifdef RX_CACHING
rckemacif->rx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_MPE);
#else
rckemacif->rx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_NO_CACHE);
#endif
if (!(rckemacif->rx_buffer)) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: out of memory\n"));
kfree(rckemacif, sizeof(rckemacif_t));
return ERR_MEM;
}
memset(rckemacif->rx_buffer, 0x00, 0x20);
memset(rckemacif->rx_buffer + 0x20, 0xDA, BUFFER_SIZE - 0x20);
rckemacif->rx_buffer_max = CLINE_PACKETS(BUFFER_SIZE) - 1;
/* allocate the send buffers */
rckemacif->tx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_NO_CACHE|MAP_WT|MAP_MPE);
if (!(rckemacif->tx_buffer)) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: out of memory\n"));
kfree(rckemacif->rx_buffer, BUFFER_SIZE);
kfree(rckemacif, sizeof(rckemacif_t));
return ERR_MEM;
}
memset(rckemacif->tx_buffer, 0x00, 0x20);
memset(rckemacif->tx_buffer + 0x20, 0xDA, BUFFER_SIZE - 0x20);
rckemacif->tx_buffer_max = CLINE_PACKETS(BUFFER_SIZE) - 1;
netif->state = rckemacif;
/* Depending on core location read own private data
* (offset, subdest, route)
*/
tmp = z == 0 ? ReadConfigReg(CRB_OWN + LUT0) : ReadConfigReg(CRB_OWN + LUT1);
tile_offset = (uint64_t)((uint64_t) tmp & 0x3FF) << 24;
subdest = (tmp >> 10) & 0x07;
route = (tmp >> 13) & 0xFF;
mode = (subdest << 8) + route;
LWIP_DEBUGF(NETIF_DEBUG, ("tile_offset = 0x%llx\n", tile_offset));
/* get fpga/sccKit port settings */
tmp = *((volatile int*)(FPGA_BASE + 0x822C));
tmp = *((volatile int*)(FPGA_BASE + 0x822C));
macPorts = ((tmp >> 9 ) & 0xFF);
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: eMAC0: %s eMAC1: %s eMAC2: %s eMAC3: %s\n",
(macPorts & EMAC0) != 0 ? "present" : "-",
(macPorts & EMAC1) != 0 ? "present" : "-",
(macPorts & EMAC2) != 0 ? "present" : "-",
(macPorts & EMAC3) != 0 ? "present" : "-"));
// determine device and emac number
num_emac=0;
while (((macPorts & (1 << num_emac)) == 0) && (num_emac < 4))
num_emac++;
if (num_emac >= 4)
return ERR_ARG;
mynetif = netif;
rckemacif->num_emac = num_emac;
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: used eMAC device %d\n", num_emac));
tmp = read_emac(num_emac, EMAC_IPCONF+TRANSMITTER_ADDRESS, 0);
tmp = read_emac(num_emac, EMAC_IPCONF+RECEIVER1_ADDRESS, 0);
if (core == 0) {
/* Only core 0 initialize the xilinx port */
int flow_control = 0;
int transmitter_addr = 0;
int receiver1_addr = 0;
int config_add = 0;
int add_filter_mod = 0;
/* Disable tx and rx flow control of eMAC */
LWIP_DEBUGF(NETIF_DEBUG, ("Disabling tx/rx flow control of eMAC%d\n", num_emac));
flow_control = read_emac(num_emac, EMAC_IPCONF+CONFIG_FLOW_CONTROL_ADD, 0);
/* Set top 3 bits of the flow control configuration to zero,
* therefore disabling tx and rx flow control
*/
flow_control &= 0x7FFFFFF;
write_emac(num_emac, EMAC_IPCONF+CONFIG_FLOW_CONTROL_ADD, 0, flow_control);
/* Sanity check */
flow_control = read_emac(num_emac, EMAC_IPCONF+CONFIG_FLOW_CONTROL_ADD, 0);
LWIP_DEBUGF(NETIF_DEBUG, (" CONFIG_FLOW_CONTROL_ADD set: 0x%x\n", flow_control));
/* Setting the tx configuration bit to enable the transmitter and
* set to full duplex mode.
*/
LWIP_DEBUGF(NETIF_DEBUG, ("Setting rx configuration of eMAC%d\n", num_emac));
transmitter_addr = read_emac(num_emac, EMAC_IPCONF+TRANSMITTER_ADDRESS, 0);
/* Now set the relevant bits and write back into the register:
* 26 (half duplex) = 0, 28 (transmit enable) = 1, 31 (reset) = 0
*/
transmitter_addr &= ~(1 << 31);
transmitter_addr &= ~(1 << 26);
transmitter_addr |= (1 << 28);
write_emac(num_emac, EMAC_IPCONF+TRANSMITTER_ADDRESS, 0, transmitter_addr);
transmitter_addr = read_emac(num_emac, EMAC_IPCONF+TRANSMITTER_ADDRESS, 0);
LWIP_DEBUGF(NETIF_DEBUG, (" TRANSMITTER_ADDRESS set: %x\n", transmitter_addr));
/* Setting the rx configuration bit to enable the transmitter and
* set to full duplex mode.
*/
LWIP_DEBUGF(NETIF_DEBUG, ("Setting IP configuration of EMAC%d\n", num_emac));
/* Read the current config value from the register */
receiver1_addr = read_emac(num_emac, EMAC_IPCONF+RECEIVER1_ADDRESS, 0);
/* Now set the relevant bits and write back into the register:
* 25 = 1, 26 = 0, 28 = 1, 31 = 0
*/
/* Length/Type Error Check Disable */
receiver1_addr |= (1 << 25);
/* Disable Half Duplex => Full Duplex */
receiver1_addr &= ~(1 << 26);
/* Receiver enable */
receiver1_addr |= (1 << 28);
/* Reset */
receiver1_addr &= ~(1 << 31);
write_emac(num_emac, EMAC_IPCONF+RECEIVER1_ADDRESS, 0, receiver1_addr);
receiver1_addr = read_emac(num_emac, EMAC_IPCONF+RECEIVER1_ADDRESS, 0);
LWIP_DEBUGF(NETIF_DEBUG, (" RECEIVER1_ADDRESS set: %x\n", receiver1_addr));
/* Setting the speed to eMAC to 1Gb/s */
LWIP_DEBUGF(NETIF_DEBUG, ("Setting speed of EMAC%d to 1Gb/s\n", num_emac));
/* Read the current config value from register */
config_add = read_emac(num_emac, EMAC_IPCONF+CONFIG_ADD, 0);
/* Now set the relevant bits and write back into the register:
* 31 = 1, 30 = 0
*/
/* MAC Speed Configuration: 00 - 10Mbps, 01 - 100Mbps, 10 - 1Gbps */
config_add |= (1 << 31);
config_add &= ~(1 << 30);
write_emac(num_emac, EMAC_IPCONF+CONFIG_ADD, 0, config_add);
config_add = read_emac(num_emac, EMAC_IPCONF+CONFIG_ADD, 0);
LWIP_DEBUGF(NETIF_DEBUG, (" CONFIG_ADD set: %x\n", config_add));
/* Read the current config addr filter mode */
add_filter_mod = read_emac(num_emac, EMAC_IPCONF+ADD_FILTER_MOD, 0);
/* Not set the relevant bits and write back into the register:
* 31 (promiscuous mode) = 1 not working, but thats ok!
*/
add_filter_mod |= (1 << 31);
write_emac(num_emac, EMAC_IPCONF+ADD_FILTER_MOD, 0, add_filter_mod);
add_filter_mod = read_emac(num_emac, EMAC_IPCONF+ADD_FILTER_MOD, 0);
LWIP_DEBUGF(NETIF_DEBUG, (" ADD_FILTER_MOD set: %x\n", add_filter_mod));
}
RCCE_barrier(&RCCE_COMM_WORLD);
/* Start address */
LWIP_DEBUGF(NETIF_DEBUG, (" RX Buffer %p (%lx phys)\n", rckemacif->rx_buffer, virt_to_phys((uint32_t)rckemacif->rx_buffer)));
/**** Receiver configuration ****/
uint64_t addr_offset = (tile_offset + (uint64_t) virt_to_phys((uint32_t) rckemacif->rx_buffer)) >> 5;
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_START_ADDRESS, core, (uint32_t) addr_offset);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Buffer set to @%x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_START_ADDRESS, core)));
/* Get buffer write offset */
write_offset = read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_WRITE_OFFSET, core);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Buffer write offset at: %d\n", write_offset));
/* Set buffer read offset to write offset */
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_READ_OFFSET, core, write_offset);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Buffer read offset set to: %d\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_READ_OFFSET, core)));
rckemacif->rx_read_offset = write_offset;
/* Size */
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_SIZE, core, rckemacif->rx_buffer_max);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Size set to %d\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_SIZE, core)));
/* Threshold */
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_THRESHOLD, core, 0x01);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Threshold set to %x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_THRESHOLD, core)));
/* Route */
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_MODE, core, (z << 24) | (((y << 4) | x) << 16) | mode);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Mode set to %x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_MODE, core)));
// determine mac address
uint32_t mac1 = *((volatile uint32_t*)(FPGA_BASE+0x7E00));
uint32_t mac2 = *((volatile uint32_t*)(FPGA_BASE+0x7E04));
uint64_t mac = (((unsigned long long)mac1) << 32) + (unsigned long long) mac2;
if (mac == 0x00)
mac = MAC_ADDRESS;
/* Calculate mac address of core depending on selected emac device */
mac = mac + (1 << num_emac) * 0x100 + core;
for (i=0; i<6; i++)
mynetif->hwaddr[5-i] = (mac >> (i*8)) & 0xFF;
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: MAC address "));
for (i=0; i<6; i++)
LWIP_DEBUGF(NETIF_DEBUG, ("%02x ", mynetif->hwaddr[i]));
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_MAC_ADDRESS_HI, core, MAC_HI(mac));
LWIP_DEBUGF(NETIF_DEBUG, (" MAC1 set to %x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_MAC_ADDRESS_HI, core)));
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_MAC_ADDRESS_LO, core, MAC_LO(mac));
LWIP_DEBUGF(NETIF_DEBUG, (" MAC2 set to %x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_MAC_ADDRESS_LO, core)));
/* Activate network port by setting enable bit */
write_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_ENABLE, core, 0x01);
LWIP_DEBUGF(NETIF_DEBUG, (" RX Port enable set to %x\n", read_emac(num_emac, EMAC_RX_CONTROL + EMAC_RX_NETWORK_PORT_ENABLE, core)));
/**** Transfer configuration ****/
/* Start address */
LWIP_DEBUGF(NETIF_DEBUG, (" TX Buffer %p (%lx phys)\n", rckemacif->tx_buffer, virt_to_phys((uint32_t)rckemacif->tx_buffer)));
write_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_START_ADDRESS, core, (uint32_t) (((uint64_t) virt_to_phys((uint32_t)rckemacif->tx_buffer) + tile_offset) >> 5));
LWIP_DEBUGF(NETIF_DEBUG, (" TX Buffer set to @%x\n", read_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_START_ADDRESS, core)));
/* Get buffer read offset */
read_offset = read_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_READ_OFFSET, core);
LWIP_DEBUGF(NETIF_DEBUG, (" TX Buffer read offset at: %d\n", read_offset));
/* Set buffer write offset to read offset */
write_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_WRITE_OFFSET, core, read_offset);
LWIP_DEBUGF(NETIF_DEBUG, (" TX Buffer write offset set to: %d\n", read_emac(num_emac, EMAC_TX_CONTROL+ EMAC_TX_BUFFER_WRITE_OFFSET, core)));
rckemacif->tx_write_offset = read_offset;
/* Size */
write_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_SIZE, core, rckemacif->tx_buffer_max);
LWIP_DEBUGF(NETIF_DEBUG, (" TX Size set to %d\n", read_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_BUFFER_SIZE, core)));
/* Route */
write_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_MODE, core, mode);
LWIP_DEBUGF(NETIF_DEBUG, (" TX Mode set to %x\n", read_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_MODE, core)));
/* Activate network port by setting enable bit */
write_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_NETWORK_PORT_ENABLE, core, 0x01);
LWIP_DEBUGF(NETIF_DEBUG, (" TX Port enable set to %x\n", read_emac(num_emac, EMAC_TX_CONTROL + EMAC_TX_NETWORK_PORT_ENABLE, core)));
/* Enable interrupt */
*((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + core * 8)) &= ~(1 << num_emac);
//*((volatile unsigned int*) (FPGA_BASE + IRQ_CONFIG + core * 4)) = EMAC_IRQ_CONFIG;
LWIP_DEBUGF(NETIF_DEBUG, (" IRQ_MASK set to 0x%x\n", *((volatile unsigned int*) (FPGA_BASE + IRQ_MASK + core * 8))));
//LWIP_DEBUGF(NETIF_DEBUG, (" IRQ_CONFIG set to 0x%x\n", *((volatile unsigned int*) (FPGA_BASE + IRQ_CONFIG + core * 8))));
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 1000 /* speed */);
/* administrative details */
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->num = 0;
/* downward functions */
netif->output = etharp_output;
netif->linkoutput = rckemacif_output;
/* maximum transfer unit */
netif->mtu = 1500;
/* broadcast capability */
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
/* hardware address length */
netif->hwaddr_len = 6;
rckemacif->ethaddr = (struct eth_addr *)netif->hwaddr;
// flush write combining buffers
*(int *)RCCE_fool_write_combine_buffer = 1;
return ERR_OK;
}
#endif