diff -r af21f0bdc7c9 -r 2b9c78543663 master/device.c --- a/master/device.c Thu Sep 06 14:21:02 2012 +0200 +++ b/master/device.c Mon Nov 03 15:20:05 2014 +0100 @@ -54,16 +54,10 @@ } while (0) #endif -/** List of intervals for frame statistics [s]. - */ -static const unsigned int rate_intervals[] = { - 1, 10, 60 -}; - /*****************************************************************************/ /** Constructor. - * + * * \return 0 in case of success, else < 0 */ int ec_device_init( @@ -78,19 +72,50 @@ char ifname[10]; char mb = 'x'; #endif + + device->master = master; + device->dev = NULL; + device->poll = NULL; + device->module = NULL; + device->open = 0; + device->link_state = 0; + for (i = 0; i < EC_TX_RING_SIZE; i++) { + device->tx_skb[i] = NULL; + } + device->tx_ring_index = 0; +#ifdef EC_HAVE_CYCLES + device->cycles_poll = 0; +#endif +#ifdef EC_DEBUG_RING + device->timeval_poll.tv_sec = 0; + device->timeval_poll.tv_usec = 0; +#endif + device->jiffies_poll = 0; + + ec_device_clear_stats(device); + +#ifdef EC_DEBUG_RING + for (i = 0; i < EC_DEBUG_RING_SIZE; i++) { + ec_debug_frame_t *df = &device->debug_frames[i]; + df->dir = TX; + df->t.tv_sec = 0; + df->t.tv_usec = 0; + memset(df->data, 0, EC_MAX_DATA_SIZE); + df->data_size = 0; + } +#endif #ifdef EC_DEBUG_RING device->debug_frame_index = 0; device->debug_frame_count = 0; #endif - device->master = master; - device->tx_ring_index = 0; - #ifdef EC_DEBUG_IF - if (device == &master->main_device) + if (device == &master->devices[EC_DEVICE_MAIN]) { mb = 'm'; - else if (device == &master->backup_device) + } + else { mb = 'b'; + } sprintf(ifname, "ecdbg%c%u", mb, master->index); @@ -101,9 +126,6 @@ } #endif - 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_MASTER_ERR(master, "Error allocating device socket buffer!\n"); @@ -118,13 +140,14 @@ memset(eth->h_dest, 0xFF, ETH_ALEN); } - ec_device_detach(device); // resets remaining fields return 0; out_tx_ring: - for (i = 0; i < EC_TX_RING_SIZE; i++) - if (device->tx_skb[i]) + 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); out_return: @@ -142,7 +165,9 @@ { unsigned int i; - if (device->open) ec_device_close(device); + if (device->open) { + ec_device_close(device); + } for (i = 0; i < EC_TX_RING_SIZE; i++) dev_kfree_skb(device->tx_skb[i]); #ifdef EC_DEBUG_IF @@ -203,8 +228,9 @@ ec_device_clear_stats(device); - for (i = 0; i < EC_TX_RING_SIZE; i++) + for (i = 0; i < EC_TX_RING_SIZE; i++) { device->tx_skb[i]->dev = NULL; + } } /*****************************************************************************/ @@ -309,30 +335,6 @@ { struct sk_buff *skb = device->tx_skb[device->tx_ring_index]; - // frame statistics - if (unlikely(jiffies - device->stats_jiffies >= HZ)) { - unsigned int i; - u32 tx_frame_rate = - (u32) (device->tx_count - device->last_tx_count) * 1000; - u32 tx_byte_rate = - (device->tx_bytes - device->last_tx_bytes); - u64 loss = device->tx_count - device->rx_count; - s32 loss_rate = (s32) (loss - device->last_loss) * 1000; - for (i = 0; i < EC_RATE_COUNT; i++) { - unsigned int n = rate_intervals[i]; - device->tx_frame_rates[i] = - (device->tx_frame_rates[i] * (n - 1) + tx_frame_rate) / n; - device->tx_byte_rates[i] = - (device->tx_byte_rates[i] * (n - 1) + tx_byte_rate) / n; - device->loss_rates[i] = - (device->loss_rates[i] * (n - 1) + loss_rate) / n; - } - device->last_tx_count = device->tx_count; - device->last_tx_bytes = device->tx_bytes; - device->last_loss = loss; - device->stats_jiffies = jiffies; - } - // set the right length for the data skb->len = ETH_HLEN + size; @@ -350,7 +352,9 @@ #endif { device->tx_count++; + device->master->device_stats.tx_count++; device->tx_bytes += ETH_HLEN + size; + device->master->device_stats.tx_bytes += ETH_HLEN + size; #ifdef EC_DEBUG_IF ec_debug_send(&device->dbg, skb->data, ETH_HLEN + size); #endif @@ -375,16 +379,20 @@ // zero frame statistics device->tx_count = 0; + device->last_tx_count = 0; device->rx_count = 0; + device->last_rx_count = 0; + device->tx_bytes = 0; + device->last_tx_bytes = 0; + device->rx_bytes = 0; + device->last_rx_bytes = 0; device->tx_errors = 0; - device->tx_bytes = 0; - device->last_tx_count = 0; - device->last_tx_bytes = 0; - device->last_loss = 0; + for (i = 0; i < EC_RATE_COUNT; i++) { device->tx_frame_rates[i] = 0; + device->rx_frame_rates[i] = 0; device->tx_byte_rates[i] = 0; - device->loss_rates[i] = 0; + device->rx_byte_rates[i] = 0; } } @@ -403,10 +411,12 @@ ec_debug_frame_t *df = &device->debug_frames[device->debug_frame_index]; df->dir = dir; - if (dir == TX) + if (dir == TX) { do_gettimeofday(&df->t); - else + } + else { df->t = device->timeval_poll; + } memcpy(df->data, data, size); df->data_size = size; @@ -479,6 +489,43 @@ device->poll(device->dev); } +/*****************************************************************************/ + +/** Update device statistics. + */ +void ec_device_update_stats( + ec_device_t *device /**< EtherCAT device */ + ) +{ + unsigned int i; + + s32 tx_frame_rate = (device->tx_count - device->last_tx_count) * 1000; + s32 rx_frame_rate = (device->rx_count - device->last_rx_count) * 1000; + s32 tx_byte_rate = (device->tx_bytes - device->last_tx_bytes); + s32 rx_byte_rate = (device->rx_bytes - device->last_rx_bytes); + + /* Low-pass filter: + * Y_n = y_(n - 1) + T / tau * (x - y_(n - 1)) | T = 1 + * -> Y_n += (x - y_(n - 1)) / tau + */ + for (i = 0; i < EC_RATE_COUNT; i++) { + s32 n = rate_intervals[i]; + device->tx_frame_rates[i] += + (tx_frame_rate - device->tx_frame_rates[i]) / n; + device->rx_frame_rates[i] += + (rx_frame_rate - device->rx_frame_rates[i]) / n; + device->tx_byte_rates[i] += + (tx_byte_rate - device->tx_byte_rates[i]) / n; + device->rx_byte_rates[i] += + (rx_byte_rate - device->rx_byte_rates[i]) / n; + } + + device->last_tx_count = device->tx_count; + device->last_rx_count = device->rx_count; + device->last_tx_bytes = device->tx_bytes; + device->last_rx_bytes = device->rx_bytes; +} + /****************************************************************************** * Device interface *****************************************************************************/ @@ -496,14 +543,25 @@ void ecdev_withdraw(ec_device_t *device /**< EtherCAT device */) { ec_master_t *master = device->master; - char str[20]; - - ec_mac_print(device->dev->dev_addr, str); - EC_MASTER_INFO(master, "Releasing main device %s.\n", str); - - ec_mutex_lock(&master->device_mutex); + char dev_str[20], mac_str[20]; + + ec_mac_print(device->dev->dev_addr, mac_str); + + if (device == &master->devices[EC_DEVICE_MAIN]) { + sprintf(dev_str, "main"); + } else if (device == &master->devices[EC_DEVICE_BACKUP]) { + sprintf(dev_str, "backup"); + } else { + EC_MASTER_WARN(master, "%s() called with unknown device %s!\n", + __func__, mac_str); + sprintf(dev_str, "UNKNOWN"); + } + + EC_MASTER_INFO(master, "Releasing %s device %s.\n", dev_str, mac_str); + + down(&master->device_sem); ec_device_detach(device); - ec_mutex_unlock(&master->device_mutex); + up(&master->device_sem); } /*****************************************************************************/ @@ -516,17 +574,29 @@ int ecdev_open(ec_device_t *device /**< EtherCAT device */) { int ret; + ec_master_t *master = device->master; + unsigned int all_open = 1, dev_idx; ret = ec_device_open(device); if (ret) { - EC_MASTER_ERR(device->master, "Failed to open device!\n"); + EC_MASTER_ERR(master, "Failed to open device!\n"); return ret; } - ret = ec_master_enter_idle_phase(device->master); - if (ret) { - EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n"); - return ret; + for (dev_idx = EC_DEVICE_MAIN; + dev_idx < ec_master_num_devices(device->master); dev_idx++) { + if (!master->devices[dev_idx].open) { + all_open = 0; + break; + } + } + + if (all_open) { + ret = ec_master_enter_idle_phase(device->master); + if (ret) { + EC_MASTER_ERR(device->master, "Failed to enter IDLE phase!\n"); + return ret; + } } return 0; @@ -541,10 +611,15 @@ */ void ecdev_close(ec_device_t *device /**< EtherCAT device */) { - ec_master_leave_idle_phase(device->master); - - if (ec_device_close(device)) - EC_MASTER_WARN(device->master, "Failed to close device!\n"); + ec_master_t *master = device->master; + + if (master->phase == EC_IDLE) { + ec_master_leave_idle_phase(master); + } + + if (ec_device_close(device)) { + EC_MASTER_WARN(master, "Failed to close device!\n"); + } } /*****************************************************************************/ @@ -553,7 +628,7 @@ * * Forwards the received data to the master. The master will analyze the frame * and dispatch the received commands to the sending instances. - * + * * \ingroup DeviceInterface */ void ecdev_receive( @@ -572,6 +647,9 @@ } device->rx_count++; + device->master->device_stats.rx_count++; + device->rx_bytes += size; + device->master->device_stats.rx_bytes += size; if (unlikely(device->master->debug_level > 1)) { EC_MASTER_DBG(device->master, 2, "Received frame:\n"); @@ -585,7 +663,7 @@ ec_device_debug_ring_append(device, RX, ec_data, ec_size); #endif - ec_master_receive_datagrams(device->master, ec_data, ec_size); + ec_master_receive_datagrams(device->master, device, ec_data, ec_size); } /*****************************************************************************/ @@ -594,7 +672,7 @@ * * If the device notifies the master about the link being down, the master * will not try to send frames using this device. - * + * * \ingroup DeviceInterface */ void ecdev_set_link( @@ -603,14 +681,15 @@ ) { if (unlikely(!device)) { - EC_MASTER_WARN(device->master, "ecdev_set_link(): No device!\n"); + EC_WARN("ecdev_set_link() called with null device!\n"); return; } if (likely(state != device->link_state)) { device->link_state = state; EC_MASTER_INFO(device->master, - "Link state changed to %s.\n", (state ? "UP" : "DOWN")); + "Link state of %s changed to %s.\n", + device->dev->name, (state ? "UP" : "DOWN")); } } @@ -619,13 +698,15 @@ /** Reads the link state. * * \ingroup DeviceInterface + * + * \return Link state. */ uint8_t ecdev_get_link( const ec_device_t *device /**< EtherCAT device */ ) { if (unlikely(!device)) { - EC_MASTER_WARN(device->master, "ecdev_get_link(): No device!\n"); + EC_WARN("ecdev_get_link() called with null device!\n"); return 0; }