Change in osmo-e1d[master]: Add support for icE1usb interrupt endpoint error reporting

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Sun Dec 27 18:46:25 UTC 2020


laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-e1d/+/21782 )

Change subject: Add support for icE1usb interrupt endpoint error reporting
......................................................................

Add support for icE1usb interrupt endpoint error reporting

Related: OS#4674
Change-Id: I5b0bf3cf40c623c17f2e88292e880b545c36b7b6
Depends: osmo-e1-hardware If157fde9d4ca05910b09537e19f37603c6d925f0
---
M src/Makefile.am
A src/ice1usb_proto.h
M src/usb.c
3 files changed, 196 insertions(+), 3 deletions(-)

Approvals:
  Jenkins Builder: Verified
  tnt: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved



diff --git a/src/Makefile.am b/src/Makefile.am
index 6dd13ce..d9d8236 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@
 
 noinst_HEADERS = \
 	e1d.h \
+	ice1usb_proto.h \
 	log.h \
 	$(NULL)
 
diff --git a/src/ice1usb_proto.h b/src/ice1usb_proto.h
new file mode 100644
index 0000000..5f5f31c
--- /dev/null
+++ b/src/ice1usb_proto.h
@@ -0,0 +1,99 @@
+#pragma once
+
+/* Header file describing the USB protocol between the icE1usb firmware and the host
+ * software (currently really only osmo-e1d) */
+
+/***********************************************************************
+ * Control Endpoint / Device Requests
+ ***********************************************************************/
+
+/*! returns a bit-mask of optional device capabilities (see enum e1usb_dev_capability) */
+#define ICE1USB_DEV_GET_CAPABILITIES	0x01
+#define ICE1USB_DEV_GET_FW_BUILD	0x02
+
+enum e1usb_dev_capability {
+	/*! Does this board have a GPS-DO */
+	ICE1USB_DEV_CAP_GPSDO,
+};
+
+
+/* Interface Requests */
+
+/*! returns a bit-mask of optional device capabilities (see enum e1usb_intf_capability) */
+#define ICE1USB_INTF_GET_CAPABILITIES	0x01
+#define ICE1USB_INTF_SET_TX_CFG		0x02	/*!< struct ice1usb_tx_config */
+#define ICE1USB_INTF_GET_TX_CFG		0x03	/*!< struct ice1usb_tx_config */
+#define ICE1USB_INTF_SET_RX_CFG		0x04	/*!< struct ice1usb_rx_config */
+#define ICE1USB_INTF_GET_RX_CFG		0x05	/*!< struct ice1usb_rx_config */
+
+//enum e1usb_intf_capability { };
+
+enum ice1usb_tx_mode {
+	ICE1USB_TX_MODE_TRANSP		= 0,
+	ICE1USB_TX_MODE_TS0		= 1,
+	ICE1USB_TX_MODE_TS0_CRC4	= 2,
+	ICE1USB_TX_MODE_TS0_CRC4_E	= 3,
+};
+
+enum ice1usb_tx_timing {
+	ICE1USB_TX_TIME_SRC_LOCAL	= 0,
+	ICE1USB_TX_TIME_SRC_REMOTE	= 1,
+};
+
+enum ice1usb_tx_ext_loopback {
+	ICE1USB_TX_EXT_LOOPBACK_OFF	= 0,
+	ICE1USB_TX_EXT_LOOPBACK_SAME	= 1,
+	ICE1USB_TX_EXT_LOOPBACK_CROSS	= 2,
+};
+
+/* ICE1USB_INTF_{GET,SET}_TX_CFG */
+struct ice1usb_tx_config {
+	uint8_t mode;		/*!< enum ice1usb_tx_mode */
+	uint8_t timing;		/*!< enum ice1usb_tx_timing */
+	uint8_t ext_loopback;	/*!< enum ice1usb_tx_ext_loopback */
+	uint8_t alarm;		/*!< 1 = transmit alarm; 0 = don't */
+} __attribute__((packed));
+
+
+enum ice1usb_rx_mode {
+	/*! transparent, unaligned bitstream */
+	ICE1USB_RX_MODE_TRANSP		= 0,
+	/*! alignment to E1 frame */
+	ICE1USB_RX_MODE_FRAME		= 2,
+	/*! alignment to E1 multiframe */
+	ICE1USB_RX_MODE_MULTIFRAME	= 3,
+};
+
+/* ICE1USB_INTF_{GET,SET}_RX_CFG */
+struct ice1usb_rx_config {
+	uint8_t mode;		/*!< enum ice1usb_rx_mode */
+} __attribute__((packed));
+
+
+/***********************************************************************
+ * Interrupt Endpoint
+ ***********************************************************************/
+
+enum ice1usb_irq_type {
+	ICE1USB_IRQQ_T_ERRCNT		= 1,
+};
+
+/* Ensue ro keep those in sync with e1.h */
+#define ICE1USB_ERR_F_ALIGN_ERR	0x01
+#define ICE1USB_ERR_F_TICK_ERR	0x02
+
+struct ice1usb_irq_err {
+	/* 16-bit little-endian counters */
+	uint16_t crc;
+	uint16_t align;
+	uint16_t ovfl;
+	uint16_t unfl;
+	uint8_t flags;
+} __attribute__((packed));
+
+struct ice1usb_irq {
+	uint8_t type; 		/*!< enum ice1usb_irq_type */
+	union {
+		struct ice1usb_irq_err errors;
+	} u;
+} __attribute__((packed));
diff --git a/src/usb.c b/src/usb.c
index be4de44..35d47ec 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -36,6 +36,7 @@
 
 #include "e1d.h"
 #include "log.h"
