metalsvm/drivers/net/rckemac.c
2011-08-02 15:58:20 +02:00

759 lines
26 KiB
C
Raw 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 <netif/etharp.h>
#include <net/rckemac.h>
/* 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
// 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
#define IRQ_STATUS 0xD000
#define IRQ_MASK 0xD200
#define IRQ_RESET 0xD400
#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)
/* Flush */
#define CL1FLUSH __asm__ volatile (".byte 0x0F; .byte 0x0A;\n")
/* 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)
static struct netif* mynetif;
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;
/* check for over/underflow */
if (BUILTIN_EXPECT((p->tot_len < 20) || (p->tot_len > 1536), 0)) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_output: illegal packet length %d => drop\n", p->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);
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"));
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(((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 = q->len > bytes_to_copy-i ? bytes_to_copy-i : q->len;
memcpy(((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((uint8_t*) addr, q->payload + sz, q->len - sz);
bytes_left -= (q->len - sz);
i = q->len - sz;
}
for(q=q->next; (q != 0); q = q->next) {
memcpy(((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;
/* 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_input(struct netif* netif, struct pbuf* p)
{
struct eth_hdr *ethhdr;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_ARP:
case ETHTYPE_IP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (mynetif->input(p, mynetif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: IP input error\n"));
pbuf_free(p);
}
break;
default:
pbuf_free(p);
break;
}
}
static void rckemacif_rx_handler(struct netif* netif, unsigned int write_offset)
{
rckemacif_t* rckemacif = netif->state;
unsigned short read_offset;
unsigned int counter;
volatile void *addr;
uint16_t i, length;
struct pbuf *p;
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;
write_emac(rckemacif->num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_READ_OFFSET, rckemacif->core, read_offset);
rckemacif->rx_read_offset = read_offset;
return;
}
while(1) {
if ((write_offset != 0) && (rckemacif->rx_read_offset != write_offset)) {
read_offset = rckemacif->rx_read_offset;
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 ((length < 20) || (length > 1536)) {
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 (p) {
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
if (read_offset < write_offset) {
for (q=p, counter=0; q!=NULL; q=q->next) {
for(i=0; i<q->len; i++, counter++) {
((uint8_t*) q->payload)[i] = ((uint8_t*)addr)[2 + counter];
}
}
read_offset += CLINE_PACKETS(p->len + 2) - 1;
} else {
int rest;
int bytesLeft = length;
int bytesToCopy = length;
/* 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));
for (q=p, counter=0; q!=NULL; q=q->next) {
for(i=0; i<q->len; i++, counter++) {
if (counter < bytesToCopy)
((uint8_t*) q->payload)[i] = ((uint8_t*)addr)[2 + counter];
else
goto out;
}
}
out:
bytesLeft -= bytesToCopy;
if (bytesLeft != 0) {
addr = rckemacif->rx_buffer + 0x20;
LWIP_DEBUGF(NETIF_DEBUG, ("copying from %p, left: %d (%x)\n", addr, bytesLeft, ((uint8_t*)addr)[0]));
for(counter=0; (i<q->len) && (counter < bytesLeft); i++, counter++)
((uint8_t*) q->payload)[i] = ((uint8_t*)addr)[counter];
for(q=q->next; (q!=NULL) && (counter < bytesLeft); q=q->next) {
for(i=0; (i<q->len) && (counter < bytesLeft); i++, counter++) {
((uint8_t*) q->payload)[i] = ((uint8_t*)addr)[counter];
}
}
read_offset = CLINE_PACKETS(bytesLeft);
} else {
read_offset += CLINE_PACKETS(p->len + 2) - 1;
}
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
rckemacif_input(netif, p);
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;
} else break;
}
}
static void rckemacif_handler(struct state* s)
{
unsigned int status, tmp;
unsigned int write_offset;
rckemacif_t* rckemacif = mynetif->state;
status = *((volatile int*) (FPGA_BASE + IRQ_STATUS + rckemacif->core * 2 * 4));
// read twice to be sure
status = *((volatile int*) (FPGA_BASE + IRQ_STATUS + rckemacif->core * 2 * 4));
if (!(status & (1 << rckemacif->num_emac))) {
LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_handler: no interrupt\n"));
return;
}
nexttry:
/* check for updated write offset */
CL1FLUSH;
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_rx_handler(mynetif, write_offset);
goto nexttry;
}
/* Set interrupt bit */
tmp = *((volatile unsigned int*) rckemacif->irq_address);
tmp &= ~(EMAC_IRQ_MASK);
*((volatile unsigned int*) rckemacif->irq_address) = tmp;
/* Reset */
*((volatile unsigned*) (FPGA_BASE + IRQ_RESET + rckemacif->core * 2 * 4)) = (1 << rckemacif->num_emac);
}
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_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, 0, sizeof(rckemacif_t));
rckemacif->core = core;
/* allocate the receive buffer */
rckemacif->rx_buffer = mem_allocation(BUFFER_SIZE, MAP_KERNEL_SPACE|MAP_NO_CACHE);
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);
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)
*/
if (z == 0) {
tmp = ReadConfigReg(CRB_OWN + LUT0);
rckemacif->irq_address = (void*) (CRB_OWN + GLCFG0);
} else {
tmp = ReadConfigReg(CRB_OWN + LUT1);
rckemacif->irq_address = (void*) (CRB_OWN + GLCFG1);
}
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));
}
sleep(3);
/* 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)));
// set interrupt handler (INTR/LINT0)
irq_install_handler(125, rckemacif_handler);
/* Enable interrupt */
tmp = *((volatile int*) (FPGA_BASE + IRQ_MASK + core * 2 * 4));
*((volatile int*) (FPGA_BASE + IRQ_MASK + core * 2 * 4)) = tmp & ~(1 << num_emac);
*((volatile int*) (FPGA_BASE + IRQ_CONFIG + core * 4)) = EMAC_IRQ_CONFIG;
/*
* 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 | NETIF_FLAG_LINK_UP;
/* hardware address length */
netif->hwaddr_len = 6;
rckemacif->ethaddr = (struct eth_addr *)netif->hwaddr;
return ERR_OK;
}
#endif