/* * 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 User’s Guide (Revision 0.92 Part 9). */ #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) #include #include #include #include #include #include /* 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