+#include "ice1usb_proto.h"
 
 
 #define USB_VID		0x1d50
@@ -57,6 +58,7 @@
 	uint8_t ep_in;
 	uint8_t ep_out;
 	uint8_t ep_fb;
+	uint8_t ep_int;
 
 	/* Max packet size */
 	int pkt_size;
@@ -66,6 +68,12 @@
 	struct e1_usb_flow *flow_out;
 	struct e1_usb_flow *flow_fb;
 
+	/* Interrupt */
+	struct {
+		uint8_t buf[10];
+		struct ice1usb_irq_err last_errcnt;
+	} irq;
+
 	/* Rate regulation */
 	uint32_t r_acc;
 	uint32_t r_sw;
@@ -98,8 +106,6 @@
 	struct e1_usb_flow_entry *entries;
 };
 
-
-
 // ---------------------------------------------------------------------------
 // USB data transfer
 // ---------------------------------------------------------------------------
@@ -275,6 +281,88 @@
 	return 0;
 }
 
+// ---------------------------------------------------------------------------
+// USB interrupt
+// ---------------------------------------------------------------------------
+
+static int resubmit_irq(struct e1_line *line);
+
+static void rx_interrupt_errcnt(struct e1_line *line, const struct ice1usb_irq_err *errcnt)
+{
+	struct e1_usb_line_data *ld = (struct e1_usb_line_data *) line->drv_data;
+	struct ice1usb_irq_err *last = &ld->irq.last_errcnt;
+
+	if (errcnt->crc != last->crc) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "CRC error count %d (was %d)\n",
+			errcnt->crc, last->crc);
+	}
+
+	if (errcnt->align != last->align) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "ALIGNMENT error count %d (was %d)\n",
+			errcnt->align, last->align);
+	}
+
+	if (errcnt->ovfl != last->ovfl) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "OVERFLOW error count %d (was %d)\n",
+			errcnt->ovfl, last->ovfl);
+	}
+
+	if (errcnt->unfl != last->unfl) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "UNDERFLOW error count %d (was %d)\n",
+			errcnt->unfl, last->unfl);
+	}
+
+	if ((errcnt->flags & ICE1USB_ERR_F_ALIGN_ERR) != (last->flags & ICE1USB_ERR_F_ALIGN_ERR)) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "ALIGNMENT %s\n",
+			errcnt->flags & ICE1USB_ERR_F_ALIGN_ERR ? "LOST" : "REGAINED");
+	}
+
+	if ((errcnt->flags & ICE1USB_ERR_F_TICK_ERR) != (last->flags & ICE1USB_ERR_F_TICK_ERR)) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "Rx Clock %s\n",
+			errcnt->flags & ICE1USB_ERR_F_TICK_ERR ? "LOST" : "REGAINED");
+	}
+
+	ld->irq.last_errcnt = *errcnt;
+}
+
+static void interrupt_ep_cb(struct libusb_transfer *xfer)
+{
+	struct e1_line *line = (struct e1_line *) xfer->user_data;
+	const struct ice1usb_irq *irq = (const struct ice1usb_irq *) xfer->buffer;
+
+	if (!xfer->actual_length) {
+		LOGPLI(line, DE1D, LOGL_ERROR, "Zero-Length Interrupt transfer\n");
+		goto out;
+	}
+
+	switch (irq->type) {
+	case ICE1USB_IRQQ_T_ERRCNT:
+		if (xfer->actual_length < sizeof(*irq)) {
+			LOGPLI(line, DE1D, LOGL_ERROR, "Short ERRCNT interrupt: %u<%zu\n",
+				xfer->actual_length, sizeof(*irq));
+			break;
+		}
+		rx_interrupt_errcnt(line, &irq->u.errors);
+		break;
+	default:
+		LOGPLI(line, DE1D, LOGL_INFO, "Unsupported interrupt 0x%02x\n", irq->type);
+		break;
+	}
+
+out:
+	resubmit_irq(line);
+}
+
+static int resubmit_irq(struct e1_line *line)
+{
+	struct e1_usb_line_data *ld = (struct e1_usb_line_data *) line->drv_data;
+	struct e1_usb_intf_data *id = (struct e1_usb_intf_data *) line->intf->drv_data;
+	struct libusb_transfer *xfr = libusb_alloc_transfer(0);
+
+	libusb_fill_interrupt_transfer(xfr, id->devh, ld->ep_int, ld->irq.buf, sizeof(ld->irq.buf),
+					interrupt_ep_cb, line, 0);
+	return libusb_submit_transfer(xfr);
+}
 
 // ---------------------------------------------------------------------------
 // Init / Probing
