EoE - TX fragmenting works. TCP traffic possible.
--- a/master/ethernet.c Fri May 05 14:45:02 2006 +0000
+++ b/master/ethernet.c Mon May 08 16:46:43 2006 +0000
@@ -41,19 +41,6 @@
/*****************************************************************************/
-/**
- Queued frame structure.
-*/
-
-typedef struct
-{
- struct list_head queue; /**< list item */
- struct sk_buff *skb; /**< socket buffer */
-}
-ec_eoe_frame_t;
-
-/*****************************************************************************/
-
void ec_eoe_flush(ec_eoe_t *);
void ec_eoedev_init(struct net_device *);
int ec_eoedev_open(struct net_device *);
@@ -154,6 +141,78 @@
/*****************************************************************************/
/**
+ Sends a frame or the next fragment.
+*/
+
+int ec_eoe_send(ec_eoe_t *eoe)
+{
+ ec_eoe_frame_t *frame = eoe->tx_frame;
+ size_t remaining_size, current_size, complete_offset;
+ unsigned int last_fragment;
+ uint8_t *data;
+#if EOE_DEBUG_LEVEL > 1
+ unsigned int i;
+#endif
+
+ remaining_size = frame->skb->len - eoe->tx_offset;
+
+ if (remaining_size <= eoe->slave->sii_tx_mailbox_size - 10) {
+ current_size = remaining_size;
+ last_fragment = 1;
+ }
+ else {
+ current_size = ((eoe->slave->sii_tx_mailbox_size - 10) / 32) * 32;
+ last_fragment = 0;
+ }
+
+ if (eoe->tx_fragment_number) {
+ complete_offset = eoe->tx_offset / 32;
+ }
+ else {
+ complete_offset = remaining_size / 32 + 1;
+ }
+
+#if EOE_DEBUG_LEVEL > 0
+ EC_DBG("EoE TX sending %sfragment %i with %i octets (%i)."
+ " %i frames queued.\n", last_fragment ? "last " : "",
+ eoe->tx_fragment_number, current_size, complete_offset,
+ eoe->queued_frames);
+#endif
+
+#if EOE_DEBUG_LEVEL > 1
+ EC_DBG("");
+ for (i = 0; i < current_size; i++) {
+ printk("%02X ", frame->skb->data[eoe->tx_offset + i]);
+ if ((i + 1) % 16 == 0) {
+ printk("\n");
+ EC_DBG("");
+ }
+ }
+ printk("\n");
+#endif
+
+ if (!(data = ec_slave_mbox_prepare_send(eoe->slave, 0x02,
+ current_size + 4)))
+ return -1;
+
+ EC_WRITE_U8 (data, 0x00); // eoe fragment req.
+ EC_WRITE_U8 (data + 1, last_fragment);
+ EC_WRITE_U16(data + 2, ((eoe->tx_fragment_number & 0x3F) |
+ (complete_offset & 0x3F) << 6 |
+ (eoe->tx_frame_number & 0x0F) << 12));
+
+ memcpy(data + 4, frame->skb->data + eoe->tx_offset, current_size);
+ ec_master_queue_command(eoe->slave->master, &eoe->slave->mbox_command);
+
+ eoe->tx_offset += current_size;
+ eoe->tx_fragment_number++;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
Runs the EoE state machine.
*/
@@ -343,28 +402,13 @@
eoe->queued_frames--;
spin_unlock_bh(&eoe->tx_queue_lock);
-#if EOE_DEBUG_LEVEL > 0
- EC_DBG("EoE TX Sending frame with %i octets."
- " (%i frames queued).\n",
- frame->skb->len, eoe->queued_frames);
-
-#if EOE_DEBUG_LEVEL > 1
- EC_DBG("");
- for (i = 0; i < frame->skb->len; i++) {
- printk("%02X ", frame->skb->data[i]);
- if ((i + 1) % 16 == 0) {
- printk("\n");
- EC_DBG("");
- }
- }
- printk("\n");
-#endif
-
- if (wakeup) EC_DBG("waking up TX queue...\n");
-#endif
-
- if (!(data = ec_slave_mbox_prepare_send(eoe->slave, 0x02,
- frame->skb->len + 4))) {
+ eoe->tx_frame_number++;
+ eoe->tx_frame_number %= 16;
+ eoe->tx_frame = frame;
+ eoe->tx_fragment_number = 0;
+ eoe->tx_offset = 0;
+
+ if (ec_eoe_send(eoe)) {
dev_kfree_skb(frame->skb);
kfree(frame);
eoe->stats.tx_errors++;
@@ -372,18 +416,9 @@
break;
}
- eoe->tx_frame_number++;
- eoe->tx_frame_number %= 16;
-
- EC_WRITE_U16(data, 0x0100); // eoe fragment req.
- EC_WRITE_U16(data + 2, (eoe->tx_frame_number & 0x0F) << 12);
-
- memcpy(data + 4, frame->skb->data, frame->skb->len);
- ec_master_queue_command(master, &eoe->slave->mbox_command);
-
- eoe->last_tx_bytes = frame->skb->len;
- dev_kfree_skb(frame->skb);
- kfree(frame);
+#if EOE_DEBUG_LEVEL > 0
+ if (wakeup) EC_DBG("waking up TX queue...\n");
+#endif
eoe->state = EC_EOE_TX_SENT;
break;
@@ -400,9 +435,24 @@
break;
}
- eoe->stats.tx_packets++;
- eoe->stats.tx_bytes += eoe->last_tx_bytes;
- eoe->state = EC_EOE_RX_START;
+ // frame completely sent
+ if (eoe->tx_offset >= eoe->tx_frame->skb->len) {
+ eoe->stats.tx_packets++;
+ eoe->stats.tx_bytes += eoe->tx_frame->skb->len;
+ dev_kfree_skb(eoe->tx_frame->skb);
+ kfree(eoe->tx_frame);
+ eoe->state = EC_EOE_RX_START;
+ }
+ else { // send next fragment
+ if (ec_eoe_send(eoe)) {
+ dev_kfree_skb(eoe->tx_frame->skb);
+ kfree(eoe->tx_frame);
+ eoe->stats.tx_errors++;
+ eoe->state = EC_EOE_RX_START;
+ break;
+ }
+ }
+
break;
default:
@@ -497,12 +547,14 @@
ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
ec_eoe_frame_t *frame;
- if (skb->len + 10 > eoe->slave->sii_tx_mailbox_size) {
+#if 0
+ if (skb->len > eoe->slave->sii_tx_mailbox_size - 10) {
EC_WARN("EoE TX frame (%i octets) exceeds MTU. dropping.\n", skb->len);
dev_kfree_skb(skb);
eoe->stats.tx_dropped++;
return 0;
}
+#endif
if (!(frame =
(ec_eoe_frame_t *) kmalloc(sizeof(ec_eoe_frame_t), GFP_ATOMIC))) {
--- a/master/ethernet.h Fri May 05 14:45:02 2006 +0000
+++ b/master/ethernet.h Mon May 08 16:46:43 2006 +0000
@@ -48,15 +48,26 @@
EC_EOE_RX_CHECK, /**< checking frame was sent. */
EC_EOE_RX_FETCH, /**< there is new data; fetching frame was sent. */
EC_EOE_TX_START, /**< start sending a queued frame. */
- EC_EOE_TX_SENT, /**< queued frame was sent; start checking. */
- EC_EOE_TX_CHECK, /**< check mailbox for acknowledgement. */
- EC_EOE_TX_FETCH, /**< receive mailbox response */
+ EC_EOE_TX_SENT /**< queued frame was sent. */
}
ec_eoe_state_t;
/*****************************************************************************/
/**
+ Queued frame structure.
+*/
+
+typedef struct
+{
+ struct list_head queue; /**< list item */
+ struct sk_buff *skb; /**< socket buffer */
+}
+ec_eoe_frame_t;
+
+/*****************************************************************************/
+
+/**
Ethernet-over-EtherCAT (EoE) Object.
The master creates one of these objects for each slave that supports the
EoE protocol.
@@ -78,8 +89,10 @@
unsigned int tx_queue_active; /**< kernel netif queue started */
unsigned int queued_frames; /**< number of frames in the queue */
spinlock_t tx_queue_lock; /**< spinlock for the send queue */
- uint8_t tx_frame_number; /**< Number of the transmitted frame */
- size_t last_tx_bytes; /**< number of bytes currently transmitted */
+ ec_eoe_frame_t *tx_frame; /**< current TX frame */
+ uint8_t tx_frame_number; /**< number of the transmitted frame */
+ uint8_t tx_fragment_number; /**< number of the fragment */
+ size_t tx_offset; /**< numbero of octets sent */
}
ec_eoe_t;