Merge pull request #1726 from cesanta/qp

Add MAC addr filtering to stm32 driver. Record free space in q profiler
This commit is contained in:
Sergey Lyubka 2022-09-10 18:19:36 +01:00 committed by GitHub
commit 7e875ba89d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 91 deletions

View File

@ -1,6 +1,6 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
// https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
// https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
#pragma once

View File

@ -97,8 +97,11 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) {
ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
// TODO(cpq): setup MAC filtering
(void) userdata, (void) mac;
// MAC address filtering
ETH->MACA0HR = ((uint32_t) mac[5] << 8U) | mac[4];
ETH->MACA0LR = (uint32_t) (mac[3] << 24) | ((uint32_t) mac[2] << 16) |
((uint32_t) mac[1] << 8) | mac[0];
(void) userdata;
return true;
}
@ -139,9 +142,7 @@ static bool mip_driver_stm32_up(void *userdata) {
void ETH_IRQHandler(void);
void ETH_IRQHandler(void) {
#ifdef MIP_QPROFILE
qp_mark(QP_IRQTRIGGERED, 0);
#endif
volatile uint32_t sr = ETH->DMASR;
if (sr & BIT(6)) { // Frame received, loop
for (uint32_t i = 0; i < ETH_DESC_CNT; i++) {

View File

@ -64,7 +64,8 @@ struct mip_if {
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
uint16_t eport; // Next ephemeral port
int state; // Current state
uint16_t dropped; // Number of dropped frames
uint8_t state; // Current state
#define MIP_STATE_DOWN 0 // Interface is down
#define MIP_STATE_UP 1 // Interface is up
#define MIP_STATE_READY 2 // Interface is up and has IP
@ -202,7 +203,11 @@ static bool q_write(struct queue *q, const void *buf, size_t len) {
return success;
}
static size_t q_avail(struct queue *q) {
static inline size_t q_space(struct queue *q) {
return q->tail > q->head ? q->tail - q->head : q->tail + (q->len - q->head);
}
static inline size_t q_avail(struct queue *q) {
size_t n = 0;
if (q->tail != q->head) q_copyout(q, (uint8_t *) &n, sizeof(n), q->tail);
return n;
@ -788,13 +793,9 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
: ifp->driver->rx(ifp->rx.buf, ifp->rx.len,
ifp->driver_data);
if (len == 0) break;
#ifdef MIP_QPROFILE
qp_mark(QP_FRAMEPOPPED, (int) len);
#endif
qp_mark(QP_FRAMEPOPPED, (int) q_space(&ifp->queue));
mip_rx(ifp, ifp->rx.buf, len);
#ifdef MIP_QPROFILE
qp_mark(QP_FRAMEDONE, (int) len);
#endif
qp_mark(QP_FRAMEDONE, (int) q_space(&ifp->queue));
}
// Process timeouts
@ -825,12 +826,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
// our lock-free queue with preallocated buffer to copy data and return asap
static void on_rx(void *buf, size_t len, void *userdata) {
struct mip_if *ifp = (struct mip_if *) userdata;
#ifndef MIP_QPROFILE
if (!q_write(&ifp->queue, buf, len)) MG_ERROR(("dropped %d", (int) len));
#else
qp_mark(q_write(&ifp->queue, buf, len) ? QP_FRAMEPUSHED : QP_FRAMEDROPPED,
(int) len);
#endif
if (q_write(&ifp->queue, buf, len)) {
qp_mark(QP_FRAMEPUSHED, (int) q_space(&ifp->queue));
} else {
ifp->dropped++;
qp_mark(QP_FRAMEDROPPED, ifp->dropped);
MG_ERROR(("dropped %d", (int) len));
}
}
void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg,
@ -958,7 +960,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
#pragma pack(push, 1)
struct qpentry {
uint64_t timestamp;
uint32_t timestamp;
uint16_t type;
uint16_t len;
};
@ -970,14 +972,11 @@ static struct queue qp;
// TODO(scaprile): avoid concurrency issues (2 queues ?)
void qp_mark(unsigned int type, int len) {
static bool ovf = false;
static uint16_t drop_ctr = 0, irq_ctr = 0;
struct qpentry e = {
.timestamp = mg_millis(), .type = (uint16_t) type, .len = (uint16_t) len};
if (type == QP_IRQTRIGGERED)
e.len = ++irq_ctr; // only incremented on IRQ calls
else if (type == QP_FRAMEDROPPED)
++drop_ctr; // only incremented on IRQ calls
static uint16_t irq_ctr = 0, drop_ctr = 0;
struct qpentry e = {.timestamp = (uint32_t) mg_millis(),
.type = (uint16_t) type,
.len = (uint16_t) len};
if (type == QP_IRQTRIGGERED) e.len = ++irq_ctr;
if (ovf) {
e.type = (uint16_t) QP_QUEUEOVF;
e.len = drop_ctr;
@ -987,20 +986,15 @@ void qp_mark(unsigned int type, int len) {
void qp_log(void) {
struct qpentry e;
for (int i = 0; i < 10; i++)
if (q_read(&qp, &e))
MG_INFO(("%llu, %u, %u", e.timestamp, e.type, e.len));
else
break;
const char *titles[] = {"IRQ ", "PUSH", "POP ", "DONE", "DROP", "OVFL"};
for (int i = 0; i < 10 && q_read(&qp, &e); i++) {
MG_INFO(("%lx %s %u", e.timestamp, titles[e.type], e.len));
}
}
void qp_init(void) {
unsigned int qlen = 500 * (sizeof(size_t) + sizeof(struct qpentry));
qp.buf = calloc(1, qlen);
qp.len = qlen;
// THERE IS NO FREE
qp.len = 500 * (sizeof(size_t) + sizeof(struct qpentry));
qp.buf = calloc(1, qp.len); // THERE IS NO FREE
}
#endif // MIP_QPROFILE

View File

@ -32,17 +32,18 @@ struct mip_spi {
};
#ifdef MIP_QPROFILE
enum { // payload is frame length unless otherwise noted
enum {
QP_IRQTRIGGERED = 0, // payload is number of interrupts so far
QP_FRAMEPUSHED,
QP_FRAMEPOPPED,
QP_FRAMEDONE,
QP_FRAMEDROPPED,
QP_QUEUEOVF // profiling queue is full, payload is number of frame drops so
// far
QP_FRAMEPUSHED, // available space in the frame queue
QP_FRAMEPOPPED, // available space in the frame queue
QP_FRAMEDONE, // available space in the frame queue
QP_FRAMEDROPPED, // number of dropped frames
QP_QUEUEOVF // profiling queue is full, payload is number of frame drops
};
void qp_mark(unsigned int type, int len);
void qp_log(void); // timestamp, type, payload
void qp_init(void);
#else
#define qp_mark(a, b)
#endif

View File

@ -6079,8 +6079,11 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) {
ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
// TODO(cpq): setup MAC filtering
(void) userdata, (void) mac;
// MAC address filtering
ETH->MACA0HR = ((uint32_t) mac[5] << 8U) | mac[4];
ETH->MACA0LR = (uint32_t) (mac[3] << 24) | ((uint32_t) mac[2] << 16) |
((uint32_t) mac[1] << 8) | mac[0];
(void) userdata;
return true;
}
@ -6121,9 +6124,7 @@ static bool mip_driver_stm32_up(void *userdata) {
void ETH_IRQHandler(void);
void ETH_IRQHandler(void) {
#ifdef MIP_QPROFILE
qp_mark(QP_IRQTRIGGERED, 0);
#endif
volatile uint32_t sr = ETH->DMASR;
if (sr & BIT(6)) { // Frame received, loop
for (uint32_t i = 0; i < ETH_DESC_CNT; i++) {
@ -6365,7 +6366,8 @@ struct mip_if {
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
uint16_t eport; // Next ephemeral port
int state; // Current state
uint16_t dropped; // Number of dropped frames
uint8_t state; // Current state
#define MIP_STATE_DOWN 0 // Interface is down
#define MIP_STATE_UP 1 // Interface is up
#define MIP_STATE_READY 2 // Interface is up and has IP
@ -6503,7 +6505,11 @@ static bool q_write(struct queue *q, const void *buf, size_t len) {
return success;
}
static size_t q_avail(struct queue *q) {
static inline size_t q_space(struct queue *q) {
return q->tail > q->head ? q->tail - q->head : q->tail + (q->len - q->head);
}
static inline size_t q_avail(struct queue *q) {
size_t n = 0;
if (q->tail != q->head) q_copyout(q, (uint8_t *) &n, sizeof(n), q->tail);
return n;
@ -7089,13 +7095,9 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
: ifp->driver->rx(ifp->rx.buf, ifp->rx.len,
ifp->driver_data);
if (len == 0) break;
#ifdef MIP_QPROFILE
qp_mark(QP_FRAMEPOPPED, (int) len);
#endif
qp_mark(QP_FRAMEPOPPED, (int) q_space(&ifp->queue));
mip_rx(ifp, ifp->rx.buf, len);
#ifdef MIP_QPROFILE
qp_mark(QP_FRAMEDONE, (int) len);
#endif
qp_mark(QP_FRAMEDONE, (int) q_space(&ifp->queue));
}
// Process timeouts
@ -7126,12 +7128,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
// our lock-free queue with preallocated buffer to copy data and return asap
static void on_rx(void *buf, size_t len, void *userdata) {
struct mip_if *ifp = (struct mip_if *) userdata;
#ifndef MIP_QPROFILE
if (!q_write(&ifp->queue, buf, len)) MG_ERROR(("dropped %d", (int) len));
#else
qp_mark(q_write(&ifp->queue, buf, len) ? QP_FRAMEPUSHED : QP_FRAMEDROPPED,
(int) len);
#endif
if (q_write(&ifp->queue, buf, len)) {
qp_mark(QP_FRAMEPUSHED, (int) q_space(&ifp->queue));
} else {
ifp->dropped++;
qp_mark(QP_FRAMEDROPPED, ifp->dropped);
MG_ERROR(("dropped %d", (int) len));
}
}
void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg,
@ -7259,7 +7262,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
#pragma pack(push, 1)
struct qpentry {
uint64_t timestamp;
uint32_t timestamp;
uint16_t type;
uint16_t len;
};
@ -7271,14 +7274,11 @@ static struct queue qp;
// TODO(scaprile): avoid concurrency issues (2 queues ?)
void qp_mark(unsigned int type, int len) {
static bool ovf = false;
static uint16_t drop_ctr = 0, irq_ctr = 0;
struct qpentry e = {
.timestamp = mg_millis(), .type = (uint16_t) type, .len = (uint16_t) len};
if (type == QP_IRQTRIGGERED)
e.len = ++irq_ctr; // only incremented on IRQ calls
else if (type == QP_FRAMEDROPPED)
++drop_ctr; // only incremented on IRQ calls
static uint16_t irq_ctr = 0, drop_ctr = 0;
struct qpentry e = {.timestamp = (uint32_t) mg_millis(),
.type = (uint16_t) type,
.len = (uint16_t) len};
if (type == QP_IRQTRIGGERED) e.len = ++irq_ctr;
if (ovf) {
e.type = (uint16_t) QP_QUEUEOVF;
e.len = drop_ctr;
@ -7288,20 +7288,15 @@ void qp_mark(unsigned int type, int len) {
void qp_log(void) {
struct qpentry e;
for (int i = 0; i < 10; i++)
if (q_read(&qp, &e))
MG_INFO(("%llu, %u, %u", e.timestamp, e.type, e.len));
else
break;
const char *titles[] = {"IRQ ", "PUSH", "POP ", "DONE", "DROP", "OVFL"};
for (int i = 0; i < 10 && q_read(&qp, &e); i++) {
MG_INFO(("%lx %s %u", e.timestamp, titles[e.type], e.len));
}
}
void qp_init(void) {
unsigned int qlen = 500 * (sizeof(size_t) + sizeof(struct qpentry));
qp.buf = calloc(1, qlen);
qp.len = qlen;
// THERE IS NO FREE
qp.len = 500 * (sizeof(size_t) + sizeof(struct qpentry));
qp.buf = calloc(1, qp.len); // THERE IS NO FREE
}
#endif // MIP_QPROFILE

View File

@ -1456,19 +1456,20 @@ struct mip_spi {
};
#ifdef MIP_QPROFILE
enum { // payload is frame length unless otherwise noted
enum {
QP_IRQTRIGGERED = 0, // payload is number of interrupts so far
QP_FRAMEPUSHED,
QP_FRAMEPOPPED,
QP_FRAMEDONE,
QP_FRAMEDROPPED,
QP_QUEUEOVF // profiling queue is full, payload is number of frame drops so
// far
QP_FRAMEPUSHED, // available space in the frame queue
QP_FRAMEPOPPED, // available space in the frame queue
QP_FRAMEDONE, // available space in the frame queue
QP_FRAMEDROPPED, // number of dropped frames
QP_QUEUEOVF // profiling queue is full, payload is number of frame drops
};
void qp_mark(unsigned int type, int len);
void qp_log(void); // timestamp, type, payload
void qp_init(void);
#else
#define qp_mark(a, b)
#endif
#ifdef __cplusplus