Skip to content

drivers/imx-enet: Add support for ethernet in imxrt1064-evk #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _targets/Makefile.armv7a7-imx6ull
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
NET_DRIVERS_SUPPORTED := enet tuntap
NET_DRIVERS ?= $(NET_DRIVERS_SUPPORTED)

DRIVERS_SRCS_enet = imx6-enet.c ephy.c gpio.c imx6ull-gpio.c $(DRIVERS_SRCS_UTIL) hw-debug.c
DRIVERS_SRCS_enet = imx-enet.c ephy.c imx6ull-gpio.c $(DRIVERS_SRCS_UTIL) hw-debug.c
6 changes: 4 additions & 2 deletions _targets/Makefile.armv7m7-imxrt106x
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
#
# iMX RT1064 target
#
# Copyright 2021 Phoenix Systems
# Copyright 2021, 2024 Phoenix Systems
#

NET_DRIVERS_SUPPORTED := pppou pppos
NET_DRIVERS_SUPPORTED := pppou pppos enet
NET_DRIVERS ?= $(NET_DRIVERS_SUPPORTED)
PPPOS_MODEM ?= huawei

DRIVERS_SRCS_enet = imx-enet.c ephy.c imxrt106x-gpio.c $(DRIVERS_SRCS_UTIL)
3 changes: 3 additions & 0 deletions drivers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
ifeq ($(EPHY_KSZ8081),RNA)
LOCAL_CFLAGS := -DEPHY_KSZ8081RNA
endif
ifeq ($(EPHY_KSZ8081),RNB)
LOCAL_CFLAGS := -DEPHY_KSZ8081RNB
endif
ifeq ($(EPHY_KSZ8081),RND)
LOCAL_CFLAGS := -DEPHY_KSZ8081RND
endif
Expand Down
130 changes: 75 additions & 55 deletions drivers/bdring.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


#define MAX_TX_FRAGMENTS 8
Expand All @@ -41,67 +42,72 @@
*/


static int is_power_of_2(size_t n)
static inline bool net_isPowerOf2(size_t n)
{
return !(n & (n - 1));
return (n & (n - 1)) == 0;
}