@@ -316,7 +404,7 @@
 			continue;
 
 		id = &cd->interface[i].altsetting[1];
-		if ((id->bInterfaceClass != 0xff) || (id->bInterfaceSubClass != 0xe1) || (id->bNumEndpoints != 3))
+		if ((id->bInterfaceClass != 0xff) || (id->bInterfaceSubClass != 0xe1) || (id->bNumEndpoints < 3))
 			continue;
 
 		/* Get interface and set it up */
@@ -353,6 +441,8 @@
 				else if (line_data->pkt_size != id->endpoint[j].wMaxPacketSize)
 					LOGP(DE1D, LOGL_ERROR, "Inconsistent max packet size %d vs %d\n",
 						line_data->pkt_size, (int)id->endpoint[j].wMaxPacketSize);
+			} else if (id->endpoint[j].bmAttributes == 0x03) {
+				line_data->ep_int = id->endpoint[j].bEndpointAddress;
 			} else {
 				LOGP(DE1D, LOGL_ERROR, "Invalid EP %02x\n", id->endpoint[j].bEndpointAddress);
 			}
@@ -372,6 +462,9 @@
 		e1uf_start(line_data->flow_in);
 		e1uf_start(line_data->flow_out);
 		e1uf_start(line_data->flow_fb);
+
+		if (line_data->ep_int)
+			resubmit_irq(line);
 	}
 
 	return 0;

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/21782
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: I5b0bf3cf40c623c17f2e88292e880b545c36b7b6
Gerrit-Change-Number: 21782
Gerrit-PatchSet: 5
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: tnt <tnt at 246tNt.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201227/b77fd2c3/attachment.htm>


More information about the gerrit-log mailing list