# HG changeset patch # User Florian Pose # Date 1186674356 0 # Node ID e341f1788608cee9571e5b9803becf3021375c81 # Parent fe7cf37c33f1ed9f34ee819da358d5d5c0f7d56f Switched to tx socket buffer ring to avoid race conditions when multiple instances call ec_device_send() in short intervals. diff -r fe7cf37c33f1 -r e341f1788608 master/device.c --- a/master/device.c Thu Aug 09 15:01:14 2007 +0000 +++ b/master/device.c Thu Aug 09 15:45:56 2007 +0000 @@ -69,6 +69,8 @@ ec_master_t *master /**< master owning the device */ ) { + unsigned int i; + struct ethhdr *eth; #ifdef EC_DEBUG_IF char ifname[10]; char mb = 'x'; @@ -79,6 +81,7 @@ #endif device->master = master; + device->tx_ring_index = 0; #ifdef EC_DEBUG_IF if (device == &master->main_device) @@ -94,29 +97,33 @@ } #endif - if (!(device->tx_skb = dev_alloc_skb(ETH_FRAME_LEN))) { - EC_ERR("Error allocating device socket buffer!\n"); -#ifdef EC_DEBUG_IF - goto out_debug; -#else - goto out_return; -#endif - } - - // add Ethernet-II-header - skb_reserve(device->tx_skb, ETH_HLEN); - device->eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN); - device->eth->h_proto = htons(0x88A4); - memset(device->eth->h_dest, 0xFF, ETH_ALEN); + for (i = 0; i < EC_TX_RING_SIZE; i++) + device->tx_skb[i] = NULL; + + for (i = 0; i < EC_TX_RING_SIZE; i++) { + if (!(device->tx_skb[i] = dev_alloc_skb(ETH_FRAME_LEN))) { + EC_ERR("Error allocating device socket buffer!\n"); + goto out_tx_ring; + } + + // add Ethernet-II-header + skb_reserve(device->tx_skb[i], ETH_HLEN); + eth = (struct ethhdr *) skb_push(device->tx_skb[i], ETH_HLEN); + eth->h_proto = htons(0x88A4); + memset(eth->h_dest, 0xFF, ETH_ALEN); + } ec_device_detach(device); // resets remaining fields return 0; -#ifdef EC_DEBUG_IF - out_debug: +out_tx_ring: + for (i = 0; i < EC_TX_RING_SIZE; i++) + if (device->tx_skb[i]) + dev_kfree_skb(device->tx_skb[i]); +#ifdef EC_DEBUG_IF ec_debug_clear(&device->dbg); -#endif - out_return: +out_return: +#endif return -1; } @@ -128,8 +135,11 @@ void ec_device_clear(ec_device_t *device /**< EtherCAT device */) { + unsigned int i; + if (device->open) ec_device_close(device); - dev_kfree_skb(device->tx_skb); + for (i = 0; i < EC_TX_RING_SIZE; i++) + dev_kfree_skb(device->tx_skb[i]); #ifdef EC_DEBUG_IF ec_debug_clear(&device->dbg); #endif @@ -147,14 +157,20 @@ struct module *module /**< the device's module */ ) { + unsigned int i; + struct ethhdr *eth; + ec_device_detach(device); // resets fields device->dev = net_dev; device->poll = poll; device->module = module; - device->tx_skb->dev = net_dev; - memcpy(device->eth->h_source, net_dev->dev_addr, ETH_ALEN); + for (i = 0; i < EC_TX_RING_SIZE; i++) { + device->tx_skb[i]->dev = net_dev; + eth = (struct ethhdr *) (device->tx_skb[i]->data + ETH_HLEN); + memcpy(eth->h_source, net_dev->dev_addr, ETH_ALEN); + } } /*****************************************************************************/ @@ -165,6 +181,8 @@ void ec_device_detach(ec_device_t *device /**< EtherCAT device */) { + unsigned int i; + device->dev = NULL; device->poll = NULL; device->module = NULL; @@ -172,7 +190,8 @@ device->link_state = 0; // down device->tx_count = 0; device->rx_count = 0; - device->tx_skb->dev = NULL; + for (i = 0; i < EC_TX_RING_SIZE; i++) + device->tx_skb[i]->dev = NULL; } /*****************************************************************************/ @@ -236,7 +255,12 @@ uint8_t *ec_device_tx_data(ec_device_t *device /**< EtherCAT device */) { - return device->tx_skb->data + ETH_HLEN; + /* cycle through socket buffers, because otherwise there is a race + * condition, if multiple frames are sent and the DMA is not scheduled in + * between. */ + device->tx_ring_index++; + device->tx_ring_index %= EC_TX_RING_SIZE; + return device->tx_skb[device->tx_ring_index]->data + ETH_HLEN; } /*****************************************************************************/ @@ -251,27 +275,29 @@ size_t size /**< number of bytes to send */ ) { + struct sk_buff *skb = device->tx_skb[device->tx_ring_index]; + if (unlikely(!device->link_state)) // Link down return; // set the right length for the data - device->tx_skb->len = ETH_HLEN + size; + skb->len = ETH_HLEN + size; if (unlikely(device->master->debug_level > 1)) { EC_DBG("sending frame:\n"); - ec_print_data(device->tx_skb->data + ETH_HLEN, size); - } - -#ifdef EC_DEBUG_IF - ec_debug_send(&device->dbg, device->tx_skb->data, ETH_HLEN + size); + ec_print_data(skb->data + ETH_HLEN, size); + } + +#ifdef EC_DEBUG_IF + ec_debug_send(&device->dbg, skb->data, ETH_HLEN + size); #endif #ifdef EC_DEBUG_RING ec_device_debug_ring_append( - device, TX, device->tx_skb->data + ETH_HLEN, size); + device, TX, skb->data + ETH_HLEN, size); #endif // start sending - device->dev->hard_start_xmit(device->tx_skb, device->dev); + device->dev->hard_start_xmit(skb, device->dev); device->tx_count++; } @@ -389,7 +415,7 @@ if (unlikely(device->master->debug_level > 1)) { EC_DBG("Received frame:\n"); - ec_print_data_diff(device->tx_skb->data + ETH_HLEN, ec_data, ec_size); + ec_print_data(ec_data, ec_size); } #ifdef EC_DEBUG_IF diff -r fe7cf37c33f1 -r e341f1788608 master/device.h --- a/master/device.h Thu Aug 09 15:01:14 2007 +0000 +++ b/master/device.h Thu Aug 09 15:45:56 2007 +0000 @@ -47,6 +47,8 @@ #include "../devices/ecdev.h" #include "globals.h" +#define EC_TX_RING_SIZE 2 + #ifdef EC_DEBUG_IF #include "debug.h" #endif @@ -84,8 +86,8 @@ struct module *module; /**< pointer to the device's owning module */ uint8_t open; /**< true, if the net_device has been opened */ uint8_t link_state; /**< device link state */ - struct sk_buff *tx_skb; /**< transmit socket buffer */ - struct ethhdr *eth; /**< pointer to ethernet header in socket buffer */ + struct sk_buff *tx_skb[EC_TX_RING_SIZE]; /**< transmit skb ring */ + unsigned int tx_ring_index; cycles_t cycles_poll; /**< cycles of last poll */ #ifdef EC_DEBUG_RING struct timeval timeval_poll;