int net_initRings(net_bufdesc_ring_t *rings, const size_t *sizes, size_t nrings, const net_bufdesc_ops_t *ops)
{
size_t i, nb, sz, psz, align;
size_t i, nb, sz, align;
addr_t phys;
struct pbuf **bufp;
void *p;

align = ops->ring_alignment;
if (align) {
if (!is_power_of_2(align))
if (align != 0) {
if (!net_isPowerOf2(align)) {
return -EINVAL;
}
--align;
}

if (net_initPktMem(ops->pkt_buf_sz) < 0) {
return -EINVAL;
}

// FIXME: check for overflows
nb = sz = 0;
nb = 0;
sz = 0;
for (i = 0; i < nrings; ++i) {
if (!net_isPowerOf2(sizes[i])) {
return -EINVAL;
}

nb += sizes[i];
sz += sizes[i] * ops->desc_size;
sz = (sz + align) & ~align;

if (!is_power_of_2(sizes[i]))
return -EINVAL;
sz = (sz + align - 1) & ~(align - 1);
}

bufp = calloc(nb, sizeof(*bufp));
if (!bufp)
if (bufp == NULL) {
return -ENOMEM;
}

p = dmammap(sz);
if (!p) {
if (p == NULL) {
free(bufp);
return -ENOMEM;
}

psz = sz;
phys = mphys(p, &psz);
if ((psz != sz) || (phys & align)) {
if (psz != sz)
printf("ERROR: got non-contiguous ring buffer (%zu/%zu segment)\n", psz, sz);
else
printf("ERROR: got unaligned ring buffer (at 0x%zx, align mask: 0x%zx)\n", (size_t)phys, align);
phys = va2pa(p);
if ((phys & align) != 0) {
printf("ERROR: got unaligned ring buffer (at 0x%zx, align mask: 0x%zx)\n", (size_t)phys, align);
munmap(p, sz);
free(bufp);
return -ENODEV;
return -ENOMEM;
}

/*printf("descriptor rings: virt 0x%zx phys 0x%zx\n", (size_t)p, (size_t)phys);*/
/* printf("descriptor rings: virt 0x%zx phys 0x%zx\n", (size_t)p, (size_t)phys); */

memset(p, 0, sz);

for (i = 0; i < nrings; ++i) {
rings[i].ring = p;
rings[i].bufp = bufp;
rings[i].head = rings[i].tail = 0;
atomic_init(&rings[i].head, 0);
atomic_init(&rings[i].tail, 0);
rings[i].last = sizes[i] - 1;
rings[i].phys = phys;
rings[i].ops = ops;
Expand All @@ -125,30 +131,35 @@ size_t net_receivePackets(net_bufdesc_ring_t *ring, struct netif *ni, unsigned e

mutexLock(ring->lock);
n = 0;
i = ring->head;
i = atomic_load(&ring->head);
pkt = NULL;

for (;;) {
if (i == ring->tail)
if (i == atomic_load(&ring->tail)) {
break;
}

sz = ring->ops->nextRxBufferSize(ring, i);
if (!sz)
if (sz == 0) {
break;
}

p = ring->bufp[i];
p->tot_len = p->len = sz;

if (!pkt)
if (pkt == NULL) {
pkt = p;
else
}
else {
pbuf_cat(pkt, p);
}

if (ring->ops->pktRxFinished(ring, i)) {
pbuf_header_force(p, ETH_PAD_SIZE - ethpad);
#ifdef LWIP_HOOK_ETH_INPUT
if (LWIP_HOOK_ETH_INPUT(p, ni))
if (LWIP_HOOK_ETH_INPUT(p, ni)) {
pbuf_free(p);
}
else
#endif
{
Expand All @@ -157,11 +168,11 @@ size_t net_receivePackets(net_bufdesc_ring_t *ring, struct netif *ni, unsigned e
pkt = NULL;
}

i = (i + 1) & ring->last; // NOTE: 2^n ring size verified in net_initRings
i = (i + 1) & ring->last; /* NOTE: 2^n ring size verified in net_initRings */
++n;
}

ring->head = i;
atomic_store(&ring->head, i);
mutexUnlock(ring->lock);
return n;
}
Expand All @@ -176,25 +187,26 @@ size_t net_refillRx(net_bufdesc_ring_t *ring, size_t ethpad)

n = 0;
i = ring->tail;
nxt = (i + 1) & ring->last; // NOTE: 2^n ring size verified in net_initRings
nxt = (i + 1) & ring->last; /* NOTE: 2^n ring size verified in net_initRings */
sz = ring->ops->pkt_buf_sz;

while (nxt != ring->head) {
while (nxt != atomic_load(&ring->head)) {
p = net_allocDMAPbuf(&pa, sz);
if (!p)
if (p == NULL) {
break;
}

pbuf_header_force(p, ethpad - ETH_PAD_SIZE);

ring->bufp[i] = p;
ring->ops->fillRxDesc(ring, i, pa, sz, 0);

i = nxt;
nxt = (nxt + 1) & ring->last; // NOTE: 2^n ring size verified in net_initRings
nxt = (nxt + 1) & ring->last; /* NOTE: 2^n ring size verified in net_initRings */
++n;
}

ring->tail = i;
atomic_store(&ring->tail, i);
mutexUnlock(ring->lock);
return n;
}
Expand All @@ -206,23 +218,25 @@ size_t net_reapTxFinished(net_bufdesc_ring_t *ring)
mutexLock(ring->lock);

n = 0;
i = ring->tail;
i = atomic_load(&ring->tail);
head = atomic_load(&ring->head);
while (i != head) {
if (!ring->ops->nextTxDone(ring, i))
if (ring->ops->nextTxDone(ring, i) == 0) {
break;
}

if (ring->bufp[i]) {
if (ring->bufp[i] != NULL) {
pbuf_free(ring->bufp[i]);
ring->bufp[i] = NULL;
}

i = (i + 1) & ring->last; // NOTE: 2^n ring size verified in net_initRings
i = (i + 1) & ring->last; /* NOTE: 2^n ring size verified in net_initRings */
++n;
}

if (n)
if (n > 0) {
atomic_store(&ring->tail, i);
}

mutexUnlock(ring->lock);
return n;
Expand All @@ -237,24 +251,27 @@ static size_t net_fillFragments(struct pbuf *p, addr_t *pa, size_t *psz, size_t
sz = p->tot_len;
n = fragsz = 0;

while (sz) {
if (++n >= max_n)
while (sz != 0) {
if (++n >= max_n) {
return 0;
}

if (!fragsz) {
if (fragsz == 0) {
fragsz = p->len;
data = p->payload;
}

*psz = fragsz <= max_fragsz ? fragsz : max_fragsz;
*pa = mphys(data, psz);
*pa = va2pa(data);
sz -= *psz;
fragsz -= *psz;

if (!fragsz)
if (fragsz == 0) {
p = p->next;
else
}
else {
data += *psz;
}

++psz, ++pa;
}
Expand All @@ -271,31 +288,34 @@ size_t net_transmitPacket(net_bufdesc_ring_t *ring, struct pbuf *p)
int last;

p = net_makeDMAPbuf(p);
if (!p)
if (p == NULL) {
return 0;
}

mutexLock(ring->lock);
// NOTE: 2^n ring size verified in net_initRings
n = atomic_load(&ring->tail); // access tail once - it may be advanced by tx_done thread
i = ring->head;
/* NOTE: 2^n ring size verified in net_initRings */
n = atomic_load(&ring->tail); /* access tail once - it may be advanced by tx_done thread */
i = atomic_load(&ring->head);
n = (n - i - 1) & ring->last;
if (n > MAX_TX_FRAGMENTS)
if (n > MAX_TX_FRAGMENTS) {
n = MAX_TX_FRAGMENTS;
}

frags = n = net_fillFragments(p, pa, psz, n, ring->ops->max_tx_frag);
if (!frags) {
if (frags == 0) {
pbuf_free(p);
mutexUnlock(ring->lock);
return 0; /* dropped: too many fragments or empty packet */
return 0; /* dropped: too many fragments or empty packet */
}

/* fill fragments from last to avoid race against HW */
i = ni = (i + n) & ring->last;
ring->bufp[i] = p;
last = BDRING_SEG_LAST;
while (n--) {
if (!n)
while (n-- > 0) {
if (n == 0) {
last |= BDRING_SEG_FIRST;
}
i = (i - 1) & ring->last;
ring->ops->fillTxDesc(ring, i, pa[n], psz[n], last);
last = 0;
Expand Down
8 changes: 3 additions & 5 deletions drivers/bdring.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ enum {
};


typedef struct net_bufdesc_ops_
{
typedef struct net_bufdesc_ops_ {
size_t (*nextRxBufferSize)(const net_bufdesc_ring_t *ring, size_t i);
int (*pktRxFinished)(const net_bufdesc_ring_t *ring, size_t i);
void (*fillRxDesc)(const net_bufdesc_ring_t *ring, size_t i, addr_t pa, size_t sz, unsigned seg /* = zero */);
Expand All @@ -42,11 +41,10 @@ typedef struct net_bufdesc_ops_
} net_bufdesc_ops_t;


struct net_bufdesc_ring_
{
struct net_bufdesc_ring_ {
volatile void *ring;
struct pbuf **bufp;
volatile unsigned head, tail;
volatile atomic_uint head, tail;
unsigned last;
addr_t phys;
const net_bufdesc_ops_t *ops;
Expand Down
Loading
Loading