metalsvm/drivers/net/rckemac.c

831 lines
28 KiB
C
Raw Permalink Normal View History

2011-06-27 11:40:37 +02:00
/*
* 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>
2011-09-01 13:02:08 -07:00
#include <lwip/tcpip.h>
2011-06-27 11:40:37 +02:00
#include <netif/etharp.h>
#include <net/rckemac.h>
2011-09-23 11:54:28 -07:00
/* 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
2011-06-27 11:40:37 +02:00
/* 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
2011-10-08 23:09:51 -07:00
#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
2011-06-27 11:40:37 +02:00
// 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
2011-10-08 23:09:51 -07:00
#endif
2011-06-27 11:40:37 +02:00
#define IRQ_STATUS 0xD000
#define IRQ_MASK 0xD200
#define IRQ_RESET 0xD400
2011-10-08 23:09:51 -07:00
#define IRQ_REQUEST 0xD600
2011-06-27 11:40:37 +02:00
#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)
2011-06-27 11:40:37 +02:00
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;
}
2011-06-27 11:40:37 +02:00
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;
2011-06-27 11:40:37 +02:00
/* check for over/underflow */
if (BUILTIN_EXPECT((p->tot_len < 20 /* IP header size */) || (p->tot_len > 1536), 0)) {
2011-10-04 11:39:53 -07:00
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_output: illegal packet length %d => drop\n", p->tot_len));
2011-06-27 11:40:37 +02:00
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);
2011-09-15 03:18:07 -07:00
//LWIP_DEBUGF(NETIF_DEBUG, ("TX packets: %d\n", packets));
2011-06-27 11:40:37 +02:00
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)
2011-06-27 11:40:37 +02:00
sum = rckemacif->tx_buffer_max - rckemacif->tx_write_offset + read_offset - 1;
else if (read_offset > rckemacif->tx_write_offset)
2011-06-27 11:40:37 +02:00
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;
2011-06-27 11:40:37 +02:00
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);
2011-06-27 11:40:37 +02:00
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));
2011-06-27 11:40:37 +02:00
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);
2011-06-27 11:40:37 +02:00
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));
2011-06-27 11:40:37 +02:00
i = 0;
if (sz < q->len) {
memcpy_to_nc((uint8_t*) addr, q->payload + sz, q->len - sz);
2011-06-27 11:40:37 +02:00
i = q->len - sz;
}
for(q=q->next; (q != 0); q = q->next) {
memcpy_to_nc(((uint8_t*) addr) + i, q->payload, q->len);
2011-06-27 11:40:37 +02:00
i += q->len;
}
rest = bytes_left % 32;
if (rest != 0)
rest = 32 - rest;
//LWIP_DEBUGF(NETIF_DEBUG, ("Rest is %d\n", rest));
2011-06-27 11:40:37 +02:00
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;
2011-06-27 11:40:37 +02:00
/* set new write offset */
2011-09-15 03:18:07 -07:00
//LWIP_DEBUGF(NETIF_DEBUG, ("Update tx write offset: %d (read offset %d)\n", rckemacif->tx_write_offset, read_offset));
2011-06-27 11:40:37 +02:00
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;
2011-08-27 14:28:59 -07:00
unsigned short read_offset = rckemacif->rx_read_offset;
volatile void *addr = NULL;
uint16_t i, length = 0;
2011-09-14 23:41:34 -07:00
struct pbuf *p = NULL;
2011-06-27 11:40:37 +02:00
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;
2011-08-27 14:28:59 -07:00
goto rxDone;
2011-06-27 11:40:37 +02:00
}
2011-08-27 14:28:59 -07:00
again:
CL1INV; // invalidate L1 cache entries of the receiver buffers
2011-08-27 14:28:59 -07:00
read_offset++;
if (read_offset < 1 || read_offset > rckemacif->rx_buffer_max) {
read_offset = 1;
}
addr = rckemacif->rx_buffer + read_offset * 32;
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
length = U16(addr);
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
// Check for over/underflow
2011-10-16 22:10:04 -07:00
if (BUILTIN_EXPECT((length < 20) || (length > 1536), 0)) {
2011-08-27 14:28:59 -07:00
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));
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
read_offset = write_offset;
2011-06-27 11:40:37 +02:00
#if 1
2011-08-27 14:28:59 -07:00
kprintf("Buffer:\n");
for (i = 0; i < 32; i++) {
kprintf("%2.2x ", ((char*)addr)[i] & 0xFF);
}
kprintf("\n");
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
kprintf("Buffer0:\n");
for (i = 0; i < 32; i++) {
kprintf("%2.2x ", ((char*)rckemacif->rx_buffer)[i] & 0xFF);
}
kprintf("\n");
2011-06-27 11:40:37 +02:00
#endif
2011-08-27 14:28:59 -07:00
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
goto rxDone;
}
2011-06-27 11:40:37 +02:00
#if ETH_PAD_SIZE
2011-08-27 14:28:59 -07:00
length += ETH_PAD_SIZE; /* allow room for Ethernet padding */
2011-06-27 11:40:37 +02:00
#endif
2011-08-27 14:28:59 -07:00
//LWIP_DEBUGF(NETIF_DEBUG, ("length %u, read_offset %u, write_offset %u\n", length, read_offset, write_offset));
2011-06-27 11:40:37 +02:00
2011-08-27 14:28:59 -07:00
p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
2011-10-16 22:10:04 -07:00
if (BUILTIN_EXPECT(p != NULL, 1)) {
2011-06-27 11:40:37 +02:00
#if ETH_PAD_SIZE
2011-08-27 14:28:59 -07:00
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
2011-06-27 11:40:37 +02:00
#endif
2011-08-27 14:28:59 -07:00
if (read_offset < write_offset) {
unsigned int counter;
2011-08-27 14:28:59 -07:00
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;
2011-08-27 14:28:59 -07:00
} else {
int rest;
int bytesLeft = length;
int bytesToCopy = length;
int counter = 0;
2011-08-27 14:28:59 -07:00
/* 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;
2011-08-27 14:28:59 -07:00
}
2011-06-27 11:40:37 +02:00
out:
2011-08-27 14:28:59 -07:00
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);
}
2011-08-27 14:28:59 -07:00
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;
2011-08-27 14:28:59 -07:00
}
read_offset = CLINE_PACKETS(bytesLeft);
} else {
read_offset += CLINE_PACKETS(p->tot_len + 2) - 1;
2011-08-27 14:28:59 -07:00
}
}
2011-06-27 11:40:37 +02:00
#if ETH_PAD_SIZE
2011-08-27 14:28:59 -07:00
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
2011-06-27 11:40:37 +02:00
#endif
2011-08-27 14:28:59 -07:00
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);
}
2011-06-27 11:40:37 +02:00
rxDone:
2011-08-27 14:28:59 -07:00
/* 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;
2011-09-14 23:41:34 -07:00
if (p) {
netif->input(p, netif);
2011-09-14 23:41:34 -07:00
p = NULL;
}
if (read_offset != write_offset)
goto again;
/* Enable eMAC interrupt */
2011-10-08 23:09:51 -07:00
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;
2011-06-27 11:40:37 +02:00
}
/* 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);
}
2011-10-08 23:09:51 -07:00
void rckemacif_handler(struct state* s, uint32_t status)
2011-06-27 11:40:37 +02:00
{
unsigned int write_offset;
rckemacif_t* rckemacif = mynetif->state;
2011-10-08 23:09:51 -07:00
if (!(status & (1 << rckemacif->num_emac)))
2011-06-27 11:40:37 +02:00
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) {
2011-10-08 23:09:51 -07:00
/* 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
2011-06-27 11:40:37 +02:00
}
}
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"));
2011-06-27 11:40:37 +02:00
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));
2011-06-27 11:40:37 +02:00
rckemacif->core = core;
/* allocate the receive buffer */
#ifdef RX_CACHING
rckemacif->rx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_MPE);
#else
2011-06-27 11:40:37 +02:00
rckemacif->rx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_NO_CACHE);
#endif
2011-06-27 11:40:37 +02:00
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);
2011-06-27 11:40:37 +02:00
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)
*/
2011-10-09 13:02:18 -07:00
tmp = z == 0 ? ReadConfigReg(CRB_OWN + LUT0) : ReadConfigReg(CRB_OWN + LUT1);
2011-06-27 11:40:37 +02:00
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);
2011-06-27 11:40:37 +02:00
/* 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 */
2011-10-10 22:01:38 +02:00
*((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))));
2011-06-27 11:40:37 +02:00
/*
* 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;
2011-06-27 11:40:37 +02:00
/* 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;
2011-06-27 11:40:37 +02:00
return ERR_OK;
}
#endif