fp@145: /******************************************************************************
fp@145:  *
fp@145:  *  $Id$
fp@145:  *
fp@1326:  *  Copyright (C) 2006-2008  Florian Pose, Ingenieurgemeinschaft IgH
fp@197:  *
fp@197:  *  This file is part of the IgH EtherCAT Master.
fp@197:  *
fp@1326:  *  The IgH EtherCAT Master is free software; you can redistribute it and/or
fp@1326:  *  modify it under the terms of the GNU General Public License version 2, as
fp@1326:  *  published by the Free Software Foundation.
fp@1326:  *
fp@1326:  *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
fp@1326:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
fp@1326:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
fp@1326:  *  Public License for more details.
fp@1326:  *
fp@1326:  *  You should have received a copy of the GNU General Public License along
fp@1326:  *  with the IgH EtherCAT Master; if not, write to the Free Software
fp@197:  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
fp@197:  *
fp@1363:  *  ---
fp@1363:  *
fp@1363:  *  The license mentioned above concerns the source code only. Using the
fp@1363:  *  EtherCAT technology and brand is only permitted in compliance with the
fp@1363:  *  industrial property and similar rights of Beckhoff Automation GmbH.
fp@246:  *
fp@145:  *****************************************************************************/
fp@145: 
fp@199: /**
fp@199:    \file
fp@1327:    Ethernet over EtherCAT (EoE).
fp@199: */
fp@199: 
fp@199: /*****************************************************************************/
fp@199: 
martin@1579: #include <linux/version.h>
fp@294: #include <linux/netdevice.h>
fp@210: #include <linux/etherdevice.h>
fp@210: 
fp@145: #include "globals.h"
fp@145: #include "master.h"
fp@145: #include "slave.h"
fp@145: #include "mailbox.h"
fp@145: #include "ethernet.h"
fp@145: 
fp@629: /*****************************************************************************/
fp@629: 
fp@1486: /** Defines the debug level of EoE processing.
fp@629:  *
fp@629:  * 0 = No debug messages.
fp@1486:  * 1 = Output warnings.
fp@1486:  * 2 = Output actions.
fp@1486:  * 3 = Output actions and frame data.
fp@629:  */
fp@1489: #define EOE_DEBUG_LEVEL 1
fp@215: 
fp@1486: /** Size of the EoE tx queue.
fp@1486:  */
fp@629: #define EC_EOE_TX_QUEUE_SIZE 100
fp@629: 
fp@1486: /** Number of tries.
fp@1486:  */
fp@1489: #define EC_EOE_TRIES 100
fp@1486: 
fp@145: /*****************************************************************************/
fp@145: 
fp@214: void ec_eoe_flush(ec_eoe_t *);
fp@218: 
fp@218: // state functions
fp@218: void ec_eoe_state_rx_start(ec_eoe_t *);
fp@218: void ec_eoe_state_rx_check(ec_eoe_t *);
fp@218: void ec_eoe_state_rx_fetch(ec_eoe_t *);
fp@218: void ec_eoe_state_tx_start(ec_eoe_t *);
fp@218: void ec_eoe_state_tx_sent(ec_eoe_t *);
fp@218: 
fp@218: // net_device functions
fp@203: int ec_eoedev_open(struct net_device *);
fp@203: int ec_eoedev_stop(struct net_device *);
fp@203: int ec_eoedev_tx(struct sk_buff *, struct net_device *);
fp@203: struct net_device_stats *ec_eoedev_stats(struct net_device *);
fp@203: 
fp@203: /*****************************************************************************/
fp@203: 
fp@1561: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
fp@1907: /** Device operations for EoE interfaces.
fp@1907:  */
fp@1561: static const struct net_device_ops ec_eoedev_ops = {
martin@1579:     .ndo_open = ec_eoedev_open,
martin@1579:     .ndo_stop = ec_eoedev_stop,
martin@1579:     .ndo_start_xmit = ec_eoedev_tx,
martin@1579:     .ndo_get_stats = ec_eoedev_stats,
martin@1579: };
martin@1579: #endif
martin@1579: 
fp@203: /*****************************************************************************/
fp@203: 
fp@1487: /** EoE constructor.
fp@1487:  *
fp@661:  * Initializes the EoE handler, creates a net_device and registers it.
fp@2522:  *
fp@2522:  * \return Zero on success, otherwise a negative error code.
fp@661:  */
fp@661: int ec_eoe_init(
fp@661:         ec_eoe_t *eoe, /**< EoE handler */
fp@661:         ec_slave_t *slave /**< EtherCAT slave */
fp@661:         )
fp@203: {
fp@213:     ec_eoe_t **priv;
fp@1313:     int i, ret = 0;
fp@719:     char name[EC_DATAGRAM_NAME_SIZE];
fp@661: 
fp@661:     eoe->slave = slave;
fp@661: 
fp@293:     ec_datagram_init(&eoe->datagram);
fp@721:     eoe->queue_datagram = 0;
fp@218:     eoe->state = ec_eoe_state_rx_start;
fp@210:     eoe->opened = 0;
fp@218:     eoe->rx_skb = NULL;
fp@218:     eoe->rx_expected_fragment = 0;
fp@212:     INIT_LIST_HEAD(&eoe->tx_queue);
fp@218:     eoe->tx_frame = NULL;
fp@214:     eoe->tx_queue_active = 0;
fp@1485:     eoe->tx_queue_size = EC_EOE_TX_QUEUE_SIZE;
fp@218:     eoe->tx_queued_frames = 0;
martin@1579: 
martin@1579:     sema_init(&eoe->tx_queue_sem, 1);
fp@214:     eoe->tx_frame_number = 0xFF;
fp@214:     memset(&eoe->stats, 0, sizeof(struct net_device_stats));
fp@203: 
fp@336:     eoe->rx_counter = 0;
fp@336:     eoe->tx_counter = 0;
fp@336:     eoe->rx_rate = 0;
fp@336:     eoe->tx_rate = 0;
fp@344:     eoe->rate_jiffies = 0;
fp@1489:     eoe->rx_idle = 1;
fp@1489:     eoe->tx_idle = 1;
fp@336: 
fp@712:     /* device name eoe<MASTER>[as]<SLAVE>, because networking scripts don't
fp@712:      * like hyphens etc. in interface names. */
fp@1909:     if (slave->effective_alias) {
fp@719:         snprintf(name, EC_DATAGRAM_NAME_SIZE,
fp@1909:                 "eoe%ua%u", slave->master->index, slave->effective_alias);
fp@712:     } else {
fp@719:         snprintf(name, EC_DATAGRAM_NAME_SIZE,
fp@719:                 "eoe%us%u", slave->master->index, slave->ring_position);
fp@719:     }
fp@719: 
fp@719:     snprintf(eoe->datagram.name, EC_DATAGRAM_NAME_SIZE, name);
fp@661: 
fp@2631: #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
fp@2631:     eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, NET_NAME_UNKNOWN,
fp@2631:             ether_setup);
fp@2631: #else
fp@2631:     eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup);
fp@2631: #endif
fp@2631:     if (!eoe->dev) {
fp@1921:         EC_SLAVE_ERR(slave, "Unable to allocate net_device %s"
fp@1921:                 " for EoE handler!\n", name);
fp@1313:         ret = -ENODEV;
fp@203:         goto out_return;
fp@203:     }
fp@203: 
fp@218:     // initialize net_device
fp@1561: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
fp@1561:     eoe->dev->netdev_ops = &ec_eoedev_ops;
martin@1579: #else
fp@218:     eoe->dev->open = ec_eoedev_open;
fp@218:     eoe->dev->stop = ec_eoedev_stop;
fp@218:     eoe->dev->hard_start_xmit = ec_eoedev_tx;
fp@218:     eoe->dev->get_stats = ec_eoedev_stats;
martin@1579: #endif
fp@218: 
fp@218:     for (i = 0; i < ETH_ALEN; i++)
fp@218:         eoe->dev->dev_addr[i] = i | (i << 4);
fp@218: 
fp@218:     // initialize private data
fp@203:     priv = netdev_priv(eoe->dev);
fp@213:     *priv = eoe;
fp@203: 
fp@218:     // Usually setting the MTU appropriately makes the upper layers
fp@218:     // do the frame fragmenting. In some cases this doesn't work
fp@218:     // so the MTU is left on the Ethernet standard value and fragmenting
fp@218:     // is done "manually".
fp@218: #if 0
fp@1338:     eoe->dev->mtu = slave->configured_rx_mailbox_size - ETH_HLEN - 10;
fp@218: #endif
fp@214: 
fp@203:     // connect the net_device to the kernel
fp@1313:     ret = register_netdev(eoe->dev);
fp@1313:     if (ret) {
fp@1921:         EC_SLAVE_ERR(slave, "Unable to register net_device:"
fp@1921:                 " error %i\n", ret);
fp@203:         goto out_free;
fp@203:     }
fp@203: 
fp@218:     // make the last address octet unique
fp@218:     eoe->dev->dev_addr[ETH_ALEN - 1] = (uint8_t) eoe->dev->ifindex;
fp@203:     return 0;
fp@203: 
fp@203:  out_free:
fp@203:     free_netdev(eoe->dev);
fp@203:     eoe->dev = NULL;
fp@203:  out_return:
fp@1313:     return ret;
fp@145: }
fp@145: 
fp@145: /*****************************************************************************/
fp@145: 
fp@1487: /** EoE destructor.
fp@1487:  *
fp@1487:  * Unregisteres the net_device and frees allocated memory.
fp@1487:  */
fp@251: void ec_eoe_clear(ec_eoe_t *eoe /**< EoE handler */)
fp@145: {
fp@552:     unregister_netdev(eoe->dev); // possibly calls close callback
fp@214: 
fp@214:     // empty transmit queue
fp@214:     ec_eoe_flush(eoe);
fp@218: 
fp@218:     if (eoe->tx_frame) {
fp@218:         dev_kfree_skb(eoe->tx_frame->skb);
fp@218:         kfree(eoe->tx_frame);
fp@218:     }
fp@218: 
fp@1552:     if (eoe->rx_skb)
fp@1552:         dev_kfree_skb(eoe->rx_skb);
fp@1552: 
fp@1552:     free_netdev(eoe->dev);
fp@279: 
fp@293:     ec_datagram_clear(&eoe->datagram);
fp@214: }
fp@214: 
fp@214: /*****************************************************************************/
fp@214: 
fp@1487: /** Empties the transmit queue.
fp@1487:  */
fp@251: void ec_eoe_flush(ec_eoe_t *eoe /**< EoE handler */)
fp@214: {
fp@214:     ec_eoe_frame_t *frame, *next;
fp@214: 
fp@1489:     down(&eoe->tx_queue_sem);
fp@214: 
fp@214:     list_for_each_entry_safe(frame, next, &eoe->tx_queue, queue) {
fp@214:         list_del(&frame->queue);
fp@214:         dev_kfree_skb(frame->skb);
fp@214:         kfree(frame);
fp@214:     }
fp@218:     eoe->tx_queued_frames = 0;
fp@214: 
fp@1489:     up(&eoe->tx_queue_sem);
fp@145: }
fp@145: 
fp@145: /*****************************************************************************/
fp@145: 
fp@1487: /** Sends a frame or the next fragment.
fp@2522:  *
fp@2522:  * \return Zero on success, otherwise a negative error code.
fp@1487:  */
fp@251: int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@217:     size_t remaining_size, current_size, complete_offset;
fp@217:     unsigned int last_fragment;
fp@217:     uint8_t *data;
fp@1486: #if EOE_DEBUG_LEVEL >= 3
fp@217:     unsigned int i;
fp@217: #endif
fp@217: 
fp@218:     remaining_size = eoe->tx_frame->skb->len - eoe->tx_offset;
fp@217: 
fp@1338:     if (remaining_size <= eoe->slave->configured_tx_mailbox_size - 10) {
fp@217:         current_size = remaining_size;
fp@217:         last_fragment = 1;
fp@1337:     } else {
fp@1338:         current_size = ((eoe->slave->configured_tx_mailbox_size - 10) / 32) * 32;
fp@217:         last_fragment = 0;
fp@217:     }
fp@217: 
fp@217:     if (eoe->tx_fragment_number) {
fp@217:         complete_offset = eoe->tx_offset / 32;
fp@217:     }
fp@217:     else {
fp@319:         // complete size in 32 bit blocks, rounded up.
fp@217:         complete_offset = remaining_size / 32 + 1;
fp@217:     }
fp@217: 
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1921:     EC_SLAVE_DBG(slave, 0, "EoE %s TX sending fragment %u%s"
fp@1921:             " with %u octets (%u). %u frames queued.\n",
fp@1921:             eoe->dev->name, eoe->tx_fragment_number,
fp@1921:             last_fragment ? "" : "+", current_size, complete_offset,
fp@1921:             eoe->tx_queued_frames);
fp@217: #endif
fp@217: 
fp@1486: #if EOE_DEBUG_LEVEL >= 3
fp@1921:     EC_SLAVE_DBG(master, 0, "");
fp@217:     for (i = 0; i < current_size; i++) {
fp@340:         printk("%02X ", eoe->tx_frame->skb->data[eoe->tx_offset + i]);
fp@217:         if ((i + 1) % 16 == 0) {
fp@217:             printk("\n");
fp@1921:             EC_SLAVE_DBG(master, 0, "");
fp@217:         }
fp@217:     }
fp@217:     printk("\n");
fp@217: #endif
fp@217: 
fp@1313:     data = ec_slave_mbox_prepare_send(eoe->slave, &eoe->datagram,
fp@1313:             0x02, current_size + 4);
fp@1313:     if (IS_ERR(data))
fp@1313:         return PTR_ERR(data);
fp@217: 
fp@217:     EC_WRITE_U8 (data,     0x00); // eoe fragment req.
fp@217:     EC_WRITE_U8 (data + 1, last_fragment);
fp@217:     EC_WRITE_U16(data + 2, ((eoe->tx_fragment_number & 0x3F) |
fp@217:                             (complete_offset & 0x3F) << 6 |
fp@217:                             (eoe->tx_frame_number & 0x0F) << 12));
fp@217: 
fp@218:     memcpy(data + 4, eoe->tx_frame->skb->data + eoe->tx_offset, current_size);
fp@721:     eoe->queue_datagram = 1;
fp@217: 
fp@217:     eoe->tx_offset += current_size;
fp@217:     eoe->tx_fragment_number++;
fp@217:     return 0;
fp@217: }
fp@217: 
fp@217: /*****************************************************************************/
fp@217: 
fp@1487: /** Runs the EoE state machine.
fp@1487:  */
fp@251: void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@1484:     if (!eoe->opened)
fp@1484:         return;
fp@145: 
fp@721:     // if the datagram was not sent, or is not yet received, skip this cycle
fp@721:     if (eoe->queue_datagram || eoe->datagram.state == EC_DATAGRAM_SENT)
fp@721:         return;
fp@721: 
fp@218:     // call state function
fp@218:     eoe->state(eoe);
fp@336: 
fp@336:     // update statistics
fp@344:     if (jiffies - eoe->rate_jiffies > HZ) {
fp@1485:         eoe->rx_rate = eoe->rx_counter;
fp@1485:         eoe->tx_rate = eoe->tx_counter;
fp@336:         eoe->rx_counter = 0;
fp@336:         eoe->tx_counter = 0;
fp@344:         eoe->rate_jiffies = jiffies;
fp@336:     }
fp@721: 
fp@719:     ec_datagram_output_stats(&eoe->datagram);
fp@145: }
fp@145: 
fp@145: /*****************************************************************************/
fp@145: 
fp@1487: /** Queues the datagram, if necessary.
fp@1487:  */
fp@721: void ec_eoe_queue(ec_eoe_t *eoe /**< EoE handler */)
fp@721: {
fp@721:    if (eoe->queue_datagram) {
fp@1500:        ec_master_queue_datagram_ext(eoe->slave->master, &eoe->datagram);
fp@721:        eoe->queue_datagram = 0;
fp@721:    }
fp@721: }
fp@721: 
fp@721: /*****************************************************************************/
fp@721: 
fp@1487: /** Returns the state of the device.
fp@1487:  *
fp@1487:  * \return 1 if the device is "up", 0 if it is "down"
fp@1487:  */
fp@661: int ec_eoe_is_open(const ec_eoe_t *eoe /**< EoE handler */)
fp@661: {
fp@661:     return eoe->opened;
fp@251: }
fp@251: 
fp@1489: /*****************************************************************************/
fp@1489: 
fp@1489: /** Returns the idle state.
fp@1489:  *
fp@1489:  * \retval 1 The device is idle.
fp@1489:  * \retval 0 The device is busy.
fp@1489:  */
fp@1489: int ec_eoe_is_idle(const ec_eoe_t *eoe /**< EoE handler */)
fp@1489: {
fp@1489:     return eoe->rx_idle && eoe->tx_idle;
fp@1489: }
fp@1489: 
fp@218: /******************************************************************************
fp@218:  *  STATE PROCESSING FUNCTIONS
fp@218:  *****************************************************************************/
fp@218: 
fp@1487: /** State: RX_START.
fp@1487:  *
fp@1487:  * Starts a new receiving sequence by queueing a datagram that checks the
fp@1487:  * slave's mailbox for a new EoE datagram.
fp@2267:  *
fp@2522:  * \todo Use both devices.
fp@1487:  */
fp@251: void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@1489:     if (eoe->slave->error_flag ||
fp@2267:             !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
fp@1489:         eoe->rx_idle = 1;
fp@1489:         eoe->tx_idle = 1;
fp@1489:         return;
fp@1489:     }
fp@261: 
fp@293:     ec_slave_mbox_prepare_check(eoe->slave, &eoe->datagram);
fp@721:     eoe->queue_datagram = 1;
fp@218:     eoe->state = ec_eoe_state_rx_check;
fp@218: }
fp@218: 
fp@218: /*****************************************************************************/
fp@218: 
fp@1487: /** State: RX_CHECK.
fp@1487:  *
fp@1487:  * Processes the checking datagram sent in RX_START and issues a receive
fp@1487:  * datagram, if new data is available.
fp@1487:  */
fp@251: void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@325:     if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
fp@218:         eoe->stats.rx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "Failed to receive mbox"
fp@1921:                 " check datagram for %s.\n", eoe->dev->name);
fp@1486: #endif
fp@218:         eoe->state = ec_eoe_state_tx_start;
fp@218:         return;
fp@218:     }
fp@218: 
fp@293:     if (!ec_slave_mbox_check(&eoe->datagram)) {
fp@1489:         eoe->rx_idle = 1;
fp@218:         eoe->state = ec_eoe_state_tx_start;
fp@218:         return;
fp@218:     }
fp@218: 
fp@1489:     eoe->rx_idle = 0;
fp@293:     ec_slave_mbox_prepare_fetch(eoe->slave, &eoe->datagram);
fp@721:     eoe->queue_datagram = 1;
fp@218:     eoe->state = ec_eoe_state_rx_fetch;
fp@218: }
fp@218: 
fp@218: /*****************************************************************************/
fp@218: 
fp@1487: /** State: RX_FETCH.
fp@1487:  *
fp@1487:  * Checks if the requested data of RX_CHECK was received and processes the EoE
fp@1487:  * datagram.
fp@1487:  */
fp@251: void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@218:     size_t rec_size, data_size;
fp@391:     uint8_t *data, frame_type, last_fragment, time_appended, mbox_prot;
fp@2336:     uint8_t fragment_offset, fragment_number;
fp@2336: #if EOE_DEBUG_LEVEL >= 2
fp@2336:     uint8_t frame_number;
fp@2336: #endif
fp@218:     off_t offset;
fp@1486: #if EOE_DEBUG_LEVEL >= 3
fp@340:     unsigned int i;
fp@340: #endif
fp@218: 
fp@325:     if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
fp@218:         eoe->stats.rx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "Failed to receive mbox"
fp@1921:                 " fetch datagram for %s.\n", eoe->dev->name);
fp@1486: #endif
fp@218:         eoe->state = ec_eoe_state_tx_start;
fp@218:         return;
fp@218:     }
fp@218: 
fp@1313:     data = ec_slave_mbox_fetch(eoe->slave, &eoe->datagram,
fp@1313:             &mbox_prot, &rec_size);
fp@1313:     if (IS_ERR(data)) {
fp@390:         eoe->stats.rx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "Invalid mailbox response for %s.\n",
fp@1486:                 eoe->dev->name);
fp@1486: #endif
fp@390:         eoe->state = ec_eoe_state_tx_start;
fp@390:         return;
fp@390:     }
fp@390: 
fp@689:     if (mbox_prot != 0x02) { // EoE FIXME mailbox handler necessary
fp@218:         eoe->stats.rx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "Other mailbox protocol response for %s.\n",
fp@1486:                 eoe->dev->name);
fp@1486: #endif
fp@218:         eoe->state = ec_eoe_state_tx_start;
fp@218:         return;
fp@218:     }
fp@218: 
fp@218:     frame_type = EC_READ_U16(data) & 0x000F;
fp@218: 
fp@322:     if (frame_type != 0x00) {
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "%s: Other frame received."
fp@1921:                 " Dropping.\n", eoe->dev->name);
fp@218: #endif
fp@218:         eoe->stats.rx_dropped++;
fp@218:         eoe->state = ec_eoe_state_tx_start;
fp@322:         return;
fp@322:     }
fp@322: 
fp@322:     // EoE Fragment Request received
fp@322: 
fp@322:     last_fragment = (EC_READ_U16(data) >> 8) & 0x0001;
fp@322:     time_appended = (EC_READ_U16(data) >> 9) & 0x0001;
fp@322:     fragment_number = EC_READ_U16(data + 2) & 0x003F;
fp@322:     fragment_offset = (EC_READ_U16(data + 2) >> 6) & 0x003F;
fp@2336: #if EOE_DEBUG_LEVEL >= 2
fp@322:     frame_number = (EC_READ_U16(data + 2) >> 12) & 0x000F;
fp@2336: #endif
fp@322: 
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1921:     EC_SLAVE_DBG(eoe->slave, 0, "EoE %s RX fragment %u%s, offset %u,"
fp@1921:             " frame %u%s, %u octets\n", eoe->dev->name, fragment_number,
fp@2421:            last_fragment ? "" : "+", fragment_offset, frame_number,
fp@322:            time_appended ? ", + timestamp" : "",
fp@322:            time_appended ? rec_size - 8 : rec_size - 4);
fp@322: #endif
fp@322: 
fp@1486: #if EOE_DEBUG_LEVEL >= 3
fp@1921:     EC_SLAVE_DBG(eoe->slave, 0, "");
fp@322:     for (i = 0; i < rec_size - 4; i++) {
fp@322:         printk("%02X ", data[i + 4]);
fp@322:         if ((i + 1) % 16 == 0) {
fp@322:             printk("\n");
fp@1921:             EC_SLAVE_DBG(eoe->slave, 0, "");
fp@322:         }
fp@322:     }
fp@322:     printk("\n");
fp@322: #endif
fp@322: 
fp@322:     data_size = time_appended ? rec_size - 8 : rec_size - 4;
fp@322: 
fp@322:     if (!fragment_number) {
fp@322:         if (eoe->rx_skb) {
fp@1921:             EC_SLAVE_WARN(eoe->slave, "EoE RX freeing old socket buffer.\n");
fp@322:             dev_kfree_skb(eoe->rx_skb);
fp@322:         }
fp@322: 
fp@322:         // new socket buffer
fp@322:         if (!(eoe->rx_skb = dev_alloc_skb(fragment_offset * 32))) {
fp@322:             if (printk_ratelimit())
fp@1921:                 EC_SLAVE_WARN(eoe->slave, "EoE RX low on mem,"
fp@1921:                         " frame dropped.\n");
fp@322:             eoe->stats.rx_dropped++;
fp@322:             eoe->state = ec_eoe_state_tx_start;
fp@322:             return;
fp@322:         }
fp@322: 
fp@322:         eoe->rx_skb_offset = 0;
fp@322:         eoe->rx_skb_size = fragment_offset * 32;
fp@322:         eoe->rx_expected_fragment = 0;
fp@322:     }
fp@322:     else {
fp@322:         if (!eoe->rx_skb) {
fp@322:             eoe->stats.rx_dropped++;
fp@322:             eoe->state = ec_eoe_state_tx_start;
fp@322:             return;
fp@322:         }
fp@322: 
fp@322:         offset = fragment_offset * 32;
fp@322:         if (offset != eoe->rx_skb_offset ||
fp@322:             offset + data_size > eoe->rx_skb_size ||
fp@322:             fragment_number != eoe->rx_expected_fragment) {
fp@322:             dev_kfree_skb(eoe->rx_skb);
fp@322:             eoe->rx_skb = NULL;
fp@322:             eoe->stats.rx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:             EC_SLAVE_WARN(eoe->slave, "Fragmenting error at %s.\n",
fp@1921:                     eoe->dev->name);
fp@1486: #endif
fp@322:             eoe->state = ec_eoe_state_tx_start;
fp@322:             return;
fp@322:         }
fp@322:     }
fp@322: 
fp@322:     // copy fragment into socket buffer
fp@322:     memcpy(skb_put(eoe->rx_skb, data_size), data + 4, data_size);
fp@322:     eoe->rx_skb_offset += data_size;
fp@322: 
fp@322:     if (last_fragment) {
fp@322:         // update statistics
fp@322:         eoe->stats.rx_packets++;
fp@322:         eoe->stats.rx_bytes += eoe->rx_skb->len;
fp@336:         eoe->rx_counter += eoe->rx_skb->len;
fp@322: 
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1921:         EC_SLAVE_DBG(eoe->slave, 0, "EoE %s RX frame completed"
fp@1921:                 " with %u octets.\n", eoe->dev->name, eoe->rx_skb->len);
fp@322: #endif
fp@322: 
fp@322:         // pass socket buffer to network stack
fp@322:         eoe->rx_skb->dev = eoe->dev;
fp@322:         eoe->rx_skb->protocol = eth_type_trans(eoe->rx_skb, eoe->dev);
fp@322:         eoe->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
fp@322:         if (netif_rx(eoe->rx_skb)) {
fp@1921:             EC_SLAVE_WARN(eoe->slave, "EoE RX netif_rx failed.\n");
fp@322:         }
fp@322:         eoe->rx_skb = NULL;
fp@322: 
fp@322:         eoe->state = ec_eoe_state_tx_start;
fp@322:     }
fp@322:     else {
fp@322:         eoe->rx_expected_fragment++;
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1921:         EC_SLAVE_DBG(eoe->slave, 0, "EoE %s RX expecting fragment %u\n",
fp@770:                eoe->dev->name, eoe->rx_expected_fragment);
fp@322: #endif
fp@322:         eoe->state = ec_eoe_state_rx_start;
fp@218:     }
fp@218: }
fp@218: 
fp@218: /*****************************************************************************/
fp@218: 
fp@1487: /** State: TX START.
fp@1487:  *
fp@1487:  * Starts a new transmit sequence. If no data is available, a new receive
fp@1487:  * sequence is started instead.
fp@2267:  *
fp@2522:  * \todo Use both devices.
fp@1487:  */
fp@251: void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@340:     unsigned int wakeup = 0;
fp@218: #endif
fp@218: 
fp@1489:     if (eoe->slave->error_flag ||
fp@2267:             !eoe->slave->master->devices[EC_DEVICE_MAIN].link_state) {
fp@1489:         eoe->rx_idle = 1;
fp@1489:         eoe->tx_idle = 1;
fp@1489:         return;
fp@1489:     }
fp@1489: 
fp@1489:     down(&eoe->tx_queue_sem);
fp@218: 
fp@218:     if (!eoe->tx_queued_frames || list_empty(&eoe->tx_queue)) {
fp@1489:         up(&eoe->tx_queue_sem);
fp@1489:         eoe->tx_idle = 1;
fp@218:         // no data available.
fp@218:         // start a new receive immediately.
fp@218:         ec_eoe_state_rx_start(eoe);
fp@218:         return;
fp@218:     }
fp@218: 
fp@218:     // take the first frame out of the queue
fp@218:     eoe->tx_frame = list_entry(eoe->tx_queue.next, ec_eoe_frame_t, queue);
fp@218:     list_del(&eoe->tx_frame->queue);
fp@218:     if (!eoe->tx_queue_active &&
fp@1485:         eoe->tx_queued_frames == eoe->tx_queue_size / 2) {
fp@218:         netif_wake_queue(eoe->dev);
fp@218:         eoe->tx_queue_active = 1;
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@218:         wakeup = 1;
fp@218: #endif
fp@218:     }
fp@218: 
fp@218:     eoe->tx_queued_frames--;
fp@1489:     up(&eoe->tx_queue_sem);
fp@1489: 
fp@1489:     eoe->tx_idle = 0;
fp@218: 
fp@218:     eoe->tx_frame_number++;
fp@218:     eoe->tx_frame_number %= 16;
fp@218:     eoe->tx_fragment_number = 0;
fp@218:     eoe->tx_offset = 0;
fp@218: 
fp@218:     if (ec_eoe_send(eoe)) {
fp@218:         dev_kfree_skb(eoe->tx_frame->skb);
fp@218:         kfree(eoe->tx_frame);
fp@218:         eoe->tx_frame = NULL;
fp@218:         eoe->stats.tx_errors++;
fp@218:         eoe->state = ec_eoe_state_rx_start;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:         EC_SLAVE_WARN(eoe->slave, "Send error at %s.\n", eoe->dev->name);
fp@1486: #endif
fp@1486:         return;
fp@1486:     }
fp@1486: 
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1484:     if (wakeup)
fp@1921:         EC_SLAVE_DBG(eoe->slave, 0, "EoE %s waking up TX queue...\n",
fp@1921:                 eoe->dev->name);
fp@218: #endif
fp@218: 
fp@1486:     eoe->tries = EC_EOE_TRIES;
fp@218:     eoe->state = ec_eoe_state_tx_sent;
fp@218: }
fp@218: 
fp@218: /*****************************************************************************/
fp@218: 
fp@1487: /** State: TX SENT.
fp@1487:  *
fp@1487:  * Checks is the previous transmit datagram succeded and sends the next
fp@1487:  * fragment, if necessary.
fp@1487:  */
fp@251: void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */)
fp@218: {
fp@325:     if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
fp@1486:         if (eoe->tries) {
fp@1486:             eoe->tries--; // try again
fp@1486:             eoe->queue_datagram = 1;
fp@1486:         } else {
fp@1486:             eoe->stats.tx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:             EC_SLAVE_WARN(eoe->slave, "Failed to receive send"
fp@1921:                     " datagram for %s after %u tries.\n",
fp@1489:                     eoe->dev->name, EC_EOE_TRIES);
fp@1486: #endif
fp@1486:             eoe->state = ec_eoe_state_rx_start;
fp@1486:         }
fp@218:         return;
fp@218:     }
fp@218: 
fp@293:     if (eoe->datagram.working_counter != 1) {
fp@1486:         if (eoe->tries) {
fp@1486:             eoe->tries--; // try again
fp@1486:             eoe->queue_datagram = 1;
fp@1486:         } else {
fp@1486:             eoe->stats.tx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:             EC_SLAVE_WARN(eoe->slave, "No sending response"
fp@1921:                     " for %s after %u tries.\n",
fp@1489:                     eoe->dev->name, EC_EOE_TRIES);
fp@1486: #endif
fp@1486:             eoe->state = ec_eoe_state_rx_start;
fp@1486:         }
fp@218:         return;
fp@218:     }
fp@218: 
fp@218:     // frame completely sent
fp@218:     if (eoe->tx_offset >= eoe->tx_frame->skb->len) {
fp@218:         eoe->stats.tx_packets++;
fp@218:         eoe->stats.tx_bytes += eoe->tx_frame->skb->len;
fp@336:         eoe->tx_counter += eoe->tx_frame->skb->len;
fp@218:         dev_kfree_skb(eoe->tx_frame->skb);
fp@218:         kfree(eoe->tx_frame);
fp@218:         eoe->tx_frame = NULL;
fp@218:         eoe->state = ec_eoe_state_rx_start;
fp@218:     }
fp@218:     else { // send next fragment
fp@218:         if (ec_eoe_send(eoe)) {
fp@218:             dev_kfree_skb(eoe->tx_frame->skb);
fp@218:             kfree(eoe->tx_frame);
fp@218:             eoe->tx_frame = NULL;
fp@218:             eoe->stats.tx_errors++;
fp@1486: #if EOE_DEBUG_LEVEL >= 1
fp@1921:             EC_SLAVE_WARN(eoe->slave, "Send error at %s.\n", eoe->dev->name);
fp@1486: #endif
fp@218:             eoe->state = ec_eoe_state_rx_start;
fp@218:         }
fp@218:     }
fp@218: }
fp@218: 
fp@218: /******************************************************************************
fp@218:  *  NET_DEVICE functions
fp@218:  *****************************************************************************/
fp@203: 
fp@1487: /** Opens the virtual network device.
fp@2522:  *
fp@2522:  * \return Always zero (success).
fp@1487:  */
fp@203: int ec_eoedev_open(struct net_device *dev /**< EoE net_device */)
fp@203: {
fp@213:     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
fp@214:     ec_eoe_flush(eoe);
fp@212:     eoe->opened = 1;
fp@1489:     eoe->rx_idle = 0;
fp@1489:     eoe->tx_idle = 0;
fp@203:     netif_start_queue(dev);
fp@214:     eoe->tx_queue_active = 1;
fp@1488: #if EOE_DEBUG_LEVEL >= 2
fp@1921:     EC_SLAVE_DBG(eoe->slave, 0, "%s opened.\n", dev->name);
fp@1488: #endif
fp@689:     ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
fp@203:     return 0;
fp@203: }
fp@203: 
fp@203: /*****************************************************************************/
fp@203: 
fp@1487: /** Stops the virtual network device.
fp@2522:  *
fp@2522:  * \return Always zero (success).
fp@1487:  */
fp@203: int ec_eoedev_stop(struct net_device *dev /**< EoE net_device */)
fp@203: {
fp@213:     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
fp@203:     netif_stop_queue(dev);
fp@1489:     eoe->rx_idle = 1;
fp@1489:     eoe->tx_idle = 1;
fp@214:     eoe->tx_queue_active = 0;
fp@212:     eoe->opened = 0;
fp@214:     ec_eoe_flush(eoe);
fp@1488: #if EOE_DEBUG_LEVEL >= 2
fp@1921:     EC_SLAVE_DBG(eoe->slave, 0, "%s stopped.\n", dev->name);
fp@1488: #endif
fp@689:     ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_PREOP);
fp@203:     return 0;
fp@203: }
fp@203: 
fp@203: /*****************************************************************************/
fp@203: 
fp@1487: /** Transmits data via the virtual network device.
fp@2522:  *
fp@2522:  * \return Zero on success, non-zero on failure.
fp@1487:  */
fp@203: int ec_eoedev_tx(struct sk_buff *skb, /**< transmit socket buffer */
fp@203:                  struct net_device *dev /**< EoE net_device */
fp@212:                 )
fp@212: {
fp@213:     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
fp@214:     ec_eoe_frame_t *frame;
fp@214: 
fp@217: #if 0
fp@1338:     if (skb->len > eoe->slave->configured_tx_mailbox_size - 10) {
fp@1921:         EC_SLAVE_WARN(eoe->slave, "EoE TX frame (%u octets)"
fp@1921:                 " exceeds MTU. dropping.\n", skb->len);
fp@214:         dev_kfree_skb(skb);
fp@214:         eoe->stats.tx_dropped++;
fp@214:         return 0;
fp@214:     }
fp@217: #endif
fp@214: 
fp@214:     if (!(frame =
fp@214:           (ec_eoe_frame_t *) kmalloc(sizeof(ec_eoe_frame_t), GFP_ATOMIC))) {
fp@214:         if (printk_ratelimit())
fp@1921:             EC_SLAVE_WARN(eoe->slave, "EoE TX: low on mem. frame dropped.\n");
fp@214:         return 1;
fp@214:     }
fp@214: 
fp@214:     frame->skb = skb;
fp@212: 
fp@1489:     down(&eoe->tx_queue_sem);
fp@214:     list_add_tail(&frame->queue, &eoe->tx_queue);
fp@218:     eoe->tx_queued_frames++;
fp@1485:     if (eoe->tx_queued_frames == eoe->tx_queue_size) {
fp@212:         netif_stop_queue(dev);
fp@214:         eoe->tx_queue_active = 0;
fp@214:     }
fp@1489:     up(&eoe->tx_queue_sem);
fp@212: 
fp@1486: #if EOE_DEBUG_LEVEL >= 2
fp@1921:     EC_SLAVE_DBG(eoe->slave, 0, "EoE %s TX queued frame"
fp@1921:             " with %u octets (%u frames queued).\n",
fp@1921:             eoe->dev->name, skb->len, eoe->tx_queued_frames);
fp@214:     if (!eoe->tx_queue_active)
fp@1921:         EC_SLAVE_WARN(eoe->slave, "EoE TX queue is now full.\n");
fp@215: #endif
fp@214: 
fp@203:     return 0;
fp@203: }
fp@203: 
fp@203: /*****************************************************************************/
fp@203: 
fp@1487: /** Gets statistics about the virtual network device.
fp@2522:  *
fp@2522:  * \return Statistics.
fp@1487:  */
fp@1487: struct net_device_stats *ec_eoedev_stats(
fp@1487:         struct net_device *dev /**< EoE net_device */
fp@1487:         )
fp@203: {
fp@213:     ec_eoe_t *eoe = *((ec_eoe_t **) netdev_priv(dev));
fp@212:     return &eoe->stats;
fp@212: }
fp@212: 
fp@212: /*****************************************************************************/